Commit | Line | Data |
---|---|---|
2e9bffc4 SL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Rockchip PCIE3.0 phy driver | |
4 | * | |
5 | * Copyright (C) 2022 Rockchip Electronics Co., Ltd. | |
6 | */ | |
7 | ||
8 | #include <linux/clk.h> | |
9 | #include <linux/delay.h> | |
10 | #include <linux/io.h> | |
11 | #include <linux/iopoll.h> | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/mfd/syscon.h> | |
14 | #include <linux/module.h> | |
7559e757 | 15 | #include <linux/of.h> |
2e9bffc4 SL |
16 | #include <linux/phy/pcie.h> |
17 | #include <linux/phy/phy.h> | |
7559e757 | 18 | #include <linux/platform_device.h> |
2e9bffc4 SL |
19 | #include <linux/regmap.h> |
20 | #include <linux/reset.h> | |
21 | ||
22 | /* Register for RK3568 */ | |
23 | #define GRF_PCIE30PHY_CON1 0x4 | |
24 | #define GRF_PCIE30PHY_CON6 0x18 | |
25 | #define GRF_PCIE30PHY_CON9 0x24 | |
26 | #define GRF_PCIE30PHY_DA_OCM (BIT(15) | BIT(31)) | |
27 | #define GRF_PCIE30PHY_STATUS0 0x80 | |
28 | #define GRF_PCIE30PHY_WR_EN (0xf << 16) | |
29 | #define SRAM_INIT_DONE(reg) (reg & BIT(14)) | |
30 | ||
31 | #define RK3568_BIFURCATION_LANE_0_1 BIT(0) | |
32 | ||
33 | /* Register for RK3588 */ | |
34 | #define PHP_GRF_PCIESEL_CON 0x100 | |
35 | #define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 | |
36 | #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 | |
37 | #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 | |
38 | #define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) | |
39 | ||
40 | #define RK3588_BIFURCATION_LANE_0_1 BIT(0) | |
41 | #define RK3588_BIFURCATION_LANE_2_3 BIT(1) | |
42 | #define RK3588_LANE_AGGREGATION BIT(2) | |
55491a5f SR |
43 | #define RK3588_PCIE1LN_SEL_EN (GENMASK(1, 0) << 16) |
44 | #define RK3588_PCIE30_PHY_MODE_EN (GENMASK(2, 0) << 16) | |
2e9bffc4 SL |
45 | |
46 | struct rockchip_p3phy_ops; | |
47 | ||
48 | struct rockchip_p3phy_priv { | |
49 | const struct rockchip_p3phy_ops *ops; | |
50 | void __iomem *mmio; | |
51 | /* mode: RC, EP */ | |
52 | int mode; | |
53 | /* pcie30_phymode: Aggregation, Bifurcation */ | |
54 | int pcie30_phymode; | |
55 | struct regmap *phy_grf; | |
56 | struct regmap *pipe_grf; | |
57 | struct reset_control *p30phy; | |
58 | struct phy *phy; | |
59 | struct clk_bulk_data *clks; | |
60 | int num_clks; | |
61 | int num_lanes; | |
62 | u32 lanes[4]; | |
63 | }; | |
64 | ||
65 | struct rockchip_p3phy_ops { | |
66 | int (*phy_init)(struct rockchip_p3phy_priv *priv); | |
67 | }; | |
68 | ||
69 | static int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) | |
70 | { | |
71 | struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); | |
72 | ||
73 | /* Actually We don't care EP/RC mode, but just record it */ | |
74 | switch (submode) { | |
75 | case PHY_MODE_PCIE_RC: | |
76 | priv->mode = PHY_MODE_PCIE_RC; | |
77 | break; | |
78 | case PHY_MODE_PCIE_EP: | |
79 | priv->mode = PHY_MODE_PCIE_EP; | |
80 | break; | |
81 | default: | |
82 | dev_err(&phy->dev, "%s, invalid mode\n", __func__); | |
83 | return -EINVAL; | |
84 | } | |
85 | ||
86 | return 0; | |
87 | } | |
88 | ||
89 | static int rockchip_p3phy_rk3568_init(struct rockchip_p3phy_priv *priv) | |
90 | { | |
91 | struct phy *phy = priv->phy; | |
92 | bool bifurcation = false; | |
93 | int ret; | |
94 | u32 reg; | |
95 | ||
96 | /* Deassert PCIe PMA output clamp mode */ | |
97 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM); | |
98 | ||
99 | for (int i = 0; i < priv->num_lanes; i++) { | |
100 | dev_info(&phy->dev, "lane number %d, val %d\n", i, priv->lanes[i]); | |
101 | if (priv->lanes[i] > 1) | |
102 | bifurcation = true; | |
103 | } | |
104 | ||
105 | /* Set bifurcation if needed, and it doesn't care RC/EP */ | |
106 | if (bifurcation) { | |
107 | dev_info(&phy->dev, "bifurcation enabled\n"); | |
108 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, | |
109 | GRF_PCIE30PHY_WR_EN | RK3568_BIFURCATION_LANE_0_1); | |
110 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1, | |
111 | GRF_PCIE30PHY_DA_OCM); | |
112 | } else { | |
113 | dev_dbg(&phy->dev, "bifurcation disabled\n"); | |
114 | regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, | |
115 | GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1); | |
116 | } | |
117 | ||
118 | reset_control_deassert(priv->p30phy); | |
119 | ||
120 | ret = regmap_read_poll_timeout(priv->phy_grf, | |
121 | GRF_PCIE30PHY_STATUS0, | |
122 | reg, SRAM_INIT_DONE(reg), | |
123 | 0, 500); | |
124 | if (ret) | |
125 | dev_err(&priv->phy->dev, "%s: lock failed 0x%x, check input refclk and power supply\n", | |
126 | __func__, reg); | |
127 | return ret; | |
128 | } | |
129 | ||
130 | static const struct rockchip_p3phy_ops rk3568_ops = { | |
131 | .phy_init = rockchip_p3phy_rk3568_init, | |
132 | }; | |
133 | ||
134 | static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) | |
135 | { | |
136 | u32 reg = 0; | |
f8020dfb | 137 | u8 mode = RK3588_LANE_AGGREGATION; /* default */ |
2e9bffc4 SL |
138 | int ret; |
139 | ||
140 | /* Deassert PCIe PMA output clamp mode */ | |
141 | regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24)); | |
142 | ||
143 | /* Set bifurcation if needed */ | |
144 | for (int i = 0; i < priv->num_lanes; i++) { | |
2e9bffc4 | 145 | if (priv->lanes[i] > 1) |
f8020dfb MT |
146 | mode &= ~RK3588_LANE_AGGREGATION; |
147 | if (priv->lanes[i] == 3) | |
148 | mode |= RK3588_BIFURCATION_LANE_0_1; | |
149 | if (priv->lanes[i] == 4) | |
150 | mode |= RK3588_BIFURCATION_LANE_2_3; | |
2e9bffc4 SL |
151 | } |
152 | ||
f8020dfb | 153 | reg = mode; |
55491a5f SR |
154 | regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, |
155 | RK3588_PCIE30_PHY_MODE_EN | reg); | |
2e9bffc4 SL |
156 | |
157 | /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ | |
158 | if (!IS_ERR(priv->pipe_grf)) { | |
55491a5f | 159 | reg = mode & (RK3588_BIFURCATION_LANE_0_1 | RK3588_BIFURCATION_LANE_2_3); |
2e9bffc4 SL |
160 | if (reg) |
161 | regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, | |
55491a5f | 162 | RK3588_PCIE1LN_SEL_EN | reg); |
2e9bffc4 SL |
163 | } |
164 | ||
165 | reset_control_deassert(priv->p30phy); | |
166 | ||
167 | ret = regmap_read_poll_timeout(priv->phy_grf, | |
168 | RK3588_PCIE3PHY_GRF_PHY0_STATUS1, | |
169 | reg, RK3588_SRAM_INIT_DONE(reg), | |
170 | 0, 500); | |
171 | ret |= regmap_read_poll_timeout(priv->phy_grf, | |
172 | RK3588_PCIE3PHY_GRF_PHY1_STATUS1, | |
173 | reg, RK3588_SRAM_INIT_DONE(reg), | |
174 | 0, 500); | |
175 | if (ret) | |
176 | dev_err(&priv->phy->dev, "lock failed 0x%x, check input refclk and power supply\n", | |
177 | reg); | |
178 | return ret; | |
179 | } | |
180 | ||
181 | static const struct rockchip_p3phy_ops rk3588_ops = { | |
182 | .phy_init = rockchip_p3phy_rk3588_init, | |
183 | }; | |
184 | ||
185 | static int rochchip_p3phy_init(struct phy *phy) | |
186 | { | |
187 | struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); | |
188 | int ret; | |
189 | ||
190 | ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); | |
191 | if (ret) { | |
192 | dev_err(&priv->phy->dev, "failed to enable PCIe bulk clks %d\n", ret); | |
193 | return ret; | |
194 | } | |
195 | ||
196 | reset_control_assert(priv->p30phy); | |
197 | udelay(1); | |
198 | ||
199 | if (priv->ops->phy_init) { | |
200 | ret = priv->ops->phy_init(priv); | |
201 | if (ret) | |
202 | clk_bulk_disable_unprepare(priv->num_clks, priv->clks); | |
203 | } | |
204 | ||
205 | return ret; | |
206 | } | |
207 | ||
208 | static int rochchip_p3phy_exit(struct phy *phy) | |
209 | { | |
210 | struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); | |
211 | ||
212 | clk_bulk_disable_unprepare(priv->num_clks, priv->clks); | |
213 | reset_control_assert(priv->p30phy); | |
214 | return 0; | |
215 | } | |
216 | ||
217 | static const struct phy_ops rochchip_p3phy_ops = { | |
218 | .init = rochchip_p3phy_init, | |
219 | .exit = rochchip_p3phy_exit, | |
220 | .set_mode = rockchip_p3phy_set_mode, | |
221 | .owner = THIS_MODULE, | |
222 | }; | |
223 | ||
224 | static int rockchip_p3phy_probe(struct platform_device *pdev) | |
225 | { | |
226 | struct phy_provider *phy_provider; | |
227 | struct device *dev = &pdev->dev; | |
228 | struct rockchip_p3phy_priv *priv; | |
229 | struct device_node *np = dev->of_node; | |
2e9bffc4 SL |
230 | int ret; |
231 | ||
232 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
233 | if (!priv) | |
234 | return -ENOMEM; | |
235 | ||
8b8934ac | 236 | priv->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); |
2e9bffc4 SL |
237 | if (IS_ERR(priv->mmio)) { |
238 | ret = PTR_ERR(priv->mmio); | |
239 | return ret; | |
240 | } | |
241 | ||
242 | priv->ops = of_device_get_match_data(&pdev->dev); | |
243 | if (!priv->ops) { | |
244 | dev_err(dev, "no of match data provided\n"); | |
245 | return -EINVAL; | |
246 | } | |
247 | ||
248 | priv->phy_grf = syscon_regmap_lookup_by_phandle(np, "rockchip,phy-grf"); | |
249 | if (IS_ERR(priv->phy_grf)) { | |
250 | dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); | |
251 | return PTR_ERR(priv->phy_grf); | |
252 | } | |
253 | ||
37d40a21 AJ |
254 | if (of_device_is_compatible(np, "rockchip,rk3588-pcie3-phy")) { |
255 | priv->pipe_grf = | |
256 | syscon_regmap_lookup_by_phandle(dev->of_node, | |
257 | "rockchip,pipe-grf"); | |
258 | if (IS_ERR(priv->pipe_grf)) | |
259 | dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); | |
260 | } else { | |
261 | priv->pipe_grf = NULL; | |
262 | } | |
2e9bffc4 SL |
263 | |
264 | priv->num_lanes = of_property_read_variable_u32_array(dev->of_node, "data-lanes", | |
265 | priv->lanes, 2, | |
266 | ARRAY_SIZE(priv->lanes)); | |
267 | ||
268 | /* if no data-lanes assume aggregation */ | |
269 | if (priv->num_lanes == -EINVAL) { | |
270 | dev_dbg(dev, "no data-lanes property found\n"); | |
271 | priv->num_lanes = 1; | |
272 | priv->lanes[0] = 1; | |
273 | } else if (priv->num_lanes < 0) { | |
274 | dev_err(dev, "failed to read data-lanes property %d\n", priv->num_lanes); | |
275 | return priv->num_lanes; | |
276 | } | |
277 | ||
278 | priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); | |
279 | if (IS_ERR(priv->phy)) { | |
280 | dev_err(dev, "failed to create combphy\n"); | |
281 | return PTR_ERR(priv->phy); | |
282 | } | |
283 | ||
284 | priv->p30phy = devm_reset_control_get_optional_exclusive(dev, "phy"); | |
285 | if (IS_ERR(priv->p30phy)) { | |
286 | return dev_err_probe(dev, PTR_ERR(priv->p30phy), | |
287 | "failed to get phy reset control\n"); | |
288 | } | |
289 | if (!priv->p30phy) | |
290 | dev_info(dev, "no phy reset control specified\n"); | |
291 | ||
292 | priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks); | |
293 | if (priv->num_clks < 1) | |
294 | return -ENODEV; | |
295 | ||
296 | dev_set_drvdata(dev, priv); | |
297 | phy_set_drvdata(priv->phy, priv); | |
298 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | |
299 | return PTR_ERR_OR_ZERO(phy_provider); | |
300 | } | |
301 | ||
302 | static const struct of_device_id rockchip_p3phy_of_match[] = { | |
303 | { .compatible = "rockchip,rk3568-pcie3-phy", .data = &rk3568_ops }, | |
304 | { .compatible = "rockchip,rk3588-pcie3-phy", .data = &rk3588_ops }, | |
305 | { }, | |
306 | }; | |
307 | MODULE_DEVICE_TABLE(of, rockchip_p3phy_of_match); | |
308 | ||
309 | static struct platform_driver rockchip_p3phy_driver = { | |
310 | .probe = rockchip_p3phy_probe, | |
311 | .driver = { | |
312 | .name = "rockchip-snps-pcie3-phy", | |
313 | .of_match_table = rockchip_p3phy_of_match, | |
314 | }, | |
315 | }; | |
316 | module_platform_driver(rockchip_p3phy_driver); | |
317 | MODULE_DESCRIPTION("Rockchip Synopsys PCIe 3.0 PHY driver"); | |
318 | MODULE_LICENSE("GPL"); |