1 // SPDX-License-Identifier: (GPL-2.0-only)
2 /*
3  * Rockchip PCIe PHY driver
4  *
5  * Copyright (C) 2020 Amarula Solutions(India)
6  * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
7  * Copyright (C) 2016 ROCKCHIP, Inc.
8  */
9 
10 #include <common.h>
11 #include <clk.h>
12 #include <dm.h>
13 #include <asm/global_data.h>
14 #include <dm/device_compat.h>
15 #include <generic-phy.h>
16 #include <reset.h>
17 #include <syscon.h>
18 #include <asm/gpio.h>
19 #include <asm/io.h>
20 #include <linux/iopoll.h>
21 #include <asm/arch-rockchip/clock.h>
22 
23 DECLARE_GLOBAL_DATA_PTR;
24 
25 /*
26  * The higher 16-bit of this register is used for write protection
27  * only if BIT(x + 16) set to 1 the BIT(x) can be written.
28  */
29 #define HIWORD_UPDATE(val, mask, shift) \
30 		((val) << (shift) | (mask) << ((shift) + 16))
31 
32 #define PHY_MAX_LANE_NUM      4
33 #define PHY_CFG_DATA_SHIFT    7
34 #define PHY_CFG_ADDR_SHIFT    1
35 #define PHY_CFG_DATA_MASK     0xf
36 #define PHY_CFG_ADDR_MASK     0x3f
37 #define PHY_CFG_RD_MASK       0x3ff
38 #define PHY_CFG_WR_ENABLE     1
39 #define PHY_CFG_WR_DISABLE    1
40 #define PHY_CFG_WR_SHIFT      0
41 #define PHY_CFG_WR_MASK       1
42 #define PHY_CFG_PLL_LOCK      0x10
43 #define PHY_CFG_CLK_TEST      0x10
44 #define PHY_CFG_CLK_SCC       0x12
45 #define PHY_CFG_SEPE_RATE     BIT(3)
46 #define PHY_CFG_PLL_100M      BIT(3)
47 #define PHY_PLL_LOCKED        BIT(9)
48 #define PHY_PLL_OUTPUT        BIT(10)
49 #define PHY_LANE_RX_DET_SHIFT 11
50 #define PHY_LANE_RX_DET_TH    0x1
51 #define PHY_LANE_IDLE_OFF     0x1
52 #define PHY_LANE_IDLE_MASK    0x1
53 #define PHY_LANE_IDLE_A_SHIFT 3
54 #define PHY_LANE_IDLE_B_SHIFT 4
55 #define PHY_LANE_IDLE_C_SHIFT 5
56 #define PHY_LANE_IDLE_D_SHIFT 6
57 
58 struct rockchip_pcie_phy_data {
59 	unsigned int pcie_conf;
60 	unsigned int pcie_status;
61 	unsigned int pcie_laneoff;
62 };
63 
64 struct rockchip_pcie_phy {
65 	void *reg_base;
66 	struct clk refclk;
67 	struct reset_ctl phy_rst;
68 	const struct rockchip_pcie_phy_data *data;
69 };
70 
phy_wr_cfg(struct rockchip_pcie_phy * priv,u32 addr,u32 data)71 static void phy_wr_cfg(struct rockchip_pcie_phy *priv, u32 addr, u32 data)
72 {
73 	u32 reg;
74 
75 	reg = HIWORD_UPDATE(data, PHY_CFG_DATA_MASK, PHY_CFG_DATA_SHIFT);
76 	reg |= HIWORD_UPDATE(addr, PHY_CFG_ADDR_MASK, PHY_CFG_ADDR_SHIFT);
77 	writel(reg, priv->reg_base + priv->data->pcie_conf);
78 
79 	udelay(1);
80 
81 	reg = HIWORD_UPDATE(PHY_CFG_WR_ENABLE,
82 			    PHY_CFG_WR_MASK,
83 			    PHY_CFG_WR_SHIFT);
84 	writel(reg, priv->reg_base + priv->data->pcie_conf);
85 
86 	udelay(1);
87 
88 	reg = HIWORD_UPDATE(PHY_CFG_WR_DISABLE,
89 			    PHY_CFG_WR_MASK,
90 			    PHY_CFG_WR_SHIFT);
91 	writel(reg, priv->reg_base + priv->data->pcie_conf);
92 }
93 
rockchip_pcie_phy_power_on(struct phy * phy)94 static int rockchip_pcie_phy_power_on(struct phy *phy)
95 {
96 	struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
97 	int ret = 0;
98 	u32 reg, status;
99 
100 	ret = reset_deassert(&priv->phy_rst);
101 	if (ret) {
102 		dev_err(phy->dev, "failed to assert phy reset\n");
103 		return ret;
104 	}
105 
106 	reg = HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
107 			    PHY_CFG_ADDR_MASK,
108 			    PHY_CFG_ADDR_SHIFT);
109 	writel(reg, priv->reg_base + priv->data->pcie_conf);
110 
111 	reg = HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
112 			    PHY_LANE_IDLE_MASK,
113 			    PHY_LANE_IDLE_A_SHIFT);
114 	writel(reg, priv->reg_base + priv->data->pcie_laneoff);
115 
116 	ret = -EINVAL;
117 	ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status,
118 				       status,
119 				       status & PHY_PLL_LOCKED,
120 				       20 * 1000,
121 				       50);
122 	if (ret) {
123 		dev_err(phy->dev, "pll lock timeout!\n");
124 		goto err_pll_lock;
125 	}
126 
127 	phy_wr_cfg(priv, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE);
128 	phy_wr_cfg(priv, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M);
129 
130 	ret = -ETIMEDOUT;
131 	ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status,
132 				       status,
133 				       !(status & PHY_PLL_OUTPUT),
134 				       20 * 1000,
135 				       50);
136 	if (ret) {
137 		dev_err(phy->dev, "pll output enable timeout!\n");
138 		goto err_pll_lock;
139 	}
140 
141 	reg = HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
142 			    PHY_CFG_ADDR_MASK,
143 			    PHY_CFG_ADDR_SHIFT);
144 	writel(reg, priv->reg_base + priv->data->pcie_conf);
145 
146 	ret = -EINVAL;
147 	ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status,
148 				       status,
149 				       status & PHY_PLL_LOCKED,
150 				       20 * 1000,
151 				       50);
152 	if (ret) {
153 		dev_err(phy->dev, "pll relock timeout!\n");
154 		goto err_pll_lock;
155 	}
156 
157 	return 0;
158 
159 err_pll_lock:
160 	reset_assert(&priv->phy_rst);
161 	return ret;
162 }
163 
rockchip_pcie_phy_power_off(struct phy * phy)164 static int rockchip_pcie_phy_power_off(struct phy *phy)
165 {
166 	struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
167 	int ret;
168 	u32 reg;
169 
170 	reg = HIWORD_UPDATE(PHY_LANE_IDLE_OFF,
171 			    PHY_LANE_IDLE_MASK,
172 			    PHY_LANE_IDLE_A_SHIFT);
173 	writel(reg, priv->reg_base + priv->data->pcie_laneoff);
174 
175 	ret = reset_assert(&priv->phy_rst);
176 	if (ret) {
177 		dev_err(phy->dev, "failed to assert phy reset\n");
178 		return ret;
179 	}
180 
181 	return 0;
182 }
183 
rockchip_pcie_phy_init(struct phy * phy)184 static int rockchip_pcie_phy_init(struct phy *phy)
185 {
186 	struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
187 	int ret;
188 
189 	ret = clk_enable(&priv->refclk);
190 	if (ret) {
191 		dev_err(phy->dev, "failed to enable refclk clock\n");
192 		return ret;
193 	}
194 
195 	ret = reset_assert(&priv->phy_rst);
196 	if (ret) {
197 		dev_err(phy->dev, "failed to assert phy reset\n");
198 		goto err_reset;
199 	}
200 
201 	return 0;
202 
203 err_reset:
204 	clk_disable(&priv->refclk);
205 	return ret;
206 }
207 
rockchip_pcie_phy_exit(struct phy * phy)208 static int rockchip_pcie_phy_exit(struct phy *phy)
209 {
210 	struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev);
211 
212 	clk_disable(&priv->refclk);
213 
214 	return 0;
215 }
216 
217 static struct phy_ops rockchip_pcie_phy_ops = {
218 	.init = rockchip_pcie_phy_init,
219 	.power_on = rockchip_pcie_phy_power_on,
220 	.power_off = rockchip_pcie_phy_power_off,
221 	.exit = rockchip_pcie_phy_exit,
222 };
223 
rockchip_pcie_phy_probe(struct udevice * dev)224 static int rockchip_pcie_phy_probe(struct udevice *dev)
225 {
226 	struct rockchip_pcie_phy *priv = dev_get_priv(dev);
227 	int ret;
228 
229 	priv->data = (const struct rockchip_pcie_phy_data *)
230 						dev_get_driver_data(dev);
231 	if (!priv->data)
232 		return -EINVAL;
233 
234 	priv->reg_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
235 
236 	ret = clk_get_by_name(dev, "refclk", &priv->refclk);
237 	if (ret) {
238 		dev_err(dev, "failed to get refclk clock phandle\n");
239 		return ret;
240 	}
241 
242 	ret = reset_get_by_name(dev, "phy", &priv->phy_rst);
243 	if (ret) {
244 		dev_err(dev, "failed to get phy reset phandle\n");
245 		return ret;
246 	}
247 
248 	return 0;
249 }
250 
251 static const struct rockchip_pcie_phy_data rk3399_pcie_data = {
252 	.pcie_conf = 0xe220,
253 	.pcie_status = 0xe2a4,
254 	.pcie_laneoff = 0xe214,
255 };
256 
257 static const struct udevice_id rockchip_pcie_phy_ids[] = {
258 	{
259 		.compatible = "rockchip,rk3399-pcie-phy",
260 		.data = (ulong)&rk3399_pcie_data,
261 	},
262 	{ /* sentile */ }
263 };
264 
265 U_BOOT_DRIVER(rockchip_pcie_phy) = {
266 	.name	= "rockchip_pcie_phy",
267 	.id	= UCLASS_PHY,
268 	.of_match = rockchip_pcie_phy_ids,
269 	.ops = &rockchip_pcie_phy_ops,
270 	.probe = rockchip_pcie_phy_probe,
271 	.priv_auto	= sizeof(struct rockchip_pcie_phy),
272 };
273