1 // SPDX-License-Identifier: GPL-2.0
3 * Rockchip MIPI RX Innosilicon DPHY driver
5 * Copyright (C) 2021 Fuzhou Rockchip Electronics Co., Ltd.
8 #include <linux/bitfield.h>
10 #include <linux/delay.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
15 #include <linux/of_platform.h>
16 #include <linux/phy/phy.h>
17 #include <linux/phy/phy-mipi-dphy.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/reset.h>
24 #define RK1808_GRF_PD_VI_CON_OFFSET 0x0430
26 #define RK3326_GRF_PD_VI_CON_OFFSET 0x0430
28 #define RK3368_GRF_SOC_CON6_OFFSET 0x0418
30 #define RK3568_GRF_VI_CON0 0x0340
31 #define RK3568_GRF_VI_CON1 0x0344
34 #define CSIDPHY_CTRL_LANE_ENABLE 0x00
35 #define CSIDPHY_CTRL_LANE_ENABLE_CK BIT(6)
36 #define CSIDPHY_CTRL_LANE_ENABLE_MASK GENMASK(5, 2)
37 #define CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED BIT(0)
39 /* not present on all variants */
40 #define CSIDPHY_CTRL_PWRCTL 0x04
41 #define CSIDPHY_CTRL_PWRCTL_UNDEFINED GENMASK(7, 5)
42 #define CSIDPHY_CTRL_PWRCTL_SYNCRST BIT(2)
43 #define CSIDPHY_CTRL_PWRCTL_LDO_PD BIT(1)
44 #define CSIDPHY_CTRL_PWRCTL_PLL_PD BIT(0)
46 #define CSIDPHY_CTRL_DIG_RST 0x80
47 #define CSIDPHY_CTRL_DIG_RST_UNDEFINED 0x1e
48 #define CSIDPHY_CTRL_DIG_RST_RESET BIT(0)
50 /* offset after ths_settle_offset */
51 #define CSIDPHY_CLK_THS_SETTLE 0
52 #define CSIDPHY_LANE_THS_SETTLE(n) (((n) + 1) * 0x80)
53 #define CSIDPHY_THS_SETTLE_MASK GENMASK(6, 0)
55 /* offset after calib_offset */
56 #define CSIDPHY_CLK_CALIB_EN 0
57 #define CSIDPHY_LANE_CALIB_EN(n) (((n) + 1) * 0x80)
58 #define CSIDPHY_CALIB_EN BIT(7)
60 /* Configure the count time of the THS-SETTLE by protocol. */
61 #define RK1808_CSIDPHY_CLK_WR_THS_SETTLE 0x160
62 #define RK3326_CSIDPHY_CLK_WR_THS_SETTLE 0x100
63 #define RK3368_CSIDPHY_CLK_WR_THS_SETTLE 0x100
64 #define RK3568_CSIDPHY_CLK_WR_THS_SETTLE 0x160
66 /* Calibration reception enable */
67 #define RK1808_CSIDPHY_CLK_CALIB_EN 0x168
68 #define RK3568_CSIDPHY_CLK_CALIB_EN 0x168
71 * The higher 16-bit of this register is used for write protection
72 * only if BIT(x + 16) set to 1 the BIT(x) can be written.
74 #define HIWORD_UPDATE(val, mask, shift) \
75 ((val) << (shift) | (mask) << ((shift) + 16))
77 #define HZ_TO_MHZ(freq) div_u64(freq, 1000 * 1000)
81 GRF_DPHY_CSIPHY_FORCERXMODE
,
82 GRF_DPHY_CSIPHY_CLKLANE_EN
,
83 GRF_DPHY_CSIPHY_DATALANE_EN
,
92 #define PHY_REG(_offset, _width, _shift) \
93 { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
95 static const struct dphy_reg rk1808_grf_dphy_regs
[] = {
96 [GRF_DPHY_CSIPHY_FORCERXMODE
] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET
, 4, 0),
97 [GRF_DPHY_CSIPHY_CLKLANE_EN
] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET
, 1, 8),
98 [GRF_DPHY_CSIPHY_DATALANE_EN
] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET
, 4, 4),
101 static const struct dphy_reg rk3326_grf_dphy_regs
[] = {
102 [GRF_DPHY_CSIPHY_FORCERXMODE
] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET
, 4, 0),
103 [GRF_DPHY_CSIPHY_CLKLANE_EN
] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET
, 1, 8),
104 [GRF_DPHY_CSIPHY_DATALANE_EN
] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET
, 4, 4),
107 static const struct dphy_reg rk3368_grf_dphy_regs
[] = {
108 [GRF_DPHY_CSIPHY_FORCERXMODE
] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET
, 4, 8),
111 static const struct dphy_reg rk3568_grf_dphy_regs
[] = {
112 [GRF_DPHY_CSIPHY_FORCERXMODE
] = PHY_REG(RK3568_GRF_VI_CON0
, 4, 0),
113 [GRF_DPHY_CSIPHY_DATALANE_EN
] = PHY_REG(RK3568_GRF_VI_CON0
, 4, 4),
114 [GRF_DPHY_CSIPHY_CLKLANE_EN
] = PHY_REG(RK3568_GRF_VI_CON0
, 1, 8),
117 struct hsfreq_range
{
122 struct dphy_drv_data
{
124 int ths_settle_offset
;
126 const struct hsfreq_range
*hsfreq_ranges
;
127 int num_hsfreq_ranges
;
128 const struct dphy_reg
*grf_regs
;
131 struct rockchip_inno_csidphy
{
133 void __iomem
*phy_base
;
136 struct reset_control
*rst
;
137 const struct dphy_drv_data
*drv_data
;
138 struct phy_configure_opts_mipi_dphy config
;
142 static inline void write_grf_reg(struct rockchip_inno_csidphy
*priv
,
145 const struct dphy_drv_data
*drv_data
= priv
->drv_data
;
146 const struct dphy_reg
*reg
= &drv_data
->grf_regs
[index
];
149 regmap_write(priv
->grf
, reg
->offset
,
150 HIWORD_UPDATE(value
, reg
->mask
, reg
->shift
));
153 /* These tables must be sorted by .range_h ascending. */
154 static const struct hsfreq_range rk1808_mipidphy_hsfreq_ranges
[] = {
155 { 109, 0x02}, { 149, 0x03}, { 199, 0x06}, { 249, 0x06},
156 { 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e},
157 { 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e},
158 {1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37},
159 {2199, 0x3c}, {2399, 0x41}, {2499, 0x46}
162 static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges
[] = {
163 { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
164 { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
165 { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
166 {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
169 static const struct hsfreq_range rk3368_mipidphy_hsfreq_ranges
[] = {
170 { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
171 { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
172 { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
173 {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
176 static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy
*priv
,
177 int hsfreq
, int offset
)
179 const struct dphy_drv_data
*drv_data
= priv
->drv_data
;
182 val
= readl(priv
->phy_base
+ drv_data
->ths_settle_offset
+ offset
);
183 val
&= ~CSIDPHY_THS_SETTLE_MASK
;
185 writel(val
, priv
->phy_base
+ drv_data
->ths_settle_offset
+ offset
);
188 static int rockchip_inno_csidphy_configure(struct phy
*phy
,
189 union phy_configure_opts
*opts
)
191 struct rockchip_inno_csidphy
*priv
= phy_get_drvdata(phy
);
192 const struct dphy_drv_data
*drv_data
= priv
->drv_data
;
193 struct phy_configure_opts_mipi_dphy
*config
= &opts
->mipi_dphy
;
194 unsigned int hsfreq
= 0;
199 /* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
200 ret
= phy_mipi_dphy_config_validate(config
);
204 data_rate_mbps
= HZ_TO_MHZ(config
->hs_clk_rate
);
206 dev_dbg(priv
->dev
, "lanes %d - data_rate_mbps %llu\n",
207 config
->lanes
, data_rate_mbps
);
208 for (i
= 0; i
< drv_data
->num_hsfreq_ranges
; i
++) {
209 if (drv_data
->hsfreq_ranges
[i
].range_h
>= data_rate_mbps
) {
210 hsfreq
= drv_data
->hsfreq_ranges
[i
].cfg_bit
;
217 priv
->hsfreq
= hsfreq
;
218 priv
->config
= *config
;
222 static int rockchip_inno_csidphy_power_on(struct phy
*phy
)
224 struct rockchip_inno_csidphy
*priv
= phy_get_drvdata(phy
);
225 const struct dphy_drv_data
*drv_data
= priv
->drv_data
;
226 u64 data_rate_mbps
= HZ_TO_MHZ(priv
->config
.hs_clk_rate
);
230 ret
= clk_enable(priv
->pclk
);
234 ret
= pm_runtime_resume_and_get(priv
->dev
);
236 clk_disable(priv
->pclk
);
241 if (drv_data
->pwrctl_offset
>= 0)
242 writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED
|
243 CSIDPHY_CTRL_PWRCTL_SYNCRST
,
244 priv
->phy_base
+ drv_data
->pwrctl_offset
);
246 /* set data lane num and enable clock lane */
247 val
= FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_MASK
, GENMASK(priv
->config
.lanes
- 1, 0)) |
248 FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_CK
, 1) |
249 FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED
, 1);
250 writel(val
, priv
->phy_base
+ CSIDPHY_CTRL_LANE_ENABLE
);
252 /* Reset dphy analog part */
253 if (drv_data
->pwrctl_offset
>= 0)
254 writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED
,
255 priv
->phy_base
+ drv_data
->pwrctl_offset
);
256 usleep_range(500, 1000);
258 /* Reset dphy digital part */
259 writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED
,
260 priv
->phy_base
+ CSIDPHY_CTRL_DIG_RST
);
261 writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED
+ CSIDPHY_CTRL_DIG_RST_RESET
,
262 priv
->phy_base
+ CSIDPHY_CTRL_DIG_RST
);
264 /* not into receive mode/wait stopstate */
265 write_grf_reg(priv
, GRF_DPHY_CSIPHY_FORCERXMODE
, 0x0);
267 /* enable calibration */
268 if (data_rate_mbps
> 1500 && drv_data
->calib_offset
>= 0) {
269 writel(CSIDPHY_CALIB_EN
,
270 priv
->phy_base
+ drv_data
->calib_offset
+
271 CSIDPHY_CLK_CALIB_EN
);
272 for (i
= 0; i
< priv
->config
.lanes
; i
++)
273 writel(CSIDPHY_CALIB_EN
,
274 priv
->phy_base
+ drv_data
->calib_offset
+
275 CSIDPHY_LANE_CALIB_EN(i
));
278 rockchip_inno_csidphy_ths_settle(priv
, priv
->hsfreq
,
279 CSIDPHY_CLK_THS_SETTLE
);
280 for (i
= 0; i
< priv
->config
.lanes
; i
++)
281 rockchip_inno_csidphy_ths_settle(priv
, priv
->hsfreq
,
282 CSIDPHY_LANE_THS_SETTLE(i
));
284 write_grf_reg(priv
, GRF_DPHY_CSIPHY_CLKLANE_EN
, 0x1);
285 write_grf_reg(priv
, GRF_DPHY_CSIPHY_DATALANE_EN
,
286 GENMASK(priv
->config
.lanes
- 1, 0));
291 static int rockchip_inno_csidphy_power_off(struct phy
*phy
)
293 struct rockchip_inno_csidphy
*priv
= phy_get_drvdata(phy
);
294 const struct dphy_drv_data
*drv_data
= priv
->drv_data
;
296 /* disable all lanes */
297 writel(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED
,
298 priv
->phy_base
+ CSIDPHY_CTRL_LANE_ENABLE
);
300 /* disable pll and ldo */
301 if (drv_data
->pwrctl_offset
>= 0)
302 writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED
|
303 CSIDPHY_CTRL_PWRCTL_LDO_PD
|
304 CSIDPHY_CTRL_PWRCTL_PLL_PD
,
305 priv
->phy_base
+ drv_data
->pwrctl_offset
);
306 usleep_range(500, 1000);
308 pm_runtime_put(priv
->dev
);
309 clk_disable(priv
->pclk
);
314 static int rockchip_inno_csidphy_init(struct phy
*phy
)
316 struct rockchip_inno_csidphy
*priv
= phy_get_drvdata(phy
);
318 return clk_prepare(priv
->pclk
);
321 static int rockchip_inno_csidphy_exit(struct phy
*phy
)
323 struct rockchip_inno_csidphy
*priv
= phy_get_drvdata(phy
);
325 clk_unprepare(priv
->pclk
);
330 static const struct phy_ops rockchip_inno_csidphy_ops
= {
331 .power_on
= rockchip_inno_csidphy_power_on
,
332 .power_off
= rockchip_inno_csidphy_power_off
,
333 .init
= rockchip_inno_csidphy_init
,
334 .exit
= rockchip_inno_csidphy_exit
,
335 .configure
= rockchip_inno_csidphy_configure
,
336 .owner
= THIS_MODULE
,
339 static const struct dphy_drv_data rk1808_mipidphy_drv_data
= {
341 .ths_settle_offset
= RK1808_CSIDPHY_CLK_WR_THS_SETTLE
,
342 .calib_offset
= RK1808_CSIDPHY_CLK_CALIB_EN
,
343 .hsfreq_ranges
= rk1808_mipidphy_hsfreq_ranges
,
344 .num_hsfreq_ranges
= ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges
),
345 .grf_regs
= rk1808_grf_dphy_regs
,
348 static const struct dphy_drv_data rk3326_mipidphy_drv_data
= {
349 .pwrctl_offset
= CSIDPHY_CTRL_PWRCTL
,
350 .ths_settle_offset
= RK3326_CSIDPHY_CLK_WR_THS_SETTLE
,
352 .hsfreq_ranges
= rk3326_mipidphy_hsfreq_ranges
,
353 .num_hsfreq_ranges
= ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges
),
354 .grf_regs
= rk3326_grf_dphy_regs
,
357 static const struct dphy_drv_data rk3368_mipidphy_drv_data
= {
358 .pwrctl_offset
= CSIDPHY_CTRL_PWRCTL
,
359 .ths_settle_offset
= RK3368_CSIDPHY_CLK_WR_THS_SETTLE
,
361 .hsfreq_ranges
= rk3368_mipidphy_hsfreq_ranges
,
362 .num_hsfreq_ranges
= ARRAY_SIZE(rk3368_mipidphy_hsfreq_ranges
),
363 .grf_regs
= rk3368_grf_dphy_regs
,
366 static const struct dphy_drv_data rk3568_mipidphy_drv_data
= {
368 .ths_settle_offset
= RK3568_CSIDPHY_CLK_WR_THS_SETTLE
,
369 .calib_offset
= RK3568_CSIDPHY_CLK_CALIB_EN
,
370 .hsfreq_ranges
= rk1808_mipidphy_hsfreq_ranges
,
371 .num_hsfreq_ranges
= ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges
),
372 .grf_regs
= rk3568_grf_dphy_regs
,
375 static const struct of_device_id rockchip_inno_csidphy_match_id
[] = {
377 .compatible
= "rockchip,px30-csi-dphy",
378 .data
= &rk3326_mipidphy_drv_data
,
381 .compatible
= "rockchip,rk1808-csi-dphy",
382 .data
= &rk1808_mipidphy_drv_data
,
385 .compatible
= "rockchip,rk3326-csi-dphy",
386 .data
= &rk3326_mipidphy_drv_data
,
389 .compatible
= "rockchip,rk3368-csi-dphy",
390 .data
= &rk3368_mipidphy_drv_data
,
393 .compatible
= "rockchip,rk3568-csi-dphy",
394 .data
= &rk3568_mipidphy_drv_data
,
398 MODULE_DEVICE_TABLE(of
, rockchip_inno_csidphy_match_id
);
400 static int rockchip_inno_csidphy_probe(struct platform_device
*pdev
)
402 struct rockchip_inno_csidphy
*priv
;
403 struct device
*dev
= &pdev
->dev
;
404 struct phy_provider
*phy_provider
;
407 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
412 platform_set_drvdata(pdev
, priv
);
414 priv
->drv_data
= of_device_get_match_data(dev
);
415 if (!priv
->drv_data
) {
416 dev_err(dev
, "Can't find device data\n");
420 priv
->grf
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
422 if (IS_ERR(priv
->grf
)) {
423 dev_err(dev
, "Can't find GRF syscon\n");
424 return PTR_ERR(priv
->grf
);
427 priv
->phy_base
= devm_platform_ioremap_resource(pdev
, 0);
428 if (IS_ERR(priv
->phy_base
))
429 return PTR_ERR(priv
->phy_base
);
431 priv
->pclk
= devm_clk_get(dev
, "pclk");
432 if (IS_ERR(priv
->pclk
)) {
433 dev_err(dev
, "failed to get pclk\n");
434 return PTR_ERR(priv
->pclk
);
437 priv
->rst
= devm_reset_control_get(dev
, "apb");
438 if (IS_ERR(priv
->rst
)) {
439 dev_err(dev
, "failed to get system reset control\n");
440 return PTR_ERR(priv
->rst
);
443 phy
= devm_phy_create(dev
, NULL
, &rockchip_inno_csidphy_ops
);
445 dev_err(dev
, "failed to create phy\n");
449 phy_set_drvdata(phy
, priv
);
451 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
452 if (IS_ERR(phy_provider
)) {
453 dev_err(dev
, "failed to register phy provider\n");
454 return PTR_ERR(phy_provider
);
457 pm_runtime_enable(dev
);
462 static void rockchip_inno_csidphy_remove(struct platform_device
*pdev
)
464 struct rockchip_inno_csidphy
*priv
= platform_get_drvdata(pdev
);
466 pm_runtime_disable(priv
->dev
);
469 static struct platform_driver rockchip_inno_csidphy_driver
= {
471 .name
= "rockchip-inno-csidphy",
472 .of_match_table
= rockchip_inno_csidphy_match_id
,
474 .probe
= rockchip_inno_csidphy_probe
,
475 .remove
= rockchip_inno_csidphy_remove
,
478 module_platform_driver(rockchip_inno_csidphy_driver
);
479 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
480 MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");
481 MODULE_LICENSE("GPL v2");