static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux, const u8 *buffer, ssize_t len) { int ret; u32 val = 0; u32 retry; u16 reg; const u8 *data = buffer; reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET; while (val < len) { /* DPCD write for AVI IF can fail on a slow FW day, so retry */ for (retry = 0; retry < 5; retry++) { ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1); if (ret == 1) { break; } else if (retry < 4) { mdelay(50); continue; } else { DRM_ERROR("DPCD write failed at:0x%x\n", reg); return false; } } val++; reg++; data++; } val = 0; reg = LSPCON_MCA_AVI_IF_CTRL; ret = drm_dp_dpcd_read(aux, reg, &val, 1); if (ret < 0) { DRM_ERROR("DPCD read failed, address 0x%x\n", reg); return false; } /* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */ val &= ~LSPCON_MCA_AVI_IF_HANDLED; val |= LSPCON_MCA_AVI_IF_KICKOFF; ret = drm_dp_dpcd_write(aux, reg, &val, 1); if (ret < 0) { DRM_ERROR("DPCD read failed, address 0x%x\n", reg); return false; } val = 0; ret = drm_dp_dpcd_read(aux, reg, &val, 1); if (ret < 0) { DRM_ERROR("DPCD read failed, address 0x%x\n", reg); return false; } if (val == LSPCON_MCA_AVI_IF_HANDLED) DRM_DEBUG_KMS("AVI IF handled by FW\n"); return true; }
bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl) { mutex_lock(&ctrl->dev_mutex); DBG("connect status = %d", ctrl->edp_connected); if (ctrl->edp_connected) { mutex_unlock(&ctrl->dev_mutex); return true; } if (!ctrl->power_on) { edp_ctrl_phy_aux_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); } if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd, DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) { pr_err("%s: AUX channel is NOT ready\n", __func__); memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE); } else { ctrl->edp_connected = true; } if (!ctrl->power_on) { edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); } DBG("exit: connect status=%d", ctrl->edp_connected); mutex_unlock(&ctrl->dev_mutex); return ctrl->edp_connected; }
static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 buf[3]; if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); }
static enum drm_connector_status xilinx_drm_dp_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct xilinx_drm_dp *dp = to_dp(encoder); struct xilinx_drm_dp_link_config *link_config = &dp->link_config; u32 state; int ret; state = xilinx_drm_readl(dp->iomem, XILINX_DP_TX_INTR_SIGNAL_STATE); if (state & XILINX_DP_TX_INTR_SIGNAL_STATE_HPD) { ret = drm_dp_dpcd_read(&dp->aux, 0x0, dp->dpcd, sizeof(dp->dpcd)); if (ret < 0) return connector_status_disconnected; link_config->max_rate = min_t(int, drm_dp_max_link_rate(dp->dpcd), dp->config.max_link_rate); link_config->max_lanes = min_t(u8, drm_dp_max_lane_count(dp->dpcd), dp->config.max_lanes); return connector_status_connected; }
static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux) { u8 avi_if_ctrl; u8 retry; ssize_t ret; /* Check if LSPCON FW is ready for data */ for (retry = 0; retry < 5; retry++) { if (retry) usleep_range(200, 300); ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL, &avi_if_ctrl, 1); if (ret < 0) { DRM_ERROR("Failed to read AVI IF control\n"); return false; } if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0) return true; } DRM_ERROR("Parade FW not ready to accept AVI IF\n"); return false; }
/* * Read the current backlight value from DPCD register(s) based * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported */ static uint32_t intel_dp_aux_get_backlight(struct intel_connector *connector) { struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); uint8_t read_val[2] = { 0x0 }; uint16_t level = 0; if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, &read_val, sizeof(read_val)) < 0) { DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n", DP_EDP_BACKLIGHT_BRIGHTNESS_MSB); return 0; } level = read_val[0]; if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) level = (read_val[0] << 8 | read_val[1]); return level; }
bool dm_helpers_dp_read_dpcd( struct dc_context *ctx, const struct dc_link *link, uint32_t address, uint8_t *data, uint32_t size) { struct amdgpu_dm_connector *aconnector = link->priv; if (!aconnector) { DRM_ERROR("Failed to found connector for link!"); return false; } return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address, data, size) > 0; }
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[DP_DPCD_SIZE]; int ret; ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, DP_DPCD_SIZE); if (ret > 0) { memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd), dig_connector->dpcd); radeon_dp_probe_oui(radeon_connector); return true; } dig_connector->dpcd[0] = 0; return false; }
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[DP_DPCD_SIZE]; int ret, i; ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, DP_DPCD_SIZE); if (ret > 0) { memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); DRM_DEBUG_KMS("DPCD: "); for (i = 0; i < DP_DPCD_SIZE; i++) DRM_DEBUG_KMS("%02x ", msg[i]); DRM_DEBUG_KMS("\n"); radeon_dp_probe_oui(radeon_connector); return true; } dig_connector->dpcd[0] = 0; return false; }
static int drm_dp_cec_received(struct drm_dp_aux *aux) { struct cec_adapter *adap = aux->cec.adap; struct cec_msg msg; u8 rx_msg_info; ssize_t err; err = drm_dp_dpcd_readb(aux, DP_CEC_RX_MESSAGE_INFO, &rx_msg_info); if (err < 0) return err; if (!(rx_msg_info & DP_CEC_RX_MESSAGE_ENDED)) return 0; msg.len = (rx_msg_info & DP_CEC_RX_MESSAGE_LEN_MASK) + 1; err = drm_dp_dpcd_read(aux, DP_CEC_RX_MESSAGE_BUFFER, msg.msg, msg.len); if (err < 0) return err; cec_received_msg(adap, &msg); return 0; }
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[DP_DPCD_SIZE]; int ret; char dpcd_hex_dump[DP_DPCD_SIZE * 3]; ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, DP_DPCD_SIZE); if (ret > 0) { memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); hex_dump_to_buffer(dig_connector->dpcd, sizeof(dig_connector->dpcd), 32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false); DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); radeon_dp_probe_oui(radeon_connector); return true; } dig_connector->dpcd[0] = 0; return false; }
static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) { int lane, lane_count, retval; u32 reg; u8 link_align, link_status[2], adjust_request[2]; usleep_range(400, 401); lane_count = dp->link_train.lane_count; retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); if (retval < 0) return retval; if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { analogix_dp_reduce_link_rate(dp); return -EIO; } retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, adjust_request, 2); if (retval < 0) return retval; retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, &link_align); if (retval < 0) return retval; analogix_dp_get_adjust_training_lane(dp, adjust_request); if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { /* traing pattern Set to Normal */ analogix_dp_training_pattern_dis(dp); dev_info(dp->dev, "Link Training success!\n"); analogix_dp_get_link_bandwidth(dp, ®); dp->link_train.link_rate = reg; dev_dbg(dp->dev, "final bandwidth = %.2x\n", dp->link_train.link_rate); analogix_dp_get_lane_count(dp, ®); dp->link_train.lane_count = reg; dev_dbg(dp->dev, "final lane count = %.2x\n", dp->link_train.lane_count); /* set enhanced mode if available */ analogix_dp_set_enhanced_mode(dp); dp->link_train.lt_state = FINISHED; return 0; } /* not all locked */ dp->link_train.eq_loop++; if (dp->link_train.eq_loop > MAX_EQ_LOOP) { dev_err(dp->dev, "EQ Max loop\n"); analogix_dp_reduce_link_rate(dp); return -EIO; } for (lane = 0; lane < lane_count; lane++) analogix_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link_train.training_lane, lane_count); if (retval < 0) return retval; return 0; }
static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) { int lane, lane_count, retval; u8 voltage_swing, pre_emphasis, training_lane; u8 link_status[2], adjust_request[2]; usleep_range(100, 101); lane_count = dp->link_train.lane_count; retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); if (retval < 0) return retval; retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, adjust_request, 2); if (retval < 0) return retval; if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ analogix_dp_set_training_pattern(dp, TRAINING_PTN2); retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2); if (retval < 0) return retval; dev_info(dp->dev, "Link Training Clock Recovery success\n"); dp->link_train.lt_state = EQUALIZER_TRAINING; } else { for (lane = 0; lane < lane_count; lane++) { training_lane = analogix_dp_get_lane_link_training( dp, lane); voltage_swing = analogix_dp_get_adjust_request_voltage( adjust_request, lane); pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( adjust_request, lane); if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing && DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis) dp->link_train.cr_loop[lane]++; if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || voltage_swing == VOLTAGE_LEVEL_3 || pre_emphasis == PRE_EMPHASIS_LEVEL_3) { dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", dp->link_train.cr_loop[lane], voltage_swing, pre_emphasis); analogix_dp_reduce_link_rate(dp); return -EIO; } } } analogix_dp_get_adjust_training_lane(dp, adjust_request); for (lane = 0; lane < lane_count; lane++) analogix_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link_train.training_lane, lane_count); if (retval < 0) return retval; return 0; }