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