1*7caff0fcSAndrey Gusakov /* 2*7caff0fcSAndrey Gusakov * tc358767 eDP bridge driver 3*7caff0fcSAndrey Gusakov * 4*7caff0fcSAndrey Gusakov * Copyright (C) 2016 CogentEmbedded Inc 5*7caff0fcSAndrey Gusakov * Author: Andrey Gusakov <andrey.gusakov@cogentembedded.com> 6*7caff0fcSAndrey Gusakov * 7*7caff0fcSAndrey Gusakov * Copyright (C) 2016 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> 8*7caff0fcSAndrey Gusakov * 9*7caff0fcSAndrey Gusakov * Initially based on: drivers/gpu/drm/i2c/tda998x_drv.c 10*7caff0fcSAndrey Gusakov * 11*7caff0fcSAndrey Gusakov * Copyright (C) 2012 Texas Instruments 12*7caff0fcSAndrey Gusakov * Author: Rob Clark <robdclark@gmail.com> 13*7caff0fcSAndrey Gusakov * 14*7caff0fcSAndrey Gusakov * This program is free software; you can redistribute it and/or modify 15*7caff0fcSAndrey Gusakov * it under the terms of the GNU General Public License as published by 16*7caff0fcSAndrey Gusakov * the Free Software Foundation; either version 2 of the License, or 17*7caff0fcSAndrey Gusakov * (at your option) any later version. 18*7caff0fcSAndrey Gusakov * 19*7caff0fcSAndrey Gusakov * This program is distributed in the hope that it will be useful, 20*7caff0fcSAndrey Gusakov * but WITHOUT ANY WARRANTY; without even the implied warranty of 21*7caff0fcSAndrey Gusakov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22*7caff0fcSAndrey Gusakov * GNU General Public License for more details. 23*7caff0fcSAndrey Gusakov */ 24*7caff0fcSAndrey Gusakov 25*7caff0fcSAndrey Gusakov #include <linux/clk.h> 26*7caff0fcSAndrey Gusakov #include <linux/device.h> 27*7caff0fcSAndrey Gusakov #include <linux/gpio/consumer.h> 28*7caff0fcSAndrey Gusakov #include <linux/i2c.h> 29*7caff0fcSAndrey Gusakov #include <linux/kernel.h> 30*7caff0fcSAndrey Gusakov #include <linux/module.h> 31*7caff0fcSAndrey Gusakov #include <linux/regmap.h> 32*7caff0fcSAndrey Gusakov #include <linux/slab.h> 33*7caff0fcSAndrey Gusakov 34*7caff0fcSAndrey Gusakov #include <drm/drm_atomic_helper.h> 35*7caff0fcSAndrey Gusakov #include <drm/drm_crtc_helper.h> 36*7caff0fcSAndrey Gusakov #include <drm/drm_dp_helper.h> 37*7caff0fcSAndrey Gusakov #include <drm/drm_edid.h> 38*7caff0fcSAndrey Gusakov #include <drm/drm_of.h> 39*7caff0fcSAndrey Gusakov #include <drm/drm_panel.h> 40*7caff0fcSAndrey Gusakov 41*7caff0fcSAndrey Gusakov /* Registers */ 42*7caff0fcSAndrey Gusakov 43*7caff0fcSAndrey Gusakov /* Display Parallel Interface */ 44*7caff0fcSAndrey Gusakov #define DPIPXLFMT 0x0440 45*7caff0fcSAndrey Gusakov #define VS_POL_ACTIVE_LOW (1 << 10) 46*7caff0fcSAndrey Gusakov #define HS_POL_ACTIVE_LOW (1 << 9) 47*7caff0fcSAndrey Gusakov #define DE_POL_ACTIVE_HIGH (0 << 8) 48*7caff0fcSAndrey Gusakov #define SUB_CFG_TYPE_CONFIG1 (0 << 2) /* LSB aligned */ 49*7caff0fcSAndrey Gusakov #define SUB_CFG_TYPE_CONFIG2 (1 << 2) /* Loosely Packed */ 50*7caff0fcSAndrey Gusakov #define SUB_CFG_TYPE_CONFIG3 (2 << 2) /* LSB aligned 8-bit */ 51*7caff0fcSAndrey Gusakov #define DPI_BPP_RGB888 (0 << 0) 52*7caff0fcSAndrey Gusakov #define DPI_BPP_RGB666 (1 << 0) 53*7caff0fcSAndrey Gusakov #define DPI_BPP_RGB565 (2 << 0) 54*7caff0fcSAndrey Gusakov 55*7caff0fcSAndrey Gusakov /* Video Path */ 56*7caff0fcSAndrey Gusakov #define VPCTRL0 0x0450 57*7caff0fcSAndrey Gusakov #define OPXLFMT_RGB666 (0 << 8) 58*7caff0fcSAndrey Gusakov #define OPXLFMT_RGB888 (1 << 8) 59*7caff0fcSAndrey Gusakov #define FRMSYNC_DISABLED (0 << 4) /* Video Timing Gen Disabled */ 60*7caff0fcSAndrey Gusakov #define FRMSYNC_ENABLED (1 << 4) /* Video Timing Gen Enabled */ 61*7caff0fcSAndrey Gusakov #define MSF_DISABLED (0 << 0) /* Magic Square FRC disabled */ 62*7caff0fcSAndrey Gusakov #define MSF_ENABLED (1 << 0) /* Magic Square FRC enabled */ 63*7caff0fcSAndrey Gusakov #define HTIM01 0x0454 64*7caff0fcSAndrey Gusakov #define HTIM02 0x0458 65*7caff0fcSAndrey Gusakov #define VTIM01 0x045c 66*7caff0fcSAndrey Gusakov #define VTIM02 0x0460 67*7caff0fcSAndrey Gusakov #define VFUEN0 0x0464 68*7caff0fcSAndrey Gusakov #define VFUEN BIT(0) /* Video Frame Timing Upload */ 69*7caff0fcSAndrey Gusakov 70*7caff0fcSAndrey Gusakov /* System */ 71*7caff0fcSAndrey Gusakov #define TC_IDREG 0x0500 72*7caff0fcSAndrey Gusakov #define SYSCTRL 0x0510 73*7caff0fcSAndrey Gusakov #define DP0_AUDSRC_NO_INPUT (0 << 3) 74*7caff0fcSAndrey Gusakov #define DP0_AUDSRC_I2S_RX (1 << 3) 75*7caff0fcSAndrey Gusakov #define DP0_VIDSRC_NO_INPUT (0 << 0) 76*7caff0fcSAndrey Gusakov #define DP0_VIDSRC_DSI_RX (1 << 0) 77*7caff0fcSAndrey Gusakov #define DP0_VIDSRC_DPI_RX (2 << 0) 78*7caff0fcSAndrey Gusakov #define DP0_VIDSRC_COLOR_BAR (3 << 0) 79*7caff0fcSAndrey Gusakov 80*7caff0fcSAndrey Gusakov /* Control */ 81*7caff0fcSAndrey Gusakov #define DP0CTL 0x0600 82*7caff0fcSAndrey Gusakov #define VID_MN_GEN BIT(6) /* Auto-generate M/N values */ 83*7caff0fcSAndrey Gusakov #define EF_EN BIT(5) /* Enable Enhanced Framing */ 84*7caff0fcSAndrey Gusakov #define VID_EN BIT(1) /* Video transmission enable */ 85*7caff0fcSAndrey Gusakov #define DP_EN BIT(0) /* Enable DPTX function */ 86*7caff0fcSAndrey Gusakov 87*7caff0fcSAndrey Gusakov /* Clocks */ 88*7caff0fcSAndrey Gusakov #define DP0_VIDMNGEN0 0x0610 89*7caff0fcSAndrey Gusakov #define DP0_VIDMNGEN1 0x0614 90*7caff0fcSAndrey Gusakov #define DP0_VMNGENSTATUS 0x0618 91*7caff0fcSAndrey Gusakov 92*7caff0fcSAndrey Gusakov /* Main Channel */ 93*7caff0fcSAndrey Gusakov #define DP0_SECSAMPLE 0x0640 94*7caff0fcSAndrey Gusakov #define DP0_VIDSYNCDELAY 0x0644 95*7caff0fcSAndrey Gusakov #define DP0_TOTALVAL 0x0648 96*7caff0fcSAndrey Gusakov #define DP0_STARTVAL 0x064c 97*7caff0fcSAndrey Gusakov #define DP0_ACTIVEVAL 0x0650 98*7caff0fcSAndrey Gusakov #define DP0_SYNCVAL 0x0654 99*7caff0fcSAndrey Gusakov #define DP0_MISC 0x0658 100*7caff0fcSAndrey Gusakov #define TU_SIZE_RECOMMENDED (0x3f << 16) /* LSCLK cycles per TU */ 101*7caff0fcSAndrey Gusakov #define BPC_6 (0 << 5) 102*7caff0fcSAndrey Gusakov #define BPC_8 (1 << 5) 103*7caff0fcSAndrey Gusakov 104*7caff0fcSAndrey Gusakov /* AUX channel */ 105*7caff0fcSAndrey Gusakov #define DP0_AUXCFG0 0x0660 106*7caff0fcSAndrey Gusakov #define DP0_AUXCFG1 0x0664 107*7caff0fcSAndrey Gusakov #define AUX_RX_FILTER_EN BIT(16) 108*7caff0fcSAndrey Gusakov 109*7caff0fcSAndrey Gusakov #define DP0_AUXADDR 0x0668 110*7caff0fcSAndrey Gusakov #define DP0_AUXWDATA(i) (0x066c + (i) * 4) 111*7caff0fcSAndrey Gusakov #define DP0_AUXRDATA(i) (0x067c + (i) * 4) 112*7caff0fcSAndrey Gusakov #define DP0_AUXSTATUS 0x068c 113*7caff0fcSAndrey Gusakov #define AUX_STATUS_MASK 0xf0 114*7caff0fcSAndrey Gusakov #define AUX_STATUS_SHIFT 4 115*7caff0fcSAndrey Gusakov #define AUX_TIMEOUT BIT(1) 116*7caff0fcSAndrey Gusakov #define AUX_BUSY BIT(0) 117*7caff0fcSAndrey Gusakov #define DP0_AUXI2CADR 0x0698 118*7caff0fcSAndrey Gusakov 119*7caff0fcSAndrey Gusakov /* Link Training */ 120*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL 0x06a0 121*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_SCRMBLDIS BIT(13) 122*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_EN810B BIT(12) 123*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_NOTP (0 << 8) 124*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_TP1 (1 << 8) 125*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_TP2 (2 << 8) 126*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_LANESKEW BIT(7) 127*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_SSCG BIT(3) 128*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_LANES_1 (0 << 2) 129*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_LANES_2 (1 << 2) 130*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_BW27 (1 << 1) 131*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_BW162 (0 << 1) 132*7caff0fcSAndrey Gusakov #define DP0_SRCCTRL_AUTOCORRECT BIT(0) 133*7caff0fcSAndrey Gusakov #define DP0_LTSTAT 0x06d0 134*7caff0fcSAndrey Gusakov #define LT_LOOPDONE BIT(13) 135*7caff0fcSAndrey Gusakov #define LT_STATUS_MASK (0x1f << 8) 136*7caff0fcSAndrey Gusakov #define LT_CHANNEL1_EQ_BITS (DP_CHANNEL_EQ_BITS << 4) 137*7caff0fcSAndrey Gusakov #define LT_INTERLANE_ALIGN_DONE BIT(3) 138*7caff0fcSAndrey Gusakov #define LT_CHANNEL0_EQ_BITS (DP_CHANNEL_EQ_BITS) 139*7caff0fcSAndrey Gusakov #define DP0_SNKLTCHGREQ 0x06d4 140*7caff0fcSAndrey Gusakov #define DP0_LTLOOPCTRL 0x06d8 141*7caff0fcSAndrey Gusakov #define DP0_SNKLTCTRL 0x06e4 142*7caff0fcSAndrey Gusakov 143*7caff0fcSAndrey Gusakov /* PHY */ 144*7caff0fcSAndrey Gusakov #define DP_PHY_CTRL 0x0800 145*7caff0fcSAndrey Gusakov #define DP_PHY_RST BIT(28) /* DP PHY Global Soft Reset */ 146*7caff0fcSAndrey Gusakov #define BGREN BIT(25) /* AUX PHY BGR Enable */ 147*7caff0fcSAndrey Gusakov #define PWR_SW_EN BIT(24) /* PHY Power Switch Enable */ 148*7caff0fcSAndrey Gusakov #define PHY_M1_RST BIT(12) /* Reset PHY1 Main Channel */ 149*7caff0fcSAndrey Gusakov #define PHY_RDY BIT(16) /* PHY Main Channels Ready */ 150*7caff0fcSAndrey Gusakov #define PHY_M0_RST BIT(8) /* Reset PHY0 Main Channel */ 151*7caff0fcSAndrey Gusakov #define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */ 152*7caff0fcSAndrey Gusakov #define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */ 153*7caff0fcSAndrey Gusakov 154*7caff0fcSAndrey Gusakov /* PLL */ 155*7caff0fcSAndrey Gusakov #define DP0_PLLCTRL 0x0900 156*7caff0fcSAndrey Gusakov #define DP1_PLLCTRL 0x0904 /* not defined in DS */ 157*7caff0fcSAndrey Gusakov #define PXL_PLLCTRL 0x0908 158*7caff0fcSAndrey Gusakov #define PLLUPDATE BIT(2) 159*7caff0fcSAndrey Gusakov #define PLLBYP BIT(1) 160*7caff0fcSAndrey Gusakov #define PLLEN BIT(0) 161*7caff0fcSAndrey Gusakov #define PXL_PLLPARAM 0x0914 162*7caff0fcSAndrey Gusakov #define IN_SEL_REFCLK (0 << 14) 163*7caff0fcSAndrey Gusakov #define SYS_PLLPARAM 0x0918 164*7caff0fcSAndrey Gusakov #define REF_FREQ_38M4 (0 << 8) /* 38.4 MHz */ 165*7caff0fcSAndrey Gusakov #define REF_FREQ_19M2 (1 << 8) /* 19.2 MHz */ 166*7caff0fcSAndrey Gusakov #define REF_FREQ_26M (2 << 8) /* 26 MHz */ 167*7caff0fcSAndrey Gusakov #define REF_FREQ_13M (3 << 8) /* 13 MHz */ 168*7caff0fcSAndrey Gusakov #define SYSCLK_SEL_LSCLK (0 << 4) 169*7caff0fcSAndrey Gusakov #define LSCLK_DIV_1 (0 << 0) 170*7caff0fcSAndrey Gusakov #define LSCLK_DIV_2 (1 << 0) 171*7caff0fcSAndrey Gusakov 172*7caff0fcSAndrey Gusakov /* Test & Debug */ 173*7caff0fcSAndrey Gusakov #define TSTCTL 0x0a00 174*7caff0fcSAndrey Gusakov #define PLL_DBG 0x0a04 175*7caff0fcSAndrey Gusakov 176*7caff0fcSAndrey Gusakov static bool tc_test_pattern; 177*7caff0fcSAndrey Gusakov module_param_named(test, tc_test_pattern, bool, 0644); 178*7caff0fcSAndrey Gusakov 179*7caff0fcSAndrey Gusakov struct tc_edp_link { 180*7caff0fcSAndrey Gusakov struct drm_dp_link base; 181*7caff0fcSAndrey Gusakov u8 assr; 182*7caff0fcSAndrey Gusakov int scrambler_dis; 183*7caff0fcSAndrey Gusakov int spread; 184*7caff0fcSAndrey Gusakov int coding8b10b; 185*7caff0fcSAndrey Gusakov u8 swing; 186*7caff0fcSAndrey Gusakov u8 preemp; 187*7caff0fcSAndrey Gusakov }; 188*7caff0fcSAndrey Gusakov 189*7caff0fcSAndrey Gusakov struct tc_data { 190*7caff0fcSAndrey Gusakov struct device *dev; 191*7caff0fcSAndrey Gusakov struct regmap *regmap; 192*7caff0fcSAndrey Gusakov struct drm_dp_aux aux; 193*7caff0fcSAndrey Gusakov 194*7caff0fcSAndrey Gusakov struct drm_bridge bridge; 195*7caff0fcSAndrey Gusakov struct drm_connector connector; 196*7caff0fcSAndrey Gusakov struct drm_panel *panel; 197*7caff0fcSAndrey Gusakov 198*7caff0fcSAndrey Gusakov /* link settings */ 199*7caff0fcSAndrey Gusakov struct tc_edp_link link; 200*7caff0fcSAndrey Gusakov 201*7caff0fcSAndrey Gusakov /* display edid */ 202*7caff0fcSAndrey Gusakov struct edid *edid; 203*7caff0fcSAndrey Gusakov /* current mode */ 204*7caff0fcSAndrey Gusakov struct drm_display_mode *mode; 205*7caff0fcSAndrey Gusakov 206*7caff0fcSAndrey Gusakov u32 rev; 207*7caff0fcSAndrey Gusakov u8 assr; 208*7caff0fcSAndrey Gusakov 209*7caff0fcSAndrey Gusakov struct gpio_desc *sd_gpio; 210*7caff0fcSAndrey Gusakov struct gpio_desc *reset_gpio; 211*7caff0fcSAndrey Gusakov struct clk *refclk; 212*7caff0fcSAndrey Gusakov }; 213*7caff0fcSAndrey Gusakov 214*7caff0fcSAndrey Gusakov static inline struct tc_data *aux_to_tc(struct drm_dp_aux *a) 215*7caff0fcSAndrey Gusakov { 216*7caff0fcSAndrey Gusakov return container_of(a, struct tc_data, aux); 217*7caff0fcSAndrey Gusakov } 218*7caff0fcSAndrey Gusakov 219*7caff0fcSAndrey Gusakov static inline struct tc_data *bridge_to_tc(struct drm_bridge *b) 220*7caff0fcSAndrey Gusakov { 221*7caff0fcSAndrey Gusakov return container_of(b, struct tc_data, bridge); 222*7caff0fcSAndrey Gusakov } 223*7caff0fcSAndrey Gusakov 224*7caff0fcSAndrey Gusakov static inline struct tc_data *connector_to_tc(struct drm_connector *c) 225*7caff0fcSAndrey Gusakov { 226*7caff0fcSAndrey Gusakov return container_of(c, struct tc_data, connector); 227*7caff0fcSAndrey Gusakov } 228*7caff0fcSAndrey Gusakov 229*7caff0fcSAndrey Gusakov /* Simple macros to avoid repeated error checks */ 230*7caff0fcSAndrey Gusakov #define tc_write(reg, var) \ 231*7caff0fcSAndrey Gusakov do { \ 232*7caff0fcSAndrey Gusakov ret = regmap_write(tc->regmap, reg, var); \ 233*7caff0fcSAndrey Gusakov if (ret) \ 234*7caff0fcSAndrey Gusakov goto err; \ 235*7caff0fcSAndrey Gusakov } while (0) 236*7caff0fcSAndrey Gusakov #define tc_read(reg, var) \ 237*7caff0fcSAndrey Gusakov do { \ 238*7caff0fcSAndrey Gusakov ret = regmap_read(tc->regmap, reg, var); \ 239*7caff0fcSAndrey Gusakov if (ret) \ 240*7caff0fcSAndrey Gusakov goto err; \ 241*7caff0fcSAndrey Gusakov } while (0) 242*7caff0fcSAndrey Gusakov 243*7caff0fcSAndrey Gusakov static inline int tc_poll_timeout(struct regmap *map, unsigned int addr, 244*7caff0fcSAndrey Gusakov unsigned int cond_mask, 245*7caff0fcSAndrey Gusakov unsigned int cond_value, 246*7caff0fcSAndrey Gusakov unsigned long sleep_us, u64 timeout_us) 247*7caff0fcSAndrey Gusakov { 248*7caff0fcSAndrey Gusakov ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); 249*7caff0fcSAndrey Gusakov unsigned int val; 250*7caff0fcSAndrey Gusakov int ret; 251*7caff0fcSAndrey Gusakov 252*7caff0fcSAndrey Gusakov for (;;) { 253*7caff0fcSAndrey Gusakov ret = regmap_read(map, addr, &val); 254*7caff0fcSAndrey Gusakov if (ret) 255*7caff0fcSAndrey Gusakov break; 256*7caff0fcSAndrey Gusakov if ((val & cond_mask) == cond_value) 257*7caff0fcSAndrey Gusakov break; 258*7caff0fcSAndrey Gusakov if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { 259*7caff0fcSAndrey Gusakov ret = regmap_read(map, addr, &val); 260*7caff0fcSAndrey Gusakov break; 261*7caff0fcSAndrey Gusakov } 262*7caff0fcSAndrey Gusakov if (sleep_us) 263*7caff0fcSAndrey Gusakov usleep_range((sleep_us >> 2) + 1, sleep_us); 264*7caff0fcSAndrey Gusakov } 265*7caff0fcSAndrey Gusakov return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT); 266*7caff0fcSAndrey Gusakov } 267*7caff0fcSAndrey Gusakov 268*7caff0fcSAndrey Gusakov static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms) 269*7caff0fcSAndrey Gusakov { 270*7caff0fcSAndrey Gusakov return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0, 271*7caff0fcSAndrey Gusakov 1000, 1000 * timeout_ms); 272*7caff0fcSAndrey Gusakov } 273*7caff0fcSAndrey Gusakov 274*7caff0fcSAndrey Gusakov static int tc_aux_get_status(struct tc_data *tc, u8 *reply) 275*7caff0fcSAndrey Gusakov { 276*7caff0fcSAndrey Gusakov int ret; 277*7caff0fcSAndrey Gusakov u32 value; 278*7caff0fcSAndrey Gusakov 279*7caff0fcSAndrey Gusakov ret = regmap_read(tc->regmap, DP0_AUXSTATUS, &value); 280*7caff0fcSAndrey Gusakov if (ret < 0) 281*7caff0fcSAndrey Gusakov return ret; 282*7caff0fcSAndrey Gusakov if (value & AUX_BUSY) { 283*7caff0fcSAndrey Gusakov if (value & AUX_TIMEOUT) { 284*7caff0fcSAndrey Gusakov dev_err(tc->dev, "i2c access timeout!\n"); 285*7caff0fcSAndrey Gusakov return -ETIMEDOUT; 286*7caff0fcSAndrey Gusakov } 287*7caff0fcSAndrey Gusakov return -EBUSY; 288*7caff0fcSAndrey Gusakov } 289*7caff0fcSAndrey Gusakov 290*7caff0fcSAndrey Gusakov *reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT; 291*7caff0fcSAndrey Gusakov return 0; 292*7caff0fcSAndrey Gusakov } 293*7caff0fcSAndrey Gusakov 294*7caff0fcSAndrey Gusakov static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, 295*7caff0fcSAndrey Gusakov struct drm_dp_aux_msg *msg) 296*7caff0fcSAndrey Gusakov { 297*7caff0fcSAndrey Gusakov struct tc_data *tc = aux_to_tc(aux); 298*7caff0fcSAndrey Gusakov size_t size = min_t(size_t, 8, msg->size); 299*7caff0fcSAndrey Gusakov u8 request = msg->request & ~DP_AUX_I2C_MOT; 300*7caff0fcSAndrey Gusakov u8 *buf = msg->buffer; 301*7caff0fcSAndrey Gusakov u32 tmp = 0; 302*7caff0fcSAndrey Gusakov int i = 0; 303*7caff0fcSAndrey Gusakov int ret; 304*7caff0fcSAndrey Gusakov 305*7caff0fcSAndrey Gusakov if (size == 0) 306*7caff0fcSAndrey Gusakov return 0; 307*7caff0fcSAndrey Gusakov 308*7caff0fcSAndrey Gusakov ret = tc_aux_wait_busy(tc, 100); 309*7caff0fcSAndrey Gusakov if (ret) 310*7caff0fcSAndrey Gusakov goto err; 311*7caff0fcSAndrey Gusakov 312*7caff0fcSAndrey Gusakov if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) { 313*7caff0fcSAndrey Gusakov /* Store data */ 314*7caff0fcSAndrey Gusakov while (i < size) { 315*7caff0fcSAndrey Gusakov if (request == DP_AUX_NATIVE_WRITE) 316*7caff0fcSAndrey Gusakov tmp = tmp | (buf[i] << (8 * (i & 0x3))); 317*7caff0fcSAndrey Gusakov else 318*7caff0fcSAndrey Gusakov tmp = (tmp << 8) | buf[i]; 319*7caff0fcSAndrey Gusakov i++; 320*7caff0fcSAndrey Gusakov if (((i % 4) == 0) || (i == size)) { 321*7caff0fcSAndrey Gusakov tc_write(DP0_AUXWDATA(i >> 2), tmp); 322*7caff0fcSAndrey Gusakov tmp = 0; 323*7caff0fcSAndrey Gusakov } 324*7caff0fcSAndrey Gusakov } 325*7caff0fcSAndrey Gusakov } else if (request != DP_AUX_I2C_READ && 326*7caff0fcSAndrey Gusakov request != DP_AUX_NATIVE_READ) { 327*7caff0fcSAndrey Gusakov return -EINVAL; 328*7caff0fcSAndrey Gusakov } 329*7caff0fcSAndrey Gusakov 330*7caff0fcSAndrey Gusakov /* Store address */ 331*7caff0fcSAndrey Gusakov tc_write(DP0_AUXADDR, msg->address); 332*7caff0fcSAndrey Gusakov /* Start transfer */ 333*7caff0fcSAndrey Gusakov tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request); 334*7caff0fcSAndrey Gusakov 335*7caff0fcSAndrey Gusakov ret = tc_aux_wait_busy(tc, 100); 336*7caff0fcSAndrey Gusakov if (ret) 337*7caff0fcSAndrey Gusakov goto err; 338*7caff0fcSAndrey Gusakov 339*7caff0fcSAndrey Gusakov ret = tc_aux_get_status(tc, &msg->reply); 340*7caff0fcSAndrey Gusakov if (ret) 341*7caff0fcSAndrey Gusakov goto err; 342*7caff0fcSAndrey Gusakov 343*7caff0fcSAndrey Gusakov if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) { 344*7caff0fcSAndrey Gusakov /* Read data */ 345*7caff0fcSAndrey Gusakov while (i < size) { 346*7caff0fcSAndrey Gusakov if ((i % 4) == 0) 347*7caff0fcSAndrey Gusakov tc_read(DP0_AUXRDATA(i >> 2), &tmp); 348*7caff0fcSAndrey Gusakov buf[i] = tmp & 0xff; 349*7caff0fcSAndrey Gusakov tmp = tmp >> 8; 350*7caff0fcSAndrey Gusakov i++; 351*7caff0fcSAndrey Gusakov } 352*7caff0fcSAndrey Gusakov } 353*7caff0fcSAndrey Gusakov 354*7caff0fcSAndrey Gusakov return size; 355*7caff0fcSAndrey Gusakov err: 356*7caff0fcSAndrey Gusakov return ret; 357*7caff0fcSAndrey Gusakov } 358*7caff0fcSAndrey Gusakov 359*7caff0fcSAndrey Gusakov static const char * const training_pattern1_errors[] = { 360*7caff0fcSAndrey Gusakov "No errors", 361*7caff0fcSAndrey Gusakov "Aux write error", 362*7caff0fcSAndrey Gusakov "Aux read error", 363*7caff0fcSAndrey Gusakov "Max voltage reached error", 364*7caff0fcSAndrey Gusakov "Loop counter expired error", 365*7caff0fcSAndrey Gusakov "res", "res", "res" 366*7caff0fcSAndrey Gusakov }; 367*7caff0fcSAndrey Gusakov 368*7caff0fcSAndrey Gusakov static const char * const training_pattern2_errors[] = { 369*7caff0fcSAndrey Gusakov "No errors", 370*7caff0fcSAndrey Gusakov "Aux write error", 371*7caff0fcSAndrey Gusakov "Aux read error", 372*7caff0fcSAndrey Gusakov "Clock recovery failed error", 373*7caff0fcSAndrey Gusakov "Loop counter expired error", 374*7caff0fcSAndrey Gusakov "res", "res", "res" 375*7caff0fcSAndrey Gusakov }; 376*7caff0fcSAndrey Gusakov 377*7caff0fcSAndrey Gusakov static u32 tc_srcctrl(struct tc_data *tc) 378*7caff0fcSAndrey Gusakov { 379*7caff0fcSAndrey Gusakov /* 380*7caff0fcSAndrey Gusakov * No training pattern, skew lane 1 data by two LSCLK cycles with 381*7caff0fcSAndrey Gusakov * respect to lane 0 data, AutoCorrect Mode = 0 382*7caff0fcSAndrey Gusakov */ 383*7caff0fcSAndrey Gusakov u32 reg = DP0_SRCCTRL_NOTP | DP0_SRCCTRL_LANESKEW; 384*7caff0fcSAndrey Gusakov 385*7caff0fcSAndrey Gusakov if (tc->link.scrambler_dis) 386*7caff0fcSAndrey Gusakov reg |= DP0_SRCCTRL_SCRMBLDIS; /* Scrambler Disabled */ 387*7caff0fcSAndrey Gusakov if (tc->link.coding8b10b) 388*7caff0fcSAndrey Gusakov /* Enable 8/10B Encoder (TxData[19:16] not used) */ 389*7caff0fcSAndrey Gusakov reg |= DP0_SRCCTRL_EN810B; 390*7caff0fcSAndrey Gusakov if (tc->link.spread) 391*7caff0fcSAndrey Gusakov reg |= DP0_SRCCTRL_SSCG; /* Spread Spectrum Enable */ 392*7caff0fcSAndrey Gusakov if (tc->link.base.num_lanes == 2) 393*7caff0fcSAndrey Gusakov reg |= DP0_SRCCTRL_LANES_2; /* Two Main Channel Lanes */ 394*7caff0fcSAndrey Gusakov if (tc->link.base.rate != 162000) 395*7caff0fcSAndrey Gusakov reg |= DP0_SRCCTRL_BW27; /* 2.7 Gbps link */ 396*7caff0fcSAndrey Gusakov return reg; 397*7caff0fcSAndrey Gusakov } 398*7caff0fcSAndrey Gusakov 399*7caff0fcSAndrey Gusakov static void tc_wait_pll_lock(struct tc_data *tc) 400*7caff0fcSAndrey Gusakov { 401*7caff0fcSAndrey Gusakov /* Wait for PLL to lock: up to 2.09 ms, depending on refclk */ 402*7caff0fcSAndrey Gusakov usleep_range(3000, 6000); 403*7caff0fcSAndrey Gusakov } 404*7caff0fcSAndrey Gusakov 405*7caff0fcSAndrey Gusakov static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock) 406*7caff0fcSAndrey Gusakov { 407*7caff0fcSAndrey Gusakov int ret; 408*7caff0fcSAndrey Gusakov int i_pre, best_pre = 1; 409*7caff0fcSAndrey Gusakov int i_post, best_post = 1; 410*7caff0fcSAndrey Gusakov int div, best_div = 1; 411*7caff0fcSAndrey Gusakov int mul, best_mul = 1; 412*7caff0fcSAndrey Gusakov int delta, best_delta; 413*7caff0fcSAndrey Gusakov int ext_div[] = {1, 2, 3, 5, 7}; 414*7caff0fcSAndrey Gusakov int best_pixelclock = 0; 415*7caff0fcSAndrey Gusakov int vco_hi = 0; 416*7caff0fcSAndrey Gusakov 417*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "PLL: requested %d pixelclock, ref %d\n", pixelclock, 418*7caff0fcSAndrey Gusakov refclk); 419*7caff0fcSAndrey Gusakov best_delta = pixelclock; 420*7caff0fcSAndrey Gusakov /* Loop over all possible ext_divs, skipping invalid configurations */ 421*7caff0fcSAndrey Gusakov for (i_pre = 0; i_pre < ARRAY_SIZE(ext_div); i_pre++) { 422*7caff0fcSAndrey Gusakov /* 423*7caff0fcSAndrey Gusakov * refclk / ext_pre_div should be in the 1 to 200 MHz range. 424*7caff0fcSAndrey Gusakov * We don't allow any refclk > 200 MHz, only check lower bounds. 425*7caff0fcSAndrey Gusakov */ 426*7caff0fcSAndrey Gusakov if (refclk / ext_div[i_pre] < 1000000) 427*7caff0fcSAndrey Gusakov continue; 428*7caff0fcSAndrey Gusakov for (i_post = 0; i_post < ARRAY_SIZE(ext_div); i_post++) { 429*7caff0fcSAndrey Gusakov for (div = 1; div <= 16; div++) { 430*7caff0fcSAndrey Gusakov u32 clk; 431*7caff0fcSAndrey Gusakov u64 tmp; 432*7caff0fcSAndrey Gusakov 433*7caff0fcSAndrey Gusakov tmp = pixelclock * ext_div[i_pre] * 434*7caff0fcSAndrey Gusakov ext_div[i_post] * div; 435*7caff0fcSAndrey Gusakov do_div(tmp, refclk); 436*7caff0fcSAndrey Gusakov mul = tmp; 437*7caff0fcSAndrey Gusakov 438*7caff0fcSAndrey Gusakov /* Check limits */ 439*7caff0fcSAndrey Gusakov if ((mul < 1) || (mul > 128)) 440*7caff0fcSAndrey Gusakov continue; 441*7caff0fcSAndrey Gusakov 442*7caff0fcSAndrey Gusakov clk = (refclk / ext_div[i_pre] / div) * mul; 443*7caff0fcSAndrey Gusakov /* 444*7caff0fcSAndrey Gusakov * refclk * mul / (ext_pre_div * pre_div) 445*7caff0fcSAndrey Gusakov * should be in the 150 to 650 MHz range 446*7caff0fcSAndrey Gusakov */ 447*7caff0fcSAndrey Gusakov if ((clk > 650000000) || (clk < 150000000)) 448*7caff0fcSAndrey Gusakov continue; 449*7caff0fcSAndrey Gusakov 450*7caff0fcSAndrey Gusakov clk = clk / ext_div[i_post]; 451*7caff0fcSAndrey Gusakov delta = clk - pixelclock; 452*7caff0fcSAndrey Gusakov 453*7caff0fcSAndrey Gusakov if (abs(delta) < abs(best_delta)) { 454*7caff0fcSAndrey Gusakov best_pre = i_pre; 455*7caff0fcSAndrey Gusakov best_post = i_post; 456*7caff0fcSAndrey Gusakov best_div = div; 457*7caff0fcSAndrey Gusakov best_mul = mul; 458*7caff0fcSAndrey Gusakov best_delta = delta; 459*7caff0fcSAndrey Gusakov best_pixelclock = clk; 460*7caff0fcSAndrey Gusakov } 461*7caff0fcSAndrey Gusakov } 462*7caff0fcSAndrey Gusakov } 463*7caff0fcSAndrey Gusakov } 464*7caff0fcSAndrey Gusakov if (best_pixelclock == 0) { 465*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Failed to calc clock for %d pixelclock\n", 466*7caff0fcSAndrey Gusakov pixelclock); 467*7caff0fcSAndrey Gusakov return -EINVAL; 468*7caff0fcSAndrey Gusakov } 469*7caff0fcSAndrey Gusakov 470*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "PLL: got %d, delta %d\n", best_pixelclock, 471*7caff0fcSAndrey Gusakov best_delta); 472*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "PLL: %d / %d / %d * %d / %d\n", refclk, 473*7caff0fcSAndrey Gusakov ext_div[best_pre], best_div, best_mul, ext_div[best_post]); 474*7caff0fcSAndrey Gusakov 475*7caff0fcSAndrey Gusakov /* if VCO >= 300 MHz */ 476*7caff0fcSAndrey Gusakov if (refclk / ext_div[best_pre] / best_div * best_mul >= 300000000) 477*7caff0fcSAndrey Gusakov vco_hi = 1; 478*7caff0fcSAndrey Gusakov /* see DS */ 479*7caff0fcSAndrey Gusakov if (best_div == 16) 480*7caff0fcSAndrey Gusakov best_div = 0; 481*7caff0fcSAndrey Gusakov if (best_mul == 128) 482*7caff0fcSAndrey Gusakov best_mul = 0; 483*7caff0fcSAndrey Gusakov 484*7caff0fcSAndrey Gusakov /* Power up PLL and switch to bypass */ 485*7caff0fcSAndrey Gusakov tc_write(PXL_PLLCTRL, PLLBYP | PLLEN); 486*7caff0fcSAndrey Gusakov 487*7caff0fcSAndrey Gusakov tc_write(PXL_PLLPARAM, 488*7caff0fcSAndrey Gusakov (vco_hi << 24) | /* For PLL VCO >= 300 MHz = 1 */ 489*7caff0fcSAndrey Gusakov (ext_div[best_pre] << 20) | /* External Pre-divider */ 490*7caff0fcSAndrey Gusakov (ext_div[best_post] << 16) | /* External Post-divider */ 491*7caff0fcSAndrey Gusakov IN_SEL_REFCLK | /* Use RefClk as PLL input */ 492*7caff0fcSAndrey Gusakov (best_div << 8) | /* Divider for PLL RefClk */ 493*7caff0fcSAndrey Gusakov (best_mul << 0)); /* Multiplier for PLL */ 494*7caff0fcSAndrey Gusakov 495*7caff0fcSAndrey Gusakov /* Force PLL parameter update and disable bypass */ 496*7caff0fcSAndrey Gusakov tc_write(PXL_PLLCTRL, PLLUPDATE | PLLEN); 497*7caff0fcSAndrey Gusakov 498*7caff0fcSAndrey Gusakov tc_wait_pll_lock(tc); 499*7caff0fcSAndrey Gusakov 500*7caff0fcSAndrey Gusakov return 0; 501*7caff0fcSAndrey Gusakov err: 502*7caff0fcSAndrey Gusakov return ret; 503*7caff0fcSAndrey Gusakov } 504*7caff0fcSAndrey Gusakov 505*7caff0fcSAndrey Gusakov static int tc_pxl_pll_dis(struct tc_data *tc) 506*7caff0fcSAndrey Gusakov { 507*7caff0fcSAndrey Gusakov /* Enable PLL bypass, power down PLL */ 508*7caff0fcSAndrey Gusakov return regmap_write(tc->regmap, PXL_PLLCTRL, PLLBYP); 509*7caff0fcSAndrey Gusakov } 510*7caff0fcSAndrey Gusakov 511*7caff0fcSAndrey Gusakov static int tc_stream_clock_calc(struct tc_data *tc) 512*7caff0fcSAndrey Gusakov { 513*7caff0fcSAndrey Gusakov int ret; 514*7caff0fcSAndrey Gusakov /* 515*7caff0fcSAndrey Gusakov * If the Stream clock and Link Symbol clock are 516*7caff0fcSAndrey Gusakov * asynchronous with each other, the value of M changes over 517*7caff0fcSAndrey Gusakov * time. This way of generating link clock and stream 518*7caff0fcSAndrey Gusakov * clock is called Asynchronous Clock mode. The value M 519*7caff0fcSAndrey Gusakov * must change while the value N stays constant. The 520*7caff0fcSAndrey Gusakov * value of N in this Asynchronous Clock mode must be set 521*7caff0fcSAndrey Gusakov * to 2^15 or 32,768. 522*7caff0fcSAndrey Gusakov * 523*7caff0fcSAndrey Gusakov * LSCLK = 1/10 of high speed link clock 524*7caff0fcSAndrey Gusakov * 525*7caff0fcSAndrey Gusakov * f_STRMCLK = M/N * f_LSCLK 526*7caff0fcSAndrey Gusakov * M/N = f_STRMCLK / f_LSCLK 527*7caff0fcSAndrey Gusakov * 528*7caff0fcSAndrey Gusakov */ 529*7caff0fcSAndrey Gusakov tc_write(DP0_VIDMNGEN1, 32768); 530*7caff0fcSAndrey Gusakov 531*7caff0fcSAndrey Gusakov return 0; 532*7caff0fcSAndrey Gusakov err: 533*7caff0fcSAndrey Gusakov return ret; 534*7caff0fcSAndrey Gusakov } 535*7caff0fcSAndrey Gusakov 536*7caff0fcSAndrey Gusakov static int tc_aux_link_setup(struct tc_data *tc) 537*7caff0fcSAndrey Gusakov { 538*7caff0fcSAndrey Gusakov unsigned long rate; 539*7caff0fcSAndrey Gusakov u32 value; 540*7caff0fcSAndrey Gusakov int ret; 541*7caff0fcSAndrey Gusakov 542*7caff0fcSAndrey Gusakov rate = clk_get_rate(tc->refclk); 543*7caff0fcSAndrey Gusakov switch (rate) { 544*7caff0fcSAndrey Gusakov case 38400000: 545*7caff0fcSAndrey Gusakov value = REF_FREQ_38M4; 546*7caff0fcSAndrey Gusakov break; 547*7caff0fcSAndrey Gusakov case 26000000: 548*7caff0fcSAndrey Gusakov value = REF_FREQ_26M; 549*7caff0fcSAndrey Gusakov break; 550*7caff0fcSAndrey Gusakov case 19200000: 551*7caff0fcSAndrey Gusakov value = REF_FREQ_19M2; 552*7caff0fcSAndrey Gusakov break; 553*7caff0fcSAndrey Gusakov case 13000000: 554*7caff0fcSAndrey Gusakov value = REF_FREQ_13M; 555*7caff0fcSAndrey Gusakov break; 556*7caff0fcSAndrey Gusakov default: 557*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate); 558*7caff0fcSAndrey Gusakov return -EINVAL; 559*7caff0fcSAndrey Gusakov } 560*7caff0fcSAndrey Gusakov 561*7caff0fcSAndrey Gusakov /* Setup DP-PHY / PLL */ 562*7caff0fcSAndrey Gusakov value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; 563*7caff0fcSAndrey Gusakov tc_write(SYS_PLLPARAM, value); 564*7caff0fcSAndrey Gusakov 565*7caff0fcSAndrey Gusakov tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN); 566*7caff0fcSAndrey Gusakov 567*7caff0fcSAndrey Gusakov /* 568*7caff0fcSAndrey Gusakov * Initially PLLs are in bypass. Force PLL parameter update, 569*7caff0fcSAndrey Gusakov * disable PLL bypass, enable PLL 570*7caff0fcSAndrey Gusakov */ 571*7caff0fcSAndrey Gusakov tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN); 572*7caff0fcSAndrey Gusakov tc_wait_pll_lock(tc); 573*7caff0fcSAndrey Gusakov 574*7caff0fcSAndrey Gusakov tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN); 575*7caff0fcSAndrey Gusakov tc_wait_pll_lock(tc); 576*7caff0fcSAndrey Gusakov 577*7caff0fcSAndrey Gusakov ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 578*7caff0fcSAndrey Gusakov 1000); 579*7caff0fcSAndrey Gusakov if (ret == -ETIMEDOUT) { 580*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Timeout waiting for PHY to become ready"); 581*7caff0fcSAndrey Gusakov return ret; 582*7caff0fcSAndrey Gusakov } else if (ret) 583*7caff0fcSAndrey Gusakov goto err; 584*7caff0fcSAndrey Gusakov 585*7caff0fcSAndrey Gusakov /* Setup AUX link */ 586*7caff0fcSAndrey Gusakov tc_write(DP0_AUXCFG1, AUX_RX_FILTER_EN | 587*7caff0fcSAndrey Gusakov (0x06 << 8) | /* Aux Bit Period Calculator Threshold */ 588*7caff0fcSAndrey Gusakov (0x3f << 0)); /* Aux Response Timeout Timer */ 589*7caff0fcSAndrey Gusakov 590*7caff0fcSAndrey Gusakov return 0; 591*7caff0fcSAndrey Gusakov err: 592*7caff0fcSAndrey Gusakov dev_err(tc->dev, "tc_aux_link_setup failed: %d\n", ret); 593*7caff0fcSAndrey Gusakov return ret; 594*7caff0fcSAndrey Gusakov } 595*7caff0fcSAndrey Gusakov 596*7caff0fcSAndrey Gusakov static int tc_get_display_props(struct tc_data *tc) 597*7caff0fcSAndrey Gusakov { 598*7caff0fcSAndrey Gusakov int ret; 599*7caff0fcSAndrey Gusakov /* temp buffer */ 600*7caff0fcSAndrey Gusakov u8 tmp[8]; 601*7caff0fcSAndrey Gusakov 602*7caff0fcSAndrey Gusakov /* Read DP Rx Link Capability */ 603*7caff0fcSAndrey Gusakov ret = drm_dp_link_probe(&tc->aux, &tc->link.base); 604*7caff0fcSAndrey Gusakov if (ret < 0) 605*7caff0fcSAndrey Gusakov goto err_dpcd_read; 606*7caff0fcSAndrey Gusakov if ((tc->link.base.rate != 162000) && (tc->link.base.rate != 270000)) 607*7caff0fcSAndrey Gusakov goto err_dpcd_inval; 608*7caff0fcSAndrey Gusakov 609*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp); 610*7caff0fcSAndrey Gusakov if (ret < 0) 611*7caff0fcSAndrey Gusakov goto err_dpcd_read; 612*7caff0fcSAndrey Gusakov tc->link.spread = tmp[0] & BIT(0); /* 0.5% down spread */ 613*7caff0fcSAndrey Gusakov 614*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_readb(&tc->aux, DP_MAIN_LINK_CHANNEL_CODING, tmp); 615*7caff0fcSAndrey Gusakov if (ret < 0) 616*7caff0fcSAndrey Gusakov goto err_dpcd_read; 617*7caff0fcSAndrey Gusakov tc->link.coding8b10b = tmp[0] & BIT(0); 618*7caff0fcSAndrey Gusakov tc->link.scrambler_dis = 0; 619*7caff0fcSAndrey Gusakov /* read assr */ 620*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_readb(&tc->aux, DP_EDP_CONFIGURATION_SET, tmp); 621*7caff0fcSAndrey Gusakov if (ret < 0) 622*7caff0fcSAndrey Gusakov goto err_dpcd_read; 623*7caff0fcSAndrey Gusakov tc->link.assr = tmp[0] & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE; 624*7caff0fcSAndrey Gusakov 625*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "DPCD rev: %d.%d, rate: %s, lanes: %d, framing: %s\n", 626*7caff0fcSAndrey Gusakov tc->link.base.revision >> 4, tc->link.base.revision & 0x0f, 627*7caff0fcSAndrey Gusakov (tc->link.base.rate == 162000) ? "1.62Gbps" : "2.7Gbps", 628*7caff0fcSAndrey Gusakov tc->link.base.num_lanes, 629*7caff0fcSAndrey Gusakov (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ? 630*7caff0fcSAndrey Gusakov "enhanced" : "non-enhanced"); 631*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "ANSI 8B/10B: %d\n", tc->link.coding8b10b); 632*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "Display ASSR: %d, TC358767 ASSR: %d\n", 633*7caff0fcSAndrey Gusakov tc->link.assr, tc->assr); 634*7caff0fcSAndrey Gusakov 635*7caff0fcSAndrey Gusakov return 0; 636*7caff0fcSAndrey Gusakov 637*7caff0fcSAndrey Gusakov err_dpcd_read: 638*7caff0fcSAndrey Gusakov dev_err(tc->dev, "failed to read DPCD: %d\n", ret); 639*7caff0fcSAndrey Gusakov return ret; 640*7caff0fcSAndrey Gusakov err_dpcd_inval: 641*7caff0fcSAndrey Gusakov dev_err(tc->dev, "invalid DPCD\n"); 642*7caff0fcSAndrey Gusakov return -EINVAL; 643*7caff0fcSAndrey Gusakov } 644*7caff0fcSAndrey Gusakov 645*7caff0fcSAndrey Gusakov static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) 646*7caff0fcSAndrey Gusakov { 647*7caff0fcSAndrey Gusakov int ret; 648*7caff0fcSAndrey Gusakov int vid_sync_dly; 649*7caff0fcSAndrey Gusakov int max_tu_symbol; 650*7caff0fcSAndrey Gusakov 651*7caff0fcSAndrey Gusakov int left_margin = mode->htotal - mode->hsync_end; 652*7caff0fcSAndrey Gusakov int right_margin = mode->hsync_start - mode->hdisplay; 653*7caff0fcSAndrey Gusakov int hsync_len = mode->hsync_end - mode->hsync_start; 654*7caff0fcSAndrey Gusakov int upper_margin = mode->vtotal - mode->vsync_end; 655*7caff0fcSAndrey Gusakov int lower_margin = mode->vsync_start - mode->vdisplay; 656*7caff0fcSAndrey Gusakov int vsync_len = mode->vsync_end - mode->vsync_start; 657*7caff0fcSAndrey Gusakov 658*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "set mode %dx%d\n", 659*7caff0fcSAndrey Gusakov mode->hdisplay, mode->vdisplay); 660*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "H margin %d,%d sync %d\n", 661*7caff0fcSAndrey Gusakov left_margin, right_margin, hsync_len); 662*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "V margin %d,%d sync %d\n", 663*7caff0fcSAndrey Gusakov upper_margin, lower_margin, vsync_len); 664*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal); 665*7caff0fcSAndrey Gusakov 666*7caff0fcSAndrey Gusakov 667*7caff0fcSAndrey Gusakov /* LCD Ctl Frame Size */ 668*7caff0fcSAndrey Gusakov tc_write(VPCTRL0, (0x40 << 20) /* VSDELAY */ | 669*7caff0fcSAndrey Gusakov OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED); 670*7caff0fcSAndrey Gusakov tc_write(HTIM01, (left_margin << 16) | /* H back porch */ 671*7caff0fcSAndrey Gusakov (hsync_len << 0)); /* Hsync */ 672*7caff0fcSAndrey Gusakov tc_write(HTIM02, (right_margin << 16) | /* H front porch */ 673*7caff0fcSAndrey Gusakov (mode->hdisplay << 0)); /* width */ 674*7caff0fcSAndrey Gusakov tc_write(VTIM01, (upper_margin << 16) | /* V back porch */ 675*7caff0fcSAndrey Gusakov (vsync_len << 0)); /* Vsync */ 676*7caff0fcSAndrey Gusakov tc_write(VTIM02, (lower_margin << 16) | /* V front porch */ 677*7caff0fcSAndrey Gusakov (mode->vdisplay << 0)); /* height */ 678*7caff0fcSAndrey Gusakov tc_write(VFUEN0, VFUEN); /* update settings */ 679*7caff0fcSAndrey Gusakov 680*7caff0fcSAndrey Gusakov /* Test pattern settings */ 681*7caff0fcSAndrey Gusakov tc_write(TSTCTL, 682*7caff0fcSAndrey Gusakov (120 << 24) | /* Red Color component value */ 683*7caff0fcSAndrey Gusakov (20 << 16) | /* Green Color component value */ 684*7caff0fcSAndrey Gusakov (99 << 8) | /* Blue Color component value */ 685*7caff0fcSAndrey Gusakov (1 << 4) | /* Enable I2C Filter */ 686*7caff0fcSAndrey Gusakov (2 << 0) | /* Color bar Mode */ 687*7caff0fcSAndrey Gusakov 0); 688*7caff0fcSAndrey Gusakov 689*7caff0fcSAndrey Gusakov /* DP Main Stream Attributes */ 690*7caff0fcSAndrey Gusakov vid_sync_dly = hsync_len + left_margin + mode->hdisplay; 691*7caff0fcSAndrey Gusakov tc_write(DP0_VIDSYNCDELAY, 692*7caff0fcSAndrey Gusakov (0x003e << 16) | /* thresh_dly */ 693*7caff0fcSAndrey Gusakov (vid_sync_dly << 0)); 694*7caff0fcSAndrey Gusakov 695*7caff0fcSAndrey Gusakov tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal)); 696*7caff0fcSAndrey Gusakov 697*7caff0fcSAndrey Gusakov tc_write(DP0_STARTVAL, 698*7caff0fcSAndrey Gusakov ((upper_margin + vsync_len) << 16) | 699*7caff0fcSAndrey Gusakov ((left_margin + hsync_len) << 0)); 700*7caff0fcSAndrey Gusakov 701*7caff0fcSAndrey Gusakov tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay)); 702*7caff0fcSAndrey Gusakov 703*7caff0fcSAndrey Gusakov tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0)); 704*7caff0fcSAndrey Gusakov 705*7caff0fcSAndrey Gusakov tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW | 706*7caff0fcSAndrey Gusakov DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888); 707*7caff0fcSAndrey Gusakov 708*7caff0fcSAndrey Gusakov /* 709*7caff0fcSAndrey Gusakov * Recommended maximum number of symbols transferred in a transfer unit: 710*7caff0fcSAndrey Gusakov * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size, 711*7caff0fcSAndrey Gusakov * (output active video bandwidth in bytes)) 712*7caff0fcSAndrey Gusakov * Must be less than tu_size. 713*7caff0fcSAndrey Gusakov */ 714*7caff0fcSAndrey Gusakov max_tu_symbol = TU_SIZE_RECOMMENDED - 1; 715*7caff0fcSAndrey Gusakov tc_write(DP0_MISC, (max_tu_symbol << 23) | TU_SIZE_RECOMMENDED | BPC_8); 716*7caff0fcSAndrey Gusakov 717*7caff0fcSAndrey Gusakov return 0; 718*7caff0fcSAndrey Gusakov err: 719*7caff0fcSAndrey Gusakov return ret; 720*7caff0fcSAndrey Gusakov } 721*7caff0fcSAndrey Gusakov 722*7caff0fcSAndrey Gusakov static int tc_link_training(struct tc_data *tc, int pattern) 723*7caff0fcSAndrey Gusakov { 724*7caff0fcSAndrey Gusakov const char * const *errors; 725*7caff0fcSAndrey Gusakov u32 srcctrl = tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS | 726*7caff0fcSAndrey Gusakov DP0_SRCCTRL_AUTOCORRECT; 727*7caff0fcSAndrey Gusakov int timeout; 728*7caff0fcSAndrey Gusakov int retry; 729*7caff0fcSAndrey Gusakov u32 value; 730*7caff0fcSAndrey Gusakov int ret; 731*7caff0fcSAndrey Gusakov 732*7caff0fcSAndrey Gusakov if (pattern == DP_TRAINING_PATTERN_1) { 733*7caff0fcSAndrey Gusakov srcctrl |= DP0_SRCCTRL_TP1; 734*7caff0fcSAndrey Gusakov errors = training_pattern1_errors; 735*7caff0fcSAndrey Gusakov } else { 736*7caff0fcSAndrey Gusakov srcctrl |= DP0_SRCCTRL_TP2; 737*7caff0fcSAndrey Gusakov errors = training_pattern2_errors; 738*7caff0fcSAndrey Gusakov } 739*7caff0fcSAndrey Gusakov 740*7caff0fcSAndrey Gusakov /* Set DPCD 0x102 for Training Part 1 or 2 */ 741*7caff0fcSAndrey Gusakov tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE | pattern); 742*7caff0fcSAndrey Gusakov 743*7caff0fcSAndrey Gusakov tc_write(DP0_LTLOOPCTRL, 744*7caff0fcSAndrey Gusakov (0x0f << 28) | /* Defer Iteration Count */ 745*7caff0fcSAndrey Gusakov (0x0f << 24) | /* Loop Iteration Count */ 746*7caff0fcSAndrey Gusakov (0x0d << 0)); /* Loop Timer Delay */ 747*7caff0fcSAndrey Gusakov 748*7caff0fcSAndrey Gusakov retry = 5; 749*7caff0fcSAndrey Gusakov do { 750*7caff0fcSAndrey Gusakov /* Set DP0 Training Pattern */ 751*7caff0fcSAndrey Gusakov tc_write(DP0_SRCCTRL, srcctrl); 752*7caff0fcSAndrey Gusakov 753*7caff0fcSAndrey Gusakov /* Enable DP0 to start Link Training */ 754*7caff0fcSAndrey Gusakov tc_write(DP0CTL, DP_EN); 755*7caff0fcSAndrey Gusakov 756*7caff0fcSAndrey Gusakov /* wait */ 757*7caff0fcSAndrey Gusakov timeout = 1000; 758*7caff0fcSAndrey Gusakov do { 759*7caff0fcSAndrey Gusakov tc_read(DP0_LTSTAT, &value); 760*7caff0fcSAndrey Gusakov udelay(1); 761*7caff0fcSAndrey Gusakov } while ((!(value & LT_LOOPDONE)) && (--timeout)); 762*7caff0fcSAndrey Gusakov if (timeout == 0) { 763*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Link training timeout!\n"); 764*7caff0fcSAndrey Gusakov } else { 765*7caff0fcSAndrey Gusakov int pattern = (value >> 11) & 0x3; 766*7caff0fcSAndrey Gusakov int error = (value >> 8) & 0x7; 767*7caff0fcSAndrey Gusakov 768*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, 769*7caff0fcSAndrey Gusakov "Link training phase %d done after %d uS: %s\n", 770*7caff0fcSAndrey Gusakov pattern, 1000 - timeout, errors[error]); 771*7caff0fcSAndrey Gusakov if (pattern == DP_TRAINING_PATTERN_1 && error == 0) 772*7caff0fcSAndrey Gusakov break; 773*7caff0fcSAndrey Gusakov if (pattern == DP_TRAINING_PATTERN_2) { 774*7caff0fcSAndrey Gusakov value &= LT_CHANNEL1_EQ_BITS | 775*7caff0fcSAndrey Gusakov LT_INTERLANE_ALIGN_DONE | 776*7caff0fcSAndrey Gusakov LT_CHANNEL0_EQ_BITS; 777*7caff0fcSAndrey Gusakov /* in case of two lanes */ 778*7caff0fcSAndrey Gusakov if ((tc->link.base.num_lanes == 2) && 779*7caff0fcSAndrey Gusakov (value == (LT_CHANNEL1_EQ_BITS | 780*7caff0fcSAndrey Gusakov LT_INTERLANE_ALIGN_DONE | 781*7caff0fcSAndrey Gusakov LT_CHANNEL0_EQ_BITS))) 782*7caff0fcSAndrey Gusakov break; 783*7caff0fcSAndrey Gusakov /* in case of one line */ 784*7caff0fcSAndrey Gusakov if ((tc->link.base.num_lanes == 1) && 785*7caff0fcSAndrey Gusakov (value == (LT_INTERLANE_ALIGN_DONE | 786*7caff0fcSAndrey Gusakov LT_CHANNEL0_EQ_BITS))) 787*7caff0fcSAndrey Gusakov break; 788*7caff0fcSAndrey Gusakov } 789*7caff0fcSAndrey Gusakov } 790*7caff0fcSAndrey Gusakov /* restart */ 791*7caff0fcSAndrey Gusakov tc_write(DP0CTL, 0); 792*7caff0fcSAndrey Gusakov usleep_range(10, 20); 793*7caff0fcSAndrey Gusakov } while (--retry); 794*7caff0fcSAndrey Gusakov if (retry == 0) { 795*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Failed to finish training phase %d\n", 796*7caff0fcSAndrey Gusakov pattern); 797*7caff0fcSAndrey Gusakov } 798*7caff0fcSAndrey Gusakov 799*7caff0fcSAndrey Gusakov return 0; 800*7caff0fcSAndrey Gusakov err: 801*7caff0fcSAndrey Gusakov return ret; 802*7caff0fcSAndrey Gusakov } 803*7caff0fcSAndrey Gusakov 804*7caff0fcSAndrey Gusakov static int tc_main_link_setup(struct tc_data *tc) 805*7caff0fcSAndrey Gusakov { 806*7caff0fcSAndrey Gusakov struct drm_dp_aux *aux = &tc->aux; 807*7caff0fcSAndrey Gusakov struct device *dev = tc->dev; 808*7caff0fcSAndrey Gusakov unsigned int rate; 809*7caff0fcSAndrey Gusakov u32 dp_phy_ctrl; 810*7caff0fcSAndrey Gusakov int timeout; 811*7caff0fcSAndrey Gusakov bool aligned; 812*7caff0fcSAndrey Gusakov bool ready; 813*7caff0fcSAndrey Gusakov u32 value; 814*7caff0fcSAndrey Gusakov int ret; 815*7caff0fcSAndrey Gusakov u8 tmp[8]; 816*7caff0fcSAndrey Gusakov 817*7caff0fcSAndrey Gusakov /* display mode should be set at this point */ 818*7caff0fcSAndrey Gusakov if (!tc->mode) 819*7caff0fcSAndrey Gusakov return -EINVAL; 820*7caff0fcSAndrey Gusakov 821*7caff0fcSAndrey Gusakov /* from excel file - DP0_SrcCtrl */ 822*7caff0fcSAndrey Gusakov tc_write(DP0_SRCCTRL, DP0_SRCCTRL_SCRMBLDIS | DP0_SRCCTRL_EN810B | 823*7caff0fcSAndrey Gusakov DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 | 824*7caff0fcSAndrey Gusakov DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT); 825*7caff0fcSAndrey Gusakov /* from excel file - DP1_SrcCtrl */ 826*7caff0fcSAndrey Gusakov tc_write(0x07a0, 0x00003083); 827*7caff0fcSAndrey Gusakov 828*7caff0fcSAndrey Gusakov rate = clk_get_rate(tc->refclk); 829*7caff0fcSAndrey Gusakov switch (rate) { 830*7caff0fcSAndrey Gusakov case 38400000: 831*7caff0fcSAndrey Gusakov value = REF_FREQ_38M4; 832*7caff0fcSAndrey Gusakov break; 833*7caff0fcSAndrey Gusakov case 26000000: 834*7caff0fcSAndrey Gusakov value = REF_FREQ_26M; 835*7caff0fcSAndrey Gusakov break; 836*7caff0fcSAndrey Gusakov case 19200000: 837*7caff0fcSAndrey Gusakov value = REF_FREQ_19M2; 838*7caff0fcSAndrey Gusakov break; 839*7caff0fcSAndrey Gusakov case 13000000: 840*7caff0fcSAndrey Gusakov value = REF_FREQ_13M; 841*7caff0fcSAndrey Gusakov break; 842*7caff0fcSAndrey Gusakov default: 843*7caff0fcSAndrey Gusakov return -EINVAL; 844*7caff0fcSAndrey Gusakov } 845*7caff0fcSAndrey Gusakov value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; 846*7caff0fcSAndrey Gusakov tc_write(SYS_PLLPARAM, value); 847*7caff0fcSAndrey Gusakov /* Setup Main Link */ 848*7caff0fcSAndrey Gusakov dp_phy_ctrl = BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN | PHY_M0_EN; 849*7caff0fcSAndrey Gusakov tc_write(DP_PHY_CTRL, dp_phy_ctrl); 850*7caff0fcSAndrey Gusakov msleep(100); 851*7caff0fcSAndrey Gusakov 852*7caff0fcSAndrey Gusakov /* PLL setup */ 853*7caff0fcSAndrey Gusakov tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN); 854*7caff0fcSAndrey Gusakov tc_wait_pll_lock(tc); 855*7caff0fcSAndrey Gusakov 856*7caff0fcSAndrey Gusakov tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN); 857*7caff0fcSAndrey Gusakov tc_wait_pll_lock(tc); 858*7caff0fcSAndrey Gusakov 859*7caff0fcSAndrey Gusakov /* PXL PLL setup */ 860*7caff0fcSAndrey Gusakov if (tc_test_pattern) { 861*7caff0fcSAndrey Gusakov ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk), 862*7caff0fcSAndrey Gusakov 1000 * tc->mode->clock); 863*7caff0fcSAndrey Gusakov if (ret) 864*7caff0fcSAndrey Gusakov goto err; 865*7caff0fcSAndrey Gusakov } 866*7caff0fcSAndrey Gusakov 867*7caff0fcSAndrey Gusakov /* Reset/Enable Main Links */ 868*7caff0fcSAndrey Gusakov dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST; 869*7caff0fcSAndrey Gusakov tc_write(DP_PHY_CTRL, dp_phy_ctrl); 870*7caff0fcSAndrey Gusakov usleep_range(100, 200); 871*7caff0fcSAndrey Gusakov dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST); 872*7caff0fcSAndrey Gusakov tc_write(DP_PHY_CTRL, dp_phy_ctrl); 873*7caff0fcSAndrey Gusakov 874*7caff0fcSAndrey Gusakov timeout = 1000; 875*7caff0fcSAndrey Gusakov do { 876*7caff0fcSAndrey Gusakov tc_read(DP_PHY_CTRL, &value); 877*7caff0fcSAndrey Gusakov udelay(1); 878*7caff0fcSAndrey Gusakov } while ((!(value & PHY_RDY)) && (--timeout)); 879*7caff0fcSAndrey Gusakov 880*7caff0fcSAndrey Gusakov if (timeout == 0) { 881*7caff0fcSAndrey Gusakov dev_err(dev, "timeout waiting for phy become ready"); 882*7caff0fcSAndrey Gusakov return -ETIMEDOUT; 883*7caff0fcSAndrey Gusakov } 884*7caff0fcSAndrey Gusakov 885*7caff0fcSAndrey Gusakov /* Set misc: 8 bits per color */ 886*7caff0fcSAndrey Gusakov ret = regmap_update_bits(tc->regmap, DP0_MISC, BPC_8, BPC_8); 887*7caff0fcSAndrey Gusakov if (ret) 888*7caff0fcSAndrey Gusakov goto err; 889*7caff0fcSAndrey Gusakov 890*7caff0fcSAndrey Gusakov /* 891*7caff0fcSAndrey Gusakov * ASSR mode 892*7caff0fcSAndrey Gusakov * on TC358767 side ASSR configured through strap pin 893*7caff0fcSAndrey Gusakov * seems there is no way to change this setting from SW 894*7caff0fcSAndrey Gusakov * 895*7caff0fcSAndrey Gusakov * check is tc configured for same mode 896*7caff0fcSAndrey Gusakov */ 897*7caff0fcSAndrey Gusakov if (tc->assr != tc->link.assr) { 898*7caff0fcSAndrey Gusakov dev_dbg(dev, "Trying to set display to ASSR: %d\n", 899*7caff0fcSAndrey Gusakov tc->assr); 900*7caff0fcSAndrey Gusakov /* try to set ASSR on display side */ 901*7caff0fcSAndrey Gusakov tmp[0] = tc->assr; 902*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_writeb(aux, DP_EDP_CONFIGURATION_SET, tmp[0]); 903*7caff0fcSAndrey Gusakov if (ret < 0) 904*7caff0fcSAndrey Gusakov goto err_dpcd_read; 905*7caff0fcSAndrey Gusakov /* read back */ 906*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_readb(aux, DP_EDP_CONFIGURATION_SET, tmp); 907*7caff0fcSAndrey Gusakov if (ret < 0) 908*7caff0fcSAndrey Gusakov goto err_dpcd_read; 909*7caff0fcSAndrey Gusakov 910*7caff0fcSAndrey Gusakov if (tmp[0] != tc->assr) { 911*7caff0fcSAndrey Gusakov dev_warn(dev, "Failed to switch display ASSR to %d, falling back to unscrambled mode\n", 912*7caff0fcSAndrey Gusakov tc->assr); 913*7caff0fcSAndrey Gusakov /* trying with disabled scrambler */ 914*7caff0fcSAndrey Gusakov tc->link.scrambler_dis = 1; 915*7caff0fcSAndrey Gusakov } 916*7caff0fcSAndrey Gusakov } 917*7caff0fcSAndrey Gusakov 918*7caff0fcSAndrey Gusakov /* Setup Link & DPRx Config for Training */ 919*7caff0fcSAndrey Gusakov ret = drm_dp_link_configure(aux, &tc->link.base); 920*7caff0fcSAndrey Gusakov if (ret < 0) 921*7caff0fcSAndrey Gusakov goto err_dpcd_write; 922*7caff0fcSAndrey Gusakov 923*7caff0fcSAndrey Gusakov /* DOWNSPREAD_CTRL */ 924*7caff0fcSAndrey Gusakov tmp[0] = tc->link.spread ? DP_SPREAD_AMP_0_5 : 0x00; 925*7caff0fcSAndrey Gusakov /* MAIN_LINK_CHANNEL_CODING_SET */ 926*7caff0fcSAndrey Gusakov tmp[1] = tc->link.coding8b10b ? DP_SET_ANSI_8B10B : 0x00; 927*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_write(aux, DP_DOWNSPREAD_CTRL, tmp, 2); 928*7caff0fcSAndrey Gusakov if (ret < 0) 929*7caff0fcSAndrey Gusakov goto err_dpcd_write; 930*7caff0fcSAndrey Gusakov 931*7caff0fcSAndrey Gusakov ret = tc_link_training(tc, DP_TRAINING_PATTERN_1); 932*7caff0fcSAndrey Gusakov if (ret) 933*7caff0fcSAndrey Gusakov goto err; 934*7caff0fcSAndrey Gusakov 935*7caff0fcSAndrey Gusakov ret = tc_link_training(tc, DP_TRAINING_PATTERN_2); 936*7caff0fcSAndrey Gusakov if (ret) 937*7caff0fcSAndrey Gusakov goto err; 938*7caff0fcSAndrey Gusakov 939*7caff0fcSAndrey Gusakov /* Clear DPCD 0x102 */ 940*7caff0fcSAndrey Gusakov /* Note: Can Not use DP0_SNKLTCTRL (0x06E4) short cut */ 941*7caff0fcSAndrey Gusakov tmp[0] = tc->link.scrambler_dis ? DP_LINK_SCRAMBLING_DISABLE : 0x00; 942*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_writeb(aux, DP_TRAINING_PATTERN_SET, tmp[0]); 943*7caff0fcSAndrey Gusakov if (ret < 0) 944*7caff0fcSAndrey Gusakov goto err_dpcd_write; 945*7caff0fcSAndrey Gusakov 946*7caff0fcSAndrey Gusakov /* Clear Training Pattern, set AutoCorrect Mode = 1 */ 947*7caff0fcSAndrey Gusakov tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_AUTOCORRECT); 948*7caff0fcSAndrey Gusakov 949*7caff0fcSAndrey Gusakov /* Wait */ 950*7caff0fcSAndrey Gusakov timeout = 100; 951*7caff0fcSAndrey Gusakov do { 952*7caff0fcSAndrey Gusakov udelay(1); 953*7caff0fcSAndrey Gusakov /* Read DPCD 0x202-0x207 */ 954*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_read_link_status(aux, tmp + 2); 955*7caff0fcSAndrey Gusakov if (ret < 0) 956*7caff0fcSAndrey Gusakov goto err_dpcd_read; 957*7caff0fcSAndrey Gusakov ready = (tmp[2] == ((DP_CHANNEL_EQ_BITS << 4) | /* Lane1 */ 958*7caff0fcSAndrey Gusakov DP_CHANNEL_EQ_BITS)); /* Lane0 */ 959*7caff0fcSAndrey Gusakov aligned = tmp[4] & DP_INTERLANE_ALIGN_DONE; 960*7caff0fcSAndrey Gusakov } while ((--timeout) && !(ready && aligned)); 961*7caff0fcSAndrey Gusakov 962*7caff0fcSAndrey Gusakov if (timeout == 0) { 963*7caff0fcSAndrey Gusakov /* Read DPCD 0x200-0x201 */ 964*7caff0fcSAndrey Gusakov ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2); 965*7caff0fcSAndrey Gusakov if (ret < 0) 966*7caff0fcSAndrey Gusakov goto err_dpcd_read; 967*7caff0fcSAndrey Gusakov dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]); 968*7caff0fcSAndrey Gusakov dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n", 969*7caff0fcSAndrey Gusakov tmp[1]); 970*7caff0fcSAndrey Gusakov dev_info(dev, "0x0202 LANE0_1_STATUS: 0x%02x\n", tmp[2]); 971*7caff0fcSAndrey Gusakov dev_info(dev, "0x0204 LANE_ALIGN_STATUS_UPDATED: 0x%02x\n", 972*7caff0fcSAndrey Gusakov tmp[4]); 973*7caff0fcSAndrey Gusakov dev_info(dev, "0x0205 SINK_STATUS: 0x%02x\n", tmp[5]); 974*7caff0fcSAndrey Gusakov dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n", 975*7caff0fcSAndrey Gusakov tmp[6]); 976*7caff0fcSAndrey Gusakov 977*7caff0fcSAndrey Gusakov if (!ready) 978*7caff0fcSAndrey Gusakov dev_err(dev, "Lane0/1 not ready\n"); 979*7caff0fcSAndrey Gusakov if (!aligned) 980*7caff0fcSAndrey Gusakov dev_err(dev, "Lane0/1 not aligned\n"); 981*7caff0fcSAndrey Gusakov return -EAGAIN; 982*7caff0fcSAndrey Gusakov } 983*7caff0fcSAndrey Gusakov 984*7caff0fcSAndrey Gusakov ret = tc_set_video_mode(tc, tc->mode); 985*7caff0fcSAndrey Gusakov if (ret) 986*7caff0fcSAndrey Gusakov goto err; 987*7caff0fcSAndrey Gusakov 988*7caff0fcSAndrey Gusakov /* Set M/N */ 989*7caff0fcSAndrey Gusakov ret = tc_stream_clock_calc(tc); 990*7caff0fcSAndrey Gusakov if (ret) 991*7caff0fcSAndrey Gusakov goto err; 992*7caff0fcSAndrey Gusakov 993*7caff0fcSAndrey Gusakov return 0; 994*7caff0fcSAndrey Gusakov err_dpcd_read: 995*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Failed to read DPCD: %d\n", ret); 996*7caff0fcSAndrey Gusakov return ret; 997*7caff0fcSAndrey Gusakov err_dpcd_write: 998*7caff0fcSAndrey Gusakov dev_err(tc->dev, "Failed to write DPCD: %d\n", ret); 999*7caff0fcSAndrey Gusakov err: 1000*7caff0fcSAndrey Gusakov return ret; 1001*7caff0fcSAndrey Gusakov } 1002*7caff0fcSAndrey Gusakov 1003*7caff0fcSAndrey Gusakov static int tc_main_link_stream(struct tc_data *tc, int state) 1004*7caff0fcSAndrey Gusakov { 1005*7caff0fcSAndrey Gusakov int ret; 1006*7caff0fcSAndrey Gusakov u32 value; 1007*7caff0fcSAndrey Gusakov 1008*7caff0fcSAndrey Gusakov dev_dbg(tc->dev, "stream: %d\n", state); 1009*7caff0fcSAndrey Gusakov 1010*7caff0fcSAndrey Gusakov if (state) { 1011*7caff0fcSAndrey Gusakov value = VID_MN_GEN | DP_EN; 1012*7caff0fcSAndrey Gusakov if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 1013*7caff0fcSAndrey Gusakov value |= EF_EN; 1014*7caff0fcSAndrey Gusakov tc_write(DP0CTL, value); 1015*7caff0fcSAndrey Gusakov /* 1016*7caff0fcSAndrey Gusakov * VID_EN assertion should be delayed by at least N * LSCLK 1017*7caff0fcSAndrey Gusakov * cycles from the time VID_MN_GEN is enabled in order to 1018*7caff0fcSAndrey Gusakov * generate stable values for VID_M. LSCLK is 270 MHz or 1019*7caff0fcSAndrey Gusakov * 162 MHz, VID_N is set to 32768 in tc_stream_clock_calc(), 1020*7caff0fcSAndrey Gusakov * so a delay of at least 203 us should suffice. 1021*7caff0fcSAndrey Gusakov */ 1022*7caff0fcSAndrey Gusakov usleep_range(500, 1000); 1023*7caff0fcSAndrey Gusakov value |= VID_EN; 1024*7caff0fcSAndrey Gusakov tc_write(DP0CTL, value); 1025*7caff0fcSAndrey Gusakov /* Set input interface */ 1026*7caff0fcSAndrey Gusakov value = DP0_AUDSRC_NO_INPUT; 1027*7caff0fcSAndrey Gusakov if (tc_test_pattern) 1028*7caff0fcSAndrey Gusakov value |= DP0_VIDSRC_COLOR_BAR; 1029*7caff0fcSAndrey Gusakov else 1030*7caff0fcSAndrey Gusakov value |= DP0_VIDSRC_DPI_RX; 1031*7caff0fcSAndrey Gusakov tc_write(SYSCTRL, value); 1032*7caff0fcSAndrey Gusakov } else { 1033*7caff0fcSAndrey Gusakov tc_write(DP0CTL, 0); 1034*7caff0fcSAndrey Gusakov } 1035*7caff0fcSAndrey Gusakov 1036*7caff0fcSAndrey Gusakov return 0; 1037*7caff0fcSAndrey Gusakov err: 1038*7caff0fcSAndrey Gusakov return ret; 1039*7caff0fcSAndrey Gusakov } 1040*7caff0fcSAndrey Gusakov 1041*7caff0fcSAndrey Gusakov static enum drm_connector_status 1042*7caff0fcSAndrey Gusakov tc_connector_detect(struct drm_connector *connector, bool force) 1043*7caff0fcSAndrey Gusakov { 1044*7caff0fcSAndrey Gusakov return connector_status_connected; 1045*7caff0fcSAndrey Gusakov } 1046*7caff0fcSAndrey Gusakov 1047*7caff0fcSAndrey Gusakov static void tc_bridge_pre_enable(struct drm_bridge *bridge) 1048*7caff0fcSAndrey Gusakov { 1049*7caff0fcSAndrey Gusakov struct tc_data *tc = bridge_to_tc(bridge); 1050*7caff0fcSAndrey Gusakov 1051*7caff0fcSAndrey Gusakov drm_panel_prepare(tc->panel); 1052*7caff0fcSAndrey Gusakov } 1053*7caff0fcSAndrey Gusakov 1054*7caff0fcSAndrey Gusakov static void tc_bridge_enable(struct drm_bridge *bridge) 1055*7caff0fcSAndrey Gusakov { 1056*7caff0fcSAndrey Gusakov struct tc_data *tc = bridge_to_tc(bridge); 1057*7caff0fcSAndrey Gusakov int ret; 1058*7caff0fcSAndrey Gusakov 1059*7caff0fcSAndrey Gusakov ret = tc_main_link_setup(tc); 1060*7caff0fcSAndrey Gusakov if (ret < 0) { 1061*7caff0fcSAndrey Gusakov dev_err(tc->dev, "main link setup error: %d\n", ret); 1062*7caff0fcSAndrey Gusakov return; 1063*7caff0fcSAndrey Gusakov } 1064*7caff0fcSAndrey Gusakov 1065*7caff0fcSAndrey Gusakov ret = tc_main_link_stream(tc, 1); 1066*7caff0fcSAndrey Gusakov if (ret < 0) { 1067*7caff0fcSAndrey Gusakov dev_err(tc->dev, "main link stream start error: %d\n", ret); 1068*7caff0fcSAndrey Gusakov return; 1069*7caff0fcSAndrey Gusakov } 1070*7caff0fcSAndrey Gusakov 1071*7caff0fcSAndrey Gusakov drm_panel_enable(tc->panel); 1072*7caff0fcSAndrey Gusakov } 1073*7caff0fcSAndrey Gusakov 1074*7caff0fcSAndrey Gusakov static void tc_bridge_disable(struct drm_bridge *bridge) 1075*7caff0fcSAndrey Gusakov { 1076*7caff0fcSAndrey Gusakov struct tc_data *tc = bridge_to_tc(bridge); 1077*7caff0fcSAndrey Gusakov int ret; 1078*7caff0fcSAndrey Gusakov 1079*7caff0fcSAndrey Gusakov drm_panel_disable(tc->panel); 1080*7caff0fcSAndrey Gusakov 1081*7caff0fcSAndrey Gusakov ret = tc_main_link_stream(tc, 0); 1082*7caff0fcSAndrey Gusakov if (ret < 0) 1083*7caff0fcSAndrey Gusakov dev_err(tc->dev, "main link stream stop error: %d\n", ret); 1084*7caff0fcSAndrey Gusakov } 1085*7caff0fcSAndrey Gusakov 1086*7caff0fcSAndrey Gusakov static void tc_bridge_post_disable(struct drm_bridge *bridge) 1087*7caff0fcSAndrey Gusakov { 1088*7caff0fcSAndrey Gusakov struct tc_data *tc = bridge_to_tc(bridge); 1089*7caff0fcSAndrey Gusakov 1090*7caff0fcSAndrey Gusakov drm_panel_unprepare(tc->panel); 1091*7caff0fcSAndrey Gusakov } 1092*7caff0fcSAndrey Gusakov 1093*7caff0fcSAndrey Gusakov static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, 1094*7caff0fcSAndrey Gusakov const struct drm_display_mode *mode, 1095*7caff0fcSAndrey Gusakov struct drm_display_mode *adj) 1096*7caff0fcSAndrey Gusakov { 1097*7caff0fcSAndrey Gusakov /* Fixup sync polarities, both hsync and vsync are active low */ 1098*7caff0fcSAndrey Gusakov adj->flags = mode->flags; 1099*7caff0fcSAndrey Gusakov adj->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); 1100*7caff0fcSAndrey Gusakov adj->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); 1101*7caff0fcSAndrey Gusakov 1102*7caff0fcSAndrey Gusakov return true; 1103*7caff0fcSAndrey Gusakov } 1104*7caff0fcSAndrey Gusakov 1105*7caff0fcSAndrey Gusakov static int tc_connector_mode_valid(struct drm_connector *connector, 1106*7caff0fcSAndrey Gusakov struct drm_display_mode *mode) 1107*7caff0fcSAndrey Gusakov { 1108*7caff0fcSAndrey Gusakov /* Accept any mode */ 1109*7caff0fcSAndrey Gusakov return MODE_OK; 1110*7caff0fcSAndrey Gusakov } 1111*7caff0fcSAndrey Gusakov 1112*7caff0fcSAndrey Gusakov static void tc_bridge_mode_set(struct drm_bridge *bridge, 1113*7caff0fcSAndrey Gusakov struct drm_display_mode *mode, 1114*7caff0fcSAndrey Gusakov struct drm_display_mode *adj) 1115*7caff0fcSAndrey Gusakov { 1116*7caff0fcSAndrey Gusakov struct tc_data *tc = bridge_to_tc(bridge); 1117*7caff0fcSAndrey Gusakov 1118*7caff0fcSAndrey Gusakov tc->mode = mode; 1119*7caff0fcSAndrey Gusakov } 1120*7caff0fcSAndrey Gusakov 1121*7caff0fcSAndrey Gusakov static int tc_connector_get_modes(struct drm_connector *connector) 1122*7caff0fcSAndrey Gusakov { 1123*7caff0fcSAndrey Gusakov struct tc_data *tc = connector_to_tc(connector); 1124*7caff0fcSAndrey Gusakov struct edid *edid; 1125*7caff0fcSAndrey Gusakov unsigned int count; 1126*7caff0fcSAndrey Gusakov 1127*7caff0fcSAndrey Gusakov if (tc->panel && tc->panel->funcs && tc->panel->funcs->get_modes) { 1128*7caff0fcSAndrey Gusakov count = tc->panel->funcs->get_modes(tc->panel); 1129*7caff0fcSAndrey Gusakov if (count > 0) 1130*7caff0fcSAndrey Gusakov return count; 1131*7caff0fcSAndrey Gusakov } 1132*7caff0fcSAndrey Gusakov 1133*7caff0fcSAndrey Gusakov edid = drm_get_edid(connector, &tc->aux.ddc); 1134*7caff0fcSAndrey Gusakov 1135*7caff0fcSAndrey Gusakov kfree(tc->edid); 1136*7caff0fcSAndrey Gusakov tc->edid = edid; 1137*7caff0fcSAndrey Gusakov if (!edid) 1138*7caff0fcSAndrey Gusakov return 0; 1139*7caff0fcSAndrey Gusakov 1140*7caff0fcSAndrey Gusakov drm_mode_connector_update_edid_property(connector, edid); 1141*7caff0fcSAndrey Gusakov count = drm_add_edid_modes(connector, edid); 1142*7caff0fcSAndrey Gusakov 1143*7caff0fcSAndrey Gusakov return count; 1144*7caff0fcSAndrey Gusakov } 1145*7caff0fcSAndrey Gusakov 1146*7caff0fcSAndrey Gusakov static void tc_connector_set_polling(struct tc_data *tc, 1147*7caff0fcSAndrey Gusakov struct drm_connector *connector) 1148*7caff0fcSAndrey Gusakov { 1149*7caff0fcSAndrey Gusakov /* TODO: add support for HPD */ 1150*7caff0fcSAndrey Gusakov connector->polled = DRM_CONNECTOR_POLL_CONNECT | 1151*7caff0fcSAndrey Gusakov DRM_CONNECTOR_POLL_DISCONNECT; 1152*7caff0fcSAndrey Gusakov } 1153*7caff0fcSAndrey Gusakov 1154*7caff0fcSAndrey Gusakov static struct drm_encoder * 1155*7caff0fcSAndrey Gusakov tc_connector_best_encoder(struct drm_connector *connector) 1156*7caff0fcSAndrey Gusakov { 1157*7caff0fcSAndrey Gusakov struct tc_data *tc = connector_to_tc(connector); 1158*7caff0fcSAndrey Gusakov 1159*7caff0fcSAndrey Gusakov return tc->bridge.encoder; 1160*7caff0fcSAndrey Gusakov } 1161*7caff0fcSAndrey Gusakov 1162*7caff0fcSAndrey Gusakov static const struct drm_connector_helper_funcs tc_connector_helper_funcs = { 1163*7caff0fcSAndrey Gusakov .get_modes = tc_connector_get_modes, 1164*7caff0fcSAndrey Gusakov .mode_valid = tc_connector_mode_valid, 1165*7caff0fcSAndrey Gusakov .best_encoder = tc_connector_best_encoder, 1166*7caff0fcSAndrey Gusakov }; 1167*7caff0fcSAndrey Gusakov 1168*7caff0fcSAndrey Gusakov static void tc_connector_destroy(struct drm_connector *connector) 1169*7caff0fcSAndrey Gusakov { 1170*7caff0fcSAndrey Gusakov drm_connector_unregister(connector); 1171*7caff0fcSAndrey Gusakov drm_connector_cleanup(connector); 1172*7caff0fcSAndrey Gusakov } 1173*7caff0fcSAndrey Gusakov 1174*7caff0fcSAndrey Gusakov static const struct drm_connector_funcs tc_connector_funcs = { 1175*7caff0fcSAndrey Gusakov .dpms = drm_atomic_helper_connector_dpms, 1176*7caff0fcSAndrey Gusakov .fill_modes = drm_helper_probe_single_connector_modes, 1177*7caff0fcSAndrey Gusakov .detect = tc_connector_detect, 1178*7caff0fcSAndrey Gusakov .destroy = tc_connector_destroy, 1179*7caff0fcSAndrey Gusakov .reset = drm_atomic_helper_connector_reset, 1180*7caff0fcSAndrey Gusakov .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 1181*7caff0fcSAndrey Gusakov .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 1182*7caff0fcSAndrey Gusakov }; 1183*7caff0fcSAndrey Gusakov 1184*7caff0fcSAndrey Gusakov static int tc_bridge_attach(struct drm_bridge *bridge) 1185*7caff0fcSAndrey Gusakov { 1186*7caff0fcSAndrey Gusakov u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; 1187*7caff0fcSAndrey Gusakov struct tc_data *tc = bridge_to_tc(bridge); 1188*7caff0fcSAndrey Gusakov struct drm_device *drm = bridge->dev; 1189*7caff0fcSAndrey Gusakov int ret; 1190*7caff0fcSAndrey Gusakov 1191*7caff0fcSAndrey Gusakov /* Create eDP connector */ 1192*7caff0fcSAndrey Gusakov drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); 1193*7caff0fcSAndrey Gusakov ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, 1194*7caff0fcSAndrey Gusakov DRM_MODE_CONNECTOR_eDP); 1195*7caff0fcSAndrey Gusakov if (ret) 1196*7caff0fcSAndrey Gusakov return ret; 1197*7caff0fcSAndrey Gusakov 1198*7caff0fcSAndrey Gusakov if (tc->panel) 1199*7caff0fcSAndrey Gusakov drm_panel_attach(tc->panel, &tc->connector); 1200*7caff0fcSAndrey Gusakov 1201*7caff0fcSAndrey Gusakov drm_display_info_set_bus_formats(&tc->connector.display_info, 1202*7caff0fcSAndrey Gusakov &bus_format, 1); 1203*7caff0fcSAndrey Gusakov drm_mode_connector_attach_encoder(&tc->connector, tc->bridge.encoder); 1204*7caff0fcSAndrey Gusakov 1205*7caff0fcSAndrey Gusakov return 0; 1206*7caff0fcSAndrey Gusakov } 1207*7caff0fcSAndrey Gusakov 1208*7caff0fcSAndrey Gusakov static const struct drm_bridge_funcs tc_bridge_funcs = { 1209*7caff0fcSAndrey Gusakov .attach = tc_bridge_attach, 1210*7caff0fcSAndrey Gusakov .mode_set = tc_bridge_mode_set, 1211*7caff0fcSAndrey Gusakov .pre_enable = tc_bridge_pre_enable, 1212*7caff0fcSAndrey Gusakov .enable = tc_bridge_enable, 1213*7caff0fcSAndrey Gusakov .disable = tc_bridge_disable, 1214*7caff0fcSAndrey Gusakov .post_disable = tc_bridge_post_disable, 1215*7caff0fcSAndrey Gusakov .mode_fixup = tc_bridge_mode_fixup, 1216*7caff0fcSAndrey Gusakov }; 1217*7caff0fcSAndrey Gusakov 1218*7caff0fcSAndrey Gusakov static bool tc_readable_reg(struct device *dev, unsigned int reg) 1219*7caff0fcSAndrey Gusakov { 1220*7caff0fcSAndrey Gusakov return reg != SYSCTRL; 1221*7caff0fcSAndrey Gusakov } 1222*7caff0fcSAndrey Gusakov 1223*7caff0fcSAndrey Gusakov static const struct regmap_range tc_volatile_ranges[] = { 1224*7caff0fcSAndrey Gusakov regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS), 1225*7caff0fcSAndrey Gusakov regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), 1226*7caff0fcSAndrey Gusakov regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL), 1227*7caff0fcSAndrey Gusakov regmap_reg_range(DP0_PLLCTRL, PXL_PLLCTRL), 1228*7caff0fcSAndrey Gusakov regmap_reg_range(VFUEN0, VFUEN0), 1229*7caff0fcSAndrey Gusakov }; 1230*7caff0fcSAndrey Gusakov 1231*7caff0fcSAndrey Gusakov static const struct regmap_access_table tc_volatile_table = { 1232*7caff0fcSAndrey Gusakov .yes_ranges = tc_volatile_ranges, 1233*7caff0fcSAndrey Gusakov .n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges), 1234*7caff0fcSAndrey Gusakov }; 1235*7caff0fcSAndrey Gusakov 1236*7caff0fcSAndrey Gusakov static bool tc_writeable_reg(struct device *dev, unsigned int reg) 1237*7caff0fcSAndrey Gusakov { 1238*7caff0fcSAndrey Gusakov return (reg != TC_IDREG) && 1239*7caff0fcSAndrey Gusakov (reg != DP0_LTSTAT) && 1240*7caff0fcSAndrey Gusakov (reg != DP0_SNKLTCHGREQ); 1241*7caff0fcSAndrey Gusakov } 1242*7caff0fcSAndrey Gusakov 1243*7caff0fcSAndrey Gusakov static const struct regmap_config tc_regmap_config = { 1244*7caff0fcSAndrey Gusakov .name = "tc358767", 1245*7caff0fcSAndrey Gusakov .reg_bits = 16, 1246*7caff0fcSAndrey Gusakov .val_bits = 32, 1247*7caff0fcSAndrey Gusakov .reg_stride = 4, 1248*7caff0fcSAndrey Gusakov .max_register = PLL_DBG, 1249*7caff0fcSAndrey Gusakov .cache_type = REGCACHE_RBTREE, 1250*7caff0fcSAndrey Gusakov .readable_reg = tc_readable_reg, 1251*7caff0fcSAndrey Gusakov .volatile_table = &tc_volatile_table, 1252*7caff0fcSAndrey Gusakov .writeable_reg = tc_writeable_reg, 1253*7caff0fcSAndrey Gusakov .reg_format_endian = REGMAP_ENDIAN_BIG, 1254*7caff0fcSAndrey Gusakov .val_format_endian = REGMAP_ENDIAN_LITTLE, 1255*7caff0fcSAndrey Gusakov }; 1256*7caff0fcSAndrey Gusakov 1257*7caff0fcSAndrey Gusakov static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) 1258*7caff0fcSAndrey Gusakov { 1259*7caff0fcSAndrey Gusakov struct device *dev = &client->dev; 1260*7caff0fcSAndrey Gusakov struct device_node *ep; 1261*7caff0fcSAndrey Gusakov struct tc_data *tc; 1262*7caff0fcSAndrey Gusakov int ret; 1263*7caff0fcSAndrey Gusakov 1264*7caff0fcSAndrey Gusakov tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL); 1265*7caff0fcSAndrey Gusakov if (!tc) 1266*7caff0fcSAndrey Gusakov return -ENOMEM; 1267*7caff0fcSAndrey Gusakov 1268*7caff0fcSAndrey Gusakov tc->dev = dev; 1269*7caff0fcSAndrey Gusakov 1270*7caff0fcSAndrey Gusakov /* port@2 is the output port */ 1271*7caff0fcSAndrey Gusakov ep = of_graph_get_endpoint_by_regs(dev->of_node, 2, -1); 1272*7caff0fcSAndrey Gusakov if (ep) { 1273*7caff0fcSAndrey Gusakov struct device_node *remote; 1274*7caff0fcSAndrey Gusakov 1275*7caff0fcSAndrey Gusakov remote = of_graph_get_remote_port_parent(ep); 1276*7caff0fcSAndrey Gusakov if (!remote) { 1277*7caff0fcSAndrey Gusakov dev_warn(dev, "endpoint %s not connected\n", 1278*7caff0fcSAndrey Gusakov ep->full_name); 1279*7caff0fcSAndrey Gusakov of_node_put(ep); 1280*7caff0fcSAndrey Gusakov return -ENODEV; 1281*7caff0fcSAndrey Gusakov } 1282*7caff0fcSAndrey Gusakov of_node_put(ep); 1283*7caff0fcSAndrey Gusakov tc->panel = of_drm_find_panel(remote); 1284*7caff0fcSAndrey Gusakov if (tc->panel) { 1285*7caff0fcSAndrey Gusakov dev_dbg(dev, "found panel %s\n", remote->full_name); 1286*7caff0fcSAndrey Gusakov } else { 1287*7caff0fcSAndrey Gusakov dev_dbg(dev, "waiting for panel %s\n", 1288*7caff0fcSAndrey Gusakov remote->full_name); 1289*7caff0fcSAndrey Gusakov of_node_put(remote); 1290*7caff0fcSAndrey Gusakov return -EPROBE_DEFER; 1291*7caff0fcSAndrey Gusakov } 1292*7caff0fcSAndrey Gusakov of_node_put(remote); 1293*7caff0fcSAndrey Gusakov } 1294*7caff0fcSAndrey Gusakov 1295*7caff0fcSAndrey Gusakov /* Shut down GPIO is optional */ 1296*7caff0fcSAndrey Gusakov tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); 1297*7caff0fcSAndrey Gusakov if (IS_ERR(tc->sd_gpio)) 1298*7caff0fcSAndrey Gusakov return PTR_ERR(tc->sd_gpio); 1299*7caff0fcSAndrey Gusakov 1300*7caff0fcSAndrey Gusakov if (tc->sd_gpio) { 1301*7caff0fcSAndrey Gusakov gpiod_set_value_cansleep(tc->sd_gpio, 0); 1302*7caff0fcSAndrey Gusakov usleep_range(5000, 10000); 1303*7caff0fcSAndrey Gusakov } 1304*7caff0fcSAndrey Gusakov 1305*7caff0fcSAndrey Gusakov /* Reset GPIO is optional */ 1306*7caff0fcSAndrey Gusakov tc->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 1307*7caff0fcSAndrey Gusakov if (IS_ERR(tc->reset_gpio)) 1308*7caff0fcSAndrey Gusakov return PTR_ERR(tc->reset_gpio); 1309*7caff0fcSAndrey Gusakov 1310*7caff0fcSAndrey Gusakov if (tc->reset_gpio) { 1311*7caff0fcSAndrey Gusakov gpiod_set_value_cansleep(tc->reset_gpio, 1); 1312*7caff0fcSAndrey Gusakov usleep_range(5000, 10000); 1313*7caff0fcSAndrey Gusakov } 1314*7caff0fcSAndrey Gusakov 1315*7caff0fcSAndrey Gusakov tc->refclk = devm_clk_get(dev, "ref"); 1316*7caff0fcSAndrey Gusakov if (IS_ERR(tc->refclk)) { 1317*7caff0fcSAndrey Gusakov ret = PTR_ERR(tc->refclk); 1318*7caff0fcSAndrey Gusakov dev_err(dev, "Failed to get refclk: %d\n", ret); 1319*7caff0fcSAndrey Gusakov return ret; 1320*7caff0fcSAndrey Gusakov } 1321*7caff0fcSAndrey Gusakov 1322*7caff0fcSAndrey Gusakov tc->regmap = devm_regmap_init_i2c(client, &tc_regmap_config); 1323*7caff0fcSAndrey Gusakov if (IS_ERR(tc->regmap)) { 1324*7caff0fcSAndrey Gusakov ret = PTR_ERR(tc->regmap); 1325*7caff0fcSAndrey Gusakov dev_err(dev, "Failed to initialize regmap: %d\n", ret); 1326*7caff0fcSAndrey Gusakov return ret; 1327*7caff0fcSAndrey Gusakov } 1328*7caff0fcSAndrey Gusakov 1329*7caff0fcSAndrey Gusakov ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev); 1330*7caff0fcSAndrey Gusakov if (ret) { 1331*7caff0fcSAndrey Gusakov dev_err(tc->dev, "can not read device ID: %d\n", ret); 1332*7caff0fcSAndrey Gusakov return ret; 1333*7caff0fcSAndrey Gusakov } 1334*7caff0fcSAndrey Gusakov 1335*7caff0fcSAndrey Gusakov if ((tc->rev != 0x6601) && (tc->rev != 0x6603)) { 1336*7caff0fcSAndrey Gusakov dev_err(tc->dev, "invalid device ID: 0x%08x\n", tc->rev); 1337*7caff0fcSAndrey Gusakov return -EINVAL; 1338*7caff0fcSAndrey Gusakov } 1339*7caff0fcSAndrey Gusakov 1340*7caff0fcSAndrey Gusakov tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */ 1341*7caff0fcSAndrey Gusakov 1342*7caff0fcSAndrey Gusakov ret = tc_aux_link_setup(tc); 1343*7caff0fcSAndrey Gusakov if (ret) 1344*7caff0fcSAndrey Gusakov return ret; 1345*7caff0fcSAndrey Gusakov 1346*7caff0fcSAndrey Gusakov /* Register DP AUX channel */ 1347*7caff0fcSAndrey Gusakov tc->aux.name = "TC358767 AUX i2c adapter"; 1348*7caff0fcSAndrey Gusakov tc->aux.dev = tc->dev; 1349*7caff0fcSAndrey Gusakov tc->aux.transfer = tc_aux_transfer; 1350*7caff0fcSAndrey Gusakov ret = drm_dp_aux_register(&tc->aux); 1351*7caff0fcSAndrey Gusakov if (ret) 1352*7caff0fcSAndrey Gusakov return ret; 1353*7caff0fcSAndrey Gusakov 1354*7caff0fcSAndrey Gusakov ret = tc_get_display_props(tc); 1355*7caff0fcSAndrey Gusakov if (ret) 1356*7caff0fcSAndrey Gusakov goto err_unregister_aux; 1357*7caff0fcSAndrey Gusakov 1358*7caff0fcSAndrey Gusakov tc_connector_set_polling(tc, &tc->connector); 1359*7caff0fcSAndrey Gusakov 1360*7caff0fcSAndrey Gusakov tc->bridge.funcs = &tc_bridge_funcs; 1361*7caff0fcSAndrey Gusakov tc->bridge.of_node = dev->of_node; 1362*7caff0fcSAndrey Gusakov ret = drm_bridge_add(&tc->bridge); 1363*7caff0fcSAndrey Gusakov if (ret) { 1364*7caff0fcSAndrey Gusakov dev_err(dev, "Failed to add drm_bridge: %d\n", ret); 1365*7caff0fcSAndrey Gusakov goto err_unregister_aux; 1366*7caff0fcSAndrey Gusakov } 1367*7caff0fcSAndrey Gusakov 1368*7caff0fcSAndrey Gusakov i2c_set_clientdata(client, tc); 1369*7caff0fcSAndrey Gusakov 1370*7caff0fcSAndrey Gusakov return 0; 1371*7caff0fcSAndrey Gusakov err_unregister_aux: 1372*7caff0fcSAndrey Gusakov drm_dp_aux_unregister(&tc->aux); 1373*7caff0fcSAndrey Gusakov return ret; 1374*7caff0fcSAndrey Gusakov } 1375*7caff0fcSAndrey Gusakov 1376*7caff0fcSAndrey Gusakov static int tc_remove(struct i2c_client *client) 1377*7caff0fcSAndrey Gusakov { 1378*7caff0fcSAndrey Gusakov struct tc_data *tc = i2c_get_clientdata(client); 1379*7caff0fcSAndrey Gusakov 1380*7caff0fcSAndrey Gusakov drm_bridge_remove(&tc->bridge); 1381*7caff0fcSAndrey Gusakov drm_dp_aux_unregister(&tc->aux); 1382*7caff0fcSAndrey Gusakov 1383*7caff0fcSAndrey Gusakov tc_pxl_pll_dis(tc); 1384*7caff0fcSAndrey Gusakov 1385*7caff0fcSAndrey Gusakov return 0; 1386*7caff0fcSAndrey Gusakov } 1387*7caff0fcSAndrey Gusakov 1388*7caff0fcSAndrey Gusakov static const struct i2c_device_id tc358767_i2c_ids[] = { 1389*7caff0fcSAndrey Gusakov { "tc358767", 0 }, 1390*7caff0fcSAndrey Gusakov { } 1391*7caff0fcSAndrey Gusakov }; 1392*7caff0fcSAndrey Gusakov MODULE_DEVICE_TABLE(i2c, tc358767_i2c_ids); 1393*7caff0fcSAndrey Gusakov 1394*7caff0fcSAndrey Gusakov static const struct of_device_id tc358767_of_ids[] = { 1395*7caff0fcSAndrey Gusakov { .compatible = "toshiba,tc358767", }, 1396*7caff0fcSAndrey Gusakov { } 1397*7caff0fcSAndrey Gusakov }; 1398*7caff0fcSAndrey Gusakov MODULE_DEVICE_TABLE(of, tc358767_of_ids); 1399*7caff0fcSAndrey Gusakov 1400*7caff0fcSAndrey Gusakov static struct i2c_driver tc358767_driver = { 1401*7caff0fcSAndrey Gusakov .driver = { 1402*7caff0fcSAndrey Gusakov .name = "tc358767", 1403*7caff0fcSAndrey Gusakov .of_match_table = tc358767_of_ids, 1404*7caff0fcSAndrey Gusakov }, 1405*7caff0fcSAndrey Gusakov .id_table = tc358767_i2c_ids, 1406*7caff0fcSAndrey Gusakov .probe = tc_probe, 1407*7caff0fcSAndrey Gusakov .remove = tc_remove, 1408*7caff0fcSAndrey Gusakov }; 1409*7caff0fcSAndrey Gusakov module_i2c_driver(tc358767_driver); 1410*7caff0fcSAndrey Gusakov 1411*7caff0fcSAndrey Gusakov MODULE_AUTHOR("Andrey Gusakov <andrey.gusakov@cogentembedded.com>"); 1412*7caff0fcSAndrey Gusakov MODULE_DESCRIPTION("tc358767 eDP encoder driver"); 1413*7caff0fcSAndrey Gusakov MODULE_LICENSE("GPL"); 1414