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 18 static 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 106 static 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 116 static 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 126 static void sun8i_hdmi_phy_set_polarity(struct sun8i_hdmi_phy *phy, 127 const struct drm_display_mode *mode) 128 { 129 u32 val = 0; 130 131 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 132 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC; 133 134 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 135 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC; 136 137 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 138 SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val); 139 }; 140 141 static int sun8i_a83t_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, 142 const struct drm_display_info *display, 143 const struct drm_display_mode *mode) 144 { 145 unsigned int clk_rate = mode->crtc_clock * 1000; 146 struct sun8i_hdmi_phy *phy = data; 147 148 sun8i_hdmi_phy_set_polarity(phy, mode); 149 150 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 151 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 152 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN); 153 154 /* power down */ 155 dw_hdmi_phy_gen2_txpwron(hdmi, 0); 156 dw_hdmi_phy_gen2_pddq(hdmi, 1); 157 158 dw_hdmi_phy_gen2_reset(hdmi); 159 160 dw_hdmi_phy_gen2_pddq(hdmi, 0); 161 162 dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR); 163 164 /* 165 * Values are taken from BSP HDMI driver. Although AW didn't 166 * release any documentation, explanation of this values can 167 * be found in i.MX 6Dual/6Quad Reference Manual. 168 */ 169 if (clk_rate <= 27000000) { 170 dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06); 171 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); 172 dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10); 173 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19); 174 dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e); 175 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); 176 } else if (clk_rate <= 74250000) { 177 dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06); 178 dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); 179 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); 180 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19); 181 dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e); 182 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); 183 } else if (clk_rate <= 148500000) { 184 dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06); 185 dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); 186 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); 187 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19); 188 dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e); 189 dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09); 190 } else { 191 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06); 192 dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); 193 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); 194 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19); 195 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e); 196 dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09); 197 } 198 199 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e); 200 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); 201 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17); 202 203 dw_hdmi_phy_gen2_txpwron(hdmi, 1); 204 205 return 0; 206 } 207 208 static void sun8i_a83t_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) 209 { 210 struct sun8i_hdmi_phy *phy = data; 211 212 dw_hdmi_phy_gen2_txpwron(hdmi, 0); 213 dw_hdmi_phy_gen2_pddq(hdmi, 1); 214 215 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 216 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0); 217 } 218 219 static const struct dw_hdmi_phy_ops sun8i_a83t_hdmi_phy_ops = { 220 .init = sun8i_a83t_hdmi_phy_config, 221 .disable = sun8i_a83t_hdmi_phy_disable, 222 .read_hpd = dw_hdmi_phy_read_hpd, 223 .update_hpd = dw_hdmi_phy_update_hpd, 224 .setup_hpd = dw_hdmi_phy_setup_hpd, 225 }; 226 227 static int sun8i_h3_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, 228 const struct drm_display_info *display, 229 const struct drm_display_mode *mode) 230 { 231 unsigned int clk_rate = mode->crtc_clock * 1000; 232 struct sun8i_hdmi_phy *phy = data; 233 u32 pll_cfg1_init; 234 u32 pll_cfg2_init; 235 u32 ana_cfg1_end; 236 u32 ana_cfg2_init; 237 u32 ana_cfg3_init; 238 u32 b_offset = 0; 239 u32 val; 240 241 if (phy->variant->has_phy_clk) 242 clk_set_rate(phy->clk_phy, clk_rate); 243 244 sun8i_hdmi_phy_set_polarity(phy, mode); 245 246 /* bandwidth / frequency independent settings */ 247 248 pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN | 249 SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN | 250 SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) | 251 SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) | 252 SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN | 253 SUN8I_HDMI_PHY_PLL_CFG1_CS | 254 SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) | 255 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) | 256 SUN8I_HDMI_PHY_PLL_CFG1_BWS; 257 258 pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H | 259 SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN | 260 SUN8I_HDMI_PHY_PLL_CFG2_SDIV2; 261 262 ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) | 263 SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT | 264 SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT | 265 SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT | 266 SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT | 267 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL | 268 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG | 269 SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS | 270 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN | 271 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK | 272 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL | 273 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK | 274 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | 275 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | 276 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | 277 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 | 278 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | 279 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | 280 SUN8I_HDMI_PHY_ANA_CFG1_CKEN | 281 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN | 282 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS | 283 SUN8I_HDMI_PHY_ANA_CFG1_ENBI; 284 285 ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN | 286 SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK | 287 SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN | 288 SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) | 289 SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1); 290 291 ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) | 292 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN | 293 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN; 294 295 /* bandwidth / frequency dependent settings */ 296 if (clk_rate <= 27000000) { 297 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | 298 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); 299 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | 300 SUN8I_HDMI_PHY_PLL_CFG2_S(4); 301 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW; 302 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) | 303 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal); 304 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) | 305 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5); 306 } else if (clk_rate <= 74250000) { 307 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | 308 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); 309 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | 310 SUN8I_HDMI_PHY_PLL_CFG2_S(5); 311 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW; 312 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) | 313 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal); 314 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) | 315 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7); 316 } else if (clk_rate <= 148500000) { 317 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | 318 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); 319 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | 320 SUN8I_HDMI_PHY_PLL_CFG2_S(6); 321 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK | 322 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW | 323 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2); 324 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) | 325 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9); 326 } else { 327 b_offset = 2; 328 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63); 329 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) | 330 SUN8I_HDMI_PHY_PLL_CFG2_S(7); 331 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK | 332 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW | 333 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4); 334 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) | 335 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) | 336 SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3); 337 } 338 339 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 340 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0); 341 342 /* 343 * NOTE: We have to be careful not to overwrite PHY parent 344 * clock selection bit and clock divider. 345 */ 346 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 347 (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 348 pll_cfg1_init); 349 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 350 (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK, 351 pll_cfg2_init); 352 usleep_range(10000, 15000); 353 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG, 354 SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2); 355 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 356 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN, 357 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN); 358 msleep(100); 359 360 /* get B value */ 361 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val); 362 val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >> 363 SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT; 364 val = min(val + b_offset, (u32)0x3f); 365 366 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 367 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 | 368 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD, 369 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 | 370 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD); 371 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 372 SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK, 373 val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT); 374 msleep(100); 375 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end); 376 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init); 377 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init); 378 379 return 0; 380 } 381 382 static void sun8i_h3_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) 383 { 384 struct sun8i_hdmi_phy *phy = data; 385 386 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 387 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN | 388 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS | 389 SUN8I_HDMI_PHY_ANA_CFG1_ENBI); 390 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0); 391 } 392 393 static const struct dw_hdmi_phy_ops sun8i_h3_hdmi_phy_ops = { 394 .init = sun8i_h3_hdmi_phy_config, 395 .disable = sun8i_h3_hdmi_phy_disable, 396 .read_hpd = dw_hdmi_phy_read_hpd, 397 .update_hpd = dw_hdmi_phy_update_hpd, 398 .setup_hpd = dw_hdmi_phy_setup_hpd, 399 }; 400 401 static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy) 402 { 403 /* enable read access to HDMI controller */ 404 regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG, 405 SUN8I_HDMI_PHY_READ_EN_MAGIC); 406 407 /* unscramble register offsets */ 408 regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG, 409 SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC); 410 } 411 412 static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy) 413 { 414 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 415 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 416 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN); 417 418 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, 419 0xffff0000, 0x80c00000); 420 } 421 422 static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) 423 { 424 sun8i_hdmi_phy_unlock(phy); 425 426 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 427 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK, 428 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK); 429 430 /* 431 * Set PHY I2C address. It must match to the address set by 432 * dw_hdmi_phy_set_slave_addr(). 433 */ 434 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 435 SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK, 436 SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR)); 437 } 438 439 static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy) 440 { 441 unsigned int val; 442 443 sun8i_hdmi_phy_unlock(phy); 444 445 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0); 446 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 447 SUN8I_HDMI_PHY_ANA_CFG1_ENBI, 448 SUN8I_HDMI_PHY_ANA_CFG1_ENBI); 449 udelay(5); 450 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 451 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN, 452 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN); 453 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 454 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS, 455 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS); 456 usleep_range(10, 20); 457 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 458 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN, 459 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN); 460 udelay(5); 461 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 462 SUN8I_HDMI_PHY_ANA_CFG1_CKEN, 463 SUN8I_HDMI_PHY_ANA_CFG1_CKEN); 464 usleep_range(40, 100); 465 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 466 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL, 467 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL); 468 usleep_range(100, 200); 469 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 470 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG, 471 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG); 472 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 473 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | 474 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | 475 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2, 476 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | 477 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | 478 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2); 479 480 /* wait for calibration to finish */ 481 regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val, 482 (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D), 483 100, 2000); 484 485 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 486 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK, 487 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK); 488 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 489 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | 490 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | 491 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | 492 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK, 493 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | 494 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | 495 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | 496 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK); 497 498 /* enable DDC communication */ 499 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, 500 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | 501 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN, 502 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | 503 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN); 504 505 /* reset PHY PLL clock parent */ 506 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 507 SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0); 508 509 /* set HW control of CEC pins */ 510 regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0); 511 512 /* read calibration data */ 513 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val); 514 phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2; 515 } 516 517 int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) 518 { 519 int ret; 520 521 ret = reset_control_deassert(phy->rst_phy); 522 if (ret) { 523 dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret); 524 return ret; 525 } 526 527 ret = clk_prepare_enable(phy->clk_bus); 528 if (ret) { 529 dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret); 530 goto err_assert_rst_phy; 531 } 532 533 ret = clk_prepare_enable(phy->clk_mod); 534 if (ret) { 535 dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret); 536 goto err_disable_clk_bus; 537 } 538 539 if (phy->variant->has_phy_clk) { 540 ret = sun8i_phy_clk_create(phy, phy->dev, 541 phy->variant->has_second_pll); 542 if (ret) { 543 dev_err(phy->dev, "Couldn't create the PHY clock\n"); 544 goto err_disable_clk_mod; 545 } 546 547 clk_prepare_enable(phy->clk_phy); 548 } 549 550 phy->variant->phy_init(phy); 551 552 return 0; 553 554 err_disable_clk_mod: 555 clk_disable_unprepare(phy->clk_mod); 556 err_disable_clk_bus: 557 clk_disable_unprepare(phy->clk_bus); 558 err_assert_rst_phy: 559 reset_control_assert(phy->rst_phy); 560 561 return ret; 562 } 563 564 void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy) 565 { 566 clk_disable_unprepare(phy->clk_mod); 567 clk_disable_unprepare(phy->clk_bus); 568 clk_disable_unprepare(phy->clk_phy); 569 570 reset_control_assert(phy->rst_phy); 571 } 572 573 void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, 574 struct dw_hdmi_plat_data *plat_data) 575 { 576 const struct sun8i_hdmi_phy_variant *variant = phy->variant; 577 578 if (variant->phy_ops) { 579 plat_data->phy_ops = variant->phy_ops; 580 plat_data->phy_name = "sun8i_dw_hdmi_phy"; 581 plat_data->phy_data = phy; 582 } else { 583 plat_data->mpll_cfg = variant->mpll_cfg; 584 plat_data->cur_ctr = variant->cur_ctr; 585 plat_data->phy_config = variant->phy_cfg; 586 } 587 } 588 589 static const struct regmap_config sun8i_hdmi_phy_regmap_config = { 590 .reg_bits = 32, 591 .val_bits = 32, 592 .reg_stride = 4, 593 .max_register = SUN8I_HDMI_PHY_CEC_REG, 594 .name = "phy" 595 }; 596 597 static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { 598 .phy_ops = &sun8i_a83t_hdmi_phy_ops, 599 .phy_init = &sun8i_hdmi_phy_init_a83t, 600 }; 601 602 static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { 603 .has_phy_clk = true, 604 .phy_ops = &sun8i_h3_hdmi_phy_ops, 605 .phy_init = &sun8i_hdmi_phy_init_h3, 606 }; 607 608 static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = { 609 .has_phy_clk = true, 610 .has_second_pll = true, 611 .phy_ops = &sun8i_h3_hdmi_phy_ops, 612 .phy_init = &sun8i_hdmi_phy_init_h3, 613 }; 614 615 static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = { 616 .has_phy_clk = true, 617 .phy_ops = &sun8i_h3_hdmi_phy_ops, 618 .phy_init = &sun8i_hdmi_phy_init_h3, 619 }; 620 621 static 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 628 static 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 652 int 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 673 static int sun8i_hdmi_phy_probe(struct platform_device *pdev) 674 { 675 struct device *dev = &pdev->dev; 676 struct sun8i_hdmi_phy *phy; 677 void __iomem *regs; 678 679 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 680 if (!phy) 681 return -ENOMEM; 682 683 phy->variant = of_device_get_match_data(dev); 684 phy->dev = dev; 685 686 regs = devm_platform_ioremap_resource(pdev, 0); 687 if (IS_ERR(regs)) 688 return dev_err_probe(dev, PTR_ERR(regs), 689 "Couldn't map the HDMI PHY registers\n"); 690 691 phy->regs = devm_regmap_init_mmio(dev, regs, 692 &sun8i_hdmi_phy_regmap_config); 693 if (IS_ERR(phy->regs)) 694 return dev_err_probe(dev, PTR_ERR(phy->regs), 695 "Couldn't create the HDMI PHY regmap\n"); 696 697 phy->clk_bus = devm_clk_get(dev, "bus"); 698 if (IS_ERR(phy->clk_bus)) 699 return dev_err_probe(dev, PTR_ERR(phy->clk_bus), 700 "Could not get bus clock\n"); 701 702 phy->clk_mod = devm_clk_get(dev, "mod"); 703 if (IS_ERR(phy->clk_mod)) 704 return dev_err_probe(dev, PTR_ERR(phy->clk_mod), 705 "Could not get mod clock\n"); 706 707 if (phy->variant->has_phy_clk) { 708 phy->clk_pll0 = devm_clk_get(dev, "pll-0"); 709 if (IS_ERR(phy->clk_pll0)) 710 return dev_err_probe(dev, PTR_ERR(phy->clk_pll0), 711 "Could not get pll-0 clock\n"); 712 713 if (phy->variant->has_second_pll) { 714 phy->clk_pll1 = devm_clk_get(dev, "pll-1"); 715 if (IS_ERR(phy->clk_pll1)) 716 return dev_err_probe(dev, PTR_ERR(phy->clk_pll1), 717 "Could not get pll-1 clock\n"); 718 } 719 } 720 721 phy->rst_phy = devm_reset_control_get_shared(dev, "phy"); 722 if (IS_ERR(phy->rst_phy)) 723 return dev_err_probe(dev, PTR_ERR(phy->rst_phy), 724 "Could not get phy reset control\n"); 725 726 platform_set_drvdata(pdev, phy); 727 728 return 0; 729 } 730 731 struct platform_driver sun8i_hdmi_phy_driver = { 732 .probe = sun8i_hdmi_phy_probe, 733 .driver = { 734 .name = "sun8i-hdmi-phy", 735 .of_match_table = sun8i_hdmi_phy_of_table, 736 }, 737 }; 738