static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp, bool enable) { u8 data; int retval; retval = s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data); if (retval < 0) return retval; if (enable) { retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, DPCD_ENHANCED_FRAME_EN | DPCD_LANE_COUNT_SET(data)); } else { retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_CONFIGURATION_SET, 0); retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, DPCD_LANE_COUNT_SET(data)); } return retval; }
static void s5p_dp_disable_rx_zmux(struct s5p_dp_device *dp) { s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED1, 0); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED2, 0x83); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3, 0x27); }
void s5p_dp_rx_control(struct s5p_dp_device *dp, bool enable) { s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED1,0); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED2,0x90); if (enable) { s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3,0x84); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3,0x00); } else { s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3,0x80); } }
static void s5p_dp_link_start_for_psr(struct s5p_dp_device *dp) { u8 buf[4]; int lane; int lane_count; lane_count = dp->link_train.lane_count; dp->link_train.lt_state = CLOCK_RECOVERY; dp->link_train.eq_loop = 0; for (lane = 0; lane < lane_count; lane++) dp->link_train.cr_loop[lane] = 0; /* Set training pattern 1 */ s5p_dp_set_training_pattern(dp, TRAINING_PTN1); /* Set RX training pattern */ buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]); for (lane = 0; lane < lane_count; lane++) buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; s5p_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, lane_count, buf); }
static int s5p_dp_process_equalizer_training_for_psr(struct s5p_dp_device *dp) { u8 link_status[6]; int lane; int lane_count; u8 buf[5]; u32 reg; u8 adjust_request[2]; s5p_dp_sr_wait_on(dp); s5p_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, 6, link_status); lane_count = dp->link_train.lane_count; if (s5p_dp_clock_recovery_ok(link_status, lane_count) == 0) { adjust_request[0] = link_status[4]; adjust_request[1] = link_status[5]; if (s5p_dp_channel_eq_ok(link_status, lane_count) == 0) { /* traing pattern Set to Normal */ s5p_dp_training_pattern_dis(dp); dev_dbg(dp->dev, "Link Training success!\n"); s5p_dp_get_link_bandwidth(dp, ®); dp->link_train.link_rate = reg; dev_dbg(dp->dev, "final bandwidth = %.2x\n", dp->link_train.link_rate); s5p_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); dp->link_train.lt_state = FINISHED; } else { /* not all locked */ dp->link_train.eq_loop++; if (dp->link_train.eq_loop > MAX_EQ_LOOP) { s5p_dp_reduce_link_rate(dp); } else { s5p_dp_get_adjust_train(dp, adjust_request); for (lane = 0; lane < lane_count; lane++) { s5p_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); buf[lane] = dp->link_train.training_lane[lane]; s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET + lane, buf[lane]); } } } } else { s5p_dp_reduce_link_rate(dp); } return 0; }
static int s5p_dp_training_pattern_dis(struct s5p_dp_device *dp) { int retval; s5p_dp_set_training_pattern(dp, DP_NONE); retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, DPCD_TRAINING_PATTERN_DISABLED); if (retval < 0) return retval; return 0; }
static int s5p_dp_enable_scramble(struct s5p_dp_device *dp, bool enable) { u8 data; int retval; if (enable) { s5p_dp_enable_scrambling(dp); retval = s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, &data); if (retval < 0) return retval; retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); if (retval < 0) return retval; } else { s5p_dp_disable_scrambling(dp); retval = s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, &data); if (retval < 0) return retval; retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, (u8)(data | DPCD_SCRAMBLING_DISABLED)); if (retval < 0) return retval; } return 0; }
/* * Set DP to enhanced mode. We use this for EVT1 * param dp pointer to main s5p-dp structure * return status */ static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp) { u8 data; if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data)) { printk(BIOS_DEBUG, "DPCD read error\n"); return -ERR_DPCD_READ_ERROR1; } if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, DPCD_ENHANCED_FRAME_EN | (data & DPCD_LANE_COUNT_SET_MASK))) { printk(BIOS_DEBUG, "DPCD write error\n"); return -ERR_DPCD_WRITE_ERROR1; } return 0; }
/* * Enable scrambles mode. We use this for EVT1 * param dp pointer to main s5p-dp structure * return status */ static int s5p_dp_enable_scramble(struct s5p_dp_device *dp) { u8 data; struct exynos5_dp *base = dp->base; clrbits_le32(&base->dp_training_ptn_set, SCRAMBLING_DISABLE); if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, &data)) { printk(BIOS_DEBUG, "DPCD read error\n"); return -ERR_DPCD_READ_ERROR2; } if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, (u8)(data & ~DPCD_SCRAMBLING_DISABLED))) { printk(BIOS_DEBUG, "DPCD write error\n"); return -ERR_DPCD_WRITE_ERROR2; } return 0; }
static int s5p_dp_psr_pre_entry(struct s5p_dp_device *dp) { struct platform_device *pdev; struct s5p_dp_platdata *pdata; int timeout_loop = 0; struct fb_event event; pdev = to_platform_device(dp->dev); pdata = pdev->dev.platform_data; mutex_lock(&dp->lock); dev_dbg(dp->dev, "%s +\n", __func__); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_PRE_ENTRY, 0x1); dp->psr_enter_state = PSR_PRE_ENTRY_DONE; dev_dbg(dp->dev, "%s -\n", __func__); mutex_unlock(&dp->lock); return 0; }
static int s5p_dp_read_edid(struct s5p_dp_device *dp) { unsigned char edid[EDID_BLOCK_LENGTH * 2]; unsigned int extend_block = 0; unsigned char sum; unsigned char test_vector; int retval; /* * EDID device address is 0x50. * However, if necessary, you must have set upper address * into E-EDID in I2C device, 0x30. */ /* Read Extension Flag, Number of 128-byte EDID extension blocks */ retval = s5p_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, &extend_block); if (retval < 0) { dev_err(dp->dev, "EDID extension flag failed!\n"); return -EIO; } if (extend_block > 0) { dev_dbg(dp->dev, "EDID data includes a single extension!\n"); /* Read EDID data */ retval = s5p_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); if (retval != 0) { dev_err(dp->dev, "EDID Read failed!\n"); return -EIO; } sum = s5p_dp_calc_edid_check_sum(edid); if (sum != 0) { dev_err(dp->dev, "EDID bad checksum!\n"); return -EIO; } /* Read additional EDID data */ retval = s5p_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR, EDID_BLOCK_LENGTH, EDID_BLOCK_LENGTH, &edid[EDID_BLOCK_LENGTH]); if (retval != 0) { dev_err(dp->dev, "EDID Read failed!\n"); return -EIO; } sum = s5p_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); if (sum != 0) { dev_err(dp->dev, "EDID bad checksum!\n"); return -EIO; } retval = s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, &test_vector); if (retval < 0) { dev_err(dp->dev, "DPCD EDID Read failed!\n"); return retval; } if (test_vector & DPCD_TEST_EDID_READ) { retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TEST_EDID_CHECKSUM, edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); if (retval < 0) { dev_err(dp->dev, "DPCD EDID Write failed!\n"); return retval; } retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); if (retval < 0) { dev_err(dp->dev, "DPCD EDID checksum failed!\n"); return retval; } } } else { dev_info(dp->dev, "EDID data does not include any extensions.\n"); /* Read EDID data */ retval = s5p_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); if (retval != 0) { dev_err(dp->dev, "EDID Read failed!\n"); return -EIO; } sum = s5p_dp_calc_edid_check_sum(edid); if (sum != 0) { dev_err(dp->dev, "EDID bad checksum!\n"); return -EIO; } retval = s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, &test_vector); if (retval < 0) { dev_err(dp->dev, "DPCD EDID Read failed!\n"); return retval; } if (test_vector & DPCD_TEST_EDID_READ) { retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); if (retval < 0) { dev_err(dp->dev, "DPCD EDID Write failed!\n"); return retval; } retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); if (retval < 0) { dev_err(dp->dev, "DPCD EDID checksum failed!\n"); return retval; } } } dev_err(dp->dev, "EDID Read success!\n"); return 0; }
static int s5p_dp_process_clock_recovery(struct s5p_dp_device *dp) { u8 link_status[2]; int lane; int lane_count; u8 adjust_request[2]; u8 voltage_swing; u8 pre_emphasis; u8 training_lane; int retval; udelay(100); lane_count = dp->link_train.lane_count; retval = s5p_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, 2, link_status); if (retval < 0) { dev_err(dp->dev, "failed to read lane status!\n"); return retval; } dev_err(dp->dev, "link status[0] : %x\n", link_status[0]); dev_err(dp->dev, "link status[1] : %x\n", link_status[1]); if (s5p_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ s5p_dp_set_training_pattern(dp, TRAINING_PTN2); for (lane = 0; lane < lane_count; lane++) { retval = s5p_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); if (retval < 0) { dev_err(dp->dev, "failed to read adjust request!\n"); return retval; } voltage_swing = s5p_dp_get_adjust_request_voltage( adjust_request, lane); pre_emphasis = s5p_dp_get_adjust_request_pre_emphasis( adjust_request, lane); training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | DPCD_PRE_EMPHASIS_SET(pre_emphasis); if (voltage_swing == VOLTAGE_LEVEL_3) training_lane |= DPCD_MAX_SWING_REACHED; if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; dp->link_train.training_lane[lane] = training_lane; s5p_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); } retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2); if (retval < 0) { dev_err(dp->dev, "failed to set training pattern 2!\n"); return retval; } retval = s5p_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, lane_count, dp->link_train.training_lane); if (retval < 0) { dev_err(dp->dev, "failed to set training lane!\n"); 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 = s5p_dp_get_lane_link_training( dp, lane); retval = s5p_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); if (retval < 0) { dev_err(dp->dev, "failed to read adjust request!\n"); return retval; } voltage_swing = s5p_dp_get_adjust_request_voltage( adjust_request, lane); pre_emphasis = s5p_dp_get_adjust_request_pre_emphasis( adjust_request, lane); if (voltage_swing == VOLTAGE_LEVEL_3 || pre_emphasis == PRE_EMPHASIS_LEVEL_3) { dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); goto reduce_link_rate; } 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) { dev_err(dp->dev, "CR Max loop\n"); goto reduce_link_rate; } } training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | DPCD_PRE_EMPHASIS_SET(pre_emphasis); if (voltage_swing == VOLTAGE_LEVEL_3) training_lane |= DPCD_MAX_SWING_REACHED; if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; dp->link_train.training_lane[lane] = training_lane; s5p_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); } retval = s5p_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, lane_count, dp->link_train.training_lane); if (retval < 0) { dev_err(dp->dev, "failed to set training lane!\n"); return retval; } } return 0; reduce_link_rate: s5p_dp_reduce_link_rate(dp); return -EIO; }
static int s5p_dp_link_start(struct s5p_dp_device *dp) { u8 buf[4]; int lane; int lane_count; int retval; lane_count = dp->link_train.lane_count; dp->link_train.lt_state = CLOCK_RECOVERY; dp->link_train.eq_loop = 0; for (lane = 0; lane < lane_count; lane++) dp->link_train.cr_loop[lane] = 0; /* Set sink to D0 (Sink Not Ready) mode. */ retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); if (retval < 0) { dev_err(dp->dev, "failed to set sink device to D0!\n"); return retval; } /* Set link rate and count as you want to establish*/ s5p_dp_set_link_bandwidth(dp, dp->link_train.link_rate); s5p_dp_set_lane_count(dp, dp->link_train.lane_count); /* Setup RX configuration */ buf[0] = dp->link_train.link_rate; buf[1] = dp->link_train.lane_count; retval = s5p_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, 2, buf); if (retval < 0) { dev_err(dp->dev, "failed to set bandwidth and lane count!\n"); return retval; } /* Set TX pre-emphasis to level1 */ for (lane = 0; lane < lane_count; lane++) s5p_dp_set_lane_lane_pre_emphasis(dp, PRE_EMPHASIS_LEVEL_1, lane); /* Set training pattern 1 */ s5p_dp_set_training_pattern(dp, TRAINING_PTN1); /* Set RX training pattern */ retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); if (retval < 0) { dev_err(dp->dev, "failed to set training pattern 1!\n"); return retval; } for (lane = 0; lane < lane_count; lane++) buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; retval = s5p_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, lane_count, buf); if (retval < 0) { dev_err(dp->dev, "failed to set training lane!\n"); return retval; } return 0; }
static int s5p_dp_init_training(struct s5p_dp_device *dp, enum link_lane_count_type max_lane, enum link_rate_type max_rate) { int retval; #ifdef CONFIG_S5P_DP_PSR u8 data; #endif /* * MACRO_RST must be applied after the PLL_LOCK to avoid * the DP inter pair skew issue for at least 10 us */ s5p_dp_reset_macro(dp); #ifdef CONFIG_S5P_DP_PSR s5p_dp_enable_rx_to_enhanced_mode(dp, 0); s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_EDP_CONFIGURATION_SET, &data); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_EDP_CONFIGURATION_SET, data | (1<<1)); s5p_dp_enable_enhanced_mode(dp, 1); #endif /* Initialize by reading RX's DPCD */ retval = s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); if (retval < 0) return retval; retval = s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); if (retval < 0) return retval; if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n", dp->link_train.link_rate); dp->link_train.link_rate = LINK_RATE_1_62GBPS; } if (dp->link_train.lane_count == 0) { dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n", dp->link_train.lane_count); dp->link_train.lane_count = (u8)LANE_COUNT1; } /* Setup TX lane count & rate */ if (dp->link_train.lane_count > max_lane) dp->link_train.lane_count = max_lane; if (dp->link_train.link_rate > max_rate) dp->link_train.link_rate = max_rate; #ifdef CONFIG_S5P_DP_PSR s5p_dp_enable_ssc(dp, 0); #endif /* All DP analog module power up */ s5p_dp_set_analog_power_down(dp, POWER_ALL, 0); return 0; }
static int s5p_dp_enable(struct s5p_dp_device *dp) { int ret = 0; int retry = 0; struct s5p_dp_platdata *pdata = dp->dev->platform_data; u32 reg; #ifdef CONFIG_S5P_DP_PSR if ((dp->psr_enter_state == PSR_PRE_ENTER) || (dp->psr_enter_state == PSR_ENTER_DONE)) { s5p_dp_psr_exit(dp); } #endif mutex_lock(&dp->lock); #ifdef CONFIG_S5P_DP_ESD_RECOVERY if (dp->enabled) s5p_dp_disable_esd_interrupt(dp); #endif if (dp->enabled) goto out; dp->enabled = 1; clk_enable(dp->clock); pm_runtime_get_sync(dp->dev); dp_phy_init: s5p_dp_init_dp(dp); #if 0 if (!soc_is_exynos5250()) { ret = s5p_dp_detect_hpd(dp); if (ret) { dev_err(dp->dev, "unable to detect hpd\n"); goto out; } } #endif #if 0 ret = s5p_dp_handle_edid(dp); if (ret) { dev_err(dp->dev, "unable to handle edid\n"); goto out; } #endif if (soc_is_exynos5250()) s5p_dp_disable_rx_zmux(dp); /* Non-enhance mode setting */ ret = s5p_dp_enable_scramble(dp, 0); if (ret) { dev_err(dp->dev, "unable to set scramble\n"); goto out; } ret = s5p_dp_enable_rx_to_enhanced_mode(dp, 0); if (ret) { dev_err(dp->dev, "unable to set enhanced mode\n"); goto out; } s5p_dp_enable_enhanced_mode(dp, 0); /* Rx data disable */ if (soc_is_exynos5250()) s5p_dp_rx_control(dp,0); /* Link Training */ ret = s5p_dp_set_link_train(dp, dp->video_info->lane_count, dp->video_info->link_rate); if (ret) { dev_err(dp->dev, "unable to do link train\n"); goto out; } /* Rx data enable */ if (soc_is_exynos5250()) s5p_dp_rx_control(dp,1); s5p_dp_set_lane_count(dp, dp->video_info->lane_count); s5p_dp_set_link_bandwidth(dp, dp->video_info->link_rate); s5p_dp_init_video(dp); ret = s5p_dp_config_video(dp, dp->video_info); if (ret) { dev_err(dp->dev, "unable to config video\n"); goto out; } #ifdef CONFIG_S5P_DP_PSR s5p_dp_scramber_rst_cnt(dp); s5p_dp_write_byte_to_dpcd(dp, 0x491, 0x80); s5p_dp_write_byte_to_dpcd(dp, 0x492, 0x04); s5p_dp_write_byte_to_dpcd(dp, 0x493, 0x31); writel(0x2F, dp->reg_base + 0x730); /* S5P_DP_VIDEO_FIFO_THRD */ reg = readl(dp->reg_base + 0x800); /* S5P_DP_SOC_GENERAL_CTL */ reg |= (1<<31); writel(reg, dp->reg_base + 0x800); s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_PSR_CONFIGURATION, DPCD_PSR_ENABLE); s5p_dp_set_video_timing(dp); #endif if (pdata->backlight_on) pdata->backlight_on(); #ifdef CONFIG_S5P_DP_ESD_RECOVERY s5p_dp_enable_esd_interrupt(dp); #endif mutex_unlock(&dp->lock); return 0; out: if (retry < 3) { if (pdata->lcd_off) pdata->lcd_off(); if (pdata->lcd_on) pdata->lcd_on(); retry++; goto dp_phy_init; } dev_err(dp->dev, "DP LT exceeds max retry count"); if (pdata->backlight_off) pdata->backlight_off(); if (pdata->lcd_off) pdata->lcd_off(); mutex_unlock(&dp->lock); return ret; }
int s5p_dp_psr_exit(struct s5p_dp_device *dp) { struct platform_device *pdev; struct s5p_dp_platdata *pdata; int timeout_loop = 0; u8 data; u32 reg; int ret = 0; pdev = to_platform_device(dp->dev); pdata = pdev->dev.platform_data; mutex_lock(&dp->lock); dev_dbg(dp->dev, "%s +\n", __func__); if (dp->psr_enter_state == PSR_NONE) { dev_info(dp->dev, "%s: Already edP PSR_EXIT state\n", __func__); dp->psr_exit_state = PSR_NONE; mutex_unlock(&dp->lock); return 0; } clk_enable(dp->clock); s5p_dp_exit_psr(dp); s5p_dp_set_fifo_reset(dp); s5p_dp_reset_macro_onoff(dp, 1); s5p_dp_set_analog_power_down(dp, ANALOG_TOTAL, 0); if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { timeout_loop++; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "failed to get pll lock status\n"); ret = -ETIMEDOUT; goto err_exit; } udelay(10); } } ndelay(600); s5p_dp_clear_fifo_reset(dp); s5p_dp_reset_macro_onoff(dp, 0); s5p_dp_reset_serdes_fifo(dp); /* Set sink to D0 (Normal operation) mode. */ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); s5p_dp_set_link_train_for_psr(dp, dp->video_info->lane_count, dp->video_info->link_rate); s5p_dp_set_idle_en(dp); timeout_loop = 0; for (;;) { timeout_loop++; if (s5p_dp_get_psr_status(dp) == PSR_STATUS_INACTIVE) break; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "DP: Timeout of PSR inactive\n"); ret = -ETIMEDOUT; goto err_exit; } usleep_range(100, 110); } s5p_dp_set_force_stream_valid(dp); timeout_loop = 0; for (;;) { timeout_loop++; if (s5p_dp_is_video_stream_on(dp) == 0) break; if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "Timeout of video streamclk ok\n"); ret = -ETIMEDOUT; goto err_exit; } usleep_range(1000, 1100); } timeout_loop = 0; for (;;) { timeout_loop++; s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_SINK_PSR_STATUS, &data); if (data == SINK_PSR_INACTIVE_STATE || data == 4) { break; } if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { dev_err(dp->dev, "LCD: Timeout of Sink PSR inactive\n"); ret = -ETIMEDOUT; goto err_exit; } usleep_range(100, 110); } dp->psr_enter_state = PSR_NONE; dp->psr_exit_state = PSR_EXIT_DONE; dev_dbg(dp->dev, "%s -\n", __func__); mutex_unlock(&dp->lock); return ret; err_exit: dp->psr_exit_state = PSR_NONE; dev_dbg(dp->dev, "%s -\n", __func__); mutex_unlock(&dp->lock); return ret; }
/* * DP H/w Link Training. Set DPCD link rate and bandwidth. * param dp pointer to main s5p-dp structure * param max_lane No of lanes * param max_rate bandwidth * return status */ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp, unsigned int max_lane, unsigned int max_rate) { int pll_is_locked = 0; u32 data; int lane; struct mono_time current, end; struct exynos5_dp *base = dp->base; /* Stop Video */ clrbits_le32(&base->video_ctl_1, VIDEO_EN); timer_monotonic_get(¤t); end = current; mono_time_add_msecs(&end, PLL_LOCK_TIMEOUT); while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) { if (mono_time_after(¤t, &end)) { /* Ignore this error, and try to continue */ printk(BIOS_ERR, "PLL is not locked yet.\n"); break; } timer_monotonic_get(¤t); } printk(BIOS_SPEW, "PLL is %slocked\n", pll_is_locked == PLL_LOCKED ? "": "not "); /* Reset Macro */ setbits_le32(&base->dp_phy_test, MACRO_RST); /* 10 us is the minimum reset time. */ udelay(10); clrbits_le32(&base->dp_phy_test, MACRO_RST); /* Set TX pre-emphasis to minimum */ for (lane = 0; lane < max_lane; lane++) if (s5p_dp_set_lane_lane_pre_emphasis(dp, PRE_EMPHASIS_LEVEL_0, lane)) { printk(BIOS_DEBUG, "Unable to set pre emphasis level\n"); return -ERR_PRE_EMPHASIS_LEVELS; } /* All DP analog module power up */ writel(0x00, &base->dp_phy_pd); /* Initialize by reading RX's DPCD */ s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__, dp->link_train.link_rate, dp->link_train.lane_count); if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n", dp->link_train.link_rate); /* Not Retrying */ return -ERR_LINK_RATE_ABNORMAL; } if (dp->link_train.lane_count == 0) { printk(BIOS_DEBUG, "Rx Max Lane count is abnormal :%x !\n", dp->link_train.lane_count); /* Not retrying */ return -ERR_MAX_LANE_COUNT_ABNORMAL; } /* Setup TX lane count & rate */ if (dp->link_train.lane_count > max_lane) dp->link_train.lane_count = max_lane; if (dp->link_train.link_rate > max_rate) dp->link_train.link_rate = max_rate; /* Set link rate and count as you want to establish*/ writel(dp->link_train.lane_count, &base->lane_count_set); writel(dp->link_train.link_rate, &base->link_bw_set); /* Set sink to D0 (Sink Not Ready) mode. */ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); /* Start HW link training */ writel(HW_TRAINING_EN, &base->dp_hw_link_training); /* Wait until HW link training done */ s5p_dp_wait_hw_link_training_done(dp); /* Get hardware link training status */ data = readl(&base->dp_hw_link_training); printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data); if (data != 0) { printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data); return -ERR_LINK_TRAINING_FAILURE; } /* Get Link Bandwidth */ data = readl(&base->link_bw_set); dp->link_train.link_rate = data; data = readl(&base->lane_count_set); dp->link_train.lane_count = data; printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n", dp->link_train.link_rate, data); return 0; }
static int s5p_dp_process_clock_recovery_for_psr(struct s5p_dp_device *dp) { u8 data; u8 link_status[6]; int lane; int lane_count; u8 buf[5]; u8 adjust_request[2]; u8 voltage_swing; u8 pre_emphasis; u8 training_lane; s5p_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, 6, link_status); lane_count = dp->link_train.lane_count; if (s5p_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ s5p_dp_set_training_pattern(dp, TRAINING_PTN2); adjust_request[0] = link_status[4]; adjust_request[1] = link_status[5]; s5p_dp_get_adjust_train(dp, adjust_request); buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2; s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]); for (lane = 0; lane < lane_count; lane++) { s5p_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); buf[lane] = dp->link_train.training_lane[lane]; s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET + lane, buf[lane]); } dp->link_train.lt_state = EQUALIZER_TRAINING; } else { s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_ADJUST_REQUEST_LANE0_1, &data); adjust_request[0] = data; s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_ADJUST_REQUEST_LANE2_3, &data); adjust_request[1] = data; for (lane = 0; lane < lane_count; lane++) { training_lane = s5p_dp_get_lane_link_training(dp, lane); voltage_swing = s5p_dp_get_adjust_request_voltage( adjust_request, lane); pre_emphasis = s5p_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]++; dp->link_train.training_lane[lane] = training_lane; } if (s5p_dp_check_max_cr_loop(dp, voltage_swing) != 0) { s5p_dp_reduce_link_rate(dp); } else { s5p_dp_get_adjust_train(dp, adjust_request); for (lane = 0; lane < lane_count; lane++) { s5p_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); buf[lane] = dp->link_train.training_lane[lane]; s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET + lane, buf[lane]); } } } return 0; }