static bool exec_script(struct nv50_disp_priv *priv, int head, int id) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info; struct dcb_output dcb; u8 ver, hdr, cnt, len; u16 data; u32 ctrl = 0x00000000; u32 reg; int i; /* DAC */ for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { if (nv_device(priv)->chipset < 0x90 || nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0xa0) { reg = 0x610b74; } else { reg = 0x610798; } for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) ctrl = nv_rd32(priv, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) ctrl = nv_rd32(priv, 0x610b84 + (i * 8)); i += 8; } if (!(ctrl & (1 << head))) return false; i--; data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[id], .outp = &dcb, .crtc = head, .execute = 1, }; return nvbios_exec(&init) == 0; } return false; } static u32 exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, struct dcb_output *outp) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info1; struct nvbios_ocfg info2; u8 ver, hdr, cnt, len; u32 ctrl = 0x00000000; u32 data, conf = ~0; u32 reg; int i; /* DAC */ for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { if (nv_device(priv)->chipset < 0x90 || nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0xa0) { reg = 0x610b70; } else { reg = 0x610794; } for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) ctrl = nv_rd32(priv, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) ctrl = nv_rd32(priv, 0x610b80 + (i * 8)); i += 8; } if (!(ctrl & (1 << head))) return conf; i--; data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); if (!data) return conf; if (outp->location == 0) { switch (outp->type) { case DCB_OUTPUT_TMDS: conf = (ctrl & 0x00000f00) >> 8; if (pclk >= 165000) conf |= 0x0100; break; case DCB_OUTPUT_LVDS: conf = priv->sor.lvdsconf; break; case DCB_OUTPUT_DP: conf = (ctrl & 0x00000f00) >> 8; break; case DCB_OUTPUT_ANALOG: default: conf = 0x00ff; break; } } else { conf = (ctrl & 0x00000f00) >> 8; pclk = pclk / 2; } data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = data, .outp = outp, .crtc = head, .execute = 1, }; nvbios_exec(&init); } } return conf; }
static bool exec_script(struct nv50_disp_priv *priv, int head, int id) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info; struct dcb_output dcb; u8 ver, hdr, cnt, len; u32 ctrl = 0x00000000; u16 data; int outp; for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20)); if (ctrl & (1 << head)) break; } if (outp == 8) return false; data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[id], .outp = &dcb, .crtc = head, .execute = 1, }; return nvbios_exec(&init) == 0; } return false; } static u32 exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, struct dcb_output *dcb) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info1; struct nvbios_ocfg info2; u8 ver, hdr, cnt, len; u32 ctrl = 0x00000000; u32 data, conf = ~0; int outp; for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20)); if (ctrl & (1 << head)) break; } if (outp == 8) return false; data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); if (data == 0x0000) return conf; switch (dcb->type) { case DCB_OUTPUT_TMDS: conf = (ctrl & 0x00000f00) >> 8; if (pclk >= 165000) conf |= 0x0100; break; case DCB_OUTPUT_LVDS: conf = priv->sor.lvdsconf; break; case DCB_OUTPUT_DP: conf = (ctrl & 0x00000f00) >> 8; break; case DCB_OUTPUT_ANALOG: default: conf = 0x00ff; break; } data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = data, .outp = dcb, .crtc = head, .execute = 1, }; nvbios_exec(&init); } } return conf; } static void nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) { exec_script(priv, head, 1); }