1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Rockchip AXI PCIe host controller driver |
4 | * |
5 | * Copyright (c) 2016 Rockchip, Inc. |
6 | * |
7 | * Author: Shawn Lin <shawn.lin@rock-chips.com> |
8 | * Wenrui Li <wenrui.li@rock-chips.com> |
9 | * |
10 | * Bits taken from Synopsys DesignWare Host controller driver and |
11 | * ARM PCI Host generic driver. |
12 | */ |
13 | |
14 | #include <linux/clk.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/gpio/consumer.h> |
17 | #include <linux/iopoll.h> |
18 | #include <linux/of.h> |
19 | #include <linux/of_pci.h> |
20 | #include <linux/phy/phy.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/reset.h> |
23 | |
24 | #include "../pci.h" |
25 | #include "pcie-rockchip.h" |
26 | |
27 | int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) |
28 | { |
29 | struct device *dev = rockchip->dev; |
30 | struct platform_device *pdev = to_platform_device(dev); |
31 | struct device_node *node = dev->of_node; |
32 | struct resource *regs; |
33 | int err; |
34 | |
35 | if (rockchip->is_rc) { |
36 | regs = platform_get_resource_byname(pdev, |
37 | IORESOURCE_MEM, |
38 | "axi-base" ); |
39 | rockchip->reg_base = devm_pci_remap_cfg_resource(dev, res: regs); |
40 | if (IS_ERR(ptr: rockchip->reg_base)) |
41 | return PTR_ERR(ptr: rockchip->reg_base); |
42 | } else { |
43 | rockchip->mem_res = |
44 | platform_get_resource_byname(pdev, IORESOURCE_MEM, |
45 | "mem-base" ); |
46 | if (!rockchip->mem_res) |
47 | return -EINVAL; |
48 | } |
49 | |
50 | rockchip->apb_base = |
51 | devm_platform_ioremap_resource_byname(pdev, name: "apb-base" ); |
52 | if (IS_ERR(ptr: rockchip->apb_base)) |
53 | return PTR_ERR(ptr: rockchip->apb_base); |
54 | |
55 | err = rockchip_pcie_get_phys(rockchip); |
56 | if (err) |
57 | return err; |
58 | |
59 | rockchip->lanes = 1; |
60 | err = of_property_read_u32(np: node, propname: "num-lanes" , out_value: &rockchip->lanes); |
61 | if (!err && (rockchip->lanes == 0 || |
62 | rockchip->lanes == 3 || |
63 | rockchip->lanes > 4)) { |
64 | dev_warn(dev, "invalid num-lanes, default to use one lane\n" ); |
65 | rockchip->lanes = 1; |
66 | } |
67 | |
68 | rockchip->link_gen = of_pci_get_max_link_speed(node); |
69 | if (rockchip->link_gen < 0 || rockchip->link_gen > 2) |
70 | rockchip->link_gen = 2; |
71 | |
72 | rockchip->core_rst = devm_reset_control_get_exclusive(dev, id: "core" ); |
73 | if (IS_ERR(ptr: rockchip->core_rst)) { |
74 | if (PTR_ERR(ptr: rockchip->core_rst) != -EPROBE_DEFER) |
75 | dev_err(dev, "missing core reset property in node\n" ); |
76 | return PTR_ERR(ptr: rockchip->core_rst); |
77 | } |
78 | |
79 | rockchip->mgmt_rst = devm_reset_control_get_exclusive(dev, id: "mgmt" ); |
80 | if (IS_ERR(ptr: rockchip->mgmt_rst)) { |
81 | if (PTR_ERR(ptr: rockchip->mgmt_rst) != -EPROBE_DEFER) |
82 | dev_err(dev, "missing mgmt reset property in node\n" ); |
83 | return PTR_ERR(ptr: rockchip->mgmt_rst); |
84 | } |
85 | |
86 | rockchip->mgmt_sticky_rst = devm_reset_control_get_exclusive(dev, |
87 | id: "mgmt-sticky" ); |
88 | if (IS_ERR(ptr: rockchip->mgmt_sticky_rst)) { |
89 | if (PTR_ERR(ptr: rockchip->mgmt_sticky_rst) != -EPROBE_DEFER) |
90 | dev_err(dev, "missing mgmt-sticky reset property in node\n" ); |
91 | return PTR_ERR(ptr: rockchip->mgmt_sticky_rst); |
92 | } |
93 | |
94 | rockchip->pipe_rst = devm_reset_control_get_exclusive(dev, id: "pipe" ); |
95 | if (IS_ERR(ptr: rockchip->pipe_rst)) { |
96 | if (PTR_ERR(ptr: rockchip->pipe_rst) != -EPROBE_DEFER) |
97 | dev_err(dev, "missing pipe reset property in node\n" ); |
98 | return PTR_ERR(ptr: rockchip->pipe_rst); |
99 | } |
100 | |
101 | rockchip->pm_rst = devm_reset_control_get_exclusive(dev, id: "pm" ); |
102 | if (IS_ERR(ptr: rockchip->pm_rst)) { |
103 | if (PTR_ERR(ptr: rockchip->pm_rst) != -EPROBE_DEFER) |
104 | dev_err(dev, "missing pm reset property in node\n" ); |
105 | return PTR_ERR(ptr: rockchip->pm_rst); |
106 | } |
107 | |
108 | rockchip->pclk_rst = devm_reset_control_get_exclusive(dev, id: "pclk" ); |
109 | if (IS_ERR(ptr: rockchip->pclk_rst)) { |
110 | if (PTR_ERR(ptr: rockchip->pclk_rst) != -EPROBE_DEFER) |
111 | dev_err(dev, "missing pclk reset property in node\n" ); |
112 | return PTR_ERR(ptr: rockchip->pclk_rst); |
113 | } |
114 | |
115 | rockchip->aclk_rst = devm_reset_control_get_exclusive(dev, id: "aclk" ); |
116 | if (IS_ERR(ptr: rockchip->aclk_rst)) { |
117 | if (PTR_ERR(ptr: rockchip->aclk_rst) != -EPROBE_DEFER) |
118 | dev_err(dev, "missing aclk reset property in node\n" ); |
119 | return PTR_ERR(ptr: rockchip->aclk_rst); |
120 | } |
121 | |
122 | if (rockchip->is_rc) { |
123 | rockchip->ep_gpio = devm_gpiod_get_optional(dev, con_id: "ep" , |
124 | flags: GPIOD_OUT_HIGH); |
125 | if (IS_ERR(ptr: rockchip->ep_gpio)) |
126 | return dev_err_probe(dev, err: PTR_ERR(ptr: rockchip->ep_gpio), |
127 | fmt: "failed to get ep GPIO\n" ); |
128 | } |
129 | |
130 | rockchip->aclk_pcie = devm_clk_get(dev, id: "aclk" ); |
131 | if (IS_ERR(ptr: rockchip->aclk_pcie)) { |
132 | dev_err(dev, "aclk clock not found\n" ); |
133 | return PTR_ERR(ptr: rockchip->aclk_pcie); |
134 | } |
135 | |
136 | rockchip->aclk_perf_pcie = devm_clk_get(dev, id: "aclk-perf" ); |
137 | if (IS_ERR(ptr: rockchip->aclk_perf_pcie)) { |
138 | dev_err(dev, "aclk_perf clock not found\n" ); |
139 | return PTR_ERR(ptr: rockchip->aclk_perf_pcie); |
140 | } |
141 | |
142 | rockchip->hclk_pcie = devm_clk_get(dev, id: "hclk" ); |
143 | if (IS_ERR(ptr: rockchip->hclk_pcie)) { |
144 | dev_err(dev, "hclk clock not found\n" ); |
145 | return PTR_ERR(ptr: rockchip->hclk_pcie); |
146 | } |
147 | |
148 | rockchip->clk_pcie_pm = devm_clk_get(dev, id: "pm" ); |
149 | if (IS_ERR(ptr: rockchip->clk_pcie_pm)) { |
150 | dev_err(dev, "pm clock not found\n" ); |
151 | return PTR_ERR(ptr: rockchip->clk_pcie_pm); |
152 | } |
153 | |
154 | return 0; |
155 | } |
156 | EXPORT_SYMBOL_GPL(rockchip_pcie_parse_dt); |
157 | |
158 | #define rockchip_pcie_read_addr(addr) rockchip_pcie_read(rockchip, addr) |
159 | /* 100 ms max wait time for PHY PLLs to lock */ |
160 | #define RK_PHY_PLL_LOCK_TIMEOUT_US 100000 |
161 | /* Sleep should be less than 20ms */ |
162 | #define RK_PHY_PLL_LOCK_SLEEP_US 1000 |
163 | |
164 | int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) |
165 | { |
166 | struct device *dev = rockchip->dev; |
167 | int err, i; |
168 | u32 regs; |
169 | |
170 | err = reset_control_assert(rstc: rockchip->aclk_rst); |
171 | if (err) { |
172 | dev_err(dev, "assert aclk_rst err %d\n" , err); |
173 | return err; |
174 | } |
175 | |
176 | err = reset_control_assert(rstc: rockchip->pclk_rst); |
177 | if (err) { |
178 | dev_err(dev, "assert pclk_rst err %d\n" , err); |
179 | return err; |
180 | } |
181 | |
182 | err = reset_control_assert(rstc: rockchip->pm_rst); |
183 | if (err) { |
184 | dev_err(dev, "assert pm_rst err %d\n" , err); |
185 | return err; |
186 | } |
187 | |
188 | for (i = 0; i < MAX_LANE_NUM; i++) { |
189 | err = phy_init(phy: rockchip->phys[i]); |
190 | if (err) { |
191 | dev_err(dev, "init phy%d err %d\n" , i, err); |
192 | goto err_exit_phy; |
193 | } |
194 | } |
195 | |
196 | err = reset_control_assert(rstc: rockchip->core_rst); |
197 | if (err) { |
198 | dev_err(dev, "assert core_rst err %d\n" , err); |
199 | goto err_exit_phy; |
200 | } |
201 | |
202 | err = reset_control_assert(rstc: rockchip->mgmt_rst); |
203 | if (err) { |
204 | dev_err(dev, "assert mgmt_rst err %d\n" , err); |
205 | goto err_exit_phy; |
206 | } |
207 | |
208 | err = reset_control_assert(rstc: rockchip->mgmt_sticky_rst); |
209 | if (err) { |
210 | dev_err(dev, "assert mgmt_sticky_rst err %d\n" , err); |
211 | goto err_exit_phy; |
212 | } |
213 | |
214 | err = reset_control_assert(rstc: rockchip->pipe_rst); |
215 | if (err) { |
216 | dev_err(dev, "assert pipe_rst err %d\n" , err); |
217 | goto err_exit_phy; |
218 | } |
219 | |
220 | udelay(10); |
221 | |
222 | err = reset_control_deassert(rstc: rockchip->pm_rst); |
223 | if (err) { |
224 | dev_err(dev, "deassert pm_rst err %d\n" , err); |
225 | goto err_exit_phy; |
226 | } |
227 | |
228 | err = reset_control_deassert(rstc: rockchip->aclk_rst); |
229 | if (err) { |
230 | dev_err(dev, "deassert aclk_rst err %d\n" , err); |
231 | goto err_exit_phy; |
232 | } |
233 | |
234 | err = reset_control_deassert(rstc: rockchip->pclk_rst); |
235 | if (err) { |
236 | dev_err(dev, "deassert pclk_rst err %d\n" , err); |
237 | goto err_exit_phy; |
238 | } |
239 | |
240 | if (rockchip->link_gen == 2) |
241 | rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2, |
242 | PCIE_CLIENT_CONFIG); |
243 | else |
244 | rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, |
245 | PCIE_CLIENT_CONFIG); |
246 | |
247 | regs = PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE | |
248 | PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes); |
249 | |
250 | if (rockchip->is_rc) |
251 | regs |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC; |
252 | else |
253 | regs |= PCIE_CLIENT_CONF_DISABLE | PCIE_CLIENT_MODE_EP; |
254 | |
255 | rockchip_pcie_write(rockchip, val: regs, PCIE_CLIENT_CONFIG); |
256 | |
257 | for (i = 0; i < MAX_LANE_NUM; i++) { |
258 | err = phy_power_on(phy: rockchip->phys[i]); |
259 | if (err) { |
260 | dev_err(dev, "power on phy%d err %d\n" , i, err); |
261 | goto err_power_off_phy; |
262 | } |
263 | } |
264 | |
265 | err = readx_poll_timeout(rockchip_pcie_read_addr, |
266 | PCIE_CLIENT_SIDE_BAND_STATUS, |
267 | regs, !(regs & PCIE_CLIENT_PHY_ST), |
268 | RK_PHY_PLL_LOCK_SLEEP_US, |
269 | RK_PHY_PLL_LOCK_TIMEOUT_US); |
270 | if (err) { |
271 | dev_err(dev, "PHY PLLs could not lock, %d\n" , err); |
272 | goto err_power_off_phy; |
273 | } |
274 | |
275 | /* |
276 | * Please don't reorder the deassert sequence of the following |
277 | * four reset pins. |
278 | */ |
279 | err = reset_control_deassert(rstc: rockchip->mgmt_sticky_rst); |
280 | if (err) { |
281 | dev_err(dev, "deassert mgmt_sticky_rst err %d\n" , err); |
282 | goto err_power_off_phy; |
283 | } |
284 | |
285 | err = reset_control_deassert(rstc: rockchip->core_rst); |
286 | if (err) { |
287 | dev_err(dev, "deassert core_rst err %d\n" , err); |
288 | goto err_power_off_phy; |
289 | } |
290 | |
291 | err = reset_control_deassert(rstc: rockchip->mgmt_rst); |
292 | if (err) { |
293 | dev_err(dev, "deassert mgmt_rst err %d\n" , err); |
294 | goto err_power_off_phy; |
295 | } |
296 | |
297 | err = reset_control_deassert(rstc: rockchip->pipe_rst); |
298 | if (err) { |
299 | dev_err(dev, "deassert pipe_rst err %d\n" , err); |
300 | goto err_power_off_phy; |
301 | } |
302 | |
303 | return 0; |
304 | err_power_off_phy: |
305 | while (i--) |
306 | phy_power_off(phy: rockchip->phys[i]); |
307 | i = MAX_LANE_NUM; |
308 | err_exit_phy: |
309 | while (i--) |
310 | phy_exit(phy: rockchip->phys[i]); |
311 | return err; |
312 | } |
313 | EXPORT_SYMBOL_GPL(rockchip_pcie_init_port); |
314 | |
315 | int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) |
316 | { |
317 | struct device *dev = rockchip->dev; |
318 | struct phy *phy; |
319 | char *name; |
320 | u32 i; |
321 | |
322 | phy = devm_phy_get(dev, string: "pcie-phy" ); |
323 | if (!IS_ERR(ptr: phy)) { |
324 | rockchip->legacy_phy = true; |
325 | rockchip->phys[0] = phy; |
326 | dev_warn(dev, "legacy phy model is deprecated!\n" ); |
327 | return 0; |
328 | } |
329 | |
330 | if (PTR_ERR(ptr: phy) == -EPROBE_DEFER) |
331 | return PTR_ERR(ptr: phy); |
332 | |
333 | dev_dbg(dev, "missing legacy phy; search for per-lane PHY\n" ); |
334 | |
335 | for (i = 0; i < MAX_LANE_NUM; i++) { |
336 | name = kasprintf(GFP_KERNEL, fmt: "pcie-phy-%u" , i); |
337 | if (!name) |
338 | return -ENOMEM; |
339 | |
340 | phy = devm_of_phy_get(dev, np: dev->of_node, con_id: name); |
341 | kfree(objp: name); |
342 | |
343 | if (IS_ERR(ptr: phy)) { |
344 | if (PTR_ERR(ptr: phy) != -EPROBE_DEFER) |
345 | dev_err(dev, "missing phy for lane %d: %ld\n" , |
346 | i, PTR_ERR(phy)); |
347 | return PTR_ERR(ptr: phy); |
348 | } |
349 | |
350 | rockchip->phys[i] = phy; |
351 | } |
352 | |
353 | return 0; |
354 | } |
355 | EXPORT_SYMBOL_GPL(rockchip_pcie_get_phys); |
356 | |
357 | void rockchip_pcie_deinit_phys(struct rockchip_pcie *rockchip) |
358 | { |
359 | int i; |
360 | |
361 | for (i = 0; i < MAX_LANE_NUM; i++) { |
362 | /* inactive lanes are already powered off */ |
363 | if (rockchip->lanes_map & BIT(i)) |
364 | phy_power_off(phy: rockchip->phys[i]); |
365 | phy_exit(phy: rockchip->phys[i]); |
366 | } |
367 | } |
368 | EXPORT_SYMBOL_GPL(rockchip_pcie_deinit_phys); |
369 | |
370 | int rockchip_pcie_enable_clocks(struct rockchip_pcie *rockchip) |
371 | { |
372 | struct device *dev = rockchip->dev; |
373 | int err; |
374 | |
375 | err = clk_prepare_enable(clk: rockchip->aclk_pcie); |
376 | if (err) { |
377 | dev_err(dev, "unable to enable aclk_pcie clock\n" ); |
378 | return err; |
379 | } |
380 | |
381 | err = clk_prepare_enable(clk: rockchip->aclk_perf_pcie); |
382 | if (err) { |
383 | dev_err(dev, "unable to enable aclk_perf_pcie clock\n" ); |
384 | goto err_aclk_perf_pcie; |
385 | } |
386 | |
387 | err = clk_prepare_enable(clk: rockchip->hclk_pcie); |
388 | if (err) { |
389 | dev_err(dev, "unable to enable hclk_pcie clock\n" ); |
390 | goto err_hclk_pcie; |
391 | } |
392 | |
393 | err = clk_prepare_enable(clk: rockchip->clk_pcie_pm); |
394 | if (err) { |
395 | dev_err(dev, "unable to enable clk_pcie_pm clock\n" ); |
396 | goto err_clk_pcie_pm; |
397 | } |
398 | |
399 | return 0; |
400 | |
401 | err_clk_pcie_pm: |
402 | clk_disable_unprepare(clk: rockchip->hclk_pcie); |
403 | err_hclk_pcie: |
404 | clk_disable_unprepare(clk: rockchip->aclk_perf_pcie); |
405 | err_aclk_perf_pcie: |
406 | clk_disable_unprepare(clk: rockchip->aclk_pcie); |
407 | return err; |
408 | } |
409 | EXPORT_SYMBOL_GPL(rockchip_pcie_enable_clocks); |
410 | |
411 | void rockchip_pcie_disable_clocks(void *data) |
412 | { |
413 | struct rockchip_pcie *rockchip = data; |
414 | |
415 | clk_disable_unprepare(clk: rockchip->clk_pcie_pm); |
416 | clk_disable_unprepare(clk: rockchip->hclk_pcie); |
417 | clk_disable_unprepare(clk: rockchip->aclk_perf_pcie); |
418 | clk_disable_unprepare(clk: rockchip->aclk_pcie); |
419 | } |
420 | EXPORT_SYMBOL_GPL(rockchip_pcie_disable_clocks); |
421 | |
422 | void rockchip_pcie_cfg_configuration_accesses( |
423 | struct rockchip_pcie *rockchip, u32 type) |
424 | { |
425 | u32 ob_desc_0; |
426 | |
427 | /* Configuration Accesses for region 0 */ |
428 | rockchip_pcie_write(rockchip, val: 0x0, PCIE_RC_BAR_CONF); |
429 | |
430 | rockchip_pcie_write(rockchip, |
431 | val: (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS), |
432 | PCIE_CORE_OB_REGION_ADDR0); |
433 | rockchip_pcie_write(rockchip, RC_REGION_0_ADDR_TRANS_H, |
434 | PCIE_CORE_OB_REGION_ADDR1); |
435 | ob_desc_0 = rockchip_pcie_read(rockchip, PCIE_CORE_OB_REGION_DESC0); |
436 | ob_desc_0 &= ~(RC_REGION_0_TYPE_MASK); |
437 | ob_desc_0 |= (type | (0x1 << 23)); |
438 | rockchip_pcie_write(rockchip, val: ob_desc_0, PCIE_CORE_OB_REGION_DESC0); |
439 | rockchip_pcie_write(rockchip, val: 0x0, PCIE_CORE_OB_REGION_DESC1); |
440 | } |
441 | EXPORT_SYMBOL_GPL(rockchip_pcie_cfg_configuration_accesses); |
442 | |