// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. * Copyright 2009 Jonathan Corbet <[email protected]> */ /* * Core code for the Via multifunction framebuffer device. */ #include <linux/aperture.h> #include <linux/via-core.h> #include <linux/via_i2c.h> #include "via-gpio.h" #include "global.h" #include <linux/module.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/list.h> #include <linux/pm.h> /* * The default port config. */ static struct via_port_cfg adap_configs[] = …; /* * The OLPC XO-1.5 puts the camera power and reset lines onto * GPIO 2C. */ static struct via_port_cfg olpc_adap_configs[] = …; /* * We currently only support one viafb device (will there ever be * more than one?), so just declare it globally here. */ static struct viafb_dev global_dev; /* * Basic register access; spinlock required. */ static inline void viafb_mmio_write(int reg, u32 v) { … } static inline int viafb_mmio_read(int reg) { … } /* ---------------------------------------------------------------------- */ /* * Interrupt management. We have a single IRQ line for a lot of * different functions, so we need to share it. The design here * is that we don't want to reimplement the shared IRQ code here; * we also want to avoid having contention for a single handler thread. * So each subdev driver which needs interrupts just requests * them directly from the kernel. We just have what's needed for * overall access to the interrupt control register. */ /* * Which interrupts are enabled now? */ static u32 viafb_enabled_ints; static void viafb_int_init(void) { … } /* * Allow subdevs to ask for specific interrupts to be enabled. These * functions must be called with reg_lock held */ void viafb_irq_enable(u32 mask) { … } EXPORT_SYMBOL_GPL(…); void viafb_irq_disable(u32 mask) { … } EXPORT_SYMBOL_GPL(…); /* ---------------------------------------------------------------------- */ /* * Currently, the camera driver is the only user of the DMA code, so we * only compile it in if the camera driver is being built. Chances are, * most viafb systems will not need to have this extra code for a while. * As soon as another user comes long, the ifdef can be removed. */ #if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA) /* * Access to the DMA engine. This currently provides what the camera * driver needs (i.e. outgoing only) but is easily expandable if need * be. */ /* * There are four DMA channels in the vx855. For now, we only * use one of them, though. Most of the time, the DMA channel * will be idle, so we keep the IRQ handler unregistered except * when some subsystem has indicated an interest. */ static int viafb_dma_users; static DECLARE_COMPLETION(viafb_dma_completion); /* * This mutex protects viafb_dma_users and our global interrupt * registration state; it also serializes access to the DMA * engine. */ static DEFINE_MUTEX(viafb_dma_lock); /* * The VX855 DMA descriptor (used for s/g transfers) looks * like this. */ struct viafb_vx855_dma_descr { … }; /* * Flags added to the "next descriptor low" pointers */ #define VIAFB_DMA_MAGIC … #define VIAFB_DMA_FINAL_SEGMENT … /* * The completion IRQ handler. */ static irqreturn_t viafb_dma_irq(int irq, void *data) { … } /* * Indicate a need for DMA functionality. */ int viafb_request_dma(void) { … } EXPORT_SYMBOL_GPL(…); void viafb_release_dma(void) { … } EXPORT_SYMBOL_GPL(…); /* * Do a scatter/gather DMA copy from FB memory. You must have done * a successful call to viafb_request_dma() first. */ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg) { … } EXPORT_SYMBOL_GPL(…); #endif /* CONFIG_VIDEO_VIA_CAMERA */ /* ---------------------------------------------------------------------- */ /* * Figure out how big our framebuffer memory is. Kind of ugly, * but evidently we can't trust the information found in the * fbdev configuration area. */ static u16 via_function3[] = …; /* Get the BIOS-configured framebuffer size from PCI configuration space * of function 3 in the respective chipset */ static int viafb_get_fb_size_from_pci(int chip_type) { … } /* * Figure out and map our MMIO regions. */ static int via_pci_setup_mmio(struct viafb_dev *vdev) { … } static void via_pci_teardown_mmio(struct viafb_dev *vdev) { … } /* * Create our subsidiary devices. */ static struct viafb_subdev_info { … } viafb_subdevs[] = …; #define N_SUBDEVS … static int via_create_subdev(struct viafb_dev *vdev, struct viafb_subdev_info *info) { … } static int via_setup_subdevs(struct viafb_dev *vdev) { … } static void via_teardown_subdevs(void) { … } /* * Power management functions */ static __maybe_unused LIST_HEAD(viafb_pm_hooks); static __maybe_unused DEFINE_MUTEX(viafb_pm_hooks_lock); void viafb_pm_register(struct viafb_pm_hooks *hooks) { … } EXPORT_SYMBOL_GPL(…); void viafb_pm_unregister(struct viafb_pm_hooks *hooks) { … } EXPORT_SYMBOL_GPL(…); static int __maybe_unused via_suspend(struct device *dev) { … } static int __maybe_unused via_resume(struct device *dev) { … } static int via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { … } static void via_pci_remove(struct pci_dev *pdev) { … } static const struct pci_device_id via_pci_table[] = …; MODULE_DEVICE_TABLE(pci, via_pci_table); static const struct dev_pm_ops via_pm_ops = …; static struct pci_driver via_driver = …; static int __init via_core_init(void) { … } static void __exit via_core_exit(void) { … } module_init(…) …; module_exit(via_core_exit);