From 99145fe39cd039c79cecd13520bd7e53d2372874 Mon Sep 17 00:00:00 2001
From: Damien Diederen
Date: Sat, 22 Mar 2014 18:55:00 +0100
Subject: [PATCH] [WIP,BROKEN] drm/nv50: Hack FORCE_DP_TRAIN method for DPMS
power-on
Display doesn't wake up properly, though.
---
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 27 ++++++++++++++++++++++
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h | 4 ++++
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c | 1 +
drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c | 18 +++++++++++++++
drivers/gpu/drm/nouveau/core/include/core/class.h | 1 +
drivers/gpu/drm/nouveau/nouveau_dp.c | 5 +---
12 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 9ad722e..29be94f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -1130,6 +1130,32 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
bestVTUi << 8 | unk);
}
+void
+nv50_force_dp_train(struct nv50_disp_priv *priv, int head)
+{
+ struct dcb_output outp;
+ u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+ exec_clkcmp(priv, head, 0xff, pclk, &outp);
+
+ if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
+ u32 soff = (ffs(outp.or) - 1) * 0x08;
+ u32 ctrl = nv_rd32(priv, 0x610794 + 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);
+ }
+}
+
static void
nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
{
@@ -1341,6 +1367,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
index d31d426..262edae 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
@@ -30,6 +30,7 @@ struct nv50_disp_priv {
struct {
int nr;
int (*power)(struct nv50_disp_priv *, int sor, u32 data);
+ int (*force_dp_train)(struct nv50_disp_priv *);
int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32);
int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32);
u32 lvdsconf;
@@ -64,6 +65,9 @@ int nvd0_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32);
int nv50_sor_mthd(struct nouveau_object *, u32, void *, u32);
int nv50_sor_power(struct nv50_disp_priv *, int, u32);
+int nv50_sor_force_dp_train(struct nv50_disp_priv *);
+
+void nv50_force_dp_train(struct nv50_disp_priv *, int);
int nv94_sor_dp_train_init(struct nv50_disp_priv *, int, int, int, u16, u16,
u32, struct dcb_output *);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
index ef9ce30..0031979 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
@@ -85,6 +85,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
index a518543..9348836 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
@@ -85,6 +85,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hdmi = nv84_hdmi_ctrl;
priv->sor.dp = &nv94_sor_dp_func;
priv->pior.power = nv50_pior_power;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
index 6cf8eef..7bc433d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
@@ -71,6 +71,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
index 6ad6dce..601fb99 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
@@ -86,6 +86,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hda_eld = nva3_hda_eld;
priv->sor.hdmi = nva3_hdmi_ctrl;
priv->sor.dp = &nv94_sor_dp_func;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 1c5e4e8..513fc1b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -1029,6 +1029,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index ab63f32..901345d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -71,6 +71,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
index 05fee10..b994894 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
@@ -71,6 +71,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
+ priv->sor.force_dp_train = nv50_sor_force_dp_train;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
index 526b752..52d598c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
@@ -22,6 +22,8 @@
* Authors: Ben Skeggs
*/
+#include
+
#include
#include
@@ -32,10 +34,23 @@
#include "nv50.h"
int
+nv50_sor_force_dp_train(struct nv50_disp_priv *priv)
+{
+ int head;
+
+ for (head = 0; head < priv->head.nr; head++) {
+ nv50_force_dp_train(priv, head);
+ }
+
+ return 0;
+}
+
+int
nv50_sor_power(struct nv50_disp_priv *priv, int or, u32 data)
{
const u32 stat = data & NV50_DISP_SOR_PWR_STATE;
const u32 soff = (or * 0x800);
+
nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
@@ -71,6 +86,9 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
ret = 0;
break;
+ case NV50_DISP_SOR_FORCE_DP_TRAIN:
+ ret = priv->sor.force_dp_train(priv);
+ break;
default:
BUG_ON(1);
}
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index e71a432..e1b93a4 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -293,6 +293,7 @@ struct nv04_display_scanoutpos {
#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f
#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000
#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff
+#define NV50_DISP_SOR_FORCE_DP_TRAIN 0x00014000
#define NV50_DISP_DAC_MTHD 0x00020000
#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 4c8c554..ec8b6cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -114,9 +114,6 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
nv_wraux(auxch, DP_SET_POWER, &status, 1);
- /* FIXME */
- /*
if (mode == DRM_MODE_DPMS_ON)
- nouveau_dp_train(...);
- */
+ nv_call(core, NV50_DISP_SOR_FORCE_DP_TRAIN, 0);
}
--
1.9.1