summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-19 14:06:07 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 16:02:09 +1000
commit2863cf0d5b0af65c90f90897e8ff3d5483fe40fd (patch)
tree9b47583e4ad1556c225e4dbe4879c7f13e59dfbd
parent8d5320e2cc2ebe96c0e24d21f39e9e5ad5f63656 (diff)
disp/dp: make use of existing output data for link training
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--nvkm/engine/disp/dport.c167
-rw-r--r--nvkm/engine/disp/dport.h19
-rw-r--r--nvkm/engine/disp/gm107.c1
-rw-r--r--nvkm/engine/disp/nv50.c7
-rw-r--r--nvkm/engine/disp/nv50.h2
-rw-r--r--nvkm/engine/disp/nv84.c1
-rw-r--r--nvkm/engine/disp/nv94.c2
-rw-r--r--nvkm/engine/disp/nva0.c1
-rw-r--r--nvkm/engine/disp/nva3.c2
-rw-r--r--nvkm/engine/disp/nvd0.c4
-rw-r--r--nvkm/engine/disp/nve0.c1
-rw-r--r--nvkm/engine/disp/nvf0.c1
-rw-r--r--nvkm/engine/disp/outpdp.h5
-rw-r--r--nvkm/engine/disp/piornv50.c68
-rw-r--r--nvkm/engine/disp/sornv94.c50
-rw-r--r--nvkm/engine/disp/sornvd0.c50
16 files changed, 133 insertions, 248 deletions
diff --git a/nvkm/engine/disp/dport.c b/nvkm/engine/disp/dport.c
index 3814c3d3..efccbabc 100644
--- a/nvkm/engine/disp/dport.c
+++ b/nvkm/engine/disp/dport.c
@@ -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];
@@ -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/nvkm/engine/disp/dport.h b/nvkm/engine/disp/dport.h
index 436358e5..2712e31c 100644
--- a/nvkm/engine/disp/dport.h
+++ b/nvkm/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/nvkm/engine/disp/gm107.c b/nvkm/engine/disp/gm107.c
index a5b0ad6d..9fc7447f 100644
--- a/nvkm/engine/disp/gm107.c
+++ b/nvkm/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/nvkm/engine/disp/nv50.c b/nvkm/engine/disp/nv50.c
index d2553c91..2b9ef826 100644
--- a/nvkm/engine/disp/nv50.c
+++ b/nvkm/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/nvkm/engine/disp/nv50.h b/nvkm/engine/disp/nv50.h
index d5468a61..67ad3f1f 100644
--- a/nvkm/engine/disp/nv50.h
+++ b/nvkm/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/nvkm/engine/disp/nv84.c b/nvkm/engine/disp/nv84.c
index 436f0a5e..1cc62e43 100644
--- a/nvkm/engine/disp/nv84.c
+++ b/nvkm/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/nvkm/engine/disp/nv94.c b/nvkm/engine/disp/nv94.c
index 14f53143..240b69a8 100644
--- a/nvkm/engine/disp/nv94.c
+++ b/nvkm/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/nvkm/engine/disp/nva0.c b/nvkm/engine/disp/nva0.c
index b8926200..6237a9a3 100644
--- a/nvkm/engine/disp/nva0.c
+++ b/nvkm/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/nvkm/engine/disp/nva3.c b/nvkm/engine/disp/nva3.c
index aae561ff..705c6784 100644
--- a/nvkm/engine/disp/nva3.c
+++ b/nvkm/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/nvkm/engine/disp/nvd0.c b/nvkm/engine/disp/nvd0.c
index 27ec9954..77e7ade1 100644
--- a/nvkm/engine/disp/nvd0.c
+++ b/nvkm/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/nvkm/engine/disp/nve0.c b/nvkm/engine/disp/nve0.c
index 90f79be9..11328e3f 100644
--- a/nvkm/engine/disp/nve0.c
+++ b/nvkm/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/nvkm/engine/disp/nvf0.c b/nvkm/engine/disp/nvf0.c
index 25a18dff..10438808 100644
--- a/nvkm/engine/disp/nvf0.c
+++ b/nvkm/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/nvkm/engine/disp/outpdp.h b/nvkm/engine/disp/outpdp.h
index 228b5d84..ab328dca 100644
--- a/nvkm/engine/disp/outpdp.h
+++ b/nvkm/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/nvkm/engine/disp/piornv50.c b/nvkm/engine/disp/piornv50.c
index 2c1eacd8..491e4d83 100644
--- a/nvkm/engine/disp/piornv50.c
+++ b/nvkm/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)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(disp);
- return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
-}
-
static int
-nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp,
- int head, int pattern)
+nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
{
- 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;
+ 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_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
- int head, int lane_nr, int link_bw, bool enh)
+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);
+ 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/nvkm/engine/disp/sornv94.c b/nvkm/engine/disp/sornv94.c
index ca551eab..5ee9a12b 100644
--- a/nvkm/engine/disp/sornv94.c
+++ b/nvkm/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/nvkm/engine/disp/sornvd0.c b/nvkm/engine/disp/sornvd0.c
index ffd4531d..c3120a76 100644
--- a/nvkm/engine/disp/sornvd0.c
+++ b/nvkm/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,
};