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