0001
0002
0003
0004
0005
0006 #include <linux/delay.h>
0007 #include <linux/of_address.h>
0008 #include <linux/of_platform.h>
0009
0010 #include "sun8i_dw_hdmi.h"
0011
0012
0013
0014
0015
0016 #define I2C_ADDR 0x69
0017
0018 static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
0019 {
0020 30666000, {
0021 { 0x00b3, 0x0000 },
0022 { 0x2153, 0x0000 },
0023 { 0x40f3, 0x0000 },
0024 },
0025 }, {
0026 36800000, {
0027 { 0x00b3, 0x0000 },
0028 { 0x2153, 0x0000 },
0029 { 0x40a2, 0x0001 },
0030 },
0031 }, {
0032 46000000, {
0033 { 0x00b3, 0x0000 },
0034 { 0x2142, 0x0001 },
0035 { 0x40a2, 0x0001 },
0036 },
0037 }, {
0038 61333000, {
0039 { 0x0072, 0x0001 },
0040 { 0x2142, 0x0001 },
0041 { 0x40a2, 0x0001 },
0042 },
0043 }, {
0044 73600000, {
0045 { 0x0072, 0x0001 },
0046 { 0x2142, 0x0001 },
0047 { 0x4061, 0x0002 },
0048 },
0049 }, {
0050 92000000, {
0051 { 0x0072, 0x0001 },
0052 { 0x2145, 0x0002 },
0053 { 0x4061, 0x0002 },
0054 },
0055 }, {
0056 122666000, {
0057 { 0x0051, 0x0002 },
0058 { 0x2145, 0x0002 },
0059 { 0x4061, 0x0002 },
0060 },
0061 }, {
0062 147200000, {
0063 { 0x0051, 0x0002 },
0064 { 0x2145, 0x0002 },
0065 { 0x4064, 0x0003 },
0066 },
0067 }, {
0068 184000000, {
0069 { 0x0051, 0x0002 },
0070 { 0x214c, 0x0003 },
0071 { 0x4064, 0x0003 },
0072 },
0073 }, {
0074 226666000, {
0075 { 0x0040, 0x0003 },
0076 { 0x214c, 0x0003 },
0077 { 0x4064, 0x0003 },
0078 },
0079 }, {
0080 272000000, {
0081 { 0x0040, 0x0003 },
0082 { 0x214c, 0x0003 },
0083 { 0x5a64, 0x0003 },
0084 },
0085 }, {
0086 340000000, {
0087 { 0x0040, 0x0003 },
0088 { 0x3b4c, 0x0003 },
0089 { 0x5a64, 0x0003 },
0090 },
0091 }, {
0092 594000000, {
0093 { 0x1a40, 0x0003 },
0094 { 0x3b4c, 0x0003 },
0095 { 0x5a64, 0x0003 },
0096 },
0097 }, {
0098 ~0UL, {
0099 { 0x0000, 0x0000 },
0100 { 0x0000, 0x0000 },
0101 { 0x0000, 0x0000 },
0102 },
0103 }
0104 };
0105
0106 static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = {
0107
0108 { 27000000, { 0x0012, 0x0000, 0x0000 }, },
0109 { 74250000, { 0x0013, 0x001a, 0x001b }, },
0110 { 148500000, { 0x0019, 0x0033, 0x0034 }, },
0111 { 297000000, { 0x0019, 0x001b, 0x001b }, },
0112 { 594000000, { 0x0010, 0x001b, 0x001b }, },
0113 { ~0UL, { 0x0000, 0x0000, 0x0000 }, }
0114 };
0115
0116 static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
0117
0118 { 27000000, 0x8009, 0x0007, 0x02b0 },
0119 { 74250000, 0x8009, 0x0006, 0x022d },
0120 { 148500000, 0x8029, 0x0006, 0x0270 },
0121 { 297000000, 0x8039, 0x0005, 0x01ab },
0122 { 594000000, 0x8029, 0x0000, 0x008a },
0123 { ~0UL, 0x0000, 0x0000, 0x0000}
0124 };
0125
0126 static void sun8i_hdmi_phy_set_polarity(struct sun8i_hdmi_phy *phy,
0127 const struct drm_display_mode *mode)
0128 {
0129 u32 val = 0;
0130
0131 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
0132 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;
0133
0134 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
0135 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;
0136
0137 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
0138 SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);
0139 };
0140
0141 static int sun8i_a83t_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
0142 const struct drm_display_info *display,
0143 const struct drm_display_mode *mode)
0144 {
0145 unsigned int clk_rate = mode->crtc_clock * 1000;
0146 struct sun8i_hdmi_phy *phy = data;
0147
0148 sun8i_hdmi_phy_set_polarity(phy, mode);
0149
0150 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
0151 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
0152 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
0153
0154
0155 dw_hdmi_phy_gen2_txpwron(hdmi, 0);
0156 dw_hdmi_phy_gen2_pddq(hdmi, 1);
0157
0158 dw_hdmi_phy_gen2_reset(hdmi);
0159
0160 dw_hdmi_phy_gen2_pddq(hdmi, 0);
0161
0162 dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
0163
0164
0165
0166
0167
0168
0169 if (clk_rate <= 27000000) {
0170 dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
0171 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
0172 dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
0173 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
0174 dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
0175 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
0176 } else if (clk_rate <= 74250000) {
0177 dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
0178 dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
0179 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
0180 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
0181 dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
0182 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
0183 } else if (clk_rate <= 148500000) {
0184 dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
0185 dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
0186 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
0187 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
0188 dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
0189 dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
0190 } else {
0191 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
0192 dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
0193 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
0194 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
0195 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
0196 dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
0197 }
0198
0199 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
0200 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
0201 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
0202
0203 dw_hdmi_phy_gen2_txpwron(hdmi, 1);
0204
0205 return 0;
0206 }
0207
0208 static void sun8i_a83t_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
0209 {
0210 struct sun8i_hdmi_phy *phy = data;
0211
0212 dw_hdmi_phy_gen2_txpwron(hdmi, 0);
0213 dw_hdmi_phy_gen2_pddq(hdmi, 1);
0214
0215 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
0216 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
0217 }
0218
0219 static const struct dw_hdmi_phy_ops sun8i_a83t_hdmi_phy_ops = {
0220 .init = sun8i_a83t_hdmi_phy_config,
0221 .disable = sun8i_a83t_hdmi_phy_disable,
0222 .read_hpd = dw_hdmi_phy_read_hpd,
0223 .update_hpd = dw_hdmi_phy_update_hpd,
0224 .setup_hpd = dw_hdmi_phy_setup_hpd,
0225 };
0226
0227 static int sun8i_h3_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
0228 const struct drm_display_info *display,
0229 const struct drm_display_mode *mode)
0230 {
0231 unsigned int clk_rate = mode->crtc_clock * 1000;
0232 struct sun8i_hdmi_phy *phy = data;
0233 u32 pll_cfg1_init;
0234 u32 pll_cfg2_init;
0235 u32 ana_cfg1_end;
0236 u32 ana_cfg2_init;
0237 u32 ana_cfg3_init;
0238 u32 b_offset = 0;
0239 u32 val;
0240
0241 if (phy->variant->has_phy_clk)
0242 clk_set_rate(phy->clk_phy, clk_rate);
0243
0244 sun8i_hdmi_phy_set_polarity(phy, mode);
0245
0246
0247
0248 pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
0249 SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
0250 SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
0251 SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
0252 SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
0253 SUN8I_HDMI_PHY_PLL_CFG1_CS |
0254 SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
0255 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
0256 SUN8I_HDMI_PHY_PLL_CFG1_BWS;
0257
0258 pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
0259 SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
0260 SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
0261
0262 ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
0263 SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
0264 SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
0265 SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
0266 SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
0267 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
0268 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
0269 SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
0270 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
0271 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK |
0272 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
0273 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
0274 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
0275 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
0276 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
0277 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
0278 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
0279 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
0280 SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
0281 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
0282 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
0283 SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
0284
0285 ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
0286 SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
0287 SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
0288 SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
0289 SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
0290
0291 ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
0292 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
0293 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
0294
0295
0296 if (clk_rate <= 27000000) {
0297 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
0298 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
0299 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
0300 SUN8I_HDMI_PHY_PLL_CFG2_S(4);
0301 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
0302 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
0303 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
0304 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
0305 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
0306 } else if (clk_rate <= 74250000) {
0307 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
0308 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
0309 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
0310 SUN8I_HDMI_PHY_PLL_CFG2_S(5);
0311 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
0312 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
0313 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
0314 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
0315 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
0316 } else if (clk_rate <= 148500000) {
0317 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
0318 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
0319 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
0320 SUN8I_HDMI_PHY_PLL_CFG2_S(6);
0321 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
0322 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
0323 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
0324 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
0325 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
0326 } else {
0327 b_offset = 2;
0328 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
0329 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
0330 SUN8I_HDMI_PHY_PLL_CFG2_S(7);
0331 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
0332 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
0333 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
0334 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
0335 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) |
0336 SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3);
0337 }
0338
0339 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0340 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
0341
0342
0343
0344
0345
0346 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
0347 (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
0348 pll_cfg1_init);
0349 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
0350 (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
0351 pll_cfg2_init);
0352 usleep_range(10000, 15000);
0353 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG,
0354 SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2);
0355 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
0356 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN,
0357 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
0358 msleep(100);
0359
0360
0361 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
0362 val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >>
0363 SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
0364 val = min(val + b_offset, (u32)0x3f);
0365
0366 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
0367 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
0368 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD,
0369 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
0370 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
0371 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
0372 SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK,
0373 val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT);
0374 msleep(100);
0375 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end);
0376 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init);
0377 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init);
0378
0379 return 0;
0380 }
0381
0382 static void sun8i_h3_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
0383 {
0384 struct sun8i_hdmi_phy *phy = data;
0385
0386 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0387 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
0388 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
0389 SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
0390 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
0391 }
0392
0393 static const struct dw_hdmi_phy_ops sun8i_h3_hdmi_phy_ops = {
0394 .init = sun8i_h3_hdmi_phy_config,
0395 .disable = sun8i_h3_hdmi_phy_disable,
0396 .read_hpd = dw_hdmi_phy_read_hpd,
0397 .update_hpd = dw_hdmi_phy_update_hpd,
0398 .setup_hpd = dw_hdmi_phy_setup_hpd,
0399 };
0400
0401 static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy)
0402 {
0403
0404 regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
0405 SUN8I_HDMI_PHY_READ_EN_MAGIC);
0406
0407
0408 regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
0409 SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
0410 }
0411
0412 static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy)
0413 {
0414 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
0415 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
0416 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
0417
0418 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
0419 0xffff0000, 0x80c00000);
0420 }
0421
0422 static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
0423 {
0424 sun8i_hdmi_phy_unlock(phy);
0425
0426 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
0427 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
0428 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
0429
0430
0431
0432
0433
0434 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
0435 SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK,
0436 SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
0437 }
0438
0439 static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
0440 {
0441 unsigned int val;
0442
0443 sun8i_hdmi_phy_unlock(phy);
0444
0445 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
0446 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0447 SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
0448 SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
0449 udelay(5);
0450 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0451 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN,
0452 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
0453 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0454 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS,
0455 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
0456 usleep_range(10, 20);
0457 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0458 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN,
0459 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
0460 udelay(5);
0461 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0462 SUN8I_HDMI_PHY_ANA_CFG1_CKEN,
0463 SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
0464 usleep_range(40, 100);
0465 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0466 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL,
0467 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
0468 usleep_range(100, 200);
0469 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0470 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG,
0471 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
0472 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0473 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
0474 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
0475 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2,
0476 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
0477 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
0478 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
0479
0480
0481 regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val,
0482 (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D),
0483 100, 2000);
0484
0485 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0486 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK,
0487 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
0488 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
0489 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
0490 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
0491 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
0492 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK,
0493 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
0494 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
0495 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
0496 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK);
0497
0498
0499 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG,
0500 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
0501 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN,
0502 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
0503 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
0504
0505
0506 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
0507 SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0);
0508
0509
0510 regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0);
0511
0512
0513 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
0514 phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
0515 }
0516
0517 int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
0518 {
0519 int ret;
0520
0521 ret = reset_control_deassert(phy->rst_phy);
0522 if (ret) {
0523 dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret);
0524 return ret;
0525 }
0526
0527 ret = clk_prepare_enable(phy->clk_bus);
0528 if (ret) {
0529 dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret);
0530 goto err_assert_rst_phy;
0531 }
0532
0533 ret = clk_prepare_enable(phy->clk_mod);
0534 if (ret) {
0535 dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret);
0536 goto err_disable_clk_bus;
0537 }
0538
0539 if (phy->variant->has_phy_clk) {
0540 ret = sun8i_phy_clk_create(phy, phy->dev,
0541 phy->variant->has_second_pll);
0542 if (ret) {
0543 dev_err(phy->dev, "Couldn't create the PHY clock\n");
0544 goto err_disable_clk_mod;
0545 }
0546
0547 clk_prepare_enable(phy->clk_phy);
0548 }
0549
0550 phy->variant->phy_init(phy);
0551
0552 return 0;
0553
0554 err_disable_clk_mod:
0555 clk_disable_unprepare(phy->clk_mod);
0556 err_disable_clk_bus:
0557 clk_disable_unprepare(phy->clk_bus);
0558 err_assert_rst_phy:
0559 reset_control_assert(phy->rst_phy);
0560
0561 return ret;
0562 }
0563
0564 void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy)
0565 {
0566 clk_disable_unprepare(phy->clk_mod);
0567 clk_disable_unprepare(phy->clk_bus);
0568 clk_disable_unprepare(phy->clk_phy);
0569
0570 reset_control_assert(phy->rst_phy);
0571 }
0572
0573 void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
0574 struct dw_hdmi_plat_data *plat_data)
0575 {
0576 const struct sun8i_hdmi_phy_variant *variant = phy->variant;
0577
0578 if (variant->phy_ops) {
0579 plat_data->phy_ops = variant->phy_ops;
0580 plat_data->phy_name = "sun8i_dw_hdmi_phy";
0581 plat_data->phy_data = phy;
0582 } else {
0583 plat_data->mpll_cfg = variant->mpll_cfg;
0584 plat_data->cur_ctr = variant->cur_ctr;
0585 plat_data->phy_config = variant->phy_cfg;
0586 }
0587 }
0588
0589 static const struct regmap_config sun8i_hdmi_phy_regmap_config = {
0590 .reg_bits = 32,
0591 .val_bits = 32,
0592 .reg_stride = 4,
0593 .max_register = SUN8I_HDMI_PHY_CEC_REG,
0594 .name = "phy"
0595 };
0596
0597 static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
0598 .phy_ops = &sun8i_a83t_hdmi_phy_ops,
0599 .phy_init = &sun8i_hdmi_phy_init_a83t,
0600 };
0601
0602 static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
0603 .has_phy_clk = true,
0604 .phy_ops = &sun8i_h3_hdmi_phy_ops,
0605 .phy_init = &sun8i_hdmi_phy_init_h3,
0606 };
0607
0608 static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
0609 .has_phy_clk = true,
0610 .has_second_pll = true,
0611 .phy_ops = &sun8i_h3_hdmi_phy_ops,
0612 .phy_init = &sun8i_hdmi_phy_init_h3,
0613 };
0614
0615 static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
0616 .has_phy_clk = true,
0617 .phy_ops = &sun8i_h3_hdmi_phy_ops,
0618 .phy_init = &sun8i_hdmi_phy_init_h3,
0619 };
0620
0621 static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
0622 .cur_ctr = sun50i_h6_cur_ctr,
0623 .mpll_cfg = sun50i_h6_mpll_cfg,
0624 .phy_cfg = sun50i_h6_phy_config,
0625 .phy_init = &sun50i_hdmi_phy_init_h6,
0626 };
0627
0628 static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
0629 {
0630 .compatible = "allwinner,sun8i-a83t-hdmi-phy",
0631 .data = &sun8i_a83t_hdmi_phy,
0632 },
0633 {
0634 .compatible = "allwinner,sun8i-h3-hdmi-phy",
0635 .data = &sun8i_h3_hdmi_phy,
0636 },
0637 {
0638 .compatible = "allwinner,sun8i-r40-hdmi-phy",
0639 .data = &sun8i_r40_hdmi_phy,
0640 },
0641 {
0642 .compatible = "allwinner,sun50i-a64-hdmi-phy",
0643 .data = &sun50i_a64_hdmi_phy,
0644 },
0645 {
0646 .compatible = "allwinner,sun50i-h6-hdmi-phy",
0647 .data = &sun50i_h6_hdmi_phy,
0648 },
0649 { }
0650 };
0651
0652 int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
0653 {
0654 struct platform_device *pdev = of_find_device_by_node(node);
0655 struct sun8i_hdmi_phy *phy;
0656
0657 if (!pdev)
0658 return -EPROBE_DEFER;
0659
0660 phy = platform_get_drvdata(pdev);
0661 if (!phy) {
0662 put_device(&pdev->dev);
0663 return -EPROBE_DEFER;
0664 }
0665
0666 hdmi->phy = phy;
0667
0668 put_device(&pdev->dev);
0669
0670 return 0;
0671 }
0672
0673 static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
0674 {
0675 struct device *dev = &pdev->dev;
0676 struct sun8i_hdmi_phy *phy;
0677 void __iomem *regs;
0678
0679 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
0680 if (!phy)
0681 return -ENOMEM;
0682
0683 phy->variant = of_device_get_match_data(dev);
0684 phy->dev = dev;
0685
0686 regs = devm_platform_ioremap_resource(pdev, 0);
0687 if (IS_ERR(regs))
0688 return dev_err_probe(dev, PTR_ERR(regs),
0689 "Couldn't map the HDMI PHY registers\n");
0690
0691 phy->regs = devm_regmap_init_mmio(dev, regs,
0692 &sun8i_hdmi_phy_regmap_config);
0693 if (IS_ERR(phy->regs))
0694 return dev_err_probe(dev, PTR_ERR(phy->regs),
0695 "Couldn't create the HDMI PHY regmap\n");
0696
0697 phy->clk_bus = devm_clk_get(dev, "bus");
0698 if (IS_ERR(phy->clk_bus))
0699 return dev_err_probe(dev, PTR_ERR(phy->clk_bus),
0700 "Could not get bus clock\n");
0701
0702 phy->clk_mod = devm_clk_get(dev, "mod");
0703 if (IS_ERR(phy->clk_mod))
0704 return dev_err_probe(dev, PTR_ERR(phy->clk_mod),
0705 "Could not get mod clock\n");
0706
0707 if (phy->variant->has_phy_clk) {
0708 phy->clk_pll0 = devm_clk_get(dev, "pll-0");
0709 if (IS_ERR(phy->clk_pll0))
0710 return dev_err_probe(dev, PTR_ERR(phy->clk_pll0),
0711 "Could not get pll-0 clock\n");
0712
0713 if (phy->variant->has_second_pll) {
0714 phy->clk_pll1 = devm_clk_get(dev, "pll-1");
0715 if (IS_ERR(phy->clk_pll1))
0716 return dev_err_probe(dev, PTR_ERR(phy->clk_pll1),
0717 "Could not get pll-1 clock\n");
0718 }
0719 }
0720
0721 phy->rst_phy = devm_reset_control_get_shared(dev, "phy");
0722 if (IS_ERR(phy->rst_phy))
0723 return dev_err_probe(dev, PTR_ERR(phy->rst_phy),
0724 "Could not get phy reset control\n");
0725
0726 platform_set_drvdata(pdev, phy);
0727
0728 return 0;
0729 }
0730
0731 struct platform_driver sun8i_hdmi_phy_driver = {
0732 .probe = sun8i_hdmi_phy_probe,
0733 .driver = {
0734 .name = "sun8i-hdmi-phy",
0735 .of_match_table = sun8i_hdmi_phy_of_table,
0736 },
0737 };