162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Rockchip PCIe PHY driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
662306a36Sopenharmony_ci * Copyright (C) 2016 ROCKCHIP, Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/of_address.h>
1662306a36Sopenharmony_ci#include <linux/of_platform.h>
1762306a36Sopenharmony_ci#include <linux/phy/phy.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci#include <linux/reset.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * The higher 16-bit of this register is used for write protection
2462306a36Sopenharmony_ci * only if BIT(x + 16) set to 1 the BIT(x) can be written.
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci#define HIWORD_UPDATE(val, mask, shift) \
2762306a36Sopenharmony_ci		((val) << (shift) | (mask) << ((shift) + 16))
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define PHY_MAX_LANE_NUM      4
3062306a36Sopenharmony_ci#define PHY_CFG_DATA_SHIFT    7
3162306a36Sopenharmony_ci#define PHY_CFG_ADDR_SHIFT    1
3262306a36Sopenharmony_ci#define PHY_CFG_DATA_MASK     0xf
3362306a36Sopenharmony_ci#define PHY_CFG_ADDR_MASK     0x3f
3462306a36Sopenharmony_ci#define PHY_CFG_RD_MASK       0x3ff
3562306a36Sopenharmony_ci#define PHY_CFG_WR_ENABLE     1
3662306a36Sopenharmony_ci#define PHY_CFG_WR_DISABLE    1
3762306a36Sopenharmony_ci#define PHY_CFG_WR_SHIFT      0
3862306a36Sopenharmony_ci#define PHY_CFG_WR_MASK       1
3962306a36Sopenharmony_ci#define PHY_CFG_PLL_LOCK      0x10
4062306a36Sopenharmony_ci#define PHY_CFG_CLK_TEST      0x10
4162306a36Sopenharmony_ci#define PHY_CFG_CLK_SCC       0x12
4262306a36Sopenharmony_ci#define PHY_CFG_SEPE_RATE     BIT(3)
4362306a36Sopenharmony_ci#define PHY_CFG_PLL_100M      BIT(3)
4462306a36Sopenharmony_ci#define PHY_PLL_LOCKED        BIT(9)
4562306a36Sopenharmony_ci#define PHY_PLL_OUTPUT        BIT(10)
4662306a36Sopenharmony_ci#define PHY_LANE_A_STATUS     0x30
4762306a36Sopenharmony_ci#define PHY_LANE_B_STATUS     0x31
4862306a36Sopenharmony_ci#define PHY_LANE_C_STATUS     0x32
4962306a36Sopenharmony_ci#define PHY_LANE_D_STATUS     0x33
5062306a36Sopenharmony_ci#define PHY_LANE_RX_DET_SHIFT 11
5162306a36Sopenharmony_ci#define PHY_LANE_RX_DET_TH    0x1
5262306a36Sopenharmony_ci#define PHY_LANE_IDLE_OFF     0x1
5362306a36Sopenharmony_ci#define PHY_LANE_IDLE_MASK    0x1
5462306a36Sopenharmony_ci#define PHY_LANE_IDLE_A_SHIFT 3
5562306a36Sopenharmony_ci#define PHY_LANE_IDLE_B_SHIFT 4
5662306a36Sopenharmony_ci#define PHY_LANE_IDLE_C_SHIFT 5
5762306a36Sopenharmony_ci#define PHY_LANE_IDLE_D_SHIFT 6
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct rockchip_pcie_data {
6062306a36Sopenharmony_ci	unsigned int pcie_conf;
6162306a36Sopenharmony_ci	unsigned int pcie_status;
6262306a36Sopenharmony_ci	unsigned int pcie_laneoff;
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct rockchip_pcie_phy {
6662306a36Sopenharmony_ci	struct rockchip_pcie_data *phy_data;
6762306a36Sopenharmony_ci	struct regmap *reg_base;
6862306a36Sopenharmony_ci	struct phy_pcie_instance {
6962306a36Sopenharmony_ci		struct phy *phy;
7062306a36Sopenharmony_ci		u32 index;
7162306a36Sopenharmony_ci	} phys[PHY_MAX_LANE_NUM];
7262306a36Sopenharmony_ci	struct mutex pcie_mutex;
7362306a36Sopenharmony_ci	struct reset_control *phy_rst;
7462306a36Sopenharmony_ci	struct clk *clk_pciephy_ref;
7562306a36Sopenharmony_ci	int pwr_cnt;
7662306a36Sopenharmony_ci	int init_cnt;
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic struct rockchip_pcie_phy *to_pcie_phy(struct phy_pcie_instance *inst)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	return container_of(inst, struct rockchip_pcie_phy,
8262306a36Sopenharmony_ci					phys[inst->index]);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic struct phy *rockchip_pcie_phy_of_xlate(struct device *dev,
8662306a36Sopenharmony_ci					      struct of_phandle_args *args)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct rockchip_pcie_phy *rk_phy = dev_get_drvdata(dev);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (args->args_count == 0)
9162306a36Sopenharmony_ci		return rk_phy->phys[0].phy;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (WARN_ON(args->args[0] >= PHY_MAX_LANE_NUM))
9462306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return rk_phy->phys[args->args[0]].phy;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic inline void phy_wr_cfg(struct rockchip_pcie_phy *rk_phy,
10162306a36Sopenharmony_ci			      u32 addr, u32 data)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
10462306a36Sopenharmony_ci		     HIWORD_UPDATE(data,
10562306a36Sopenharmony_ci				   PHY_CFG_DATA_MASK,
10662306a36Sopenharmony_ci				   PHY_CFG_DATA_SHIFT) |
10762306a36Sopenharmony_ci		     HIWORD_UPDATE(addr,
10862306a36Sopenharmony_ci				   PHY_CFG_ADDR_MASK,
10962306a36Sopenharmony_ci				   PHY_CFG_ADDR_SHIFT));
11062306a36Sopenharmony_ci	udelay(1);
11162306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
11262306a36Sopenharmony_ci		     HIWORD_UPDATE(PHY_CFG_WR_ENABLE,
11362306a36Sopenharmony_ci				   PHY_CFG_WR_MASK,
11462306a36Sopenharmony_ci				   PHY_CFG_WR_SHIFT));
11562306a36Sopenharmony_ci	udelay(1);
11662306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
11762306a36Sopenharmony_ci		     HIWORD_UPDATE(PHY_CFG_WR_DISABLE,
11862306a36Sopenharmony_ci				   PHY_CFG_WR_MASK,
11962306a36Sopenharmony_ci				   PHY_CFG_WR_SHIFT));
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int rockchip_pcie_phy_power_off(struct phy *phy)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct phy_pcie_instance *inst = phy_get_drvdata(phy);
12562306a36Sopenharmony_ci	struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
12662306a36Sopenharmony_ci	int err = 0;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	mutex_lock(&rk_phy->pcie_mutex);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base,
13162306a36Sopenharmony_ci		     rk_phy->phy_data->pcie_laneoff,
13262306a36Sopenharmony_ci		     HIWORD_UPDATE(PHY_LANE_IDLE_OFF,
13362306a36Sopenharmony_ci				   PHY_LANE_IDLE_MASK,
13462306a36Sopenharmony_ci				   PHY_LANE_IDLE_A_SHIFT + inst->index));
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (--rk_phy->pwr_cnt)
13762306a36Sopenharmony_ci		goto err_out;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	err = reset_control_assert(rk_phy->phy_rst);
14062306a36Sopenharmony_ci	if (err) {
14162306a36Sopenharmony_ci		dev_err(&phy->dev, "assert phy_rst err %d\n", err);
14262306a36Sopenharmony_ci		goto err_restore;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cierr_out:
14662306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cierr_restore:
15062306a36Sopenharmony_ci	rk_phy->pwr_cnt++;
15162306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base,
15262306a36Sopenharmony_ci		     rk_phy->phy_data->pcie_laneoff,
15362306a36Sopenharmony_ci		     HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
15462306a36Sopenharmony_ci				   PHY_LANE_IDLE_MASK,
15562306a36Sopenharmony_ci				   PHY_LANE_IDLE_A_SHIFT + inst->index));
15662306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
15762306a36Sopenharmony_ci	return err;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int rockchip_pcie_phy_power_on(struct phy *phy)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct phy_pcie_instance *inst = phy_get_drvdata(phy);
16362306a36Sopenharmony_ci	struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
16462306a36Sopenharmony_ci	int err = 0;
16562306a36Sopenharmony_ci	u32 status;
16662306a36Sopenharmony_ci	unsigned long timeout;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	mutex_lock(&rk_phy->pcie_mutex);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (rk_phy->pwr_cnt++)
17162306a36Sopenharmony_ci		goto err_out;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	err = reset_control_deassert(rk_phy->phy_rst);
17462306a36Sopenharmony_ci	if (err) {
17562306a36Sopenharmony_ci		dev_err(&phy->dev, "deassert phy_rst err %d\n", err);
17662306a36Sopenharmony_ci		goto err_pwr_cnt;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
18062306a36Sopenharmony_ci		     HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
18162306a36Sopenharmony_ci				   PHY_CFG_ADDR_MASK,
18262306a36Sopenharmony_ci				   PHY_CFG_ADDR_SHIFT));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base,
18562306a36Sopenharmony_ci		     rk_phy->phy_data->pcie_laneoff,
18662306a36Sopenharmony_ci		     HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
18762306a36Sopenharmony_ci				   PHY_LANE_IDLE_MASK,
18862306a36Sopenharmony_ci				   PHY_LANE_IDLE_A_SHIFT + inst->index));
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/*
19162306a36Sopenharmony_ci	 * No documented timeout value for phy operation below,
19262306a36Sopenharmony_ci	 * so we make it large enough here. And we use loop-break
19362306a36Sopenharmony_ci	 * method which should not be harmful.
19462306a36Sopenharmony_ci	 */
19562306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(1000);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	err = -EINVAL;
19862306a36Sopenharmony_ci	while (time_before(jiffies, timeout)) {
19962306a36Sopenharmony_ci		regmap_read(rk_phy->reg_base,
20062306a36Sopenharmony_ci			    rk_phy->phy_data->pcie_status,
20162306a36Sopenharmony_ci			    &status);
20262306a36Sopenharmony_ci		if (status & PHY_PLL_LOCKED) {
20362306a36Sopenharmony_ci			dev_dbg(&phy->dev, "pll locked!\n");
20462306a36Sopenharmony_ci			err = 0;
20562306a36Sopenharmony_ci			break;
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci		msleep(20);
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (err) {
21162306a36Sopenharmony_ci		dev_err(&phy->dev, "pll lock timeout!\n");
21262306a36Sopenharmony_ci		goto err_pll_lock;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	phy_wr_cfg(rk_phy, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE);
21662306a36Sopenharmony_ci	phy_wr_cfg(rk_phy, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	err = -ETIMEDOUT;
21962306a36Sopenharmony_ci	while (time_before(jiffies, timeout)) {
22062306a36Sopenharmony_ci		regmap_read(rk_phy->reg_base,
22162306a36Sopenharmony_ci			    rk_phy->phy_data->pcie_status,
22262306a36Sopenharmony_ci			    &status);
22362306a36Sopenharmony_ci		if (!(status & PHY_PLL_OUTPUT)) {
22462306a36Sopenharmony_ci			dev_dbg(&phy->dev, "pll output enable done!\n");
22562306a36Sopenharmony_ci			err = 0;
22662306a36Sopenharmony_ci			break;
22762306a36Sopenharmony_ci		}
22862306a36Sopenharmony_ci		msleep(20);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (err) {
23262306a36Sopenharmony_ci		dev_err(&phy->dev, "pll output enable timeout!\n");
23362306a36Sopenharmony_ci		goto err_pll_lock;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
23762306a36Sopenharmony_ci		     HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
23862306a36Sopenharmony_ci				   PHY_CFG_ADDR_MASK,
23962306a36Sopenharmony_ci				   PHY_CFG_ADDR_SHIFT));
24062306a36Sopenharmony_ci	err = -EINVAL;
24162306a36Sopenharmony_ci	while (time_before(jiffies, timeout)) {
24262306a36Sopenharmony_ci		regmap_read(rk_phy->reg_base,
24362306a36Sopenharmony_ci			    rk_phy->phy_data->pcie_status,
24462306a36Sopenharmony_ci			    &status);
24562306a36Sopenharmony_ci		if (status & PHY_PLL_LOCKED) {
24662306a36Sopenharmony_ci			dev_dbg(&phy->dev, "pll relocked!\n");
24762306a36Sopenharmony_ci			err = 0;
24862306a36Sopenharmony_ci			break;
24962306a36Sopenharmony_ci		}
25062306a36Sopenharmony_ci		msleep(20);
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (err) {
25462306a36Sopenharmony_ci		dev_err(&phy->dev, "pll relock timeout!\n");
25562306a36Sopenharmony_ci		goto err_pll_lock;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cierr_out:
25962306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
26062306a36Sopenharmony_ci	return 0;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cierr_pll_lock:
26362306a36Sopenharmony_ci	reset_control_assert(rk_phy->phy_rst);
26462306a36Sopenharmony_cierr_pwr_cnt:
26562306a36Sopenharmony_ci	rk_phy->pwr_cnt--;
26662306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
26762306a36Sopenharmony_ci	return err;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int rockchip_pcie_phy_init(struct phy *phy)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct phy_pcie_instance *inst = phy_get_drvdata(phy);
27362306a36Sopenharmony_ci	struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
27462306a36Sopenharmony_ci	int err = 0;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	mutex_lock(&rk_phy->pcie_mutex);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (rk_phy->init_cnt++)
27962306a36Sopenharmony_ci		goto err_out;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	err = clk_prepare_enable(rk_phy->clk_pciephy_ref);
28262306a36Sopenharmony_ci	if (err) {
28362306a36Sopenharmony_ci		dev_err(&phy->dev, "Fail to enable pcie ref clock.\n");
28462306a36Sopenharmony_ci		goto err_refclk;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	err = reset_control_assert(rk_phy->phy_rst);
28862306a36Sopenharmony_ci	if (err) {
28962306a36Sopenharmony_ci		dev_err(&phy->dev, "assert phy_rst err %d\n", err);
29062306a36Sopenharmony_ci		goto err_reset;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cierr_out:
29462306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
29562306a36Sopenharmony_ci	return 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cierr_reset:
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	clk_disable_unprepare(rk_phy->clk_pciephy_ref);
30062306a36Sopenharmony_cierr_refclk:
30162306a36Sopenharmony_ci	rk_phy->init_cnt--;
30262306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
30362306a36Sopenharmony_ci	return err;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic int rockchip_pcie_phy_exit(struct phy *phy)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct phy_pcie_instance *inst = phy_get_drvdata(phy);
30962306a36Sopenharmony_ci	struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	mutex_lock(&rk_phy->pcie_mutex);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (--rk_phy->init_cnt)
31462306a36Sopenharmony_ci		goto err_init_cnt;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	clk_disable_unprepare(rk_phy->clk_pciephy_ref);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cierr_init_cnt:
31962306a36Sopenharmony_ci	mutex_unlock(&rk_phy->pcie_mutex);
32062306a36Sopenharmony_ci	return 0;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic const struct phy_ops ops = {
32462306a36Sopenharmony_ci	.init		= rockchip_pcie_phy_init,
32562306a36Sopenharmony_ci	.exit		= rockchip_pcie_phy_exit,
32662306a36Sopenharmony_ci	.power_on	= rockchip_pcie_phy_power_on,
32762306a36Sopenharmony_ci	.power_off	= rockchip_pcie_phy_power_off,
32862306a36Sopenharmony_ci	.owner		= THIS_MODULE,
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic const struct rockchip_pcie_data rk3399_pcie_data = {
33262306a36Sopenharmony_ci	.pcie_conf = 0xe220,
33362306a36Sopenharmony_ci	.pcie_status = 0xe2a4,
33462306a36Sopenharmony_ci	.pcie_laneoff = 0xe214,
33562306a36Sopenharmony_ci};
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic const struct of_device_id rockchip_pcie_phy_dt_ids[] = {
33862306a36Sopenharmony_ci	{
33962306a36Sopenharmony_ci		.compatible = "rockchip,rk3399-pcie-phy",
34062306a36Sopenharmony_ci		.data = &rk3399_pcie_data,
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci	{}
34362306a36Sopenharmony_ci};
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_pcie_phy_dt_ids);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int rockchip_pcie_phy_probe(struct platform_device *pdev)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
35062306a36Sopenharmony_ci	struct rockchip_pcie_phy *rk_phy;
35162306a36Sopenharmony_ci	struct phy_provider *phy_provider;
35262306a36Sopenharmony_ci	struct regmap *grf;
35362306a36Sopenharmony_ci	const struct of_device_id *of_id;
35462306a36Sopenharmony_ci	int i;
35562306a36Sopenharmony_ci	u32 phy_num;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	grf = syscon_node_to_regmap(dev->parent->of_node);
35862306a36Sopenharmony_ci	if (IS_ERR(grf)) {
35962306a36Sopenharmony_ci		dev_err(dev, "Cannot find GRF syscon\n");
36062306a36Sopenharmony_ci		return PTR_ERR(grf);
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
36462306a36Sopenharmony_ci	if (!rk_phy)
36562306a36Sopenharmony_ci		return -ENOMEM;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	of_id = of_match_device(rockchip_pcie_phy_dt_ids, &pdev->dev);
36862306a36Sopenharmony_ci	if (!of_id)
36962306a36Sopenharmony_ci		return -EINVAL;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	rk_phy->phy_data = (struct rockchip_pcie_data *)of_id->data;
37262306a36Sopenharmony_ci	rk_phy->reg_base = grf;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	mutex_init(&rk_phy->pcie_mutex);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	rk_phy->phy_rst = devm_reset_control_get(dev, "phy");
37762306a36Sopenharmony_ci	if (IS_ERR(rk_phy->phy_rst)) {
37862306a36Sopenharmony_ci		if (PTR_ERR(rk_phy->phy_rst) != -EPROBE_DEFER)
37962306a36Sopenharmony_ci			dev_err(dev,
38062306a36Sopenharmony_ci				"missing phy property for reset controller\n");
38162306a36Sopenharmony_ci		return PTR_ERR(rk_phy->phy_rst);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	rk_phy->clk_pciephy_ref = devm_clk_get(dev, "refclk");
38562306a36Sopenharmony_ci	if (IS_ERR(rk_phy->clk_pciephy_ref)) {
38662306a36Sopenharmony_ci		dev_err(dev, "refclk not found.\n");
38762306a36Sopenharmony_ci		return PTR_ERR(rk_phy->clk_pciephy_ref);
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/* parse #phy-cells to see if it's legacy PHY model */
39162306a36Sopenharmony_ci	if (of_property_read_u32(dev->of_node, "#phy-cells", &phy_num))
39262306a36Sopenharmony_ci		return -ENOENT;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	phy_num = (phy_num == 0) ? 1 : PHY_MAX_LANE_NUM;
39562306a36Sopenharmony_ci	dev_dbg(dev, "phy number is %d\n", phy_num);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	for (i = 0; i < phy_num; i++) {
39862306a36Sopenharmony_ci		rk_phy->phys[i].phy = devm_phy_create(dev, dev->of_node, &ops);
39962306a36Sopenharmony_ci		if (IS_ERR(rk_phy->phys[i].phy)) {
40062306a36Sopenharmony_ci			dev_err(dev, "failed to create PHY%d\n", i);
40162306a36Sopenharmony_ci			return PTR_ERR(rk_phy->phys[i].phy);
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci		rk_phy->phys[i].index = i;
40462306a36Sopenharmony_ci		phy_set_drvdata(rk_phy->phys[i].phy, &rk_phy->phys[i]);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	platform_set_drvdata(pdev, rk_phy);
40862306a36Sopenharmony_ci	phy_provider = devm_of_phy_provider_register(dev,
40962306a36Sopenharmony_ci					rockchip_pcie_phy_of_xlate);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(phy_provider);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic struct platform_driver rockchip_pcie_driver = {
41562306a36Sopenharmony_ci	.probe		= rockchip_pcie_phy_probe,
41662306a36Sopenharmony_ci	.driver		= {
41762306a36Sopenharmony_ci		.name	= "rockchip-pcie-phy",
41862306a36Sopenharmony_ci		.of_match_table = rockchip_pcie_phy_dt_ids,
41962306a36Sopenharmony_ci	},
42062306a36Sopenharmony_ci};
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cimodule_platform_driver(rockchip_pcie_driver);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ciMODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");
42562306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip PCIe PHY driver");
42662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
427