diff options
Diffstat (limited to 'arch/sh/drivers/pci/pcie-sh7786.c')
| -rw-r--r-- | arch/sh/drivers/pci/pcie-sh7786.c | 103 |
1 files changed, 66 insertions, 37 deletions
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index a162a7f86b2e..a78b9a935585 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Low-Level PCI Express Support for the SH7786 * * Copyright (C) 2009 - 2011 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. */ #define pr_fmt(fmt) "PCI: " fmt @@ -15,12 +12,14 @@ #include <linux/io.h> #include <linux/async.h> #include <linux/delay.h> +#include <linux/dma-map-ops.h> #include <linux/slab.h> #include <linux/clk.h> #include <linux/sh_clk.h> #include <linux/sh_intc.h> +#include <cpu/sh7786.h> #include "pcie-sh7786.h" -#include <asm/sizes.h> +#include <linux/sizes.h> struct sh7786_pcie_port { struct pci_channel *hose; @@ -32,6 +31,8 @@ struct sh7786_pcie_port { static struct sh7786_pcie_port *sh7786_pcie_ports; static unsigned int nr_ports; +size_t memsize; +u64 memstart; static struct sh7786_pcie_hwops { int (*core_init)(void); @@ -40,73 +41,73 @@ static struct sh7786_pcie_hwops { static struct resource sh7786_pci0_resources[] = { { - .name = "PCIe0 IO", + .name = "PCIe0 MEM 0", .start = 0xfd000000, .end = 0xfd000000 + SZ_8M - 1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_MEM, }, { - .name = "PCIe0 MEM 0", + .name = "PCIe0 MEM 1", .start = 0xc0000000, .end = 0xc0000000 + SZ_512M - 1, .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, }, { - .name = "PCIe0 MEM 1", + .name = "PCIe0 MEM 2", .start = 0x10000000, .end = 0x10000000 + SZ_64M - 1, .flags = IORESOURCE_MEM, }, { - .name = "PCIe0 MEM 2", + .name = "PCIe0 IO", .start = 0xfe100000, .end = 0xfe100000 + SZ_1M - 1, - .flags = IORESOURCE_MEM, + .flags = IORESOURCE_IO, }, }; static struct resource sh7786_pci1_resources[] = { { - .name = "PCIe1 IO", + .name = "PCIe1 MEM 0", .start = 0xfd800000, .end = 0xfd800000 + SZ_8M - 1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_MEM, }, { - .name = "PCIe1 MEM 0", + .name = "PCIe1 MEM 1", .start = 0xa0000000, .end = 0xa0000000 + SZ_512M - 1, .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, }, { - .name = "PCIe1 MEM 1", + .name = "PCIe1 MEM 2", .start = 0x30000000, .end = 0x30000000 + SZ_256M - 1, .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, }, { - .name = "PCIe1 MEM 2", + .name = "PCIe1 IO", .start = 0xfe300000, .end = 0xfe300000 + SZ_1M - 1, - .flags = IORESOURCE_MEM, + .flags = IORESOURCE_IO, }, }; static struct resource sh7786_pci2_resources[] = { { - .name = "PCIe2 IO", + .name = "PCIe2 MEM 0", .start = 0xfc800000, .end = 0xfc800000 + SZ_4M - 1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_MEM, }, { - .name = "PCIe2 MEM 0", + .name = "PCIe2 MEM 1", .start = 0x80000000, .end = 0x80000000 + SZ_512M - 1, .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, }, { - .name = "PCIe2 MEM 1", + .name = "PCIe2 MEM 2", .start = 0x20000000, .end = 0x20000000 + SZ_256M - 1, .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, }, { - .name = "PCIe2 MEM 2", + .name = "PCIe2 IO", .start = 0xfcd00000, .end = 0xfcd00000 + SZ_1M - 1, - .flags = IORESOURCE_MEM, + .flags = IORESOURCE_IO, }, }; @@ -138,12 +139,12 @@ static void sh7786_pci_fixup(struct pci_dev *dev) * Prevent enumeration of root complex resources. */ if (pci_is_root_bus(dev->bus) && dev->devfn == 0) { - int i; + struct resource *r; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } @@ -301,8 +302,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port) { struct pci_channel *chan = port->hose; unsigned int data; - phys_addr_t memphys; - size_t memsize; + phys_addr_t memstart, memend; int ret, i, win; /* Begin initialization */ @@ -313,7 +313,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port) * class to match. Hardware takes care of propagating the IDSETR * settings, so there is no need to bother with a quirk. */ - pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1); + pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI_NORMAL << 8, SH4A_PCIEIDSETR1); /* Initialize default capabilities. */ data = pci_read_reg(chan, SH4A_PCIEEXPCAP0); @@ -357,15 +357,24 @@ static int __init pcie_init(struct sh7786_pcie_port *port) data |= (0xff << 16); pci_write_reg(chan, data, SH4A_PCIEMACCTLR); - memphys = __pa(memory_start); - memsize = roundup_pow_of_two(memory_end - memory_start); + memstart = __pa(memory_start); + memend = __pa(memory_end); + memsize = roundup_pow_of_two(memend - memstart); + + /* + * The start address must be aligned on its size. So we round + * it down, and then recalculate the size so that it covers + * the entire memory. + */ + memstart = ALIGN_DOWN(memstart, memsize); + memsize = roundup_pow_of_two(memend - memstart); /* * If there's more than 512MB of memory, we need to roll over to * LAR1/LAMR1. */ if (memsize > SZ_512M) { - pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1); + pci_write_reg(chan, memstart + SZ_512M, SH4A_PCIELAR1); pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1, SH4A_PCIELAMR1); memsize = SZ_512M; @@ -381,7 +390,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port) * LAR0/LAMR0 covers up to the first 512MB, which is enough to * cover all of lowmem on most platforms. */ - pci_write_reg(chan, memphys, SH4A_PCIELAR0); + pci_write_reg(chan, memstart, SH4A_PCIELAR0); pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0); /* Finish initialization */ @@ -438,6 +447,9 @@ static int __init pcie_init(struct sh7786_pcie_port *port) * mode, so just skip them entirely. */ if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) + res->flags |= IORESOURCE_DISABLED; + + if (res->flags & IORESOURCE_DISABLED) continue; pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win)); @@ -467,11 +479,17 @@ static int __init pcie_init(struct sh7786_pcie_port *port) return 0; } -int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { return evt2irq(0xae0); } +void pcibios_bus_add_device(struct pci_dev *pdev) +{ + dma_direct_set_offset(&pdev->dev, __pa(memory_start), + __pa(memory_start) - memstart, memsize); +} + static int __init sh7786_pcie_core_init(void) { /* Return the number of ports */ @@ -527,6 +545,7 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = { static int __init sh7786_pcie_init(void) { struct clk *platclk; + u32 mm_sel; int i; printk(KERN_NOTICE "PCI: Starting initialization.\n"); @@ -539,7 +558,7 @@ static int __init sh7786_pcie_init(void) if (unlikely(nr_ports == 0)) return -ENODEV; - sh7786_pcie_ports = kzalloc(nr_ports * sizeof(struct sh7786_pcie_port), + sh7786_pcie_ports = kcalloc(nr_ports, sizeof(struct sh7786_pcie_port), GFP_KERNEL); if (unlikely(!sh7786_pcie_ports)) return -ENOMEM; @@ -560,6 +579,16 @@ static int __init sh7786_pcie_init(void) clk_enable(platclk); + mm_sel = sh7786_mm_sel(); + + /* + * Depending on the MMSELR register value, the PCIe0 MEM 1 + * area may not be available. See Table 13.11 of the SH7786 + * datasheet. + */ + if (mm_sel != 1 && mm_sel != 2 && mm_sel != 5 && mm_sel != 6) + sh7786_pci0_resources[2].flags |= IORESOURCE_DISABLED; + printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports); for (i = 0; i < nr_ports; i++) { |
