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 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_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 
188 static 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 
336 static 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 
358 static 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 
368 static 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 
378 static 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 
385 static 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 
393 static 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 
404 static 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 
414 static 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 
431 static 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 
509 void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
510 {
511 	phy->variant->phy_init(phy);
512 }
513 
514 void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
515 			    struct dw_hdmi_plat_data *plat_data)
516 {
517 	struct sun8i_hdmi_phy_variant *variant = phy->variant;
518 
519 	if (variant->is_custom_phy) {
520 		plat_data->phy_ops = &sun8i_hdmi_phy_ops;
521 		plat_data->phy_name = "sun8i_dw_hdmi_phy";
522 		plat_data->phy_data = phy;
523 	} else {
524 		plat_data->mpll_cfg = variant->mpll_cfg;
525 		plat_data->cur_ctr = variant->cur_ctr;
526 		plat_data->phy_config = variant->phy_cfg;
527 	}
528 }
529 
530 static const struct regmap_config sun8i_hdmi_phy_regmap_config = {
531 	.reg_bits	= 32,
532 	.val_bits	= 32,
533 	.reg_stride	= 4,
534 	.max_register	= SUN8I_HDMI_PHY_CEC_REG,
535 	.name		= "phy"
536 };
537 
538 static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
539 	.is_custom_phy = true,
540 	.phy_init = &sun8i_hdmi_phy_init_a83t,
541 	.phy_disable = &sun8i_hdmi_phy_disable_a83t,
542 	.phy_config = &sun8i_hdmi_phy_config_a83t,
543 };
544 
545 static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
546 	.has_phy_clk = true,
547 	.is_custom_phy = true,
548 	.phy_init = &sun8i_hdmi_phy_init_h3,
549 	.phy_disable = &sun8i_hdmi_phy_disable_h3,
550 	.phy_config = &sun8i_hdmi_phy_config_h3,
551 };
552 
553 static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
554 	.has_phy_clk = true,
555 	.has_second_pll = true,
556 	.is_custom_phy = true,
557 	.phy_init = &sun8i_hdmi_phy_init_h3,
558 	.phy_disable = &sun8i_hdmi_phy_disable_h3,
559 	.phy_config = &sun8i_hdmi_phy_config_h3,
560 };
561 
562 static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
563 	.has_phy_clk = true,
564 	.is_custom_phy = true,
565 	.phy_init = &sun8i_hdmi_phy_init_h3,
566 	.phy_disable = &sun8i_hdmi_phy_disable_h3,
567 	.phy_config = &sun8i_hdmi_phy_config_h3,
568 };
569 
570 static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
571 	.cur_ctr  = sun50i_h6_cur_ctr,
572 	.mpll_cfg = sun50i_h6_mpll_cfg,
573 	.phy_cfg  = sun50i_h6_phy_config,
574 	.phy_init = &sun50i_hdmi_phy_init_h6,
575 };
576 
577 static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
578 	{
579 		.compatible = "allwinner,sun8i-a83t-hdmi-phy",
580 		.data = &sun8i_a83t_hdmi_phy,
581 	},
582 	{
583 		.compatible = "allwinner,sun8i-h3-hdmi-phy",
584 		.data = &sun8i_h3_hdmi_phy,
585 	},
586 	{
587 		.compatible = "allwinner,sun8i-r40-hdmi-phy",
588 		.data = &sun8i_r40_hdmi_phy,
589 	},
590 	{
591 		.compatible = "allwinner,sun50i-a64-hdmi-phy",
592 		.data = &sun50i_a64_hdmi_phy,
593 	},
594 	{
595 		.compatible = "allwinner,sun50i-h6-hdmi-phy",
596 		.data = &sun50i_h6_hdmi_phy,
597 	},
598 	{ /* sentinel */ }
599 };
600 
601 int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
602 {
603 	struct platform_device *pdev = of_find_device_by_node(node);
604 	struct sun8i_hdmi_phy *phy;
605 
606 	if (!pdev)
607 		return -EPROBE_DEFER;
608 
609 	phy = platform_get_drvdata(pdev);
610 	if (!phy)
611 		return -EPROBE_DEFER;
612 
613 	hdmi->phy = phy;
614 
615 	put_device(&pdev->dev);
616 
617 	return 0;
618 }
619 
620 static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
621 {
622 	const struct of_device_id *match;
623 	struct device *dev = &pdev->dev;
624 	struct device_node *node = dev->of_node;
625 	struct sun8i_hdmi_phy *phy;
626 	struct resource res;
627 	void __iomem *regs;
628 	int ret;
629 
630 	match = of_match_node(sun8i_hdmi_phy_of_table, node);
631 	if (!match) {
632 		dev_err(dev, "Incompatible HDMI PHY\n");
633 		return -EINVAL;
634 	}
635 
636 	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
637 	if (!phy)
638 		return -ENOMEM;
639 
640 	phy->variant = (struct sun8i_hdmi_phy_variant *)match->data;
641 
642 	ret = of_address_to_resource(node, 0, &res);
643 	if (ret) {
644 		dev_err(dev, "phy: Couldn't get our resources\n");
645 		return ret;
646 	}
647 
648 	regs = devm_ioremap_resource(dev, &res);
649 	if (IS_ERR(regs)) {
650 		dev_err(dev, "Couldn't map the HDMI PHY registers\n");
651 		return PTR_ERR(regs);
652 	}
653 
654 	phy->regs = devm_regmap_init_mmio(dev, regs,
655 					  &sun8i_hdmi_phy_regmap_config);
656 	if (IS_ERR(phy->regs)) {
657 		dev_err(dev, "Couldn't create the HDMI PHY regmap\n");
658 		return PTR_ERR(phy->regs);
659 	}
660 
661 	phy->clk_bus = of_clk_get_by_name(node, "bus");
662 	if (IS_ERR(phy->clk_bus)) {
663 		dev_err(dev, "Could not get bus clock\n");
664 		return PTR_ERR(phy->clk_bus);
665 	}
666 
667 	phy->clk_mod = of_clk_get_by_name(node, "mod");
668 	if (IS_ERR(phy->clk_mod)) {
669 		dev_err(dev, "Could not get mod clock\n");
670 		ret = PTR_ERR(phy->clk_mod);
671 		goto err_put_clk_bus;
672 	}
673 
674 	if (phy->variant->has_phy_clk) {
675 		phy->clk_pll0 = of_clk_get_by_name(node, "pll-0");
676 		if (IS_ERR(phy->clk_pll0)) {
677 			dev_err(dev, "Could not get pll-0 clock\n");
678 			ret = PTR_ERR(phy->clk_pll0);
679 			goto err_put_clk_mod;
680 		}
681 
682 		if (phy->variant->has_second_pll) {
683 			phy->clk_pll1 = of_clk_get_by_name(node, "pll-1");
684 			if (IS_ERR(phy->clk_pll1)) {
685 				dev_err(dev, "Could not get pll-1 clock\n");
686 				ret = PTR_ERR(phy->clk_pll1);
687 				goto err_put_clk_pll0;
688 			}
689 		}
690 	}
691 
692 	phy->rst_phy = of_reset_control_get_shared(node, "phy");
693 	if (IS_ERR(phy->rst_phy)) {
694 		dev_err(dev, "Could not get phy reset control\n");
695 		ret = PTR_ERR(phy->rst_phy);
696 		goto err_put_clk_pll1;
697 	}
698 
699 	ret = reset_control_deassert(phy->rst_phy);
700 	if (ret) {
701 		dev_err(dev, "Cannot deassert phy reset control: %d\n", ret);
702 		goto err_put_rst_phy;
703 	}
704 
705 	ret = clk_prepare_enable(phy->clk_bus);
706 	if (ret) {
707 		dev_err(dev, "Cannot enable bus clock: %d\n", ret);
708 		goto err_deassert_rst_phy;
709 	}
710 
711 	ret = clk_prepare_enable(phy->clk_mod);
712 	if (ret) {
713 		dev_err(dev, "Cannot enable mod clock: %d\n", ret);
714 		goto err_disable_clk_bus;
715 	}
716 
717 	if (phy->variant->has_phy_clk) {
718 		ret = sun8i_phy_clk_create(phy, dev,
719 					   phy->variant->has_second_pll);
720 		if (ret) {
721 			dev_err(dev, "Couldn't create the PHY clock\n");
722 			goto err_disable_clk_mod;
723 		}
724 
725 		clk_prepare_enable(phy->clk_phy);
726 	}
727 
728 	platform_set_drvdata(pdev, phy);
729 
730 	return 0;
731 
732 err_disable_clk_mod:
733 	clk_disable_unprepare(phy->clk_mod);
734 err_disable_clk_bus:
735 	clk_disable_unprepare(phy->clk_bus);
736 err_deassert_rst_phy:
737 	reset_control_assert(phy->rst_phy);
738 err_put_rst_phy:
739 	reset_control_put(phy->rst_phy);
740 err_put_clk_pll1:
741 	clk_put(phy->clk_pll1);
742 err_put_clk_pll0:
743 	clk_put(phy->clk_pll0);
744 err_put_clk_mod:
745 	clk_put(phy->clk_mod);
746 err_put_clk_bus:
747 	clk_put(phy->clk_bus);
748 
749 	return ret;
750 }
751 
752 static int sun8i_hdmi_phy_remove(struct platform_device *pdev)
753 {
754 	struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev);
755 
756 	clk_disable_unprepare(phy->clk_mod);
757 	clk_disable_unprepare(phy->clk_bus);
758 	clk_disable_unprepare(phy->clk_phy);
759 
760 	reset_control_assert(phy->rst_phy);
761 
762 	reset_control_put(phy->rst_phy);
763 
764 	clk_put(phy->clk_pll0);
765 	clk_put(phy->clk_pll1);
766 	clk_put(phy->clk_mod);
767 	clk_put(phy->clk_bus);
768 	return 0;
769 }
770 
771 struct platform_driver sun8i_hdmi_phy_driver = {
772 	.probe  = sun8i_hdmi_phy_probe,
773 	.remove = sun8i_hdmi_phy_remove,
774 	.driver = {
775 		.name = "sun8i-hdmi-phy",
776 		.of_match_table = sun8i_hdmi_phy_of_table,
777 	},
778 };
779