diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c | 152 |
1 files changed, 34 insertions, 118 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index 2ef774731629..1864fa98e6b1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -24,15 +24,10 @@ #include "priv.h" -struct nv50_gpio_priv { - struct nouveau_gpio base; -}; - -static void +void nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) { struct nouveau_bios *bios = nouveau_bios(gpio); - struct nv50_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; int ent = -1; @@ -55,7 +50,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(priv, reg, 0x00010001 << lsh, val << lsh); + nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh); } } @@ -72,7 +67,7 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift) return 0; } -static int +int nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) { u32 reg, shift; @@ -84,7 +79,7 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) return 0; } -static int +int nv50_gpio_sense(struct nouveau_gpio *gpio, int line) { u32 reg, shift; @@ -95,119 +90,40 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line) return !!(nv_rd32(gpio, reg) & (4 << shift)); } -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 > 0x92) - intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070); - - hi = (intr0 & 0x0000ffff) | (intr1 << 16); - lo = (intr0 >> 16) | (intr1 & 0xffff0000); - - 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 > 0x92) - 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, - struct nouveau_object **pobject) -{ - struct nv50_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, - nv_device(parent)->chipset > 0x92 ? 32 : 16, - &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.reset = nv50_gpio_reset; - priv->base.drive = nv50_gpio_drive; - priv->base.sense = nv50_gpio_sense; - 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; -} - -void -nv50_gpio_dtor(struct nouveau_object *object) -{ - struct nv50_gpio_priv *priv = (void *)object; - nouveau_gpio_destroy(&priv->base); -} - -int -nv50_gpio_init(struct nouveau_object *object) +static void +nv50_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { - struct nv50_gpio_priv *priv = (void *)object; - int ret; - - ret = nouveau_gpio_init(&priv->base); - if (ret) - return ret; - - /* disable, and ack any pending gpio interrupts */ - nv_wr32(priv, 0xe050, 0x00000000); - nv_wr32(priv, 0xe054, 0xffffffff); - if (nv_device(priv)->chipset > 0x92) { - nv_wr32(priv, 0xe070, 0x00000000); - nv_wr32(priv, 0xe074, 0xffffffff); - } - - return 0; + u32 intr = nv_rd32(gpio, 0x00e054); + u32 stat = nv_rd32(gpio, 0x00e050) & intr; + *lo = (stat & 0xffff0000) >> 16; + *hi = (stat & 0x0000ffff); + nv_wr32(gpio, 0x00e054, intr); } -int -nv50_gpio_fini(struct nouveau_object *object, bool suspend) +static void +nv50_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { - struct nv50_gpio_priv *priv = (void *)object; - nv_wr32(priv, 0xe050, 0x00000000); - if (nv_device(priv)->chipset > 0x92) - nv_wr32(priv, 0xe070, 0x00000000); - return nouveau_gpio_fini(&priv->base, suspend); + u32 inte = nv_rd32(gpio, 0x00e050); + if (type & NVKM_GPIO_LO) + inte = (inte & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte = (inte & ~mask) | data; + nv_wr32(gpio, 0x00e050, inte); } -struct nouveau_oclass -nv50_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_gpio_ctor, - .dtor = nv50_gpio_dtor, - .init = nv50_gpio_init, - .fini = nv50_gpio_fini, +struct nouveau_oclass * +nv50_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 16, + .intr_stat = nv50_gpio_intr_stat, + .intr_mask = nv50_gpio_intr_mask, + .drive = nv50_gpio_drive, + .sense = nv50_gpio_sense, + .reset = nv50_gpio_reset, +}.base; |