Commit 3b52a1f9 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/disp/dp: make use of existing output data for link training

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2bd651ea
...@@ -33,24 +33,13 @@ ...@@ -33,24 +33,13 @@
#include <core/class.h> #include <core/class.h>
#include "dport.h" #include "dport.h"
#include "outpdp.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)
/****************************************************************************** /******************************************************************************
* link training * link training
*****************************************************************************/ *****************************************************************************/
struct dp_state { struct dp_state {
const struct nouveau_dp_func *func; struct nvkm_output_dp *outp;
struct nouveau_disp *disp;
struct dcb_output *outp;
struct nvbios_dpout info;
u8 version;
struct nouveau_i2c_port *aux;
int head;
u8 dpcd[16];
int link_nr; int link_nr;
u32 link_bw; u32 link_bw;
u8 stat[6]; u8 stat[6];
...@@ -63,14 +52,16 @@ struct dp_state { ...@@ -63,14 +52,16 @@ struct dp_state {
static int static int
dp_set_link_config(struct dp_state *dp) 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 nouveau_bios *bios = nouveau_bios(disp);
struct nvbios_init init = { struct nvbios_init init = {
.subdev = nv_subdev(dp->disp), .subdev = nv_subdev(disp),
.bios = bios, .bios = bios,
.offset = 0x0000, .offset = 0x0000,
.outp = dp->outp, .outp = &outp->base.info,
.crtc = dp->head, .crtc = -1,
.execute = 1, .execute = 1,
}; };
u32 lnkcmp; u32 lnkcmp;
...@@ -80,8 +71,8 @@ dp_set_link_config(struct dp_state *dp) ...@@ -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); DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
/* set desired link configuration on the source */ /* set desired link configuration on the source */
if ((lnkcmp = dp->info.lnkcmp)) { if ((lnkcmp = dp->outp->info.lnkcmp)) {
if (dp->version < 0x30) { if (outp->version < 0x30) {
while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
lnkcmp += 4; lnkcmp += 4;
init.offset = nv_ro16(bios, lnkcmp + 2); init.offset = nv_ro16(bios, lnkcmp + 2);
...@@ -94,43 +85,45 @@ dp_set_link_config(struct dp_state *dp) ...@@ -94,43 +85,45 @@ dp_set_link_config(struct dp_state *dp)
nvbios_exec(&init); nvbios_exec(&init);
} }
ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
dp->link_nr, dp->link_bw / 27000, outp->dpcd[DPCD_RC02] &
dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP);
DPCD_RC02_ENHANCED_FRAME_CAP);
if (ret) { if (ret) {
ERR("lnk_ctl failed with %d\n", ret); if (ret < 0)
ERR("lnk_ctl failed with %d\n", ret);
return ret; return ret;
} }
/* set desired link configuration on the sink */ /* set desired link configuration on the sink */
sink[0] = dp->link_bw / 27000; sink[0] = dp->link_bw / 27000;
sink[1] = dp->link_nr; 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; 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 static void
dp_set_training_pattern(struct dp_state *dp, u8 pattern) 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; u8 sink_tp;
DBG("training pattern %d\n", pattern); 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 &= ~DPCD_LC02_TRAINING_PATTERN_SET;
sink_tp |= pattern; sink_tp |= pattern;
nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
} }
static int static int
dp_link_train_commit(struct dp_state *dp, bool pc) dp_link_train_commit(struct dp_state *dp, bool pc)
{ {
const struct nouveau_dp_func *func = dp->func; struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
struct nouveau_disp *disp = dp->disp; struct nvkm_output_dp *outp = dp->outp;
int ret, i; int ret, i;
for (i = 0; i < dp->link_nr; i++) { for (i = 0; i < dp->link_nr; i++) {
...@@ -146,15 +139,15 @@ dp_link_train_commit(struct dp_state *dp, bool pc) ...@@ -146,15 +139,15 @@ dp_link_train_commit(struct dp_state *dp, bool pc)
dp->pc2conf[i >> 1] |= 4 << ((i & 1) * 4); dp->pc2conf[i >> 1] |= 4 << ((i & 1) * 4);
DBG("config lane %d %02x\n", i, dp->conf[i]); 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) if (ret)
return ret; return ret;
if (pc) { 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) if (ret)
return ret; return ret;
} }
...@@ -165,19 +158,20 @@ dp_link_train_commit(struct dp_state *dp, bool pc) ...@@ -165,19 +158,20 @@ dp_link_train_commit(struct dp_state *dp, bool pc)
static int static int
dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
{ {
struct nvkm_output_dp *outp = dp->outp;
int ret; int ret;
if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
else else
udelay(delay); 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) if (ret)
return ret; return ret;
if (pc) { 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) if (ret)
dp->pc2stat = 0x00; dp->pc2stat = 0x00;
DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
...@@ -225,10 +219,11 @@ dp_link_train_cr(struct dp_state *dp) ...@@ -225,10 +219,11 @@ dp_link_train_cr(struct dp_state *dp)
static int static int
dp_link_train_eq(struct dp_state *dp) dp_link_train_eq(struct dp_state *dp)
{ {
struct nvkm_output_dp *outp = dp->outp;
bool eq_done = false, cr_done = true; bool eq_done = false, cr_done = true;
int tries = 0, i; 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); dp_set_training_pattern(dp, 3);
else else
dp_set_training_pattern(dp, 2); dp_set_training_pattern(dp, 2);
...@@ -257,39 +252,45 @@ dp_link_train_eq(struct dp_state *dp) ...@@ -257,39 +252,45 @@ dp_link_train_eq(struct dp_state *dp)
static void static void
dp_link_train_init(struct dp_state *dp, bool spread) 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 = { struct nvbios_init init = {
.subdev = nv_subdev(dp->disp), .subdev = nv_subdev(disp),
.bios = nouveau_bios(dp->disp), .bios = bios,
.outp = dp->outp, .outp = &outp->base.info,
.crtc = dp->head, .crtc = -1,
.execute = 1, .execute = 1,
}; };
/* set desired spread */ /* set desired spread */
if (spread) if (spread)
init.offset = dp->info.script[2]; init.offset = outp->info.script[2];
else else
init.offset = dp->info.script[3]; init.offset = outp->info.script[3];
nvbios_exec(&init); nvbios_exec(&init);
/* pre-train script */ /* pre-train script */
init.offset = dp->info.script[0]; init.offset = outp->info.script[0];
nvbios_exec(&init); nvbios_exec(&init);
} }
static void static void
dp_link_train_fini(struct dp_state *dp) 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 = { struct nvbios_init init = {
.subdev = nv_subdev(dp->disp), .subdev = nv_subdev(disp),
.bios = nouveau_bios(dp->disp), .bios = bios,
.outp = dp->outp, .outp = &outp->base.info,
.crtc = dp->head, .crtc = -1,
.execute = 1, .execute = 1,
}; };
/* post-train script */ /* post-train script */
init.offset = dp->info.script[1], init.offset = outp->info.script[1],
nvbios_exec(&init); nvbios_exec(&init);
} }
...@@ -311,65 +312,25 @@ static const struct dp_rates { ...@@ -311,65 +312,25 @@ static const struct dp_rates {
}; };
int int
nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, nouveau_dp_train(struct nvkm_output_dp *outp, u32 datarate)
struct dcb_output *outp, int head, u32 datarate)
{ {
struct nouveau_bios *bios = nouveau_bios(disp); struct nouveau_disp *disp = nouveau_disp(outp);
struct nouveau_i2c *i2c = nouveau_i2c(disp);
const struct dp_rates *cfg = nouveau_dp_rates; const struct dp_rates *cfg = nouveau_dp_rates;
struct dp_state _dp = { struct dp_state _dp = {
.disp = disp,
.func = func,
.outp = outp, .outp = outp,
.head = head,
}, *dp = &_dp; }, *dp = &_dp;
u8 hdr, cnt, len;
u32 data;
int ret; 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 */ /* bring capabilities within encoder limits */
if (nv_mclass(disp) < NVD0_DISP_CLASS) if (nv_mclass(disp) < NVD0_DISP_CLASS)
dp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
if ((dp->dpcd[2] & 0x1f) > dp->outp->dpconf.link_nr) { if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
dp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
dp->dpcd[2] |= dp->outp->dpconf.link_nr; outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
} }
if (dp->dpcd[1] > dp->outp->dpconf.link_bw) if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
dp->dpcd[1] = dp->outp->dpconf.link_bw; outp->dpcd[1] = outp->base.info.dpconf.link_bw;
dp->pc2 = dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
/* restrict link config to the lowest required rate, if requested */ /* restrict link config to the lowest required rate, if requested */
if (datarate) { if (datarate) {
...@@ -380,12 +341,12 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, ...@@ -380,12 +341,12 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
cfg--; cfg--;
/* enable down-spreading and execute pre-train script from vbios */ /* 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) { while (ret = -EIO, (++cfg)->rate) {
/* select next configuration supported by encoder and sink */ /* select next configuration supported by encoder and sink */
while (cfg->nr > (dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
cfg->bw > (dp->dpcd[DPCD_RC01_MAX_LINK_RATE])) cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
cfg++; cfg++;
dp->link_bw = cfg->bw * 27000; dp->link_bw = cfg->bw * 27000;
dp->link_nr = cfg->nr; dp->link_nr = cfg->nr;
......
...@@ -71,23 +71,4 @@ ...@@ -71,23 +71,4 @@
#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c #define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c
#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03 #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 #endif
...@@ -81,7 +81,6 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -81,7 +81,6 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
......
...@@ -1471,8 +1471,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) ...@@ -1471,8 +1471,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
break; break;
} }
nouveau_dp_train(&priv->base, priv->sor.dp, nouveau_dp_train((void *)outp, datarate);
&outp->info, head, datarate);
} }
exec_clkcmp(priv, head, 0, pclk, &conf); exec_clkcmp(priv, head, 0, pclk, &conf);
...@@ -1551,8 +1550,7 @@ nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) ...@@ -1551,8 +1550,7 @@ nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
break; break;
} }
nouveau_dp_train(&priv->base, priv->pior.dp, nouveau_dp_train((void *)outp, datarate);
&outp->info, head, datarate);
} }
} }
...@@ -1665,7 +1663,6 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1665,7 +1663,6 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense; priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
......
...@@ -45,13 +45,11 @@ struct nv50_disp_priv { ...@@ -45,13 +45,11 @@ struct nv50_disp_priv {
int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32);
int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32);
u32 lvdsconf; u32 lvdsconf;
const struct nouveau_dp_func *dp;
} sor; } sor;
struct { struct {
int nr; int nr;
int (*power)(struct nv50_disp_priv *, int ext, u32 data); int (*power)(struct nv50_disp_priv *, int ext, u32 data);
u8 type[3]; u8 type[3];
const struct nouveau_dp_func *dp;
} pior; } pior;
}; };
......
...@@ -264,7 +264,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -264,7 +264,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl; priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
......
...@@ -122,9 +122,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -122,9 +122,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense; priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl; priv->sor.hdmi = nv84_hdmi_ctrl;
priv->sor.dp = &nv94_sor_dp_func;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
......
...@@ -126,7 +126,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -126,7 +126,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl; priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
......
...@@ -96,9 +96,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -96,9 +96,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nva3_hda_eld; priv->sor.hda_eld = nva3_hda_eld;
priv->sor.hdmi = nva3_hdmi_ctrl; priv->sor.hdmi = nva3_hdmi_ctrl;
priv->sor.dp = &nv94_sor_dp_func;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
......
...@@ -1149,8 +1149,7 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) ...@@ -1149,8 +1149,7 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
break; break;
} }
nouveau_dp_train(&priv->base, priv->sor.dp, nouveau_dp_train((void *)outp, pclk);
&outp->info, head, pclk);
} }
exec_clkcmp(priv, head, 0, pclk, &conf); exec_clkcmp(priv, head, 0, pclk, &conf);
...@@ -1360,7 +1359,6 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1360,7 +1359,6 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
......
...@@ -246,7 +246,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -246,7 +246,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
......
...@@ -81,7 +81,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -81,7 +81,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
......
...@@ -48,6 +48,11 @@ int _nvkm_output_dp_fini(struct nouveau_object *, bool); ...@@ -48,6 +48,11 @@ int _nvkm_output_dp_fini(struct nouveau_object *, bool);
struct nvkm_output_dp_impl { struct nvkm_output_dp_impl {
struct nvkm_output_impl base; 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 #endif
...@@ -70,70 +70,33 @@ nv50_pior_tmds_impl = { ...@@ -70,70 +70,33 @@ nv50_pior_tmds_impl = {
* DisplayPort * DisplayPort
*****************************************************************************/ *****************************************************************************/
static struct nouveau_i2c_port *
nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp)
{
struct nouveau_i2c *i2c = nouveau_i2c(disp);
return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
}
static int static int
nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
int head, int pattern)
{ {
struct nouveau_i2c_port *port; struct nouveau_i2c_port *port = outp->base.edid;
int ret = -EINVAL; if (port && port->func->pattern)
return port->func->pattern(port, pattern);
port = nv50_pior_dp_find(disp, outp); return port ? 0 : -ENODEV;
if (port) {
if (port->func->pattern)
ret = port->func->pattern(port, pattern);
else
ret = 0;
}
return ret;
} }
static int static int
nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
int head, int lane_nr, int link_bw, bool enh)
{ {
struct nouveau_i2c_port *port; struct nouveau_i2c_port *port = outp->base.edid;
int ret = -EINVAL;
port = nv50_pior_dp_find(disp, outp);
if (port && port->func->lnk_ctl) if (port && port->func->lnk_ctl)
ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh); return port->func->lnk_ctl(port, nr, bw, ef);
return port ? 0 : -ENODEV;
return ret;
} }
static int static int
nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
int head, int lane, int vsw, int pre)
{ {
struct nouveau_i2c_port *port; struct nouveau_i2c_port *port = outp->base.edid;
int ret = -EINVAL; if (port && port->func->drv_ctl)
return port->func->drv_ctl(port, ln, vs, pe);
port = nv50_pior_dp_find(disp, outp); return port ? 0 : -ENODEV;
if (port) {
if (port->func->drv_ctl)
ret = port->func->drv_ctl(port, lane, vsw, pre);
else
ret = 0;
}
return ret;
} }
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 static int
nv50_pior_dp_ctor(struct nouveau_object *parent, nv50_pior_dp_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
...@@ -163,6 +126,9 @@ nv50_pior_dp_impl = { ...@@ -163,6 +126,9 @@ nv50_pior_dp_impl = {
.init = _nvkm_output_dp_init, .init = _nvkm_output_dp_init,
.fini = _nvkm_output_dp_fini, .fini = _nvkm_output_dp_fini,
}, },
.pattern = nv50_pior_dp_pattern,
.lnk_ctl = nv50_pior_dp_lnk_ctl,
.drv_ctl = nv50_pior_dp_drv_ctl,
}; };
/****************************************************************************** /******************************************************************************
......
...@@ -34,15 +34,15 @@ ...@@ -34,15 +34,15 @@
#include "outpdp.h" #include "outpdp.h"
static inline u32 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 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 static inline u32
...@@ -56,20 +56,18 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) ...@@ -56,20 +56,18 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
} }
static int static int
nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
int head, 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); const u32 loff = nv94_sor_loff(outp);
nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
return 0; return 0;
} }
static int static int
nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
int head, int link_nr, int link_bw, bool enh_frame)
{ {
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 soff = nv94_sor_soff(outp);
const u32 loff = nv94_sor_loff(outp); const u32 loff = nv94_sor_loff(outp);
u32 dpctrl = 0x00000000; u32 dpctrl = 0x00000000;
...@@ -77,13 +75,13 @@ nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, ...@@ -77,13 +75,13 @@ nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
u32 lane = 0; u32 lane = 0;
int i; int i;
dpctrl |= ((1 << link_nr) - 1) << 16; dpctrl |= ((1 << nr) - 1) << 16;
if (enh_frame) if (ef)
dpctrl |= 0x00004000; dpctrl |= 0x00004000;
if (link_bw > 0x06) if (bw > 0x06)
clksor |= 0x00040000; 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); lane |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
...@@ -93,24 +91,24 @@ nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, ...@@ -93,24 +91,24 @@ nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
} }
static int static int
nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
int head, int lane, int swing, int preem)
{ {
struct nouveau_bios *bios = nouveau_bios(disp); struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
struct nv50_disp_priv *priv = (void *)disp; struct nouveau_bios *bios = nouveau_bios(priv);
const u32 shift = nv94_sor_dp_lane_map(priv, lane); const u32 shift = nv94_sor_dp_lane_map(priv, ln);
const u32 loff = nv94_sor_loff(outp); const u32 loff = nv94_sor_loff(outp);
u32 addr, data[3]; u32 addr, data[3];
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
struct nvbios_dpout info; struct nvbios_dpout info;
struct nvbios_dpcfg ocfg; 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); &ver, &hdr, &cnt, &len, &info);
if (!addr) if (!addr)
return -ENODEV; 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); &ver, &hdr, &cnt, &len, &ocfg);
if (!addr) if (!addr)
return -EINVAL; return -EINVAL;
...@@ -124,13 +122,6 @@ nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, ...@@ -124,13 +122,6 @@ nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
return 0; 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 struct nvkm_output_dp_impl
nv94_sor_dp_impl = { nv94_sor_dp_impl = {
.base.base.handle = DCB_OUTPUT_DP, .base.base.handle = DCB_OUTPUT_DP,
...@@ -140,4 +131,7 @@ nv94_sor_dp_impl = { ...@@ -140,4 +131,7 @@ nv94_sor_dp_impl = {
.init = _nvkm_output_dp_init, .init = _nvkm_output_dp_init,
.fini = _nvkm_output_dp_fini, .fini = _nvkm_output_dp_fini,
}, },
.pattern = nv94_sor_dp_pattern,
.lnk_ctl = nv94_sor_dp_lnk_ctl,
.drv_ctl = nv94_sor_dp_drv_ctl,
}; };
...@@ -33,15 +33,15 @@ ...@@ -33,15 +33,15 @@
#include "nv50.h" #include "nv50.h"
static inline u32 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 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 static inline u32
...@@ -52,20 +52,18 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) ...@@ -52,20 +52,18 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
} }
static int static int
nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
int head, 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); const u32 loff = nvd0_sor_loff(outp);
nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
return 0; return 0;
} }
static int static int
nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
int head, int link_nr, int link_bw, bool enh_frame)
{ {
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 soff = nvd0_sor_soff(outp);
const u32 loff = nvd0_sor_loff(outp); const u32 loff = nvd0_sor_loff(outp);
u32 dpctrl = 0x00000000; u32 dpctrl = 0x00000000;
...@@ -73,12 +71,12 @@ nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, ...@@ -73,12 +71,12 @@ nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
u32 lane = 0; u32 lane = 0;
int i; int i;
clksor |= link_bw << 18; clksor |= bw << 18;
dpctrl |= ((1 << link_nr) - 1) << 16; dpctrl |= ((1 << nr) - 1) << 16;
if (enh_frame) if (ef)
dpctrl |= 0x00004000; 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); lane |= 1 << (nvd0_sor_dp_lane_map(priv, i) >> 3);
nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
...@@ -88,24 +86,24 @@ nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, ...@@ -88,24 +86,24 @@ nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
} }
static int static int
nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
int head, int lane, int swing, int preem)
{ {
struct nouveau_bios *bios = nouveau_bios(disp); struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
struct nv50_disp_priv *priv = (void *)disp; struct nouveau_bios *bios = nouveau_bios(priv);
const u32 shift = nvd0_sor_dp_lane_map(priv, lane); const u32 shift = nvd0_sor_dp_lane_map(priv, ln);
const u32 loff = nvd0_sor_loff(outp); const u32 loff = nvd0_sor_loff(outp);
u32 addr, data[3]; u32 addr, data[3];
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
struct nvbios_dpout info; struct nvbios_dpout info;
struct nvbios_dpcfg ocfg; 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); &ver, &hdr, &cnt, &len, &info);
if (!addr) if (!addr)
return -ENODEV; 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); &ver, &hdr, &cnt, &len, &ocfg);
if (!addr) if (!addr)
return -EINVAL; return -EINVAL;
...@@ -120,13 +118,6 @@ nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, ...@@ -120,13 +118,6 @@ nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
return 0; 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 struct nvkm_output_dp_impl
nvd0_sor_dp_impl = { nvd0_sor_dp_impl = {
.base.base.handle = DCB_OUTPUT_DP, .base.base.handle = DCB_OUTPUT_DP,
...@@ -136,4 +127,7 @@ nvd0_sor_dp_impl = { ...@@ -136,4 +127,7 @@ nvd0_sor_dp_impl = {
.init = _nvkm_output_dp_init, .init = _nvkm_output_dp_init,
.fini = _nvkm_output_dp_fini, .fini = _nvkm_output_dp_fini,
}, },
.pattern = nvd0_sor_dp_pattern,
.lnk_ctl = nvd0_sor_dp_lnk_ctl,
.drv_ctl = nvd0_sor_dp_drv_ctl,
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment