Path: blob/master/drivers/gpu/drm/bridge/synopsys/dw-dp.c
29285 views
// SPDX-License-Identifier: GPL-2.01/*2* Synopsys DesignWare Cores DisplayPort Transmitter Controller3*4* Copyright (c) 2025 Rockchip Electronics Co., Ltd.5*6* Author: Andy Yan <[email protected]>7*/8#include <linux/bitfield.h>9#include <linux/clk.h>10#include <linux/iopoll.h>11#include <linux/irq.h>12#include <linux/media-bus-format.h>13#include <linux/of_device.h>14#include <linux/platform_device.h>15#include <linux/regmap.h>16#include <linux/reset.h>17#include <linux/phy/phy.h>18#include <linux/unaligned.h>1920#include <drm/bridge/dw_dp.h>21#include <drm/drm_atomic_helper.h>22#include <drm/drm_bridge.h>23#include <drm/drm_bridge_connector.h>24#include <drm/display/drm_dp_helper.h>25#include <drm/drm_edid.h>26#include <drm/drm_of.h>27#include <drm/drm_print.h>28#include <drm/drm_probe_helper.h>29#include <drm/drm_simple_kms_helper.h>3031#define DW_DP_VERSION_NUMBER 0x000032#define DW_DP_VERSION_TYPE 0x000433#define DW_DP_ID 0x00083435#define DW_DP_CONFIG_REG1 0x010036#define DW_DP_CONFIG_REG2 0x010437#define DW_DP_CONFIG_REG3 0x01083839#define DW_DP_CCTL 0x020040#define FORCE_HPD BIT(4)41#define DEFAULT_FAST_LINK_TRAIN_EN BIT(2)42#define ENHANCE_FRAMING_EN BIT(1)43#define SCRAMBLE_DIS BIT(0)44#define DW_DP_SOFT_RESET_CTRL 0x020445#define VIDEO_RESET BIT(5)46#define AUX_RESET BIT(4)47#define AUDIO_SAMPLER_RESET BIT(3)48#define HDCP_MODULE_RESET BIT(2)49#define PHY_SOFT_RESET BIT(1)50#define CONTROLLER_RESET BIT(0)5152#define DW_DP_VSAMPLE_CTRL 0x030053#define PIXEL_MODE_SELECT GENMASK(22, 21)54#define VIDEO_MAPPING GENMASK(20, 16)55#define VIDEO_STREAM_ENABLE BIT(5)5657#define DW_DP_VSAMPLE_STUFF_CTRL1 0x03045859#define DW_DP_VSAMPLE_STUFF_CTRL2 0x03086061#define DW_DP_VINPUT_POLARITY_CTRL 0x030c62#define DE_IN_POLARITY BIT(2)63#define HSYNC_IN_POLARITY BIT(1)64#define VSYNC_IN_POLARITY BIT(0)6566#define DW_DP_VIDEO_CONFIG1 0x031067#define HACTIVE GENMASK(31, 16)68#define HBLANK GENMASK(15, 2)69#define I_P BIT(1)70#define R_V_BLANK_IN_OSC BIT(0)7172#define DW_DP_VIDEO_CONFIG2 0x031473#define VBLANK GENMASK(31, 16)74#define VACTIVE GENMASK(15, 0)7576#define DW_DP_VIDEO_CONFIG3 0x031877#define H_SYNC_WIDTH GENMASK(31, 16)78#define H_FRONT_PORCH GENMASK(15, 0)7980#define DW_DP_VIDEO_CONFIG4 0x031c81#define V_SYNC_WIDTH GENMASK(31, 16)82#define V_FRONT_PORCH GENMASK(15, 0)8384#define DW_DP_VIDEO_CONFIG5 0x032085#define INIT_THRESHOLD_HI GENMASK(22, 21)86#define AVERAGE_BYTES_PER_TU_FRAC GENMASK(19, 16)87#define INIT_THRESHOLD GENMASK(13, 7)88#define AVERAGE_BYTES_PER_TU GENMASK(6, 0)8990#define DW_DP_VIDEO_MSA1 0x032491#define VSTART GENMASK(31, 16)92#define HSTART GENMASK(15, 0)9394#define DW_DP_VIDEO_MSA2 0x032895#define MISC0 GENMASK(31, 24)9697#define DW_DP_VIDEO_MSA3 0x032c98#define MISC1 GENMASK(31, 24)99100#define DW_DP_VIDEO_HBLANK_INTERVAL 0x0330101#define HBLANK_INTERVAL_EN BIT(16)102#define HBLANK_INTERVAL GENMASK(15, 0)103104#define DW_DP_AUD_CONFIG1 0x0400105#define AUDIO_TIMESTAMP_VERSION_NUM GENMASK(29, 24)106#define AUDIO_PACKET_ID GENMASK(23, 16)107#define AUDIO_MUTE BIT(15)108#define NUM_CHANNELS GENMASK(14, 12)109#define HBR_MODE_ENABLE BIT(10)110#define AUDIO_DATA_WIDTH GENMASK(9, 5)111#define AUDIO_DATA_IN_EN GENMASK(4, 1)112#define AUDIO_INF_SELECT BIT(0)113114#define DW_DP_SDP_VERTICAL_CTRL 0x0500115#define EN_VERTICAL_SDP BIT(2)116#define EN_AUDIO_STREAM_SDP BIT(1)117#define EN_AUDIO_TIMESTAMP_SDP BIT(0)118#define DW_DP_SDP_HORIZONTAL_CTRL 0x0504119#define EN_HORIZONTAL_SDP BIT(2)120#define DW_DP_SDP_STATUS_REGISTER 0x0508121#define DW_DP_SDP_MANUAL_CTRL 0x050c122#define DW_DP_SDP_STATUS_EN 0x0510123124#define DW_DP_SDP_REGISTER_BANK 0x0600125#define SDP_REGS GENMASK(31, 0)126127#define DW_DP_PHYIF_CTRL 0x0a00128#define PHY_WIDTH BIT(25)129#define PHY_POWERDOWN GENMASK(20, 17)130#define PHY_BUSY GENMASK(15, 12)131#define SSC_DIS BIT(16)132#define XMIT_ENABLE GENMASK(11, 8)133#define PHY_LANES GENMASK(7, 6)134#define PHY_RATE GENMASK(5, 4)135#define TPS_SEL GENMASK(3, 0)136137#define DW_DP_PHY_TX_EQ 0x0a04138#define DW_DP_CUSTOMPAT0 0x0a08139#define DW_DP_CUSTOMPAT1 0x0a0c140#define DW_DP_CUSTOMPAT2 0x0a10141#define DW_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET 0x0a14142#define DW_DP_PHYIF_PWRDOWN_CTRL 0x0a18143144#define DW_DP_AUX_CMD 0x0b00145#define AUX_CMD_TYPE GENMASK(31, 28)146#define AUX_ADDR GENMASK(27, 8)147#define I2C_ADDR_ONLY BIT(4)148#define AUX_LEN_REQ GENMASK(3, 0)149150#define DW_DP_AUX_STATUS 0x0b04151#define AUX_TIMEOUT BIT(17)152#define AUX_BYTES_READ GENMASK(23, 19)153#define AUX_STATUS GENMASK(7, 4)154155#define DW_DP_AUX_DATA0 0x0b08156#define DW_DP_AUX_DATA1 0x0b0c157#define DW_DP_AUX_DATA2 0x0b10158#define DW_DP_AUX_DATA3 0x0b14159160#define DW_DP_GENERAL_INTERRUPT 0x0d00161#define VIDEO_FIFO_OVERFLOW_STREAM0 BIT(6)162#define AUDIO_FIFO_OVERFLOW_STREAM0 BIT(5)163#define SDP_EVENT_STREAM0 BIT(4)164#define AUX_CMD_INVALID BIT(3)165#define HDCP_EVENT BIT(2)166#define AUX_REPLY_EVENT BIT(1)167#define HPD_EVENT BIT(0)168169#define DW_DP_GENERAL_INTERRUPT_ENABLE 0x0d04170#define HDCP_EVENT_EN BIT(2)171#define AUX_REPLY_EVENT_EN BIT(1)172#define HPD_EVENT_EN BIT(0)173174#define DW_DP_HPD_STATUS 0x0d08175#define HPD_STATE GENMASK(11, 9)176#define HPD_STATUS BIT(8)177#define HPD_HOT_UNPLUG BIT(2)178#define HPD_HOT_PLUG BIT(1)179#define HPD_IRQ BIT(0)180181#define DW_DP_HPD_INTERRUPT_ENABLE 0x0d0c182#define HPD_UNPLUG_ERR_EN BIT(3)183#define HPD_UNPLUG_EN BIT(2)184#define HPD_PLUG_EN BIT(1)185#define HPD_IRQ_EN BIT(0)186187#define DW_DP_HDCP_CFG 0x0e00188#define DPCD12PLUS BIT(7)189#define CP_IRQ BIT(6)190#define BYPENCRYPTION BIT(5)191#define HDCP_LOCK BIT(4)192#define ENCRYPTIONDISABLE BIT(3)193#define ENABLE_HDCP_13 BIT(2)194#define ENABLE_HDCP BIT(1)195196#define DW_DP_HDCP_OBS 0x0e04197#define HDCP22_RE_AUTHENTICATION_REQ BIT(31)198#define HDCP22_AUTHENTICATION_FAILED BIT(30)199#define HDCP22_AUTHENTICATION_SUCCESS BIT(29)200#define HDCP22_CAPABLE_SINK BIT(28)201#define HDCP22_SINK_CAP_CHECK_COMPLETE BIT(27)202#define HDCP22_STATE GENMASK(26, 24)203#define HDCP22_BOOTED BIT(23)204#define HDCP13_BSTATUS GENMASK(22, 19)205#define REPEATER BIT(18)206#define HDCP_CAPABLE BIT(17)207#define STATEE GENMASK(16, 14)208#define STATEOEG GENMASK(13, 11)209#define STATER GENMASK(10, 8)210#define STATEA GENMASK(7, 4)211#define SUBSTATEA GENMASK(3, 1)212#define HDCPENGAGED BIT(0)213214#define DW_DP_HDCP_APIINTCLR 0x0e08215#define DW_DP_HDCP_APIINTSTAT 0x0e0c216#define DW_DP_HDCP_APIINTMSK 0x0e10217#define HDCP22_GPIOINT BIT(8)218#define HDCP_ENGAGED BIT(7)219#define HDCP_FAILED BIT(6)220#define KSVSHA1CALCDONEINT BIT(5)221#define AUXRESPNACK7TIMES BIT(4)222#define AUXRESPTIMEOUT BIT(3)223#define AUXRESPDEFER7TIMES BIT(2)224#define KSVACCESSINT BIT(0)225226#define DW_DP_HDCP_KSVMEMCTRL 0x0e18227#define KSVSHA1STATUS BIT(4)228#define KSVMEMACCESS BIT(1)229#define KSVMEMREQUEST BIT(0)230231#define DW_DP_HDCP_REG_BKSV0 0x3600232#define DW_DP_HDCP_REG_BKSV1 0x3604233#define DW_DP_HDCP_REG_ANCONF 0x3608234#define AN_BYPASS BIT(0)235236#define DW_DP_HDCP_REG_AN0 0x360c237#define DW_DP_HDCP_REG_AN1 0x3610238#define DW_DP_HDCP_REG_RMLCTL 0x3614239#define ODPK_DECRYPT_ENABLE BIT(0)240241#define DW_DP_HDCP_REG_RMLSTS 0x3618242#define IDPK_WR_OK_STS BIT(6)243#define IDPK_DATA_INDEX GENMASK(5, 0)244#define DW_DP_HDCP_REG_SEED 0x361c245#define DW_DP_HDCP_REG_DPK0 0x3620246#define DW_DP_HDCP_REG_DPK1 0x3624247#define DW_DP_HDCP22_GPIOSTS 0x3628248#define DW_DP_HDCP22_GPIOCHNGSTS 0x362c249#define DW_DP_HDCP_REG_DPK_CRC 0x3630250251#define DW_DP_MAX_REGISTER DW_DP_HDCP_REG_DPK_CRC252253#define SDP_REG_BANK_SIZE 16254255struct dw_dp_link_caps {256bool enhanced_framing;257bool tps3_supported;258bool tps4_supported;259bool fast_training;260bool channel_coding;261bool ssc;262};263264struct dw_dp_link_train_set {265unsigned int voltage_swing[4];266unsigned int pre_emphasis[4];267bool voltage_max_reached[4];268bool pre_max_reached[4];269};270271struct dw_dp_link_train {272struct dw_dp_link_train_set adjust;273bool clock_recovered;274bool channel_equalized;275};276277struct dw_dp_link {278u8 dpcd[DP_RECEIVER_CAP_SIZE];279unsigned char revision;280unsigned int rate;281unsigned int lanes;282u8 sink_count;283u8 vsc_sdp_supported;284struct dw_dp_link_caps caps;285struct dw_dp_link_train train;286struct drm_dp_desc desc;287};288289struct dw_dp_bridge_state {290struct drm_bridge_state base;291struct drm_display_mode mode;292u8 video_mapping;293u8 color_format;294u8 bpc;295u8 bpp;296};297298struct dw_dp_sdp {299struct dp_sdp base;300unsigned long flags;301};302303struct dw_dp_hotplug {304bool long_hpd;305};306307struct dw_dp {308struct drm_bridge bridge;309struct device *dev;310struct regmap *regmap;311struct phy *phy;312struct clk *apb_clk;313struct clk *aux_clk;314struct clk *i2s_clk;315struct clk *spdif_clk;316struct clk *hdcp_clk;317struct reset_control *rstc;318struct completion complete;319int irq;320struct work_struct hpd_work;321struct dw_dp_hotplug hotplug;322/* Serialize hpd status access */323struct mutex irq_lock;324325struct drm_dp_aux aux;326327struct dw_dp_link link;328struct dw_dp_plat_data plat_data;329u8 pixel_mode;330331DECLARE_BITMAP(sdp_reg_bank, SDP_REG_BANK_SIZE);332};333334enum {335DW_DP_RGB_6BIT,336DW_DP_RGB_8BIT,337DW_DP_RGB_10BIT,338DW_DP_RGB_12BIT,339DW_DP_RGB_16BIT,340DW_DP_YCBCR444_8BIT,341DW_DP_YCBCR444_10BIT,342DW_DP_YCBCR444_12BIT,343DW_DP_YCBCR444_16BIT,344DW_DP_YCBCR422_8BIT,345DW_DP_YCBCR422_10BIT,346DW_DP_YCBCR422_12BIT,347DW_DP_YCBCR422_16BIT,348DW_DP_YCBCR420_8BIT,349DW_DP_YCBCR420_10BIT,350DW_DP_YCBCR420_12BIT,351DW_DP_YCBCR420_16BIT,352};353354enum {355DW_DP_MP_SINGLE_PIXEL,356DW_DP_MP_DUAL_PIXEL,357DW_DP_MP_QUAD_PIXEL,358};359360enum {361DW_DP_SDP_VERTICAL_INTERVAL = BIT(0),362DW_DP_SDP_HORIZONTAL_INTERVAL = BIT(1),363};364365enum {366DW_DP_HPD_STATE_IDLE,367DW_DP_HPD_STATE_UNPLUG,368DP_DP_HPD_STATE_TIMEOUT = 4,369DW_DP_HPD_STATE_PLUG = 7370};371372enum {373DW_DP_PHY_PATTERN_NONE,374DW_DP_PHY_PATTERN_TPS_1,375DW_DP_PHY_PATTERN_TPS_2,376DW_DP_PHY_PATTERN_TPS_3,377DW_DP_PHY_PATTERN_TPS_4,378DW_DP_PHY_PATTERN_SERM,379DW_DP_PHY_PATTERN_PBRS7,380DW_DP_PHY_PATTERN_CUSTOM_80BIT,381DW_DP_PHY_PATTERN_CP2520_1,382DW_DP_PHY_PATTERN_CP2520_2,383};384385struct dw_dp_output_format {386u32 bus_format;387u32 color_format;388u8 video_mapping;389u8 bpc;390u8 bpp;391};392393#define to_dw_dp_bridge_state(s) container_of(s, struct dw_dp_bridge_state, base)394395static const struct dw_dp_output_format dw_dp_output_formats[] = {396{ MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_10BIT, 10, 30 },397{ MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_8BIT, 8, 24 },398{ MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_10BIT, 10, 30 },399{ MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCBCR444, DW_DP_YCBCR444_8BIT, 8, 24},400{ MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_10BIT, 10, 20 },401{ MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCBCR422, DW_DP_YCBCR422_8BIT, 8, 16 },402{ MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420_10BIT, 10, 15 },403{ MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCBCR420, DW_DP_YCBCR420_8BIT, 8, 12 },404{ MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, DW_DP_RGB_6BIT, 6, 18 },405};406407static const struct dw_dp_output_format *dw_dp_get_output_format(u32 bus_format)408{409unsigned int i;410411for (i = 0; i < ARRAY_SIZE(dw_dp_output_formats); i++)412if (dw_dp_output_formats[i].bus_format == bus_format)413return &dw_dp_output_formats[i];414415return NULL;416}417418static inline struct dw_dp *bridge_to_dp(struct drm_bridge *b)419{420return container_of(b, struct dw_dp, bridge);421}422423static struct dw_dp_bridge_state *dw_dp_get_bridge_state(struct dw_dp *dp)424{425struct dw_dp_bridge_state *dw_bridge_state;426struct drm_bridge_state *state;427428state = drm_priv_to_bridge_state(dp->bridge.base.state);429if (!state)430return NULL;431432dw_bridge_state = to_dw_dp_bridge_state(state);433if (!dw_bridge_state)434return NULL;435436return dw_bridge_state;437}438439static inline void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern)440{441regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, TPS_SEL,442FIELD_PREP(TPS_SEL, pattern));443}444445static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes)446{447u32 xmit_enable;448449switch (lanes) {450case 4:451case 2:452case 1:453xmit_enable = GENMASK(lanes - 1, 0);454break;455case 0:456default:457xmit_enable = 0;458break;459}460461regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, XMIT_ENABLE,462FIELD_PREP(XMIT_ENABLE, xmit_enable));463}464465static bool dw_dp_bandwidth_ok(struct dw_dp *dp,466const struct drm_display_mode *mode, u32 bpp,467unsigned int lanes, unsigned int rate)468{469u32 max_bw, req_bw;470471req_bw = mode->clock * bpp / 8;472max_bw = lanes * rate;473if (req_bw > max_bw)474return false;475476return true;477}478479static bool dw_dp_hpd_detect(struct dw_dp *dp)480{481u32 value;482483regmap_read(dp->regmap, DW_DP_HPD_STATUS, &value);484485return FIELD_GET(HPD_STATE, value) == DW_DP_HPD_STATE_PLUG;486}487488static void dw_dp_link_caps_reset(struct dw_dp_link_caps *caps)489{490caps->enhanced_framing = false;491caps->tps3_supported = false;492caps->tps4_supported = false;493caps->fast_training = false;494caps->channel_coding = false;495}496497static void dw_dp_link_reset(struct dw_dp_link *link)498{499link->vsc_sdp_supported = 0;500link->sink_count = 0;501link->revision = 0;502link->rate = 0;503link->lanes = 0;504505dw_dp_link_caps_reset(&link->caps);506memset(link->dpcd, 0, sizeof(link->dpcd));507}508509static int dw_dp_link_parse(struct dw_dp *dp, struct drm_connector *connector)510{511struct dw_dp_link *link = &dp->link;512int ret;513514dw_dp_link_reset(link);515516ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd);517if (ret < 0)518return ret;519520drm_dp_read_desc(&dp->aux, &link->desc, drm_dp_is_branch(link->dpcd));521522if (drm_dp_read_sink_count_cap(connector, link->dpcd, &link->desc)) {523ret = drm_dp_read_sink_count(&dp->aux);524if (ret < 0)525return ret;526527link->sink_count = ret;528529/* Dongle connected, but no display */530if (!link->sink_count)531return -ENODEV;532}533534link->vsc_sdp_supported = drm_dp_vsc_sdp_supported(&dp->aux, link->dpcd);535536link->revision = link->dpcd[DP_DPCD_REV];537link->rate = min_t(u32, min(dp->plat_data.max_link_rate,538dp->phy->attrs.max_link_rate * 100),539drm_dp_max_link_rate(link->dpcd));540link->lanes = min_t(u8, phy_get_bus_width(dp->phy),541drm_dp_max_lane_count(link->dpcd));542543link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd);544link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd);545link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd);546link->caps.fast_training = drm_dp_fast_training_cap(link->dpcd);547link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd);548link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5);549550return 0;551}552553static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp)554{555struct dw_dp_link *link = &dp->link;556struct dw_dp_link_train_set *train_set = &link->train.adjust;557unsigned int lanes = dp->link.lanes;558union phy_configure_opts phy_cfg;559unsigned int *vs, *pe;560int i, ret;561u8 buf[4];562563vs = train_set->voltage_swing;564pe = train_set->pre_emphasis;565566for (i = 0; i < lanes; i++) {567phy_cfg.dp.voltage[i] = vs[i];568phy_cfg.dp.pre[i] = pe[i];569}570571phy_cfg.dp.set_lanes = false;572phy_cfg.dp.set_rate = false;573phy_cfg.dp.set_voltages = true;574575ret = phy_configure(dp->phy, &phy_cfg);576if (ret)577return ret;578579for (i = 0; i < lanes; i++) {580buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) |581(pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT);582if (train_set->voltage_max_reached[i])583buf[i] |= DP_TRAIN_MAX_SWING_REACHED;584if (train_set->pre_max_reached[i])585buf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;586}587588ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes);589if (ret < 0)590return ret;591592return 0;593}594595static int dw_dp_phy_configure(struct dw_dp *dp, unsigned int rate,596unsigned int lanes, bool ssc)597{598union phy_configure_opts phy_cfg;599int ret;600601/* Move PHY to P3 */602regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, PHY_POWERDOWN,603FIELD_PREP(PHY_POWERDOWN, 0x3));604605phy_cfg.dp.lanes = lanes;606phy_cfg.dp.link_rate = rate / 100;607phy_cfg.dp.ssc = ssc;608phy_cfg.dp.set_lanes = true;609phy_cfg.dp.set_rate = true;610phy_cfg.dp.set_voltages = false;611ret = phy_configure(dp->phy, &phy_cfg);612if (ret)613return ret;614615regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, PHY_LANES,616FIELD_PREP(PHY_LANES, lanes / 2));617618/* Move PHY to P0 */619regmap_update_bits(dp->regmap, DW_DP_PHYIF_CTRL, PHY_POWERDOWN,620FIELD_PREP(PHY_POWERDOWN, 0x0));621622dw_dp_phy_xmit_enable(dp, lanes);623624return 0;625}626627static int dw_dp_link_configure(struct dw_dp *dp)628{629struct dw_dp_link *link = &dp->link;630u8 buf[2];631int ret;632633ret = dw_dp_phy_configure(dp, link->rate, link->lanes, link->caps.ssc);634if (ret)635return ret;636637buf[0] = drm_dp_link_rate_to_bw_code(link->rate);638buf[1] = link->lanes;639640if (link->caps.enhanced_framing) {641buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;642regmap_update_bits(dp->regmap, DW_DP_CCTL, ENHANCE_FRAMING_EN,643FIELD_PREP(ENHANCE_FRAMING_EN, 1));644} else {645regmap_update_bits(dp->regmap, DW_DP_CCTL, ENHANCE_FRAMING_EN,646FIELD_PREP(ENHANCE_FRAMING_EN, 0));647}648649ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf));650if (ret < 0)651return ret;652653buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0;654buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0;655656ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, sizeof(buf));657if (ret < 0)658return ret;659660return 0;661}662663static void dw_dp_link_train_init(struct dw_dp_link_train *train)664{665struct dw_dp_link_train_set *adj = &train->adjust;666unsigned int i;667668for (i = 0; i < 4; i++) {669adj->voltage_swing[i] = 0;670adj->pre_emphasis[i] = 0;671adj->voltage_max_reached[i] = false;672adj->pre_max_reached[i] = false;673}674675train->clock_recovered = false;676train->channel_equalized = false;677}678679static bool dw_dp_link_train_valid(const struct dw_dp_link_train *train)680{681return train->clock_recovered && train->channel_equalized;682}683684static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern)685{686u8 buf = 0;687int ret;688689if (pattern && pattern != DP_TRAINING_PATTERN_4) {690buf |= DP_LINK_SCRAMBLING_DISABLE;691692regmap_update_bits(dp->regmap, DW_DP_CCTL, SCRAMBLE_DIS,693FIELD_PREP(SCRAMBLE_DIS, 1));694} else {695regmap_update_bits(dp->regmap, DW_DP_CCTL, SCRAMBLE_DIS,696FIELD_PREP(SCRAMBLE_DIS, 0));697}698699switch (pattern) {700case DP_TRAINING_PATTERN_DISABLE:701dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_NONE);702break;703case DP_TRAINING_PATTERN_1:704dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_1);705break;706case DP_TRAINING_PATTERN_2:707dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_2);708break;709case DP_TRAINING_PATTERN_3:710dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_3);711break;712case DP_TRAINING_PATTERN_4:713dw_dp_phy_set_pattern(dp, DW_DP_PHY_PATTERN_TPS_4);714break;715default:716return -EINVAL;717}718719ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,720buf | pattern);721if (ret < 0)722return ret;723724return 0;725}726727static u8 dw_dp_voltage_max(u8 preemph)728{729switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {730case DP_TRAIN_PRE_EMPH_LEVEL_0:731return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;732case DP_TRAIN_PRE_EMPH_LEVEL_1:733return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;734case DP_TRAIN_PRE_EMPH_LEVEL_2:735return DP_TRAIN_VOLTAGE_SWING_LEVEL_1;736case DP_TRAIN_PRE_EMPH_LEVEL_3:737default:738return DP_TRAIN_VOLTAGE_SWING_LEVEL_0;739}740}741742static bool dw_dp_link_get_adjustments(struct dw_dp_link *link,743u8 status[DP_LINK_STATUS_SIZE])744{745struct dw_dp_link_train_set *adj = &link->train.adjust;746unsigned int i;747bool changed = false;748u8 v = 0;749u8 p = 0;750751for (i = 0; i < link->lanes; i++) {752v = drm_dp_get_adjust_request_voltage(status, i);753v >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;754p = drm_dp_get_adjust_request_pre_emphasis(status, i);755p >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;756757if (v != adj->voltage_swing[i] || p != adj->pre_emphasis[i])758changed = true;759760if (p >= (DP_TRAIN_PRE_EMPH_LEVEL_3 >> DP_TRAIN_PRE_EMPHASIS_SHIFT)) {761adj->pre_emphasis[i] = DP_TRAIN_PRE_EMPH_LEVEL_3 >>762DP_TRAIN_PRE_EMPHASIS_SHIFT;763adj->pre_max_reached[i] = true;764} else {765adj->pre_emphasis[i] = p;766adj->pre_max_reached[i] = false;767}768769v = min(v, dw_dp_voltage_max(p));770if (v >= (DP_TRAIN_VOLTAGE_SWING_LEVEL_3 >> DP_TRAIN_VOLTAGE_SWING_SHIFT)) {771adj->voltage_swing[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 >>772DP_TRAIN_VOLTAGE_SWING_SHIFT;773adj->voltage_max_reached[i] = true;774} else {775adj->voltage_swing[i] = v;776adj->voltage_max_reached[i] = false;777}778}779780return changed;781}782783static int dw_dp_link_clock_recovery(struct dw_dp *dp)784{785struct dw_dp_link *link = &dp->link;786u8 status[DP_LINK_STATUS_SIZE];787unsigned int tries = 0;788int ret;789bool adj_changed;790791ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1);792if (ret)793return ret;794795for (;;) {796ret = dw_dp_link_train_update_vs_emph(dp);797if (ret)798return ret;799800drm_dp_link_train_clock_recovery_delay(&dp->aux, link->dpcd);801802ret = drm_dp_dpcd_read_link_status(&dp->aux, status);803if (ret < 0) {804dev_err(dp->dev, "failed to read link status: %d\n", ret);805return ret;806}807808if (drm_dp_clock_recovery_ok(status, link->lanes)) {809link->train.clock_recovered = true;810break;811}812813/*814* According to DP spec 1.4, if current ADJ is the same815* with previous REQ, we need to retry 5 times.816*/817adj_changed = dw_dp_link_get_adjustments(link, status);818if (!adj_changed)819tries++;820else821tries = 0;822823if (tries == 5)824break;825}826827return 0;828}829830static int dw_dp_link_channel_equalization(struct dw_dp *dp)831{832struct dw_dp_link *link = &dp->link;833u8 status[DP_LINK_STATUS_SIZE], pattern;834unsigned int tries;835int ret;836837if (link->caps.tps4_supported)838pattern = DP_TRAINING_PATTERN_4;839else if (link->caps.tps3_supported)840pattern = DP_TRAINING_PATTERN_3;841else842pattern = DP_TRAINING_PATTERN_2;843ret = dw_dp_link_train_set_pattern(dp, pattern);844if (ret)845return ret;846847for (tries = 1; tries < 5; tries++) {848ret = dw_dp_link_train_update_vs_emph(dp);849if (ret)850return ret;851852drm_dp_link_train_channel_eq_delay(&dp->aux, link->dpcd);853854ret = drm_dp_dpcd_read_link_status(&dp->aux, status);855if (ret < 0)856return ret;857858if (!drm_dp_clock_recovery_ok(status, link->lanes)) {859dev_err(dp->dev, "clock recovery lost while equalizing channel\n");860link->train.clock_recovered = false;861break;862}863864if (drm_dp_channel_eq_ok(status, link->lanes)) {865link->train.channel_equalized = true;866break;867}868869dw_dp_link_get_adjustments(link, status);870}871872return 0;873}874875static int dw_dp_link_downgrade(struct dw_dp *dp)876{877struct dw_dp_link *link = &dp->link;878struct dw_dp_bridge_state *state;879880state = dw_dp_get_bridge_state(dp);881882switch (link->rate) {883case 162000:884return -EINVAL;885case 270000:886link->rate = 162000;887break;888case 540000:889link->rate = 270000;890break;891case 810000:892link->rate = 540000;893break;894}895896if (!dw_dp_bandwidth_ok(dp, &state->mode, state->bpp, link->lanes,897link->rate))898return -E2BIG;899900return 0;901}902903static int dw_dp_link_train_full(struct dw_dp *dp)904{905struct dw_dp_link *link = &dp->link;906int ret;907908retry:909dw_dp_link_train_init(&link->train);910911dev_dbg(dp->dev, "full-training link: %u lane%s at %u MHz\n",912link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100);913914ret = dw_dp_link_configure(dp);915if (ret < 0) {916dev_err(dp->dev, "failed to configure DP link: %d\n", ret);917return ret;918}919920ret = dw_dp_link_clock_recovery(dp);921if (ret < 0) {922dev_err(dp->dev, "clock recovery failed: %d\n", ret);923goto out;924}925926if (!link->train.clock_recovered) {927dev_err(dp->dev, "clock recovery failed, downgrading link\n");928929ret = dw_dp_link_downgrade(dp);930if (ret < 0)931goto out;932else933goto retry;934}935936dev_dbg(dp->dev, "clock recovery succeeded\n");937938ret = dw_dp_link_channel_equalization(dp);939if (ret < 0) {940dev_err(dp->dev, "channel equalization failed: %d\n", ret);941goto out;942}943944if (!link->train.channel_equalized) {945dev_err(dp->dev, "channel equalization failed, downgrading link\n");946947ret = dw_dp_link_downgrade(dp);948if (ret < 0)949goto out;950else951goto retry;952}953954dev_dbg(dp->dev, "channel equalization succeeded\n");955956out:957dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);958return ret;959}960961static int dw_dp_link_train_fast(struct dw_dp *dp)962{963struct dw_dp_link *link = &dp->link;964int ret;965u8 status[DP_LINK_STATUS_SIZE];966u8 pattern;967968dw_dp_link_train_init(&link->train);969970dev_dbg(dp->dev, "fast-training link: %u lane%s at %u MHz\n",971link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100);972973ret = dw_dp_link_configure(dp);974if (ret < 0) {975dev_err(dp->dev, "failed to configure DP link: %d\n", ret);976return ret;977}978979ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1);980if (ret)981goto out;982983usleep_range(500, 1000);984985if (link->caps.tps4_supported)986pattern = DP_TRAINING_PATTERN_4;987else if (link->caps.tps3_supported)988pattern = DP_TRAINING_PATTERN_3;989else990pattern = DP_TRAINING_PATTERN_2;991ret = dw_dp_link_train_set_pattern(dp, pattern);992if (ret)993goto out;994995usleep_range(500, 1000);996997ret = drm_dp_dpcd_read_link_status(&dp->aux, status);998if (ret < 0) {999dev_err(dp->dev, "failed to read link status: %d\n", ret);1000goto out;1001}10021003if (!drm_dp_clock_recovery_ok(status, link->lanes)) {1004dev_err(dp->dev, "clock recovery failed\n");1005ret = -EIO;1006goto out;1007}10081009if (!drm_dp_channel_eq_ok(status, link->lanes)) {1010dev_err(dp->dev, "channel equalization failed\n");1011ret = -EIO;1012goto out;1013}10141015out:1016dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);1017return ret;1018}10191020static int dw_dp_link_train(struct dw_dp *dp)1021{1022struct dw_dp_link *link = &dp->link;1023int ret;10241025if (link->caps.fast_training) {1026if (dw_dp_link_train_valid(&link->train)) {1027ret = dw_dp_link_train_fast(dp);1028if (ret < 0)1029dev_err(dp->dev, "fast link training failed: %d\n", ret);1030else1031return 0;1032}1033}10341035ret = dw_dp_link_train_full(dp);1036if (ret < 0) {1037dev_err(dp->dev, "full link training failed: %d\n", ret);1038return ret;1039}10401041return 0;1042}10431044static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp)1045{1046const u8 *payload = sdp->base.db;1047u32 reg;1048int i, nr;10491050nr = find_first_zero_bit(dp->sdp_reg_bank, SDP_REG_BANK_SIZE);1051if (nr < SDP_REG_BANK_SIZE)1052set_bit(nr, dp->sdp_reg_bank);1053else1054return -EBUSY;10551056reg = DW_DP_SDP_REGISTER_BANK + nr * 9 * 4;10571058/* SDP header */1059regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->base.sdp_header));10601061/* SDP data payload */1062for (i = 1; i < 9; i++, payload += 4)1063regmap_write(dp->regmap, reg + i * 4,1064FIELD_PREP(SDP_REGS, get_unaligned_le32(payload)));10651066if (sdp->flags & DW_DP_SDP_VERTICAL_INTERVAL)1067regmap_update_bits(dp->regmap, DW_DP_SDP_VERTICAL_CTRL,1068EN_VERTICAL_SDP << nr,1069EN_VERTICAL_SDP << nr);10701071if (sdp->flags & DW_DP_SDP_HORIZONTAL_INTERVAL)1072regmap_update_bits(dp->regmap, DW_DP_SDP_HORIZONTAL_CTRL,1073EN_HORIZONTAL_SDP << nr,1074EN_HORIZONTAL_SDP << nr);10751076return 0;1077}10781079static int dw_dp_send_vsc_sdp(struct dw_dp *dp)1080{1081struct dw_dp_bridge_state *state;1082struct dw_dp_sdp sdp = {};1083struct drm_dp_vsc_sdp vsc = {};10841085state = dw_dp_get_bridge_state(dp);1086if (!state)1087return -EINVAL;10881089vsc.bpc = state->bpc;10901091vsc.sdp_type = DP_SDP_VSC;1092vsc.revision = 0x5;1093vsc.length = 0x13;1094vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED;10951096sdp.flags = DW_DP_SDP_VERTICAL_INTERVAL;10971098switch (state->color_format) {1099case DRM_COLOR_FORMAT_YCBCR444:1100vsc.pixelformat = DP_PIXELFORMAT_YUV444;1101break;1102case DRM_COLOR_FORMAT_YCBCR420:1103vsc.pixelformat = DP_PIXELFORMAT_YUV420;1104break;1105case DRM_COLOR_FORMAT_YCBCR422:1106vsc.pixelformat = DP_PIXELFORMAT_YUV422;1107break;1108case DRM_COLOR_FORMAT_RGB444:1109default:1110vsc.pixelformat = DP_PIXELFORMAT_RGB;1111break;1112}11131114if (state->color_format == DRM_COLOR_FORMAT_RGB444) {1115vsc.colorimetry = DP_COLORIMETRY_DEFAULT;1116vsc.dynamic_range = DP_DYNAMIC_RANGE_VESA;1117} else {1118vsc.colorimetry = DP_COLORIMETRY_BT709_YCC;1119vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA;1120}11211122drm_dp_vsc_sdp_pack(&vsc, &sdp.base);11231124return dw_dp_send_sdp(dp, &sdp);1125}11261127static int dw_dp_video_set_pixel_mode(struct dw_dp *dp)1128{1129switch (dp->pixel_mode) {1130case DW_DP_MP_SINGLE_PIXEL:1131case DW_DP_MP_DUAL_PIXEL:1132case DW_DP_MP_QUAD_PIXEL:1133break;1134default:1135return -EINVAL;1136}11371138regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, PIXEL_MODE_SELECT,1139FIELD_PREP(PIXEL_MODE_SELECT, dp->pixel_mode));11401141return 0;1142}11431144static bool dw_dp_video_need_vsc_sdp(struct dw_dp *dp)1145{1146struct dw_dp_link *link = &dp->link;1147struct dw_dp_bridge_state *state;11481149state = dw_dp_get_bridge_state(dp);1150if (!state)1151return -EINVAL;11521153if (!link->vsc_sdp_supported)1154return false;11551156if (state->color_format == DRM_COLOR_FORMAT_YCBCR420)1157return true;11581159return false;1160}11611162static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc,1163u16 vstart, u16 hstart)1164{1165u16 misc = 0;11661167if (dw_dp_video_need_vsc_sdp(dp))1168misc |= DP_MSA_MISC_COLOR_VSC_SDP;11691170switch (color_format) {1171case DRM_COLOR_FORMAT_RGB444:1172misc |= DP_MSA_MISC_COLOR_RGB;1173break;1174case DRM_COLOR_FORMAT_YCBCR444:1175misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709;1176break;1177case DRM_COLOR_FORMAT_YCBCR422:1178misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709;1179break;1180case DRM_COLOR_FORMAT_YCBCR420:1181break;1182default:1183return -EINVAL;1184}11851186switch (bpc) {1187case 6:1188misc |= DP_MSA_MISC_6_BPC;1189break;1190case 8:1191misc |= DP_MSA_MISC_8_BPC;1192break;1193case 10:1194misc |= DP_MSA_MISC_10_BPC;1195break;1196case 12:1197misc |= DP_MSA_MISC_12_BPC;1198break;1199case 16:1200misc |= DP_MSA_MISC_16_BPC;1201break;1202default:1203return -EINVAL;1204}12051206regmap_write(dp->regmap, DW_DP_VIDEO_MSA1,1207FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart));1208regmap_write(dp->regmap, DW_DP_VIDEO_MSA2, FIELD_PREP(MISC0, misc));1209regmap_write(dp->regmap, DW_DP_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8));12101211return 0;1212}12131214static void dw_dp_video_disable(struct dw_dp *dp)1215{1216regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE,1217FIELD_PREP(VIDEO_STREAM_ENABLE, 0));1218}12191220static int dw_dp_video_enable(struct dw_dp *dp)1221{1222struct dw_dp_link *link = &dp->link;1223struct dw_dp_bridge_state *state;1224struct drm_display_mode *mode;1225u8 color_format, bpc, bpp;1226u8 init_threshold, vic;1227u32 hstart, hactive, hblank, h_sync_width, h_front_porch;1228u32 vstart, vactive, vblank, v_sync_width, v_front_porch;1229u32 peak_stream_bandwidth, link_bandwidth;1230u32 average_bytes_per_tu, average_bytes_per_tu_frac;1231u32 ts, hblank_interval;1232u32 value;1233int ret;12341235state = dw_dp_get_bridge_state(dp);1236if (!state)1237return -EINVAL;12381239bpc = state->bpc;1240bpp = state->bpp;1241color_format = state->color_format;1242mode = &state->mode;12431244vstart = mode->vtotal - mode->vsync_start;1245hstart = mode->htotal - mode->hsync_start;12461247ret = dw_dp_video_set_pixel_mode(dp);1248if (ret)1249return ret;12501251ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart);1252if (ret)1253return ret;12541255regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, VIDEO_MAPPING,1256FIELD_PREP(VIDEO_MAPPING, state->video_mapping));12571258/* Configure DW_DP_VINPUT_POLARITY_CTRL register */1259value = 0;1260if (mode->flags & DRM_MODE_FLAG_PHSYNC)1261value |= FIELD_PREP(HSYNC_IN_POLARITY, 1);1262if (mode->flags & DRM_MODE_FLAG_PVSYNC)1263value |= FIELD_PREP(VSYNC_IN_POLARITY, 1);1264regmap_write(dp->regmap, DW_DP_VINPUT_POLARITY_CTRL, value);12651266/* Configure DW_DP_VIDEO_CONFIG1 register */1267hactive = mode->hdisplay;1268hblank = mode->htotal - mode->hdisplay;1269value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank);1270if (mode->flags & DRM_MODE_FLAG_INTERLACE)1271value |= FIELD_PREP(I_P, 1);1272vic = drm_match_cea_mode(mode);1273if (vic == 5 || vic == 6 || vic == 7 ||1274vic == 10 || vic == 11 || vic == 20 ||1275vic == 21 || vic == 22 || vic == 39 ||1276vic == 25 || vic == 26 || vic == 40 ||1277vic == 44 || vic == 45 || vic == 46 ||1278vic == 50 || vic == 51 || vic == 54 ||1279vic == 55 || vic == 58 || vic == 59)1280value |= R_V_BLANK_IN_OSC;1281regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG1, value);12821283/* Configure DW_DP_VIDEO_CONFIG2 register */1284vblank = mode->vtotal - mode->vdisplay;1285vactive = mode->vdisplay;1286regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG2,1287FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive));12881289/* Configure DW_DP_VIDEO_CONFIG3 register */1290h_sync_width = mode->hsync_end - mode->hsync_start;1291h_front_porch = mode->hsync_start - mode->hdisplay;1292regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG3,1293FIELD_PREP(H_SYNC_WIDTH, h_sync_width) |1294FIELD_PREP(H_FRONT_PORCH, h_front_porch));12951296/* Configure DW_DP_VIDEO_CONFIG4 register */1297v_sync_width = mode->vsync_end - mode->vsync_start;1298v_front_porch = mode->vsync_start - mode->vdisplay;1299regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG4,1300FIELD_PREP(V_SYNC_WIDTH, v_sync_width) |1301FIELD_PREP(V_FRONT_PORCH, v_front_porch));13021303/* Configure DW_DP_VIDEO_CONFIG5 register */1304peak_stream_bandwidth = mode->clock * bpp / 8;1305link_bandwidth = (link->rate / 1000) * link->lanes;1306ts = peak_stream_bandwidth * 64 / link_bandwidth;1307average_bytes_per_tu = ts / 1000;1308average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10;1309if (dp->pixel_mode == DW_DP_MP_SINGLE_PIXEL) {1310if (average_bytes_per_tu < 6)1311init_threshold = 32;1312else if (hblank <= 80 && color_format != DRM_COLOR_FORMAT_YCBCR420)1313init_threshold = 12;1314else if (hblank <= 40 && color_format == DRM_COLOR_FORMAT_YCBCR420)1315init_threshold = 3;1316else1317init_threshold = 16;1318} else {1319u32 t1 = 0, t2 = 0, t3 = 0;13201321switch (bpc) {1322case 6:1323t1 = (4 * 1000 / 9) * link->lanes;1324break;1325case 8:1326if (color_format == DRM_COLOR_FORMAT_YCBCR422) {1327t1 = (1000 / 2) * link->lanes;1328} else {1329if (dp->pixel_mode == DW_DP_MP_DUAL_PIXEL)1330t1 = (1000 / 3) * link->lanes;1331else1332t1 = (3000 / 16) * link->lanes;1333}1334break;1335case 10:1336if (color_format == DRM_COLOR_FORMAT_YCBCR422)1337t1 = (2000 / 5) * link->lanes;1338else1339t1 = (4000 / 15) * link->lanes;1340break;1341case 12:1342if (color_format == DRM_COLOR_FORMAT_YCBCR422) {1343if (dp->pixel_mode == DW_DP_MP_DUAL_PIXEL)1344t1 = (1000 / 6) * link->lanes;1345else1346t1 = (1000 / 3) * link->lanes;1347} else {1348t1 = (2000 / 9) * link->lanes;1349}1350break;1351case 16:1352if (color_format != DRM_COLOR_FORMAT_YCBCR422 &&1353dp->pixel_mode == DW_DP_MP_DUAL_PIXEL)1354t1 = (1000 / 6) * link->lanes;1355else1356t1 = (1000 / 4) * link->lanes;1357break;1358default:1359return -EINVAL;1360}13611362if (color_format == DRM_COLOR_FORMAT_YCBCR420)1363t2 = (link->rate / 4) * 1000 / (mode->clock / 2);1364else1365t2 = (link->rate / 4) * 1000 / mode->clock;13661367if (average_bytes_per_tu_frac)1368t3 = average_bytes_per_tu + 1;1369else1370t3 = average_bytes_per_tu;1371init_threshold = t1 * t2 * t3 / (1000 * 1000);1372if (init_threshold <= 16 || average_bytes_per_tu < 10)1373init_threshold = 40;1374}13751376regmap_write(dp->regmap, DW_DP_VIDEO_CONFIG5,1377FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) |1378FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC, average_bytes_per_tu_frac) |1379FIELD_PREP(INIT_THRESHOLD, init_threshold) |1380FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu));13811382/* Configure DW_DP_VIDEO_HBLANK_INTERVAL register */1383hblank_interval = hblank * (link->rate / 4) / mode->clock;1384regmap_write(dp->regmap, DW_DP_VIDEO_HBLANK_INTERVAL,1385FIELD_PREP(HBLANK_INTERVAL_EN, 1) |1386FIELD_PREP(HBLANK_INTERVAL, hblank_interval));13871388/* Video stream enable */1389regmap_update_bits(dp->regmap, DW_DP_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE,1390FIELD_PREP(VIDEO_STREAM_ENABLE, 1));13911392if (dw_dp_video_need_vsc_sdp(dp))1393dw_dp_send_vsc_sdp(dp);13941395return 0;1396}13971398static void dw_dp_hpd_init(struct dw_dp *dp)1399{1400/* Enable all HPD interrupts */1401regmap_update_bits(dp->regmap, DW_DP_HPD_INTERRUPT_ENABLE,1402HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN,1403FIELD_PREP(HPD_UNPLUG_EN, 1) |1404FIELD_PREP(HPD_PLUG_EN, 1) |1405FIELD_PREP(HPD_IRQ_EN, 1));14061407/* Enable all top-level interrupts */1408regmap_update_bits(dp->regmap, DW_DP_GENERAL_INTERRUPT_ENABLE,1409HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1));1410}14111412static void dw_dp_aux_init(struct dw_dp *dp)1413{1414regmap_update_bits(dp->regmap, DW_DP_GENERAL_INTERRUPT_ENABLE,1415AUX_REPLY_EVENT_EN, FIELD_PREP(AUX_REPLY_EVENT_EN, 1));1416}14171418static void dw_dp_init_hw(struct dw_dp *dp)1419{1420regmap_update_bits(dp->regmap, DW_DP_CCTL, DEFAULT_FAST_LINK_TRAIN_EN,1421FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0));14221423dw_dp_hpd_init(dp);1424dw_dp_aux_init(dp);1425}14261427static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size)1428{1429size_t i, j;14301431for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {1432size_t num = min_t(size_t, size - i * 4, 4);1433u32 value = 0;14341435for (j = 0; j < num; j++)1436value |= buffer[i * 4 + j] << (j * 8);14371438regmap_write(dp->regmap, DW_DP_AUX_DATA0 + i * 4, value);1439}14401441return size;1442}14431444static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size)1445{1446size_t i, j;14471448for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {1449size_t num = min_t(size_t, size - i * 4, 4);1450u32 value;14511452regmap_read(dp->regmap, DW_DP_AUX_DATA0 + i * 4, &value);14531454for (j = 0; j < num; j++)1455buffer[i * 4 + j] = value >> (j * 8);1456}14571458return size;1459}14601461static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,1462struct drm_dp_aux_msg *msg)1463{1464struct dw_dp *dp = container_of(aux, struct dw_dp, aux);1465unsigned long timeout = msecs_to_jiffies(10);1466u32 status, value;1467ssize_t ret = 0;14681469if (WARN_ON(msg->size > 16))1470return -E2BIG;14711472switch (msg->request & ~DP_AUX_I2C_MOT) {1473case DP_AUX_NATIVE_WRITE:1474case DP_AUX_I2C_WRITE:1475case DP_AUX_I2C_WRITE_STATUS_UPDATE:1476ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size);1477if (ret < 0)1478return ret;1479break;1480case DP_AUX_NATIVE_READ:1481case DP_AUX_I2C_READ:1482break;1483default:1484return -EINVAL;1485}14861487if (msg->size > 0)1488value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1);1489else1490value = FIELD_PREP(I2C_ADDR_ONLY, 1);1491value |= FIELD_PREP(AUX_CMD_TYPE, msg->request);1492value |= FIELD_PREP(AUX_ADDR, msg->address);1493regmap_write(dp->regmap, DW_DP_AUX_CMD, value);14941495status = wait_for_completion_timeout(&dp->complete, timeout);1496if (!status) {1497dev_err(dp->dev, "timeout waiting for AUX reply\n");1498return -ETIMEDOUT;1499}15001501regmap_read(dp->regmap, DW_DP_AUX_STATUS, &value);1502if (value & AUX_TIMEOUT)1503return -ETIMEDOUT;15041505msg->reply = FIELD_GET(AUX_STATUS, value);15061507if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) {1508if (msg->request & DP_AUX_I2C_READ) {1509size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1;15101511if (count != msg->size)1512return -EBUSY;15131514ret = dw_dp_aux_read_data(dp, msg->buffer, count);1515if (ret < 0)1516return ret;1517}1518}15191520return ret;1521}15221523/*1524* Limits for the video timing for DP:1525* 1. the hfp should be 2 pixels aligned;1526* 2. the minimum hsync should be 9 pixel;1527* 3. the minimum hbp should be 16 pixel;1528*/1529static int dw_dp_bridge_atomic_check(struct drm_bridge *bridge,1530struct drm_bridge_state *bridge_state,1531struct drm_crtc_state *crtc_state,1532struct drm_connector_state *conn_state)1533{1534struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;1535struct dw_dp *dp = bridge_to_dp(bridge);1536struct dw_dp_bridge_state *state;1537const struct dw_dp_output_format *fmt;1538struct drm_display_mode *mode;1539int min_hbp = 16;1540int min_hsync = 9;15411542state = to_dw_dp_bridge_state(bridge_state);1543mode = &state->mode;15441545fmt = dw_dp_get_output_format(bridge_state->output_bus_cfg.format);1546if (!fmt)1547return -EINVAL;15481549state->video_mapping = fmt->video_mapping;1550state->color_format = fmt->color_format;1551state->bpc = fmt->bpc;1552state->bpp = fmt->bpp;15531554if ((adjusted_mode->hsync_start - adjusted_mode->hdisplay) & 0x1) {1555adjusted_mode->hsync_start += 1;1556dev_warn(dp->dev, "hfp is not 2 pixeel aligned, fixup to aligned hfp\n");1557}15581559if (adjusted_mode->hsync_end - adjusted_mode->hsync_start < min_hsync) {1560adjusted_mode->hsync_end = adjusted_mode->hsync_start + min_hsync;1561dev_warn(dp->dev, "hsync is too narrow, fixup to min hsync:%d\n", min_hsync);1562}15631564if (adjusted_mode->htotal - adjusted_mode->hsync_end < min_hbp) {1565adjusted_mode->htotal = adjusted_mode->hsync_end + min_hbp;1566dev_warn(dp->dev, "hbp is too narrow, fixup to min hbp:%d\n", min_hbp);1567}15681569drm_mode_copy(mode, adjusted_mode);15701571return 0;1572}15731574static enum drm_mode_status dw_dp_bridge_mode_valid(struct drm_bridge *bridge,1575const struct drm_display_info *info,1576const struct drm_display_mode *mode)1577{1578struct dw_dp *dp = bridge_to_dp(bridge);1579struct dw_dp_link *link = &dp->link;1580u32 min_bpp;15811582if (info->color_formats & DRM_COLOR_FORMAT_YCBCR420 &&1583link->vsc_sdp_supported &&1584(drm_mode_is_420_only(info, mode) || drm_mode_is_420_also(info, mode)))1585min_bpp = 12;1586else if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)1587min_bpp = 16;1588else if (info->color_formats & DRM_COLOR_FORMAT_RGB444)1589min_bpp = 18;1590else1591min_bpp = 24;15921593if (!link->vsc_sdp_supported &&1594drm_mode_is_420_only(info, mode))1595return MODE_NO_420;15961597if (!dw_dp_bandwidth_ok(dp, mode, min_bpp, link->lanes, link->rate))1598return MODE_CLOCK_HIGH;15991600return MODE_OK;1601}16021603static bool dw_dp_needs_link_retrain(struct dw_dp *dp)1604{1605struct dw_dp_link *link = &dp->link;1606u8 link_status[DP_LINK_STATUS_SIZE];16071608if (!dw_dp_link_train_valid(&link->train))1609return false;16101611if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) < 0)1612return false;16131614/* Retrain if Channel EQ or CR not ok */1615return !drm_dp_channel_eq_ok(link_status, dp->link.lanes);1616}16171618static void dw_dp_link_disable(struct dw_dp *dp)1619{1620struct dw_dp_link *link = &dp->link;16211622if (dw_dp_hpd_detect(dp))1623drm_dp_link_power_down(&dp->aux, dp->link.revision);16241625dw_dp_phy_xmit_enable(dp, 0);16261627phy_power_off(dp->phy);16281629link->train.clock_recovered = false;1630link->train.channel_equalized = false;1631}16321633static int dw_dp_link_enable(struct dw_dp *dp)1634{1635int ret;16361637ret = phy_power_on(dp->phy);1638if (ret)1639return ret;16401641ret = drm_dp_link_power_up(&dp->aux, dp->link.revision);1642if (ret < 0)1643return ret;16441645ret = dw_dp_link_train(dp);16461647return ret;1648}16491650static void dw_dp_bridge_atomic_enable(struct drm_bridge *bridge,1651struct drm_atomic_state *state)1652{1653struct dw_dp *dp = bridge_to_dp(bridge);1654struct drm_connector *connector;1655struct drm_connector_state *conn_state;1656int ret;16571658connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);1659if (!connector) {1660dev_err(dp->dev, "failed to get connector\n");1661return;1662}16631664conn_state = drm_atomic_get_new_connector_state(state, connector);1665if (!conn_state) {1666dev_err(dp->dev, "failed to get connector state\n");1667return;1668}16691670set_bit(0, dp->sdp_reg_bank);16711672ret = dw_dp_link_enable(dp);1673if (ret < 0) {1674dev_err(dp->dev, "failed to enable link: %d\n", ret);1675return;1676}16771678ret = dw_dp_video_enable(dp);1679if (ret < 0) {1680dev_err(dp->dev, "failed to enable video: %d\n", ret);1681return;1682}1683}16841685static void dw_dp_reset(struct dw_dp *dp)1686{1687int val;16881689disable_irq(dp->irq);1690regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET,1691FIELD_PREP(CONTROLLER_RESET, 1));1692usleep_range(10, 20);1693regmap_update_bits(dp->regmap, DW_DP_SOFT_RESET_CTRL, CONTROLLER_RESET,1694FIELD_PREP(CONTROLLER_RESET, 0));16951696dw_dp_init_hw(dp);1697regmap_read_poll_timeout(dp->regmap, DW_DP_HPD_STATUS, val,1698FIELD_GET(HPD_HOT_PLUG, val), 200, 200000);1699regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_PLUG);1700enable_irq(dp->irq);1701}17021703static void dw_dp_bridge_atomic_disable(struct drm_bridge *bridge,1704struct drm_atomic_state *state)1705{1706struct dw_dp *dp = bridge_to_dp(bridge);17071708dw_dp_video_disable(dp);1709dw_dp_link_disable(dp);1710bitmap_zero(dp->sdp_reg_bank, SDP_REG_BANK_SIZE);1711dw_dp_reset(dp);1712}17131714static bool dw_dp_hpd_detect_link(struct dw_dp *dp, struct drm_connector *connector)1715{1716int ret;17171718ret = phy_power_on(dp->phy);1719if (ret < 0)1720return false;1721ret = dw_dp_link_parse(dp, connector);1722phy_power_off(dp->phy);17231724return !ret;1725}17261727static enum drm_connector_status dw_dp_bridge_detect(struct drm_bridge *bridge,1728struct drm_connector *connector)1729{1730struct dw_dp *dp = bridge_to_dp(bridge);17311732if (!dw_dp_hpd_detect(dp))1733return connector_status_disconnected;17341735if (!dw_dp_hpd_detect_link(dp, connector))1736return connector_status_disconnected;17371738return connector_status_connected;1739}17401741static const struct drm_edid *dw_dp_bridge_edid_read(struct drm_bridge *bridge,1742struct drm_connector *connector)1743{1744struct dw_dp *dp = bridge_to_dp(bridge);1745const struct drm_edid *edid;1746int ret;17471748ret = phy_power_on(dp->phy);1749if (ret)1750return NULL;17511752edid = drm_edid_read_ddc(connector, &dp->aux.ddc);17531754phy_power_off(dp->phy);17551756return edid;1757}17581759static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,1760struct drm_bridge_state *bridge_state,1761struct drm_crtc_state *crtc_state,1762struct drm_connector_state *conn_state,1763unsigned int *num_output_fmts)1764{1765struct dw_dp *dp = bridge_to_dp(bridge);1766struct dw_dp_link *link = &dp->link;1767struct drm_display_info *di = &conn_state->connector->display_info;1768struct drm_display_mode mode = crtc_state->mode;1769const struct dw_dp_output_format *fmt;1770u32 i, j = 0;1771u32 *output_fmts;17721773*num_output_fmts = 0;17741775output_fmts = kcalloc(ARRAY_SIZE(dw_dp_output_formats), sizeof(*output_fmts), GFP_KERNEL);1776if (!output_fmts)1777return NULL;17781779for (i = 0; i < ARRAY_SIZE(dw_dp_output_formats); i++) {1780fmt = &dw_dp_output_formats[i];17811782if (fmt->bpc > conn_state->max_bpc)1783continue;17841785if (!(fmt->color_format & di->color_formats))1786continue;17871788if (fmt->color_format == DRM_COLOR_FORMAT_YCBCR420 &&1789!link->vsc_sdp_supported)1790continue;17911792if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR420 &&1793drm_mode_is_420_only(di, &mode))1794continue;17951796if (!dw_dp_bandwidth_ok(dp, &mode, fmt->bpp, link->lanes, link->rate))1797continue;17981799output_fmts[j++] = fmt->bus_format;1800}18011802*num_output_fmts = j;18031804return output_fmts;1805}18061807static struct drm_bridge_state *dw_dp_bridge_atomic_duplicate_state(struct drm_bridge *bridge)1808{1809struct dw_dp_bridge_state *state;18101811state = kzalloc(sizeof(*state), GFP_KERNEL);1812if (!state)1813return NULL;18141815__drm_atomic_helper_bridge_duplicate_state(bridge, &state->base);18161817return &state->base;1818}18191820static const struct drm_bridge_funcs dw_dp_bridge_funcs = {1821.atomic_duplicate_state = dw_dp_bridge_atomic_duplicate_state,1822.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,1823.atomic_reset = drm_atomic_helper_bridge_reset,1824.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,1825.atomic_get_output_bus_fmts = dw_dp_bridge_atomic_get_output_bus_fmts,1826.atomic_check = dw_dp_bridge_atomic_check,1827.mode_valid = dw_dp_bridge_mode_valid,1828.atomic_enable = dw_dp_bridge_atomic_enable,1829.atomic_disable = dw_dp_bridge_atomic_disable,1830.detect = dw_dp_bridge_detect,1831.edid_read = dw_dp_bridge_edid_read,1832};18331834static int dw_dp_link_retrain(struct dw_dp *dp)1835{1836struct drm_device *dev = dp->bridge.dev;1837struct drm_modeset_acquire_ctx ctx;1838int ret;18391840if (!dw_dp_needs_link_retrain(dp))1841return 0;18421843dev_dbg(dp->dev, "Retraining link\n");18441845drm_modeset_acquire_init(&ctx, 0);1846for (;;) {1847ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx);1848if (ret != -EDEADLK)1849break;18501851drm_modeset_backoff(&ctx);1852}18531854if (!ret)1855ret = dw_dp_link_train(dp);18561857drm_modeset_drop_locks(&ctx);1858drm_modeset_acquire_fini(&ctx);18591860return ret;1861}18621863static void dw_dp_hpd_work(struct work_struct *work)1864{1865struct dw_dp *dp = container_of(work, struct dw_dp, hpd_work);1866bool long_hpd;1867int ret;18681869mutex_lock(&dp->irq_lock);1870long_hpd = dp->hotplug.long_hpd;1871mutex_unlock(&dp->irq_lock);18721873dev_dbg(dp->dev, "[drm] Get hpd irq - %s\n", long_hpd ? "long" : "short");18741875if (!long_hpd) {1876if (dw_dp_needs_link_retrain(dp)) {1877ret = dw_dp_link_retrain(dp);1878if (ret)1879dev_warn(dp->dev, "Retrain link failed\n");1880}1881} else {1882drm_helper_hpd_irq_event(dp->bridge.dev);1883}1884}18851886static void dw_dp_handle_hpd_event(struct dw_dp *dp)1887{1888u32 value;18891890mutex_lock(&dp->irq_lock);1891regmap_read(dp->regmap, DW_DP_HPD_STATUS, &value);18921893if (value & HPD_IRQ) {1894dev_dbg(dp->dev, "IRQ from the HPD\n");1895dp->hotplug.long_hpd = false;1896regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_IRQ);1897}18981899if (value & HPD_HOT_PLUG) {1900dev_dbg(dp->dev, "Hot plug detected\n");1901dp->hotplug.long_hpd = true;1902regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_PLUG);1903}19041905if (value & HPD_HOT_UNPLUG) {1906dev_dbg(dp->dev, "Unplug detected\n");1907dp->hotplug.long_hpd = true;1908regmap_write(dp->regmap, DW_DP_HPD_STATUS, HPD_HOT_UNPLUG);1909}1910mutex_unlock(&dp->irq_lock);19111912schedule_work(&dp->hpd_work);1913}19141915static irqreturn_t dw_dp_irq(int irq, void *data)1916{1917struct dw_dp *dp = data;1918u32 value;19191920regmap_read(dp->regmap, DW_DP_GENERAL_INTERRUPT, &value);1921if (!value)1922return IRQ_NONE;19231924if (value & HPD_EVENT)1925dw_dp_handle_hpd_event(dp);19261927if (value & AUX_REPLY_EVENT) {1928regmap_write(dp->regmap, DW_DP_GENERAL_INTERRUPT, AUX_REPLY_EVENT);1929complete(&dp->complete);1930}19311932return IRQ_HANDLED;1933}19341935static const struct regmap_range dw_dp_readable_ranges[] = {1936regmap_reg_range(DW_DP_VERSION_NUMBER, DW_DP_ID),1937regmap_reg_range(DW_DP_CONFIG_REG1, DW_DP_CONFIG_REG3),1938regmap_reg_range(DW_DP_CCTL, DW_DP_SOFT_RESET_CTRL),1939regmap_reg_range(DW_DP_VSAMPLE_CTRL, DW_DP_VIDEO_HBLANK_INTERVAL),1940regmap_reg_range(DW_DP_AUD_CONFIG1, DW_DP_AUD_CONFIG1),1941regmap_reg_range(DW_DP_SDP_VERTICAL_CTRL, DW_DP_SDP_STATUS_EN),1942regmap_reg_range(DW_DP_PHYIF_CTRL, DW_DP_PHYIF_PWRDOWN_CTRL),1943regmap_reg_range(DW_DP_AUX_CMD, DW_DP_AUX_DATA3),1944regmap_reg_range(DW_DP_GENERAL_INTERRUPT, DW_DP_HPD_INTERRUPT_ENABLE),1945};19461947static const struct regmap_access_table dw_dp_readable_table = {1948.yes_ranges = dw_dp_readable_ranges,1949.n_yes_ranges = ARRAY_SIZE(dw_dp_readable_ranges),1950};19511952static const struct regmap_config dw_dp_regmap_config = {1953.reg_bits = 32,1954.reg_stride = 4,1955.val_bits = 32,1956.fast_io = true,1957.max_register = DW_DP_MAX_REGISTER,1958.rd_table = &dw_dp_readable_table,1959};19601961static void dw_dp_phy_exit(void *data)1962{1963struct dw_dp *dp = data;19641965phy_exit(dp->phy);1966}19671968struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,1969const struct dw_dp_plat_data *plat_data)1970{1971struct platform_device *pdev = to_platform_device(dev);1972struct dw_dp *dp;1973struct drm_bridge *bridge;1974void __iomem *res;1975int ret;19761977dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);1978if (!dp)1979return ERR_PTR(-ENOMEM);19801981dp = devm_drm_bridge_alloc(dev, struct dw_dp, bridge, &dw_dp_bridge_funcs);1982if (IS_ERR(dp))1983return ERR_CAST(dp);19841985dp->dev = dev;1986dp->pixel_mode = DW_DP_MP_QUAD_PIXEL;19871988dp->plat_data.max_link_rate = plat_data->max_link_rate;1989bridge = &dp->bridge;1990mutex_init(&dp->irq_lock);1991INIT_WORK(&dp->hpd_work, dw_dp_hpd_work);1992init_completion(&dp->complete);19931994res = devm_platform_ioremap_resource(pdev, 0);1995if (IS_ERR(res))1996return ERR_CAST(res);19971998dp->regmap = devm_regmap_init_mmio(dev, res, &dw_dp_regmap_config);1999if (IS_ERR(dp->regmap)) {2000dev_err_probe(dev, PTR_ERR(dp->regmap), "failed to create regmap\n");2001return ERR_CAST(dp->regmap);2002}20032004dp->phy = devm_of_phy_get(dev, dev->of_node, NULL);2005if (IS_ERR(dp->phy)) {2006dev_err_probe(dev, PTR_ERR(dp->phy), "failed to get phy\n");2007return ERR_CAST(dp->phy);2008}20092010dp->apb_clk = devm_clk_get_enabled(dev, "apb");2011if (IS_ERR(dp->apb_clk)) {2012dev_err_probe(dev, PTR_ERR(dp->apb_clk), "failed to get apb clock\n");2013return ERR_CAST(dp->apb_clk);2014}20152016dp->aux_clk = devm_clk_get_enabled(dev, "aux");2017if (IS_ERR(dp->aux_clk)) {2018dev_err_probe(dev, PTR_ERR(dp->aux_clk), "failed to get aux clock\n");2019return ERR_CAST(dp->aux_clk);2020}20212022dp->i2s_clk = devm_clk_get(dev, "i2s");2023if (IS_ERR(dp->i2s_clk)) {2024dev_err_probe(dev, PTR_ERR(dp->i2s_clk), "failed to get i2s clock\n");2025return ERR_CAST(dp->i2s_clk);2026}20272028dp->spdif_clk = devm_clk_get(dev, "spdif");2029if (IS_ERR(dp->spdif_clk)) {2030dev_err_probe(dev, PTR_ERR(dp->spdif_clk), "failed to get spdif clock\n");2031return ERR_CAST(dp->spdif_clk);2032}20332034dp->hdcp_clk = devm_clk_get(dev, "hdcp");2035if (IS_ERR(dp->hdcp_clk)) {2036dev_err_probe(dev, PTR_ERR(dp->hdcp_clk), "failed to get hdcp clock\n");2037return ERR_CAST(dp->hdcp_clk);2038}20392040dp->rstc = devm_reset_control_get(dev, NULL);2041if (IS_ERR(dp->rstc)) {2042dev_err_probe(dev, PTR_ERR(dp->rstc), "failed to get reset control\n");2043return ERR_CAST(dp->rstc);2044}20452046bridge->of_node = dev->of_node;2047bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;2048bridge->type = DRM_MODE_CONNECTOR_DisplayPort;2049bridge->ycbcr_420_allowed = true;20502051dp->aux.dev = dev;2052dp->aux.drm_dev = encoder->dev;2053dp->aux.name = dev_name(dev);2054dp->aux.transfer = dw_dp_aux_transfer;2055ret = drm_dp_aux_register(&dp->aux);2056if (ret) {2057dev_err_probe(dev, ret, "Aux register failed\n");2058return ERR_PTR(ret);2059}20602061ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);2062if (ret)2063dev_err_probe(dev, ret, "Failed to attach bridge\n");20642065dw_dp_init_hw(dp);20662067ret = phy_init(dp->phy);2068if (ret) {2069dev_err_probe(dev, ret, "phy init failed\n");2070return ERR_PTR(ret);2071}20722073ret = devm_add_action_or_reset(dev, dw_dp_phy_exit, dp);2074if (ret)2075return ERR_PTR(ret);20762077dp->irq = platform_get_irq(pdev, 0);2078if (dp->irq < 0)2079return ERR_PTR(ret);20802081ret = devm_request_threaded_irq(dev, dp->irq, NULL, dw_dp_irq,2082IRQF_ONESHOT, dev_name(dev), dp);2083if (ret) {2084dev_err_probe(dev, ret, "failed to request irq\n");2085return ERR_PTR(ret);2086}20872088return dp;2089}2090EXPORT_SYMBOL_GPL(dw_dp_bind);20912092MODULE_AUTHOR("Andy Yan <[email protected]>");2093MODULE_DESCRIPTION("DW DP Core Library");2094MODULE_LICENSE("GPL");209520962097