drm/nouveau/bios/disp: fix handling of "match any protocol" entries

As it turns out, a value of 0xff means "any protocol" and not "VGA".

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Cc: stable@vger.kernel.org
This commit is contained in:
Ben Skeggs 2016-05-25 10:56:24 +10:00
parent 92181d47ee
commit bc9139d23f
4 changed files with 17 additions and 21 deletions

View File

@ -25,7 +25,8 @@ u16 nvbios_outp_match(struct nvkm_bios *, u16 type, u16 mask,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *); u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *);
struct nvbios_ocfg { struct nvbios_ocfg {
u16 match; u8 proto;
u8 flags;
u16 clkcmp[2]; u16 clkcmp[2];
}; };
@ -33,7 +34,7 @@ u16 nvbios_ocfg_entry(struct nvkm_bios *, u16 outp, u8 idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u16 nvbios_ocfg_parse(struct nvkm_bios *, u16 outp, u8 idx, u16 nvbios_ocfg_parse(struct nvkm_bios *, u16 outp, u8 idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *); u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *);
u16 nvbios_ocfg_match(struct nvkm_bios *, u16 outp, u16 type, u16 nvbios_ocfg_match(struct nvkm_bios *, u16 outp, u8 proto, u8 flags,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *); u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *);
u16 nvbios_oclk_match(struct nvkm_bios *, u16 cmp, u32 khz); u16 nvbios_oclk_match(struct nvkm_bios *, u16 cmp, u32 khz);
#endif #endif

View File

@ -76,6 +76,7 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
mask |= 0x0001 << or; mask |= 0x0001 << or;
mask |= 0x0100 << head; mask |= 0x0100 << head;
list_for_each_entry(outp, &disp->base.outp, head) { list_for_each_entry(outp, &disp->base.outp, head) {
if ((outp->info.hasht & 0xff) == type && if ((outp->info.hasht & 0xff) == type &&
(outp->info.hashm & mask) == mask) { (outp->info.hashm & mask) == mask) {
@ -155,25 +156,21 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
if (!outp) if (!outp)
return NULL; return NULL;
*conf = (ctrl & 0x00000f00) >> 8;
switch (outp->info.type) { switch (outp->info.type) {
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
*conf = (ctrl & 0x00000f00) >> 8;
if (*conf == 5) if (*conf == 5)
*conf |= 0x0100; *conf |= 0x0100;
break; break;
case DCB_OUTPUT_LVDS: case DCB_OUTPUT_LVDS:
*conf = disp->sor.lvdsconf; *conf |= disp->sor.lvdsconf;
break; break;
case DCB_OUTPUT_DP:
*conf = (ctrl & 0x00000f00) >> 8;
break;
case DCB_OUTPUT_ANALOG:
default: default:
*conf = 0x00ff;
break; break;
} }
data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8,
&ver, &hdr, &cnt, &len, &info2);
if (data && id < 0xff) { if (data && id < 0xff) {
data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
if (data) { if (data) {

View File

@ -387,22 +387,17 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
if (!outp) if (!outp)
return NULL; return NULL;
*conf = (ctrl & 0x00000f00) >> 8;
if (outp->info.location == 0) { if (outp->info.location == 0) {
switch (outp->info.type) { switch (outp->info.type) {
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
*conf = (ctrl & 0x00000f00) >> 8;
if (*conf == 5) if (*conf == 5)
*conf |= 0x0100; *conf |= 0x0100;
break; break;
case DCB_OUTPUT_LVDS: case DCB_OUTPUT_LVDS:
*conf = disp->sor.lvdsconf; *conf |= disp->sor.lvdsconf;
break; break;
case DCB_OUTPUT_DP:
*conf = (ctrl & 0x00000f00) >> 8;
break;
case DCB_OUTPUT_ANALOG:
default: default:
*conf = 0x00ff;
break; break;
} }
} else { } else {
@ -410,7 +405,8 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
pclk = pclk / 2; pclk = pclk / 2;
} }
data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8,
&ver, &hdr, &cnt, &len, &info2);
if (data && id < 0xff) { if (data && id < 0xff) {
data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
if (data) { if (data) {

View File

@ -141,7 +141,8 @@ nvbios_ocfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
{ {
u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len); u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len);
if (data) { if (data) {
info->match = nvbios_rd16(bios, data + 0x00); info->proto = nvbios_rd08(bios, data + 0x00);
info->flags = nvbios_rd16(bios, data + 0x01);
info->clkcmp[0] = nvbios_rd16(bios, data + 0x02); info->clkcmp[0] = nvbios_rd16(bios, data + 0x02);
info->clkcmp[1] = nvbios_rd16(bios, data + 0x04); info->clkcmp[1] = nvbios_rd16(bios, data + 0x04);
} }
@ -149,12 +150,13 @@ nvbios_ocfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
} }
u16 u16
nvbios_ocfg_match(struct nvkm_bios *bios, u16 outp, u16 type, nvbios_ocfg_match(struct nvkm_bios *bios, u16 outp, u8 proto, u8 flags,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info) u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info)
{ {
u16 data, idx = 0; u16 data, idx = 0;
while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) { while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) {
if (info->match == type) if ((info->proto == proto || info->proto == 0xff) &&
(info->flags == flags))
break; break;
} }
return data; return data;