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