sh: Improved multi-resource handling for SH7780 PCI.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 1 Feb 2010 11:01:50 +0000 (20:01 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 1 Feb 2010 11:01:50 +0000 (20:01 +0900)
The SH7780 PCI controller supports 3 different ranges of PCI memory in
addition to its PCI I/O window. In the case of 29-bit mode, only 2 memory
windows are supported, while in 32-bit mode all 3 are visible. This
attempts to make the resource handling completely dynamic and to permit
platforms to map in as many apertures as they can handle.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/drivers/pci/fixups-dreamcast.c
arch/sh/drivers/pci/fixups-se7751.c
arch/sh/drivers/pci/pci-dreamcast.c
arch/sh/drivers/pci/pci-sh5.c
arch/sh/drivers/pci/pci-sh7751.c
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/drivers/pci/pci-sh7780.h
arch/sh/drivers/pci/pci.c
arch/sh/include/asm/pci.h

index ed7f489936f1e3075428434ef61b8f0739150084..942ef4f155f534ebe46aa77ca8279c95002b8d35 100644 (file)
@@ -39,7 +39,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
                /*
                 * We also assume that dev->devfn == 0
                 */
-               dev->resource[1].start  = p->io_resource->start  + 0x100;
+               dev->resource[1].start  = p->resources[0].start  + 0x100;
                dev->resource[1].end    = dev->resource[1].start + 0x200 - 1;
 
                /*
index 475fa9f0fe2ccc0e23b4275e2bf6cbb6b7faa5d2..a4c7d3a4efca4ef65296d8c8dcba1b517ce844c2 100644 (file)
@@ -97,12 +97,12 @@ int pci_fixup_pcic(struct pci_channel *chan)
        * meaning all calls go straight through... use BUG_ON to
        * catch erroneous assumption.
        */
-       BUG_ON(chan->mem_resource->start != SH7751_PCI_MEMORY_BASE);
+       BUG_ON(chan->resources[1].start != SH7751_PCI_MEMORY_BASE);
 
-       PCIC_WRITE(SH7751_PCIMBR, chan->mem_resource->start);
+       PCIC_WRITE(SH7751_PCIMBR, chan->resources[1].start);
 
        /* Set IOBR for window containing area specified in pci.h */
-       PCIC_WRITE(SH7751_PCIIOBR, (chan->io_resource->start & SH7751_PCIIOBR_MASK));
+       PCIC_WRITE(SH7751_PCIIOBR, (chan->resources[0].start & SH7751_PCIIOBR_MASK));
 
        /* All done, may as well say so... */
        printk("SH7751 PCI: Finished initialization of the PCI controller\n");
index bd5a1e50ebf629d8db648cc7005c738eb5981ca6..633694193af8f7c08011ac971c28d3f58424dd2a 100644 (file)
 #include <asm/irq.h>
 #include <mach/pci.h>
 
-static struct resource gapspci_io_resource = {
-       .name   = "GAPSPCI IO",
-       .start  = GAPSPCI_BBA_CONFIG,
-       .end    = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1,
-       .flags  = IORESOURCE_IO,
-};
-
-static struct resource gapspci_mem_resource = {
-       .name   = "GAPSPCI mem",
-       .start  = GAPSPCI_DMA_BASE,
-       .end    = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1,
-       .flags  = IORESOURCE_MEM,
+static struct resource gapspci_resources[] = {
+       {
+               .name   = "GAPSPCI IO",
+               .start  = GAPSPCI_BBA_CONFIG,
+               .end    = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1,
+               .flags  = IORESOURCE_IO,
+       },  {
+               .name   = "GAPSPCI mem",
+               .start  = GAPSPCI_DMA_BASE,
+               .end    = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
 };
 
 static struct pci_channel dreamcast_pci_controller = {
        .pci_ops        = &gapspci_pci_ops,
-       .io_resource    = &gapspci_io_resource,
+       .resources      = gapspci_resources,
+       .nr_resources   = ARRAY_SIZE(gapspci_resources),
        .io_offset      = 0x00000000,
-       .mem_resource   = &gapspci_mem_resource,
        .mem_offset     = 0x00000000,
 };
 
index bce73faabc88267fcc149db90ccfaa9d7532d59f..0bf296c7879593b1d1aa9f9c020b5f54e7682a2e 100644 (file)
@@ -89,14 +89,13 @@ static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static struct resource sh5_io_resource = { /* place holder */ };
-static struct resource sh5_mem_resource = { /* place holder */ };
+static struct resource sh5_pci_resources[2];
 
 static struct pci_channel sh5pci_controller = {
        .pci_ops                = &sh5_pci_ops,
-       .mem_resource           = &sh5_mem_resource,
+       .resources              = sh5_pci_resources,
+       .nr_resources           = ARRAY_SIZE(sh5_pci_resources),
        .mem_offset             = 0x00000000,
-       .io_resource            = &sh5_io_resource,
        .io_offset              = 0x00000000,
 };
 
@@ -210,11 +209,11 @@ static int __init sh5pci_init(void)
         SH5PCI_WRITE(AINTM, ~0);
         SH5PCI_WRITE(PINTM, ~0);
 
-       sh5_io_resource.start = PCI_IO_AREA;
-       sh5_io_resource.end = PCI_IO_AREA + 0x10000;
+       sh5_pci_resources[0].start = PCI_IO_AREA;
+       sh5_pci_resources[0].end = PCI_IO_AREA + 0x10000;
 
-       sh5_mem_resource.start = memStart;
-       sh5_mem_resource.end = memStart + memSize;
+       sh5_pci_resources[1].start = memStart;
+       sh5_pci_resources[1].end = memStart + memSize;
 
        return register_pci_controller(&sh5pci_controller);
 }
index 6ad5beb524aacf4467961e7f536349d09923eb3d..17811e5d287bd46b159f908a8e880972ab4251b2 100644 (file)
@@ -44,25 +44,25 @@ static int __init __area_sdram_check(struct pci_channel *chan,
        return 1;
 }
 
-static struct resource sh7751_io_resource = {
-       .name   = "SH7751_IO",
-       .start  = SH7751_PCI_IO_BASE,
-       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7751_mem_resource = {
-       .name   = "SH7751_mem",
-       .start  = SH7751_PCI_MEMORY_BASE,
-       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
+static struct resource sh7751_pci_resources[] = {
+       {
+               .name   = "SH7751_IO",
+               .start  = SH7751_PCI_IO_BASE,
+               .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
+               .flags  = IORESOURCE_IO
+       }, {
+               .name   = "SH7751_mem",
+               .start  = SH7751_PCI_MEMORY_BASE,
+               .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       },
 };
 
 static struct pci_channel sh7751_pci_controller = {
        .pci_ops        = &sh4_pci_ops,
-       .mem_resource   = &sh7751_mem_resource,
+       .resources      = sh7751_pci_resources,
+       .nr_resources   = ARRAY_SIZE(sh7751_pci_resources),
        .mem_offset     = 0x00000000,
-       .io_resource    = &sh7751_io_resource,
        .io_offset      = 0x00000000,
        .io_map_base    = SH7751_PCI_IO_BASE,
 };
@@ -128,13 +128,13 @@ static int __init sh7751_pci_init(void)
        /* Set the local 16MB PCI memory space window to
         * the lowest PCI mapped address
         */
-       word = chan->mem_resource->start & SH4_PCIMBR_MASK;
+       word = chan->resources[1].start & SH4_PCIMBR_MASK;
        pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word);
        pci_write_reg(chan, word , SH4_PCIMBR);
 
        /* Make sure the MSB's of IO window are set to access PCI space
         * correctly */
-       word = chan->io_resource->start & SH4_PCIIOBR_MASK;
+       word = chan->resources[0].start & SH4_PCIIOBR_MASK;
        pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word);
        pci_write_reg(chan, word, SH4_PCIIOBR);
 
index 86373314f45829a1e9d12560fd45660ffbe3e31b..472f67aec337b185c9b7daf906a48cf397d4ff09 100644 (file)
 #include <asm/mmu.h>
 #include <asm/sizes.h>
 
-static struct resource sh7785_io_resource = {
-       .name   = "SH7785_IO",
-       .start  = 0x1000,
-       .end    = SH7780_PCI_IO_SIZE - 1,
-       .flags  = IORESOURCE_IO
-};
-
-static struct resource sh7785_mem_resource = {
-       .name   = "SH7785_mem",
-       .start  = SH7780_PCI_MEMORY_BASE,
-       .end    = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM
+static struct resource sh7785_pci_resources[] = {
+       {
+               .name   = "SH7785_IO",
+               .start  = 0x1000,
+               .end    = SZ_4M - 1,
+               .flags  = IORESOURCE_IO,
+       }, {
+               .name   = "PCI MEM 0",
+               .start  = 0xfd000000,
+               .end    = 0xfd000000 + SZ_16M - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "PCI MEM 1",
+               .start  = 0x10000000,
+               .end    = 0x10000000 + SZ_64M - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               /*
+                * 32-bit only resources must be last.
+                */
+               .name   = "PCI MEM 2",
+               .start  = 0xc0000000,
+               .end    = 0xc0000000 + SZ_512M - 1,
+               .flags  = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
+       },
 };
 
 static struct pci_channel sh7780_pci_controller = {
        .pci_ops        = &sh4_pci_ops,
-       .mem_resource   = &sh7785_mem_resource,
-       .mem_offset     = 0x00000000,
-       .io_resource    = &sh7785_io_resource,
-       .io_offset      = 0x00000000,
-       .io_map_base    = SH7780_PCI_IO_BASE,
+       .resources      = sh7785_pci_resources,
+       .nr_resources   = ARRAY_SIZE(sh7785_pci_resources),
+       .io_offset      = 0,
+       .mem_offset     = 0,
+       .io_map_base    = 0xfe200000,
        .serr_irq       = evt2irq(0xa00),
        .err_irq        = evt2irq(0xaa0),
 };
@@ -231,7 +244,7 @@ static int __init sh7780_pci_init(void)
        size_t memsize;
        unsigned int id;
        const char *type;
-       int ret;
+       int ret, i;
 
        printk(KERN_NOTICE "PCI: Starting intialization.\n");
 
@@ -279,8 +292,6 @@ static int __init sh7780_pci_init(void)
         */
        __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);
 
-       __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);
-
        memphys = __pa(memory_start);
        memsize = roundup_pow_of_two(memory_end - memory_start);
 
@@ -324,9 +335,40 @@ static int __init sh7780_pci_init(void)
        __raw_writel(0, chan->reg_base + SH7780_PCICSCR1);
        __raw_writel(0, chan->reg_base + SH7780_PCICSAR1);
 
-       __raw_writel(0xfd000000, chan->reg_base + SH7780_PCIMBR0);
-       __raw_writel(0x00fc0000, chan->reg_base + SH7780_PCIMBMR0);
+       /*
+        * Setup the memory BARs
+        */
+       for (i = 0; i < chan->nr_resources; i++) {
+               struct resource *res = chan->resources + (i + 1);
+               resource_size_t size;
+
+               if (unlikely(res->flags & IORESOURCE_IO))
+                       continue;
+
+               /*
+                * Make sure we're in the right physical addressing mode
+                * for dealing with the resource.
+                */
+               if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) {
+                       chan->nr_resources--;
+                       continue;
+               }
 
+               size = resource_size(res);
+
+               /*
+                * The MBMR mask is calculated in units of 256kB, which
+                * keeps things pretty simple.
+                */
+               __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
+                            chan->reg_base + SH7780_PCIMBMR(i));
+               __raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i));
+       }
+
+       /*
+        * And I/O.
+        */
+       __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);
        __raw_writel(0, chan->reg_base + SH7780_PCIIOBR);
        __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);
 
