Skip to content

Commit 1800c66

Browse files
committed
Merge branch 'pci/controller/layerscape'
- Add suspend/resume support for Layerscape LS1043a, including software-managed PME_Turn_Off and transitions between L0, L2/L3_Ready Link states (Frank Li) * pci/controller/layerscape: PCI: layerscape: Add suspend/resume for ls1043a PCI: layerscape(ep): Rename pf_* as pf_lut_* PCI: layerscape: Add suspend/resume for ls1021a PCI: layerscape: Add function pointer for exit_from_l2()
2 parents 921e097 + 27b3bcb commit 1800c66

File tree

2 files changed

+176
-31
lines changed

2 files changed

+176
-31
lines changed

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct ls_pcie_ep {
4949
bool big_endian;
5050
};
5151

52-
static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
52+
static u32 ls_pcie_pf_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
5353
{
5454
struct dw_pcie *pci = pcie->pci;
5555

@@ -59,7 +59,7 @@ static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
5959
return ioread32(pci->dbi_base + offset);
6060
}
6161

62-
static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
62+
static void ls_pcie_pf_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
6363
{
6464
struct dw_pcie *pci = pcie->pci;
6565

@@ -76,8 +76,8 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
7676
u32 val, cfg;
7777
u8 offset;
7878

79-
val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
80-
ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
79+
val = ls_pcie_pf_lut_readl(pcie, PEX_PF0_PME_MES_DR);
80+
ls_pcie_pf_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
8181

8282
if (!val)
8383
return IRQ_NONE;
@@ -96,9 +96,9 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
9696
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap);
9797
dw_pcie_dbi_ro_wr_dis(pci);
9898

99-
cfg = ls_lut_readl(pcie, PEX_PF0_CONFIG);
99+
cfg = ls_pcie_pf_lut_readl(pcie, PEX_PF0_CONFIG);
100100
cfg |= PEX_PF0_CFG_READY;
101-
ls_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
101+
ls_pcie_pf_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
102102
dw_pcie_ep_linkup(&pci->ep);
103103

104104
dev_dbg(pci->dev, "Link up\n");
@@ -130,10 +130,10 @@ static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
130130
}
131131

132132
/* Enable interrupts */
133-
val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
133+
val = ls_pcie_pf_lut_readl(pcie, PEX_PF0_PME_MES_IER);
134134
val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
135135
PEX_PF0_PME_MES_IER_LUDIE;
136-
ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
136+
ls_pcie_pf_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
137137

138138
return 0;
139139
}

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

Lines changed: 168 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,41 @@
3535
#define PF_MCR_PTOMR BIT(0)
3636
#define PF_MCR_EXL2S BIT(1)
3737

38+
/* LS1021A PEXn PM Write Control Register */
39+
#define SCFG_PEXPMWRCR(idx) (0x5c + (idx) * 0x64)
40+
#define PMXMTTURNOFF BIT(31)
41+
#define SCFG_PEXSFTRSTCR 0x190
42+
#define PEXSR(idx) BIT(idx)
43+
44+
/* LS1043A PEX PME control register */
45+
#define SCFG_PEXPMECR 0x144
46+
#define PEXPME(idx) BIT(31 - (idx) * 4)
47+
48+
/* LS1043A PEX LUT debug register */
49+
#define LS_PCIE_LDBG 0x7fc
50+
#define LDBG_SR BIT(30)
51+
#define LDBG_WE BIT(31)
52+
3853
#define PCIE_IATU_NUM 6
3954

4055
struct ls_pcie_drvdata {
41-
const u32 pf_off;
56+
const u32 pf_lut_off;
57+
const struct dw_pcie_host_ops *ops;
58+
int (*exit_from_l2)(struct dw_pcie_rp *pp);
59+
bool scfg_support;
4260
bool pm_support;
4361
};
4462

4563
struct ls_pcie {
4664
struct dw_pcie *pci;
4765
const struct ls_pcie_drvdata *drvdata;
48-
void __iomem *pf_base;
66+
void __iomem *pf_lut_base;
67+
struct regmap *scfg;
68+
int index;
4969
bool big_endian;
5070
};
5171

52-
#define ls_pcie_pf_readl_addr(addr) ls_pcie_pf_readl(pcie, addr)
72+
#define ls_pcie_pf_lut_readl_addr(addr) ls_pcie_pf_lut_readl(pcie, addr)
5373
#define to_ls_pcie(x) dev_get_drvdata((x)->dev)
5474

5575
static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
@@ -90,20 +110,20 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
90110
iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
91111
}
92112

