summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-02-18 23:17:53 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-02-20 16:01:02 +1000
commit0a0afd282fd715dd63d64b243299a64da14f8e8d (patch)
tree2ab42981dd69f24fba45b72ec842b64288b76661 /drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
parent5cc027f6b1ec651c18a4322ed3e30c6e9cf01e96 (diff)
downloadop-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.c29
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);
OpenPOWER on IntegriCloud