xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/rk628/rk628_combtxphy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4  *
5  * Author: Shunqing Chen <csq@rock-chips.com>
6  */
7 
8 #include <linux/delay.h>
9 #include "rk628.h"
10 #include "rk628_combtxphy.h"
11 #include "rk628_cru.h"
12 
rk628_txphy_set_bus_width(struct rk628 * rk628,u32 bus_width)13 void rk628_txphy_set_bus_width(struct rk628 *rk628, u32 bus_width)
14 {
15 	struct rk628_combtxphy *txphy = rk628->txphy;
16 
17 	txphy->bus_width = bus_width;
18 }
19 EXPORT_SYMBOL(rk628_txphy_set_bus_width);
20 
rk628_txphy_get_bus_width(struct rk628 * rk628)21 u32 rk628_txphy_get_bus_width(struct rk628 *rk628)
22 {
23 	struct rk628_combtxphy *txphy = rk628->txphy;
24 
25 	return txphy->bus_width;
26 }
27 EXPORT_SYMBOL(rk628_txphy_get_bus_width);
28 
rk628_combtxphy_dsi_power_on(struct rk628 * rk628)29 static void rk628_combtxphy_dsi_power_on(struct rk628 *rk628)
30 {
31 	struct rk628_combtxphy *txphy = rk628->txphy;
32 
33 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_BUS_WIDTH_MASK |
34 			      SW_GVI_LVDS_EN_MASK |
35 			      SW_MIPI_DSI_EN_MASK,
36 			      SW_BUS_WIDTH_8BIT | SW_MIPI_DSI_EN);
37 
38 	if (txphy->flags & COMBTXPHY_MODULEA_EN)
39 		rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_MODULEA_EN_MASK,
40 				      SW_MODULEA_EN);
41 	if (txphy->flags & COMBTXPHY_MODULEB_EN)
42 		rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_MODULEB_EN_MASK,
43 				      SW_MODULEB_EN);
44 
45 	rk628_i2c_write(rk628,  COMBTXPHY_CON5, SW_REF_DIV(txphy->ref_div - 1) |
46 			SW_PLL_FB_DIV(txphy->fb_div) |
47 			SW_PLL_FRAC_DIV(txphy->frac_div) |
48 			SW_RATE(txphy->rate_div / 2));
49 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_PD_PLL, 0);
50 	usleep_range(100, 200);
51 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON9, SW_DSI_FSET_EN_MASK |
52 			      SW_DSI_RCAL_EN_MASK, SW_DSI_FSET_EN |
53 			      SW_DSI_RCAL_EN);
54 	usleep_range(100, 200);
55 }
56 
rk628_combtxphy_lvds_power_on(struct rk628 * rk628)57 static void rk628_combtxphy_lvds_power_on(struct rk628 *rk628)
58 {
59 	struct rk628_combtxphy *txphy = rk628->txphy;
60 
61 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON7, SW_TX_MODE_MASK, SW_TX_MODE(3));
62 	rk628_i2c_write(rk628,  COMBTXPHY_CON10, TX7_CKDRV_EN | TX2_CKDRV_EN);
63 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_BUS_WIDTH_MASK |
64 			      SW_GVI_LVDS_EN_MASK | SW_MIPI_DSI_EN_MASK,
65 			      SW_BUS_WIDTH_7BIT | SW_GVI_LVDS_EN);
66 
67 	if (txphy->flags & COMBTXPHY_MODULEA_EN)
68 		rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_MODULEA_EN_MASK,
69 				      SW_MODULEA_EN);
70 	if (txphy->flags & COMBTXPHY_MODULEB_EN)
71 		rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_MODULEB_EN_MASK,
72 				      SW_MODULEB_EN);
73 
74 	rk628_i2c_write(rk628,  COMBTXPHY_CON5, SW_REF_DIV(txphy->ref_div - 1) |
75 			SW_PLL_FB_DIV(txphy->fb_div) |
76 			SW_PLL_FRAC_DIV(txphy->frac_div) |
77 			SW_RATE(txphy->rate_div / 2));
78 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_PD_PLL | SW_TX_PD_MASK, 0);
79 	usleep_range(100, 200);
80 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_TX_IDLE_MASK, 0);
81 }
82 
rk628_combtxphy_gvi_power_on(struct rk628 * rk628)83 static void rk628_combtxphy_gvi_power_on(struct rk628 *rk628)
84 {
85 	struct rk628_combtxphy *txphy = rk628->txphy;
86 
87 	rk628_i2c_write(rk628,  COMBTXPHY_CON5, SW_REF_DIV(txphy->ref_div - 1) |
88 			SW_PLL_FB_DIV(txphy->fb_div) |
89 			SW_PLL_FRAC_DIV(txphy->frac_div) |
90 			SW_RATE(txphy->rate_div / 2));
91 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_BUS_WIDTH_MASK |
92 			      SW_GVI_LVDS_EN_MASK | SW_MIPI_DSI_EN_MASK |
93 			      SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
94 			      SW_BUS_WIDTH_10BIT | SW_GVI_LVDS_EN |
95 			      SW_MODULEB_EN | SW_MODULEA_EN);
96 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_PD_PLL | SW_TX_PD_MASK, 0);
97 	usleep_range(100, 200);
98 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_TX_IDLE_MASK, 0);
99 }
100 
rk628_txphy_set_mode(struct rk628 * rk628,enum phy_mode mode)101 void rk628_txphy_set_mode(struct rk628 *rk628, enum phy_mode mode)
102 {
103 	unsigned int fvco, frac_rate, fin = 24;
104 	struct rk628_combtxphy *txphy = rk628->txphy;
105 
106 	switch (mode) {
107 	case PHY_MODE_VIDEO_MIPI:
108 	{
109 		int bus_width = rk628_txphy_get_bus_width(rk628);
110 		unsigned int fhsc = bus_width >> 8;
111 		unsigned int flags = bus_width & 0xff;
112 
113 		fhsc = fin * (fhsc / fin);
114 		if (fhsc < 80 || fhsc > 1500)
115 			return;
116 		else if (fhsc < 375)
117 			txphy->rate_div = 4;
118 		else if (fhsc < 750)
119 			txphy->rate_div = 2;
120 		else
121 			txphy->rate_div = 1;
122 
123 		txphy->flags = flags;
124 
125 		fvco = fhsc * 2 * txphy->rate_div;
126 		txphy->ref_div = 1;
127 		txphy->fb_div = fvco / 8 / fin;
128 		frac_rate = fvco - (fin * 8 * txphy->fb_div);
129 		if (frac_rate) {
130 			frac_rate <<= 10;
131 			frac_rate /= fin * 8;
132 			txphy->frac_div = frac_rate;
133 		} else {
134 			txphy->frac_div = 0;
135 		}
136 
137 		fvco = fin * (1024 * txphy->fb_div + txphy->frac_div);
138 		fvco *= 8;
139 		fvco = DIV_ROUND_UP(fvco, 1024 * txphy->ref_div);
140 		fhsc = fvco / 2 / txphy->rate_div;
141 		txphy->bus_width = fhsc;
142 
143 		break;
144 	}
145 	case PHY_MODE_VIDEO_LVDS:
146 	{
147 		int bus_width = rk628_txphy_get_bus_width(rk628);
148 		unsigned int flags = bus_width & 0xff;
149 		unsigned int rate = (bus_width >> 8) * 7;
150 
151 		txphy->flags = flags;
152 		txphy->ref_div = 1;
153 		txphy->fb_div = 14;
154 		txphy->frac_div = 0;
155 
156 		if (rate < 500)
157 			txphy->rate_div = 4;
158 		else if (rate < 1000)
159 			txphy->rate_div = 2;
160 		else
161 			txphy->rate_div = 1;
162 		break;
163 	}
164 	case PHY_MODE_VIDEO_GVI:
165 	{
166 		unsigned int fhsc = rk628_txphy_get_bus_width(rk628) & 0xfff;
167 
168 		if (fhsc < 500 || fhsc > 4000)
169 			return;
170 		else if (fhsc < 1000)
171 			txphy->rate_div = 4;
172 		else if (fhsc < 2000)
173 			txphy->rate_div = 2;
174 		else
175 			txphy->rate_div = 1;
176 		fvco = fhsc * txphy->rate_div;
177 
178 		txphy->ref_div = 1;
179 		txphy->fb_div = fvco / 8 / fin;
180 		frac_rate = fvco - (fin * 8 * txphy->fb_div);
181 
182 		if (frac_rate) {
183 			frac_rate <<= 10;
184 			frac_rate /= fin * 8;
185 			txphy->frac_div = frac_rate;
186 		} else {
187 			txphy->frac_div = 0;
188 		}
189 
190 		fvco = fin * (1024 * txphy->fb_div + txphy->frac_div);
191 		fvco *= 8;
192 		fvco /= 1024 * txphy->ref_div;
193 		fhsc = fvco / txphy->rate_div;
194 		txphy->bus_width = fhsc;
195 		break;
196 	}
197 	default:
198 		break;
199 	}
200 
201 	txphy->mode = mode;
202 }
203 EXPORT_SYMBOL(rk628_txphy_set_mode);
204 
rk628_txphy_power_on(struct rk628 * rk628)205 void rk628_txphy_power_on(struct rk628 *rk628)
206 {
207 	struct rk628_combtxphy *txphy = rk628->txphy;
208 
209 	rk628_control_assert(rk628, RGU_TXPHY_CON);
210 	udelay(10);
211 	rk628_control_deassert(rk628, RGU_TXPHY_CON);
212 	udelay(10);
213 
214 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK |
215 			      SW_PD_PLL_MASK, SW_TX_IDLE(0x3ff) |
216 			      SW_TX_PD(0x3ff) | SW_PD_PLL);
217 
218 	switch (txphy->mode) {
219 	case PHY_MODE_VIDEO_MIPI:
220 
221 		rk628_i2c_update_bits(rk628,  GRF_POST_PROC_CON,
222 				      SW_TXPHY_REFCLK_SEL_MASK,
223 				      SW_TXPHY_REFCLK_SEL(0));
224 		rk628_combtxphy_dsi_power_on(rk628);
225 		break;
226 	case PHY_MODE_VIDEO_LVDS:
227 		rk628_i2c_update_bits(rk628,  GRF_POST_PROC_CON,
228 				      SW_TXPHY_REFCLK_SEL_MASK,
229 				      SW_TXPHY_REFCLK_SEL(1));
230 		rk628_combtxphy_lvds_power_on(rk628);
231 		break;
232 	case PHY_MODE_VIDEO_GVI:
233 		rk628_i2c_update_bits(rk628,  GRF_POST_PROC_CON,
234 				      SW_TXPHY_REFCLK_SEL_MASK,
235 				      SW_TXPHY_REFCLK_SEL(0));
236 		rk628_combtxphy_gvi_power_on(rk628);
237 		break;
238 	default:
239 		break;
240 	}
241 }
242 EXPORT_SYMBOL(rk628_txphy_power_on);
243 
rk628_txphy_power_off(struct rk628 * rk628)244 void rk628_txphy_power_off(struct rk628 *rk628)
245 {
246 	rk628_i2c_update_bits(rk628,  COMBTXPHY_CON0, SW_TX_IDLE_MASK | SW_TX_PD_MASK |
247 			      SW_PD_PLL_MASK | SW_MODULEB_EN_MASK |
248 			      SW_MODULEA_EN_MASK, SW_TX_IDLE(0x3ff) |
249 			      SW_TX_PD(0x3ff) | SW_PD_PLL);
250 }
251 EXPORT_SYMBOL(rk628_txphy_power_off);
252 
rk628_txphy_register(struct rk628 * rk628)253 struct rk628_combtxphy *rk628_txphy_register(struct rk628 *rk628)
254 {
255 	struct rk628_combtxphy *txphy;
256 
257 	txphy = devm_kzalloc(rk628->dev, sizeof(*txphy), GFP_KERNEL);
258 	if (!txphy)
259 		return NULL;
260 
261 	rk628->txphy = txphy;
262 
263 	return txphy;
264 }
265 EXPORT_SYMBOL(rk628_txphy_register);
266