1 | // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
2 | /* |
3 | * Rockchip MIPI Synopsys DPHY RX0 driver |
4 | * |
5 | * Copyright (C) 2019 Collabora, Ltd. |
6 | * |
7 | * Based on: |
8 | * |
9 | * drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c |
10 | * in https://chromium.googlesource.com/chromiumos/third_party/kernel, |
11 | * chromeos-4.4 branch. |
12 | * |
13 | * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. |
14 | * Jacob Chen <jacob2.chen@rock-chips.com> |
15 | * Shunqian Zheng <zhengsq@rock-chips.com> |
16 | */ |
17 | |
18 | #include <linux/clk.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/io.h> |
21 | #include <linux/mfd/syscon.h> |
22 | #include <linux/module.h> |
23 | #include <linux/of.h> |
24 | #include <linux/phy/phy.h> |
25 | #include <linux/phy/phy-mipi-dphy.h> |
26 | #include <linux/platform_device.h> |
27 | #include <linux/regmap.h> |
28 | |
29 | #define RK3399_GRF_SOC_CON9 0x6224 |
30 | #define RK3399_GRF_SOC_CON21 0x6254 |
31 | #define RK3399_GRF_SOC_CON22 0x6258 |
32 | #define RK3399_GRF_SOC_CON23 0x625c |
33 | #define RK3399_GRF_SOC_CON24 0x6260 |
34 | #define RK3399_GRF_SOC_CON25 0x6264 |
35 | #define RK3399_GRF_SOC_STATUS1 0xe2a4 |
36 | |
37 | #define CLOCK_LANE_HS_RX_CONTROL 0x34 |
38 | #define LANE0_HS_RX_CONTROL 0x44 |
39 | #define LANE1_HS_RX_CONTROL 0x54 |
40 | #define LANE2_HS_RX_CONTROL 0x84 |
41 | #define LANE3_HS_RX_CONTROL 0x94 |
42 | #define LANES_THS_SETTLE_CONTROL 0x75 |
43 | #define THS_SETTLE_COUNTER_THRESHOLD 0x04 |
44 | |
45 | struct hsfreq_range { |
46 | u16 range_h; |
47 | u8 cfg_bit; |
48 | }; |
49 | |
50 | static const struct hsfreq_range rk3399_mipidphy_hsfreq_ranges[] = { |
51 | { 89, 0x00 }, { 99, 0x10 }, { 109, 0x20 }, { 129, 0x01 }, |
52 | { 139, 0x11 }, { 149, 0x21 }, { 169, 0x02 }, { 179, 0x12 }, |
53 | { 199, 0x22 }, { 219, 0x03 }, { 239, 0x13 }, { 249, 0x23 }, |
54 | { 269, 0x04 }, { 299, 0x14 }, { 329, 0x05 }, { 359, 0x15 }, |
55 | { 399, 0x25 }, { 449, 0x06 }, { 499, 0x16 }, { 549, 0x07 }, |
56 | { 599, 0x17 }, { 649, 0x08 }, { 699, 0x18 }, { 749, 0x09 }, |
57 | { 799, 0x19 }, { 849, 0x29 }, { 899, 0x39 }, { 949, 0x0a }, |
58 | { 999, 0x1a }, { 1049, 0x2a }, { 1099, 0x3a }, { 1149, 0x0b }, |
59 | { 1199, 0x1b }, { 1249, 0x2b }, { 1299, 0x3b }, { 1349, 0x0c }, |
60 | { 1399, 0x1c }, { 1449, 0x2c }, { 1500, 0x3c } |
61 | }; |
62 | |
63 | static const char * const rk3399_mipidphy_clks[] = { |
64 | "dphy-ref" , |
65 | "dphy-cfg" , |
66 | "grf" , |
67 | }; |
68 | |
69 | enum dphy_reg_id { |
70 | GRF_DPHY_RX0_TURNDISABLE = 0, |
71 | GRF_DPHY_RX0_FORCERXMODE, |
72 | GRF_DPHY_RX0_FORCETXSTOPMODE, |
73 | GRF_DPHY_RX0_ENABLE, |
74 | GRF_DPHY_RX0_TESTCLR, |
75 | GRF_DPHY_RX0_TESTCLK, |
76 | GRF_DPHY_RX0_TESTEN, |
77 | GRF_DPHY_RX0_TESTDIN, |
78 | GRF_DPHY_RX0_TURNREQUEST, |
79 | GRF_DPHY_RX0_TESTDOUT, |
80 | GRF_DPHY_TX0_TURNDISABLE, |
81 | GRF_DPHY_TX0_FORCERXMODE, |
82 | GRF_DPHY_TX0_FORCETXSTOPMODE, |
83 | GRF_DPHY_TX0_TURNREQUEST, |
84 | GRF_DPHY_TX1RX1_TURNDISABLE, |
85 | GRF_DPHY_TX1RX1_FORCERXMODE, |
86 | GRF_DPHY_TX1RX1_FORCETXSTOPMODE, |
87 | GRF_DPHY_TX1RX1_ENABLE, |
88 | GRF_DPHY_TX1RX1_MASTERSLAVEZ, |
89 | GRF_DPHY_TX1RX1_BASEDIR, |
90 | GRF_DPHY_TX1RX1_ENABLECLK, |
91 | GRF_DPHY_TX1RX1_TURNREQUEST, |
92 | GRF_DPHY_RX1_SRC_SEL, |
93 | /* rk3288 only */ |
94 | GRF_CON_DISABLE_ISP, |
95 | GRF_CON_ISP_DPHY_SEL, |
96 | GRF_DSI_CSI_TESTBUS_SEL, |
97 | GRF_DVP_V18SEL, |
98 | /* below is for rk3399 only */ |
99 | GRF_DPHY_RX0_CLK_INV_SEL, |
100 | GRF_DPHY_RX1_CLK_INV_SEL, |
101 | }; |
102 | |
103 | struct dphy_reg { |
104 | u16 offset; |
105 | u8 mask; |
106 | u8 shift; |
107 | }; |
108 | |
109 | #define PHY_REG(_offset, _width, _shift) \ |
110 | { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, } |
111 | |
112 | static const struct dphy_reg rk3399_grf_dphy_regs[] = { |
113 | [GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON9, 4, 0), |
114 | [GRF_DPHY_RX0_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 10), |
115 | [GRF_DPHY_RX1_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 11), |
116 | [GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 0), |
117 | [GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 4), |
118 | [GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 8), |
119 | [GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 12), |
120 | [GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 0), |
121 | [GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 4), |
122 | [GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 8), |
123 | [GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 12), |
124 | [GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 0), |
125 | [GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 4), |
126 | [GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 8), |
127 | [GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 12), |
128 | [GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON24, 4, 0), |
129 | [GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 4), |
130 | [GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 5), |
131 | [GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 6), |
132 | [GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 7), |
133 | [GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3399_GRF_SOC_CON25, 8, 0), |
134 | [GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 8), |
135 | [GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 9), |
136 | [GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 10), |
137 | [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3399_GRF_SOC_STATUS1, 8, 0), |
138 | }; |
139 | |
140 | struct rk_dphy_drv_data { |
141 | const char * const *clks; |
142 | unsigned int num_clks; |
143 | const struct hsfreq_range *hsfreq_ranges; |
144 | unsigned int num_hsfreq_ranges; |
145 | const struct dphy_reg *regs; |
146 | }; |
147 | |
148 | struct rk_dphy { |
149 | struct device *dev; |
150 | struct regmap *grf; |
151 | struct clk_bulk_data *clks; |
152 | |
153 | const struct rk_dphy_drv_data *drv_data; |
154 | struct phy_configure_opts_mipi_dphy config; |
155 | |
156 | u8 hsfreq; |
157 | }; |
158 | |
159 | static inline void rk_dphy_write_grf(struct rk_dphy *priv, |
160 | unsigned int index, u8 value) |
161 | { |
162 | const struct dphy_reg *reg = &priv->drv_data->regs[index]; |
163 | /* Update high word */ |
164 | unsigned int val = (value << reg->shift) | |
165 | (reg->mask << (reg->shift + 16)); |
166 | |
167 | if (WARN_ON(!reg->offset)) |
168 | return; |
169 | regmap_write(map: priv->grf, reg: reg->offset, val); |
170 | } |
171 | |
172 | static void rk_dphy_write(struct rk_dphy *priv, u8 test_code, u8 test_data) |
173 | { |
174 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTDIN, value: test_code); |
175 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTEN, value: 1); |
176 | /* |
177 | * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content |
178 | * is latched internally as the current test code. Test data is |
179 | * programmed internally by rising edge on TESTCLK. |
180 | * This code assumes that TESTCLK is already 1. |
181 | */ |
182 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTCLK, value: 0); |
183 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTEN, value: 0); |
184 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTDIN, value: test_data); |
185 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTCLK, value: 1); |
186 | } |
187 | |
188 | static void rk_dphy_enable(struct rk_dphy *priv) |
189 | { |
190 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_FORCERXMODE, value: 0); |
191 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_FORCETXSTOPMODE, value: 0); |
192 | |
193 | /* Disable lane turn around, which is ignored in receive mode */ |
194 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TURNREQUEST, value: 0); |
195 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TURNDISABLE, value: 0xf); |
196 | |
197 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_ENABLE, |
198 | GENMASK(priv->config.lanes - 1, 0)); |
199 | |
200 | /* dphy start */ |
201 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTCLK, value: 1); |
202 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTCLR, value: 1); |
203 | usleep_range(min: 100, max: 150); |
204 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_TESTCLR, value: 0); |
205 | usleep_range(min: 100, max: 150); |
206 | |
207 | /* set clock lane */ |
208 | /* HS hsfreq_range & lane 0 settle bypass */ |
209 | rk_dphy_write(priv, CLOCK_LANE_HS_RX_CONTROL, test_data: 0); |
210 | /* HS RX Control of lane0 */ |
211 | rk_dphy_write(priv, LANE0_HS_RX_CONTROL, test_data: priv->hsfreq << 1); |
212 | /* HS RX Control of lane1 */ |
213 | rk_dphy_write(priv, LANE1_HS_RX_CONTROL, test_data: priv->hsfreq << 1); |
214 | /* HS RX Control of lane2 */ |
215 | rk_dphy_write(priv, LANE2_HS_RX_CONTROL, test_data: priv->hsfreq << 1); |
216 | /* HS RX Control of lane3 */ |
217 | rk_dphy_write(priv, LANE3_HS_RX_CONTROL, test_data: priv->hsfreq << 1); |
218 | /* HS RX Data Lanes Settle State Time Control */ |
219 | rk_dphy_write(priv, LANES_THS_SETTLE_CONTROL, |
220 | THS_SETTLE_COUNTER_THRESHOLD); |
221 | |
222 | /* Normal operation */ |
223 | rk_dphy_write(priv, test_code: 0x0, test_data: 0); |
224 | } |
225 | |
226 | static int rk_dphy_configure(struct phy *phy, union phy_configure_opts *opts) |
227 | { |
228 | struct rk_dphy *priv = phy_get_drvdata(phy); |
229 | const struct rk_dphy_drv_data *drv_data = priv->drv_data; |
230 | struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy; |
231 | unsigned int hsfreq = 0; |
232 | unsigned int i; |
233 | u64 data_rate_mbps; |
234 | int ret; |
235 | |
236 | /* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */ |
237 | ret = phy_mipi_dphy_config_validate(cfg: config); |
238 | if (ret) |
239 | return ret; |
240 | |
241 | data_rate_mbps = div_u64(dividend: config->hs_clk_rate, divisor: 1000 * 1000); |
242 | |
243 | dev_dbg(priv->dev, "lanes %d - data_rate_mbps %llu\n" , |
244 | config->lanes, data_rate_mbps); |
245 | for (i = 0; i < drv_data->num_hsfreq_ranges; i++) { |
246 | if (drv_data->hsfreq_ranges[i].range_h >= data_rate_mbps) { |
247 | hsfreq = drv_data->hsfreq_ranges[i].cfg_bit; |
248 | break; |
249 | } |
250 | } |
251 | if (!hsfreq) |
252 | return -EINVAL; |
253 | |
254 | priv->hsfreq = hsfreq; |
255 | priv->config = *config; |
256 | return 0; |
257 | } |
258 | |
259 | static int rk_dphy_power_on(struct phy *phy) |
260 | { |
261 | struct rk_dphy *priv = phy_get_drvdata(phy); |
262 | int ret; |
263 | |
264 | ret = clk_bulk_enable(num_clks: priv->drv_data->num_clks, clks: priv->clks); |
265 | if (ret) |
266 | return ret; |
267 | |
268 | rk_dphy_enable(priv); |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | static int rk_dphy_power_off(struct phy *phy) |
274 | { |
275 | struct rk_dphy *priv = phy_get_drvdata(phy); |
276 | |
277 | rk_dphy_write_grf(priv, index: GRF_DPHY_RX0_ENABLE, value: 0); |
278 | clk_bulk_disable(num_clks: priv->drv_data->num_clks, clks: priv->clks); |
279 | return 0; |
280 | } |
281 | |
282 | static int rk_dphy_init(struct phy *phy) |
283 | { |
284 | struct rk_dphy *priv = phy_get_drvdata(phy); |
285 | |
286 | return clk_bulk_prepare(num_clks: priv->drv_data->num_clks, clks: priv->clks); |
287 | } |
288 | |
289 | static int rk_dphy_exit(struct phy *phy) |
290 | { |
291 | struct rk_dphy *priv = phy_get_drvdata(phy); |
292 | |
293 | clk_bulk_unprepare(num_clks: priv->drv_data->num_clks, clks: priv->clks); |
294 | return 0; |
295 | } |
296 | |
297 | static const struct phy_ops rk_dphy_ops = { |
298 | .power_on = rk_dphy_power_on, |
299 | .power_off = rk_dphy_power_off, |
300 | .init = rk_dphy_init, |
301 | .exit = rk_dphy_exit, |
302 | .configure = rk_dphy_configure, |
303 | .owner = THIS_MODULE, |
304 | }; |
305 | |
306 | static const struct rk_dphy_drv_data rk3399_mipidphy_drv_data = { |
307 | .clks = rk3399_mipidphy_clks, |
308 | .num_clks = ARRAY_SIZE(rk3399_mipidphy_clks), |
309 | .hsfreq_ranges = rk3399_mipidphy_hsfreq_ranges, |
310 | .num_hsfreq_ranges = ARRAY_SIZE(rk3399_mipidphy_hsfreq_ranges), |
311 | .regs = rk3399_grf_dphy_regs, |
312 | }; |
313 | |
314 | static const struct of_device_id rk_dphy_dt_ids[] = { |
315 | { |
316 | .compatible = "rockchip,rk3399-mipi-dphy-rx0" , |
317 | .data = &rk3399_mipidphy_drv_data, |
318 | }, |
319 | {} |
320 | }; |
321 | MODULE_DEVICE_TABLE(of, rk_dphy_dt_ids); |
322 | |
323 | static int rk_dphy_probe(struct platform_device *pdev) |
324 | { |
325 | struct device *dev = &pdev->dev; |
326 | struct device_node *np = dev->of_node; |
327 | const struct rk_dphy_drv_data *drv_data; |
328 | struct phy_provider *phy_provider; |
329 | struct rk_dphy *priv; |
330 | struct phy *phy; |
331 | unsigned int i; |
332 | int ret; |
333 | |
334 | if (!dev->parent || !dev->parent->of_node) |
335 | return -ENODEV; |
336 | |
337 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
338 | if (!priv) |
339 | return -ENOMEM; |
340 | priv->dev = dev; |
341 | |
342 | priv->grf = syscon_node_to_regmap(np: dev->parent->of_node); |
343 | if (IS_ERR(ptr: priv->grf)) { |
344 | dev_err(dev, "Can't find GRF syscon\n" ); |
345 | return -ENODEV; |
346 | } |
347 | |
348 | drv_data = of_device_get_match_data(dev); |
349 | priv->drv_data = drv_data; |
350 | priv->clks = devm_kcalloc(dev: &pdev->dev, n: drv_data->num_clks, |
351 | size: sizeof(*priv->clks), GFP_KERNEL); |
352 | if (!priv->clks) |
353 | return -ENOMEM; |
354 | for (i = 0; i < drv_data->num_clks; i++) |
355 | priv->clks[i].id = drv_data->clks[i]; |
356 | ret = devm_clk_bulk_get(dev: &pdev->dev, num_clks: drv_data->num_clks, clks: priv->clks); |
357 | if (ret) |
358 | return ret; |
359 | |
360 | phy = devm_phy_create(dev, node: np, ops: &rk_dphy_ops); |
361 | if (IS_ERR(ptr: phy)) { |
362 | dev_err(dev, "failed to create phy\n" ); |
363 | return PTR_ERR(ptr: phy); |
364 | } |
365 | phy_set_drvdata(phy, data: priv); |
366 | |
367 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
368 | |
369 | return PTR_ERR_OR_ZERO(ptr: phy_provider); |
370 | } |
371 | |
372 | static struct platform_driver rk_dphy_driver = { |
373 | .probe = rk_dphy_probe, |
374 | .driver = { |
375 | .name = "rockchip-mipi-dphy-rx0" , |
376 | .of_match_table = rk_dphy_dt_ids, |
377 | }, |
378 | }; |
379 | module_platform_driver(rk_dphy_driver); |
380 | |
381 | MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>" ); |
382 | MODULE_DESCRIPTION("Rockchip MIPI Synopsys DPHY RX0 driver" ); |
383 | MODULE_LICENSE("Dual MIT/GPL" ); |
384 | |