1 // SPDX-License-Identifier: GPL-2.0
3 * PCIe controller EP driver for Freescale Layerscape SoCs
5 * Copyright (C) 2018 NXP Semiconductor.
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/of_pci.h>
13 #include <linux/of_platform.h>
14 #include <linux/of_address.h>
15 #include <linux/pci.h>
16 #include <linux/platform_device.h>
17 #include <linux/resource.h>
19 #include "pcie-designware.h"
21 #define PEX_PF0_CONFIG 0xC0014
22 #define PEX_PF0_CFG_READY BIT(0)
24 /* PEX PFa PCIE PME and message interrupt registers*/
25 #define PEX_PF0_PME_MES_DR 0xC0020
26 #define PEX_PF0_PME_MES_DR_LUD BIT(7)
27 #define PEX_PF0_PME_MES_DR_LDD BIT(9)
28 #define PEX_PF0_PME_MES_DR_HRD BIT(10)
30 #define PEX_PF0_PME_MES_IER 0xC0028
31 #define PEX_PF0_PME_MES_IER_LUDIE BIT(7)
32 #define PEX_PF0_PME_MES_IER_LDDIE BIT(9)
33 #define PEX_PF0_PME_MES_IER_HRDIE BIT(10)
35 #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
37 struct ls_pcie_ep_drvdata {
39 const struct dw_pcie_ep_ops *ops;
40 const struct dw_pcie_ops *dw_pcie_ops;
45 struct pci_epc_features *ls_epc;
46 const struct ls_pcie_ep_drvdata *drvdata;
51 static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
53 struct dw_pcie *pci = pcie->pci;
56 return ioread32be(pci->dbi_base + offset);
58 return ioread32(pci->dbi_base + offset);
61 static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
63 struct dw_pcie *pci = pcie->pci;
66 iowrite32be(value, pci->dbi_base + offset);
68 iowrite32(value, pci->dbi_base + offset);
71 static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
73 struct ls_pcie_ep *pcie = dev_id;
74 struct dw_pcie *pci = pcie->pci;
77 val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
78 ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
83 if (val & PEX_PF0_PME_MES_DR_LUD) {
84 cfg = ls_lut_readl(pcie, PEX_PF0_CONFIG);
85 cfg |= PEX_PF0_CFG_READY;
86 ls_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
87 dw_pcie_ep_linkup(&pci->ep);
89 dev_dbg(pci->dev, "Link up\n");
90 } else if (val & PEX_PF0_PME_MES_DR_LDD) {
91 dev_dbg(pci->dev, "Link down\n");
92 } else if (val & PEX_PF0_PME_MES_DR_HRD) {
93 dev_dbg(pci->dev, "Hot reset\n");
99 static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
100 struct platform_device *pdev)
105 pcie->irq = platform_get_irq_byname(pdev, "pme");
109 ret = devm_request_irq(&pdev->dev, pcie->irq, ls_pcie_ep_event_handler,
110 IRQF_SHARED, pdev->name, pcie);
112 dev_err(&pdev->dev, "Can't register PCIe IRQ\n");
116 /* Enable interrupts */
117 val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
118 val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
119 PEX_PF0_PME_MES_IER_LUDIE;
120 ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
125 static const struct pci_epc_features*
126 ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
128 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
129 struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
134 static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
136 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
137 struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
138 struct dw_pcie_ep_func *ep_func;
141 ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
145 for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
146 dw_pcie_ep_reset_bar(pci, bar);
148 pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
149 pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
152 static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
153 enum pci_epc_irq_type type, u16 interrupt_num)
155 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
158 case PCI_EPC_IRQ_LEGACY:
159 return dw_pcie_ep_raise_legacy_irq(ep, func_no);
160 case PCI_EPC_IRQ_MSI:
161 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
162 case PCI_EPC_IRQ_MSIX:
163 return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
166 dev_err(pci->dev, "UNKNOWN IRQ type\n");
171 static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
174 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
175 struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
177 WARN_ON(func_no && !pcie->drvdata->func_offset);
178 return pcie->drvdata->func_offset * func_no;
181 static const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
182 .ep_init = ls_pcie_ep_init,
183 .raise_irq = ls_pcie_ep_raise_irq,
184 .get_features = ls_pcie_ep_get_features,
185 .func_conf_select = ls_pcie_ep_func_conf_select,
188 static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
189 .ops = &ls_pcie_ep_ops,
192 static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = {
193 .func_offset = 0x20000,
194 .ops = &ls_pcie_ep_ops,
197 static const struct ls_pcie_ep_drvdata lx2_ep_drvdata = {
198 .func_offset = 0x8000,
199 .ops = &ls_pcie_ep_ops,
202 static const struct of_device_id ls_pcie_ep_of_match[] = {
203 { .compatible = "fsl,ls1028a-pcie-ep", .data = &ls1_ep_drvdata },
204 { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
205 { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
206 { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
207 { .compatible = "fsl,lx2160ar2-pcie-ep", .data = &lx2_ep_drvdata },
211 static int __init ls_pcie_ep_probe(struct platform_device *pdev)
213 struct device *dev = &pdev->dev;
215 struct ls_pcie_ep *pcie;
216 struct pci_epc_features *ls_epc;
217 struct resource *dbi_base;
220 pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
224 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
228 ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL);
232 pcie->drvdata = of_device_get_match_data(dev);
235 pci->ops = pcie->drvdata->dw_pcie_ops;
237 ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4);
238 ls_epc->linkup_notifier = true;
241 pcie->ls_epc = ls_epc;
243 dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
244 pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
245 if (IS_ERR(pci->dbi_base))
246 return PTR_ERR(pci->dbi_base);
248 pci->ep.ops = &ls_pcie_ep_ops;
250 pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
252 platform_set_drvdata(pdev, pcie);
254 ret = dw_pcie_ep_init(&pci->ep);
258 return ls_pcie_ep_interrupt_init(pcie, pdev);
261 static struct platform_driver ls_pcie_ep_driver = {
263 .name = "layerscape-pcie-ep",
264 .of_match_table = ls_pcie_ep_of_match,
265 .suppress_bind_attrs = true,
268 builtin_platform_driver_probe(ls_pcie_ep_driver, ls_pcie_ep_probe);