index dee069c3865d1c5b3ee961fdc15beab0b293ff50..205dcbefe2756270f239c8ec7ea499aa0051ac92 100644 (file)
 #define SH7780_PCI_CONFIG_BASE 0xFD000000      /* Config space base addr */
 #define SH7780_PCI_CONFIG_SIZE 0x01000000      /* Config space size */
 
-#define SH7780_PCI_MEMORY_BASE 0xFD000000      /* Memory space base addr */
-#define SH7780_PCI_MEM_SIZE    0x01000000      /* Size of Memory window */
-
-#define SH7780_PCI_IO_BASE     0xFE200000      /* IO space base address */
-#define SH7780_PCI_IO_SIZE     0x00400000      /* Size of IO window */
-
 #define SH7780_PCIREG_BASE     0xFE040000      /* PCI regs base address */
 
 /* SH7780 PCI Config Registers */
 #define SH7780_PCIPINT         0x1CC           /* Power Mgmnt Int. Register */
 #define SH7780_PCIPINTM                0x1D0           /* Power Mgmnt Mask Register */
 
-#define SH7780_PCIMBR0         0x1E0
-#define SH7780_PCIMBMR0                0x1E4
-#define SH7780_PCIMBR1         0x1E8
-#define SH7780_PCIMBMR1                0x1EC
-#define SH7780_PCIMBR2         0x1F0
-#define SH7780_PCIMBMR2                0x1F4
+#define SH7780_PCIMBR(x)       (0x1E0 + ((x) * 8))
+#define SH7780_PCIMBMR(x)      (0x1E4 + ((x) * 8))
 #define SH7780_PCIIOBR         0x1F8
 #define SH7780_PCIIOBMR                0x1FC
 #define SH7780_PCICSCR0                0x210           /* Cache Snoop1 Cnt. Register */
