]> Git Repo - linux.git/blob - drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
Merge tag 'ucount-rlimits-cleanups-for-v5.19' of git://git.kernel.org/pub/scm/linux...
[linux.git] / drivers / gpu / drm / sun4i / sun8i_hdmi_phy.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 Jernej Skrabec <[email protected]>
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 void sun8i_hdmi_phy_set_polarity(struct sun8i_hdmi_phy *phy,
127                                         const struct drm_display_mode *mode)
128 {
129         u32 val = 0;
130
131         if (mode->flags & DRM_MODE_FLAG_NHSYNC)
132                 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;
133
134         if (mode->flags & DRM_MODE_FLAG_NVSYNC)
135                 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;
136
137         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
138                            SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);
139 };
140
141 static int sun8i_a83t_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
142                                       const struct drm_display_info *display,
143                                       const struct drm_display_mode *mode)
144 {
145         unsigned int clk_rate = mode->crtc_clock * 1000;
146         struct sun8i_hdmi_phy *phy = data;
147
148         sun8i_hdmi_phy_set_polarity(phy, mode);
149
150         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
151                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
152                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
153
154         /* power down */
155         dw_hdmi_phy_gen2_txpwron(hdmi, 0);
156         dw_hdmi_phy_gen2_pddq(hdmi, 1);
157
158         dw_hdmi_phy_gen2_reset(hdmi);
159
160         dw_hdmi_phy_gen2_pddq(hdmi, 0);
161
162         dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
163
164         /*
165          * Values are taken from BSP HDMI driver. Although AW didn't
166          * release any documentation, explanation of this values can
167          * be found in i.MX 6Dual/6Quad Reference Manual.
168          */
169         if (clk_rate <= 27000000) {
170                 dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
171                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
172                 dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
173                 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
174                 dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
175                 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
176         } else if (clk_rate <= 74250000) {
177                 dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
178                 dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
179                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
180                 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
181                 dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
182                 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
183         } else if (clk_rate <= 148500000) {
184                 dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
185                 dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
186                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
187                 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
188                 dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
189                 dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
190         } else {
191                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
192                 dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
193                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
194                 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
195                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
196                 dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
197         }
198
199         dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
200         dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
201         dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
202
203         dw_hdmi_phy_gen2_txpwron(hdmi, 1);
204
205         return 0;
206 }
207
208 static void sun8i_a83t_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
209 {
210         struct sun8i_hdmi_phy *phy = data;
211
212         dw_hdmi_phy_gen2_txpwron(hdmi, 0);
213         dw_hdmi_phy_gen2_pddq(hdmi, 1);
214
215         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
216                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
217 }
218
219 static const struct dw_hdmi_phy_ops sun8i_a83t_hdmi_phy_ops = {
220         .init           = sun8i_a83t_hdmi_phy_config,
221         .disable        = sun8i_a83t_hdmi_phy_disable,
222         .read_hpd       = dw_hdmi_phy_read_hpd,
223         .update_hpd     = dw_hdmi_phy_update_hpd,
224         .setup_hpd      = dw_hdmi_phy_setup_hpd,
225 };
226
227 static int sun8i_h3_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
228                                     const struct drm_display_info *display,
229                                     const struct drm_display_mode *mode)
230 {
231         unsigned int clk_rate = mode->crtc_clock * 1000;
232         struct sun8i_hdmi_phy *phy = data;
233         u32 pll_cfg1_init;
234         u32 pll_cfg2_init;
235         u32 ana_cfg1_end;
236         u32 ana_cfg2_init;
237         u32 ana_cfg3_init;
238         u32 b_offset = 0;
239         u32 val;
240
241         if (phy->variant->has_phy_clk)
242                 clk_set_rate(phy->clk_phy, clk_rate);
243
244         sun8i_hdmi_phy_set_polarity(phy, mode);
245
246         /* bandwidth / frequency independent settings */
247
248         pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
249                         SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
250                         SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
251                         SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
252                         SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
253                         SUN8I_HDMI_PHY_PLL_CFG1_CS |
254                         SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
255                         SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
256                         SUN8I_HDMI_PHY_PLL_CFG1_BWS;
257
258         pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
259                         SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
260                         SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
261
262         ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
263                        SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
264                        SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
265                        SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
266                        SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
267                        SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
268                        SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
269                        SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
270                        SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
271                        SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK |
272                        SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
273                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
274                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
275                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
276                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
277                        SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
278                        SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
279                        SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
280                        SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
281                        SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
282                        SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
283                        SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
284
285         ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
286                         SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
287                         SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
288                         SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
289                         SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
290
291         ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
292                         SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
293                         SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
294
295         /* bandwidth / frequency dependent settings */
296         if (clk_rate <= 27000000) {
297                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
298                                  SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
299                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
300                                  SUN8I_HDMI_PHY_PLL_CFG2_S(4);
301                 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
302                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
303                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
304                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
305                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
306         } else if (clk_rate <= 74250000) {
307                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
308                                  SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
309                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
310                                  SUN8I_HDMI_PHY_PLL_CFG2_S(5);
311                 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
312                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
313                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
314                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
315                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
316         } else if (clk_rate <= 148500000) {
317                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
318                                  SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
319                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
320                                  SUN8I_HDMI_PHY_PLL_CFG2_S(6);
321                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
322                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
323                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
324                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
325                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
326         } else {
327                 b_offset = 2;
328                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
329                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
330                                  SUN8I_HDMI_PHY_PLL_CFG2_S(7);
331                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
332                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
333                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
334                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
335                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) |
336                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3);
337         }
338
339         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
340                            SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
341
342         /*
343          * NOTE: We have to be careful not to overwrite PHY parent
344          * clock selection bit and clock divider.
345          */
346         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
347                            (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
348                            pll_cfg1_init);
349         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
350                            (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
351                            pll_cfg2_init);
352         usleep_range(10000, 15000);
353         regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG,
354                      SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2);
355         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
356                            SUN8I_HDMI_PHY_PLL_CFG1_PLLEN,
357                            SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
358         msleep(100);
359
360         /* get B value */
361         regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
362         val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >>
363                 SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
364         val = min(val + b_offset, (u32)0x3f);
365
366         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
367                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
368                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD,
369                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
370                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
371         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
372                            SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK,
373                            val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT);
374         msleep(100);
375         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end);
376         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init);
377         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init);
378
379         return 0;
380 }
381
382 static void sun8i_h3_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
383 {
384         struct sun8i_hdmi_phy *phy = data;
385
386         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
387                      SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
388                      SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
389                      SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
390         regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
391 }
392
393 static const struct dw_hdmi_phy_ops sun8i_h3_hdmi_phy_ops = {
394         .init           = sun8i_h3_hdmi_phy_config,
395         .disable        = sun8i_h3_hdmi_phy_disable,
396         .read_hpd       = dw_hdmi_phy_read_hpd,
397         .update_hpd     = dw_hdmi_phy_update_hpd,
398         .setup_hpd      = dw_hdmi_phy_setup_hpd,
399 };
400
401 static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy)
402 {
403         /* enable read access to HDMI controller */
404         regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
405                      SUN8I_HDMI_PHY_READ_EN_MAGIC);
406
407         /* unscramble register offsets */
408         regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
409                      SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
410 }
411
412 static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy)
413 {
414         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
415                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
416                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
417
418         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
419                            0xffff0000, 0x80c00000);
420 }
421
422 static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
423 {
424         sun8i_hdmi_phy_unlock(phy);
425
426         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
427                            SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
428                            SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
429
430         /*
431          * Set PHY I2C address. It must match to the address set by
432          * dw_hdmi_phy_set_slave_addr().
433          */
434         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
435                            SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK,
436                            SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
437 }
438
439 static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
440 {
441         unsigned int val;
442
443         sun8i_hdmi_phy_unlock(phy);
444
445         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
446         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
447                            SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
448                            SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
449         udelay(5);
450         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
451                            SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN,
452                            SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
453         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
454                            SUN8I_HDMI_PHY_ANA_CFG1_ENVBS,
455                            SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
456         usleep_range(10, 20);
457         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
458                            SUN8I_HDMI_PHY_ANA_CFG1_LDOEN,
459                            SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
460         udelay(5);
461         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
462                            SUN8I_HDMI_PHY_ANA_CFG1_CKEN,
463                            SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
464         usleep_range(40, 100);
465         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
466                            SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL,
467                            SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
468         usleep_range(100, 200);
469         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
470                            SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG,
471                            SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
472         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
473                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
474                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
475                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2,
476                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
477                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
478                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
479
480         /* wait for calibration to finish */
481         regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val,
482                                  (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D),
483                                  100, 2000);
484
485         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
486                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK,
487                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
488         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
489                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
490                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
491                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
492                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK,
493                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
494                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
495                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
496                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK);
497
498         /* enable DDC communication */
499         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG,
500                            SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
501                            SUN8I_HDMI_PHY_ANA_CFG3_SDAEN,
502                            SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
503                            SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
504
505         /* reset PHY PLL clock parent */
506         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
507                            SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0);
508
509         /* set HW control of CEC pins */
510         regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0);
511
512         /* read calibration data */
513         regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
514         phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
515 }
516
517 int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
518 {
519         int ret;
520
521         ret = reset_control_deassert(phy->rst_phy);
522         if (ret) {
523                 dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret);
524                 return ret;
525         }
526
527         ret = clk_prepare_enable(phy->clk_bus);
528         if (ret) {
529                 dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret);
530                 goto err_assert_rst_phy;
531         }
532
533         ret = clk_prepare_enable(phy->clk_mod);
534         if (ret) {
535                 dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret);
536                 goto err_disable_clk_bus;
537         }
538
539         if (phy->variant->has_phy_clk) {
540                 ret = sun8i_phy_clk_create(phy, phy->dev,
541                                            phy->variant->has_second_pll);
542                 if (ret) {
543                         dev_err(phy->dev, "Couldn't create the PHY clock\n");
544                         goto err_disable_clk_mod;
545                 }
546
547                 clk_prepare_enable(phy->clk_phy);
548         }
549
550         phy->variant->phy_init(phy);
551
552         return 0;
553
554 err_disable_clk_mod:
555         clk_disable_unprepare(phy->clk_mod);
556 err_disable_clk_bus:
557         clk_disable_unprepare(phy->clk_bus);
558 err_assert_rst_phy:
559         reset_control_assert(phy->rst_phy);
560
561         return ret;
562 }
563
564 void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy)
565 {
566         clk_disable_unprepare(phy->clk_mod);
567         clk_disable_unprepare(phy->clk_bus);
568         clk_disable_unprepare(phy->clk_phy);
569
570         reset_control_assert(phy->rst_phy);
571 }
572
573 void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
574                             struct dw_hdmi_plat_data *plat_data)
575 {
576         const struct sun8i_hdmi_phy_variant *variant = phy->variant;
577
578         if (variant->phy_ops) {
579                 plat_data->phy_ops = variant->phy_ops;
580                 plat_data->phy_name = "sun8i_dw_hdmi_phy";
581                 plat_data->phy_data = phy;
582         } else {
583                 plat_data->mpll_cfg = variant->mpll_cfg;
584                 plat_data->cur_ctr = variant->cur_ctr;
585                 plat_data->phy_config = variant->phy_cfg;
586         }
587 }
588
589 static const struct regmap_config sun8i_hdmi_phy_regmap_config = {
590         .reg_bits       = 32,
591         .val_bits       = 32,
592         .reg_stride     = 4,
593         .max_register   = SUN8I_HDMI_PHY_CEC_REG,
594         .name           = "phy"
595 };
596
597 static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
598         .phy_ops = &sun8i_a83t_hdmi_phy_ops,
599         .phy_init = &sun8i_hdmi_phy_init_a83t,
600 };
601
602 static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
603         .has_phy_clk = true,
604         .phy_ops = &sun8i_h3_hdmi_phy_ops,
605         .phy_init = &sun8i_hdmi_phy_init_h3,
606 };
607
608 static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
609         .has_phy_clk = true,
610         .has_second_pll = true,
611         .phy_ops = &sun8i_h3_hdmi_phy_ops,
612         .phy_init = &sun8i_hdmi_phy_init_h3,
613 };
614
615 static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
616         .has_phy_clk = true,
617         .phy_ops = &sun8i_h3_hdmi_phy_ops,
618         .phy_init = &sun8i_hdmi_phy_init_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                 put_device(&pdev->dev);
663                 return -EPROBE_DEFER;
664         }
665
666         hdmi->phy = phy;
667
668         put_device(&pdev->dev);
669
670         return 0;
671 }
672
673 static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
674 {
675         struct device *dev = &pdev->dev;
676         struct sun8i_hdmi_phy *phy;
677         void __iomem *regs;
678
679         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
680         if (!phy)
681                 return -ENOMEM;
682
683         phy->variant = of_device_get_match_data(dev);
684         phy->dev = dev;
685
686         regs = devm_platform_ioremap_resource(pdev, 0);
687         if (IS_ERR(regs))
688                 return dev_err_probe(dev, PTR_ERR(regs),
689                                      "Couldn't map the HDMI PHY registers\n");
690
691         phy->regs = devm_regmap_init_mmio(dev, regs,
692                                           &sun8i_hdmi_phy_regmap_config);
693         if (IS_ERR(phy->regs))
694                 return dev_err_probe(dev, PTR_ERR(phy->regs),
695                                      "Couldn't create the HDMI PHY regmap\n");
696
697         phy->clk_bus = devm_clk_get(dev, "bus");
698         if (IS_ERR(phy->clk_bus))
699                 return dev_err_probe(dev, PTR_ERR(phy->clk_bus),
700                                      "Could not get bus clock\n");
701
702         phy->clk_mod = devm_clk_get(dev, "mod");
703         if (IS_ERR(phy->clk_mod))
704                 return dev_err_probe(dev, PTR_ERR(phy->clk_mod),
705                                      "Could not get mod clock\n");
706
707         if (phy->variant->has_phy_clk) {
708                 phy->clk_pll0 = devm_clk_get(dev, "pll-0");
709                 if (IS_ERR(phy->clk_pll0))
710                         return dev_err_probe(dev, PTR_ERR(phy->clk_pll0),
711                                              "Could not get pll-0 clock\n");
712
713                 if (phy->variant->has_second_pll) {
714                         phy->clk_pll1 = devm_clk_get(dev, "pll-1");
715                         if (IS_ERR(phy->clk_pll1))
716                                 return dev_err_probe(dev, PTR_ERR(phy->clk_pll1),
717                                                      "Could not get pll-1 clock\n");
718                 }
719         }
720
721         phy->rst_phy = devm_reset_control_get_shared(dev, "phy");
722         if (IS_ERR(phy->rst_phy))
723                 return dev_err_probe(dev, PTR_ERR(phy->rst_phy),
724                                      "Could not get phy reset control\n");
725
726         platform_set_drvdata(pdev, phy);
727
728         return 0;
729 }
730
731 struct platform_driver sun8i_hdmi_phy_driver = {
732         .probe  = sun8i_hdmi_phy_probe,
733         .driver = {
734                 .name = "sun8i-hdmi-phy",
735                 .of_match_table = sun8i_hdmi_phy_of_table,
736         },
737 };
This page took 0.114532 seconds and 4 git commands to generate.