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