提交 3b52a1f9 编写于 作者: B Ben Skeggs

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

Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
上级 2bd651ea
......@@ -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;
......
......@@ -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
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
};
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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
......@@ -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,
};
/******************************************************************************
......
......@@ -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,
};
......@@ -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,
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册