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 265*1a00cf6eSWyon 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 retval = analogix_dp_read_bytes_from_dpcd(dp, 2756f920c07SWyon Bi DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); 2766f920c07SWyon Bi if (retval) 2776f920c07SWyon Bi return retval; 2786f920c07SWyon Bi 2796f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { 2807adc0066SWyon Bi if (analogix_dp_tps3_supported(dp)) 2817adc0066SWyon Bi training_pattern = TRAINING_PTN3; 2827adc0066SWyon Bi 2837adc0066SWyon Bi /* set training pattern for EQ */ 2847adc0066SWyon Bi analogix_dp_set_training_pattern(dp, training_pattern); 2856f920c07SWyon Bi 2866f920c07SWyon Bi retval = analogix_dp_write_byte_to_dpcd(dp, 2876f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 2887adc0066SWyon Bi (training_pattern == TRAINING_PTN3 ? 2897adc0066SWyon Bi DP_TRAINING_PATTERN_3 : DP_TRAINING_PATTERN_2)); 2906f920c07SWyon Bi if (retval) 2916f920c07SWyon Bi return retval; 2926f920c07SWyon Bi 2936f920c07SWyon Bi dev_info(dp->dev, "Link Training Clock Recovery success\n"); 2946f920c07SWyon Bi dp->link_train.lt_state = EQUALIZER_TRAINING; 2956f920c07SWyon Bi } else { 2966f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2976f920c07SWyon Bi training_lane = analogix_dp_get_lane_link_training( 2986f920c07SWyon Bi dp, lane); 2996f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 3006f920c07SWyon Bi adjust_request, lane); 3016f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 3026f920c07SWyon Bi adjust_request, lane); 3036f920c07SWyon Bi 3046f920c07SWyon Bi if (DPCD_VOLTAGE_SWING_GET(training_lane) == 3056f920c07SWyon Bi voltage_swing && 3066f920c07SWyon Bi DPCD_PRE_EMPHASIS_GET(training_lane) == 3076f920c07SWyon Bi pre_emphasis) 3086f920c07SWyon Bi dp->link_train.cr_loop[lane]++; 3096f920c07SWyon Bi 3106f920c07SWyon Bi if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || 3116f920c07SWyon Bi voltage_swing == VOLTAGE_LEVEL_3 || 3126f920c07SWyon Bi pre_emphasis == PRE_EMPHASIS_LEVEL_3) { 3136f920c07SWyon Bi dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", 3146f920c07SWyon Bi dp->link_train.cr_loop[lane], 3156f920c07SWyon Bi voltage_swing, pre_emphasis); 3166f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3176f920c07SWyon Bi return -EIO; 3186f920c07SWyon Bi } 3196f920c07SWyon Bi } 3206f920c07SWyon Bi } 3216f920c07SWyon Bi 3226f920c07SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 323253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 3246f920c07SWyon Bi 3256f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, 3266f920c07SWyon Bi DP_TRAINING_LANE0_SET, lane_count, 3276f920c07SWyon Bi dp->link_train.training_lane); 3286f920c07SWyon Bi if (retval) 3296f920c07SWyon Bi return retval; 3306f920c07SWyon Bi 3316f920c07SWyon Bi return retval; 3326f920c07SWyon Bi } 3336f920c07SWyon Bi 3346f920c07SWyon Bi static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) 3356f920c07SWyon Bi { 336253c2dc8SWyon Bi int lane_count, retval; 3376f920c07SWyon Bi u32 reg; 3386f920c07SWyon Bi u8 link_align, link_status[2], adjust_request[2]; 3396f920c07SWyon Bi 340*1a00cf6eSWyon Bi drm_dp_link_train_channel_eq_delay(dp->dpcd); 3416f920c07SWyon Bi 3426f920c07SWyon Bi lane_count = dp->link_train.lane_count; 3436f920c07SWyon Bi 3446f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 3456f920c07SWyon Bi DP_LANE0_1_STATUS, 2, link_status); 3466f920c07SWyon Bi if (retval) 3476f920c07SWyon Bi return retval; 3486f920c07SWyon Bi 3496f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { 3506f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3516f920c07SWyon Bi return -EIO; 3526f920c07SWyon Bi } 3536f920c07SWyon Bi 3546f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 3556f920c07SWyon Bi DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); 3566f920c07SWyon Bi if (retval) 3576f920c07SWyon Bi return retval; 3586f920c07SWyon Bi 3596f920c07SWyon Bi retval = analogix_dp_read_byte_from_dpcd(dp, 3606f920c07SWyon Bi DP_LANE_ALIGN_STATUS_UPDATED, &link_align); 3616f920c07SWyon Bi if (retval) 3626f920c07SWyon Bi return retval; 3636f920c07SWyon Bi 3646f920c07SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 3656f920c07SWyon Bi 3666f920c07SWyon Bi if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { 3676f920c07SWyon Bi /* traing pattern Set to Normal */ 3686f920c07SWyon Bi analogix_dp_training_pattern_dis(dp); 3696f920c07SWyon Bi 3706f920c07SWyon Bi printf("Link Training success!\n"); 3716f920c07SWyon Bi 3726f920c07SWyon Bi analogix_dp_get_link_bandwidth(dp, ®); 3736f920c07SWyon Bi dp->link_train.link_rate = reg; 3746f920c07SWyon Bi analogix_dp_get_lane_count(dp, ®); 3756f920c07SWyon Bi dp->link_train.lane_count = reg; 3766f920c07SWyon Bi 3776f920c07SWyon Bi printf("final link rate = 0x%.2x, lane count = 0x%.2x\n", 3786f920c07SWyon Bi dp->link_train.link_rate, dp->link_train.lane_count); 3796f920c07SWyon Bi 3806f920c07SWyon Bi /* set enhanced mode if available */ 3816f920c07SWyon Bi analogix_dp_set_enhanced_mode(dp); 3826f920c07SWyon Bi dp->link_train.lt_state = FINISHED; 3836f920c07SWyon Bi 3846f920c07SWyon Bi return 0; 3856f920c07SWyon Bi } 3866f920c07SWyon Bi 3876f920c07SWyon Bi /* not all locked */ 3886f920c07SWyon Bi dp->link_train.eq_loop++; 3896f920c07SWyon Bi 3906f920c07SWyon Bi if (dp->link_train.eq_loop > MAX_EQ_LOOP) { 3916f920c07SWyon Bi dev_dbg(dp->dev, "EQ Max loop\n"); 3926f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3936f920c07SWyon Bi return -EIO; 3946f920c07SWyon Bi } 3956f920c07SWyon Bi 396253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 3976f920c07SWyon Bi 3986f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, 3996f920c07SWyon Bi lane_count, dp->link_train.training_lane); 4006f920c07SWyon Bi 4016f920c07SWyon Bi return retval; 4026f920c07SWyon Bi } 4036f920c07SWyon Bi 4046f920c07SWyon Bi static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, 4056f920c07SWyon Bi u8 *bandwidth) 4066f920c07SWyon Bi { 4076f920c07SWyon Bi u8 data; 4086f920c07SWyon Bi 4096f920c07SWyon Bi /* 4106f920c07SWyon Bi * For DP rev.1.1, Maximum link rate of Main Link lanes 4116f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps 4126f920c07SWyon Bi * For DP rev.1.2, Maximum link rate of Main Link lanes 4136f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps 4146f920c07SWyon Bi */ 4156f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); 4166f920c07SWyon Bi *bandwidth = data; 4176f920c07SWyon Bi } 4186f920c07SWyon Bi 4196f920c07SWyon Bi static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, 4206f920c07SWyon Bi u8 *lane_count) 4216f920c07SWyon Bi { 4226f920c07SWyon Bi u8 data; 4236f920c07SWyon Bi 4246f920c07SWyon Bi /* 4256f920c07SWyon Bi * For DP rev.1.1, Maximum number of Main Link lanes 4266f920c07SWyon Bi * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes 4276f920c07SWyon Bi */ 4286f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); 4296f920c07SWyon Bi *lane_count = DPCD_MAX_LANE_COUNT(data); 4306f920c07SWyon Bi } 4316f920c07SWyon Bi 4326f920c07SWyon Bi static int analogix_dp_init_training(struct analogix_dp_device *dp, 4336f920c07SWyon Bi enum link_lane_count_type max_lane, 4346f920c07SWyon Bi int max_rate) 4356f920c07SWyon Bi { 436699c29a5SWyon Bi u8 dpcd; 437699c29a5SWyon Bi 4386f920c07SWyon Bi /* 4396f920c07SWyon Bi * MACRO_RST must be applied after the PLL_LOCK to avoid 4406f920c07SWyon Bi * the DP inter pair skew issue for at least 10 us 4416f920c07SWyon Bi */ 4426f920c07SWyon Bi analogix_dp_reset_macro(dp); 4436f920c07SWyon Bi 4446f920c07SWyon Bi /* Initialize by reading RX's DPCD */ 4456f920c07SWyon Bi analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); 4466f920c07SWyon Bi analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); 4476f920c07SWyon Bi 4486f920c07SWyon Bi if ((dp->link_train.link_rate != DP_LINK_BW_1_62) && 4496f920c07SWyon Bi (dp->link_train.link_rate != DP_LINK_BW_2_7) && 4506f920c07SWyon Bi (dp->link_train.link_rate != DP_LINK_BW_5_4)) { 4516f920c07SWyon Bi dev_err(dp->dev, "failed to get Rx Max Link Rate\n"); 4526f920c07SWyon Bi return -ENODEV; 4536f920c07SWyon Bi } 4546f920c07SWyon Bi 4556f920c07SWyon Bi if (dp->link_train.lane_count == 0) { 4566f920c07SWyon Bi dev_err(dp->dev, "failed to get Rx Max Lane Count\n"); 4576f920c07SWyon Bi return -ENODEV; 4586f920c07SWyon Bi } 4596f920c07SWyon Bi 4606f920c07SWyon Bi /* Setup TX lane count & rate */ 4616f920c07SWyon Bi if (dp->link_train.lane_count > max_lane) 4626f920c07SWyon Bi dp->link_train.lane_count = max_lane; 4636f920c07SWyon Bi if (dp->link_train.link_rate > max_rate) 4646f920c07SWyon Bi dp->link_train.link_rate = max_rate; 4656f920c07SWyon Bi 466699c29a5SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_DOWNSPREAD, &dpcd); 467699c29a5SWyon Bi dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); 468699c29a5SWyon Bi 4696f920c07SWyon Bi /* All DP analog module power up */ 4706f920c07SWyon Bi analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); 4716f920c07SWyon Bi 4726f920c07SWyon Bi return 0; 4736f920c07SWyon Bi } 4746f920c07SWyon Bi 4756f920c07SWyon Bi static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) 4766f920c07SWyon Bi { 4776f920c07SWyon Bi int retval = 0, training_finished = 0; 4786f920c07SWyon Bi 4796f920c07SWyon Bi dp->link_train.lt_state = START; 4806f920c07SWyon Bi 4816f920c07SWyon Bi /* Process here */ 4826f920c07SWyon Bi while (!retval && !training_finished) { 4836f920c07SWyon Bi switch (dp->link_train.lt_state) { 4846f920c07SWyon Bi case START: 4856f920c07SWyon Bi retval = analogix_dp_link_start(dp); 4866f920c07SWyon Bi if (retval) 4876f920c07SWyon Bi dev_err(dp->dev, "LT link start failed!\n"); 4886f920c07SWyon Bi break; 4896f920c07SWyon Bi case CLOCK_RECOVERY: 4906f920c07SWyon Bi retval = analogix_dp_process_clock_recovery(dp); 4916f920c07SWyon Bi if (retval) 4926f920c07SWyon Bi dev_err(dp->dev, "LT CR failed!\n"); 4936f920c07SWyon Bi break; 4946f920c07SWyon Bi case EQUALIZER_TRAINING: 4956f920c07SWyon Bi retval = analogix_dp_process_equalizer_training(dp); 4966f920c07SWyon Bi if (retval) 4976f920c07SWyon Bi dev_err(dp->dev, "LT EQ failed!\n"); 4986f920c07SWyon Bi break; 4996f920c07SWyon Bi case FINISHED: 5006f920c07SWyon Bi training_finished = 1; 5016f920c07SWyon Bi break; 5026f920c07SWyon Bi case FAILED: 5036f920c07SWyon Bi return -EREMOTEIO; 5046f920c07SWyon Bi } 5056f920c07SWyon Bi } 5066f920c07SWyon Bi 5076f920c07SWyon Bi return retval; 5086f920c07SWyon Bi } 5096f920c07SWyon Bi 5106f920c07SWyon Bi static int analogix_dp_set_link_train(struct analogix_dp_device *dp, 5116f920c07SWyon Bi u32 count, u32 bwtype) 5126f920c07SWyon Bi { 51321069358SWyon Bi int i, ret; 5146f920c07SWyon Bi 51521069358SWyon Bi for (i = 0; i < 5; i++) { 5166f920c07SWyon Bi ret = analogix_dp_init_training(dp, count, bwtype); 5176f920c07SWyon Bi if (ret < 0) { 5186f920c07SWyon Bi dev_err(dp->dev, "failed to init training\n"); 5196f920c07SWyon Bi return ret; 5206f920c07SWyon Bi } 5216f920c07SWyon Bi 5226f920c07SWyon Bi ret = analogix_dp_sw_link_training(dp); 52321069358SWyon Bi if (!ret) 52421069358SWyon Bi break; 5256f920c07SWyon Bi } 5266f920c07SWyon Bi 52721069358SWyon Bi return ret; 5286f920c07SWyon Bi } 5296f920c07SWyon Bi 5306f920c07SWyon Bi static int analogix_dp_config_video(struct analogix_dp_device *dp) 5316f920c07SWyon Bi { 5326f920c07SWyon Bi int timeout_loop = 0; 5336f920c07SWyon Bi int done_count = 0; 5346f920c07SWyon Bi 5356f920c07SWyon Bi analogix_dp_config_video_slave_mode(dp); 5366f920c07SWyon Bi 5376f920c07SWyon Bi analogix_dp_set_video_color_format(dp); 5386f920c07SWyon Bi 5396f920c07SWyon Bi if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { 5406f920c07SWyon Bi dev_err(dp->dev, "PLL is not locked yet.\n"); 5416f920c07SWyon Bi return -EINVAL; 5426f920c07SWyon Bi } 5436f920c07SWyon Bi 5446f920c07SWyon Bi for (;;) { 5456f920c07SWyon Bi timeout_loop++; 5466f920c07SWyon Bi if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0) 5476f920c07SWyon Bi break; 5486f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 5496f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 5506f920c07SWyon Bi return -ETIMEDOUT; 5516f920c07SWyon Bi } 5526f920c07SWyon Bi 5536f920c07SWyon Bi udelay(2); 5546f920c07SWyon Bi } 5556f920c07SWyon Bi 5566f920c07SWyon Bi /* Set to use the register calculated M/N video */ 5576f920c07SWyon Bi analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); 5586f920c07SWyon Bi 5596f920c07SWyon Bi /* For video bist, Video timing must be generated by register */ 5606f920c07SWyon Bi analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); 5616f920c07SWyon Bi 5626f920c07SWyon Bi /* Disable video mute */ 5636f920c07SWyon Bi analogix_dp_enable_video_mute(dp, 0); 5646f920c07SWyon Bi 5656f920c07SWyon Bi /* Configure video slave mode */ 5666f920c07SWyon Bi analogix_dp_enable_video_master(dp, 0); 5676f920c07SWyon Bi 5686f920c07SWyon Bi /* Enable video input */ 5696f920c07SWyon Bi analogix_dp_start_video(dp); 5706f920c07SWyon Bi 5716f920c07SWyon Bi timeout_loop = 0; 5726f920c07SWyon Bi 5736f920c07SWyon Bi for (;;) { 5746f920c07SWyon Bi timeout_loop++; 5756f920c07SWyon Bi if (analogix_dp_is_video_stream_on(dp) == 0) { 5766f920c07SWyon Bi done_count++; 5776f920c07SWyon Bi if (done_count > 10) 5786f920c07SWyon Bi break; 5796f920c07SWyon Bi } else if (done_count) { 5806f920c07SWyon Bi done_count = 0; 5816f920c07SWyon Bi } 5826f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 5836f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 5846f920c07SWyon Bi return -ETIMEDOUT; 5856f920c07SWyon Bi } 5866f920c07SWyon Bi 5876f920c07SWyon Bi udelay(1001); 5886f920c07SWyon Bi } 5896f920c07SWyon Bi 5906f920c07SWyon Bi return 0; 5916f920c07SWyon Bi } 5926f920c07SWyon Bi 5936f920c07SWyon Bi static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, 5946f920c07SWyon Bi bool enable) 5956f920c07SWyon Bi { 5966f920c07SWyon Bi u8 data; 5976f920c07SWyon Bi 5986f920c07SWyon Bi if (enable) { 5996f920c07SWyon Bi analogix_dp_enable_scrambling(dp); 6006f920c07SWyon Bi 6016f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, 6026f920c07SWyon Bi &data); 6036f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6046f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 6056f920c07SWyon Bi (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); 6066f920c07SWyon Bi } else { 6076f920c07SWyon Bi analogix_dp_disable_scrambling(dp); 6086f920c07SWyon Bi 6096f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, 6106f920c07SWyon Bi &data); 6116f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6126f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 6136f920c07SWyon Bi (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); 6146f920c07SWyon Bi } 6156f920c07SWyon Bi } 6166f920c07SWyon Bi 6176f920c07SWyon Bi static void analogix_dp_init_dp(struct analogix_dp_device *dp) 6186f920c07SWyon Bi { 6196f920c07SWyon Bi analogix_dp_reset(dp); 6206f920c07SWyon Bi 6216f920c07SWyon Bi analogix_dp_swreset(dp); 6226f920c07SWyon Bi 6236f920c07SWyon Bi analogix_dp_init_analog_param(dp); 6246f920c07SWyon Bi analogix_dp_init_interrupt(dp); 6256f920c07SWyon Bi 6266f920c07SWyon Bi /* SW defined function Normal operation */ 6276f920c07SWyon Bi analogix_dp_enable_sw_function(dp); 6286f920c07SWyon Bi 6296f920c07SWyon Bi analogix_dp_config_interrupt(dp); 6306f920c07SWyon Bi analogix_dp_init_analog_func(dp); 6316f920c07SWyon Bi 6326f920c07SWyon Bi analogix_dp_init_hpd(dp); 6336f920c07SWyon Bi analogix_dp_init_aux(dp); 6346f920c07SWyon Bi } 6356f920c07SWyon Bi 6366f920c07SWyon Bi static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) 6376f920c07SWyon Bi { 6386f920c07SWyon Bi int i; 6396f920c07SWyon Bi unsigned char sum = 0; 6406f920c07SWyon Bi 6416f920c07SWyon Bi for (i = 0; i < EDID_BLOCK_LENGTH; i++) 6426f920c07SWyon Bi sum = sum + edid_data[i]; 6436f920c07SWyon Bi 6446f920c07SWyon Bi return sum; 6456f920c07SWyon Bi } 6466f920c07SWyon Bi 6476f920c07SWyon Bi static int analogix_dp_read_edid(struct analogix_dp_device *dp) 6486f920c07SWyon Bi { 6496f920c07SWyon Bi unsigned char *edid = dp->edid; 6506f920c07SWyon Bi unsigned int extend_block = 0; 6516f920c07SWyon Bi unsigned char test_vector; 6526f920c07SWyon Bi int retval; 6536f920c07SWyon Bi 6546f920c07SWyon Bi /* 6556f920c07SWyon Bi * EDID device address is 0x50. 6566f920c07SWyon Bi * However, if necessary, you must have set upper address 6576f920c07SWyon Bi * into E-EDID in I2C device, 0x30. 6586f920c07SWyon Bi */ 6596f920c07SWyon Bi 6606f920c07SWyon Bi /* Read Extension Flag, Number of 128-byte EDID extension blocks */ 6616f920c07SWyon Bi retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, 6626f920c07SWyon Bi EDID_EXTENSION_FLAG, 6636f920c07SWyon Bi &extend_block); 6646f920c07SWyon Bi if (retval) 6656f920c07SWyon Bi return retval; 6666f920c07SWyon Bi 6676f920c07SWyon Bi if (extend_block > 0) { 6686f920c07SWyon Bi debug("EDID data includes a single extension!\n"); 6696f920c07SWyon Bi 6706f920c07SWyon Bi /* Read EDID data */ 6716f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6726f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, 6736f920c07SWyon Bi EDID_HEADER_PATTERN, 6746f920c07SWyon Bi EDID_BLOCK_LENGTH, 6756f920c07SWyon Bi &edid[EDID_HEADER_PATTERN]); 6766f920c07SWyon Bi if (retval < 0) 6776f920c07SWyon Bi return retval; 6786f920c07SWyon Bi 6796f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(edid)) 6806f920c07SWyon Bi return -EINVAL; 6816f920c07SWyon Bi 6826f920c07SWyon Bi /* Read additional EDID data */ 6836f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6846f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, 6856f920c07SWyon Bi EDID_BLOCK_LENGTH, 6866f920c07SWyon Bi EDID_BLOCK_LENGTH, 6876f920c07SWyon Bi &edid[EDID_BLOCK_LENGTH]); 6886f920c07SWyon Bi if (retval < 0) 6896f920c07SWyon Bi return retval; 6906f920c07SWyon Bi 6916f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH])) 6926f920c07SWyon Bi return -EINVAL; 6936f920c07SWyon Bi 6946f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, 6956f920c07SWyon Bi &test_vector); 6966f920c07SWyon Bi if (test_vector & DP_TEST_LINK_EDID_READ) { 6976f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6986f920c07SWyon Bi DP_TEST_EDID_CHECKSUM, 6996f920c07SWyon Bi edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); 7006f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 7016f920c07SWyon Bi DP_TEST_RESPONSE, 7026f920c07SWyon Bi DP_TEST_EDID_CHECKSUM_WRITE); 7036f920c07SWyon Bi } 7046f920c07SWyon Bi } else { 7056f920c07SWyon Bi dev_info(dp->dev, 7066f920c07SWyon Bi "EDID data does not include any extensions.\n"); 7076f920c07SWyon Bi 7086f920c07SWyon Bi /* Read EDID data */ 7096f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 7106f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, 7116f920c07SWyon Bi EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); 7126f920c07SWyon Bi if (retval < 0) 7136f920c07SWyon Bi return retval; 7146f920c07SWyon Bi 7156f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(edid)) 7166f920c07SWyon Bi return -EINVAL; 7176f920c07SWyon Bi 7186f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, 7196f920c07SWyon Bi &test_vector); 7206f920c07SWyon Bi if (test_vector & DP_TEST_LINK_EDID_READ) { 7216f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 7226f920c07SWyon Bi DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); 7236f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 7246f920c07SWyon Bi DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); 7256f920c07SWyon Bi } 7266f920c07SWyon Bi } 7276f920c07SWyon Bi 7286f920c07SWyon Bi return 0; 7296f920c07SWyon Bi } 7306f920c07SWyon Bi 7316f920c07SWyon Bi static int analogix_dp_handle_edid(struct analogix_dp_device *dp) 7326f920c07SWyon Bi { 7336f920c07SWyon Bi u8 buf[12]; 7346f920c07SWyon Bi int i, try = 5; 7356f920c07SWyon Bi int retval; 7366f920c07SWyon Bi 7376f920c07SWyon Bi retry: 7386f920c07SWyon Bi /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ 7396f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); 7406f920c07SWyon Bi 7416f920c07SWyon Bi if (retval && try--) { 7426f920c07SWyon Bi mdelay(10); 7436f920c07SWyon Bi goto retry; 7446f920c07SWyon Bi } 7456f920c07SWyon Bi 7466f920c07SWyon Bi if (retval) 7476f920c07SWyon Bi return retval; 7486f920c07SWyon Bi 7496f920c07SWyon Bi /* Read EDID */ 7506f920c07SWyon Bi for (i = 0; i < 3; i++) { 7516f920c07SWyon Bi retval = analogix_dp_read_edid(dp); 7526f920c07SWyon Bi if (!retval) 7536f920c07SWyon Bi break; 7546f920c07SWyon Bi } 7556f920c07SWyon Bi 7566f920c07SWyon Bi return retval; 7576f920c07SWyon Bi } 7586f920c07SWyon Bi 75958c17f51SSandy Huang static int analogix_dp_connector_pre_init(struct display_state *state) 76058c17f51SSandy Huang { 76158c17f51SSandy Huang struct connector_state *conn_state = &state->conn_state; 76258c17f51SSandy Huang 76358c17f51SSandy Huang conn_state->type = DRM_MODE_CONNECTOR_eDP; 76458c17f51SSandy Huang 76558c17f51SSandy Huang return 0; 76658c17f51SSandy Huang } 76758c17f51SSandy Huang 7686f920c07SWyon Bi static int analogix_dp_connector_init(struct display_state *state) 7696f920c07SWyon Bi { 7706f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 7716f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 7726f920c07SWyon Bi 7737adc0066SWyon Bi conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_eDP1 : VOP_OUTPUT_IF_eDP0; 7746f920c07SWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 7756f920c07SWyon Bi conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 7766f920c07SWyon Bi 777699c29a5SWyon Bi reset_assert_bulk(&dp->resets); 778dddde95bSWyon Bi udelay(1); 779699c29a5SWyon Bi reset_deassert_bulk(&dp->resets); 780dddde95bSWyon Bi 781cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, dp->id); 7827adc0066SWyon Bi generic_phy_set_mode(&dp->phy, PHY_MODE_DP); 783699c29a5SWyon Bi generic_phy_power_on(&dp->phy); 7846f920c07SWyon Bi analogix_dp_init_dp(dp); 7856f920c07SWyon Bi 7866f920c07SWyon Bi return 0; 7876f920c07SWyon Bi } 7886f920c07SWyon Bi 7896f920c07SWyon Bi static int analogix_dp_connector_get_edid(struct display_state *state) 7906f920c07SWyon Bi { 7916f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 7926f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 7936f920c07SWyon Bi int ret; 7946f920c07SWyon Bi 7956f920c07SWyon Bi ret = analogix_dp_handle_edid(dp); 7966f920c07SWyon Bi if (ret) { 7976f920c07SWyon Bi dev_err(dp->dev, "failed to get edid\n"); 7986f920c07SWyon Bi return ret; 7996f920c07SWyon Bi } 8006f920c07SWyon Bi 8016f920c07SWyon Bi memcpy(&conn_state->edid, &dp->edid, sizeof(dp->edid)); 8026f920c07SWyon Bi 8036f920c07SWyon Bi return 0; 8046f920c07SWyon Bi } 8056f920c07SWyon Bi 8066f920c07SWyon Bi static int analogix_dp_connector_enable(struct display_state *state) 8076f920c07SWyon Bi { 8086f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 8096f920c07SWyon Bi struct crtc_state *crtc_state = &state->crtc_state; 8106f920c07SWyon Bi const struct rockchip_connector *connector = conn_state->connector; 8116f920c07SWyon Bi const struct rockchip_dp_chip_data *pdata = connector->data; 8126f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 8132a74799bSJianqun Xu struct video_info *video = &dp->video_info; 8146f920c07SWyon Bi u32 val; 8156f920c07SWyon Bi int ret; 8166f920c07SWyon Bi 817699c29a5SWyon Bi if (pdata->lcdsel_grf_reg) { 8186f920c07SWyon Bi if (crtc_state->crtc_id) 8196f920c07SWyon Bi val = pdata->lcdsel_lit; 8206f920c07SWyon Bi else 8216f920c07SWyon Bi val = pdata->lcdsel_big; 8226f920c07SWyon Bi 8237adc0066SWyon Bi regmap_write(dp->grf, pdata->lcdsel_grf_reg, val); 8246f920c07SWyon Bi } 8256f920c07SWyon Bi 8267adc0066SWyon Bi if (pdata->chip_type == RK3588_EDP) 8277adc0066SWyon Bi regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0, 8287adc0066SWyon Bi EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 1)); 8297adc0066SWyon Bi 8302a74799bSJianqun Xu switch (conn_state->bpc) { 8312a74799bSJianqun Xu case 12: 8322a74799bSJianqun Xu video->color_depth = COLOR_12; 8332a74799bSJianqun Xu break; 8342a74799bSJianqun Xu case 10: 8352a74799bSJianqun Xu video->color_depth = COLOR_10; 8362a74799bSJianqun Xu break; 8372a74799bSJianqun Xu case 6: 8382a74799bSJianqun Xu video->color_depth = COLOR_6; 8392a74799bSJianqun Xu break; 8402a74799bSJianqun Xu case 8: 8412a74799bSJianqun Xu default: 8422a74799bSJianqun Xu video->color_depth = COLOR_8; 8432a74799bSJianqun Xu break; 8442a74799bSJianqun Xu } 8452a74799bSJianqun Xu 846*1a00cf6eSWyon Bi ret = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 847*1a00cf6eSWyon Bi DP_RECEIVER_CAP_SIZE, dp->dpcd); 848*1a00cf6eSWyon Bi if (ret) { 849*1a00cf6eSWyon Bi dev_err(dp->dev, "failed to read dpcd caps: %d\n", ret); 850*1a00cf6eSWyon Bi return ret; 851*1a00cf6eSWyon Bi } 852*1a00cf6eSWyon Bi 8536f920c07SWyon Bi ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, 8546f920c07SWyon Bi dp->video_info.max_link_rate); 8556f920c07SWyon Bi if (ret) { 8566f920c07SWyon Bi dev_err(dp->dev, "unable to do link train\n"); 8576f920c07SWyon Bi return ret; 8586f920c07SWyon Bi } 8596f920c07SWyon Bi 8606f920c07SWyon Bi analogix_dp_enable_scramble(dp, 1); 8616f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(dp, 1); 8626f920c07SWyon Bi analogix_dp_enable_enhanced_mode(dp, 1); 8636f920c07SWyon Bi 8646f920c07SWyon Bi analogix_dp_init_video(dp); 8656f920c07SWyon Bi ret = analogix_dp_config_video(dp); 8666f920c07SWyon Bi if (ret) { 8676f920c07SWyon Bi dev_err(dp->dev, "unable to config video\n"); 8686f920c07SWyon Bi return ret; 8696f920c07SWyon Bi } 8706f920c07SWyon Bi 8716f920c07SWyon Bi return 0; 8726f920c07SWyon Bi } 8736f920c07SWyon Bi 8746f920c07SWyon Bi static int analogix_dp_connector_disable(struct display_state *state) 8756f920c07SWyon Bi { 8767adc0066SWyon Bi struct connector_state *conn_state = &state->conn_state; 8777adc0066SWyon Bi const struct rockchip_connector *connector = conn_state->connector; 8787adc0066SWyon Bi const struct rockchip_dp_chip_data *pdata = connector->data; 8797adc0066SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 8807adc0066SWyon Bi 8817adc0066SWyon Bi if (pdata->chip_type == RK3588_EDP) 8827adc0066SWyon Bi regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0, 8837adc0066SWyon Bi EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 0)); 8846f920c07SWyon Bi 8856f920c07SWyon Bi return 0; 8866f920c07SWyon Bi } 8876f920c07SWyon Bi 888d90a0d9fSWyon Bi static int analogix_dp_connector_detect(struct display_state *state) 889d90a0d9fSWyon Bi { 890d90a0d9fSWyon Bi struct connector_state *conn_state = &state->conn_state; 891d90a0d9fSWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 892d90a0d9fSWyon Bi 893d90a0d9fSWyon Bi return analogix_dp_detect(dp); 894d90a0d9fSWyon Bi } 895d90a0d9fSWyon Bi 8966f920c07SWyon Bi static const struct rockchip_connector_funcs analogix_dp_connector_funcs = { 89758c17f51SSandy Huang .pre_init = analogix_dp_connector_pre_init, 8986f920c07SWyon Bi .init = analogix_dp_connector_init, 8996f920c07SWyon Bi .get_edid = analogix_dp_connector_get_edid, 9006f920c07SWyon Bi .enable = analogix_dp_connector_enable, 9016f920c07SWyon Bi .disable = analogix_dp_connector_disable, 902d90a0d9fSWyon Bi .detect = analogix_dp_connector_detect, 9036f920c07SWyon Bi }; 9046f920c07SWyon Bi 9056f920c07SWyon Bi static int analogix_dp_probe(struct udevice *dev) 9066f920c07SWyon Bi { 9076f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(dev); 9086f920c07SWyon Bi const struct rockchip_connector *connector = 9096f920c07SWyon Bi (const struct rockchip_connector *)dev_get_driver_data(dev); 9106f920c07SWyon Bi const struct rockchip_dp_chip_data *pdata = connector->data; 9117adc0066SWyon Bi struct udevice *syscon; 9126f920c07SWyon Bi int ret; 9136f920c07SWyon Bi 9146f920c07SWyon Bi dp->reg_base = dev_read_addr_ptr(dev); 9156f920c07SWyon Bi 916cb17ca6cSSandy Huang dp->id = of_alias_get_id(ofnode_to_np(dev->node), "edp"); 917cb17ca6cSSandy Huang if (dp->id < 0) 918cb17ca6cSSandy Huang dp->id = 0; 9197adc0066SWyon Bi 9207adc0066SWyon Bi ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,grf", 9217adc0066SWyon Bi &syscon); 9227adc0066SWyon Bi if (!ret) { 9237adc0066SWyon Bi dp->grf = syscon_get_regmap(syscon); 9247adc0066SWyon Bi if (!dp->grf) 9257adc0066SWyon Bi return -ENODEV; 9267adc0066SWyon Bi } 9277adc0066SWyon Bi 928699c29a5SWyon Bi ret = reset_get_bulk(dev, &dp->resets); 929dddde95bSWyon Bi if (ret) { 930dddde95bSWyon Bi dev_err(dev, "failed to get reset control: %d\n", ret); 931dddde95bSWyon Bi return ret; 932dddde95bSWyon Bi } 933dddde95bSWyon Bi 9346f920c07SWyon Bi ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio, 9356f920c07SWyon Bi GPIOD_IS_IN); 9366f920c07SWyon Bi if (ret && ret != -ENOENT) { 9376f920c07SWyon Bi dev_err(dev, "failed to get hpd GPIO: %d\n", ret); 9386f920c07SWyon Bi return ret; 9396f920c07SWyon Bi } 9406f920c07SWyon Bi 941699c29a5SWyon Bi generic_phy_get_by_name(dev, "dp", &dp->phy); 942699c29a5SWyon Bi 943d90a0d9fSWyon Bi dp->force_hpd = dev_read_bool(dev, "force-hpd"); 944d90a0d9fSWyon Bi 9456f920c07SWyon Bi dp->plat_data.dev_type = ROCKCHIP_DP; 9466f920c07SWyon Bi dp->plat_data.subdev_type = pdata->chip_type; 947699c29a5SWyon Bi dp->plat_data.ssc = pdata->ssc; 9487adc0066SWyon Bi 9497adc0066SWyon Bi dp->video_info.max_link_rate = pdata->max_link_rate; 9507adc0066SWyon Bi dp->video_info.max_lane_count = pdata->max_lane_count; 9516f920c07SWyon Bi 9526f920c07SWyon Bi dp->dev = dev; 9536f920c07SWyon Bi 9546f920c07SWyon Bi return 0; 9556f920c07SWyon Bi } 9566f920c07SWyon Bi 9576f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3288_edp_platform_data = { 9586f920c07SWyon Bi .lcdsel_grf_reg = 0x025c, 9596f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 9606f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 9616f920c07SWyon Bi .chip_type = RK3288_DP, 9627adc0066SWyon Bi 9637adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 9647adc0066SWyon Bi .max_lane_count = 4, 9656f920c07SWyon Bi }; 9666f920c07SWyon Bi 9676f920c07SWyon Bi static const struct rockchip_connector rk3288_edp_driver_data = { 9686f920c07SWyon Bi .funcs = &analogix_dp_connector_funcs, 9696f920c07SWyon Bi .data = &rk3288_edp_platform_data, 9706f920c07SWyon Bi }; 9716f920c07SWyon Bi 9726f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3368_edp_platform_data = { 9736f920c07SWyon Bi .chip_type = RK3368_EDP, 9747adc0066SWyon Bi 9757adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 9767adc0066SWyon Bi .max_lane_count = 4, 9776f920c07SWyon Bi }; 9786f920c07SWyon Bi 9796f920c07SWyon Bi static const struct rockchip_connector rk3368_edp_driver_data = { 9806f920c07SWyon Bi .funcs = &analogix_dp_connector_funcs, 9816f920c07SWyon Bi .data = &rk3368_edp_platform_data, 9826f920c07SWyon Bi }; 9836f920c07SWyon Bi 9846f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3399_edp_platform_data = { 9856f920c07SWyon Bi .lcdsel_grf_reg = 0x6250, 9866f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 9876f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 9886f920c07SWyon Bi .chip_type = RK3399_EDP, 9897adc0066SWyon Bi 9907adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 9917adc0066SWyon Bi .max_lane_count = 4, 9926f920c07SWyon Bi }; 9936f920c07SWyon Bi 9946f920c07SWyon Bi static const struct rockchip_connector rk3399_edp_driver_data = { 9956f920c07SWyon Bi .funcs = &analogix_dp_connector_funcs, 9966f920c07SWyon Bi .data = &rk3399_edp_platform_data, 9976f920c07SWyon Bi }; 9986f920c07SWyon Bi 999699c29a5SWyon Bi static const struct rockchip_dp_chip_data rk3568_edp_platform_data = { 1000699c29a5SWyon Bi .chip_type = RK3568_EDP, 1001699c29a5SWyon Bi .ssc = true, 10027adc0066SWyon Bi 10037adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 10047adc0066SWyon Bi .max_lane_count = 4, 1005699c29a5SWyon Bi }; 1006699c29a5SWyon Bi 1007699c29a5SWyon Bi static const struct rockchip_connector rk3568_edp_driver_data = { 1008699c29a5SWyon Bi .funcs = &analogix_dp_connector_funcs, 1009699c29a5SWyon Bi .data = &rk3568_edp_platform_data, 1010699c29a5SWyon Bi }; 1011699c29a5SWyon Bi 10127adc0066SWyon Bi static const struct rockchip_dp_chip_data rk3588_edp_platform_data = { 10137adc0066SWyon Bi .chip_type = RK3588_EDP, 10147adc0066SWyon Bi .ssc = true, 10157adc0066SWyon Bi 10167adc0066SWyon Bi .max_link_rate = DP_LINK_BW_5_4, 10177adc0066SWyon Bi .max_lane_count = 4, 10187adc0066SWyon Bi }; 10197adc0066SWyon Bi 10207adc0066SWyon Bi static const struct rockchip_connector rk3588_edp_driver_data = { 10217adc0066SWyon Bi .funcs = &analogix_dp_connector_funcs, 10227adc0066SWyon Bi .data = &rk3588_edp_platform_data, 10237adc0066SWyon Bi }; 10247adc0066SWyon Bi 10256f920c07SWyon Bi static const struct udevice_id analogix_dp_ids[] = { 10266f920c07SWyon Bi { 10276f920c07SWyon Bi .compatible = "rockchip,rk3288-dp", 10286f920c07SWyon Bi .data = (ulong)&rk3288_edp_driver_data, 10296f920c07SWyon Bi }, { 10306f920c07SWyon Bi .compatible = "rockchip,rk3368-edp", 10316f920c07SWyon Bi .data = (ulong)&rk3368_edp_driver_data, 10326f920c07SWyon Bi }, { 10336f920c07SWyon Bi .compatible = "rockchip,rk3399-edp", 10346f920c07SWyon Bi .data = (ulong)&rk3399_edp_driver_data, 1035699c29a5SWyon Bi }, { 1036699c29a5SWyon Bi .compatible = "rockchip,rk3568-edp", 1037699c29a5SWyon Bi .data = (ulong)&rk3568_edp_driver_data, 10387adc0066SWyon Bi }, { 10397adc0066SWyon Bi .compatible = "rockchip,rk3588-edp", 10407adc0066SWyon Bi .data = (ulong)&rk3588_edp_driver_data, 10416f920c07SWyon Bi }, 10426f920c07SWyon Bi {} 10436f920c07SWyon Bi }; 10446f920c07SWyon Bi 10456f920c07SWyon Bi U_BOOT_DRIVER(analogix_dp) = { 10466f920c07SWyon Bi .name = "analogix_dp", 10476f920c07SWyon Bi .id = UCLASS_DISPLAY, 10486f920c07SWyon Bi .of_match = analogix_dp_ids, 10496f920c07SWyon Bi .probe = analogix_dp_probe, 10506f920c07SWyon Bi .priv_auto_alloc_size = sizeof(struct analogix_dp_device), 10516f920c07SWyon Bi }; 1052