/* * The clock divider is based off the hrawclk, and would like to run at * 2MHz. So, take the hrawclk value and divide by 2000 and use that
*/ return DIV_ROUND_CLOSEST(DISPLAY_RUNTIME_INFO(display)->rawclk_freq, 2000);
}
/* * The clock divider is based off the cdclk or PCH rawclk, and would * like to run at 2MHz. So, take the cdclk or PCH rawclk value and * divide by 2000 and use that
*/ if (dig_port->aux_ch == AUX_CH_A)
freq = display->cdclk.hw.cdclk; else
freq = DISPLAY_RUNTIME_INFO(display)->rawclk_freq; return DIV_ROUND_CLOSEST(freq, 2000);
}
static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
{ /* * SKL doesn't need us to program the AUX clock divider (Hardware will * derive the clock from CDCLK automatically). We still implement the * get_aux_clock_divider vfunc to plug-in into the existing code.
*/ return index ? 0 : 1;
}
staticint intel_dp_aux_sync_len(void)
{ int precharge = 16; /* 10-16 */ int preamble = 16;
return precharge + preamble;
}
int intel_dp_aux_fw_sync_len(struct intel_dp *intel_dp)
{ int precharge = 10; /* 10-16 */ int preamble = 8;
/* * We faced some glitches on Dell Precision 5490 MTL laptop with panel: * "Manufacturer: AUO, Model: 63898" when using HW default 18. Using 20 * is fixing these problems with the panel. It is still within range * mentioned in eDP specification. Increasing Fast Wake sync length is * causing problems with other panels: increase length as a quirk for * this specific laptop.
*/ if (intel_has_dpcd_quirk(intel_dp, QUIRK_FW_SYNC_LEN))
precharge += 2;
return precharge + preamble;
}
staticint g4x_dp_aux_precharge_len(void)
{ int precharge_min = 10; int preamble = 16;
/* HW wants the length of the extra precharge in 2us units */ return (intel_dp_aux_sync_len() -
precharge_min - preamble) / 2;
}
/* Max timeout value on G4x-BDW: 1.6ms */ if (display->platform.broadwell)
timeout = DP_AUX_CH_CTL_TIME_OUT_600us; else
timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
if (intel_tc_port_in_tbt_alt_mode(dig_port))
ret |= DP_AUX_CH_CTL_TBT_IO;
/* * Power request bit is already set during aux power well enable. * Preserve the bit across aux transactions.
*/ if (DISPLAY_VER(display) >= 14)
ret |= XELPDP_DP_AUX_CH_CTL_POWER_REQUEST;
ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp); for (i = 0; i < ARRAY_SIZE(ch_data); i++)
ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
intel_digital_port_lock(encoder); /* * Abort transfers on a disconnected port as required by * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX * timeouts that would otherwise happen.
*/ if (!intel_dp_is_edp(intel_dp) &&
!intel_digital_port_connected_locked(&dig_port->base)) {
ret = -ENXIO; goto out_unlock;
}
/* * The PPS state needs to be locked for: * - eDP on all platforms, since AUX transfers on eDP need VDD power * (either forced or via panel power) which depends on the PPS * state. * - non-eDP on platforms where the PPS is a pipe instance (VLV/CHV), * since changing the PPS state (via a parallel modeset for * instance) may interfere with the AUX transfers on a non-eDP * output as well.
*/ if (intel_dp_is_edp(intel_dp) ||
display->platform.valleyview || display->platform.cherryview)
pps_wakeref = intel_pps_lock(intel_dp);
/* * We will be called with VDD already enabled for dpcd/edid/oui reads. * In such cases we want to leave VDD enabled and it's up to upper layers * to turn it off. But for eg. i2c-dev access we need to turn it on/off * ourselves.
*/
vdd = intel_pps_vdd_on_unlocked(intel_dp);
/* * dp aux is extremely sensitive to irq latency, hence request the * lowest possible wakeup latency and so prevent the cpu from going into * deep sleep states.
*/
cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
intel_pps_check_power_unlocked(intel_dp);
/* * FIXME PSR should be disabled here to prevent * it using the same AUX CH simultaneously
*/
/* Try to wait for any previous AUX channel activity */ for (try = 0; try < 3; try++) {
status = intel_de_read_notrace(display, ch_ctl); if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) break;
msleep(1);
} /* just trace the final value */
trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
if (try == 3) { const u32 status = intel_de_read(display, ch_ctl);
if (status != intel_dp->aux_busy_last_status) {
drm_WARN(display->drm, 1, "%s: not started (status 0x%08x)\n",
intel_dp->aux.name, status);
intel_dp->aux_busy_last_status = status;
}
ret = -EBUSY; goto out;
}
/* Only 5 data registers! */ if (drm_WARN_ON(display->drm, send_bytes > 20 || recv_size > 20)) {
ret = -E2BIG; goto out;
}
/* Must try at least 3 times according to DP spec */ for (try = 0; try < 5; try++) { /* Load the send data into the aux channel data registers */ for (i = 0; i < send_bytes; i += 4)
intel_de_write(display, ch_data[i >> 2],
intel_dp_aux_pack(send + i,
send_bytes - i));
/* Send the command and wait for it to complete */
intel_de_write(display, ch_ctl, send_ctl);
status = intel_dp_aux_wait_done(intel_dp);
/* Clear done status and any errors */
intel_de_write(display, ch_ctl,
status | DP_AUX_CH_CTL_DONE |
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR);
/* * DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2 * 400us delay required for errors and timeouts * Timeout errors from the HW already meet this * requirement so skip to next iteration
*/ if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) continue;
if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
usleep_range(400, 500); continue;
} if (status & DP_AUX_CH_CTL_DONE) goto done;
}
}
if ((status & DP_AUX_CH_CTL_DONE) == 0) {
drm_err(display->drm, "%s: not done (status 0x%08x)\n",
intel_dp->aux.name, status);
ret = -EBUSY; goto out;
}
done: /* * Check for timeout or receive error. Timeouts occur when the sink is * not connected.
*/ if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
drm_err(display->drm, "%s: receive error (status 0x%08x)\n",
intel_dp->aux.name, status);
ret = -EIO; goto out;
}
/* * Timeouts occur when the device isn't connected, so they're "normal" * -- don't fill the kernel log with these
*/ if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
drm_dbg_kms(display->drm, "%s: timeout (status 0x%08x)\n",
intel_dp->aux.name, status);
ret = -ETIMEDOUT; goto out;
}
/* Unload any bytes sent back from the other side */
recv_bytes = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, status);
/* * By BSpec: "Message sizes of 0 or >20 are not allowed." * We have no idea of what happened so we return -EBUSY so * drm layer takes care for the necessary retries.
*/ if (recv_bytes == 0 || recv_bytes > 20) {
drm_dbg_kms(display->drm, "%s: Forbidden recv_bytes = %d on aux transaction\n",
intel_dp->aux.name, recv_bytes);
ret = -EBUSY; goto out;
}
if (recv_bytes > recv_size)
recv_bytes = recv_size;
for (i = 0; i < recv_bytes; i += 4)
intel_dp_aux_unpack(intel_de_read(display, ch_data[i >> 2]),
recv + i, recv_bytes - i);
ret = recv_bytes;
out:
cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
if (vdd)
intel_pps_vdd_off_unlocked(intel_dp, false);
if (pps_wakeref)
intel_pps_unlock(intel_dp, pps_wakeref);
static u32 intel_dp_aux_xfer_flags(conststruct drm_dp_aux_msg *msg)
{ /* * If we're trying to send the HDCP Aksv, we need to set a the Aksv * select bit to inform the hardware to send the Aksv after our header * since we can't access that data from software.
*/ if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
msg->address == DP_AUX_HDCP_AKSV) return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
if (msg->buffer)
memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
rxbuf, rxsize, flags); if (ret > 0) {
msg->reply = rxbuf[0] >> 4;
if (ret > 1) { /* Number of bytes written in a short write. */
ret = clamp_t(int, rxbuf[1], 0, msg->size);
} else { /* Return payload size. */
ret = msg->size;
}
} break;
case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ:
txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
rxsize = msg->size + 1;
if (drm_WARN_ON(display->drm, rxsize > 20)) return -E2BIG;
ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
rxbuf, rxsize, flags); if (ret > 0) {
msg->reply = rxbuf[0] >> 4; /* * Assume happy day, and copy the data. The caller is * expected to check msg->reply before touching it. * * Return payload size.
*/
ret--;
memcpy(msg->buffer, rxbuf + 1, ret);
} break;
switch (aux_ch) { case AUX_CH_A: case AUX_CH_B: case AUX_CH_C: case AUX_CH_D: case AUX_CH_E: case AUX_CH_F: return DP_AUX_CH_CTL(aux_ch); default:
MISSING_CASE(aux_ch); return DP_AUX_CH_CTL(AUX_CH_A);
}
}
switch (aux_ch) { case AUX_CH_A: case AUX_CH_B: case AUX_CH_C: case AUX_CH_D: case AUX_CH_E: case AUX_CH_F: return DP_AUX_CH_DATA(aux_ch, index); default:
MISSING_CASE(aux_ch); return DP_AUX_CH_DATA(AUX_CH_A, index);
}
}
switch (aux_ch) { case AUX_CH_A: case AUX_CH_B: case AUX_CH_C: case AUX_CH_USBC1: case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: case AUX_CH_USBC5: /* aka AUX_CH_D_XELPD */ case AUX_CH_USBC6: /* aka AUX_CH_E_XELPD */ return DP_AUX_CH_CTL(aux_ch); default:
MISSING_CASE(aux_ch); return DP_AUX_CH_CTL(AUX_CH_A);
}
}
switch (aux_ch) { case AUX_CH_A: case AUX_CH_B: case AUX_CH_C: case AUX_CH_USBC1: case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: case AUX_CH_USBC5: /* aka AUX_CH_D_XELPD */ case AUX_CH_USBC6: /* aka AUX_CH_E_XELPD */ return DP_AUX_CH_DATA(aux_ch, index); default:
MISSING_CASE(aux_ch); return DP_AUX_CH_DATA(AUX_CH_A, index);
}
}
switch (aux_ch) { case AUX_CH_A: case AUX_CH_B: case AUX_CH_USBC1: case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: return XELPDP_DP_AUX_CH_CTL(display, aux_ch); default:
MISSING_CASE(aux_ch); return XELPDP_DP_AUX_CH_CTL(display, AUX_CH_A);
}
}
switch (aux_ch) { case AUX_CH_A: case AUX_CH_B: case AUX_CH_USBC1: case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: return XELPDP_DP_AUX_CH_DATA(display, aux_ch, index); default:
MISSING_CASE(aux_ch); return XELPDP_DP_AUX_CH_DATA(display, AUX_CH_A, index);
}
}
void intel_dp_aux_fini(struct intel_dp *intel_dp)
{ if (cpu_latency_qos_request_active(&intel_dp->pm_qos))
cpu_latency_qos_remove_request(&intel_dp->pm_qos);
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.