93-
static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off)
113+
static u32 ls_pcie_pf_lut_readl(struct ls_pcie *pcie, u32 off)
94114
{
95115
if (pcie->big_endian)
96-
return ioread32be(pcie->pf_base + off);
116+
return ioread32be(pcie->pf_lut_base + off);
97117

98-
return ioread32(pcie->pf_base + off);
118+
return ioread32(pcie->pf_lut_base + off);
99119
}
100120

101-
static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val)
121+
static void ls_pcie_pf_lut_writel(struct ls_pcie *pcie, u32 off, u32 val)
102122
{
103123
if (pcie->big_endian)
104-
iowrite32be(val, pcie->pf_base + off);
124+
iowrite32be(val, pcie->pf_lut_base + off);
105125
else
106-
iowrite32(val, pcie->pf_base + off);
126+
iowrite32(val, pcie->pf_lut_base + off);
107127
}
108128

109129
static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
@@ -113,19 +133,19 @@ static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
113133
u32 val;
114134
int ret;
115135

116-
val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
136+
val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
117137
val |= PF_MCR_PTOMR;
118-
ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
138+
ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
119139

120-
ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
140+
ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
121141
val, !(val & PF_MCR_PTOMR),
122142
PCIE_PME_TO_L2_TIMEOUT_US/10,
123143
PCIE_PME_TO_L2_TIMEOUT_US);
124144
if (ret)
125145
dev_err(pcie->pci->dev, "PME_Turn_off timeout\n");
126146
}
127147

128-
static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
148+
static int ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
129149
{
130150
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
131151
struct ls_pcie *pcie = to_ls_pcie(pci);
@@ -136,20 +156,22 @@ static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
136156
* Set PF_MCR_EXL2S bit in LS_PCIE_PF_MCR register for the link
137157
* to exit L2 state.
138158
*/
139-
val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
159+
val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
140160
val |= PF_MCR_EXL2S;
141-
ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
161+
ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
142162

143163
/*
144164
* L2 exit timeout of 10ms is not defined in the specifications,
145165
* it was chosen based on empirical observations.
146166
*/
147-
ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
167+
ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
148168
val, !(val & PF_MCR_EXL2S),
149169
1000,
150170
10000);
151171
if (ret)
152172
dev_err(pcie->pci->dev, "L2 exit timeout\n");
173+
174+
return ret;
153175
}
154176

155177
static int ls_pcie_host_init(struct dw_pcie_rp *pp)
@@ -168,25 +190,130 @@ static int ls_pcie_host_init(struct dw_pcie_rp *pp)
168190
return 0;
169191
}
170192

193+
static void scfg_pcie_send_turnoff_msg(struct regmap *scfg, u32 reg, u32 mask)
194+
{
195+
/* Send PME_Turn_Off message */
196+
regmap_write_bits(scfg, reg, mask, mask);
197+
198+
/*
199+
* There is no specific register to check for PME_To_Ack from endpoint.
200+
* So on the safe side, wait for PCIE_PME_TO_L2_TIMEOUT_US.
201+
*/
202+
mdelay(PCIE_PME_TO_L2_TIMEOUT_US/1000);
203+
204+
/*
205+
* Layerscape hardware reference manual recommends clearing the PMXMTTURNOFF bit
206+
* to complete the PME_Turn_Off handshake.
207+
*/
208+
regmap_write_bits(scfg, reg, mask, 0);
209+
}
210+
211+
static void ls1021a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
212+
{
213+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
214+
struct ls_pcie *pcie = to_ls_pcie(pci);
215+
216+
scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), PMXMTTURNOFF);
217+
}
218+
219+
static int scfg_pcie_exit_from_l2(struct regmap *scfg, u32 reg, u32 mask)
220+
{
221+
/* Reset the PEX wrapper to bring the link out of L2 */
222+
regmap_write_bits(scfg, reg, mask, mask);
223+
regmap_write_bits(scfg, reg, mask, 0);
224+
225+
return 0;
226+
}
227+
228+
static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
229+
{
230+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
231+
struct ls_pcie *pcie = to_ls_pcie(pci);
232+
233+
return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
234+
}
235+
236+
static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
237+
{
238+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
239+
struct ls_pcie *pcie = to_ls_pcie(pci);
240+
241+
scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
242+
}
243+
244+
static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
245+
{
246+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
247+
struct ls_pcie *pcie = to_ls_pcie(pci);
248+
u32 val;
249+
250+
/*
251+
* Reset the PEX wrapper to bring the link out of L2.
252+
* LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
253+
* clearing the soft reset on the PEX module.
254+
* LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
255+
*/
256+
val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
257+
val |= LDBG_WE;
258+
ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
259+
260+
val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
261+
val |= LDBG_SR;
262+
ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
263+
264+
val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
265+
val &= ~LDBG_SR;
266+
ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
267+
268+
val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
269+
val &= ~LDBG_WE;
270+
ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
271+
272+
return 0;
273+
}
274+
171275
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
172276
.init = ls_pcie_host_init,
173277
.pme_turn_off = ls_pcie_send_turnoff_msg,
174278
};
175279

