sun8i_hdmi_phy.c (22525B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net> 4 */ 5 6#include <linux/delay.h> 7#include <linux/of_address.h> 8#include <linux/of_platform.h> 9 10#include "sun8i_dw_hdmi.h" 11 12/* 13 * Address can be actually any value. Here is set to same value as 14 * it is set in BSP driver. 15 */ 16#define I2C_ADDR 0x69 17 18static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = { 19 { 20 30666000, { 21 { 0x00b3, 0x0000 }, 22 { 0x2153, 0x0000 }, 23 { 0x40f3, 0x0000 }, 24 }, 25 }, { 26 36800000, { 27 { 0x00b3, 0x0000 }, 28 { 0x2153, 0x0000 }, 29 { 0x40a2, 0x0001 }, 30 }, 31 }, { 32 46000000, { 33 { 0x00b3, 0x0000 }, 34 { 0x2142, 0x0001 }, 35 { 0x40a2, 0x0001 }, 36 }, 37 }, { 38 61333000, { 39 { 0x0072, 0x0001 }, 40 { 0x2142, 0x0001 }, 41 { 0x40a2, 0x0001 }, 42 }, 43 }, { 44 73600000, { 45 { 0x0072, 0x0001 }, 46 { 0x2142, 0x0001 }, 47 { 0x4061, 0x0002 }, 48 }, 49 }, { 50 92000000, { 51 { 0x0072, 0x0001 }, 52 { 0x2145, 0x0002 }, 53 { 0x4061, 0x0002 }, 54 }, 55 }, { 56 122666000, { 57 { 0x0051, 0x0002 }, 58 { 0x2145, 0x0002 }, 59 { 0x4061, 0x0002 }, 60 }, 61 }, { 62 147200000, { 63 { 0x0051, 0x0002 }, 64 { 0x2145, 0x0002 }, 65 { 0x4064, 0x0003 }, 66 }, 67 }, { 68 184000000, { 69 { 0x0051, 0x0002 }, 70 { 0x214c, 0x0003 }, 71 { 0x4064, 0x0003 }, 72 }, 73 }, { 74 226666000, { 75 { 0x0040, 0x0003 }, 76 { 0x214c, 0x0003 }, 77 { 0x4064, 0x0003 }, 78 }, 79 }, { 80 272000000, { 81 { 0x0040, 0x0003 }, 82 { 0x214c, 0x0003 }, 83 { 0x5a64, 0x0003 }, 84 }, 85 }, { 86 340000000, { 87 { 0x0040, 0x0003 }, 88 { 0x3b4c, 0x0003 }, 89 { 0x5a64, 0x0003 }, 90 }, 91 }, { 92 594000000, { 93 { 0x1a40, 0x0003 }, 94 { 0x3b4c, 0x0003 }, 95 { 0x5a64, 0x0003 }, 96 }, 97 }, { 98 ~0UL, { 99 { 0x0000, 0x0000 }, 100 { 0x0000, 0x0000 }, 101 { 0x0000, 0x0000 }, 102 }, 103 } 104}; 105 106static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = { 107 /* pixelclk bpp8 bpp10 bpp12 */ 108 { 27000000, { 0x0012, 0x0000, 0x0000 }, }, 109 { 74250000, { 0x0013, 0x001a, 0x001b }, }, 110 { 148500000, { 0x0019, 0x0033, 0x0034 }, }, 111 { 297000000, { 0x0019, 0x001b, 0x001b }, }, 112 { 594000000, { 0x0010, 0x001b, 0x001b }, }, 113 { ~0UL, { 0x0000, 0x0000, 0x0000 }, } 114}; 115 116static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = { 117 /*pixelclk symbol term vlev*/ 118 { 27000000, 0x8009, 0x0007, 0x02b0 }, 119 { 74250000, 0x8009, 0x0006, 0x022d }, 120 { 148500000, 0x8029, 0x0006, 0x0270 }, 121 { 297000000, 0x8039, 0x0005, 0x01ab }, 122 { 594000000, 0x8029, 0x0000, 0x008a }, 123 { ~0UL, 0x0000, 0x0000, 0x0000} 124}; 125 126static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi, 127 struct sun8i_hdmi_phy *phy, 128 unsigned int clk_rate) 129{ 130 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 131 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 132 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN); 133 134 /* power down */ 135 dw_hdmi_phy_gen2_txpwron(hdmi, 0); 136 dw_hdmi_phy_gen2_pddq(hdmi, 1); 137 138 dw_hdmi_phy_gen2_reset(hdmi); 139 140 dw_hdmi_phy_gen2_pddq(hdmi, 0); 141 142 dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR); 143 144 /* 145 * Values are taken from BSP HDMI driver. Although AW didn't 146 * release any documentation, explanation of this values can 147 * be found in i.MX 6Dual/6Quad Reference Manual. 148 */ 149 if (clk_rate <= 27000000) { 150 dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06); 151 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); 152 dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10); 153 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19); 154 dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e); 155 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); 156 } else if (clk_rate <= 74250000) { 157 dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06); 158 dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); 159 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); 160 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19); 161 dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e); 162 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); 163 } else if (clk_rate <= 148500000) { 164 dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06); 165 dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); 166 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); 167 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19); 168 dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e); 169 dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09); 170 } else { 171 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06); 172 dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); 173 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); 174 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19); 175 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e); 176 dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09); 177 } 178 179 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e); 180 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); 181 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17); 182 183 dw_hdmi_phy_gen2_txpwron(hdmi, 1); 184 185 return 0; 186} 187 188static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, 189 struct sun8i_hdmi_phy *phy, 190 unsigned int clk_rate) 191{ 192 u32 pll_cfg1_init; 193 u32 pll_cfg2_init; 194 u32 ana_cfg1_end; 195 u32 ana_cfg2_init; 196 u32 ana_cfg3_init; 197 u32 b_offset = 0; 198 u32 val; 199 200 /* bandwidth / frequency independent settings */ 201 202 pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN | 203 SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN | 204 SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) | 205 SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) | 206 SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN | 207 SUN8I_HDMI_PHY_PLL_CFG1_CS | 208 SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) | 209 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) | 210 SUN8I_HDMI_PHY_PLL_CFG1_BWS; 211 212 pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H | 213 SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN | 214 SUN8I_HDMI_PHY_PLL_CFG2_SDIV2; 215 216 ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) | 217 SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT | 218 SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT | 219 SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT | 220 SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT | 221 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL | 222 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG | 223 SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS | 224 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN | 225 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK | 226 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL | 227 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK | 228 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | 229 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | 230 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | 231 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 | 232 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | 233 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | 234 SUN8I_HDMI_PHY_ANA_CFG1_CKEN | 235 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN | 236 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS | 237 SUN8I_HDMI_PHY_ANA_CFG1_ENBI; 238 239 ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN | 240 SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK | 241 SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN | 242 SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) | 243 SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1); 244 245 ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) | 246 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN | 247 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN; 248 249 /* bandwidth / frequency dependent settings */ 250 if (clk_rate <= 27000000) { 251 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | 252 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); 253 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | 254 SUN8I_HDMI_PHY_PLL_CFG2_S(4); 255 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW; 256 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) | 257 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal); 258 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) | 259 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5); 260 } else if (clk_rate <= 74250000) { 261 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | 262 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); 263 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | 264 SUN8I_HDMI_PHY_PLL_CFG2_S(5); 265 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW; 266 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) | 267 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal); 268 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) | 269 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7); 270 } else if (clk_rate <= 148500000) { 271 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | 272 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); 273 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | 274 SUN8I_HDMI_PHY_PLL_CFG2_S(6); 275 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK | 276 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW | 277 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2); 278 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) | 279 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9); 280 } else { 281 b_offset = 2; 282 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63); 283 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) | 284 SUN8I_HDMI_PHY_PLL_CFG2_S(7); 285 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK | 286 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW | 287 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4); 288 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) | 289 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) | 290 SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3); 291 } 292 293 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 294 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0); 295 296 /* 297 * NOTE: We have to be careful not to overwrite PHY parent 298 * clock selection bit and clock divider. 299 */ 300 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 301 (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 302 pll_cfg1_init); 303 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 304 (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK, 305 pll_cfg2_init); 306 usleep_range(10000, 15000); 307 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG, 308 SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2); 309 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 310 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN, 311 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN); 312 msleep(100); 313 314 /* get B value */ 315 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val); 316 val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >> 317 SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT; 318 val = min(val + b_offset, (u32)0x3f); 319 320 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 321 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 | 322 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD, 323 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 | 324 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD); 325 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 326 SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK, 327 val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT); 328 msleep(100); 329 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end); 330 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init); 331 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init); 332 333 return 0; 334} 335 336static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, 337 const struct drm_display_info *display, 338 const struct drm_display_mode *mode) 339{ 340 struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; 341 u32 val = 0; 342 343 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 344 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC; 345 346 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 347 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC; 348 349 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 350 SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val); 351 352 if (phy->variant->has_phy_clk) 353 clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000); 354 355 return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000); 356}; 357 358static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi, 359 struct sun8i_hdmi_phy *phy) 360{ 361 dw_hdmi_phy_gen2_txpwron(hdmi, 0); 362 dw_hdmi_phy_gen2_pddq(hdmi, 1); 363 364 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 365 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0); 366} 367 368static void sun8i_hdmi_phy_disable_h3(struct dw_hdmi *hdmi, 369 struct sun8i_hdmi_phy *phy) 370{ 371 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 372 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN | 373 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS | 374 SUN8I_HDMI_PHY_ANA_CFG1_ENBI); 375 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0); 376} 377 378static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) 379{ 380 struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; 381 382 phy->variant->phy_disable(hdmi, phy); 383} 384 385static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = { 386 .init = &sun8i_hdmi_phy_config, 387 .disable = &sun8i_hdmi_phy_disable, 388 .read_hpd = &dw_hdmi_phy_read_hpd, 389 .update_hpd = &dw_hdmi_phy_update_hpd, 390 .setup_hpd = &dw_hdmi_phy_setup_hpd, 391}; 392 393static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy) 394{ 395 /* enable read access to HDMI controller */ 396 regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG, 397 SUN8I_HDMI_PHY_READ_EN_MAGIC); 398 399 /* unscramble register offsets */ 400 regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG, 401 SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC); 402} 403 404static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy) 405{ 406 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 407 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 408 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN); 409 410 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 411 0xffff0000, 0x80c00000); 412} 413 414static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) 415{ 416 sun8i_hdmi_phy_unlock(phy); 417 418 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 419 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK, 420 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK); 421 422 /* 423 * Set PHY I2C address. It must match to the address set by 424 * dw_hdmi_phy_set_slave_addr(). 425 */ 426 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 427 SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK, 428 SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR)); 429} 430 431static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy) 432{ 433 unsigned int val; 434 435 sun8i_hdmi_phy_unlock(phy); 436 437 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0); 438 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 439 SUN8I_HDMI_PHY_ANA_CFG1_ENBI, 440 SUN8I_HDMI_PHY_ANA_CFG1_ENBI); 441 udelay(5); 442 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 443 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN, 444 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN); 445 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 446 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS, 447 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS); 448 usleep_range(10, 20); 449 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 450 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN, 451 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN); 452 udelay(5); 453 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 454 SUN8I_HDMI_PHY_ANA_CFG1_CKEN, 455 SUN8I_HDMI_PHY_ANA_CFG1_CKEN); 456 usleep_range(40, 100); 457 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 458 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL, 459 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL); 460 usleep_range(100, 200); 461 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 462 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG, 463 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG); 464 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 465 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | 466 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | 467 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2, 468 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | 469 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | 470 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2); 471 472 /* wait for calibration to finish */ 473 regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val, 474 (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D), 475 100, 2000); 476 477 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 478 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK, 479 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK); 480 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 481 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | 482 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | 483 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | 484 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK, 485 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | 486 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | 487 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | 488 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK); 489 490 /* enable DDC communication */ 491 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, 492 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | 493 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN, 494 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | 495 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN); 496 497 /* reset PHY PLL clock parent */ 498 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 499 SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0); 500 501 /* set HW control of CEC pins */ 502 regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0); 503 504 /* read calibration data */ 505 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val); 506 phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2; 507} 508 509int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) 510{ 511 int ret; 512 513 ret = reset_control_deassert(phy->rst_phy); 514 if (ret) { 515 dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret); 516 return ret; 517 } 518 519 ret = clk_prepare_enable(phy->clk_bus); 520 if (ret) { 521 dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret); 522 goto err_assert_rst_phy; 523 } 524 525 ret = clk_prepare_enable(phy->clk_mod); 526 if (ret) { 527 dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret); 528 goto err_disable_clk_bus; 529 } 530 531 if (phy->variant->has_phy_clk) { 532 ret = sun8i_phy_clk_create(phy, phy->dev, 533 phy->variant->has_second_pll); 534 if (ret) { 535 dev_err(phy->dev, "Couldn't create the PHY clock\n"); 536 goto err_disable_clk_mod; 537 } 538 539 clk_prepare_enable(phy->clk_phy); 540 } 541 542 phy->variant->phy_init(phy); 543 544 return 0; 545 546err_disable_clk_mod: 547 clk_disable_unprepare(phy->clk_mod); 548err_disable_clk_bus: 549 clk_disable_unprepare(phy->clk_bus); 550err_assert_rst_phy: 551 reset_control_assert(phy->rst_phy); 552 553 return ret; 554} 555 556void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy) 557{ 558 clk_disable_unprepare(phy->clk_mod); 559 clk_disable_unprepare(phy->clk_bus); 560 clk_disable_unprepare(phy->clk_phy); 561 562 reset_control_assert(phy->rst_phy); 563} 564 565void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, 566 struct dw_hdmi_plat_data *plat_data) 567{ 568 struct sun8i_hdmi_phy_variant *variant = phy->variant; 569 570 if (variant->is_custom_phy) { 571 plat_data->phy_ops = &sun8i_hdmi_phy_ops; 572 plat_data->phy_name = "sun8i_dw_hdmi_phy"; 573 plat_data->phy_data = phy; 574 } else { 575 plat_data->mpll_cfg = variant->mpll_cfg; 576 plat_data->cur_ctr = variant->cur_ctr; 577 plat_data->phy_config = variant->phy_cfg; 578 } 579} 580 581static const struct regmap_config sun8i_hdmi_phy_regmap_config = { 582 .reg_bits = 32, 583 .val_bits = 32, 584 .reg_stride = 4, 585 .max_register = SUN8I_HDMI_PHY_CEC_REG, 586 .name = "phy" 587}; 588 589static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { 590 .is_custom_phy = true, 591 .phy_init = &sun8i_hdmi_phy_init_a83t, 592 .phy_disable = &sun8i_hdmi_phy_disable_a83t, 593 .phy_config = &sun8i_hdmi_phy_config_a83t, 594}; 595 596static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { 597 .has_phy_clk = true, 598 .is_custom_phy = true, 599 .phy_init = &sun8i_hdmi_phy_init_h3, 600 .phy_disable = &sun8i_hdmi_phy_disable_h3, 601 .phy_config = &sun8i_hdmi_phy_config_h3, 602}; 603 604static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = { 605 .has_phy_clk = true, 606 .has_second_pll = true, 607 .is_custom_phy = true, 608 .phy_init = &sun8i_hdmi_phy_init_h3, 609 .phy_disable = &sun8i_hdmi_phy_disable_h3, 610 .phy_config = &sun8i_hdmi_phy_config_h3, 611}; 612 613static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = { 614 .has_phy_clk = true, 615 .is_custom_phy = true, 616 .phy_init = &sun8i_hdmi_phy_init_h3, 617 .phy_disable = &sun8i_hdmi_phy_disable_h3, 618 .phy_config = &sun8i_hdmi_phy_config_h3, 619}; 620 621static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = { 622 .cur_ctr = sun50i_h6_cur_ctr, 623 .mpll_cfg = sun50i_h6_mpll_cfg, 624 .phy_cfg = sun50i_h6_phy_config, 625 .phy_init = &sun50i_hdmi_phy_init_h6, 626}; 627 628static const struct of_device_id sun8i_hdmi_phy_of_table[] = { 629 { 630 .compatible = "allwinner,sun8i-a83t-hdmi-phy", 631 .data = &sun8i_a83t_hdmi_phy, 632 }, 633 { 634 .compatible = "allwinner,sun8i-h3-hdmi-phy", 635 .data = &sun8i_h3_hdmi_phy, 636 }, 637 { 638 .compatible = "allwinner,sun8i-r40-hdmi-phy", 639 .data = &sun8i_r40_hdmi_phy, 640 }, 641 { 642 .compatible = "allwinner,sun50i-a64-hdmi-phy", 643 .data = &sun50i_a64_hdmi_phy, 644 }, 645 { 646 .compatible = "allwinner,sun50i-h6-hdmi-phy", 647 .data = &sun50i_h6_hdmi_phy, 648 }, 649 { /* sentinel */ } 650}; 651 652int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node) 653{ 654 struct platform_device *pdev = of_find_device_by_node(node); 655 struct sun8i_hdmi_phy *phy; 656 657 if (!pdev) 658 return -EPROBE_DEFER; 659 660 phy = platform_get_drvdata(pdev); 661 if (!phy) { 662 put_device(&pdev->dev); 663 return -EPROBE_DEFER; 664 } 665 666 hdmi->phy = phy; 667 668 put_device(&pdev->dev); 669 670 return 0; 671} 672 673static int sun8i_hdmi_phy_probe(struct platform_device *pdev) 674{ 675 const struct of_device_id *match; 676 struct device *dev = &pdev->dev; 677 struct device_node *node = dev->of_node; 678 struct sun8i_hdmi_phy *phy; 679 struct resource res; 680 void __iomem *regs; 681 int ret; 682 683 match = of_match_node(sun8i_hdmi_phy_of_table, node); 684 if (!match) { 685 dev_err(dev, "Incompatible HDMI PHY\n"); 686 return -EINVAL; 687 } 688 689 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 690 if (!phy) 691 return -ENOMEM; 692 693 phy->variant = (struct sun8i_hdmi_phy_variant *)match->data; 694 phy->dev = dev; 695 696 ret = of_address_to_resource(node, 0, &res); 697 if (ret) { 698 dev_err(dev, "phy: Couldn't get our resources\n"); 699 return ret; 700 } 701 702 regs = devm_ioremap_resource(dev, &res); 703 if (IS_ERR(regs)) { 704 dev_err(dev, "Couldn't map the HDMI PHY registers\n"); 705 return PTR_ERR(regs); 706 } 707 708 phy->regs = devm_regmap_init_mmio(dev, regs, 709 &sun8i_hdmi_phy_regmap_config); 710 if (IS_ERR(phy->regs)) { 711 dev_err(dev, "Couldn't create the HDMI PHY regmap\n"); 712 return PTR_ERR(phy->regs); 713 } 714 715 phy->clk_bus = of_clk_get_by_name(node, "bus"); 716 if (IS_ERR(phy->clk_bus)) { 717 dev_err(dev, "Could not get bus clock\n"); 718 return PTR_ERR(phy->clk_bus); 719 } 720 721 phy->clk_mod = of_clk_get_by_name(node, "mod"); 722 if (IS_ERR(phy->clk_mod)) { 723 dev_err(dev, "Could not get mod clock\n"); 724 ret = PTR_ERR(phy->clk_mod); 725 goto err_put_clk_bus; 726 } 727 728 if (phy->variant->has_phy_clk) { 729 phy->clk_pll0 = of_clk_get_by_name(node, "pll-0"); 730 if (IS_ERR(phy->clk_pll0)) { 731 dev_err(dev, "Could not get pll-0 clock\n"); 732 ret = PTR_ERR(phy->clk_pll0); 733 goto err_put_clk_mod; 734 } 735 736 if (phy->variant->has_second_pll) { 737 phy->clk_pll1 = of_clk_get_by_name(node, "pll-1"); 738 if (IS_ERR(phy->clk_pll1)) { 739 dev_err(dev, "Could not get pll-1 clock\n"); 740 ret = PTR_ERR(phy->clk_pll1); 741 goto err_put_clk_pll0; 742 } 743 } 744 } 745 746 phy->rst_phy = of_reset_control_get_shared(node, "phy"); 747 if (IS_ERR(phy->rst_phy)) { 748 dev_err(dev, "Could not get phy reset control\n"); 749 ret = PTR_ERR(phy->rst_phy); 750 goto err_put_clk_pll1; 751 } 752 753 platform_set_drvdata(pdev, phy); 754 755 return 0; 756 757err_put_clk_pll1: 758 clk_put(phy->clk_pll1); 759err_put_clk_pll0: 760 clk_put(phy->clk_pll0); 761err_put_clk_mod: 762 clk_put(phy->clk_mod); 763err_put_clk_bus: 764 clk_put(phy->clk_bus); 765 766 return ret; 767} 768 769static int sun8i_hdmi_phy_remove(struct platform_device *pdev) 770{ 771 struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev); 772 773 reset_control_put(phy->rst_phy); 774 775 clk_put(phy->clk_pll0); 776 clk_put(phy->clk_pll1); 777 clk_put(phy->clk_mod); 778 clk_put(phy->clk_bus); 779 return 0; 780} 781 782struct platform_driver sun8i_hdmi_phy_driver = { 783 .probe = sun8i_hdmi_phy_probe, 784 .remove = sun8i_hdmi_phy_remove, 785 .driver = { 786 .name = "sun8i-hdmi-phy", 787 .of_match_table = sun8i_hdmi_phy_of_table, 788 }, 789};