diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev')
31 files changed, 1215 insertions, 578 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c index 5ac010efd959..2ede3bcd96a1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c @@ -28,12 +28,12 @@ #include <subdev/bios/dcb.h> #include <subdev/bios/conn.h> -u16 -dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +u32 +nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { - u16 dcb = dcb_table(bios, ver, hdr, cnt, len); + u32 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb && *ver >= 0x30 && *hdr >= 0x16) { - u16 data = nv_ro16(bios, dcb + 0x14); + u32 data = nv_ro16(bios, dcb + 0x14); if (data) { *ver = nv_ro08(bios, data + 0); *hdr = nv_ro08(bios, data + 1); @@ -42,15 +42,59 @@ dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) return data; } } - return 0x0000; + return 0x00000000; } -u16 -dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) +u32 +nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_connT *info) +{ + u32 data = nvbios_connTe(bios, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x30: + case 0x40: + return data; + default: + break; + } + return 0x00000000; +} + +u32 +nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) { u8 hdr, cnt; - u16 data = dcb_conntab(bios, ver, &hdr, &cnt, len); + u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len); if (data && idx < cnt) return data + hdr + (idx * *len); - return 0x0000; + return 0x00000000; +} + +u32 +nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, + struct nvbios_connE *info) +{ + u32 data = nvbios_connEe(bios, idx, ver, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x30: + case 0x40: + info->type = nv_ro08(bios, data + 0x00); + info->location = nv_ro08(bios, data + 0x01) & 0x0f; + info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4; + info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6; + if (*len < 4) + return data; + info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2; + info->dp |= nv_ro08(bios, data + 0x02) & 0x0c; + info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4; + info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4; + info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; + info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4; + return data; + default: + break; + } + return 0x00000000; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c index 7628fe759220..f309dd657250 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c @@ -162,18 +162,20 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, struct nvbios_dpcfg *info) { u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); if (data) { switch (*ver) { case 0x21: - info->drv = nv_ro08(bios, data + 0x02); - info->pre = nv_ro08(bios, data + 0x03); - info->unk = nv_ro08(bios, data + 0x04); + info->dc = nv_ro08(bios, data + 0x02); + info->pe = nv_ro08(bios, data + 0x03); + info->tx_pu = nv_ro08(bios, data + 0x04); break; case 0x30: case 0x40: - info->drv = nv_ro08(bios, data + 0x01); - info->pre = nv_ro08(bios, data + 0x02); - info->unk = nv_ro08(bios, data + 0x03); + info->pc = nv_ro08(bios, data + 0x00); + info->dc = nv_ro08(bios, data + 0x01); + info->pe = nv_ro08(bios, data + 0x02); + info->tx_pu = nv_ro08(bios, data + 0x03); break; default: data = 0x0000; @@ -184,7 +186,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, } u16 -nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, +nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { @@ -193,16 +195,15 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, if (*ver >= 0x30) { const u8 vsoff[] = { 0, 4, 7, 9 }; - idx = (un * 10) + vsoff[vs] + pe; + idx = (pc * 10) + vsoff[vs] + pe; } else { - while ((data = nvbios_dpcfg_entry(bios, outp, idx, + while ((data = nvbios_dpcfg_entry(bios, outp, ++idx, ver, hdr, cnt, len))) { if (nv_ro08(bios, data + 0x00) == vs && nv_ro08(bios, data + 0x01) == pe) break; - idx++; } } - return nvbios_dpcfg_parse(bios, outp, pe, ver, hdr, cnt, len, info); + return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index acaeaf79e3f0..626380f9e4c0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -98,15 +98,16 @@ static u8 init_conn(struct nvbios_init *init) { struct nouveau_bios *bios = init->bios; - u8 ver, len; - u16 conn; + struct nvbios_connE connE; + u8 ver, hdr; + u32 conn; if (init_exec(init)) { if (init->outp) { conn = init->outp->connector; - conn = dcb_conn(bios, conn, &ver, &len); + conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE); if (conn) - return nv_ro08(bios, conn); + return connE.type; } error("script needs connector type\n"); diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index f572c2804c32..45e0202f3151 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -22,21 +22,24 @@ * Authors: Ben Skeggs */ -#include <subdev/gpio.h> #include <subdev/bios.h> #include <subdev/bios/gpio.h> +#include "priv.h" + static int nouveau_gpio_drive(struct nouveau_gpio *gpio, int idx, int line, int dir, int out) { - return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV; + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV; } static int nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) { - return gpio->sense ? gpio->sense(gpio, line) : -ENODEV; + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + return impl->sense ? impl->sense(gpio, line) : -ENODEV; } static int @@ -102,6 +105,80 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) return ret; } +static void +nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_gpio *gpio = nouveau_gpio(event->priv); + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + impl->intr_mask(gpio, type, 1 << index, 0); +} + +static void +nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_gpio *gpio = nouveau_gpio(event->priv); + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + impl->intr_mask(gpio, type, 1 << index, 1 << index); +} + +static void +nouveau_gpio_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_gpio *gpio = nouveau_gpio(subdev); + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + u32 hi, lo, e, i; + + impl->intr_stat(gpio, &hi, &lo); + + for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) { + if (hi & (1 << i)) + e |= NVKM_GPIO_HI; + if (lo & (1 << i)) + e |= NVKM_GPIO_LO; + nouveau_event_trigger(gpio->events, e, i); + } +} + +int +_nouveau_gpio_fini(struct nouveau_object *object, bool suspend) +{ + const struct nouveau_gpio_impl *impl = (void *)object->oclass; + struct nouveau_gpio *gpio = nouveau_gpio(object); + u32 mask = (1 << impl->lines) - 1; + + impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); + impl->intr_stat(gpio, &mask, &mask); + + return nouveau_subdev_fini(&gpio->base, suspend); +} + +static struct dmi_system_id gpio_reset_ids[] = { + { + .ident = "Apple Macbook 10,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), + } + }, + { } +}; + +int +_nouveau_gpio_init(struct nouveau_object *object) +{ + struct nouveau_gpio *gpio = nouveau_gpio(object); + int ret; + + ret = nouveau_subdev_init(&gpio->base); + if (ret) + return ret; + + if (gpio->reset && dmi_check_system(gpio_reset_ids)) + gpio->reset(gpio, DCB_GPIO_UNUSED); + + return ret; +} + void _nouveau_gpio_dtor(struct nouveau_object *object) { @@ -113,9 +190,10 @@ _nouveau_gpio_dtor(struct nouveau_object *object) int nouveau_gpio_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, int lines, + struct nouveau_oclass *oclass, int length, void **pobject) { + const struct nouveau_gpio_impl *impl = (void *)oclass; struct nouveau_gpio *gpio; int ret; @@ -125,34 +203,34 @@ 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->reset = impl->reset; + + ret = nouveau_event_create(2, impl->lines, &gpio->events); + if (ret) + return ret; + + gpio->events->priv = gpio; + gpio->events->enable = nouveau_gpio_intr_enable; + gpio->events->disable = nouveau_gpio_intr_disable; + nv_subdev(gpio)->intr = nouveau_gpio_intr; return 0; } -static struct dmi_system_id gpio_reset_ids[] = { - { - .ident = "Apple Macbook 10,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), - } - }, - { } -}; - int -nouveau_gpio_init(struct nouveau_gpio *gpio) +_nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - int ret = nouveau_subdev_init(&gpio->base); - if (ret == 0 && gpio->reset) { - if (dmi_check_system(gpio_reset_ids)) - gpio->reset(gpio, DCB_GPIO_UNUSED); - } - return ret; + struct nouveau_gpio *gpio; + int ret; + + ret = nouveau_gpio_create(parent, engine, oclass, &gpio); + *pobject = nv_object(gpio); + if (ret) + return ret; + + 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 76d5d5465ddd..27ad23eaf185 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c @@ -26,10 +26,6 @@ #include "priv.h" -struct nv10_gpio_priv { - struct nouveau_gpio base; -}; - static int nv10_gpio_sense(struct nouveau_gpio *gpio, int line) { @@ -83,95 +79,38 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) } 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; - - 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, - struct nouveau_object **pobject) +nv10_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { - struct nv10_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, 16, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.drive = nv10_gpio_drive; - priv->base.sense = nv10_gpio_sense; - 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; + u32 intr = nv_rd32(gpio, 0x001104); + u32 stat = nv_rd32(gpio, 0x001144) & intr; + *lo = (stat & 0xffff0000) >> 16; + *hi = (stat & 0x0000ffff); + nv_wr32(gpio, 0x001104, intr); } static void -nv10_gpio_dtor(struct nouveau_object *object) -{ - struct nv10_gpio_priv *priv = (void *)object; - nouveau_gpio_destroy(&priv->base); -} - -static int -nv10_gpio_init(struct nouveau_object *object) -{ - struct nv10_gpio_priv *priv = (void *)object; - int ret; - - ret = nouveau_gpio_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x001144, 0x00000000); - nv_wr32(priv, 0x001104, 0xffffffff); - return 0; -} - -static int -nv10_gpio_fini(struct nouveau_object *object, bool suspend) +nv10_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { - struct nv10_gpio_priv *priv = (void *)object; - nv_wr32(priv, 0x001144, 0x00000000); - return nouveau_gpio_fini(&priv->base, suspend); + u32 inte = nv_rd32(gpio, 0x001144); + if (type & NVKM_GPIO_LO) + inte = (inte & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte = (inte & ~mask) | data; + nv_wr32(gpio, 0x001144, inte); } -struct nouveau_oclass -nv10_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0x10), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv10_gpio_ctor, - .dtor = nv10_gpio_dtor, - .init = nv10_gpio_init, - .fini = nv10_gpio_fini, +struct nouveau_oclass * +nv10_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x10), + .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 = nv10_gpio_intr_stat, + .intr_mask = nv10_gpio_intr_mask, + .drive = nv10_gpio_drive, + .sense = nv10_gpio_sense, +}.base; 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; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c new file mode 100644 index 000000000000..252083d376f5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +void +nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) +{ + u32 intr0 = nv_rd32(gpio, 0x00e054); + u32 intr1 = nv_rd32(gpio, 0x00e074); + u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0; + u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1; + *lo = (stat1 & 0xffff0000) | (stat0 >> 16); + *hi = (stat1 << 16) | (stat0 & 0x0000ffff); + nv_wr32(gpio, 0x00e054, intr0); + nv_wr32(gpio, 0x00e074, intr1); +} + +void +nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) +{ + u32 inte0 = nv_rd32(gpio, 0x00e050); + u32 inte1 = nv_rd32(gpio, 0x00e070); + if (type & NVKM_GPIO_LO) + inte0 = (inte0 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff); + mask >>= 16; + data >>= 16; + if (type & NVKM_GPIO_LO) + inte1 = (inte1 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte1 = (inte1 & ~mask) | data; + nv_wr32(gpio, 0x00e050, inte0); + nv_wr32(gpio, 0x00e070, inte1); +} + +struct nouveau_oclass * +nv92_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x92), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, + }, + .lines = 32, + .intr_stat = nv92_gpio_intr_stat, + .intr_mask = nv92_gpio_intr_mask, + .drive = nv50_gpio_drive, + .sense = nv50_gpio_sense, + .reset = nv50_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index 010431e3acec..a4682b0956ad 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c @@ -24,15 +24,10 @@ #include "priv.h" -struct nvd0_gpio_priv { - struct nouveau_gpio base; -}; - void nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) { struct nouveau_bios *bios = nouveau_bios(gpio); - struct nvd0_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; int ent = -1; @@ -51,9 +46,9 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(priv, 0x00d610 + (line * 4), 0xff, unk0); + nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0); if (unk1--) - nv_mask(priv, 0x00d740 + (unk1 * 4), 0xff, line); + nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line); } } @@ -72,36 +67,19 @@ nvd0_gpio_sense(struct nouveau_gpio *gpio, int line) return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); } -static int -nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvd0_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.reset = nvd0_gpio_reset; - priv->base.drive = nvd0_gpio_drive; - priv->base.sense = nvd0_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; -} - -struct nouveau_oclass -nvd0_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0xd0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvd0_gpio_ctor, - .dtor = nv50_gpio_dtor, - .init = nv50_gpio_init, - .fini = nv50_gpio_fini, +struct nouveau_oclass * +nvd0_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0xd0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 32, + .intr_stat = nv92_gpio_intr_stat, + .intr_mask = nv92_gpio_intr_mask, + .drive = nvd0_gpio_drive, + .sense = nvd0_gpio_sense, + .reset = nvd0_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c index 8988621373b0..e1145b48c76c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c @@ -24,108 +24,51 @@ #include "priv.h" -struct nve0_gpio_priv { - struct nouveau_gpio base; -}; - -void -nve0_gpio_intr(struct nouveau_subdev *subdev) +static void +nve0_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { - struct nve0_gpio_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0xdc00) & nv_rd32(priv, 0xdc08); - u32 intr1 = nv_rd32(priv, 0xdc80) & nv_rd32(priv, 0xdc88); - u32 hi = (intr0 & 0x0000ffff) | (intr1 << 16); - u32 lo = (intr0 >> 16) | (intr1 & 0xffff0000); - int i; - - for (i = 0; (hi | lo) && i < 32; i++) { - if ((hi | lo) & (1 << i)) - nouveau_event_trigger(priv->base.events, i); - } - - nv_wr32(priv, 0xdc00, intr0); - nv_wr32(priv, 0xdc80, intr1); + u32 intr0 = nv_rd32(gpio, 0x00dc00); + u32 intr1 = nv_rd32(gpio, 0x00dc80); + u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0; + u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1; + *lo = (stat1 & 0xffff0000) | (stat0 >> 16); + *hi = (stat1 << 16) | (stat0 & 0x0000ffff); + nv_wr32(gpio, 0x00dc00, intr0); + nv_wr32(gpio, 0x00dc80, intr1); } void -nve0_gpio_intr_enable(struct nouveau_event *event, int line) +nve0_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { - const u32 addr = line < 16 ? 0xdc00 : 0xdc80; - const u32 mask = 0x00010001 << (line & 0xf); - nv_wr32(event->priv, addr + 0x00, mask); - nv_mask(event->priv, addr + 0x08, mask, mask); -} - -void -nve0_gpio_intr_disable(struct nouveau_event *event, int line) -{ - const u32 addr = line < 16 ? 0xdc00 : 0xdc80; - const u32 mask = 0x00010001 << (line & 0xf); - nv_mask(event->priv, addr + 0x08, mask, 0x00000000); - nv_wr32(event->priv, addr + 0x00, mask); -} - -int -nve0_gpio_fini(struct nouveau_object *object, bool suspend) -{ - struct nve0_gpio_priv *priv = (void *)object; - nv_wr32(priv, 0xdc08, 0x00000000); - nv_wr32(priv, 0xdc88, 0x00000000); - return nouveau_gpio_fini(&priv->base, suspend); -} - -int -nve0_gpio_init(struct nouveau_object *object) -{ - struct nve0_gpio_priv *priv = (void *)object; - int ret; - - ret = nouveau_gpio_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0xdc00, 0xffffffff); - nv_wr32(priv, 0xdc80, 0xffffffff); - return 0; -} - -void -nve0_gpio_dtor(struct nouveau_object *object) -{ - struct nve0_gpio_priv *priv = (void *)object; - nouveau_gpio_destroy(&priv->base); -} - -static int -nve0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nve0_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.reset = nvd0_gpio_reset; - priv->base.drive = nvd0_gpio_drive; - priv->base.sense = nvd0_gpio_sense; - priv->base.events->priv = priv; - priv->base.events->enable = nve0_gpio_intr_enable; - priv->base.events->disable = nve0_gpio_intr_disable; - nv_subdev(priv)->intr = nve0_gpio_intr; - return 0; + u32 inte0 = nv_rd32(gpio, 0x00dc08); + u32 inte1 = nv_rd32(gpio, 0x00dc88); + if (type & NVKM_GPIO_LO) + inte0 = (inte0 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff); + mask >>= 16; + data >>= 16; + if (type & NVKM_GPIO_LO) + inte1 = (inte1 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte1 = (inte1 & ~mask) | data; + nv_wr32(gpio, 0x00dc08, inte0); + nv_wr32(gpio, 0x00dc88, inte1); } -struct nouveau_oclass -nve0_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0xe0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nve0_gpio_ctor, - .dtor = nv50_gpio_dtor, - .init = nve0_gpio_init, - .fini = nve0_gpio_fini, +struct nouveau_oclass * +nve0_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0xe0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 32, + .intr_stat = nve0_gpio_intr_stat, + .intr_mask = nve0_gpio_intr_mask, + .drive = nvd0_gpio_drive, + .sense = nvd0_gpio_sense, + .reset = nvd0_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h index 2ee1c895c782..e1724dfc86ae 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h @@ -3,15 +3,65 @@ #include <subdev/gpio.h> -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_intr_enable(struct nouveau_event *, int line); -void nv50_gpio_intr_disable(struct nouveau_event *, int line); +#define nouveau_gpio_create(p,e,o,d) \ + nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_gpio_destroy(p) ({ \ + struct nouveau_gpio *gpio = (p); \ + _nouveau_gpio_dtor(nv_object(gpio)); \ +}) +#define nouveau_gpio_init(p) ({ \ + struct nouveau_gpio *gpio = (p); \ + _nouveau_gpio_init(nv_object(gpio)); \ +}) +#define nouveau_gpio_fini(p,s) ({ \ + struct nouveau_gpio *gpio = (p); \ + _nouveau_gpio_fini(nv_object(gpio), (s)); \ +}) + +int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int _nouveau_gpio_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nouveau_gpio_dtor(struct nouveau_object *); +int _nouveau_gpio_init(struct nouveau_object *); +int _nouveau_gpio_fini(struct nouveau_object *, bool); + +struct nouveau_gpio_impl { + struct nouveau_oclass base; + int lines; + + /* read and ack pending interrupts, returning only data + * for lines that have not been masked off, while still + * performing the ack for anything that was pending. + */ + void (*intr_stat)(struct nouveau_gpio *, u32 *, u32 *); + + /* mask on/off interrupts for hi/lo transitions on a + * given set of gpio lines + */ + void (*intr_mask)(struct nouveau_gpio *, u32, u32, u32); + + /* configure gpio direction and output value */ + int (*drive)(struct nouveau_gpio *, int line, int dir, int out); + + /* sense current state of given gpio line */ + int (*sense)(struct nouveau_gpio *, int line); + + /*XXX*/ + void (*reset)(struct nouveau_gpio *, u8); +}; + +void nv50_gpio_reset(struct nouveau_gpio *, u8); +int nv50_gpio_drive(struct nouveau_gpio *, int, int, int); +int nv50_gpio_sense(struct nouveau_gpio *, int); + +void nv92_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *); +void nv92_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32); void nvd0_gpio_reset(struct nouveau_gpio *, u8); int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); int nvd0_gpio_sense(struct nouveau_gpio *, int); + #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c index 4b195ac4da66..2c2731a6cf91 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include <subdev/i2c.h> +#include "port.h" struct anx9805_i2c_port { struct nouveau_i2c_port base; @@ -37,6 +37,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; u8 tmp, i; + DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh); + nv_wri2cr(mast, chan->addr, 0xa0, link_bw); nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); nv_wri2cr(mast, chan->addr, 0xa2, 0x01); @@ -60,21 +62,29 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) } static int -anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) +anx9805_aux(struct nouveau_i2c_port *port, bool retry, + u8 type, u32 addr, u8 *data, u8 size) { struct anx9805_i2c_port *chan = (void *)port; struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; int i, ret = -ETIMEDOUT; + u8 buf[16] = {}; u8 tmp; + DBG("%02x %05x %d\n", type, addr, size); + tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); nv_wri2cr(mast, chan->ctrl, 0x07, tmp); nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); nv_wri2cr(mast, chan->addr, 0xe4, 0x80); - for (i = 0; !(type & 1) && i < size; i++) - nv_wri2cr(mast, chan->addr, 0xf0 + i, data[i]); + if (!(type & 1)) { + memcpy(buf, data, size); + DBG("%16ph", buf); + for (i = 0; i < size; i++) + nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]); + } nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); @@ -93,8 +103,13 @@ anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) goto done; } - for (i = 0; (type & 1) && i < size; i++) - data[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); + if (type & 1) { + for (i = 0; i < size; i++) + buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); + DBG("%16ph", buf); + memcpy(data, buf, size); + } + ret = 0; done: nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c index 5de074ad170b..02eb42be2e9e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c @@ -22,15 +22,19 @@ * Authors: Ben Skeggs */ -#include <subdev/i2c.h> +#include "priv.h" int nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) { + struct nouveau_i2c *i2c = nouveau_i2c(port); if (port->func->aux) { - if (port->func->acquire) - port->func->acquire(port); - return port->func->aux(port, 9, addr, data, size); + int ret = i2c->acquire(port, 0); + if (ret == 0) { + ret = port->func->aux(port, true, 9, addr, data, size); + i2c->release(port); + } + return ret; } return -ENODEV; } @@ -38,10 +42,14 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) int nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) { + struct nouveau_i2c *i2c = nouveau_i2c(port); if (port->func->aux) { - if (port->func->acquire) - port->func->acquire(port); - return port->func->aux(port, 8, addr, data, size); + int ret = i2c->acquire(port, 0); + if (ret == 0) { + ret = port->func->aux(port, true, 8, addr, data, size); + i2c->release(port); + } + return ret; } return -ENODEV; } @@ -50,13 +58,16 @@ static int aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct nouveau_i2c_port *port = adap->algo_data; + struct nouveau_i2c *i2c = nouveau_i2c(port); struct i2c_msg *msg = msgs; int ret, mcnt = num; if (!port->func->aux) return -ENODEV; - if ( port->func->acquire) - port->func->acquire(port); + + ret = i2c->acquire(port, 0); + if (ret) + return ret; while (mcnt--) { u8 remaining = msg->len; @@ -74,9 +85,11 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (mcnt || remaining > 16) cmd |= 4; /* MOT */ - ret = port->func->aux(port, cmd, msg->addr, ptr, cnt); - if (ret < 0) + ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt); + if (ret < 0) { + i2c->release(port); return ret; + } ptr += cnt; remaining -= cnt; @@ -85,6 +98,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) msg++; } + i2c->release(port); return num; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index 378e05b88e6f..09ba2cc851cf 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -23,13 +23,16 @@ */ #include <core/option.h> +#include <core/event.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> #include <subdev/bios/i2c.h> -#include <subdev/i2c.h> #include <subdev/vga.h> +#include "priv.h" +#include "pad.h" + /****************************************************************************** * interface to linux i2c bit-banging algorithm *****************************************************************************/ @@ -45,9 +48,15 @@ nouveau_i2c_pre_xfer(struct i2c_adapter *adap) { struct i2c_algo_bit_data *bit = adap->algo_data; struct nouveau_i2c_port *port = bit->data; - if (port->func->acquire) - port->func->acquire(port); - return 0; + return nouveau_i2c(port)->acquire(port, bit->timeout); +} + +static void +nouveau_i2c_post_xfer(struct i2c_adapter *adap) +{ + struct i2c_algo_bit_data *bit = adap->algo_data; + struct nouveau_i2c_port *port = bit->data; + return nouveau_i2c(port)->release(port); } static void @@ -82,6 +91,15 @@ nouveau_i2c_getsda(void *data) * base i2c "port" class implementation *****************************************************************************/ +int +_nouveau_i2c_port_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_i2c_port *port = (void *)object; + struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); + nv_ofuncs(pad)->fini(nv_object(pad), suspend); + return nouveau_object_fini(&port->base, suspend); +} + void _nouveau_i2c_port_dtor(struct nouveau_object *object) { @@ -98,7 +116,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, const struct nouveau_i2c_func *func, int size, void **pobject) { - struct nouveau_device *device = nv_device(parent); + struct nouveau_device *device = nv_device(engine); struct nouveau_i2c *i2c = (void *)engine; struct nouveau_i2c_port *port; int ret; @@ -113,8 +131,9 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, port->adapter.owner = THIS_MODULE; port->adapter.dev.parent = nv_device_base(device); port->index = index; + port->aux = -1; port->func = func; - i2c_set_adapdata(&port->adapter, i2c); + mutex_init(&port->mutex); if ( algo == &nouveau_i2c_bit_algo && !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { @@ -128,6 +147,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, bit->timeout = usecs_to_jiffies(2200); bit->data = port; bit->pre_xfer = nouveau_i2c_pre_xfer; + bit->post_xfer = nouveau_i2c_post_xfer; bit->setsda = nouveau_i2c_setsda; bit->setscl = nouveau_i2c_setscl; bit->getsda = nouveau_i2c_getsda; @@ -141,7 +161,6 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, ret = i2c_add_adapter(&port->adapter); } - /* drop port's i2c subdev refcount, i2c handles this itself */ if (ret == 0) list_add_tail(&port->head, &i2c->ports); return ret; @@ -193,6 +212,75 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type) return NULL; } +static void +nouveau_i2c_release_pad(struct nouveau_i2c_port *port) +{ + struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); + struct nouveau_i2c *i2c = nouveau_i2c(port); + + if (atomic_dec_and_test(&nv_object(pad)->usecount)) { + nv_ofuncs(pad)->fini(nv_object(pad), false); + wake_up_all(&i2c->wait); + } +} + +static int +nouveau_i2c_try_acquire_pad(struct nouveau_i2c_port *port) +{ + struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); + + if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) { + struct nouveau_object *owner = (void *)pad->port; + do { + if (owner == (void *)port) + return 0; + owner = owner->parent; + } while(owner); + nouveau_i2c_release_pad(port); + return -EBUSY; + } + + pad->next = port; + nv_ofuncs(pad)->init(nv_object(pad)); + return 0; +} + +static int +nouveau_i2c_acquire_pad(struct nouveau_i2c_port *port, unsigned long timeout) +{ + struct nouveau_i2c *i2c = nouveau_i2c(port); + + if (timeout) { + if (wait_event_timeout(i2c->wait, + nouveau_i2c_try_acquire_pad(port) == 0, + timeout) == 0) + return -EBUSY; + } else { + wait_event(i2c->wait, nouveau_i2c_try_acquire_pad(port) == 0); + } + + return 0; +} + +static void +nouveau_i2c_release(struct nouveau_i2c_port *port) +__releases(pad->mutex) +{ + nouveau_i2c(port)->release_pad(port); + mutex_unlock(&port->mutex); +} + +static int +nouveau_i2c_acquire(struct nouveau_i2c_port *port, unsigned long timeout) +__acquires(pad->mutex) +{ + int ret; + mutex_lock(&port->mutex); + if ((ret = nouveau_i2c(port)->acquire_pad(port, timeout))) + mutex_unlock(&port->mutex); + return ret; +} + static int nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, struct nouveau_i2c_board_info *info, @@ -237,11 +325,59 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, return -ENODEV; } +static void +nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_i2c *i2c = nouveau_i2c(event->priv); + struct nouveau_i2c_port *port = i2c->find(i2c, index); + const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; + if (port && port->aux >= 0) + impl->aux_mask(i2c, type, 1 << port->aux, 0); +} + +static void +nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_i2c *i2c = nouveau_i2c(event->priv); + struct nouveau_i2c_port *port = i2c->find(i2c, index); + const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; + if (port && port->aux >= 0) + impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); +} + +static void +nouveau_i2c_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev); + struct nouveau_i2c *i2c = nouveau_i2c(subdev); + struct nouveau_i2c_port *port; + u32 hi, lo, rq, tx, e; + + if (impl->aux_stat) { + impl->aux_stat(i2c, &hi, &lo, &rq, &tx); + if (hi || lo || rq || tx) { + list_for_each_entry(port, &i2c->ports, head) { + if (e = 0, port->aux < 0) + continue; + + if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG; + if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG; + if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; + if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; + + nouveau_event_trigger(i2c->ntfy, e, port->index); + } + } + } +} + int _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) { + struct nouveau_i2c_impl *impl = (void *)nv_oclass(object); struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port; + u32 mask; int ret; list_for_each_entry(port, &i2c->ports, head) { @@ -250,6 +386,11 @@ _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) goto fail; } + if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { + impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); + impl->aux_stat(i2c, &mask, &mask, &mask, &mask); + } + return nouveau_subdev_fini(&i2c->base, suspend); fail: list_for_each_entry_continue_reverse(port, &i2c->ports, head) { @@ -290,6 +431,8 @@ _nouveau_i2c_dtor(struct nouveau_object *object) struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port, *temp; + nouveau_event_destroy(&i2c->ntfy); + list_for_each_entry_safe(port, temp, &i2c->ports, head) { nouveau_object_ref(NULL, (struct nouveau_object **)&port); } @@ -306,14 +449,14 @@ int nouveau_i2c_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, - struct nouveau_oclass *sclass, int length, void **pobject) { + const struct nouveau_i2c_impl *impl = (void *)oclass; struct nouveau_bios *bios = nouveau_bios(parent); struct nouveau_i2c *i2c; struct nouveau_object *object; struct dcb_i2c_entry info; - int ret, i, j, index = -1; + int ret, i, j, index = -1, pad; struct dcb_output outp; u8 ver, hdr; u32 data; @@ -324,24 +467,48 @@ nouveau_i2c_create_(struct nouveau_object *parent, if (ret) return ret; + nv_subdev(i2c)->intr = nouveau_i2c_intr; i2c->find = nouveau_i2c_find; i2c->find_type = nouveau_i2c_find_type; + i2c->acquire_pad = nouveau_i2c_acquire_pad; + i2c->release_pad = nouveau_i2c_release_pad; + i2c->acquire = nouveau_i2c_acquire; + i2c->release = nouveau_i2c_release; i2c->identify = nouveau_i2c_identify; + init_waitqueue_head(&i2c->wait); INIT_LIST_HEAD(&i2c->ports); while (!dcb_i2c_parse(bios, ++index, &info)) { if (info.type == DCB_I2C_UNUSED) continue; - oclass = sclass; + if (info.share != DCB_I2C_UNUSED) { + if (info.type == DCB_I2C_NVIO_AUX) + pad = info.drive; + else + pad = info.share; + oclass = impl->pad_s; + } else { + pad = 0x100 + info.drive; + oclass = impl->pad_x; + } + + ret = nouveau_object_ctor(NULL, *pobject, oclass, + NULL, pad, &parent); + if (ret < 0) + continue; + + oclass = impl->sclass; do { ret = -EINVAL; if (oclass->handle == info.type) { - ret = nouveau_object_ctor(*pobject, *pobject, + ret = nouveau_object_ctor(parent, *pobject, oclass, &info, index, &object); } } while (ret && (++oclass)->handle); + + nouveau_object_ref(NULL, &parent); } /* in addition to the busses specified in the i2c table, there @@ -380,5 +547,28 @@ nouveau_i2c_create_(struct nouveau_object *parent, } } + ret = nouveau_event_create(4, index, &i2c->ntfy); + if (ret) + return ret; + + i2c->ntfy->priv = i2c; + i2c->ntfy->enable = nouveau_i2c_intr_enable; + i2c->ntfy->disable = nouveau_i2c_intr_disable; + return 0; +} + +int +_nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_i2c *i2c; + int ret; + + ret = nouveau_i2c_create(parent, engine, oclass, &i2c); + *pobject = nv_object(i2c); + if (ret) + return ret; + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c index a6e72d3b06b5..813ffc96e864 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include "subdev/i2c.h" +#include "priv.h" #ifdef CONFIG_NOUVEAU_I2C_INTERNAL #define T_TIMEOUT 2200000 @@ -187,8 +187,9 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_msg *msg = msgs; int ret = 0, mcnt = num; - if (port->func->acquire) - port->func->acquire(port); + ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT)); + if (ret) + return ret; while (!ret && mcnt--) { u8 remaining = msg->len; @@ -210,6 +211,7 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) } i2c_stop(port); + nouveau_i2c(port)->release(port); return (ret < 0) ? ret : num; } #else diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c index 860d5d2365da..b1725bdea967 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c @@ -22,9 +22,10 @@ * Authors: Ben Skeggs */ -#include <subdev/i2c.h> #include <subdev/vga.h> +#include "priv.h" + struct nv04_i2c_priv { struct nouveau_i2c base; }; @@ -115,29 +116,15 @@ nv04_i2c_sclass[] = { {} }; -static int -nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv04_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv04_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv04_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv04_i2c_ctor, +struct nouveau_oclass * +nv04_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv04_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c index 0c2655a03bb4..f16c87ce5ba1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c @@ -22,9 +22,10 @@ * Authors: Ben Skeggs */ -#include <subdev/i2c.h> #include <subdev/vga.h> +#include "priv.h" + struct nv4e_i2c_priv { struct nouveau_i2c base; }; @@ -107,29 +108,15 @@ nv4e_i2c_sclass[] = { {} }; -static int -nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv4e_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv4e_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv4e_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x4e), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv4e_i2c_ctor, +struct nouveau_oclass * +nv4e_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x4e), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv4e_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c index a8d67a287704..7b8756d4df08 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c @@ -121,29 +121,15 @@ nv50_i2c_sclass[] = { {} }; -static int -nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv50_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv50_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_i2c_ctor, +struct nouveau_oclass * +nv50_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv50_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h index 4e5ba48ebf5a..5d2a77421c74 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h @@ -1,7 +1,7 @@ #ifndef __NV50_I2C_H__ #define __NV50_I2C_H__ -#include <subdev/i2c.h> +#include "priv.h" struct nv50_i2c_priv { struct nouveau_i2c base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c index df6d3e4b68be..f59c3a255462 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c @@ -24,6 +24,36 @@ #include "nv50.h" +void +nv94_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) +{ + u32 intr = nv_rd32(i2c, 0x00e06c); + u32 stat = nv_rd32(i2c, 0x00e068) & intr, i; + for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { + if ((stat & (1 << (i * 4)))) *hi |= 1 << i; + if ((stat & (2 << (i * 4)))) *lo |= 1 << i; + if ((stat & (4 << (i * 4)))) *rq |= 1 << i; + if ((stat & (8 << (i * 4)))) *tx |= 1 << i; + } + nv_wr32(i2c, 0x00e06c, intr); +} + +void +nv94_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data) +{ + u32 temp = nv_rd32(i2c, 0x00e068), i; + for (i = 0; i < 8; i++) { + if (mask & (1 << i)) { + if (!(data & (1 << i))) { + temp &= ~(type << (i * 4)); + continue; + } + temp |= type << (i * 4); + } + } + nv_wr32(i2c, 0x00e068, temp); +} + #define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) #define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) @@ -69,7 +99,8 @@ auxch_init(struct nouveau_i2c *aux, int ch) } int -nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) +nv94_aux(struct nouveau_i2c_port *base, bool retry, + u8 type, u32 addr, u8 *data, u8 size) { struct nouveau_i2c *aux = nouveau_i2c(base); struct nv50_i2c_port *port = (void *)base; @@ -105,9 +136,8 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) ctrl |= size - 1; nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); - /* retry transaction a number of times on failure... */ - ret = -EREMOTEIO; - for (retries = 0; retries < 32; retries++) { + /* (maybe) retry transaction a number of times on failure... */ + for (retries = 0; !ret && retries < 32; retries++) { /* reset, and delay a while if this is a retry */ nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); @@ -123,16 +153,21 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) udelay(1); if (!timeout--) { AUX_ERR("tx req timeout 0x%08x\n", ctrl); + ret = -EIO; goto out; } } while (ctrl & 0x00010000); + ret = 1; /* read status, and check if transaction completed ok */ stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); - if (!(stat & 0x000f0f00)) { - ret = 0; - break; - } + if ((stat & 0x000f0000) == 0x00080000 || + (stat & 0x000f0000) == 0x00020000) + ret = retry ? 0 : 1; + if ((stat & 0x00000100)) + ret = -ETIMEDOUT; + if ((stat & 0x00000e00)) + ret = -EIO; AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); } @@ -147,29 +182,11 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) out: auxch_fini(aux, ch); - return ret; -} - -void -nv94_i2c_acquire(struct nouveau_i2c_port *base) -{ - struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; - struct nv50_i2c_port *port = (void *)base; - if (port->ctrl) { - nv_mask(priv, port->ctrl + 0x0c, 0x00000001, 0x00000000); - nv_mask(priv, port->ctrl + 0x00, 0x0000f003, port->data); - } -} - -void -nv94_i2c_release(struct nouveau_i2c_port *base) -{ + return ret < 0 ? ret : (stat & 0x000f0000) >> 16; } static const struct nouveau_i2c_func nv94_i2c_func = { - .acquire = nv94_i2c_acquire, - .release = nv94_i2c_release, .drive_scl = nv50_i2c_drive_scl, .drive_sda = nv50_i2c_drive_sda, .sense_scl = nv50_i2c_sense_scl, @@ -206,8 +223,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, static const struct nouveau_i2c_func nv94_aux_func = { - .acquire = nv94_i2c_acquire, - .release = nv94_i2c_release, .aux = nv94_aux, }; @@ -227,6 +242,7 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + port->base.aux = info->drive; port->addr = info->drive; if (info->share != DCB_I2C_UNUSED) { port->ctrl = 0x00e500 + (info->drive * 0x50); @@ -257,29 +273,19 @@ nv94_i2c_sclass[] = { {} }; -static int -nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv94_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv94_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x94), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv94_i2c_ctor, +struct nouveau_oclass * +nv94_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x94), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv94_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv94_i2c_pad_oclass, + .aux = 4, + .aux_stat = nv94_aux_stat, + .aux_mask = nv94_aux_mask, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c index 29967d30f97c..364ddb1c5f03 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c @@ -42,8 +42,6 @@ nvd0_i2c_sense_sda(struct nouveau_i2c_port *base) static const struct nouveau_i2c_func nvd0_i2c_func = { - .acquire = nv94_i2c_acquire, - .release = nv94_i2c_release, .drive_scl = nv50_i2c_drive_scl, .drive_sda = nv50_i2c_drive_sda, .sense_scl = nvd0_i2c_sense_scl, @@ -75,7 +73,7 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -static struct nouveau_oclass +struct nouveau_oclass nvd0_i2c_sclass[] = { { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), .ofuncs = &(struct nouveau_ofuncs) { @@ -96,29 +94,19 @@ nvd0_i2c_sclass[] = { {} }; -static int -nvd0_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nvd0_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nvd0_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0xd0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvd0_i2c_ctor, +struct nouveau_oclass * +nvd0_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0xd0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nvd0_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv94_i2c_pad_oclass, + .aux = 4, + .aux_stat = nv94_aux_stat, + .aux_mask = nv94_aux_mask, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c new file mode 100644 index 000000000000..cae77e1ad8dc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c @@ -0,0 +1,72 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nv50.h" + +static void +nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) +{ + u32 intr = nv_rd32(i2c, 0x00dc60); + u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i; + for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { + if ((stat & (1 << (i * 4)))) *hi |= 1 << i; + if ((stat & (2 << (i * 4)))) *lo |= 1 << i; + if ((stat & (4 << (i * 4)))) *rq |= 1 << i; + if ((stat & (8 << (i * 4)))) *tx |= 1 << i; + } + nv_wr32(i2c, 0x00dc60, intr); +} + +static void +nve0_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data) +{ + u32 temp = nv_rd32(i2c, 0x00dc68), i; + for (i = 0; i < 8; i++) { + if (mask & (1 << i)) { + if (!(data & (1 << i))) { + temp &= ~(type << (i * 4)); + continue; + } + temp |= type << (i * 4); + } + } + nv_wr32(i2c, 0x00dc68, temp); +} + +struct nouveau_oclass * +nve0_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0xe0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, + .dtor = _nouveau_i2c_dtor, + .init = _nouveau_i2c_init, + .fini = _nouveau_i2c_fini, + }, + .sclass = nvd0_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv94_i2c_pad_oclass, + .aux = 4, + .aux_stat = nve0_aux_stat, + .aux_mask = nve0_aux_mask, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c new file mode 100644 index 000000000000..e9e412477c12 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c @@ -0,0 +1,84 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "pad.h" + +int +_nvkm_i2c_pad_fini(struct nouveau_object *object, bool suspend) +{ + struct nvkm_i2c_pad *pad = (void *)object; + DBG("-> NULL\n"); + pad->port = NULL; + return nouveau_object_fini(&pad->base, suspend); +} + +int +_nvkm_i2c_pad_init(struct nouveau_object *object) +{ + struct nvkm_i2c_pad *pad = (void *)object; + DBG("-> PORT:%02x\n", pad->next->index); + pad->port = pad->next; + return nouveau_object_init(&pad->base); +} + +int +nvkm_i2c_pad_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int index, + int size, void **pobject) +{ + struct nouveau_i2c *i2c = (void *)engine; + struct nouveau_i2c_port *port; + struct nvkm_i2c_pad *pad; + int ret; + + list_for_each_entry(port, &i2c->ports, head) { + pad = nvkm_i2c_pad(port); + if (pad->index == index) { + atomic_inc(&nv_object(pad)->refcount); + *pobject = pad; + return 1; + } + } + + ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject); + pad = *pobject; + if (ret) + return ret; + + pad->index = index; + return 0; +} + +int +_nvkm_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 index, + struct nouveau_object **pobject) +{ + struct nvkm_i2c_pad *pad; + int ret; + ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); + *pobject = nv_object(pad); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h new file mode 100644 index 000000000000..452ac10c3004 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h @@ -0,0 +1,58 @@ +#ifndef __NVKM_I2C_PAD_H__ +#define __NVKM_I2C_PAD_H__ + +#include "priv.h" + +struct nvkm_i2c_pad { + struct nouveau_object base; + int index; + struct nouveau_i2c_port *port; + struct nouveau_i2c_port *next; +}; + +static inline struct nvkm_i2c_pad * +nvkm_i2c_pad(struct nouveau_i2c_port *port) +{ + struct nouveau_object *pad = nv_object(port); + while (pad->parent) + pad = pad->parent; + return (void *)pad; +} + +#define nvkm_i2c_pad_create(p,e,o,i,d) \ + nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d) +#define nvkm_i2c_pad_destroy(p) ({ \ + struct nvkm_i2c_pad *_p = (p); \ + _nvkm_i2c_pad_dtor(nv_object(_p)); \ +}) +#define nvkm_i2c_pad_init(p) ({ \ + struct nvkm_i2c_pad *_p = (p); \ + _nvkm_i2c_pad_init(nv_object(_p)); \ +}) +#define nvkm_i2c_pad_fini(p,s) ({ \ + struct nvkm_i2c_pad *_p = (p); \ + _nvkm_i2c_pad_fini(nv_object(_p), (s)); \ +}) + +int nvkm_i2c_pad_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int index, int, void **); + +int _nvkm_i2c_pad_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +#define _nvkm_i2c_pad_dtor nouveau_object_destroy +int _nvkm_i2c_pad_init(struct nouveau_object *); +int _nvkm_i2c_pad_fini(struct nouveau_object *, bool); + +#ifndef MSG +#define MSG(l,f,a...) do { \ + struct nvkm_i2c_pad *_pad = (void *)pad; \ + nv_##l(nv_object(_pad)->engine, "PAD:%c:%02x: "f, \ + _pad->index >= 0x100 ? 'X' : 'S', \ + _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \ +} while(0) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c new file mode 100644 index 000000000000..2c4b61296dd1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c @@ -0,0 +1,35 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "pad.h" + +struct nouveau_oclass +nv04_i2c_pad_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_i2c_pad_ctor, + .dtor = _nvkm_i2c_pad_dtor, + .init = _nvkm_i2c_pad_init, + .fini = _nvkm_i2c_pad_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c new file mode 100644 index 000000000000..0dc6753014f0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c @@ -0,0 +1,86 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "pad.h" + +struct nv94_i2c_pad { + struct nvkm_i2c_pad base; + int addr; +}; + +static int +nv94_i2c_pad_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_i2c *i2c = (void *)object->engine; + struct nv94_i2c_pad *pad = (void *)object; + nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001); + return nvkm_i2c_pad_fini(&pad->base, suspend); +} + +static int +nv94_i2c_pad_init(struct nouveau_object *object) +{ + struct nouveau_i2c *i2c = (void *)object->engine; + struct nv94_i2c_pad *pad = (void *)object; + + switch (nv_oclass(pad->base.next)->handle) { + case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): + nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002); + break; + case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): + default: + nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001); + break; + } + + nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000); + return nvkm_i2c_pad_init(&pad->base); +} + +static int +nv94_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 index, + struct nouveau_object **pobject) +{ + struct nv94_i2c_pad *pad; + int ret; + + ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); + *pobject = nv_object(pad); + if (ret) + return ret; + + pad->addr = index * 0x50;; + return 0; +} + +struct nouveau_oclass +nv94_i2c_pad_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv94_i2c_pad_ctor, + .dtor = _nvkm_i2c_pad_dtor, + .init = nv94_i2c_pad_init, + .fini = nv94_i2c_pad_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h new file mode 100644 index 000000000000..a8ff6e077af5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h @@ -0,0 +1,15 @@ +#ifndef __NVKM_I2C_PORT_H__ +#define __NVKM_I2C_PORT_H__ + +#include "priv.h" + +#ifndef MSG +#define MSG(l,f,a...) do { \ + struct nouveau_i2c_port *_port = (void *)port; \ + nv_##l(nv_object(_port)->engine, "PORT:%02x: "f, _port->index, ##a); \ +} while(0) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h new file mode 100644 index 000000000000..780090b6425a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h @@ -0,0 +1,85 @@ +#ifndef __NVKM_I2C_H__ +#define __NVKM_I2C_H__ + +#include <subdev/i2c.h> + +extern struct nouveau_oclass nv04_i2c_pad_oclass; +extern struct nouveau_oclass nv94_i2c_pad_oclass; + +#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \ + nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \ + sizeof(**d), (void **)d) +#define nouveau_i2c_port_destroy(p) ({ \ + struct nouveau_i2c_port *port = (p); \ + _nouveau_i2c_port_dtor(nv_object(i2c)); \ +}) +#define nouveau_i2c_port_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_i2c_port_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u8, + const struct i2c_algorithm *, + const struct nouveau_i2c_func *, + int, void **); +void _nouveau_i2c_port_dtor(struct nouveau_object *); +#define _nouveau_i2c_port_init nouveau_object_init +int _nouveau_i2c_port_fini(struct nouveau_object *, bool); + +#define nouveau_i2c_create(p,e,o,d) \ + nouveau_i2c_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_i2c_destroy(p) ({ \ + struct nouveau_i2c *i2c = (p); \ + _nouveau_i2c_dtor(nv_object(i2c)); \ +}) +#define nouveau_i2c_init(p) ({ \ + struct nouveau_i2c *i2c = (p); \ + _nouveau_i2c_init(nv_object(i2c)); \ +}) +#define nouveau_i2c_fini(p,s) ({ \ + struct nouveau_i2c *i2c = (p); \ + _nouveau_i2c_fini(nv_object(i2c), (s)); \ +}) + +int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int _nouveau_i2c_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nouveau_i2c_dtor(struct nouveau_object *); +int _nouveau_i2c_init(struct nouveau_object *); +int _nouveau_i2c_fini(struct nouveau_object *, bool); + +extern struct nouveau_oclass nouveau_anx9805_sclass[]; +extern struct nouveau_oclass nvd0_i2c_sclass[]; + +extern const struct i2c_algorithm nouveau_i2c_bit_algo; +extern const struct i2c_algorithm nouveau_i2c_aux_algo; + +struct nouveau_i2c_impl { + struct nouveau_oclass base; + + /* supported i2c port classes */ + struct nouveau_oclass *sclass; + struct nouveau_oclass *pad_x; + struct nouveau_oclass *pad_s; + + /* number of native dp aux channels present */ + int aux; + + /* read and ack pending interrupts, returning only data + * for ports that have not been masked off, while still + * performing the ack for anything that was pending. + */ + void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); + + /* mask on/off interrupt types for a given set of auxch + */ + void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32); +}; + +void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); +void nv94_aux_mask(struct nouveau_i2c *, u32, u32, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c index 90d8bf8ce0dc..9ca93e2718f7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c @@ -34,7 +34,8 @@ nv50_mc_intr[] = { { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x80000000, NVDEV_ENGINE_SW }, { 0x0002d101, NVDEV_SUBDEV_FB }, diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c index 95b3d35388a8..3c76d9038f38 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c @@ -36,7 +36,8 @@ nv98_mc_intr[] = { { 0x00040000, NVDEV_SUBDEV_PWR }, /* NVA3:NVC0 */ { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */ { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x80000000, NVDEV_ENGINE_SW }, diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index ac7f99a15fa7..f9c6a678b47d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -38,7 +38,8 @@ nvc0_mc_intr[] = { { 0x00040000, NVDEV_SUBDEV_THERM }, { 0x00020000, NVDEV_ENGINE_VP }, { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ { 0x01000000, NVDEV_SUBDEV_PWR }, { 0x02000000, NVDEV_SUBDEV_LTCG }, { 0x08000000, NVDEV_SUBDEV_FB }, diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c index 64f8b4702bf7..fcaabe8456e3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c @@ -150,7 +150,7 @@ mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb) * common example is DP->eDP. */ conn = bios->data; - conn += dcb_conn(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len); + conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len); type = conn[0]; switch (ctx.desc.conn_type) { case 0x01: /* LVDS */ |