Commit b6c58b1d authored by Paul Mundt's avatar Paul Mundt

sh: Improved multi-resource handling for SH7780 PCI.

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: default avatarPaul Mundt <lethal@linux-sh.org>
parent ef407bee
...@@ -39,7 +39,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev) ...@@ -39,7 +39,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
/* /*
* We also assume that dev->devfn == 0 * 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; dev->resource[1].end = dev->resource[1].start + 0x200 - 1;
/* /*
......
...@@ -97,12 +97,12 @@ int pci_fixup_pcic(struct pci_channel *chan) ...@@ -97,12 +97,12 @@ int pci_fixup_pcic(struct pci_channel *chan)
* meaning all calls go straight through... use BUG_ON to * meaning all calls go straight through... use BUG_ON to
* catch erroneous assumption. * 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 */ /* 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... */ /* All done, may as well say so... */
printk("SH7751 PCI: Finished initialization of the PCI controller\n"); printk("SH7751 PCI: Finished initialization of the PCI controller\n");
......
...@@ -25,25 +25,25 @@ ...@@ -25,25 +25,25 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <mach/pci.h> #include <mach/pci.h>
static struct resource gapspci_io_resource = { static struct resource gapspci_resources[] = {
.name = "GAPSPCI IO", {
.start = GAPSPCI_BBA_CONFIG, .name = "GAPSPCI IO",
.end = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1, .start = GAPSPCI_BBA_CONFIG,
.flags = IORESOURCE_IO, .end = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1,
}; .flags = IORESOURCE_IO,
}, {
static struct resource gapspci_mem_resource = { .name = "GAPSPCI mem",
.name = "GAPSPCI mem", .start = GAPSPCI_DMA_BASE,
.start = GAPSPCI_DMA_BASE, .end = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1,
.end = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1, .flags = IORESOURCE_MEM,
.flags = IORESOURCE_MEM, },
}; };
static struct pci_channel dreamcast_pci_controller = { static struct pci_channel dreamcast_pci_controller = {
.pci_ops = &gapspci_pci_ops, .pci_ops = &gapspci_pci_ops,
.io_resource = &gapspci_io_resource, .resources = gapspci_resources,
.nr_resources = ARRAY_SIZE(gapspci_resources),
.io_offset = 0x00000000, .io_offset = 0x00000000,
.mem_resource = &gapspci_mem_resource,
.mem_offset = 0x00000000, .mem_offset = 0x00000000,
}; };
......
...@@ -89,14 +89,13 @@ static irqreturn_t pcish5_serr_irq(int irq, void *dev_id) ...@@ -89,14 +89,13 @@ static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
} }
static struct resource sh5_io_resource = { /* place holder */ }; static struct resource sh5_pci_resources[2];
static struct resource sh5_mem_resource = { /* place holder */ };
static struct pci_channel sh5pci_controller = { static struct pci_channel sh5pci_controller = {
.pci_ops = &sh5_pci_ops, .pci_ops = &sh5_pci_ops,
.mem_resource = &sh5_mem_resource, .resources = sh5_pci_resources,
.nr_resources = ARRAY_SIZE(sh5_pci_resources),
.mem_offset = 0x00000000, .mem_offset = 0x00000000,
.io_resource = &sh5_io_resource,
.io_offset = 0x00000000, .io_offset = 0x00000000,
}; };
...@@ -210,11 +209,11 @@ static int __init sh5pci_init(void) ...@@ -210,11 +209,11 @@ static int __init sh5pci_init(void)
SH5PCI_WRITE(AINTM, ~0); SH5PCI_WRITE(AINTM, ~0);
SH5PCI_WRITE(PINTM, ~0); SH5PCI_WRITE(PINTM, ~0);
sh5_io_resource.start = PCI_IO_AREA; sh5_pci_resources[0].start = PCI_IO_AREA;
sh5_io_resource.end = PCI_IO_AREA + 0x10000; sh5_pci_resources[0].end = PCI_IO_AREA + 0x10000;
sh5_mem_resource.start = memStart; sh5_pci_resources[1].start = memStart;
sh5_mem_resource.end = memStart + memSize; sh5_pci_resources[1].end = memStart + memSize;
return register_pci_controller(&sh5pci_controller); return register_pci_controller(&sh5pci_controller);
} }
......
...@@ -44,25 +44,25 @@ static int __init __area_sdram_check(struct pci_channel *chan, ...@@ -44,25 +44,25 @@ static int __init __area_sdram_check(struct pci_channel *chan,
return 1; return 1;
} }
static struct resource sh7751_io_resource = { static struct resource sh7751_pci_resources[] = {
.name = "SH7751_IO", {
.start = SH7751_PCI_IO_BASE, .name = "SH7751_IO",
.end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, .start = SH7751_PCI_IO_BASE,
.flags = IORESOURCE_IO .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
}; .flags = IORESOURCE_IO
}, {
static struct resource sh7751_mem_resource = { .name = "SH7751_mem",
.name = "SH7751_mem", .start = SH7751_PCI_MEMORY_BASE,
.start = SH7751_PCI_MEMORY_BASE, .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
.end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, .flags = IORESOURCE_MEM
.flags = IORESOURCE_MEM },
}; };
static struct pci_channel sh7751_pci_controller = { static struct pci_channel sh7751_pci_controller = {
.pci_ops = &sh4_pci_ops, .pci_ops = &sh4_pci_ops,
.mem_resource = &sh7751_mem_resource, .resources = sh7751_pci_resources,
.nr_resources = ARRAY_SIZE(sh7751_pci_resources),
.mem_offset = 0x00000000, .mem_offset = 0x00000000,
.io_resource = &sh7751_io_resource,
.io_offset = 0x00000000, .io_offset = 0x00000000,
.io_map_base = SH7751_PCI_IO_BASE, .io_map_base = SH7751_PCI_IO_BASE,
}; };
...@@ -128,13 +128,13 @@ static int __init sh7751_pci_init(void) ...@@ -128,13 +128,13 @@ static int __init sh7751_pci_init(void)
/* Set the local 16MB PCI memory space window to /* Set the local 16MB PCI memory space window to
* the lowest PCI mapped address * 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); pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word);
pci_write_reg(chan, word , SH4_PCIMBR); pci_write_reg(chan, word , SH4_PCIMBR);
/* Make sure the MSB's of IO window are set to access PCI space /* Make sure the MSB's of IO window are set to access PCI space
* correctly */ * 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); pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word);
pci_write_reg(chan, word, SH4_PCIIOBR); pci_write_reg(chan, word, SH4_PCIIOBR);
......
...@@ -21,27 +21,40 @@ ...@@ -21,27 +21,40 @@
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/sizes.h> #include <asm/sizes.h>
static struct resource sh7785_io_resource = { static struct resource sh7785_pci_resources[] = {
.name = "SH7785_IO", {
.start = 0x1000, .name = "SH7785_IO",
.end = SH7780_PCI_IO_SIZE - 1, .start = 0x1000,
.flags = IORESOURCE_IO .end = SZ_4M - 1,
}; .flags = IORESOURCE_IO,
}, {
static struct resource sh7785_mem_resource = { .name = "PCI MEM 0",
.name = "SH7785_mem", .start = 0xfd000000,
.start = SH7780_PCI_MEMORY_BASE, .end = 0xfd000000 + SZ_16M - 1,
.end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, .flags = IORESOURCE_MEM,
.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 = { static struct pci_channel sh7780_pci_controller = {
.pci_ops = &sh4_pci_ops, .pci_ops = &sh4_pci_ops,
.mem_resource = &sh7785_mem_resource, .resources = sh7785_pci_resources,
.mem_offset = 0x00000000, .nr_resources = ARRAY_SIZE(sh7785_pci_resources),
.io_resource = &sh7785_io_resource, .io_offset = 0,
.io_offset = 0x00000000, .mem_offset = 0,
.io_map_base = SH7780_PCI_IO_BASE, .io_map_base = 0xfe200000,
.serr_irq = evt2irq(0xa00), .serr_irq = evt2irq(0xa00),
.err_irq = evt2irq(0xaa0), .err_irq = evt2irq(0xaa0),
}; };
...@@ -231,7 +244,7 @@ static int __init sh7780_pci_init(void) ...@@ -231,7 +244,7 @@ static int __init sh7780_pci_init(void)
size_t memsize; size_t memsize;
unsigned int id; unsigned int id;
const char *type; const char *type;
int ret; int ret, i;
printk(KERN_NOTICE "PCI: Starting intialization.\n"); printk(KERN_NOTICE "PCI: Starting intialization.\n");
...@@ -279,8 +292,6 @@ static int __init sh7780_pci_init(void) ...@@ -279,8 +292,6 @@ static int __init sh7780_pci_init(void)
*/ */
__raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR); __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);
__raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);
memphys = __pa(memory_start); memphys = __pa(memory_start);
memsize = roundup_pow_of_two(memory_end - memory_start); memsize = roundup_pow_of_two(memory_end - memory_start);
...@@ -324,9 +335,40 @@ static int __init sh7780_pci_init(void) ...@@ -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_PCICSCR1);
__raw_writel(0, chan->reg_base + SH7780_PCICSAR1); __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_PCIIOBR);
__raw_writel(0, chan->reg_base + SH7780_PCIIOBMR); __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);
......
...@@ -26,12 +26,6 @@ ...@@ -26,12 +26,6 @@
#define SH7780_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */ #define SH7780_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */
#define SH7780_PCI_CONFIG_SIZE 0x01000000 /* Config space size */ #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 */ #define SH7780_PCIREG_BASE 0xFE040000 /* PCI regs base address */
/* SH7780 PCI Config Registers */ /* SH7780 PCI Config Registers */
...@@ -46,12 +40,8 @@ ...@@ -46,12 +40,8 @@
#define SH7780_PCIPINT 0x1CC /* Power Mgmnt Int. Register */ #define SH7780_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
#define SH7780_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */ #define SH7780_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
#define SH7780_PCIMBR0 0x1E0 #define SH7780_PCIMBR(x) (0x1E0 + ((x) * 8))
#define SH7780_PCIMBMR0 0x1E4 #define SH7780_PCIMBMR(x) (0x1E4 + ((x) * 8))
#define SH7780_PCIMBR1 0x1E8
#define SH7780_PCIMBMR1 0x1EC
#define SH7780_PCIMBR2 0x1F0
#define SH7780_PCIMBMR2 0x1F4
#define SH7780_PCIIOBR 0x1F8 #define SH7780_PCIIOBR 0x1F8
#define SH7780_PCIIOBMR 0x1FC #define SH7780_PCIIOBMR 0x1FC
#define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */ #define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */
......
...@@ -60,11 +60,18 @@ static DEFINE_MUTEX(pci_scan_mutex); ...@@ -60,11 +60,18 @@ static DEFINE_MUTEX(pci_scan_mutex);
int __devinit register_pci_controller(struct pci_channel *hose) int __devinit register_pci_controller(struct pci_channel *hose)
{ {
if (request_resource(&iomem_resource, hose->mem_resource) < 0) int i;
goto out;
if (request_resource(&ioport_resource, hose->io_resource) < 0) { for (i = 0; i < hose->nr_resources; i++) {
release_resource(hose->mem_resource); struct resource *res = hose->resources + i;
goto out;
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; *hose_tail = hose;
...@@ -96,6 +103,9 @@ int __devinit register_pci_controller(struct pci_channel *hose) ...@@ -96,6 +103,9 @@ int __devinit register_pci_controller(struct pci_channel *hose)
return 0; return 0;
out: out:
for (--i; i >= 0; i--)
release_resource(&hose->resources[i]);
printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n"); printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
return -1; return -1;
} }
...@@ -149,11 +159,13 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) ...@@ -149,11 +159,13 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{ {
struct pci_dev *dev = bus->self; struct pci_dev *dev = bus->self;
struct list_head *ln; struct list_head *ln;
struct pci_channel *chan = bus->sysdata; struct pci_channel *hose = bus->sysdata;
if (!dev) { if (!dev) {
bus->resource[0] = chan->io_resource; int i;
bus->resource[1] = chan->mem_resource;
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) { for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
...@@ -174,21 +186,18 @@ void pcibios_align_resource(void *data, struct resource *res, ...@@ -174,21 +186,18 @@ void pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t align) resource_size_t size, resource_size_t align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
struct pci_channel *chan = dev->sysdata; struct pci_channel *hose = dev->sysdata;
resource_size_t start = res->start; resource_size_t start = res->start;
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
if (start < PCIBIOS_MIN_IO + chan->io_resource->start) if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
start = PCIBIOS_MIN_IO + chan->io_resource->start; start = PCIBIOS_MIN_IO + hose->resources[0].start;
/* /*
* Put everything into 0x00-0xff region modulo 0x400. * Put everything into 0x00-0xff region modulo 0x400.
*/ */
if (start & 0x300) if (start & 0x300)
start = (start + 0x3ff) & ~0x3ff; 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; res->start = start;
......
...@@ -18,8 +18,9 @@ struct pci_channel { ...@@ -18,8 +18,9 @@ struct pci_channel {
struct pci_bus *bus; struct pci_bus *bus;
struct pci_ops *pci_ops; 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 io_offset;
unsigned long mem_offset; unsigned long mem_offset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment