diff options
Diffstat (limited to 'drivers/pci/host/pci-rcar-gen2.c')
-rw-r--r-- | drivers/pci/host/pci-rcar-gen2.c | 180 |
1 files changed, 117 insertions, 63 deletions
diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index ceec147baec3..fd3e3ab56509 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
21 | #include <linux/sizes.h> | ||
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | 23 | ||
23 | /* AHB-PCI Bridge PCI communication registers */ | 24 | /* AHB-PCI Bridge PCI communication registers */ |
@@ -39,9 +40,26 @@ | |||
39 | 40 | ||
40 | #define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20) | 41 | #define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20) |
41 | #define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24) | 42 | #define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24) |
43 | #define RCAR_PCI_INT_SIGTABORT (1 << 0) | ||
44 | #define RCAR_PCI_INT_SIGRETABORT (1 << 1) | ||
45 | #define RCAR_PCI_INT_REMABORT (1 << 2) | ||
46 | #define RCAR_PCI_INT_PERR (1 << 3) | ||
47 | #define RCAR_PCI_INT_SIGSERR (1 << 4) | ||
48 | #define RCAR_PCI_INT_RESERR (1 << 5) | ||
49 | #define RCAR_PCI_INT_WIN1ERR (1 << 12) | ||
50 | #define RCAR_PCI_INT_WIN2ERR (1 << 13) | ||
42 | #define RCAR_PCI_INT_A (1 << 16) | 51 | #define RCAR_PCI_INT_A (1 << 16) |
43 | #define RCAR_PCI_INT_B (1 << 17) | 52 | #define RCAR_PCI_INT_B (1 << 17) |
44 | #define RCAR_PCI_INT_PME (1 << 19) | 53 | #define RCAR_PCI_INT_PME (1 << 19) |
54 | #define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \ | ||
55 | RCAR_PCI_INT_SIGRETABORT | \ | ||
56 | RCAR_PCI_INT_SIGRETABORT | \ | ||
57 | RCAR_PCI_INT_REMABORT | \ | ||
58 | RCAR_PCI_INT_PERR | \ | ||
59 | RCAR_PCI_INT_SIGSERR | \ | ||
60 | RCAR_PCI_INT_RESERR | \ | ||
61 | RCAR_PCI_INT_WIN1ERR | \ | ||
62 | RCAR_PCI_INT_WIN2ERR) | ||
45 | 63 | ||
46 | #define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30) | 64 | #define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30) |
47 | #define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0) | 65 | #define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0) |
@@ -74,9 +92,6 @@ | |||
74 | 92 | ||
75 | #define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48) | 93 | #define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48) |
76 | 94 | ||
77 | /* Number of internal PCI controllers */ | ||
78 | #define RCAR_PCI_NR_CONTROLLERS 3 | ||
79 | |||
80 | struct rcar_pci_priv { | 95 | struct rcar_pci_priv { |
81 | struct device *dev; | 96 | struct device *dev; |
82 | void __iomem *reg; | 97 | void __iomem *reg; |
@@ -84,6 +99,7 @@ struct rcar_pci_priv { | |||
84 | struct resource mem_res; | 99 | struct resource mem_res; |
85 | struct resource *cfg_res; | 100 | struct resource *cfg_res; |
86 | int irq; | 101 | int irq; |
102 | unsigned long window_size; | ||
87 | }; | 103 | }; |
88 | 104 | ||
89 | /* PCI configuration space operations */ | 105 | /* PCI configuration space operations */ |
@@ -102,6 +118,10 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn, | |||
102 | if (slot > 2) | 118 | if (slot > 2) |
103 | return NULL; | 119 | return NULL; |
104 | 120 | ||
121 | /* bridge logic only has registers to 0x40 */ | ||
122 | if (slot == 0x0 && where >= 0x40) | ||
123 | return NULL; | ||
124 | |||
105 | val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG : | 125 | val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG : |
106 | RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG; | 126 | RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG; |
107 | 127 | ||
@@ -156,7 +176,7 @@ static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn, | |||
156 | } | 176 | } |
157 | 177 | ||
158 | /* PCI interrupt mapping */ | 178 | /* PCI interrupt mapping */ |
159 | static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 179 | static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
160 | { | 180 | { |
161 | struct pci_sys_data *sys = dev->bus->sysdata; | 181 | struct pci_sys_data *sys = dev->bus->sysdata; |
162 | struct rcar_pci_priv *priv = sys->private_data; | 182 | struct rcar_pci_priv *priv = sys->private_data; |
@@ -164,8 +184,48 @@ static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | |||
164 | return priv->irq; | 184 | return priv->irq; |
165 | } | 185 | } |
166 | 186 | ||
187 | #ifdef CONFIG_PCI_DEBUG | ||
188 | /* if debug enabled, then attach an error handler irq to the bridge */ | ||
189 | |||
190 | static irqreturn_t rcar_pci_err_irq(int irq, void *pw) | ||
191 | { | ||
192 | struct rcar_pci_priv *priv = pw; | ||
193 | u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG); | ||
194 | |||
195 | if (status & RCAR_PCI_INT_ALLERRORS) { | ||
196 | dev_err(priv->dev, "error irq: status %08x\n", status); | ||
197 | |||
198 | /* clear the error(s) */ | ||
199 | iowrite32(status & RCAR_PCI_INT_ALLERRORS, | ||
200 | priv->reg + RCAR_PCI_INT_STATUS_REG); | ||
201 | return IRQ_HANDLED; | ||
202 | } | ||
203 | |||
204 | return IRQ_NONE; | ||
205 | } | ||
206 | |||
207 | static void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) | ||
208 | { | ||
209 | int ret; | ||
210 | u32 val; | ||
211 | |||
212 | ret = devm_request_irq(priv->dev, priv->irq, rcar_pci_err_irq, | ||
213 | IRQF_SHARED, "error irq", priv); | ||
214 | if (ret) { | ||
215 | dev_err(priv->dev, "cannot claim IRQ for error handling\n"); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | val = ioread32(priv->reg + RCAR_PCI_INT_ENABLE_REG); | ||
220 | val |= RCAR_PCI_INT_ALLERRORS; | ||
221 | iowrite32(val, priv->reg + RCAR_PCI_INT_ENABLE_REG); | ||
222 | } | ||
223 | #else | ||
224 | static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { } | ||
225 | #endif | ||
226 | |||
167 | /* PCI host controller setup */ | 227 | /* PCI host controller setup */ |
168 | static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) | 228 | static int rcar_pci_setup(int nr, struct pci_sys_data *sys) |
169 | { | 229 | { |
170 | struct rcar_pci_priv *priv = sys->private_data; | 230 | struct rcar_pci_priv *priv = sys->private_data; |
171 | void __iomem *reg = priv->reg; | 231 | void __iomem *reg = priv->reg; |
@@ -183,10 +243,31 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) | |||
183 | iowrite32(val, reg + RCAR_USBCTR_REG); | 243 | iowrite32(val, reg + RCAR_USBCTR_REG); |
184 | udelay(4); | 244 | udelay(4); |
185 | 245 | ||
186 | /* De-assert reset and set PCIAHB window1 size to 1GB */ | 246 | /* De-assert reset and reset PCIAHB window1 size */ |
187 | val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK | | 247 | val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK | |
188 | RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST); | 248 | RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST); |
189 | iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG); | 249 | |
250 | /* Setup PCIAHB window1 size */ | ||
251 | switch (priv->window_size) { | ||
252 | case SZ_2G: | ||
253 | val |= RCAR_USBCTR_PCIAHB_WIN1_2G; | ||
254 | break; | ||
255 | case SZ_1G: | ||
256 | val |= RCAR_USBCTR_PCIAHB_WIN1_1G; | ||
257 | break; | ||
258 | case SZ_512M: | ||
259 | val |= RCAR_USBCTR_PCIAHB_WIN1_512M; | ||
260 | break; | ||
261 | default: | ||
262 | pr_warn("unknown window size %ld - defaulting to 256M\n", | ||
263 | priv->window_size); | ||
264 | priv->window_size = SZ_256M; | ||
265 | /* fall-through */ | ||
266 | case SZ_256M: | ||
267 | val |= RCAR_USBCTR_PCIAHB_WIN1_256M; | ||
268 | break; | ||
269 | } | ||
270 | iowrite32(val, reg + RCAR_USBCTR_REG); | ||
190 | 271 | ||
191 | /* Configure AHB master and slave modes */ | 272 | /* Configure AHB master and slave modes */ |
192 | iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG); | 273 | iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG); |
@@ -197,7 +278,7 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) | |||
197 | RCAR_PCI_ARBITER_PCIBP_MODE; | 278 | RCAR_PCI_ARBITER_PCIBP_MODE; |
198 | iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG); | 279 | iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG); |
199 | 280 | ||
200 | /* PCI-AHB mapping: 0x40000000-0x80000000 */ | 281 | /* PCI-AHB mapping: 0x40000000 base */ |
201 | iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16, | 282 | iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16, |
202 | reg + RCAR_PCIAHB_WIN1_CTR_REG); | 283 | reg + RCAR_PCIAHB_WIN1_CTR_REG); |
203 | 284 | ||
@@ -224,10 +305,15 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) | |||
224 | iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME, | 305 | iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME, |
225 | reg + RCAR_PCI_INT_ENABLE_REG); | 306 | reg + RCAR_PCI_INT_ENABLE_REG); |
226 | 307 | ||
308 | if (priv->irq > 0) | ||
309 | rcar_pci_setup_errirq(priv); | ||
310 | |||
227 | /* Add PCI resources */ | 311 | /* Add PCI resources */ |
228 | pci_add_resource(&sys->resources, &priv->io_res); | 312 | pci_add_resource(&sys->resources, &priv->io_res); |
229 | pci_add_resource(&sys->resources, &priv->mem_res); | 313 | pci_add_resource(&sys->resources, &priv->mem_res); |
230 | 314 | ||
315 | /* Setup bus number based on platform device id */ | ||
316 | sys->busnr = to_platform_device(priv->dev)->id; | ||
231 | return 1; | 317 | return 1; |
232 | } | 318 | } |
233 | 319 | ||
@@ -236,48 +322,13 @@ static struct pci_ops rcar_pci_ops = { | |||
236 | .write = rcar_pci_write_config, | 322 | .write = rcar_pci_write_config, |
237 | }; | 323 | }; |
238 | 324 | ||
239 | static struct hw_pci rcar_hw_pci __initdata = { | 325 | static int rcar_pci_probe(struct platform_device *pdev) |
240 | .map_irq = rcar_pci_map_irq, | ||
241 | .ops = &rcar_pci_ops, | ||
242 | .setup = rcar_pci_setup, | ||
243 | }; | ||
244 | |||
245 | static int rcar_pci_count __initdata; | ||
246 | |||
247 | static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv) | ||
248 | { | ||
249 | void **private_data; | ||
250 | int count; | ||
251 | |||
252 | if (rcar_hw_pci.nr_controllers < rcar_pci_count) | ||
253 | goto add_priv; | ||
254 | |||
255 | /* (Re)allocate private data pointer array if needed */ | ||
256 | count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS; | ||
257 | private_data = kzalloc(count * sizeof(void *), GFP_KERNEL); | ||
258 | if (!private_data) | ||
259 | return -ENOMEM; | ||
260 | |||
261 | rcar_pci_count = count; | ||
262 | if (rcar_hw_pci.private_data) { | ||
263 | memcpy(private_data, rcar_hw_pci.private_data, | ||
264 | rcar_hw_pci.nr_controllers * sizeof(void *)); | ||
265 | kfree(rcar_hw_pci.private_data); | ||
266 | } | ||
267 | |||
268 | rcar_hw_pci.private_data = private_data; | ||
269 | |||
270 | add_priv: | ||
271 | /* Add private data pointer to the array */ | ||
272 | rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int __init rcar_pci_probe(struct platform_device *pdev) | ||
277 | { | 326 | { |
278 | struct resource *cfg_res, *mem_res; | 327 | struct resource *cfg_res, *mem_res; |
279 | struct rcar_pci_priv *priv; | 328 | struct rcar_pci_priv *priv; |
280 | void __iomem *reg; | 329 | void __iomem *reg; |
330 | struct hw_pci hw; | ||
331 | void *hw_private[1]; | ||
281 | 332 | ||
282 | cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 333 | cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
283 | reg = devm_ioremap_resource(&pdev->dev, cfg_res); | 334 | reg = devm_ioremap_resource(&pdev->dev, cfg_res); |
@@ -308,31 +359,34 @@ static int __init rcar_pci_probe(struct platform_device *pdev) | |||
308 | priv->reg = reg; | 359 | priv->reg = reg; |
309 | priv->dev = &pdev->dev; | 360 | priv->dev = &pdev->dev; |
310 | 361 | ||
311 | return rcar_pci_add_controller(priv); | 362 | if (priv->irq < 0) { |
363 | dev_err(&pdev->dev, "no valid irq found\n"); | ||
364 | return priv->irq; | ||
365 | } | ||
366 | |||
367 | priv->window_size = SZ_1G; | ||
368 | |||
369 | hw_private[0] = priv; | ||
370 | memset(&hw, 0, sizeof(hw)); | ||
371 | hw.nr_controllers = ARRAY_SIZE(hw_private); | ||
372 | hw.private_data = hw_private; | ||
373 | hw.map_irq = rcar_pci_map_irq; | ||
374 | hw.ops = &rcar_pci_ops; | ||
375 | hw.setup = rcar_pci_setup; | ||
376 | pci_common_init_dev(&pdev->dev, &hw); | ||
377 | return 0; | ||
312 | } | 378 | } |
313 | 379 | ||
314 | static struct platform_driver rcar_pci_driver = { | 380 | static struct platform_driver rcar_pci_driver = { |
315 | .driver = { | 381 | .driver = { |
316 | .name = "pci-rcar-gen2", | 382 | .name = "pci-rcar-gen2", |
383 | .owner = THIS_MODULE, | ||
384 | .suppress_bind_attrs = true, | ||
317 | }, | 385 | }, |
386 | .probe = rcar_pci_probe, | ||
318 | }; | 387 | }; |
319 | 388 | ||
320 | static int __init rcar_pci_init(void) | 389 | module_platform_driver(rcar_pci_driver); |
321 | { | ||
322 | int retval; | ||
323 | |||
324 | retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe); | ||
325 | if (!retval) | ||
326 | pci_common_init(&rcar_hw_pci); | ||
327 | |||
328 | /* Private data pointer array is not needed any more */ | ||
329 | kfree(rcar_hw_pci.private_data); | ||
330 | rcar_hw_pci.private_data = NULL; | ||
331 | |||
332 | return retval; | ||
333 | } | ||
334 | |||
335 | subsys_initcall(rcar_pci_init); | ||
336 | 390 | ||
337 | MODULE_LICENSE("GPL v2"); | 391 | MODULE_LICENSE("GPL v2"); |
338 | MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI"); | 392 | MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI"); |