diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-08-28 03:00:30 (GMT) |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-12-02 05:43:49 (GMT) |
commit | c21e6b302a1eac4b3379bf8e472fffb8dda18371 (patch) | |
tree | 12b29f79b71795af124a8a7da3dd83e92885a8f1 /drivers/gpu/drm/nouveau | |
parent | 1f89b4756fb83f385ac0e277b092774c01a5ab9c (diff) | |
download | linux-c21e6b302a1eac4b3379bf8e472fffb8dda18371.tar.xz |
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 <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
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 3989022..16db08d 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 <subdev/bios/init.h> #include <subdev/i2c.h> -#include <engine/disp.h> +#include "nv50.h" #include <nvif/class.h> @@ -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 ebd68eb2..c41a928 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 9a0058ca..070bfca 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 2aae9d3..cc1d7b0 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 ee1f7ae..0b4fad3 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) { |