index 8e42dfbbe76a27f88f0c7d326187a74b47e64f1a..f4a69833fce286f95477cb6c38db76733b1616f9 100644 (file)
@@ -60,11 +60,18 @@ static DEFINE_MUTEX(pci_scan_mutex);
 
 int __devinit register_pci_controller(struct pci_channel *hose)
 {
-       if (request_resource(&iomem_resource, hose->mem_resource) < 0)
-               goto out;
-       if (request_resource(&ioport_resource, hose->io_resource) < 0) {
-               release_resource(hose->mem_resource);
-               goto out;
+       int i;
+
+       for (i = 0; i < hose->nr_resources; i++) {
+               struct resource *res = hose->resources + i;
+
+               if (res->flags & IORESOURCE_IO) {
+                       if (request_resource(&ioport_resource, res) < 0)
+                               goto out;
+               } else {
+                       if (request_resource(&iomem_resource, res) < 0)
+                               goto out;
+               }
        }
 
        *hose_tail = hose;
@@ -96,6 +103,9 @@ int __devinit register_pci_controller(struct pci_channel *hose)
        return 0;
 
 out:
+       for (--i; i >= 0; i--)
+               release_resource(&hose->resources[i]);
+
        printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
        return -1;
 }
@@ -149,11 +159,13 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev = bus->self;
        struct list_head *ln;
-       struct pci_channel *chan = bus->sysdata;
+       struct pci_channel *hose = bus->sysdata;
 
        if (!dev) {
-               bus->resource[0] = chan->io_resource;
-               bus->resource[1] = chan->mem_resource;
+               int i;
+
+               for (i = 0; i < hose->nr_resources; i++)
+                       bus->resource[i] = hose->resources + i;
        }
 
        for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
@@ -174,21 +186,18 @@ void pcibios_align_resource(void *data, struct resource *res,
                            resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
-       struct pci_channel *chan = dev->sysdata;
+       struct pci_channel *hose = dev->sysdata;
        resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
-               if (start < PCIBIOS_MIN_IO + chan->io_resource->start)
-                       start = PCIBIOS_MIN_IO + chan->io_resource->start;
+               if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
+                       start = PCIBIOS_MIN_IO + hose->resources[0].start;
 
                /*
                  * Put everything into 0x00-0xff region modulo 0x400.
                 */
                if (start & 0x300)
                        start = (start + 0x3ff) & ~0x3ff;
-       } else if (res->flags & IORESOURCE_MEM) {
-               if (start < PCIBIOS_MIN_MEM + chan->mem_resource->start)
-                       start = PCIBIOS_MIN_MEM + chan->mem_resource->start;
        }
 
        res->start = start;
index 1de83f2161f7b126a9e18157b9e65f520cbb0f11..6d762cca2312ac219d91d579a6f7c6198fee2f17 100644 (file)
@@ -18,8 +18,9 @@ struct pci_channel {
        struct pci_bus          *bus;
 
        struct pci_ops          *pci_ops;
-       struct resource         *io_resource;
-       struct resource         *mem_resource;
+
+       struct resource         *resources;
+       unsigned int            nr_resources;
 
        unsigned long           io_offset;
        unsigned long           mem_offset;