1fb43630cSZhang Yubing // SPDX-License-Identifier: GPL-2.0-or-later 2fb43630cSZhang Yubing /* 3fb43630cSZhang Yubing * Rockchip USBDP Combo PHY with Samsung IP block driver 4fb43630cSZhang Yubing * 5fb43630cSZhang Yubing * Copyright (C) 2021 Rockchip Electronics Co., Ltd 6fb43630cSZhang Yubing */ 7fb43630cSZhang Yubing 8fb43630cSZhang Yubing #include <config.h> 9fb43630cSZhang Yubing #include <common.h> 10fb43630cSZhang Yubing #include <errno.h> 11fb43630cSZhang Yubing #include <malloc.h> 12fb43630cSZhang Yubing #include <asm/unaligned.h> 13fb43630cSZhang Yubing #include <asm/io.h> 14fb43630cSZhang Yubing #include <clk.h> 15fb43630cSZhang Yubing #include <dm/device.h> 16fb43630cSZhang Yubing #include <dm/of_access.h> 17fb43630cSZhang Yubing #include <dm/read.h> 18fb43630cSZhang Yubing #include <generic-phy.h> 19fb43630cSZhang Yubing #include <linux/bitfield.h> 20fb43630cSZhang Yubing #include <linux/hdmi.h> 21fb43630cSZhang Yubing #include <linux/media-bus-format.h> 22fb43630cSZhang Yubing #include <linux/list.h> 23fb43630cSZhang Yubing #include <asm/gpio.h> 24fb43630cSZhang Yubing #include <generic-phy.h> 25fb43630cSZhang Yubing #include <regmap.h> 26fb43630cSZhang Yubing #include <reset.h> 27fb43630cSZhang Yubing #include <drm/drm_dp_helper.h> 28fb43630cSZhang Yubing 29fb43630cSZhang Yubing #include "rockchip_display.h" 30fb43630cSZhang Yubing #include "rockchip_crtc.h" 31fb43630cSZhang Yubing #include "rockchip_connector.h" 32fb43630cSZhang Yubing 33fb43630cSZhang Yubing #define DPTX_VERSION_NUMBER 0x0000 34fb43630cSZhang Yubing #define DPTX_VERSION_TYPE 0x0004 35fb43630cSZhang Yubing #define DPTX_ID 0x0008 36fb43630cSZhang Yubing 37fb43630cSZhang Yubing #define DPTX_CONFIG_REG1 0x0100 38fb43630cSZhang Yubing #define DPTX_CONFIG_REG2 0x0104 39fb43630cSZhang Yubing #define DPTX_CONFIG_REG3 0x0108 40fb43630cSZhang Yubing 41fb43630cSZhang Yubing #define DPTX_CCTL 0x0200 42fb43630cSZhang Yubing #define FORCE_HPD BIT(4) 43fb43630cSZhang Yubing #define DEFAULT_FAST_LINK_TRAIN_EN BIT(2) 44fb43630cSZhang Yubing #define ENHANCE_FRAMING_EN BIT(1) 45fb43630cSZhang Yubing #define SCRAMBLE_DIS BIT(0) 46fb43630cSZhang Yubing #define DPTX_SOFT_RESET_CTRL 0x0204 47fb43630cSZhang Yubing #define VIDEO_RESET BIT(5) 48fb43630cSZhang Yubing #define AUX_RESET BIT(4) 49fb43630cSZhang Yubing #define AUDIO_SAMPLER_RESET BIT(3) 50fb43630cSZhang Yubing #define PHY_SOFT_RESET BIT(1) 51fb43630cSZhang Yubing #define CONTROLLER_RESET BIT(0) 52fb43630cSZhang Yubing 53fb43630cSZhang Yubing #define DPTX_VSAMPLE_CTRL 0x0300 54fb43630cSZhang Yubing #define PIXEL_MODE_SELECT GENMASK(22, 21) 55fb43630cSZhang Yubing #define VIDEO_MAPPING GENMASK(20, 16) 56fb43630cSZhang Yubing #define VIDEO_STREAM_ENABLE BIT(5) 57fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL1 0x0304 58fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL2 0x0308 59fb43630cSZhang Yubing #define DPTX_VINPUT_POLARITY_CTRL 0x030c 60fb43630cSZhang Yubing #define DE_IN_POLARITY BIT(2) 61fb43630cSZhang Yubing #define HSYNC_IN_POLARITY BIT(1) 62fb43630cSZhang Yubing #define VSYNC_IN_POLARITY BIT(0) 63fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG1 0x0310 64fb43630cSZhang Yubing #define HACTIVE GENMASK(31, 16) 65fb43630cSZhang Yubing #define HBLANK GENMASK(15, 2) 66fb43630cSZhang Yubing #define I_P BIT(1) 67fb43630cSZhang Yubing #define R_V_BLANK_IN_OSC BIT(0) 68fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG2 0x0314 69fb43630cSZhang Yubing #define VBLANK GENMASK(31, 16) 70fb43630cSZhang Yubing #define VACTIVE GENMASK(15, 0) 71fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG3 0x0318 72fb43630cSZhang Yubing #define H_SYNC_WIDTH GENMASK(31, 16) 73fb43630cSZhang Yubing #define H_FRONT_PORCH GENMASK(15, 0) 74fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG4 0x031c 75fb43630cSZhang Yubing #define V_SYNC_WIDTH GENMASK(31, 16) 76fb43630cSZhang Yubing #define V_FRONT_PORCH GENMASK(15, 0) 77fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG5 0x0320 78fb43630cSZhang Yubing #define INIT_THRESHOLD_HI GENMASK(22, 21) 79fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU_FRAC GENMASK(19, 16) 80fb43630cSZhang Yubing #define INIT_THRESHOLD GENMASK(13, 7) 81fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU GENMASK(6, 0) 82fb43630cSZhang Yubing #define DPTX_VIDEO_MSA1 0x0324 83fb43630cSZhang Yubing #define VSTART GENMASK(31, 16) 84fb43630cSZhang Yubing #define HSTART GENMASK(15, 0) 85fb43630cSZhang Yubing #define DPTX_VIDEO_MSA2 0x0328 86fb43630cSZhang Yubing #define MISC0 GENMASK(31, 24) 87fb43630cSZhang Yubing #define DPTX_VIDEO_MSA3 0x032c 88fb43630cSZhang Yubing #define MISC1 GENMASK(31, 24) 89fb43630cSZhang Yubing #define DPTX_VIDEO_HBLANK_INTERVAL 0x0330 90fb43630cSZhang Yubing #define HBLANK_INTERVAL_EN BIT(16) 91fb43630cSZhang Yubing #define HBLANK_INTERVAL GENMASK(15, 0) 92fb43630cSZhang Yubing 93fb43630cSZhang Yubing #define DPTX_AUD_CONFIG1 0x0400 94fb43630cSZhang Yubing #define AUDIO_TIMESTAMP_VERSION_NUM GENMASK(29, 24) 95fb43630cSZhang Yubing #define AUDIO_PACKET_ID GENMASK(23, 16) 96fb43630cSZhang Yubing #define AUDIO_MUTE BIT(15) 97fb43630cSZhang Yubing #define NUM_CHANNELS GENMASK(14, 12) 98fb43630cSZhang Yubing #define HBR_MODE_ENABLE BIT(10) 99fb43630cSZhang Yubing #define AUDIO_DATA_WIDTH GENMASK(9, 5) 100fb43630cSZhang Yubing #define AUDIO_DATA_IN_EN GENMASK(4, 1) 101fb43630cSZhang Yubing #define AUDIO_INF_SELECT BIT(0) 102fb43630cSZhang Yubing 103fb43630cSZhang Yubing #define DPTX_SDP_VERTICAL_CTRL 0x0500 104fb43630cSZhang Yubing #define EN_VERTICAL_SDP BIT(2) 105fb43630cSZhang Yubing #define EN_AUDIO_STREAM_SDP BIT(1) 106fb43630cSZhang Yubing #define EN_AUDIO_TIMESTAMP_SDP BIT(0) 107fb43630cSZhang Yubing #define DPTX_SDP_HORIZONTAL_CTRL 0x0504 108fb43630cSZhang Yubing #define EN_HORIZONTAL_SDP BIT(2) 109fb43630cSZhang Yubing #define DPTX_SDP_STATUS_REGISTER 0x0508 110fb43630cSZhang Yubing #define DPTX_SDP_MANUAL_CTRL 0x050c 111fb43630cSZhang Yubing #define DPTX_SDP_STATUS_EN 0x0510 112fb43630cSZhang Yubing 113fb43630cSZhang Yubing #define DPTX_SDP_REGISTER_BANK 0x0600 114fb43630cSZhang Yubing #define SDP_REGS GENMASK(31, 0) 115fb43630cSZhang Yubing 116fb43630cSZhang Yubing #define DPTX_PHYIF_CTRL 0x0a00 117fb43630cSZhang Yubing #define PHY_WIDTH BIT(25) 118fb43630cSZhang Yubing #define PHY_POWERDOWN GENMASK(20, 17) 119fb43630cSZhang Yubing #define PHY_BUSY GENMASK(15, 12) 120fb43630cSZhang Yubing #define SSC_DIS BIT(16) 121fb43630cSZhang Yubing #define XMIT_ENABLE GENMASK(11, 8) 122fb43630cSZhang Yubing #define PHY_LANES GENMASK(7, 6) 123fb43630cSZhang Yubing #define PHY_RATE GENMASK(5, 4) 124fb43630cSZhang Yubing #define TPS_SEL GENMASK(3, 0) 125fb43630cSZhang Yubing #define DPTX_PHY_TX_EQ 0x0a04 126fb43630cSZhang Yubing #define DPTX_CUSTOMPAT0 0x0a08 127fb43630cSZhang Yubing #define DPTX_CUSTOMPAT1 0x0a0c 128fb43630cSZhang Yubing #define DPTX_CUSTOMPAT2 0x0a10 129fb43630cSZhang Yubing #define DPTX_HBR2_COMPLIANCE_SCRAMBLER_RESET 0x0a14 130fb43630cSZhang Yubing #define DPTX_PHYIF_PWRDOWN_CTRL 0x0a18 131fb43630cSZhang Yubing 132fb43630cSZhang Yubing #define DPTX_AUX_CMD 0x0b00 133fb43630cSZhang Yubing #define AUX_CMD_TYPE GENMASK(31, 28) 134fb43630cSZhang Yubing #define AUX_ADDR GENMASK(27, 8) 135fb43630cSZhang Yubing #define I2C_ADDR_ONLY BIT(4) 136fb43630cSZhang Yubing #define AUX_LEN_REQ GENMASK(3, 0) 137fb43630cSZhang Yubing #define DPTX_AUX_STATUS 0x0b04 138fb43630cSZhang Yubing #define AUX_TIMEOUT BIT(17) 139fb43630cSZhang Yubing #define AUX_BYTES_READ GENMASK(23, 19) 140fb43630cSZhang Yubing #define AUX_STATUS GENMASK(7, 4) 141fb43630cSZhang Yubing #define DPTX_AUX_DATA0 0x0b08 142fb43630cSZhang Yubing #define DPTX_AUX_DATA1 0x0b0c 143fb43630cSZhang Yubing #define DPTX_AUX_DATA2 0x0b10 144fb43630cSZhang Yubing #define DPTX_AUX_DATA3 0x0b14 145fb43630cSZhang Yubing 146fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT 0x0d00 147fb43630cSZhang Yubing #define VIDEO_FIFO_OVERFLOW_STREAM0 BIT(6) 148fb43630cSZhang Yubing #define AUDIO_FIFO_OVERFLOW_STREAM0 BIT(5) 149fb43630cSZhang Yubing #define SDP_EVENT_STREAM0 BIT(4) 150fb43630cSZhang Yubing #define AUX_CMD_INVALID BIT(3) 151fb43630cSZhang Yubing #define AUX_REPLY_EVENT BIT(1) 152fb43630cSZhang Yubing #define HPD_EVENT BIT(0) 153fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT_ENABLE 0x0d04 154fb43630cSZhang Yubing #define AUX_REPLY_EVENT_EN BIT(1) 155fb43630cSZhang Yubing #define HPD_EVENT_EN BIT(0) 156fb43630cSZhang Yubing #define DPTX_HPD_STATUS 0x0d08 157fb43630cSZhang Yubing #define HPD_STATE GENMASK(11, 9) 158fb43630cSZhang Yubing #define HPD_STATUS BIT(8) 159fb43630cSZhang Yubing #define HPD_HOT_UNPLUG BIT(2) 160fb43630cSZhang Yubing #define HPD_HOT_PLUG BIT(1) 161fb43630cSZhang Yubing #define HPD_IRQ BIT(0) 162fb43630cSZhang Yubing #define DPTX_HPD_INTERRUPT_ENABLE 0x0d0c 163fb43630cSZhang Yubing #define HPD_UNPLUG_ERR_EN BIT(3) 164fb43630cSZhang Yubing #define HPD_UNPLUG_EN BIT(2) 165fb43630cSZhang Yubing #define HPD_PLUG_EN BIT(1) 166fb43630cSZhang Yubing #define HPD_IRQ_EN BIT(0) 167fb43630cSZhang Yubing 168fb43630cSZhang Yubing #define DPTX_MAX_REGISTER DPTX_HPD_INTERRUPT_ENABLE 169fb43630cSZhang Yubing 170fb43630cSZhang Yubing #define SDP_REG_BANK_SIZE 16 171fb43630cSZhang Yubing 172fb43630cSZhang Yubing struct drm_dp_link_caps { 173fb43630cSZhang Yubing bool enhanced_framing; 174fb43630cSZhang Yubing bool tps3_supported; 175fb43630cSZhang Yubing bool tps4_supported; 176fb43630cSZhang Yubing bool channel_coding; 177fb43630cSZhang Yubing bool ssc; 178fb43630cSZhang Yubing }; 179fb43630cSZhang Yubing 180fb43630cSZhang Yubing struct drm_dp_link_train_set { 181fb43630cSZhang Yubing unsigned int voltage_swing[4]; 182fb43630cSZhang Yubing unsigned int pre_emphasis[4]; 183fb43630cSZhang Yubing }; 184fb43630cSZhang Yubing 185fb43630cSZhang Yubing struct drm_dp_link_train { 186fb43630cSZhang Yubing struct drm_dp_link_train_set request; 187fb43630cSZhang Yubing struct drm_dp_link_train_set adjust; 188fb43630cSZhang Yubing bool clock_recovered; 189fb43630cSZhang Yubing bool channel_equalized; 190fb43630cSZhang Yubing }; 191fb43630cSZhang Yubing 192fb43630cSZhang Yubing struct dw_dp_link { 193fb43630cSZhang Yubing u8 dpcd[DP_RECEIVER_CAP_SIZE]; 194fb43630cSZhang Yubing unsigned char revision; 195fb43630cSZhang Yubing unsigned int rate; 196fb43630cSZhang Yubing unsigned int lanes; 197fb43630cSZhang Yubing struct drm_dp_link_caps caps; 198fb43630cSZhang Yubing struct drm_dp_link_train train; 199fb43630cSZhang Yubing u8 sink_count; 200fb43630cSZhang Yubing u8 vsc_sdp_extension_for_colorimetry_supported; 201fb43630cSZhang Yubing }; 202fb43630cSZhang Yubing 203fb43630cSZhang Yubing struct dw_dp_video { 204fb43630cSZhang Yubing struct drm_display_mode mode; 205fb43630cSZhang Yubing u32 bus_format; 206fb43630cSZhang Yubing u8 video_mapping; 207fb43630cSZhang Yubing u8 pixel_mode; 208fb43630cSZhang Yubing u8 color_format; 209fb43630cSZhang Yubing u8 bpc; 210fb43630cSZhang Yubing u8 bpp; 211fb43630cSZhang Yubing }; 212fb43630cSZhang Yubing 213fb43630cSZhang Yubing struct dw_dp_sdp { 214fb43630cSZhang Yubing struct dp_sdp_header header; 215fb43630cSZhang Yubing u8 db[32]; 216fb43630cSZhang Yubing unsigned long flags; 217fb43630cSZhang Yubing }; 218fb43630cSZhang Yubing 219fb43630cSZhang Yubing struct dw_dp { 220fb43630cSZhang Yubing struct udevice *dev; 221fb43630cSZhang Yubing struct regmap *regmap; 222fb43630cSZhang Yubing struct phy phy; 223fb43630cSZhang Yubing struct reset_ctl reset; 224fb43630cSZhang Yubing int id; 225fb43630cSZhang Yubing 226fb43630cSZhang Yubing struct gpio_desc hpd_gpio; 227fb43630cSZhang Yubing struct drm_dp_aux aux; 228fb43630cSZhang Yubing struct dw_dp_link link; 229fb43630cSZhang Yubing struct dw_dp_video video; 2305efdd3e2SZhang Yubing 2315fbef17aSZhang Yubing bool force_hpd; 2325efdd3e2SZhang Yubing bool force_output; 233fb43630cSZhang Yubing }; 234fb43630cSZhang Yubing 235fb43630cSZhang Yubing enum { 236fb43630cSZhang Yubing SOURCE_STATE_IDLE, 237fb43630cSZhang Yubing SOURCE_STATE_UNPLUG, 238fb43630cSZhang Yubing SOURCE_STATE_HPD_TIMEOUT = 4, 239fb43630cSZhang Yubing SOURCE_STATE_PLUG = 7 240fb43630cSZhang Yubing }; 241fb43630cSZhang Yubing 242fb43630cSZhang Yubing enum { 243fb43630cSZhang Yubing DPTX_VM_RGB_6BIT, 244fb43630cSZhang Yubing DPTX_VM_RGB_8BIT, 245fb43630cSZhang Yubing DPTX_VM_RGB_10BIT, 246fb43630cSZhang Yubing DPTX_VM_RGB_12BIT, 247fb43630cSZhang Yubing DPTX_VM_RGB_16BIT, 248fb43630cSZhang Yubing DPTX_VM_YCBCR444_8BIT, 249fb43630cSZhang Yubing DPTX_VM_YCBCR444_10BIT, 250fb43630cSZhang Yubing DPTX_VM_YCBCR444_12BIT, 251fb43630cSZhang Yubing DPTX_VM_YCBCR444_16BIT, 252fb43630cSZhang Yubing DPTX_VM_YCBCR422_8BIT, 253fb43630cSZhang Yubing DPTX_VM_YCBCR422_10BIT, 254fb43630cSZhang Yubing DPTX_VM_YCBCR422_12BIT, 255fb43630cSZhang Yubing DPTX_VM_YCBCR422_16BIT, 256fb43630cSZhang Yubing DPTX_VM_YCBCR420_8BIT, 257fb43630cSZhang Yubing DPTX_VM_YCBCR420_10BIT, 258fb43630cSZhang Yubing DPTX_VM_YCBCR420_12BIT, 259fb43630cSZhang Yubing DPTX_VM_YCBCR420_16BIT, 260fb43630cSZhang Yubing }; 261fb43630cSZhang Yubing 262fb43630cSZhang Yubing enum { 263fb43630cSZhang Yubing DPTX_MP_SINGLE_PIXEL, 264fb43630cSZhang Yubing DPTX_MP_DUAL_PIXEL, 265fb43630cSZhang Yubing DPTX_MP_QUAD_PIXEL, 266fb43630cSZhang Yubing }; 267fb43630cSZhang Yubing 268fb43630cSZhang Yubing enum { 269fb43630cSZhang Yubing DPTX_SDP_VERTICAL_INTERVAL = BIT(0), 270fb43630cSZhang Yubing DPTX_SDP_HORIZONTAL_INTERVAL = BIT(1), 271fb43630cSZhang Yubing }; 272fb43630cSZhang Yubing 273fb43630cSZhang Yubing enum { 274fb43630cSZhang Yubing DPTX_PHY_PATTERN_NONE, 275fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_1, 276fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_2, 277fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_3, 278fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_4, 279fb43630cSZhang Yubing DPTX_PHY_PATTERN_SERM, 280fb43630cSZhang Yubing DPTX_PHY_PATTERN_PBRS7, 281fb43630cSZhang Yubing DPTX_PHY_PATTERN_CUSTOM_80BIT, 282fb43630cSZhang Yubing DPTX_PHY_PATTERN_CP2520_1, 283fb43630cSZhang Yubing DPTX_PHY_PATTERN_CP2520_2, 284fb43630cSZhang Yubing }; 285fb43630cSZhang Yubing 2865efdd3e2SZhang Yubing enum { 2875efdd3e2SZhang Yubing DPTX_PHYRATE_RBR, 2885efdd3e2SZhang Yubing DPTX_PHYRATE_HBR, 2895efdd3e2SZhang Yubing DPTX_PHYRATE_HBR2, 2905efdd3e2SZhang Yubing DPTX_PHYRATE_HBR3, 2915efdd3e2SZhang Yubing }; 2925efdd3e2SZhang Yubing 293fb43630cSZhang Yubing struct dw_dp_output_format { 294fb43630cSZhang Yubing u32 bus_format; 295fb43630cSZhang Yubing u32 color_format; 296fb43630cSZhang Yubing u8 video_mapping; 297fb43630cSZhang Yubing u8 bpc; 298fb43630cSZhang Yubing u8 bpp; 299fb43630cSZhang Yubing }; 300fb43630cSZhang Yubing 301fb43630cSZhang Yubing static const struct dw_dp_output_format possible_output_fmts[] = { 302fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, 303fb43630cSZhang Yubing DPTX_VM_RGB_10BIT, 10, 30 }, 304fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, 305fb43630cSZhang Yubing DPTX_VM_RGB_8BIT, 8, 24 }, 306fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444, 307fb43630cSZhang Yubing DPTX_VM_YCBCR444_10BIT, 10, 30 }, 308fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444, 309fb43630cSZhang Yubing DPTX_VM_YCBCR444_8BIT, 8, 24}, 310fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422, 311fb43630cSZhang Yubing DPTX_VM_YCBCR422_10BIT, 10, 20 }, 312fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422, 313fb43630cSZhang Yubing DPTX_VM_YCBCR422_8BIT, 8, 16 }, 314fb43630cSZhang Yubing { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCRCB420, 315fb43630cSZhang Yubing DPTX_VM_YCBCR420_10BIT, 10, 15 }, 316fb43630cSZhang Yubing { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCRCB420, 317fb43630cSZhang Yubing DPTX_VM_YCBCR420_8BIT, 8, 12 }, 318fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, 319fb43630cSZhang Yubing DPTX_VM_RGB_6BIT, 6, 18 }, 320fb43630cSZhang Yubing }; 321fb43630cSZhang Yubing 322fb43630cSZhang Yubing static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size) 323fb43630cSZhang Yubing { 324fb43630cSZhang Yubing size_t i, j; 325fb43630cSZhang Yubing 326fb43630cSZhang Yubing for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { 327fb43630cSZhang Yubing size_t num = min_t(size_t, size - i * 4, 4); 328fb43630cSZhang Yubing u32 value = 0; 329fb43630cSZhang Yubing 330fb43630cSZhang Yubing for (j = 0; j < num; j++) 331fb43630cSZhang Yubing value |= buffer[i * 4 + j] << (j * 8); 332fb43630cSZhang Yubing 333fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_AUX_DATA0 + i * 4, value); 334fb43630cSZhang Yubing } 335fb43630cSZhang Yubing 336fb43630cSZhang Yubing return size; 337fb43630cSZhang Yubing } 338fb43630cSZhang Yubing 339fb43630cSZhang Yubing static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size) 340fb43630cSZhang Yubing { 341fb43630cSZhang Yubing size_t i, j; 342fb43630cSZhang Yubing 343fb43630cSZhang Yubing for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { 344fb43630cSZhang Yubing size_t num = min_t(size_t, size - i * 4, 4); 345fb43630cSZhang Yubing u32 value; 346fb43630cSZhang Yubing 347fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_AUX_DATA0 + i * 4, &value); 348fb43630cSZhang Yubing 349fb43630cSZhang Yubing for (j = 0; j < num; j++) 350fb43630cSZhang Yubing buffer[i * 4 + j] = value >> (j * 8); 351fb43630cSZhang Yubing } 352fb43630cSZhang Yubing 353fb43630cSZhang Yubing return size; 354fb43630cSZhang Yubing } 355fb43630cSZhang Yubing 356fb43630cSZhang Yubing static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, 357fb43630cSZhang Yubing struct drm_dp_aux_msg *msg) 358fb43630cSZhang Yubing { 359fb43630cSZhang Yubing u32 status, value; 360fb43630cSZhang Yubing ssize_t ret = 0; 361fb43630cSZhang Yubing int timeout = 0; 362fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(aux->dev); 363fb43630cSZhang Yubing 364fb43630cSZhang Yubing if (WARN_ON(msg->size > 16)) 365fb43630cSZhang Yubing return -E2BIG; 366fb43630cSZhang Yubing 367fb43630cSZhang Yubing switch (msg->request & ~DP_AUX_I2C_MOT) { 368fb43630cSZhang Yubing case DP_AUX_NATIVE_WRITE: 369fb43630cSZhang Yubing case DP_AUX_I2C_WRITE: 370fb43630cSZhang Yubing case DP_AUX_I2C_WRITE_STATUS_UPDATE: 371fb43630cSZhang Yubing ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size); 372fb43630cSZhang Yubing if (ret < 0) 373fb43630cSZhang Yubing return ret; 374fb43630cSZhang Yubing break; 375fb43630cSZhang Yubing case DP_AUX_NATIVE_READ: 376fb43630cSZhang Yubing case DP_AUX_I2C_READ: 377fb43630cSZhang Yubing break; 378fb43630cSZhang Yubing default: 379fb43630cSZhang Yubing return -EINVAL; 380fb43630cSZhang Yubing } 381fb43630cSZhang Yubing 382fb43630cSZhang Yubing if (msg->size > 0) 383fb43630cSZhang Yubing value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1); 384fb43630cSZhang Yubing else 385fb43630cSZhang Yubing value = FIELD_PREP(I2C_ADDR_ONLY, 1); 386fb43630cSZhang Yubing 387fb43630cSZhang Yubing value |= FIELD_PREP(AUX_CMD_TYPE, msg->request); 388fb43630cSZhang Yubing value |= FIELD_PREP(AUX_ADDR, msg->address); 389fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_AUX_CMD, value); 390fb43630cSZhang Yubing 391fb43630cSZhang Yubing timeout = regmap_read_poll_timeout(dp->regmap, DPTX_GENERAL_INTERRUPT, 392fb43630cSZhang Yubing status, status & AUX_REPLY_EVENT, 393fb43630cSZhang Yubing 200, 10); 394fb43630cSZhang Yubing 395fb43630cSZhang Yubing if (timeout) { 396fb43630cSZhang Yubing printf("timeout waiting for AUX reply\n"); 397fb43630cSZhang Yubing return -ETIMEDOUT; 398fb43630cSZhang Yubing } 399fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_GENERAL_INTERRUPT, AUX_REPLY_EVENT); 400fb43630cSZhang Yubing 401fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_AUX_STATUS, &value); 402fb43630cSZhang Yubing if (value & AUX_TIMEOUT) { 403fb43630cSZhang Yubing printf("aux timeout\n"); 404fb43630cSZhang Yubing return -ETIMEDOUT; 405fb43630cSZhang Yubing } 406fb43630cSZhang Yubing 407fb43630cSZhang Yubing msg->reply = FIELD_GET(AUX_STATUS, value); 408fb43630cSZhang Yubing 409fb43630cSZhang Yubing if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) { 410fb43630cSZhang Yubing if (msg->request & DP_AUX_I2C_READ) { 411fb43630cSZhang Yubing size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1; 412fb43630cSZhang Yubing 413fb43630cSZhang Yubing if (count != msg->size) { 414fb43630cSZhang Yubing printf("aux fail to read %lu bytes\n", count); 415fb43630cSZhang Yubing return -EBUSY; 416fb43630cSZhang Yubing } 417fb43630cSZhang Yubing 418fb43630cSZhang Yubing ret = dw_dp_aux_read_data(dp, msg->buffer, count); 419fb43630cSZhang Yubing if (ret < 0) 420fb43630cSZhang Yubing return ret; 421fb43630cSZhang Yubing } 422fb43630cSZhang Yubing } 423fb43630cSZhang Yubing 424fb43630cSZhang Yubing return ret; 425fb43630cSZhang Yubing } 426fb43630cSZhang Yubing 427fb43630cSZhang Yubing static bool dw_dp_bandwidth_ok(struct dw_dp *dp, 428fb43630cSZhang Yubing const struct drm_display_mode *mode, u32 bpp, 429fb43630cSZhang Yubing unsigned int lanes, unsigned int rate) 430fb43630cSZhang Yubing { 431fb43630cSZhang Yubing u32 max_bw, req_bw; 432fb43630cSZhang Yubing 433fb43630cSZhang Yubing req_bw = mode->clock * bpp / 8; 434fb43630cSZhang Yubing max_bw = lanes * rate; 435fb43630cSZhang Yubing if (req_bw > max_bw) 436fb43630cSZhang Yubing return false; 437fb43630cSZhang Yubing 438fb43630cSZhang Yubing return true; 439fb43630cSZhang Yubing } 440fb43630cSZhang Yubing 441fb43630cSZhang Yubing static void dw_dp_hpd_init(struct dw_dp *dp) 442fb43630cSZhang Yubing { 4435fbef17aSZhang Yubing if (dm_gpio_is_valid(&dp->hpd_gpio) || dp->force_hpd) { 444fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD, 445fb43630cSZhang Yubing FIELD_PREP(FORCE_HPD, 1)); 446fb43630cSZhang Yubing return; 447fb43630cSZhang Yubing } 448fb43630cSZhang Yubing 449fb43630cSZhang Yubing /* Enable all HPD interrupts */ 450fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_HPD_INTERRUPT_ENABLE, 451fb43630cSZhang Yubing HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN, 452fb43630cSZhang Yubing FIELD_PREP(HPD_UNPLUG_EN, 1) | 453fb43630cSZhang Yubing FIELD_PREP(HPD_PLUG_EN, 1) | 454fb43630cSZhang Yubing FIELD_PREP(HPD_IRQ_EN, 1)); 455fb43630cSZhang Yubing 456fb43630cSZhang Yubing /* Enable all top-level interrupts */ 457fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE, 458fb43630cSZhang Yubing HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1)); 459fb43630cSZhang Yubing } 460fb43630cSZhang Yubing 461fb43630cSZhang Yubing static void dw_dp_aux_init(struct dw_dp *dp) 462fb43630cSZhang Yubing { 463fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET, 464fb43630cSZhang Yubing FIELD_PREP(AUX_RESET, 1)); 465fb43630cSZhang Yubing udelay(10); 466fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET, 467fb43630cSZhang Yubing FIELD_PREP(AUX_RESET, 0)); 468fb43630cSZhang Yubing 469fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE, 470fb43630cSZhang Yubing AUX_REPLY_EVENT_EN, 471fb43630cSZhang Yubing FIELD_PREP(AUX_REPLY_EVENT_EN, 1)); 472fb43630cSZhang Yubing } 473fb43630cSZhang Yubing 474fb43630cSZhang Yubing static void dw_dp_init(struct dw_dp *dp) 475fb43630cSZhang Yubing { 476fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET, 477fb43630cSZhang Yubing FIELD_PREP(CONTROLLER_RESET, 1)); 478fb43630cSZhang Yubing udelay(10); 479fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET, 480fb43630cSZhang Yubing FIELD_PREP(CONTROLLER_RESET, 0)); 481fb43630cSZhang Yubing 482fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET, 483fb43630cSZhang Yubing FIELD_PREP(PHY_SOFT_RESET, 1)); 484fb43630cSZhang Yubing udelay(10); 485fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET, 486fb43630cSZhang Yubing FIELD_PREP(PHY_SOFT_RESET, 0)); 487fb43630cSZhang Yubing 488fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, DEFAULT_FAST_LINK_TRAIN_EN, 489fb43630cSZhang Yubing FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0)); 490fb43630cSZhang Yubing 491fb43630cSZhang Yubing dw_dp_hpd_init(dp); 492fb43630cSZhang Yubing dw_dp_aux_init(dp); 493fb43630cSZhang Yubing } 494fb43630cSZhang Yubing 495fb43630cSZhang Yubing static void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern) 496fb43630cSZhang Yubing { 497fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, TPS_SEL, 498fb43630cSZhang Yubing FIELD_PREP(TPS_SEL, pattern)); 499fb43630cSZhang Yubing } 500fb43630cSZhang Yubing 501fb43630cSZhang Yubing static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes) 502fb43630cSZhang Yubing { 503fb43630cSZhang Yubing u32 xmit_enable; 504fb43630cSZhang Yubing 505fb43630cSZhang Yubing switch (lanes) { 506fb43630cSZhang Yubing case 4: 507fb43630cSZhang Yubing case 2: 508fb43630cSZhang Yubing case 1: 509fb43630cSZhang Yubing xmit_enable = GENMASK(lanes - 1, 0); 510fb43630cSZhang Yubing break; 511fb43630cSZhang Yubing case 0: 512fb43630cSZhang Yubing default: 513fb43630cSZhang Yubing xmit_enable = 0; 514fb43630cSZhang Yubing break; 515fb43630cSZhang Yubing } 516fb43630cSZhang Yubing 517fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, XMIT_ENABLE, 518fb43630cSZhang Yubing FIELD_PREP(XMIT_ENABLE, xmit_enable)); 519fb43630cSZhang Yubing } 520fb43630cSZhang Yubing 521fb43630cSZhang Yubing static int dw_dp_link_power_up(struct dw_dp *dp) 522fb43630cSZhang Yubing { 523fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 524fb43630cSZhang Yubing u8 value; 525fb43630cSZhang Yubing int ret; 526fb43630cSZhang Yubing 527fb43630cSZhang Yubing if (link->revision < 0x11) 528fb43630cSZhang Yubing return 0; 529fb43630cSZhang Yubing 530fb43630cSZhang Yubing ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); 531fb43630cSZhang Yubing if (ret < 0) 532fb43630cSZhang Yubing return ret; 533fb43630cSZhang Yubing 534fb43630cSZhang Yubing value &= ~DP_SET_POWER_MASK; 535fb43630cSZhang Yubing value |= DP_SET_POWER_D0; 536fb43630cSZhang Yubing 537fb43630cSZhang Yubing ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); 538fb43630cSZhang Yubing if (ret < 0) 539fb43630cSZhang Yubing return ret; 540fb43630cSZhang Yubing 541fb43630cSZhang Yubing udelay(1000); 542fb43630cSZhang Yubing return 0; 543fb43630cSZhang Yubing } 544fb43630cSZhang Yubing 545fb43630cSZhang Yubing static int dw_dp_link_probe(struct dw_dp *dp) 546fb43630cSZhang Yubing { 547fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 548fb43630cSZhang Yubing u8 dpcd; 549fb43630cSZhang Yubing int ret; 550fb43630cSZhang Yubing 551fb43630cSZhang Yubing ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd); 552fb43630cSZhang Yubing if (ret < 0) 553fb43630cSZhang Yubing return ret; 554fb43630cSZhang Yubing 555fb43630cSZhang Yubing ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, 556fb43630cSZhang Yubing &dpcd); 557fb43630cSZhang Yubing if (ret < 0) 558fb43630cSZhang Yubing return ret; 559fb43630cSZhang Yubing 560fb43630cSZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported = 561fb43630cSZhang Yubing !!(dpcd & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED); 562fb43630cSZhang Yubing 563fb43630cSZhang Yubing link->revision = link->dpcd[DP_DPCD_REV]; 564fb43630cSZhang Yubing link->rate = drm_dp_max_link_rate(link->dpcd); 565fb43630cSZhang Yubing link->lanes = min_t(u8, dp->phy.attrs.bus_width, 566fb43630cSZhang Yubing drm_dp_max_lane_count(link->dpcd)); 567fb43630cSZhang Yubing 568fb43630cSZhang Yubing link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd); 569fb43630cSZhang Yubing link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd); 570fb43630cSZhang Yubing link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd); 571fb43630cSZhang Yubing link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd); 572fb43630cSZhang Yubing link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] & 573fb43630cSZhang Yubing DP_MAX_DOWNSPREAD_0_5); 574fb43630cSZhang Yubing 575fb43630cSZhang Yubing return 0; 576fb43630cSZhang Yubing } 577fb43630cSZhang Yubing 578fb43630cSZhang Yubing static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp) 579fb43630cSZhang Yubing { 580fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 581fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &link->train.request; 582fb43630cSZhang Yubing union phy_configure_opts phy_cfg; 583fb43630cSZhang Yubing unsigned int lanes = link->lanes, *vs, *pe; 584fb43630cSZhang Yubing u8 buf[4]; 585fb43630cSZhang Yubing int i, ret; 586fb43630cSZhang Yubing 587fb43630cSZhang Yubing vs = request->voltage_swing; 588fb43630cSZhang Yubing pe = request->pre_emphasis; 589fb43630cSZhang Yubing 590fb43630cSZhang Yubing for (i = 0; i < lanes; i++) { 591fb43630cSZhang Yubing phy_cfg.dp.voltage[i] = vs[i]; 592fb43630cSZhang Yubing phy_cfg.dp.pre[i] = pe[i]; 593fb43630cSZhang Yubing } 594fb43630cSZhang Yubing phy_cfg.dp.lanes = lanes; 595fb43630cSZhang Yubing phy_cfg.dp.link_rate = link->rate / 100; 596fb43630cSZhang Yubing phy_cfg.dp.set_lanes = false; 597fb43630cSZhang Yubing phy_cfg.dp.set_rate = false; 598fb43630cSZhang Yubing phy_cfg.dp.set_voltages = true; 599fb43630cSZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg); 600fb43630cSZhang Yubing if (ret) 601fb43630cSZhang Yubing return ret; 602fb43630cSZhang Yubing 603fb43630cSZhang Yubing for (i = 0; i < lanes; i++) 604fb43630cSZhang Yubing buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) | 605fb43630cSZhang Yubing (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT); 606fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes); 607fb43630cSZhang Yubing if (ret < 0) 608fb43630cSZhang Yubing return ret; 609fb43630cSZhang Yubing 610fb43630cSZhang Yubing return 0; 611fb43630cSZhang Yubing } 612fb43630cSZhang Yubing 613fb43630cSZhang Yubing static int dw_dp_link_configure(struct dw_dp *dp) 614fb43630cSZhang Yubing { 615fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 616fb43630cSZhang Yubing union phy_configure_opts phy_cfg; 617fb43630cSZhang Yubing u8 buf[2]; 6185efdd3e2SZhang Yubing int ret, phy_rate; 619fb43630cSZhang Yubing 620fb43630cSZhang Yubing /* Move PHY to P3 */ 621fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 622fb43630cSZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x3)); 623fb43630cSZhang Yubing 624fb43630cSZhang Yubing phy_cfg.dp.lanes = link->lanes; 625fb43630cSZhang Yubing phy_cfg.dp.link_rate = link->rate / 100; 626fb43630cSZhang Yubing phy_cfg.dp.ssc = link->caps.ssc; 627fb43630cSZhang Yubing phy_cfg.dp.set_lanes = true; 628fb43630cSZhang Yubing phy_cfg.dp.set_rate = true; 629fb43630cSZhang Yubing phy_cfg.dp.set_voltages = false; 630fb43630cSZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg); 631fb43630cSZhang Yubing if (ret) 632fb43630cSZhang Yubing return ret; 633fb43630cSZhang Yubing 634fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES, 635fb43630cSZhang Yubing FIELD_PREP(PHY_LANES, link->lanes / 2)); 636fb43630cSZhang Yubing 6375efdd3e2SZhang Yubing switch (link->rate) { 6385efdd3e2SZhang Yubing case 810000: 6395efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR3; 6405efdd3e2SZhang Yubing break; 6415efdd3e2SZhang Yubing case 540000: 6425efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR2; 6435efdd3e2SZhang Yubing break; 6445efdd3e2SZhang Yubing case 270000: 6455efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR; 6465efdd3e2SZhang Yubing break; 6475efdd3e2SZhang Yubing case 162000: 6485efdd3e2SZhang Yubing default: 6495efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_RBR; 6505efdd3e2SZhang Yubing break; 6515efdd3e2SZhang Yubing } 6525efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE, 6535efdd3e2SZhang Yubing FIELD_PREP(PHY_RATE, phy_rate)); 6545efdd3e2SZhang Yubing 655fb43630cSZhang Yubing /* Move PHY to P0 */ 656fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 657fb43630cSZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x0)); 658fb43630cSZhang Yubing 659fb43630cSZhang Yubing dw_dp_phy_xmit_enable(dp, link->lanes); 660fb43630cSZhang Yubing 661fb43630cSZhang Yubing buf[0] = drm_dp_link_rate_to_bw_code(link->rate); 662fb43630cSZhang Yubing buf[1] = link->lanes; 663fb43630cSZhang Yubing 664fb43630cSZhang Yubing if (link->caps.enhanced_framing) { 665fb43630cSZhang Yubing buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; 666fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, 667fb43630cSZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 1)); 668fb43630cSZhang Yubing } else { 669fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, 670fb43630cSZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 0)); 671fb43630cSZhang Yubing } 672fb43630cSZhang Yubing 673fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf)); 674fb43630cSZhang Yubing if (ret < 0) 675fb43630cSZhang Yubing return ret; 676fb43630cSZhang Yubing 677fb43630cSZhang Yubing buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0; 678fb43630cSZhang Yubing buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0; 679fb43630cSZhang Yubing 680fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, 681fb43630cSZhang Yubing sizeof(buf)); 682fb43630cSZhang Yubing if (ret < 0) 683fb43630cSZhang Yubing return ret; 684fb43630cSZhang Yubing 685fb43630cSZhang Yubing return 0; 686fb43630cSZhang Yubing } 687fb43630cSZhang Yubing 688fb43630cSZhang Yubing static void dw_dp_link_train_init(struct drm_dp_link_train *train) 689fb43630cSZhang Yubing { 690fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &train->request; 691fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &train->adjust; 692fb43630cSZhang Yubing unsigned int i; 693fb43630cSZhang Yubing 694fb43630cSZhang Yubing for (i = 0; i < 4; i++) { 695fb43630cSZhang Yubing request->voltage_swing[i] = 0; 696fb43630cSZhang Yubing adjust->voltage_swing[i] = 0; 697fb43630cSZhang Yubing 698fb43630cSZhang Yubing request->pre_emphasis[i] = 0; 699fb43630cSZhang Yubing adjust->pre_emphasis[i] = 0; 700fb43630cSZhang Yubing } 701fb43630cSZhang Yubing 702fb43630cSZhang Yubing train->clock_recovered = false; 703fb43630cSZhang Yubing train->channel_equalized = false; 704fb43630cSZhang Yubing } 705fb43630cSZhang Yubing 706fb43630cSZhang Yubing static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern) 707fb43630cSZhang Yubing { 708fb43630cSZhang Yubing u8 buf = 0; 709fb43630cSZhang Yubing int ret; 710fb43630cSZhang Yubing 711fb43630cSZhang Yubing if (pattern && pattern != DP_TRAINING_PATTERN_4) { 712fb43630cSZhang Yubing buf |= DP_LINK_SCRAMBLING_DISABLE; 713fb43630cSZhang Yubing 714fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS, 715fb43630cSZhang Yubing FIELD_PREP(SCRAMBLE_DIS, 1)); 716fb43630cSZhang Yubing } else { 717fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS, 718fb43630cSZhang Yubing FIELD_PREP(SCRAMBLE_DIS, 0)); 719fb43630cSZhang Yubing } 720fb43630cSZhang Yubing 721fb43630cSZhang Yubing switch (pattern) { 722fb43630cSZhang Yubing case DP_TRAINING_PATTERN_DISABLE: 723fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE); 724fb43630cSZhang Yubing break; 725fb43630cSZhang Yubing case DP_TRAINING_PATTERN_1: 726fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_1); 727fb43630cSZhang Yubing break; 728fb43630cSZhang Yubing case DP_TRAINING_PATTERN_2: 729fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_2); 730fb43630cSZhang Yubing break; 731fb43630cSZhang Yubing case DP_TRAINING_PATTERN_3: 732fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_3); 733fb43630cSZhang Yubing break; 734fb43630cSZhang Yubing case DP_TRAINING_PATTERN_4: 735fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_4); 736fb43630cSZhang Yubing break; 737fb43630cSZhang Yubing default: 738fb43630cSZhang Yubing return -EINVAL; 739fb43630cSZhang Yubing } 740fb43630cSZhang Yubing 741fb43630cSZhang Yubing ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 742fb43630cSZhang Yubing buf | pattern); 743fb43630cSZhang Yubing if (ret < 0) 744fb43630cSZhang Yubing return ret; 745fb43630cSZhang Yubing 746fb43630cSZhang Yubing return 0; 747fb43630cSZhang Yubing } 748fb43630cSZhang Yubing 749fb43630cSZhang Yubing static void dw_dp_link_get_adjustments(struct dw_dp_link *link, 750fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE]) 751fb43630cSZhang Yubing { 752fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &link->train.adjust; 753fb43630cSZhang Yubing unsigned int i; 754fb43630cSZhang Yubing 755fb43630cSZhang Yubing for (i = 0; i < link->lanes; i++) { 756fb43630cSZhang Yubing adjust->voltage_swing[i] = 757fb43630cSZhang Yubing drm_dp_get_adjust_request_voltage(status, i) >> 758fb43630cSZhang Yubing DP_TRAIN_VOLTAGE_SWING_SHIFT; 759fb43630cSZhang Yubing 760fb43630cSZhang Yubing adjust->pre_emphasis[i] = 761fb43630cSZhang Yubing drm_dp_get_adjust_request_pre_emphasis(status, i) >> 762fb43630cSZhang Yubing DP_TRAIN_PRE_EMPHASIS_SHIFT; 763fb43630cSZhang Yubing } 764fb43630cSZhang Yubing } 765fb43630cSZhang Yubing 766fb43630cSZhang Yubing static void dw_dp_link_train_adjust(struct drm_dp_link_train *train) 767fb43630cSZhang Yubing { 768fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &train->request; 769fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &train->adjust; 770fb43630cSZhang Yubing unsigned int i; 771fb43630cSZhang Yubing 772fb43630cSZhang Yubing for (i = 0; i < 4; i++) 773fb43630cSZhang Yubing if (request->voltage_swing[i] != adjust->voltage_swing[i]) 774fb43630cSZhang Yubing request->voltage_swing[i] = adjust->voltage_swing[i]; 775fb43630cSZhang Yubing 776fb43630cSZhang Yubing for (i = 0; i < 4; i++) 777fb43630cSZhang Yubing if (request->pre_emphasis[i] != adjust->pre_emphasis[i]) 778fb43630cSZhang Yubing request->pre_emphasis[i] = adjust->pre_emphasis[i]; 779fb43630cSZhang Yubing } 780fb43630cSZhang Yubing 781fb43630cSZhang Yubing static int dw_dp_link_clock_recovery(struct dw_dp *dp) 782fb43630cSZhang Yubing { 783fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 784fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE]; 785fb43630cSZhang Yubing unsigned int tries = 0; 786fb43630cSZhang Yubing int ret; 787fb43630cSZhang Yubing 788fb43630cSZhang Yubing ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1); 789fb43630cSZhang Yubing if (ret) 790fb43630cSZhang Yubing return ret; 791fb43630cSZhang Yubing 792fb43630cSZhang Yubing for (;;) { 793fb43630cSZhang Yubing ret = dw_dp_link_train_update_vs_emph(dp); 794fb43630cSZhang Yubing if (ret) 795fb43630cSZhang Yubing return ret; 796fb43630cSZhang Yubing 797fb43630cSZhang Yubing drm_dp_link_train_clock_recovery_delay(link->dpcd); 798fb43630cSZhang Yubing 799fb43630cSZhang Yubing ret = drm_dp_dpcd_read_link_status(&dp->aux, status); 800fb43630cSZhang Yubing if (ret < 0) { 801fb43630cSZhang Yubing dev_err(dp->dev, "failed to read link status: %d\n", 802fb43630cSZhang Yubing ret); 803fb43630cSZhang Yubing return ret; 804fb43630cSZhang Yubing } 805fb43630cSZhang Yubing 806fb43630cSZhang Yubing if (drm_dp_clock_recovery_ok(status, link->lanes)) { 807fb43630cSZhang Yubing link->train.clock_recovered = true; 808fb43630cSZhang Yubing break; 809fb43630cSZhang Yubing } 810fb43630cSZhang Yubing 811fb43630cSZhang Yubing dw_dp_link_get_adjustments(link, status); 812fb43630cSZhang Yubing 813fb43630cSZhang Yubing if (link->train.request.voltage_swing[0] == 814fb43630cSZhang Yubing link->train.adjust.voltage_swing[0]) 815fb43630cSZhang Yubing tries++; 816fb43630cSZhang Yubing else 817fb43630cSZhang Yubing tries = 0; 818fb43630cSZhang Yubing 819fb43630cSZhang Yubing if (tries == 5) 820fb43630cSZhang Yubing break; 821fb43630cSZhang Yubing 822fb43630cSZhang Yubing dw_dp_link_train_adjust(&link->train); 823fb43630cSZhang Yubing } 824fb43630cSZhang Yubing 825fb43630cSZhang Yubing return 0; 826fb43630cSZhang Yubing } 827fb43630cSZhang Yubing 828fb43630cSZhang Yubing static int dw_dp_link_channel_equalization(struct dw_dp *dp) 829fb43630cSZhang Yubing { 830fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 831fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE], pattern; 832fb43630cSZhang Yubing unsigned int tries; 833fb43630cSZhang Yubing int ret; 834fb43630cSZhang Yubing 835fb43630cSZhang Yubing if (link->caps.tps4_supported) 836fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_4; 837fb43630cSZhang Yubing else if (link->caps.tps3_supported) 838fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_3; 839fb43630cSZhang Yubing else 840fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_2; 841fb43630cSZhang Yubing ret = dw_dp_link_train_set_pattern(dp, pattern); 842fb43630cSZhang Yubing if (ret) 843fb43630cSZhang Yubing return ret; 844fb43630cSZhang Yubing 845fb43630cSZhang Yubing for (tries = 1; tries < 5; tries++) { 846fb43630cSZhang Yubing ret = dw_dp_link_train_update_vs_emph(dp); 847fb43630cSZhang Yubing if (ret) 848fb43630cSZhang Yubing return ret; 849fb43630cSZhang Yubing 850fb43630cSZhang Yubing drm_dp_link_train_channel_eq_delay(link->dpcd); 851fb43630cSZhang Yubing 852fb43630cSZhang Yubing ret = drm_dp_dpcd_read_link_status(&dp->aux, status); 853fb43630cSZhang Yubing if (ret < 0) 854fb43630cSZhang Yubing return ret; 855fb43630cSZhang Yubing 856fb43630cSZhang Yubing if (!drm_dp_clock_recovery_ok(status, link->lanes)) { 857fb43630cSZhang Yubing dev_err(dp->dev, 858fb43630cSZhang Yubing "clock recovery lost while eq\n"); 859fb43630cSZhang Yubing link->train.clock_recovered = false; 860fb43630cSZhang Yubing break; 861fb43630cSZhang Yubing } 862fb43630cSZhang Yubing 863fb43630cSZhang Yubing if (drm_dp_channel_eq_ok(status, link->lanes)) { 864fb43630cSZhang Yubing link->train.channel_equalized = true; 865fb43630cSZhang Yubing break; 866fb43630cSZhang Yubing } 867fb43630cSZhang Yubing 868fb43630cSZhang Yubing dw_dp_link_get_adjustments(link, status); 869fb43630cSZhang Yubing dw_dp_link_train_adjust(&link->train); 870fb43630cSZhang Yubing } 871fb43630cSZhang Yubing 872fb43630cSZhang Yubing return 0; 873fb43630cSZhang Yubing } 874fb43630cSZhang Yubing 875fb43630cSZhang Yubing static int dw_dp_link_downgrade(struct dw_dp *dp) 876fb43630cSZhang Yubing { 877fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 878fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 879fb43630cSZhang Yubing 880fb43630cSZhang Yubing switch (link->rate) { 881fb43630cSZhang Yubing case 162000: 882fb43630cSZhang Yubing return -EINVAL; 883fb43630cSZhang Yubing case 270000: 884fb43630cSZhang Yubing link->rate = 162000; 885fb43630cSZhang Yubing break; 886fb43630cSZhang Yubing case 540000: 887fb43630cSZhang Yubing link->rate = 270000; 888fb43630cSZhang Yubing break; 889fb43630cSZhang Yubing case 810000: 890fb43630cSZhang Yubing link->rate = 540000; 891fb43630cSZhang Yubing break; 892fb43630cSZhang Yubing } 893fb43630cSZhang Yubing 894fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, &video->mode, video->bpp, link->lanes, 895fb43630cSZhang Yubing link->rate)) 896fb43630cSZhang Yubing return -E2BIG; 897fb43630cSZhang Yubing 898fb43630cSZhang Yubing return 0; 899fb43630cSZhang Yubing } 900fb43630cSZhang Yubing 901fb43630cSZhang Yubing static int dw_dp_link_train(struct dw_dp *dp) 902fb43630cSZhang Yubing { 903fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 904fb43630cSZhang Yubing int ret; 905fb43630cSZhang Yubing 906fb43630cSZhang Yubing retry: 907fb43630cSZhang Yubing dw_dp_link_train_init(&link->train); 908fb43630cSZhang Yubing 909fb43630cSZhang Yubing printf("training link: %u lane%s at %u MHz\n", 910fb43630cSZhang Yubing link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100); 911fb43630cSZhang Yubing 912fb43630cSZhang Yubing ret = dw_dp_link_configure(dp); 913fb43630cSZhang Yubing if (ret < 0) { 914fb43630cSZhang Yubing dev_err(dp->dev, "failed to configure DP link: %d\n", ret); 915fb43630cSZhang Yubing return ret; 916fb43630cSZhang Yubing } 917fb43630cSZhang Yubing 918fb43630cSZhang Yubing ret = dw_dp_link_clock_recovery(dp); 919fb43630cSZhang Yubing if (ret < 0) { 920fb43630cSZhang Yubing dev_err(dp->dev, "clock recovery failed: %d\n", ret); 921fb43630cSZhang Yubing goto out; 922fb43630cSZhang Yubing } 923fb43630cSZhang Yubing 924fb43630cSZhang Yubing if (!link->train.clock_recovered) { 925fb43630cSZhang Yubing dev_err(dp->dev, "clock recovery failed, downgrading link\n"); 926fb43630cSZhang Yubing 927fb43630cSZhang Yubing ret = dw_dp_link_downgrade(dp); 928fb43630cSZhang Yubing if (ret < 0) 929fb43630cSZhang Yubing goto out; 930fb43630cSZhang Yubing else 931fb43630cSZhang Yubing goto retry; 932fb43630cSZhang Yubing } 933fb43630cSZhang Yubing 934fb43630cSZhang Yubing printf("clock recovery succeeded\n"); 935fb43630cSZhang Yubing 936fb43630cSZhang Yubing ret = dw_dp_link_channel_equalization(dp); 937fb43630cSZhang Yubing if (ret < 0) { 938fb43630cSZhang Yubing dev_err(dp->dev, "channel equalization failed: %d\n", ret); 939fb43630cSZhang Yubing goto out; 940fb43630cSZhang Yubing } 941fb43630cSZhang Yubing 942fb43630cSZhang Yubing if (!link->train.channel_equalized) { 943fb43630cSZhang Yubing dev_err(dp->dev, 944fb43630cSZhang Yubing "channel equalization failed, downgrading link\n"); 945fb43630cSZhang Yubing 946fb43630cSZhang Yubing ret = dw_dp_link_downgrade(dp); 947fb43630cSZhang Yubing if (ret < 0) 948fb43630cSZhang Yubing goto out; 949fb43630cSZhang Yubing else 950fb43630cSZhang Yubing goto retry; 951fb43630cSZhang Yubing } 952fb43630cSZhang Yubing 953fb43630cSZhang Yubing printf("channel equalization succeeded\n"); 954fb43630cSZhang Yubing 955fb43630cSZhang Yubing out: 956fb43630cSZhang Yubing dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); 957fb43630cSZhang Yubing return ret; 958fb43630cSZhang Yubing } 959fb43630cSZhang Yubing 960fb43630cSZhang Yubing static int dw_dp_link_enable(struct dw_dp *dp) 961fb43630cSZhang Yubing { 962fb43630cSZhang Yubing int ret; 963fb43630cSZhang Yubing 964fb43630cSZhang Yubing ret = dw_dp_link_power_up(dp); 965fb43630cSZhang Yubing if (ret < 0) 966fb43630cSZhang Yubing return ret; 967fb43630cSZhang Yubing 968fb43630cSZhang Yubing ret = dw_dp_link_train(dp); 969fb43630cSZhang Yubing if (ret < 0) { 970fb43630cSZhang Yubing dev_err(dp->dev, "link training failed: %d\n", ret); 971fb43630cSZhang Yubing return ret; 972fb43630cSZhang Yubing } 973fb43630cSZhang Yubing 974fb43630cSZhang Yubing return 0; 975fb43630cSZhang Yubing } 976fb43630cSZhang Yubing 9775efdd3e2SZhang Yubing static int dw_dp_set_phy_default_config(struct dw_dp *dp) 9785efdd3e2SZhang Yubing { 9795efdd3e2SZhang Yubing struct dw_dp_link *link = &dp->link; 9805efdd3e2SZhang Yubing union phy_configure_opts phy_cfg; 9815efdd3e2SZhang Yubing int ret, i, phy_rate; 9825efdd3e2SZhang Yubing 9835efdd3e2SZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported = false; 9845efdd3e2SZhang Yubing link->rate = 270000; 9855efdd3e2SZhang Yubing link->lanes = dp->phy.attrs.bus_width; 9865efdd3e2SZhang Yubing 9875efdd3e2SZhang Yubing link->caps.enhanced_framing = true; 9885efdd3e2SZhang Yubing link->caps.channel_coding = true; 9895efdd3e2SZhang Yubing link->caps.ssc = true; 9905efdd3e2SZhang Yubing 9915efdd3e2SZhang Yubing /* Move PHY to P3 */ 9925efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 9935efdd3e2SZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x3)); 9945efdd3e2SZhang Yubing 9955efdd3e2SZhang Yubing for (i = 0; i < link->lanes; i++) { 9965efdd3e2SZhang Yubing phy_cfg.dp.voltage[i] = 3; 9975efdd3e2SZhang Yubing phy_cfg.dp.pre[i] = 0; 9985efdd3e2SZhang Yubing } 9995efdd3e2SZhang Yubing phy_cfg.dp.lanes = link->lanes; 10005efdd3e2SZhang Yubing phy_cfg.dp.link_rate = link->rate / 100; 10015efdd3e2SZhang Yubing phy_cfg.dp.ssc = link->caps.ssc; 10025efdd3e2SZhang Yubing phy_cfg.dp.set_lanes = true; 10035efdd3e2SZhang Yubing phy_cfg.dp.set_rate = true; 10045efdd3e2SZhang Yubing phy_cfg.dp.set_voltages = true; 10055efdd3e2SZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg); 10065efdd3e2SZhang Yubing if (ret) 10075efdd3e2SZhang Yubing return ret; 10085efdd3e2SZhang Yubing 10095efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES, 10105efdd3e2SZhang Yubing FIELD_PREP(PHY_LANES, link->lanes / 2)); 10115efdd3e2SZhang Yubing 10125efdd3e2SZhang Yubing switch (link->rate) { 10135efdd3e2SZhang Yubing case 810000: 10145efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR3; 10155efdd3e2SZhang Yubing break; 10165efdd3e2SZhang Yubing case 540000: 10175efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR2; 10185efdd3e2SZhang Yubing break; 10195efdd3e2SZhang Yubing case 270000: 10205efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR; 10215efdd3e2SZhang Yubing break; 10225efdd3e2SZhang Yubing case 162000: 10235efdd3e2SZhang Yubing default: 10245efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_RBR; 10255efdd3e2SZhang Yubing break; 10265efdd3e2SZhang Yubing } 10275efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE, 10285efdd3e2SZhang Yubing FIELD_PREP(PHY_RATE, phy_rate)); 10295efdd3e2SZhang Yubing 10305efdd3e2SZhang Yubing /* Move PHY to P0 */ 10315efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 10325efdd3e2SZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x0)); 10335efdd3e2SZhang Yubing 10345efdd3e2SZhang Yubing dw_dp_phy_xmit_enable(dp, link->lanes); 10355efdd3e2SZhang Yubing 10365efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, 10375efdd3e2SZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 1)); 10385efdd3e2SZhang Yubing 10395efdd3e2SZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE); 10405efdd3e2SZhang Yubing return 0; 10415efdd3e2SZhang Yubing } 10425efdd3e2SZhang Yubing 1043fb43630cSZhang Yubing static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp) 1044fb43630cSZhang Yubing { 1045fb43630cSZhang Yubing const u8 *payload = sdp->db; 1046fb43630cSZhang Yubing u32 reg; 1047fb43630cSZhang Yubing int i, nr = 0; 1048fb43630cSZhang Yubing 1049fb43630cSZhang Yubing reg = DPTX_SDP_REGISTER_BANK + nr * 9 * 4; 1050fb43630cSZhang Yubing 1051fb43630cSZhang Yubing /* SDP header */ 1052fb43630cSZhang Yubing regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->header)); 1053fb43630cSZhang Yubing 1054fb43630cSZhang Yubing /* SDP data payload */ 1055fb43630cSZhang Yubing for (i = 1; i < 9; i++, payload += 4) 1056fb43630cSZhang Yubing regmap_write(dp->regmap, reg + i * 4, 1057fb43630cSZhang Yubing FIELD_PREP(SDP_REGS, get_unaligned_le32(payload))); 1058fb43630cSZhang Yubing 1059fb43630cSZhang Yubing if (sdp->flags & DPTX_SDP_VERTICAL_INTERVAL) 1060fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL, 1061fb43630cSZhang Yubing EN_VERTICAL_SDP << nr, 1062fb43630cSZhang Yubing EN_VERTICAL_SDP << nr); 1063fb43630cSZhang Yubing 1064fb43630cSZhang Yubing if (sdp->flags & DPTX_SDP_HORIZONTAL_INTERVAL) 1065fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL, 1066fb43630cSZhang Yubing EN_HORIZONTAL_SDP << nr, 1067fb43630cSZhang Yubing EN_HORIZONTAL_SDP << nr); 1068fb43630cSZhang Yubing 1069fb43630cSZhang Yubing return 0; 1070fb43630cSZhang Yubing } 1071fb43630cSZhang Yubing 1072fb43630cSZhang Yubing static void dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc, 1073fb43630cSZhang Yubing struct dw_dp_sdp *sdp) 1074fb43630cSZhang Yubing { 1075fb43630cSZhang Yubing sdp->header.HB0 = 0; 1076fb43630cSZhang Yubing sdp->header.HB1 = DP_SDP_VSC; 1077fb43630cSZhang Yubing sdp->header.HB2 = vsc->revision; 1078fb43630cSZhang Yubing sdp->header.HB3 = vsc->length; 1079fb43630cSZhang Yubing 1080fb43630cSZhang Yubing sdp->db[16] = (vsc->pixelformat & 0xf) << 4; 1081fb43630cSZhang Yubing sdp->db[16] |= vsc->colorimetry & 0xf; 1082fb43630cSZhang Yubing 1083fb43630cSZhang Yubing switch (vsc->bpc) { 1084fb43630cSZhang Yubing case 8: 1085fb43630cSZhang Yubing sdp->db[17] = 0x1; 1086fb43630cSZhang Yubing break; 1087fb43630cSZhang Yubing case 10: 1088fb43630cSZhang Yubing sdp->db[17] = 0x2; 1089fb43630cSZhang Yubing break; 1090fb43630cSZhang Yubing case 12: 1091fb43630cSZhang Yubing sdp->db[17] = 0x3; 1092fb43630cSZhang Yubing break; 1093fb43630cSZhang Yubing case 16: 1094fb43630cSZhang Yubing sdp->db[17] = 0x4; 1095fb43630cSZhang Yubing break; 1096fb43630cSZhang Yubing case 6: 1097fb43630cSZhang Yubing default: 1098fb43630cSZhang Yubing break; 1099fb43630cSZhang Yubing } 1100fb43630cSZhang Yubing 1101fb43630cSZhang Yubing if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA) 1102fb43630cSZhang Yubing sdp->db[17] |= 0x80; 1103fb43630cSZhang Yubing 1104fb43630cSZhang Yubing sdp->db[18] = vsc->content_type & 0x7; 1105fb43630cSZhang Yubing 1106fb43630cSZhang Yubing sdp->flags |= DPTX_SDP_VERTICAL_INTERVAL; 1107fb43630cSZhang Yubing } 1108fb43630cSZhang Yubing 1109fb43630cSZhang Yubing static int dw_dp_send_vsc_sdp(struct dw_dp *dp) 1110fb43630cSZhang Yubing { 1111fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 1112fb43630cSZhang Yubing struct drm_dp_vsc_sdp vsc = {}; 1113fb43630cSZhang Yubing struct dw_dp_sdp sdp = {}; 1114fb43630cSZhang Yubing 1115fb43630cSZhang Yubing vsc.revision = 0x5; 1116fb43630cSZhang Yubing vsc.length = 0x13; 1117fb43630cSZhang Yubing 1118fb43630cSZhang Yubing switch (video->color_format) { 1119fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444: 1120fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV444; 1121fb43630cSZhang Yubing break; 1122fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420: 1123fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV420; 1124fb43630cSZhang Yubing break; 1125fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422: 1126fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV422; 1127fb43630cSZhang Yubing break; 1128fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444: 1129fb43630cSZhang Yubing default: 1130fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_RGB; 1131fb43630cSZhang Yubing break; 1132fb43630cSZhang Yubing } 1133fb43630cSZhang Yubing 1134fb43630cSZhang Yubing if (video->color_format == DRM_COLOR_FORMAT_RGB444) 1135fb43630cSZhang Yubing vsc.colorimetry = DP_COLORIMETRY_DEFAULT; 1136fb43630cSZhang Yubing else 1137fb43630cSZhang Yubing vsc.colorimetry = DP_COLORIMETRY_BT709_YCC; 1138fb43630cSZhang Yubing 1139fb43630cSZhang Yubing vsc.bpc = video->bpc; 1140fb43630cSZhang Yubing vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA; 1141fb43630cSZhang Yubing vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED; 1142fb43630cSZhang Yubing 1143fb43630cSZhang Yubing dw_dp_vsc_sdp_pack(&vsc, &sdp); 1144fb43630cSZhang Yubing 1145fb43630cSZhang Yubing return dw_dp_send_sdp(dp, &sdp); 1146fb43630cSZhang Yubing } 1147fb43630cSZhang Yubing 1148fb43630cSZhang Yubing static int dw_dp_video_set_pixel_mode(struct dw_dp *dp, u8 pixel_mode) 1149fb43630cSZhang Yubing { 1150fb43630cSZhang Yubing switch (pixel_mode) { 1151fb43630cSZhang Yubing case DPTX_MP_SINGLE_PIXEL: 1152fb43630cSZhang Yubing case DPTX_MP_DUAL_PIXEL: 1153fb43630cSZhang Yubing case DPTX_MP_QUAD_PIXEL: 1154fb43630cSZhang Yubing break; 1155fb43630cSZhang Yubing default: 1156fb43630cSZhang Yubing return -EINVAL; 1157fb43630cSZhang Yubing } 1158fb43630cSZhang Yubing 1159fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, PIXEL_MODE_SELECT, 1160fb43630cSZhang Yubing FIELD_PREP(PIXEL_MODE_SELECT, pixel_mode)); 1161fb43630cSZhang Yubing 1162fb43630cSZhang Yubing return 0; 1163fb43630cSZhang Yubing } 1164fb43630cSZhang Yubing 1165fb43630cSZhang Yubing static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc, 1166fb43630cSZhang Yubing u16 vstart, u16 hstart) 1167fb43630cSZhang Yubing { 1168fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1169fb43630cSZhang Yubing u16 misc = 0; 1170fb43630cSZhang Yubing 1171fb43630cSZhang Yubing if (link->vsc_sdp_extension_for_colorimetry_supported) 1172fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_VSC_SDP; 1173fb43630cSZhang Yubing 1174fb43630cSZhang Yubing switch (color_format) { 1175fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444: 1176fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_RGB; 1177fb43630cSZhang Yubing break; 1178fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444: 1179fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709; 1180fb43630cSZhang Yubing break; 1181fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422: 1182fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709; 1183fb43630cSZhang Yubing break; 1184fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420: 1185fb43630cSZhang Yubing break; 1186fb43630cSZhang Yubing default: 1187fb43630cSZhang Yubing return -EINVAL; 1188fb43630cSZhang Yubing } 1189fb43630cSZhang Yubing 1190fb43630cSZhang Yubing switch (bpc) { 1191fb43630cSZhang Yubing case 6: 1192fb43630cSZhang Yubing misc |= DP_MSA_MISC_6_BPC; 1193fb43630cSZhang Yubing break; 1194fb43630cSZhang Yubing case 8: 1195fb43630cSZhang Yubing misc |= DP_MSA_MISC_8_BPC; 1196fb43630cSZhang Yubing break; 1197fb43630cSZhang Yubing case 10: 1198fb43630cSZhang Yubing misc |= DP_MSA_MISC_10_BPC; 1199fb43630cSZhang Yubing break; 1200fb43630cSZhang Yubing case 12: 1201fb43630cSZhang Yubing misc |= DP_MSA_MISC_12_BPC; 1202fb43630cSZhang Yubing break; 1203fb43630cSZhang Yubing case 16: 1204fb43630cSZhang Yubing misc |= DP_MSA_MISC_16_BPC; 1205fb43630cSZhang Yubing break; 1206fb43630cSZhang Yubing default: 1207fb43630cSZhang Yubing return -EINVAL; 1208fb43630cSZhang Yubing } 1209fb43630cSZhang Yubing 1210fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA1, 1211fb43630cSZhang Yubing FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart)); 1212fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA2, FIELD_PREP(MISC0, misc)); 1213fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8)); 1214fb43630cSZhang Yubing 1215fb43630cSZhang Yubing return 0; 1216fb43630cSZhang Yubing } 1217fb43630cSZhang Yubing 1218fb43630cSZhang Yubing static int dw_dp_video_enable(struct dw_dp *dp) 1219fb43630cSZhang Yubing { 1220fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 1221fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1222fb43630cSZhang Yubing struct drm_display_mode *mode = &video->mode; 1223fb43630cSZhang Yubing u8 color_format = video->color_format; 1224fb43630cSZhang Yubing u8 bpc = video->bpc; 1225fb43630cSZhang Yubing u8 pixel_mode = video->pixel_mode; 1226fb43630cSZhang Yubing u8 bpp = video->bpp, init_threshold, vic; 1227fb43630cSZhang Yubing u32 hactive, hblank, h_sync_width, h_front_porch; 1228fb43630cSZhang Yubing u32 vactive, vblank, v_sync_width, v_front_porch; 1229fb43630cSZhang Yubing u32 vstart = mode->vtotal - mode->vsync_start; 1230fb43630cSZhang Yubing u32 hstart = mode->htotal - mode->hsync_start; 1231fb43630cSZhang Yubing u32 peak_stream_bandwidth, link_bandwidth; 1232fb43630cSZhang Yubing u32 average_bytes_per_tu, average_bytes_per_tu_frac; 1233fb43630cSZhang Yubing u32 ts, hblank_interval; 1234fb43630cSZhang Yubing u32 value; 1235fb43630cSZhang Yubing int ret; 1236fb43630cSZhang Yubing 1237fb43630cSZhang Yubing ret = dw_dp_video_set_pixel_mode(dp, pixel_mode); 1238fb43630cSZhang Yubing if (ret) 1239fb43630cSZhang Yubing return ret; 1240fb43630cSZhang Yubing 1241fb43630cSZhang Yubing ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart); 1242fb43630cSZhang Yubing if (ret) 1243fb43630cSZhang Yubing return ret; 1244fb43630cSZhang Yubing 1245fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_MAPPING, 1246fb43630cSZhang Yubing FIELD_PREP(VIDEO_MAPPING, video->video_mapping)); 1247fb43630cSZhang Yubing 1248fb43630cSZhang Yubing /* Configure DPTX_VINPUT_POLARITY_CTRL register */ 1249fb43630cSZhang Yubing value = 0; 1250fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_PHSYNC) 1251fb43630cSZhang Yubing value |= FIELD_PREP(HSYNC_IN_POLARITY, 1); 1252fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_PVSYNC) 1253fb43630cSZhang Yubing value |= FIELD_PREP(VSYNC_IN_POLARITY, 1); 1254fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VINPUT_POLARITY_CTRL, value); 1255fb43630cSZhang Yubing 1256fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG1 register */ 1257fb43630cSZhang Yubing hactive = mode->hdisplay; 1258fb43630cSZhang Yubing hblank = mode->htotal - mode->hdisplay; 1259fb43630cSZhang Yubing value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank); 1260fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1261fb43630cSZhang Yubing value |= FIELD_PREP(I_P, 1); 1262fb43630cSZhang Yubing vic = drm_match_cea_mode(mode); 1263fb43630cSZhang Yubing if (vic == 5 || vic == 6 || vic == 7 || 1264fb43630cSZhang Yubing vic == 10 || vic == 11 || vic == 20 || 1265fb43630cSZhang Yubing vic == 21 || vic == 22 || vic == 39 || 1266fb43630cSZhang Yubing vic == 25 || vic == 26 || vic == 40 || 1267fb43630cSZhang Yubing vic == 44 || vic == 45 || vic == 46 || 1268fb43630cSZhang Yubing vic == 50 || vic == 51 || vic == 54 || 1269fb43630cSZhang Yubing vic == 55 || vic == 58 || vic == 59) 1270fb43630cSZhang Yubing value |= R_V_BLANK_IN_OSC; 1271fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG1, value); 1272fb43630cSZhang Yubing 1273fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG2 register */ 1274fb43630cSZhang Yubing vblank = mode->vtotal - mode->vdisplay; 1275fb43630cSZhang Yubing vactive = mode->vdisplay; 1276fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG2, 1277fb43630cSZhang Yubing FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive)); 1278fb43630cSZhang Yubing 1279fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG3 register */ 1280fb43630cSZhang Yubing h_sync_width = mode->hsync_end - mode->hsync_start; 1281fb43630cSZhang Yubing h_front_porch = mode->hsync_start - mode->hdisplay; 1282fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG3, 1283fb43630cSZhang Yubing FIELD_PREP(H_SYNC_WIDTH, h_sync_width) | 1284fb43630cSZhang Yubing FIELD_PREP(H_FRONT_PORCH, h_front_porch)); 1285fb43630cSZhang Yubing 1286fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG4 register */ 1287fb43630cSZhang Yubing v_sync_width = mode->vsync_end - mode->vsync_start; 1288fb43630cSZhang Yubing v_front_porch = mode->vsync_start - mode->vdisplay; 1289fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG4, 1290fb43630cSZhang Yubing FIELD_PREP(V_SYNC_WIDTH, v_sync_width) | 1291fb43630cSZhang Yubing FIELD_PREP(V_FRONT_PORCH, v_front_porch)); 1292fb43630cSZhang Yubing 1293fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG5 register */ 1294fb43630cSZhang Yubing peak_stream_bandwidth = mode->clock * bpp / 8; 1295fb43630cSZhang Yubing link_bandwidth = (link->rate / 1000) * link->lanes; 1296fb43630cSZhang Yubing ts = peak_stream_bandwidth * 64 / link_bandwidth; 1297fb43630cSZhang Yubing average_bytes_per_tu = ts / 1000; 1298fb43630cSZhang Yubing average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10; 1299fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_SINGLE_PIXEL) { 1300fb43630cSZhang Yubing if (average_bytes_per_tu < 6) 1301fb43630cSZhang Yubing init_threshold = 32; 1302fb43630cSZhang Yubing else if (hblank <= 80 && 1303fb43630cSZhang Yubing color_format != DRM_COLOR_FORMAT_YCRCB420) 1304fb43630cSZhang Yubing init_threshold = 12; 1305fb43630cSZhang Yubing else if (hblank <= 40 && 1306fb43630cSZhang Yubing color_format == DRM_COLOR_FORMAT_YCRCB420) 1307fb43630cSZhang Yubing init_threshold = 3; 1308fb43630cSZhang Yubing else 1309fb43630cSZhang Yubing init_threshold = 16; 1310fb43630cSZhang Yubing } else { 1311fb43630cSZhang Yubing u32 t1 = 0, t2 = 0, t3 = 0; 1312fb43630cSZhang Yubing 1313fb43630cSZhang Yubing switch (bpc) { 1314fb43630cSZhang Yubing case 6: 1315fb43630cSZhang Yubing t1 = (4 * 1000 / 9) * link->lanes; 1316fb43630cSZhang Yubing break; 1317fb43630cSZhang Yubing case 8: 1318fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) { 1319fb43630cSZhang Yubing t1 = (1000 / 2) * link->lanes; 1320fb43630cSZhang Yubing } else { 1321fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_DUAL_PIXEL) 1322fb43630cSZhang Yubing t1 = (1000 / 3) * link->lanes; 1323fb43630cSZhang Yubing else 1324fb43630cSZhang Yubing t1 = (3000 / 16) * link->lanes; 1325fb43630cSZhang Yubing } 1326fb43630cSZhang Yubing break; 1327fb43630cSZhang Yubing case 10: 1328fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) 1329fb43630cSZhang Yubing t1 = (2000 / 5) * link->lanes; 1330fb43630cSZhang Yubing else 1331fb43630cSZhang Yubing t1 = (4000 / 15) * link->lanes; 1332fb43630cSZhang Yubing break; 1333fb43630cSZhang Yubing case 12: 1334fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) { 1335fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_DUAL_PIXEL) 1336fb43630cSZhang Yubing t1 = (1000 / 6) * link->lanes; 1337fb43630cSZhang Yubing else 1338fb43630cSZhang Yubing t1 = (1000 / 3) * link->lanes; 1339fb43630cSZhang Yubing } else { 1340fb43630cSZhang Yubing t1 = (2000 / 9) * link->lanes; 1341fb43630cSZhang Yubing } 1342fb43630cSZhang Yubing break; 1343fb43630cSZhang Yubing case 16: 1344fb43630cSZhang Yubing if (color_format != DRM_COLOR_FORMAT_YCRCB422 && 1345fb43630cSZhang Yubing pixel_mode == DPTX_MP_DUAL_PIXEL) 1346fb43630cSZhang Yubing t1 = (1000 / 6) * link->lanes; 1347fb43630cSZhang Yubing else 1348fb43630cSZhang Yubing t1 = (1000 / 4) * link->lanes; 1349fb43630cSZhang Yubing break; 1350fb43630cSZhang Yubing default: 1351fb43630cSZhang Yubing return -EINVAL; 1352fb43630cSZhang Yubing } 1353fb43630cSZhang Yubing 1354fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB420) 1355fb43630cSZhang Yubing t2 = (link->rate / 4) * 1000 / (mode->clock / 2); 1356fb43630cSZhang Yubing else 1357fb43630cSZhang Yubing t2 = (link->rate / 4) * 1000 / mode->clock; 1358fb43630cSZhang Yubing 1359fb43630cSZhang Yubing if (average_bytes_per_tu_frac) 1360fb43630cSZhang Yubing t3 = average_bytes_per_tu + 1; 1361fb43630cSZhang Yubing else 1362fb43630cSZhang Yubing t3 = average_bytes_per_tu; 1363fb43630cSZhang Yubing init_threshold = t1 * t2 * t3 / (1000 * 1000); 1364fb43630cSZhang Yubing if (init_threshold <= 16 || average_bytes_per_tu < 10) 1365fb43630cSZhang Yubing init_threshold = 40; 1366fb43630cSZhang Yubing } 1367fb43630cSZhang Yubing 1368fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG5, 1369fb43630cSZhang Yubing FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) | 1370fb43630cSZhang Yubing FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC, 1371fb43630cSZhang Yubing average_bytes_per_tu_frac) | 1372fb43630cSZhang Yubing FIELD_PREP(INIT_THRESHOLD, init_threshold) | 1373fb43630cSZhang Yubing FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu)); 1374fb43630cSZhang Yubing 1375fb43630cSZhang Yubing /* Configure DPTX_VIDEO_HBLANK_INTERVAL register */ 1376fb43630cSZhang Yubing hblank_interval = hblank * (link->rate / 4) / mode->clock; 1377fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_HBLANK_INTERVAL, 1378fb43630cSZhang Yubing FIELD_PREP(HBLANK_INTERVAL_EN, 1) | 1379fb43630cSZhang Yubing FIELD_PREP(HBLANK_INTERVAL, hblank_interval)); 1380fb43630cSZhang Yubing 1381fb43630cSZhang Yubing /* Video stream enable */ 1382fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE, 1383fb43630cSZhang Yubing FIELD_PREP(VIDEO_STREAM_ENABLE, 1)); 1384fb43630cSZhang Yubing 1385fb43630cSZhang Yubing if (link->vsc_sdp_extension_for_colorimetry_supported) 1386fb43630cSZhang Yubing dw_dp_send_vsc_sdp(dp); 1387fb43630cSZhang Yubing 1388fb43630cSZhang Yubing return 0; 1389fb43630cSZhang Yubing } 1390fb43630cSZhang Yubing 1391fb43630cSZhang Yubing static bool dw_dp_detect(struct dw_dp *dp) 1392fb43630cSZhang Yubing { 1393fb43630cSZhang Yubing u32 value; 1394fb43630cSZhang Yubing 1395fb43630cSZhang Yubing if (dm_gpio_is_valid(&dp->hpd_gpio)) 1396fb43630cSZhang Yubing return dm_gpio_get_value(&dp->hpd_gpio); 1397fb43630cSZhang Yubing 1398fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_HPD_STATUS, &value); 13995fbef17aSZhang Yubing if (FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG) { 1400fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_HPD_STATUS, HPD_HOT_PLUG); 1401fb43630cSZhang Yubing return true; 1402fb43630cSZhang Yubing } 1403fb43630cSZhang Yubing 1404fb43630cSZhang Yubing return false; 1405fb43630cSZhang Yubing } 1406fb43630cSZhang Yubing 1407fb43630cSZhang Yubing static int dw_dp_connector_pre_init(struct display_state *state) 1408fb43630cSZhang Yubing { 1409fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1410fb43630cSZhang Yubing 1411fb43630cSZhang Yubing conn_state->type = DRM_MODE_CONNECTOR_DisplayPort; 1412fb43630cSZhang Yubing 1413fb43630cSZhang Yubing return 0; 1414fb43630cSZhang Yubing } 1415fb43630cSZhang Yubing 1416fb43630cSZhang Yubing static int dw_dp_connector_init(struct display_state *state) 1417fb43630cSZhang Yubing { 1418fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1419fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(conn_state->dev); 1420fb43630cSZhang Yubing int ret; 1421fb43630cSZhang Yubing 1422fb43630cSZhang Yubing conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_DP1 : VOP_OUTPUT_IF_DP0; 1423fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 1424fb43630cSZhang Yubing conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 1425fb43630cSZhang Yubing 1426fb43630cSZhang Yubing clk_set_defaults(dp->dev); 1427fb43630cSZhang Yubing 1428fb43630cSZhang Yubing reset_assert(&dp->reset); 1429fb43630cSZhang Yubing udelay(20); 1430fb43630cSZhang Yubing reset_deassert(&dp->reset); 1431fb43630cSZhang Yubing 1432fb43630cSZhang Yubing conn_state->disp_info = rockchip_get_disp_info(conn_state->type, 1433fb43630cSZhang Yubing dp->id); 1434fb43630cSZhang Yubing dw_dp_init(dp); 1435fb43630cSZhang Yubing ret = generic_phy_power_on(&dp->phy); 1436fb43630cSZhang Yubing 1437fb43630cSZhang Yubing return ret; 1438fb43630cSZhang Yubing } 1439fb43630cSZhang Yubing 1440fb43630cSZhang Yubing static int dw_dp_connector_get_edid(struct display_state *state) 1441fb43630cSZhang Yubing { 1442fb43630cSZhang Yubing int ret; 1443fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1444fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(conn_state->dev); 1445fb43630cSZhang Yubing 1446fb43630cSZhang Yubing ret = drm_do_get_edid(&dp->aux.ddc, conn_state->edid); 1447fb43630cSZhang Yubing 1448fb43630cSZhang Yubing return ret; 1449fb43630cSZhang Yubing } 1450fb43630cSZhang Yubing 1451*1cf3aaecSZhang Yubing static int dw_dp_get_output_fmts_index(u32 bus_format) 1452*1cf3aaecSZhang Yubing { 1453*1cf3aaecSZhang Yubing int i; 1454*1cf3aaecSZhang Yubing 1455*1cf3aaecSZhang Yubing for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { 1456*1cf3aaecSZhang Yubing const struct dw_dp_output_format *fmt = &possible_output_fmts[i]; 1457*1cf3aaecSZhang Yubing 1458*1cf3aaecSZhang Yubing if (fmt->bus_format == bus_format) 1459*1cf3aaecSZhang Yubing break; 1460*1cf3aaecSZhang Yubing } 1461*1cf3aaecSZhang Yubing 1462*1cf3aaecSZhang Yubing if (i == ARRAY_SIZE(possible_output_fmts)) 1463*1cf3aaecSZhang Yubing return 1; 1464*1cf3aaecSZhang Yubing 1465*1cf3aaecSZhang Yubing return i; 1466*1cf3aaecSZhang Yubing } 1467*1cf3aaecSZhang Yubing 1468*1cf3aaecSZhang Yubing static int dw_dp_connector_prepare(struct display_state *state) 1469*1cf3aaecSZhang Yubing { 1470*1cf3aaecSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1471*1cf3aaecSZhang Yubing struct dw_dp *dp = dev_get_priv(conn_state->dev); 1472*1cf3aaecSZhang Yubing struct dw_dp_video *video = &dp->video; 1473*1cf3aaecSZhang Yubing int bus_fmt; 1474*1cf3aaecSZhang Yubing 1475*1cf3aaecSZhang Yubing bus_fmt = dw_dp_get_output_fmts_index(conn_state->bus_format); 1476*1cf3aaecSZhang Yubing video->video_mapping = possible_output_fmts[bus_fmt].video_mapping; 1477*1cf3aaecSZhang Yubing video->color_format = possible_output_fmts[bus_fmt].color_format; 1478*1cf3aaecSZhang Yubing video->bus_format = possible_output_fmts[bus_fmt].bus_format; 1479*1cf3aaecSZhang Yubing video->bpc = possible_output_fmts[bus_fmt].bpc; 1480*1cf3aaecSZhang Yubing video->bpp = possible_output_fmts[bus_fmt].bpp; 1481*1cf3aaecSZhang Yubing 1482*1cf3aaecSZhang Yubing return 0; 1483*1cf3aaecSZhang Yubing } 1484*1cf3aaecSZhang Yubing 1485fb43630cSZhang Yubing static int dw_dp_connector_enable(struct display_state *state) 1486fb43630cSZhang Yubing { 1487fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1488fb43630cSZhang Yubing struct drm_display_mode *mode = &conn_state->mode; 1489fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(conn_state->dev); 1490fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 1491fb43630cSZhang Yubing int ret; 1492fb43630cSZhang Yubing 1493fb43630cSZhang Yubing memcpy(&video->mode, mode, sizeof(video->mode)); 1494fb43630cSZhang Yubing video->pixel_mode = DPTX_MP_QUAD_PIXEL; 1495fb43630cSZhang Yubing 14965efdd3e2SZhang Yubing if (dp->force_output) { 14975efdd3e2SZhang Yubing ret = dw_dp_set_phy_default_config(dp); 14985efdd3e2SZhang Yubing if (ret < 0) 14995efdd3e2SZhang Yubing printf("failed to set phy_default config: %d\n", ret); 15005efdd3e2SZhang Yubing } else { 1501fb43630cSZhang Yubing ret = dw_dp_link_enable(dp); 1502fb43630cSZhang Yubing if (ret < 0) { 15035efdd3e2SZhang Yubing printf("failed to enable link: %d\n", ret); 1504fb43630cSZhang Yubing return ret; 1505fb43630cSZhang Yubing } 15065efdd3e2SZhang Yubing } 1507fb43630cSZhang Yubing 1508fb43630cSZhang Yubing ret = dw_dp_video_enable(dp); 1509fb43630cSZhang Yubing if (ret < 0) { 15105efdd3e2SZhang Yubing printf("failed to enable video: %d\n", ret); 1511fb43630cSZhang Yubing return ret; 1512fb43630cSZhang Yubing } 1513fb43630cSZhang Yubing 1514fb43630cSZhang Yubing return 0; 1515fb43630cSZhang Yubing } 1516fb43630cSZhang Yubing 1517fb43630cSZhang Yubing static int dw_dp_connector_disable(struct display_state *state) 1518fb43630cSZhang Yubing { 1519fb43630cSZhang Yubing /* TODO */ 1520fb43630cSZhang Yubing 1521fb43630cSZhang Yubing return 0; 1522fb43630cSZhang Yubing } 1523fb43630cSZhang Yubing 1524fb43630cSZhang Yubing static int dw_dp_connector_detect(struct display_state *state) 1525fb43630cSZhang Yubing { 1526fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1527fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(conn_state->dev); 1528*1cf3aaecSZhang Yubing int status, tries, ret; 1529fb43630cSZhang Yubing 1530a66bd69eSZhang Yubing for (tries = 0; tries < 200; tries++) { 1531fb43630cSZhang Yubing status = dw_dp_detect(dp); 1532fb43630cSZhang Yubing if (status) 1533fb43630cSZhang Yubing break; 1534fb43630cSZhang Yubing mdelay(2); 1535fb43630cSZhang Yubing } 1536fb43630cSZhang Yubing 15375efdd3e2SZhang Yubing if (state->force_output && !status) 15385efdd3e2SZhang Yubing dp->force_output = true; 15395efdd3e2SZhang Yubing 15405efdd3e2SZhang Yubing if (!status && !dp->force_output) 1541fb43630cSZhang Yubing generic_phy_power_off(&dp->phy); 1542fb43630cSZhang Yubing 1543*1cf3aaecSZhang Yubing if (status && !dp->force_output) { 1544*1cf3aaecSZhang Yubing ret = dw_dp_link_probe(dp); 1545*1cf3aaecSZhang Yubing if (ret) 1546*1cf3aaecSZhang Yubing printf("failed to probe DP link: %d\n", ret); 1547*1cf3aaecSZhang Yubing } 1548*1cf3aaecSZhang Yubing 1549fb43630cSZhang Yubing return status; 1550fb43630cSZhang Yubing } 1551fb43630cSZhang Yubing 1552fb43630cSZhang Yubing static int dw_dp_mode_valid(struct dw_dp *dp, struct hdmi_edid_data *edid_data) 1553fb43630cSZhang Yubing { 1554fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1555fb43630cSZhang Yubing struct drm_display_info *di = &edid_data->display_info; 1556fb43630cSZhang Yubing u32 min_bpp; 1557fb43630cSZhang Yubing int i; 1558fb43630cSZhang Yubing 1559fb43630cSZhang Yubing if (di->color_formats & DRM_COLOR_FORMAT_YCRCB420 && 1560fb43630cSZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported) 1561fb43630cSZhang Yubing min_bpp = 12; 1562fb43630cSZhang Yubing else if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422) 1563fb43630cSZhang Yubing min_bpp = 16; 1564fb43630cSZhang Yubing else if (di->color_formats & DRM_COLOR_FORMAT_RGB444) 1565fb43630cSZhang Yubing min_bpp = 18; 1566fb43630cSZhang Yubing else 1567fb43630cSZhang Yubing min_bpp = 24; 1568fb43630cSZhang Yubing 1569fb43630cSZhang Yubing for (i = 0; i < edid_data->modes; i++) { 1570fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp, link->lanes, 1571fb43630cSZhang Yubing link->rate)) 1572fb43630cSZhang Yubing edid_data->mode_buf[i].invalid = true; 1573fb43630cSZhang Yubing } 1574fb43630cSZhang Yubing 1575fb43630cSZhang Yubing return 0; 1576fb43630cSZhang Yubing } 1577fb43630cSZhang Yubing 1578fb43630cSZhang Yubing static u32 dw_dp_get_output_bus_fmts(struct dw_dp *dp, struct hdmi_edid_data *edid_data) 1579fb43630cSZhang Yubing { 1580fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1581fb43630cSZhang Yubing unsigned int i; 1582fb43630cSZhang Yubing 1583fb43630cSZhang Yubing for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { 1584fb43630cSZhang Yubing const struct dw_dp_output_format *fmt = &possible_output_fmts[i]; 1585fb43630cSZhang Yubing 1586fb43630cSZhang Yubing if (fmt->bpc > edid_data->display_info.bpc) 1587fb43630cSZhang Yubing continue; 1588fb43630cSZhang Yubing 1589fb43630cSZhang Yubing if (!(edid_data->display_info.color_formats & fmt->color_format)) 1590fb43630cSZhang Yubing continue; 1591fb43630cSZhang Yubing 1592fb43630cSZhang Yubing if (fmt->color_format == DRM_COLOR_FORMAT_YCRCB420 && 1593fb43630cSZhang Yubing !link->vsc_sdp_extension_for_colorimetry_supported) 1594fb43630cSZhang Yubing continue; 1595fb43630cSZhang Yubing 1596fb43630cSZhang Yubing if (drm_mode_is_420(&edid_data->display_info, edid_data->preferred_mode) && 1597fb43630cSZhang Yubing fmt->color_format != DRM_COLOR_FORMAT_YCRCB420) 1598fb43630cSZhang Yubing continue; 1599fb43630cSZhang Yubing 1600fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, edid_data->preferred_mode, fmt->bpp, link->lanes, 1601fb43630cSZhang Yubing link->rate)) 1602fb43630cSZhang Yubing continue; 1603fb43630cSZhang Yubing 1604fb43630cSZhang Yubing break; 1605fb43630cSZhang Yubing } 1606fb43630cSZhang Yubing 1607fb43630cSZhang Yubing if (i == ARRAY_SIZE(possible_output_fmts)) 1608fb43630cSZhang Yubing return 1; 1609fb43630cSZhang Yubing 1610fb43630cSZhang Yubing return i; 1611fb43630cSZhang Yubing } 1612fb43630cSZhang Yubing 1613fb43630cSZhang Yubing static int dw_dp_connector_get_timing(struct display_state *state) 1614fb43630cSZhang Yubing { 1615fb43630cSZhang Yubing int ret, i; 1616fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1617fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(conn_state->dev); 1618fb43630cSZhang Yubing struct drm_display_mode *mode = &conn_state->mode; 1619fb43630cSZhang Yubing struct hdmi_edid_data edid_data; 1620fb43630cSZhang Yubing struct drm_display_mode *mode_buf; 1621fb43630cSZhang Yubing u32 bus_fmt; 1622fb43630cSZhang Yubing 1623fb43630cSZhang Yubing mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode)); 1624fb43630cSZhang Yubing if (!mode_buf) 1625fb43630cSZhang Yubing return -ENOMEM; 1626fb43630cSZhang Yubing 1627fb43630cSZhang Yubing memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode)); 1628fb43630cSZhang Yubing memset(&edid_data, 0, sizeof(struct hdmi_edid_data)); 1629fb43630cSZhang Yubing edid_data.mode_buf = mode_buf; 1630fb43630cSZhang Yubing 16315efdd3e2SZhang Yubing if (!dp->force_output) { 1632fb43630cSZhang Yubing ret = drm_do_get_edid(&dp->aux.ddc, conn_state->edid); 1633fb43630cSZhang Yubing if (!ret) 1634fb43630cSZhang Yubing ret = drm_add_edid_modes(&edid_data, conn_state->edid); 1635fb43630cSZhang Yubing 1636fb43630cSZhang Yubing if (ret < 0) { 1637fb43630cSZhang Yubing printf("failed to get edid\n"); 1638fb43630cSZhang Yubing goto err; 1639fb43630cSZhang Yubing } 1640fb43630cSZhang Yubing 1641fb43630cSZhang Yubing drm_rk_filter_whitelist(&edid_data); 1642fb43630cSZhang Yubing drm_mode_max_resolution_filter(&edid_data, 1643fb43630cSZhang Yubing &state->crtc_state.max_output); 1644fb43630cSZhang Yubing dw_dp_mode_valid(dp, &edid_data); 1645fb43630cSZhang Yubing 1646fb43630cSZhang Yubing if (!drm_mode_prune_invalid(&edid_data)) { 1647fb43630cSZhang Yubing printf("can't find valid hdmi mode\n"); 1648fb43630cSZhang Yubing ret = -EINVAL; 1649fb43630cSZhang Yubing goto err; 1650fb43630cSZhang Yubing } 1651fb43630cSZhang Yubing 1652fb43630cSZhang Yubing for (i = 0; i < edid_data.modes; i++) 1653fb43630cSZhang Yubing edid_data.mode_buf[i].vrefresh = 1654fb43630cSZhang Yubing drm_mode_vrefresh(&edid_data.mode_buf[i]); 1655fb43630cSZhang Yubing 1656fb43630cSZhang Yubing drm_mode_sort(&edid_data); 1657fb43630cSZhang Yubing memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode)); 16585efdd3e2SZhang Yubing } 1659fb43630cSZhang Yubing 1660fb43630cSZhang Yubing if (state->force_output) 1661*1cf3aaecSZhang Yubing bus_fmt = dw_dp_get_output_fmts_index(state->force_bus_format); 1662fb43630cSZhang Yubing else 1663fb43630cSZhang Yubing bus_fmt = dw_dp_get_output_bus_fmts(dp, &edid_data); 1664fb43630cSZhang Yubing 1665*1cf3aaecSZhang Yubing conn_state->bus_format = possible_output_fmts[bus_fmt].bus_format; 1666fb43630cSZhang Yubing 1667*1cf3aaecSZhang Yubing switch (possible_output_fmts[bus_fmt].color_format) { 1668fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420: 1669fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420; 1670fb43630cSZhang Yubing break; 1671fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422: 1672fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY; 1673fb43630cSZhang Yubing break; 1674fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444: 1675fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444: 1676fb43630cSZhang Yubing default: 1677fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 1678fb43630cSZhang Yubing break; 1679fb43630cSZhang Yubing } 1680fb43630cSZhang Yubing 1681fb43630cSZhang Yubing err: 1682fb43630cSZhang Yubing free(mode_buf); 1683fb43630cSZhang Yubing 1684fb43630cSZhang Yubing return 0; 1685fb43630cSZhang Yubing } 1686fb43630cSZhang Yubing 1687fb43630cSZhang Yubing static const struct rockchip_connector_funcs dw_dp_connector_funcs = { 1688fb43630cSZhang Yubing .pre_init = dw_dp_connector_pre_init, 1689fb43630cSZhang Yubing .init = dw_dp_connector_init, 1690fb43630cSZhang Yubing .get_edid = dw_dp_connector_get_edid, 1691*1cf3aaecSZhang Yubing .prepare = dw_dp_connector_prepare, 1692fb43630cSZhang Yubing .enable = dw_dp_connector_enable, 1693fb43630cSZhang Yubing .disable = dw_dp_connector_disable, 1694fb43630cSZhang Yubing .detect = dw_dp_connector_detect, 1695fb43630cSZhang Yubing .get_timing = dw_dp_connector_get_timing, 1696fb43630cSZhang Yubing }; 1697fb43630cSZhang Yubing 1698fb43630cSZhang Yubing static int dw_dp_ddc_init(struct dw_dp *dp) 1699fb43630cSZhang Yubing { 1700fb43630cSZhang Yubing dp->aux.name = "dw-dp"; 1701fb43630cSZhang Yubing dp->aux.dev = dp->dev; 1702fb43630cSZhang Yubing dp->aux.transfer = dw_dp_aux_transfer; 1703fb43630cSZhang Yubing dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer; 1704fb43630cSZhang Yubing 1705fb43630cSZhang Yubing return 0; 1706fb43630cSZhang Yubing } 1707fb43630cSZhang Yubing 1708fb43630cSZhang Yubing static int dw_dp_probe(struct udevice *dev) 1709fb43630cSZhang Yubing { 1710fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(dev); 1711fb43630cSZhang Yubing int ret; 1712fb43630cSZhang Yubing 1713fb43630cSZhang Yubing ret = regmap_init_mem(dev, &dp->regmap); 1714fb43630cSZhang Yubing if (ret) 1715fb43630cSZhang Yubing return ret; 1716fb43630cSZhang Yubing 1717fb43630cSZhang Yubing dp->id = of_alias_get_id(ofnode_to_np(dev->node), "dp"); 1718fb43630cSZhang Yubing if (dp->id < 0) 1719fb43630cSZhang Yubing dp->id = 0; 1720fb43630cSZhang Yubing 1721fb43630cSZhang Yubing ret = reset_get_by_index(dev, 0, &dp->reset); 1722fb43630cSZhang Yubing if (ret) { 1723fb43630cSZhang Yubing dev_err(dev, "failed to get reset control: %d\n", ret); 1724fb43630cSZhang Yubing return ret; 1725fb43630cSZhang Yubing } 1726fb43630cSZhang Yubing 17275fbef17aSZhang Yubing dp->force_hpd = dev_read_bool(dev, "force-hpd"); 17285fbef17aSZhang Yubing 1729fb43630cSZhang Yubing ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio, 1730fb43630cSZhang Yubing GPIOD_IS_IN); 1731fb43630cSZhang Yubing if (ret && ret != -ENOENT) { 1732fb43630cSZhang Yubing dev_err(dev, "failed to get hpd GPIO: %d\n", ret); 1733fb43630cSZhang Yubing return ret; 1734fb43630cSZhang Yubing } 1735fb43630cSZhang Yubing 1736fb43630cSZhang Yubing generic_phy_get_by_index(dev, 0, &dp->phy); 1737fb43630cSZhang Yubing 1738fb43630cSZhang Yubing dp->dev = dev; 1739fb43630cSZhang Yubing 1740fb43630cSZhang Yubing dw_dp_ddc_init(dp); 1741fb43630cSZhang Yubing 1742fb43630cSZhang Yubing return 0; 1743fb43630cSZhang Yubing } 1744fb43630cSZhang Yubing 1745fb43630cSZhang Yubing static const struct rockchip_connector rk3588_dp_driver_data = { 1746fb43630cSZhang Yubing .funcs = &dw_dp_connector_funcs, 1747fb43630cSZhang Yubing }; 1748fb43630cSZhang Yubing 1749fb43630cSZhang Yubing static const struct udevice_id dw_dp_ids[] = { 1750fb43630cSZhang Yubing { 1751fb43630cSZhang Yubing .compatible = "rockchip,rk3588-dp", 1752fb43630cSZhang Yubing .data = (ulong)&rk3588_dp_driver_data 1753fb43630cSZhang Yubing }, 1754fb43630cSZhang Yubing {} 1755fb43630cSZhang Yubing }; 1756fb43630cSZhang Yubing 1757fb43630cSZhang Yubing U_BOOT_DRIVER(dw_dp) = { 1758fb43630cSZhang Yubing .name = "dw_dp", 1759fb43630cSZhang Yubing .id = UCLASS_DISPLAY, 1760fb43630cSZhang Yubing .of_match = dw_dp_ids, 1761fb43630cSZhang Yubing .probe = dw_dp_probe, 1762fb43630cSZhang Yubing .priv_auto_alloc_size = sizeof(struct dw_dp), 1763fb43630cSZhang Yubing }; 1764fb43630cSZhang Yubing 1765