From 3b52a1f90639a88b3c76e4d42b60c34dd950cad3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 19 May 2014 14:06:07 +1000 Subject: [PATCH] drm/nouveau/disp/dp: make use of existing output data for link training Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/core/engine/disp/dport.c | 167 +++++++----------- .../gpu/drm/nouveau/core/engine/disp/dport.h | 19 -- .../gpu/drm/nouveau/core/engine/disp/gm107.c | 1 - .../gpu/drm/nouveau/core/engine/disp/nv50.c | 7 +- .../gpu/drm/nouveau/core/engine/disp/nv50.h | 2 - .../gpu/drm/nouveau/core/engine/disp/nv84.c | 1 - .../gpu/drm/nouveau/core/engine/disp/nv94.c | 2 - .../gpu/drm/nouveau/core/engine/disp/nva0.c | 1 - .../gpu/drm/nouveau/core/engine/disp/nva3.c | 2 - .../gpu/drm/nouveau/core/engine/disp/nvd0.c | 4 +- .../gpu/drm/nouveau/core/engine/disp/nve0.c | 1 - .../gpu/drm/nouveau/core/engine/disp/nvf0.c | 1 - .../gpu/drm/nouveau/core/engine/disp/outpdp.h | 5 + .../drm/nouveau/core/engine/disp/piornv50.c | 70 ++------ .../drm/nouveau/core/engine/disp/sornv94.c | 50 +++--- .../drm/nouveau/core/engine/disp/sornvd0.c | 50 +++--- 16 files changed, 134 insertions(+), 249 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c index 3814c3d33812..efccbabca18c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c @@ -33,24 +33,13 @@ #include #include "dport.h" - -#define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \ - dp->outp->hasht, dp->outp->hashm, ##args) -#define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \ - dp->outp->hasht, dp->outp->hashm, ##args) +#include "outpdp.h" /****************************************************************************** * link training *****************************************************************************/ struct dp_state { - const struct nouveau_dp_func *func; - struct nouveau_disp *disp; - struct dcb_output *outp; - struct nvbios_dpout info; - u8 version; - struct nouveau_i2c_port *aux; - int head; - u8 dpcd[16]; + struct nvkm_output_dp *outp; int link_nr; u32 link_bw; u8 stat[6]; @@ -63,14 +52,16 @@ struct dp_state { static int dp_set_link_config(struct dp_state *dp) { - struct nouveau_disp *disp = dp->disp; + struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); + struct nvkm_output_dp *outp = dp->outp; + struct nouveau_disp *disp = nouveau_disp(outp); struct nouveau_bios *bios = nouveau_bios(disp); struct nvbios_init init = { - .subdev = nv_subdev(dp->disp), + .subdev = nv_subdev(disp), .bios = bios, .offset = 0x0000, - .outp = dp->outp, - .crtc = dp->head, + .outp = &outp->base.info, + .crtc = -1, .execute = 1, }; u32 lnkcmp; @@ -80,8 +71,8 @@ dp_set_link_config(struct dp_state *dp) DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); /* set desired link configuration on the source */ - if ((lnkcmp = dp->info.lnkcmp)) { - if (dp->version < 0x30) { + if ((lnkcmp = dp->outp->info.lnkcmp)) { + if (outp->version < 0x30) { while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) lnkcmp += 4; init.offset = nv_ro16(bios, lnkcmp + 2); @@ -94,43 +85,45 @@ dp_set_link_config(struct dp_state *dp) nvbios_exec(&init); } - ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, - dp->link_nr, dp->link_bw / 27000, - dp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, + outp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { - ERR("lnk_ctl failed with %d\n", ret); + if (ret < 0) + ERR("lnk_ctl failed with %d\n", ret); return ret; } /* set desired link configuration on the sink */ sink[0] = dp->link_bw / 27000; sink[1] = dp->link_nr; - if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) + if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - return nv_wraux(dp->aux, DPCD_LC00, sink, 2); + return nv_wraux(outp->base.edid, DPCD_LC00, sink, 2); } static void dp_set_training_pattern(struct dp_state *dp, u8 pattern) { + struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); + struct nvkm_output_dp *outp = dp->outp; u8 sink_tp; DBG("training pattern %d\n", pattern); - dp->func->pattern(dp->disp, dp->outp, dp->head, pattern); + impl->pattern(outp, pattern); - nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); + nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= pattern; - nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); + nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1); } static int dp_link_train_commit(struct dp_state *dp, bool pc) { - const struct nouveau_dp_func *func = dp->func; - struct nouveau_disp *disp = dp->disp; + struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); + struct nvkm_output_dp *outp = dp->outp; int ret, i; for (i = 0; i < dp->link_nr; i++) { @@ -146,15 +139,15 @@ dp_link_train_commit(struct dp_state *dp, bool pc) dp->pc2conf[i >> 1] |= 4 << ((i & 1) * 4); DBG("config lane %d %02x\n", i, dp->conf[i]); - func->drv_ctl(disp, dp->outp, dp->head, i, lvsw, lpre); + impl->drv_ctl(outp, i, lvsw, lpre, 0); } - ret = nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4); + ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4); if (ret) return ret; if (pc) { - ret = nv_wraux(dp->aux, DPCD_LC0F, dp->pc2conf, 2); + ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2); if (ret) return ret; } @@ -165,19 +158,20 @@ dp_link_train_commit(struct dp_state *dp, bool pc) static int dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) { + struct nvkm_output_dp *outp = dp->outp; int ret; - if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) - mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); + if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) + mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); else udelay(delay); - ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6); + ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6); if (ret) return ret; if (pc) { - ret = nv_rdaux(dp->aux, DPCD_LS0C, &dp->pc2stat, 1); + ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1); if (ret) dp->pc2stat = 0x00; DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); @@ -225,10 +219,11 @@ dp_link_train_cr(struct dp_state *dp) static int dp_link_train_eq(struct dp_state *dp) { + struct nvkm_output_dp *outp = dp->outp; bool eq_done = false, cr_done = true; int tries = 0, i; - if (dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) + if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) dp_set_training_pattern(dp, 3); else dp_set_training_pattern(dp, 2); @@ -257,39 +252,45 @@ dp_link_train_eq(struct dp_state *dp) static void dp_link_train_init(struct dp_state *dp, bool spread) { + struct nvkm_output_dp *outp = dp->outp; + struct nouveau_disp *disp = nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(disp); struct nvbios_init init = { - .subdev = nv_subdev(dp->disp), - .bios = nouveau_bios(dp->disp), - .outp = dp->outp, - .crtc = dp->head, + .subdev = nv_subdev(disp), + .bios = bios, + .outp = &outp->base.info, + .crtc = -1, .execute = 1, }; /* set desired spread */ if (spread) - init.offset = dp->info.script[2]; + init.offset = outp->info.script[2]; else - init.offset = dp->info.script[3]; + init.offset = outp->info.script[3]; nvbios_exec(&init); /* pre-train script */ - init.offset = dp->info.script[0]; + init.offset = outp->info.script[0]; nvbios_exec(&init); } static void dp_link_train_fini(struct dp_state *dp) { + struct nvkm_output_dp *outp = dp->outp; + struct nouveau_disp *disp = nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(disp); struct nvbios_init init = { - .subdev = nv_subdev(dp->disp), - .bios = nouveau_bios(dp->disp), - .outp = dp->outp, - .crtc = dp->head, + .subdev = nv_subdev(disp), + .bios = bios, + .outp = &outp->base.info, + .crtc = -1, .execute = 1, }; /* post-train script */ - init.offset = dp->info.script[1], + init.offset = outp->info.script[1], nvbios_exec(&init); } @@ -311,65 +312,25 @@ static const struct dp_rates { }; int -nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, - struct dcb_output *outp, int head, u32 datarate) +nouveau_dp_train(struct nvkm_output_dp *outp, u32 datarate) { - struct nouveau_bios *bios = nouveau_bios(disp); - struct nouveau_i2c *i2c = nouveau_i2c(disp); + struct nouveau_disp *disp = nouveau_disp(outp); const struct dp_rates *cfg = nouveau_dp_rates; struct dp_state _dp = { - .disp = disp, - .func = func, .outp = outp, - .head = head, }, *dp = &_dp; - u8 hdr, cnt, len; - u32 data; int ret; - /* find the bios displayport data relevant to this output */ - data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version, - &hdr, &cnt, &len, &dp->info); - if (!data) { - ERR("bios data not found\n"); - return -EINVAL; - } - - /* acquire the aux channel and fetch some info about the display */ - if (outp->location) - dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); - else - dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index)); - if (!dp->aux) { - ERR("no aux channel?!\n"); - return -ENODEV; - } - - ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd)); - if (ret) { - /* it's possible the display has been unplugged before we - * get here. we still need to execute the full set of - * vbios scripts, and program the OR at a high enough - * frequency to satisfy the target mode. failure to do - * so results at best in an UPDATE hanging, and at worst - * with PDISP running away to join the circus. - */ - dp->dpcd[1] = dp->outp->dpconf.link_bw; - dp->dpcd[2] = dp->outp->dpconf.link_nr; - dp->dpcd[3] = 0x00; - ERR("failed to read DPCD\n"); - } - /* bring capabilities within encoder limits */ if (nv_mclass(disp) < NVD0_DISP_CLASS) - dp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; - if ((dp->dpcd[2] & 0x1f) > dp->outp->dpconf.link_nr) { - dp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; - dp->dpcd[2] |= dp->outp->dpconf.link_nr; + 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; + outp->dpcd[2] |= outp->base.info.dpconf.link_nr; } - if (dp->dpcd[1] > dp->outp->dpconf.link_bw) - dp->dpcd[1] = dp->outp->dpconf.link_bw; - dp->pc2 = dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; + if (outp->dpcd[1] > outp->base.info.dpconf.link_bw) + outp->dpcd[1] = outp->base.info.dpconf.link_bw; + dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; /* restrict link config to the lowest required rate, if requested */ if (datarate) { @@ -380,12 +341,12 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, cfg--; /* enable down-spreading and execute pre-train script from vbios */ - dp_link_train_init(dp, dp->dpcd[3] & 0x01); + dp_link_train_init(dp, outp->dpcd[3] & 0x01); while (ret = -EIO, (++cfg)->rate) { /* select next configuration supported by encoder and sink */ - while (cfg->nr > (dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || - cfg->bw > (dp->dpcd[DPCD_RC01_MAX_LINK_RATE])) + while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || + cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE])) cfg++; dp->link_bw = cfg->bw * 27000; dp->link_nr = cfg->nr; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h index 436358e5cfc8..2712e31c9ce8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h @@ -71,23 +71,4 @@ #define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c #define DPCD_LS0C_LANE0_POST_CURSOR2 0x03 -struct nouveau_disp; -struct dcb_output; - -struct nouveau_dp_func { - int (*pattern)(struct nouveau_disp *, struct dcb_output *, - int head, int pattern); - int (*lnk_ctl)(struct nouveau_disp *, struct dcb_output *, int head, - int link_nr, int link_bw, bool enh_frame); - int (*drv_ctl)(struct nouveau_disp *, struct dcb_output *, int head, - int lane, int swing, int preem); -}; - -extern const struct nouveau_dp_func nv94_sor_dp_func; -extern const struct nouveau_dp_func nvd0_sor_dp_func; -extern const struct nouveau_dp_func nv50_pior_dp_func; - -int nouveau_dp_train(struct nouveau_disp *, const struct nouveau_dp_func *, - struct dcb_output *, int, u32); - #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c index a5b0ad6d3bfa..9fc7447fec90 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c @@ -81,7 +81,6 @@ gm107_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.dp = &nvd0_sor_dp_func; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index d2553c91df7d..2b9ef826959a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -1471,8 +1471,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) break; } - nouveau_dp_train(&priv->base, priv->sor.dp, - &outp->info, head, datarate); + nouveau_dp_train((void *)outp, datarate); } exec_clkcmp(priv, head, 0, pclk, &conf); @@ -1551,8 +1550,7 @@ nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) break; } - nouveau_dp_train(&priv->base, priv->pior.dp, - &outp->info, head, datarate); + nouveau_dp_train((void *)outp, datarate); } } @@ -1665,7 +1663,6 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; 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 d5468a61f5e0..67ad3f1f829c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -45,13 +45,11 @@ 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; - const struct nouveau_dp_func *dp; } sor; struct { int nr; int (*power)(struct nv50_disp_priv *, int ext, u32 data); u8 type[3]; - const struct nouveau_dp_func *dp; } pior; }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index 436f0a5eb46d..1cc62e434683 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c @@ -264,7 +264,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; 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/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index 14f53143b81b..240b69a89b7b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c @@ -122,9 +122,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; - priv->sor.dp = &nv94_sor_dp_func; 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/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c index b8926200baa7..6237a9a36f70 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c @@ -126,7 +126,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; 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/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index aae561ff838a..705c6784fb68 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -96,9 +96,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nva3_hda_eld; priv->sor.hdmi = nva3_hdmi_ctrl; - priv->sor.dp = &nv94_sor_dp_func; 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/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index 27ec9954a70b..77e7ade11af5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -1149,8 +1149,7 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) break; } - nouveau_dp_train(&priv->base, priv->sor.dp, - &outp->info, head, pclk); + nouveau_dp_train((void *)outp, pclk); } exec_clkcmp(priv, head, 0, pclk, &conf); @@ -1360,7 +1359,6 @@ nvd0_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.dp = &nvd0_sor_dp_func; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 90f79be94bd7..11328e3f5df1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c @@ -246,7 +246,6 @@ nve0_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.dp = &nvd0_sor_dp_func; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c index 25a18dffcb44..104388081d73 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c @@ -81,7 +81,6 @@ nvf0_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.dp = &nvd0_sor_dp_func; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h index 228b5d845640..ab328dcad041 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h @@ -48,6 +48,11 @@ int _nvkm_output_dp_fini(struct nouveau_object *, bool); struct nvkm_output_dp_impl { struct nvkm_output_impl base; + int (*pattern)(struct nvkm_output_dp *, int); + int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); + int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); }; +int nouveau_dp_train(struct nvkm_output_dp *, u32 rate); + #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c index 2c1eacd8019a..491e4d83b921 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c @@ -70,70 +70,33 @@ nv50_pior_tmds_impl = { * DisplayPort *****************************************************************************/ -static struct nouveau_i2c_port * -nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) +static int +nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nouveau_i2c *i2c = nouveau_i2c(disp); - return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); + struct nouveau_i2c_port *port = outp->base.edid; + if (port && port->func->pattern) + return port->func->pattern(port, pattern); + return port ? 0 : -ENODEV; } static int -nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int pattern) +nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nouveau_i2c_port *port; - int ret = -EINVAL; - - port = nv50_pior_dp_find(disp, outp); - if (port) { - if (port->func->pattern) - ret = port->func->pattern(port, pattern); - else - ret = 0; - } - - return ret; -} - -static int -nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane_nr, int link_bw, bool enh) -{ - struct nouveau_i2c_port *port; - int ret = -EINVAL; - - port = nv50_pior_dp_find(disp, outp); + struct nouveau_i2c_port *port = outp->base.edid; if (port && port->func->lnk_ctl) - ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh); - - return ret; + return port->func->lnk_ctl(port, nr, bw, ef); + return port ? 0 : -ENODEV; } static int -nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane, int vsw, int pre) +nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nouveau_i2c_port *port; - int ret = -EINVAL; - - port = nv50_pior_dp_find(disp, outp); - if (port) { - if (port->func->drv_ctl) - ret = port->func->drv_ctl(port, lane, vsw, pre); - else - ret = 0; - } - - return ret; + struct nouveau_i2c_port *port = outp->base.edid; + if (port && port->func->drv_ctl) + return port->func->drv_ctl(port, ln, vs, pe); + return port ? 0 : -ENODEV; } -const struct nouveau_dp_func -nv50_pior_dp_func = { - .pattern = nv50_pior_dp_pattern, - .lnk_ctl = nv50_pior_dp_lnk_ctl, - .drv_ctl = nv50_pior_dp_drv_ctl, -}; - static int nv50_pior_dp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -163,6 +126,9 @@ nv50_pior_dp_impl = { .init = _nvkm_output_dp_init, .fini = _nvkm_output_dp_fini, }, + .pattern = nv50_pior_dp_pattern, + .lnk_ctl = nv50_pior_dp_lnk_ctl, + .drv_ctl = nv50_pior_dp_drv_ctl, }; /****************************************************************************** diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c index ca551eabc1c9..5ee9a12be446 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c @@ -34,15 +34,15 @@ #include "outpdp.h" static inline u32 -nv94_sor_soff(struct dcb_output *outp) +nv94_sor_soff(struct nvkm_output_dp *outp) { - return (ffs(outp->or) - 1) * 0x800; + return (ffs(outp->base.info.or) - 1) * 0x800; } static inline u32 -nv94_sor_loff(struct dcb_output *outp) +nv94_sor_loff(struct nvkm_output_dp *outp) { - return nv94_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; + return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } static inline u32 @@ -56,20 +56,18 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) } static int -nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int pattern) +nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 loff = nv94_sor_loff(outp); nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; } static int -nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int link_nr, int link_bw, bool enh_frame) +nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 soff = nv94_sor_soff(outp); const u32 loff = nv94_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -77,13 +75,13 @@ nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, u32 lane = 0; int i; - dpctrl |= ((1 << link_nr) - 1) << 16; - if (enh_frame) + dpctrl |= ((1 << nr) - 1) << 16; + if (ef) dpctrl |= 0x00004000; - if (link_bw > 0x06) + if (bw > 0x06) clksor |= 0x00040000; - for (i = 0; i < link_nr; i++) + for (i = 0; i < nr; i++) lane |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3); nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); @@ -93,24 +91,24 @@ nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, } static int -nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane, int swing, int preem) +nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nouveau_bios *bios = nouveau_bios(disp); - struct nv50_disp_priv *priv = (void *)disp; - const u32 shift = nv94_sor_dp_lane_map(priv, lane); + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(priv); + const u32 shift = nv94_sor_dp_lane_map(priv, ln); const u32 loff = nv94_sor_loff(outp); u32 addr, data[3]; u8 ver, hdr, cnt, len; struct nvbios_dpout info; struct nvbios_dpcfg ocfg; - addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, + addr = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; - addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, + addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; @@ -124,13 +122,6 @@ nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, return 0; } -const struct nouveau_dp_func -nv94_sor_dp_func = { - .pattern = nv94_sor_dp_pattern, - .lnk_ctl = nv94_sor_dp_lnk_ctl, - .drv_ctl = nv94_sor_dp_drv_ctl, -}; - struct nvkm_output_dp_impl nv94_sor_dp_impl = { .base.base.handle = DCB_OUTPUT_DP, @@ -140,4 +131,7 @@ nv94_sor_dp_impl = { .init = _nvkm_output_dp_init, .fini = _nvkm_output_dp_fini, }, + .pattern = nv94_sor_dp_pattern, + .lnk_ctl = nv94_sor_dp_lnk_ctl, + .drv_ctl = nv94_sor_dp_drv_ctl, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c index ffd4531d81bb..c3120a762070 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c @@ -33,15 +33,15 @@ #include "nv50.h" static inline u32 -nvd0_sor_soff(struct dcb_output *outp) +nvd0_sor_soff(struct nvkm_output_dp *outp) { - return (ffs(outp->or) - 1) * 0x800; + return (ffs(outp->base.info.or) - 1) * 0x800; } static inline u32 -nvd0_sor_loff(struct dcb_output *outp) +nvd0_sor_loff(struct nvkm_output_dp *outp) { - return nvd0_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; + return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } static inline u32 @@ -52,20 +52,18 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) } static int -nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int pattern) +nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 loff = nvd0_sor_loff(outp); nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } static int -nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int link_nr, int link_bw, bool enh_frame) +nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 soff = nvd0_sor_soff(outp); const u32 loff = nvd0_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -73,12 +71,12 @@ nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, u32 lane = 0; int i; - clksor |= link_bw << 18; - dpctrl |= ((1 << link_nr) - 1) << 16; - if (enh_frame) + clksor |= bw << 18; + dpctrl |= ((1 << nr) - 1) << 16; + if (ef) dpctrl |= 0x00004000; - for (i = 0; i < link_nr; i++) + for (i = 0; i < nr; i++) lane |= 1 << (nvd0_sor_dp_lane_map(priv, i) >> 3); nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); @@ -88,24 +86,24 @@ nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, } static int -nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane, int swing, int preem) +nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nouveau_bios *bios = nouveau_bios(disp); - struct nv50_disp_priv *priv = (void *)disp; - const u32 shift = nvd0_sor_dp_lane_map(priv, lane); + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(priv); + const u32 shift = nvd0_sor_dp_lane_map(priv, ln); const u32 loff = nvd0_sor_loff(outp); u32 addr, data[3]; u8 ver, hdr, cnt, len; struct nvbios_dpout info; struct nvbios_dpcfg ocfg; - addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, + addr = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; - addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, + addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; @@ -120,13 +118,6 @@ nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, return 0; } -const struct nouveau_dp_func -nvd0_sor_dp_func = { - .pattern = nvd0_sor_dp_pattern, - .lnk_ctl = nvd0_sor_dp_lnk_ctl, - .drv_ctl = nvd0_sor_dp_drv_ctl, -}; - struct nvkm_output_dp_impl nvd0_sor_dp_impl = { .base.base.handle = DCB_OUTPUT_DP, @@ -136,4 +127,7 @@ nvd0_sor_dp_impl = { .init = _nvkm_output_dp_init, .fini = _nvkm_output_dp_fini, }, + .pattern = nvd0_sor_dp_pattern, + .lnk_ctl = nvd0_sor_dp_lnk_ctl, + .drv_ctl = nvd0_sor_dp_drv_ctl, };