1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2008-2018 Fuzhou Rockchip Electronics Co., Ltd
4 *
5 * Author: Wyon Bi <bivvy.bi@rock-chips.com>
6 */
7
8 #include <config.h>
9 #include <common.h>
10 #include <errno.h>
11 #include <dm.h>
12 #include <div64.h>
13 #include <asm/io.h>
14 #include <linux/ioport.h>
15 #include <linux/iopoll.h>
16 #include <linux/math64.h>
17
18 #include "rk628.h"
19 #include "rk628_cru.h"
20 #include "rk628_combtxphy.h"
21
rk628_combtxphy_dsi_power_on(struct rk628 * rk628)22 static void rk628_combtxphy_dsi_power_on(struct rk628 *rk628)
23 {
24 struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
25 u32 val = 0;
26 int ret;
27
28 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_BUS_WIDTH_MASK |
29 SW_GVI_LVDS_EN_MASK | SW_MIPI_DSI_EN_MASK,
30 SW_BUS_WIDTH_8BIT | SW_MIPI_DSI_EN);
31
32 if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
33 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
34 SW_MODULEA_EN_MASK, SW_MODULEA_EN);
35
36 if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
37 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
38 SW_MODULEB_EN_MASK, SW_MODULEB_EN);
39
40 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_PD_PLL, SW_PD_PLL);
41
42 if (combtxphy->frac_div)
43 rk628_i2c_update_bits(rk628, COMBTXPHY_CON8, SW_SSC_DEPTH_MASK | SW_SSC_EN_MASK,
44 SW_SSC_DEPTH(0) | SW_SSC_EN(1));
45
46 rk628_i2c_write(rk628, COMBTXPHY_CON5,
47 SW_REF_DIV(combtxphy->ref_div - 1) |
48 SW_PLL_FB_DIV(combtxphy->fb_div) |
49 SW_PLL_FRAC_DIV(combtxphy->frac_div) |
50 SW_RATE(combtxphy->rate_div / 2));
51
52 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_PD_PLL, 0);
53
54 ret = rk628_read_poll_timeout(rk628, GRF_DPHY0_STATUS, val,
55 val & DPHY_PHYLOCK, 0, 1000);
56 if (ret < 0)
57 printf("rk628 phy is not lock\n");
58
59 rk628_i2c_update_bits(rk628, COMBTXPHY_CON9,
60 SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK,
61 SW_DSI_FSET_EN | SW_DSI_RCAL_EN(1));
62
63 if (rk628->version == RK628F_VERSION) {
64 rk628_i2c_update_bits(rk628, COMBTXPHY_CON6,
65 SW_PLL_CTL_CON0_MASK,
66 SW_PLL_CTL_CON0(1));
67 rk628_i2c_update_bits(rk628, COMBTXPHY_CON9,
68 SW_DSI_LPTX_SR_TRIM_MASK |
69 SW_DSI_HSTX_AMP_TRIM_MASK,
70 SW_DSI_LPTX_SR_TRIM(0) |
71 SW_DSI_HSTX_AMP_TRIM(4));
72 }
73
74 udelay(400);
75 }
76
rk628_combtxphy_lvds_power_on(struct rk628 * rk628)77 static void rk628_combtxphy_lvds_power_on(struct rk628 *rk628)
78 {
79
80 struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
81 u32 val;
82 int ret;
83
84 /* Adjust terminal resistance 133 ohm, bypass 0.95v ldo for driver. */
85 if (rk628->version == RK628F_VERSION)
86 val = TX_COM_VOLT_ADJ(3);
87 else
88 val = TX_COM_VOLT_ADJ(0);
89 rk628_i2c_update_bits(rk628, COMBTXPHY_CON7,
90 SW_TX_RTERM_MASK | SW_TX_MODE_MASK |
91 BYPASS_095V_LDO_MASK | TX_COM_VOLT_ADJ_MASK,
92 SW_TX_RTERM(6) | SW_TX_MODE(3) |
93 BYPASS_095V_LDO(1) | val);
94
95 rk628_i2c_write(rk628, COMBTXPHY_CON10, TX7_CKDRV_EN | TX2_CKDRV_EN);
96 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
97 SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
98 SW_MIPI_DSI_EN_MASK,
99 SW_BUS_WIDTH_7BIT | SW_GVI_LVDS_EN);
100
101 if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
102 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
103 SW_MODULEA_EN_MASK, SW_MODULEA_EN);
104
105 if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
106 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
107 SW_MODULEB_EN_MASK, SW_MODULEB_EN);
108
109 rk628_i2c_write(rk628, COMBTXPHY_CON5,
110 SW_REF_DIV(combtxphy->ref_div - 1) |
111 SW_PLL_FB_DIV(combtxphy->fb_div) |
112 SW_PLL_FRAC_DIV(combtxphy->frac_div) |
113 SW_RATE(combtxphy->rate_div / 2));
114
115 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
116 SW_PD_PLL, 0);
117
118 ret = rk628_read_poll_timeout(rk628, GRF_DPHY0_STATUS, val,
119 val & DPHY_PHYLOCK, 0, 1000);
120 if (ret < 0)
121 printf("rk628 phy is not lock\n");
122
123 udelay(200);
124 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK, 0);
125 }
126
rk628_combtxphy_gvi_power_on(struct rk628 * rk628)127 static void rk628_combtxphy_gvi_power_on(struct rk628 *rk628)
128 {
129 struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
130 int ref_div = 0;
131
132 if (combtxphy->ref_div % 2) {
133 ref_div = combtxphy->ref_div - 1;
134 } else {
135 ref_div = BIT(4);
136 ref_div |= combtxphy->ref_div / 2 - 1;
137 }
138
139 rk628_i2c_write(rk628, COMBTXPHY_CON5,
140 SW_REF_DIV(ref_div) |
141 SW_PLL_FB_DIV(combtxphy->fb_div) |
142 SW_PLL_FRAC_DIV(combtxphy->frac_div) |
143 SW_RATE(combtxphy->rate_div / 2));
144 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
145 SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
146 SW_MIPI_DSI_EN_MASK |
147 SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
148 SW_BUS_WIDTH_10BIT | SW_GVI_LVDS_EN |
149 SW_MODULEB_EN | SW_MODULEA_EN);
150
151 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
152 SW_PD_PLL | SW_TX_PD_MASK, 0);
153 udelay(200);
154 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
155 SW_TX_IDLE_MASK, 0);
156 }
157
rk628_combtxphy_power_on(struct rk628 * rk628)158 void rk628_combtxphy_power_on(struct rk628 *rk628)
159 {
160 struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
161
162 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
163 SW_TX_IDLE_MASK | SW_TX_PD_MASK |
164 SW_PD_PLL_MASK, SW_TX_IDLE(0x3ff) |
165 SW_TX_PD(0x3ff) | SW_PD_PLL);
166
167 switch (combtxphy->mode) {
168 case RK628_PHY_MODE_VIDEO_MIPI:
169
170 rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
171 SW_TXPHY_REFCLK_SEL_MASK,
172 SW_TXPHY_REFCLK_SEL(0));
173 rk628_combtxphy_dsi_power_on(rk628);
174 break;
175 case RK628_PHY_MODE_VIDEO_LVDS:
176 rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
177 SW_TXPHY_REFCLK_SEL_MASK,
178 SW_TXPHY_REFCLK_SEL(1));
179 rk628_combtxphy_lvds_power_on(rk628);
180 break;
181 case RK628_PHY_MODE_VIDEO_GVI:
182 rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
183 SW_TXPHY_REFCLK_SEL_MASK,
184 SW_TXPHY_REFCLK_SEL(2));
185 rk628_combtxphy_gvi_power_on(rk628);
186 break;
187 default:
188 break;
189 };
190 }
191
rk628_combtxphy_power_off(struct rk628 * rk628)192 void rk628_combtxphy_power_off(struct rk628 *rk628)
193 {
194 rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_TX_IDLE_MASK |
195 SW_TX_PD_MASK | SW_PD_PLL_MASK |
196 SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
197 SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL);
198 }
199
rk628_combtxphy_set_bus_width(struct rk628 * rk628,u32 bus_width)200 void rk628_combtxphy_set_bus_width(struct rk628 *rk628, u32 bus_width)
201 {
202 rk628->combtxphy.bus_width = bus_width;
203 }
204
rk628_combtxphy_get_bus_width(struct rk628 * rk628)205 u32 rk628_combtxphy_get_bus_width(struct rk628 *rk628)
206 {
207 return rk628->combtxphy.bus_width;
208 }
209
rk628_combtxphy_set_gvi_division_mode(struct rk628 * rk628,bool division)210 void rk628_combtxphy_set_gvi_division_mode(struct rk628 *rk628, bool division)
211 {
212 rk628->combtxphy.division_mode = division;
213 }
214
rk628_combtxphy_set_mode(struct rk628 * rk628,enum rk628_phy_mode mode)215 void rk628_combtxphy_set_mode(struct rk628 *rk628, enum rk628_phy_mode mode)
216 {
217 struct rk628_combtxphy *combtxphy = &rk628->combtxphy;
218 unsigned int fvco, fpfd, fin = 24;
219
220 switch (mode) {
221 case RK628_PHY_MODE_VIDEO_MIPI:
222 {
223 int bus_width = rk628_combtxphy_get_bus_width(rk628);
224 unsigned int fhsc = bus_width >> 8;
225 unsigned int flags = bus_width & 0xff;
226
227 combtxphy->flags = flags;
228
229 /*
230 * the VCO can work from 1.5GHz to 3GHz.
231 * fhsc: 80 ~ 374, fvco: 640 ~ 2992
232 * fhsc: 375 ~ 749, fvco: 1500 ~ 2996
233 * fhsc: 750 ~ 1500, fvco: 1500 ~ 3000
234 */
235 if (fhsc < 80 || fhsc > 1500)
236 return;
237 else if (fhsc < 375)
238 combtxphy->rate_div = 4;
239 else if (fhsc < 750)
240 combtxphy->rate_div = 2;
241 else
242 combtxphy->rate_div = 1;
243
244 fvco = fhsc * 2 * combtxphy->rate_div;
245
246 /*
247 * the reference clock at PFD(FPFD = ref_clk / ref_div) about
248 * 25MHz is recommende, FPFD must range from 16MHz to 35MHz,
249 * here to find the best ref_div.
250 */
251 combtxphy->ref_div = 1;
252
253 /*
254 * fvco = fin * (fb_div + frac_div / 1024) * 8 / ref_div
255 */
256 combtxphy->fb_div = fvco * combtxphy->ref_div / 8 / fin;
257 combtxphy->frac_div = 1024 * fvco * combtxphy->ref_div / 8 / fin;
258 combtxphy->frac_div -= 1024 * combtxphy->fb_div;
259
260 /*
261 * get the actually frequency
262 */
263 fvco = fin * (1024 * combtxphy->fb_div + combtxphy->frac_div) * 8;
264 fvco = DIV_ROUND_UP(fvco, 1024 * combtxphy->ref_div);
265 fhsc = fvco / 2 / combtxphy->rate_div;
266 combtxphy->bus_width = fhsc;
267
268 break;
269 }
270 case RK628_PHY_MODE_VIDEO_LVDS:
271 {
272 int bus_width = rk628_combtxphy_get_bus_width(rk628);
273 unsigned int flags = bus_width & 0xff;
274 unsigned int rate = (bus_width >> 8) * 7;
275
276 combtxphy->flags = flags;
277 combtxphy->ref_div = 1;
278 combtxphy->fb_div = 14;
279 combtxphy->frac_div = 0;
280
281 if (rate < 500)
282 combtxphy->rate_div = 4;
283 else if (rate < 1000)
284 combtxphy->rate_div = 2;
285 else
286 combtxphy->rate_div = 1;
287 break;
288 }
289 case RK628_PHY_MODE_VIDEO_GVI:
290 {
291 unsigned int i, delta_freq, best_delta_freq, fb_div;
292 unsigned int bus_width = rk628_combtxphy_get_bus_width(rk628);
293 unsigned long ref_clk;
294 unsigned long long pre_clk;
295
296 if (bus_width < 500000 || bus_width > 4000000)
297 return;
298 else if (bus_width < 1000000)
299 combtxphy->rate_div = 4;
300 else if (bus_width < 2000000)
301 combtxphy->rate_div = 2;
302 else
303 combtxphy->rate_div = 1;
304 fvco = bus_width * combtxphy->rate_div;
305 ref_clk = rk628_cru_clk_get_rate(rk628, CGU_SCLK_VOP);
306 ref_clk = DIV_ROUND_CLOSEST(ref_clk, 1000); /* khz */
307
308 if (combtxphy->division_mode)
309 ref_clk /= 2;
310 /*
311 * the reference clock at PFD(FPFD = ref_clk / ref_div) about
312 * 25MHz is recommende, FPFD must range from 16MHz to 35MHz,
313 * here to find the best rev_div.
314 */
315 best_delta_freq = ref_clk;
316 for (i = 1; i <= 32; i++) {
317 fpfd = ref_clk / i;
318 delta_freq = abs(fpfd - 25000);
319 if (delta_freq < best_delta_freq) {
320 best_delta_freq = delta_freq;
321 combtxphy->ref_div = i;
322 }
323 }
324
325 /*
326 * ref_clk / ref_div * 8 * fb_div = FVCO
327 */
328 pre_clk = (unsigned long long)fvco * combtxphy->ref_div / 8 * 1024;
329 do_div(pre_clk, ref_clk);
330 fb_div = pre_clk / 1024;
331
332 /*
333 * get the actually frequency
334 */
335 bus_width = ref_clk / combtxphy->ref_div * 8;
336 bus_width *= fb_div;
337 bus_width /= combtxphy->rate_div;
338
339 combtxphy->frac_div = 0;
340 combtxphy->fb_div = fb_div;
341
342 combtxphy->bus_width = bus_width;
343 break;
344 }
345 default:
346 break;
347 }
348
349 combtxphy->mode = mode;
350 }
351