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