1a805770dSXiaowei Bao // SPDX-License-Identifier: GPL-2.0
2a805770dSXiaowei Bao /*
3a805770dSXiaowei Bao * PCIe controller EP driver for Freescale Layerscape SoCs
4a805770dSXiaowei Bao *
5a805770dSXiaowei Bao * Copyright (C) 2018 NXP Semiconductor.
6a805770dSXiaowei Bao *
7a805770dSXiaowei Bao * Author: Xiaowei Bao <xiaowei.bao@nxp.com>
8a805770dSXiaowei Bao */
9a805770dSXiaowei Bao
10a805770dSXiaowei Bao #include <linux/kernel.h>
11a805770dSXiaowei Bao #include <linux/init.h>
12a805770dSXiaowei Bao #include <linux/of_pci.h>
13a805770dSXiaowei Bao #include <linux/of_platform.h>
14a805770dSXiaowei Bao #include <linux/of_address.h>
15a805770dSXiaowei Bao #include <linux/pci.h>
16a805770dSXiaowei Bao #include <linux/platform_device.h>
17a805770dSXiaowei Bao #include <linux/resource.h>
18a805770dSXiaowei Bao
19a805770dSXiaowei Bao #include "pcie-designware.h"
20a805770dSXiaowei Bao
21061cbfabSFrank Li #define PEX_PF0_CONFIG 0xC0014
22061cbfabSFrank Li #define PEX_PF0_CFG_READY BIT(0)
23061cbfabSFrank Li
24061cbfabSFrank Li /* PEX PFa PCIE PME and message interrupt registers*/
25061cbfabSFrank Li #define PEX_PF0_PME_MES_DR 0xC0020
26061cbfabSFrank Li #define PEX_PF0_PME_MES_DR_LUD BIT(7)
27061cbfabSFrank Li #define PEX_PF0_PME_MES_DR_LDD BIT(9)
28061cbfabSFrank Li #define PEX_PF0_PME_MES_DR_HRD BIT(10)
29061cbfabSFrank Li
30061cbfabSFrank Li #define PEX_PF0_PME_MES_IER 0xC0028
31061cbfabSFrank Li #define PEX_PF0_PME_MES_IER_LUDIE BIT(7)
32061cbfabSFrank Li #define PEX_PF0_PME_MES_IER_LDDIE BIT(9)
33061cbfabSFrank Li #define PEX_PF0_PME_MES_IER_HRDIE BIT(10)
34061cbfabSFrank Li
351b6a0e43SXiaowei Bao #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
361b6a0e43SXiaowei Bao
371b6a0e43SXiaowei Bao struct ls_pcie_ep_drvdata {
381b6a0e43SXiaowei Bao u32 func_offset;
391b6a0e43SXiaowei Bao const struct dw_pcie_ep_ops *ops;
401b6a0e43SXiaowei Bao const struct dw_pcie_ops *dw_pcie_ops;
411b6a0e43SXiaowei Bao };
421b6a0e43SXiaowei Bao
43a805770dSXiaowei Bao struct ls_pcie_ep {
44a805770dSXiaowei Bao struct dw_pcie *pci;
45cc255eb0SXiaowei Bao struct pci_epc_features *ls_epc;
461b6a0e43SXiaowei Bao const struct ls_pcie_ep_drvdata *drvdata;
47061cbfabSFrank Li int irq;
48*17cf8661SXiaowei Bao u32 lnkcap;
49061cbfabSFrank Li bool big_endian;
50a805770dSXiaowei Bao };
51a805770dSXiaowei Bao
ls_lut_readl(struct ls_pcie_ep * pcie,u32 offset)52061cbfabSFrank Li static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
53061cbfabSFrank Li {
54061cbfabSFrank Li struct dw_pcie *pci = pcie->pci;
55061cbfabSFrank Li
56061cbfabSFrank Li if (pcie->big_endian)
57061cbfabSFrank Li return ioread32be(pci->dbi_base + offset);
58061cbfabSFrank Li else
59061cbfabSFrank Li return ioread32(pci->dbi_base + offset);
60061cbfabSFrank Li }
61061cbfabSFrank Li
ls_lut_writel(struct ls_pcie_ep * pcie,u32 offset,u32 value)62061cbfabSFrank Li static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
63061cbfabSFrank Li {
64061cbfabSFrank Li struct dw_pcie *pci = pcie->pci;
65061cbfabSFrank Li
66061cbfabSFrank Li if (pcie->big_endian)
67061cbfabSFrank Li iowrite32be(value, pci->dbi_base + offset);
68061cbfabSFrank Li else
69061cbfabSFrank Li iowrite32(value, pci->dbi_base + offset);
70061cbfabSFrank Li }
71061cbfabSFrank Li
ls_pcie_ep_event_handler(int irq,void * dev_id)72061cbfabSFrank Li static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
73061cbfabSFrank Li {
74061cbfabSFrank Li struct ls_pcie_ep *pcie = dev_id;
75061cbfabSFrank Li struct dw_pcie *pci = pcie->pci;
76061cbfabSFrank Li u32 val, cfg;
77*17cf8661SXiaowei Bao u8 offset;
78061cbfabSFrank Li
79061cbfabSFrank Li val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
80061cbfabSFrank Li ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
81061cbfabSFrank Li
82061cbfabSFrank Li if (!val)
83061cbfabSFrank Li return IRQ_NONE;
84061cbfabSFrank Li
85061cbfabSFrank Li if (val & PEX_PF0_PME_MES_DR_LUD) {
86*17cf8661SXiaowei Bao
87*17cf8661SXiaowei Bao offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
88*17cf8661SXiaowei Bao
89*17cf8661SXiaowei Bao /*
90*17cf8661SXiaowei Bao * The values of the Maximum Link Width and Supported Link
91*17cf8661SXiaowei Bao * Speed from the Link Capabilities Register will be lost
92*17cf8661SXiaowei Bao * during link down or hot reset. Restore initial value
93*17cf8661SXiaowei Bao * that configured by the Reset Configuration Word (RCW).
94*17cf8661SXiaowei Bao */
95*17cf8661SXiaowei Bao dw_pcie_dbi_ro_wr_en(pci);
96*17cf8661SXiaowei Bao dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap);
97*17cf8661SXiaowei Bao dw_pcie_dbi_ro_wr_dis(pci);
98*17cf8661SXiaowei Bao
99061cbfabSFrank Li cfg = ls_lut_readl(pcie, PEX_PF0_CONFIG);
100061cbfabSFrank Li cfg |= PEX_PF0_CFG_READY;
101061cbfabSFrank Li ls_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
102061cbfabSFrank Li dw_pcie_ep_linkup(&pci->ep);
103061cbfabSFrank Li
104061cbfabSFrank Li dev_dbg(pci->dev, "Link up\n");
105061cbfabSFrank Li } else if (val & PEX_PF0_PME_MES_DR_LDD) {
106061cbfabSFrank Li dev_dbg(pci->dev, "Link down\n");
107d28c0d84SFrank Li pci_epc_linkdown(pci->ep.epc);
108061cbfabSFrank Li } else if (val & PEX_PF0_PME_MES_DR_HRD) {
109061cbfabSFrank Li dev_dbg(pci->dev, "Hot reset\n");
110061cbfabSFrank Li }
111061cbfabSFrank Li
112061cbfabSFrank Li return IRQ_HANDLED;
113061cbfabSFrank Li }
114061cbfabSFrank Li
ls_pcie_ep_interrupt_init(struct ls_pcie_ep * pcie,struct platform_device * pdev)115061cbfabSFrank Li static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
116061cbfabSFrank Li struct platform_device *pdev)
117061cbfabSFrank Li {
118061cbfabSFrank Li u32 val;
119061cbfabSFrank Li int ret;
120061cbfabSFrank Li
121061cbfabSFrank Li pcie->irq = platform_get_irq_byname(pdev, "pme");
122061cbfabSFrank Li if (pcie->irq < 0)
123061cbfabSFrank Li return pcie->irq;
124061cbfabSFrank Li
125061cbfabSFrank Li ret = devm_request_irq(&pdev->dev, pcie->irq, ls_pcie_ep_event_handler,
126061cbfabSFrank Li IRQF_SHARED, pdev->name, pcie);
127061cbfabSFrank Li if (ret) {
128061cbfabSFrank Li dev_err(&pdev->dev, "Can't register PCIe IRQ\n");
129061cbfabSFrank Li return ret;
130061cbfabSFrank Li }
131061cbfabSFrank Li
132061cbfabSFrank Li /* Enable interrupts */
133061cbfabSFrank Li val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
134061cbfabSFrank Li val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
135061cbfabSFrank Li PEX_PF0_PME_MES_IER_LUDIE;
136061cbfabSFrank Li ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
137061cbfabSFrank Li
138061cbfabSFrank Li return 0;
139061cbfabSFrank Li }
140061cbfabSFrank Li
141a805770dSXiaowei Bao static const struct pci_epc_features*
ls_pcie_ep_get_features(struct dw_pcie_ep * ep)142a805770dSXiaowei Bao ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
143a805770dSXiaowei Bao {
144cc255eb0SXiaowei Bao struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
145cc255eb0SXiaowei Bao struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
146cc255eb0SXiaowei Bao
147cc255eb0SXiaowei Bao return pcie->ls_epc;
148a805770dSXiaowei Bao }
149a805770dSXiaowei Bao
ls_pcie_ep_init(struct dw_pcie_ep * ep)150a805770dSXiaowei Bao static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
151a805770dSXiaowei Bao {
152a805770dSXiaowei Bao struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
153cc255eb0SXiaowei Bao struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
154cc255eb0SXiaowei Bao struct dw_pcie_ep_func *ep_func;
155a805770dSXiaowei Bao enum pci_barno bar;
156a805770dSXiaowei Bao
157cc255eb0SXiaowei Bao ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
158cc255eb0SXiaowei Bao if (!ep_func)
159cc255eb0SXiaowei Bao return;
160cc255eb0SXiaowei Bao
161c9c13ba4SDenis Efremov for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
162a805770dSXiaowei Bao dw_pcie_ep_reset_bar(pci, bar);
163cc255eb0SXiaowei Bao
164cc255eb0SXiaowei Bao pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
165cc255eb0SXiaowei Bao pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
166a805770dSXiaowei Bao }
167a805770dSXiaowei Bao
ls_pcie_ep_raise_irq(struct dw_pcie_ep * ep,u8 func_no,enum pci_epc_irq_type type,u16 interrupt_num)168a805770dSXiaowei Bao static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
169a805770dSXiaowei Bao enum pci_epc_irq_type type, u16 interrupt_num)
170a805770dSXiaowei Bao {
171a805770dSXiaowei Bao struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
172a805770dSXiaowei Bao
173a805770dSXiaowei Bao switch (type) {
174a805770dSXiaowei Bao case PCI_EPC_IRQ_LEGACY:
175a805770dSXiaowei Bao return dw_pcie_ep_raise_legacy_irq(ep, func_no);
176a805770dSXiaowei Bao case PCI_EPC_IRQ_MSI:
177a805770dSXiaowei Bao return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
178a805770dSXiaowei Bao case PCI_EPC_IRQ_MSIX:
179e64844b6SXiaowei Bao return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
180e64844b6SXiaowei Bao interrupt_num);
181a805770dSXiaowei Bao default:
182a805770dSXiaowei Bao dev_err(pci->dev, "UNKNOWN IRQ type\n");
183a805770dSXiaowei Bao return -EINVAL;
184a805770dSXiaowei Bao }
185a805770dSXiaowei Bao }
186a805770dSXiaowei Bao
ls_pcie_ep_func_conf_select(struct dw_pcie_ep * ep,u8 func_no)1871b6a0e43SXiaowei Bao static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
1881b6a0e43SXiaowei Bao u8 func_no)
1891b6a0e43SXiaowei Bao {
1901b6a0e43SXiaowei Bao struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
1911b6a0e43SXiaowei Bao struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
1921b6a0e43SXiaowei Bao
1931b6a0e43SXiaowei Bao WARN_ON(func_no && !pcie->drvdata->func_offset);
1941b6a0e43SXiaowei Bao return pcie->drvdata->func_offset * func_no;
1951b6a0e43SXiaowei Bao }
1961b6a0e43SXiaowei Bao
1971b6a0e43SXiaowei Bao static const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
198a805770dSXiaowei Bao .ep_init = ls_pcie_ep_init,
199a805770dSXiaowei Bao .raise_irq = ls_pcie_ep_raise_irq,
200a805770dSXiaowei Bao .get_features = ls_pcie_ep_get_features,
2011b6a0e43SXiaowei Bao .func_conf_select = ls_pcie_ep_func_conf_select,
2021b6a0e43SXiaowei Bao };
2031b6a0e43SXiaowei Bao
2041b6a0e43SXiaowei Bao static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
2051b6a0e43SXiaowei Bao .ops = &ls_pcie_ep_ops,
2061b6a0e43SXiaowei Bao };
2071b6a0e43SXiaowei Bao
2081b6a0e43SXiaowei Bao static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = {
2091b6a0e43SXiaowei Bao .func_offset = 0x20000,
2101b6a0e43SXiaowei Bao .ops = &ls_pcie_ep_ops,
2111b6a0e43SXiaowei Bao };
2121b6a0e43SXiaowei Bao
2135bfb792fSHou Zhiqiang static const struct ls_pcie_ep_drvdata lx2_ep_drvdata = {
2145bfb792fSHou Zhiqiang .func_offset = 0x8000,
2155bfb792fSHou Zhiqiang .ops = &ls_pcie_ep_ops,
2165bfb792fSHou Zhiqiang };
2175bfb792fSHou Zhiqiang
2181b6a0e43SXiaowei Bao static const struct of_device_id ls_pcie_ep_of_match[] = {
219be567c6cSXiaowei Bao { .compatible = "fsl,ls1028a-pcie-ep", .data = &ls1_ep_drvdata },
2201b6a0e43SXiaowei Bao { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
2211b6a0e43SXiaowei Bao { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
2221b6a0e43SXiaowei Bao { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
2235bfb792fSHou Zhiqiang { .compatible = "fsl,lx2160ar2-pcie-ep", .data = &lx2_ep_drvdata },
2241b6a0e43SXiaowei Bao { },
225a805770dSXiaowei Bao };
226a805770dSXiaowei Bao
ls_pcie_ep_probe(struct platform_device * pdev)227a805770dSXiaowei Bao static int __init ls_pcie_ep_probe(struct platform_device *pdev)
228a805770dSXiaowei Bao {
229a805770dSXiaowei Bao struct device *dev = &pdev->dev;
230a805770dSXiaowei Bao struct dw_pcie *pci;
231a805770dSXiaowei Bao struct ls_pcie_ep *pcie;
232cc255eb0SXiaowei Bao struct pci_epc_features *ls_epc;
233a805770dSXiaowei Bao struct resource *dbi_base;
234*17cf8661SXiaowei Bao u8 offset;
235061cbfabSFrank Li int ret;
236a805770dSXiaowei Bao
237a805770dSXiaowei Bao pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
238a805770dSXiaowei Bao if (!pcie)
239a805770dSXiaowei Bao return -ENOMEM;
240a805770dSXiaowei Bao
241a805770dSXiaowei Bao pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
242a805770dSXiaowei Bao if (!pci)
243a805770dSXiaowei Bao return -ENOMEM;
244a805770dSXiaowei Bao
245cc255eb0SXiaowei Bao ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL);
246cc255eb0SXiaowei Bao if (!ls_epc)
247cc255eb0SXiaowei Bao return -ENOMEM;
248cc255eb0SXiaowei Bao
2491b6a0e43SXiaowei Bao pcie->drvdata = of_device_get_match_data(dev);
2501b6a0e43SXiaowei Bao
2511b6a0e43SXiaowei Bao pci->dev = dev;
2521b6a0e43SXiaowei Bao pci->ops = pcie->drvdata->dw_pcie_ops;
2531b6a0e43SXiaowei Bao
2541b7996a5SKrzysztof Wilczyński ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4);
255061cbfabSFrank Li ls_epc->linkup_notifier = true;
2561b6a0e43SXiaowei Bao
2571b6a0e43SXiaowei Bao pcie->pci = pci;
2581b6a0e43SXiaowei Bao pcie->ls_epc = ls_epc;
2591b6a0e43SXiaowei Bao
260a805770dSXiaowei Bao dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
261a805770dSXiaowei Bao pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
262a805770dSXiaowei Bao if (IS_ERR(pci->dbi_base))
263a805770dSXiaowei Bao return PTR_ERR(pci->dbi_base);
264a805770dSXiaowei Bao
265a0fd361dSRob Herring pci->ep.ops = &ls_pcie_ep_ops;
266cc255eb0SXiaowei Bao
267061cbfabSFrank Li pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
268061cbfabSFrank Li
269a805770dSXiaowei Bao platform_set_drvdata(pdev, pcie);
270a805770dSXiaowei Bao
271*17cf8661SXiaowei Bao offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
272*17cf8661SXiaowei Bao pcie->lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
273*17cf8661SXiaowei Bao
274061cbfabSFrank Li ret = dw_pcie_ep_init(&pci->ep);
275061cbfabSFrank Li if (ret)
276061cbfabSFrank Li return ret;
277061cbfabSFrank Li
278061cbfabSFrank Li return ls_pcie_ep_interrupt_init(pcie, pdev);
279a805770dSXiaowei Bao }
280a805770dSXiaowei Bao
281a805770dSXiaowei Bao static struct platform_driver ls_pcie_ep_driver = {
282a805770dSXiaowei Bao .driver = {
283a805770dSXiaowei Bao .name = "layerscape-pcie-ep",
284a805770dSXiaowei Bao .of_match_table = ls_pcie_ep_of_match,
285a805770dSXiaowei Bao .suppress_bind_attrs = true,
286a805770dSXiaowei Bao },
287a805770dSXiaowei Bao };
288a805770dSXiaowei Bao builtin_platform_driver_probe(ls_pcie_ep_driver, ls_pcie_ep_probe);
289