Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Rockchip MIPI RX Innosilicon DPHY driver
  4 *
  5 * Copyright (C) 2021 Fuzhou Rockchip Electronics Co., Ltd.
  6 */
  7
  8#include <linux/bitfield.h>
  9#include <linux/clk.h>
 10#include <linux/delay.h>
 11#include <linux/io.h>
 12#include <linux/mfd/syscon.h>
 13#include <linux/module.h>
 14#include <linux/of.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>
 22
 23/* GRF */
 24#define RK1808_GRF_PD_VI_CON_OFFSET	0x0430
 25
 26#define RK3326_GRF_PD_VI_CON_OFFSET	0x0430
 27
 28#define RK3368_GRF_SOC_CON6_OFFSET	0x0418
 29
 30#define RK3568_GRF_VI_CON0		0x0340
 31#define RK3568_GRF_VI_CON1		0x0344
 32
 33/* PHY */
 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)
 38
 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)
 45
 46#define CSIDPHY_CTRL_DIG_RST			0x80
 47#define CSIDPHY_CTRL_DIG_RST_UNDEFINED		0x1e
 48#define CSIDPHY_CTRL_DIG_RST_RESET		BIT(0)
 49
 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)
 54
 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)
 59
 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
 65
 66/* Calibration reception enable */
 67#define RK1808_CSIDPHY_CLK_CALIB_EN		0x168
 68#define RK3568_CSIDPHY_CLK_CALIB_EN		0x168
 69
 70/*
 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.
 73 */
 74#define HIWORD_UPDATE(val, mask, shift) \
 75		((val) << (shift) | (mask) << ((shift) + 16))
 76
 77#define HZ_TO_MHZ(freq)				div_u64(freq, 1000 * 1000)
 78
 79enum dphy_reg_id {
 80	/* rk1808 & rk3326 */
 81	GRF_DPHY_CSIPHY_FORCERXMODE,
 82	GRF_DPHY_CSIPHY_CLKLANE_EN,
 83	GRF_DPHY_CSIPHY_DATALANE_EN,
 84};
 85
 86struct dphy_reg {
 87	u32 offset;
 88	u32 mask;
 89	u32 shift;
 90};
 91
 92#define PHY_REG(_offset, _width, _shift) \
 93	{ .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
 94
 95static 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),
 99};
