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