/** * struct i2c_algo_dp_aux_data - driver interface structure for i2c over dp * aux algorithm * @running: set by the algo indicating whether an i2c is ongoing or whether * the i2c bus is quiescent * @address: i2c target address for the currently ongoing transfer * @aux_ch: driver callback to transfer a single byte of the i2c payload
*/ struct i2c_algo_dp_aux_data { bool running;
u16 address; int (*aux_ch) (struct i2c_adapter *adapter, int mode, uint8_t write_byte,
uint8_t *read_byte);
};
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ staticint
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
uint8_t write_byte, uint8_t *read_byte)
{ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; int ret;
ret = (*algo_data->aux_ch)(adapter, mode,
write_byte, read_byte); return ret;
}
/* * I2C over AUX CH
*/
/* * Send the address. If the I2C link is running, this 'restarts' * the connection with the new address, this is used for doing * a write followed by a read (as needed for DDC)
*/ staticint
i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
{ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; int mode = MODE_I2C_START;
/* * Stop the I2C transaction. This closes out the link, sending * a bare address packet with the MOT bit turned off
*/ staticvoid
i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
{ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; int mode = MODE_I2C_STOP;
/* * Write a single byte to the current I2C address, the * I2C link must be running or this returns -EIO
*/ staticint
i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
{ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
/* * Read a single byte from the current I2C address, the * I2C link must be running or this returns -EIO
*/ staticint
i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
{ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
/* * FIXME: This is the old dp aux helper, gma500 is the last driver that needs to * be ported over to the new helper code in drm_dp_helper.c like i915 or radeon.
*/ staticint
i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
{ int error;
static uint32_t dp_vswing_premph_table[] = {
0x55338954, 0x4000,
0x554d8954, 0x2000,
0x55668954, 0,
0x559ac0d4, 0x6000,
}; /** * is_edp - is the given port attached to an eDP panel (either CPU or PCH) * @encoder: GMA encoder struct * * If a CPU or PCH DP output is attached to an eDP panel, this function * will return true, and false otherwise.
*/ staticbool is_edp(struct gma_encoder *encoder)
{ return encoder->type == INTEL_OUTPUT_EDP;
}
DRM_DEBUG_KMS("\n"); /* * If we enable the backlight right away following a panel power * on, we may see slight flicker as the panel syncs with the eDP * link. So delay a bit to make sure the image is solid before * allowing it to appear.
*/
msleep(300);
pp = REG_READ(PP_CONTROL);
if (is_edp(encoder) && intel_dp->panel_fixed_mode) { if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) return MODE_PANEL; if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay) return MODE_PANEL;
}
/* only refuse the mode on non eDP since we have seen some weird eDP panels
which are outside spec tolerances but somehow work by magic */ if (!is_edp(encoder) &&
(cdv_intel_dp_link_required(mode->clock, dev_priv->edp.bpp)
> cdv_intel_dp_max_data_rate(max_link_clock, max_lanes))) return MODE_CLOCK_HIGH;
if (is_edp(encoder)) { if (cdv_intel_dp_link_required(mode->clock, 24)
> cdv_intel_dp_max_data_rate(max_link_clock, max_lanes)) return MODE_CLOCK_HIGH;
} if (mode->clock < 10000) return MODE_CLOCK_LOW;
return MODE_OK;
}
static uint32_t
pack_aux(uint8_t *src, int src_bytes)
{ int i;
uint32_t v = 0;
if (src_bytes > 4)
src_bytes = 4; for (i = 0; i < src_bytes; i++)
v |= ((uint32_t) src[i]) << ((3-i) * 8); return v;
}
staticvoid
unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
{ int i; if (dst_bytes > 4)
dst_bytes = 4; for (i = 0; i < dst_bytes; i++)
dst[i] = src >> ((3-i) * 8);
}
/* The clock divider is based off the hrawclk, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that * On CDV platform it uses 200MHz as hrawclk. *
*/
aux_clock_divider = 200 / 2;
precharge = 4; if (is_edp(encoder))
precharge = 10;
if (REG_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
REG_READ(ch_ctl)); return -EBUSY;
}
/* 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)
REG_WRITE(ch_data + i,
pack_aux(send + i, send_bytes - i));
/* Send the command and wait for it to complete */
REG_WRITE(ch_ctl,
DP_AUX_CH_CTL_SEND_BUSY |
DP_AUX_CH_CTL_TIME_OUT_400us |
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
DP_AUX_CH_CTL_DONE |
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR); for (;;) {
status = REG_READ(ch_ctl); if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) break;
udelay(100);
}
/* Clear done status and any errors */
REG_WRITE(ch_ctl,
status |
DP_AUX_CH_CTL_DONE |
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR); if (status & DP_AUX_CH_CTL_DONE) break;
}
if ((status & DP_AUX_CH_CTL_DONE) == 0) {
DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status); return -EBUSY;
}
/* Check for timeout or receive error. * Timeouts occur when the sink is not connected
*/ if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status); return -EIO;
}
/* 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_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status); return -ETIMEDOUT;
}
/* Unload any bytes sent back from the other side */
recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); if (recv_bytes > recv_size)
recv_bytes = recv_size;
for (i = 0; i < recv_bytes; i += 4)
unpack_aux(REG_READ(ch_data + i),
recv + i, recv_bytes - i);
return recv_bytes;
}
/* Write data to the aux channel in native mode */ staticint
cdv_intel_dp_aux_native_write(struct gma_encoder *encoder,
uint16_t address, uint8_t *send, int send_bytes)
{ int ret;
uint8_t msg[20]; int msg_bytes;
uint8_t ack;
/* Write a single byte to the aux channel in native mode */ staticint
cdv_intel_dp_aux_native_write_1(struct gma_encoder *encoder,
uint16_t address, uint8_t byte)
{ return cdv_intel_dp_aux_native_write(encoder, address, &byte, 1);
}
/* read bytes from a native aux channel */ staticint
cdv_intel_dp_aux_native_read(struct gma_encoder *encoder,
uint16_t address, uint8_t *recv, int recv_bytes)
{
uint8_t msg[4]; int msg_bytes;
uint8_t reply[20]; int reply_bytes;
uint8_t ack; int ret;
for (retry = 0; retry < 5; retry++) {
ret = cdv_intel_dp_aux_ch(encoder,
msg, msg_bytes,
reply, reply_bytes); if (ret < 0) {
DRM_DEBUG_KMS("aux_ch failed %d\n", ret); return ret;
}
switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) { case DP_AUX_NATIVE_REPLY_ACK: /* I2C-over-AUX Reply field is only valid * when paired with AUX ACK.
*/ break; case DP_AUX_NATIVE_REPLY_NACK:
DRM_DEBUG_KMS("aux_ch native nack\n"); return -EREMOTEIO; case DP_AUX_NATIVE_REPLY_DEFER:
udelay(100); continue; default:
DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
reply[0]); return -EREMOTEIO;
}
if (is_edp(encoder))
cdv_intel_edp_panel_vdd_on(encoder);
ret = i2c_dp_aux_add_bus(&intel_dp->adapter); if (is_edp(encoder))
cdv_intel_edp_panel_vdd_off(encoder);
/* * Compute the GMCH and Link ratios. The '3' here is * the number of bytes_per_pixel post-LUT, which we always * set up for 8-bits of R/G/B, or 3 bytes total.
*/
cdv_intel_dp_compute_m_n(bpp, lane_count,
mode->clock, adjusted_mode->clock, &m_n);
/* If the sink supports it, try to set the power state appropriately */ staticvoid cdv_intel_dp_sink_dpms(struct gma_encoder *encoder, int mode)
{ struct cdv_intel_dp *intel_dp = encoder->dev_priv; int ret, i;
/* Should have a valid DPCD by this point */ if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) return;
if (mode != DRM_MODE_DPMS_ON) {
ret = cdv_intel_dp_aux_native_write_1(encoder, DP_SET_POWER,
DP_SET_POWER_D3); if (ret != 1)
DRM_DEBUG_DRIVER("failed to write sink power state\n");
} else { /* * When turning on, we need to retry for 1ms to give the sink * time to wake up.
*/ for (i = 0; i < 3; i++) {
ret = cdv_intel_dp_aux_native_write_1(encoder,
DP_SET_POWER,
DP_SET_POWER_D0); if (ret == 1) break;
udelay(1000);
}
}
}
if (edp) {
cdv_intel_edp_backlight_off(intel_encoder);
cdv_intel_edp_panel_off(intel_encoder);
cdv_intel_edp_panel_vdd_on(intel_encoder);
} /* Wake up the sink first */
cdv_intel_dp_sink_dpms(intel_encoder, DRM_MODE_DPMS_ON);
cdv_intel_dp_link_down(intel_encoder); if (edp)
cdv_intel_edp_panel_vdd_off(intel_encoder);
}
if (edp)
cdv_intel_edp_panel_on(intel_encoder);
cdv_intel_dp_start_link_train(intel_encoder);
cdv_intel_dp_complete_link_train(intel_encoder); if (edp)
cdv_intel_edp_backlight_on(intel_encoder);
}
if (mode != DRM_MODE_DPMS_ON) { if (edp) {
cdv_intel_edp_backlight_off(intel_encoder);
cdv_intel_edp_panel_vdd_on(intel_encoder);
}
cdv_intel_dp_sink_dpms(intel_encoder, mode);
cdv_intel_dp_link_down(intel_encoder); if (edp) {
cdv_intel_edp_panel_vdd_off(intel_encoder);
cdv_intel_edp_panel_off(intel_encoder);
}
} else { if (edp)
cdv_intel_edp_panel_on(intel_encoder);
cdv_intel_dp_sink_dpms(intel_encoder, mode); if (!(dp_reg & DP_PORT_EN)) {
cdv_intel_dp_start_link_train(intel_encoder);
cdv_intel_dp_complete_link_train(intel_encoder);
} if (edp)
cdv_intel_edp_backlight_on(intel_encoder);
}
}
/* * Native read with retry for link status and receiver capability reads for * cases where the sink may still be asleep.
*/ staticbool
cdv_intel_dp_aux_native_read_retry(struct gma_encoder *encoder, uint16_t address,
uint8_t *recv, int recv_bytes)
{ int ret, i;
/* * Sinks are *supposed* to come up within 1ms from an off state, * but we're also supposed to retry 3 times per the spec.
*/ for (i = 0; i < 3; i++) {
ret = cdv_intel_dp_aux_native_read(encoder, address, recv,
recv_bytes); if (ret == recv_bytes) returntrue;
udelay(1000);
}
returnfalse;
}
/* * Fetch AUX CH registers 0x202 - 0x207 which contain * link status information
*/ staticbool
cdv_intel_dp_get_link_status(struct gma_encoder *encoder)
{ struct cdv_intel_dp *intel_dp = encoder->dev_priv; return cdv_intel_dp_aux_native_read_retry(encoder,
DP_LANE0_1_STATUS,
intel_dp->link_status,
DP_LINK_STATUS_SIZE);
}
static uint8_t
cdv_intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane)
{ int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); int s = ((lane & 1) ?
DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
uint8_t l = cdv_intel_dp_link_status(link_status, i);
static uint8_t
cdv_intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane)
{ int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); int s = ((lane & 1) ?
DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
uint8_t l = cdv_intel_dp_link_status(link_status, i);
staticvoid
cdv_intel_get_adjust_train(struct gma_encoder *encoder)
{ struct cdv_intel_dp *intel_dp = encoder->dev_priv;
uint8_t v = 0;
uint8_t p = 0; int lane;
for (lane = 0; lane < intel_dp->lane_count; lane++) {
uint8_t this_v = cdv_intel_get_adjust_request_voltage(intel_dp->link_status, lane);
uint8_t this_p = cdv_intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
if (this_v > v)
v = this_v; if (this_p > p)
p = this_p;
}
if (v >= CDV_DP_VOLTAGE_MAX)
v = CDV_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
if (p == DP_TRAIN_PRE_EMPHASIS_MASK)
p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
for (lane = 0; lane < 4; lane++)
intel_dp->train_set[lane] = v | p;
}
static uint8_t
cdv_intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane)
{ int i = DP_LANE0_1_STATUS + (lane >> 1); int s = (lane & 1) * 4;
uint8_t l = cdv_intel_dp_link_status(link_status, i);
return (l >> s) & 0xf;
}
/* Check for clock recovery is done on all channels */ staticbool
cdv_intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
{ int lane;
uint8_t lane_status;
for (lane = 0; lane < lane_count; lane++) {
lane_status = cdv_intel_get_lane_status(link_status, lane); if ((lane_status & DP_LANE_CR_DONE) == 0) returnfalse;
} returntrue;
}
/* Check to see if channel eq is done on all channels */ #define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
DP_LANE_CHANNEL_EQ_DONE|\
DP_LANE_SYMBOL_LOCKED) staticbool
cdv_intel_channel_eq_ok(struct gma_encoder *encoder)
{ struct cdv_intel_dp *intel_dp = encoder->dev_priv;
uint8_t lane_align;
uint8_t lane_status; int lane;
lane_align = cdv_intel_dp_link_status(intel_dp->link_status,
DP_LANE_ALIGN_STATUS_UPDATED); if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) returnfalse; for (lane = 0; lane < intel_dp->lane_count; lane++) {
lane_status = cdv_intel_get_lane_status(intel_dp->link_status, lane); if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) returnfalse;
} returntrue;
}
/* ;gfx_dpio_set_reg(0x8148, 0x55338954) * The VSwing_PreEmph table is also considered based on the vswing/premp
*/
index = (vswing + premph) * 2; if (premph == 1 && vswing == 1) {
cdv_sb_write(dev, ddi_reg->VSwing2, 0x055738954);
} else
cdv_sb_write(dev, ddi_reg->VSwing2, dp_vswing_premph_table[index]);
/* Enable corresponding port and start training pattern 1 */ staticvoid
cdv_intel_dp_start_link_train(struct gma_encoder *encoder)
{ struct drm_device *dev = encoder->base.dev; struct cdv_intel_dp *intel_dp = encoder->dev_priv; int i;
uint8_t voltage; bool clock_recovery = false; int tries;
u32 reg;
uint32_t DP = intel_dp->DP;
DP |= DP_PORT_EN;
DP &= ~DP_LINK_TRAIN_MASK;
reg = DP;
reg |= DP_LINK_TRAIN_PAT_1; /* Enable output, wait for it to become active */
REG_WRITE(intel_dp->output_reg, reg);
REG_READ(intel_dp->output_reg);
gma_wait_for_vblank(dev);
DRM_DEBUG_KMS("Link config\n"); /* Write the link configuration data */
cdv_intel_dp_aux_native_write(encoder, DP_LINK_BW_SET,
intel_dp->link_configuration,
2);
for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
intel_dp->train_set[0],
intel_dp->link_configuration[0],
intel_dp->link_configuration[1]);
if (!cdv_intel_dp_set_link_train(encoder, reg, DP_TRAINING_PATTERN_1)) {
DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 1\n");
}
cdv_intel_dp_set_vswing_premph(encoder, intel_dp->train_set[0]); /* Set training pattern 1 */
udelay(200); if (!cdv_intel_dp_get_link_status(encoder)) break;
DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
if (cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
DRM_DEBUG_KMS("PT1 train is done\n");
clock_recovery = true; break;
}
/* Check to see if we've tried the max voltage */ for (i = 0; i < intel_dp->lane_count; i++) if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; if (i == intel_dp->lane_count) break;
/* Check to see if we've tried the same voltage 5 times */ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
++tries; if (tries == 5) break;
} else
tries = 0;
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Compute new intel_dp->train_set as requested by target */
cdv_intel_get_adjust_train(encoder);
}
if (!clock_recovery) {
DRM_DEBUG_KMS("failure in DP pattern 1 training, train set %x\n", intel_dp->train_set[0]);
}
DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
intel_dp->train_set[0],
intel_dp->link_configuration[0],
intel_dp->link_configuration[1]); /* channel eq pattern */
if (!cdv_intel_dp_set_link_train(encoder, reg,
DP_TRAINING_PATTERN_2)) {
DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 2\n");
} /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
if (cr_tries > 5) {
DRM_ERROR("failed to train DP, aborting\n");
cdv_intel_dp_link_down(encoder); break;
}
udelay(1000); if (!cdv_intel_dp_get_link_status(encoder)) break;
DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
/* Make sure clock is still ok */ if (!cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
cdv_intel_dp_start_link_train(encoder);
cr_tries++; continue;
}
if (cdv_intel_channel_eq_ok(encoder)) {
DRM_DEBUG_KMS("PT2 train is done\n"); break;
}
/* Try 5 times, then try clock recovery if that fails */ if (tries > 5) {
cdv_intel_dp_link_down(encoder);
cdv_intel_dp_start_link_train(encoder);
tries = 0;
cr_tries++; continue;
}
/* Compute new intel_dp->train_set as requested by target */
cdv_intel_get_adjust_train(encoder);
++tries;
status = connector_status_disconnected; if (cdv_intel_dp_aux_native_read(encoder, 0x000, intel_dp->dpcd, sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
{ if (intel_dp->dpcd[DP_DPCD_REV] != 0)
status = connector_status_connected;
} if (status == connector_status_connected)
DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
intel_dp->dpcd[0], intel_dp->dpcd[1],
intel_dp->dpcd[2], intel_dp->dpcd[3]); return status;
}
/* * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. * * \return true if DP port is connected. * \return false if DP port is disconnected.
*/ staticenum drm_connector_status
cdv_intel_dp_detect(struct drm_connector *connector, bool force)
{ struct gma_encoder *encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = encoder->dev_priv; enum drm_connector_status status; struct edid *edid = NULL; int edp = is_edp(encoder);
intel_dp->has_audio = false;
if (edp)
cdv_intel_edp_panel_vdd_on(encoder);
status = cdv_dp_detect(encoder); if (status != connector_status_connected) { if (edp)
cdv_intel_edp_panel_vdd_off(encoder); return status;
}
if (intel_dp->force_audio) {
intel_dp->has_audio = intel_dp->force_audio > 0;
} else {
edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) {
intel_dp->has_audio = drm_detect_monitor_audio(edid);
kfree(edid);
}
} if (edp)
cdv_intel_edp_panel_vdd_off(encoder);
return connector_status_connected;
}
staticint cdv_intel_dp_get_modes(struct drm_connector *connector)
{ struct gma_encoder *intel_encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; struct edid *edid = NULL; int ret = 0; int edp = is_edp(intel_encoder);
edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) {
drm_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
}
/* check the VBT to see whether the eDP is on DP-D port */ staticbool cdv_intel_dpc_is_edp(struct drm_device *dev)
{ struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct child_device_config *p_child; int i;
if (!dev_priv->child_dev_num) returnfalse;
for (i = 0; i < dev_priv->child_dev_num; i++) {
p_child = dev_priv->child_dev + i;
We need this disable dot get correct behaviour while enabling DP/eDP. TODO - investigate if we can turn it back to normality
after enabling */ staticvoid cdv_disable_intel_clock_gating(struct drm_device *dev)
{
u32 reg_value;
reg_value = REG_READ(DSPCLK_GATE_D);
/* Set up the DDC bus. */ switch (output_reg) { case DP_B:
name = "DPDDC-B";
gma_encoder->ddi_select = (DP_MASK | DDI0_SELECT); break; case DP_C:
name = "DPDDC-C";
gma_encoder->ddi_select = (DP_MASK | DDI1_SELECT); break;
}
DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
intel_dp->panel_power_cycle_delay);
DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
cdv_intel_edp_panel_vdd_on(gma_encoder);
ret = cdv_intel_dp_aux_native_read(gma_encoder, DP_DPCD_REV,
intel_dp->dpcd, sizeof(intel_dp->dpcd));
cdv_intel_edp_panel_vdd_off(gma_encoder); if (ret <= 0) { /* if this fails, presume the device is a ghost */
DRM_INFO("failed to retrieve link info, disabling eDP\n");
drm_encoder_cleanup(encoder);
cdv_intel_dp_destroy(connector); goto err_connector;
} else {
DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
intel_dp->dpcd[0], intel_dp->dpcd[1],
intel_dp->dpcd[2], intel_dp->dpcd[3]);
} /* The CDV reference driver moves pnale backlight setup into the displays that have a backlight: this is a good idea and one we should probably adopt, however
we need to migrate all the drivers before we can do that */ /*cdv_intel_panel_setup_backlight(dev); */
} return;
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.