diff options
Diffstat (limited to 'src/cpu/samsung/exynos5420/dp.c')
-rw-r--r-- | src/cpu/samsung/exynos5420/dp.c | 910 |
1 files changed, 0 insertions, 910 deletions
diff --git a/src/cpu/samsung/exynos5420/dp.c b/src/cpu/samsung/exynos5420/dp.c deleted file mode 100644 index b147035b64..0000000000 --- a/src/cpu/samsung/exynos5420/dp.c +++ /dev/null @@ -1,910 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: Donghwa Lee <dh09.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <arch/io.h> -#include <stdlib.h> -#include <string.h> -#include <timer.h> -#include <delay.h> -#include <console/console.h> -#include <lib.h> -#include "timer.h" -#include "power.h" -#include "sysreg.h" - -#include "dp.h" -#include "fimd.h" -#include "i2c.h" - -/* - * Here is the rough outline of how we bring up the display: - * 1. Upon power-on Sink generates a hot plug detection pulse thru HPD - * 2. Source determines video mode by reading DPCD receiver capability field - * (DPCD 00000h to 0000Dh) including eDP CP capability register (DPCD - * 0000Dh). - * 3. Sink replies DPCD receiver capability field. - * 4. Source starts EDID read thru I2C-over-AUX. - * 5. Sink replies EDID thru I2C-over-AUX. - * 6. Source determines link configuration, such as MAX_LINK_RATE and - * MAX_LANE_COUNT. Source also determines which type of eDP Authentication - * method to use and writes DPCD link configuration field (DPCD 00100h to - * 0010Ah) including eDP configuration set (DPCD 0010Ah). - * 7. Source starts link training. Sink does clock recovery and equalization. - * 8. Source reads DPCD link status field (DPCD 00200h to 0020Bh). - * 9. Sink replies DPCD link status field. If main link is not stable, Source - * repeats Step 7. - * 10. Source sends MSA (Main Stream Attribute) data. Sink extracts video - * parameters and recovers stream clock. - * 11. Source sends video data. - */ - - -static int exynos_dp_init_dp(void) -{ - int ret; - exynos_dp_reset(); - - /* SW defined function Normal operation */ - exynos_dp_enable_sw_func(DP_ENABLE); - - ret = exynos_dp_init_analog_func(); - if (ret != EXYNOS_DP_SUCCESS) - return ret; - - exynos_dp_init_hpd(); - exynos_dp_init_aux(); - - return ret; -} - -static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static unsigned int exynos_dp_read_edid(void) -{ - unsigned char edid[EDID_BLOCK_LENGTH * 2]; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval = 0; - - /* - * 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 */ - if (exynos_dp_read_byte_from_i2c - (I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, &extend_block)) - return -1; - - if (extend_block > 0) { - /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - - if (retval != 0) { - printk(BIOS_ERR, "DP EDID Read failed!\n"); - return -1; - } - sum = exynos_dp_calc_edid_check_sum(edid); - if (sum != 0) { - printk(BIOS_ERR, "DP EDID bad checksum!\n"); - return -1; - } - /* Read additional EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - &edid[EDID_BLOCK_LENGTH]); - if (retval != 0) { - printk(BIOS_ERR, "DP EDID Read failed!\n"); - return -1; - } - sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); - if (sum != 0) { - printk(BIOS_ERR, "DP EDID bad checksum!\n"); - return -1; - } - exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, - &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); - } - } else { - /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - - if (retval != 0) { - printk(BIOS_ERR, "DP EDID Read failed!\n"); - return -1; - } - sum = exynos_dp_calc_edid_check_sum(edid); - if (sum != 0) { - printk(BIOS_ERR, "DP EDID bad checksum!\n"); - return -1; - } - - exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, - &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, - edid[EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); - } - - } - - return 0; -} - -static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) -{ - unsigned char buf[12]; - unsigned int ret; - unsigned char temp; - unsigned char retry_cnt; - unsigned char dpcd_rev[16]; - unsigned char lane_bw[16]; - unsigned char lane_cnt[16]; - - memset(dpcd_rev, 0, sizeof(dpcd_rev)); - memset(lane_bw, 0, sizeof(lane_bw)); - memset(lane_cnt, 0, sizeof(lane_cnt)); - memset(buf, 0, sizeof(buf)); - - retry_cnt = 5; - while (retry_cnt) { - /* Read DPCD 0x0000-0x000b */ - ret = exynos_dp_read_bytes_from_dpcd(DPCD_DPCD_REV, 12, - buf); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printk(BIOS_ERR, "DP read_byte_from_dpcd() failed\n"); - return ret; - } - retry_cnt--; - } else - break; - } - /* */ - temp = buf[DPCD_DPCD_REV]; - if (temp == DP_DPCD_REV_10 || temp == DP_DPCD_REV_11) - edp_info->dpcd_rev = temp; - else { - printk(BIOS_ERR, "DP Wrong DPCD Rev : %x\n", temp); - return -1; - } - temp = buf[DPCD_MAX_LINK_RATE]; - if (temp == DP_LANE_BW_1_62 || temp == DP_LANE_BW_2_70) - edp_info->lane_bw = temp; - else { - printk(BIOS_ERR, "DP Wrong MAX LINK RATE : %x\n", temp); - return -1; - } - /*Refer VESA Display Port Stnadard Ver1.1a Page 120 */ - if (edp_info->dpcd_rev == DP_DPCD_REV_11) { - temp = buf[DPCD_MAX_LANE_COUNT] & 0x1f; - if (buf[DPCD_MAX_LANE_COUNT] & 0x80) - edp_info->dpcd_efc = 1; - else - edp_info->dpcd_efc = 0; - } else { - temp = buf[DPCD_MAX_LANE_COUNT]; - edp_info->dpcd_efc = 0; - } - - if (temp == DP_LANE_CNT_1 || temp == DP_LANE_CNT_2 || - temp == DP_LANE_CNT_4) { - edp_info->lane_cnt = temp; - } else { - printk(BIOS_ERR, "DP Wrong MAX LANE COUNT : %x\n", temp); - return -1; - } - - if (edp_info->raw_edid){ - ret = EXYNOS_DP_SUCCESS; - printk(BIOS_SPEW, "EDID compiled in, skipping read\n"); - } else { - ret = exynos_dp_read_edid(); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP exynos_dp_read_edid() failed\n"); - return -1; - } - } - - return ret; -} - -static void exynos_dp_init_training(void) -{ - /* - * MACRO_RST must be applied after the PLL_LOCK to avoid - * the DP inter pair skew issue for at least 10 us - */ - exynos_dp_reset_macro(); - - /* All DP analog module power up */ - exynos_dp_set_analog_power_down(POWER_ALL, 0); -} - -static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) -{ - unsigned char buf[5]; - unsigned int ret; - - edp_info->lt_info.lt_status = DP_LT_CR; - edp_info->lt_info.ep_loop = 0; - edp_info->lt_info.cr_loop[0] = 0; - edp_info->lt_info.cr_loop[1] = 0; - edp_info->lt_info.cr_loop[2] = 0; - edp_info->lt_info.cr_loop[3] = 0; - - /* Set sink to D0 (Sink Not Ready) mode. */ - ret = exynos_dp_write_byte_to_dpcd(DPCD_SINK_POWER_STATE, - DPCD_SET_POWER_STATE_D0); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP write_dpcd_byte failed\n"); - return ret; - } - - /* Set link rate and count as you want to establish*/ - exynos_dp_set_link_bandwidth(edp_info->lane_bw); - exynos_dp_set_lane_count(edp_info->lane_cnt); - - /* Setup RX configuration */ - buf[0] = edp_info->lane_bw; - buf[1] = edp_info->lane_cnt; - - ret = exynos_dp_write_bytes_to_dpcd(DPCD_LINK_BW_SET, 2, - buf); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP write_dpcd_byte failed\n"); - return ret; - } - - exynos_dp_set_lane_pre_emphasis(PRE_EMPHASIS_LEVEL_0, - edp_info->lane_cnt); - - /* Set training pattern 1 */ - exynos_dp_set_training_pattern(TRAINING_PTN1); - - /* Set RX training pattern */ - buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; - - buf[1] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - buf[2] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - buf[3] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - - ret = exynos_dp_write_bytes_to_dpcd(DPCD_TRAINING_PATTERN_SET, - 5, buf); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP write_dpcd_byte failed\n"); - return ret; - } - return ret; -} - -static unsigned int exynos_dp_training_pattern_dis(void) -{ - unsigned int ret; - - exynos_dp_set_training_pattern(DP_NONE); - - ret = exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - DPCD_TRAINING_PATTERN_DISABLED); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP requst_link_traninig_req failed\n"); - return -1; - } - - return ret; -} - -static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) -{ - unsigned char data; - unsigned int ret; - - ret = exynos_dp_read_byte_from_dpcd(DPCD_LANE_COUNT_SET, - &data); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read_from_dpcd failed\n"); - return -1; - } - - if (enable) - data = DPCD_ENHANCED_FRAME_EN | DPCD_LN_COUNT_SET(data); - else - data = DPCD_LN_COUNT_SET(data); - - ret = exynos_dp_write_byte_to_dpcd(DPCD_LANE_COUNT_SET, - data); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP write_to_dpcd failed\n"); - return -1; - - } - - return ret; -} - -static unsigned int exynos_dp_set_enhanced_mode(unsigned char enhance_mode) -{ - unsigned int ret; - - ret = exynos_dp_enable_rx_to_enhanced_mode(enhance_mode); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP rx_enhance_mode failed\n"); - return -1; - } - - exynos_dp_enable_enhanced_mode(enhance_mode); - - return ret; -} - -static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, - unsigned char *status) -{ - unsigned int ret, i; - unsigned char buf[2]; - unsigned char lane_stat[DP_LANE_CNT_4] = {0,}; - const unsigned char shift_val[] = {0, 4, 0, 4}; - - ret = exynos_dp_read_bytes_from_dpcd(DPCD_LANE0_1_STATUS, 2, buf); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read lane status failed\n"); - return ret; - } - - for (i = 0; i < edp_info->lane_cnt; i++) { - lane_stat[i] = (buf[(i / 2)] >> shift_val[i]) & 0x0f; - if (lane_stat[0] != lane_stat[i]) { - printk(BIOS_ERR, "Wrong lane status\n"); - return -1; - } - } - - *status = lane_stat[0]; - - return ret; -} - -static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, - unsigned char *sw, unsigned char *em) -{ - const unsigned char shift_val[] = {0, 4, 0, 4}; - unsigned int ret; - unsigned char buf; - unsigned int dpcd_addr; - - /*lane_num value is used as arry index, so this range 0 ~ 3 */ - dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); - - ret = exynos_dp_read_byte_from_dpcd(dpcd_addr, &buf); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read adjust request failed\n"); - return -1; - } - - *sw = ((buf >> shift_val[lane_num]) & 0x03); - *em = ((buf >> shift_val[lane_num]) & 0x0c) >> 2; - - return ret; -} - -static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) -{ - int ret; - - ret = exynos_dp_training_pattern_dis(); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP training_patter_disable() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - } - - ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP set_enhanced_mode() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - } - - return ret; -} - -static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) -{ - int ret; - - if (edp_info->lane_bw == DP_LANE_BW_2_70) { - edp_info->lane_bw = DP_LANE_BW_1_62; - printk(BIOS_ERR, "DP Change lane bw to 1.62Gbps\n"); - edp_info->lt_info.lt_status = DP_LT_START; - ret = EXYNOS_DP_SUCCESS; - } else { - ret = exynos_dp_training_pattern_dis(); - if (ret != EXYNOS_DP_SUCCESS) - printk(BIOS_ERR, "DP training_patter_disable() failed\n"); - - ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); - if (ret != EXYNOS_DP_SUCCESS) - printk(BIOS_ERR, "DP set_enhanced_mode() failed\n"); - - edp_info->lt_info.lt_status = DP_LT_FAIL; - } - - return ret; -} - -static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info - *edp_info) -{ - unsigned int ret; - unsigned char lane_stat; - unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0, }; - unsigned int i; - unsigned char adj_req_sw; - unsigned char adj_req_em; - unsigned char buf[5]; - - mdelay(1); - - ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read lane status failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - if (lane_stat & DP_LANE_STAT_CR_DONE) { - printk(BIOS_DEBUG,"DP clock Recovery training succeed\n"); - exynos_dp_set_training_pattern(TRAINING_PTN2); - - for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(i, &adj_req_sw, - &adj_req_em); - if (ret != EXYNOS_DP_SUCCESS) { - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - lt_ctl_val[i] = 0; - lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; - - if ((adj_req_sw == VOLTAGE_LEVEL_3) - || (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { - lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | - MAX_PRE_EMPHASIS_REACH_3; - } - exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); - } - - buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2; - buf[1] = lt_ctl_val[0]; - buf[2] = lt_ctl_val[1]; - buf[3] = lt_ctl_val[2]; - buf[4] = lt_ctl_val[3]; - - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_PATTERN_SET, 5, buf); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP write training pattern1 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } else - edp_info->lt_info.lt_status = DP_LT_ET; - } else { - for (i = 0; i < edp_info->lane_cnt; i++) { - lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis(i); - ret = exynos_dp_read_dpcd_adj_req(i, - &adj_req_sw, &adj_req_em); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read adj req failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - if ((adj_req_sw == VOLTAGE_LEVEL_3) || - (adj_req_em == PRE_EMPHASIS_LEVEL_3)) - ret = exynos_dp_reduce_link_rate(edp_info); - - if ((DRIVE_CURRENT_SET_0_GET(lt_ctl_val[i]) == - adj_req_sw) && - (PRE_EMPHASIS_SET_0_GET(lt_ctl_val[i]) == - adj_req_em)) { - edp_info->lt_info.cr_loop[i]++; - if (edp_info->lt_info.cr_loop[i] == MAX_CR_LOOP) - ret = exynos_dp_reduce_link_rate( - edp_info); - } - - lt_ctl_val[i] = 0; - lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; - - if ((adj_req_sw == VOLTAGE_LEVEL_3) || - (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { - lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | - MAX_PRE_EMPHASIS_REACH_3; - } - exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); - } - - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP write training pattern2 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - } - - return ret; -} - -static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info - *edp_info) -{ - unsigned int ret; - unsigned char lane_stat, adj_req_sw, adj_req_em, i; - unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0,}; - unsigned char interlane_aligned = 0; - unsigned char f_bw; - unsigned char f_lane_cnt; - unsigned char sink_stat; - - mdelay(1); - - ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read lane status failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - printk(BIOS_DEBUG,"DP lane stat : %x\n", lane_stat); - - if (lane_stat & DP_LANE_STAT_CR_DONE) { - printk(BIOS_DEBUG, "DP_LANE_STAT_CR_DONE ok\n"); - ret = exynos_dp_read_byte_from_dpcd(DPCD_LN_ALIGN_UPDATED, - &sink_stat); - if (ret != EXYNOS_DP_SUCCESS) { - edp_info->lt_info.lt_status = DP_LT_FAIL; - printk(BIOS_ERR, "DP read DPCD_LN_ALIGN_UPDATED failed\n"); - return ret; - } - - interlane_aligned = (sink_stat & DPCD_INTERLANE_ALIGN_DONE); - printk(BIOS_DEBUG, "interlane_aligned: %d\n", interlane_aligned); - printk(BIOS_DEBUG, "Check %d lanes\n", edp_info->lane_cnt); - - for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(i, - &adj_req_sw, &adj_req_em); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP read adj req 1 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - - return ret; - } - - lt_ctl_val[i] = 0; - lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; - - if ((adj_req_sw == VOLTAGE_LEVEL_3) || - (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { - lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3; - lt_ctl_val[i] |= MAX_PRE_EMPHASIS_REACH_3; - } - } - - if (((lane_stat&DP_LANE_STAT_CE_DONE) && - (lane_stat&DP_LANE_STAT_SYM_LOCK)) - && (interlane_aligned == DPCD_INTERLANE_ALIGN_DONE)) { - printk(BIOS_DEBUG,"DP Equalizer training succeed\n"); - - f_bw = exynos_dp_get_link_bandwidth(); - f_lane_cnt = exynos_dp_get_lane_count(); - - printk(BIOS_DEBUG,"DP final BandWidth : %x\n", f_bw); - printk(BIOS_DEBUG,"DP final Lane Count : %x\n", f_lane_cnt); - - edp_info->lt_info.lt_status = DP_LT_FINISHED; - - exynos_dp_equalizer_err_link(edp_info); - - } else { - edp_info->lt_info.ep_loop++; - - if (edp_info->lt_info.ep_loop > MAX_EQ_LOOP) { - if (edp_info->lane_bw == DP_LANE_BW_2_70) { - ret = exynos_dp_reduce_link_rate( - edp_info); - } else { - edp_info->lt_info.lt_status = - DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); - } - } else { - for (i = 0; i < edp_info->lane_cnt; i++) - exynos_dp_set_lanex_pre_emphasis( - lt_ctl_val[i], i); - - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_LANE0_SET, - 4, lt_ctl_val); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP set lt pattern failed\n"); - edp_info->lt_info.lt_status = - DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); - } - } - } - } else if (edp_info->lane_bw == DP_LANE_BW_2_70) { - ret = exynos_dp_reduce_link_rate(edp_info); - } else { - edp_info->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); - } - - return ret; -} - -static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) -{ - /* the C compiler is almost smart enough to know this gets set. - * But not quite. - */ - unsigned int ret = 0; - int training_finished; - - /* Turn off unnecessary lane */ - if (edp_info->lane_cnt == 1) - exynos_dp_set_analog_power_down(CH1_BLOCK, 1); - - training_finished = 0; - - edp_info->lt_info.lt_status = DP_LT_START; - - /* Process here */ - while (!training_finished) { - switch (edp_info->lt_info.lt_status) { - case DP_LT_START: - ret = exynos_dp_link_start(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP LT:link start failed\n"); - training_finished = 1; - } - break; - case DP_LT_CR: - ret = exynos_dp_process_clock_recovery(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP LT:clock recovery failed\n"); - training_finished = 1; - } - break; - case DP_LT_ET: - ret = exynos_dp_process_equalizer_training(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP LT:equalizer training failed\n"); - training_finished = 1; - } - break; - case DP_LT_FINISHED: - training_finished = 1; - break; - case DP_LT_FAIL: - printk(BIOS_ERR,"DP: %s: DP_LT_FAIL: failed\n", __func__); - training_finished = 1; - ret = -1; - } - } - - return ret; -} - -static unsigned int exynos_dp_set_link_train(struct edp_device_info *edp_info) -{ - unsigned int ret; - - exynos_dp_init_training(); - - ret = exynos_dp_sw_link_training(edp_info); - if (ret != EXYNOS_DP_SUCCESS) - printk(BIOS_ERR, "DP dp_sw_link_traning() failed\n"); - - return ret; -} - -static void exynos_dp_enable_scramble(unsigned int enable) -{ - unsigned char data; - - if (enable) { - exynos_dp_enable_scrambling(DP_ENABLE); - - exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); - } else { - exynos_dp_enable_scrambling(DP_DISABLE); - exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - (u8)(data | DPCD_SCRAMBLING_DISABLED)); - } -} - -static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) -{ - unsigned int ret = 0; - unsigned int retry_cnt; - - mdelay(1); - - if (edp_info->video_info.master_mode) { - printk(BIOS_ERR, - "DP does not support master mode: bailing out\n"); - return -1; - } else { - /* debug slave */ - exynos_dp_config_video_slave_mode(&edp_info->video_info); - } - - exynos_dp_set_video_color_format(&edp_info->video_info); - - ret = exynos_dp_get_pll_lock_status(); - if (ret != PLL_LOCKED) { - printk(BIOS_ERR, "DP PLL is not locked yet\n"); - return -1; - } - - if (edp_info->video_info.master_mode == 0) { - retry_cnt = 10; - while (retry_cnt) { - ret = exynos_dp_is_slave_video_stream_clock_on(); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printk(BIOS_ERR, "DP stream_clock_on failed\n"); - return ret; - } - retry_cnt--; - mdelay(1); - } else { - printk(BIOS_DEBUG, "DP stream_clock succeeds\n"); - break; - } - } - } - - /* Set to use the register calculated M/N video */ - exynos_dp_set_video_cr_mn(CALCULATED_M, 0, 0); - - /* For video bist, Video timing must be generated by register - * not clear if we still need this. We could take it out and it - * might appear to work, then fail strangely. - */ - exynos_dp_set_video_timing_mode(VIDEO_TIMING_FROM_CAPTURE); - - /* we need to be sure this is off. */ - exynos_dp_disable_video_bist(); - - /* Disable video mute */ - exynos_dp_enable_video_mute(DP_DISABLE); - - /* Configure video Master or Slave mode */ - exynos_dp_enable_video_master(edp_info->video_info.master_mode); - - /* Enable video */ - exynos_dp_start_video(); - - if (edp_info->video_info.master_mode == 0) { - retry_cnt = 500; - while (retry_cnt) { - ret = exynos_dp_is_video_stream_on(); - if (ret != EXYNOS_DP_SUCCESS) { - retry_cnt--; - if (retry_cnt == 0) { - printk(BIOS_ERR, "DP Timeout of video stream\n"); - } - } else { - printk(BIOS_DEBUG, "DP video stream is on\n"); - break; - } - /* this is a cheap operation, involving some register - * reads, and no AUX channel IO. A ms. delay is fine. - */ - mdelay(1); - } - } - - return ret; -} - -int exynos_init_dp(struct edp_device_info *edp_info) -{ - unsigned int ret; - - - dp_phy_control(1); - - ret = exynos_dp_init_dp(); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP exynos_dp_init_dp() failed\n"); - return ret; - } - - ret = exynos_dp_handle_edid(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "EDP handle_edid fail\n"); - return ret; - } - - ret = exynos_dp_set_link_train(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "DP link training fail\n"); - return ret; - } - printk(BIOS_DEBUG, "EDP link training ok\n"); - - exynos_dp_enable_scramble(DP_ENABLE); - exynos_dp_enable_rx_to_enhanced_mode(DP_ENABLE); - exynos_dp_enable_enhanced_mode(DP_ENABLE); - - exynos_dp_set_link_bandwidth(edp_info->lane_bw); - exynos_dp_set_lane_count(edp_info->lane_cnt); - - exynos_dp_init_video(); - ret = exynos_dp_config_video(edp_info); - - if (ret != EXYNOS_DP_SUCCESS) { - printk(BIOS_ERR, "Exynos DP init failed\n"); - return ret; - } - printk(BIOS_DEBUG, "Exynos DP init done\n"); - - return ret; -} |