Loading drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h +5 −3 Original line number Diff line number Diff line Loading @@ -25,9 +25,11 @@ struct dcb_gpio_func { u8 param; }; u16 dcb_gpio_table(struct nouveau_bios *); u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver); int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line, u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len); u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *); u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line, u8 *ver, u8 *len, struct dcb_gpio_func *); #endif drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c +75 −53 Original line number Diff line number Diff line Loading @@ -27,84 +27,105 @@ #include <subdev/bios/gpio.h> u16 dcb_gpio_table(struct nouveau_bios *bios) dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u8 ver, hdr, cnt, len; u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); u16 data = 0x0000; u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { if (ver >= 0x30 && hdr >= 0x0c) return nv_ro16(bios, dcb + 0x0a); if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) return nv_ro16(bios, dcb - 0x0f); if (*ver >= 0x30 && *hdr >= 0x0c) data = nv_ro16(bios, dcb + 0x0a); else if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) data = nv_ro16(bios, dcb - 0x0f); if (data) { *ver = nv_ro08(bios, data + 0x00); if (*ver < 0x30) { *hdr = 3; *cnt = nv_ro08(bios, data + 0x02); *len = nv_ro08(bios, data + 0x01); } else if (*ver <= 0x41) { *hdr = nv_ro08(bios, data + 0x01); *cnt = nv_ro08(bios, data + 0x02); *len = nv_ro08(bios, data + 0x03); } else { data = 0x0000; } return 0x0000; } } return data; } u16 dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver) dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len) { u16 gpio = dcb_gpio_table(bios); if (gpio) { *ver = nv_ro08(bios, gpio); if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2)) return gpio + 3 + (ent * nv_ro08(bios, gpio + 1)); else if (ent < nv_ro08(bios, gpio + 2)) return gpio + nv_ro08(bios, gpio + 1) + (ent * nv_ro08(bios, gpio + 3)); } u8 hdr, cnt; u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000; if (gpio && ent < cnt) return gpio + hdr + (ent * *len); return 0x0000; } int dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, u16 dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) { u8 ver, hdr, cnt, len; u16 entry; int i = -1; while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) { if (ver < 0x40) { u16 data = nv_ro16(bios, entry); u16 data = dcb_gpio_entry(bios, idx, ent, ver, len); if (data) { if (*ver < 0x40) { u16 info = nv_ro16(bios, data); *gpio = (struct dcb_gpio_func) { .line = (data & 0x001f) >> 0, .func = (data & 0x07e0) >> 5, .log[0] = (data & 0x1800) >> 11, .log[1] = (data & 0x6000) >> 13, .param = !!(data & 0x8000), .line = (info & 0x001f) >> 0, .func = (info & 0x07e0) >> 5, .log[0] = (info & 0x1800) >> 11, .log[1] = (info & 0x6000) >> 13, .param = !!(info & 0x8000), }; } else if (ver < 0x41) { u32 data = nv_ro32(bios, entry); if (*ver < 0x41) { u32 info = nv_ro32(bios, data); *gpio = (struct dcb_gpio_func) { .line = (data & 0x0000001f) >> 0, .func = (data & 0x0000ff00) >> 8, .log[0] = (data & 0x18000000) >> 27, .log[1] = (data & 0x60000000) >> 29, .param = !!(data & 0x80000000), .line = (info & 0x0000001f) >> 0, .func = (info & 0x0000ff00) >> 8, .log[0] = (info & 0x18000000) >> 27, .log[1] = (info & 0x60000000) >> 29, .param = !!(info & 0x80000000), }; } else { u32 data = nv_ro32(bios, entry + 0); u8 data1 = nv_ro32(bios, entry + 4); u32 info = nv_ro32(bios, data + 0); u8 info1 = nv_ro32(bios, data + 4); *gpio = (struct dcb_gpio_func) { .line = (data & 0x0000003f) >> 0, .func = (data & 0x0000ff00) >> 8, .log[0] = (data1 & 0x30) >> 4, .log[1] = (data1 & 0xc0) >> 6, .param = !!(data & 0x80000000), .line = (info & 0x0000003f) >> 0, .func = (info & 0x0000ff00) >> 8, .log[0] = (info1 & 0x30) >> 4, .log[1] = (info1 & 0xc0) >> 6, .param = !!(info & 0x80000000), }; } } return data; } u16 dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) { u8 hdr, cnt, i = 0; u16 data; while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) { if ((line == 0xff || line == gpio->line) && (func == 0xff || func == gpio->func)) return 0; return data; } /* DCB 2.2, fixed TVDAC GPIO data */ if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len))) { if (ver >= 0x22 && ver < 0x30 && func == DCB_GPIO_TVDAC0) { u8 conf = nv_ro08(bios, entry - 5); u8 addr = nv_ro08(bios, entry - 4); if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) { if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { u8 conf = nv_ro08(bios, data - 5); u8 addr = nv_ro08(bios, data - 4); if (conf & 0x01) { *gpio = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, Loading @@ -112,10 +133,11 @@ dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, .log[0] = !!(conf & 0x02), .log[1] = !(conf & 0x02), }; return 0; *ver = 0x00; return data; } } } return -EINVAL; return 0x0000; } drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +6 −1 Original line number Diff line number Diff line Loading @@ -43,10 +43,15 @@ static int nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { struct nouveau_bios *bios = nouveau_bios(gpio); u8 ver, len; u16 data; if (line == 0xff && tag == 0xff) return -EINVAL; if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func)) data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func); if (data) return 0; /* Apple iMac G4 NV18 */ Loading drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +2 −2 Original line number Diff line number Diff line Loading @@ -33,11 +33,11 @@ nv50_gpio_reset(struct nouveau_gpio *gpio) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nv50_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; u8 ver; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { static const u32 regs[] = { 0xe100, 0xe28c }; u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000001f); Loading drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +2 −2 Original line number Diff line number Diff line Loading @@ -33,11 +33,11 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nvd0_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; u8 ver; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000003f); u8 defs = !!(data & 0x00000080); Loading Loading
drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h +5 −3 Original line number Diff line number Diff line Loading @@ -25,9 +25,11 @@ struct dcb_gpio_func { u8 param; }; u16 dcb_gpio_table(struct nouveau_bios *); u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver); int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line, u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len); u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *); u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line, u8 *ver, u8 *len, struct dcb_gpio_func *); #endif
drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c +75 −53 Original line number Diff line number Diff line Loading @@ -27,84 +27,105 @@ #include <subdev/bios/gpio.h> u16 dcb_gpio_table(struct nouveau_bios *bios) dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u8 ver, hdr, cnt, len; u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); u16 data = 0x0000; u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { if (ver >= 0x30 && hdr >= 0x0c) return nv_ro16(bios, dcb + 0x0a); if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) return nv_ro16(bios, dcb - 0x0f); if (*ver >= 0x30 && *hdr >= 0x0c) data = nv_ro16(bios, dcb + 0x0a); else if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) data = nv_ro16(bios, dcb - 0x0f); if (data) { *ver = nv_ro08(bios, data + 0x00); if (*ver < 0x30) { *hdr = 3; *cnt = nv_ro08(bios, data + 0x02); *len = nv_ro08(bios, data + 0x01); } else if (*ver <= 0x41) { *hdr = nv_ro08(bios, data + 0x01); *cnt = nv_ro08(bios, data + 0x02); *len = nv_ro08(bios, data + 0x03); } else { data = 0x0000; } return 0x0000; } } return data; } u16 dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver) dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len) { u16 gpio = dcb_gpio_table(bios); if (gpio) { *ver = nv_ro08(bios, gpio); if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2)) return gpio + 3 + (ent * nv_ro08(bios, gpio + 1)); else if (ent < nv_ro08(bios, gpio + 2)) return gpio + nv_ro08(bios, gpio + 1) + (ent * nv_ro08(bios, gpio + 3)); } u8 hdr, cnt; u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000; if (gpio && ent < cnt) return gpio + hdr + (ent * *len); return 0x0000; } int dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, u16 dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) { u8 ver, hdr, cnt, len; u16 entry; int i = -1; while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) { if (ver < 0x40) { u16 data = nv_ro16(bios, entry); u16 data = dcb_gpio_entry(bios, idx, ent, ver, len); if (data) { if (*ver < 0x40) { u16 info = nv_ro16(bios, data); *gpio = (struct dcb_gpio_func) { .line = (data & 0x001f) >> 0, .func = (data & 0x07e0) >> 5, .log[0] = (data & 0x1800) >> 11, .log[1] = (data & 0x6000) >> 13, .param = !!(data & 0x8000), .line = (info & 0x001f) >> 0, .func = (info & 0x07e0) >> 5, .log[0] = (info & 0x1800) >> 11, .log[1] = (info & 0x6000) >> 13, .param = !!(info & 0x8000), }; } else if (ver < 0x41) { u32 data = nv_ro32(bios, entry); if (*ver < 0x41) { u32 info = nv_ro32(bios, data); *gpio = (struct dcb_gpio_func) { .line = (data & 0x0000001f) >> 0, .func = (data & 0x0000ff00) >> 8, .log[0] = (data & 0x18000000) >> 27, .log[1] = (data & 0x60000000) >> 29, .param = !!(data & 0x80000000), .line = (info & 0x0000001f) >> 0, .func = (info & 0x0000ff00) >> 8, .log[0] = (info & 0x18000000) >> 27, .log[1] = (info & 0x60000000) >> 29, .param = !!(info & 0x80000000), }; } else { u32 data = nv_ro32(bios, entry + 0); u8 data1 = nv_ro32(bios, entry + 4); u32 info = nv_ro32(bios, data + 0); u8 info1 = nv_ro32(bios, data + 4); *gpio = (struct dcb_gpio_func) { .line = (data & 0x0000003f) >> 0, .func = (data & 0x0000ff00) >> 8, .log[0] = (data1 & 0x30) >> 4, .log[1] = (data1 & 0xc0) >> 6, .param = !!(data & 0x80000000), .line = (info & 0x0000003f) >> 0, .func = (info & 0x0000ff00) >> 8, .log[0] = (info1 & 0x30) >> 4, .log[1] = (info1 & 0xc0) >> 6, .param = !!(info & 0x80000000), }; } } return data; } u16 dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) { u8 hdr, cnt, i = 0; u16 data; while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) { if ((line == 0xff || line == gpio->line) && (func == 0xff || func == gpio->func)) return 0; return data; } /* DCB 2.2, fixed TVDAC GPIO data */ if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len))) { if (ver >= 0x22 && ver < 0x30 && func == DCB_GPIO_TVDAC0) { u8 conf = nv_ro08(bios, entry - 5); u8 addr = nv_ro08(bios, entry - 4); if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) { if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { u8 conf = nv_ro08(bios, data - 5); u8 addr = nv_ro08(bios, data - 4); if (conf & 0x01) { *gpio = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, Loading @@ -112,10 +133,11 @@ dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, .log[0] = !!(conf & 0x02), .log[1] = !(conf & 0x02), }; return 0; *ver = 0x00; return data; } } } return -EINVAL; return 0x0000; }
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +6 −1 Original line number Diff line number Diff line Loading @@ -43,10 +43,15 @@ static int nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { struct nouveau_bios *bios = nouveau_bios(gpio); u8 ver, len; u16 data; if (line == 0xff && tag == 0xff) return -EINVAL; if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func)) data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func); if (data) return 0; /* Apple iMac G4 NV18 */ Loading
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +2 −2 Original line number Diff line number Diff line Loading @@ -33,11 +33,11 @@ nv50_gpio_reset(struct nouveau_gpio *gpio) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nv50_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; u8 ver; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { static const u32 regs[] = { 0xe100, 0xe28c }; u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000001f); Loading
drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +2 −2 Original line number Diff line number Diff line Loading @@ -33,11 +33,11 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nvd0_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; u8 ver; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000003f); u8 defs = !!(data & 0x00000080); Loading