1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
|
From f8691a62199319d9e37cd451a9b8364aa640c4cb Mon Sep 17 00:00:00 2001
From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
Date: Thu, 18 May 2017 17:45:19 +0900
Subject: [PATCH 11/15] Add rcar-pci hibernation code
Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
---
drivers/pci/host/pci-rcar-gen2.c | 281 ++++++++++++++++++++++++++++++++++++---
1 file changed, 266 insertions(+), 15 deletions(-)
diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c
index 57b6572..4cb9693 100644
--- a/drivers/pci/host/pci-rcar-gen2.c
+++ b/drivers/pci/host/pci-rcar-gen2.c
@@ -23,9 +23,12 @@
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/usb/phy.h>
+#include <linux/clk.h>
/* AHB-PCI Bridge PCI communication registers */
#define RCAR_AHBPCI_PCICOM_OFFSET 0x800
+#define RCAR_PCICONF_OHCI 0x0
+#define RCAR_PCICONF_EHCI 0x100
#define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
#define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
@@ -104,6 +107,14 @@ struct rcar_pci_priv {
int domain;
int irq;
unsigned long window_size;
+ void __iomem *ohci_memdata;
+ void __iomem *ehci_memdata;
+#ifndef MCCILDK_CHANGE_DISABLE
+ u32 store_cfg[12];
+#else
+ u32 store_cfg[9];
+#endif
+ struct usb_phy *phy;
};
/* PCI configuration space operations */
@@ -276,12 +287,6 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
/* Configure AHB master and slave modes */
iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
- /* Configure PCI arbiter */
- val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
- val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
- RCAR_PCI_ARBITER_PCIBP_MODE;
- iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
-
/* PCI-AHB mapping: 0x40000000 base */
iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
reg + RCAR_PCIAHB_WIN1_CTR_REG);
@@ -290,9 +295,25 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
val = priv->mem_res.start | RCAR_AHBPCI_WIN_CTR_MEM;
iowrite32(val, reg + RCAR_AHBPCI_WIN2_CTR_REG);
+ /* Enable PCI interrupts */
+ iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
+ reg + RCAR_PCI_INT_ENABLE_REG);
+
+ /* Configure PCI arbiter */
+ val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
+ val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
+ RCAR_PCI_ARBITER_PCIBP_MODE;
+ iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
+
/* Enable AHB-PCI bridge PCI configuration access */
iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ val = ioread32(reg + PCI_COMMAND);
+
+ val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ iowrite32(val, reg + PCI_COMMAND);
+
/* Set PCI-AHB Window1 address */
iowrite32(0x40000000 | PCI_BASE_ADDRESS_MEM_PREFETCH,
reg + PCI_BASE_ADDRESS_1);
@@ -300,15 +321,6 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
iowrite32(val, reg + PCI_BASE_ADDRESS_0);
- val = ioread32(reg + PCI_COMMAND);
- val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
- iowrite32(val, reg + PCI_COMMAND);
-
- /* Enable PCI interrupts */
- iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
- reg + RCAR_PCI_INT_ENABLE_REG);
-
if (priv->irq > 0)
rcar_pci_setup_errirq(priv);
@@ -326,6 +338,8 @@ static struct pci_ops rcar_pci_ops = {
.write = rcar_pci_write_config,
};
+#define RCAR_MAX_PCI_HOSTS 2
+static struct rcar_pci_priv *keep_priv[RCAR_MAX_PCI_HOSTS];
static int rcar_pci_probe(struct platform_device *pdev)
{
struct resource *cfg_res, *mem_res;
@@ -350,6 +364,7 @@ static int rcar_pci_probe(struct platform_device *pdev)
return -ENOMEM;
priv->mem_res = *mem_res;
+ keep_priv[pdev->id] = priv;
/*
* The controller does not support/use port I/O,
* so setup a dummy port I/O region here.
@@ -378,6 +393,7 @@ static int rcar_pci_probe(struct platform_device *pdev)
return PTR_ERR(phy);
usb_phy_init(phy);
+ priv->phy = phy;
hw_private[0] = priv;
memset(&hw, 0, sizeof(hw));
@@ -390,14 +406,249 @@ static int rcar_pci_probe(struct platform_device *pdev)
hw.domain = priv->domain;
#endif
pci_common_init_dev(&pdev->dev, &hw);
+ priv->ohci_memdata = ioremap(cfg_res->start - 0x10000, 0x1000);
+ priv->ehci_memdata = ioremap(cfg_res->start - 0x10000 + 0x1000, 0x1000);
+ return 0;
+}
+
+static int rcar_pci_suspend(struct device *dev)
+{
+ struct clk *clk;
+ clk = clk_get(NULL, "ehci");
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+ return 0;
+}
+static int rcar_pci_resume(struct device *dev)
+{
+ struct clk *clk;
+ clk = clk_get(NULL, "ehci");
+ clk_prepare_enable(clk);
+ clk_put(clk);
+ return 0;
+}
+static u32 rcar_pci_get_conf(struct rcar_pci_priv *priv, int id, int offset)
+{
+ u32 val, kpt;
+ void __iomem *data;
+ kpt = ioread32(priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ val = id ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
+ RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
+
+ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ data = priv->reg + (id >> 1) * 0x100;
+ val = ioread32(data + offset);
+ iowrite32(kpt, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ return val;
+}
+
+static void rcar_pci_set_conf(struct rcar_pci_priv *priv,
+ int id, int offset, u32 d)
+{
+ u32 val, kpt;
+ void __iomem *data;
+ kpt = ioread32(priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ val = id ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
+ RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
+
+ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ data = priv->reg + (id >> 1) * 0x100;
+ iowrite32(d, data + offset);
+ iowrite32(kpt, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+}
+
+
+static int rcar_pci_freeze(struct device *dev)
+{
+ struct rcar_pci_priv *priv = keep_priv[to_platform_device(dev)->id];
+ struct clk *clk;
+ clk = clk_get(NULL, "ehci");
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+
+#ifndef MCCILDK_CHANGE_DISABLE
+ priv->store_cfg[0] = rcar_pci_get_conf(priv, 0, PCI_COMMAND);
+ priv->store_cfg[1] = rcar_pci_get_conf(priv, 1, PCI_COMMAND);
+ priv->store_cfg[2] = rcar_pci_get_conf(priv, 2, PCI_COMMAND);
+ priv->store_cfg[3] = rcar_pci_get_conf(priv, 0, PCI_CACHE_LINE_SIZE);
+ priv->store_cfg[4] = rcar_pci_get_conf(priv, 1, PCI_CACHE_LINE_SIZE);
+ priv->store_cfg[5] = rcar_pci_get_conf(priv, 2, PCI_CACHE_LINE_SIZE);
+ priv->store_cfg[6] = rcar_pci_get_conf(priv, 0, PCI_INTERRUPT_LINE);
+ priv->store_cfg[7] = rcar_pci_get_conf(priv, 1, PCI_INTERRUPT_LINE);
+ priv->store_cfg[8] = rcar_pci_get_conf(priv, 2, PCI_INTERRUPT_LINE);
+ priv->store_cfg[9] = rcar_pci_get_conf(priv, 0, PCI_BASE_ADDRESS_0);
+ priv->store_cfg[10] = rcar_pci_get_conf(priv, 1, PCI_BASE_ADDRESS_0);
+ priv->store_cfg[11] = rcar_pci_get_conf(priv, 2, PCI_BASE_ADDRESS_0);
+#else
+ priv->store_cfg[0] = rcar_pci_get_conf(priv, 0, 0x04);
+ priv->store_cfg[1] = rcar_pci_get_conf(priv, 1, 0x04);
+ priv->store_cfg[2] = rcar_pci_get_conf(priv, 2, 0x04);
+ priv->store_cfg[3] = rcar_pci_get_conf(priv, 0, 0x0c);
+ priv->store_cfg[4] = rcar_pci_get_conf(priv, 1, 0x0c);
+ priv->store_cfg[5] = rcar_pci_get_conf(priv, 2, 0x0c);
+ priv->store_cfg[6] = rcar_pci_get_conf(priv, 0, 0x3c);
+ priv->store_cfg[7] = rcar_pci_get_conf(priv, 1, 0x3c);
+ priv->store_cfg[8] = rcar_pci_get_conf(priv, 2, 0x3c);
+#endif
+ pm_runtime_disable(priv->dev);
+ return 0;
+}
+
+static int rcar_pci_restore(struct device *dev)
+{
+ struct clk *clk;
+ void *m;
+ u32 val;
+ struct rcar_pci_priv *priv = keep_priv[to_platform_device(dev)->id];
+ void __iomem *reg = priv->reg;
+ int id = to_platform_device(dev)->id;
+
+ pm_runtime_enable(priv->dev);
+ pm_runtime_get_sync(priv->dev);
+
+ clk = clk_get(NULL, "ehci");
+ clk_prepare_enable(clk);
+ clk_put(clk);
+ clk = clk_get(NULL, "hsusb");
+ clk_prepare_enable(clk);
+ clk_put(clk);
+ usb_phy_set_suspend(priv->phy, 0);
+ m = ioremap(0xe61501c4, 4);
+ val = readl(m);
+ iounmap(m);
+ m = ioremap(0xe615014c, 4);
+ writel(val & ~(3 << 3), m);
+ iounmap(m);
+ val = ioread32(reg + RCAR_PCI_UNIT_REV_REG);
+ dev_info(priv->dev, "PCI: bus%u revision %x\n", id, val);
+
+ /* Disable Direct Power Down State and assert reset */
+ val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD;
+#ifndef MCCILDK_CHANGE_DISABLE
+ val |= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST;
+#else
+ val |= RCAR_USBCTR_USBH_RST;
+#endif
+ iowrite32(val, reg + RCAR_USBCTR_REG);
+ udelay(4);
+ /* De-assert reset */
+#ifndef MCCILDK_CHANGE_DISABLE
+ val &= ~(RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST
+ | RCAR_USBCTR_PCICLK_MASK);
+ iowrite32(val, reg + RCAR_USBCTR_REG);
+ /* reset PCIAHB window size */
+ val &= ~RCAR_USBCTR_PCIAHB_WIN1_MASK;
+ val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
+ iowrite32(val, reg + RCAR_USBCTR_REG);
+#else
+ val &= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST
+ | RCAR_USBCTR_PCICLK_MASK;
+ iowrite32(val, reg + RCAR_USBCTR_REG);
+ val &= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST
+ | RCAR_USBCTR_PCICLK_MASK;
+ iowrite32(val, reg + RCAR_USBCTR_REG);
+ /* reset PCIAHB window size */
+ val &= RCAR_USBCTR_PCIAHB_WIN1_MASK;
+ val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
+ iowrite32(val, reg + RCAR_USBCTR_REG);
+#endif
+
+ /* Configure AHB master and slave modes */
+ iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
+
+ /* PCI-AHB mapping: 0x40000000 base */
+ iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
+ reg + RCAR_PCIAHB_WIN1_CTR_REG);
+
+ /* AHB-PCI mapping: OHCI/EHCI registers */
+ val = priv->mem_res.start | RCAR_AHBPCI_WIN_CTR_MEM;
+ iowrite32(val, reg + RCAR_AHBPCI_WIN2_CTR_REG);
+
+ /* Enable PCI interrupts */
+ iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
+ reg + RCAR_PCI_INT_ENABLE_REG);
+
+ /* Configure PCI arbiter */
+ val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
+ val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
+ RCAR_PCI_ARBITER_PCIBP_MODE;
+ iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
+
+ /* Enable AHB-PCI bridge PCI configuration access */
+ iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
+ reg + RCAR_AHBPCI_WIN1_CTR_REG);
+
+ val = ioread32(reg + PCI_COMMAND);
+ val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ iowrite32(val, reg + PCI_COMMAND);
+
+ /* Set PCI-AHB Window1 address */
+ iowrite32(0x40000000 | PCI_BASE_ADDRESS_MEM_PREFETCH,
+ reg + PCI_BASE_ADDRESS_1);
+ /* Set AHB-PCI bridge PCI communication area address */
+ val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
+ iowrite32(val, reg + PCI_BASE_ADDRESS_0);
+
+ if (priv->irq > 0)
+ rcar_pci_setup_errirq(priv);
+#ifndef MCCILDK_CHANGE_DISABLE
+ rcar_pci_set_conf(priv, 0, PCI_COMMAND, priv->store_cfg[0]);
+ rcar_pci_set_conf(priv, 1, PCI_COMMAND, priv->store_cfg[1]);
+ rcar_pci_set_conf(priv, 2, PCI_COMMAND, priv->store_cfg[2]);
+ rcar_pci_set_conf(priv, 0, PCI_CACHE_LINE_SIZE, priv->store_cfg[3]);
+ rcar_pci_set_conf(priv, 1, PCI_CACHE_LINE_SIZE, priv->store_cfg[4]);
+ rcar_pci_set_conf(priv, 2, PCI_CACHE_LINE_SIZE, priv->store_cfg[5]);
+ rcar_pci_set_conf(priv, 0, PCI_INTERRUPT_LINE, priv->store_cfg[6]);
+ rcar_pci_set_conf(priv, 1, PCI_INTERRUPT_LINE, priv->store_cfg[7]);
+ rcar_pci_set_conf(priv, 2, PCI_INTERRUPT_LINE, priv->store_cfg[8]);
+ rcar_pci_set_conf(priv, 1, PCI_BASE_ADDRESS_0, priv->store_cfg[10]);
+ rcar_pci_set_conf(priv, 2, PCI_BASE_ADDRESS_0, priv->store_cfg[11]);
+#else
+ rcar_pci_set_conf(priv, 1, PCI_COMMAND, PCI_COMMAND_SERR
+ | PCI_COMMAND_PARITY | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_MASTER);
+ rcar_pci_set_conf(priv, 1, PCI_BASE_ADDRESS_0
+ priv->cfg_res->start - 0x10000);
+ rcar_pci_set_conf(priv, 2, PCI_COMMAND, PCI_COMMAND_SERR
+ | PCI_COMMAND_PARITY | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_MASTER);
+ rcar_pci_set_conf(priv, 2, PCI_BASE_ADDRESS_0,
+ priv->cfg_res->start - 0x10000 + 0x1000);
+ rcar_pci_set_conf(priv, 0, PCI_CACHE_LINE_SIZE, priv->store_cfg[3]);
+ rcar_pci_set_conf(priv, 1, PCI_CACHE_LINE_SIZE, priv->store_cfg[4]);
+ rcar_pci_set_conf(priv, 2, PCI_CACHE_LINE_SIZE, priv->store_cfg[5]);
+ rcar_pci_set_conf(priv, 0, PCI_INTERRUPT_LINE, 0x00020100);
+ rcar_pci_set_conf(priv, 1, PCI_INTERRUPT_LINE, 0x2a010100);
+ rcar_pci_set_conf(priv, 2, PCI_INTERRUPT_LINE, 0x22100200);
+ val = RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG;
+ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+ val = ioread32(priv->reg + 0x04);
+ iowrite32(val | (1 << 1), priv->reg + 0x04);
+ val = ioread32(priv->reg + 0x104);
+ iowrite32(val | (1 << 1), priv->reg + 0x104);
+
+ val = RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
+ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
+#endif
return 0;
}
+static const struct dev_pm_ops rcar_pci_pm_ops = {
+ .suspend = rcar_pci_suspend,
+ .resume = rcar_pci_resume,
+ .freeze_noirq = rcar_pci_freeze,
+ .restore_noirq = rcar_pci_restore,
+ .thaw = rcar_pci_resume,
+ .poweroff = rcar_pci_suspend
+};
+
static struct platform_driver rcar_pci_driver = {
.driver = {
.name = "pci-rcar-gen2",
.owner = THIS_MODULE,
.suppress_bind_attrs = true,
+ .pm = &rcar_pci_pm_ops,
},
.probe = rcar_pci_probe,
};
--
1.8.3.1
|