Skip to content

Commit 061cbfa

Browse files
nxpfranklibjorn-helgaas
authored andcommitted
PCI: layerscape: Add the endpoint linkup notifier support
Layerscape has PME interrupt, which can be used as linkup notifier. Set CFG_READY bit of PEX_PF0_CONFIG to enable accesses from root complex when linkup detected. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Xiaowei Bao <[email protected]> Signed-off-by: Frank Li <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Acked-by: Manivannan Sadhasivam <[email protected]>
1 parent 4ab9120 commit 061cbfa

File tree

1 file changed

+99
-1
lines changed

1 file changed

+99
-1
lines changed

drivers/pci/controller/dwc/pci-layerscape-ep.c

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@
1818

1919
#include "pcie-designware.h"
2020

21+
#define PEX_PF0_CONFIG 0xC0014
22+
#define PEX_PF0_CFG_READY BIT(0)
23+
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)
29+
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)
34+
2135
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
2236

2337
struct ls_pcie_ep_drvdata {
@@ -30,8 +44,84 @@ struct ls_pcie_ep {
3044
struct dw_pcie *pci;
3145
struct pci_epc_features *ls_epc;
3246
const struct ls_pcie_ep_drvdata *drvdata;
47+
int irq;
48+
bool big_endian;
3349
};
3450

51+
static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
52+
{
53+
struct dw_pcie *pci = pcie->pci;
54+
55+
if (pcie->big_endian)
56+
return ioread32be(pci->dbi_base + offset);
57+
else
58+
return ioread32(pci->dbi_base + offset);
59+
}
60+
61+
static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
62+
{
63+
struct dw_pcie *pci = pcie->pci;
64+
65+
if (pcie->big_endian)
66+
iowrite32be(value, pci->dbi_base + offset);
67+
else
68+
iowrite32(value, pci->dbi_base + offset);
69+
}
70+
71+
static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
72+
{
73+
struct ls_pcie_ep *pcie = dev_id;
74+
struct dw_pcie *pci = pcie->pci;
75+
u32 val, cfg;
76+
77+
val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
78+
ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
79+
80+
if (!val)
81+
return IRQ_NONE;
82+
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);
88+
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");
94+
}
95+
96+
return IRQ_HANDLED;
97+
}
98+
99+
static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
100+
struct platform_device *pdev)
101+
{
102+
u32 val;
103+
int ret;
104+
105+
pcie->irq = platform_get_irq_byname(pdev, "pme");
106+
if (pcie->irq < 0)
107+
return pcie->irq;
108+
109+
ret = devm_request_irq(&pdev->dev, pcie->irq, ls_pcie_ep_event_handler,
110+
IRQF_SHARED, pdev->name, pcie);
111+
if (ret) {
112+
dev_err(&pdev->dev, "Can't register PCIe IRQ\n");
113+
return ret;
114+
}
115+
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);
121+
122+
return 0;
123+
}
124+
35125
static const struct pci_epc_features*
36126
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
37127
{
@@ -125,6 +215,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
125215
struct ls_pcie_ep *pcie;
126216
struct pci_epc_features *ls_epc;
127217
struct resource *dbi_base;
218+
int ret;
128219

129220
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
130221
if (!pcie)
@@ -144,6 +235,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
144235
pci->ops = pcie->drvdata->dw_pcie_ops;
145236

146237
ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4);
238+
ls_epc->linkup_notifier = true;
147239

148240
pcie->pci = pci;
149241
pcie->ls_epc = ls_epc;
@@ -155,9 +247,15 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
155247

156248
pci->ep.ops = &ls_pcie_ep_ops;
157249

250+
pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
251+
158252
platform_set_drvdata(pdev, pcie);
159253

160-
return dw_pcie_ep_init(&pci->ep);
254+
ret = dw_pcie_ep_init(&pci->ep);
255+
if (ret)
256+
return ret;
257+
258+
return ls_pcie_ep_interrupt_init(pcie, pdev);
161259
}
162260

163261
static struct platform_driver ls_pcie_ep_driver = {

0 commit comments

Comments
 (0)