100
101static 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),
105};
106
107static const struct dphy_reg rk3368_grf_dphy_regs[] = {
108	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET, 4, 8),
109};
110
111static 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),
115};
116
117struct hsfreq_range {
118	u32 range_h;
119	u8 cfg_bit;
120};
121
122struct dphy_drv_data {
123	int pwrctl_offset;
124	int ths_settle_offset;
125	int calib_offset;
126	const struct hsfreq_range *hsfreq_ranges;
127	int num_hsfreq_ranges;
128	const struct dphy_reg *grf_regs;
129};
130
131struct rockchip_inno_csidphy {
132	struct device *dev;
133	void __iomem *phy_base;
134	struct clk *pclk;
135	struct regmap *grf;
136	struct reset_control *rst;
137	const struct dphy_drv_data *drv_data;
138	struct phy_configure_opts_mipi_dphy config;
139	u8 hsfreq;
140};
141
142static inline void write_grf_reg(struct rockchip_inno_csidphy *priv,
143				 int index, u8 value)
144{
145	const struct dphy_drv_data *drv_data = priv->drv_data;
146	const struct dphy_reg *reg = &drv_data->grf_regs[index];
147
148	if (reg->offset)
149		regmap_write(priv->grf, reg->offset,
150			     HIWORD_UPDATE(value, reg->mask, reg->shift));
151}
152
153/* These tables must be sorted by .range_h ascending. */
154static 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}
160};
161
162static 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}
167};
168
169static 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}
174};
175
176static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy *priv,
177					     int hsfreq, int offset)
178{
179	const struct dphy_drv_data *drv_data = priv->drv_data;
180	u32 val;
181
182	val = readl(priv->phy_base + drv_data->ths_settle_offset + offset);
183	val &= ~CSIDPHY_THS_SETTLE_MASK;
184	val |= hsfreq;
185	writel(val, priv->phy_base + drv_data->ths_settle_offset + offset);
186}
187
188static int rockchip_inno_csidphy_configure(struct phy *phy,
189					   union phy_configure_opts *opts)
190{
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;
195	unsigned int i;
196	u64 data_rate_mbps;
197	int ret;
198
199	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
200	ret = phy_mipi_dphy_config_validate(config);
201	if (ret)
202		return ret;
203
204	data_rate_mbps = HZ_TO_MHZ(config->hs_clk_rate);
205
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;
211			break;
212		}
213	}
214	if (!hsfreq)
215		return -EINVAL;
216
217	priv->hsfreq = hsfreq;
218	priv->config = *config;
219	return 0;
220}
221
222static int rockchip_inno_csidphy_power_on(struct phy *phy)
223{
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);
227	u32 val;
228	int ret, i;
229
230	ret = clk_enable(priv->pclk);
231	if (ret < 0)
232		return ret;
233
234	ret = pm_runtime_resume_and_get(priv->dev);
235	if (ret < 0) {
236		clk_disable(priv->pclk);
237		return ret;
238	}
239
240	/* phy start */
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);
245
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);
251
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);
257
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);
263
264	/* not into receive mode/wait stopstate */
265	write_grf_reg(priv, GRF_DPHY_CSIPHY_FORCERXMODE, 0x0);
266
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));
276	}
277
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));
283
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));
287
288	return 0;
289}
290
291static int rockchip_inno_csidphy_power_off(struct phy *phy)
292{
293	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
294	const struct dphy_drv_data *drv_data = priv->drv_data;
295
296	/* disable all lanes */
297	writel(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED,
298	       priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
299
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);
307
308	pm_runtime_put(priv->dev);
309	clk_disable(priv->pclk);
310
311	return 0;
312}
313
314static int rockchip_inno_csidphy_init(struct phy *phy)
315{
316	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
317
318	return clk_prepare(priv->pclk);
319}
320
321static int rockchip_inno_csidphy_exit(struct phy *phy)
322{
323	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
324
325	clk_unprepare(priv->pclk);
326
327	return 0;
328}
329
330static 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,
337};
338
339static const struct dphy_drv_data rk1808_mipidphy_drv_data = {
340	.pwrctl_offset = -1,
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,
346};
347
348static 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,
351	.calib_offset = -1,
352	.hsfreq_ranges = rk3326_mipidphy_hsfreq_ranges,
353	.num_hsfreq_ranges = ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges),
354	.grf_regs = rk3326_grf_dphy_regs,
355};
356
357static 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,
360	.calib_offset = -1,
361	.hsfreq_ranges = rk3368_mipidphy_hsfreq_ranges,
362	.num_hsfreq_ranges = ARRAY_SIZE(rk3368_mipidphy_hsfreq_ranges),
363	.grf_regs = rk3368_grf_dphy_regs,
364};
365
366static const struct dphy_drv_data rk3568_mipidphy_drv_data = {
367	.pwrctl_offset = -1,
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,
373};
374
375static const struct of_device_id rockchip_inno_csidphy_match_id[] = {
376	{
377		.compatible = "rockchip,px30-csi-dphy",
378		.data = &rk3326_mipidphy_drv_data,
379	},
380	{
381		.compatible = "rockchip,rk1808-csi-dphy",
382		.data = &rk1808_mipidphy_drv_data,
383	},
384	{
385		.compatible = "rockchip,rk3326-csi-dphy",
386		.data = &rk3326_mipidphy_drv_data,
387	},
388	{
389		.compatible = "rockchip,rk3368-csi-dphy",
390		.data = &rk3368_mipidphy_drv_data,
391	},
392	{
393		.compatible = "rockchip,rk3568-csi-dphy",
394		.data = &rk3568_mipidphy_drv_data,
395	},
396	{}
397};
398MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id);
399
400static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
401{
402	struct rockchip_inno_csidphy *priv;
403	struct device *dev = &pdev->dev;
404	struct phy_provider *phy_provider;
405	struct phy *phy;
406
407	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
408	if (!priv)
409		return -ENOMEM;
410
411	priv->dev = dev;
412	platform_set_drvdata(pdev, priv);
413
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");
417		return -ENODEV;
418	}
419
420	priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
421						    "rockchip,grf");
422	if (IS_ERR(priv->grf)) {
423		dev_err(dev, "Can't find GRF syscon\n");
424		return PTR_ERR(priv->grf);
425	}
426
427	priv->phy_base = devm_platform_ioremap_resource(pdev, 0);
428	if (IS_ERR(priv->phy_base))
429		return PTR_ERR(priv->phy_base);
430
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);
435	}
436
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);
441	}
442
443	phy = devm_phy_create(dev, NULL, &rockchip_inno_csidphy_ops);
444	if (IS_ERR(phy)) {
445		dev_err(dev, "failed to create phy\n");
446		return PTR_ERR(phy);
447	}
448
449	phy_set_drvdata(phy, priv);
450
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);
455	}
456
457	pm_runtime_enable(dev);
458
459	return 0;
460}
461
462static int rockchip_inno_csidphy_remove(struct platform_device *pdev)
463{
464	struct rockchip_inno_csidphy *priv = platform_get_drvdata(pdev);
465
466	pm_runtime_disable(priv->dev);
467
468	return 0;
469}
470
471static struct platform_driver rockchip_inno_csidphy_driver = {
472	.driver = {
473		.name = "rockchip-inno-csidphy",
474		.of_match_table = rockchip_inno_csidphy_match_id,
475	},
476	.probe = rockchip_inno_csidphy_probe,
477	.remove = rockchip_inno_csidphy_remove,
478};
479
480module_platform_driver(rockchip_inno_csidphy_driver);
481MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
482MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");
483MODULE_LICENSE("GPL v2");