xref: /rk3399_rockchip-uboot/drivers/video/drm/rk628/rk628_combtxphy.c (revision a8a4d6c05a2e5f52e75e5096f9470aa3d36fd000)
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 
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 
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 
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 
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 
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 
200 void rk628_combtxphy_set_bus_width(struct rk628 *rk628, u32 bus_width)
201 {
202 	rk628->combtxphy.bus_width = bus_width;
203 }
204 
205 u32 rk628_combtxphy_get_bus_width(struct rk628 *rk628)
206 {
207 	return rk628->combtxphy.bus_width;
208 }
209 
210 void rk628_combtxphy_set_gvi_division_mode(struct rk628 *rk628, bool division)
211 {
212 	rk628->combtxphy.division_mode = division;
213 }
214 
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