Merge remote-tracking branch 'spi/for-5.14' into spi-next
[linux-2.6-microblaze.git] / drivers / gpu / drm / sun4i / sun8i_hdmi_phy.c
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 };