Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358289
b: refs/heads/master
c: 4f47643
h: refs/heads/master
i:
  358287: 780eeda
v: v3
  • Loading branch information
Ben Skeggs committed Feb 20, 2013
1 parent 1cc2d56 commit 41e9c61
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 220 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0f0800661a125ddb038462570c869fe6f8ab5737
refs/heads/master: 4f47643dbb4c345c5beebe53588682a7ff2c872a
31 changes: 13 additions & 18 deletions trunk/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,26 @@

#include <core/subdev.h>
#include <core/device.h>
#include <core/event.h>

#include <subdev/bios.h>
#include <subdev/bios/gpio.h>

struct nouveau_gpio {
struct nouveau_subdev base;

struct nouveau_event *events;

/* hardware interfaces */
void (*reset)(struct nouveau_gpio *, u8 func);
int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
int (*sense)(struct nouveau_gpio *, int line);
void (*irq_enable)(struct nouveau_gpio *, int line, bool);

/* software interfaces */
int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
struct dcb_gpio_func *);
int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line);
int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on);

/* interrupt handling */
struct list_head isr;
spinlock_t lock;

void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask);
int (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
void (*)(void *, int state), void *data);
void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
void (*)(void *, int state), void *data);
};

static inline struct nouveau_gpio *
Expand All @@ -42,14 +33,17 @@ nouveau_gpio(void *obj)

#define nouveau_gpio_create(p,e,o,l,d) \
nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d)
#define nouveau_gpio_destroy(p) \
nouveau_subdev_destroy(&(p)->base)
#define nouveau_gpio_destroy(p) ({ \
struct nouveau_gpio *gpio = (p); \
_nouveau_gpio_dtor(nv_object(gpio)); \
})
#define nouveau_gpio_fini(p,s) \
nouveau_subdev_fini(&(p)->base, (s))

int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, int, void **);
int nouveau_gpio_init(struct nouveau_gpio *);
int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, int, void **);
void _nouveau_gpio_dtor(struct nouveau_object *);
int nouveau_gpio_init(struct nouveau_gpio *);

extern struct nouveau_oclass nv10_gpio_oclass;
extern struct nouveau_oclass nv50_gpio_oclass;
Expand All @@ -59,6 +53,7 @@ void nv50_gpio_dtor(struct nouveau_object *);
int nv50_gpio_init(struct nouveau_object *);
int nv50_gpio_fini(struct nouveau_object *, bool);
void nv50_gpio_intr(struct nouveau_subdev *);
void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool);
void nv50_gpio_intr_enable(struct nouveau_event *, int line);
void nv50_gpio_intr_disable(struct nouveau_event *, int line);

#endif
137 changes: 9 additions & 128 deletions trunk/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}

Expand Down
33 changes: 22 additions & 11 deletions trunk/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,37 @@ 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)
{
struct nv10_gpio_priv *priv = (void *)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,
Expand All @@ -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;
}
Expand Down
39 changes: 27 additions & 12 deletions trunk/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,36 +94,49 @@ 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)
intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);

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,
Expand All @@ -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;
}
Expand Down
4 changes: 3 additions & 1 deletion trunk/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 41e9c61

Please sign in to comment.