brintos

brintos / linux-shallow public Read only

0
0
Text · 13.8 KiB · 98c92d6 Raw
482 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Rockchip MIPI RX Innosilicon DPHY driver4 *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	0x043025 26#define RK3326_GRF_PD_VI_CON_OFFSET	0x043027 28#define RK3368_GRF_SOC_CON6_OFFSET	0x041829 30#define RK3568_GRF_VI_CON0		0x034031#define RK3568_GRF_VI_CON1		0x034432 33/* PHY */34#define CSIDPHY_CTRL_LANE_ENABLE		0x0035#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			0x0441#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			0x8047#define CSIDPHY_CTRL_DIG_RST_UNDEFINED		0x1e48#define CSIDPHY_CTRL_DIG_RST_RESET		BIT(0)49 50/* offset after ths_settle_offset */51#define CSIDPHY_CLK_THS_SETTLE			052#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			057#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	0x16062#define RK3326_CSIDPHY_CLK_WR_THS_SETTLE	0x10063#define RK3368_CSIDPHY_CLK_WR_THS_SETTLE	0x10064#define RK3568_CSIDPHY_CLK_WR_THS_SETTLE	0x16065 66/* Calibration reception enable */67#define RK1808_CSIDPHY_CLK_CALIB_EN		0x16868#define RK3568_CSIDPHY_CLK_CALIB_EN		0x16869 70/*71 * The higher 16-bit of this register is used for write protection72 * 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 void 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 469static struct platform_driver rockchip_inno_csidphy_driver = {470	.driver = {471		.name = "rockchip-inno-csidphy",472		.of_match_table = rockchip_inno_csidphy_match_id,473	},474	.probe = rockchip_inno_csidphy_probe,475	.remove_new = rockchip_inno_csidphy_remove,476};477 478module_platform_driver(rockchip_inno_csidphy_driver);479MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");480MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");481MODULE_LICENSE("GPL v2");482