1*08a7aa1eSSimon Glass /* 2*08a7aa1eSSimon Glass * Copyright (C) 2012 Samsung Electronics 3*08a7aa1eSSimon Glass * 4*08a7aa1eSSimon Glass * Author: Donghwa Lee <dh09.lee@samsung.com> 5*08a7aa1eSSimon Glass * 6*08a7aa1eSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 7*08a7aa1eSSimon Glass */ 8*08a7aa1eSSimon Glass 9*08a7aa1eSSimon Glass #include <config.h> 10*08a7aa1eSSimon Glass #include <common.h> 11*08a7aa1eSSimon Glass #include <malloc.h> 12*08a7aa1eSSimon Glass #include <linux/compat.h> 13*08a7aa1eSSimon Glass #include <linux/err.h> 14*08a7aa1eSSimon Glass #include <asm/arch/clk.h> 15*08a7aa1eSSimon Glass #include <asm/arch/cpu.h> 16*08a7aa1eSSimon Glass #include <asm/arch/dp_info.h> 17*08a7aa1eSSimon Glass #include <asm/arch/dp.h> 18*08a7aa1eSSimon Glass #include <fdtdec.h> 19*08a7aa1eSSimon Glass #include <libfdt.h> 20*08a7aa1eSSimon Glass 21*08a7aa1eSSimon Glass #include "exynos_dp_lowlevel.h" 22*08a7aa1eSSimon Glass 23*08a7aa1eSSimon Glass DECLARE_GLOBAL_DATA_PTR; 24*08a7aa1eSSimon Glass 25*08a7aa1eSSimon Glass void __exynos_set_dp_phy(unsigned int onoff) 26*08a7aa1eSSimon Glass { 27*08a7aa1eSSimon Glass } 28*08a7aa1eSSimon Glass void exynos_set_dp_phy(unsigned int onoff) 29*08a7aa1eSSimon Glass __attribute__((weak, alias("__exynos_set_dp_phy"))); 30*08a7aa1eSSimon Glass 31*08a7aa1eSSimon Glass static void exynos_dp_disp_info(struct edp_disp_info *disp_info) 32*08a7aa1eSSimon Glass { 33*08a7aa1eSSimon Glass disp_info->h_total = disp_info->h_res + disp_info->h_sync_width + 34*08a7aa1eSSimon Glass disp_info->h_back_porch + disp_info->h_front_porch; 35*08a7aa1eSSimon Glass disp_info->v_total = disp_info->v_res + disp_info->v_sync_width + 36*08a7aa1eSSimon Glass disp_info->v_back_porch + disp_info->v_front_porch; 37*08a7aa1eSSimon Glass 38*08a7aa1eSSimon Glass return; 39*08a7aa1eSSimon Glass } 40*08a7aa1eSSimon Glass 41*08a7aa1eSSimon Glass static int exynos_dp_init_dp(void) 42*08a7aa1eSSimon Glass { 43*08a7aa1eSSimon Glass int ret; 44*08a7aa1eSSimon Glass exynos_dp_reset(); 45*08a7aa1eSSimon Glass 46*08a7aa1eSSimon Glass /* SW defined function Normal operation */ 47*08a7aa1eSSimon Glass exynos_dp_enable_sw_func(DP_ENABLE); 48*08a7aa1eSSimon Glass 49*08a7aa1eSSimon Glass ret = exynos_dp_init_analog_func(); 50*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) 51*08a7aa1eSSimon Glass return ret; 52*08a7aa1eSSimon Glass 53*08a7aa1eSSimon Glass exynos_dp_init_hpd(); 54*08a7aa1eSSimon Glass exynos_dp_init_aux(); 55*08a7aa1eSSimon Glass 56*08a7aa1eSSimon Glass return ret; 57*08a7aa1eSSimon Glass } 58*08a7aa1eSSimon Glass 59*08a7aa1eSSimon Glass static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) 60*08a7aa1eSSimon Glass { 61*08a7aa1eSSimon Glass int i; 62*08a7aa1eSSimon Glass unsigned char sum = 0; 63*08a7aa1eSSimon Glass 64*08a7aa1eSSimon Glass for (i = 0; i < EDID_BLOCK_LENGTH; i++) 65*08a7aa1eSSimon Glass sum = sum + edid_data[i]; 66*08a7aa1eSSimon Glass 67*08a7aa1eSSimon Glass return sum; 68*08a7aa1eSSimon Glass } 69*08a7aa1eSSimon Glass 70*08a7aa1eSSimon Glass static unsigned int exynos_dp_read_edid(void) 71*08a7aa1eSSimon Glass { 72*08a7aa1eSSimon Glass unsigned char edid[EDID_BLOCK_LENGTH * 2]; 73*08a7aa1eSSimon Glass unsigned int extend_block = 0; 74*08a7aa1eSSimon Glass unsigned char sum; 75*08a7aa1eSSimon Glass unsigned char test_vector; 76*08a7aa1eSSimon Glass int retval; 77*08a7aa1eSSimon Glass 78*08a7aa1eSSimon Glass /* 79*08a7aa1eSSimon Glass * EDID device address is 0x50. 80*08a7aa1eSSimon Glass * However, if necessary, you must have set upper address 81*08a7aa1eSSimon Glass * into E-EDID in I2C device, 0x30. 82*08a7aa1eSSimon Glass */ 83*08a7aa1eSSimon Glass 84*08a7aa1eSSimon Glass /* Read Extension Flag, Number of 128-byte EDID extension blocks */ 85*08a7aa1eSSimon Glass exynos_dp_read_byte_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, 86*08a7aa1eSSimon Glass &extend_block); 87*08a7aa1eSSimon Glass 88*08a7aa1eSSimon Glass if (extend_block > 0) { 89*08a7aa1eSSimon Glass printf("DP EDID data includes a single extension!\n"); 90*08a7aa1eSSimon Glass 91*08a7aa1eSSimon Glass /* Read EDID data */ 92*08a7aa1eSSimon Glass retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, 93*08a7aa1eSSimon Glass EDID_HEADER_PATTERN, 94*08a7aa1eSSimon Glass EDID_BLOCK_LENGTH, 95*08a7aa1eSSimon Glass &edid[EDID_HEADER_PATTERN]); 96*08a7aa1eSSimon Glass if (retval != 0) { 97*08a7aa1eSSimon Glass printf("DP EDID Read failed!\n"); 98*08a7aa1eSSimon Glass return -1; 99*08a7aa1eSSimon Glass } 100*08a7aa1eSSimon Glass sum = exynos_dp_calc_edid_check_sum(edid); 101*08a7aa1eSSimon Glass if (sum != 0) { 102*08a7aa1eSSimon Glass printf("DP EDID bad checksum!\n"); 103*08a7aa1eSSimon Glass return -1; 104*08a7aa1eSSimon Glass } 105*08a7aa1eSSimon Glass 106*08a7aa1eSSimon Glass /* Read additional EDID data */ 107*08a7aa1eSSimon Glass retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, 108*08a7aa1eSSimon Glass EDID_BLOCK_LENGTH, 109*08a7aa1eSSimon Glass EDID_BLOCK_LENGTH, 110*08a7aa1eSSimon Glass &edid[EDID_BLOCK_LENGTH]); 111*08a7aa1eSSimon Glass if (retval != 0) { 112*08a7aa1eSSimon Glass printf("DP EDID Read failed!\n"); 113*08a7aa1eSSimon Glass return -1; 114*08a7aa1eSSimon Glass } 115*08a7aa1eSSimon Glass sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); 116*08a7aa1eSSimon Glass if (sum != 0) { 117*08a7aa1eSSimon Glass printf("DP EDID bad checksum!\n"); 118*08a7aa1eSSimon Glass return -1; 119*08a7aa1eSSimon Glass } 120*08a7aa1eSSimon Glass 121*08a7aa1eSSimon Glass exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, 122*08a7aa1eSSimon Glass &test_vector); 123*08a7aa1eSSimon Glass if (test_vector & DPCD_TEST_EDID_READ) { 124*08a7aa1eSSimon Glass exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, 125*08a7aa1eSSimon Glass edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); 126*08a7aa1eSSimon Glass exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, 127*08a7aa1eSSimon Glass DPCD_TEST_EDID_CHECKSUM_WRITE); 128*08a7aa1eSSimon Glass } 129*08a7aa1eSSimon Glass } else { 130*08a7aa1eSSimon Glass debug("DP EDID data does not include any extensions.\n"); 131*08a7aa1eSSimon Glass 132*08a7aa1eSSimon Glass /* Read EDID data */ 133*08a7aa1eSSimon Glass retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, 134*08a7aa1eSSimon Glass EDID_HEADER_PATTERN, 135*08a7aa1eSSimon Glass EDID_BLOCK_LENGTH, 136*08a7aa1eSSimon Glass &edid[EDID_HEADER_PATTERN]); 137*08a7aa1eSSimon Glass 138*08a7aa1eSSimon Glass if (retval != 0) { 139*08a7aa1eSSimon Glass printf("DP EDID Read failed!\n"); 140*08a7aa1eSSimon Glass return -1; 141*08a7aa1eSSimon Glass } 142*08a7aa1eSSimon Glass sum = exynos_dp_calc_edid_check_sum(edid); 143*08a7aa1eSSimon Glass if (sum != 0) { 144*08a7aa1eSSimon Glass printf("DP EDID bad checksum!\n"); 145*08a7aa1eSSimon Glass return -1; 146*08a7aa1eSSimon Glass } 147*08a7aa1eSSimon Glass 148*08a7aa1eSSimon Glass exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, 149*08a7aa1eSSimon Glass &test_vector); 150*08a7aa1eSSimon Glass if (test_vector & DPCD_TEST_EDID_READ) { 151*08a7aa1eSSimon Glass exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, 152*08a7aa1eSSimon Glass edid[EDID_CHECKSUM]); 153*08a7aa1eSSimon Glass exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, 154*08a7aa1eSSimon Glass DPCD_TEST_EDID_CHECKSUM_WRITE); 155*08a7aa1eSSimon Glass } 156*08a7aa1eSSimon Glass } 157*08a7aa1eSSimon Glass 158*08a7aa1eSSimon Glass debug("DP EDID Read success!\n"); 159*08a7aa1eSSimon Glass 160*08a7aa1eSSimon Glass return 0; 161*08a7aa1eSSimon Glass } 162*08a7aa1eSSimon Glass 163*08a7aa1eSSimon Glass static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) 164*08a7aa1eSSimon Glass { 165*08a7aa1eSSimon Glass unsigned char buf[12]; 166*08a7aa1eSSimon Glass unsigned int ret; 167*08a7aa1eSSimon Glass unsigned char temp; 168*08a7aa1eSSimon Glass unsigned char retry_cnt; 169*08a7aa1eSSimon Glass unsigned char dpcd_rev[16]; 170*08a7aa1eSSimon Glass unsigned char lane_bw[16]; 171*08a7aa1eSSimon Glass unsigned char lane_cnt[16]; 172*08a7aa1eSSimon Glass 173*08a7aa1eSSimon Glass memset(dpcd_rev, 0, 16); 174*08a7aa1eSSimon Glass memset(lane_bw, 0, 16); 175*08a7aa1eSSimon Glass memset(lane_cnt, 0, 16); 176*08a7aa1eSSimon Glass memset(buf, 0, 12); 177*08a7aa1eSSimon Glass 178*08a7aa1eSSimon Glass retry_cnt = 5; 179*08a7aa1eSSimon Glass while (retry_cnt) { 180*08a7aa1eSSimon Glass /* Read DPCD 0x0000-0x000b */ 181*08a7aa1eSSimon Glass ret = exynos_dp_read_bytes_from_dpcd(DPCD_DPCD_REV, 12, 182*08a7aa1eSSimon Glass buf); 183*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 184*08a7aa1eSSimon Glass if (retry_cnt == 0) { 185*08a7aa1eSSimon Glass printf("DP read_byte_from_dpcd() failed\n"); 186*08a7aa1eSSimon Glass return ret; 187*08a7aa1eSSimon Glass } 188*08a7aa1eSSimon Glass retry_cnt--; 189*08a7aa1eSSimon Glass } else 190*08a7aa1eSSimon Glass break; 191*08a7aa1eSSimon Glass } 192*08a7aa1eSSimon Glass 193*08a7aa1eSSimon Glass /* */ 194*08a7aa1eSSimon Glass temp = buf[DPCD_DPCD_REV]; 195*08a7aa1eSSimon Glass if (temp == DP_DPCD_REV_10 || temp == DP_DPCD_REV_11) 196*08a7aa1eSSimon Glass edp_info->dpcd_rev = temp; 197*08a7aa1eSSimon Glass else { 198*08a7aa1eSSimon Glass printf("DP Wrong DPCD Rev : %x\n", temp); 199*08a7aa1eSSimon Glass return -ENODEV; 200*08a7aa1eSSimon Glass } 201*08a7aa1eSSimon Glass 202*08a7aa1eSSimon Glass temp = buf[DPCD_MAX_LINK_RATE]; 203*08a7aa1eSSimon Glass if (temp == DP_LANE_BW_1_62 || temp == DP_LANE_BW_2_70) 204*08a7aa1eSSimon Glass edp_info->lane_bw = temp; 205*08a7aa1eSSimon Glass else { 206*08a7aa1eSSimon Glass printf("DP Wrong MAX LINK RATE : %x\n", temp); 207*08a7aa1eSSimon Glass return -EINVAL; 208*08a7aa1eSSimon Glass } 209*08a7aa1eSSimon Glass 210*08a7aa1eSSimon Glass /* Refer VESA Display Port Standard Ver1.1a Page 120 */ 211*08a7aa1eSSimon Glass if (edp_info->dpcd_rev == DP_DPCD_REV_11) { 212*08a7aa1eSSimon Glass temp = buf[DPCD_MAX_LANE_COUNT] & 0x1f; 213*08a7aa1eSSimon Glass if (buf[DPCD_MAX_LANE_COUNT] & 0x80) 214*08a7aa1eSSimon Glass edp_info->dpcd_efc = 1; 215*08a7aa1eSSimon Glass else 216*08a7aa1eSSimon Glass edp_info->dpcd_efc = 0; 217*08a7aa1eSSimon Glass } else { 218*08a7aa1eSSimon Glass temp = buf[DPCD_MAX_LANE_COUNT]; 219*08a7aa1eSSimon Glass edp_info->dpcd_efc = 0; 220*08a7aa1eSSimon Glass } 221*08a7aa1eSSimon Glass 222*08a7aa1eSSimon Glass if (temp == DP_LANE_CNT_1 || temp == DP_LANE_CNT_2 || 223*08a7aa1eSSimon Glass temp == DP_LANE_CNT_4) { 224*08a7aa1eSSimon Glass edp_info->lane_cnt = temp; 225*08a7aa1eSSimon Glass } else { 226*08a7aa1eSSimon Glass printf("DP Wrong MAX LANE COUNT : %x\n", temp); 227*08a7aa1eSSimon Glass return -EINVAL; 228*08a7aa1eSSimon Glass } 229*08a7aa1eSSimon Glass 230*08a7aa1eSSimon Glass ret = exynos_dp_read_edid(); 231*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 232*08a7aa1eSSimon Glass printf("DP exynos_dp_read_edid() failed\n"); 233*08a7aa1eSSimon Glass return -EINVAL; 234*08a7aa1eSSimon Glass } 235*08a7aa1eSSimon Glass 236*08a7aa1eSSimon Glass return ret; 237*08a7aa1eSSimon Glass } 238*08a7aa1eSSimon Glass 239*08a7aa1eSSimon Glass static void exynos_dp_init_training(void) 240*08a7aa1eSSimon Glass { 241*08a7aa1eSSimon Glass /* 242*08a7aa1eSSimon Glass * MACRO_RST must be applied after the PLL_LOCK to avoid 243*08a7aa1eSSimon Glass * the DP inter pair skew issue for at least 10 us 244*08a7aa1eSSimon Glass */ 245*08a7aa1eSSimon Glass exynos_dp_reset_macro(); 246*08a7aa1eSSimon Glass 247*08a7aa1eSSimon Glass /* All DP analog module power up */ 248*08a7aa1eSSimon Glass exynos_dp_set_analog_power_down(POWER_ALL, 0); 249*08a7aa1eSSimon Glass } 250*08a7aa1eSSimon Glass 251*08a7aa1eSSimon Glass static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) 252*08a7aa1eSSimon Glass { 253*08a7aa1eSSimon Glass unsigned char buf[5]; 254*08a7aa1eSSimon Glass unsigned int ret = 0; 255*08a7aa1eSSimon Glass 256*08a7aa1eSSimon Glass debug("DP: %s was called\n", __func__); 257*08a7aa1eSSimon Glass 258*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_CR; 259*08a7aa1eSSimon Glass edp_info->lt_info.ep_loop = 0; 260*08a7aa1eSSimon Glass edp_info->lt_info.cr_loop[0] = 0; 261*08a7aa1eSSimon Glass edp_info->lt_info.cr_loop[1] = 0; 262*08a7aa1eSSimon Glass edp_info->lt_info.cr_loop[2] = 0; 263*08a7aa1eSSimon Glass edp_info->lt_info.cr_loop[3] = 0; 264*08a7aa1eSSimon Glass 265*08a7aa1eSSimon Glass /* Set sink to D0 (Sink Not Ready) mode. */ 266*08a7aa1eSSimon Glass ret = exynos_dp_write_byte_to_dpcd(DPCD_SINK_POWER_STATE, 267*08a7aa1eSSimon Glass DPCD_SET_POWER_STATE_D0); 268*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 269*08a7aa1eSSimon Glass printf("DP write_dpcd_byte failed\n"); 270*08a7aa1eSSimon Glass return ret; 271*08a7aa1eSSimon Glass } 272*08a7aa1eSSimon Glass 273*08a7aa1eSSimon Glass /* Set link rate and count as you want to establish */ 274*08a7aa1eSSimon Glass exynos_dp_set_link_bandwidth(edp_info->lane_bw); 275*08a7aa1eSSimon Glass exynos_dp_set_lane_count(edp_info->lane_cnt); 276*08a7aa1eSSimon Glass 277*08a7aa1eSSimon Glass /* Setup RX configuration */ 278*08a7aa1eSSimon Glass buf[0] = edp_info->lane_bw; 279*08a7aa1eSSimon Glass buf[1] = edp_info->lane_cnt; 280*08a7aa1eSSimon Glass 281*08a7aa1eSSimon Glass ret = exynos_dp_write_bytes_to_dpcd(DPCD_LINK_BW_SET, 2, 282*08a7aa1eSSimon Glass buf); 283*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 284*08a7aa1eSSimon Glass printf("DP write_dpcd_byte failed\n"); 285*08a7aa1eSSimon Glass return ret; 286*08a7aa1eSSimon Glass } 287*08a7aa1eSSimon Glass 288*08a7aa1eSSimon Glass exynos_dp_set_lane_pre_emphasis(PRE_EMPHASIS_LEVEL_0, 289*08a7aa1eSSimon Glass edp_info->lane_cnt); 290*08a7aa1eSSimon Glass 291*08a7aa1eSSimon Glass /* Set training pattern 1 */ 292*08a7aa1eSSimon Glass exynos_dp_set_training_pattern(TRAINING_PTN1); 293*08a7aa1eSSimon Glass 294*08a7aa1eSSimon Glass /* Set RX training pattern */ 295*08a7aa1eSSimon Glass buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; 296*08a7aa1eSSimon Glass 297*08a7aa1eSSimon Glass buf[1] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | 298*08a7aa1eSSimon Glass DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; 299*08a7aa1eSSimon Glass buf[2] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | 300*08a7aa1eSSimon Glass DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; 301*08a7aa1eSSimon Glass buf[3] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | 302*08a7aa1eSSimon Glass DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; 303*08a7aa1eSSimon Glass buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | 304*08a7aa1eSSimon Glass DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; 305*08a7aa1eSSimon Glass 306*08a7aa1eSSimon Glass ret = exynos_dp_write_bytes_to_dpcd(DPCD_TRAINING_PATTERN_SET, 307*08a7aa1eSSimon Glass 5, buf); 308*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 309*08a7aa1eSSimon Glass printf("DP write_dpcd_byte failed\n"); 310*08a7aa1eSSimon Glass return ret; 311*08a7aa1eSSimon Glass } 312*08a7aa1eSSimon Glass 313*08a7aa1eSSimon Glass return ret; 314*08a7aa1eSSimon Glass } 315*08a7aa1eSSimon Glass 316*08a7aa1eSSimon Glass static unsigned int exynos_dp_training_pattern_dis(void) 317*08a7aa1eSSimon Glass { 318*08a7aa1eSSimon Glass unsigned int ret = EXYNOS_DP_SUCCESS; 319*08a7aa1eSSimon Glass 320*08a7aa1eSSimon Glass exynos_dp_set_training_pattern(DP_NONE); 321*08a7aa1eSSimon Glass 322*08a7aa1eSSimon Glass ret = exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, 323*08a7aa1eSSimon Glass DPCD_TRAINING_PATTERN_DISABLED); 324*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 325*08a7aa1eSSimon Glass printf("DP request_link_training_req failed\n"); 326*08a7aa1eSSimon Glass return -EAGAIN; 327*08a7aa1eSSimon Glass } 328*08a7aa1eSSimon Glass 329*08a7aa1eSSimon Glass return ret; 330*08a7aa1eSSimon Glass } 331*08a7aa1eSSimon Glass 332*08a7aa1eSSimon Glass static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) 333*08a7aa1eSSimon Glass { 334*08a7aa1eSSimon Glass unsigned char data; 335*08a7aa1eSSimon Glass unsigned int ret = EXYNOS_DP_SUCCESS; 336*08a7aa1eSSimon Glass 337*08a7aa1eSSimon Glass ret = exynos_dp_read_byte_from_dpcd(DPCD_LANE_COUNT_SET, 338*08a7aa1eSSimon Glass &data); 339*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 340*08a7aa1eSSimon Glass printf("DP read_from_dpcd failed\n"); 341*08a7aa1eSSimon Glass return -EAGAIN; 342*08a7aa1eSSimon Glass } 343*08a7aa1eSSimon Glass 344*08a7aa1eSSimon Glass if (enable) 345*08a7aa1eSSimon Glass data = DPCD_ENHANCED_FRAME_EN | DPCD_LN_COUNT_SET(data); 346*08a7aa1eSSimon Glass else 347*08a7aa1eSSimon Glass data = DPCD_LN_COUNT_SET(data); 348*08a7aa1eSSimon Glass 349*08a7aa1eSSimon Glass ret = exynos_dp_write_byte_to_dpcd(DPCD_LANE_COUNT_SET, 350*08a7aa1eSSimon Glass data); 351*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 352*08a7aa1eSSimon Glass printf("DP write_to_dpcd failed\n"); 353*08a7aa1eSSimon Glass return -EAGAIN; 354*08a7aa1eSSimon Glass 355*08a7aa1eSSimon Glass } 356*08a7aa1eSSimon Glass 357*08a7aa1eSSimon Glass return ret; 358*08a7aa1eSSimon Glass } 359*08a7aa1eSSimon Glass 360*08a7aa1eSSimon Glass static unsigned int exynos_dp_set_enhanced_mode(unsigned char enhance_mode) 361*08a7aa1eSSimon Glass { 362*08a7aa1eSSimon Glass unsigned int ret = EXYNOS_DP_SUCCESS; 363*08a7aa1eSSimon Glass 364*08a7aa1eSSimon Glass ret = exynos_dp_enable_rx_to_enhanced_mode(enhance_mode); 365*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 366*08a7aa1eSSimon Glass printf("DP rx_enhance_mode failed\n"); 367*08a7aa1eSSimon Glass return -EAGAIN; 368*08a7aa1eSSimon Glass } 369*08a7aa1eSSimon Glass 370*08a7aa1eSSimon Glass exynos_dp_enable_enhanced_mode(enhance_mode); 371*08a7aa1eSSimon Glass 372*08a7aa1eSSimon Glass return ret; 373*08a7aa1eSSimon Glass } 374*08a7aa1eSSimon Glass 375*08a7aa1eSSimon Glass static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, 376*08a7aa1eSSimon Glass unsigned char *status) 377*08a7aa1eSSimon Glass { 378*08a7aa1eSSimon Glass unsigned int ret, i; 379*08a7aa1eSSimon Glass unsigned char buf[2]; 380*08a7aa1eSSimon Glass unsigned char lane_stat[DP_LANE_CNT_4] = {0,}; 381*08a7aa1eSSimon Glass unsigned char shift_val[DP_LANE_CNT_4] = {0,}; 382*08a7aa1eSSimon Glass 383*08a7aa1eSSimon Glass shift_val[0] = 0; 384*08a7aa1eSSimon Glass shift_val[1] = 4; 385*08a7aa1eSSimon Glass shift_val[2] = 0; 386*08a7aa1eSSimon Glass shift_val[3] = 4; 387*08a7aa1eSSimon Glass 388*08a7aa1eSSimon Glass ret = exynos_dp_read_bytes_from_dpcd(DPCD_LANE0_1_STATUS, 2, buf); 389*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 390*08a7aa1eSSimon Glass printf("DP read lane status failed\n"); 391*08a7aa1eSSimon Glass return ret; 392*08a7aa1eSSimon Glass } 393*08a7aa1eSSimon Glass 394*08a7aa1eSSimon Glass for (i = 0; i < edp_info->lane_cnt; i++) { 395*08a7aa1eSSimon Glass lane_stat[i] = (buf[(i / 2)] >> shift_val[i]) & 0x0f; 396*08a7aa1eSSimon Glass if (lane_stat[0] != lane_stat[i]) { 397*08a7aa1eSSimon Glass printf("Wrong lane status\n"); 398*08a7aa1eSSimon Glass return -EINVAL; 399*08a7aa1eSSimon Glass } 400*08a7aa1eSSimon Glass } 401*08a7aa1eSSimon Glass 402*08a7aa1eSSimon Glass *status = lane_stat[0]; 403*08a7aa1eSSimon Glass 404*08a7aa1eSSimon Glass return ret; 405*08a7aa1eSSimon Glass } 406*08a7aa1eSSimon Glass 407*08a7aa1eSSimon Glass static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, 408*08a7aa1eSSimon Glass unsigned char *sw, unsigned char *em) 409*08a7aa1eSSimon Glass { 410*08a7aa1eSSimon Glass unsigned int ret = EXYNOS_DP_SUCCESS; 411*08a7aa1eSSimon Glass unsigned char buf; 412*08a7aa1eSSimon Glass unsigned int dpcd_addr; 413*08a7aa1eSSimon Glass unsigned char shift_val[DP_LANE_CNT_4] = {0, 4, 0, 4}; 414*08a7aa1eSSimon Glass 415*08a7aa1eSSimon Glass /* lane_num value is used as array index, so this range 0 ~ 3 */ 416*08a7aa1eSSimon Glass dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); 417*08a7aa1eSSimon Glass 418*08a7aa1eSSimon Glass ret = exynos_dp_read_byte_from_dpcd(dpcd_addr, &buf); 419*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 420*08a7aa1eSSimon Glass printf("DP read adjust request failed\n"); 421*08a7aa1eSSimon Glass return -EAGAIN; 422*08a7aa1eSSimon Glass } 423*08a7aa1eSSimon Glass 424*08a7aa1eSSimon Glass *sw = ((buf >> shift_val[lane_num]) & 0x03); 425*08a7aa1eSSimon Glass *em = ((buf >> shift_val[lane_num]) & 0x0c) >> 2; 426*08a7aa1eSSimon Glass 427*08a7aa1eSSimon Glass return ret; 428*08a7aa1eSSimon Glass } 429*08a7aa1eSSimon Glass 430*08a7aa1eSSimon Glass static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) 431*08a7aa1eSSimon Glass { 432*08a7aa1eSSimon Glass int ret; 433*08a7aa1eSSimon Glass 434*08a7aa1eSSimon Glass ret = exynos_dp_training_pattern_dis(); 435*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 436*08a7aa1eSSimon Glass printf("DP training_pattern_disable() failed\n"); 437*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 438*08a7aa1eSSimon Glass } 439*08a7aa1eSSimon Glass 440*08a7aa1eSSimon Glass ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); 441*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 442*08a7aa1eSSimon Glass printf("DP set_enhanced_mode() failed\n"); 443*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 444*08a7aa1eSSimon Glass } 445*08a7aa1eSSimon Glass 446*08a7aa1eSSimon Glass return ret; 447*08a7aa1eSSimon Glass } 448*08a7aa1eSSimon Glass 449*08a7aa1eSSimon Glass static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) 450*08a7aa1eSSimon Glass { 451*08a7aa1eSSimon Glass int ret; 452*08a7aa1eSSimon Glass 453*08a7aa1eSSimon Glass if (edp_info->lane_bw == DP_LANE_BW_2_70) { 454*08a7aa1eSSimon Glass edp_info->lane_bw = DP_LANE_BW_1_62; 455*08a7aa1eSSimon Glass printf("DP Change lane bw to 1.62Gbps\n"); 456*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_START; 457*08a7aa1eSSimon Glass ret = EXYNOS_DP_SUCCESS; 458*08a7aa1eSSimon Glass } else { 459*08a7aa1eSSimon Glass ret = exynos_dp_training_pattern_dis(); 460*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) 461*08a7aa1eSSimon Glass printf("DP training_patter_disable() failed\n"); 462*08a7aa1eSSimon Glass 463*08a7aa1eSSimon Glass ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); 464*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) 465*08a7aa1eSSimon Glass printf("DP set_enhanced_mode() failed\n"); 466*08a7aa1eSSimon Glass 467*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 468*08a7aa1eSSimon Glass } 469*08a7aa1eSSimon Glass 470*08a7aa1eSSimon Glass return ret; 471*08a7aa1eSSimon Glass } 472*08a7aa1eSSimon Glass 473*08a7aa1eSSimon Glass static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info 474*08a7aa1eSSimon Glass *edp_info) 475*08a7aa1eSSimon Glass { 476*08a7aa1eSSimon Glass unsigned int ret = EXYNOS_DP_SUCCESS; 477*08a7aa1eSSimon Glass unsigned char lane_stat; 478*08a7aa1eSSimon Glass unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0, }; 479*08a7aa1eSSimon Glass unsigned int i; 480*08a7aa1eSSimon Glass unsigned char adj_req_sw; 481*08a7aa1eSSimon Glass unsigned char adj_req_em; 482*08a7aa1eSSimon Glass unsigned char buf[5]; 483*08a7aa1eSSimon Glass 484*08a7aa1eSSimon Glass debug("DP: %s was called\n", __func__); 485*08a7aa1eSSimon Glass mdelay(1); 486*08a7aa1eSSimon Glass 487*08a7aa1eSSimon Glass ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); 488*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 489*08a7aa1eSSimon Glass printf("DP read lane status failed\n"); 490*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 491*08a7aa1eSSimon Glass return ret; 492*08a7aa1eSSimon Glass } 493*08a7aa1eSSimon Glass 494*08a7aa1eSSimon Glass if (lane_stat & DP_LANE_STAT_CR_DONE) { 495*08a7aa1eSSimon Glass debug("DP clock Recovery training succeed\n"); 496*08a7aa1eSSimon Glass exynos_dp_set_training_pattern(TRAINING_PTN2); 497*08a7aa1eSSimon Glass 498*08a7aa1eSSimon Glass for (i = 0; i < edp_info->lane_cnt; i++) { 499*08a7aa1eSSimon Glass ret = exynos_dp_read_dpcd_adj_req(i, &adj_req_sw, 500*08a7aa1eSSimon Glass &adj_req_em); 501*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 502*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 503*08a7aa1eSSimon Glass return ret; 504*08a7aa1eSSimon Glass } 505*08a7aa1eSSimon Glass 506*08a7aa1eSSimon Glass lt_ctl_val[i] = 0; 507*08a7aa1eSSimon Glass lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; 508*08a7aa1eSSimon Glass 509*08a7aa1eSSimon Glass if ((adj_req_sw == VOLTAGE_LEVEL_3) 510*08a7aa1eSSimon Glass || (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { 511*08a7aa1eSSimon Glass lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | 512*08a7aa1eSSimon Glass MAX_PRE_EMPHASIS_REACH_3; 513*08a7aa1eSSimon Glass } 514*08a7aa1eSSimon Glass exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); 515*08a7aa1eSSimon Glass } 516*08a7aa1eSSimon Glass 517*08a7aa1eSSimon Glass buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2; 518*08a7aa1eSSimon Glass buf[1] = lt_ctl_val[0]; 519*08a7aa1eSSimon Glass buf[2] = lt_ctl_val[1]; 520*08a7aa1eSSimon Glass buf[3] = lt_ctl_val[2]; 521*08a7aa1eSSimon Glass buf[4] = lt_ctl_val[3]; 522*08a7aa1eSSimon Glass 523*08a7aa1eSSimon Glass ret = exynos_dp_write_bytes_to_dpcd( 524*08a7aa1eSSimon Glass DPCD_TRAINING_PATTERN_SET, 5, buf); 525*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 526*08a7aa1eSSimon Glass printf("DP write training pattern1 failed\n"); 527*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 528*08a7aa1eSSimon Glass return ret; 529*08a7aa1eSSimon Glass } else 530*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_ET; 531*08a7aa1eSSimon Glass } else { 532*08a7aa1eSSimon Glass for (i = 0; i < edp_info->lane_cnt; i++) { 533*08a7aa1eSSimon Glass lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis(i); 534*08a7aa1eSSimon Glass ret = exynos_dp_read_dpcd_adj_req(i, 535*08a7aa1eSSimon Glass &adj_req_sw, &adj_req_em); 536*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 537*08a7aa1eSSimon Glass printf("DP read adj req failed\n"); 538*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 539*08a7aa1eSSimon Glass return ret; 540*08a7aa1eSSimon Glass } 541*08a7aa1eSSimon Glass 542*08a7aa1eSSimon Glass if ((adj_req_sw == VOLTAGE_LEVEL_3) || 543*08a7aa1eSSimon Glass (adj_req_em == PRE_EMPHASIS_LEVEL_3)) 544*08a7aa1eSSimon Glass ret = exynos_dp_reduce_link_rate(edp_info); 545*08a7aa1eSSimon Glass 546*08a7aa1eSSimon Glass if ((DRIVE_CURRENT_SET_0_GET(lt_ctl_val[i]) == 547*08a7aa1eSSimon Glass adj_req_sw) && 548*08a7aa1eSSimon Glass (PRE_EMPHASIS_SET_0_GET(lt_ctl_val[i]) == 549*08a7aa1eSSimon Glass adj_req_em)) { 550*08a7aa1eSSimon Glass edp_info->lt_info.cr_loop[i]++; 551*08a7aa1eSSimon Glass if (edp_info->lt_info.cr_loop[i] == MAX_CR_LOOP) 552*08a7aa1eSSimon Glass ret = exynos_dp_reduce_link_rate( 553*08a7aa1eSSimon Glass edp_info); 554*08a7aa1eSSimon Glass } 555*08a7aa1eSSimon Glass 556*08a7aa1eSSimon Glass lt_ctl_val[i] = 0; 557*08a7aa1eSSimon Glass lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; 558*08a7aa1eSSimon Glass 559*08a7aa1eSSimon Glass if ((adj_req_sw == VOLTAGE_LEVEL_3) || 560*08a7aa1eSSimon Glass (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { 561*08a7aa1eSSimon Glass lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | 562*08a7aa1eSSimon Glass MAX_PRE_EMPHASIS_REACH_3; 563*08a7aa1eSSimon Glass } 564*08a7aa1eSSimon Glass exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); 565*08a7aa1eSSimon Glass } 566*08a7aa1eSSimon Glass 567*08a7aa1eSSimon Glass ret = exynos_dp_write_bytes_to_dpcd( 568*08a7aa1eSSimon Glass DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); 569*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 570*08a7aa1eSSimon Glass printf("DP write training pattern2 failed\n"); 571*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 572*08a7aa1eSSimon Glass return ret; 573*08a7aa1eSSimon Glass } 574*08a7aa1eSSimon Glass } 575*08a7aa1eSSimon Glass 576*08a7aa1eSSimon Glass return ret; 577*08a7aa1eSSimon Glass } 578*08a7aa1eSSimon Glass 579*08a7aa1eSSimon Glass static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info 580*08a7aa1eSSimon Glass *edp_info) 581*08a7aa1eSSimon Glass { 582*08a7aa1eSSimon Glass unsigned int ret = EXYNOS_DP_SUCCESS; 583*08a7aa1eSSimon Glass unsigned char lane_stat, adj_req_sw, adj_req_em, i; 584*08a7aa1eSSimon Glass unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0,}; 585*08a7aa1eSSimon Glass unsigned char interlane_aligned = 0; 586*08a7aa1eSSimon Glass unsigned char f_bw; 587*08a7aa1eSSimon Glass unsigned char f_lane_cnt; 588*08a7aa1eSSimon Glass unsigned char sink_stat; 589*08a7aa1eSSimon Glass 590*08a7aa1eSSimon Glass mdelay(1); 591*08a7aa1eSSimon Glass 592*08a7aa1eSSimon Glass ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); 593*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 594*08a7aa1eSSimon Glass printf("DP read lane status failed\n"); 595*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 596*08a7aa1eSSimon Glass return ret; 597*08a7aa1eSSimon Glass } 598*08a7aa1eSSimon Glass 599*08a7aa1eSSimon Glass debug("DP lane stat : %x\n", lane_stat); 600*08a7aa1eSSimon Glass 601*08a7aa1eSSimon Glass if (lane_stat & DP_LANE_STAT_CR_DONE) { 602*08a7aa1eSSimon Glass ret = exynos_dp_read_byte_from_dpcd(DPCD_LN_ALIGN_UPDATED, 603*08a7aa1eSSimon Glass &sink_stat); 604*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 605*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 606*08a7aa1eSSimon Glass 607*08a7aa1eSSimon Glass return ret; 608*08a7aa1eSSimon Glass } 609*08a7aa1eSSimon Glass 610*08a7aa1eSSimon Glass interlane_aligned = (sink_stat & DPCD_INTERLANE_ALIGN_DONE); 611*08a7aa1eSSimon Glass 612*08a7aa1eSSimon Glass for (i = 0; i < edp_info->lane_cnt; i++) { 613*08a7aa1eSSimon Glass ret = exynos_dp_read_dpcd_adj_req(i, 614*08a7aa1eSSimon Glass &adj_req_sw, &adj_req_em); 615*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 616*08a7aa1eSSimon Glass printf("DP read adj req 1 failed\n"); 617*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 618*08a7aa1eSSimon Glass 619*08a7aa1eSSimon Glass return ret; 620*08a7aa1eSSimon Glass } 621*08a7aa1eSSimon Glass 622*08a7aa1eSSimon Glass lt_ctl_val[i] = 0; 623*08a7aa1eSSimon Glass lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; 624*08a7aa1eSSimon Glass 625*08a7aa1eSSimon Glass if ((adj_req_sw == VOLTAGE_LEVEL_3) || 626*08a7aa1eSSimon Glass (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { 627*08a7aa1eSSimon Glass lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3; 628*08a7aa1eSSimon Glass lt_ctl_val[i] |= MAX_PRE_EMPHASIS_REACH_3; 629*08a7aa1eSSimon Glass } 630*08a7aa1eSSimon Glass } 631*08a7aa1eSSimon Glass 632*08a7aa1eSSimon Glass if (((lane_stat&DP_LANE_STAT_CE_DONE) && 633*08a7aa1eSSimon Glass (lane_stat&DP_LANE_STAT_SYM_LOCK)) 634*08a7aa1eSSimon Glass && (interlane_aligned == DPCD_INTERLANE_ALIGN_DONE)) { 635*08a7aa1eSSimon Glass debug("DP Equalizer training succeed\n"); 636*08a7aa1eSSimon Glass 637*08a7aa1eSSimon Glass f_bw = exynos_dp_get_link_bandwidth(); 638*08a7aa1eSSimon Glass f_lane_cnt = exynos_dp_get_lane_count(); 639*08a7aa1eSSimon Glass 640*08a7aa1eSSimon Glass debug("DP final BandWidth : %x\n", f_bw); 641*08a7aa1eSSimon Glass debug("DP final Lane Count : %x\n", f_lane_cnt); 642*08a7aa1eSSimon Glass 643*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FINISHED; 644*08a7aa1eSSimon Glass 645*08a7aa1eSSimon Glass exynos_dp_equalizer_err_link(edp_info); 646*08a7aa1eSSimon Glass 647*08a7aa1eSSimon Glass } else { 648*08a7aa1eSSimon Glass edp_info->lt_info.ep_loop++; 649*08a7aa1eSSimon Glass 650*08a7aa1eSSimon Glass if (edp_info->lt_info.ep_loop > MAX_EQ_LOOP) { 651*08a7aa1eSSimon Glass if (edp_info->lane_bw == DP_LANE_BW_2_70) { 652*08a7aa1eSSimon Glass ret = exynos_dp_reduce_link_rate( 653*08a7aa1eSSimon Glass edp_info); 654*08a7aa1eSSimon Glass } else { 655*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = 656*08a7aa1eSSimon Glass DP_LT_FAIL; 657*08a7aa1eSSimon Glass exynos_dp_equalizer_err_link(edp_info); 658*08a7aa1eSSimon Glass } 659*08a7aa1eSSimon Glass } else { 660*08a7aa1eSSimon Glass for (i = 0; i < edp_info->lane_cnt; i++) 661*08a7aa1eSSimon Glass exynos_dp_set_lanex_pre_emphasis( 662*08a7aa1eSSimon Glass lt_ctl_val[i], i); 663*08a7aa1eSSimon Glass 664*08a7aa1eSSimon Glass ret = exynos_dp_write_bytes_to_dpcd( 665*08a7aa1eSSimon Glass DPCD_TRAINING_LANE0_SET, 666*08a7aa1eSSimon Glass 4, lt_ctl_val); 667*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 668*08a7aa1eSSimon Glass printf("DP set lt pattern failed\n"); 669*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = 670*08a7aa1eSSimon Glass DP_LT_FAIL; 671*08a7aa1eSSimon Glass exynos_dp_equalizer_err_link(edp_info); 672*08a7aa1eSSimon Glass } 673*08a7aa1eSSimon Glass } 674*08a7aa1eSSimon Glass } 675*08a7aa1eSSimon Glass } else if (edp_info->lane_bw == DP_LANE_BW_2_70) { 676*08a7aa1eSSimon Glass ret = exynos_dp_reduce_link_rate(edp_info); 677*08a7aa1eSSimon Glass } else { 678*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_FAIL; 679*08a7aa1eSSimon Glass exynos_dp_equalizer_err_link(edp_info); 680*08a7aa1eSSimon Glass } 681*08a7aa1eSSimon Glass 682*08a7aa1eSSimon Glass return ret; 683*08a7aa1eSSimon Glass } 684*08a7aa1eSSimon Glass 685*08a7aa1eSSimon Glass static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) 686*08a7aa1eSSimon Glass { 687*08a7aa1eSSimon Glass unsigned int ret = 0; 688*08a7aa1eSSimon Glass int training_finished; 689*08a7aa1eSSimon Glass 690*08a7aa1eSSimon Glass /* Turn off unnecessary lane */ 691*08a7aa1eSSimon Glass if (edp_info->lane_cnt == 1) 692*08a7aa1eSSimon Glass exynos_dp_set_analog_power_down(CH1_BLOCK, 1); 693*08a7aa1eSSimon Glass 694*08a7aa1eSSimon Glass training_finished = 0; 695*08a7aa1eSSimon Glass 696*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = DP_LT_START; 697*08a7aa1eSSimon Glass 698*08a7aa1eSSimon Glass /* Process here */ 699*08a7aa1eSSimon Glass while (!training_finished) { 700*08a7aa1eSSimon Glass switch (edp_info->lt_info.lt_status) { 701*08a7aa1eSSimon Glass case DP_LT_START: 702*08a7aa1eSSimon Glass ret = exynos_dp_link_start(edp_info); 703*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 704*08a7aa1eSSimon Glass printf("DP LT:link start failed\n"); 705*08a7aa1eSSimon Glass return ret; 706*08a7aa1eSSimon Glass } 707*08a7aa1eSSimon Glass break; 708*08a7aa1eSSimon Glass case DP_LT_CR: 709*08a7aa1eSSimon Glass ret = exynos_dp_process_clock_recovery(edp_info); 710*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 711*08a7aa1eSSimon Glass printf("DP LT:clock recovery failed\n"); 712*08a7aa1eSSimon Glass return ret; 713*08a7aa1eSSimon Glass } 714*08a7aa1eSSimon Glass break; 715*08a7aa1eSSimon Glass case DP_LT_ET: 716*08a7aa1eSSimon Glass ret = exynos_dp_process_equalizer_training(edp_info); 717*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 718*08a7aa1eSSimon Glass printf("DP LT:equalizer training failed\n"); 719*08a7aa1eSSimon Glass return ret; 720*08a7aa1eSSimon Glass } 721*08a7aa1eSSimon Glass break; 722*08a7aa1eSSimon Glass case DP_LT_FINISHED: 723*08a7aa1eSSimon Glass training_finished = 1; 724*08a7aa1eSSimon Glass break; 725*08a7aa1eSSimon Glass case DP_LT_FAIL: 726*08a7aa1eSSimon Glass return -1; 727*08a7aa1eSSimon Glass } 728*08a7aa1eSSimon Glass } 729*08a7aa1eSSimon Glass 730*08a7aa1eSSimon Glass return ret; 731*08a7aa1eSSimon Glass } 732*08a7aa1eSSimon Glass 733*08a7aa1eSSimon Glass static unsigned int exynos_dp_set_link_train(struct edp_device_info *edp_info) 734*08a7aa1eSSimon Glass { 735*08a7aa1eSSimon Glass unsigned int ret; 736*08a7aa1eSSimon Glass 737*08a7aa1eSSimon Glass exynos_dp_init_training(); 738*08a7aa1eSSimon Glass 739*08a7aa1eSSimon Glass ret = exynos_dp_sw_link_training(edp_info); 740*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) 741*08a7aa1eSSimon Glass printf("DP dp_sw_link_training() failed\n"); 742*08a7aa1eSSimon Glass 743*08a7aa1eSSimon Glass return ret; 744*08a7aa1eSSimon Glass } 745*08a7aa1eSSimon Glass 746*08a7aa1eSSimon Glass static void exynos_dp_enable_scramble(unsigned int enable) 747*08a7aa1eSSimon Glass { 748*08a7aa1eSSimon Glass unsigned char data; 749*08a7aa1eSSimon Glass 750*08a7aa1eSSimon Glass if (enable) { 751*08a7aa1eSSimon Glass exynos_dp_enable_scrambling(DP_ENABLE); 752*08a7aa1eSSimon Glass 753*08a7aa1eSSimon Glass exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, 754*08a7aa1eSSimon Glass &data); 755*08a7aa1eSSimon Glass exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, 756*08a7aa1eSSimon Glass (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); 757*08a7aa1eSSimon Glass } else { 758*08a7aa1eSSimon Glass exynos_dp_enable_scrambling(DP_DISABLE); 759*08a7aa1eSSimon Glass exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, 760*08a7aa1eSSimon Glass &data); 761*08a7aa1eSSimon Glass exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, 762*08a7aa1eSSimon Glass (u8)(data | DPCD_SCRAMBLING_DISABLED)); 763*08a7aa1eSSimon Glass } 764*08a7aa1eSSimon Glass } 765*08a7aa1eSSimon Glass 766*08a7aa1eSSimon Glass static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) 767*08a7aa1eSSimon Glass { 768*08a7aa1eSSimon Glass unsigned int ret = 0; 769*08a7aa1eSSimon Glass unsigned int retry_cnt; 770*08a7aa1eSSimon Glass 771*08a7aa1eSSimon Glass mdelay(1); 772*08a7aa1eSSimon Glass 773*08a7aa1eSSimon Glass if (edp_info->video_info.master_mode) { 774*08a7aa1eSSimon Glass printf("DP does not support master mode\n"); 775*08a7aa1eSSimon Glass return -ENODEV; 776*08a7aa1eSSimon Glass } else { 777*08a7aa1eSSimon Glass /* debug slave */ 778*08a7aa1eSSimon Glass exynos_dp_config_video_slave_mode(&edp_info->video_info); 779*08a7aa1eSSimon Glass } 780*08a7aa1eSSimon Glass 781*08a7aa1eSSimon Glass exynos_dp_set_video_color_format(&edp_info->video_info); 782*08a7aa1eSSimon Glass 783*08a7aa1eSSimon Glass if (edp_info->video_info.bist_mode) { 784*08a7aa1eSSimon Glass if (exynos_dp_config_video_bist(edp_info) != 0) 785*08a7aa1eSSimon Glass return -1; 786*08a7aa1eSSimon Glass } 787*08a7aa1eSSimon Glass 788*08a7aa1eSSimon Glass ret = exynos_dp_get_pll_lock_status(); 789*08a7aa1eSSimon Glass if (ret != PLL_LOCKED) { 790*08a7aa1eSSimon Glass printf("DP PLL is not locked yet\n"); 791*08a7aa1eSSimon Glass return -EIO; 792*08a7aa1eSSimon Glass } 793*08a7aa1eSSimon Glass 794*08a7aa1eSSimon Glass if (edp_info->video_info.master_mode == 0) { 795*08a7aa1eSSimon Glass retry_cnt = 10; 796*08a7aa1eSSimon Glass while (retry_cnt) { 797*08a7aa1eSSimon Glass ret = exynos_dp_is_slave_video_stream_clock_on(); 798*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 799*08a7aa1eSSimon Glass if (retry_cnt == 0) { 800*08a7aa1eSSimon Glass printf("DP stream_clock_on failed\n"); 801*08a7aa1eSSimon Glass return ret; 802*08a7aa1eSSimon Glass } 803*08a7aa1eSSimon Glass retry_cnt--; 804*08a7aa1eSSimon Glass mdelay(1); 805*08a7aa1eSSimon Glass } else 806*08a7aa1eSSimon Glass break; 807*08a7aa1eSSimon Glass } 808*08a7aa1eSSimon Glass } 809*08a7aa1eSSimon Glass 810*08a7aa1eSSimon Glass /* Set to use the register calculated M/N video */ 811*08a7aa1eSSimon Glass exynos_dp_set_video_cr_mn(CALCULATED_M, 0, 0); 812*08a7aa1eSSimon Glass 813*08a7aa1eSSimon Glass /* For video bist, Video timing must be generated by register */ 814*08a7aa1eSSimon Glass exynos_dp_set_video_timing_mode(VIDEO_TIMING_FROM_CAPTURE); 815*08a7aa1eSSimon Glass 816*08a7aa1eSSimon Glass /* Enable video bist */ 817*08a7aa1eSSimon Glass if (edp_info->video_info.bist_pattern != COLOR_RAMP && 818*08a7aa1eSSimon Glass edp_info->video_info.bist_pattern != BALCK_WHITE_V_LINES && 819*08a7aa1eSSimon Glass edp_info->video_info.bist_pattern != COLOR_SQUARE) 820*08a7aa1eSSimon Glass exynos_dp_enable_video_bist(edp_info->video_info.bist_mode); 821*08a7aa1eSSimon Glass else 822*08a7aa1eSSimon Glass exynos_dp_enable_video_bist(DP_DISABLE); 823*08a7aa1eSSimon Glass 824*08a7aa1eSSimon Glass /* Disable video mute */ 825*08a7aa1eSSimon Glass exynos_dp_enable_video_mute(DP_DISABLE); 826*08a7aa1eSSimon Glass 827*08a7aa1eSSimon Glass /* Configure video Master or Slave mode */ 828*08a7aa1eSSimon Glass exynos_dp_enable_video_master(edp_info->video_info.master_mode); 829*08a7aa1eSSimon Glass 830*08a7aa1eSSimon Glass /* Enable video */ 831*08a7aa1eSSimon Glass exynos_dp_start_video(); 832*08a7aa1eSSimon Glass 833*08a7aa1eSSimon Glass if (edp_info->video_info.master_mode == 0) { 834*08a7aa1eSSimon Glass retry_cnt = 100; 835*08a7aa1eSSimon Glass while (retry_cnt) { 836*08a7aa1eSSimon Glass ret = exynos_dp_is_video_stream_on(); 837*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 838*08a7aa1eSSimon Glass if (retry_cnt == 0) { 839*08a7aa1eSSimon Glass printf("DP Timeout of video stream\n"); 840*08a7aa1eSSimon Glass return ret; 841*08a7aa1eSSimon Glass } 842*08a7aa1eSSimon Glass retry_cnt--; 843*08a7aa1eSSimon Glass mdelay(5); 844*08a7aa1eSSimon Glass } else 845*08a7aa1eSSimon Glass break; 846*08a7aa1eSSimon Glass } 847*08a7aa1eSSimon Glass } 848*08a7aa1eSSimon Glass 849*08a7aa1eSSimon Glass return ret; 850*08a7aa1eSSimon Glass } 851*08a7aa1eSSimon Glass 852*08a7aa1eSSimon Glass int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info) 853*08a7aa1eSSimon Glass { 854*08a7aa1eSSimon Glass unsigned int node = fdtdec_next_compatible(blob, 0, 855*08a7aa1eSSimon Glass COMPAT_SAMSUNG_EXYNOS5_DP); 856*08a7aa1eSSimon Glass if (node <= 0) { 857*08a7aa1eSSimon Glass debug("exynos_dp: Can't get device node for dp\n"); 858*08a7aa1eSSimon Glass return -ENODEV; 859*08a7aa1eSSimon Glass } 860*08a7aa1eSSimon Glass 861*08a7aa1eSSimon Glass edp_info->disp_info.h_res = fdtdec_get_int(blob, node, 862*08a7aa1eSSimon Glass "samsung,h-res", 0); 863*08a7aa1eSSimon Glass edp_info->disp_info.h_sync_width = fdtdec_get_int(blob, node, 864*08a7aa1eSSimon Glass "samsung,h-sync-width", 0); 865*08a7aa1eSSimon Glass edp_info->disp_info.h_back_porch = fdtdec_get_int(blob, node, 866*08a7aa1eSSimon Glass "samsung,h-back-porch", 0); 867*08a7aa1eSSimon Glass edp_info->disp_info.h_front_porch = fdtdec_get_int(blob, node, 868*08a7aa1eSSimon Glass "samsung,h-front-porch", 0); 869*08a7aa1eSSimon Glass edp_info->disp_info.v_res = fdtdec_get_int(blob, node, 870*08a7aa1eSSimon Glass "samsung,v-res", 0); 871*08a7aa1eSSimon Glass edp_info->disp_info.v_sync_width = fdtdec_get_int(blob, node, 872*08a7aa1eSSimon Glass "samsung,v-sync-width", 0); 873*08a7aa1eSSimon Glass edp_info->disp_info.v_back_porch = fdtdec_get_int(blob, node, 874*08a7aa1eSSimon Glass "samsung,v-back-porch", 0); 875*08a7aa1eSSimon Glass edp_info->disp_info.v_front_porch = fdtdec_get_int(blob, node, 876*08a7aa1eSSimon Glass "samsung,v-front-porch", 0); 877*08a7aa1eSSimon Glass edp_info->disp_info.v_sync_rate = fdtdec_get_int(blob, node, 878*08a7aa1eSSimon Glass "samsung,v-sync-rate", 0); 879*08a7aa1eSSimon Glass 880*08a7aa1eSSimon Glass edp_info->lt_info.lt_status = fdtdec_get_int(blob, node, 881*08a7aa1eSSimon Glass "samsung,lt-status", 0); 882*08a7aa1eSSimon Glass 883*08a7aa1eSSimon Glass edp_info->video_info.master_mode = fdtdec_get_int(blob, node, 884*08a7aa1eSSimon Glass "samsung,master-mode", 0); 885*08a7aa1eSSimon Glass edp_info->video_info.bist_mode = fdtdec_get_int(blob, node, 886*08a7aa1eSSimon Glass "samsung,bist-mode", 0); 887*08a7aa1eSSimon Glass edp_info->video_info.bist_pattern = fdtdec_get_int(blob, node, 888*08a7aa1eSSimon Glass "samsung,bist-pattern", 0); 889*08a7aa1eSSimon Glass edp_info->video_info.h_sync_polarity = fdtdec_get_int(blob, node, 890*08a7aa1eSSimon Glass "samsung,h-sync-polarity", 0); 891*08a7aa1eSSimon Glass edp_info->video_info.v_sync_polarity = fdtdec_get_int(blob, node, 892*08a7aa1eSSimon Glass "samsung,v-sync-polarity", 0); 893*08a7aa1eSSimon Glass edp_info->video_info.interlaced = fdtdec_get_int(blob, node, 894*08a7aa1eSSimon Glass "samsung,interlaced", 0); 895*08a7aa1eSSimon Glass edp_info->video_info.color_space = fdtdec_get_int(blob, node, 896*08a7aa1eSSimon Glass "samsung,color-space", 0); 897*08a7aa1eSSimon Glass edp_info->video_info.dynamic_range = fdtdec_get_int(blob, node, 898*08a7aa1eSSimon Glass "samsung,dynamic-range", 0); 899*08a7aa1eSSimon Glass edp_info->video_info.ycbcr_coeff = fdtdec_get_int(blob, node, 900*08a7aa1eSSimon Glass "samsung,ycbcr-coeff", 0); 901*08a7aa1eSSimon Glass edp_info->video_info.color_depth = fdtdec_get_int(blob, node, 902*08a7aa1eSSimon Glass "samsung,color-depth", 0); 903*08a7aa1eSSimon Glass return 0; 904*08a7aa1eSSimon Glass } 905*08a7aa1eSSimon Glass 906*08a7aa1eSSimon Glass unsigned int exynos_init_dp(void) 907*08a7aa1eSSimon Glass { 908*08a7aa1eSSimon Glass unsigned int ret; 909*08a7aa1eSSimon Glass struct edp_device_info *edp_info; 910*08a7aa1eSSimon Glass 911*08a7aa1eSSimon Glass edp_info = kzalloc(sizeof(struct edp_device_info), GFP_KERNEL); 912*08a7aa1eSSimon Glass if (!edp_info) { 913*08a7aa1eSSimon Glass debug("failed to allocate edp device object.\n"); 914*08a7aa1eSSimon Glass return -EFAULT; 915*08a7aa1eSSimon Glass } 916*08a7aa1eSSimon Glass 917*08a7aa1eSSimon Glass if (exynos_dp_parse_dt(gd->fdt_blob, edp_info)) 918*08a7aa1eSSimon Glass debug("unable to parse DP DT node\n"); 919*08a7aa1eSSimon Glass 920*08a7aa1eSSimon Glass exynos_dp_set_base_addr(); 921*08a7aa1eSSimon Glass 922*08a7aa1eSSimon Glass exynos_dp_disp_info(&edp_info->disp_info); 923*08a7aa1eSSimon Glass 924*08a7aa1eSSimon Glass exynos_set_dp_phy(1); 925*08a7aa1eSSimon Glass 926*08a7aa1eSSimon Glass ret = exynos_dp_init_dp(); 927*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 928*08a7aa1eSSimon Glass printf("DP exynos_dp_init_dp() failed\n"); 929*08a7aa1eSSimon Glass return ret; 930*08a7aa1eSSimon Glass } 931*08a7aa1eSSimon Glass 932*08a7aa1eSSimon Glass ret = exynos_dp_handle_edid(edp_info); 933*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 934*08a7aa1eSSimon Glass printf("EDP handle_edid fail\n"); 935*08a7aa1eSSimon Glass return ret; 936*08a7aa1eSSimon Glass } 937*08a7aa1eSSimon Glass 938*08a7aa1eSSimon Glass ret = exynos_dp_set_link_train(edp_info); 939*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 940*08a7aa1eSSimon Glass printf("DP link training fail\n"); 941*08a7aa1eSSimon Glass return ret; 942*08a7aa1eSSimon Glass } 943*08a7aa1eSSimon Glass 944*08a7aa1eSSimon Glass exynos_dp_enable_scramble(DP_ENABLE); 945*08a7aa1eSSimon Glass exynos_dp_enable_rx_to_enhanced_mode(DP_ENABLE); 946*08a7aa1eSSimon Glass exynos_dp_enable_enhanced_mode(DP_ENABLE); 947*08a7aa1eSSimon Glass 948*08a7aa1eSSimon Glass exynos_dp_set_link_bandwidth(edp_info->lane_bw); 949*08a7aa1eSSimon Glass exynos_dp_set_lane_count(edp_info->lane_cnt); 950*08a7aa1eSSimon Glass 951*08a7aa1eSSimon Glass exynos_dp_init_video(); 952*08a7aa1eSSimon Glass ret = exynos_dp_config_video(edp_info); 953*08a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 954*08a7aa1eSSimon Glass printf("Exynos DP init failed\n"); 955*08a7aa1eSSimon Glass return ret; 956*08a7aa1eSSimon Glass } 957*08a7aa1eSSimon Glass 958*08a7aa1eSSimon Glass debug("Exynos DP init done\n"); 959*08a7aa1eSSimon Glass 960*08a7aa1eSSimon Glass return ret; 961*08a7aa1eSSimon Glass } 962