From 4f47643dbb4c345c5beebe53588682a7ff2c872a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 3 Feb 2013 12:56:16 +1000 Subject: drm/nouveau/gpio: use event interfaces for interrupt signalling Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/subdev/gpio/base.c | 137 ++---------------------- drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c | 33 ++++-- drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c | 39 ++++--- drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c | 4 +- 4 files changed, 61 insertions(+), 152 deletions(-) (limited to 'drivers/gpu/drm/nouveau/core/subdev') diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index 6f574fdc27c1..d422acc9af15 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -102,129 +102,12 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) return ret; } -static int -nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on) -{ - struct dcb_gpio_func func; - int ret; - - ret = nouveau_gpio_find(gpio, idx, tag, line, &func); - if (ret == 0) { - if (idx == 0 && gpio->irq_enable) - gpio->irq_enable(gpio, func.line, on); - else - ret = -ENODEV; - } - - return ret; -} - -struct gpio_isr { - struct nouveau_gpio *gpio; - struct list_head head; - struct work_struct work; - int idx; - struct dcb_gpio_func func; - void (*handler)(void *, int); - void *data; - bool inhibit; -}; - -static void -nouveau_gpio_isr_bh(struct work_struct *work) -{ - struct gpio_isr *isr = container_of(work, struct gpio_isr, work); - struct nouveau_gpio *gpio = isr->gpio; - unsigned long flags; - int state; - - state = nouveau_gpio_get(gpio, isr->idx, isr->func.func, - isr->func.line); - if (state >= 0) - isr->handler(isr->data, state); - - spin_lock_irqsave(&gpio->lock, flags); - isr->inhibit = false; - spin_unlock_irqrestore(&gpio->lock, flags); -} - -static void -nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask) -{ - struct gpio_isr *isr; - - if (idx != 0) - return; - - spin_lock(&gpio->lock); - list_for_each_entry(isr, &gpio->isr, head) { - if (line_mask & (1 << isr->func.line)) { - if (isr->inhibit) - continue; - isr->inhibit = true; - schedule_work(&isr->work); - } - } - spin_unlock(&gpio->lock); -} - -static int -nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, - void (*handler)(void *, int), void *data) -{ - struct gpio_isr *isr; - unsigned long flags; - int ret; - - isr = kzalloc(sizeof(*isr), GFP_KERNEL); - if (!isr) - return -ENOMEM; - - ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func); - if (ret) { - kfree(isr); - return ret; - } - - INIT_WORK(&isr->work, nouveau_gpio_isr_bh); - isr->gpio = gpio; - isr->handler = handler; - isr->data = data; - isr->idx = idx; - - spin_lock_irqsave(&gpio->lock, flags); - list_add(&isr->head, &gpio->isr); - spin_unlock_irqrestore(&gpio->lock, flags); - return 0; -} - -static void -nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, - void (*handler)(void *, int), void *data) +void +_nouveau_gpio_dtor(struct nouveau_object *object) { - struct gpio_isr *isr, *tmp; - struct dcb_gpio_func func; - unsigned long flags; - LIST_HEAD(tofree); - int ret; - - ret = nouveau_gpio_find(gpio, idx, tag, line, &func); - if (ret == 0) { - spin_lock_irqsave(&gpio->lock, flags); - list_for_each_entry_safe(isr, tmp, &gpio->isr, head) { - if (memcmp(&isr->func, &func, sizeof(func)) || - isr->idx != idx || - isr->handler != handler || isr->data != data) - continue; - list_move_tail(&isr->head, &tofree); - } - spin_unlock_irqrestore(&gpio->lock, flags); - - list_for_each_entry_safe(isr, tmp, &tofree, head) { - flush_work(&isr->work); - kfree(isr); - } - } + struct nouveau_gpio *gpio = (void *)object; + nouveau_event_destroy(&gpio->events); + nouveau_subdev_destroy(&gpio->base); } int @@ -242,15 +125,13 @@ nouveau_gpio_create_(struct nouveau_object *parent, if (ret) return ret; + ret = nouveau_event_create(lines, &gpio->events); + if (ret) + return ret; + gpio->find = nouveau_gpio_find; gpio->set = nouveau_gpio_set; gpio->get = nouveau_gpio_get; - gpio->irq = nouveau_gpio_irq; - gpio->isr_run = nouveau_gpio_isr_run; - gpio->isr_add = nouveau_gpio_isr_add; - gpio->isr_del = nouveau_gpio_isr_del; - INIT_LIST_HEAD(&gpio->isr); - spin_lock_init(&gpio->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c index cf38d2a1d7f1..9665f5f70ee3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c @@ -82,15 +82,6 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) return 0; } -static void -nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on) -{ - u32 mask = 0x00010001 << line; - - nv_wr32(gpio, 0x001104, mask); - nv_mask(gpio, 0x001144, mask, on ? mask : 0); -} - static void nv10_gpio_intr(struct nouveau_subdev *subdev) { @@ -98,12 +89,30 @@ nv10_gpio_intr(struct nouveau_subdev *subdev) u32 intr = nv_rd32(priv, 0x001104); u32 hi = (intr & 0x0000ffff) >> 0; u32 lo = (intr & 0xffff0000) >> 16; + int i; - priv->base.isr_run(&priv->base, 0, hi | lo); + for (i = 0; (hi | lo) && i < 32; i++) { + if ((hi | lo) & (1 << i)) + nouveau_event_trigger(priv->base.events, i); + } nv_wr32(priv, 0x001104, intr); } +static void +nv10_gpio_intr_enable(struct nouveau_event *event, int line) +{ + nv_wr32(event->priv, 0x001104, 0x00010001 << line); + nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line); +} + +static void +nv10_gpio_intr_disable(struct nouveau_event *event, int line) +{ + nv_wr32(event->priv, 0x001104, 0x00010001 << line); + nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000); +} + static int nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -119,7 +128,9 @@ nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.drive = nv10_gpio_drive; priv->base.sense = nv10_gpio_sense; - priv->base.irq_enable = nv10_gpio_irq_enable; + priv->base.events->priv = priv; + priv->base.events->enable = nv10_gpio_intr_enable; + priv->base.events->disable = nv10_gpio_intr_disable; nv_subdev(priv)->intr = nv10_gpio_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index dd022a5787b6..cbe609aa237c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -94,22 +94,13 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line) return !!(nv_rd32(gpio, reg) & (4 << shift)); } -void -nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on) -{ - u32 reg = line < 16 ? 0xe050 : 0xe070; - u32 mask = 0x00010001 << (line & 0xf); - - nv_wr32(gpio, reg + 4, mask); - nv_mask(gpio, reg + 0, mask, on ? mask : 0); -} - void nv50_gpio_intr(struct nouveau_subdev *subdev) { struct nv50_gpio_priv *priv = (void *)subdev; u32 intr0, intr1 = 0; u32 hi, lo; + int i; intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); if (nv_device(priv)->chipset >= 0x90) @@ -117,13 +108,35 @@ nv50_gpio_intr(struct nouveau_subdev *subdev) hi = (intr0 & 0x0000ffff) | (intr1 << 16); lo = (intr0 >> 16) | (intr1 & 0xffff0000); - priv->base.isr_run(&priv->base, 0, hi | lo); + + for (i = 0; (hi | lo) && i < 32; i++) { + if ((hi | lo) & (1 << i)) + nouveau_event_trigger(priv->base.events, i); + } nv_wr32(priv, 0xe054, intr0); if (nv_device(priv)->chipset >= 0x90) nv_wr32(priv, 0xe074, intr1); } +void +nv50_gpio_intr_enable(struct nouveau_event *event, int line) +{ + const u32 addr = line < 16 ? 0xe050 : 0xe070; + const u32 mask = 0x00010001 << (line & 0xf); + nv_wr32(event->priv, addr + 0x04, mask); + nv_mask(event->priv, addr + 0x00, mask, mask); +} + +void +nv50_gpio_intr_disable(struct nouveau_event *event, int line) +{ + const u32 addr = line < 16 ? 0xe050 : 0xe070; + const u32 mask = 0x00010001 << (line & 0xf); + nv_wr32(event->priv, addr + 0x04, mask); + nv_mask(event->priv, addr + 0x00, mask, 0x00000000); +} + static int nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -142,7 +155,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.reset = nv50_gpio_reset; priv->base.drive = nv50_gpio_drive; priv->base.sense = nv50_gpio_sense; - priv->base.irq_enable = nv50_gpio_irq_enable; + priv->base.events->priv = priv; + priv->base.events->enable = nv50_gpio_intr_enable; + priv->base.events->disable = nv50_gpio_intr_disable; nv_subdev(priv)->intr = nv50_gpio_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index bc74199259a2..5ef16a262de7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c @@ -88,7 +88,9 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.reset = nvd0_gpio_reset; priv->base.drive = nvd0_gpio_drive; priv->base.sense = nvd0_gpio_sense; - priv->base.irq_enable = nv50_gpio_irq_enable; + priv->base.events->priv = priv; + priv->base.events->enable = nv50_gpio_intr_enable; + priv->base.events->disable = nv50_gpio_intr_disable; nv_subdev(priv)->intr = nv50_gpio_intr; return 0; } -- cgit v1.2.3