summaryrefslogtreecommitdiff
path: root/drivers/video/via/via-core.c
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2010-04-23 09:46:59 -0600
committerJonathan Corbet <corbet@lwn.net>2010-05-07 17:17:38 -0600
commit94dd1a856b23bd51dfebf68e6dd63cfd4d4fd5ae (patch)
tree32d573966e60cf0b2b41e785015366f6a2eeff0e /drivers/video/via/via-core.c
parent6b841edf572ad757f11013326b796e126f05a719 (diff)
viafb: Add a simple interrupt management infrastructure
The viafb device shares a single interrupt control register among several distinct subunits. This adds a simple layer for management of that register. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte <laforge@gnumonks.org> Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Diffstat (limited to 'drivers/video/via/via-core.c')
-rw-r--r--drivers/video/via/via-core.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index 5a78ef9cb382..701b95575747 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -35,6 +35,65 @@ static struct viafb_dev global_dev;
/*
+ * Basic register access; spinlock required.
+ */
+static inline void viafb_mmio_write(int reg, u32 v)
+{
+ iowrite32(v, global_dev.engine_mmio + reg);
+}
+
+static inline int viafb_mmio_read(int reg)
+{
+ return ioread32(global_dev.engine_mmio + 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)
+{
+ viafb_enabled_ints = 0;
+
+ viafb_mmio_write(VDE_INTERRUPT, 0);
+}
+
+/*
+ * 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)
+{
+ viafb_enabled_ints |= mask;
+ viafb_mmio_write(VDE_INTERRUPT, viafb_enabled_ints | VDE_I_ENABLE);
+}
+EXPORT_SYMBOL_GPL(viafb_irq_enable);
+
+void viafb_irq_disable(u32 mask)
+{
+ viafb_enabled_ints &= ~mask;
+ if (viafb_enabled_ints == 0)
+ viafb_mmio_write(VDE_INTERRUPT, 0); /* Disable entirely */
+ else
+ viafb_mmio_write(VDE_INTERRUPT,
+ viafb_enabled_ints | VDE_I_ENABLE);
+}
+EXPORT_SYMBOL_GPL(viafb_irq_disable);
+
+
+/*
* 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.
@@ -275,8 +334,10 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
if (ret)
goto out_disable;
/*
- * Create our subdevices. Continue even if some things fail.
+ * Set up interrupts and create our subdevices. Continue even if
+ * some things fail.
*/
+ viafb_int_init();
via_setup_subdevs(&global_dev);
/*
* Set up the framebuffer.
@@ -284,6 +345,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
ret = via_fb_pci_probe(&global_dev);
if (ret)
goto out_subdevs;
+
return 0;
out_subdevs: