summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-06-11 13:06:48 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 16:11:47 +1000
commit1ae5a62bb8b6b544bdfac7bdcb15c9eb22dd6620 (patch)
tree665fca654f1bc03b7009c2987ff737992303dfb3
parent8777c5c11764d8336d8270f96778158c34c92108 (diff)
drm/nouveau/disp/dp: fix tmds passthrough on dp connector
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c26
2 files changed, 54 insertions, 10 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 90974cd087c1..1e85f36c705f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -1171,7 +1171,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
return NULL;
}
-static bool
+static struct nvkm_output *
exec_script(struct nv50_disp_priv *priv, int head, int id)
{
struct nouveau_bios *bios = nouveau_bios(priv);
@@ -1208,7 +1208,7 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
}
if (!(ctrl & (1 << head)))
- return false;
+ return NULL;
i--;
outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
@@ -1222,10 +1222,10 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
.execute = 1,
};
- return nvbios_exec(&init) == 0;
+ nvbios_exec(&init);
}
- return false;
+ return outp;
}
static struct nvkm_output *
@@ -1325,7 +1325,35 @@ nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
static void
nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
{
- exec_script(priv, head, 2);
+ struct nvkm_output *outp = exec_script(priv, head, 2);
+
+ /* the binary driver does this outside of the supervisor handling
+ * (after the third supervisor from a detach). we (currently?)
+ * allow both detach/attach to happen in the same set of
+ * supervisor interrupts, so it would make sense to execute this
+ * (full power down?) script after all the detach phases of the
+ * supervisor handling. like with training if needed from the
+ * second supervisor, nvidia doesn't do this, so who knows if it's
+ * entirely safe, but it does appear to work..
+ *
+ * without this script being run, on some configurations i've
+ * seen, switching from DP to TMDS on a DP connector may result
+ * in a blank screen (SOR_PWR off/on can restore it)
+ */
+ if (outp && outp->info.type == DCB_OUTPUT_DP) {
+ struct nvkm_output_dp *outpdp = (void *)outp;
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = nouveau_bios(priv),
+ .outp = &outp->info,
+ .crtc = head,
+ .offset = outpdp->info.script[4],
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ atomic_set(&outpdp->lt.done, 0);
+ }
}
static void
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index b998040b5cca..48aa38a87e3f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -962,7 +962,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
return NULL;
}
-static bool
+static struct nvkm_output *
exec_script(struct nv50_disp_priv *priv, int head, int id)
{
struct nouveau_bios *bios = nouveau_bios(priv);
@@ -979,7 +979,7 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
}
if (or == 8)
- return false;
+ return NULL;
outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
if (outp) {
@@ -992,10 +992,10 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
.execute = 1,
};
- return nvbios_exec(&init) == 0;
+ nvbios_exec(&init);
}
- return false;
+ return outp;
}
static struct nvkm_output *
@@ -1069,7 +1069,23 @@ nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
static void
nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
{
- exec_script(priv, head, 2);
+ struct nvkm_output *outp = exec_script(priv, head, 2);
+
+ /* see note in nv50_disp_intr_unk20_0() */
+ if (outp && outp->info.type == DCB_OUTPUT_DP) {
+ struct nvkm_output_dp *outpdp = (void *)outp;
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = nouveau_bios(priv),
+ .outp = &outp->info,
+ .crtc = head,
+ .offset = outpdp->info.script[4],
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ atomic_set(&outpdp->lt.done, 0);
+ }
}
static void