280+
static const struct dw_pcie_host_ops ls1021a_pcie_host_ops = {
281+
.init = ls_pcie_host_init,
282+
.pme_turn_off = ls1021a_pcie_send_turnoff_msg,
283+
};
284+
176285
static const struct ls_pcie_drvdata ls1021a_drvdata = {
177-
.pm_support = false,
286+
.pm_support = true,
287+
.scfg_support = true,
288+
.ops = &ls1021a_pcie_host_ops,
289+
.exit_from_l2 = ls1021a_pcie_exit_from_l2,
290+
};
291+
292+
static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
293+
.init = ls_pcie_host_init,
294+
.pme_turn_off = ls1043a_pcie_send_turnoff_msg,
295+
};
296+
297+
static const struct ls_pcie_drvdata ls1043a_drvdata = {
298+
.pf_lut_off = 0x10000,
299+
.pm_support = true,
300+
.scfg_support = true,
301+
.ops = &ls1043a_pcie_host_ops,
302+
.exit_from_l2 = ls1043a_pcie_exit_from_l2,
178303
};
179304

180305
static const struct ls_pcie_drvdata layerscape_drvdata = {
181-
.pf_off = 0xc0000,
306+
.pf_lut_off = 0xc0000,
182307
.pm_support = true,
308+
.ops = &ls_pcie_host_ops,
309+
.exit_from_l2 = ls_pcie_exit_from_l2,
183310
};
184311

185312
static const struct of_device_id ls_pcie_of_match[] = {
186313
{ .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
187314
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
188315
{ .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
189-
{ .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
316+
{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
190317
{ .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
191318
{ .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
192319
{ .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
@@ -201,6 +328,8 @@ static int ls_pcie_probe(struct platform_device *pdev)
201328
struct dw_pcie *pci;
202329
struct ls_pcie *pcie;
203330
struct resource *dbi_base;
331+
u32 index[2];
332+
int ret;
204333

205334
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
206335
if (!pcie)
@@ -213,9 +342,8 @@ static int ls_pcie_probe(struct platform_device *pdev)
213342
pcie->drvdata = of_device_get_match_data(dev);
214343

215344
pci->dev = dev;
216-
pci->pp.ops = &ls_pcie_host_ops;
217-
218345
pcie->pci = pci;
346+
pci->pp.ops = pcie->drvdata->ops;
219347

220348
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
221349
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
@@ -224,7 +352,21 @@ static int ls_pcie_probe(struct platform_device *pdev)
224352

225353
pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
226354

227-
pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off;
355+
pcie->pf_lut_base = pci->dbi_base + pcie->drvdata->pf_lut_off;
356+
357+
if (pcie->drvdata->scfg_support) {
358+
pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg");
359+
if (IS_ERR(pcie->scfg)) {
360+
dev_err(dev, "No syscfg phandle specified\n");
361+
return PTR_ERR(pcie->scfg);
362+
}
363+
364+
ret = of_property_read_u32_array(dev->of_node, "fsl,pcie-scfg", index, 2);
365+
if (ret)
366+
return ret;
367+
368+
pcie->index = index[1];
369+
}
228370

229371
if (!ls_pcie_is_bridge(pcie))
230372
return -ENODEV;
@@ -247,11 +389,14 @@ static int ls_pcie_suspend_noirq(struct device *dev)
247389
static int ls_pcie_resume_noirq(struct device *dev)
248390
{
249391
struct ls_pcie *pcie = dev_get_drvdata(dev);
392+
int ret;
250393

251394
if (!pcie->drvdata->pm_support)
252395
return 0;
253396

254-
ls_pcie_exit_from_l2(&pcie->pci->pp);
397+
ret = pcie->drvdata->exit_from_l2(&pcie->pci->pp);
398+
if (ret)
399+
return ret;
255400

256401
return dw_pcie_resume_noirq(pcie->pci);
257402
}

0 commit comments

Comments
 (0)