Loading drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h +0 −29 Original line number Diff line number Diff line Loading @@ -58,33 +58,4 @@ u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec) (struct nouveau_bios *, void *, int index, u16 entry)); /* BIT 'U'/'d' table encoder subtables have hashes matching them to * a particular set of encoders. * * This function returns true if a particular DCB entry matches. */ static inline bool dcb_hash_match(struct dcb_output *dcb, u32 hash) { if ((hash & 0x000000f0) != (dcb->location << 4)) return false; if ((hash & 0x0000000f) != dcb->type) return false; if (!(hash & (dcb->or << 16))) return false; switch (dcb->type) { case DCB_OUTPUT_TMDS: case DCB_OUTPUT_LVDS: case DCB_OUTPUT_DP: if (hash & 0x00c00000) { if (!(hash & (dcb->sorconf.link << 22))) return false; } default: return true; } } #endif drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h +29 −3 Original line number Diff line number Diff line #ifndef __NVBIOS_DP_H__ #define __NVBIOS_DP_H__ u16 dp_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u16 dp_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); u16 dp_outp_match(struct nouveau_bios *, struct dcb_output *, u8 *ver, u8 *len); struct nvbios_dpout { u16 type; u16 mask; u8 flags; u32 script[5]; u32 lnkcmp; }; u16 nvbios_dpout_parse(struct nouveau_bios *, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *); u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *); struct nvbios_dpcfg { u8 drv; u8 pre; u8 unk; }; u16 nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *); u16 nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *); #endif drivers/gpu/drm/nouveau/core/subdev/bios/dp.c +155 −27 Original line number Diff line number Diff line Loading @@ -25,23 +25,29 @@ #include "subdev/bios.h" #include "subdev/bios/bit.h" #include "subdev/bios/dcb.h" #include "subdev/bios/dp.h" u16 dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) static u16 nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_d; struct bit_entry d; if (!bit_entry(bios, 'd', &bit_d)) { if (bit_d.version == 1) { u16 data = nv_ro16(bios, bit_d.offset); if (!bit_entry(bios, 'd', &d)) { if (d.version == 1 && d.length >= 2) { u16 data = nv_ro16(bios, d.offset); if (data) { *ver = nv_ro08(bios, data + 0); *hdr = nv_ro08(bios, data + 1); *len = nv_ro08(bios, data + 2); *cnt = nv_ro08(bios, data + 3); *ver = nv_ro08(bios, data + 0x00); switch (*ver) { case 0x21: case 0x30: case 0x40: *hdr = nv_ro08(bios, data + 0x01); *len = nv_ro08(bios, data + 0x02); *cnt = nv_ro08(bios, data + 0x03); return data; default: break; } } } } Loading @@ -49,28 +55,150 @@ dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) return 0x0000; } static u16 nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { u16 outp = nv_ro16(bios, data + *hdr + idx * *len); switch (*ver * !!outp) { case 0x21: case 0x30: *hdr = nv_ro08(bios, data + 0x04); *len = nv_ro08(bios, data + 0x05); *cnt = nv_ro08(bios, outp + 0x04); break; case 0x40: *hdr = nv_ro08(bios, data + 0x04); *cnt = 0; *len = 0; break; default: break; } return outp; } *ver = 0x00; return 0x0000; } u16 dp_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *info) { u8 hdr, cnt; u16 table = dp_table(bios, ver, &hdr, &cnt, len); if (table && idx < cnt) return nv_ro16(bios, table + hdr + (idx * *len)); return 0xffff; u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len); if (data && *ver) { info->type = nv_ro16(bios, data + 0x00); info->mask = nv_ro16(bios, data + 0x02); switch (*ver) { case 0x21: case 0x30: info->flags = nv_ro08(bios, data + 0x05); info->script[0] = nv_ro16(bios, data + 0x06); info->script[1] = nv_ro16(bios, data + 0x08); info->lnkcmp = nv_ro16(bios, data + 0x0a); info->script[2] = nv_ro16(bios, data + 0x0c); info->script[3] = nv_ro16(bios, data + 0x0e); info->script[4] = nv_ro16(bios, data + 0x10); break; case 0x40: info->flags = nv_ro08(bios, data + 0x04); info->script[0] = nv_ro16(bios, data + 0x05); info->script[1] = nv_ro16(bios, data + 0x07); info->lnkcmp = nv_ro16(bios, data + 0x09); info->script[2] = nv_ro16(bios, data + 0x0b); info->script[3] = nv_ro16(bios, data + 0x0d); info->script[4] = nv_ro16(bios, data + 0x0f); break; default: data = 0x0000; break; } } return data; } u16 dp_outp_match(struct nouveau_bios *bios, struct dcb_output *outp, u8 *ver, u8 *len) nvbios_dpout_match(struct nouveau_bios *bios, u16 type, u16 mask, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *info) { u8 idx = 0; u16 data; while ((data = dp_outp(bios, idx++, ver, len)) != 0xffff) { if (data) { u32 hash = nv_ro32(bios, data); if (dcb_hash_match(outp, hash)) u16 data, idx = 0; while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) { if (data && info->type == type) { if ((info->mask & mask) == mask) break; } } return data; } static u16 nvbios_dpcfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { if (*ver >= 0x40) { outp = nvbios_dp_table(bios, ver, hdr, cnt, len); *hdr = *hdr + (*len * * cnt); *len = nv_ro08(bios, outp + 0x06); *cnt = nv_ro08(bios, outp + 0x07); } if (idx < *cnt) return outp + *hdr + (idx * *len); return 0x0000; } u16 nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); 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); 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); break; default: data = 0x0000; break; } } return data; } u16 nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { u8 idx = 0xff; u16 data; if (*ver >= 0x30) { const u8 vsoff[] = { 0, 4, 7, 9 }; idx = (un * 10) + vsoff[vs] + pe; } else { 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); } drivers/gpu/drm/nouveau/core/subdev/bios/init.c +8 −5 Original line number Diff line number Diff line Loading @@ -743,9 +743,10 @@ static void init_dp_condition(struct nvbios_init *init) { struct nouveau_bios *bios = init->bios; struct nvbios_dpout info; u8 cond = nv_ro08(bios, init->offset + 1); u8 unkn = nv_ro08(bios, init->offset + 2); u8 ver, len; u8 ver, hdr, cnt, len; u16 data; trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn); Loading @@ -759,10 +760,12 @@ init_dp_condition(struct nvbios_init *init) case 1: case 2: if ( init->outp && (data = dp_outp_match(bios, init->outp, &ver, &len))) { if (ver <= 0x40 && !(nv_ro08(bios, data + 5) & cond)) init_exec_set(init, false); if (ver == 0x40 && !(nv_ro08(bios, data + 4) & cond)) (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP, (init->outp->or << 0) | (init->outp->sorconf.link << 6), &ver, &hdr, &cnt, &len, &info))) { if (!(info.flags & cond)) init_exec_set(init, false); break; } Loading Loading
drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h +0 −29 Original line number Diff line number Diff line Loading @@ -58,33 +58,4 @@ u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec) (struct nouveau_bios *, void *, int index, u16 entry)); /* BIT 'U'/'d' table encoder subtables have hashes matching them to * a particular set of encoders. * * This function returns true if a particular DCB entry matches. */ static inline bool dcb_hash_match(struct dcb_output *dcb, u32 hash) { if ((hash & 0x000000f0) != (dcb->location << 4)) return false; if ((hash & 0x0000000f) != dcb->type) return false; if (!(hash & (dcb->or << 16))) return false; switch (dcb->type) { case DCB_OUTPUT_TMDS: case DCB_OUTPUT_LVDS: case DCB_OUTPUT_DP: if (hash & 0x00c00000) { if (!(hash & (dcb->sorconf.link << 22))) return false; } default: return true; } } #endif
drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h +29 −3 Original line number Diff line number Diff line #ifndef __NVBIOS_DP_H__ #define __NVBIOS_DP_H__ u16 dp_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u16 dp_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); u16 dp_outp_match(struct nouveau_bios *, struct dcb_output *, u8 *ver, u8 *len); struct nvbios_dpout { u16 type; u16 mask; u8 flags; u32 script[5]; u32 lnkcmp; }; u16 nvbios_dpout_parse(struct nouveau_bios *, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *); u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *); struct nvbios_dpcfg { u8 drv; u8 pre; u8 unk; }; u16 nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *); u16 nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *); #endif
drivers/gpu/drm/nouveau/core/subdev/bios/dp.c +155 −27 Original line number Diff line number Diff line Loading @@ -25,23 +25,29 @@ #include "subdev/bios.h" #include "subdev/bios/bit.h" #include "subdev/bios/dcb.h" #include "subdev/bios/dp.h" u16 dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) static u16 nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_d; struct bit_entry d; if (!bit_entry(bios, 'd', &bit_d)) { if (bit_d.version == 1) { u16 data = nv_ro16(bios, bit_d.offset); if (!bit_entry(bios, 'd', &d)) { if (d.version == 1 && d.length >= 2) { u16 data = nv_ro16(bios, d.offset); if (data) { *ver = nv_ro08(bios, data + 0); *hdr = nv_ro08(bios, data + 1); *len = nv_ro08(bios, data + 2); *cnt = nv_ro08(bios, data + 3); *ver = nv_ro08(bios, data + 0x00); switch (*ver) { case 0x21: case 0x30: case 0x40: *hdr = nv_ro08(bios, data + 0x01); *len = nv_ro08(bios, data + 0x02); *cnt = nv_ro08(bios, data + 0x03); return data; default: break; } } } } Loading @@ -49,28 +55,150 @@ dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) return 0x0000; } static u16 nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { u16 outp = nv_ro16(bios, data + *hdr + idx * *len); switch (*ver * !!outp) { case 0x21: case 0x30: *hdr = nv_ro08(bios, data + 0x04); *len = nv_ro08(bios, data + 0x05); *cnt = nv_ro08(bios, outp + 0x04); break; case 0x40: *hdr = nv_ro08(bios, data + 0x04); *cnt = 0; *len = 0; break; default: break; } return outp; } *ver = 0x00; return 0x0000; } u16 dp_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *info) { u8 hdr, cnt; u16 table = dp_table(bios, ver, &hdr, &cnt, len); if (table && idx < cnt) return nv_ro16(bios, table + hdr + (idx * *len)); return 0xffff; u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len); if (data && *ver) { info->type = nv_ro16(bios, data + 0x00); info->mask = nv_ro16(bios, data + 0x02); switch (*ver) { case 0x21: case 0x30: info->flags = nv_ro08(bios, data + 0x05); info->script[0] = nv_ro16(bios, data + 0x06); info->script[1] = nv_ro16(bios, data + 0x08); info->lnkcmp = nv_ro16(bios, data + 0x0a); info->script[2] = nv_ro16(bios, data + 0x0c); info->script[3] = nv_ro16(bios, data + 0x0e); info->script[4] = nv_ro16(bios, data + 0x10); break; case 0x40: info->flags = nv_ro08(bios, data + 0x04); info->script[0] = nv_ro16(bios, data + 0x05); info->script[1] = nv_ro16(bios, data + 0x07); info->lnkcmp = nv_ro16(bios, data + 0x09); info->script[2] = nv_ro16(bios, data + 0x0b); info->script[3] = nv_ro16(bios, data + 0x0d); info->script[4] = nv_ro16(bios, data + 0x0f); break; default: data = 0x0000; break; } } return data; } u16 dp_outp_match(struct nouveau_bios *bios, struct dcb_output *outp, u8 *ver, u8 *len) nvbios_dpout_match(struct nouveau_bios *bios, u16 type, u16 mask, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpout *info) { u8 idx = 0; u16 data; while ((data = dp_outp(bios, idx++, ver, len)) != 0xffff) { if (data) { u32 hash = nv_ro32(bios, data); if (dcb_hash_match(outp, hash)) u16 data, idx = 0; while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) { if (data && info->type == type) { if ((info->mask & mask) == mask) break; } } return data; } static u16 nvbios_dpcfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { if (*ver >= 0x40) { outp = nvbios_dp_table(bios, ver, hdr, cnt, len); *hdr = *hdr + (*len * * cnt); *len = nv_ro08(bios, outp + 0x06); *cnt = nv_ro08(bios, outp + 0x07); } if (idx < *cnt) return outp + *hdr + (idx * *len); return 0x0000; } u16 nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); 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); 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); break; default: data = 0x0000; break; } } return data; } u16 nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { u8 idx = 0xff; u16 data; if (*ver >= 0x30) { const u8 vsoff[] = { 0, 4, 7, 9 }; idx = (un * 10) + vsoff[vs] + pe; } else { 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); }
drivers/gpu/drm/nouveau/core/subdev/bios/init.c +8 −5 Original line number Diff line number Diff line Loading @@ -743,9 +743,10 @@ static void init_dp_condition(struct nvbios_init *init) { struct nouveau_bios *bios = init->bios; struct nvbios_dpout info; u8 cond = nv_ro08(bios, init->offset + 1); u8 unkn = nv_ro08(bios, init->offset + 2); u8 ver, len; u8 ver, hdr, cnt, len; u16 data; trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn); Loading @@ -759,10 +760,12 @@ init_dp_condition(struct nvbios_init *init) case 1: case 2: if ( init->outp && (data = dp_outp_match(bios, init->outp, &ver, &len))) { if (ver <= 0x40 && !(nv_ro08(bios, data + 5) & cond)) init_exec_set(init, false); if (ver == 0x40 && !(nv_ro08(bios, data + 4) & cond)) (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP, (init->outp->or << 0) | (init->outp->sorconf.link << 6), &ver, &hdr, &cnt, &len, &info))) { if (!(info.flags & cond)) init_exec_set(init, false); break; } Loading