16f920c07SWyon Bi /* 26f920c07SWyon Bi * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 36f920c07SWyon Bi * 46f920c07SWyon Bi * SPDX-License-Identifier: GPL-2.0+ 56f920c07SWyon Bi */ 66f920c07SWyon Bi 76f920c07SWyon Bi #include <config.h> 86f920c07SWyon Bi #include <common.h> 96f920c07SWyon Bi #include <errno.h> 106f920c07SWyon Bi #include <malloc.h> 116f920c07SWyon Bi #include <asm/unaligned.h> 126f920c07SWyon Bi #include <asm/io.h> 136f920c07SWyon Bi #include <dm/device.h> 14cb17ca6cSSandy Huang #include <dm/of_access.h> 156f920c07SWyon Bi #include <dm/read.h> 167adc0066SWyon Bi #include <linux/bitfield.h> 176f920c07SWyon Bi #include <linux/list.h> 186f920c07SWyon Bi #include <syscon.h> 196f920c07SWyon Bi #include <asm/arch-rockchip/clock.h> 206f920c07SWyon Bi #include <asm/gpio.h> 216f920c07SWyon Bi 226f920c07SWyon Bi #include "rockchip_display.h" 236f920c07SWyon Bi #include "rockchip_crtc.h" 246f920c07SWyon Bi #include "rockchip_connector.h" 256f920c07SWyon Bi #include "analogix_dp.h" 266f920c07SWyon Bi 277adc0066SWyon Bi #define RK3588_GRF_VO1_CON0 0x0000 287adc0066SWyon Bi #define EDP_MODE BIT(0) 297adc0066SWyon Bi #define RK3588_GRF_VO1_CON1 0x0004 307adc0066SWyon Bi 316f920c07SWyon Bi /** 326f920c07SWyon Bi * struct rockchip_dp_chip_data - splite the grf setting of kind of chips 336f920c07SWyon Bi * @lcdsel_grf_reg: grf register offset of lcdc select 346f920c07SWyon Bi * @lcdsel_big: reg value of selecting vop big for eDP 356f920c07SWyon Bi * @lcdsel_lit: reg value of selecting vop little for eDP 36699c29a5SWyon Bi * @chip_type: specific chip type 37699c29a5SWyon Bi * @ssc: check if SSC is supported by source 386f920c07SWyon Bi */ 396f920c07SWyon Bi struct rockchip_dp_chip_data { 406f920c07SWyon Bi u32 lcdsel_grf_reg; 416f920c07SWyon Bi u32 lcdsel_big; 426f920c07SWyon Bi u32 lcdsel_lit; 436f920c07SWyon Bi u32 chip_type; 44699c29a5SWyon Bi bool ssc; 457adc0066SWyon Bi 467adc0066SWyon Bi u32 max_link_rate; 477adc0066SWyon Bi u32 max_lane_count; 486f920c07SWyon Bi }; 496f920c07SWyon Bi 506f920c07SWyon Bi static void 516f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, 526f920c07SWyon Bi bool enable) 536f920c07SWyon Bi { 546f920c07SWyon Bi u8 data; 556f920c07SWyon Bi 566f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); 576f920c07SWyon Bi 586f920c07SWyon Bi if (enable) 596f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, 606f920c07SWyon Bi DP_LANE_COUNT_ENHANCED_FRAME_EN | 616f920c07SWyon Bi DPCD_LANE_COUNT_SET(data)); 626f920c07SWyon Bi else 636f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, 646f920c07SWyon Bi DPCD_LANE_COUNT_SET(data)); 656f920c07SWyon Bi } 666f920c07SWyon Bi 676f920c07SWyon Bi static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) 686f920c07SWyon Bi { 696f920c07SWyon Bi u8 data; 706f920c07SWyon Bi int retval; 716f920c07SWyon Bi 726f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); 736f920c07SWyon Bi retval = DPCD_ENHANCED_FRAME_CAP(data); 746f920c07SWyon Bi 756f920c07SWyon Bi return retval; 766f920c07SWyon Bi } 776f920c07SWyon Bi 786f920c07SWyon Bi static void analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp) 796f920c07SWyon Bi { 806f920c07SWyon Bi u8 data; 816f920c07SWyon Bi 826f920c07SWyon Bi data = analogix_dp_is_enhanced_mode_available(dp); 836f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(dp, data); 846f920c07SWyon Bi analogix_dp_enable_enhanced_mode(dp, data); 856f920c07SWyon Bi } 866f920c07SWyon Bi 876f920c07SWyon Bi static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) 886f920c07SWyon Bi { 896f920c07SWyon Bi analogix_dp_set_training_pattern(dp, DP_NONE); 906f920c07SWyon Bi 916f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET, 926f920c07SWyon Bi DP_TRAINING_PATTERN_DISABLE); 936f920c07SWyon Bi } 946f920c07SWyon Bi 956f920c07SWyon Bi static int analogix_dp_link_start(struct analogix_dp_device *dp) 966f920c07SWyon Bi { 976f920c07SWyon Bi u8 buf[4]; 98a6285d17SWyon Bi int lane, lane_count, retval; 996f920c07SWyon Bi 1006f920c07SWyon Bi lane_count = dp->link_train.lane_count; 1016f920c07SWyon Bi 1026f920c07SWyon Bi dp->link_train.lt_state = CLOCK_RECOVERY; 1036f920c07SWyon Bi dp->link_train.eq_loop = 0; 1046f920c07SWyon Bi 1056f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 1066f920c07SWyon Bi dp->link_train.cr_loop[lane] = 0; 1076f920c07SWyon Bi 1086f920c07SWyon Bi /* Set link rate and count as you want to establish*/ 1096f920c07SWyon Bi analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); 1106f920c07SWyon Bi analogix_dp_set_lane_count(dp, dp->link_train.lane_count); 1116f920c07SWyon Bi 1126f920c07SWyon Bi /* Setup RX configuration */ 1136f920c07SWyon Bi buf[0] = dp->link_train.link_rate; 1146f920c07SWyon Bi buf[1] = dp->link_train.lane_count; 1156f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); 1166f920c07SWyon Bi if (retval) 1176f920c07SWyon Bi return retval; 1186f920c07SWyon Bi 119699c29a5SWyon Bi /* Spread AMP if required, enable 8b/10b coding */ 120699c29a5SWyon Bi buf[0] = analogix_dp_ssc_supported(dp) ? DP_SPREAD_AMP_0_5 : 0; 121699c29a5SWyon Bi buf[1] = DP_SET_ANSI_8B10B; 122699c29a5SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_DOWNSPREAD_CTRL, 123699c29a5SWyon Bi 2, buf); 124699c29a5SWyon Bi if (retval < 0) 125699c29a5SWyon Bi return retval; 126699c29a5SWyon Bi 127253c2dc8SWyon Bi /* Set TX voltage-swing and pre-emphasis to minimum */ 1286f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 129253c2dc8SWyon Bi dp->link_train.training_lane[lane] = 130253c2dc8SWyon Bi DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | 131253c2dc8SWyon Bi DP_TRAIN_PRE_EMPH_LEVEL_0; 132253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 1336f920c07SWyon Bi 1346f920c07SWyon Bi /* Set training pattern 1 */ 1356f920c07SWyon Bi analogix_dp_set_training_pattern(dp, TRAINING_PTN1); 1366f920c07SWyon Bi 1376f920c07SWyon Bi /* Set RX training pattern */ 1386f920c07SWyon Bi retval = analogix_dp_write_byte_to_dpcd(dp, 1396f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 1406f920c07SWyon Bi DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); 1416f920c07SWyon Bi if (retval) 1426f920c07SWyon Bi return retval; 1436f920c07SWyon Bi 1446f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 1456f920c07SWyon Bi buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | 1466f920c07SWyon Bi DP_TRAIN_VOLTAGE_SWING_LEVEL_0; 1476f920c07SWyon Bi 1486f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, 1496f920c07SWyon Bi lane_count, buf); 1506f920c07SWyon Bi 1516f920c07SWyon Bi return retval; 1526f920c07SWyon Bi } 1536f920c07SWyon Bi 1546f920c07SWyon Bi static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) 1556f920c07SWyon Bi { 1566f920c07SWyon Bi int shift = (lane & 1) * 4; 1576f920c07SWyon Bi u8 link_value = link_status[lane >> 1]; 1586f920c07SWyon Bi 1596f920c07SWyon Bi return (link_value >> shift) & 0xf; 1606f920c07SWyon Bi } 1616f920c07SWyon Bi 1626f920c07SWyon Bi static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count) 1636f920c07SWyon Bi { 1646f920c07SWyon Bi int lane; 1656f920c07SWyon Bi u8 lane_status; 1666f920c07SWyon Bi 1676f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 1686f920c07SWyon Bi lane_status = analogix_dp_get_lane_status(link_status, lane); 1696f920c07SWyon Bi if ((lane_status & DP_LANE_CR_DONE) == 0) 1706f920c07SWyon Bi return -EINVAL; 1716f920c07SWyon Bi } 1726f920c07SWyon Bi return 0; 1736f920c07SWyon Bi } 1746f920c07SWyon Bi 1756f920c07SWyon Bi static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align, 1766f920c07SWyon Bi int lane_count) 1776f920c07SWyon Bi { 1786f920c07SWyon Bi int lane; 1796f920c07SWyon Bi u8 lane_status; 1806f920c07SWyon Bi 1816f920c07SWyon Bi if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) 1826f920c07SWyon Bi return -EINVAL; 1836f920c07SWyon Bi 1846f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 1856f920c07SWyon Bi lane_status = analogix_dp_get_lane_status(link_status, lane); 1866f920c07SWyon Bi lane_status &= DP_CHANNEL_EQ_BITS; 1876f920c07SWyon Bi if (lane_status != DP_CHANNEL_EQ_BITS) 1886f920c07SWyon Bi return -EINVAL; 1896f920c07SWyon Bi } 1906f920c07SWyon Bi 1916f920c07SWyon Bi return 0; 1926f920c07SWyon Bi } 1936f920c07SWyon Bi 1946f920c07SWyon Bi static unsigned char 1956f920c07SWyon Bi analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane) 1966f920c07SWyon Bi { 1976f920c07SWyon Bi int shift = (lane & 1) * 4; 1986f920c07SWyon Bi u8 link_value = adjust_request[lane >> 1]; 1996f920c07SWyon Bi 2006f920c07SWyon Bi return (link_value >> shift) & 0x3; 2016f920c07SWyon Bi } 2026f920c07SWyon Bi 2036f920c07SWyon Bi static unsigned char analogix_dp_get_adjust_request_pre_emphasis( 2046f920c07SWyon Bi u8 adjust_request[2], 2056f920c07SWyon Bi int lane) 2066f920c07SWyon Bi { 2076f920c07SWyon Bi int shift = (lane & 1) * 4; 2086f920c07SWyon Bi u8 link_value = adjust_request[lane >> 1]; 2096f920c07SWyon Bi 2106f920c07SWyon Bi return ((link_value >> shift) & 0xc) >> 2; 2116f920c07SWyon Bi } 2126f920c07SWyon Bi 2136f920c07SWyon Bi static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) 2146f920c07SWyon Bi { 2156f920c07SWyon Bi analogix_dp_training_pattern_dis(dp); 2166f920c07SWyon Bi analogix_dp_set_enhanced_mode(dp); 2176f920c07SWyon Bi 2186f920c07SWyon Bi dp->link_train.lt_state = FAILED; 2196f920c07SWyon Bi } 2206f920c07SWyon Bi 2216f920c07SWyon Bi static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp, 2226f920c07SWyon Bi u8 adjust_request[2]) 2236f920c07SWyon Bi { 2246f920c07SWyon Bi int lane, lane_count; 2256f920c07SWyon Bi u8 voltage_swing, pre_emphasis, training_lane; 2266f920c07SWyon Bi 2276f920c07SWyon Bi lane_count = dp->link_train.lane_count; 2286f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2296f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 2306f920c07SWyon Bi adjust_request, lane); 2316f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 2326f920c07SWyon Bi adjust_request, lane); 2336f920c07SWyon Bi training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | 2346f920c07SWyon Bi DPCD_PRE_EMPHASIS_SET(pre_emphasis); 2356f920c07SWyon Bi 2366f920c07SWyon Bi if (voltage_swing == VOLTAGE_LEVEL_3) 2376f920c07SWyon Bi training_lane |= DP_TRAIN_MAX_SWING_REACHED; 2386f920c07SWyon Bi if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) 2396f920c07SWyon Bi training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 2406f920c07SWyon Bi 2416f920c07SWyon Bi dp->link_train.training_lane[lane] = training_lane; 2426f920c07SWyon Bi } 2436f920c07SWyon Bi } 2446f920c07SWyon Bi 2457adc0066SWyon Bi static bool analogix_dp_tps3_supported(struct analogix_dp_device *dp) 2467adc0066SWyon Bi { 2477adc0066SWyon Bi bool source_tps3_supported, sink_tps3_supported; 2487adc0066SWyon Bi u8 dpcd = 0; 2497adc0066SWyon Bi 2507adc0066SWyon Bi source_tps3_supported = 2517adc0066SWyon Bi dp->video_info.max_link_rate == DP_LINK_BW_5_4; 2527adc0066SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &dpcd); 2537adc0066SWyon Bi sink_tps3_supported = dpcd & DP_TPS3_SUPPORTED; 2547adc0066SWyon Bi 2557adc0066SWyon Bi return source_tps3_supported && sink_tps3_supported; 2567adc0066SWyon Bi } 2577adc0066SWyon Bi 2586f920c07SWyon Bi static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) 2596f920c07SWyon Bi { 2606f920c07SWyon Bi int lane, lane_count, retval; 2616f920c07SWyon Bi u8 voltage_swing, pre_emphasis, training_lane; 2626f920c07SWyon Bi u8 link_status[2], adjust_request[2]; 2637adc0066SWyon Bi u8 training_pattern = TRAINING_PTN2; 2646f920c07SWyon Bi 2651a00cf6eSWyon Bi drm_dp_link_train_clock_recovery_delay(dp->dpcd); 2666f920c07SWyon Bi 2676f920c07SWyon Bi lane_count = dp->link_train.lane_count; 2686f920c07SWyon Bi 2696f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 2706f920c07SWyon Bi DP_LANE0_1_STATUS, 2, link_status); 2716f920c07SWyon Bi if (retval) 2726f920c07SWyon Bi return retval; 2736f920c07SWyon Bi 2746f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { 2757adc0066SWyon Bi if (analogix_dp_tps3_supported(dp)) 2767adc0066SWyon Bi training_pattern = TRAINING_PTN3; 2777adc0066SWyon Bi 2787adc0066SWyon Bi /* set training pattern for EQ */ 2797adc0066SWyon Bi analogix_dp_set_training_pattern(dp, training_pattern); 2806f920c07SWyon Bi 2816f920c07SWyon Bi retval = analogix_dp_write_byte_to_dpcd(dp, 2826f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 2837adc0066SWyon Bi (training_pattern == TRAINING_PTN3 ? 2847adc0066SWyon Bi DP_TRAINING_PATTERN_3 : DP_TRAINING_PATTERN_2)); 2856f920c07SWyon Bi if (retval) 2866f920c07SWyon Bi return retval; 2876f920c07SWyon Bi 2886f920c07SWyon Bi dev_info(dp->dev, "Link Training Clock Recovery success\n"); 2896f920c07SWyon Bi dp->link_train.lt_state = EQUALIZER_TRAINING; 29010d706d5SWyon Bi 29110d706d5SWyon Bi return 0; 2926f920c07SWyon Bi } else { 29310d706d5SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 29410d706d5SWyon Bi DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); 29510d706d5SWyon Bi if (retval) 29610d706d5SWyon Bi return retval; 29710d706d5SWyon Bi 2986f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2996f920c07SWyon Bi training_lane = analogix_dp_get_lane_link_training( 3006f920c07SWyon Bi dp, lane); 3016f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 3026f920c07SWyon Bi adjust_request, lane); 3036f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 3046f920c07SWyon Bi adjust_request, lane); 3056f920c07SWyon Bi 3066f920c07SWyon Bi if (DPCD_VOLTAGE_SWING_GET(training_lane) == 3076f920c07SWyon Bi voltage_swing && 3086f920c07SWyon Bi DPCD_PRE_EMPHASIS_GET(training_lane) == 3096f920c07SWyon Bi pre_emphasis) 3106f920c07SWyon Bi dp->link_train.cr_loop[lane]++; 3116f920c07SWyon Bi 3126f920c07SWyon Bi if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || 3136f920c07SWyon Bi voltage_swing == VOLTAGE_LEVEL_3 || 3146f920c07SWyon Bi pre_emphasis == PRE_EMPHASIS_LEVEL_3) { 3156f920c07SWyon Bi dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", 3166f920c07SWyon Bi dp->link_train.cr_loop[lane], 3176f920c07SWyon Bi voltage_swing, pre_emphasis); 3186f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3196f920c07SWyon Bi return -EIO; 3206f920c07SWyon Bi } 3216f920c07SWyon Bi } 3226f920c07SWyon Bi } 3236f920c07SWyon Bi 3246f920c07SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 325253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 3266f920c07SWyon Bi 3276f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, 3286f920c07SWyon Bi DP_TRAINING_LANE0_SET, lane_count, 3296f920c07SWyon Bi dp->link_train.training_lane); 3306f920c07SWyon Bi if (retval) 3316f920c07SWyon Bi return retval; 3326f920c07SWyon Bi 3336f920c07SWyon Bi return retval; 3346f920c07SWyon Bi } 3356f920c07SWyon Bi 3366f920c07SWyon Bi static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) 3376f920c07SWyon Bi { 338253c2dc8SWyon Bi int lane_count, retval; 3396f920c07SWyon Bi u32 reg; 3406f920c07SWyon Bi u8 link_align, link_status[2], adjust_request[2]; 3416f920c07SWyon Bi 3421a00cf6eSWyon Bi drm_dp_link_train_channel_eq_delay(dp->dpcd); 3436f920c07SWyon Bi 3446f920c07SWyon Bi lane_count = dp->link_train.lane_count; 3456f920c07SWyon Bi 3466f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 3476f920c07SWyon Bi DP_LANE0_1_STATUS, 2, link_status); 3486f920c07SWyon Bi if (retval) 3496f920c07SWyon Bi return retval; 3506f920c07SWyon Bi 3516f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { 3526f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3536f920c07SWyon Bi return -EIO; 3546f920c07SWyon Bi } 3556f920c07SWyon Bi 3566f920c07SWyon Bi retval = analogix_dp_read_byte_from_dpcd(dp, 3576f920c07SWyon Bi DP_LANE_ALIGN_STATUS_UPDATED, &link_align); 3586f920c07SWyon Bi if (retval) 3596f920c07SWyon Bi return retval; 3606f920c07SWyon Bi 3616f920c07SWyon Bi if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { 3626f920c07SWyon Bi /* traing pattern Set to Normal */ 3636f920c07SWyon Bi analogix_dp_training_pattern_dis(dp); 3646f920c07SWyon Bi 3656f920c07SWyon Bi printf("Link Training success!\n"); 3666f920c07SWyon Bi 3676f920c07SWyon Bi analogix_dp_get_link_bandwidth(dp, ®); 3686f920c07SWyon Bi dp->link_train.link_rate = reg; 3696f920c07SWyon Bi analogix_dp_get_lane_count(dp, ®); 3706f920c07SWyon Bi dp->link_train.lane_count = reg; 3716f920c07SWyon Bi 3726f920c07SWyon Bi printf("final link rate = 0x%.2x, lane count = 0x%.2x\n", 3736f920c07SWyon Bi dp->link_train.link_rate, dp->link_train.lane_count); 3746f920c07SWyon Bi 3756f920c07SWyon Bi /* set enhanced mode if available */ 3766f920c07SWyon Bi analogix_dp_set_enhanced_mode(dp); 3776f920c07SWyon Bi dp->link_train.lt_state = FINISHED; 3786f920c07SWyon Bi 3796f920c07SWyon Bi return 0; 3806f920c07SWyon Bi } 3816f920c07SWyon Bi 3826f920c07SWyon Bi /* not all locked */ 3836f920c07SWyon Bi dp->link_train.eq_loop++; 3846f920c07SWyon Bi 3856f920c07SWyon Bi if (dp->link_train.eq_loop > MAX_EQ_LOOP) { 3866f920c07SWyon Bi dev_dbg(dp->dev, "EQ Max loop\n"); 3876f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3886f920c07SWyon Bi return -EIO; 3896f920c07SWyon Bi } 3906f920c07SWyon Bi 39110d706d5SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 39210d706d5SWyon Bi DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); 39310d706d5SWyon Bi if (retval) 39410d706d5SWyon Bi return retval; 39510d706d5SWyon Bi 39610d706d5SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 397253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 3986f920c07SWyon Bi 3996f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, 4006f920c07SWyon Bi lane_count, dp->link_train.training_lane); 4016f920c07SWyon Bi 4026f920c07SWyon Bi return retval; 4036f920c07SWyon Bi } 4046f920c07SWyon Bi 4056f920c07SWyon Bi static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, 4066f920c07SWyon Bi u8 *bandwidth) 4076f920c07SWyon Bi { 4086f920c07SWyon Bi u8 data; 4096f920c07SWyon Bi 4106f920c07SWyon Bi /* 4116f920c07SWyon Bi * For DP rev.1.1, Maximum link rate of Main Link lanes 4126f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps 4136f920c07SWyon Bi * For DP rev.1.2, Maximum link rate of Main Link lanes 4146f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps 4156f920c07SWyon Bi */ 4166f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); 4176f920c07SWyon Bi *bandwidth = data; 4186f920c07SWyon Bi } 4196f920c07SWyon Bi 4206f920c07SWyon Bi static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, 4216f920c07SWyon Bi u8 *lane_count) 4226f920c07SWyon Bi { 4236f920c07SWyon Bi u8 data; 4246f920c07SWyon Bi 4256f920c07SWyon Bi /* 4266f920c07SWyon Bi * For DP rev.1.1, Maximum number of Main Link lanes 4276f920c07SWyon Bi * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes 4286f920c07SWyon Bi */ 4296f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); 4306f920c07SWyon Bi *lane_count = DPCD_MAX_LANE_COUNT(data); 4316f920c07SWyon Bi } 4326f920c07SWyon Bi 4336f920c07SWyon Bi static int analogix_dp_init_training(struct analogix_dp_device *dp, 4346f920c07SWyon Bi enum link_lane_count_type max_lane, 4356f920c07SWyon Bi int max_rate) 4366f920c07SWyon Bi { 437699c29a5SWyon Bi u8 dpcd; 438699c29a5SWyon Bi 4396f920c07SWyon Bi /* 4406f920c07SWyon Bi * MACRO_RST must be applied after the PLL_LOCK to avoid 4416f920c07SWyon Bi * the DP inter pair skew issue for at least 10 us 4426f920c07SWyon Bi */ 4436f920c07SWyon Bi analogix_dp_reset_macro(dp); 4446f920c07SWyon Bi 4456f920c07SWyon Bi /* Initialize by reading RX's DPCD */ 4466f920c07SWyon Bi analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); 4476f920c07SWyon Bi analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); 4486f920c07SWyon Bi 4496f920c07SWyon Bi /* Setup TX lane count & rate */ 4509cf99b47SWyon Bi dp->link_train.lane_count = min_t(u8, dp->link_train.lane_count, 4519cf99b47SWyon Bi max_lane); 4529cf99b47SWyon Bi dp->link_train.link_rate = min_t(u32, dp->link_train.link_rate, 4539cf99b47SWyon Bi max_rate); 4546f920c07SWyon Bi 455699c29a5SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_DOWNSPREAD, &dpcd); 456699c29a5SWyon Bi dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); 457699c29a5SWyon Bi 4586f920c07SWyon Bi /* All DP analog module power up */ 4596f920c07SWyon Bi analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); 4606f920c07SWyon Bi 4616f920c07SWyon Bi return 0; 4626f920c07SWyon Bi } 4636f920c07SWyon Bi 4646f920c07SWyon Bi static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) 4656f920c07SWyon Bi { 4666f920c07SWyon Bi int retval = 0, training_finished = 0; 4676f920c07SWyon Bi 4686f920c07SWyon Bi dp->link_train.lt_state = START; 4696f920c07SWyon Bi 4706f920c07SWyon Bi /* Process here */ 4716f920c07SWyon Bi while (!retval && !training_finished) { 4726f920c07SWyon Bi switch (dp->link_train.lt_state) { 4736f920c07SWyon Bi case START: 4746f920c07SWyon Bi retval = analogix_dp_link_start(dp); 4756f920c07SWyon Bi if (retval) 4766f920c07SWyon Bi dev_err(dp->dev, "LT link start failed!\n"); 4776f920c07SWyon Bi break; 4786f920c07SWyon Bi case CLOCK_RECOVERY: 4796f920c07SWyon Bi retval = analogix_dp_process_clock_recovery(dp); 4806f920c07SWyon Bi if (retval) 4816f920c07SWyon Bi dev_err(dp->dev, "LT CR failed!\n"); 4826f920c07SWyon Bi break; 4836f920c07SWyon Bi case EQUALIZER_TRAINING: 4846f920c07SWyon Bi retval = analogix_dp_process_equalizer_training(dp); 4856f920c07SWyon Bi if (retval) 4866f920c07SWyon Bi dev_err(dp->dev, "LT EQ failed!\n"); 4876f920c07SWyon Bi break; 4886f920c07SWyon Bi case FINISHED: 4896f920c07SWyon Bi training_finished = 1; 4906f920c07SWyon Bi break; 4916f920c07SWyon Bi case FAILED: 4926f920c07SWyon Bi return -EREMOTEIO; 4936f920c07SWyon Bi } 4946f920c07SWyon Bi } 4956f920c07SWyon Bi 4966f920c07SWyon Bi return retval; 4976f920c07SWyon Bi } 4986f920c07SWyon Bi 4996f920c07SWyon Bi static int analogix_dp_set_link_train(struct analogix_dp_device *dp, 5006f920c07SWyon Bi u32 count, u32 bwtype) 5016f920c07SWyon Bi { 50221069358SWyon Bi int i, ret; 5036f920c07SWyon Bi 50421069358SWyon Bi for (i = 0; i < 5; i++) { 5056f920c07SWyon Bi ret = analogix_dp_init_training(dp, count, bwtype); 5066f920c07SWyon Bi if (ret < 0) { 5076f920c07SWyon Bi dev_err(dp->dev, "failed to init training\n"); 5086f920c07SWyon Bi return ret; 5096f920c07SWyon Bi } 5106f920c07SWyon Bi 5116f920c07SWyon Bi ret = analogix_dp_sw_link_training(dp); 51221069358SWyon Bi if (!ret) 51321069358SWyon Bi break; 5146f920c07SWyon Bi } 5156f920c07SWyon Bi 51621069358SWyon Bi return ret; 5176f920c07SWyon Bi } 5186f920c07SWyon Bi 5196f920c07SWyon Bi static int analogix_dp_config_video(struct analogix_dp_device *dp) 5206f920c07SWyon Bi { 5216f920c07SWyon Bi int timeout_loop = 0; 5226f920c07SWyon Bi int done_count = 0; 5236f920c07SWyon Bi 5246f920c07SWyon Bi analogix_dp_config_video_slave_mode(dp); 5256f920c07SWyon Bi 5266f920c07SWyon Bi analogix_dp_set_video_color_format(dp); 5276f920c07SWyon Bi 5286f920c07SWyon Bi if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { 5296f920c07SWyon Bi dev_err(dp->dev, "PLL is not locked yet.\n"); 5306f920c07SWyon Bi return -EINVAL; 5316f920c07SWyon Bi } 5326f920c07SWyon Bi 5336f920c07SWyon Bi for (;;) { 5346f920c07SWyon Bi timeout_loop++; 5356f920c07SWyon Bi if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0) 5366f920c07SWyon Bi break; 5376f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 5386f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 5396f920c07SWyon Bi return -ETIMEDOUT; 5406f920c07SWyon Bi } 5416f920c07SWyon Bi 5426f920c07SWyon Bi udelay(2); 5436f920c07SWyon Bi } 5446f920c07SWyon Bi 5456f920c07SWyon Bi /* Set to use the register calculated M/N video */ 5466f920c07SWyon Bi analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); 5476f920c07SWyon Bi 5486f920c07SWyon Bi /* For video bist, Video timing must be generated by register */ 549e9cac7f1SWyon Bi analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_REGISTER); 5506f920c07SWyon Bi 5516f920c07SWyon Bi /* Disable video mute */ 5526f920c07SWyon Bi analogix_dp_enable_video_mute(dp, 0); 5536f920c07SWyon Bi 5546f920c07SWyon Bi /* Configure video slave mode */ 5556f920c07SWyon Bi analogix_dp_enable_video_master(dp, 0); 5566f920c07SWyon Bi 5576f920c07SWyon Bi /* Enable video input */ 5586f920c07SWyon Bi analogix_dp_start_video(dp); 5596f920c07SWyon Bi 5606f920c07SWyon Bi timeout_loop = 0; 5616f920c07SWyon Bi 5626f920c07SWyon Bi for (;;) { 5636f920c07SWyon Bi timeout_loop++; 5646f920c07SWyon Bi if (analogix_dp_is_video_stream_on(dp) == 0) { 5656f920c07SWyon Bi done_count++; 5666f920c07SWyon Bi if (done_count > 10) 5676f920c07SWyon Bi break; 5686f920c07SWyon Bi } else if (done_count) { 5696f920c07SWyon Bi done_count = 0; 5706f920c07SWyon Bi } 5716f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 5726f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 5736f920c07SWyon Bi return -ETIMEDOUT; 5746f920c07SWyon Bi } 5756f920c07SWyon Bi 5766f920c07SWyon Bi udelay(1001); 5776f920c07SWyon Bi } 5786f920c07SWyon Bi 5796f920c07SWyon Bi return 0; 5806f920c07SWyon Bi } 5816f920c07SWyon Bi 5826f920c07SWyon Bi static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, 5836f920c07SWyon Bi bool enable) 5846f920c07SWyon Bi { 5856f920c07SWyon Bi u8 data; 5866f920c07SWyon Bi 5876f920c07SWyon Bi if (enable) { 5886f920c07SWyon Bi analogix_dp_enable_scrambling(dp); 5896f920c07SWyon Bi 5906f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, 5916f920c07SWyon Bi &data); 5926f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 5936f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 5946f920c07SWyon Bi (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); 5956f920c07SWyon Bi } else { 5966f920c07SWyon Bi analogix_dp_disable_scrambling(dp); 5976f920c07SWyon Bi 5986f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, 5996f920c07SWyon Bi &data); 6006f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6016f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 6026f920c07SWyon Bi (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); 6036f920c07SWyon Bi } 6046f920c07SWyon Bi } 6056f920c07SWyon Bi 6066f920c07SWyon Bi static void analogix_dp_init_dp(struct analogix_dp_device *dp) 6076f920c07SWyon Bi { 6086f920c07SWyon Bi analogix_dp_reset(dp); 6096f920c07SWyon Bi 6106f920c07SWyon Bi analogix_dp_swreset(dp); 6116f920c07SWyon Bi 6126f920c07SWyon Bi analogix_dp_init_analog_param(dp); 6136f920c07SWyon Bi analogix_dp_init_interrupt(dp); 6146f920c07SWyon Bi 6156f920c07SWyon Bi /* SW defined function Normal operation */ 6166f920c07SWyon Bi analogix_dp_enable_sw_function(dp); 6176f920c07SWyon Bi 6186f920c07SWyon Bi analogix_dp_config_interrupt(dp); 6196f920c07SWyon Bi analogix_dp_init_analog_func(dp); 6206f920c07SWyon Bi 6216f920c07SWyon Bi analogix_dp_init_hpd(dp); 6226f920c07SWyon Bi analogix_dp_init_aux(dp); 6236f920c07SWyon Bi } 6246f920c07SWyon Bi 6256f920c07SWyon Bi static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) 6266f920c07SWyon Bi { 6276f920c07SWyon Bi int i; 6286f920c07SWyon Bi unsigned char sum = 0; 6296f920c07SWyon Bi 6306f920c07SWyon Bi for (i = 0; i < EDID_BLOCK_LENGTH; i++) 6316f920c07SWyon Bi sum = sum + edid_data[i]; 6326f920c07SWyon Bi 6336f920c07SWyon Bi return sum; 6346f920c07SWyon Bi } 6356f920c07SWyon Bi 6366f920c07SWyon Bi static int analogix_dp_read_edid(struct analogix_dp_device *dp) 6376f920c07SWyon Bi { 6386f920c07SWyon Bi unsigned char *edid = dp->edid; 6396f920c07SWyon Bi unsigned int extend_block = 0; 6406f920c07SWyon Bi unsigned char test_vector; 6416f920c07SWyon Bi int retval; 6426f920c07SWyon Bi 6436f920c07SWyon Bi /* 6446f920c07SWyon Bi * EDID device address is 0x50. 6456f920c07SWyon Bi * However, if necessary, you must have set upper address 6466f920c07SWyon Bi * into E-EDID in I2C device, 0x30. 6476f920c07SWyon Bi */ 6486f920c07SWyon Bi 6496f920c07SWyon Bi /* Read Extension Flag, Number of 128-byte EDID extension blocks */ 6506f920c07SWyon Bi retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, 6516f920c07SWyon Bi EDID_EXTENSION_FLAG, 6526f920c07SWyon Bi &extend_block); 6536f920c07SWyon Bi if (retval) 6546f920c07SWyon Bi return retval; 6556f920c07SWyon Bi 6566f920c07SWyon Bi if (extend_block > 0) { 6576f920c07SWyon Bi debug("EDID data includes a single extension!\n"); 6586f920c07SWyon Bi 6596f920c07SWyon Bi /* Read EDID data */ 6606f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6616f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, 6626f920c07SWyon Bi EDID_HEADER_PATTERN, 6636f920c07SWyon Bi EDID_BLOCK_LENGTH, 6646f920c07SWyon Bi &edid[EDID_HEADER_PATTERN]); 6656f920c07SWyon Bi if (retval < 0) 6666f920c07SWyon Bi return retval; 6676f920c07SWyon Bi 6686f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(edid)) 6696f920c07SWyon Bi return -EINVAL; 6706f920c07SWyon Bi 6716f920c07SWyon Bi /* Read additional EDID data */ 6726f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6736f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, 6746f920c07SWyon Bi EDID_BLOCK_LENGTH, 6756f920c07SWyon Bi EDID_BLOCK_LENGTH, 6766f920c07SWyon Bi &edid[EDID_BLOCK_LENGTH]); 6776f920c07SWyon Bi if (retval < 0) 6786f920c07SWyon Bi return retval; 6796f920c07SWyon Bi 6806f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH])) 6816f920c07SWyon Bi return -EINVAL; 6826f920c07SWyon Bi 6836f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, 6846f920c07SWyon Bi &test_vector); 6856f920c07SWyon Bi if (test_vector & DP_TEST_LINK_EDID_READ) { 6866f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6876f920c07SWyon Bi DP_TEST_EDID_CHECKSUM, 6886f920c07SWyon Bi edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); 6896f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6906f920c07SWyon Bi DP_TEST_RESPONSE, 6916f920c07SWyon Bi DP_TEST_EDID_CHECKSUM_WRITE); 6926f920c07SWyon Bi } 6936f920c07SWyon Bi } else { 6946f920c07SWyon Bi dev_info(dp->dev, 6956f920c07SWyon Bi "EDID data does not include any extensions.\n"); 6966f920c07SWyon Bi 6976f920c07SWyon Bi /* Read EDID data */ 6986f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6996f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, 7006f920c07SWyon Bi EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); 7016f920c07SWyon Bi if (retval < 0) 7026f920c07SWyon Bi return retval; 7036f920c07SWyon Bi 7046f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(edid)) 7056f920c07SWyon Bi return -EINVAL; 7066f920c07SWyon Bi 7076f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, 7086f920c07SWyon Bi &test_vector); 7096f920c07SWyon Bi if (test_vector & DP_TEST_LINK_EDID_READ) { 7106f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 7116f920c07SWyon Bi DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); 7126f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 7136f920c07SWyon Bi DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); 7146f920c07SWyon Bi } 7156f920c07SWyon Bi } 7166f920c07SWyon Bi 7176f920c07SWyon Bi return 0; 7186f920c07SWyon Bi } 7196f920c07SWyon Bi 7206f920c07SWyon Bi static int analogix_dp_handle_edid(struct analogix_dp_device *dp) 7216f920c07SWyon Bi { 7226f920c07SWyon Bi u8 buf[12]; 7236f920c07SWyon Bi int i, try = 5; 7246f920c07SWyon Bi int retval; 7256f920c07SWyon Bi 7266f920c07SWyon Bi retry: 7276f920c07SWyon Bi /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ 7286f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); 7296f920c07SWyon Bi 7306f920c07SWyon Bi if (retval && try--) { 7316f920c07SWyon Bi mdelay(10); 7326f920c07SWyon Bi goto retry; 7336f920c07SWyon Bi } 7346f920c07SWyon Bi 7356f920c07SWyon Bi if (retval) 7366f920c07SWyon Bi return retval; 7376f920c07SWyon Bi 7386f920c07SWyon Bi /* Read EDID */ 7396f920c07SWyon Bi for (i = 0; i < 3; i++) { 7406f920c07SWyon Bi retval = analogix_dp_read_edid(dp); 7416f920c07SWyon Bi if (!retval) 7426f920c07SWyon Bi break; 7436f920c07SWyon Bi } 7446f920c07SWyon Bi 7456f920c07SWyon Bi return retval; 7466f920c07SWyon Bi } 7476f920c07SWyon Bi 7480594ce39SZhang Yubing static int analogix_dp_connector_init(struct rockchip_connector *conn, struct display_state *state) 74958c17f51SSandy Huang { 75058c17f51SSandy Huang struct connector_state *conn_state = &state->conn_state; 7510594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 7526f920c07SWyon Bi 7537adc0066SWyon Bi conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_eDP1 : VOP_OUTPUT_IF_eDP0; 7546f920c07SWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 7556f920c07SWyon Bi conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 7566f920c07SWyon Bi 757699c29a5SWyon Bi reset_assert_bulk(&dp->resets); 758dddde95bSWyon Bi udelay(1); 759699c29a5SWyon Bi reset_deassert_bulk(&dp->resets); 760dddde95bSWyon Bi 761cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, dp->id); 7627adc0066SWyon Bi generic_phy_set_mode(&dp->phy, PHY_MODE_DP); 763699c29a5SWyon Bi generic_phy_power_on(&dp->phy); 7646f920c07SWyon Bi analogix_dp_init_dp(dp); 7656f920c07SWyon Bi 7666f920c07SWyon Bi return 0; 7676f920c07SWyon Bi } 7686f920c07SWyon Bi 7690594ce39SZhang Yubing static int analogix_dp_connector_get_edid(struct rockchip_connector *conn, 7700594ce39SZhang Yubing struct display_state *state) 7716f920c07SWyon Bi { 7726f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 7730594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 7746f920c07SWyon Bi int ret; 7756f920c07SWyon Bi 7766f920c07SWyon Bi ret = analogix_dp_handle_edid(dp); 7776f920c07SWyon Bi if (ret) { 7786f920c07SWyon Bi dev_err(dp->dev, "failed to get edid\n"); 7796f920c07SWyon Bi return ret; 7806f920c07SWyon Bi } 7816f920c07SWyon Bi 7826f920c07SWyon Bi memcpy(&conn_state->edid, &dp->edid, sizeof(dp->edid)); 7836f920c07SWyon Bi 7846f920c07SWyon Bi return 0; 7856f920c07SWyon Bi } 7866f920c07SWyon Bi 787d3e70420SWyon Bi static int analogix_dp_link_power_up(struct analogix_dp_device *dp) 788d3e70420SWyon Bi { 789d3e70420SWyon Bi u8 value; 790d3e70420SWyon Bi int ret; 791d3e70420SWyon Bi 792d3e70420SWyon Bi if (dp->dpcd[DP_DPCD_REV] < 0x11) 793d3e70420SWyon Bi return 0; 794d3e70420SWyon Bi 795d3e70420SWyon Bi ret = analogix_dp_read_byte_from_dpcd(dp, DP_SET_POWER, &value); 796d3e70420SWyon Bi if (ret < 0) 797d3e70420SWyon Bi return ret; 798d3e70420SWyon Bi 799d3e70420SWyon Bi value &= ~DP_SET_POWER_MASK; 800d3e70420SWyon Bi value |= DP_SET_POWER_D0; 801d3e70420SWyon Bi 802d3e70420SWyon Bi ret = analogix_dp_write_byte_to_dpcd(dp, DP_SET_POWER, value); 803d3e70420SWyon Bi if (ret < 0) 804d3e70420SWyon Bi return ret; 805d3e70420SWyon Bi 806d3e70420SWyon Bi mdelay(1); 807d3e70420SWyon Bi 808d3e70420SWyon Bi return 0; 809d3e70420SWyon Bi } 810d3e70420SWyon Bi 811d3e70420SWyon Bi static int analogix_dp_link_power_down(struct analogix_dp_device *dp) 812d3e70420SWyon Bi { 813d3e70420SWyon Bi u8 value; 814d3e70420SWyon Bi int ret; 815d3e70420SWyon Bi 816d3e70420SWyon Bi if (dp->dpcd[DP_DPCD_REV] < 0x11) 817d3e70420SWyon Bi return 0; 818d3e70420SWyon Bi 819d3e70420SWyon Bi ret = analogix_dp_read_byte_from_dpcd(dp, DP_SET_POWER, &value); 820d3e70420SWyon Bi if (ret < 0) 821d3e70420SWyon Bi return ret; 822d3e70420SWyon Bi 823d3e70420SWyon Bi value &= ~DP_SET_POWER_MASK; 824d3e70420SWyon Bi value |= DP_SET_POWER_D3; 825d3e70420SWyon Bi 826d3e70420SWyon Bi ret = analogix_dp_write_byte_to_dpcd(dp, DP_SET_POWER, value); 827d3e70420SWyon Bi if (ret < 0) 828d3e70420SWyon Bi return ret; 829d3e70420SWyon Bi 830d3e70420SWyon Bi return 0; 831d3e70420SWyon Bi } 832d3e70420SWyon Bi 8330594ce39SZhang Yubing static int analogix_dp_connector_enable(struct rockchip_connector *conn, 8340594ce39SZhang Yubing struct display_state *state) 8356f920c07SWyon Bi { 8366f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 8376f920c07SWyon Bi struct crtc_state *crtc_state = &state->crtc_state; 8380594ce39SZhang Yubing const struct rockchip_dp_chip_data *pdata = 8390594ce39SZhang Yubing (const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev); 8400594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 8412a74799bSJianqun Xu struct video_info *video = &dp->video_info; 8426f920c07SWyon Bi u32 val; 8436f920c07SWyon Bi int ret; 8446f920c07SWyon Bi 845699c29a5SWyon Bi if (pdata->lcdsel_grf_reg) { 8466f920c07SWyon Bi if (crtc_state->crtc_id) 8476f920c07SWyon Bi val = pdata->lcdsel_lit; 8486f920c07SWyon Bi else 8496f920c07SWyon Bi val = pdata->lcdsel_big; 8506f920c07SWyon Bi 8517adc0066SWyon Bi regmap_write(dp->grf, pdata->lcdsel_grf_reg, val); 8526f920c07SWyon Bi } 8536f920c07SWyon Bi 8547adc0066SWyon Bi if (pdata->chip_type == RK3588_EDP) 8557adc0066SWyon Bi regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0, 8567adc0066SWyon Bi EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 1)); 8577adc0066SWyon Bi 8582a74799bSJianqun Xu switch (conn_state->bpc) { 8592a74799bSJianqun Xu case 12: 8602a74799bSJianqun Xu video->color_depth = COLOR_12; 8612a74799bSJianqun Xu break; 8622a74799bSJianqun Xu case 10: 8632a74799bSJianqun Xu video->color_depth = COLOR_10; 8642a74799bSJianqun Xu break; 8652a74799bSJianqun Xu case 6: 8662a74799bSJianqun Xu video->color_depth = COLOR_6; 8672a74799bSJianqun Xu break; 8682a74799bSJianqun Xu case 8: 8692a74799bSJianqun Xu default: 8702a74799bSJianqun Xu video->color_depth = COLOR_8; 8712a74799bSJianqun Xu break; 8722a74799bSJianqun Xu } 8732a74799bSJianqun Xu 8741a00cf6eSWyon Bi ret = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 8751a00cf6eSWyon Bi DP_RECEIVER_CAP_SIZE, dp->dpcd); 8761a00cf6eSWyon Bi if (ret) { 8771a00cf6eSWyon Bi dev_err(dp->dev, "failed to read dpcd caps: %d\n", ret); 8781a00cf6eSWyon Bi return ret; 8791a00cf6eSWyon Bi } 8801a00cf6eSWyon Bi 881d3e70420SWyon Bi ret = analogix_dp_link_power_up(dp); 882d3e70420SWyon Bi if (ret) { 883d3e70420SWyon Bi dev_err(dp->dev, "failed to power up link: %d\n", ret); 884d3e70420SWyon Bi return ret; 885d3e70420SWyon Bi } 886d3e70420SWyon Bi 8876f920c07SWyon Bi ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, 8886f920c07SWyon Bi dp->video_info.max_link_rate); 8896f920c07SWyon Bi if (ret) { 8906f920c07SWyon Bi dev_err(dp->dev, "unable to do link train\n"); 8916f920c07SWyon Bi return ret; 8926f920c07SWyon Bi } 8936f920c07SWyon Bi 8946f920c07SWyon Bi analogix_dp_enable_scramble(dp, 1); 8956f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(dp, 1); 8966f920c07SWyon Bi analogix_dp_enable_enhanced_mode(dp, 1); 8976f920c07SWyon Bi 8986f920c07SWyon Bi analogix_dp_init_video(dp); 8990b8cf90dSWyon Bi analogix_dp_set_video_format(dp, &conn_state->mode); 9000b8cf90dSWyon Bi 9010b8cf90dSWyon Bi if (dp->video_bist_enable) 9020b8cf90dSWyon Bi analogix_dp_video_bist_enable(dp); 9030b8cf90dSWyon Bi 9046f920c07SWyon Bi ret = analogix_dp_config_video(dp); 9056f920c07SWyon Bi if (ret) { 9066f920c07SWyon Bi dev_err(dp->dev, "unable to config video\n"); 9076f920c07SWyon Bi return ret; 9086f920c07SWyon Bi } 9096f920c07SWyon Bi 9106f920c07SWyon Bi return 0; 9116f920c07SWyon Bi } 9126f920c07SWyon Bi 9130594ce39SZhang Yubing static int analogix_dp_connector_disable(struct rockchip_connector *conn, 9140594ce39SZhang Yubing struct display_state *state) 9156f920c07SWyon Bi { 9160594ce39SZhang Yubing const struct rockchip_dp_chip_data *pdata = 9170594ce39SZhang Yubing (const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev); 9180594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 9197adc0066SWyon Bi 920d3e70420SWyon Bi if (!analogix_dp_get_plug_in_status(dp)) 921d3e70420SWyon Bi analogix_dp_link_power_down(dp); 922d3e70420SWyon Bi 9237adc0066SWyon Bi if (pdata->chip_type == RK3588_EDP) 9247adc0066SWyon Bi regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0, 9257adc0066SWyon Bi EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 0)); 9266f920c07SWyon Bi 9276f920c07SWyon Bi return 0; 9286f920c07SWyon Bi } 9296f920c07SWyon Bi 9300594ce39SZhang Yubing static int analogix_dp_connector_detect(struct rockchip_connector *conn, 9310594ce39SZhang Yubing struct display_state *state) 932d90a0d9fSWyon Bi { 9330594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 934d90a0d9fSWyon Bi 9351d467516SWyon Bi return analogix_dp_detect(dp); 936d90a0d9fSWyon Bi } 937d90a0d9fSWyon Bi 9386f920c07SWyon Bi static const struct rockchip_connector_funcs analogix_dp_connector_funcs = { 9396f920c07SWyon Bi .init = analogix_dp_connector_init, 9406f920c07SWyon Bi .get_edid = analogix_dp_connector_get_edid, 9416f920c07SWyon Bi .enable = analogix_dp_connector_enable, 9426f920c07SWyon Bi .disable = analogix_dp_connector_disable, 943d90a0d9fSWyon Bi .detect = analogix_dp_connector_detect, 9446f920c07SWyon Bi }; 9456f920c07SWyon Bi 946*35c48984SWyon Bi static u32 analogix_dp_parse_link_frequencies(struct analogix_dp_device *dp) 947*35c48984SWyon Bi { 948*35c48984SWyon Bi struct udevice *dev = dp->dev; 949*35c48984SWyon Bi const struct device_node *endpoint; 950*35c48984SWyon Bi u64 frequency = 0; 951*35c48984SWyon Bi 952*35c48984SWyon Bi endpoint = rockchip_of_graph_get_endpoint_by_regs(dev->node, 1, 0); 953*35c48984SWyon Bi if (!endpoint) 954*35c48984SWyon Bi return 0; 955*35c48984SWyon Bi 956*35c48984SWyon Bi if (of_property_read_u64(endpoint, "link-frequencies", &frequency) < 0) 957*35c48984SWyon Bi return 0; 958*35c48984SWyon Bi 959*35c48984SWyon Bi if (!frequency) 960*35c48984SWyon Bi return 0; 961*35c48984SWyon Bi 962*35c48984SWyon Bi do_div(frequency, 10 * 1000); /* symbol rate kbytes */ 963*35c48984SWyon Bi 964*35c48984SWyon Bi switch (frequency) { 965*35c48984SWyon Bi case 162000: 966*35c48984SWyon Bi case 270000: 967*35c48984SWyon Bi case 540000: 968*35c48984SWyon Bi break; 969*35c48984SWyon Bi default: 970*35c48984SWyon Bi dev_err(dev, "invalid link frequency value: %llu\n", frequency); 971*35c48984SWyon Bi return 0; 972*35c48984SWyon Bi } 973*35c48984SWyon Bi 974*35c48984SWyon Bi return frequency; 975*35c48984SWyon Bi } 976*35c48984SWyon Bi 9771f59ac36SWyon Bi static int analogix_dp_parse_dt(struct analogix_dp_device *dp) 9781f59ac36SWyon Bi { 9791f59ac36SWyon Bi struct udevice *dev = dp->dev; 9801f59ac36SWyon Bi int len; 9811f59ac36SWyon Bi u32 num_lanes; 982e14b9f0dSWyon Bi u32 max_link_rate; 9831f59ac36SWyon Bi int ret; 9841f59ac36SWyon Bi 9851f59ac36SWyon Bi dp->force_hpd = dev_read_bool(dev, "force-hpd"); 9861f59ac36SWyon Bi dp->video_bist_enable = dev_read_bool(dev, "analogix,video-bist-enable"); 987ae5256b5SWyon Bi dp->video_info.force_stream_valid = 988ae5256b5SWyon Bi dev_read_bool(dev, "analogix,force-stream-valid"); 9891f59ac36SWyon Bi 990*35c48984SWyon Bi max_link_rate = analogix_dp_parse_link_frequencies(dp); 991*35c48984SWyon Bi if (max_link_rate && max_link_rate < drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate)) 992*35c48984SWyon Bi dp->video_info.max_link_rate = drm_dp_link_rate_to_bw_code(max_link_rate); 993e14b9f0dSWyon Bi 9941f59ac36SWyon Bi if (dev_read_prop(dev, "data-lanes", &len)) { 9951f59ac36SWyon Bi num_lanes = len / sizeof(u32); 9961f59ac36SWyon Bi if (num_lanes < 1 || num_lanes > 4 || num_lanes == 3) { 9971f59ac36SWyon Bi dev_err(dev, "bad number of data lanes\n"); 9981f59ac36SWyon Bi return -EINVAL; 9991f59ac36SWyon Bi } 10001f59ac36SWyon Bi 10011f59ac36SWyon Bi ret = dev_read_u32_array(dev, "data-lanes", dp->lane_map, 10021f59ac36SWyon Bi num_lanes); 10031f59ac36SWyon Bi if (ret) 10041f59ac36SWyon Bi return ret; 10051f59ac36SWyon Bi 10061f59ac36SWyon Bi dp->video_info.max_lane_count = num_lanes; 10071f59ac36SWyon Bi } else { 10081f59ac36SWyon Bi dp->lane_map[0] = 0; 10091f59ac36SWyon Bi dp->lane_map[1] = 1; 10101f59ac36SWyon Bi dp->lane_map[2] = 2; 10111f59ac36SWyon Bi dp->lane_map[3] = 3; 10121f59ac36SWyon Bi } 10131f59ac36SWyon Bi 10141f59ac36SWyon Bi return 0; 10151f59ac36SWyon Bi } 10161f59ac36SWyon Bi 10176f920c07SWyon Bi static int analogix_dp_probe(struct udevice *dev) 10186f920c07SWyon Bi { 10196f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(dev); 10200594ce39SZhang Yubing const struct rockchip_dp_chip_data *pdata = 10210594ce39SZhang Yubing (const struct rockchip_dp_chip_data *)dev_get_driver_data(dev); 10227adc0066SWyon Bi struct udevice *syscon; 10236f920c07SWyon Bi int ret; 10246f920c07SWyon Bi 10256f920c07SWyon Bi dp->reg_base = dev_read_addr_ptr(dev); 10266f920c07SWyon Bi 1027cb17ca6cSSandy Huang dp->id = of_alias_get_id(ofnode_to_np(dev->node), "edp"); 1028cb17ca6cSSandy Huang if (dp->id < 0) 1029cb17ca6cSSandy Huang dp->id = 0; 10307adc0066SWyon Bi 10317adc0066SWyon Bi ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,grf", 10327adc0066SWyon Bi &syscon); 10337adc0066SWyon Bi if (!ret) { 10347adc0066SWyon Bi dp->grf = syscon_get_regmap(syscon); 10357adc0066SWyon Bi if (!dp->grf) 10367adc0066SWyon Bi return -ENODEV; 10377adc0066SWyon Bi } 10387adc0066SWyon Bi 1039699c29a5SWyon Bi ret = reset_get_bulk(dev, &dp->resets); 1040dddde95bSWyon Bi if (ret) { 1041dddde95bSWyon Bi dev_err(dev, "failed to get reset control: %d\n", ret); 1042dddde95bSWyon Bi return ret; 1043dddde95bSWyon Bi } 1044dddde95bSWyon Bi 10456f920c07SWyon Bi ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio, 10466f920c07SWyon Bi GPIOD_IS_IN); 10476f920c07SWyon Bi if (ret && ret != -ENOENT) { 10486f920c07SWyon Bi dev_err(dev, "failed to get hpd GPIO: %d\n", ret); 10496f920c07SWyon Bi return ret; 10506f920c07SWyon Bi } 10516f920c07SWyon Bi 1052699c29a5SWyon Bi generic_phy_get_by_name(dev, "dp", &dp->phy); 1053699c29a5SWyon Bi 10546f920c07SWyon Bi dp->plat_data.dev_type = ROCKCHIP_DP; 10556f920c07SWyon Bi dp->plat_data.subdev_type = pdata->chip_type; 1056699c29a5SWyon Bi dp->plat_data.ssc = pdata->ssc; 10577adc0066SWyon Bi 10587adc0066SWyon Bi dp->video_info.max_link_rate = pdata->max_link_rate; 10597adc0066SWyon Bi dp->video_info.max_lane_count = pdata->max_lane_count; 10606f920c07SWyon Bi 10616f920c07SWyon Bi dp->dev = dev; 10626f920c07SWyon Bi 10631f59ac36SWyon Bi ret = analogix_dp_parse_dt(dp); 10641f59ac36SWyon Bi if (ret) { 10651f59ac36SWyon Bi dev_err(dev, "failed to parse DT: %d\n", ret); 10661f59ac36SWyon Bi return ret; 10671f59ac36SWyon Bi } 10681f59ac36SWyon Bi 10690594ce39SZhang Yubing rockchip_connector_bind(&dp->connector, dev, dp->id, &analogix_dp_connector_funcs, 10700594ce39SZhang Yubing NULL, DRM_MODE_CONNECTOR_eDP); 10710594ce39SZhang Yubing 10726f920c07SWyon Bi return 0; 10736f920c07SWyon Bi } 10746f920c07SWyon Bi 10756f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3288_edp_platform_data = { 10766f920c07SWyon Bi .lcdsel_grf_reg = 0x025c, 10776f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 10786f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 10796f920c07SWyon Bi .chip_type = RK3288_DP, 10807adc0066SWyon Bi 10817adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 10827adc0066SWyon Bi .max_lane_count = 4, 10836f920c07SWyon Bi }; 10846f920c07SWyon Bi 10856f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3368_edp_platform_data = { 10866f920c07SWyon Bi .chip_type = RK3368_EDP, 10877adc0066SWyon Bi 10887adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 10897adc0066SWyon Bi .max_lane_count = 4, 10906f920c07SWyon Bi }; 10916f920c07SWyon Bi 10926f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3399_edp_platform_data = { 10936f920c07SWyon Bi .lcdsel_grf_reg = 0x6250, 10946f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 10956f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 10966f920c07SWyon Bi .chip_type = RK3399_EDP, 1097e417664aSWyon Bi .ssc = true, 10987adc0066SWyon Bi 1099e417664aSWyon Bi .max_link_rate = DP_LINK_BW_5_4, 11007adc0066SWyon Bi .max_lane_count = 4, 11016f920c07SWyon Bi }; 11026f920c07SWyon Bi 1103699c29a5SWyon Bi static const struct rockchip_dp_chip_data rk3568_edp_platform_data = { 1104699c29a5SWyon Bi .chip_type = RK3568_EDP, 1105699c29a5SWyon Bi .ssc = true, 11067adc0066SWyon Bi 11077adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 11087adc0066SWyon Bi .max_lane_count = 4, 1109699c29a5SWyon Bi }; 1110699c29a5SWyon Bi 11117adc0066SWyon Bi static const struct rockchip_dp_chip_data rk3588_edp_platform_data = { 11127adc0066SWyon Bi .chip_type = RK3588_EDP, 11137adc0066SWyon Bi .ssc = true, 11147adc0066SWyon Bi 11157adc0066SWyon Bi .max_link_rate = DP_LINK_BW_5_4, 11167adc0066SWyon Bi .max_lane_count = 4, 11177adc0066SWyon Bi }; 11187adc0066SWyon Bi 11196f920c07SWyon Bi static const struct udevice_id analogix_dp_ids[] = { 11206f920c07SWyon Bi { 11216f920c07SWyon Bi .compatible = "rockchip,rk3288-dp", 11220594ce39SZhang Yubing .data = (ulong)&rk3288_edp_platform_data, 11236f920c07SWyon Bi }, { 11246f920c07SWyon Bi .compatible = "rockchip,rk3368-edp", 11250594ce39SZhang Yubing .data = (ulong)&rk3368_edp_platform_data, 11266f920c07SWyon Bi }, { 11276f920c07SWyon Bi .compatible = "rockchip,rk3399-edp", 11280594ce39SZhang Yubing .data = (ulong)&rk3399_edp_platform_data, 1129699c29a5SWyon Bi }, { 1130699c29a5SWyon Bi .compatible = "rockchip,rk3568-edp", 11310594ce39SZhang Yubing .data = (ulong)&rk3568_edp_platform_data, 11327adc0066SWyon Bi }, { 11337adc0066SWyon Bi .compatible = "rockchip,rk3588-edp", 11340594ce39SZhang Yubing .data = (ulong)&rk3588_edp_platform_data, 11356f920c07SWyon Bi }, 11366f920c07SWyon Bi {} 11376f920c07SWyon Bi }; 11386f920c07SWyon Bi 11396f920c07SWyon Bi U_BOOT_DRIVER(analogix_dp) = { 11406f920c07SWyon Bi .name = "analogix_dp", 11416f920c07SWyon Bi .id = UCLASS_DISPLAY, 11426f920c07SWyon Bi .of_match = analogix_dp_ids, 11436f920c07SWyon Bi .probe = analogix_dp_probe, 11446f920c07SWyon Bi .priv_auto_alloc_size = sizeof(struct analogix_dp_device), 11456f920c07SWyon Bi }; 1146