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