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