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