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> 14*cb17ca6cSSandy Huang #include <dm/of_access.h> 156f920c07SWyon Bi #include <dm/read.h> 166f920c07SWyon Bi #include <linux/list.h> 176f920c07SWyon Bi #include <syscon.h> 186f920c07SWyon Bi #include <asm/arch-rockchip/clock.h> 196f920c07SWyon Bi #include <asm/gpio.h> 206f920c07SWyon Bi 216f920c07SWyon Bi #include "rockchip_display.h" 226f920c07SWyon Bi #include "rockchip_crtc.h" 236f920c07SWyon Bi #include "rockchip_connector.h" 246f920c07SWyon Bi #include "analogix_dp.h" 256f920c07SWyon Bi 266f920c07SWyon Bi /** 276f920c07SWyon Bi * struct rockchip_dp_chip_data - splite the grf setting of kind of chips 286f920c07SWyon Bi * @lcdsel_grf_reg: grf register offset of lcdc select 296f920c07SWyon Bi * @lcdsel_big: reg value of selecting vop big for eDP 306f920c07SWyon Bi * @lcdsel_lit: reg value of selecting vop little for eDP 31699c29a5SWyon Bi * @chip_type: specific chip type 32699c29a5SWyon Bi * @ssc: check if SSC is supported by source 336f920c07SWyon Bi */ 346f920c07SWyon Bi struct rockchip_dp_chip_data { 356f920c07SWyon Bi u32 lcdsel_grf_reg; 366f920c07SWyon Bi u32 lcdsel_big; 376f920c07SWyon Bi u32 lcdsel_lit; 386f920c07SWyon Bi u32 chip_type; 39699c29a5SWyon Bi bool ssc; 406f920c07SWyon Bi }; 416f920c07SWyon Bi 426f920c07SWyon Bi static void 436f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, 446f920c07SWyon Bi bool enable) 456f920c07SWyon Bi { 466f920c07SWyon Bi u8 data; 476f920c07SWyon Bi 486f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); 496f920c07SWyon Bi 506f920c07SWyon Bi if (enable) 516f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, 526f920c07SWyon Bi DP_LANE_COUNT_ENHANCED_FRAME_EN | 536f920c07SWyon Bi DPCD_LANE_COUNT_SET(data)); 546f920c07SWyon Bi else 556f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, 566f920c07SWyon Bi DPCD_LANE_COUNT_SET(data)); 576f920c07SWyon Bi } 586f920c07SWyon Bi 596f920c07SWyon Bi static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) 606f920c07SWyon Bi { 616f920c07SWyon Bi u8 data; 626f920c07SWyon Bi int retval; 636f920c07SWyon Bi 646f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); 656f920c07SWyon Bi retval = DPCD_ENHANCED_FRAME_CAP(data); 666f920c07SWyon Bi 676f920c07SWyon Bi return retval; 686f920c07SWyon Bi } 696f920c07SWyon Bi 706f920c07SWyon Bi static void analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp) 716f920c07SWyon Bi { 726f920c07SWyon Bi u8 data; 736f920c07SWyon Bi 746f920c07SWyon Bi data = analogix_dp_is_enhanced_mode_available(dp); 756f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(dp, data); 766f920c07SWyon Bi analogix_dp_enable_enhanced_mode(dp, data); 776f920c07SWyon Bi } 786f920c07SWyon Bi 796f920c07SWyon Bi static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) 806f920c07SWyon Bi { 816f920c07SWyon Bi analogix_dp_set_training_pattern(dp, DP_NONE); 826f920c07SWyon Bi 836f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET, 846f920c07SWyon Bi DP_TRAINING_PATTERN_DISABLE); 856f920c07SWyon Bi } 866f920c07SWyon Bi 876f920c07SWyon Bi static int analogix_dp_link_start(struct analogix_dp_device *dp) 886f920c07SWyon Bi { 896f920c07SWyon Bi u8 buf[4]; 90a6285d17SWyon Bi int lane, lane_count, retval; 916f920c07SWyon Bi 926f920c07SWyon Bi lane_count = dp->link_train.lane_count; 936f920c07SWyon Bi 946f920c07SWyon Bi dp->link_train.lt_state = CLOCK_RECOVERY; 956f920c07SWyon Bi dp->link_train.eq_loop = 0; 966f920c07SWyon Bi 976f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 986f920c07SWyon Bi dp->link_train.cr_loop[lane] = 0; 996f920c07SWyon Bi 1006f920c07SWyon Bi /* Set link rate and count as you want to establish*/ 1016f920c07SWyon Bi analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); 1026f920c07SWyon Bi analogix_dp_set_lane_count(dp, dp->link_train.lane_count); 1036f920c07SWyon Bi 1046f920c07SWyon Bi /* Setup RX configuration */ 1056f920c07SWyon Bi buf[0] = dp->link_train.link_rate; 1066f920c07SWyon Bi buf[1] = dp->link_train.lane_count; 1076f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); 1086f920c07SWyon Bi if (retval) 1096f920c07SWyon Bi return retval; 1106f920c07SWyon Bi 111699c29a5SWyon Bi /* Spread AMP if required, enable 8b/10b coding */ 112699c29a5SWyon Bi buf[0] = analogix_dp_ssc_supported(dp) ? DP_SPREAD_AMP_0_5 : 0; 113699c29a5SWyon Bi buf[1] = DP_SET_ANSI_8B10B; 114699c29a5SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_DOWNSPREAD_CTRL, 115699c29a5SWyon Bi 2, buf); 116699c29a5SWyon Bi if (retval < 0) 117699c29a5SWyon Bi return retval; 118699c29a5SWyon Bi 119253c2dc8SWyon Bi /* Set TX voltage-swing and pre-emphasis to minimum */ 1206f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 121253c2dc8SWyon Bi dp->link_train.training_lane[lane] = 122253c2dc8SWyon Bi DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | 123253c2dc8SWyon Bi DP_TRAIN_PRE_EMPH_LEVEL_0; 124253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 1256f920c07SWyon Bi 1266f920c07SWyon Bi /* Set training pattern 1 */ 1276f920c07SWyon Bi analogix_dp_set_training_pattern(dp, TRAINING_PTN1); 1286f920c07SWyon Bi 1296f920c07SWyon Bi /* Set RX training pattern */ 1306f920c07SWyon Bi retval = analogix_dp_write_byte_to_dpcd(dp, 1316f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 1326f920c07SWyon Bi DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); 1336f920c07SWyon Bi if (retval) 1346f920c07SWyon Bi return retval; 1356f920c07SWyon Bi 1366f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 1376f920c07SWyon Bi buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | 1386f920c07SWyon Bi DP_TRAIN_VOLTAGE_SWING_LEVEL_0; 1396f920c07SWyon Bi 1406f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, 1416f920c07SWyon Bi lane_count, buf); 1426f920c07SWyon Bi 1436f920c07SWyon Bi return retval; 1446f920c07SWyon Bi } 1456f920c07SWyon Bi 1466f920c07SWyon Bi static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) 1476f920c07SWyon Bi { 1486f920c07SWyon Bi int shift = (lane & 1) * 4; 1496f920c07SWyon Bi u8 link_value = link_status[lane >> 1]; 1506f920c07SWyon Bi 1516f920c07SWyon Bi return (link_value >> shift) & 0xf; 1526f920c07SWyon Bi } 1536f920c07SWyon Bi 1546f920c07SWyon Bi static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count) 1556f920c07SWyon Bi { 1566f920c07SWyon Bi int lane; 1576f920c07SWyon Bi u8 lane_status; 1586f920c07SWyon Bi 1596f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 1606f920c07SWyon Bi lane_status = analogix_dp_get_lane_status(link_status, lane); 1616f920c07SWyon Bi if ((lane_status & DP_LANE_CR_DONE) == 0) 1626f920c07SWyon Bi return -EINVAL; 1636f920c07SWyon Bi } 1646f920c07SWyon Bi return 0; 1656f920c07SWyon Bi } 1666f920c07SWyon Bi 1676f920c07SWyon Bi static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align, 1686f920c07SWyon Bi int lane_count) 1696f920c07SWyon Bi { 1706f920c07SWyon Bi int lane; 1716f920c07SWyon Bi u8 lane_status; 1726f920c07SWyon Bi 1736f920c07SWyon Bi if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) 1746f920c07SWyon Bi return -EINVAL; 1756f920c07SWyon Bi 1766f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 1776f920c07SWyon Bi lane_status = analogix_dp_get_lane_status(link_status, lane); 1786f920c07SWyon Bi lane_status &= DP_CHANNEL_EQ_BITS; 1796f920c07SWyon Bi if (lane_status != DP_CHANNEL_EQ_BITS) 1806f920c07SWyon Bi return -EINVAL; 1816f920c07SWyon Bi } 1826f920c07SWyon Bi 1836f920c07SWyon Bi return 0; 1846f920c07SWyon Bi } 1856f920c07SWyon Bi 1866f920c07SWyon Bi static unsigned char 1876f920c07SWyon Bi analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane) 1886f920c07SWyon Bi { 1896f920c07SWyon Bi int shift = (lane & 1) * 4; 1906f920c07SWyon Bi u8 link_value = adjust_request[lane >> 1]; 1916f920c07SWyon Bi 1926f920c07SWyon Bi return (link_value >> shift) & 0x3; 1936f920c07SWyon Bi } 1946f920c07SWyon Bi 1956f920c07SWyon Bi static unsigned char analogix_dp_get_adjust_request_pre_emphasis( 1966f920c07SWyon Bi u8 adjust_request[2], 1976f920c07SWyon Bi int lane) 1986f920c07SWyon Bi { 1996f920c07SWyon Bi int shift = (lane & 1) * 4; 2006f920c07SWyon Bi u8 link_value = adjust_request[lane >> 1]; 2016f920c07SWyon Bi 2026f920c07SWyon Bi return ((link_value >> shift) & 0xc) >> 2; 2036f920c07SWyon Bi } 2046f920c07SWyon Bi 2056f920c07SWyon Bi static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) 2066f920c07SWyon Bi { 2076f920c07SWyon Bi analogix_dp_training_pattern_dis(dp); 2086f920c07SWyon Bi analogix_dp_set_enhanced_mode(dp); 2096f920c07SWyon Bi 2106f920c07SWyon Bi dp->link_train.lt_state = FAILED; 2116f920c07SWyon Bi } 2126f920c07SWyon Bi 2136f920c07SWyon Bi static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp, 2146f920c07SWyon Bi u8 adjust_request[2]) 2156f920c07SWyon Bi { 2166f920c07SWyon Bi int lane, lane_count; 2176f920c07SWyon Bi u8 voltage_swing, pre_emphasis, training_lane; 2186f920c07SWyon Bi 2196f920c07SWyon Bi lane_count = dp->link_train.lane_count; 2206f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2216f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 2226f920c07SWyon Bi adjust_request, lane); 2236f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 2246f920c07SWyon Bi adjust_request, lane); 2256f920c07SWyon Bi training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | 2266f920c07SWyon Bi DPCD_PRE_EMPHASIS_SET(pre_emphasis); 2276f920c07SWyon Bi 2286f920c07SWyon Bi if (voltage_swing == VOLTAGE_LEVEL_3) 2296f920c07SWyon Bi training_lane |= DP_TRAIN_MAX_SWING_REACHED; 2306f920c07SWyon Bi if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) 2316f920c07SWyon Bi training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 2326f920c07SWyon Bi 2336f920c07SWyon Bi dp->link_train.training_lane[lane] = training_lane; 2346f920c07SWyon Bi } 2356f920c07SWyon Bi } 2366f920c07SWyon Bi 2376f920c07SWyon Bi static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) 2386f920c07SWyon Bi { 2396f920c07SWyon Bi int lane, lane_count, retval; 2406f920c07SWyon Bi u8 voltage_swing, pre_emphasis, training_lane; 2416f920c07SWyon Bi u8 link_status[2], adjust_request[2]; 2426f920c07SWyon Bi 2436f920c07SWyon Bi udelay(101); 2446f920c07SWyon Bi 2456f920c07SWyon Bi lane_count = dp->link_train.lane_count; 2466f920c07SWyon Bi 2476f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 2486f920c07SWyon Bi DP_LANE0_1_STATUS, 2, link_status); 2496f920c07SWyon Bi if (retval) 2506f920c07SWyon Bi return retval; 2516f920c07SWyon Bi 2526f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 2536f920c07SWyon Bi DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); 2546f920c07SWyon Bi if (retval) 2556f920c07SWyon Bi return retval; 2566f920c07SWyon Bi 2576f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { 2586f920c07SWyon Bi /* set training pattern 2 for EQ */ 2596f920c07SWyon Bi analogix_dp_set_training_pattern(dp, TRAINING_PTN2); 2606f920c07SWyon Bi 2616f920c07SWyon Bi retval = analogix_dp_write_byte_to_dpcd(dp, 2626f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 2636f920c07SWyon Bi DP_LINK_SCRAMBLING_DISABLE | 2646f920c07SWyon Bi DP_TRAINING_PATTERN_2); 2656f920c07SWyon Bi if (retval) 2666f920c07SWyon Bi return retval; 2676f920c07SWyon Bi 2686f920c07SWyon Bi dev_info(dp->dev, "Link Training Clock Recovery success\n"); 2696f920c07SWyon Bi dp->link_train.lt_state = EQUALIZER_TRAINING; 2706f920c07SWyon Bi } else { 2716f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2726f920c07SWyon Bi training_lane = analogix_dp_get_lane_link_training( 2736f920c07SWyon Bi dp, lane); 2746f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 2756f920c07SWyon Bi adjust_request, lane); 2766f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 2776f920c07SWyon Bi adjust_request, lane); 2786f920c07SWyon Bi 2796f920c07SWyon Bi if (DPCD_VOLTAGE_SWING_GET(training_lane) == 2806f920c07SWyon Bi voltage_swing && 2816f920c07SWyon Bi DPCD_PRE_EMPHASIS_GET(training_lane) == 2826f920c07SWyon Bi pre_emphasis) 2836f920c07SWyon Bi dp->link_train.cr_loop[lane]++; 2846f920c07SWyon Bi 2856f920c07SWyon Bi if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || 2866f920c07SWyon Bi voltage_swing == VOLTAGE_LEVEL_3 || 2876f920c07SWyon Bi pre_emphasis == PRE_EMPHASIS_LEVEL_3) { 2886f920c07SWyon Bi dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", 2896f920c07SWyon Bi dp->link_train.cr_loop[lane], 2906f920c07SWyon Bi voltage_swing, pre_emphasis); 2916f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 2926f920c07SWyon Bi return -EIO; 2936f920c07SWyon Bi } 2946f920c07SWyon Bi } 2956f920c07SWyon Bi } 2966f920c07SWyon Bi 2976f920c07SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 298253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 2996f920c07SWyon Bi 3006f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, 3016f920c07SWyon Bi DP_TRAINING_LANE0_SET, lane_count, 3026f920c07SWyon Bi dp->link_train.training_lane); 3036f920c07SWyon Bi if (retval) 3046f920c07SWyon Bi return retval; 3056f920c07SWyon Bi 3066f920c07SWyon Bi return retval; 3076f920c07SWyon Bi } 3086f920c07SWyon Bi 3096f920c07SWyon Bi static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) 3106f920c07SWyon Bi { 311253c2dc8SWyon Bi int lane_count, retval; 3126f920c07SWyon Bi u32 reg; 3136f920c07SWyon Bi u8 link_align, link_status[2], adjust_request[2]; 3146f920c07SWyon Bi 3156f920c07SWyon Bi udelay(401); 3166f920c07SWyon Bi 3176f920c07SWyon Bi lane_count = dp->link_train.lane_count; 3186f920c07SWyon Bi 3196f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 3206f920c07SWyon Bi DP_LANE0_1_STATUS, 2, link_status); 3216f920c07SWyon Bi if (retval) 3226f920c07SWyon Bi return retval; 3236f920c07SWyon Bi 3246f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { 3256f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3266f920c07SWyon Bi return -EIO; 3276f920c07SWyon Bi } 3286f920c07SWyon Bi 3296f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, 3306f920c07SWyon Bi DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); 3316f920c07SWyon Bi if (retval) 3326f920c07SWyon Bi return retval; 3336f920c07SWyon Bi 3346f920c07SWyon Bi retval = analogix_dp_read_byte_from_dpcd(dp, 3356f920c07SWyon Bi DP_LANE_ALIGN_STATUS_UPDATED, &link_align); 3366f920c07SWyon Bi if (retval) 3376f920c07SWyon Bi return retval; 3386f920c07SWyon Bi 3396f920c07SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 3406f920c07SWyon Bi 3416f920c07SWyon Bi if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { 3426f920c07SWyon Bi /* traing pattern Set to Normal */ 3436f920c07SWyon Bi analogix_dp_training_pattern_dis(dp); 3446f920c07SWyon Bi 3456f920c07SWyon Bi printf("Link Training success!\n"); 3466f920c07SWyon Bi 3476f920c07SWyon Bi analogix_dp_get_link_bandwidth(dp, ®); 3486f920c07SWyon Bi dp->link_train.link_rate = reg; 3496f920c07SWyon Bi analogix_dp_get_lane_count(dp, ®); 3506f920c07SWyon Bi dp->link_train.lane_count = reg; 3516f920c07SWyon Bi 3526f920c07SWyon Bi printf("final link rate = 0x%.2x, lane count = 0x%.2x\n", 3536f920c07SWyon Bi dp->link_train.link_rate, dp->link_train.lane_count); 3546f920c07SWyon Bi 3556f920c07SWyon Bi /* set enhanced mode if available */ 3566f920c07SWyon Bi analogix_dp_set_enhanced_mode(dp); 3576f920c07SWyon Bi dp->link_train.lt_state = FINISHED; 3586f920c07SWyon Bi 3596f920c07SWyon Bi return 0; 3606f920c07SWyon Bi } 3616f920c07SWyon Bi 3626f920c07SWyon Bi /* not all locked */ 3636f920c07SWyon Bi dp->link_train.eq_loop++; 3646f920c07SWyon Bi 3656f920c07SWyon Bi if (dp->link_train.eq_loop > MAX_EQ_LOOP) { 3666f920c07SWyon Bi dev_dbg(dp->dev, "EQ Max loop\n"); 3676f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 3686f920c07SWyon Bi return -EIO; 3696f920c07SWyon Bi } 3706f920c07SWyon Bi 371253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 3726f920c07SWyon Bi 3736f920c07SWyon Bi retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, 3746f920c07SWyon Bi lane_count, dp->link_train.training_lane); 3756f920c07SWyon Bi 3766f920c07SWyon Bi return retval; 3776f920c07SWyon Bi } 3786f920c07SWyon Bi 3796f920c07SWyon Bi static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, 3806f920c07SWyon Bi u8 *bandwidth) 3816f920c07SWyon Bi { 3826f920c07SWyon Bi u8 data; 3836f920c07SWyon Bi 3846f920c07SWyon Bi /* 3856f920c07SWyon Bi * For DP rev.1.1, Maximum link rate of Main Link lanes 3866f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps 3876f920c07SWyon Bi * For DP rev.1.2, Maximum link rate of Main Link lanes 3886f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps 3896f920c07SWyon Bi */ 3906f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); 3916f920c07SWyon Bi *bandwidth = data; 3926f920c07SWyon Bi } 3936f920c07SWyon Bi 3946f920c07SWyon Bi static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, 3956f920c07SWyon Bi u8 *lane_count) 3966f920c07SWyon Bi { 3976f920c07SWyon Bi u8 data; 3986f920c07SWyon Bi 3996f920c07SWyon Bi /* 4006f920c07SWyon Bi * For DP rev.1.1, Maximum number of Main Link lanes 4016f920c07SWyon Bi * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes 4026f920c07SWyon Bi */ 4036f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); 4046f920c07SWyon Bi *lane_count = DPCD_MAX_LANE_COUNT(data); 4056f920c07SWyon Bi } 4066f920c07SWyon Bi 4076f920c07SWyon Bi static int analogix_dp_init_training(struct analogix_dp_device *dp, 4086f920c07SWyon Bi enum link_lane_count_type max_lane, 4096f920c07SWyon Bi int max_rate) 4106f920c07SWyon Bi { 411699c29a5SWyon Bi u8 dpcd; 412699c29a5SWyon Bi 4136f920c07SWyon Bi /* 4146f920c07SWyon Bi * MACRO_RST must be applied after the PLL_LOCK to avoid 4156f920c07SWyon Bi * the DP inter pair skew issue for at least 10 us 4166f920c07SWyon Bi */ 4176f920c07SWyon Bi analogix_dp_reset_macro(dp); 4186f920c07SWyon Bi 4196f920c07SWyon Bi /* Initialize by reading RX's DPCD */ 4206f920c07SWyon Bi analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); 4216f920c07SWyon Bi analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); 4226f920c07SWyon Bi 4236f920c07SWyon Bi if ((dp->link_train.link_rate != DP_LINK_BW_1_62) && 4246f920c07SWyon Bi (dp->link_train.link_rate != DP_LINK_BW_2_7) && 4256f920c07SWyon Bi (dp->link_train.link_rate != DP_LINK_BW_5_4)) { 4266f920c07SWyon Bi dev_err(dp->dev, "failed to get Rx Max Link Rate\n"); 4276f920c07SWyon Bi return -ENODEV; 4286f920c07SWyon Bi } 4296f920c07SWyon Bi 4306f920c07SWyon Bi if (dp->link_train.lane_count == 0) { 4316f920c07SWyon Bi dev_err(dp->dev, "failed to get Rx Max Lane Count\n"); 4326f920c07SWyon Bi return -ENODEV; 4336f920c07SWyon Bi } 4346f920c07SWyon Bi 4356f920c07SWyon Bi /* Setup TX lane count & rate */ 4366f920c07SWyon Bi if (dp->link_train.lane_count > max_lane) 4376f920c07SWyon Bi dp->link_train.lane_count = max_lane; 4386f920c07SWyon Bi if (dp->link_train.link_rate > max_rate) 4396f920c07SWyon Bi dp->link_train.link_rate = max_rate; 4406f920c07SWyon Bi 441699c29a5SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_MAX_DOWNSPREAD, &dpcd); 442699c29a5SWyon Bi dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); 443699c29a5SWyon Bi 4446f920c07SWyon Bi /* All DP analog module power up */ 4456f920c07SWyon Bi analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); 4466f920c07SWyon Bi 4476f920c07SWyon Bi return 0; 4486f920c07SWyon Bi } 4496f920c07SWyon Bi 4506f920c07SWyon Bi static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) 4516f920c07SWyon Bi { 4526f920c07SWyon Bi int retval = 0, training_finished = 0; 4536f920c07SWyon Bi 4546f920c07SWyon Bi dp->link_train.lt_state = START; 4556f920c07SWyon Bi 4566f920c07SWyon Bi /* Process here */ 4576f920c07SWyon Bi while (!retval && !training_finished) { 4586f920c07SWyon Bi switch (dp->link_train.lt_state) { 4596f920c07SWyon Bi case START: 4606f920c07SWyon Bi retval = analogix_dp_link_start(dp); 4616f920c07SWyon Bi if (retval) 4626f920c07SWyon Bi dev_err(dp->dev, "LT link start failed!\n"); 4636f920c07SWyon Bi break; 4646f920c07SWyon Bi case CLOCK_RECOVERY: 4656f920c07SWyon Bi retval = analogix_dp_process_clock_recovery(dp); 4666f920c07SWyon Bi if (retval) 4676f920c07SWyon Bi dev_err(dp->dev, "LT CR failed!\n"); 4686f920c07SWyon Bi break; 4696f920c07SWyon Bi case EQUALIZER_TRAINING: 4706f920c07SWyon Bi retval = analogix_dp_process_equalizer_training(dp); 4716f920c07SWyon Bi if (retval) 4726f920c07SWyon Bi dev_err(dp->dev, "LT EQ failed!\n"); 4736f920c07SWyon Bi break; 4746f920c07SWyon Bi case FINISHED: 4756f920c07SWyon Bi training_finished = 1; 4766f920c07SWyon Bi break; 4776f920c07SWyon Bi case FAILED: 4786f920c07SWyon Bi return -EREMOTEIO; 4796f920c07SWyon Bi } 4806f920c07SWyon Bi } 4816f920c07SWyon Bi 4826f920c07SWyon Bi return retval; 4836f920c07SWyon Bi } 4846f920c07SWyon Bi 4856f920c07SWyon Bi static int analogix_dp_set_link_train(struct analogix_dp_device *dp, 4866f920c07SWyon Bi u32 count, u32 bwtype) 4876f920c07SWyon Bi { 4886f920c07SWyon Bi int ret; 4896f920c07SWyon Bi 4906f920c07SWyon Bi ret = analogix_dp_init_training(dp, count, bwtype); 4916f920c07SWyon Bi if (ret < 0) { 4926f920c07SWyon Bi dev_err(dp->dev, "failed to init training\n"); 4936f920c07SWyon Bi return ret; 4946f920c07SWyon Bi } 4956f920c07SWyon Bi 4966f920c07SWyon Bi ret = analogix_dp_sw_link_training(dp); 4976f920c07SWyon Bi if (ret < 0) { 4986f920c07SWyon Bi dev_err(dp->dev, "failed to do sw link training\n"); 4996f920c07SWyon Bi return ret; 5006f920c07SWyon Bi } 5016f920c07SWyon Bi 5026f920c07SWyon Bi return 0; 5036f920c07SWyon Bi } 5046f920c07SWyon Bi 5056f920c07SWyon Bi static int analogix_dp_config_video(struct analogix_dp_device *dp) 5066f920c07SWyon Bi { 5076f920c07SWyon Bi int timeout_loop = 0; 5086f920c07SWyon Bi int done_count = 0; 5096f920c07SWyon Bi 5106f920c07SWyon Bi analogix_dp_config_video_slave_mode(dp); 5116f920c07SWyon Bi 5126f920c07SWyon Bi analogix_dp_set_video_color_format(dp); 5136f920c07SWyon Bi 5146f920c07SWyon Bi if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { 5156f920c07SWyon Bi dev_err(dp->dev, "PLL is not locked yet.\n"); 5166f920c07SWyon Bi return -EINVAL; 5176f920c07SWyon Bi } 5186f920c07SWyon Bi 5196f920c07SWyon Bi for (;;) { 5206f920c07SWyon Bi timeout_loop++; 5216f920c07SWyon Bi if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0) 5226f920c07SWyon Bi break; 5236f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 5246f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 5256f920c07SWyon Bi return -ETIMEDOUT; 5266f920c07SWyon Bi } 5276f920c07SWyon Bi 5286f920c07SWyon Bi udelay(2); 5296f920c07SWyon Bi } 5306f920c07SWyon Bi 5316f920c07SWyon Bi /* Set to use the register calculated M/N video */ 5326f920c07SWyon Bi analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); 5336f920c07SWyon Bi 5346f920c07SWyon Bi /* For video bist, Video timing must be generated by register */ 5356f920c07SWyon Bi analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); 5366f920c07SWyon Bi 5376f920c07SWyon Bi /* Disable video mute */ 5386f920c07SWyon Bi analogix_dp_enable_video_mute(dp, 0); 5396f920c07SWyon Bi 5406f920c07SWyon Bi /* Configure video slave mode */ 5416f920c07SWyon Bi analogix_dp_enable_video_master(dp, 0); 5426f920c07SWyon Bi 5436f920c07SWyon Bi /* Enable video input */ 5446f920c07SWyon Bi analogix_dp_start_video(dp); 5456f920c07SWyon Bi 5466f920c07SWyon Bi timeout_loop = 0; 5476f920c07SWyon Bi 5486f920c07SWyon Bi for (;;) { 5496f920c07SWyon Bi timeout_loop++; 5506f920c07SWyon Bi if (analogix_dp_is_video_stream_on(dp) == 0) { 5516f920c07SWyon Bi done_count++; 5526f920c07SWyon Bi if (done_count > 10) 5536f920c07SWyon Bi break; 5546f920c07SWyon Bi } else if (done_count) { 5556f920c07SWyon Bi done_count = 0; 5566f920c07SWyon Bi } 5576f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 5586f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 5596f920c07SWyon Bi return -ETIMEDOUT; 5606f920c07SWyon Bi } 5616f920c07SWyon Bi 5626f920c07SWyon Bi udelay(1001); 5636f920c07SWyon Bi } 5646f920c07SWyon Bi 5656f920c07SWyon Bi return 0; 5666f920c07SWyon Bi } 5676f920c07SWyon Bi 5686f920c07SWyon Bi static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, 5696f920c07SWyon Bi bool enable) 5706f920c07SWyon Bi { 5716f920c07SWyon Bi u8 data; 5726f920c07SWyon Bi 5736f920c07SWyon Bi if (enable) { 5746f920c07SWyon Bi analogix_dp_enable_scrambling(dp); 5756f920c07SWyon Bi 5766f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, 5776f920c07SWyon Bi &data); 5786f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 5796f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 5806f920c07SWyon Bi (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); 5816f920c07SWyon Bi } else { 5826f920c07SWyon Bi analogix_dp_disable_scrambling(dp); 5836f920c07SWyon Bi 5846f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, 5856f920c07SWyon Bi &data); 5866f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 5876f920c07SWyon Bi DP_TRAINING_PATTERN_SET, 5886f920c07SWyon Bi (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); 5896f920c07SWyon Bi } 5906f920c07SWyon Bi } 5916f920c07SWyon Bi 5926f920c07SWyon Bi static void analogix_dp_init_dp(struct analogix_dp_device *dp) 5936f920c07SWyon Bi { 5946f920c07SWyon Bi analogix_dp_reset(dp); 5956f920c07SWyon Bi 5966f920c07SWyon Bi analogix_dp_swreset(dp); 5976f920c07SWyon Bi 5986f920c07SWyon Bi analogix_dp_init_analog_param(dp); 5996f920c07SWyon Bi analogix_dp_init_interrupt(dp); 6006f920c07SWyon Bi 6016f920c07SWyon Bi /* SW defined function Normal operation */ 6026f920c07SWyon Bi analogix_dp_enable_sw_function(dp); 6036f920c07SWyon Bi 6046f920c07SWyon Bi analogix_dp_config_interrupt(dp); 6056f920c07SWyon Bi analogix_dp_init_analog_func(dp); 6066f920c07SWyon Bi 6076f920c07SWyon Bi analogix_dp_init_hpd(dp); 6086f920c07SWyon Bi analogix_dp_init_aux(dp); 6096f920c07SWyon Bi } 6106f920c07SWyon Bi 6116f920c07SWyon Bi static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) 6126f920c07SWyon Bi { 6136f920c07SWyon Bi int i; 6146f920c07SWyon Bi unsigned char sum = 0; 6156f920c07SWyon Bi 6166f920c07SWyon Bi for (i = 0; i < EDID_BLOCK_LENGTH; i++) 6176f920c07SWyon Bi sum = sum + edid_data[i]; 6186f920c07SWyon Bi 6196f920c07SWyon Bi return sum; 6206f920c07SWyon Bi } 6216f920c07SWyon Bi 6226f920c07SWyon Bi static int analogix_dp_read_edid(struct analogix_dp_device *dp) 6236f920c07SWyon Bi { 6246f920c07SWyon Bi unsigned char *edid = dp->edid; 6256f920c07SWyon Bi unsigned int extend_block = 0; 6266f920c07SWyon Bi unsigned char test_vector; 6276f920c07SWyon Bi int retval; 6286f920c07SWyon Bi 6296f920c07SWyon Bi /* 6306f920c07SWyon Bi * EDID device address is 0x50. 6316f920c07SWyon Bi * However, if necessary, you must have set upper address 6326f920c07SWyon Bi * into E-EDID in I2C device, 0x30. 6336f920c07SWyon Bi */ 6346f920c07SWyon Bi 6356f920c07SWyon Bi /* Read Extension Flag, Number of 128-byte EDID extension blocks */ 6366f920c07SWyon Bi retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, 6376f920c07SWyon Bi EDID_EXTENSION_FLAG, 6386f920c07SWyon Bi &extend_block); 6396f920c07SWyon Bi if (retval) 6406f920c07SWyon Bi return retval; 6416f920c07SWyon Bi 6426f920c07SWyon Bi if (extend_block > 0) { 6436f920c07SWyon Bi debug("EDID data includes a single extension!\n"); 6446f920c07SWyon Bi 6456f920c07SWyon Bi /* Read EDID data */ 6466f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6476f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, 6486f920c07SWyon Bi EDID_HEADER_PATTERN, 6496f920c07SWyon Bi EDID_BLOCK_LENGTH, 6506f920c07SWyon Bi &edid[EDID_HEADER_PATTERN]); 6516f920c07SWyon Bi if (retval < 0) 6526f920c07SWyon Bi return retval; 6536f920c07SWyon Bi 6546f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(edid)) 6556f920c07SWyon Bi return -EINVAL; 6566f920c07SWyon Bi 6576f920c07SWyon Bi /* Read additional EDID data */ 6586f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6596f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, 6606f920c07SWyon Bi EDID_BLOCK_LENGTH, 6616f920c07SWyon Bi EDID_BLOCK_LENGTH, 6626f920c07SWyon Bi &edid[EDID_BLOCK_LENGTH]); 6636f920c07SWyon Bi if (retval < 0) 6646f920c07SWyon Bi return retval; 6656f920c07SWyon Bi 6666f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH])) 6676f920c07SWyon Bi return -EINVAL; 6686f920c07SWyon Bi 6696f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, 6706f920c07SWyon Bi &test_vector); 6716f920c07SWyon Bi if (test_vector & DP_TEST_LINK_EDID_READ) { 6726f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6736f920c07SWyon Bi DP_TEST_EDID_CHECKSUM, 6746f920c07SWyon Bi edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); 6756f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6766f920c07SWyon Bi DP_TEST_RESPONSE, 6776f920c07SWyon Bi DP_TEST_EDID_CHECKSUM_WRITE); 6786f920c07SWyon Bi } 6796f920c07SWyon Bi } else { 6806f920c07SWyon Bi dev_info(dp->dev, 6816f920c07SWyon Bi "EDID data does not include any extensions.\n"); 6826f920c07SWyon Bi 6836f920c07SWyon Bi /* Read EDID data */ 6846f920c07SWyon Bi retval = analogix_dp_read_bytes_from_i2c(dp, 6856f920c07SWyon Bi I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, 6866f920c07SWyon Bi EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); 6876f920c07SWyon Bi if (retval < 0) 6886f920c07SWyon Bi return retval; 6896f920c07SWyon Bi 6906f920c07SWyon Bi if (analogix_dp_calc_edid_check_sum(edid)) 6916f920c07SWyon Bi return -EINVAL; 6926f920c07SWyon Bi 6936f920c07SWyon Bi analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, 6946f920c07SWyon Bi &test_vector); 6956f920c07SWyon Bi if (test_vector & DP_TEST_LINK_EDID_READ) { 6966f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6976f920c07SWyon Bi DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); 6986f920c07SWyon Bi analogix_dp_write_byte_to_dpcd(dp, 6996f920c07SWyon Bi DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); 7006f920c07SWyon Bi } 7016f920c07SWyon Bi } 7026f920c07SWyon Bi 7036f920c07SWyon Bi return 0; 7046f920c07SWyon Bi } 7056f920c07SWyon Bi 7066f920c07SWyon Bi static int analogix_dp_handle_edid(struct analogix_dp_device *dp) 7076f920c07SWyon Bi { 7086f920c07SWyon Bi u8 buf[12]; 7096f920c07SWyon Bi int i, try = 5; 7106f920c07SWyon Bi int retval; 7116f920c07SWyon Bi 7126f920c07SWyon Bi retry: 7136f920c07SWyon Bi /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ 7146f920c07SWyon Bi retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); 7156f920c07SWyon Bi 7166f920c07SWyon Bi if (retval && try--) { 7176f920c07SWyon Bi mdelay(10); 7186f920c07SWyon Bi goto retry; 7196f920c07SWyon Bi } 7206f920c07SWyon Bi 7216f920c07SWyon Bi if (retval) 7226f920c07SWyon Bi return retval; 7236f920c07SWyon Bi 7246f920c07SWyon Bi /* Read EDID */ 7256f920c07SWyon Bi for (i = 0; i < 3; i++) { 7266f920c07SWyon Bi retval = analogix_dp_read_edid(dp); 7276f920c07SWyon Bi if (!retval) 7286f920c07SWyon Bi break; 7296f920c07SWyon Bi } 7306f920c07SWyon Bi 7316f920c07SWyon Bi return retval; 7326f920c07SWyon Bi } 7336f920c07SWyon Bi 73458c17f51SSandy Huang static int analogix_dp_connector_pre_init(struct display_state *state) 73558c17f51SSandy Huang { 73658c17f51SSandy Huang struct connector_state *conn_state = &state->conn_state; 73758c17f51SSandy Huang 73858c17f51SSandy Huang conn_state->type = DRM_MODE_CONNECTOR_eDP; 73958c17f51SSandy Huang 74058c17f51SSandy Huang return 0; 74158c17f51SSandy Huang } 74258c17f51SSandy Huang 7436f920c07SWyon Bi static int analogix_dp_connector_init(struct display_state *state) 7446f920c07SWyon Bi { 7456f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 7466f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 7476f920c07SWyon Bi 748699c29a5SWyon Bi conn_state->output_if |= VOP_OUTPUT_IF_eDP0; 7496f920c07SWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 7506f920c07SWyon Bi conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 7516f920c07SWyon Bi 752699c29a5SWyon Bi reset_assert_bulk(&dp->resets); 753dddde95bSWyon Bi udelay(1); 754699c29a5SWyon Bi reset_deassert_bulk(&dp->resets); 755dddde95bSWyon Bi 756*cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, dp->id); 757699c29a5SWyon Bi generic_phy_power_on(&dp->phy); 7586f920c07SWyon Bi analogix_dp_init_dp(dp); 7596f920c07SWyon Bi 7606f920c07SWyon Bi return 0; 7616f920c07SWyon Bi } 7626f920c07SWyon Bi 7636f920c07SWyon Bi static int analogix_dp_connector_get_edid(struct display_state *state) 7646f920c07SWyon Bi { 7656f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 7666f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 7676f920c07SWyon Bi int ret; 7686f920c07SWyon Bi 7696f920c07SWyon Bi ret = analogix_dp_handle_edid(dp); 7706f920c07SWyon Bi if (ret) { 7716f920c07SWyon Bi dev_err(dp->dev, "failed to get edid\n"); 7726f920c07SWyon Bi return ret; 7736f920c07SWyon Bi } 7746f920c07SWyon Bi 7756f920c07SWyon Bi memcpy(&conn_state->edid, &dp->edid, sizeof(dp->edid)); 7766f920c07SWyon Bi 7776f920c07SWyon Bi return 0; 7786f920c07SWyon Bi } 7796f920c07SWyon Bi 7806f920c07SWyon Bi static int analogix_dp_connector_enable(struct display_state *state) 7816f920c07SWyon Bi { 7826f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 7836f920c07SWyon Bi struct crtc_state *crtc_state = &state->crtc_state; 7846f920c07SWyon Bi const struct rockchip_connector *connector = conn_state->connector; 7856f920c07SWyon Bi const struct rockchip_dp_chip_data *pdata = connector->data; 7866f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 7872a74799bSJianqun Xu struct video_info *video = &dp->video_info; 7886f920c07SWyon Bi u32 val; 7896f920c07SWyon Bi int ret; 7906f920c07SWyon Bi 791699c29a5SWyon Bi if (pdata->lcdsel_grf_reg) { 7926f920c07SWyon Bi if (crtc_state->crtc_id) 7936f920c07SWyon Bi val = pdata->lcdsel_lit; 7946f920c07SWyon Bi else 7956f920c07SWyon Bi val = pdata->lcdsel_big; 7966f920c07SWyon Bi 797699c29a5SWyon Bi writel(val, syscon_get_first_range(ROCKCHIP_SYSCON_GRF) + pdata->lcdsel_grf_reg); 7986f920c07SWyon Bi } 7996f920c07SWyon Bi 8002a74799bSJianqun Xu switch (conn_state->bpc) { 8012a74799bSJianqun Xu case 12: 8022a74799bSJianqun Xu video->color_depth = COLOR_12; 8032a74799bSJianqun Xu break; 8042a74799bSJianqun Xu case 10: 8052a74799bSJianqun Xu video->color_depth = COLOR_10; 8062a74799bSJianqun Xu break; 8072a74799bSJianqun Xu case 6: 8082a74799bSJianqun Xu video->color_depth = COLOR_6; 8092a74799bSJianqun Xu break; 8102a74799bSJianqun Xu case 8: 8112a74799bSJianqun Xu default: 8122a74799bSJianqun Xu video->color_depth = COLOR_8; 8132a74799bSJianqun Xu break; 8142a74799bSJianqun Xu } 8152a74799bSJianqun Xu 8166f920c07SWyon Bi ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, 8176f920c07SWyon Bi dp->video_info.max_link_rate); 8186f920c07SWyon Bi if (ret) { 8196f920c07SWyon Bi dev_err(dp->dev, "unable to do link train\n"); 8206f920c07SWyon Bi return ret; 8216f920c07SWyon Bi } 8226f920c07SWyon Bi 8236f920c07SWyon Bi analogix_dp_enable_scramble(dp, 1); 8246f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(dp, 1); 8256f920c07SWyon Bi analogix_dp_enable_enhanced_mode(dp, 1); 8266f920c07SWyon Bi 8276f920c07SWyon Bi analogix_dp_init_video(dp); 8286f920c07SWyon Bi ret = analogix_dp_config_video(dp); 8296f920c07SWyon Bi if (ret) { 8306f920c07SWyon Bi dev_err(dp->dev, "unable to config video\n"); 8316f920c07SWyon Bi return ret; 8326f920c07SWyon Bi } 8336f920c07SWyon Bi 8346f920c07SWyon Bi return 0; 8356f920c07SWyon Bi } 8366f920c07SWyon Bi 8376f920c07SWyon Bi static int analogix_dp_connector_disable(struct display_state *state) 8386f920c07SWyon Bi { 8396f920c07SWyon Bi /* TODO */ 8406f920c07SWyon Bi 8416f920c07SWyon Bi return 0; 8426f920c07SWyon Bi } 8436f920c07SWyon Bi 844d90a0d9fSWyon Bi static int analogix_dp_connector_detect(struct display_state *state) 845d90a0d9fSWyon Bi { 846d90a0d9fSWyon Bi struct connector_state *conn_state = &state->conn_state; 847d90a0d9fSWyon Bi struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); 848d90a0d9fSWyon Bi 849d90a0d9fSWyon Bi return analogix_dp_detect(dp); 850d90a0d9fSWyon Bi } 851d90a0d9fSWyon Bi 8526f920c07SWyon Bi static const struct rockchip_connector_funcs analogix_dp_connector_funcs = { 85358c17f51SSandy Huang .pre_init = analogix_dp_connector_pre_init, 8546f920c07SWyon Bi .init = analogix_dp_connector_init, 8556f920c07SWyon Bi .get_edid = analogix_dp_connector_get_edid, 8566f920c07SWyon Bi .enable = analogix_dp_connector_enable, 8576f920c07SWyon Bi .disable = analogix_dp_connector_disable, 858d90a0d9fSWyon Bi .detect = analogix_dp_connector_detect, 8596f920c07SWyon Bi }; 8606f920c07SWyon Bi 8616f920c07SWyon Bi static int analogix_dp_probe(struct udevice *dev) 8626f920c07SWyon Bi { 8636f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(dev); 8646f920c07SWyon Bi const struct rockchip_connector *connector = 8656f920c07SWyon Bi (const struct rockchip_connector *)dev_get_driver_data(dev); 8666f920c07SWyon Bi const struct rockchip_dp_chip_data *pdata = connector->data; 8676f920c07SWyon Bi int ret; 8686f920c07SWyon Bi 8696f920c07SWyon Bi dp->reg_base = dev_read_addr_ptr(dev); 8706f920c07SWyon Bi 871*cb17ca6cSSandy Huang dp->id = of_alias_get_id(ofnode_to_np(dev->node), "edp"); 872*cb17ca6cSSandy Huang if (dp->id < 0) 873*cb17ca6cSSandy Huang dp->id = 0; 874699c29a5SWyon Bi ret = reset_get_bulk(dev, &dp->resets); 875dddde95bSWyon Bi if (ret) { 876dddde95bSWyon Bi dev_err(dev, "failed to get reset control: %d\n", ret); 877dddde95bSWyon Bi return ret; 878dddde95bSWyon Bi } 879dddde95bSWyon Bi 8806f920c07SWyon Bi ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio, 8816f920c07SWyon Bi GPIOD_IS_IN); 8826f920c07SWyon Bi if (ret && ret != -ENOENT) { 8836f920c07SWyon Bi dev_err(dev, "failed to get hpd GPIO: %d\n", ret); 8846f920c07SWyon Bi return ret; 8856f920c07SWyon Bi } 8866f920c07SWyon Bi 887699c29a5SWyon Bi generic_phy_get_by_name(dev, "dp", &dp->phy); 888699c29a5SWyon Bi 889d90a0d9fSWyon Bi dp->force_hpd = dev_read_bool(dev, "force-hpd"); 890d90a0d9fSWyon Bi 8916f920c07SWyon Bi dp->plat_data.dev_type = ROCKCHIP_DP; 8926f920c07SWyon Bi dp->plat_data.subdev_type = pdata->chip_type; 893699c29a5SWyon Bi dp->plat_data.ssc = pdata->ssc; 8946f920c07SWyon Bi /* 8956f920c07SWyon Bi * Like Rockchip DisplayPort TRM indicate that "Main link 8966f920c07SWyon Bi * containing 4 physical lanes of 2.7/1.62 Gbps/lane". 8976f920c07SWyon Bi */ 8986f920c07SWyon Bi dp->video_info.max_link_rate = 0x0A; 8996f920c07SWyon Bi dp->video_info.max_lane_count = 0x04; 9006f920c07SWyon Bi 9016f920c07SWyon Bi dp->dev = dev; 9026f920c07SWyon Bi 9036f920c07SWyon Bi return 0; 9046f920c07SWyon Bi } 9056f920c07SWyon Bi 9066f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3288_edp_platform_data = { 9076f920c07SWyon Bi .lcdsel_grf_reg = 0x025c, 9086f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 9096f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 9106f920c07SWyon Bi .chip_type = RK3288_DP, 9116f920c07SWyon Bi }; 9126f920c07SWyon Bi 9136f920c07SWyon Bi static const struct rockchip_connector rk3288_edp_driver_data = { 9146f920c07SWyon Bi .funcs = &analogix_dp_connector_funcs, 9156f920c07SWyon Bi .data = &rk3288_edp_platform_data, 9166f920c07SWyon Bi }; 9176f920c07SWyon Bi 9186f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3368_edp_platform_data = { 9196f920c07SWyon Bi .chip_type = RK3368_EDP, 9206f920c07SWyon Bi }; 9216f920c07SWyon Bi 9226f920c07SWyon Bi static const struct rockchip_connector rk3368_edp_driver_data = { 9236f920c07SWyon Bi .funcs = &analogix_dp_connector_funcs, 9246f920c07SWyon Bi .data = &rk3368_edp_platform_data, 9256f920c07SWyon Bi }; 9266f920c07SWyon Bi 9276f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3399_edp_platform_data = { 9286f920c07SWyon Bi .lcdsel_grf_reg = 0x6250, 9296f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 9306f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 9316f920c07SWyon Bi .chip_type = RK3399_EDP, 9326f920c07SWyon Bi }; 9336f920c07SWyon Bi 9346f920c07SWyon Bi static const struct rockchip_connector rk3399_edp_driver_data = { 9356f920c07SWyon Bi .funcs = &analogix_dp_connector_funcs, 9366f920c07SWyon Bi .data = &rk3399_edp_platform_data, 9376f920c07SWyon Bi }; 9386f920c07SWyon Bi 939699c29a5SWyon Bi static const struct rockchip_dp_chip_data rk3568_edp_platform_data = { 940699c29a5SWyon Bi .chip_type = RK3568_EDP, 941699c29a5SWyon Bi .ssc = true, 942699c29a5SWyon Bi }; 943699c29a5SWyon Bi 944699c29a5SWyon Bi static const struct rockchip_connector rk3568_edp_driver_data = { 945699c29a5SWyon Bi .funcs = &analogix_dp_connector_funcs, 946699c29a5SWyon Bi .data = &rk3568_edp_platform_data, 947699c29a5SWyon Bi }; 948699c29a5SWyon Bi 9496f920c07SWyon Bi static const struct udevice_id analogix_dp_ids[] = { 9506f920c07SWyon Bi { 9516f920c07SWyon Bi .compatible = "rockchip,rk3288-dp", 9526f920c07SWyon Bi .data = (ulong)&rk3288_edp_driver_data, 9536f920c07SWyon Bi }, { 9546f920c07SWyon Bi .compatible = "rockchip,rk3368-edp", 9556f920c07SWyon Bi .data = (ulong)&rk3368_edp_driver_data, 9566f920c07SWyon Bi }, { 9576f920c07SWyon Bi .compatible = "rockchip,rk3399-edp", 9586f920c07SWyon Bi .data = (ulong)&rk3399_edp_driver_data, 959699c29a5SWyon Bi }, { 960699c29a5SWyon Bi .compatible = "rockchip,rk3568-edp", 961699c29a5SWyon Bi .data = (ulong)&rk3568_edp_driver_data, 9626f920c07SWyon Bi }, 9636f920c07SWyon Bi {} 9646f920c07SWyon Bi }; 9656f920c07SWyon Bi 9666f920c07SWyon Bi U_BOOT_DRIVER(analogix_dp) = { 9676f920c07SWyon Bi .name = "analogix_dp", 9686f920c07SWyon Bi .id = UCLASS_DISPLAY, 9696f920c07SWyon Bi .of_match = analogix_dp_ids, 9706f920c07SWyon Bi .probe = analogix_dp_probe, 9716f920c07SWyon Bi .priv_auto_alloc_size = sizeof(struct analogix_dp_device), 9726f920c07SWyon Bi }; 973