From c21e6b302a1eac4b3379bf8e472fffb8dda18371 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 28 Aug 2014 13:00:30 +1000 Subject: [PATCH] drm/gm204/disp: some magic that fixes bringup of uninitialised outputs Probably missing something here, doesn't make a lot of sense to write or+link data into a register whose offset is calculated by the same or+link info.. This is the all I've witnessed the binary driver and vbios doing so far, so it'll do. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/disp/dport.c | 9 ++++++--- drivers/gpu/drm/nouveau/core/engine/disp/gm204.c | 1 + drivers/gpu/drm/nouveau/core/engine/disp/nv50.h | 2 ++ drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 3 +++ drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c | 12 ++++++++++++ 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c index 39890221b91c..16db08dfba6e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c @@ -28,7 +28,7 @@ #include #include -#include +#include "nv50.h" #include @@ -326,7 +326,7 @@ void nouveau_dp_train(struct work_struct *w) { struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); - struct nouveau_disp *disp = nouveau_disp(outp); + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const struct dp_rates *cfg = nouveau_dp_rates; struct dp_state _dp = { .outp = outp, @@ -334,8 +334,11 @@ nouveau_dp_train(struct work_struct *w) u32 datarate = 0; int ret; + if (!outp->base.info.location && priv->sor.magic) + priv->sor.magic(&outp->base); + /* bring capabilities within encoder limits */ - if (nv_mclass(disp) < GF110_DISP) + if (nv_mclass(priv) < GF110_DISP) outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c index ebd68eb222a4..c41a928aa385 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c @@ -85,6 +85,7 @@ gm204_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hdmi = nvd0_hdmi_ctrl; + priv->sor.magic = gm204_sor_magic; 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 9a0058ca8365..070bfcaaca83 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -42,6 +42,7 @@ struct nv50_disp_priv { int (*hda_eld)(NV50_DISP_MTHD_V1); int (*hdmi)(NV50_DISP_MTHD_V1); u32 lvdsconf; + void (*magic)(struct nvkm_output *); } sor; struct { int nr; @@ -245,6 +246,7 @@ extern struct nvkm_output_dp_impl nvd0_sor_dp_impl; int nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); extern struct nouveau_oclass *nvd0_disp_outp_sclass[]; +void gm204_sor_magic(struct nvkm_output *outp); extern struct nvkm_output_dp_impl gm204_sor_dp_impl; #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index 2aae9d3a5e54..cc1d7b0ead32 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -1055,6 +1055,9 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) if (nvkm_output_dp_train(outp, pclk, true)) ERR("link not trained before attach\n"); + } else { + if (priv->sor.magic) + priv->sor.magic(outp); } exec_clkcmp(priv, head, 0, pclk, &conf); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c index ee1f7ae8a52f..0b4fad39e9a6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c @@ -44,6 +44,18 @@ gm204_sor_loff(struct nvkm_output_dp *outp) return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } +void +gm204_sor_magic(struct nvkm_output *outp) +{ + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); + const u32 soff = outp->or * 0x100; + const u32 data = outp->or + 1; + if (outp->info.sorconf.link & 1) + nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data); + if (outp->info.sorconf.link & 2) + nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data); +} + static inline u32 gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) {