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> 177ac3c934SZhang Yubing #include <dm/lists.h> 18fb43630cSZhang Yubing #include <dm/read.h> 19fb43630cSZhang Yubing #include <generic-phy.h> 20fb43630cSZhang Yubing #include <linux/bitfield.h> 21fb43630cSZhang Yubing #include <linux/hdmi.h> 22fb43630cSZhang Yubing #include <linux/media-bus-format.h> 23fb43630cSZhang Yubing #include <linux/list.h> 24fb43630cSZhang Yubing #include <asm/gpio.h> 25fb43630cSZhang Yubing #include <generic-phy.h> 26fb43630cSZhang Yubing #include <regmap.h> 27fb43630cSZhang Yubing #include <reset.h> 28fb43630cSZhang Yubing #include <drm/drm_dp_helper.h> 29fb43630cSZhang Yubing 30fb43630cSZhang Yubing #include "rockchip_display.h" 31fb43630cSZhang Yubing #include "rockchip_crtc.h" 32fb43630cSZhang Yubing #include "rockchip_connector.h" 33fb43630cSZhang Yubing 34fb43630cSZhang Yubing #define DPTX_VERSION_NUMBER 0x0000 35fb43630cSZhang Yubing #define DPTX_VERSION_TYPE 0x0004 36fb43630cSZhang Yubing #define DPTX_ID 0x0008 37fb43630cSZhang Yubing 38fb43630cSZhang Yubing #define DPTX_CONFIG_REG1 0x0100 39fb43630cSZhang Yubing #define DPTX_CONFIG_REG2 0x0104 40fb43630cSZhang Yubing #define DPTX_CONFIG_REG3 0x0108 41fb43630cSZhang Yubing 42fb43630cSZhang Yubing #define DPTX_CCTL 0x0200 43fb43630cSZhang Yubing #define FORCE_HPD BIT(4) 44fb43630cSZhang Yubing #define DEFAULT_FAST_LINK_TRAIN_EN BIT(2) 45fb43630cSZhang Yubing #define ENHANCE_FRAMING_EN BIT(1) 46fb43630cSZhang Yubing #define SCRAMBLE_DIS BIT(0) 47fb43630cSZhang Yubing #define DPTX_SOFT_RESET_CTRL 0x0204 48fb43630cSZhang Yubing #define VIDEO_RESET BIT(5) 49fb43630cSZhang Yubing #define AUX_RESET BIT(4) 50fb43630cSZhang Yubing #define AUDIO_SAMPLER_RESET BIT(3) 51fb43630cSZhang Yubing #define PHY_SOFT_RESET BIT(1) 52fb43630cSZhang Yubing #define CONTROLLER_RESET BIT(0) 53fb43630cSZhang Yubing 54fb43630cSZhang Yubing #define DPTX_VSAMPLE_CTRL 0x0300 55fb43630cSZhang Yubing #define PIXEL_MODE_SELECT GENMASK(22, 21) 56fb43630cSZhang Yubing #define VIDEO_MAPPING GENMASK(20, 16) 57fb43630cSZhang Yubing #define VIDEO_STREAM_ENABLE BIT(5) 58fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL1 0x0304 59fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL2 0x0308 60fb43630cSZhang Yubing #define DPTX_VINPUT_POLARITY_CTRL 0x030c 61fb43630cSZhang Yubing #define DE_IN_POLARITY BIT(2) 62fb43630cSZhang Yubing #define HSYNC_IN_POLARITY BIT(1) 63fb43630cSZhang Yubing #define VSYNC_IN_POLARITY BIT(0) 64fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG1 0x0310 65fb43630cSZhang Yubing #define HACTIVE GENMASK(31, 16) 66fb43630cSZhang Yubing #define HBLANK GENMASK(15, 2) 67fb43630cSZhang Yubing #define I_P BIT(1) 68fb43630cSZhang Yubing #define R_V_BLANK_IN_OSC BIT(0) 69fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG2 0x0314 70fb43630cSZhang Yubing #define VBLANK GENMASK(31, 16) 71fb43630cSZhang Yubing #define VACTIVE GENMASK(15, 0) 72fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG3 0x0318 73fb43630cSZhang Yubing #define H_SYNC_WIDTH GENMASK(31, 16) 74fb43630cSZhang Yubing #define H_FRONT_PORCH GENMASK(15, 0) 75fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG4 0x031c 76fb43630cSZhang Yubing #define V_SYNC_WIDTH GENMASK(31, 16) 77fb43630cSZhang Yubing #define V_FRONT_PORCH GENMASK(15, 0) 78fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG5 0x0320 79fb43630cSZhang Yubing #define INIT_THRESHOLD_HI GENMASK(22, 21) 80fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU_FRAC GENMASK(19, 16) 81fb43630cSZhang Yubing #define INIT_THRESHOLD GENMASK(13, 7) 82fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU GENMASK(6, 0) 83fb43630cSZhang Yubing #define DPTX_VIDEO_MSA1 0x0324 84fb43630cSZhang Yubing #define VSTART GENMASK(31, 16) 85fb43630cSZhang Yubing #define HSTART GENMASK(15, 0) 86fb43630cSZhang Yubing #define DPTX_VIDEO_MSA2 0x0328 87fb43630cSZhang Yubing #define MISC0 GENMASK(31, 24) 88fb43630cSZhang Yubing #define DPTX_VIDEO_MSA3 0x032c 89fb43630cSZhang Yubing #define MISC1 GENMASK(31, 24) 90fb43630cSZhang Yubing #define DPTX_VIDEO_HBLANK_INTERVAL 0x0330 91fb43630cSZhang Yubing #define HBLANK_INTERVAL_EN BIT(16) 92fb43630cSZhang Yubing #define HBLANK_INTERVAL GENMASK(15, 0) 93fb43630cSZhang Yubing 94fb43630cSZhang Yubing #define DPTX_AUD_CONFIG1 0x0400 95fb43630cSZhang Yubing #define AUDIO_TIMESTAMP_VERSION_NUM GENMASK(29, 24) 96fb43630cSZhang Yubing #define AUDIO_PACKET_ID GENMASK(23, 16) 97fb43630cSZhang Yubing #define AUDIO_MUTE BIT(15) 98fb43630cSZhang Yubing #define NUM_CHANNELS GENMASK(14, 12) 99fb43630cSZhang Yubing #define HBR_MODE_ENABLE BIT(10) 100fb43630cSZhang Yubing #define AUDIO_DATA_WIDTH GENMASK(9, 5) 101fb43630cSZhang Yubing #define AUDIO_DATA_IN_EN GENMASK(4, 1) 102fb43630cSZhang Yubing #define AUDIO_INF_SELECT BIT(0) 103fb43630cSZhang Yubing 104fb43630cSZhang Yubing #define DPTX_SDP_VERTICAL_CTRL 0x0500 105fb43630cSZhang Yubing #define EN_VERTICAL_SDP BIT(2) 106fb43630cSZhang Yubing #define EN_AUDIO_STREAM_SDP BIT(1) 107fb43630cSZhang Yubing #define EN_AUDIO_TIMESTAMP_SDP BIT(0) 108fb43630cSZhang Yubing #define DPTX_SDP_HORIZONTAL_CTRL 0x0504 109fb43630cSZhang Yubing #define EN_HORIZONTAL_SDP BIT(2) 110fb43630cSZhang Yubing #define DPTX_SDP_STATUS_REGISTER 0x0508 111fb43630cSZhang Yubing #define DPTX_SDP_MANUAL_CTRL 0x050c 112fb43630cSZhang Yubing #define DPTX_SDP_STATUS_EN 0x0510 113fb43630cSZhang Yubing 114fb43630cSZhang Yubing #define DPTX_SDP_REGISTER_BANK 0x0600 115fb43630cSZhang Yubing #define SDP_REGS GENMASK(31, 0) 116fb43630cSZhang Yubing 117fb43630cSZhang Yubing #define DPTX_PHYIF_CTRL 0x0a00 118fb43630cSZhang Yubing #define PHY_WIDTH BIT(25) 119fb43630cSZhang Yubing #define PHY_POWERDOWN GENMASK(20, 17) 120fb43630cSZhang Yubing #define PHY_BUSY GENMASK(15, 12) 121fb43630cSZhang Yubing #define SSC_DIS BIT(16) 122fb43630cSZhang Yubing #define XMIT_ENABLE GENMASK(11, 8) 123fb43630cSZhang Yubing #define PHY_LANES GENMASK(7, 6) 124fb43630cSZhang Yubing #define PHY_RATE GENMASK(5, 4) 125fb43630cSZhang Yubing #define TPS_SEL GENMASK(3, 0) 126fb43630cSZhang Yubing #define DPTX_PHY_TX_EQ 0x0a04 127fb43630cSZhang Yubing #define DPTX_CUSTOMPAT0 0x0a08 128fb43630cSZhang Yubing #define DPTX_CUSTOMPAT1 0x0a0c 129fb43630cSZhang Yubing #define DPTX_CUSTOMPAT2 0x0a10 130fb43630cSZhang Yubing #define DPTX_HBR2_COMPLIANCE_SCRAMBLER_RESET 0x0a14 131fb43630cSZhang Yubing #define DPTX_PHYIF_PWRDOWN_CTRL 0x0a18 132fb43630cSZhang Yubing 133fb43630cSZhang Yubing #define DPTX_AUX_CMD 0x0b00 134fb43630cSZhang Yubing #define AUX_CMD_TYPE GENMASK(31, 28) 135fb43630cSZhang Yubing #define AUX_ADDR GENMASK(27, 8) 136fb43630cSZhang Yubing #define I2C_ADDR_ONLY BIT(4) 137fb43630cSZhang Yubing #define AUX_LEN_REQ GENMASK(3, 0) 138fb43630cSZhang Yubing #define DPTX_AUX_STATUS 0x0b04 139fb43630cSZhang Yubing #define AUX_TIMEOUT BIT(17) 140fb43630cSZhang Yubing #define AUX_BYTES_READ GENMASK(23, 19) 141fb43630cSZhang Yubing #define AUX_STATUS GENMASK(7, 4) 142fb43630cSZhang Yubing #define DPTX_AUX_DATA0 0x0b08 143fb43630cSZhang Yubing #define DPTX_AUX_DATA1 0x0b0c 144fb43630cSZhang Yubing #define DPTX_AUX_DATA2 0x0b10 145fb43630cSZhang Yubing #define DPTX_AUX_DATA3 0x0b14 146fb43630cSZhang Yubing 147fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT 0x0d00 148fb43630cSZhang Yubing #define VIDEO_FIFO_OVERFLOW_STREAM0 BIT(6) 149fb43630cSZhang Yubing #define AUDIO_FIFO_OVERFLOW_STREAM0 BIT(5) 150fb43630cSZhang Yubing #define SDP_EVENT_STREAM0 BIT(4) 151fb43630cSZhang Yubing #define AUX_CMD_INVALID BIT(3) 152fb43630cSZhang Yubing #define AUX_REPLY_EVENT BIT(1) 153fb43630cSZhang Yubing #define HPD_EVENT BIT(0) 154fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT_ENABLE 0x0d04 155fb43630cSZhang Yubing #define AUX_REPLY_EVENT_EN BIT(1) 156fb43630cSZhang Yubing #define HPD_EVENT_EN BIT(0) 157fb43630cSZhang Yubing #define DPTX_HPD_STATUS 0x0d08 158fb43630cSZhang Yubing #define HPD_STATE GENMASK(11, 9) 159fb43630cSZhang Yubing #define HPD_STATUS BIT(8) 160fb43630cSZhang Yubing #define HPD_HOT_UNPLUG BIT(2) 161fb43630cSZhang Yubing #define HPD_HOT_PLUG BIT(1) 162fb43630cSZhang Yubing #define HPD_IRQ BIT(0) 163fb43630cSZhang Yubing #define DPTX_HPD_INTERRUPT_ENABLE 0x0d0c 164fb43630cSZhang Yubing #define HPD_UNPLUG_ERR_EN BIT(3) 165fb43630cSZhang Yubing #define HPD_UNPLUG_EN BIT(2) 166fb43630cSZhang Yubing #define HPD_PLUG_EN BIT(1) 167fb43630cSZhang Yubing #define HPD_IRQ_EN BIT(0) 168fb43630cSZhang Yubing 169fb43630cSZhang Yubing #define DPTX_MAX_REGISTER DPTX_HPD_INTERRUPT_ENABLE 170fb43630cSZhang Yubing 171fb43630cSZhang Yubing #define SDP_REG_BANK_SIZE 16 172fb43630cSZhang Yubing 173fb43630cSZhang Yubing struct drm_dp_link_caps { 174fb43630cSZhang Yubing bool enhanced_framing; 175fb43630cSZhang Yubing bool tps3_supported; 176fb43630cSZhang Yubing bool tps4_supported; 177fb43630cSZhang Yubing bool channel_coding; 178fb43630cSZhang Yubing bool ssc; 179fb43630cSZhang Yubing }; 180fb43630cSZhang Yubing 181fb43630cSZhang Yubing struct drm_dp_link_train_set { 182fb43630cSZhang Yubing unsigned int voltage_swing[4]; 183fb43630cSZhang Yubing unsigned int pre_emphasis[4]; 184fb43630cSZhang Yubing }; 185fb43630cSZhang Yubing 186fb43630cSZhang Yubing struct drm_dp_link_train { 187fb43630cSZhang Yubing struct drm_dp_link_train_set request; 188fb43630cSZhang Yubing struct drm_dp_link_train_set adjust; 189fb43630cSZhang Yubing bool clock_recovered; 190fb43630cSZhang Yubing bool channel_equalized; 191fb43630cSZhang Yubing }; 192fb43630cSZhang Yubing 193fb43630cSZhang Yubing struct dw_dp_link { 194fb43630cSZhang Yubing u8 dpcd[DP_RECEIVER_CAP_SIZE]; 195fb43630cSZhang Yubing unsigned char revision; 196fb43630cSZhang Yubing unsigned int rate; 197fb43630cSZhang Yubing unsigned int lanes; 198fb43630cSZhang Yubing struct drm_dp_link_caps caps; 199fb43630cSZhang Yubing struct drm_dp_link_train train; 200fb43630cSZhang Yubing u8 sink_count; 201fb43630cSZhang Yubing u8 vsc_sdp_extension_for_colorimetry_supported; 202fb43630cSZhang Yubing }; 203fb43630cSZhang Yubing 204fb43630cSZhang Yubing struct dw_dp_video { 205fb43630cSZhang Yubing struct drm_display_mode mode; 206fb43630cSZhang Yubing u32 bus_format; 207fb43630cSZhang Yubing u8 video_mapping; 208fb43630cSZhang Yubing u8 pixel_mode; 209fb43630cSZhang Yubing u8 color_format; 210fb43630cSZhang Yubing u8 bpc; 211fb43630cSZhang Yubing u8 bpp; 212fb43630cSZhang Yubing }; 213fb43630cSZhang Yubing 214fb43630cSZhang Yubing struct dw_dp_sdp { 215fb43630cSZhang Yubing struct dp_sdp_header header; 216fb43630cSZhang Yubing u8 db[32]; 217fb43630cSZhang Yubing unsigned long flags; 218fb43630cSZhang Yubing }; 219fb43630cSZhang Yubing 2205fc83b1eSZhang Yubing struct dw_dp_chip_data { 2215fc83b1eSZhang Yubing int pixel_mode; 2225fc83b1eSZhang Yubing }; 2235fc83b1eSZhang Yubing 224fb43630cSZhang Yubing struct dw_dp { 2250594ce39SZhang Yubing struct rockchip_connector connector; 226fb43630cSZhang Yubing struct udevice *dev; 227fb43630cSZhang Yubing struct regmap *regmap; 228fb43630cSZhang Yubing struct phy phy; 229fb43630cSZhang Yubing struct reset_ctl reset; 230fb43630cSZhang Yubing int id; 231fb43630cSZhang Yubing 232fb43630cSZhang Yubing struct gpio_desc hpd_gpio; 233fb43630cSZhang Yubing struct drm_dp_aux aux; 234fb43630cSZhang Yubing struct dw_dp_link link; 235fb43630cSZhang Yubing struct dw_dp_video video; 2365efdd3e2SZhang Yubing 2375fbef17aSZhang Yubing bool force_hpd; 2385efdd3e2SZhang Yubing bool force_output; 239549d42b6SWyon Bi u32 max_link_rate; 240fb43630cSZhang Yubing }; 241fb43630cSZhang Yubing 242fb43630cSZhang Yubing enum { 243fb43630cSZhang Yubing SOURCE_STATE_IDLE, 244fb43630cSZhang Yubing SOURCE_STATE_UNPLUG, 245fb43630cSZhang Yubing SOURCE_STATE_HPD_TIMEOUT = 4, 246fb43630cSZhang Yubing SOURCE_STATE_PLUG = 7 247fb43630cSZhang Yubing }; 248fb43630cSZhang Yubing 249fb43630cSZhang Yubing enum { 250fb43630cSZhang Yubing DPTX_VM_RGB_6BIT, 251fb43630cSZhang Yubing DPTX_VM_RGB_8BIT, 252fb43630cSZhang Yubing DPTX_VM_RGB_10BIT, 253fb43630cSZhang Yubing DPTX_VM_RGB_12BIT, 254fb43630cSZhang Yubing DPTX_VM_RGB_16BIT, 255fb43630cSZhang Yubing DPTX_VM_YCBCR444_8BIT, 256fb43630cSZhang Yubing DPTX_VM_YCBCR444_10BIT, 257fb43630cSZhang Yubing DPTX_VM_YCBCR444_12BIT, 258fb43630cSZhang Yubing DPTX_VM_YCBCR444_16BIT, 259fb43630cSZhang Yubing DPTX_VM_YCBCR422_8BIT, 260fb43630cSZhang Yubing DPTX_VM_YCBCR422_10BIT, 261fb43630cSZhang Yubing DPTX_VM_YCBCR422_12BIT, 262fb43630cSZhang Yubing DPTX_VM_YCBCR422_16BIT, 263fb43630cSZhang Yubing DPTX_VM_YCBCR420_8BIT, 264fb43630cSZhang Yubing DPTX_VM_YCBCR420_10BIT, 265fb43630cSZhang Yubing DPTX_VM_YCBCR420_12BIT, 266fb43630cSZhang Yubing DPTX_VM_YCBCR420_16BIT, 267fb43630cSZhang Yubing }; 268fb43630cSZhang Yubing 269fb43630cSZhang Yubing enum { 270fb43630cSZhang Yubing DPTX_MP_SINGLE_PIXEL, 271fb43630cSZhang Yubing DPTX_MP_DUAL_PIXEL, 272fb43630cSZhang Yubing DPTX_MP_QUAD_PIXEL, 273fb43630cSZhang Yubing }; 274fb43630cSZhang Yubing 275fb43630cSZhang Yubing enum { 276fb43630cSZhang Yubing DPTX_SDP_VERTICAL_INTERVAL = BIT(0), 277fb43630cSZhang Yubing DPTX_SDP_HORIZONTAL_INTERVAL = BIT(1), 278fb43630cSZhang Yubing }; 279fb43630cSZhang Yubing 280fb43630cSZhang Yubing enum { 281fb43630cSZhang Yubing DPTX_PHY_PATTERN_NONE, 282fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_1, 283fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_2, 284fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_3, 285fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_4, 286fb43630cSZhang Yubing DPTX_PHY_PATTERN_SERM, 287fb43630cSZhang Yubing DPTX_PHY_PATTERN_PBRS7, 288fb43630cSZhang Yubing DPTX_PHY_PATTERN_CUSTOM_80BIT, 289fb43630cSZhang Yubing DPTX_PHY_PATTERN_CP2520_1, 290fb43630cSZhang Yubing DPTX_PHY_PATTERN_CP2520_2, 291fb43630cSZhang Yubing }; 292fb43630cSZhang Yubing 2935efdd3e2SZhang Yubing enum { 2945efdd3e2SZhang Yubing DPTX_PHYRATE_RBR, 2955efdd3e2SZhang Yubing DPTX_PHYRATE_HBR, 2965efdd3e2SZhang Yubing DPTX_PHYRATE_HBR2, 2975efdd3e2SZhang Yubing DPTX_PHYRATE_HBR3, 2985efdd3e2SZhang Yubing }; 2995efdd3e2SZhang Yubing 300fb43630cSZhang Yubing struct dw_dp_output_format { 301fb43630cSZhang Yubing u32 bus_format; 302fb43630cSZhang Yubing u32 color_format; 303fb43630cSZhang Yubing u8 video_mapping; 304fb43630cSZhang Yubing u8 bpc; 305fb43630cSZhang Yubing u8 bpp; 306fb43630cSZhang Yubing }; 307fb43630cSZhang Yubing 308fb43630cSZhang Yubing static const struct dw_dp_output_format possible_output_fmts[] = { 309fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, 310fb43630cSZhang Yubing DPTX_VM_RGB_10BIT, 10, 30 }, 311fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, 312fb43630cSZhang Yubing DPTX_VM_RGB_8BIT, 8, 24 }, 313fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444, 314fb43630cSZhang Yubing DPTX_VM_YCBCR444_10BIT, 10, 30 }, 315fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444, 316fb43630cSZhang Yubing DPTX_VM_YCBCR444_8BIT, 8, 24}, 317fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422, 318fb43630cSZhang Yubing DPTX_VM_YCBCR422_10BIT, 10, 20 }, 319fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422, 320fb43630cSZhang Yubing DPTX_VM_YCBCR422_8BIT, 8, 16 }, 321fb43630cSZhang Yubing { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCRCB420, 322fb43630cSZhang Yubing DPTX_VM_YCBCR420_10BIT, 10, 15 }, 323fb43630cSZhang Yubing { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCRCB420, 324fb43630cSZhang Yubing DPTX_VM_YCBCR420_8BIT, 8, 12 }, 325fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, 326fb43630cSZhang Yubing DPTX_VM_RGB_6BIT, 6, 18 }, 327fb43630cSZhang Yubing }; 328fb43630cSZhang Yubing 329fb43630cSZhang Yubing static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size) 330fb43630cSZhang Yubing { 331fb43630cSZhang Yubing size_t i, j; 332fb43630cSZhang Yubing 333fb43630cSZhang Yubing for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { 334fb43630cSZhang Yubing size_t num = min_t(size_t, size - i * 4, 4); 335fb43630cSZhang Yubing u32 value = 0; 336fb43630cSZhang Yubing 337fb43630cSZhang Yubing for (j = 0; j < num; j++) 338fb43630cSZhang Yubing value |= buffer[i * 4 + j] << (j * 8); 339fb43630cSZhang Yubing 340fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_AUX_DATA0 + i * 4, value); 341fb43630cSZhang Yubing } 342fb43630cSZhang Yubing 343fb43630cSZhang Yubing return size; 344fb43630cSZhang Yubing } 345fb43630cSZhang Yubing 346fb43630cSZhang Yubing static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size) 347fb43630cSZhang Yubing { 348fb43630cSZhang Yubing size_t i, j; 349fb43630cSZhang Yubing 350fb43630cSZhang Yubing for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { 351fb43630cSZhang Yubing size_t num = min_t(size_t, size - i * 4, 4); 352fb43630cSZhang Yubing u32 value; 353fb43630cSZhang Yubing 354fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_AUX_DATA0 + i * 4, &value); 355fb43630cSZhang Yubing 356fb43630cSZhang Yubing for (j = 0; j < num; j++) 357fb43630cSZhang Yubing buffer[i * 4 + j] = value >> (j * 8); 358fb43630cSZhang Yubing } 359fb43630cSZhang Yubing 360fb43630cSZhang Yubing return size; 361fb43630cSZhang Yubing } 362fb43630cSZhang Yubing 363fb43630cSZhang Yubing static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, 364fb43630cSZhang Yubing struct drm_dp_aux_msg *msg) 365fb43630cSZhang Yubing { 366fb43630cSZhang Yubing u32 status, value; 367fb43630cSZhang Yubing ssize_t ret = 0; 368fb43630cSZhang Yubing int timeout = 0; 369fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(aux->dev); 370fb43630cSZhang Yubing 371fb43630cSZhang Yubing if (WARN_ON(msg->size > 16)) 372fb43630cSZhang Yubing return -E2BIG; 373fb43630cSZhang Yubing 374fb43630cSZhang Yubing switch (msg->request & ~DP_AUX_I2C_MOT) { 375fb43630cSZhang Yubing case DP_AUX_NATIVE_WRITE: 376fb43630cSZhang Yubing case DP_AUX_I2C_WRITE: 377fb43630cSZhang Yubing case DP_AUX_I2C_WRITE_STATUS_UPDATE: 378fb43630cSZhang Yubing ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size); 379fb43630cSZhang Yubing if (ret < 0) 380fb43630cSZhang Yubing return ret; 381fb43630cSZhang Yubing break; 382fb43630cSZhang Yubing case DP_AUX_NATIVE_READ: 383fb43630cSZhang Yubing case DP_AUX_I2C_READ: 384fb43630cSZhang Yubing break; 385fb43630cSZhang Yubing default: 386fb43630cSZhang Yubing return -EINVAL; 387fb43630cSZhang Yubing } 388fb43630cSZhang Yubing 389fb43630cSZhang Yubing if (msg->size > 0) 390fb43630cSZhang Yubing value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1); 391fb43630cSZhang Yubing else 392fb43630cSZhang Yubing value = FIELD_PREP(I2C_ADDR_ONLY, 1); 393fb43630cSZhang Yubing 394fb43630cSZhang Yubing value |= FIELD_PREP(AUX_CMD_TYPE, msg->request); 395fb43630cSZhang Yubing value |= FIELD_PREP(AUX_ADDR, msg->address); 396fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_AUX_CMD, value); 397fb43630cSZhang Yubing 398fb43630cSZhang Yubing timeout = regmap_read_poll_timeout(dp->regmap, DPTX_GENERAL_INTERRUPT, 399fb43630cSZhang Yubing status, status & AUX_REPLY_EVENT, 400fb43630cSZhang Yubing 200, 10); 401fb43630cSZhang Yubing 402fb43630cSZhang Yubing if (timeout) { 403fb43630cSZhang Yubing printf("timeout waiting for AUX reply\n"); 404fb43630cSZhang Yubing return -ETIMEDOUT; 405fb43630cSZhang Yubing } 406fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_GENERAL_INTERRUPT, AUX_REPLY_EVENT); 407fb43630cSZhang Yubing 408fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_AUX_STATUS, &value); 409fb43630cSZhang Yubing if (value & AUX_TIMEOUT) { 410fb43630cSZhang Yubing printf("aux timeout\n"); 411fb43630cSZhang Yubing return -ETIMEDOUT; 412fb43630cSZhang Yubing } 413fb43630cSZhang Yubing 414fb43630cSZhang Yubing msg->reply = FIELD_GET(AUX_STATUS, value); 415fb43630cSZhang Yubing 416fb43630cSZhang Yubing if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) { 417fb43630cSZhang Yubing if (msg->request & DP_AUX_I2C_READ) { 418fb43630cSZhang Yubing size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1; 419fb43630cSZhang Yubing 420fb43630cSZhang Yubing if (count != msg->size) { 421fb43630cSZhang Yubing printf("aux fail to read %lu bytes\n", count); 422fb43630cSZhang Yubing return -EBUSY; 423fb43630cSZhang Yubing } 424fb43630cSZhang Yubing 425fb43630cSZhang Yubing ret = dw_dp_aux_read_data(dp, msg->buffer, count); 426fb43630cSZhang Yubing if (ret < 0) 427fb43630cSZhang Yubing return ret; 428fb43630cSZhang Yubing } 429fb43630cSZhang Yubing } 430fb43630cSZhang Yubing 431fb43630cSZhang Yubing return ret; 432fb43630cSZhang Yubing } 433fb43630cSZhang Yubing 434fb43630cSZhang Yubing static bool dw_dp_bandwidth_ok(struct dw_dp *dp, 435fb43630cSZhang Yubing const struct drm_display_mode *mode, u32 bpp, 436fb43630cSZhang Yubing unsigned int lanes, unsigned int rate) 437fb43630cSZhang Yubing { 438fb43630cSZhang Yubing u32 max_bw, req_bw; 439fb43630cSZhang Yubing 440fb43630cSZhang Yubing req_bw = mode->clock * bpp / 8; 441fb43630cSZhang Yubing max_bw = lanes * rate; 442fb43630cSZhang Yubing if (req_bw > max_bw) 443fb43630cSZhang Yubing return false; 444fb43630cSZhang Yubing 445fb43630cSZhang Yubing return true; 446fb43630cSZhang Yubing } 447fb43630cSZhang Yubing 448fb43630cSZhang Yubing static void dw_dp_hpd_init(struct dw_dp *dp) 449fb43630cSZhang Yubing { 4505fbef17aSZhang Yubing if (dm_gpio_is_valid(&dp->hpd_gpio) || dp->force_hpd) { 451fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD, 452fb43630cSZhang Yubing FIELD_PREP(FORCE_HPD, 1)); 453fb43630cSZhang Yubing return; 454fb43630cSZhang Yubing } 455fb43630cSZhang Yubing 456fb43630cSZhang Yubing /* Enable all HPD interrupts */ 457fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_HPD_INTERRUPT_ENABLE, 458fb43630cSZhang Yubing HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN, 459fb43630cSZhang Yubing FIELD_PREP(HPD_UNPLUG_EN, 1) | 460fb43630cSZhang Yubing FIELD_PREP(HPD_PLUG_EN, 1) | 461fb43630cSZhang Yubing FIELD_PREP(HPD_IRQ_EN, 1)); 462fb43630cSZhang Yubing 463fb43630cSZhang Yubing /* Enable all top-level interrupts */ 464fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE, 465fb43630cSZhang Yubing HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1)); 466fb43630cSZhang Yubing } 467fb43630cSZhang Yubing 468fb43630cSZhang Yubing static void dw_dp_aux_init(struct dw_dp *dp) 469fb43630cSZhang Yubing { 470fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET, 471fb43630cSZhang Yubing FIELD_PREP(AUX_RESET, 1)); 472fb43630cSZhang Yubing udelay(10); 473fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET, 474fb43630cSZhang Yubing FIELD_PREP(AUX_RESET, 0)); 475fb43630cSZhang Yubing 476fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE, 477fb43630cSZhang Yubing AUX_REPLY_EVENT_EN, 478fb43630cSZhang Yubing FIELD_PREP(AUX_REPLY_EVENT_EN, 1)); 479fb43630cSZhang Yubing } 480fb43630cSZhang Yubing 481fb43630cSZhang Yubing static void dw_dp_init(struct dw_dp *dp) 482fb43630cSZhang Yubing { 483fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET, 484fb43630cSZhang Yubing FIELD_PREP(CONTROLLER_RESET, 1)); 485fb43630cSZhang Yubing udelay(10); 486fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET, 487fb43630cSZhang Yubing FIELD_PREP(CONTROLLER_RESET, 0)); 488fb43630cSZhang Yubing 489fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET, 490fb43630cSZhang Yubing FIELD_PREP(PHY_SOFT_RESET, 1)); 491fb43630cSZhang Yubing udelay(10); 492fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET, 493fb43630cSZhang Yubing FIELD_PREP(PHY_SOFT_RESET, 0)); 494fb43630cSZhang Yubing 495fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, DEFAULT_FAST_LINK_TRAIN_EN, 496fb43630cSZhang Yubing FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0)); 497fb43630cSZhang Yubing 498fb43630cSZhang Yubing dw_dp_hpd_init(dp); 499fb43630cSZhang Yubing dw_dp_aux_init(dp); 500fb43630cSZhang Yubing } 501fb43630cSZhang Yubing 502fb43630cSZhang Yubing static void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern) 503fb43630cSZhang Yubing { 504fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, TPS_SEL, 505fb43630cSZhang Yubing FIELD_PREP(TPS_SEL, pattern)); 506fb43630cSZhang Yubing } 507fb43630cSZhang Yubing 508fb43630cSZhang Yubing static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes) 509fb43630cSZhang Yubing { 510fb43630cSZhang Yubing u32 xmit_enable; 511fb43630cSZhang Yubing 512fb43630cSZhang Yubing switch (lanes) { 513fb43630cSZhang Yubing case 4: 514fb43630cSZhang Yubing case 2: 515fb43630cSZhang Yubing case 1: 516fb43630cSZhang Yubing xmit_enable = GENMASK(lanes - 1, 0); 517fb43630cSZhang Yubing break; 518fb43630cSZhang Yubing case 0: 519fb43630cSZhang Yubing default: 520fb43630cSZhang Yubing xmit_enable = 0; 521fb43630cSZhang Yubing break; 522fb43630cSZhang Yubing } 523fb43630cSZhang Yubing 524fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, XMIT_ENABLE, 525fb43630cSZhang Yubing FIELD_PREP(XMIT_ENABLE, xmit_enable)); 526fb43630cSZhang Yubing } 527fb43630cSZhang Yubing 528fb43630cSZhang Yubing static int dw_dp_link_power_up(struct dw_dp *dp) 529fb43630cSZhang Yubing { 530fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 531fb43630cSZhang Yubing u8 value; 532fb43630cSZhang Yubing int ret; 533fb43630cSZhang Yubing 534fb43630cSZhang Yubing if (link->revision < 0x11) 535fb43630cSZhang Yubing return 0; 536fb43630cSZhang Yubing 537fb43630cSZhang Yubing ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); 538fb43630cSZhang Yubing if (ret < 0) 539fb43630cSZhang Yubing return ret; 540fb43630cSZhang Yubing 541fb43630cSZhang Yubing value &= ~DP_SET_POWER_MASK; 542fb43630cSZhang Yubing value |= DP_SET_POWER_D0; 543fb43630cSZhang Yubing 544fb43630cSZhang Yubing ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); 545fb43630cSZhang Yubing if (ret < 0) 546fb43630cSZhang Yubing return ret; 547fb43630cSZhang Yubing 548fb43630cSZhang Yubing udelay(1000); 549fb43630cSZhang Yubing return 0; 550fb43630cSZhang Yubing } 551fb43630cSZhang Yubing 552fb43630cSZhang Yubing static int dw_dp_link_probe(struct dw_dp *dp) 553fb43630cSZhang Yubing { 554fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 555fb43630cSZhang Yubing u8 dpcd; 556fb43630cSZhang Yubing int ret; 557fb43630cSZhang Yubing 5582493a680SZhang Yubing drm_dp_dpcd_writeb(&dp->aux, DP_MSTM_CTRL, 0); 559fb43630cSZhang Yubing ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd); 560fb43630cSZhang Yubing if (ret < 0) 561fb43630cSZhang Yubing return ret; 562fb43630cSZhang Yubing 563fb43630cSZhang Yubing ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, 564fb43630cSZhang Yubing &dpcd); 565fb43630cSZhang Yubing if (ret < 0) 566fb43630cSZhang Yubing return ret; 567fb43630cSZhang Yubing 568fb43630cSZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported = 569fb43630cSZhang Yubing !!(dpcd & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED); 570fb43630cSZhang Yubing 571fb43630cSZhang Yubing link->revision = link->dpcd[DP_DPCD_REV]; 572549d42b6SWyon Bi link->rate = min_t(u32, min(dp->max_link_rate, dp->phy.attrs.max_link_rate * 100), 573ca4b9d14SWyon Bi drm_dp_max_link_rate(link->dpcd)); 574fb43630cSZhang Yubing link->lanes = min_t(u8, dp->phy.attrs.bus_width, 575fb43630cSZhang Yubing drm_dp_max_lane_count(link->dpcd)); 576fb43630cSZhang Yubing 577fb43630cSZhang Yubing link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd); 578fb43630cSZhang Yubing link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd); 579fb43630cSZhang Yubing link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd); 580fb43630cSZhang Yubing link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd); 581fb43630cSZhang Yubing link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] & 582fb43630cSZhang Yubing DP_MAX_DOWNSPREAD_0_5); 583fb43630cSZhang Yubing 584fb43630cSZhang Yubing return 0; 585fb43630cSZhang Yubing } 586fb43630cSZhang Yubing 587fb43630cSZhang Yubing static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp) 588fb43630cSZhang Yubing { 589fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 590fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &link->train.request; 591fb43630cSZhang Yubing union phy_configure_opts phy_cfg; 592fb43630cSZhang Yubing unsigned int lanes = link->lanes, *vs, *pe; 593fb43630cSZhang Yubing u8 buf[4]; 594fb43630cSZhang Yubing int i, ret; 595fb43630cSZhang Yubing 596fb43630cSZhang Yubing vs = request->voltage_swing; 597fb43630cSZhang Yubing pe = request->pre_emphasis; 598fb43630cSZhang Yubing 599fb43630cSZhang Yubing for (i = 0; i < lanes; i++) { 600fb43630cSZhang Yubing phy_cfg.dp.voltage[i] = vs[i]; 601fb43630cSZhang Yubing phy_cfg.dp.pre[i] = pe[i]; 602fb43630cSZhang Yubing } 603fb43630cSZhang Yubing phy_cfg.dp.lanes = lanes; 604fb43630cSZhang Yubing phy_cfg.dp.link_rate = link->rate / 100; 605fb43630cSZhang Yubing phy_cfg.dp.set_lanes = false; 606fb43630cSZhang Yubing phy_cfg.dp.set_rate = false; 607fb43630cSZhang Yubing phy_cfg.dp.set_voltages = true; 608fb43630cSZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg); 609fb43630cSZhang Yubing if (ret) 610fb43630cSZhang Yubing return ret; 611fb43630cSZhang Yubing 612fb43630cSZhang Yubing for (i = 0; i < lanes; i++) 613fb43630cSZhang Yubing buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) | 614fb43630cSZhang Yubing (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT); 615fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes); 616fb43630cSZhang Yubing if (ret < 0) 617fb43630cSZhang Yubing return ret; 618fb43630cSZhang Yubing 619fb43630cSZhang Yubing return 0; 620fb43630cSZhang Yubing } 621fb43630cSZhang Yubing 622fb43630cSZhang Yubing static int dw_dp_link_configure(struct dw_dp *dp) 623fb43630cSZhang Yubing { 624fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 625fb43630cSZhang Yubing union phy_configure_opts phy_cfg; 626fb43630cSZhang Yubing u8 buf[2]; 6275efdd3e2SZhang Yubing int ret, phy_rate; 628fb43630cSZhang Yubing 629fb43630cSZhang Yubing /* Move PHY to P3 */ 630fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 631fb43630cSZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x3)); 632fb43630cSZhang Yubing 633fb43630cSZhang Yubing phy_cfg.dp.lanes = link->lanes; 634fb43630cSZhang Yubing phy_cfg.dp.link_rate = link->rate / 100; 635fb43630cSZhang Yubing phy_cfg.dp.ssc = link->caps.ssc; 636fb43630cSZhang Yubing phy_cfg.dp.set_lanes = true; 637fb43630cSZhang Yubing phy_cfg.dp.set_rate = true; 638fb43630cSZhang Yubing phy_cfg.dp.set_voltages = false; 639fb43630cSZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg); 640fb43630cSZhang Yubing if (ret) 641fb43630cSZhang Yubing return ret; 642fb43630cSZhang Yubing 643fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES, 644fb43630cSZhang Yubing FIELD_PREP(PHY_LANES, link->lanes / 2)); 645fb43630cSZhang Yubing 6465efdd3e2SZhang Yubing switch (link->rate) { 6475efdd3e2SZhang Yubing case 810000: 6485efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR3; 6495efdd3e2SZhang Yubing break; 6505efdd3e2SZhang Yubing case 540000: 6515efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR2; 6525efdd3e2SZhang Yubing break; 6535efdd3e2SZhang Yubing case 270000: 6545efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR; 6555efdd3e2SZhang Yubing break; 6565efdd3e2SZhang Yubing case 162000: 6575efdd3e2SZhang Yubing default: 6585efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_RBR; 6595efdd3e2SZhang Yubing break; 6605efdd3e2SZhang Yubing } 6615efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE, 6625efdd3e2SZhang Yubing FIELD_PREP(PHY_RATE, phy_rate)); 6635efdd3e2SZhang Yubing 664fb43630cSZhang Yubing /* Move PHY to P0 */ 665fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 666fb43630cSZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x0)); 667fb43630cSZhang Yubing 668fb43630cSZhang Yubing dw_dp_phy_xmit_enable(dp, link->lanes); 669fb43630cSZhang Yubing 670fb43630cSZhang Yubing buf[0] = drm_dp_link_rate_to_bw_code(link->rate); 671fb43630cSZhang Yubing buf[1] = link->lanes; 672fb43630cSZhang Yubing 673fb43630cSZhang Yubing if (link->caps.enhanced_framing) { 674fb43630cSZhang Yubing buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; 675fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, 676fb43630cSZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 1)); 677fb43630cSZhang Yubing } else { 678fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, 679fb43630cSZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 0)); 680fb43630cSZhang Yubing } 681fb43630cSZhang Yubing 682fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf)); 683fb43630cSZhang Yubing if (ret < 0) 684fb43630cSZhang Yubing return ret; 685fb43630cSZhang Yubing 686fb43630cSZhang Yubing buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0; 687fb43630cSZhang Yubing buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0; 688fb43630cSZhang Yubing 689fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, 690fb43630cSZhang Yubing sizeof(buf)); 691fb43630cSZhang Yubing if (ret < 0) 692fb43630cSZhang Yubing return ret; 693fb43630cSZhang Yubing 694fb43630cSZhang Yubing return 0; 695fb43630cSZhang Yubing } 696fb43630cSZhang Yubing 697fb43630cSZhang Yubing static void dw_dp_link_train_init(struct drm_dp_link_train *train) 698fb43630cSZhang Yubing { 699fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &train->request; 700fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &train->adjust; 701fb43630cSZhang Yubing unsigned int i; 702fb43630cSZhang Yubing 703fb43630cSZhang Yubing for (i = 0; i < 4; i++) { 704fb43630cSZhang Yubing request->voltage_swing[i] = 0; 705fb43630cSZhang Yubing adjust->voltage_swing[i] = 0; 706fb43630cSZhang Yubing 707fb43630cSZhang Yubing request->pre_emphasis[i] = 0; 708fb43630cSZhang Yubing adjust->pre_emphasis[i] = 0; 709fb43630cSZhang Yubing } 710fb43630cSZhang Yubing 711fb43630cSZhang Yubing train->clock_recovered = false; 712fb43630cSZhang Yubing train->channel_equalized = false; 713fb43630cSZhang Yubing } 714fb43630cSZhang Yubing 715fb43630cSZhang Yubing static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern) 716fb43630cSZhang Yubing { 717fb43630cSZhang Yubing u8 buf = 0; 718fb43630cSZhang Yubing int ret; 719fb43630cSZhang Yubing 720fb43630cSZhang Yubing if (pattern && pattern != DP_TRAINING_PATTERN_4) { 721fb43630cSZhang Yubing buf |= DP_LINK_SCRAMBLING_DISABLE; 722fb43630cSZhang Yubing 723fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS, 724fb43630cSZhang Yubing FIELD_PREP(SCRAMBLE_DIS, 1)); 725fb43630cSZhang Yubing } else { 726fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS, 727fb43630cSZhang Yubing FIELD_PREP(SCRAMBLE_DIS, 0)); 728fb43630cSZhang Yubing } 729fb43630cSZhang Yubing 730fb43630cSZhang Yubing switch (pattern) { 731fb43630cSZhang Yubing case DP_TRAINING_PATTERN_DISABLE: 732fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE); 733fb43630cSZhang Yubing break; 734fb43630cSZhang Yubing case DP_TRAINING_PATTERN_1: 735fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_1); 736fb43630cSZhang Yubing break; 737fb43630cSZhang Yubing case DP_TRAINING_PATTERN_2: 738fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_2); 739fb43630cSZhang Yubing break; 740fb43630cSZhang Yubing case DP_TRAINING_PATTERN_3: 741fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_3); 742fb43630cSZhang Yubing break; 743fb43630cSZhang Yubing case DP_TRAINING_PATTERN_4: 744fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_4); 745fb43630cSZhang Yubing break; 746fb43630cSZhang Yubing default: 747fb43630cSZhang Yubing return -EINVAL; 748fb43630cSZhang Yubing } 749fb43630cSZhang Yubing 750fb43630cSZhang Yubing ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 751fb43630cSZhang Yubing buf | pattern); 752fb43630cSZhang Yubing if (ret < 0) 753fb43630cSZhang Yubing return ret; 754fb43630cSZhang Yubing 755fb43630cSZhang Yubing return 0; 756fb43630cSZhang Yubing } 757fb43630cSZhang Yubing 758fb43630cSZhang Yubing static void dw_dp_link_get_adjustments(struct dw_dp_link *link, 759fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE]) 760fb43630cSZhang Yubing { 761fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &link->train.adjust; 762fb43630cSZhang Yubing unsigned int i; 763fb43630cSZhang Yubing 764fb43630cSZhang Yubing for (i = 0; i < link->lanes; i++) { 765fb43630cSZhang Yubing adjust->voltage_swing[i] = 766fb43630cSZhang Yubing drm_dp_get_adjust_request_voltage(status, i) >> 767fb43630cSZhang Yubing DP_TRAIN_VOLTAGE_SWING_SHIFT; 768fb43630cSZhang Yubing 769fb43630cSZhang Yubing adjust->pre_emphasis[i] = 770fb43630cSZhang Yubing drm_dp_get_adjust_request_pre_emphasis(status, i) >> 771fb43630cSZhang Yubing DP_TRAIN_PRE_EMPHASIS_SHIFT; 772fb43630cSZhang Yubing } 773fb43630cSZhang Yubing } 774fb43630cSZhang Yubing 775fb43630cSZhang Yubing static void dw_dp_link_train_adjust(struct drm_dp_link_train *train) 776fb43630cSZhang Yubing { 777fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &train->request; 778fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &train->adjust; 779fb43630cSZhang Yubing unsigned int i; 780fb43630cSZhang Yubing 781fb43630cSZhang Yubing for (i = 0; i < 4; i++) 782fb43630cSZhang Yubing if (request->voltage_swing[i] != adjust->voltage_swing[i]) 783fb43630cSZhang Yubing request->voltage_swing[i] = adjust->voltage_swing[i]; 784fb43630cSZhang Yubing 785fb43630cSZhang Yubing for (i = 0; i < 4; i++) 786fb43630cSZhang Yubing if (request->pre_emphasis[i] != adjust->pre_emphasis[i]) 787fb43630cSZhang Yubing request->pre_emphasis[i] = adjust->pre_emphasis[i]; 788fb43630cSZhang Yubing } 789fb43630cSZhang Yubing 790fb43630cSZhang Yubing static int dw_dp_link_clock_recovery(struct dw_dp *dp) 791fb43630cSZhang Yubing { 792fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 793fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE]; 794fb43630cSZhang Yubing unsigned int tries = 0; 795fb43630cSZhang Yubing int ret; 796fb43630cSZhang Yubing 797fb43630cSZhang Yubing ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1); 798fb43630cSZhang Yubing if (ret) 799fb43630cSZhang Yubing return ret; 800fb43630cSZhang Yubing 801fb43630cSZhang Yubing for (;;) { 802fb43630cSZhang Yubing ret = dw_dp_link_train_update_vs_emph(dp); 803fb43630cSZhang Yubing if (ret) 804fb43630cSZhang Yubing return ret; 805fb43630cSZhang Yubing 806fb43630cSZhang Yubing drm_dp_link_train_clock_recovery_delay(link->dpcd); 807fb43630cSZhang Yubing 808fb43630cSZhang Yubing ret = drm_dp_dpcd_read_link_status(&dp->aux, status); 809fb43630cSZhang Yubing if (ret < 0) { 810fb43630cSZhang Yubing dev_err(dp->dev, "failed to read link status: %d\n", 811fb43630cSZhang Yubing ret); 812fb43630cSZhang Yubing return ret; 813fb43630cSZhang Yubing } 814fb43630cSZhang Yubing 815fb43630cSZhang Yubing if (drm_dp_clock_recovery_ok(status, link->lanes)) { 816fb43630cSZhang Yubing link->train.clock_recovered = true; 817fb43630cSZhang Yubing break; 818fb43630cSZhang Yubing } 819fb43630cSZhang Yubing 820fb43630cSZhang Yubing dw_dp_link_get_adjustments(link, status); 821fb43630cSZhang Yubing 822fb43630cSZhang Yubing if (link->train.request.voltage_swing[0] == 823fb43630cSZhang Yubing link->train.adjust.voltage_swing[0]) 824fb43630cSZhang Yubing tries++; 825fb43630cSZhang Yubing else 826fb43630cSZhang Yubing tries = 0; 827fb43630cSZhang Yubing 828fb43630cSZhang Yubing if (tries == 5) 829fb43630cSZhang Yubing break; 830fb43630cSZhang Yubing 831fb43630cSZhang Yubing dw_dp_link_train_adjust(&link->train); 832fb43630cSZhang Yubing } 833fb43630cSZhang Yubing 834fb43630cSZhang Yubing return 0; 835fb43630cSZhang Yubing } 836fb43630cSZhang Yubing 837fb43630cSZhang Yubing static int dw_dp_link_channel_equalization(struct dw_dp *dp) 838fb43630cSZhang Yubing { 839fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 840fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE], pattern; 841fb43630cSZhang Yubing unsigned int tries; 842fb43630cSZhang Yubing int ret; 843fb43630cSZhang Yubing 844fb43630cSZhang Yubing if (link->caps.tps4_supported) 845fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_4; 846fb43630cSZhang Yubing else if (link->caps.tps3_supported) 847fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_3; 848fb43630cSZhang Yubing else 849fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_2; 850fb43630cSZhang Yubing ret = dw_dp_link_train_set_pattern(dp, pattern); 851fb43630cSZhang Yubing if (ret) 852fb43630cSZhang Yubing return ret; 853fb43630cSZhang Yubing 854fb43630cSZhang Yubing for (tries = 1; tries < 5; tries++) { 855fb43630cSZhang Yubing ret = dw_dp_link_train_update_vs_emph(dp); 856fb43630cSZhang Yubing if (ret) 857fb43630cSZhang Yubing return ret; 858fb43630cSZhang Yubing 859fb43630cSZhang Yubing drm_dp_link_train_channel_eq_delay(link->dpcd); 860fb43630cSZhang Yubing 861fb43630cSZhang Yubing ret = drm_dp_dpcd_read_link_status(&dp->aux, status); 862fb43630cSZhang Yubing if (ret < 0) 863fb43630cSZhang Yubing return ret; 864fb43630cSZhang Yubing 865fb43630cSZhang Yubing if (!drm_dp_clock_recovery_ok(status, link->lanes)) { 866fb43630cSZhang Yubing dev_err(dp->dev, 867fb43630cSZhang Yubing "clock recovery lost while eq\n"); 868fb43630cSZhang Yubing link->train.clock_recovered = false; 869fb43630cSZhang Yubing break; 870fb43630cSZhang Yubing } 871fb43630cSZhang Yubing 872fb43630cSZhang Yubing if (drm_dp_channel_eq_ok(status, link->lanes)) { 873fb43630cSZhang Yubing link->train.channel_equalized = true; 874fb43630cSZhang Yubing break; 875fb43630cSZhang Yubing } 876fb43630cSZhang Yubing 877fb43630cSZhang Yubing dw_dp_link_get_adjustments(link, status); 878fb43630cSZhang Yubing dw_dp_link_train_adjust(&link->train); 879fb43630cSZhang Yubing } 880fb43630cSZhang Yubing 881fb43630cSZhang Yubing return 0; 882fb43630cSZhang Yubing } 883fb43630cSZhang Yubing 884fb43630cSZhang Yubing static int dw_dp_link_downgrade(struct dw_dp *dp) 885fb43630cSZhang Yubing { 886fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 887fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 888fb43630cSZhang Yubing 889fb43630cSZhang Yubing switch (link->rate) { 890fb43630cSZhang Yubing case 162000: 891fb43630cSZhang Yubing return -EINVAL; 892fb43630cSZhang Yubing case 270000: 893fb43630cSZhang Yubing link->rate = 162000; 894fb43630cSZhang Yubing break; 895fb43630cSZhang Yubing case 540000: 896fb43630cSZhang Yubing link->rate = 270000; 897fb43630cSZhang Yubing break; 898fb43630cSZhang Yubing case 810000: 899fb43630cSZhang Yubing link->rate = 540000; 900fb43630cSZhang Yubing break; 901fb43630cSZhang Yubing } 902fb43630cSZhang Yubing 903fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, &video->mode, video->bpp, link->lanes, 904fb43630cSZhang Yubing link->rate)) 905fb43630cSZhang Yubing return -E2BIG; 906fb43630cSZhang Yubing 907fb43630cSZhang Yubing return 0; 908fb43630cSZhang Yubing } 909fb43630cSZhang Yubing 910fb43630cSZhang Yubing static int dw_dp_link_train(struct dw_dp *dp) 911fb43630cSZhang Yubing { 912fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 913fb43630cSZhang Yubing int ret; 914fb43630cSZhang Yubing 915fb43630cSZhang Yubing retry: 916fb43630cSZhang Yubing dw_dp_link_train_init(&link->train); 917fb43630cSZhang Yubing 918fb43630cSZhang Yubing printf("training link: %u lane%s at %u MHz\n", 919fb43630cSZhang Yubing link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100); 920fb43630cSZhang Yubing 921fb43630cSZhang Yubing ret = dw_dp_link_configure(dp); 922fb43630cSZhang Yubing if (ret < 0) { 923fb43630cSZhang Yubing dev_err(dp->dev, "failed to configure DP link: %d\n", ret); 924fb43630cSZhang Yubing return ret; 925fb43630cSZhang Yubing } 926fb43630cSZhang Yubing 927fb43630cSZhang Yubing ret = dw_dp_link_clock_recovery(dp); 928fb43630cSZhang Yubing if (ret < 0) { 929fb43630cSZhang Yubing dev_err(dp->dev, "clock recovery failed: %d\n", ret); 930fb43630cSZhang Yubing goto out; 931fb43630cSZhang Yubing } 932fb43630cSZhang Yubing 933fb43630cSZhang Yubing if (!link->train.clock_recovered) { 934fb43630cSZhang Yubing dev_err(dp->dev, "clock recovery failed, downgrading link\n"); 935fb43630cSZhang Yubing 936fb43630cSZhang Yubing ret = dw_dp_link_downgrade(dp); 937fb43630cSZhang Yubing if (ret < 0) 938fb43630cSZhang Yubing goto out; 939fb43630cSZhang Yubing else 940fb43630cSZhang Yubing goto retry; 941fb43630cSZhang Yubing } 942fb43630cSZhang Yubing 943fb43630cSZhang Yubing printf("clock recovery succeeded\n"); 944fb43630cSZhang Yubing 945fb43630cSZhang Yubing ret = dw_dp_link_channel_equalization(dp); 946fb43630cSZhang Yubing if (ret < 0) { 947fb43630cSZhang Yubing dev_err(dp->dev, "channel equalization failed: %d\n", ret); 948fb43630cSZhang Yubing goto out; 949fb43630cSZhang Yubing } 950fb43630cSZhang Yubing 951fb43630cSZhang Yubing if (!link->train.channel_equalized) { 952fb43630cSZhang Yubing dev_err(dp->dev, 953fb43630cSZhang Yubing "channel equalization failed, downgrading link\n"); 954fb43630cSZhang Yubing 955fb43630cSZhang Yubing ret = dw_dp_link_downgrade(dp); 956fb43630cSZhang Yubing if (ret < 0) 957fb43630cSZhang Yubing goto out; 958fb43630cSZhang Yubing else 959fb43630cSZhang Yubing goto retry; 960fb43630cSZhang Yubing } 961fb43630cSZhang Yubing 962fb43630cSZhang Yubing printf("channel equalization succeeded\n"); 963fb43630cSZhang Yubing 964fb43630cSZhang Yubing out: 965fb43630cSZhang Yubing dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); 966fb43630cSZhang Yubing return ret; 967fb43630cSZhang Yubing } 968fb43630cSZhang Yubing 969fb43630cSZhang Yubing static int dw_dp_link_enable(struct dw_dp *dp) 970fb43630cSZhang Yubing { 971fb43630cSZhang Yubing int ret; 972fb43630cSZhang Yubing 973fb43630cSZhang Yubing ret = dw_dp_link_power_up(dp); 974fb43630cSZhang Yubing if (ret < 0) 975fb43630cSZhang Yubing return ret; 976fb43630cSZhang Yubing 977fb43630cSZhang Yubing ret = dw_dp_link_train(dp); 978fb43630cSZhang Yubing if (ret < 0) { 979fb43630cSZhang Yubing dev_err(dp->dev, "link training failed: %d\n", ret); 980fb43630cSZhang Yubing return ret; 981fb43630cSZhang Yubing } 982fb43630cSZhang Yubing 983fb43630cSZhang Yubing return 0; 984fb43630cSZhang Yubing } 985fb43630cSZhang Yubing 9865efdd3e2SZhang Yubing static int dw_dp_set_phy_default_config(struct dw_dp *dp) 9875efdd3e2SZhang Yubing { 9885efdd3e2SZhang Yubing struct dw_dp_link *link = &dp->link; 9895efdd3e2SZhang Yubing union phy_configure_opts phy_cfg; 9905efdd3e2SZhang Yubing int ret, i, phy_rate; 9915efdd3e2SZhang Yubing 9925efdd3e2SZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported = false; 9935efdd3e2SZhang Yubing link->rate = 270000; 9945efdd3e2SZhang Yubing link->lanes = dp->phy.attrs.bus_width; 9955efdd3e2SZhang Yubing 9965efdd3e2SZhang Yubing link->caps.enhanced_framing = true; 9975efdd3e2SZhang Yubing link->caps.channel_coding = true; 9985efdd3e2SZhang Yubing link->caps.ssc = true; 9995efdd3e2SZhang Yubing 10005efdd3e2SZhang Yubing /* Move PHY to P3 */ 10015efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 10025efdd3e2SZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x3)); 10035efdd3e2SZhang Yubing 10045efdd3e2SZhang Yubing for (i = 0; i < link->lanes; i++) { 10055efdd3e2SZhang Yubing phy_cfg.dp.voltage[i] = 3; 10065efdd3e2SZhang Yubing phy_cfg.dp.pre[i] = 0; 10075efdd3e2SZhang Yubing } 10085efdd3e2SZhang Yubing phy_cfg.dp.lanes = link->lanes; 10095efdd3e2SZhang Yubing phy_cfg.dp.link_rate = link->rate / 100; 10105efdd3e2SZhang Yubing phy_cfg.dp.ssc = link->caps.ssc; 10115efdd3e2SZhang Yubing phy_cfg.dp.set_lanes = true; 10125efdd3e2SZhang Yubing phy_cfg.dp.set_rate = true; 10135efdd3e2SZhang Yubing phy_cfg.dp.set_voltages = true; 10145efdd3e2SZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg); 10155efdd3e2SZhang Yubing if (ret) 10165efdd3e2SZhang Yubing return ret; 10175efdd3e2SZhang Yubing 10185efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES, 10195efdd3e2SZhang Yubing FIELD_PREP(PHY_LANES, link->lanes / 2)); 10205efdd3e2SZhang Yubing 10215efdd3e2SZhang Yubing switch (link->rate) { 10225efdd3e2SZhang Yubing case 810000: 10235efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR3; 10245efdd3e2SZhang Yubing break; 10255efdd3e2SZhang Yubing case 540000: 10265efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR2; 10275efdd3e2SZhang Yubing break; 10285efdd3e2SZhang Yubing case 270000: 10295efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR; 10305efdd3e2SZhang Yubing break; 10315efdd3e2SZhang Yubing case 162000: 10325efdd3e2SZhang Yubing default: 10335efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_RBR; 10345efdd3e2SZhang Yubing break; 10355efdd3e2SZhang Yubing } 10365efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE, 10375efdd3e2SZhang Yubing FIELD_PREP(PHY_RATE, phy_rate)); 10385efdd3e2SZhang Yubing 10395efdd3e2SZhang Yubing /* Move PHY to P0 */ 10405efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, 10415efdd3e2SZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x0)); 10425efdd3e2SZhang Yubing 10435efdd3e2SZhang Yubing dw_dp_phy_xmit_enable(dp, link->lanes); 10445efdd3e2SZhang Yubing 10455efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, 10465efdd3e2SZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 1)); 10475efdd3e2SZhang Yubing 10485efdd3e2SZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE); 10495efdd3e2SZhang Yubing return 0; 10505efdd3e2SZhang Yubing } 10515efdd3e2SZhang Yubing 1052fb43630cSZhang Yubing static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp) 1053fb43630cSZhang Yubing { 1054fb43630cSZhang Yubing const u8 *payload = sdp->db; 1055fb43630cSZhang Yubing u32 reg; 1056fb43630cSZhang Yubing int i, nr = 0; 1057fb43630cSZhang Yubing 1058fb43630cSZhang Yubing reg = DPTX_SDP_REGISTER_BANK + nr * 9 * 4; 1059fb43630cSZhang Yubing 1060fb43630cSZhang Yubing /* SDP header */ 1061fb43630cSZhang Yubing regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->header)); 1062fb43630cSZhang Yubing 1063fb43630cSZhang Yubing /* SDP data payload */ 1064fb43630cSZhang Yubing for (i = 1; i < 9; i++, payload += 4) 1065fb43630cSZhang Yubing regmap_write(dp->regmap, reg + i * 4, 1066fb43630cSZhang Yubing FIELD_PREP(SDP_REGS, get_unaligned_le32(payload))); 1067fb43630cSZhang Yubing 1068fb43630cSZhang Yubing if (sdp->flags & DPTX_SDP_VERTICAL_INTERVAL) 1069fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL, 1070fb43630cSZhang Yubing EN_VERTICAL_SDP << nr, 1071fb43630cSZhang Yubing EN_VERTICAL_SDP << nr); 1072fb43630cSZhang Yubing 1073fb43630cSZhang Yubing if (sdp->flags & DPTX_SDP_HORIZONTAL_INTERVAL) 1074fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL, 1075fb43630cSZhang Yubing EN_HORIZONTAL_SDP << nr, 1076fb43630cSZhang Yubing EN_HORIZONTAL_SDP << nr); 1077fb43630cSZhang Yubing 1078fb43630cSZhang Yubing return 0; 1079fb43630cSZhang Yubing } 1080fb43630cSZhang Yubing 1081fb43630cSZhang Yubing static void dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc, 1082fb43630cSZhang Yubing struct dw_dp_sdp *sdp) 1083fb43630cSZhang Yubing { 1084fb43630cSZhang Yubing sdp->header.HB0 = 0; 1085fb43630cSZhang Yubing sdp->header.HB1 = DP_SDP_VSC; 1086fb43630cSZhang Yubing sdp->header.HB2 = vsc->revision; 1087fb43630cSZhang Yubing sdp->header.HB3 = vsc->length; 1088fb43630cSZhang Yubing 1089fb43630cSZhang Yubing sdp->db[16] = (vsc->pixelformat & 0xf) << 4; 1090fb43630cSZhang Yubing sdp->db[16] |= vsc->colorimetry & 0xf; 1091fb43630cSZhang Yubing 1092fb43630cSZhang Yubing switch (vsc->bpc) { 1093fb43630cSZhang Yubing case 8: 1094fb43630cSZhang Yubing sdp->db[17] = 0x1; 1095fb43630cSZhang Yubing break; 1096fb43630cSZhang Yubing case 10: 1097fb43630cSZhang Yubing sdp->db[17] = 0x2; 1098fb43630cSZhang Yubing break; 1099fb43630cSZhang Yubing case 12: 1100fb43630cSZhang Yubing sdp->db[17] = 0x3; 1101fb43630cSZhang Yubing break; 1102fb43630cSZhang Yubing case 16: 1103fb43630cSZhang Yubing sdp->db[17] = 0x4; 1104fb43630cSZhang Yubing break; 1105fb43630cSZhang Yubing case 6: 1106fb43630cSZhang Yubing default: 1107fb43630cSZhang Yubing break; 1108fb43630cSZhang Yubing } 1109fb43630cSZhang Yubing 1110fb43630cSZhang Yubing if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA) 1111fb43630cSZhang Yubing sdp->db[17] |= 0x80; 1112fb43630cSZhang Yubing 1113fb43630cSZhang Yubing sdp->db[18] = vsc->content_type & 0x7; 1114fb43630cSZhang Yubing 1115fb43630cSZhang Yubing sdp->flags |= DPTX_SDP_VERTICAL_INTERVAL; 1116fb43630cSZhang Yubing } 1117fb43630cSZhang Yubing 1118fb43630cSZhang Yubing static int dw_dp_send_vsc_sdp(struct dw_dp *dp) 1119fb43630cSZhang Yubing { 1120fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 1121fb43630cSZhang Yubing struct drm_dp_vsc_sdp vsc = {}; 1122fb43630cSZhang Yubing struct dw_dp_sdp sdp = {}; 1123fb43630cSZhang Yubing 1124fb43630cSZhang Yubing vsc.revision = 0x5; 1125fb43630cSZhang Yubing vsc.length = 0x13; 1126fb43630cSZhang Yubing 1127fb43630cSZhang Yubing switch (video->color_format) { 1128fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444: 1129fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV444; 1130fb43630cSZhang Yubing break; 1131fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420: 1132fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV420; 1133fb43630cSZhang Yubing break; 1134fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422: 1135fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV422; 1136fb43630cSZhang Yubing break; 1137fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444: 1138fb43630cSZhang Yubing default: 1139fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_RGB; 1140fb43630cSZhang Yubing break; 1141fb43630cSZhang Yubing } 1142fb43630cSZhang Yubing 1143fb43630cSZhang Yubing if (video->color_format == DRM_COLOR_FORMAT_RGB444) 1144fb43630cSZhang Yubing vsc.colorimetry = DP_COLORIMETRY_DEFAULT; 1145fb43630cSZhang Yubing else 1146fb43630cSZhang Yubing vsc.colorimetry = DP_COLORIMETRY_BT709_YCC; 1147fb43630cSZhang Yubing 1148fb43630cSZhang Yubing vsc.bpc = video->bpc; 1149fb43630cSZhang Yubing vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA; 1150fb43630cSZhang Yubing vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED; 1151fb43630cSZhang Yubing 1152fb43630cSZhang Yubing dw_dp_vsc_sdp_pack(&vsc, &sdp); 1153fb43630cSZhang Yubing 1154fb43630cSZhang Yubing return dw_dp_send_sdp(dp, &sdp); 1155fb43630cSZhang Yubing } 1156fb43630cSZhang Yubing 1157fb43630cSZhang Yubing static int dw_dp_video_set_pixel_mode(struct dw_dp *dp, u8 pixel_mode) 1158fb43630cSZhang Yubing { 1159fb43630cSZhang Yubing switch (pixel_mode) { 1160fb43630cSZhang Yubing case DPTX_MP_SINGLE_PIXEL: 1161fb43630cSZhang Yubing case DPTX_MP_DUAL_PIXEL: 1162fb43630cSZhang Yubing case DPTX_MP_QUAD_PIXEL: 1163fb43630cSZhang Yubing break; 1164fb43630cSZhang Yubing default: 1165fb43630cSZhang Yubing return -EINVAL; 1166fb43630cSZhang Yubing } 1167fb43630cSZhang Yubing 1168fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, PIXEL_MODE_SELECT, 1169fb43630cSZhang Yubing FIELD_PREP(PIXEL_MODE_SELECT, pixel_mode)); 1170fb43630cSZhang Yubing 1171fb43630cSZhang Yubing return 0; 1172fb43630cSZhang Yubing } 1173fb43630cSZhang Yubing 1174fb43630cSZhang Yubing static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc, 1175fb43630cSZhang Yubing u16 vstart, u16 hstart) 1176fb43630cSZhang Yubing { 1177fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1178fb43630cSZhang Yubing u16 misc = 0; 1179fb43630cSZhang Yubing 1180fb43630cSZhang Yubing if (link->vsc_sdp_extension_for_colorimetry_supported) 1181fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_VSC_SDP; 1182fb43630cSZhang Yubing 1183fb43630cSZhang Yubing switch (color_format) { 1184fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444: 1185fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_RGB; 1186fb43630cSZhang Yubing break; 1187fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444: 1188fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709; 1189fb43630cSZhang Yubing break; 1190fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422: 1191fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709; 1192fb43630cSZhang Yubing break; 1193fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420: 1194fb43630cSZhang Yubing break; 1195fb43630cSZhang Yubing default: 1196fb43630cSZhang Yubing return -EINVAL; 1197fb43630cSZhang Yubing } 1198fb43630cSZhang Yubing 1199fb43630cSZhang Yubing switch (bpc) { 1200fb43630cSZhang Yubing case 6: 1201fb43630cSZhang Yubing misc |= DP_MSA_MISC_6_BPC; 1202fb43630cSZhang Yubing break; 1203fb43630cSZhang Yubing case 8: 1204fb43630cSZhang Yubing misc |= DP_MSA_MISC_8_BPC; 1205fb43630cSZhang Yubing break; 1206fb43630cSZhang Yubing case 10: 1207fb43630cSZhang Yubing misc |= DP_MSA_MISC_10_BPC; 1208fb43630cSZhang Yubing break; 1209fb43630cSZhang Yubing case 12: 1210fb43630cSZhang Yubing misc |= DP_MSA_MISC_12_BPC; 1211fb43630cSZhang Yubing break; 1212fb43630cSZhang Yubing case 16: 1213fb43630cSZhang Yubing misc |= DP_MSA_MISC_16_BPC; 1214fb43630cSZhang Yubing break; 1215fb43630cSZhang Yubing default: 1216fb43630cSZhang Yubing return -EINVAL; 1217fb43630cSZhang Yubing } 1218fb43630cSZhang Yubing 1219fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA1, 1220fb43630cSZhang Yubing FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart)); 1221fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA2, FIELD_PREP(MISC0, misc)); 1222fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8)); 1223fb43630cSZhang Yubing 1224fb43630cSZhang Yubing return 0; 1225fb43630cSZhang Yubing } 1226fb43630cSZhang Yubing 1227fb43630cSZhang Yubing static int dw_dp_video_enable(struct dw_dp *dp) 1228fb43630cSZhang Yubing { 1229fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 1230fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1231fb43630cSZhang Yubing struct drm_display_mode *mode = &video->mode; 1232fb43630cSZhang Yubing u8 color_format = video->color_format; 1233fb43630cSZhang Yubing u8 bpc = video->bpc; 1234fb43630cSZhang Yubing u8 pixel_mode = video->pixel_mode; 1235fb43630cSZhang Yubing u8 bpp = video->bpp, init_threshold, vic; 1236fb43630cSZhang Yubing u32 hactive, hblank, h_sync_width, h_front_porch; 1237fb43630cSZhang Yubing u32 vactive, vblank, v_sync_width, v_front_porch; 1238fb43630cSZhang Yubing u32 vstart = mode->vtotal - mode->vsync_start; 1239fb43630cSZhang Yubing u32 hstart = mode->htotal - mode->hsync_start; 1240fb43630cSZhang Yubing u32 peak_stream_bandwidth, link_bandwidth; 1241fb43630cSZhang Yubing u32 average_bytes_per_tu, average_bytes_per_tu_frac; 1242fb43630cSZhang Yubing u32 ts, hblank_interval; 1243fb43630cSZhang Yubing u32 value; 1244fb43630cSZhang Yubing int ret; 1245fb43630cSZhang Yubing 1246fb43630cSZhang Yubing ret = dw_dp_video_set_pixel_mode(dp, pixel_mode); 1247fb43630cSZhang Yubing if (ret) 1248fb43630cSZhang Yubing return ret; 1249fb43630cSZhang Yubing 1250fb43630cSZhang Yubing ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart); 1251fb43630cSZhang Yubing if (ret) 1252fb43630cSZhang Yubing return ret; 1253fb43630cSZhang Yubing 1254fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_MAPPING, 1255fb43630cSZhang Yubing FIELD_PREP(VIDEO_MAPPING, video->video_mapping)); 1256fb43630cSZhang Yubing 1257fb43630cSZhang Yubing /* Configure DPTX_VINPUT_POLARITY_CTRL register */ 1258fb43630cSZhang Yubing value = 0; 1259fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_PHSYNC) 1260fb43630cSZhang Yubing value |= FIELD_PREP(HSYNC_IN_POLARITY, 1); 1261fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_PVSYNC) 1262fb43630cSZhang Yubing value |= FIELD_PREP(VSYNC_IN_POLARITY, 1); 1263fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VINPUT_POLARITY_CTRL, value); 1264fb43630cSZhang Yubing 1265fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG1 register */ 1266fb43630cSZhang Yubing hactive = mode->hdisplay; 1267fb43630cSZhang Yubing hblank = mode->htotal - mode->hdisplay; 1268fb43630cSZhang Yubing value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank); 1269fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1270fb43630cSZhang Yubing value |= FIELD_PREP(I_P, 1); 1271fb43630cSZhang Yubing vic = drm_match_cea_mode(mode); 1272fb43630cSZhang Yubing if (vic == 5 || vic == 6 || vic == 7 || 1273fb43630cSZhang Yubing vic == 10 || vic == 11 || vic == 20 || 1274fb43630cSZhang Yubing vic == 21 || vic == 22 || vic == 39 || 1275fb43630cSZhang Yubing vic == 25 || vic == 26 || vic == 40 || 1276fb43630cSZhang Yubing vic == 44 || vic == 45 || vic == 46 || 1277fb43630cSZhang Yubing vic == 50 || vic == 51 || vic == 54 || 1278fb43630cSZhang Yubing vic == 55 || vic == 58 || vic == 59) 1279fb43630cSZhang Yubing value |= R_V_BLANK_IN_OSC; 1280fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG1, value); 1281fb43630cSZhang Yubing 1282fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG2 register */ 1283fb43630cSZhang Yubing vblank = mode->vtotal - mode->vdisplay; 1284fb43630cSZhang Yubing vactive = mode->vdisplay; 1285fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG2, 1286fb43630cSZhang Yubing FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive)); 1287fb43630cSZhang Yubing 1288fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG3 register */ 1289fb43630cSZhang Yubing h_sync_width = mode->hsync_end - mode->hsync_start; 1290fb43630cSZhang Yubing h_front_porch = mode->hsync_start - mode->hdisplay; 1291fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG3, 1292fb43630cSZhang Yubing FIELD_PREP(H_SYNC_WIDTH, h_sync_width) | 1293fb43630cSZhang Yubing FIELD_PREP(H_FRONT_PORCH, h_front_porch)); 1294fb43630cSZhang Yubing 1295fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG4 register */ 1296fb43630cSZhang Yubing v_sync_width = mode->vsync_end - mode->vsync_start; 1297fb43630cSZhang Yubing v_front_porch = mode->vsync_start - mode->vdisplay; 1298fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG4, 1299fb43630cSZhang Yubing FIELD_PREP(V_SYNC_WIDTH, v_sync_width) | 1300fb43630cSZhang Yubing FIELD_PREP(V_FRONT_PORCH, v_front_porch)); 1301fb43630cSZhang Yubing 1302fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG5 register */ 1303fb43630cSZhang Yubing peak_stream_bandwidth = mode->clock * bpp / 8; 1304fb43630cSZhang Yubing link_bandwidth = (link->rate / 1000) * link->lanes; 1305fb43630cSZhang Yubing ts = peak_stream_bandwidth * 64 / link_bandwidth; 1306fb43630cSZhang Yubing average_bytes_per_tu = ts / 1000; 1307fb43630cSZhang Yubing average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10; 1308fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_SINGLE_PIXEL) { 1309fb43630cSZhang Yubing if (average_bytes_per_tu < 6) 1310fb43630cSZhang Yubing init_threshold = 32; 1311fb43630cSZhang Yubing else if (hblank <= 80 && 1312fb43630cSZhang Yubing color_format != DRM_COLOR_FORMAT_YCRCB420) 1313fb43630cSZhang Yubing init_threshold = 12; 1314fb43630cSZhang Yubing else if (hblank <= 40 && 1315fb43630cSZhang Yubing color_format == DRM_COLOR_FORMAT_YCRCB420) 1316fb43630cSZhang Yubing init_threshold = 3; 1317fb43630cSZhang Yubing else 1318fb43630cSZhang Yubing init_threshold = 16; 1319fb43630cSZhang Yubing } else { 1320fb43630cSZhang Yubing u32 t1 = 0, t2 = 0, t3 = 0; 1321fb43630cSZhang Yubing 1322fb43630cSZhang Yubing switch (bpc) { 1323fb43630cSZhang Yubing case 6: 1324fb43630cSZhang Yubing t1 = (4 * 1000 / 9) * link->lanes; 1325fb43630cSZhang Yubing break; 1326fb43630cSZhang Yubing case 8: 1327fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) { 1328fb43630cSZhang Yubing t1 = (1000 / 2) * link->lanes; 1329fb43630cSZhang Yubing } else { 1330fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_DUAL_PIXEL) 1331fb43630cSZhang Yubing t1 = (1000 / 3) * link->lanes; 1332fb43630cSZhang Yubing else 1333fb43630cSZhang Yubing t1 = (3000 / 16) * link->lanes; 1334fb43630cSZhang Yubing } 1335fb43630cSZhang Yubing break; 1336fb43630cSZhang Yubing case 10: 1337fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) 1338fb43630cSZhang Yubing t1 = (2000 / 5) * link->lanes; 1339fb43630cSZhang Yubing else 1340fb43630cSZhang Yubing t1 = (4000 / 15) * link->lanes; 1341fb43630cSZhang Yubing break; 1342fb43630cSZhang Yubing case 12: 1343fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) { 1344fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_DUAL_PIXEL) 1345fb43630cSZhang Yubing t1 = (1000 / 6) * link->lanes; 1346fb43630cSZhang Yubing else 1347fb43630cSZhang Yubing t1 = (1000 / 3) * link->lanes; 1348fb43630cSZhang Yubing } else { 1349fb43630cSZhang Yubing t1 = (2000 / 9) * link->lanes; 1350fb43630cSZhang Yubing } 1351fb43630cSZhang Yubing break; 1352fb43630cSZhang Yubing case 16: 1353fb43630cSZhang Yubing if (color_format != DRM_COLOR_FORMAT_YCRCB422 && 1354fb43630cSZhang Yubing pixel_mode == DPTX_MP_DUAL_PIXEL) 1355fb43630cSZhang Yubing t1 = (1000 / 6) * link->lanes; 1356fb43630cSZhang Yubing else 1357fb43630cSZhang Yubing t1 = (1000 / 4) * link->lanes; 1358fb43630cSZhang Yubing break; 1359fb43630cSZhang Yubing default: 1360fb43630cSZhang Yubing return -EINVAL; 1361fb43630cSZhang Yubing } 1362fb43630cSZhang Yubing 1363fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB420) 1364fb43630cSZhang Yubing t2 = (link->rate / 4) * 1000 / (mode->clock / 2); 1365fb43630cSZhang Yubing else 1366fb43630cSZhang Yubing t2 = (link->rate / 4) * 1000 / mode->clock; 1367fb43630cSZhang Yubing 1368fb43630cSZhang Yubing if (average_bytes_per_tu_frac) 1369fb43630cSZhang Yubing t3 = average_bytes_per_tu + 1; 1370fb43630cSZhang Yubing else 1371fb43630cSZhang Yubing t3 = average_bytes_per_tu; 1372fb43630cSZhang Yubing init_threshold = t1 * t2 * t3 / (1000 * 1000); 1373fb43630cSZhang Yubing if (init_threshold <= 16 || average_bytes_per_tu < 10) 1374fb43630cSZhang Yubing init_threshold = 40; 1375fb43630cSZhang Yubing } 1376fb43630cSZhang Yubing 1377fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG5, 1378fb43630cSZhang Yubing FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) | 1379fb43630cSZhang Yubing FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC, 1380fb43630cSZhang Yubing average_bytes_per_tu_frac) | 1381fb43630cSZhang Yubing FIELD_PREP(INIT_THRESHOLD, init_threshold) | 1382fb43630cSZhang Yubing FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu)); 1383fb43630cSZhang Yubing 1384fb43630cSZhang Yubing /* Configure DPTX_VIDEO_HBLANK_INTERVAL register */ 1385fb43630cSZhang Yubing hblank_interval = hblank * (link->rate / 4) / mode->clock; 1386fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_HBLANK_INTERVAL, 1387fb43630cSZhang Yubing FIELD_PREP(HBLANK_INTERVAL_EN, 1) | 1388fb43630cSZhang Yubing FIELD_PREP(HBLANK_INTERVAL, hblank_interval)); 1389fb43630cSZhang Yubing 1390fb43630cSZhang Yubing /* Video stream enable */ 1391fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE, 1392fb43630cSZhang Yubing FIELD_PREP(VIDEO_STREAM_ENABLE, 1)); 1393fb43630cSZhang Yubing 1394fb43630cSZhang Yubing if (link->vsc_sdp_extension_for_colorimetry_supported) 1395fb43630cSZhang Yubing dw_dp_send_vsc_sdp(dp); 1396fb43630cSZhang Yubing 1397fb43630cSZhang Yubing return 0; 1398fb43630cSZhang Yubing } 1399fb43630cSZhang Yubing 1400fb43630cSZhang Yubing static bool dw_dp_detect(struct dw_dp *dp) 1401fb43630cSZhang Yubing { 1402fb43630cSZhang Yubing u32 value; 1403fb43630cSZhang Yubing 1404fb43630cSZhang Yubing if (dm_gpio_is_valid(&dp->hpd_gpio)) 1405fb43630cSZhang Yubing return dm_gpio_get_value(&dp->hpd_gpio); 1406fb43630cSZhang Yubing 1407fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_HPD_STATUS, &value); 14085fbef17aSZhang Yubing if (FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG) { 1409fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_HPD_STATUS, HPD_HOT_PLUG); 1410fb43630cSZhang Yubing return true; 1411fb43630cSZhang Yubing } 1412fb43630cSZhang Yubing 1413fb43630cSZhang Yubing return false; 1414fb43630cSZhang Yubing } 1415fb43630cSZhang Yubing 14167ac3c934SZhang Yubing static struct dw_dp *connector_to_dw_dp(struct rockchip_connector *conn) 14177ac3c934SZhang Yubing { 14187ac3c934SZhang Yubing struct dw_dp *dp; 14197ac3c934SZhang Yubing 14207ac3c934SZhang Yubing if (dev_get_priv(conn->dev)) 14217ac3c934SZhang Yubing dp = dev_get_priv(conn->dev); 14227ac3c934SZhang Yubing else 14237ac3c934SZhang Yubing dp = dev_get_priv(conn->dev->parent); 14247ac3c934SZhang Yubing 14257ac3c934SZhang Yubing return dp; 14267ac3c934SZhang Yubing } 14277ac3c934SZhang Yubing 14280594ce39SZhang Yubing static int dw_dp_connector_init(struct rockchip_connector *conn, struct display_state *state) 1429fb43630cSZhang Yubing { 1430fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 14317ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn); 1432fb43630cSZhang Yubing int ret; 1433fb43630cSZhang Yubing 14347ac3c934SZhang Yubing if (dev_get_priv(conn->dev)) 14357ac3c934SZhang Yubing dp = dev_get_priv(conn->dev); 14367ac3c934SZhang Yubing else 14377ac3c934SZhang Yubing dp = dev_get_priv(conn->dev->parent); 1438fb43630cSZhang Yubing conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_DP1 : VOP_OUTPUT_IF_DP0; 1439fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 1440df0a5c43SDamon Ding conn_state->color_encoding = DRM_COLOR_YCBCR_BT709; 1441fb43630cSZhang Yubing 1442fb43630cSZhang Yubing clk_set_defaults(dp->dev); 1443fb43630cSZhang Yubing 1444fb43630cSZhang Yubing reset_assert(&dp->reset); 1445fb43630cSZhang Yubing udelay(20); 1446fb43630cSZhang Yubing reset_deassert(&dp->reset); 1447fb43630cSZhang Yubing 1448fb43630cSZhang Yubing conn_state->disp_info = rockchip_get_disp_info(conn_state->type, 1449fb43630cSZhang Yubing dp->id); 1450fb43630cSZhang Yubing dw_dp_init(dp); 1451fb43630cSZhang Yubing ret = generic_phy_power_on(&dp->phy); 1452fb43630cSZhang Yubing 1453fb43630cSZhang Yubing return ret; 1454fb43630cSZhang Yubing } 1455fb43630cSZhang Yubing 14560594ce39SZhang Yubing static int dw_dp_connector_get_edid(struct rockchip_connector *conn, struct display_state *state) 1457fb43630cSZhang Yubing { 1458fb43630cSZhang Yubing int ret; 1459fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 14607ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn); 1461fb43630cSZhang Yubing 1462*9c170041SAlgea Cao conn_state->edid = drm_do_get_edid(&dp->aux.ddc); 1463*9c170041SAlgea Cao if (!conn_state->edid) 1464*9c170041SAlgea Cao ret = -EINVAL; 1465fb43630cSZhang Yubing 1466fb43630cSZhang Yubing return ret; 1467fb43630cSZhang Yubing } 1468fb43630cSZhang Yubing 14691cf3aaecSZhang Yubing static int dw_dp_get_output_fmts_index(u32 bus_format) 14701cf3aaecSZhang Yubing { 14711cf3aaecSZhang Yubing int i; 14721cf3aaecSZhang Yubing 14731cf3aaecSZhang Yubing for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { 14741cf3aaecSZhang Yubing const struct dw_dp_output_format *fmt = &possible_output_fmts[i]; 14751cf3aaecSZhang Yubing 14761cf3aaecSZhang Yubing if (fmt->bus_format == bus_format) 14771cf3aaecSZhang Yubing break; 14781cf3aaecSZhang Yubing } 14791cf3aaecSZhang Yubing 14801cf3aaecSZhang Yubing if (i == ARRAY_SIZE(possible_output_fmts)) 14811cf3aaecSZhang Yubing return 1; 14821cf3aaecSZhang Yubing 14831cf3aaecSZhang Yubing return i; 14841cf3aaecSZhang Yubing } 14851cf3aaecSZhang Yubing 14860594ce39SZhang Yubing static int dw_dp_connector_prepare(struct rockchip_connector *conn, struct display_state *state) 14871cf3aaecSZhang Yubing { 14881cf3aaecSZhang Yubing struct connector_state *conn_state = &state->conn_state; 14897ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn); 14901cf3aaecSZhang Yubing struct dw_dp_video *video = &dp->video; 14911cf3aaecSZhang Yubing int bus_fmt; 14921cf3aaecSZhang Yubing 14931cf3aaecSZhang Yubing bus_fmt = dw_dp_get_output_fmts_index(conn_state->bus_format); 14941cf3aaecSZhang Yubing video->video_mapping = possible_output_fmts[bus_fmt].video_mapping; 14951cf3aaecSZhang Yubing video->color_format = possible_output_fmts[bus_fmt].color_format; 14961cf3aaecSZhang Yubing video->bus_format = possible_output_fmts[bus_fmt].bus_format; 14971cf3aaecSZhang Yubing video->bpc = possible_output_fmts[bus_fmt].bpc; 14981cf3aaecSZhang Yubing video->bpp = possible_output_fmts[bus_fmt].bpp; 14991cf3aaecSZhang Yubing 15001cf3aaecSZhang Yubing return 0; 15011cf3aaecSZhang Yubing } 15021cf3aaecSZhang Yubing 15030594ce39SZhang Yubing static int dw_dp_connector_enable(struct rockchip_connector *conn, struct display_state *state) 1504fb43630cSZhang Yubing { 1505fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 1506fb43630cSZhang Yubing struct drm_display_mode *mode = &conn_state->mode; 15077ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn); 1508fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video; 1509fb43630cSZhang Yubing int ret; 1510fb43630cSZhang Yubing 1511fb43630cSZhang Yubing memcpy(&video->mode, mode, sizeof(video->mode)); 1512fb43630cSZhang Yubing 15135efdd3e2SZhang Yubing if (dp->force_output) { 15145efdd3e2SZhang Yubing ret = dw_dp_set_phy_default_config(dp); 15155efdd3e2SZhang Yubing if (ret < 0) 15165efdd3e2SZhang Yubing printf("failed to set phy_default config: %d\n", ret); 15175efdd3e2SZhang Yubing } else { 1518fb43630cSZhang Yubing ret = dw_dp_link_enable(dp); 1519fb43630cSZhang Yubing if (ret < 0) { 15205efdd3e2SZhang Yubing printf("failed to enable link: %d\n", ret); 1521fb43630cSZhang Yubing return ret; 1522fb43630cSZhang Yubing } 15235efdd3e2SZhang Yubing } 1524fb43630cSZhang Yubing 1525fb43630cSZhang Yubing ret = dw_dp_video_enable(dp); 1526fb43630cSZhang Yubing if (ret < 0) { 15275efdd3e2SZhang Yubing printf("failed to enable video: %d\n", ret); 1528fb43630cSZhang Yubing return ret; 1529fb43630cSZhang Yubing } 1530fb43630cSZhang Yubing 1531fb43630cSZhang Yubing return 0; 1532fb43630cSZhang Yubing } 1533fb43630cSZhang Yubing 15340594ce39SZhang Yubing static int dw_dp_connector_disable(struct rockchip_connector *conn, struct display_state *state) 1535fb43630cSZhang Yubing { 1536fb43630cSZhang Yubing /* TODO */ 1537fb43630cSZhang Yubing 1538fb43630cSZhang Yubing return 0; 1539fb43630cSZhang Yubing } 1540fb43630cSZhang Yubing 15410594ce39SZhang Yubing static int dw_dp_connector_detect(struct rockchip_connector *conn, struct display_state *state) 1542fb43630cSZhang Yubing { 15437ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn); 15441cf3aaecSZhang Yubing int status, tries, ret; 1545fb43630cSZhang Yubing 1546a66bd69eSZhang Yubing for (tries = 0; tries < 200; tries++) { 1547fb43630cSZhang Yubing status = dw_dp_detect(dp); 1548fb43630cSZhang Yubing if (status) 1549fb43630cSZhang Yubing break; 1550fb43630cSZhang Yubing mdelay(2); 1551fb43630cSZhang Yubing } 1552fb43630cSZhang Yubing 15535efdd3e2SZhang Yubing if (state->force_output && !status) 15545efdd3e2SZhang Yubing dp->force_output = true; 15555efdd3e2SZhang Yubing 15565efdd3e2SZhang Yubing if (!status && !dp->force_output) 1557fb43630cSZhang Yubing generic_phy_power_off(&dp->phy); 1558fb43630cSZhang Yubing 15591cf3aaecSZhang Yubing if (status && !dp->force_output) { 15601cf3aaecSZhang Yubing ret = dw_dp_link_probe(dp); 15611cf3aaecSZhang Yubing if (ret) 15621cf3aaecSZhang Yubing printf("failed to probe DP link: %d\n", ret); 15631cf3aaecSZhang Yubing } 15641cf3aaecSZhang Yubing 1565fb43630cSZhang Yubing return status; 1566fb43630cSZhang Yubing } 1567fb43630cSZhang Yubing 1568fb43630cSZhang Yubing static int dw_dp_mode_valid(struct dw_dp *dp, struct hdmi_edid_data *edid_data) 1569fb43630cSZhang Yubing { 1570fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1571fb43630cSZhang Yubing struct drm_display_info *di = &edid_data->display_info; 1572fb43630cSZhang Yubing u32 min_bpp; 1573fb43630cSZhang Yubing int i; 1574fb43630cSZhang Yubing 1575fb43630cSZhang Yubing if (di->color_formats & DRM_COLOR_FORMAT_YCRCB420 && 1576fb43630cSZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported) 1577fb43630cSZhang Yubing min_bpp = 12; 1578fb43630cSZhang Yubing else if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422) 1579fb43630cSZhang Yubing min_bpp = 16; 1580fb43630cSZhang Yubing else if (di->color_formats & DRM_COLOR_FORMAT_RGB444) 1581fb43630cSZhang Yubing min_bpp = 18; 1582fb43630cSZhang Yubing else 1583fb43630cSZhang Yubing min_bpp = 24; 1584fb43630cSZhang Yubing 1585fb43630cSZhang Yubing for (i = 0; i < edid_data->modes; i++) { 1586fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp, link->lanes, 1587fb43630cSZhang Yubing link->rate)) 1588fb43630cSZhang Yubing edid_data->mode_buf[i].invalid = true; 1589fb43630cSZhang Yubing } 1590fb43630cSZhang Yubing 1591fb43630cSZhang Yubing return 0; 1592fb43630cSZhang Yubing } 1593fb43630cSZhang Yubing 1594fb43630cSZhang Yubing static u32 dw_dp_get_output_bus_fmts(struct dw_dp *dp, struct hdmi_edid_data *edid_data) 1595fb43630cSZhang Yubing { 1596fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link; 1597fb43630cSZhang Yubing unsigned int i; 1598fb43630cSZhang Yubing 1599fb43630cSZhang Yubing for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { 1600fb43630cSZhang Yubing const struct dw_dp_output_format *fmt = &possible_output_fmts[i]; 1601fb43630cSZhang Yubing 1602fb43630cSZhang Yubing if (fmt->bpc > edid_data->display_info.bpc) 1603fb43630cSZhang Yubing continue; 1604fb43630cSZhang Yubing 1605fb43630cSZhang Yubing if (!(edid_data->display_info.color_formats & fmt->color_format)) 1606fb43630cSZhang Yubing continue; 1607fb43630cSZhang Yubing 1608fb43630cSZhang Yubing if (fmt->color_format == DRM_COLOR_FORMAT_YCRCB420 && 1609fb43630cSZhang Yubing !link->vsc_sdp_extension_for_colorimetry_supported) 1610fb43630cSZhang Yubing continue; 1611fb43630cSZhang Yubing 1612fb43630cSZhang Yubing if (drm_mode_is_420(&edid_data->display_info, edid_data->preferred_mode) && 1613fb43630cSZhang Yubing fmt->color_format != DRM_COLOR_FORMAT_YCRCB420) 1614fb43630cSZhang Yubing continue; 1615fb43630cSZhang Yubing 1616fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, edid_data->preferred_mode, fmt->bpp, link->lanes, 1617fb43630cSZhang Yubing link->rate)) 1618fb43630cSZhang Yubing continue; 1619fb43630cSZhang Yubing 1620fb43630cSZhang Yubing break; 1621fb43630cSZhang Yubing } 1622fb43630cSZhang Yubing 1623fb43630cSZhang Yubing if (i == ARRAY_SIZE(possible_output_fmts)) 1624fb43630cSZhang Yubing return 1; 1625fb43630cSZhang Yubing 1626fb43630cSZhang Yubing return i; 1627fb43630cSZhang Yubing } 1628fb43630cSZhang Yubing 16290594ce39SZhang Yubing static int dw_dp_connector_get_timing(struct rockchip_connector *conn, struct display_state *state) 1630fb43630cSZhang Yubing { 1631*9c170041SAlgea Cao int ret = 0, i; 1632fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state; 16337ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn); 1634fb43630cSZhang Yubing struct drm_display_mode *mode = &conn_state->mode; 1635fb43630cSZhang Yubing struct hdmi_edid_data edid_data; 1636fb43630cSZhang Yubing struct drm_display_mode *mode_buf; 1637364352d1SZhang Yubing struct vop_rect rect; 1638fb43630cSZhang Yubing u32 bus_fmt; 1639fb43630cSZhang Yubing 1640fb43630cSZhang Yubing mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode)); 1641fb43630cSZhang Yubing if (!mode_buf) 1642fb43630cSZhang Yubing return -ENOMEM; 1643fb43630cSZhang Yubing 1644fb43630cSZhang Yubing memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode)); 1645fb43630cSZhang Yubing memset(&edid_data, 0, sizeof(struct hdmi_edid_data)); 1646fb43630cSZhang Yubing edid_data.mode_buf = mode_buf; 1647fb43630cSZhang Yubing 16485efdd3e2SZhang Yubing if (!dp->force_output) { 1649*9c170041SAlgea Cao conn_state->edid = drm_do_get_edid(&dp->aux.ddc); 1650*9c170041SAlgea Cao if (conn_state->edid) 1651fb43630cSZhang Yubing ret = drm_add_edid_modes(&edid_data, conn_state->edid); 1652fb43630cSZhang Yubing 1653*9c170041SAlgea Cao if (ret <= 0) { 1654fb43630cSZhang Yubing printf("failed to get edid\n"); 1655fb43630cSZhang Yubing goto err; 1656fb43630cSZhang Yubing } 1657fb43630cSZhang Yubing 16587ac3c934SZhang Yubing //drm_rk_filter_whitelist(&edid_data); 1659364352d1SZhang Yubing if (state->conn_state.secondary) { 1660364352d1SZhang Yubing rect.width = state->crtc_state.max_output.width / 2; 1661364352d1SZhang Yubing rect.height = state->crtc_state.max_output.height / 2; 1662364352d1SZhang Yubing } else { 1663364352d1SZhang Yubing rect.width = state->crtc_state.max_output.width; 1664364352d1SZhang Yubing rect.height = state->crtc_state.max_output.height; 1665364352d1SZhang Yubing } 1666364352d1SZhang Yubing 1667364352d1SZhang Yubing drm_mode_max_resolution_filter(&edid_data, &rect); 1668fb43630cSZhang Yubing dw_dp_mode_valid(dp, &edid_data); 1669fb43630cSZhang Yubing 1670fb43630cSZhang Yubing if (!drm_mode_prune_invalid(&edid_data)) { 16714f1d0c46SZhang Yubing printf("can't find valid dp mode\n"); 1672fb43630cSZhang Yubing ret = -EINVAL; 1673fb43630cSZhang Yubing goto err; 1674fb43630cSZhang Yubing } 1675fb43630cSZhang Yubing 1676fb43630cSZhang Yubing for (i = 0; i < edid_data.modes; i++) 1677fb43630cSZhang Yubing edid_data.mode_buf[i].vrefresh = 1678fb43630cSZhang Yubing drm_mode_vrefresh(&edid_data.mode_buf[i]); 1679fb43630cSZhang Yubing 1680fb43630cSZhang Yubing drm_mode_sort(&edid_data); 1681fb43630cSZhang Yubing memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode)); 16825efdd3e2SZhang Yubing } 1683fb43630cSZhang Yubing 1684fb43630cSZhang Yubing if (state->force_output) 16851cf3aaecSZhang Yubing bus_fmt = dw_dp_get_output_fmts_index(state->force_bus_format); 1686fb43630cSZhang Yubing else 1687fb43630cSZhang Yubing bus_fmt = dw_dp_get_output_bus_fmts(dp, &edid_data); 1688fb43630cSZhang Yubing 16891cf3aaecSZhang Yubing conn_state->bus_format = possible_output_fmts[bus_fmt].bus_format; 1690fb43630cSZhang Yubing 16911cf3aaecSZhang Yubing switch (possible_output_fmts[bus_fmt].color_format) { 1692fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420: 1693fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420; 1694fb43630cSZhang Yubing break; 1695fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422: 1696fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY; 1697fb43630cSZhang Yubing break; 1698fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444: 1699fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444: 1700fb43630cSZhang Yubing default: 1701fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 1702fb43630cSZhang Yubing break; 1703fb43630cSZhang Yubing } 1704fb43630cSZhang Yubing 1705fb43630cSZhang Yubing err: 1706fb43630cSZhang Yubing free(mode_buf); 1707fb43630cSZhang Yubing 1708fb43630cSZhang Yubing return 0; 1709fb43630cSZhang Yubing } 1710fb43630cSZhang Yubing 1711fb43630cSZhang Yubing static const struct rockchip_connector_funcs dw_dp_connector_funcs = { 1712fb43630cSZhang Yubing .init = dw_dp_connector_init, 1713fb43630cSZhang Yubing .get_edid = dw_dp_connector_get_edid, 17141cf3aaecSZhang Yubing .prepare = dw_dp_connector_prepare, 1715fb43630cSZhang Yubing .enable = dw_dp_connector_enable, 1716fb43630cSZhang Yubing .disable = dw_dp_connector_disable, 1717fb43630cSZhang Yubing .detect = dw_dp_connector_detect, 1718fb43630cSZhang Yubing .get_timing = dw_dp_connector_get_timing, 1719fb43630cSZhang Yubing }; 1720fb43630cSZhang Yubing 1721fb43630cSZhang Yubing static int dw_dp_ddc_init(struct dw_dp *dp) 1722fb43630cSZhang Yubing { 1723fb43630cSZhang Yubing dp->aux.name = "dw-dp"; 1724fb43630cSZhang Yubing dp->aux.dev = dp->dev; 1725fb43630cSZhang Yubing dp->aux.transfer = dw_dp_aux_transfer; 1726fb43630cSZhang Yubing dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer; 1727fb43630cSZhang Yubing 1728fb43630cSZhang Yubing return 0; 1729fb43630cSZhang Yubing } 1730fb43630cSZhang Yubing 1731549d42b6SWyon Bi static u32 dw_dp_parse_link_frequencies(struct dw_dp *dp) 1732549d42b6SWyon Bi { 1733549d42b6SWyon Bi struct udevice *dev = dp->dev; 1734549d42b6SWyon Bi const struct device_node *endpoint; 1735549d42b6SWyon Bi u64 frequency = 0; 1736549d42b6SWyon Bi 1737549d42b6SWyon Bi endpoint = rockchip_of_graph_get_endpoint_by_regs(dev->node, 1, 0); 1738549d42b6SWyon Bi if (!endpoint) 1739549d42b6SWyon Bi return 0; 1740549d42b6SWyon Bi 1741549d42b6SWyon Bi if (of_property_read_u64(endpoint, "link-frequencies", &frequency) < 0) 1742549d42b6SWyon Bi return 0; 1743549d42b6SWyon Bi 1744549d42b6SWyon Bi if (!frequency) 1745549d42b6SWyon Bi return 0; 1746549d42b6SWyon Bi 1747549d42b6SWyon Bi do_div(frequency, 10 * 1000); /* symbol rate kbytes */ 1748549d42b6SWyon Bi 1749549d42b6SWyon Bi switch (frequency) { 1750549d42b6SWyon Bi case 162000: 1751549d42b6SWyon Bi case 270000: 1752549d42b6SWyon Bi case 540000: 1753549d42b6SWyon Bi case 810000: 1754549d42b6SWyon Bi break; 1755549d42b6SWyon Bi default: 1756549d42b6SWyon Bi dev_err(dev, "invalid link frequency value: %llu\n", frequency); 1757549d42b6SWyon Bi return 0; 1758549d42b6SWyon Bi } 1759549d42b6SWyon Bi 1760549d42b6SWyon Bi return frequency; 1761549d42b6SWyon Bi } 1762549d42b6SWyon Bi 1763549d42b6SWyon Bi static int dw_dp_parse_dt(struct dw_dp *dp) 1764549d42b6SWyon Bi { 1765549d42b6SWyon Bi dp->force_hpd = dev_read_bool(dp->dev, "force-hpd"); 1766549d42b6SWyon Bi 1767549d42b6SWyon Bi dp->max_link_rate = dw_dp_parse_link_frequencies(dp); 1768549d42b6SWyon Bi if (!dp->max_link_rate) 1769549d42b6SWyon Bi dp->max_link_rate = 810000; 1770549d42b6SWyon Bi 1771549d42b6SWyon Bi return 0; 1772549d42b6SWyon Bi } 1773549d42b6SWyon Bi 1774fb43630cSZhang Yubing static int dw_dp_probe(struct udevice *dev) 1775fb43630cSZhang Yubing { 1776fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(dev); 17775fc83b1eSZhang Yubing const struct dw_dp_chip_data *pdata = 17785fc83b1eSZhang Yubing (const struct dw_dp_chip_data *)dev_get_driver_data(dev); 1779fb43630cSZhang Yubing int ret; 1780fb43630cSZhang Yubing 1781fb43630cSZhang Yubing ret = regmap_init_mem(dev, &dp->regmap); 1782fb43630cSZhang Yubing if (ret) 1783fb43630cSZhang Yubing return ret; 1784fb43630cSZhang Yubing 1785fb43630cSZhang Yubing dp->id = of_alias_get_id(ofnode_to_np(dev->node), "dp"); 1786fb43630cSZhang Yubing if (dp->id < 0) 1787fb43630cSZhang Yubing dp->id = 0; 1788fb43630cSZhang Yubing 17895fc83b1eSZhang Yubing dp->video.pixel_mode = pdata->pixel_mode; 17905fc83b1eSZhang Yubing 1791fb43630cSZhang Yubing ret = reset_get_by_index(dev, 0, &dp->reset); 1792fb43630cSZhang Yubing if (ret) { 1793fb43630cSZhang Yubing dev_err(dev, "failed to get reset control: %d\n", ret); 1794fb43630cSZhang Yubing return ret; 1795fb43630cSZhang Yubing } 1796fb43630cSZhang Yubing 1797fb43630cSZhang Yubing ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio, 1798fb43630cSZhang Yubing GPIOD_IS_IN); 1799fb43630cSZhang Yubing if (ret && ret != -ENOENT) { 1800fb43630cSZhang Yubing dev_err(dev, "failed to get hpd GPIO: %d\n", ret); 1801fb43630cSZhang Yubing return ret; 1802fb43630cSZhang Yubing } 1803fb43630cSZhang Yubing 1804fb43630cSZhang Yubing generic_phy_get_by_index(dev, 0, &dp->phy); 1805fb43630cSZhang Yubing 1806fb43630cSZhang Yubing dp->dev = dev; 1807fb43630cSZhang Yubing 1808549d42b6SWyon Bi ret = dw_dp_parse_dt(dp); 1809549d42b6SWyon Bi if (ret) { 1810549d42b6SWyon Bi dev_err(dev, "failed to parse DT\n"); 1811549d42b6SWyon Bi return ret; 1812549d42b6SWyon Bi } 1813549d42b6SWyon Bi 1814fb43630cSZhang Yubing dw_dp_ddc_init(dp); 1815fb43630cSZhang Yubing 18160594ce39SZhang Yubing rockchip_connector_bind(&dp->connector, dev, dp->id, &dw_dp_connector_funcs, NULL, 18170594ce39SZhang Yubing DRM_MODE_CONNECTOR_DisplayPort); 18180594ce39SZhang Yubing 1819fb43630cSZhang Yubing return 0; 1820fb43630cSZhang Yubing } 1821fb43630cSZhang Yubing 18227ac3c934SZhang Yubing static int dw_dp_bind(struct udevice *parent) 18237ac3c934SZhang Yubing { 18247ac3c934SZhang Yubing struct udevice *child; 18257ac3c934SZhang Yubing ofnode subnode; 18267ac3c934SZhang Yubing const char *node_name; 18277ac3c934SZhang Yubing int ret; 18287ac3c934SZhang Yubing 18297ac3c934SZhang Yubing dev_for_each_subnode(subnode, parent) { 18307ac3c934SZhang Yubing if (!ofnode_valid(subnode)) { 18317ac3c934SZhang Yubing printf("%s: no subnode for %s\n", __func__, parent->name); 18327ac3c934SZhang Yubing return -ENXIO; 18337ac3c934SZhang Yubing } 18347ac3c934SZhang Yubing 18357ac3c934SZhang Yubing node_name = ofnode_get_name(subnode); 18367ac3c934SZhang Yubing debug("%s: subnode %s\n", __func__, node_name); 18377ac3c934SZhang Yubing 18387ac3c934SZhang Yubing if (!strcasecmp(node_name, "dp0")) { 18397ac3c934SZhang Yubing ret = device_bind_driver_to_node(parent, 18407ac3c934SZhang Yubing "dw_dp_port0", 18417ac3c934SZhang Yubing node_name, subnode, &child); 18427ac3c934SZhang Yubing if (ret) { 18437ac3c934SZhang Yubing printf("%s: '%s' cannot bind its driver\n", 18447ac3c934SZhang Yubing __func__, node_name); 18457ac3c934SZhang Yubing return ret; 18467ac3c934SZhang Yubing } 18477ac3c934SZhang Yubing } 18487ac3c934SZhang Yubing } 18497ac3c934SZhang Yubing 18507ac3c934SZhang Yubing return 0; 18517ac3c934SZhang Yubing } 18527ac3c934SZhang Yubing 18537ac3c934SZhang Yubing static int dw_dp_port_probe(struct udevice *dev) 18547ac3c934SZhang Yubing { 18557ac3c934SZhang Yubing struct dw_dp *dp = dev_get_priv(dev->parent); 18567ac3c934SZhang Yubing 18577ac3c934SZhang Yubing rockchip_connector_bind(&dp->connector, dev, dp->id, &dw_dp_connector_funcs, NULL, 18587ac3c934SZhang Yubing DRM_MODE_CONNECTOR_DisplayPort); 18597ac3c934SZhang Yubing 18607ac3c934SZhang Yubing return 0; 18617ac3c934SZhang Yubing } 18627ac3c934SZhang Yubing 18635fc83b1eSZhang Yubing static const struct dw_dp_chip_data rk3588_dp = { 18645fc83b1eSZhang Yubing .pixel_mode = DPTX_MP_QUAD_PIXEL, 18655fc83b1eSZhang Yubing }; 18665fc83b1eSZhang Yubing 18675fc83b1eSZhang Yubing static const struct dw_dp_chip_data rk3576_dp = { 18685fc83b1eSZhang Yubing .pixel_mode = DPTX_MP_DUAL_PIXEL, 18695fc83b1eSZhang Yubing }; 18705fc83b1eSZhang Yubing 1871fb43630cSZhang Yubing static const struct udevice_id dw_dp_ids[] = { 1872fb43630cSZhang Yubing { 18735fc83b1eSZhang Yubing .compatible = "rockchip,rk3576-dp", 18745fc83b1eSZhang Yubing .data = (ulong)&rk3576_dp, 18755fc83b1eSZhang Yubing }, 18765fc83b1eSZhang Yubing { 1877fb43630cSZhang Yubing .compatible = "rockchip,rk3588-dp", 18785fc83b1eSZhang Yubing .data = (ulong)&rk3588_dp, 1879fb43630cSZhang Yubing }, 1880fb43630cSZhang Yubing {} 1881fb43630cSZhang Yubing }; 1882fb43630cSZhang Yubing 18837ac3c934SZhang Yubing U_BOOT_DRIVER(dw_dp_port) = { 18847ac3c934SZhang Yubing .name = "dw_dp_port0", 18857ac3c934SZhang Yubing .id = UCLASS_DISPLAY, 18867ac3c934SZhang Yubing .probe = dw_dp_port_probe, 18877ac3c934SZhang Yubing }; 18887ac3c934SZhang Yubing 1889fb43630cSZhang Yubing U_BOOT_DRIVER(dw_dp) = { 1890fb43630cSZhang Yubing .name = "dw_dp", 1891fb43630cSZhang Yubing .id = UCLASS_DISPLAY, 1892fb43630cSZhang Yubing .of_match = dw_dp_ids, 1893fb43630cSZhang Yubing .probe = dw_dp_probe, 18947ac3c934SZhang Yubing .bind = dw_dp_bind, 1895fb43630cSZhang Yubing .priv_auto_alloc_size = sizeof(struct dw_dp), 1896fb43630cSZhang Yubing }; 1897fb43630cSZhang Yubing 1898