int nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) { struct nvkm_output_dp *outp = (void *)base; bool retrain = true; u8 link[2], stat[3]; u32 linkrate; int ret, i; /* check that the link is trained at a high enough rate */ ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { DBG("failed to read link config, assuming no sink\n"); goto done; } linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET); linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ datarate = (datarate + 9) / 10; /* -> decakilobits */ if (linkrate < datarate) { DBG("link not trained at sufficient rate\n"); goto done; } /* check that link is still trained */ ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3); if (ret) { DBG("failed to read link status, assuming no sink\n"); goto done; } if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) { for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) { u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f; if (!(lane & DPCD_LS02_LANE0_CR_DONE) || !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { DBG("lane %d not equalised\n", lane); goto done; } } retrain = false; } else {
static void nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch, u8 *dpcd) { struct nouveau_drm *drm = nouveau_drm(dev); u8 buf[3]; if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; if (!nv_rdaux(auxch, DP_SINK_OUI, buf, 3)) NV_DEBUG(drm, "Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); if (!nv_rdaux(auxch, DP_BRANCH_OUI, buf, 3)) NV_DEBUG(drm, "Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); }
static int init_rdauxr(struct nvbios_init *init, u32 addr) { struct nouveau_i2c_port *port = init_i2c(init, -2); u8 data; if (port && init_exec(init)) { int ret = nv_rdaux(port, addr, &data, 1); if (ret) return ret; return data; } return -ENODEV; }
int nouveau_dp_detect(struct nouveau_encoder *nv_encoder) { struct drm_device *dev = nv_encoder->base.base.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_i2c_port *auxch; u8 *dpcd = nv_encoder->dp.dpcd; int ret; auxch = nv_encoder->i2c; if (!auxch) return -ENODEV; ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8); if (ret) return ret; nv_encoder->dp.link_bw = 27000 * dpcd[1]; nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]); NV_DEBUG(drm, "encoder: %dx%d\n", nv_encoder->dcb->dpconf.link_nr, nv_encoder->dcb->dpconf.link_bw); if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr) nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw) nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw; NV_DEBUG(drm, "maximum: %dx%d\n", nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); nouveau_dp_probe_oui(dev, auxch, dpcd); return 0; }