1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * PCIe host controller driver for Samsung Exynos SoCs |
4 | * |
5 | * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. |
6 | * https://www.samsung.com |
7 | * |
8 | * Author: Jingoo Han <jg1.han@samsung.com> |
9 | * Jaehoon Chung <jh80.chung@samsung.com> |
10 | */ |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> |
17 | #include <linux/pci.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/phy/phy.h> |
20 | #include <linux/regulator/consumer.h> |
21 | #include <linux/mod_devicetable.h> |
22 | #include <linux/module.h> |
23 | |
24 | #include "pcie-designware.h" |
25 | |
26 | #define to_exynos_pcie(x) dev_get_drvdata((x)->dev) |
27 | |
28 | /* PCIe ELBI registers */ |
29 | #define PCIE_IRQ_PULSE 0x000 |
30 | #define IRQ_INTA_ASSERT BIT(0) |
31 | #define IRQ_INTB_ASSERT BIT(2) |
32 | #define IRQ_INTC_ASSERT BIT(4) |
33 | #define IRQ_INTD_ASSERT BIT(6) |
34 | #define PCIE_IRQ_LEVEL 0x004 |
35 | #define PCIE_IRQ_SPECIAL 0x008 |
36 | #define PCIE_IRQ_EN_PULSE 0x00c |
37 | #define PCIE_IRQ_EN_LEVEL 0x010 |
38 | #define PCIE_IRQ_EN_SPECIAL 0x014 |
39 | #define PCIE_SW_WAKE 0x018 |
40 | #define PCIE_BUS_EN BIT(1) |
41 | #define PCIE_CORE_RESET 0x01c |
42 | #define PCIE_CORE_RESET_ENABLE BIT(0) |
43 | #define PCIE_STICKY_RESET 0x020 |
44 | #define PCIE_NONSTICKY_RESET 0x024 |
45 | #define PCIE_APP_INIT_RESET 0x028 |
46 | #define PCIE_APP_LTSSM_ENABLE 0x02c |
47 | #define PCIE_ELBI_RDLH_LINKUP 0x074 |
48 | #define PCIE_ELBI_XMLH_LINKUP BIT(4) |
49 | #define PCIE_ELBI_LTSSM_ENABLE 0x1 |
50 | #define PCIE_ELBI_SLV_AWMISC 0x11c |
51 | #define PCIE_ELBI_SLV_ARMISC 0x120 |
52 | #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) |
53 | |
54 | struct exynos_pcie { |
55 | struct dw_pcie pci; |
56 | void __iomem *elbi_base; |
57 | struct clk *clk; |
58 | struct clk *bus_clk; |
59 | struct phy *phy; |
60 | struct regulator_bulk_data supplies[2]; |
61 | }; |
62 | |
63 | static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep) |
64 | { |
65 | struct device *dev = ep->pci.dev; |
66 | int ret; |
67 | |
68 | ret = clk_prepare_enable(clk: ep->clk); |
69 | if (ret) { |
70 | dev_err(dev, "cannot enable pcie rc clock" ); |
71 | return ret; |
72 | } |
73 | |
74 | ret = clk_prepare_enable(clk: ep->bus_clk); |
75 | if (ret) { |
76 | dev_err(dev, "cannot enable pcie bus clock" ); |
77 | goto err_bus_clk; |
78 | } |
79 | |
80 | return 0; |
81 | |
82 | err_bus_clk: |
83 | clk_disable_unprepare(clk: ep->clk); |
84 | |
85 | return ret; |
86 | } |
87 | |
88 | static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep) |
89 | { |
90 | clk_disable_unprepare(clk: ep->bus_clk); |
91 | clk_disable_unprepare(clk: ep->clk); |
92 | } |
93 | |
94 | static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) |
95 | { |
96 | writel(val, addr: base + reg); |
97 | } |
98 | |
99 | static u32 exynos_pcie_readl(void __iomem *base, u32 reg) |
100 | { |
101 | return readl(addr: base + reg); |
102 | } |
103 | |
104 | static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) |
105 | { |
106 | u32 val; |
107 | |
108 | val = exynos_pcie_readl(base: ep->elbi_base, PCIE_ELBI_SLV_AWMISC); |
109 | if (on) |
110 | val |= PCIE_ELBI_SLV_DBI_ENABLE; |
111 | else |
112 | val &= ~PCIE_ELBI_SLV_DBI_ENABLE; |
113 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC); |
114 | } |
115 | |
116 | static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on) |
117 | { |
118 | u32 val; |
119 | |
120 | val = exynos_pcie_readl(base: ep->elbi_base, PCIE_ELBI_SLV_ARMISC); |
121 | if (on) |
122 | val |= PCIE_ELBI_SLV_DBI_ENABLE; |
123 | else |
124 | val &= ~PCIE_ELBI_SLV_DBI_ENABLE; |
125 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC); |
126 | } |
127 | |
128 | static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep) |
129 | { |
130 | u32 val; |
131 | |
132 | val = exynos_pcie_readl(base: ep->elbi_base, PCIE_CORE_RESET); |
133 | val &= ~PCIE_CORE_RESET_ENABLE; |
134 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_CORE_RESET); |
135 | exynos_pcie_writel(base: ep->elbi_base, val: 0, PCIE_STICKY_RESET); |
136 | exynos_pcie_writel(base: ep->elbi_base, val: 0, PCIE_NONSTICKY_RESET); |
137 | } |
138 | |
139 | static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep) |
140 | { |
141 | u32 val; |
142 | |
143 | val = exynos_pcie_readl(base: ep->elbi_base, PCIE_CORE_RESET); |
144 | val |= PCIE_CORE_RESET_ENABLE; |
145 | |
146 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_CORE_RESET); |
147 | exynos_pcie_writel(base: ep->elbi_base, val: 1, PCIE_STICKY_RESET); |
148 | exynos_pcie_writel(base: ep->elbi_base, val: 1, PCIE_NONSTICKY_RESET); |
149 | exynos_pcie_writel(base: ep->elbi_base, val: 1, PCIE_APP_INIT_RESET); |
150 | exynos_pcie_writel(base: ep->elbi_base, val: 0, PCIE_APP_INIT_RESET); |
151 | } |
152 | |
153 | static int exynos_pcie_start_link(struct dw_pcie *pci) |
154 | { |
155 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
156 | u32 val; |
157 | |
158 | val = exynos_pcie_readl(base: ep->elbi_base, PCIE_SW_WAKE); |
159 | val &= ~PCIE_BUS_EN; |
160 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_SW_WAKE); |
161 | |
162 | /* assert LTSSM enable */ |
163 | exynos_pcie_writel(base: ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE, |
164 | PCIE_APP_LTSSM_ENABLE); |
165 | return 0; |
166 | } |
167 | |
168 | static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep) |
169 | { |
170 | u32 val = exynos_pcie_readl(base: ep->elbi_base, PCIE_IRQ_PULSE); |
171 | |
172 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_IRQ_PULSE); |
173 | } |
174 | |
175 | static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) |
176 | { |
177 | struct exynos_pcie *ep = arg; |
178 | |
179 | exynos_pcie_clear_irq_pulse(ep); |
180 | return IRQ_HANDLED; |
181 | } |
182 | |
183 | static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) |
184 | { |
185 | u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | |
186 | IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; |
187 | |
188 | exynos_pcie_writel(base: ep->elbi_base, val, PCIE_IRQ_EN_PULSE); |
189 | exynos_pcie_writel(base: ep->elbi_base, val: 0, PCIE_IRQ_EN_LEVEL); |
190 | exynos_pcie_writel(base: ep->elbi_base, val: 0, PCIE_IRQ_EN_SPECIAL); |
191 | } |
192 | |
193 | static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, |
194 | u32 reg, size_t size) |
195 | { |
196 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
197 | u32 val; |
198 | |
199 | exynos_pcie_sideband_dbi_r_mode(ep, on: true); |
200 | dw_pcie_read(addr: base + reg, size, val: &val); |
201 | exynos_pcie_sideband_dbi_r_mode(ep, on: false); |
202 | return val; |
203 | } |
204 | |
205 | static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, |
206 | u32 reg, size_t size, u32 val) |
207 | { |
208 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
209 | |
210 | exynos_pcie_sideband_dbi_w_mode(ep, on: true); |
211 | dw_pcie_write(addr: base + reg, size, val); |
212 | exynos_pcie_sideband_dbi_w_mode(ep, on: false); |
213 | } |
214 | |
215 | static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn, |
216 | int where, int size, u32 *val) |
217 | { |
218 | struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); |
219 | |
220 | if (PCI_SLOT(devfn)) |
221 | return PCIBIOS_DEVICE_NOT_FOUND; |
222 | |
223 | *val = dw_pcie_read_dbi(pci, reg: where, size); |
224 | return PCIBIOS_SUCCESSFUL; |
225 | } |
226 | |
227 | static int exynos_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn, |
228 | int where, int size, u32 val) |
229 | { |
230 | struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); |
231 | |
232 | if (PCI_SLOT(devfn)) |
233 | return PCIBIOS_DEVICE_NOT_FOUND; |
234 | |
235 | dw_pcie_write_dbi(pci, reg: where, size, val); |
236 | return PCIBIOS_SUCCESSFUL; |
237 | } |
238 | |
239 | static struct pci_ops exynos_pci_ops = { |
240 | .read = exynos_pcie_rd_own_conf, |
241 | .write = exynos_pcie_wr_own_conf, |
242 | }; |
243 | |
244 | static int exynos_pcie_link_up(struct dw_pcie *pci) |
245 | { |
246 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
247 | u32 val = exynos_pcie_readl(base: ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); |
248 | |
249 | return (val & PCIE_ELBI_XMLH_LINKUP); |
250 | } |
251 | |
252 | static int exynos_pcie_host_init(struct dw_pcie_rp *pp) |
253 | { |
254 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
255 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
256 | |
257 | pp->bridge->ops = &exynos_pci_ops; |
258 | |
259 | exynos_pcie_assert_core_reset(ep); |
260 | |
261 | phy_init(phy: ep->phy); |
262 | phy_power_on(phy: ep->phy); |
263 | |
264 | exynos_pcie_deassert_core_reset(ep); |
265 | exynos_pcie_enable_irq_pulse(ep); |
266 | |
267 | return 0; |
268 | } |
269 | |
270 | static const struct dw_pcie_host_ops exynos_pcie_host_ops = { |
271 | .init = exynos_pcie_host_init, |
272 | }; |
273 | |
274 | static int exynos_add_pcie_port(struct exynos_pcie *ep, |
275 | struct platform_device *pdev) |
276 | { |
277 | struct dw_pcie *pci = &ep->pci; |
278 | struct dw_pcie_rp *pp = &pci->pp; |
279 | struct device *dev = &pdev->dev; |
280 | int ret; |
281 | |
282 | pp->irq = platform_get_irq(pdev, 0); |
283 | if (pp->irq < 0) |
284 | return pp->irq; |
285 | |
286 | ret = devm_request_irq(dev, irq: pp->irq, handler: exynos_pcie_irq_handler, |
287 | IRQF_SHARED, devname: "exynos-pcie" , dev_id: ep); |
288 | if (ret) { |
289 | dev_err(dev, "failed to request irq\n" ); |
290 | return ret; |
291 | } |
292 | |
293 | pp->ops = &exynos_pcie_host_ops; |
294 | pp->msi_irq[0] = -ENODEV; |
295 | |
296 | ret = dw_pcie_host_init(pp); |
297 | if (ret) { |
298 | dev_err(dev, "failed to initialize host\n" ); |
299 | return ret; |
300 | } |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static const struct dw_pcie_ops dw_pcie_ops = { |
306 | .read_dbi = exynos_pcie_read_dbi, |
307 | .write_dbi = exynos_pcie_write_dbi, |
308 | .link_up = exynos_pcie_link_up, |
309 | .start_link = exynos_pcie_start_link, |
310 | }; |
311 | |
312 | static int exynos_pcie_probe(struct platform_device *pdev) |
313 | { |
314 | struct device *dev = &pdev->dev; |
315 | struct exynos_pcie *ep; |
316 | struct device_node *np = dev->of_node; |
317 | int ret; |
318 | |
319 | ep = devm_kzalloc(dev, size: sizeof(*ep), GFP_KERNEL); |
320 | if (!ep) |
321 | return -ENOMEM; |
322 | |
323 | ep->pci.dev = dev; |
324 | ep->pci.ops = &dw_pcie_ops; |
325 | |
326 | ep->phy = devm_of_phy_get(dev, np, NULL); |
327 | if (IS_ERR(ptr: ep->phy)) |
328 | return PTR_ERR(ptr: ep->phy); |
329 | |
330 | /* External Local Bus interface (ELBI) registers */ |
331 | ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, name: "elbi" ); |
332 | if (IS_ERR(ptr: ep->elbi_base)) |
333 | return PTR_ERR(ptr: ep->elbi_base); |
334 | |
335 | ep->clk = devm_clk_get(dev, id: "pcie" ); |
336 | if (IS_ERR(ptr: ep->clk)) { |
337 | dev_err(dev, "Failed to get pcie rc clock\n" ); |
338 | return PTR_ERR(ptr: ep->clk); |
339 | } |
340 | |
341 | ep->bus_clk = devm_clk_get(dev, id: "pcie_bus" ); |
342 | if (IS_ERR(ptr: ep->bus_clk)) { |
343 | dev_err(dev, "Failed to get pcie bus clock\n" ); |
344 | return PTR_ERR(ptr: ep->bus_clk); |
345 | } |
346 | |
347 | ep->supplies[0].supply = "vdd18" ; |
348 | ep->supplies[1].supply = "vdd10" ; |
349 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies), |
350 | consumers: ep->supplies); |
351 | if (ret) |
352 | return ret; |
353 | |
354 | ret = exynos_pcie_init_clk_resources(ep); |
355 | if (ret) |
356 | return ret; |
357 | |
358 | ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), consumers: ep->supplies); |
359 | if (ret) |
360 | return ret; |
361 | |
362 | platform_set_drvdata(pdev, data: ep); |
363 | |
364 | ret = exynos_add_pcie_port(ep, pdev); |
365 | if (ret < 0) |
366 | goto fail_probe; |
367 | |
368 | return 0; |
369 | |
370 | fail_probe: |
371 | phy_exit(phy: ep->phy); |
372 | exynos_pcie_deinit_clk_resources(ep); |
373 | regulator_bulk_disable(ARRAY_SIZE(ep->supplies), consumers: ep->supplies); |
374 | |
375 | return ret; |
376 | } |
377 | |
378 | static void exynos_pcie_remove(struct platform_device *pdev) |
379 | { |
380 | struct exynos_pcie *ep = platform_get_drvdata(pdev); |
381 | |
382 | dw_pcie_host_deinit(pp: &ep->pci.pp); |
383 | exynos_pcie_assert_core_reset(ep); |
384 | phy_power_off(phy: ep->phy); |
385 | phy_exit(phy: ep->phy); |
386 | exynos_pcie_deinit_clk_resources(ep); |
387 | regulator_bulk_disable(ARRAY_SIZE(ep->supplies), consumers: ep->supplies); |
388 | } |
389 | |
390 | static int exynos_pcie_suspend_noirq(struct device *dev) |
391 | { |
392 | struct exynos_pcie *ep = dev_get_drvdata(dev); |
393 | |
394 | exynos_pcie_assert_core_reset(ep); |
395 | phy_power_off(phy: ep->phy); |
396 | phy_exit(phy: ep->phy); |
397 | regulator_bulk_disable(ARRAY_SIZE(ep->supplies), consumers: ep->supplies); |
398 | |
399 | return 0; |
400 | } |
401 | |
402 | static int exynos_pcie_resume_noirq(struct device *dev) |
403 | { |
404 | struct exynos_pcie *ep = dev_get_drvdata(dev); |
405 | struct dw_pcie *pci = &ep->pci; |
406 | struct dw_pcie_rp *pp = &pci->pp; |
407 | int ret; |
408 | |
409 | ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), consumers: ep->supplies); |
410 | if (ret) |
411 | return ret; |
412 | |
413 | /* exynos_pcie_host_init controls ep->phy */ |
414 | exynos_pcie_host_init(pp); |
415 | dw_pcie_setup_rc(pp); |
416 | exynos_pcie_start_link(pci); |
417 | return dw_pcie_wait_for_link(pci); |
418 | } |
419 | |
420 | static const struct dev_pm_ops exynos_pcie_pm_ops = { |
421 | NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq, |
422 | exynos_pcie_resume_noirq) |
423 | }; |
424 | |
425 | static const struct of_device_id exynos_pcie_of_match[] = { |
426 | { .compatible = "samsung,exynos5433-pcie" , }, |
427 | { }, |
428 | }; |
429 | |
430 | static struct platform_driver exynos_pcie_driver = { |
431 | .probe = exynos_pcie_probe, |
432 | .remove_new = exynos_pcie_remove, |
433 | .driver = { |
434 | .name = "exynos-pcie" , |
435 | .of_match_table = exynos_pcie_of_match, |
436 | .pm = &exynos_pcie_pm_ops, |
437 | }, |
438 | }; |
439 | module_platform_driver(exynos_pcie_driver); |
440 | MODULE_LICENSE("GPL v2" ); |
441 | MODULE_DEVICE_TABLE(of, exynos_pcie_of_match); |
442 | |