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