/* * Copyright 2014 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Ben Skeggs
*/ #include"dp.h" #include"conn.h" #include"head.h" #include"ior.h"
/* IED scripts are no longer used by UEFI/RM from Ampere, but have been updated for * the x86 option ROM. However, the relevant VBIOS table versions weren't modified, * so we're unable to detect this in a nice way.
*/ #define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100)
ret = nvkm_wraux(outp->dp.aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); if (ret) return ret;
}
/* Attempt to train the link in this configuration. */ for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) { if (lt.repeater)
OUTP_DBG(outp, "training LTTPR%d", lt.repeater); else
OUTP_DBG(outp, "training sink");
memset(lt.stat, 0x00, sizeof(lt.stat));
ret = nvkm_dp_train_cr(<); if (ret == 0)
ret = nvkm_dp_train_eq(<);
nvkm_dp_train_pattern(<, 0);
}
OUTP_DBG(outp, "programming link for %dx%02x", ior->dp.nr, ior->dp.bw);
/* Intersect misc. capabilities of the OR and sink. */ if (disp->engine.subdev.device->chipset < 0x110)
outp->dp.dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED; if (disp->engine.subdev.device->chipset < 0xd0)
outp->dp.dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
if (AMPERE_IED_HACK(disp) && (lnkcmp = outp->dp.info.script[0])) { /* Execute BeforeLinkTraining script from DP Info table. */ while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
lnkcmp += 3;
lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
if (WARN_ON(rate == outp->dp.rates)) return -EINVAL;
/* Retraining link? Skip source configuration, it can mess up the active modeset. */ if (retrain) {
mutex_lock(&outp->dp.mutex);
ret = nvkm_dp_train_link(outp, rate);
mutex_unlock(&outp->dp.mutex); return ret;
}
if (auxpwr && !outp->dp.aux_pwr) { /* eDP panels need powering on by us (if the VBIOS doesn't default it * to on) before doing any AUX channel transactions. LVDS panel power * is handled by the SOR itself, and not required for LVDS DDC.
*/ if (outp->conn->info.type == DCB_CONNECTOR_eDP) { int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); if (power == 0) {
nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
outp->dp.aux_pwr_pu = true;
}
/* We delay here unconditionally, even if already powered, * because some laptop panels having a significant resume * delay before the panel begins responding. * * This is likely a bit of a hack, but no better idea for * handling this at the moment.
*/
msleep(300);
}
OUTP_DBG(outp, "aux power -> always");
nvkm_i2c_aux_monitor(aux, true);
outp->dp.aux_pwr = true;
} else if (!auxpwr && outp->dp.aux_pwr) {
OUTP_DBG(outp, "aux power -> demand");
nvkm_i2c_aux_monitor(aux, false);
outp->dp.aux_pwr = false;
/* Restore eDP panel GPIO to its prior state if we changed it, as * it could potentially interfere with other outputs.
*/ if (outp->conn->info.type == DCB_CONNECTOR_eDP) { if (outp->dp.aux_pwr_pu) {
nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0);
outp->dp.aux_pwr_pu = false;
}
}
}
}
ret = nvkm_outp_new_(&nvkm_dp_func, disp, index, dcbE, poutp);
outp = *poutp; if (ret) return ret;
if (dcbE->location == 0)
outp->dp.aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_CCB(dcbE->i2c_index)); else
outp->dp.aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); if (!outp->dp.aux) {
OUTP_ERR(outp, "no aux"); return -EINVAL;
}
/* bios data is not optional */
data = nvbios_dpout_match(bios, outp->info.hasht, outp->info.hashm,
&outp->dp.version, &hdr, &cnt, &len, &outp->dp.info); if (!data) {
OUTP_ERR(outp, "no bios dp data"); return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.