Loading drivers/gpu/drm/nouveau/core/engine/disp/dport.c +64 −103 Original line number Diff line number Diff line Loading @@ -33,24 +33,13 @@ #include <core/class.h> #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]; Loading @@ -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; Loading @@ -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); Loading @@ -94,11 +85,11 @@ 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] & ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { if (ret < 0) ERR("lnk_ctl failed with %d\n", ret); return ret; } Loading @@ -106,31 +97,33 @@ dp_set_link_config(struct dp_state *dp) /* 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++) { Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); } Loading @@ -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) { Loading @@ -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; Loading drivers/gpu/drm/nouveau/core/engine/disp/dport.h +0 −19 Original line number Diff line number Diff line Loading @@ -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 drivers/gpu/drm/nouveau/core/engine/disp/gm107.c +0 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +2 −5 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); } } Loading Loading @@ -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; } Loading drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +0 −2 Original line number Diff line number Diff line Loading @@ -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; }; Loading Loading
drivers/gpu/drm/nouveau/core/engine/disp/dport.c +64 −103 Original line number Diff line number Diff line Loading @@ -33,24 +33,13 @@ #include <core/class.h> #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]; Loading @@ -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; Loading @@ -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); Loading @@ -94,11 +85,11 @@ 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] & ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { if (ret < 0) ERR("lnk_ctl failed with %d\n", ret); return ret; } Loading @@ -106,31 +97,33 @@ dp_set_link_config(struct dp_state *dp) /* 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++) { Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); } Loading @@ -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) { Loading @@ -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; Loading
drivers/gpu/drm/nouveau/core/engine/disp/dport.h +0 −19 Original line number Diff line number Diff line Loading @@ -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
drivers/gpu/drm/nouveau/core/engine/disp/gm107.c +0 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +2 −5 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); } } Loading Loading @@ -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; } Loading
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +0 −2 Original line number Diff line number Diff line Loading @@ -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; }; Loading