diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-02-18 23:17:53 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-02-20 16:01:02 +1000 |
commit | 0a0afd282fd715dd63d64b243299a64da14f8e8d (patch) | |
tree | 2ab42981dd69f24fba45b72ec842b64288b76661 /drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |
parent | 5cc027f6b1ec651c18a4322ed3e30c6e9cf01e96 (diff) | |
download | op-kernel-dev-0a0afd282fd715dd63d64b243299a64da14f8e8d.zip op-kernel-dev-0a0afd282fd715dd63d64b243299a64da14f8e8d.tar.gz |
drm/nv50-/disp: move DP link training to core and train from supervisor
We need to be able to do link training for PIOR-connected ANX9805 from
the third supervisor handler (due to script ordering in the bios, can't
have the "user" call train because some settings are overwritten from
the modesetting bios scripts).
This moves link training for SOR-connected DP encoders to the second
supervisor interrupt, *before* we call the modesetting scripts (yes,
different ordering from PIOR is necessary). This is useful since we
should now be able to remove some hacks to workaround races between
the supervisor and link training paths.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/engine/disp/nv50.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index d22f656..a4e2112 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -911,7 +911,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, } data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); - if (data) { + if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { @@ -1078,8 +1078,28 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) head = ffs((super & 0x00000180) >> 7) - 1; if (head >= 0) { u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; - u32 conf = exec_clkcmp(priv, head, 0, pclk, &outp); + u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); if (conf != ~0) { + if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) { + u32 soff = (ffs(outp.or) - 1) * 0x08; + u32 ctrl = nv_rd32(priv, 0x610798 + soff); + u32 datarate; + + switch ((ctrl & 0x000f0000) >> 16) { + case 6: datarate = pclk * 30 / 8; break; + case 5: datarate = pclk * 24 / 8; break; + case 2: + default: + datarate = pclk * 18 / 8; + break; + } + + nouveau_dp_train(&priv->base, priv->sor.dp, + &outp, head, datarate); + } + + exec_clkcmp(priv, head, 0, pclk, &outp); + if (outp.type == DCB_OUTPUT_ANALOG) { addr = 0x614280 + (ffs(outp.or) - 1) * 0x800; mask = 0xffffffff; @@ -1128,10 +1148,9 @@ nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super) if (head >= 0) { struct dcb_output outp; u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; - if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) { - if (outp.type == DCB_OUTPUT_TMDS) + if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) + if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS) nv50_disp_intr_unk40_tmds(priv, &outp); - } } nv_wr32(priv, 0x610030, 0x80000000); |