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> 18d67c1260SDamon Ding #include <linux/media-bus-format.h> 196f920c07SWyon Bi #include <syscon.h> 206f920c07SWyon Bi #include <asm/arch-rockchip/clock.h> 216f920c07SWyon Bi #include <asm/gpio.h> 226f920c07SWyon Bi 236f920c07SWyon Bi #include "rockchip_display.h" 246f920c07SWyon Bi #include "rockchip_crtc.h" 256f920c07SWyon Bi #include "rockchip_connector.h" 266f920c07SWyon Bi #include "analogix_dp.h" 276f920c07SWyon Bi 287adc0066SWyon Bi #define RK3588_GRF_VO1_CON0 0x0000 297adc0066SWyon Bi #define EDP_MODE BIT(0) 307adc0066SWyon Bi #define RK3588_GRF_VO1_CON1 0x0004 317adc0066SWyon Bi 326f920c07SWyon Bi /** 336f920c07SWyon Bi * struct rockchip_dp_chip_data - splite the grf setting of kind of chips 346f920c07SWyon Bi * @lcdsel_grf_reg: grf register offset of lcdc select 356f920c07SWyon Bi * @lcdsel_big: reg value of selecting vop big for eDP 366f920c07SWyon Bi * @lcdsel_lit: reg value of selecting vop little for eDP 37699c29a5SWyon Bi * @chip_type: specific chip type 38699c29a5SWyon Bi * @ssc: check if SSC is supported by source 39d67c1260SDamon Ding * @max_link_rate: max supported link rate 40d67c1260SDamon Ding * @max_lane_count: max supported lane count 41d67c1260SDamon Ding * @format_yuv: check if yuv color format is supported 4232035f4bSDamon Ding * @support_dp_mode: check if dp mode is supported 43d67c1260SDamon Ding * @max_bpc: max supported bpc which set to 8 by default 446f920c07SWyon Bi */ 456f920c07SWyon Bi struct rockchip_dp_chip_data { 466f920c07SWyon Bi u32 lcdsel_grf_reg; 476f920c07SWyon Bi u32 lcdsel_big; 486f920c07SWyon Bi u32 lcdsel_lit; 496f920c07SWyon Bi u32 chip_type; 50699c29a5SWyon Bi bool ssc; 517adc0066SWyon Bi 527adc0066SWyon Bi u32 max_link_rate; 537adc0066SWyon Bi u32 max_lane_count; 54d67c1260SDamon Ding bool format_yuv; 5532035f4bSDamon Ding bool support_dp_mode; 56d67c1260SDamon Ding u8 max_bpc; 576f920c07SWyon Bi }; 586f920c07SWyon Bi 59d67c1260SDamon Ding static const struct analogix_dp_output_format possible_output_fmts[] = { 60d67c1260SDamon Ding { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, 10 }, 61d67c1260SDamon Ding { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, 8 }, 62d67c1260SDamon Ding { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, 6 }, 63d67c1260SDamon Ding { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444, 10 }, 64d67c1260SDamon Ding { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444, 8}, 65d67c1260SDamon Ding { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422, 10 }, 66d67c1260SDamon Ding { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422, 8 }, 67d67c1260SDamon Ding }; 68d67c1260SDamon Ding 69d67c1260SDamon Ding static u8 analogix_dp_get_output_bpp(const struct analogix_dp_output_format *fmt) 70d67c1260SDamon Ding { 71d67c1260SDamon Ding switch (fmt->color_format) { 72d67c1260SDamon Ding case DRM_COLOR_FORMAT_YCRCB422: 73d67c1260SDamon Ding return fmt->bpc * 2; 74d67c1260SDamon Ding case DRM_COLOR_FORMAT_RGB444: 75d67c1260SDamon Ding case DRM_COLOR_FORMAT_YCRCB444: 76d67c1260SDamon Ding default: 77d67c1260SDamon Ding return fmt->bpc * 3; 78d67c1260SDamon Ding } 79d67c1260SDamon Ding } 80d67c1260SDamon Ding 812fcb4783SDamon Ding static int 826f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, 836f920c07SWyon Bi bool enable) 846f920c07SWyon Bi { 856f920c07SWyon Bi u8 data; 862fcb4783SDamon Ding int ret; 876f920c07SWyon Bi 882fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data); 892fcb4783SDamon Ding if (ret != 1) 902fcb4783SDamon Ding return ret; 916f920c07SWyon Bi 926f920c07SWyon Bi if (enable) 932fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, 946f920c07SWyon Bi DP_LANE_COUNT_ENHANCED_FRAME_EN | 956f920c07SWyon Bi DPCD_LANE_COUNT_SET(data)); 966f920c07SWyon Bi else 972fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, 986f920c07SWyon Bi DPCD_LANE_COUNT_SET(data)); 992fcb4783SDamon Ding 1002fcb4783SDamon Ding return ret < 0 ? ret : 0; 1016f920c07SWyon Bi } 1026f920c07SWyon Bi 1032fcb4783SDamon Ding static int analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp) 1046f920c07SWyon Bi { 1051bf3c971SDamon Ding bool enhanced_frame_en; 1066f920c07SWyon Bi u8 data; 1072fcb4783SDamon Ding int ret; 1086f920c07SWyon Bi 1091bf3c971SDamon Ding enhanced_frame_en = drm_dp_enhanced_frame_cap(dp->dpcd); 1101bf3c971SDamon Ding 1111bf3c971SDamon Ding ret = analogix_dp_enable_rx_to_enhanced_mode(dp, enhanced_frame_en); 1122fcb4783SDamon Ding if (ret < 0) 1132fcb4783SDamon Ding return ret; 1142fcb4783SDamon Ding 1151bf3c971SDamon Ding if (!enhanced_frame_en) { 11606b1b28fSDamon Ding /* 11706b1b28fSDamon Ding * As the Table 3-4 in eDP v1.2 spec: 11806b1b28fSDamon Ding * DPCD 0000Dh: 11906b1b28fSDamon Ding * Bit 1 = FRAMING_CHANGE_CAPABLE 12006b1b28fSDamon Ding * A setting of 1 indicates that this is an eDP device that 12106b1b28fSDamon Ding * uses only Enhanced Framing, independently of the setting by 12206b1b28fSDamon Ding * the source of ENHANCED_FRAME_EN 12306b1b28fSDamon Ding * 12406b1b28fSDamon Ding * And as the Table 3-3 in eDP v1.4 spec: 12506b1b28fSDamon Ding * DPCD 0000Dh: 12606b1b28fSDamon Ding * Bit 1 = RESERVED for eDP 12706b1b28fSDamon Ding * New to eDP v1.4.(Read all 0s) 12806b1b28fSDamon Ding */ 12906b1b28fSDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_CONFIGURATION_CAP, 13006b1b28fSDamon Ding &data); 13106b1b28fSDamon Ding if (ret < 0) 13206b1b28fSDamon Ding return ret; 13306b1b28fSDamon Ding 1341bf3c971SDamon Ding enhanced_frame_en = !!(data & DP_FRAMING_CHANGE_CAP); 13506b1b28fSDamon Ding } 13606b1b28fSDamon Ding 1371bf3c971SDamon Ding analogix_dp_enable_enhanced_mode(dp, enhanced_frame_en); 1382fcb4783SDamon Ding 1392fcb4783SDamon Ding return 0; 1406f920c07SWyon Bi } 1416f920c07SWyon Bi 1422fcb4783SDamon Ding static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) 1436f920c07SWyon Bi { 1442fcb4783SDamon Ding int ret; 1452fcb4783SDamon Ding 1466f920c07SWyon Bi analogix_dp_set_training_pattern(dp, DP_NONE); 1476f920c07SWyon Bi 1482fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 1496f920c07SWyon Bi DP_TRAINING_PATTERN_DISABLE); 1502fcb4783SDamon Ding 1512fcb4783SDamon Ding return ret < 0 ? ret : 0; 1526f920c07SWyon Bi } 1536f920c07SWyon Bi 154fc275078SDamon Ding static int analogix_dp_enable_sink_to_assr_mode(struct analogix_dp_device *dp, bool enable) 155fc275078SDamon Ding { 156fc275078SDamon Ding u8 data; 157fc275078SDamon Ding int ret; 158fc275078SDamon Ding 159fc275078SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_CONFIGURATION_SET, &data); 160fc275078SDamon Ding if (ret != 1) 161fc275078SDamon Ding return ret; 162fc275078SDamon Ding 163fc275078SDamon Ding if (enable) 164fc275078SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET, 165fc275078SDamon Ding data | DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); 166fc275078SDamon Ding else 1674e1a12d5SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET, 168fc275078SDamon Ding data & ~DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); 169fc275078SDamon Ding 170fc275078SDamon Ding return ret < 0 ? ret : 0; 171fc275078SDamon Ding } 172fc275078SDamon Ding 173fc275078SDamon Ding static int analogix_dp_set_assr_mode(struct analogix_dp_device *dp) 174fc275078SDamon Ding { 175fc275078SDamon Ding bool assr_en; 176fc275078SDamon Ding int ret; 177fc275078SDamon Ding 178fc275078SDamon Ding assr_en = drm_dp_alternate_scrambler_reset_cap(dp->dpcd); 179fc275078SDamon Ding 180fc275078SDamon Ding ret = analogix_dp_enable_sink_to_assr_mode(dp, assr_en); 181fc275078SDamon Ding if (ret < 0) 182fc275078SDamon Ding return ret; 183fc275078SDamon Ding 184fc275078SDamon Ding analogix_dp_enable_assr_mode(dp, assr_en); 185fc275078SDamon Ding 186fc275078SDamon Ding return 0; 187fc275078SDamon Ding } 188fc275078SDamon Ding 1896f920c07SWyon Bi static int analogix_dp_link_start(struct analogix_dp_device *dp) 1906f920c07SWyon Bi { 1916f920c07SWyon Bi u8 buf[4]; 192a6285d17SWyon Bi int lane, lane_count, retval; 1936f920c07SWyon Bi 1946f920c07SWyon Bi lane_count = dp->link_train.lane_count; 1956f920c07SWyon Bi 1966f920c07SWyon Bi dp->link_train.lt_state = CLOCK_RECOVERY; 1976f920c07SWyon Bi dp->link_train.eq_loop = 0; 1986f920c07SWyon Bi 1996f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 2006f920c07SWyon Bi dp->link_train.cr_loop[lane] = 0; 2016f920c07SWyon Bi 2026f920c07SWyon Bi /* Set link rate and count as you want to establish */ 2036f920c07SWyon Bi analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); 2046f920c07SWyon Bi analogix_dp_set_lane_count(dp, dp->link_train.lane_count); 2056f920c07SWyon Bi 2067477c1efSDamon Ding if (dp->nr_link_rate_table) { 2077477c1efSDamon Ding /* Setup DP_LINK_RATE_SET for eDP 1.4 and later */ 2082fcb4783SDamon Ding drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, dp->link_train.lane_count); 2092fcb4783SDamon Ding drm_dp_dpcd_writeb(&dp->aux, DP_LINK_RATE_SET, dp->link_rate_select); 2107477c1efSDamon Ding } else { 2117477c1efSDamon Ding /* Setup DP_LINK_BW_SET for eDP 1.3 and earlier */ 2126f920c07SWyon Bi buf[0] = dp->link_train.link_rate; 2136f920c07SWyon Bi buf[1] = dp->link_train.lane_count; 2142fcb4783SDamon Ding retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2); 2152fcb4783SDamon Ding if (retval < 0) 2166f920c07SWyon Bi return retval; 2177477c1efSDamon Ding } 2186f920c07SWyon Bi 219699c29a5SWyon Bi /* Spread AMP if required, enable 8b/10b coding */ 220699c29a5SWyon Bi buf[0] = analogix_dp_ssc_supported(dp) ? DP_SPREAD_AMP_0_5 : 0; 221699c29a5SWyon Bi buf[1] = DP_SET_ANSI_8B10B; 2222fcb4783SDamon Ding retval = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, 2); 223699c29a5SWyon Bi if (retval < 0) 224699c29a5SWyon Bi return retval; 225699c29a5SWyon Bi 226fc275078SDamon Ding /* set ASSR if available */ 227fc275078SDamon Ding retval = analogix_dp_set_assr_mode(dp); 228fc275078SDamon Ding if (retval < 0) { 229fc275078SDamon Ding dev_err(dp->dev, "failed to set assr mode\n"); 230fc275078SDamon Ding return retval; 231fc275078SDamon Ding } 232fc275078SDamon Ding 233ea286ea2SDamon Ding /* set enhanced mode if available */ 234ea286ea2SDamon Ding retval = analogix_dp_set_enhanced_mode(dp); 235ea286ea2SDamon Ding if (retval < 0) { 236ea286ea2SDamon Ding dev_err(dp->dev, "failed to set enhance mode\n"); 237ea286ea2SDamon Ding return retval; 238ea286ea2SDamon Ding } 239ea286ea2SDamon Ding 240253c2dc8SWyon Bi /* Set TX voltage-swing and pre-emphasis to minimum */ 2416f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 242253c2dc8SWyon Bi dp->link_train.training_lane[lane] = 243253c2dc8SWyon Bi DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | 244253c2dc8SWyon Bi DP_TRAIN_PRE_EMPH_LEVEL_0; 245253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 2466f920c07SWyon Bi 2476f920c07SWyon Bi /* Set training pattern 1 */ 2486f920c07SWyon Bi analogix_dp_set_training_pattern(dp, TRAINING_PTN1); 2496f920c07SWyon Bi 2506f920c07SWyon Bi /* Set RX training pattern */ 2512fcb4783SDamon Ding retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 2526f920c07SWyon Bi DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); 2532fcb4783SDamon Ding if (retval < 0) 2546f920c07SWyon Bi return retval; 2556f920c07SWyon Bi 2566f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) 2576f920c07SWyon Bi buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | 2586f920c07SWyon Bi DP_TRAIN_VOLTAGE_SWING_LEVEL_0; 2596f920c07SWyon Bi 2602fcb4783SDamon Ding retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, 2612fcb4783SDamon Ding lane_count); 2622fcb4783SDamon Ding if (retval < 0) 2636f920c07SWyon Bi return retval; 2642fcb4783SDamon Ding 2652fcb4783SDamon Ding return 0; 2666f920c07SWyon Bi } 2676f920c07SWyon Bi 2686f920c07SWyon Bi static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) 2696f920c07SWyon Bi { 2706f920c07SWyon Bi int shift = (lane & 1) * 4; 2716f920c07SWyon Bi u8 link_value = link_status[lane >> 1]; 2726f920c07SWyon Bi 2736f920c07SWyon Bi return (link_value >> shift) & 0xf; 2746f920c07SWyon Bi } 2756f920c07SWyon Bi 2766f920c07SWyon Bi static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count) 2776f920c07SWyon Bi { 2786f920c07SWyon Bi int lane; 2796f920c07SWyon Bi u8 lane_status; 2806f920c07SWyon Bi 2816f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2826f920c07SWyon Bi lane_status = analogix_dp_get_lane_status(link_status, lane); 2836f920c07SWyon Bi if ((lane_status & DP_LANE_CR_DONE) == 0) 2846f920c07SWyon Bi return -EINVAL; 2856f920c07SWyon Bi } 2866f920c07SWyon Bi return 0; 2876f920c07SWyon Bi } 2886f920c07SWyon Bi 2896f920c07SWyon Bi static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align, 2906f920c07SWyon Bi int lane_count) 2916f920c07SWyon Bi { 2926f920c07SWyon Bi int lane; 2936f920c07SWyon Bi u8 lane_status; 2946f920c07SWyon Bi 2956f920c07SWyon Bi if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0) 2966f920c07SWyon Bi return -EINVAL; 2976f920c07SWyon Bi 2986f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 2996f920c07SWyon Bi lane_status = analogix_dp_get_lane_status(link_status, lane); 3006f920c07SWyon Bi lane_status &= DP_CHANNEL_EQ_BITS; 3016f920c07SWyon Bi if (lane_status != DP_CHANNEL_EQ_BITS) 3026f920c07SWyon Bi return -EINVAL; 3036f920c07SWyon Bi } 3046f920c07SWyon Bi 3056f920c07SWyon Bi return 0; 3066f920c07SWyon Bi } 3076f920c07SWyon Bi 3086f920c07SWyon Bi static unsigned char 3096f920c07SWyon Bi analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane) 3106f920c07SWyon Bi { 3116f920c07SWyon Bi int shift = (lane & 1) * 4; 3126f920c07SWyon Bi u8 link_value = adjust_request[lane >> 1]; 3136f920c07SWyon Bi 3146f920c07SWyon Bi return (link_value >> shift) & 0x3; 3156f920c07SWyon Bi } 3166f920c07SWyon Bi 3176f920c07SWyon Bi static unsigned char analogix_dp_get_adjust_request_pre_emphasis( 3186f920c07SWyon Bi u8 adjust_request[2], 3196f920c07SWyon Bi int lane) 3206f920c07SWyon Bi { 3216f920c07SWyon Bi int shift = (lane & 1) * 4; 3226f920c07SWyon Bi u8 link_value = adjust_request[lane >> 1]; 3236f920c07SWyon Bi 3246f920c07SWyon Bi return ((link_value >> shift) & 0xc) >> 2; 3256f920c07SWyon Bi } 3266f920c07SWyon Bi 3276f920c07SWyon Bi static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) 3286f920c07SWyon Bi { 3296f920c07SWyon Bi analogix_dp_training_pattern_dis(dp); 3306f920c07SWyon Bi analogix_dp_set_enhanced_mode(dp); 3316f920c07SWyon Bi 3326f920c07SWyon Bi dp->link_train.lt_state = FAILED; 3336f920c07SWyon Bi } 3346f920c07SWyon Bi 3356f920c07SWyon Bi static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp, 3366f920c07SWyon Bi u8 adjust_request[2]) 3376f920c07SWyon Bi { 3386f920c07SWyon Bi int lane, lane_count; 3396f920c07SWyon Bi u8 voltage_swing, pre_emphasis, training_lane; 3406f920c07SWyon Bi 3416f920c07SWyon Bi lane_count = dp->link_train.lane_count; 3426f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 3436f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 3446f920c07SWyon Bi adjust_request, lane); 3456f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 3466f920c07SWyon Bi adjust_request, lane); 3476f920c07SWyon Bi training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | 3486f920c07SWyon Bi DPCD_PRE_EMPHASIS_SET(pre_emphasis); 3496f920c07SWyon Bi 3506f920c07SWyon Bi if (voltage_swing == VOLTAGE_LEVEL_3) 3516f920c07SWyon Bi training_lane |= DP_TRAIN_MAX_SWING_REACHED; 3526f920c07SWyon Bi if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) 3536f920c07SWyon Bi training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; 3546f920c07SWyon Bi 3556f920c07SWyon Bi dp->link_train.training_lane[lane] = training_lane; 3566f920c07SWyon Bi } 3576f920c07SWyon Bi } 3586f920c07SWyon Bi 3597adc0066SWyon Bi static bool analogix_dp_tps3_supported(struct analogix_dp_device *dp) 3607adc0066SWyon Bi { 3617adc0066SWyon Bi bool source_tps3_supported, sink_tps3_supported; 3627adc0066SWyon Bi u8 dpcd = 0; 3637adc0066SWyon Bi 3647adc0066SWyon Bi source_tps3_supported = 3657adc0066SWyon Bi dp->video_info.max_link_rate == DP_LINK_BW_5_4; 3662fcb4783SDamon Ding drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &dpcd); 3677adc0066SWyon Bi sink_tps3_supported = dpcd & DP_TPS3_SUPPORTED; 3687adc0066SWyon Bi 3697adc0066SWyon Bi return source_tps3_supported && sink_tps3_supported; 3707adc0066SWyon Bi } 3717adc0066SWyon Bi 3726f920c07SWyon Bi static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) 3736f920c07SWyon Bi { 3746f920c07SWyon Bi int lane, lane_count, retval; 3756f920c07SWyon Bi u8 voltage_swing, pre_emphasis, training_lane; 3766f920c07SWyon Bi u8 link_status[2], adjust_request[2]; 3777adc0066SWyon Bi u8 training_pattern = TRAINING_PTN2; 3786f920c07SWyon Bi 3791a00cf6eSWyon Bi drm_dp_link_train_clock_recovery_delay(dp->dpcd); 3806f920c07SWyon Bi 3816f920c07SWyon Bi lane_count = dp->link_train.lane_count; 3826f920c07SWyon Bi 3832fcb4783SDamon Ding retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); 3842fcb4783SDamon Ding if (retval < 0) 3856f920c07SWyon Bi return retval; 3866f920c07SWyon Bi 3876f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { 3887adc0066SWyon Bi if (analogix_dp_tps3_supported(dp)) 3897adc0066SWyon Bi training_pattern = TRAINING_PTN3; 3907adc0066SWyon Bi 3917adc0066SWyon Bi /* set training pattern for EQ */ 3927adc0066SWyon Bi analogix_dp_set_training_pattern(dp, training_pattern); 3936f920c07SWyon Bi 3942fcb4783SDamon Ding retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 3952fcb4783SDamon Ding DP_LINK_SCRAMBLING_DISABLE | 3967adc0066SWyon Bi (training_pattern == TRAINING_PTN3 ? 3977adc0066SWyon Bi DP_TRAINING_PATTERN_3 : DP_TRAINING_PATTERN_2)); 3982fcb4783SDamon Ding if (retval < 0) 3996f920c07SWyon Bi return retval; 4006f920c07SWyon Bi 4016f920c07SWyon Bi dev_info(dp->dev, "Link Training Clock Recovery success\n"); 4026f920c07SWyon Bi dp->link_train.lt_state = EQUALIZER_TRAINING; 40310d706d5SWyon Bi 40410d706d5SWyon Bi return 0; 4056f920c07SWyon Bi } else { 4062fcb4783SDamon Ding retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, 4072fcb4783SDamon Ding adjust_request, 2); 4082fcb4783SDamon Ding if (retval < 0) 40910d706d5SWyon Bi return retval; 41010d706d5SWyon Bi 4116f920c07SWyon Bi for (lane = 0; lane < lane_count; lane++) { 4126f920c07SWyon Bi training_lane = analogix_dp_get_lane_link_training( 4136f920c07SWyon Bi dp, lane); 4146f920c07SWyon Bi voltage_swing = analogix_dp_get_adjust_request_voltage( 4156f920c07SWyon Bi adjust_request, lane); 4166f920c07SWyon Bi pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( 4176f920c07SWyon Bi adjust_request, lane); 4186f920c07SWyon Bi 4196f920c07SWyon Bi if (DPCD_VOLTAGE_SWING_GET(training_lane) == 4206f920c07SWyon Bi voltage_swing && 4216f920c07SWyon Bi DPCD_PRE_EMPHASIS_GET(training_lane) == 4226f920c07SWyon Bi pre_emphasis) 4236f920c07SWyon Bi dp->link_train.cr_loop[lane]++; 4246f920c07SWyon Bi 4251ee9f77bSGuochun Huang /* 4261ee9f77bSGuochun Huang * In DP spec 1.3, Condition of CR fail are 4271ee9f77bSGuochun Huang * outlined in section 3.5.1.2.2.1, figure 3-20: 4281ee9f77bSGuochun Huang * 4291ee9f77bSGuochun Huang * 1. Maximum Voltage Swing reached 4301ee9f77bSGuochun Huang * 2. Same Voltage five times 4311ee9f77bSGuochun Huang */ 4326f920c07SWyon Bi if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || 4331ee9f77bSGuochun Huang DPCD_VOLTAGE_SWING_GET(training_lane) == VOLTAGE_LEVEL_3) { 4346f920c07SWyon Bi dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", 4356f920c07SWyon Bi dp->link_train.cr_loop[lane], 4366f920c07SWyon Bi voltage_swing, pre_emphasis); 4376f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 4386f920c07SWyon Bi return -EIO; 4396f920c07SWyon Bi } 4406f920c07SWyon Bi } 4416f920c07SWyon Bi } 4426f920c07SWyon Bi 4436f920c07SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 444253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 4456f920c07SWyon Bi 4462fcb4783SDamon Ding retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, 4472fcb4783SDamon Ding dp->link_train.training_lane, lane_count); 4482fcb4783SDamon Ding if (retval < 0) 4496f920c07SWyon Bi return retval; 4506f920c07SWyon Bi 4512fcb4783SDamon Ding return 0; 4526f920c07SWyon Bi } 4536f920c07SWyon Bi 4546f920c07SWyon Bi static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) 4556f920c07SWyon Bi { 456253c2dc8SWyon Bi int lane_count, retval; 4576f920c07SWyon Bi u32 reg; 4586f920c07SWyon Bi u8 link_align, link_status[2], adjust_request[2]; 4596f920c07SWyon Bi 4601a00cf6eSWyon Bi drm_dp_link_train_channel_eq_delay(dp->dpcd); 4616f920c07SWyon Bi 4626f920c07SWyon Bi lane_count = dp->link_train.lane_count; 4636f920c07SWyon Bi 4642fcb4783SDamon Ding retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); 4652fcb4783SDamon Ding if (retval < 0) 4666f920c07SWyon Bi return retval; 4676f920c07SWyon Bi 4686f920c07SWyon Bi if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { 4696f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 4706f920c07SWyon Bi return -EIO; 4716f920c07SWyon Bi } 4726f920c07SWyon Bi 4732fcb4783SDamon Ding retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, &link_align); 4742fcb4783SDamon Ding if (retval < 0) 4756f920c07SWyon Bi return retval; 4766f920c07SWyon Bi 4776f920c07SWyon Bi if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { 4786f920c07SWyon Bi /* traing pattern Set to Normal */ 4792fcb4783SDamon Ding retval = analogix_dp_training_pattern_dis(dp); 4802fcb4783SDamon Ding if (retval < 0) 4812fcb4783SDamon Ding return retval; 4826f920c07SWyon Bi 4836f920c07SWyon Bi printf("Link Training success!\n"); 4846f920c07SWyon Bi 4856f920c07SWyon Bi analogix_dp_get_link_bandwidth(dp, ®); 4866f920c07SWyon Bi dp->link_train.link_rate = reg; 4876f920c07SWyon Bi analogix_dp_get_lane_count(dp, ®); 4886f920c07SWyon Bi dp->link_train.lane_count = reg; 4896f920c07SWyon Bi 4906f920c07SWyon Bi printf("final link rate = 0x%.2x, lane count = 0x%.2x\n", 4916f920c07SWyon Bi dp->link_train.link_rate, dp->link_train.lane_count); 4926f920c07SWyon Bi 4936f920c07SWyon Bi dp->link_train.lt_state = FINISHED; 4946f920c07SWyon Bi 4956f920c07SWyon Bi return 0; 4966f920c07SWyon Bi } 4976f920c07SWyon Bi 4986f920c07SWyon Bi /* not all locked */ 4996f920c07SWyon Bi dp->link_train.eq_loop++; 5006f920c07SWyon Bi 5016f920c07SWyon Bi if (dp->link_train.eq_loop > MAX_EQ_LOOP) { 5026f920c07SWyon Bi dev_dbg(dp->dev, "EQ Max loop\n"); 5036f920c07SWyon Bi analogix_dp_reduce_link_rate(dp); 5046f920c07SWyon Bi return -EIO; 5056f920c07SWyon Bi } 5066f920c07SWyon Bi 5072fcb4783SDamon Ding retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, adjust_request, 2); 5082fcb4783SDamon Ding if (retval < 0) 50910d706d5SWyon Bi return retval; 51010d706d5SWyon Bi 51110d706d5SWyon Bi analogix_dp_get_adjust_training_lane(dp, adjust_request); 512253c2dc8SWyon Bi analogix_dp_set_lane_link_training(dp); 5136f920c07SWyon Bi 5142fcb4783SDamon Ding retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, 5152fcb4783SDamon Ding dp->link_train.training_lane, lane_count); 5162fcb4783SDamon Ding if (retval < 0) 5176f920c07SWyon Bi return retval; 5182fcb4783SDamon Ding 5192fcb4783SDamon Ding return 0; 5206f920c07SWyon Bi } 5216f920c07SWyon Bi 5227477c1efSDamon Ding static bool analogix_dp_bandwidth_ok(struct analogix_dp_device *dp, 523d67c1260SDamon Ding const struct drm_display_mode *mode, u32 bpp, 5247477c1efSDamon Ding unsigned int rate, unsigned int lanes) 5257477c1efSDamon Ding { 5267477c1efSDamon Ding u32 max_bw, req_bw; 5277477c1efSDamon Ding 5287477c1efSDamon Ding req_bw = mode->clock * bpp / 8; 5297477c1efSDamon Ding max_bw = lanes * rate; 5307477c1efSDamon Ding if (req_bw > max_bw) 5317477c1efSDamon Ding return false; 5327477c1efSDamon Ding 5337477c1efSDamon Ding return true; 5347477c1efSDamon Ding } 5357477c1efSDamon Ding 5367477c1efSDamon Ding static bool analogix_dp_link_config_validate(u8 link_rate, u8 lane_count) 5377477c1efSDamon Ding { 5387477c1efSDamon Ding switch (link_rate) { 5397477c1efSDamon Ding case DP_LINK_BW_1_62: 5407477c1efSDamon Ding case DP_LINK_BW_2_7: 5417477c1efSDamon Ding case DP_LINK_BW_5_4: 542ead74bb6SDamon Ding /* Supported link rate in eDP 1.4 */ 543ead74bb6SDamon Ding case EDP_LINK_BW_2_16: 544ead74bb6SDamon Ding case EDP_LINK_BW_2_43: 545ead74bb6SDamon Ding case EDP_LINK_BW_3_24: 546ead74bb6SDamon Ding case EDP_LINK_BW_4_32: 5477477c1efSDamon Ding break; 5487477c1efSDamon Ding default: 5497477c1efSDamon Ding return false; 5507477c1efSDamon Ding } 5517477c1efSDamon Ding 5527477c1efSDamon Ding switch (lane_count) { 5537477c1efSDamon Ding case LANE_COUNT1: 5547477c1efSDamon Ding case LANE_COUNT2: 5557477c1efSDamon Ding case LANE_COUNT4: 5567477c1efSDamon Ding break; 5577477c1efSDamon Ding default: 5587477c1efSDamon Ding return false; 5597477c1efSDamon Ding } 5607477c1efSDamon Ding 5617477c1efSDamon Ding return true; 5627477c1efSDamon Ding } 5637477c1efSDamon Ding 5647477c1efSDamon Ding static int analogix_dp_select_link_rate_from_table(struct analogix_dp_device *dp) 5657477c1efSDamon Ding { 5667477c1efSDamon Ding int i; 5677477c1efSDamon Ding u8 bw_code; 5687477c1efSDamon Ding u32 max_link_rate = drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate); 5697477c1efSDamon Ding 5707477c1efSDamon Ding for (i = 0; i < dp->nr_link_rate_table; i++) { 5717477c1efSDamon Ding bw_code = drm_dp_link_rate_to_bw_code(dp->link_rate_table[i]); 5727477c1efSDamon Ding 573d67c1260SDamon Ding if (!analogix_dp_bandwidth_ok(dp, &dp->video_info.mode, 574d67c1260SDamon Ding analogix_dp_get_output_bpp(dp->output_fmt), 575d67c1260SDamon Ding dp->link_rate_table[i], dp->link_train.lane_count)) 5767477c1efSDamon Ding continue; 5777477c1efSDamon Ding 5787477c1efSDamon Ding if (dp->link_rate_table[i] <= max_link_rate && 5797477c1efSDamon Ding analogix_dp_link_config_validate(bw_code, dp->link_train.lane_count)) { 5807477c1efSDamon Ding dp->link_rate_select = i; 5817477c1efSDamon Ding return bw_code; 5827477c1efSDamon Ding } 5837477c1efSDamon Ding } 5847477c1efSDamon Ding 5857477c1efSDamon Ding return 0; 5867477c1efSDamon Ding } 5877477c1efSDamon Ding 5887477c1efSDamon Ding static int analogix_dp_select_rx_bandwidth(struct analogix_dp_device *dp) 5897477c1efSDamon Ding { 5907477c1efSDamon Ding if (dp->nr_link_rate_table) 5917477c1efSDamon Ding /* 5927477c1efSDamon Ding * Select the smallest one among link rates which meet 5937477c1efSDamon Ding * the bandwidth requirement for eDP 1.4 and later. 5947477c1efSDamon Ding */ 5957477c1efSDamon Ding dp->link_train.link_rate = analogix_dp_select_link_rate_from_table(dp); 5967477c1efSDamon Ding else 5977477c1efSDamon Ding /* 5987477c1efSDamon Ding * Select the smaller one between rx DP_MAX_LINK_RATE 5997477c1efSDamon Ding * and the max link rate supported by the platform. 6007477c1efSDamon Ding */ 6017477c1efSDamon Ding dp->link_train.link_rate = min_t(u32, dp->link_train.link_rate, 6027477c1efSDamon Ding dp->video_info.max_link_rate); 6037477c1efSDamon Ding if (!dp->link_train.link_rate) 6047477c1efSDamon Ding return -EINVAL; 6057477c1efSDamon Ding 6067477c1efSDamon Ding return 0; 6077477c1efSDamon Ding } 6087477c1efSDamon Ding 6097477c1efSDamon Ding static int analogix_dp_init_link_rate_table(struct analogix_dp_device *dp) 6107477c1efSDamon Ding { 6117477c1efSDamon Ding u8 link_rate_table[DP_MAX_SUPPORTED_RATES * 2]; 6127477c1efSDamon Ding int i; 6137477c1efSDamon Ding int ret; 6147477c1efSDamon Ding 6152fcb4783SDamon Ding ret = drm_dp_dpcd_read(&dp->aux, DP_SUPPORTED_LINK_RATES, link_rate_table, 6162fcb4783SDamon Ding sizeof(link_rate_table)); 6172fcb4783SDamon Ding if (ret < 0) 6187477c1efSDamon Ding return ret; 6197477c1efSDamon Ding 6207477c1efSDamon Ding for (i = 0; i < ARRAY_SIZE(link_rate_table) / 2; i++) { 6217477c1efSDamon Ding int val = link_rate_table[2 * i] | link_rate_table[2 * i + 1] << 8; 6227477c1efSDamon Ding 6237477c1efSDamon Ding if (val == 0) 6247477c1efSDamon Ding break; 6257477c1efSDamon Ding 6267477c1efSDamon Ding /* Convert to the link_rate as drm_dp_bw_code_to_link_rate() */ 6277477c1efSDamon Ding dp->link_rate_table[i] = (val * 20); 6287477c1efSDamon Ding } 6297477c1efSDamon Ding dp->nr_link_rate_table = i; 6307477c1efSDamon Ding 6317477c1efSDamon Ding return 0; 6327477c1efSDamon Ding } 6337477c1efSDamon Ding 6342fcb4783SDamon Ding static int analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, 6356f920c07SWyon Bi u8 *bandwidth) 6366f920c07SWyon Bi { 6376f920c07SWyon Bi u8 data; 6387477c1efSDamon Ding int ret; 6396f920c07SWyon Bi 6402fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_DPCD_REV, &data); 6412fcb4783SDamon Ding if (ret == 1 && data >= DP_EDP_14) { 6427477c1efSDamon Ding u32 max_link_rate; 6437477c1efSDamon Ding 6447477c1efSDamon Ding /* As the Table 4-23 in eDP 1.4 spec, the link rate table is required */ 6457477c1efSDamon Ding if (!dp->nr_link_rate_table) { 6462fcb4783SDamon Ding dev_info(dp->dev, "eDP version: 0x%02x supports link rate table\n", 6472fcb4783SDamon Ding data); 6487477c1efSDamon Ding 6497477c1efSDamon Ding if (analogix_dp_init_link_rate_table(dp)) 6502fcb4783SDamon Ding dev_err(dp->dev, "failed to read link rate table: %d\n", 6512fcb4783SDamon Ding ret); 6527477c1efSDamon Ding } 6537477c1efSDamon Ding max_link_rate = dp->link_rate_table[dp->nr_link_rate_table - 1]; 6547477c1efSDamon Ding *bandwidth = drm_dp_link_rate_to_bw_code(max_link_rate); 6557477c1efSDamon Ding } else { 6566f920c07SWyon Bi /* 6576f920c07SWyon Bi * For DP rev.1.1, Maximum link rate of Main Link lanes 6586f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps 6596f920c07SWyon Bi * For DP rev.1.2, Maximum link rate of Main Link lanes 6606f920c07SWyon Bi * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps 6616f920c07SWyon Bi */ 6622fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data); 6632fcb4783SDamon Ding if (ret < 0) 6642fcb4783SDamon Ding return ret; 6652fcb4783SDamon Ding 6666f920c07SWyon Bi *bandwidth = data; 6676f920c07SWyon Bi } 6682fcb4783SDamon Ding 6692fcb4783SDamon Ding return 0; 6707477c1efSDamon Ding } 6716f920c07SWyon Bi 6722fcb4783SDamon Ding static int analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, 6736f920c07SWyon Bi u8 *lane_count) 6746f920c07SWyon Bi { 6756f920c07SWyon Bi u8 data; 6762fcb4783SDamon Ding int ret; 6776f920c07SWyon Bi 6786f920c07SWyon Bi /* 6796f920c07SWyon Bi * For DP rev.1.1, Maximum number of Main Link lanes 6806f920c07SWyon Bi * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes 6816f920c07SWyon Bi */ 6822fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); 6832fcb4783SDamon Ding if (ret < 0) 6842fcb4783SDamon Ding return ret; 6852fcb4783SDamon Ding 6866f920c07SWyon Bi *lane_count = DPCD_MAX_LANE_COUNT(data); 6872fcb4783SDamon Ding 6882fcb4783SDamon Ding return 0; 6896f920c07SWyon Bi } 6906f920c07SWyon Bi 6916f920c07SWyon Bi static int analogix_dp_init_training(struct analogix_dp_device *dp, 6926f920c07SWyon Bi enum link_lane_count_type max_lane, 6936f920c07SWyon Bi int max_rate) 6946f920c07SWyon Bi { 695699c29a5SWyon Bi u8 dpcd; 696699c29a5SWyon Bi 6976f920c07SWyon Bi /* 6986f920c07SWyon Bi * MACRO_RST must be applied after the PLL_LOCK to avoid 6996f920c07SWyon Bi * the DP inter pair skew issue for at least 10 us 7006f920c07SWyon Bi */ 7016f920c07SWyon Bi analogix_dp_reset_macro(dp); 7026f920c07SWyon Bi 7037477c1efSDamon Ding /* Setup TX lane count */ 7047477c1efSDamon Ding dp->link_train.lane_count = min_t(u32, dp->link_train.lane_count, max_lane); 7057477c1efSDamon Ding 7067477c1efSDamon Ding /* Setup TX lane rate */ 7077477c1efSDamon Ding if (analogix_dp_select_rx_bandwidth(dp)) { 7087477c1efSDamon Ding dev_err(dp->dev, "Select rx bandwidth failed\n"); 7097477c1efSDamon Ding return -EINVAL; 7107477c1efSDamon Ding } 7116f920c07SWyon Bi 7122fcb4783SDamon Ding drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &dpcd); 713699c29a5SWyon Bi dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); 714699c29a5SWyon Bi 7156f920c07SWyon Bi /* All DP analog module power up */ 7166f920c07SWyon Bi analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); 7176f920c07SWyon Bi 7186f920c07SWyon Bi return 0; 7196f920c07SWyon Bi } 7206f920c07SWyon Bi 7216f920c07SWyon Bi static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) 7226f920c07SWyon Bi { 7236f920c07SWyon Bi int retval = 0, training_finished = 0; 7246f920c07SWyon Bi 7256f920c07SWyon Bi dp->link_train.lt_state = START; 7266f920c07SWyon Bi 7276f920c07SWyon Bi /* Process here */ 7286f920c07SWyon Bi while (!retval && !training_finished) { 7296f920c07SWyon Bi switch (dp->link_train.lt_state) { 7306f920c07SWyon Bi case START: 7316f920c07SWyon Bi retval = analogix_dp_link_start(dp); 7326f920c07SWyon Bi if (retval) 7336f920c07SWyon Bi dev_err(dp->dev, "LT link start failed!\n"); 7346f920c07SWyon Bi break; 7356f920c07SWyon Bi case CLOCK_RECOVERY: 7366f920c07SWyon Bi retval = analogix_dp_process_clock_recovery(dp); 7376f920c07SWyon Bi if (retval) 7386f920c07SWyon Bi dev_err(dp->dev, "LT CR failed!\n"); 7396f920c07SWyon Bi break; 7406f920c07SWyon Bi case EQUALIZER_TRAINING: 7416f920c07SWyon Bi retval = analogix_dp_process_equalizer_training(dp); 7426f920c07SWyon Bi if (retval) 7436f920c07SWyon Bi dev_err(dp->dev, "LT EQ failed!\n"); 7446f920c07SWyon Bi break; 7456f920c07SWyon Bi case FINISHED: 7466f920c07SWyon Bi training_finished = 1; 7476f920c07SWyon Bi break; 7486f920c07SWyon Bi case FAILED: 7496f920c07SWyon Bi return -EREMOTEIO; 7506f920c07SWyon Bi } 7516f920c07SWyon Bi } 7526f920c07SWyon Bi 7536f920c07SWyon Bi return retval; 7546f920c07SWyon Bi } 7556f920c07SWyon Bi 7566f920c07SWyon Bi static int analogix_dp_set_link_train(struct analogix_dp_device *dp, 7576f920c07SWyon Bi u32 count, u32 bwtype) 7586f920c07SWyon Bi { 75921069358SWyon Bi int i, ret; 7606f920c07SWyon Bi 76121069358SWyon Bi for (i = 0; i < 5; i++) { 7626f920c07SWyon Bi ret = analogix_dp_init_training(dp, count, bwtype); 7636f920c07SWyon Bi if (ret < 0) { 7646f920c07SWyon Bi dev_err(dp->dev, "failed to init training\n"); 7656f920c07SWyon Bi return ret; 7666f920c07SWyon Bi } 7676f920c07SWyon Bi 7686f920c07SWyon Bi ret = analogix_dp_sw_link_training(dp); 76921069358SWyon Bi if (!ret) 77021069358SWyon Bi break; 7716f920c07SWyon Bi } 7726f920c07SWyon Bi 77321069358SWyon Bi return ret; 7746f920c07SWyon Bi } 7756f920c07SWyon Bi 7766f920c07SWyon Bi static int analogix_dp_config_video(struct analogix_dp_device *dp) 7776f920c07SWyon Bi { 7786f920c07SWyon Bi int timeout_loop = 0; 7796f920c07SWyon Bi int done_count = 0; 7806f920c07SWyon Bi 7816f920c07SWyon Bi analogix_dp_config_video_slave_mode(dp); 7826f920c07SWyon Bi 7836f920c07SWyon Bi analogix_dp_set_video_color_format(dp); 7846f920c07SWyon Bi 7856f920c07SWyon Bi if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { 7866f920c07SWyon Bi dev_err(dp->dev, "PLL is not locked yet.\n"); 7876f920c07SWyon Bi return -EINVAL; 7886f920c07SWyon Bi } 7896f920c07SWyon Bi 7906f920c07SWyon Bi for (;;) { 7916f920c07SWyon Bi timeout_loop++; 7926f920c07SWyon Bi if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0) 7936f920c07SWyon Bi break; 7946f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 7956f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 7966f920c07SWyon Bi return -ETIMEDOUT; 7976f920c07SWyon Bi } 7986f920c07SWyon Bi 7996f920c07SWyon Bi udelay(2); 8006f920c07SWyon Bi } 8016f920c07SWyon Bi 8026f920c07SWyon Bi /* Set to use the register calculated M/N video */ 8036f920c07SWyon Bi analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); 8046f920c07SWyon Bi 8056f920c07SWyon Bi /* For video bist, Video timing must be generated by register */ 806e9cac7f1SWyon Bi analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_REGISTER); 8076f920c07SWyon Bi 8086f920c07SWyon Bi /* Disable video mute */ 8096f920c07SWyon Bi analogix_dp_enable_video_mute(dp, 0); 8106f920c07SWyon Bi 8116f920c07SWyon Bi /* Configure video slave mode */ 8126f920c07SWyon Bi analogix_dp_enable_video_master(dp, 0); 8136f920c07SWyon Bi 8146f920c07SWyon Bi /* Enable video input */ 8156f920c07SWyon Bi analogix_dp_start_video(dp); 8166f920c07SWyon Bi 8176f920c07SWyon Bi timeout_loop = 0; 8186f920c07SWyon Bi 8196f920c07SWyon Bi for (;;) { 8206f920c07SWyon Bi timeout_loop++; 8216f920c07SWyon Bi if (analogix_dp_is_video_stream_on(dp) == 0) { 8226f920c07SWyon Bi done_count++; 8236f920c07SWyon Bi if (done_count > 10) 8246f920c07SWyon Bi break; 8256f920c07SWyon Bi } else if (done_count) { 8266f920c07SWyon Bi done_count = 0; 8276f920c07SWyon Bi } 8286f920c07SWyon Bi if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { 8296f920c07SWyon Bi dev_err(dp->dev, "Timeout of video streamclk ok\n"); 8306f920c07SWyon Bi return -ETIMEDOUT; 8316f920c07SWyon Bi } 8326f920c07SWyon Bi 8336f920c07SWyon Bi udelay(1001); 8346f920c07SWyon Bi } 8356f920c07SWyon Bi 8366f920c07SWyon Bi return 0; 8376f920c07SWyon Bi } 8386f920c07SWyon Bi 8392fcb4783SDamon Ding static int analogix_dp_enable_scramble(struct analogix_dp_device *dp, 8406f920c07SWyon Bi bool enable) 8416f920c07SWyon Bi { 8426f920c07SWyon Bi u8 data; 8432fcb4783SDamon Ding int ret; 8446f920c07SWyon Bi 8456f920c07SWyon Bi if (enable) { 8466f920c07SWyon Bi analogix_dp_enable_scrambling(dp); 8476f920c07SWyon Bi 8482fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, 8496f920c07SWyon Bi &data); 8502fcb4783SDamon Ding if (ret != 1) 8512fcb4783SDamon Ding return ret; 8522fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 8536f920c07SWyon Bi (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); 8546f920c07SWyon Bi } else { 8556f920c07SWyon Bi analogix_dp_disable_scrambling(dp); 8566f920c07SWyon Bi 8572fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, 8586f920c07SWyon Bi &data); 8592fcb4783SDamon Ding if (ret != 1) 8602fcb4783SDamon Ding return ret; 8612fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 8626f920c07SWyon Bi (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); 8636f920c07SWyon Bi } 8642fcb4783SDamon Ding return ret < 0 ? ret : 0; 8656f920c07SWyon Bi } 8666f920c07SWyon Bi 8676f920c07SWyon Bi static void analogix_dp_init_dp(struct analogix_dp_device *dp) 8686f920c07SWyon Bi { 8696f920c07SWyon Bi analogix_dp_reset(dp); 8706f920c07SWyon Bi 8716f920c07SWyon Bi analogix_dp_swreset(dp); 8726f920c07SWyon Bi 8736f920c07SWyon Bi analogix_dp_init_analog_param(dp); 8746f920c07SWyon Bi analogix_dp_init_interrupt(dp); 8756f920c07SWyon Bi 8766f920c07SWyon Bi /* SW defined function Normal operation */ 8776f920c07SWyon Bi analogix_dp_enable_sw_function(dp); 8786f920c07SWyon Bi 8796f920c07SWyon Bi analogix_dp_config_interrupt(dp); 8806f920c07SWyon Bi analogix_dp_init_analog_func(dp); 8816f920c07SWyon Bi 8826f920c07SWyon Bi analogix_dp_init_hpd(dp); 8836f920c07SWyon Bi analogix_dp_init_aux(dp); 8846f920c07SWyon Bi } 8856f920c07SWyon Bi 8860594ce39SZhang Yubing static int analogix_dp_connector_init(struct rockchip_connector *conn, struct display_state *state) 88758c17f51SSandy Huang { 88858c17f51SSandy Huang struct connector_state *conn_state = &state->conn_state; 8890594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 8906c0d4eb6SDamon Ding int submode = PHY_SUBMODE_EDP; 8916c0d4eb6SDamon Ding 8926c0d4eb6SDamon Ding if (!conn->panel) 8936c0d4eb6SDamon Ding dp->dp_mode = true; 8946f920c07SWyon Bi 895e29a4df2SDamon Ding if (dev_read_bool(conn->dev, "dp-mode")) 896e29a4df2SDamon Ding dp->dp_mode = true; 89794834379SDamon Ding else if (dev_read_bool(conn->dev, "edp-mode")) 89894834379SDamon Ding dp->dp_mode = false; 899e29a4df2SDamon Ding 9007adc0066SWyon Bi conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_eDP1 : VOP_OUTPUT_IF_eDP0; 9016f920c07SWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 902df0a5c43SDamon Ding conn_state->color_encoding = DRM_COLOR_YCBCR_BT709; 903df0a5c43SDamon Ding conn_state->color_range = DRM_COLOR_YCBCR_FULL_RANGE; 9046f920c07SWyon Bi 905699c29a5SWyon Bi reset_assert_bulk(&dp->resets); 906dddde95bSWyon Bi udelay(1); 907699c29a5SWyon Bi reset_deassert_bulk(&dp->resets); 908dddde95bSWyon Bi 909cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, dp->id); 9106c0d4eb6SDamon Ding if (dp->plat_data.support_dp_mode && dp->dp_mode) 9116c0d4eb6SDamon Ding submode = PHY_SUBMODE_DP; 9126c0d4eb6SDamon Ding generic_phy_set_mode_ext(&dp->phy, PHY_MODE_DP, submode); 913699c29a5SWyon Bi generic_phy_power_on(&dp->phy); 9146f920c07SWyon Bi analogix_dp_init_dp(dp); 9156f920c07SWyon Bi 9166f920c07SWyon Bi return 0; 9176f920c07SWyon Bi } 9186f920c07SWyon Bi 9190594ce39SZhang Yubing static int analogix_dp_connector_get_edid(struct rockchip_connector *conn, 9200594ce39SZhang Yubing struct display_state *state) 9216f920c07SWyon Bi { 9226f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 9230594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 924*9c170041SAlgea Cao int ret = 0; 9256f920c07SWyon Bi 926*9c170041SAlgea Cao conn_state->edid = drm_do_get_edid(&dp->aux.ddc); 927*9c170041SAlgea Cao if (!conn_state->edid) 928*9c170041SAlgea Cao ret = -EINVAL; 929eb6d4c72SDamon Ding 9306f920c07SWyon Bi return ret; 9316f920c07SWyon Bi } 9326f920c07SWyon Bi 933d3e70420SWyon Bi static int analogix_dp_link_power_up(struct analogix_dp_device *dp) 934d3e70420SWyon Bi { 935d3e70420SWyon Bi u8 value; 936d3e70420SWyon Bi int ret; 937d3e70420SWyon Bi 938d3e70420SWyon Bi if (dp->dpcd[DP_DPCD_REV] < 0x11) 939d3e70420SWyon Bi return 0; 940d3e70420SWyon Bi 9412fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); 942d3e70420SWyon Bi if (ret < 0) 943d3e70420SWyon Bi return ret; 944d3e70420SWyon Bi 945d3e70420SWyon Bi value &= ~DP_SET_POWER_MASK; 946d3e70420SWyon Bi value |= DP_SET_POWER_D0; 947d3e70420SWyon Bi 9482fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); 949d3e70420SWyon Bi if (ret < 0) 950d3e70420SWyon Bi return ret; 951d3e70420SWyon Bi 952d3e70420SWyon Bi mdelay(1); 953d3e70420SWyon Bi 954d3e70420SWyon Bi return 0; 955d3e70420SWyon Bi } 956d3e70420SWyon Bi 957d3e70420SWyon Bi static int analogix_dp_link_power_down(struct analogix_dp_device *dp) 958d3e70420SWyon Bi { 959d3e70420SWyon Bi u8 value; 960d3e70420SWyon Bi int ret; 961d3e70420SWyon Bi 962d3e70420SWyon Bi if (dp->dpcd[DP_DPCD_REV] < 0x11) 963d3e70420SWyon Bi return 0; 964d3e70420SWyon Bi 9652fcb4783SDamon Ding ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); 966d3e70420SWyon Bi if (ret < 0) 967d3e70420SWyon Bi return ret; 968d3e70420SWyon Bi 969d3e70420SWyon Bi value &= ~DP_SET_POWER_MASK; 970d3e70420SWyon Bi value |= DP_SET_POWER_D3; 971d3e70420SWyon Bi 9722fcb4783SDamon Ding ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); 973d3e70420SWyon Bi if (ret < 0) 974d3e70420SWyon Bi return ret; 975d3e70420SWyon Bi 976d3e70420SWyon Bi return 0; 977d3e70420SWyon Bi } 978d3e70420SWyon Bi 979d67c1260SDamon Ding static u32 analogix_dp_get_output_format(struct analogix_dp_device *dp, u32 bus_format) 980d67c1260SDamon Ding { 981d67c1260SDamon Ding unsigned int i; 982d67c1260SDamon Ding 983d67c1260SDamon Ding for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { 984d67c1260SDamon Ding const struct analogix_dp_output_format *fmt = &possible_output_fmts[i]; 985d67c1260SDamon Ding 986d67c1260SDamon Ding if (fmt->bus_format == bus_format) 987d67c1260SDamon Ding break; 988d67c1260SDamon Ding } 989d67c1260SDamon Ding 990d67c1260SDamon Ding if (i == ARRAY_SIZE(possible_output_fmts)) 991d67c1260SDamon Ding return 1; 992d67c1260SDamon Ding 993d67c1260SDamon Ding return i; 994d67c1260SDamon Ding } 995d67c1260SDamon Ding 996d67c1260SDamon Ding static u32 analogix_dp_get_output_format_by_edid(struct analogix_dp_device *dp, 997d67c1260SDamon Ding struct hdmi_edid_data *edid_data) 998d67c1260SDamon Ding { 999d67c1260SDamon Ding unsigned int i; 1000d67c1260SDamon Ding 1001d67c1260SDamon Ding for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { 1002d67c1260SDamon Ding const struct analogix_dp_output_format *fmt = &possible_output_fmts[i]; 1003d67c1260SDamon Ding 1004d67c1260SDamon Ding if (fmt->bpc > edid_data->display_info.bpc || fmt->bpc > dp->plat_data.max_bpc) 1005d67c1260SDamon Ding continue; 1006d67c1260SDamon Ding 1007d67c1260SDamon Ding if (!(edid_data->display_info.color_formats & fmt->color_format)) 1008d67c1260SDamon Ding continue; 1009d67c1260SDamon Ding 1010d67c1260SDamon Ding if (!analogix_dp_bandwidth_ok(dp, edid_data->preferred_mode, 1011d67c1260SDamon Ding analogix_dp_get_output_bpp(fmt), 1012d67c1260SDamon Ding drm_dp_bw_code_to_link_rate(dp->link_train.link_rate), 1013d67c1260SDamon Ding dp->link_train.lane_count)) 1014d67c1260SDamon Ding continue; 1015d67c1260SDamon Ding 1016d67c1260SDamon Ding break; 1017d67c1260SDamon Ding } 1018d67c1260SDamon Ding 1019d67c1260SDamon Ding if (i == ARRAY_SIZE(possible_output_fmts)) 1020d67c1260SDamon Ding return 1; 1021d67c1260SDamon Ding 1022d67c1260SDamon Ding return i; 1023d67c1260SDamon Ding } 1024d67c1260SDamon Ding 10250594ce39SZhang Yubing static int analogix_dp_connector_enable(struct rockchip_connector *conn, 10260594ce39SZhang Yubing struct display_state *state) 10276f920c07SWyon Bi { 10286f920c07SWyon Bi struct connector_state *conn_state = &state->conn_state; 10296f920c07SWyon Bi struct crtc_state *crtc_state = &state->crtc_state; 10300594ce39SZhang Yubing const struct rockchip_dp_chip_data *pdata = 10310594ce39SZhang Yubing (const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev); 10320594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 10332a74799bSJianqun Xu struct video_info *video = &dp->video_info; 10346e378f44SDamon Ding struct drm_display_mode mode; 1035d67c1260SDamon Ding u32 fmt_id; 10366f920c07SWyon Bi u32 val; 10376f920c07SWyon Bi int ret; 10386f920c07SWyon Bi 10397477c1efSDamon Ding drm_mode_copy(&video->mode, &conn_state->mode); 10407477c1efSDamon Ding 1041699c29a5SWyon Bi if (pdata->lcdsel_grf_reg) { 10426f920c07SWyon Bi if (crtc_state->crtc_id) 10436f920c07SWyon Bi val = pdata->lcdsel_lit; 10446f920c07SWyon Bi else 10456f920c07SWyon Bi val = pdata->lcdsel_big; 10466f920c07SWyon Bi 10477adc0066SWyon Bi regmap_write(dp->grf, pdata->lcdsel_grf_reg, val); 10486f920c07SWyon Bi } 10496f920c07SWyon Bi 10507adc0066SWyon Bi if (pdata->chip_type == RK3588_EDP) 10517adc0066SWyon Bi regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0, 10527adc0066SWyon Bi EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 1)); 10537adc0066SWyon Bi 1054d67c1260SDamon Ding if (!dp->output_fmt) { 1055d67c1260SDamon Ding fmt_id = analogix_dp_get_output_format(dp, conn_state->bus_format); 1056d67c1260SDamon Ding dp->output_fmt = &possible_output_fmts[fmt_id]; 1057d67c1260SDamon Ding } 1058d67c1260SDamon Ding 1059d67c1260SDamon Ding switch (dp->output_fmt->bpc) { 10602a74799bSJianqun Xu case 12: 10612a74799bSJianqun Xu video->color_depth = COLOR_12; 10622a74799bSJianqun Xu break; 10632a74799bSJianqun Xu case 10: 10642a74799bSJianqun Xu video->color_depth = COLOR_10; 10652a74799bSJianqun Xu break; 10662a74799bSJianqun Xu case 6: 10672a74799bSJianqun Xu video->color_depth = COLOR_6; 10682a74799bSJianqun Xu break; 10692a74799bSJianqun Xu case 8: 10702a74799bSJianqun Xu default: 10712a74799bSJianqun Xu video->color_depth = COLOR_8; 10722a74799bSJianqun Xu break; 10732a74799bSJianqun Xu } 1074d67c1260SDamon Ding if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_YCRCB444) { 1075d67c1260SDamon Ding video->color_space = COLOR_YCBCR444; 1076d67c1260SDamon Ding video->ycbcr_coeff = COLOR_YCBCR709; 1077d67c1260SDamon Ding } else if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_YCRCB422) { 1078d67c1260SDamon Ding video->color_space = COLOR_YCBCR422; 1079d67c1260SDamon Ding video->ycbcr_coeff = COLOR_YCBCR709; 1080d67c1260SDamon Ding } else { 1081d67c1260SDamon Ding video->color_space = COLOR_RGB; 1082d67c1260SDamon Ding video->ycbcr_coeff = COLOR_YCBCR601; 1083d67c1260SDamon Ding } 10842a74799bSJianqun Xu 10852fcb4783SDamon Ding ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd, DP_RECEIVER_CAP_SIZE); 10862fcb4783SDamon Ding if (ret < 0) { 10871a00cf6eSWyon Bi dev_err(dp->dev, "failed to read dpcd caps: %d\n", ret); 10881a00cf6eSWyon Bi return ret; 10891a00cf6eSWyon Bi } 10901a00cf6eSWyon Bi 1091d3e70420SWyon Bi ret = analogix_dp_link_power_up(dp); 1092d3e70420SWyon Bi if (ret) { 1093d3e70420SWyon Bi dev_err(dp->dev, "failed to power up link: %d\n", ret); 1094d3e70420SWyon Bi return ret; 1095d3e70420SWyon Bi } 1096d3e70420SWyon Bi 10976f920c07SWyon Bi ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, 10986f920c07SWyon Bi dp->video_info.max_link_rate); 10996f920c07SWyon Bi if (ret) { 11006f920c07SWyon Bi dev_err(dp->dev, "unable to do link train\n"); 11016f920c07SWyon Bi return ret; 11026f920c07SWyon Bi } 11036f920c07SWyon Bi 11042fcb4783SDamon Ding ret = analogix_dp_enable_scramble(dp, 1); 11052fcb4783SDamon Ding if (ret < 0) { 11062fcb4783SDamon Ding dev_err(dp->dev, "can not enable scramble\n"); 11072fcb4783SDamon Ding return ret; 11082fcb4783SDamon Ding } 11092fcb4783SDamon Ding 11106f920c07SWyon Bi analogix_dp_init_video(dp); 11116e378f44SDamon Ding 11126e378f44SDamon Ding drm_mode_copy(&mode, &conn_state->mode); 11136e378f44SDamon Ding if (conn->dual_channel_mode) 11146e378f44SDamon Ding drm_mode_convert_to_origin_mode(&mode); 11156e378f44SDamon Ding analogix_dp_set_video_format(dp, &mode); 11160b8cf90dSWyon Bi 11170b8cf90dSWyon Bi if (dp->video_bist_enable) 11180b8cf90dSWyon Bi analogix_dp_video_bist_enable(dp); 11190b8cf90dSWyon Bi 11206f920c07SWyon Bi ret = analogix_dp_config_video(dp); 11216f920c07SWyon Bi if (ret) { 11226f920c07SWyon Bi dev_err(dp->dev, "unable to config video\n"); 11236f920c07SWyon Bi return ret; 11246f920c07SWyon Bi } 11256f920c07SWyon Bi 11266f920c07SWyon Bi return 0; 11276f920c07SWyon Bi } 11286f920c07SWyon Bi 11290594ce39SZhang Yubing static int analogix_dp_connector_disable(struct rockchip_connector *conn, 11300594ce39SZhang Yubing struct display_state *state) 11316f920c07SWyon Bi { 11320594ce39SZhang Yubing const struct rockchip_dp_chip_data *pdata = 11330594ce39SZhang Yubing (const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev); 11340594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 11357adc0066SWyon Bi 1136d3e70420SWyon Bi if (!analogix_dp_get_plug_in_status(dp)) 1137d3e70420SWyon Bi analogix_dp_link_power_down(dp); 1138d3e70420SWyon Bi 11397adc0066SWyon Bi if (pdata->chip_type == RK3588_EDP) 11407adc0066SWyon Bi regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0, 11417adc0066SWyon Bi EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 0)); 11426f920c07SWyon Bi 11436f920c07SWyon Bi return 0; 11446f920c07SWyon Bi } 11456f920c07SWyon Bi 11460594ce39SZhang Yubing static int analogix_dp_connector_detect(struct rockchip_connector *conn, 11470594ce39SZhang Yubing struct display_state *state) 1148d90a0d9fSWyon Bi { 11490594ce39SZhang Yubing struct analogix_dp_device *dp = dev_get_priv(conn->dev); 1150d67c1260SDamon Ding int ret; 1151d90a0d9fSWyon Bi 1152d67c1260SDamon Ding if (analogix_dp_detect(dp)) { 1153d67c1260SDamon Ding /* Initialize by reading RX's DPCD */ 1154d67c1260SDamon Ding ret = analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); 1155d67c1260SDamon Ding if (ret) { 1156d67c1260SDamon Ding dev_err(dp->dev, "failed to read max link rate\n"); 1157d67c1260SDamon Ding return 0; 1158d67c1260SDamon Ding } 1159d67c1260SDamon Ding 1160d67c1260SDamon Ding ret = analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); 1161d67c1260SDamon Ding if (ret) { 1162d67c1260SDamon Ding dev_err(dp->dev, "failed to read max lane count\n"); 1163d67c1260SDamon Ding return 0; 1164d67c1260SDamon Ding } 1165d67c1260SDamon Ding 1166d67c1260SDamon Ding return 1; 1167d67c1260SDamon Ding } else { 1168d67c1260SDamon Ding return 0; 1169d67c1260SDamon Ding } 1170d90a0d9fSWyon Bi } 1171d90a0d9fSWyon Bi 1172f38653b8SDamon Ding static int analogix_dp_connector_mode_valid(struct rockchip_connector *conn, 1173f38653b8SDamon Ding struct display_state *state) 1174f38653b8SDamon Ding { 1175f38653b8SDamon Ding struct connector_state *conn_state = &state->conn_state; 1176f38653b8SDamon Ding struct videomode vm; 1177f38653b8SDamon Ding 1178f38653b8SDamon Ding drm_display_mode_to_videomode(&conn_state->mode, &vm); 1179f38653b8SDamon Ding 1180f38653b8SDamon Ding if (!vm.hfront_porch || !vm.hback_porch || !vm.vfront_porch || !vm.vback_porch) { 1181f38653b8SDamon Ding dev_err(dp->dev, "front porch or back porch can not be 0\n"); 1182f38653b8SDamon Ding return MODE_BAD; 1183f38653b8SDamon Ding } 1184f38653b8SDamon Ding 1185f38653b8SDamon Ding return MODE_OK; 1186f38653b8SDamon Ding } 1187f38653b8SDamon Ding 1188d67c1260SDamon Ding static int analogix_dp_mode_valid(struct analogix_dp_device *dp, struct hdmi_edid_data *edid_data) 1189d67c1260SDamon Ding { 1190d67c1260SDamon Ding struct drm_display_info *di = &edid_data->display_info; 1191d67c1260SDamon Ding u32 max_link_rate, max_lane_count; 1192d67c1260SDamon Ding u32 min_bpp; 1193d67c1260SDamon Ding int i; 1194d67c1260SDamon Ding 1195d67c1260SDamon Ding if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422) 1196d67c1260SDamon Ding min_bpp = 16; 1197d67c1260SDamon Ding else if (di->color_formats & DRM_COLOR_FORMAT_RGB444) 1198d67c1260SDamon Ding min_bpp = 18; 1199d67c1260SDamon Ding else 1200d67c1260SDamon Ding min_bpp = 24; 1201d67c1260SDamon Ding 1202d67c1260SDamon Ding max_link_rate = min_t(u32, dp->video_info.max_link_rate, dp->link_train.link_rate); 1203d67c1260SDamon Ding max_lane_count = min_t(u32, dp->video_info.max_lane_count, dp->link_train.lane_count); 1204d67c1260SDamon Ding for (i = 0; i < edid_data->modes; i++) { 1205d67c1260SDamon Ding if (!analogix_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp, 1206d67c1260SDamon Ding drm_dp_bw_code_to_link_rate(max_link_rate), 1207d67c1260SDamon Ding max_lane_count)) 1208d67c1260SDamon Ding edid_data->mode_buf[i].invalid = true; 1209d67c1260SDamon Ding } 1210d67c1260SDamon Ding 1211d67c1260SDamon Ding return 0; 1212d67c1260SDamon Ding } 1213d67c1260SDamon Ding 1214d67c1260SDamon Ding static int analogix_dp_connector_get_timing(struct rockchip_connector *conn, 1215d67c1260SDamon Ding struct display_state *state) 1216d67c1260SDamon Ding { 1217d67c1260SDamon Ding struct connector_state *conn_state = &state->conn_state; 1218d67c1260SDamon Ding const struct rockchip_dp_chip_data *pdata = 1219d67c1260SDamon Ding (const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev); 1220d67c1260SDamon Ding struct analogix_dp_device *dp = dev_get_priv(conn->dev); 1221d67c1260SDamon Ding struct drm_display_mode *mode = &conn_state->mode; 1222d67c1260SDamon Ding struct hdmi_edid_data edid_data; 1223d67c1260SDamon Ding struct drm_display_mode *mode_buf; 1224d67c1260SDamon Ding struct vop_rect rect; 1225d67c1260SDamon Ding u32 yuv_fmts_mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422; 1226d67c1260SDamon Ding u32 fmt_id; 1227*9c170041SAlgea Cao int ret = 0, i; 1228d67c1260SDamon Ding 1229d67c1260SDamon Ding mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode)); 1230d67c1260SDamon Ding if (!mode_buf) 1231d67c1260SDamon Ding return -ENOMEM; 1232d67c1260SDamon Ding 1233d67c1260SDamon Ding memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode)); 1234d67c1260SDamon Ding memset(&edid_data, 0, sizeof(struct hdmi_edid_data)); 1235d67c1260SDamon Ding edid_data.mode_buf = mode_buf; 1236d67c1260SDamon Ding 1237*9c170041SAlgea Cao conn_state->edid = drm_do_get_edid(&dp->aux.ddc); 1238*9c170041SAlgea Cao if (conn_state->edid) 1239d67c1260SDamon Ding ret = drm_add_edid_modes(&edid_data, conn_state->edid); 1240d67c1260SDamon Ding 1241*9c170041SAlgea Cao if (ret <= 0) { 1242d67c1260SDamon Ding printf("failed to get edid\n"); 1243d67c1260SDamon Ding goto err; 1244d67c1260SDamon Ding } 1245d67c1260SDamon Ding 1246d67c1260SDamon Ding if (!pdata->format_yuv) { 1247d67c1260SDamon Ding if (edid_data.display_info.color_formats & yuv_fmts_mask) { 1248d67c1260SDamon Ding printf("Swapping display color format from YUV to RGB\n"); 1249d67c1260SDamon Ding edid_data.display_info.color_formats &= ~yuv_fmts_mask; 1250d67c1260SDamon Ding edid_data.display_info.color_formats |= DRM_COLOR_FORMAT_RGB444; 1251d67c1260SDamon Ding } 1252d67c1260SDamon Ding } 1253d67c1260SDamon Ding 1254d67c1260SDamon Ding if (state->conn_state.secondary) { 1255d67c1260SDamon Ding rect.width = state->crtc_state.max_output.width / 2; 1256d67c1260SDamon Ding rect.height = state->crtc_state.max_output.height / 2; 1257d67c1260SDamon Ding } else { 1258d67c1260SDamon Ding rect.width = state->crtc_state.max_output.width; 1259d67c1260SDamon Ding rect.height = state->crtc_state.max_output.height; 1260d67c1260SDamon Ding } 1261d67c1260SDamon Ding 1262d67c1260SDamon Ding drm_mode_max_resolution_filter(&edid_data, &rect); 1263d67c1260SDamon Ding analogix_dp_mode_valid(dp, &edid_data); 1264d67c1260SDamon Ding 1265d67c1260SDamon Ding if (!drm_mode_prune_invalid(&edid_data)) { 1266d67c1260SDamon Ding printf("can't find valid dp mode\n"); 1267d67c1260SDamon Ding ret = -EINVAL; 1268d67c1260SDamon Ding goto err; 1269d67c1260SDamon Ding } 1270d67c1260SDamon Ding 1271d67c1260SDamon Ding for (i = 0; i < edid_data.modes; i++) 1272d67c1260SDamon Ding edid_data.mode_buf[i].vrefresh = drm_mode_vrefresh(&edid_data.mode_buf[i]); 1273d67c1260SDamon Ding 1274d67c1260SDamon Ding drm_mode_sort(&edid_data); 1275d67c1260SDamon Ding memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode)); 1276d67c1260SDamon Ding 1277d67c1260SDamon Ding fmt_id = analogix_dp_get_output_format_by_edid(dp, &edid_data); 1278d67c1260SDamon Ding dp->output_fmt = &possible_output_fmts[fmt_id]; 1279d67c1260SDamon Ding 1280d67c1260SDamon Ding switch (dp->output_fmt->color_format) { 1281d67c1260SDamon Ding case DRM_COLOR_FORMAT_YCRCB422: 1282d67c1260SDamon Ding conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422; 1283d67c1260SDamon Ding break; 1284d67c1260SDamon Ding case DRM_COLOR_FORMAT_RGB444: 1285d67c1260SDamon Ding case DRM_COLOR_FORMAT_YCRCB444: 1286d67c1260SDamon Ding default: 1287d67c1260SDamon Ding conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 1288d67c1260SDamon Ding break; 1289d67c1260SDamon Ding } 1290d67c1260SDamon Ding 1291d67c1260SDamon Ding conn_state->bus_format = dp->output_fmt->bus_format; 1292d67c1260SDamon Ding conn_state->bpc = dp->output_fmt->bpc; 1293d67c1260SDamon Ding conn_state->color_encoding = DRM_COLOR_YCBCR_BT709; 1294d67c1260SDamon Ding if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_RGB444) 1295d67c1260SDamon Ding conn_state->color_range = DRM_COLOR_YCBCR_FULL_RANGE; 1296d67c1260SDamon Ding else 1297d67c1260SDamon Ding conn_state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; 1298d67c1260SDamon Ding 1299d67c1260SDamon Ding err: 1300d67c1260SDamon Ding free(mode_buf); 1301d67c1260SDamon Ding 1302d67c1260SDamon Ding return 0; 1303d67c1260SDamon Ding } 1304d67c1260SDamon Ding 13056f920c07SWyon Bi static const struct rockchip_connector_funcs analogix_dp_connector_funcs = { 13066f920c07SWyon Bi .init = analogix_dp_connector_init, 13076f920c07SWyon Bi .get_edid = analogix_dp_connector_get_edid, 13086f920c07SWyon Bi .enable = analogix_dp_connector_enable, 13096f920c07SWyon Bi .disable = analogix_dp_connector_disable, 1310d90a0d9fSWyon Bi .detect = analogix_dp_connector_detect, 1311f38653b8SDamon Ding .mode_valid = analogix_dp_connector_mode_valid, 1312d67c1260SDamon Ding .get_timing = analogix_dp_connector_get_timing, 13136f920c07SWyon Bi }; 13146f920c07SWyon Bi 131535c48984SWyon Bi static u32 analogix_dp_parse_link_frequencies(struct analogix_dp_device *dp) 131635c48984SWyon Bi { 131735c48984SWyon Bi struct udevice *dev = dp->dev; 131835c48984SWyon Bi const struct device_node *endpoint; 131935c48984SWyon Bi u64 frequency = 0; 132035c48984SWyon Bi 132135c48984SWyon Bi endpoint = rockchip_of_graph_get_endpoint_by_regs(dev->node, 1, 0); 132235c48984SWyon Bi if (!endpoint) 132335c48984SWyon Bi return 0; 132435c48984SWyon Bi 132535c48984SWyon Bi if (of_property_read_u64(endpoint, "link-frequencies", &frequency) < 0) 132635c48984SWyon Bi return 0; 132735c48984SWyon Bi 132835c48984SWyon Bi if (!frequency) 132935c48984SWyon Bi return 0; 133035c48984SWyon Bi 133135c48984SWyon Bi do_div(frequency, 10 * 1000); /* symbol rate kbytes */ 133235c48984SWyon Bi 133335c48984SWyon Bi switch (frequency) { 133435c48984SWyon Bi case 162000: 133535c48984SWyon Bi case 270000: 133635c48984SWyon Bi case 540000: 133735c48984SWyon Bi break; 133835c48984SWyon Bi default: 133935c48984SWyon Bi dev_err(dev, "invalid link frequency value: %llu\n", frequency); 134035c48984SWyon Bi return 0; 134135c48984SWyon Bi } 134235c48984SWyon Bi 134335c48984SWyon Bi return frequency; 134435c48984SWyon Bi } 134535c48984SWyon Bi 13461f59ac36SWyon Bi static int analogix_dp_parse_dt(struct analogix_dp_device *dp) 13471f59ac36SWyon Bi { 13481f59ac36SWyon Bi struct udevice *dev = dp->dev; 13491f59ac36SWyon Bi int len; 13501f59ac36SWyon Bi u32 num_lanes; 1351e14b9f0dSWyon Bi u32 max_link_rate; 13521f59ac36SWyon Bi int ret; 13531f59ac36SWyon Bi 13541f59ac36SWyon Bi dp->force_hpd = dev_read_bool(dev, "force-hpd"); 13551f59ac36SWyon Bi dp->video_bist_enable = dev_read_bool(dev, "analogix,video-bist-enable"); 1356ae5256b5SWyon Bi dp->video_info.force_stream_valid = 1357ae5256b5SWyon Bi dev_read_bool(dev, "analogix,force-stream-valid"); 13581f59ac36SWyon Bi 135935c48984SWyon Bi max_link_rate = analogix_dp_parse_link_frequencies(dp); 136035c48984SWyon Bi if (max_link_rate && max_link_rate < drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate)) 136135c48984SWyon Bi dp->video_info.max_link_rate = drm_dp_link_rate_to_bw_code(max_link_rate); 1362e14b9f0dSWyon Bi 13631f59ac36SWyon Bi if (dev_read_prop(dev, "data-lanes", &len)) { 13641f59ac36SWyon Bi num_lanes = len / sizeof(u32); 13651f59ac36SWyon Bi if (num_lanes < 1 || num_lanes > 4 || num_lanes == 3) { 13661f59ac36SWyon Bi dev_err(dev, "bad number of data lanes\n"); 13671f59ac36SWyon Bi return -EINVAL; 13681f59ac36SWyon Bi } 13691f59ac36SWyon Bi 13701f59ac36SWyon Bi ret = dev_read_u32_array(dev, "data-lanes", dp->lane_map, 13711f59ac36SWyon Bi num_lanes); 13721f59ac36SWyon Bi if (ret) 13731f59ac36SWyon Bi return ret; 13741f59ac36SWyon Bi 13751f59ac36SWyon Bi dp->video_info.max_lane_count = num_lanes; 13761f59ac36SWyon Bi } else { 13771f59ac36SWyon Bi dp->lane_map[0] = 0; 13781f59ac36SWyon Bi dp->lane_map[1] = 1; 13791f59ac36SWyon Bi dp->lane_map[2] = 2; 13801f59ac36SWyon Bi dp->lane_map[3] = 3; 13811f59ac36SWyon Bi } 13821f59ac36SWyon Bi 13831f59ac36SWyon Bi return 0; 13841f59ac36SWyon Bi } 13851f59ac36SWyon Bi 138658df3976SDamon Ding static int analogix_dp_ddc_init(struct analogix_dp_device *dp) 138758df3976SDamon Ding { 138858df3976SDamon Ding dp->aux.name = "analogix-dp"; 138958df3976SDamon Ding dp->aux.dev = dp->dev; 139058df3976SDamon Ding dp->aux.transfer = analogix_dp_aux_transfer; 139158df3976SDamon Ding dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer; 139258df3976SDamon Ding 139358df3976SDamon Ding return 0; 139458df3976SDamon Ding } 139558df3976SDamon Ding 13966f920c07SWyon Bi static int analogix_dp_probe(struct udevice *dev) 13976f920c07SWyon Bi { 13986f920c07SWyon Bi struct analogix_dp_device *dp = dev_get_priv(dev); 13990594ce39SZhang Yubing const struct rockchip_dp_chip_data *pdata = 14000594ce39SZhang Yubing (const struct rockchip_dp_chip_data *)dev_get_driver_data(dev); 14017adc0066SWyon Bi struct udevice *syscon; 14026f920c07SWyon Bi int ret; 14036f920c07SWyon Bi 14046f920c07SWyon Bi dp->reg_base = dev_read_addr_ptr(dev); 14056f920c07SWyon Bi 1406cb17ca6cSSandy Huang dp->id = of_alias_get_id(ofnode_to_np(dev->node), "edp"); 1407cb17ca6cSSandy Huang if (dp->id < 0) 1408cb17ca6cSSandy Huang dp->id = 0; 14097adc0066SWyon Bi 14107adc0066SWyon Bi ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,grf", 14117adc0066SWyon Bi &syscon); 14127adc0066SWyon Bi if (!ret) { 14137adc0066SWyon Bi dp->grf = syscon_get_regmap(syscon); 14147adc0066SWyon Bi if (!dp->grf) 14157adc0066SWyon Bi return -ENODEV; 14167adc0066SWyon Bi } 14177adc0066SWyon Bi 1418699c29a5SWyon Bi ret = reset_get_bulk(dev, &dp->resets); 1419dddde95bSWyon Bi if (ret) { 1420dddde95bSWyon Bi dev_err(dev, "failed to get reset control: %d\n", ret); 1421dddde95bSWyon Bi return ret; 1422dddde95bSWyon Bi } 1423dddde95bSWyon Bi 14246f920c07SWyon Bi ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio, 14256f920c07SWyon Bi GPIOD_IS_IN); 14266f920c07SWyon Bi if (ret && ret != -ENOENT) { 14276f920c07SWyon Bi dev_err(dev, "failed to get hpd GPIO: %d\n", ret); 14286f920c07SWyon Bi return ret; 14296f920c07SWyon Bi } 14306f920c07SWyon Bi 1431699c29a5SWyon Bi generic_phy_get_by_name(dev, "dp", &dp->phy); 1432699c29a5SWyon Bi 14336f920c07SWyon Bi dp->plat_data.dev_type = ROCKCHIP_DP; 14346f920c07SWyon Bi dp->plat_data.subdev_type = pdata->chip_type; 1435699c29a5SWyon Bi dp->plat_data.ssc = pdata->ssc; 14366c0d4eb6SDamon Ding dp->plat_data.support_dp_mode = pdata->support_dp_mode; 1437d67c1260SDamon Ding dp->plat_data.max_bpc = pdata->max_bpc ? pdata->max_bpc : 8; 14387adc0066SWyon Bi 14397adc0066SWyon Bi dp->video_info.max_link_rate = pdata->max_link_rate; 14407adc0066SWyon Bi dp->video_info.max_lane_count = pdata->max_lane_count; 14416f920c07SWyon Bi 14426f920c07SWyon Bi dp->dev = dev; 14436f920c07SWyon Bi 14441f59ac36SWyon Bi ret = analogix_dp_parse_dt(dp); 14451f59ac36SWyon Bi if (ret) { 14461f59ac36SWyon Bi dev_err(dev, "failed to parse DT: %d\n", ret); 14471f59ac36SWyon Bi return ret; 14481f59ac36SWyon Bi } 14491f59ac36SWyon Bi 145058df3976SDamon Ding analogix_dp_ddc_init(dp); 145158df3976SDamon Ding 14520594ce39SZhang Yubing rockchip_connector_bind(&dp->connector, dev, dp->id, &analogix_dp_connector_funcs, 14530594ce39SZhang Yubing NULL, DRM_MODE_CONNECTOR_eDP); 14540594ce39SZhang Yubing 14556f920c07SWyon Bi return 0; 14566f920c07SWyon Bi } 14576f920c07SWyon Bi 14586f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3288_edp_platform_data = { 14596f920c07SWyon Bi .lcdsel_grf_reg = 0x025c, 14606f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 14616f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 14626f920c07SWyon Bi .chip_type = RK3288_DP, 14637adc0066SWyon Bi 14647adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 14657adc0066SWyon Bi .max_lane_count = 4, 14666f920c07SWyon Bi }; 14676f920c07SWyon Bi 14686f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3368_edp_platform_data = { 14696f920c07SWyon Bi .chip_type = RK3368_EDP, 14707adc0066SWyon Bi 14717adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 14727adc0066SWyon Bi .max_lane_count = 4, 14736f920c07SWyon Bi }; 14746f920c07SWyon Bi 14756f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3399_edp_platform_data = { 14766f920c07SWyon Bi .lcdsel_grf_reg = 0x6250, 14776f920c07SWyon Bi .lcdsel_big = 0 | BIT(21), 14786f920c07SWyon Bi .lcdsel_lit = BIT(5) | BIT(21), 14796f920c07SWyon Bi .chip_type = RK3399_EDP, 1480e417664aSWyon Bi .ssc = true, 14817adc0066SWyon Bi 1482e417664aSWyon Bi .max_link_rate = DP_LINK_BW_5_4, 14837adc0066SWyon Bi .max_lane_count = 4, 14846f920c07SWyon Bi }; 14856f920c07SWyon Bi 1486699c29a5SWyon Bi static const struct rockchip_dp_chip_data rk3568_edp_platform_data = { 1487699c29a5SWyon Bi .chip_type = RK3568_EDP, 1488699c29a5SWyon Bi .ssc = true, 14897adc0066SWyon Bi 14907adc0066SWyon Bi .max_link_rate = DP_LINK_BW_2_7, 14917adc0066SWyon Bi .max_lane_count = 4, 1492699c29a5SWyon Bi }; 1493699c29a5SWyon Bi 149446d49f07SDamon Ding static const struct rockchip_dp_chip_data rk3576_edp_platform_data = { 149546d49f07SDamon Ding .chip_type = RK3576_EDP, 149646d49f07SDamon Ding .ssc = true, 149746d49f07SDamon Ding 149846d49f07SDamon Ding .max_link_rate = DP_LINK_BW_5_4, 149946d49f07SDamon Ding .max_lane_count = 4, 1500d67c1260SDamon Ding .format_yuv = true, 150132035f4bSDamon Ding .support_dp_mode = true, 1502d67c1260SDamon Ding .max_bpc = 10, 150346d49f07SDamon Ding }; 150446d49f07SDamon Ding 15057adc0066SWyon Bi static const struct rockchip_dp_chip_data rk3588_edp_platform_data = { 15067adc0066SWyon Bi .chip_type = RK3588_EDP, 15077adc0066SWyon Bi .ssc = true, 15087adc0066SWyon Bi 15097adc0066SWyon Bi .max_link_rate = DP_LINK_BW_5_4, 15107adc0066SWyon Bi .max_lane_count = 4, 1511d67c1260SDamon Ding .format_yuv = true, 151232035f4bSDamon Ding .support_dp_mode = true, 1513d67c1260SDamon Ding .max_bpc = 10, 15147adc0066SWyon Bi }; 15157adc0066SWyon Bi 15166f920c07SWyon Bi static const struct udevice_id analogix_dp_ids[] = { 15176f920c07SWyon Bi { 15186f920c07SWyon Bi .compatible = "rockchip,rk3288-dp", 15190594ce39SZhang Yubing .data = (ulong)&rk3288_edp_platform_data, 15206f920c07SWyon Bi }, { 15216f920c07SWyon Bi .compatible = "rockchip,rk3368-edp", 15220594ce39SZhang Yubing .data = (ulong)&rk3368_edp_platform_data, 15236f920c07SWyon Bi }, { 15246f920c07SWyon Bi .compatible = "rockchip,rk3399-edp", 15250594ce39SZhang Yubing .data = (ulong)&rk3399_edp_platform_data, 1526699c29a5SWyon Bi }, { 1527699c29a5SWyon Bi .compatible = "rockchip,rk3568-edp", 15280594ce39SZhang Yubing .data = (ulong)&rk3568_edp_platform_data, 15297adc0066SWyon Bi }, { 153046d49f07SDamon Ding .compatible = "rockchip,rk3576-edp", 153146d49f07SDamon Ding .data = (ulong)&rk3576_edp_platform_data, 153246d49f07SDamon Ding }, { 15337adc0066SWyon Bi .compatible = "rockchip,rk3588-edp", 15340594ce39SZhang Yubing .data = (ulong)&rk3588_edp_platform_data, 15356f920c07SWyon Bi }, 15366f920c07SWyon Bi {} 15376f920c07SWyon Bi }; 15386f920c07SWyon Bi 15396f920c07SWyon Bi U_BOOT_DRIVER(analogix_dp) = { 15406f920c07SWyon Bi .name = "analogix_dp", 15416f920c07SWyon Bi .id = UCLASS_DISPLAY, 15426f920c07SWyon Bi .of_match = analogix_dp_ids, 15436f920c07SWyon Bi .probe = analogix_dp_probe, 15446f920c07SWyon Bi .priv_auto_alloc_size = sizeof(struct analogix_dp_device), 15456f920c07SWyon Bi }; 1546