diff options
Diffstat (limited to 'arch/sh/drivers/pci')
41 files changed, 2832 insertions, 2205 deletions
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig deleted file mode 100644 index 7e816ededed..00000000000 --- a/arch/sh/drivers/pci/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -config PCI - bool "PCI support" - depends on SYS_SUPPORTS_PCI - help - Find out whether you have a PCI motherboard. PCI is the name of a - bus system, i.e. the way the CPU talks to the other stuff inside - your box. If you have PCI, say Y, otherwise N. - -config SH_PCIDMA_NONCOHERENT - bool "Cache and PCI noncoherent" - depends on PCI - default y - help - Enable this option if your platform does not have a CPU cache which - remains coherent with PCI DMA. It is safest to say 'Y', although you - will see better performance if you can say 'N', because the PCI DMA - code will not have to flush the CPU's caches. If you have a PCI host - bridge integrated with your SH CPU, refer carefully to the chip specs - to see if you can say 'N' here. Otherwise, leave it as 'Y'. - -# This is also board-specific -config PCI_AUTO - bool - depends on PCI - default y - -config PCI_AUTO_UPDATE_RESOURCES - bool - depends on PCI_AUTO - default y if !SH_DREAMCAST - help - Selecting this option will cause the PCI auto code to leave your - BAR values alone. Otherwise they will be updated automatically. If - for some reason, you have a board that simply refuses to work - with its resources updated beyond what they are when the device - is powered up, set this to N. Everyone else will want this as Y. - diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile index 0718805774e..82f0a335fd1 100644 --- a/arch/sh/drivers/pci/Makefile +++ b/arch/sh/drivers/pci/Makefile @@ -1,25 +1,28 @@ # # Makefile for the PCI specific kernel interface routines under Linux. # - -obj-y += pci.o -obj-$(CONFIG_PCI_AUTO) += pci-auto.o +obj-y += common.o pci.o obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7763) += pci-sh7780.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7785) += pci-sh7780.o ops-sh4.o +obj-$(CONFIG_CPU_SUBTYPE_SH7786) += pcie-sh7786.o ops-sh7786.o obj-$(CONFIG_CPU_SH5) += pci-sh5.o ops-sh5.o -obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o -obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o -obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o -obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o -obj-$(CONFIG_SH_HIGHLANDER) += ops-r7780rp.o fixups-r7780rp.o -obj-$(CONFIG_SH_SDK7780) += ops-sdk7780.o fixups-sdk7780.o -obj-$(CONFIG_SH_TITAN) += ops-titan.o -obj-$(CONFIG_SH_LANDISK) += ops-landisk.o -obj-$(CONFIG_SH_LBOX_RE2) += ops-lboxre2.o fixups-lboxre2.o -obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += ops-se7780.o fixups-se7780.o -obj-$(CONFIG_SH_CAYMAN) += ops-cayman.o +obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ + pci-dreamcast.o +obj-$(CONFIG_SH_SECUREEDGE5410) += fixups-snapgear.o +obj-$(CONFIG_SH_7751_SOLUTION_ENGINE) += fixups-se7751.o +obj-$(CONFIG_SH_RTS7751R2D) += fixups-rts7751r2d.o +obj-$(CONFIG_SH_SH03) += fixups-sh03.o +obj-$(CONFIG_SH_HIGHLANDER) += fixups-r7780rp.o +obj-$(CONFIG_SH_SH7785LCR) += fixups-r7780rp.o +obj-$(CONFIG_SH_SDK7786) += fixups-sdk7786.o +obj-$(CONFIG_SH_SDK7780) += fixups-sdk7780.o +obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += fixups-sdk7780.o +obj-$(CONFIG_SH_TITAN) += fixups-titan.o +obj-$(CONFIG_SH_LANDISK) += fixups-landisk.o +obj-$(CONFIG_SH_LBOX_RE2) += fixups-rts7751r2d.o +obj-$(CONFIG_SH_CAYMAN) += fixups-cayman.o diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c new file mode 100644 index 00000000000..dbf13819987 --- /dev/null +++ b/arch/sh/drivers/pci/common.c @@ -0,0 +1,162 @@ +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +static struct pci_dev *fake_pci_dev(struct pci_channel *hose, + int top_bus, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.sysdata = hose; + bus.ops = hose->pci_ops; + + if(busnr != top_bus) + /* Fake a parent bus structure. */ + bus.parent = &bus; + else + bus.parent = NULL; + + return &dev; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int __init early_##rw##_config_##size(struct pci_channel *hose, \ + int top_bus, int bus, int devfn, int offset, type value) \ +{ \ + return pci_##rw##_config_##size( \ + fake_pci_dev(hose, top_bus, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) + +int __init pci_is_66mhz_capable(struct pci_channel *hose, + int top_bus, int current_bus) +{ + u32 pci_devfn; + unsigned short vid; + int cap66 = -1; + u16 stat; + + printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n"); + + for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { + if (PCI_FUNC(pci_devfn)) + continue; + if (early_read_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_VENDOR_ID, &vid) != + PCIBIOS_SUCCESSFUL) + continue; + if (vid == 0xffff) + continue; + + /* check 66MHz capability */ + if (cap66 < 0) + cap66 = 1; + if (cap66) { + early_read_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_STATUS, &stat); + if (!(stat & PCI_STATUS_66MHZ)) { + printk(KERN_DEBUG + "PCI: %02x:%02x not 66MHz capable.\n", + current_bus, pci_devfn); + cap66 = 0; + break; + } + } + } + + return cap66 > 0; +} + +static void pcibios_enable_err(unsigned long __data) +{ + struct pci_channel *hose = (struct pci_channel *)__data; + + del_timer(&hose->err_timer); + printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n"); + enable_irq(hose->err_irq); +} + +static void pcibios_enable_serr(unsigned long __data) +{ + struct pci_channel *hose = (struct pci_channel *)__data; + + del_timer(&hose->serr_timer); + printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n"); + enable_irq(hose->serr_irq); +} + +void pcibios_enable_timers(struct pci_channel *hose) +{ + if (hose->err_irq) { + init_timer(&hose->err_timer); + hose->err_timer.data = (unsigned long)hose; + hose->err_timer.function = pcibios_enable_err; + } + + if (hose->serr_irq) { + init_timer(&hose->serr_timer); + hose->serr_timer.data = (unsigned long)hose; + hose->serr_timer.function = pcibios_enable_serr; + } +} + +/* + * A simple handler for the regular PCI status errors, called from IRQ + * context. + */ +unsigned int pcibios_handle_status_errors(unsigned long addr, + unsigned int status, + struct pci_channel *hose) +{ + unsigned int cmd = 0; + + if (status & PCI_STATUS_REC_MASTER_ABORT) { + printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr); + cmd |= PCI_STATUS_REC_MASTER_ABORT; + } + + if (status & PCI_STATUS_REC_TARGET_ABORT) { + printk(KERN_DEBUG "PCI: target abort: "); + pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT, 1); + printk("\n"); + + cmd |= PCI_STATUS_REC_TARGET_ABORT; + } + + if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) { + printk(KERN_DEBUG "PCI: parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | + PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY; + + /* Now back off of the IRQ for awhile */ + if (hose->err_irq) { + disable_irq_nosync(hose->err_irq); + hose->err_timer.expires = jiffies + HZ; + add_timer(&hose->err_timer); + } + } + + return cmd; +} diff --git a/arch/sh/drivers/pci/ops-cayman.c b/arch/sh/drivers/pci/fixups-cayman.c index 980275ffa30..edc2fb7a5bb 100644 --- a/arch/sh/drivers/pci/ops-cayman.c +++ b/arch/sh/drivers/pci/fixups-cayman.c @@ -2,15 +2,10 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/types.h> -#include <asm/cpu/irq.h> +#include <cpu/irq.h> #include "pci-sh5.h" -static inline u8 bridge_swizzle(u8 pin, u8 slot) -{ - return (((pin - 1) + slot) % 4) + 1; -} - -int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) +int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin) { int result = -1; @@ -42,7 +37,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) while (dev->bus->number > 0) { slot = path[i].slot = PCI_SLOT(dev->devfn); - pin = path[i].pin = bridge_swizzle(pin, slot); + pin = path[i].pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; i++; if (i > 3) panic("PCI path to root bus too long!\n"); @@ -56,7 +51,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) if ((slot < 3) || (i == 0)) { /* Bus 0 (incl. PCI-PCI bridge itself) : perform the final swizzle now. */ - result = IRQ_INTA + bridge_swizzle(pin, slot) - 1; + result = IRQ_INTA + pci_swizzle_interrupt_pin(dev, pin) - 1; } else { i--; slot = path[i].slot; @@ -80,15 +75,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) return result; } - -struct pci_channel board_pci_channels[] = { - { &sh5_pci_ops, NULL, NULL, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; -EXPORT_SYMBOL(board_pci_channels); - -int __init pcibios_init_platform(void) -{ - return sh5pci_init(__pa(memory_start), - __pa(memory_end) - __pa(memory_start)); -} diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c index c44699301ee..1d1c5a227e5 100644 --- a/arch/sh/drivers/pci/fixups-dreamcast.c +++ b/arch/sh/drivers/pci/fixups-dreamcast.c @@ -26,11 +26,13 @@ #include <asm/io.h> #include <asm/irq.h> -#include <asm/mach/pci.h> +#include <mach/pci.h> -static void __init gapspci_fixup_resources(struct pci_dev *dev) +static void gapspci_fixup_resources(struct pci_dev *dev) { - struct pci_channel *p = board_pci_channels; + struct pci_channel *p = dev->sysdata; + struct resource res; + struct pci_bus_region region; printk(KERN_NOTICE "PCI: Fixing up device %s\n", pci_name(dev)); @@ -39,15 +41,32 @@ 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; + + /* + * This is not a normal BAR, prevent any attempts to move + * the BAR, as this will result in a bus lock. + */ + dev->resource[1].flags |= IORESOURCE_PCI_FIXED; + /* * Redirect dma memory allocations to special memory window. + * + * If this GAPSPCI region were mapped by a BAR, the CPU + * phys_addr_t would be pci_resource_start(), and the bus + * address would be pci_bus_address(pci_resource_start()). + * But apparently there's no BAR mapping it, so we just + * "know" its CPU address is GAPSPCI_DMA_BASE. */ + res.start = GAPSPCI_DMA_BASE; + res.end = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1; + res.flags = IORESOURCE_MEM; + pcibios_resource_to_bus(dev->bus, ®ion, &res); BUG_ON(!dma_declare_coherent_memory(&dev->dev, - GAPSPCI_DMA_BASE, - GAPSPCI_DMA_BASE, - GAPSPCI_DMA_SIZE, + res.start, + region.start, + resource_size(&res), DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE)); break; @@ -57,7 +76,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources); -int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) +int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin) { /* * The interrupt routing semantics here are quite trivial. diff --git a/arch/sh/drivers/pci/fixups-landisk.c b/arch/sh/drivers/pci/fixups-landisk.c new file mode 100644 index 00000000000..db5b40a98e6 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-landisk.c @@ -0,0 +1,59 @@ +/* + * arch/sh/drivers/pci/fixups-landisk.c + * + * PCI initialization for the I-O DATA Device, Inc. LANDISK board + * + * Copyright (C) 2006 kogiidena + * Copyright (C) 2010 Nobuhiro Iwamatsu + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/sh_intc.h> +#include "pci-sh4.h" + +#define PCIMCR_MRSET_OFF 0xBFFFFFFF +#define PCIMCR_RFSH_OFF 0xFFFFFFFB + +int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + /* + * slot0: pin1-4 = irq5,6,7,8 + * slot1: pin1-4 = irq6,7,8,5 + * slot2: pin1-4 = irq7,8,5,6 + * slot3: pin1-4 = irq8,5,6,7 + */ + int irq = ((slot + pin - 1) & 0x3) + evt2irq(0x2a0); + + if ((slot | (pin - 1)) > 0x3) { + printk(KERN_WARNING "PCI: Bad IRQ mapping request for slot %d pin %c\n", + slot, pin - 1 + 'A'); + return -1; + } + return irq; +} + +int pci_fixup_pcic(struct pci_channel *chan) +{ + unsigned long bcr1, mcr; + + bcr1 = __raw_readl(SH7751_BCR1); + bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ + pci_write_reg(chan, bcr1, SH4_PCIBCR1); + + mcr = __raw_readl(SH7751_MCR); + mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; + pci_write_reg(chan, mcr, SH4_PCIMCR); + + pci_write_reg(chan, 0x0c000000, SH7751_PCICONF5); + pci_write_reg(chan, 0xd0000000, SH7751_PCICONF6); + pci_write_reg(chan, 0x0c000000, SH4_PCILAR0); + pci_write_reg(chan, 0x00000000, SH4_PCILAR1); + + return 0; +} diff --git a/arch/sh/drivers/pci/fixups-lboxre2.c b/arch/sh/drivers/pci/fixups-lboxre2.c deleted file mode 100644 index 1c1d41255ec..00000000000 --- a/arch/sh/drivers/pci/fixups-lboxre2.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * arch/sh/drivers/pci/fixups-lboxre2.c - * - * L-BOX RE2 PCI fixups - * - * Copyright (C) 2007 Nobuhiro Iwamatsu - * - * 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. - */ -#include "pci-sh4.h" - -#define PCIMCR_MRSET_OFF 0xBFFFFFFF -#define PCIMCR_RFSH_OFF 0xFFFFFFFB - -int pci_fixup_pcic(void) -{ - unsigned long bcr1, mcr; - - bcr1 = ctrl_inl(SH7751_BCR1); - bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ - pci_write_reg(bcr1, SH4_PCIBCR1); - - /* Enable all interrupts, so we known what to fix */ - pci_write_reg(0x0000c3ff, SH4_PCIINTM); - pci_write_reg(0x0000380f, SH4_PCIAINTM); - pci_write_reg(0xfb900047, SH7751_PCICONF1); - pci_write_reg(0xab000001, SH7751_PCICONF4); - - mcr = ctrl_inl(SH7751_MCR); - mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; - pci_write_reg(mcr, SH4_PCIMCR); - - pci_write_reg(0x0c000000, SH7751_PCICONF5); - pci_write_reg(0xd0000000, SH7751_PCICONF6); - pci_write_reg(0x0c000000, SH4_PCILAR0); - pci_write_reg(0x00000000, SH4_PCILAR1); - - return 0; -} diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c index 3e321df65d2..57ed3f09d0c 100644 --- a/arch/sh/drivers/pci/fixups-r7780rp.c +++ b/arch/sh/drivers/pci/fixups-r7780rp.c @@ -11,35 +11,11 @@ * for more details. */ #include <linux/pci.h> +#include <linux/io.h> +#include <linux/sh_intc.h> #include "pci-sh4.h" -#include <asm/io.h> -int pci_fixup_pcic(void) +int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { - pci_write_reg(0x000043ff, SH4_PCIINTM); - pci_write_reg(0x0000380f, SH4_PCIAINTM); - - pci_write_reg(0xfbb00047, SH7780_PCICMD); - pci_write_reg(0x00000000, SH7780_PCIIBAR); - - pci_write_reg(0x00011912, SH7780_PCISVID); - pci_write_reg(0x08000000, SH7780_PCICSCR0); - pci_write_reg(0x0000001b, SH7780_PCICSAR0); - pci_write_reg(0xfd000000, SH7780_PCICSCR1); - pci_write_reg(0x0000000f, SH7780_PCICSAR1); - - pci_write_reg(0xfd000000, SH7780_PCIMBR0); - pci_write_reg(0x00fc0000, SH7780_PCIMBMR0); - -#ifdef CONFIG_32BIT - pci_write_reg(0xc0000000, SH7780_PCIMBR2); - pci_write_reg(0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2); -#endif - - /* Set IOBR for windows containing area specified in pci.h */ - pci_write_reg((PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE - 1)), - SH7780_PCIIOBR); - pci_write_reg(((SH7780_PCI_IO_SIZE-1) & (7<<18)), SH7780_PCIIOBMR); - - return 0; + return evt2irq(0xa20) + slot; } diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c index 904bce8768d..eaddb56c45c 100644 --- a/arch/sh/drivers/pci/fixups-rts7751r2d.c +++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c @@ -1,43 +1,67 @@ /* * arch/sh/drivers/pci/fixups-rts7751r2d.c * - * RTS7751R2D PCI fixups + * RTS7751R2D / LBOXRE2 PCI fixups * * Copyright (C) 2003 Lineo uSolutions, Inc. * Copyright (C) 2004 Paul Mundt + * Copyright (C) 2007 Nobuhiro Iwamatsu * * 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. */ +#include <linux/pci.h> +#include <mach/lboxre2.h> +#include <mach/r2d.h> #include "pci-sh4.h" +#include <generated/machtypes.h> #define PCIMCR_MRSET_OFF 0xBFFFFFFF #define PCIMCR_RFSH_OFF 0xFFFFFFFB -int pci_fixup_pcic(void) +static u8 rts7751r2d_irq_tab[] __initdata = { + IRQ_PCI_INTA, + IRQ_PCI_INTB, + IRQ_PCI_INTC, + IRQ_PCI_INTD, +}; + +static char lboxre2_irq_tab[] __initdata = { + IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD, +}; + +int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + if (mach_is_lboxre2()) + return lboxre2_irq_tab[slot]; + else + return rts7751r2d_irq_tab[slot]; +} + +int pci_fixup_pcic(struct pci_channel *chan) { unsigned long bcr1, mcr; - bcr1 = ctrl_inl(SH7751_BCR1); + bcr1 = __raw_readl(SH7751_BCR1); bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ - pci_write_reg(bcr1, SH4_PCIBCR1); + pci_write_reg(chan, bcr1, SH4_PCIBCR1); /* Enable all interrupts, so we known what to fix */ - pci_write_reg(0x0000c3ff, SH4_PCIINTM); - pci_write_reg(0x0000380f, SH4_PCIAINTM); + pci_write_reg(chan, 0x0000c3ff, SH4_PCIINTM); + pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM); - pci_write_reg(0xfb900047, SH7751_PCICONF1); - pci_write_reg(0xab000001, SH7751_PCICONF4); + pci_write_reg(chan, 0xfb900047, SH7751_PCICONF1); + pci_write_reg(chan, 0xab000001, SH7751_PCICONF4); - mcr = ctrl_inl(SH7751_MCR); + mcr = __raw_readl(SH7751_MCR); mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; - pci_write_reg(mcr, SH4_PCIMCR); + pci_write_reg(chan, mcr, SH4_PCIMCR); - pci_write_reg(0x0c000000, SH7751_PCICONF5); - pci_write_reg(0xd0000000, SH7751_PCICONF6); - pci_write_reg(0x0c000000, SH4_PCILAR0); - pci_write_reg(0x00000000, SH4_PCILAR1); + pci_write_reg(chan, 0x0c000000, SH7751_PCICONF5); + pci_write_reg(chan, 0xd0000000, SH7751_PCICONF6); + pci_write_reg(chan, 0x0c000000, SH4_PCILAR0); + pci_write_reg(chan, 0x00000000, SH4_PCILAR1); return 0; } diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c index 2f8863099dd..c0a015ae6ec 100644 --- a/arch/sh/drivers/pci/fixups-sdk7780.c +++ b/arch/sh/drivers/pci/fixups-sdk7780.c @@ -5,55 +5,39 @@ * * Copyright (C) 2003 Lineo uSolutions, Inc. * Copyright (C) 2004 - 2006 Paul Mundt + * Copyright (C) 2006 Nobuhiro Iwamatsu * * 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. */ #include <linux/pci.h> +#include <linux/io.h> +#include <linux/sh_intc.h> #include "pci-sh4.h" -#include <asm/io.h> -int pci_fixup_pcic(void) +#define IRQ_INTA evt2irq(0xa20) +#define IRQ_INTB evt2irq(0xa40) +#define IRQ_INTC evt2irq(0xa60) +#define IRQ_INTD evt2irq(0xa80) + +/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */ +static char sdk7780_irq_tab[4][16] __initdata = { + /* INTA */ + { IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1 }, + /* INTB */ + { IRQ_INTB, IRQ_INTA, -1, IRQ_INTA, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1 }, + /* INTC */ + { IRQ_INTC, IRQ_INTB, -1, IRQ_INTB, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1 }, + /* INTD */ + { IRQ_INTD, IRQ_INTC, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1 }, +}; + +int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { - ctrl_outl(0x00000001, SH7780_PCI_VCR2); - - /* Enable all interrupts, so we know what to fix */ - pci_write_reg(0x0000C3FF, SH7780_PCIIMR); - pci_write_reg(0x0000380F, SH7780_PCIAINTM); - - /* Set up standard PCI config registers */ - pci_write_reg(0xFB00, SH7780_PCISTATUS); - pci_write_reg(0x0047, SH7780_PCICMD); - pci_write_reg(0x00, SH7780_PCIPIF); - pci_write_reg(0x00, SH7780_PCISUB); - pci_write_reg(0x06, SH7780_PCIBCC); - pci_write_reg(0x1912, SH7780_PCISVID); - pci_write_reg(0x0001, SH7780_PCISID); - - pci_write_reg(0x08000000, SH7780_PCIMBAR0); /* PCI */ - pci_write_reg(0x08000000, SH7780_PCILAR0); /* SHwy */ - pci_write_reg(0x07F00001, SH7780_PCILSR); /* size 128M w/ MBAR */ - - pci_write_reg(0x00000000, SH7780_PCIMBAR1); - pci_write_reg(0x00000000, SH7780_PCILAR1); - pci_write_reg(0x00000000, SH7780_PCILSR1); - - pci_write_reg(0xAB000801, SH7780_PCIIBAR); - - /* - * Set the MBR so PCI address is one-to-one with window, - * meaning all calls go straight through... use ifdef to - * catch erroneous assumption. - */ - pci_write_reg(0xFD000000 , SH7780_PCIMBR0); - pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0); /* 16M */ - - /* Set IOBR for window containing area specified in pci.h */ - pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR); - pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR); - - pci_write_reg(0xA5000C01, SH7780_PCICR); - - return 0; + return sdk7780_irq_tab[pin-1][slot]; } diff --git a/arch/sh/drivers/pci/fixups-sdk7786.c b/arch/sh/drivers/pci/fixups-sdk7786.c new file mode 100644 index 00000000000..36eb6fc3c18 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-sdk7786.c @@ -0,0 +1,67 @@ +/* + * SDK7786 FPGA PCIe mux handling + * + * Copyright (C) 2010 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 + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <mach/fpga.h> + +/* + * The SDK7786 FPGA supports mangling of most of the slots in some way or + * another. Slots 3/4 are special in that only one can be supported at a + * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4 + * (the horizontal edge connector) will disable slot 3 entirely. + * + * Misconfigurations can be detected through the FPGA via the slot + * resistors to determine card presence. Hotplug remains unsupported. + */ +static unsigned int slot4en __initdata; + +char *__init pcibios_setup(char *str) +{ + if (strcmp(str, "slot4en") == 0) { + slot4en = 1; + return NULL; + } + + return str; +} + +static int __init sdk7786_pci_init(void) +{ + u16 data = fpga_read_reg(PCIECR); + + /* + * Enable slot #4 if it's been specified on the command line. + * + * Optionally reroute if slot #4 has a card present while slot #3 + * does not, regardless of command line value. + * + * Card presence is logically inverted. + */ + slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3)); + if (slot4en) { + pr_info("Activating PCIe slot#4 (disabling slot#3)\n"); + + data &= ~PCIECR_PCIEMUX1; + fpga_write_reg(data, PCIECR); + + /* Warn about forced rerouting if slot#3 is occupied */ + if ((data & PCIECR_PRST3) == 0) { + pr_warning("Unreachable card detected in slot#3\n"); + return -EBUSY; + } + } else + pr_info("PCIe slot#4 disabled\n"); + + return 0; +} +postcore_initcall(sdk7786_pci_init); diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c new file mode 100644 index 00000000000..84a88ca9200 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-se7751.c @@ -0,0 +1,112 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/sh_intc.h> +#include "pci-sh4.h" + +int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin) +{ + switch (slot) { + case 0: return evt2irq(0x3a0); + case 1: return evt2irq(0x3a0); /* AMD Ethernet controller */ + case 2: return -1; + case 3: return -1; + case 4: return -1; + default: + printk("PCI: Bad IRQ mapping request for slot %d\n", slot); + return -1; + } +} + +#define PCIMCR_MRSET_OFF 0xBFFFFFFF +#define PCIMCR_RFSH_OFF 0xFFFFFFFB + +/* + * Only long word accesses of the PCIC's internal local registers and the + * configuration registers from the CPU is supported. + */ +#define PCIC_WRITE(x,v) writel((v), PCI_REG(x)) +#define PCIC_READ(x) readl(PCI_REG(x)) + +/* + * Description: This function sets up and initializes the pcic, sets + * up the BARS, maps the DRAM into the address space etc, etc. + */ +int pci_fixup_pcic(struct pci_channel *chan) +{ + unsigned long bcr1, wcr1, wcr2, wcr3, mcr; + unsigned short bcr2; + + /* + * Initialize the slave bus controller on the pcic. The values used + * here should not be hardcoded, but they should be taken from the bsc + * on the processor, to make this function as generic as possible. + * (i.e. Another sbc may usr different SDRAM timing settings -- in order + * for the pcic to work, its settings need to be exactly the same.) + */ + bcr1 = (*(volatile unsigned long*)(SH7751_BCR1)); + bcr2 = (*(volatile unsigned short*)(SH7751_BCR2)); + wcr1 = (*(volatile unsigned long*)(SH7751_WCR1)); + wcr2 = (*(volatile unsigned long*)(SH7751_WCR2)); + wcr3 = (*(volatile unsigned long*)(SH7751_WCR3)); + mcr = (*(volatile unsigned long*)(SH7751_MCR)); + + bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */ + (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1; + + bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ + PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */ + PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */ + PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */ + PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */ + PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */ + mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; + PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */ + + + /* Enable all interrupts, so we know what to fix */ + PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff); + PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f); + + /* Set up standard PCI config registers */ + PCIC_WRITE(SH7751_PCICONF1, 0xF39000C7); /* Bus Master, Mem & I/O access */ + PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */ + PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */ + PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM) */ + PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */ + PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */ + PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* MEM (full 64M exposed) */ + PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */ + PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */ + PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */ + + /* Now turn it on... */ + PCIC_WRITE(SH7751_PCICR, 0xa5000001); + + /* + * Set PCIMBR and PCIIOBR here, assuming a single window + * (16M MEM, 256K IO) is enough. If a larger space is + * needed, the readx/writex and inx/outx functions will + * have to do more (e.g. setting registers for each call). + */ + + /* + * Set the MBR so PCI address is one-to-one with window, + * meaning all calls go straight through... use BUG_ON to + * catch erroneous assumption. + */ + BUG_ON(chan->resources[1].start != SH7751_PCI_MEMORY_BASE); + + PCIC_WRITE(SH7751_PCIMBR, chan->resources[1].start); + + /* Set IOBR for window containing area specified in pci.h */ + 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"); + + return 1; +} diff --git a/arch/sh/drivers/pci/fixups-se7780.c b/arch/sh/drivers/pci/fixups-se7780.c deleted file mode 100644 index 880cea1c0d8..00000000000 --- a/arch/sh/drivers/pci/fixups-se7780.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * arch/sh/drivers/pci/fixups-se7780.c - * - * HITACHI UL Solution Engine 7780 PCI fixups - * - * Copyright (C) 2003 Lineo uSolutions, Inc. - * Copyright (C) 2004 - 2006 Paul Mundt - * Copyright (C) 2006 Nobuhiro Iwamatsu - * - * 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. - */ -#include <linux/pci.h> -#include "pci-sh4.h" -#include <asm/io.h> - -int pci_fixup_pcic(void) -{ - ctrl_outl(0x00000001, SH7780_PCI_VCR2); - - /* Enable all interrupts, so we know what to fix */ - pci_write_reg(0x0000C3FF, SH7780_PCIIMR); - pci_write_reg(0x0000380F, SH7780_PCIAINTM); - - /* Set up standard PCI config registers */ - ctrl_outw(0xFB00, PCI_REG(SH7780_PCISTATUS)); - ctrl_outw(0x0047, PCI_REG(SH7780_PCICMD)); - ctrl_outb( 0x00, PCI_REG(SH7780_PCIPIF)); - ctrl_outb( 0x00, PCI_REG(SH7780_PCISUB)); - ctrl_outb( 0x06, PCI_REG(SH7780_PCIBCC)); - ctrl_outw(0x1912, PCI_REG(SH7780_PCISVID)); - ctrl_outw(0x0001, PCI_REG(SH7780_PCISID)); - - pci_write_reg(0x08000000, SH7780_PCIMBAR0); /* PCI */ - pci_write_reg(0x08000000, SH7780_PCILAR0); /* SHwy */ - pci_write_reg(0x07F00001, SH7780_PCILSR); /* size 128M w/ MBAR */ - - pci_write_reg(0x00000000, SH7780_PCIMBAR1); - pci_write_reg(0x00000000, SH7780_PCILAR1); - pci_write_reg(0x00000000, SH7780_PCILSR1); - - pci_write_reg(0xAB000801, SH7780_PCIIBAR); - - /* - * Set the MBR so PCI address is one-to-one with window, - * meaning all calls go straight through... use ifdef to - * catch erroneous assumption. - */ - pci_write_reg(0xFD000000 , SH7780_PCIMBR0); - pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0); /* 16M */ - - /* Set IOBR for window containing area specified in pci.h */ - pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR); - pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR); - - pci_write_reg(0xA5000C01, SH7780_PCICR); - - return 0; -} diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c index 2e8a18b7ee5..16207bef9f5 100644 --- a/arch/sh/drivers/pci/fixups-sh03.c +++ b/arch/sh/drivers/pci/fixups-sh03.c @@ -2,28 +2,29 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/sh_intc.h> -int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) +int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin) { int irq; if (dev->bus->number == 0) { switch (slot) { - case 4: return 5; /* eth0 */ - case 8: return 5; /* eth1 */ - case 6: return 2; /* PCI bridge */ + case 4: return evt2irq(0x2a0); /* eth0 */ + case 8: return evt2irq(0x2a0); /* eth1 */ + case 6: return evt2irq(0x240); /* PCI bridge */ default: printk(KERN_ERR "PCI: Bad IRQ mapping request " "for slot %d\n", slot); - return 2; + return evt2irq(0x240); } } else { switch (pin) { - case 0: irq = 2; break; - case 1: irq = 2; break; - case 2: irq = 2; break; - case 3: irq = 2; break; - case 4: irq = 2; break; + case 0: irq = evt2irq(0x240); break; + case 1: irq = evt2irq(0x240); break; + case 2: irq = evt2irq(0x240); break; + case 3: irq = evt2irq(0x240); break; + case 4: irq = evt2irq(0x240); break; default: irq = -1; break; } } diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c new file mode 100644 index 00000000000..6e33ba4cd07 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-snapgear.c @@ -0,0 +1,39 @@ +/* + * arch/sh/drivers/pci/ops-snapgear.c + * + * Author: David McCullough <davidm@snapgear.com> + * + * Ported to new API by Paul Mundt <lethal@linux-sh.org> + * + * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * PCI initialization for the SnapGear boards + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/sh_intc.h> +#include "pci-sh4.h" + +int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + int irq = -1; + + switch (slot) { + case 8: /* the PCI bridge */ break; + case 11: irq = evt2irq(0x300); break; /* USB */ + case 12: irq = evt2irq(0x360); break; /* PCMCIA */ + case 13: irq = evt2irq(0x2a0); break; /* eth0 */ + case 14: irq = evt2irq(0x300); break; /* eth1 */ + case 15: irq = evt2irq(0x360); break; /* safenet (unused) */ + } + + printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n", + slot, pin - 1 + 'A', irq); + + return irq; +} diff --git a/arch/sh/drivers/pci/fixups-titan.c b/arch/sh/drivers/pci/fixups-titan.c new file mode 100644 index 00000000000..bd1addb1b8b --- /dev/null +++ b/arch/sh/drivers/pci/fixups-titan.c @@ -0,0 +1,38 @@ +/* + * arch/sh/drivers/pci/ops-titan.c + * + * Ported to new API by Paul Mundt <lethal@linux-sh.org> + * + * Modified from ops-snapgear.c written by David McCullough + * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * PCI initialization for the Titan boards + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <mach/titan.h> +#include "pci-sh4.h" + +static char titan_irq_tab[] __initdata = { + TITAN_IRQ_WAN, + TITAN_IRQ_LAN, + TITAN_IRQ_MPCIA, + TITAN_IRQ_MPCIB, + TITAN_IRQ_USB, +}; + +int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + int irq = titan_irq_tab[slot]; + + printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n", + slot, pin - 1 + 'A', irq); + + return irq; +} diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c index e1284fc6936..16e0a1baad8 100644 --- a/arch/sh/drivers/pci/ops-dreamcast.c +++ b/arch/sh/drivers/pci/ops-dreamcast.c @@ -1,15 +1,9 @@ /* - * arch/sh/drivers/pci/ops-dreamcast.c - * * PCI operations for the Sega Dreamcast * * Copyright (C) 2001, 2002 M. R. Brown * Copyright (C) 2002, 2003 Paul Mundt * - * This file originally bore the message (with enclosed-$): - * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp - * Dreamcast PCI: Supports SEGA Broadband Adaptor only. - * * 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. @@ -22,32 +16,9 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/pci.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/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 pci_ops gapspci_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &gapspci_pci_ops, &gapspci_io_resource, - &gapspci_mem_resource, 0, 1 }, - { 0, } -}; +#include <linux/module.h> +#include <linux/io.h> +#include <mach/pci.h> /* * The !gapspci_config_access case really shouldn't happen, ever, unless @@ -83,10 +54,10 @@ static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int return PCIBIOS_DEVICE_NOT_FOUND; switch (size) { - case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break; - case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break; - case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break; - } + case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break; + case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break; + case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break; + } return PCIBIOS_SUCCESSFUL; } @@ -97,72 +68,15 @@ static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int return PCIBIOS_DEVICE_NOT_FOUND; switch (size) { - case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break; - case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break; - case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break; + case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break; + case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break; + case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break; } return PCIBIOS_SUCCESSFUL; } -static struct pci_ops gapspci_pci_ops = { +struct pci_ops gapspci_pci_ops = { .read = gapspci_read, .write = gapspci_write, }; - -/* - * gapspci init - */ - -int __init gapspci_init(void) -{ - char idbuf[16]; - int i; - - /* - * FIXME: All of this wants documenting to some degree, - * even some basic register definitions would be nice. - * - * I haven't seen anything this ugly since.. maple. - */ - - for (i=0; i<16; i++) - idbuf[i] = inb(GAPSPCI_REGS+i); - - if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16)) - return -ENODEV; - - outl(0x5a14a501, GAPSPCI_REGS+0x18); - - for (i=0; i<1000000; i++) - ; - - if (inl(GAPSPCI_REGS+0x18) != 1) - return -EINVAL; - - outl(0x01000000, GAPSPCI_REGS+0x20); - outl(0x01000000, GAPSPCI_REGS+0x24); - - outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); - outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); - - outl(1, GAPSPCI_REGS+0x14); - outl(1, GAPSPCI_REGS+0x34); - - /* Setting Broadband Adapter */ - outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); - outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); - outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); - outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); - outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); - outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); - outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); - - return 0; -} - -/* Haven't done anything here as yet */ -char * __devinit pcibios_setup(char *str) -{ - return str; -} diff --git a/arch/sh/drivers/pci/ops-landisk.c b/arch/sh/drivers/pci/ops-landisk.c deleted file mode 100644 index bff09ecf341..00000000000 --- a/arch/sh/drivers/pci/ops-landisk.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * arch/sh/drivers/pci/ops-landisk.c - * - * PCI initialization for the I-O DATA Device, Inc. LANDISK board - * - * Copyright (C) 2006 kogiidena - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include "pci-sh4.h" - -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 -}; - -struct pci_channel board_pci_channels[] = { - {&sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0x3ff}, - {NULL, NULL, NULL, 0, 0}, -}; - -static struct sh4_pci_address_map sh7751_pci_map = { - .window0 = { - .base = SH7751_CS3_BASE_ADDR, - .size = (64 << 20), /* 64MB */ - }, - - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - return sh7751_pcic_init(&sh7751_pci_map); -} - -int pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - /* - * slot0: pin1-4 = irq5,6,7,8 - * slot1: pin1-4 = irq6,7,8,5 - * slot2: pin1-4 = irq7,8,5,6 - * slot3: pin1-4 = irq8,5,6,7 - */ - int irq = ((slot + pin - 1) & 0x3) + 5; - - if ((slot | (pin - 1)) > 0x3) { - printk("PCI: Bad IRQ mapping request for slot %d pin %c\n", - slot, pin - 1 + 'A'); - return -1; - } - return irq; -} diff --git a/arch/sh/drivers/pci/ops-lboxre2.c b/arch/sh/drivers/pci/ops-lboxre2.c deleted file mode 100644 index a13cb764b0b..00000000000 --- a/arch/sh/drivers/pci/ops-lboxre2.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/arch/sh/drivers/pci/ops-lboxre2.c - * - * Copyright (C) 2007 Nobuhiro Iwamatsu - * - * PCI initialization for the NTT COMWARE L-BOX RE2 - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/io.h> -#include <asm/lboxre2.h> -#include "pci-sh4.h" - -static char lboxre2_irq_tab[] __initdata = { - IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD, -}; - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - return lboxre2_irq_tab[slot]; -} - -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 -}; - -extern struct pci_ops sh7751_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; - -EXPORT_SYMBOL(board_pci_channels); - -static struct sh4_pci_address_map sh7751_pci_map = { - .window0 = { - .base = SH7751_CS3_BASE_ADDR, - .size = 0x04000000, - }, - .window1 = { - .base = 0x00000000, /* Unused */ - .size = 0x00000000, /* Unused */ - }, - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - return sh7751_pcic_init(&sh7751_pci_map); -} diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c deleted file mode 100644 index 5fdadaeed6f..00000000000 --- a/arch/sh/drivers/pci/ops-r7780rp.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Author: Ian DaSilva (idasilva@mvista.com) - * - * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * PCI initialization for the Renesas SH7780 Highlander R7780RP-1 board - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <asm/r7780rp.h> -#include <asm/io.h> -#include "pci-sh4.h" - -static char irq_tab[] __initdata = { - 65, 66, 67, 68, -}; - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - return irq_tab[slot]; -} - -static struct resource sh7780_io_resource = { - .name = "SH7780_IO", - .start = SH7780_PCI_IO_BASE, - .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1, - .flags = IORESOURCE_IO -}; - -static struct resource sh7780_mem_resource = { - .name = "SH7780_mem", - .start = SH7780_PCI_MEMORY_BASE, - .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - -extern struct pci_ops sh7780_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7780_io_resource, &sh7780_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; -EXPORT_SYMBOL(board_pci_channels); - -static struct sh4_pci_address_map sh7780_pci_map = { - .window0 = { - .base = SH7780_CS2_BASE_ADDR, - .size = 0x04000000, - }, - - .window1 = { - .base = SH7780_CS3_BASE_ADDR, - .size = 0x04000000, - }, - - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - return sh7780_pcic_init(&sh7780_pci_map); -} diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c deleted file mode 100644 index b3fa3e2ef18..00000000000 --- a/arch/sh/drivers/pci/ops-rts7751r2d.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * linux/arch/sh/drivers/pci/ops-rts7751r2d.c - * - * Author: Ian DaSilva (idasilva@mvista.com) - * - * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * PCI initialization for the Renesas SH7751R RTS7751R2D board - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/io.h> -#include <asm/rts7751r2d.h> -#include "pci-sh4.h" - -static u8 rts7751r2d_irq_tab[] __initdata = { - IRQ_PCI_INTA, - IRQ_PCI_INTB, - IRQ_PCI_INTC, - IRQ_PCI_INTD, -}; - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - return rts7751r2d_irq_tab[slot]; -} - -static struct resource sh7751_io_resource = { - .name = "SH7751_IO", - .start = 0x4000, - .end = 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 -}; - -extern struct pci_ops sh7751_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; -EXPORT_SYMBOL(board_pci_channels); - -static struct sh4_pci_address_map sh7751_pci_map = { - .window0 = { - .base = SH7751_CS3_BASE_ADDR, - .size = 0x04000000, - }, - - .window1 = { - .base = 0x00000000, /* Unused */ - .size = 0x00000000, /* Unused */ - }, - - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - __set_io_port_base(SH7751_PCI_IO_BASE); - return sh7751_pcic_init(&sh7751_pci_map); -} - diff --git a/arch/sh/drivers/pci/ops-sdk7780.c b/arch/sh/drivers/pci/ops-sdk7780.c deleted file mode 100644 index 66a9b4047f2..00000000000 --- a/arch/sh/drivers/pci/ops-sdk7780.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * linux/arch/sh/drivers/pci/ops-sdk7780.c - * - * Copyright (C) 2006 Nobuhiro Iwamatsu - * - * PCI initialization for the SDK7780SE03 - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <asm/sdk7780.h> -#include <asm/io.h> -#include "pci-sh4.h" - -/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */ -static char sdk7780_irq_tab[4][16] __initdata = { - /* INTA */ - { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - /* INTB */ - { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - /* INTC */ - { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - /* INTD */ - { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, -}; - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - return sdk7780_irq_tab[pin-1][slot]; -} - -static struct resource sdk7780_io_resource = { - .name = "SH7780_IO", - .start = SH7780_PCI_IO_BASE, - .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1, - .flags = IORESOURCE_IO -}; - -static struct resource sdk7780_mem_resource = { - .name = "SH7780_mem", - .start = SH7780_PCI_MEMORY_BASE, - .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sdk7780_io_resource, &sdk7780_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; -EXPORT_SYMBOL(board_pci_channels); - -static struct sh4_pci_address_map sdk7780_pci_map = { - .window0 = { - .base = SH7780_CS2_BASE_ADDR, - .size = 0x04000000, - }, - .window1 = { - .base = SH7780_CS3_BASE_ADDR, - .size = 0x04000000, - }, - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - printk(KERN_INFO "SH7780 PCI: Finished initializing PCI controller\n"); - return sh7780_pcic_init(&sdk7780_pci_map); -} diff --git a/arch/sh/drivers/pci/ops-se7780.c b/arch/sh/drivers/pci/ops-se7780.c deleted file mode 100644 index bbdb48c124a..00000000000 --- a/arch/sh/drivers/pci/ops-se7780.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * linux/arch/sh/drivers/pci/ops-se7780.c - * - * Copyright (C) 2006 Nobuhiro Iwamatsu - * - * PCI initialization for the Hitachi UL Solution Engine 7780SE03 - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <asm/se7780.h> -#include <asm/io.h> -#include "pci-sh4.h" - -/* - * IDSEL = AD16 PCI slot - * IDSEL = AD17 PCI slot - * IDSEL = AD18 Serial ATA Controller (Silicon Image SiL3512A) - * IDSEL = AD19 USB Host Controller (NEC uPD7210100A) - */ - -/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */ -static char se7780_irq_tab[4][16] __initdata = { - /* INTA */ - { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - /* INTB */ - { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - /* INTC */ - { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - /* INTD */ - { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, -}; - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - return se7780_irq_tab[pin-1][slot]; -} - -static struct resource se7780_io_resource = { - .name = "SH7780_IO", - .start = SH7780_PCI_IO_BASE, - .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1, - .flags = IORESOURCE_IO -}; - -static struct resource se7780_mem_resource = { - .name = "SH7780_mem", - .start = SH7780_PCI_MEMORY_BASE, - .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - -extern struct pci_ops se7780_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &se7780_io_resource, &se7780_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; -EXPORT_SYMBOL(board_pci_channels); - -static struct sh4_pci_address_map se7780_pci_map = { - .window0 = { - .base = SH7780_CS2_BASE_ADDR, - .size = 0x04000000, - }, - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - printk("SH7780 PCI: Finished initialization of the PCI controller\n"); - - /* - * FPGA PCISEL register initialize - * - * CPU || SLOT1 | SLOT2 | S-ATA | USB - * ------------------------------------- - * INTA || INTA | INTD | -- | INTB - * ------------------------------------- - * INTB || INTB | INTA | -- | INTC - * ------------------------------------- - * INTC || INTC | INTB | INTA | -- - * ------------------------------------- - * INTD || INTD | INTC | -- | INTA - * ------------------------------------- - */ - ctrl_outw(0x0013, FPGA_PCI_INTSEL1); - ctrl_outw(0xE402, FPGA_PCI_INTSEL2); - - return sh7780_pcic_init(&se7780_pci_map); -} diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c deleted file mode 100644 index ebb58e605d9..00000000000 --- a/arch/sh/drivers/pci/ops-sh03.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * linux/arch/sh/drivers/pci/ops-sh03.c - * - * PCI initialization for the Interface CTP/PCI-SH03 board - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <asm/io.h> -#include "pci-sh7751.h" - -/* - * Description: This function sets up and initializes the pcic, sets - * up the BARS, maps the DRAM into the address space etc, etc. - */ -int __init pcibios_init_platform(void) -{ - return 1; -} - -static struct resource sh7751_io_resource = { - .name = "SH03 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 = "SH03 mem", - .start = SH7751_PCI_MEMORY_BASE, - .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - -extern struct pci_ops sh4_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; - diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c index 710a3b0306e..b6234203e0a 100644 --- a/arch/sh/drivers/pci/ops-sh4.c +++ b/arch/sh/drivers/pci/ops-sh4.c @@ -1,24 +1,23 @@ /* * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780). * - * Copyright (C) 2002 - 2006 Paul Mundt + * Copyright (C) 2002 - 2009 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License v2. See the file "COPYING" in the main directory of this archive * for more details. */ #include <linux/pci.h> +#include <linux/io.h> +#include <linux/spinlock.h> #include <asm/addrspace.h> -#include <asm/io.h> #include "pci-sh4.h" /* * Direct access to PCI hardware... */ #define CONFIG_CMD(bus, devfn, where) \ - P1SEGADDR((bus->number << 16) | (devfn << 8) | (where & ~3)) - -static DEFINE_SPINLOCK(sh4_pci_lock); + (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) /* * Functions for accessing PCI configuration space with type 1 accesses @@ -26,6 +25,7 @@ static DEFINE_SPINLOCK(sh4_pci_lock); static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { + struct pci_channel *chan = bus->sysdata; unsigned long flags; u32 data; @@ -33,10 +33,10 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn, * PCIPDR may only be accessed as 32 bit words, * so we must do byte alignment by hand */ - spin_lock_irqsave(&sh4_pci_lock, flags); - pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR); - data = pci_read_reg(SH4_PCIPDR); - spin_unlock_irqrestore(&sh4_pci_lock, flags); + raw_spin_lock_irqsave(&pci_config_lock, flags); + pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR); + data = pci_read_reg(chan, SH4_PCIPDR); + raw_spin_unlock_irqrestore(&pci_config_lock, flags); switch (size) { case 1: @@ -63,14 +63,15 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn, static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { + struct pci_channel *chan = bus->sysdata; unsigned long flags; int shift; u32 data; - spin_lock_irqsave(&sh4_pci_lock, flags); - pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR); - data = pci_read_reg(SH4_PCIPDR); - spin_unlock_irqrestore(&sh4_pci_lock, flags); + raw_spin_lock_irqsave(&pci_config_lock, flags); + pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR); + data = pci_read_reg(chan, SH4_PCIPDR); + raw_spin_unlock_irqrestore(&pci_config_lock, flags); switch (size) { case 1: @@ -90,7 +91,7 @@ static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_FUNC_NOT_SUPPORTED; } - pci_write_reg(data, SH4_PCIPDR); + pci_write_reg(chan, data, SH4_PCIPDR); return PCIBIOS_SUCCESSFUL; } @@ -100,70 +101,7 @@ struct pci_ops sh4_pci_ops = { .write = sh4_pci_write, }; -/* - * Not really related to pci_ops, but it's common and not worth shoving - * somewhere else for now.. - */ -static unsigned int pci_probe = PCI_PROBE_CONF1; - -int __init sh4_pci_check_direct(void) -{ - /* - * Check if configuration works. - */ - if (pci_probe & PCI_PROBE_CONF1) { - unsigned int tmp = pci_read_reg(SH4_PCIPAR); - - pci_write_reg(P1SEG, SH4_PCIPAR); - - if (pci_read_reg(SH4_PCIPAR) == P1SEG) { - pci_write_reg(tmp, SH4_PCIPAR); - printk(KERN_INFO "PCI: Using configuration type 1\n"); - request_region(PCI_REG(SH4_PCIPAR), 8, "PCI conf1"); - - return 0; - } - - pci_write_reg(tmp, SH4_PCIPAR); - } - - pr_debug("PCI: pci_check_direct failed\n"); - return -EINVAL; -} - -/* Handle generic fixups */ -static void __init pci_fixup_ide_bases(struct pci_dev *d) -{ - int i; - - /* - * PCI IDE controllers use non-standard I/O port decoding, respect it. - */ - if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) - return; - pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d)); - for(i = 0; i < 4; i++) { - struct resource *r = &d->resource[i]; - - if ((r->start & ~0x80) == 0x374) { - r->start |= 2; - r->end = r->start; - } - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); - -char * __devinit pcibios_setup(char *str) -{ - if (!strcmp(str, "off")) { - pci_probe = 0; - return NULL; - } - - return str; -} - -int __attribute__((weak)) pci_fixup_pcic(void) +int __attribute__((weak)) pci_fixup_pcic(struct pci_channel *chan) { /* Nothing to do. */ return 0; diff --git a/arch/sh/drivers/pci/ops-sh5.c b/arch/sh/drivers/pci/ops-sh5.c index 729e38a6fe0..4ce95a001b8 100644 --- a/arch/sh/drivers/pci/ops-sh5.c +++ b/arch/sh/drivers/pci/ops-sh5.c @@ -22,31 +22,6 @@ #include <asm/io.h> #include "pci-sh5.h" -static void __init pci_fixup_ide_bases(struct pci_dev *d) -{ - int i; - - /* - * PCI IDE controllers use non-standard I/O port decoding, respect it. - */ - if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) - return; - printk("PCI: IDE base address fixup for %s\n", pci_name(d)); - for(i=0; i<4; i++) { - struct resource *r = &d->resource[i]; - if ((r->start & ~0x80) == 0x374) { - r->start |= 2; - r->end = r->start; - } - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); - -char * __devinit pcibios_setup(char *str) -{ - return str; -} - static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { diff --git a/arch/sh/drivers/pci/ops-sh7786.c b/arch/sh/drivers/pci/ops-sh7786.c new file mode 100644 index 00000000000..128421009e3 --- /dev/null +++ b/arch/sh/drivers/pci/ops-sh7786.c @@ -0,0 +1,171 @@ +/* + * Generic SH7786 PCI-Express operations. + * + * Copyright (C) 2009 - 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License v2. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include "pcie-sh7786.h" + +enum { + PCI_ACCESS_READ, + PCI_ACCESS_WRITE, +}; + +static int sh7786_pcie_config_access(unsigned char access_type, + struct pci_bus *bus, unsigned int devfn, int where, u32 *data) +{ + struct pci_channel *chan = bus->sysdata; + int dev, func, type, reg; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + type = !!bus->parent; + reg = where & ~3; + + if (bus->number > 255 || dev > 31 || func > 7) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* + * While each channel has its own memory-mapped extended config + * space, it's generally only accessible when in endpoint mode. + * When in root complex mode, the controller is unable to target + * itself with either type 0 or type 1 accesses, and indeed, any + * controller initiated target transfer to its own config space + * result in a completer abort. + * + * Each channel effectively only supports a single device, but as + * the same channel <-> device access works for any PCI_SLOT() + * value, we cheat a bit here and bind the controller's config + * space to devfn 0 in order to enable self-enumeration. In this + * case the regular PAR/PDR path is sidelined and the mangled + * config access itself is initiated as a SuperHyway transaction. + */ + if (pci_is_root_bus(bus)) { + if (dev == 0) { + if (access_type == PCI_ACCESS_READ) + *data = pci_read_reg(chan, PCI_REG(reg)); + else + pci_write_reg(chan, *data, PCI_REG(reg)); + + return PCIBIOS_SUCCESSFUL; + } else if (dev > 1) + return PCIBIOS_DEVICE_NOT_FOUND; + } + + /* Clear errors */ + pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR); + + /* Set the PIO address */ + pci_write_reg(chan, (bus->number << 24) | (dev << 19) | + (func << 16) | reg, SH4A_PCIEPAR); + + /* Enable the configuration access */ + pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR); + + /* Check for errors */ + if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Check for master and target aborts */ + if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28))) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (access_type == PCI_ACCESS_READ) + *data = pci_read_reg(chan, SH4A_PCIEPDR); + else + pci_write_reg(chan, *data, SH4A_PCIEPDR); + + /* Disable the configuration access */ + pci_write_reg(chan, 0, SH4A_PCIEPCTLR); + + return PCIBIOS_SUCCESSFUL; +} + +static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + unsigned long flags; + int ret; + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + raw_spin_lock_irqsave(&pci_config_lock, flags); + ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus, + devfn, where, &data); + if (ret != PCIBIOS_SUCCESSFUL) { + *val = 0xffffffff; + goto out; + } + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 2) << 3)) & 0xffff; + else + *val = data; + + dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x " + "where=0x%04x size=%d val=0x%08lx\n", bus->number, + devfn, where, size, (unsigned long)*val); + +out: + raw_spin_unlock_irqrestore(&pci_config_lock, flags); + return ret; +} + +static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + unsigned long flags; + int shift, ret; + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + raw_spin_lock_irqsave(&pci_config_lock, flags); + ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus, + devfn, where, &data); + if (ret != PCIBIOS_SUCCESSFUL) + goto out; + + dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x " + "where=0x%04x size=%d val=%08lx\n", bus->number, + devfn, where, size, (unsigned long)val); + + if (size == 1) { + shift = (where & 3) << 3; + data &= ~(0xff << shift); + data |= ((val & 0xff) << shift); + } else if (size == 2) { + shift = (where & 2) << 3; + data &= ~(0xffff << shift); + data |= ((val & 0xffff) << shift); + } else + data = val; + + ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus, + devfn, where, &data); +out: + raw_spin_unlock_irqrestore(&pci_config_lock, flags); + return ret; +} + +struct pci_ops sh7786_pci_ops = { + .read = sh7786_pcie_read, + .write = sh7786_pcie_write, +}; diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c deleted file mode 100644 index 53dd893d4e5..00000000000 --- a/arch/sh/drivers/pci/ops-snapgear.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * arch/sh/drivers/pci/ops-snapgear.c - * - * Author: David McCullough <davidm@snapgear.com> - * - * Ported to new API by Paul Mundt <lethal@linux-sh.org> - * - * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * PCI initialization for the SnapGear boards - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include "pci-sh4.h" - -#define SNAPGEAR_PCI_IO 0x4000 -#define SNAPGEAR_PCI_MEM 0xfd000000 - -/* PCI: default LOCAL memory window sizes (seen from PCI bus) */ -#define SNAPGEAR_LSR0_SIZE (64*(1<<20)) //64MB -#define SNAPGEAR_LSR1_SIZE (64*(1<<20)) //64MB - -static struct resource sh7751_io_resource = { - .name = "SH7751 IO", - .start = SNAPGEAR_PCI_IO, - .end = SNAPGEAR_PCI_IO + (64*1024) - 1, /* 64KiB I/O */ - .flags = IORESOURCE_IO, -}; - -static struct resource sh7751_mem_resource = { - .name = "SH7751 mem", - .start = SNAPGEAR_PCI_MEM, - .end = SNAPGEAR_PCI_MEM + (64*1024*1024) - 1, /* 64MiB mem */ - .flags = IORESOURCE_MEM, -}; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, - { 0, } -}; - -static struct sh4_pci_address_map sh7751_pci_map = { - .window0 = { - .base = SH7751_CS2_BASE_ADDR, - .size = SNAPGEAR_LSR0_SIZE, - }, - - .window1 = { - .base = SH7751_CS2_BASE_ADDR, - .size = SNAPGEAR_LSR1_SIZE, - }, - - .flags = SH4_PCIC_NO_RESET, -}; - -/* - * Initialize the SnapGear PCI interface - * Setup hardware to be Central Funtion - * Copy the BSR regs to the PCI interface - * Setup PCI windows into local RAM - */ -int __init pcibios_init_platform(void) -{ - return sh7751_pcic_init(&sh7751_pci_map); -} - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - int irq = -1; - - switch (slot) { - case 8: /* the PCI bridge */ break; - case 11: irq = 8; break; /* USB */ - case 12: irq = 11; break; /* PCMCIA */ - case 13: irq = 5; break; /* eth0 */ - case 14: irq = 8; break; /* eth1 */ - case 15: irq = 11; break; /* safenet (unused) */ - } - - printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n", - slot, pin - 1 + 'A', irq); - - return irq; -} - -void __init pcibios_fixup(void) -{ - /* Nothing to fixup .. */ -} diff --git a/arch/sh/drivers/pci/ops-titan.c b/arch/sh/drivers/pci/ops-titan.c deleted file mode 100644 index ac8ee2312cd..00000000000 --- a/arch/sh/drivers/pci/ops-titan.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * arch/sh/drivers/pci/ops-titan.c - * - * Ported to new API by Paul Mundt <lethal@linux-sh.org> - * - * Modified from ops-snapgear.c written by David McCullough - * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * PCI initialization for the Titan boards - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/io.h> -#include <asm/titan.h> -#include "pci-sh4.h" - -static char titan_irq_tab[] __initdata = { - TITAN_IRQ_WAN, - TITAN_IRQ_LAN, - TITAN_IRQ_MPCIA, - TITAN_IRQ_MPCIB, - TITAN_IRQ_USB, -}; - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - int irq = titan_irq_tab[slot]; - - printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n", - slot, pin - 1 + 'A', irq); - - return irq; -} - -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 -}; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, - { NULL, NULL, NULL, 0, 0 }, -}; -EXPORT_SYMBOL(board_pci_channels); - -static struct sh4_pci_address_map sh7751_pci_map = { - .window0 = { - .base = SH7751_CS2_BASE_ADDR, - .size = SH7751_MEM_REGION_SIZE*2, /* cs2 and cs3 */ - }, - - .window1 = { - .base = SH7751_CS2_BASE_ADDR, - .size = SH7751_MEM_REGION_SIZE*2, - }, - - .flags = SH4_PCIC_NO_RESET, -}; - -int __init pcibios_init_platform(void) -{ - return sh7751_pcic_init(&sh7751_pci_map); -} diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c deleted file mode 100644 index ea404704ace..00000000000 --- a/arch/sh/drivers/pci/pci-auto.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * PCI autoconfiguration library - * - * Author: Matt Porter <mporter@mvista.com> - * - * Copyright 2000, 2001 MontaVista Software Inc. - * Copyright 2001 Bradley D. LaRonde <brad@ltc.com> - * Copyright 2003 Paul Mundt <lethal@linux-sh.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/* - * Modified for MIPS by Jun Sun, jsun@mvista.com - * - * . Simplify the interface between pci_auto and the rest: a single function. - * . Assign resources from low address to upper address. - * . change most int to u32. - * - * Further modified to include it as mips generic code, ppopov@mvista.com. - * - * 2001-10-26 Bradley D. LaRonde <brad@ltc.com> - * - Add a top_bus argument to the "early config" functions so that - * they can set a fake parent bus pointer to convince the underlying - * pci ops to use type 1 configuration for sub busses. - * - Set bridge base and limit registers correctly. - * - Align io and memory base properly before and after bridge setup. - * - Don't fall through to pci_setup_bars for bridge. - * - Reformat the debug output to look more like lspci's output. - * - * Cloned for SuperH by M. R. Brown, mrbrown@0xd6.org - * - * 2003-08-05 Paul Mundt <lethal@linux-sh.org> - * - Don't update the BAR values on systems that already have valid addresses - * and don't want these updated for whatever reason, by way of a new config - * option check. However, we still read in the old BAR values so that they - * can still be reported through the debug output. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/pci.h> - -#define DEBUG -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* - * These functions are used early on before PCI scanning is done - * and all of the pci_dev and pci_bus structures have been created. - */ -static struct pci_dev *fake_pci_dev(struct pci_channel *hose, - int top_bus, int busnr, int devfn) -{ - static struct pci_dev dev; - static struct pci_bus bus; - - dev.bus = &bus; - dev.sysdata = hose; - dev.devfn = devfn; - bus.number = busnr; - bus.ops = hose->pci_ops; - - if(busnr != top_bus) - /* Fake a parent bus structure. */ - bus.parent = &bus; - else - bus.parent = NULL; - - return &dev; -} - -#define EARLY_PCI_OP(rw, size, type) \ -int early_##rw##_config_##size(struct pci_channel *hose, \ - int top_bus, int bus, int devfn, int offset, type value) \ -{ \ - return pci_##rw##_config_##size( \ - fake_pci_dev(hose, top_bus, bus, devfn), \ - offset, value); \ -} - -EARLY_PCI_OP(read, byte, u8 *) -EARLY_PCI_OP(read, word, u16 *) -EARLY_PCI_OP(read, dword, u32 *) -EARLY_PCI_OP(write, byte, u8) -EARLY_PCI_OP(write, word, u16) -EARLY_PCI_OP(write, dword, u32) - -static struct resource *io_resource_inuse; -static struct resource *mem_resource_inuse; - -static u32 pciauto_lower_iospc; -static u32 pciauto_upper_iospc; - -static u32 pciauto_lower_memspc; -static u32 pciauto_upper_memspc; - -static void __init -pciauto_setup_bars(struct pci_channel *hose, - int top_bus, - int current_bus, - int pci_devfn, - int bar_limit) -{ - u32 bar_response, bar_size, bar_value; - u32 bar, addr_mask, bar_nr = 0; - u32 * upper_limit; - u32 * lower_limit; - int found_mem64 = 0; - - for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) { - u32 bar_addr; - - /* Read the old BAR value */ - early_read_config_dword(hose, top_bus, - current_bus, - pci_devfn, - bar, - &bar_addr); - - /* Tickle the BAR and get the response */ - early_write_config_dword(hose, top_bus, - current_bus, - pci_devfn, - bar, - 0xffffffff); - - early_read_config_dword(hose, top_bus, - current_bus, - pci_devfn, - bar, - &bar_response); - - /* - * Write the old BAR value back out, only update the BAR - * if we implicitly want resources to be updated, which - * is done by the generic code further down. -- PFM. - */ - early_write_config_dword(hose, top_bus, - current_bus, - pci_devfn, - bar, - bar_addr); - - /* If BAR is not implemented go to the next BAR */ - if (!bar_response) - continue; - - /* - * Workaround for a BAR that doesn't use its upper word, - * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457). - * bdl <brad@ltc.com> - */ - if (!(bar_response & 0xffff0000)) - bar_response |= 0xffff0000; - -retry: - /* Check the BAR type and set our address mask */ - if (bar_response & PCI_BASE_ADDRESS_SPACE) { - addr_mask = PCI_BASE_ADDRESS_IO_MASK; - upper_limit = &pciauto_upper_iospc; - lower_limit = &pciauto_lower_iospc; - DBG(" I/O"); - } else { - if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64) - found_mem64 = 1; - - addr_mask = PCI_BASE_ADDRESS_MEM_MASK; - upper_limit = &pciauto_upper_memspc; - lower_limit = &pciauto_lower_memspc; - DBG(" Mem"); - } - - - /* Calculate requested size */ - bar_size = ~(bar_response & addr_mask) + 1; - - /* Allocate a base address */ - bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; - - if ((bar_value + bar_size) > *upper_limit) { - if (bar_response & PCI_BASE_ADDRESS_SPACE) { - if (io_resource_inuse->child) { - io_resource_inuse = - io_resource_inuse->child; - pciauto_lower_iospc = - io_resource_inuse->start; - pciauto_upper_iospc = - io_resource_inuse->end + 1; - goto retry; - } - - } else { - if (mem_resource_inuse->child) { - mem_resource_inuse = - mem_resource_inuse->child; - pciauto_lower_memspc = - mem_resource_inuse->start; - pciauto_upper_memspc = - mem_resource_inuse->end + 1; - goto retry; - } - } - DBG(" unavailable -- skipping, value %x size %x\n", - bar_value, bar_size); - continue; - } - - if (bar_value < *lower_limit || (bar_value + bar_size) >= *upper_limit) { - DBG(" unavailable -- skipping, value %x size %x\n", - bar_value, bar_size); - continue; - } - -#ifdef CONFIG_PCI_AUTO_UPDATE_RESOURCES - /* Write it out and update our limit */ - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - bar, bar_value); -#endif - - *lower_limit = bar_value + bar_size; - - /* - * If we are a 64-bit decoder then increment to the - * upper 32 bits of the bar and force it to locate - * in the lower 4GB of memory. - */ - if (found_mem64) { - bar += 4; - early_write_config_dword(hose, top_bus, - current_bus, - pci_devfn, - bar, - 0x00000000); - } - - DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size); - - bar_nr++; - } - -} - -static void __init -pciauto_prescan_setup_bridge(struct pci_channel *hose, - int top_bus, - int current_bus, - int pci_devfn, - int sub_bus) -{ - /* Configure bus number registers */ - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_PRIMARY_BUS, current_bus); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_SECONDARY_BUS, sub_bus + 1); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_SUBORDINATE_BUS, 0xff); - - /* Align memory and I/O to 1MB and 4KB boundaries. */ - pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) - & ~(0x100000 - 1); - pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) - & ~(0x1000 - 1); - - /* Set base (lower limit) of address range behind bridge. */ - early_write_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_MEMORY_BASE, pciauto_lower_memspc >> 16); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8); - early_write_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16); - - /* We don't support prefetchable memory for now, so disable */ - early_write_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_PREF_MEMORY_BASE, 0); - early_write_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_PREF_MEMORY_LIMIT, 0); -} - -static void __init -pciauto_postscan_setup_bridge(struct pci_channel *hose, - int top_bus, - int current_bus, - int pci_devfn, - int sub_bus) -{ - u32 temp; - - /* - * [jsun] we always bump up baselines a little, so that if there - * nothing behind P2P bridge, we don't wind up overlapping IO/MEM - * spaces. - */ - pciauto_lower_memspc += 1; - pciauto_lower_iospc += 1; - - /* Configure bus number registers */ - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_SUBORDINATE_BUS, sub_bus); - - /* Set upper limit of address range behind bridge. */ - early_write_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8); - early_write_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16); - - /* Align memory and I/O to 1MB and 4KB boundaries. */ - pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) - & ~(0x100000 - 1); - pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) - & ~(0x1000 - 1); - - /* Enable memory and I/O accesses, enable bus master */ - early_read_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_COMMAND, &temp); - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY - | PCI_COMMAND_MASTER); -} - -static void __init -pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose, - int top_bus, - int current_bus, - int pci_devfn, - int sub_bus) -{ - /* Configure bus number registers */ - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_PRIMARY_BUS, current_bus); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_SECONDARY_BUS, sub_bus + 1); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_SUBORDINATE_BUS, 0xff); - - /* Align memory and I/O to 4KB and 4 byte boundaries. */ - pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) - & ~(0x1000 - 1); - pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) - & ~(0x4 - 1); - - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc); - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_CB_IO_BASE_0, pciauto_lower_iospc); -} - -static void __init -pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, - int top_bus, - int current_bus, - int pci_devfn, - int sub_bus) -{ - u32 temp; - - /* - * [jsun] we always bump up baselines a little, so that if there - * nothing behind P2P bridge, we don't wind up overlapping IO/MEM - * spaces. - */ - pciauto_lower_memspc += 1; - pciauto_lower_iospc += 1; - - /* - * Configure subordinate bus number. The PCI subsystem - * bus scan will renumber buses (reserving three additional - * for this PCI<->CardBus bridge for the case where a CardBus - * adapter contains a P2P or CB2CB bridge. - */ - - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_SUBORDINATE_BUS, sub_bus); - - /* - * Reserve an additional 4MB for mem space and 16KB for - * I/O space. This should cover any additional space - * requirement of unusual CardBus devices with - * additional bridges that can consume more address space. - * - * Although pcmcia-cs currently will reprogram bridge - * windows, the goal is to add an option to leave them - * alone and use the bridge window ranges as the regions - * that are searched for free resources upon hot-insertion - * of a device. This will allow a PCI<->CardBus bridge - * configured by this routine to happily live behind a - * P2P bridge in a system. - */ - /* Align memory and I/O to 4KB and 4 byte boundaries. */ - pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) - & ~(0x1000 - 1); - pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) - & ~(0x4 - 1); - /* Set up memory and I/O filter limits, assume 32-bit I/O space */ - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1); - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1); - - /* Enable memory and I/O accesses, enable bus master */ - early_read_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_COMMAND, &temp); - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER); -} - -#define PCIAUTO_IDE_MODE_MASK 0x05 - -static int __init -pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) -{ - int sub_bus; - u32 pci_devfn, pci_class, cmdstat, found_multi=0; - unsigned short vid, did; - unsigned char header_type; - int devfn_start = 0; - int devfn_stop = 0xff; - - sub_bus = current_bus; - - if (hose->first_devfn) - devfn_start = hose->first_devfn; - if (hose->last_devfn) - devfn_stop = hose->last_devfn; - - for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) { - - if (PCI_FUNC(pci_devfn) && !found_multi) - continue; - - early_read_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_VENDOR_ID, &vid); - - if (vid == 0xffff) continue; - - early_read_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_HEADER_TYPE, &header_type); - - if (!PCI_FUNC(pci_devfn)) - found_multi = header_type & 0x80; - - early_read_config_word(hose, top_bus, current_bus, pci_devfn, - PCI_DEVICE_ID, &did); - - early_read_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_CLASS_REVISION, &pci_class); - - DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x", - current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn), - pci_class >> 16, vid, did); - if (pci_class & 0xff) - DBG(" (rev %.2x)", pci_class & 0xff); - DBG("\n"); - - if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { - DBG(" Bridge: primary=%.2x, secondary=%.2x\n", - current_bus, sub_bus + 1); - pciauto_prescan_setup_bridge(hose, top_bus, current_bus, - pci_devfn, sub_bus); - DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", - sub_bus + 1, - pciauto_lower_iospc, pciauto_lower_memspc); - sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); - DBG("Back to bus %.2x\n", current_bus); - pciauto_postscan_setup_bridge(hose, top_bus, current_bus, - pci_devfn, sub_bus); - continue; - } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) { - DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n", - current_bus, sub_bus + 1); - DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn)); - /* Place CardBus Socket/ExCA registers */ - pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0); - - pciauto_prescan_setup_cardbus_bridge(hose, top_bus, - current_bus, pci_devfn, sub_bus); - - DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", - sub_bus + 1, - pciauto_lower_iospc, pciauto_lower_memspc); - sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); - DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus); - pciauto_postscan_setup_cardbus_bridge(hose, top_bus, - current_bus, pci_devfn, sub_bus); - continue; - } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { - - unsigned char prg_iface; - - early_read_config_byte(hose, top_bus, current_bus, - pci_devfn, PCI_CLASS_PROG, &prg_iface); - if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { - DBG("Skipping legacy mode IDE controller\n"); - continue; - } - } - - /* - * Found a peripheral, enable some standard - * settings - */ - early_read_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_COMMAND, &cmdstat); - early_write_config_dword(hose, top_bus, current_bus, pci_devfn, - PCI_COMMAND, cmdstat | PCI_COMMAND_IO | - PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER); - early_write_config_byte(hose, top_bus, current_bus, pci_devfn, - PCI_LATENCY_TIMER, 0x80); - - /* Allocate PCI I/O and/or memory space */ - pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5); - } - return sub_bus; -} - -int __init -pciauto_assign_resources(int busno, struct pci_channel *hose) -{ - /* setup resource limits */ - io_resource_inuse = hose->io_resource; - mem_resource_inuse = hose->mem_resource; - - pciauto_lower_iospc = io_resource_inuse->start; - pciauto_upper_iospc = io_resource_inuse->end + 1; - pciauto_lower_memspc = mem_resource_inuse->start; - pciauto_upper_memspc = mem_resource_inuse->end + 1; - DBG("Autoconfig PCI channel 0x%p\n", hose); - DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n", - busno, pciauto_lower_iospc, pciauto_upper_iospc, - pciauto_lower_memspc, pciauto_upper_memspc); - - return pciauto_bus_scan(hose, busno, busno); -} diff --git a/arch/sh/drivers/pci/pci-dreamcast.c b/arch/sh/drivers/pci/pci-dreamcast.c new file mode 100644 index 00000000000..633694193af --- /dev/null +++ b/arch/sh/drivers/pci/pci-dreamcast.c @@ -0,0 +1,100 @@ +/* + * PCI support for the Sega Dreamcast + * + * Copyright (C) 2001, 2002 M. R. Brown + * Copyright (C) 2002, 2003 Paul Mundt + * + * This file originally bore the message (with enclosed-$): + * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp + * Dreamcast PCI: Supports SEGA Broadband Adaptor only. + * + * 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. + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/pci.h> +#include <linux/module.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <mach/pci.h> + +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, + .resources = gapspci_resources, + .nr_resources = ARRAY_SIZE(gapspci_resources), + .io_offset = 0x00000000, + .mem_offset = 0x00000000, +}; + +/* + * gapspci init + */ + +static int __init gapspci_init(void) +{ + char idbuf[16]; + int i; + + /* + * FIXME: All of this wants documenting to some degree, + * even some basic register definitions would be nice. + * + * I haven't seen anything this ugly since.. maple. + */ + + for (i=0; i<16; i++) + idbuf[i] = inb(GAPSPCI_REGS+i); + + if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16)) + return -ENODEV; + + outl(0x5a14a501, GAPSPCI_REGS+0x18); + + for (i=0; i<1000000; i++) + cpu_relax(); + + if (inl(GAPSPCI_REGS+0x18) != 1) + return -EINVAL; + + outl(0x01000000, GAPSPCI_REGS+0x20); + outl(0x01000000, GAPSPCI_REGS+0x24); + + outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); + outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); + + outl(1, GAPSPCI_REGS+0x14); + outl(1, GAPSPCI_REGS+0x34); + + /* Setting Broadband Adapter */ + outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); + outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); + outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); + outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); + outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); + outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); + outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); + + return register_pci_controller(&dreamcast_pci_controller); +} +arch_initcall(gapspci_init); diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h index 07e29506080..cbf763b3015 100644 --- a/arch/sh/drivers/pci/pci-sh4.h +++ b/arch/sh/drivers/pci/pci-sh4.h @@ -15,8 +15,6 @@ #define PCI_PROBE_BIOS 1 #define PCI_PROBE_CONF1 2 #define PCI_PROBE_CONF2 4 -#define PCI_NO_SORT 0x100 -#define PCI_BIOS_SORT 0x200 #define PCI_NO_CHECKS 0x400 #define PCI_ASSIGN_ROMS 0x1000 #define PCI_BIOS_IRQ_SCAN 0x2000 @@ -51,6 +49,17 @@ #define SH4_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */ #define SH4_PCIINT_MRPD 0x00000001 /* Master Read PERR Detect */ #define SH4_PCIINTM 0x118 /* PCI Interrupt Mask */ + #define SH4_PCIINTM_TTADIM BIT(14) /* Target-target abort interrupt */ + #define SH4_PCIINTM_TMTOIM BIT(9) /* Target retry timeout */ + #define SH4_PCIINTM_MDEIM BIT(8) /* Master function disable error */ + #define SH4_PCIINTM_APEDIM BIT(7) /* Address parity error detection */ + #define SH4_PCIINTM_SDIM BIT(6) /* SERR detection */ + #define SH4_PCIINTM_DPEITWM BIT(5) /* Data parity error for target write */ + #define SH4_PCIINTM_PEDITRM BIT(4) /* PERR detection for target read */ + #define SH4_PCIINTM_TADIMM BIT(3) /* Target abort for master */ + #define SH4_PCIINTM_MADIMM BIT(2) /* Master abort for master */ + #define SH4_PCIINTM_MWPDIM BIT(1) /* Master write data parity error */ + #define SH4_PCIINTM_MRDPEIM BIT(0) /* Master read data parity error */ #define SH4_PCIALR 0x11C /* Error Address Register */ #define SH4_PCICLR 0x120 /* Error Command/Data */ #define SH4_PCICLR_MPIO 0x80000000 @@ -63,7 +72,7 @@ #define SH4_PCIAINT 0x130 /* Arbiter Interrupt Register */ #define SH4_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */ #define SH4_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */ - #define SH4_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */ + #define SH4_PCIAINT_MBTO 0x00000800 /* Master Bus Time Out */ #define SH4_PCIAINT_TABT 0x00000008 /* Target Abort */ #define SH4_PCIAINT_MABT 0x00000004 /* Master Abort */ #define SH4_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */ @@ -151,13 +160,9 @@ #define SH4_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */ #define SH4_PCIPDR 0x220 /* Port IO Data Register */ -/* Flags */ -#define SH4_PCIC_NO_RESET 0x0001 - /* arch/sh/kernel/drivers/pci/ops-sh4.c */ extern struct pci_ops sh4_pci_ops; -int sh4_pci_check_direct(void); -int pci_fixup_pcic(void); +int pci_fixup_pcic(struct pci_channel *chan); struct sh4_pci_address_space { unsigned long base; @@ -167,16 +172,18 @@ struct sh4_pci_address_space { struct sh4_pci_address_map { struct sh4_pci_address_space window0; struct sh4_pci_address_space window1; - unsigned long flags; }; -static inline void pci_write_reg(unsigned long val, unsigned long reg) +static inline void pci_write_reg(struct pci_channel *chan, + unsigned long val, unsigned long reg) { - ctrl_outl(val, PCI_REG(reg)); + __raw_writel(val, chan->reg_base + reg); } -static inline unsigned long pci_read_reg(unsigned long reg) +static inline unsigned long pci_read_reg(struct pci_channel *chan, + unsigned long reg) { - return ctrl_inl(PCI_REG(reg)); + return __raw_readl(chan->reg_base + reg); } + #endif /* __PCI_SH4_H */ diff --git a/arch/sh/drivers/pci/pci-sh5.c b/arch/sh/drivers/pci/pci-sh5.c index a00a4df8c02..16c1e721bf5 100644 --- a/arch/sh/drivers/pci/pci-sh5.c +++ b/arch/sh/drivers/pci/pci-sh5.c @@ -19,7 +19,7 @@ #include <linux/delay.h> #include <linux/types.h> #include <linux/irq.h> -#include <asm/cpu/irq.h> +#include <cpu/irq.h> #include <asm/pci.h> #include <asm/io.h> #include "pci-sh5.h" @@ -89,29 +89,41 @@ static irqreturn_t pcish5_serr_irq(int irq, void *dev_id) return IRQ_NONE; } -int __init sh5pci_init(unsigned long memStart, unsigned long memSize) +static struct resource sh5_pci_resources[2]; + +static struct pci_channel sh5pci_controller = { + .pci_ops = &sh5_pci_ops, + .resources = sh5_pci_resources, + .nr_resources = ARRAY_SIZE(sh5_pci_resources), + .mem_offset = 0x00000000, + .io_offset = 0x00000000, +}; + +static int __init sh5pci_init(void) { + unsigned long memStart = __pa(memory_start); + unsigned long memSize = __pa(memory_end) - memStart; u32 lsr0; u32 uval; if (request_irq(IRQ_ERR, pcish5_err_irq, - IRQF_DISABLED, "PCI Error",NULL) < 0) { + 0, "PCI Error",NULL) < 0) { printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n"); return -EINVAL; } if (request_irq(IRQ_SERR, pcish5_serr_irq, - IRQF_DISABLED, "PCI SERR interrupt", NULL) < 0) { + 0, "PCI SERR interrupt", NULL) < 0) { printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n"); return -EINVAL; } - pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR"); + pcicr_virt = (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE, 1024); if (!pcicr_virt) { panic("Unable to remap PCICR\n"); } - PCI_IO_AREA = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO"); + PCI_IO_AREA = (unsigned long)ioremap_nocache(SH5PCI_IO_BASE, 0x10000); if (!PCI_IO_AREA) { panic("Unable to remap PCIIO\n"); } @@ -197,32 +209,12 @@ int __init sh5pci_init(unsigned long memStart, unsigned long memSize) SH5PCI_WRITE(AINTM, ~0); SH5PCI_WRITE(PINTM, ~0); - return 0; -} + sh5_pci_resources[0].start = PCI_IO_AREA; + sh5_pci_resources[0].end = PCI_IO_AREA + 0x10000; -void __devinit pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_dev *dev = bus->self; - int i; - - if (dev) { - for (i= 0; i < 3; i++) { - bus->resource[i] = - &dev->resource[PCI_BRIDGE_RESOURCES+i]; - bus->resource[i]->name = bus->name; - } - bus->resource[0]->flags |= IORESOURCE_IO; - bus->resource[1]->flags |= IORESOURCE_MEM; - - /* For now, propagate host limits to the bus; - * we'll adjust them later. */ - bus->resource[0]->end = 64*1024 - 1 ; - bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1; - bus->resource[0]->start = PCIBIOS_MIN_IO; - bus->resource[1]->start = PCIBIOS_MIN_MEM; - - /* Turn off downstream PF memory address range by default */ - bus->resource[2]->start = 1024*1024; - bus->resource[2]->end = bus->resource[2]->start - 1; - } + sh5_pci_resources[1].start = memStart; + sh5_pci_resources[1].end = memStart + memSize; + + return register_pci_controller(&sh5pci_controller); } +arch_initcall(sh5pci_init); diff --git a/arch/sh/drivers/pci/pci-sh5.h b/arch/sh/drivers/pci/pci-sh5.h index 7cff3fc04d3..3f01decb430 100644 --- a/arch/sh/drivers/pci/pci-sh5.h +++ b/arch/sh/drivers/pci/pci-sh5.h @@ -86,14 +86,14 @@ extern unsigned long pcicr_virt; /* #define PCISH5_VCR_REG(x) ( SH5PCI_VCR_BASE (PCISH5_VCR_##x)) */ /* Write I/O functions */ -#define SH5PCI_WRITE(reg,val) ctrl_outl((u32)(val),PCISH5_ICR_REG(reg)) -#define SH5PCI_WRITE_SHORT(reg,val) ctrl_outw((u16)(val),PCISH5_ICR_REG(reg)) -#define SH5PCI_WRITE_BYTE(reg,val) ctrl_outb((u8)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE(reg,val) __raw_writel((u32)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE_SHORT(reg,val) __raw_writew((u16)(val),PCISH5_ICR_REG(reg)) +#define SH5PCI_WRITE_BYTE(reg,val) __raw_writeb((u8)(val),PCISH5_ICR_REG(reg)) /* Read I/O functions */ -#define SH5PCI_READ(reg) ctrl_inl(PCISH5_ICR_REG(reg)) -#define SH5PCI_READ_SHORT(reg) ctrl_inw(PCISH5_ICR_REG(reg)) -#define SH5PCI_READ_BYTE(reg) ctrl_inb(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ(reg) __raw_readl(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ_SHORT(reg) __raw_readw(PCISH5_ICR_REG(reg)) +#define SH5PCI_READ_BYTE(reg) __raw_readb(PCISH5_ICR_REG(reg)) /* Set PCI config bits */ #define SET_CONFIG_BITS(bus,devfn,where) ((((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | 0x80000000) @@ -107,7 +107,4 @@ extern unsigned long pcicr_virt; extern struct pci_ops sh5_pci_ops; -/* arch/sh/drivers/pci/pci-sh5.c */ -int sh5pci_init(unsigned long memStart, unsigned long memSize); - #endif /* __PCI_SH5_H */ diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 3065eb184f0..86adb1e235c 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -1,114 +1,108 @@ /* - * Low-Level PCI Support for the SH7751 + * Low-Level PCI Support for the SH7751 * - * Dustin McIntire (dustin@sensoria.com) - * Derived from arch/i386/kernel/pci-*.c which bore the message: - * (c) 1999--2000 Martin Mares <mj@ucw.cz> + * Copyright (C) 2003 - 2009 Paul Mundt + * Copyright (C) 2001 Dustin McIntire * - * Ported to the new API by Paul Mundt <lethal@linux-sh.org> - * With cleanup by Paul van Gool <pvangool@mimotech.com> - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. + * With cleanup by Paul van Gool <pvangool@mimotech.com>, 2003. * + * 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. */ -#undef DEBUG - #include <linux/init.h> #include <linux/pci.h> #include <linux/types.h> #include <linux/errno.h> -#include <linux/delay.h> +#include <linux/io.h> #include "pci-sh4.h" #include <asm/addrspace.h> -#include <asm/io.h> - -/* - * Initialization. Try all known PCI access methods. Note that we support - * using both PCI BIOS and direct access: in such cases, we use I/O ports - * to access config space. - * - * Note that the platform specific initialization (BSC registers, and memory - * space mapping) will be called via the platform defined function - * pcibios_init_platform(). - */ -static int __init sh7751_pci_init(void) -{ - unsigned int id; - int ret; - - pr_debug("PCI: Starting intialization.\n"); - - /* check for SH7751/SH7751R hardware */ - id = pci_read_reg(SH7751_PCICONF0); - if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) && - id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) { - pr_debug("PCI: This is not an SH7751(R) (%x)\n", id); - return -ENODEV; - } - - if ((ret = sh4_pci_check_direct()) != 0) - return ret; - - return pcibios_init_platform(); -} -subsys_initcall(sh7751_pci_init); +#include <asm/sizes.h> -static int __init __area_sdram_check(unsigned int area) +static int __init __area_sdram_check(struct pci_channel *chan, + unsigned int area) { - u32 word; + unsigned long word; - word = ctrl_inl(SH7751_BCR1); + word = __raw_readl(SH7751_BCR1); /* check BCR for SDRAM in area */ if (((word >> area) & 1) == 0) { - printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", + printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%lx\n", area, word); return 0; } - pci_write_reg(word, SH4_PCIBCR1); + pci_write_reg(chan, word, SH4_PCIBCR1); - word = (u16)ctrl_inw(SH7751_BCR2); + word = __raw_readw(SH7751_BCR2); /* check BCR2 for 32bit SDRAM interface*/ if (((word >> (area << 1)) & 0x3) != 0x3) { - printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", + printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%lx\n", area, word); return 0; } - pci_write_reg(word, SH4_PCIBCR2); + pci_write_reg(chan, word, SH4_PCIBCR2); return 1; } -int __init sh7751_pcic_init(struct sh4_pci_address_map *map) +static struct resource sh7751_pci_resources[] = { + { + .name = "SH7751_IO", + .start = 0x1000, + .end = SZ_4M - 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, + .resources = sh7751_pci_resources, + .nr_resources = ARRAY_SIZE(sh7751_pci_resources), + .mem_offset = 0x00000000, + .io_offset = 0x00000000, + .io_map_base = SH7751_PCI_IO_BASE, +}; + +static struct sh4_pci_address_map sh7751_pci_map = { + .window0 = { + .base = SH7751_CS3_BASE_ADDR, + .size = 0x04000000, + }, +}; + +static int __init sh7751_pci_init(void) { - u32 reg; - u32 word; + struct pci_channel *chan = &sh7751_pci_controller; + unsigned int id; + u32 word, reg; + + printk(KERN_NOTICE "PCI: Starting initialization.\n"); + + chan->reg_base = 0xfe200000; + + /* check for SH7751/SH7751R hardware */ + id = pci_read_reg(chan, SH7751_PCICONF0); + if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) && + id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) { + pr_debug("PCI: This is not an SH7751(R) (%x)\n", id); + return -ENODEV; + } /* Set the BCR's to enable PCI access */ - reg = ctrl_inl(SH7751_BCR1); + reg = __raw_readl(SH7751_BCR1); reg |= 0x80000; - ctrl_outl(reg, SH7751_BCR1); + __raw_writel(reg, SH7751_BCR1); /* Turn the clocks back on (not done in reset)*/ - pci_write_reg(0, SH4_PCICLKR); + pci_write_reg(chan, 0, SH4_PCICLKR); /* Clear Powerdown IRQ's (not done in reset) */ word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0; - pci_write_reg(word, SH4_PCIPINT); - - /* - * This code is unused for some boards as it is done in the - * bootloader and doing it here means the MAC addresses loaded - * by the bootloader get lost. - */ - if (!(map->flags & SH4_PCIC_NO_RESET)) { - /* toggle PCI reset pin */ - word = SH4_PCICR_PREFIX | SH4_PCICR_PRST; - pci_write_reg(word, SH4_PCICR); - /* Wait for a long time... not 1 sec. but long enough */ - mdelay(100); - word = SH4_PCICR_PREFIX; - pci_write_reg(word, SH4_PCICR); - } + pci_write_reg(chan, word, SH4_PCIPINT); /* set the command/status bits to: * Wait Cycle Control + Parity Enable + Bus Master + @@ -116,89 +110,73 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) */ word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; - pci_write_reg(word, SH7751_PCICONF1); + pci_write_reg(chan, word, SH7751_PCICONF1); /* define this host as the host bridge */ word = PCI_BASE_CLASS_BRIDGE << 24; - pci_write_reg(word, SH7751_PCICONF2); + pci_write_reg(chan, word, SH7751_PCICONF2); /* Set IO and Mem windows to local address * Make PCI and local address the same for easy 1 to 1 mapping - * Window0 = map->window0.size @ non-cached area base = SDRAM - * Window1 = map->window1.size @ cached area base = SDRAM */ - word = map->window0.size - 1; - pci_write_reg(word, SH4_PCILSR0); - word = map->window1.size - 1; - pci_write_reg(word, SH4_PCILSR1); + word = sh7751_pci_map.window0.size - 1; + pci_write_reg(chan, word, SH4_PCILSR0); /* Set the values on window 0 PCI config registers */ - word = P2SEGADDR(map->window0.base); - pci_write_reg(word, SH4_PCILAR0); - pci_write_reg(word, SH7751_PCICONF5); - /* Set the values on window 1 PCI config registers */ - word = PHYSADDR(map->window1.base); - pci_write_reg(word, SH4_PCILAR1); - pci_write_reg(word, SH7751_PCICONF6); + word = P2SEGADDR(sh7751_pci_map.window0.base); + pci_write_reg(chan, word, SH4_PCILAR0); + pci_write_reg(chan, word, SH7751_PCICONF5); /* Set the local 16MB PCI memory space window to * the lowest PCI mapped address */ - word = PCIBIOS_MIN_MEM & 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(word , SH4_PCIMBR); - - /* Map IO space into PCI IO window - * The IO window is 64K-PCIBIOS_MIN_IO in size - * IO addresses will be translated to the - * PCI IO window base address - */ - pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", - PCIBIOS_MIN_IO, (64 << 10), - SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO); + pci_write_reg(chan, word , SH4_PCIMBR); /* Make sure the MSB's of IO window are set to access PCI space * correctly */ - word = PCIBIOS_MIN_IO & 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(word, SH4_PCIIOBR); + pci_write_reg(chan, word, SH4_PCIIOBR); /* Set PCI WCRx, BCRx's, copy from BSC locations */ /* check BCR for SDRAM in specified area */ - switch (map->window0.base) { - case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(0); break; - case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(1); break; - case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(2); break; - case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(3); break; - case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(4); break; - case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break; - case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break; + switch (sh7751_pci_map.window0.base) { + case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(chan, 0); break; + case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(chan, 1); break; + case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(chan, 2); break; + case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(chan, 3); break; + case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(chan, 4); break; + case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(chan, 5); break; + case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(chan, 6); break; } if (!word) - return 0; + return -1; /* configure the wait control registers */ - word = ctrl_inl(SH7751_WCR1); - pci_write_reg(word, SH4_PCIWCR1); - word = ctrl_inl(SH7751_WCR2); - pci_write_reg(word, SH4_PCIWCR2); - word = ctrl_inl(SH7751_WCR3); - pci_write_reg(word, SH4_PCIWCR3); - word = ctrl_inl(SH7751_MCR); - pci_write_reg(word, SH4_PCIMCR); + word = __raw_readl(SH7751_WCR1); + pci_write_reg(chan, word, SH4_PCIWCR1); + word = __raw_readl(SH7751_WCR2); + pci_write_reg(chan, word, SH4_PCIWCR2); + word = __raw_readl(SH7751_WCR3); + pci_write_reg(chan, word, SH4_PCIWCR3); + word = __raw_readl(SH7751_MCR); + pci_write_reg(chan, word, SH4_PCIMCR); /* NOTE: I'm ignoring the PCI error IRQs for now.. * TODO: add support for the internal error interrupts and * DMA interrupts... */ - pci_fixup_pcic(); + pci_fixup_pcic(chan); /* SH7751 init done, set central function init complete */ /* use round robin mode to stop a device starving/overruning */ word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM; - pci_write_reg(word, SH4_PCICR); + pci_write_reg(chan, word, SH4_PCICR); - return 1; + return register_pci_controller(chan); } +arch_initcall(sh7751_pci_init); diff --git a/arch/sh/drivers/pci/pci-sh7751.h b/arch/sh/drivers/pci/pci-sh7751.h index 68e3cb5e6be..5ede38c330d 100644 --- a/arch/sh/drivers/pci/pci-sh7751.h +++ b/arch/sh/drivers/pci/pci-sh7751.h @@ -26,7 +26,6 @@ #define SH7751_PCI_IO_SIZE 0x40000 /* Size of IO window */ #define SH7751_PCIREG_BASE 0xFE200000 /* PCI regs base address */ -#define PCI_REG(n) (SH7751_PCIREG_BASE+ n) #define SH7751_PCICONF0 0x0 /* PCI Config Reg 0 */ #define SH7751_PCICONF0_DEVID 0xFFFF0000 /* Device ID */ @@ -58,11 +57,11 @@ #define SH7751_PCICONF2_SCC 0x00FF0000 /* Sub-Class Code */ #define SH7751_PCICONF2_RLPI 0x0000FF00 /* Programming Interface */ #define SH7751_PCICONF2_REV 0x000000FF /* Revision ID */ -#define SH7751_PCICONF3 0xC /* PCI Config Reg 3 */ +#define SH7751_PCICONF3 0xC /* PCI Config Reg 3 */ #define SH7751_PCICONF3_BIST7 0x80000000 /* Bist Supported */ #define SH7751_PCICONF3_BIST6 0x40000000 /* Bist Executing */ #define SH7751_PCICONF3_BIST3_0 0x0F000000 /* Bist Passed */ - #define SH7751_PCICONF3_HD7 0x00800000 /* Single Funtion device */ + #define SH7751_PCICONF3_HD7 0x00800000 /* Single Function device */ #define SH7751_PCICONF3_HD6_0 0x007F0000 /* Configuration Layout */ #define SH7751_PCICONF3_LAT 0x0000FF00 /* Latency Timer */ #define SH7751_PCICONF3_CLS 0x000000FF /* Cache Line Size */ @@ -73,12 +72,12 @@ #define SH7751_PCICONF5_BASE 0xFFFFFFF0 /* Mem Space Base Addr */ #define SH7751_PCICONF5_LAP 0x00000008 /* Prefetch Enabled */ #define SH7751_PCICONF5_LAT 0x00000006 /* Local Memory type */ - #define SH7751_PCICONF5_ASI 0x00000001 /* Address Space Type */ + #define SH7751_PCICONF5_ASI 0x00000001 /* Address Space Type */ #define SH7751_PCICONF6 0x18 /* PCI Config Reg 6 */ #define SH7751_PCICONF6_BASE 0xFFFFFFF0 /* Mem Space Base Addr */ #define SH7751_PCICONF6_LAP 0x00000008 /* Prefetch Enabled */ #define SH7751_PCICONF6_LAT 0x00000006 /* Local Memory type */ - #define SH7751_PCICONF6_ASI 0x00000001 /* Address Space Type */ + #define SH7751_PCICONF6_ASI 0x00000001 /* Address Space Type */ /* PCICONF7 - PCICONF10 are undefined */ #define SH7751_PCICONF11 0x2C /* PCI Config Reg 11 */ #define SH7751_PCICONF11_SSID 0xFFFF0000 /* Subsystem ID */ @@ -127,9 +126,4 @@ #define SH7751_CS5_BASE_ADDR (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE) #define SH7751_CS6_BASE_ADDR (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE) -struct sh4_pci_address_map; - -/* arch/sh/drivers/pci/pci-sh7751.c */ -int sh7751_pcic_init(struct sh4_pci_address_map *map); - #endif /* _PCI_SH7751_H_ */ diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index b2a2bfa3c1b..5a6dab6e27d 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -1,162 +1,411 @@ /* - * Low-Level PCI Support for the SH7780 + * Low-Level PCI Support for the SH7780 * - * Dustin McIntire (dustin@sensoria.com) - * Derived from arch/i386/kernel/pci-*.c which bore the message: - * (c) 1999--2000 Martin Mares <mj@ucw.cz> - * - * Ported to the new API by Paul Mundt <lethal@linux-sh.org> - * With cleanup by Paul van Gool <pvangool@mimotech.com> - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. + * Copyright (C) 2005 - 2010 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. */ -#undef DEBUG - #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <linux/irq.h> #include <linux/errno.h> #include <linux/delay.h> +#include <linux/log2.h> #include "pci-sh4.h" +#include <asm/mmu.h> +#include <asm/sizes.h> -#define INTC_BASE 0xffd00000 -#define INTC_ICR0 (INTC_BASE+0x0) -#define INTC_ICR1 (INTC_BASE+0x1c) -#define INTC_INTPRI (INTC_BASE+0x10) -#define INTC_INTREQ (INTC_BASE+0x24) -#define INTC_INTMSK0 (INTC_BASE+0x44) -#define INTC_INTMSK1 (INTC_BASE+0x48) -#define INTC_INTMSK2 (INTC_BASE+0x40080) -#define INTC_INTMSKCLR0 (INTC_BASE+0x64) -#define INTC_INTMSKCLR1 (INTC_BASE+0x68) -#define INTC_INTMSKCLR2 (INTC_BASE+0x40084) -#define INTC_INT2MSKR (INTC_BASE+0x40038) -#define INTC_INT2MSKCR (INTC_BASE+0x4003c) +#if defined(CONFIG_CPU_BIG_ENDIAN) +# define PCICR_ENDIANNESS SH4_PCICR_BSWP +#else +# define PCICR_ENDIANNESS 0 +#endif -/* - * Initialization. Try all known PCI access methods. Note that we support - * using both PCI BIOS and direct access: in such cases, we use I/O ports - * to access config space. - * - * Note that the platform specific initialization (BSC registers, and memory - * space mapping) will be called via the platform defined function - * pcibios_init_platform(). - */ -static int __init sh7780_pci_init(void) + +static struct resource sh7785_pci_resources[] = { + { + .name = "PCI 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, + .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), +}; + +struct pci_errors { + unsigned int mask; + const char *str; +} pci_arbiter_errors[] = { + { SH4_PCIAINT_MBKN, "master broken" }, + { SH4_PCIAINT_TBTO, "target bus time out" }, + { SH4_PCIAINT_MBTO, "master bus time out" }, + { SH4_PCIAINT_TABT, "target abort" }, + { SH4_PCIAINT_MABT, "master abort" }, + { SH4_PCIAINT_RDPE, "read data parity error" }, + { SH4_PCIAINT_WDPE, "write data parity error" }, +}, pci_interrupt_errors[] = { + { SH4_PCIINT_MLCK, "master lock error" }, + { SH4_PCIINT_TABT, "target-target abort" }, + { SH4_PCIINT_TRET, "target retry time out" }, + { SH4_PCIINT_MFDE, "master function disable error" }, + { SH4_PCIINT_PRTY, "address parity error" }, + { SH4_PCIINT_SERR, "SERR" }, + { SH4_PCIINT_TWDP, "data parity error for target write" }, + { SH4_PCIINT_TRDP, "PERR detected for target read" }, + { SH4_PCIINT_MTABT, "target abort for master" }, + { SH4_PCIINT_MMABT, "master abort for master" }, + { SH4_PCIINT_MWPD, "master write data parity error" }, + { SH4_PCIINT_MRPD, "master read data parity error" }, +}; + +static irqreturn_t sh7780_pci_err_irq(int irq, void *dev_id) { - unsigned int id; - int ret, match = 0; - - pr_debug("PCI: Starting intialization.\n"); - - ctrl_outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ - - /* check for SH7780/SH7780R hardware */ - id = pci_read_reg(SH7780_PCIVID); - if ((id & 0xffff) == SH7780_VENDOR_ID) { - switch ((id >> 16) & 0xffff) { - case SH7763_DEVICE_ID: - case SH7780_DEVICE_ID: - case SH7781_DEVICE_ID: - case SH7785_DEVICE_ID: - match = 1; - break; + struct pci_channel *hose = dev_id; + unsigned long addr; + unsigned int status; + unsigned int cmd; + int i; + + addr = __raw_readl(hose->reg_base + SH4_PCIALR); + + /* + * Handle status errors. + */ + status = __raw_readw(hose->reg_base + PCI_STATUS); + if (status & (PCI_STATUS_PARITY | + PCI_STATUS_DETECTED_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT)) { + cmd = pcibios_handle_status_errors(addr, status, hose); + if (likely(cmd)) + __raw_writew(cmd, hose->reg_base + PCI_STATUS); + } + + /* + * Handle arbiter errors. + */ + status = __raw_readl(hose->reg_base + SH4_PCIAINT); + for (i = cmd = 0; i < ARRAY_SIZE(pci_arbiter_errors); i++) { + if (status & pci_arbiter_errors[i].mask) { + printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", + pci_arbiter_errors[i].str, addr); + cmd |= pci_arbiter_errors[i].mask; } } + __raw_writel(cmd, hose->reg_base + SH4_PCIAINT); - if (unlikely(!match)) { - printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); - return -ENODEV; + /* + * Handle the remaining PCI errors. + */ + status = __raw_readl(hose->reg_base + SH4_PCIINT); + for (i = cmd = 0; i < ARRAY_SIZE(pci_interrupt_errors); i++) { + if (status & pci_interrupt_errors[i].mask) { + printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", + pci_interrupt_errors[i].str, addr); + cmd |= pci_interrupt_errors[i].mask; + } } + __raw_writel(cmd, hose->reg_base + SH4_PCIINT); + + return IRQ_HANDLED; +} + +static irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id) +{ + struct pci_channel *hose = dev_id; + + printk(KERN_DEBUG "PCI: system error received: "); + pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); + printk("\n"); + + /* Deassert SERR */ + __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM); + + /* Back off the IRQ for awhile */ + disable_irq_nosync(irq); + hose->serr_timer.expires = jiffies + HZ; + add_timer(&hose->serr_timer); + + return IRQ_HANDLED; +} + +static int __init sh7780_pci_setup_irqs(struct pci_channel *hose) +{ + int ret; - /* Setup the INTC */ - if (mach_is_7780se()) { - /* ICR0: IRL=use separately */ - ctrl_outl(0x00C00020, INTC_ICR0); - /* ICR1: detect low level(for 2ndcut) */ - ctrl_outl(0xAAAA0000, INTC_ICR1); - /* INTPRI: priority=3(all) */ - ctrl_outl(0x33333333, INTC_INTPRI); + /* Clear out PCI arbiter IRQs */ + __raw_writel(0, hose->reg_base + SH4_PCIAINT); + + /* Clear all error conditions */ + __raw_writew(PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_SIG_SYSTEM_ERROR | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_SIG_TARGET_ABORT | \ + PCI_STATUS_PARITY, hose->reg_base + PCI_STATUS); + + ret = request_irq(hose->serr_irq, sh7780_pci_serr_irq, 0, + "PCI SERR interrupt", hose); + if (unlikely(ret)) { + printk(KERN_ERR "PCI: Failed hooking SERR IRQ\n"); + return ret; } - if ((ret = sh4_pci_check_direct()) != 0) + /* + * The PCI ERR IRQ needs to be IRQF_SHARED since all of the power + * down IRQ vectors are routed through the ERR IRQ vector. We + * only request_irq() once as there is only a single masking + * source for multiple events. + */ + ret = request_irq(hose->err_irq, sh7780_pci_err_irq, IRQF_SHARED, + "PCI ERR interrupt", hose); + if (unlikely(ret)) { + free_irq(hose->serr_irq, hose); return ret; + } + + /* Unmask all of the arbiter IRQs. */ + __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \ + SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \ + SH4_PCIAINT_WDPE, hose->reg_base + SH4_PCIAINTM); + + /* Unmask all of the PCI IRQs */ + __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \ + SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \ + SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \ + SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \ + SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \ + SH4_PCIINTM_MRDPEIM, hose->reg_base + SH4_PCIINTM); + + return ret; +} + +static inline void __init sh7780_pci_teardown_irqs(struct pci_channel *hose) +{ + free_irq(hose->err_irq, hose); + free_irq(hose->serr_irq, hose); +} + +static void __init sh7780_pci66_init(struct pci_channel *hose) +{ + unsigned int tmp; + + if (!pci_is_66mhz_capable(hose, 0, 0)) + return; + + /* Enable register access */ + tmp = __raw_readl(hose->reg_base + SH4_PCICR); + tmp |= SH4_PCICR_PREFIX; + __raw_writel(tmp, hose->reg_base + SH4_PCICR); - return pcibios_init_platform(); + /* Enable 66MHz operation */ + tmp = __raw_readw(hose->reg_base + PCI_STATUS); + tmp |= PCI_STATUS_66MHZ; + __raw_writew(tmp, hose->reg_base + PCI_STATUS); + + /* Done */ + tmp = __raw_readl(hose->reg_base + SH4_PCICR); + tmp |= SH4_PCICR_PREFIX | SH4_PCICR_CFIN; + __raw_writel(tmp, hose->reg_base + SH4_PCICR); } -core_initcall(sh7780_pci_init); -int __init sh7780_pcic_init(struct sh4_pci_address_map *map) +static int __init sh7780_pci_init(void) { - u32 word; + struct pci_channel *chan = &sh7780_pci_controller; + phys_addr_t memphys; + size_t memsize; + unsigned int id; + const char *type; + int ret, i; + + printk(KERN_NOTICE "PCI: Starting initialization.\n"); + + chan->reg_base = 0xfe040000; + + /* Enable CPU access to the PCIC registers. */ + __raw_writel(PCIECR_ENBL, PCIECR); + + /* Reset */ + __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST | PCICR_ENDIANNESS, + chan->reg_base + SH4_PCICR); + + /* + * Wait for it to come back up. The spec says to allow for up to + * 1 second after toggling the reset pin, but in practice 100ms + * is more than enough. + */ + mdelay(100); + + id = __raw_readw(chan->reg_base + PCI_VENDOR_ID); + if (id != PCI_VENDOR_ID_RENESAS) { + printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id); + return -ENODEV; + } + + id = __raw_readw(chan->reg_base + PCI_DEVICE_ID); + type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" : + (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" : + (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" : + (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" : + NULL; + if (unlikely(!type)) { + printk(KERN_ERR "PCI: Found an unsupported Renesas host " + "controller, device id 0x%04x.\n", id); + return -EINVAL; + } + + printk(KERN_NOTICE "PCI: Found a Renesas %s host " + "controller, revision %d.\n", type, + __raw_readb(chan->reg_base + PCI_REVISION_ID)); + + /* + * Now throw it in to register initialization mode and + * start the real work. + */ + __raw_writel(SH4_PCICR_PREFIX | PCICR_ENDIANNESS, + chan->reg_base + SH4_PCICR); + + memphys = __pa(memory_start); + memsize = roundup_pow_of_two(memory_end - memory_start); /* - * This code is unused for some boards as it is done in the - * bootloader and doing it here means the MAC addresses loaded - * by the bootloader get lost. + * If there's more than 512MB of memory, we need to roll over to + * LAR1/LSR1. */ - if (!(map->flags & SH4_PCIC_NO_RESET)) { - /* toggle PCI reset pin */ - word = SH4_PCICR_PREFIX | SH4_PCICR_PRST; - pci_write_reg(word, SH4_PCICR); - /* Wait for a long time... not 1 sec. but long enough */ - mdelay(100); - word = SH4_PCICR_PREFIX; - pci_write_reg(word, SH4_PCICR); + if (memsize > SZ_512M) { + __raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1); + __raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1, + chan->reg_base + SH4_PCILSR1); + memsize = SZ_512M; + } else { + /* + * Otherwise just zero it out and disable it. + */ + __raw_writel(0, chan->reg_base + SH4_PCILAR1); + __raw_writel(0, chan->reg_base + SH4_PCILSR1); } - /* set the command/status bits to: - * Wait Cycle Control + Parity Enable + Bus Master + - * Mem space enable + /* + * LAR0/LSR0 covers up to the first 512MB, which is enough to + * cover all of lowmem on most platforms. */ - pci_write_reg(0x00000046, SH7780_PCICMD); + __raw_writel(memphys, chan->reg_base + SH4_PCILAR0); + __raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1, + chan->reg_base + SH4_PCILSR0); - /* define this host as the host bridge */ - word = PCI_BASE_CLASS_BRIDGE << 24; - pci_write_reg(word, SH7780_PCIRID); + /* + * Hook up the ERR and SERR IRQs. + */ + ret = sh7780_pci_setup_irqs(chan); + if (unlikely(ret)) + return ret; - /* Set IO and Mem windows to local address - * Make PCI and local address the same for easy 1 to 1 mapping - * Window0 = map->window0.size @ non-cached area base = SDRAM - * Window1 = map->window1.size @ cached area base = SDRAM + /* + * Disable the cache snoop controller for non-coherent DMA. */ - word = ((map->window0.size - 1) & 0x1ff00001) | 0x01; - pci_write_reg(0x07f00001, SH4_PCILSR0); - word = ((map->window1.size - 1) & 0x1ff00001) | 0x01; - pci_write_reg(0x00000001, SH4_PCILSR1); - /* Set the values on window 0 PCI config registers */ - word = P2SEGADDR(map->window0.base); - pci_write_reg(0xa8000000, SH4_PCILAR0); - pci_write_reg(0x08000000, SH7780_PCIMBAR0); - /* Set the values on window 1 PCI config registers */ - word = P2SEGADDR(map->window1.base); - pci_write_reg(0x00000000, SH4_PCILAR1); - pci_write_reg(0x00000000, SH7780_PCIMBAR1); - - /* Map IO space into PCI IO window - * The IO window is 64K-PCIBIOS_MIN_IO in size - * IO addresses will be translated to the - * PCI IO window base address + __raw_writel(0, chan->reg_base + SH7780_PCICSCR0); + __raw_writel(0, chan->reg_base + SH7780_PCICSAR0); + __raw_writel(0, chan->reg_base + SH7780_PCICSCR1); + __raw_writel(0, chan->reg_base + SH7780_PCICSAR1); + + /* + * Setup the memory BARs */ - pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", - PCIBIOS_MIN_IO, (64 << 10), - SH7780_PCI_IO_BASE + PCIBIOS_MIN_IO); + for (i = 1; i < chan->nr_resources; i++) { + struct resource *res = chan->resources + i; + resource_size_t size; + + if (unlikely(res->flags & IORESOURCE_IO)) + continue; - /* NOTE: I'm ignoring the PCI error IRQs for now.. - * TODO: add support for the internal error interrupts and - * DMA interrupts... + /* + * 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 - 1)); + __raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i - 1)); + } + + /* + * 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); + + __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \ + PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \ + PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND); + + /* + * Initialization mode complete, release the control register and + * enable round robin mode to stop device overruns/starvation. + */ + __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO | + PCICR_ENDIANNESS, + chan->reg_base + SH4_PCICR); + + ret = register_pci_controller(chan); + if (unlikely(ret)) + goto err; + + sh7780_pci66_init(chan); - /* Apply any last-minute PCIC fixups */ - pci_fixup_pcic(); + printk(KERN_NOTICE "PCI: Running at %dMHz.\n", + (__raw_readw(chan->reg_base + PCI_STATUS) & PCI_STATUS_66MHZ) ? + 66 : 33); - /* SH7780 init done, set central function init complete */ - /* use round robin mode to stop a device starving/overruning */ - word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO; - pci_write_reg(word, SH4_PCICR); + return 0; - return 1; +err: + sh7780_pci_teardown_irqs(chan); + return ret; } +arch_initcall(sh7780_pci_init); diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h index 97b2c98f05c..1742e2c9db7 100644 --- a/arch/sh/drivers/pci/pci-sh7780.h +++ b/arch/sh/drivers/pci/pci-sh7780.h @@ -12,66 +12,17 @@ #ifndef _PCI_SH7780_H_ #define _PCI_SH7780_H_ -/* Platform Specific Values */ -#define SH7780_VENDOR_ID 0x1912 -#define SH7781_DEVICE_ID 0x0001 -#define SH7780_DEVICE_ID 0x0002 -#define SH7763_DEVICE_ID 0x0004 -#define SH7785_DEVICE_ID 0x0007 - /* SH7780 Control Registers */ -#define SH7780_PCI_VCR0 0xFE000000 -#define SH7780_PCI_VCR1 0xFE000004 -#define SH7780_PCI_VCR2 0xFE000008 +#define PCIECR 0xFE000008 +#define PCIECR_ENBL 0x01 /* SH7780 Specific Values */ #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 */ -#define PCI_REG(n) (SH7780_PCIREG_BASE+n) /* SH7780 PCI Config Registers */ -#define SH7780_PCIVID 0x000 /* Vendor ID */ -#define SH7780_PCIDID 0x002 /* Device ID */ -#define SH7780_PCICMD 0x004 /* Command */ -#define SH7780_PCISTATUS 0x006 /* Status */ -#define SH7780_PCIRID 0x008 /* Revision ID */ -#define SH7780_PCIPIF 0x009 /* Program Interface */ -#define SH7780_PCISUB 0x00a /* Sub class code */ -#define SH7780_PCIBCC 0x00b /* Base class code */ -#define SH7780_PCICLS 0x00c /* Cache line size */ -#define SH7780_PCILTM 0x00d /* latency timer */ -#define SH7780_PCIHDR 0x00e /* Header type */ -#define SH7780_PCIBIST 0x00f /* BIST */ -#define SH7780_PCIIBAR 0x010 /* IO Base address */ -#define SH7780_PCIMBAR0 0x014 /* Memory base address0 */ -#define SH7780_PCIMBAR1 0x018 /* Memory base address1 */ -#define SH7780_PCISVID 0x02c /* Sub system vendor ID */ -#define SH7780_PCISID 0x02e /* Sub system ID */ -#define SH7780_PCICP 0x034 -#define SH7780_PCIINTLINE 0x03c /* Interrupt line */ -#define SH7780_PCIINTPIN 0x03d /* Interrupt pin */ -#define SH7780_PCIMINGNT 0x03e /* Minumum grand */ -#define SH7780_PCIMAXLAT 0x03f /* Maxmum latency */ -#define SH7780_PCICID 0x040 -#define SH7780_PCINIP 0x041 -#define SH7780_PCIPMC 0x042 -#define SH7780_PCIPMCSR 0x044 -#define SH7780_PCIPMCSR_BSE 0x046 -#define SH7780_PCICDD 0x047 - -#define SH7780_PCICR 0x100 /* PCI Control Register */ -#define SH7780_PCILSR 0x104 /* PCI Local Space Register0 */ -#define SH7780_PCILSR1 0x108 /* PCI Local Space Register1 */ -#define SH7780_PCILAR0 0x10C /* PCI Local Address Register1 */ -#define SH7780_PCILAR1 0x110 /* PCI Local Address Register1 */ #define SH7780_PCIIR 0x114 /* PCI Interrupt Register */ #define SH7780_PCIIMR 0x118 /* PCI Interrupt Mask Register */ #define SH7780_PCIAIR 0x11C /* Error Address Register */ @@ -83,10 +34,8 @@ #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_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 */ @@ -94,19 +43,4 @@ #define SH7780_PCICSAR0 0x218 /* Cache Snoop1 Addr. Register */ #define SH7780_PCICSAR1 0x21C /* Cache Snoop2 Addr. Register */ -/* General Memory Config Addresses */ -#define SH7780_CS0_BASE_ADDR 0x0 -#define SH7780_MEM_REGION_SIZE 0x04000000 -#define SH7780_CS1_BASE_ADDR (SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS2_BASE_ADDR (SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS3_BASE_ADDR (SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS4_BASE_ADDR (SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS5_BASE_ADDR (SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE) -#define SH7780_CS6_BASE_ADDR (SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE) - -struct sh4_pci_address_map; - -/* arch/sh/drivers/pci/pci-sh7780.c */ -int sh7780_pcic_init(struct sh4_pci_address_map *map); - #endif /* _PCI_SH7780_H_ */ diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 49b435c3a57..1bc09ee7948 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -1,67 +1,151 @@ /* - * arch/sh/drivers/pci/pci.c + * New-style PCI core. * - * Copyright (c) 2002 M. R. Brown <mrbrown@linux-sh.org> - * Copyright (c) 2004 - 2006 Paul Mundt <lethal@linux-sh.org> + * Copyright (c) 2004 - 2009 Paul Mundt + * Copyright (c) 2002 M. R. Brown * - * These functions are collected here to reduce duplication of common - * code amongst the many platform-specific PCI support code files. - * - * These routines require the following board-specific routines: - * void pcibios_fixup_irqs(); - * - * See include/asm-sh/pci.h for more information. + * Modelled after arch/mips/pci/pci.c: + * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org) * * 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. */ #include <linux/kernel.h> +#include <linux/mm.h> #include <linux/pci.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/types.h> +#include <linux/dma-debug.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/export.h> + +unsigned long PCIBIOS_MIN_IO = 0x0000; +unsigned long PCIBIOS_MIN_MEM = 0; + +/* + * The PCI controller list. + */ +static struct pci_channel *hose_head, **hose_tail = &hose_head; -static inline u8 bridge_swizzle(u8 pin, u8 slot) +static int pci_initialized; + +static void pcibios_scanbus(struct pci_channel *hose) { - return (((pin - 1) + slot) % 4) + 1; + static int next_busno; + static int need_domain_info; + LIST_HEAD(resources); + struct resource *res; + resource_size_t offset; + int i; + struct pci_bus *bus; + + for (i = 0; i < hose->nr_resources; i++) { + res = hose->resources + i; + offset = 0; + if (res->flags & IORESOURCE_IO) + offset = hose->io_offset; + else if (res->flags & IORESOURCE_MEM) + offset = hose->mem_offset; + pci_add_resource_offset(&resources, res, offset); + } + + bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose, + &resources); + hose->bus = bus; + + need_domain_info = need_domain_info || hose->index; + hose->need_domain_info = need_domain_info; + if (bus) { + next_busno = bus->busn_res.end + 1; + /* Don't allow 8-bit bus number overflow inside the hose - + reserve some space for bridges. */ + if (next_busno > 224) { + next_busno = 0; + need_domain_info = 1; + } + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + } else { + pci_free_resource_list(&resources); + } } -static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp) +/* + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. + */ +DEFINE_RAW_SPINLOCK(pci_config_lock); +static DEFINE_MUTEX(pci_scan_mutex); + +int register_pci_controller(struct pci_channel *hose) { - u8 pin = *pinp; + 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; + } + } - while (dev->bus->parent) { - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - /* Move up the chain of bridges. */ - dev = dev->bus->self; + *hose_tail = hose; + hose_tail = &hose->next; + + /* + * Do not panic here but later - this might happen before console init. + */ + if (!hose->io_map_base) { + printk(KERN_WARNING + "registering PCI controller with io_map_base unset\n"); + } + + /* + * Setup the ERR/PERR and SERR timers, if available. + */ + pcibios_enable_timers(hose); + + /* + * Scan the bus if it is register after the PCI subsystem + * initialization. + */ + if (pci_initialized) { + mutex_lock(&pci_scan_mutex); + pcibios_scanbus(hose); + mutex_unlock(&pci_scan_mutex); } - *pinp = pin; - /* The slot is the slot of the last bridge. */ - return PCI_SLOT(dev->devfn); + 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; } static int __init pcibios_init(void) { - struct pci_channel *p; - struct pci_bus *bus; - int busno; - -#ifdef CONFIG_PCI_AUTO - /* assign resources */ - busno = 0; - for (p = board_pci_channels; p->pci_ops != NULL; p++) - busno = pciauto_assign_resources(busno, p) + 1; -#endif - - /* scan the buses */ - busno = 0; - for (p = board_pci_channels; p->pci_ops != NULL; p++) { - bus = pci_scan_bus(busno, p->pci_ops, p); - busno = bus->subordinate + 1; - } + struct pci_channel *hose; + + /* Scan all of the recorded PCI controllers. */ + for (hose = hose_head; hose; hose = hose->next) + pcibios_scanbus(hose); + + pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq); + + dma_debug_add_bus(&pci_bus_type); - pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq); + pci_initialized = 1; return 0; } @@ -71,156 +155,163 @@ subsys_initcall(pcibios_init); * Called after each bus is probed, but before its children * are examined. */ -void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus) +void pcibios_fixup_bus(struct pci_bus *bus) { - pci_read_bridge_bases(bus); -} - -void -pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) -{ - u32 new, check; - int reg; - - new = res->start | (res->flags & PCI_REGION_FLAG_MASK); - if (resource < 6) { - reg = PCI_BASE_ADDRESS_0 + 4*resource; - } else if (resource == PCI_ROM_RESOURCE) { - res->flags |= IORESOURCE_ROM_ENABLE; - new |= PCI_ROM_ADDRESS_ENABLE; - reg = dev->rom_base_reg; - } else { - /* - * Somebody might have asked allocation of a non-standard - * resource - */ - return; - } - - pci_write_config_dword(dev, reg, new); - pci_read_config_dword(dev, reg, &check); - if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? - PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { - printk(KERN_ERR "PCI: Error while updating region " - "%s/%d (%08x != %08x)\n", pci_name(dev), resource, - new, check); - } } -void pcibios_align_resource(void *data, struct resource *res, - resource_size_t size, resource_size_t align) - __attribute__ ((weak)); - /* * We need to avoid collisions with `mirrored' VGA ports * and other strange ISA hardware, so we always want the * addresses to be allocated in the 0x000-0x0ff region * modulo 0x400. */ -void pcibios_align_resource(void *data, struct resource *res, - resource_size_t size, resource_size_t align) +resource_size_t pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) { + struct pci_dev *dev = data; + struct pci_channel *hose = dev->sysdata; + resource_size_t start = res->start; + if (res->flags & IORESOURCE_IO) { - resource_size_t start = res->start; + if (start < PCIBIOS_MIN_IO + hose->resources[0].start) + start = PCIBIOS_MIN_IO + hose->resources[0].start; - if (start & 0x300) { + /* + * Put everything into 0x00-0xff region modulo 0x400. + */ + if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; - res->start = start; - } } + + return start; } -int pcibios_enable_device(struct pci_dev *dev, int mask) +static void __init +pcibios_bus_report_status_early(struct pci_channel *hose, + int top_bus, int current_bus, + unsigned int status_mask, int warn) { - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for(idx=0; idx<6; idx++) { - if (!(mask & (1 << idx))) + unsigned int pci_devfn; + u16 status; + int ret; + + for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { + if (PCI_FUNC(pci_devfn)) continue; - r = &dev->resource[idx]; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because " - "of resource collisions\n", pci_name(dev)); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (dev->resource[PCI_ROM_RESOURCE].start) - cmd |= PCI_COMMAND_MEMORY; - if (cmd != old_cmd) { - printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", - pci_name(dev), old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); + ret = early_read_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_STATUS, &status); + if (ret != PCIBIOS_SUCCESSFUL) + continue; + if (status == 0xffff) + continue; + + early_write_config_word(hose, top_bus, current_bus, + pci_devfn, PCI_STATUS, + status & status_mask); + if (warn) + printk("(%02x:%02x: %04X) ", current_bus, + pci_devfn, status); } - return 0; } /* - * If we set up a device for bus mastering, we need to check and set - * the latency timer as it may not be properly set. + * We can't use pci_find_device() here since we are + * called from interrupt context. */ -unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) +static void __init_refok +pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask, + int warn) { - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", - pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 status; + + /* + * ignore host bridge - we handle + * that separately + */ + if (dev->bus->number == 0 && dev->devfn == 0) + continue; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status == 0xffff) + continue; + + if ((status & status_mask) == 0) + continue; + + /* clear the status errors */ + pci_write_config_word(dev, PCI_STATUS, status & status_mask); + + if (warn) + printk("(%s: %04X) ", pci_name(dev), status); + } + + list_for_each_entry(dev, &bus->devices, bus_list) + if (dev->subordinate) + pcibios_bus_report_status(dev->subordinate, status_mask, warn); } -void __init pcibios_update_irq(struct pci_dev *dev, int irq) +void __init_refok pcibios_report_status(unsigned int status_mask, int warn) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + struct pci_channel *hose; + + for (hose = hose_head; hose; hose = hose->next) { + if (unlikely(!hose->bus)) + pcibios_bus_report_status_early(hose, hose_head->index, + hose->index, status_mask, warn); + else + pcibios_bus_report_status(hose->bus, status_mask, warn); + } } -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) { - unsigned long start = pci_resource_start(dev, bar); - unsigned long len = pci_resource_len(dev, bar); - unsigned long flags = pci_resource_flags(dev, bar); - - if (unlikely(!len || !start)) - return NULL; - if (maxlen && len > maxlen) - len = maxlen; + /* + * I/O space can be accessed via normal processor loads and stores on + * this platform but for now we elect not to do this and portable + * drivers should not do this anyway. + */ + if (mmap_state == pci_mmap_io) + return -EINVAL; /* - * Presently the IORESOURCE_MEM case is a bit special, most - * SH7751 style PCI controllers have PCI memory at a fixed - * location in the address space where no remapping is desired - * (typically at 0xfd000000, but is_pci_memaddr() will know - * best). With the IORESOURCE_MEM case more care has to be taken - * to inhibit page table mapping for legacy cores, but this is - * punted off to __ioremap(). - * -- PFM. + * Ignore write-combine; for now only return uncached mappings. */ - if (flags & IORESOURCE_IO) - return ioport_map(start, len); - if (flags & IORESOURCE_MEM) - return ioremap(start, len); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - return NULL; + return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +#ifndef CONFIG_GENERIC_IOMAP + +void __iomem *__pci_ioport_map(struct pci_dev *dev, + unsigned long port, unsigned int nr) +{ + struct pci_channel *chan = dev->sysdata; + + if (unlikely(!chan->io_map_base)) { + chan->io_map_base = sh_io_port_base; + + if (pci_domains_supported) + panic("To avoid data corruption io_map_base MUST be " + "set with multiple PCI domains."); + } + + return (void __iomem *)(chan->io_map_base + port); } -EXPORT_SYMBOL(pci_iomap); void pci_iounmap(struct pci_dev *dev, void __iomem *addr) { iounmap(addr); } EXPORT_SYMBOL(pci_iounmap); + +#endif /* CONFIG_GENERIC_IOMAP */ + +EXPORT_SYMBOL(PCIBIOS_MIN_IO); +EXPORT_SYMBOL(PCIBIOS_MIN_MEM); diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c new file mode 100644 index 00000000000..a162a7f86b2 --- /dev/null +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -0,0 +1,579 @@ +/* + * 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 + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/async.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/sh_clk.h> +#include <linux/sh_intc.h> +#include "pcie-sh7786.h" +#include <asm/sizes.h> + +struct sh7786_pcie_port { + struct pci_channel *hose; + struct clk *fclk, phy_clk; + unsigned int index; + int endpoint; + int link; +}; + +static struct sh7786_pcie_port *sh7786_pcie_ports; +static unsigned int nr_ports; + +static struct sh7786_pcie_hwops { + int (*core_init)(void); + async_func_t port_init_hw; +} *sh7786_pcie_hwops; + +static struct resource sh7786_pci0_resources[] = { + { + .name = "PCIe0 IO", + .start = 0xfd000000, + .end = 0xfd000000 + SZ_8M - 1, + .flags = IORESOURCE_IO, + }, { + .name = "PCIe0 MEM 0", + .start = 0xc0000000, + .end = 0xc0000000 + SZ_512M - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, + }, { + .name = "PCIe0 MEM 1", + .start = 0x10000000, + .end = 0x10000000 + SZ_64M - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "PCIe0 MEM 2", + .start = 0xfe100000, + .end = 0xfe100000 + SZ_1M - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource sh7786_pci1_resources[] = { + { + .name = "PCIe1 IO", + .start = 0xfd800000, + .end = 0xfd800000 + SZ_8M - 1, + .flags = IORESOURCE_IO, + }, { + .name = "PCIe1 MEM 0", + .start = 0xa0000000, + .end = 0xa0000000 + SZ_512M - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, + }, { + .name = "PCIe1 MEM 1", + .start = 0x30000000, + .end = 0x30000000 + SZ_256M - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, + }, { + .name = "PCIe1 MEM 2", + .start = 0xfe300000, + .end = 0xfe300000 + SZ_1M - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource sh7786_pci2_resources[] = { + { + .name = "PCIe2 IO", + .start = 0xfc800000, + .end = 0xfc800000 + SZ_4M - 1, + .flags = IORESOURCE_IO, + }, { + .name = "PCIe2 MEM 0", + .start = 0x80000000, + .end = 0x80000000 + SZ_512M - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, + }, { + .name = "PCIe2 MEM 1", + .start = 0x20000000, + .end = 0x20000000 + SZ_256M - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, + }, { + .name = "PCIe2 MEM 2", + .start = 0xfcd00000, + .end = 0xfcd00000 + SZ_1M - 1, + .flags = IORESOURCE_MEM, + }, +}; + +extern struct pci_ops sh7786_pci_ops; + +#define DEFINE_CONTROLLER(start, idx) \ +{ \ + .pci_ops = &sh7786_pci_ops, \ + .resources = sh7786_pci##idx##_resources, \ + .nr_resources = ARRAY_SIZE(sh7786_pci##idx##_resources), \ + .reg_base = start, \ + .mem_offset = 0, \ + .io_offset = 0, \ +} + +static struct pci_channel sh7786_pci_channels[] = { + DEFINE_CONTROLLER(0xfe000000, 0), + DEFINE_CONTROLLER(0xfe200000, 1), + DEFINE_CONTROLLER(0xfcc00000, 2), +}; + +static struct clk fixed_pciexclkp = { + .rate = 100000000, /* 100 MHz reference clock */ +}; + +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; + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786, + sh7786_pci_fixup); + +static int __init phy_wait_for_ack(struct pci_channel *chan) +{ + unsigned int timeout = 100; + + while (timeout--) { + if (pci_read_reg(chan, SH4A_PCIEPHYADRR) & (1 << BITS_ACK)) + return 0; + + udelay(100); + } + + return -ETIMEDOUT; +} + +static int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask) +{ + unsigned int timeout = 100; + + while (timeout--) { + if ((pci_read_reg(chan, SH4A_PCIEINTR) & mask) == mask) + return 0; + + udelay(100); + } + + return -ETIMEDOUT; +} + +static void __init phy_write_reg(struct pci_channel *chan, unsigned int addr, + unsigned int lane, unsigned int data) +{ + unsigned long phyaddr; + + phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) + + ((addr & 0xff) << BITS_ADR); + + /* Set write data */ + pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR); + pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR); + + phy_wait_for_ack(chan); + + /* Clear command */ + pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR); + pci_write_reg(chan, 0, SH4A_PCIEPHYADRR); + + phy_wait_for_ack(chan); +} + +static int __init pcie_clk_init(struct sh7786_pcie_port *port) +{ + struct pci_channel *chan = port->hose; + struct clk *clk; + char fclk_name[16]; + int ret; + + /* + * First register the fixed clock + */ + ret = clk_register(&fixed_pciexclkp); + if (unlikely(ret != 0)) + return ret; + + /* + * Grab the port's function clock, which the PHY clock depends + * on. clock lookups don't help us much at this point, since no + * dev_id is available this early. Lame. + */ + snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index); + + port->fclk = clk_get(NULL, fclk_name); + if (IS_ERR(port->fclk)) { + ret = PTR_ERR(port->fclk); + goto err_fclk; + } + + clk_enable(port->fclk); + + /* + * And now, set up the PHY clock + */ + clk = &port->phy_clk; + + memset(clk, 0, sizeof(struct clk)); + + clk->parent = &fixed_pciexclkp; + clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR); + clk->enable_bit = BITS_CKE; + + ret = sh_clk_mstp_register(clk, 1); + if (unlikely(ret < 0)) + goto err_phy; + + return 0; + +err_phy: + clk_disable(port->fclk); + clk_put(port->fclk); +err_fclk: + clk_unregister(&fixed_pciexclkp); + + return ret; +} + +static int __init phy_init(struct sh7786_pcie_port *port) +{ + struct pci_channel *chan = port->hose; + unsigned int timeout = 100; + + clk_enable(&port->phy_clk); + + /* Initialize the phy */ + phy_write_reg(chan, 0x60, 0xf, 0x004b008b); + phy_write_reg(chan, 0x61, 0xf, 0x00007b41); + phy_write_reg(chan, 0x64, 0xf, 0x00ff4f00); + phy_write_reg(chan, 0x65, 0xf, 0x09070907); + phy_write_reg(chan, 0x66, 0xf, 0x00000010); + phy_write_reg(chan, 0x74, 0xf, 0x0007001c); + phy_write_reg(chan, 0x79, 0xf, 0x01fc000d); + phy_write_reg(chan, 0xb0, 0xf, 0x00000610); + + /* Deassert Standby */ + phy_write_reg(chan, 0x67, 0x1, 0x00000400); + + /* Disable clock */ + clk_disable(&port->phy_clk); + + while (timeout--) { + if (pci_read_reg(chan, SH4A_PCIEPHYSR)) + return 0; + + udelay(100); + } + + return -ETIMEDOUT; +} + +static void __init pcie_reset(struct sh7786_pcie_port *port) +{ + struct pci_channel *chan = port->hose; + + pci_write_reg(chan, 1, SH4A_PCIESRSTR); + pci_write_reg(chan, 0, SH4A_PCIETCTLR); + pci_write_reg(chan, 0, SH4A_PCIESRSTR); + pci_write_reg(chan, 0, SH4A_PCIETXVC0SR); +} + +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; + int ret, i, win; + + /* Begin initialization */ + pcie_reset(port); + + /* + * Initial header for port config space is type 1, set the device + * 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); + + /* Initialize default capabilities. */ + data = pci_read_reg(chan, SH4A_PCIEEXPCAP0); + data &= ~(PCI_EXP_FLAGS_TYPE << 16); + + if (port->endpoint) + data |= PCI_EXP_TYPE_ENDPOINT << 20; + else + data |= PCI_EXP_TYPE_ROOT_PORT << 20; + + data |= PCI_CAP_ID_EXP; + pci_write_reg(chan, data, SH4A_PCIEEXPCAP0); + + /* Enable data link layer active state reporting */ + pci_write_reg(chan, PCI_EXP_LNKCAP_DLLLARC, SH4A_PCIEEXPCAP3); + + /* Enable extended sync and ASPM L0s support */ + data = pci_read_reg(chan, SH4A_PCIEEXPCAP4); + data &= ~PCI_EXP_LNKCTL_ASPMC; + data |= PCI_EXP_LNKCTL_ES | 1; + pci_write_reg(chan, data, SH4A_PCIEEXPCAP4); + + /* Write out the physical slot number */ + data = pci_read_reg(chan, SH4A_PCIEEXPCAP5); + data &= ~PCI_EXP_SLTCAP_PSN; + data |= (port->index + 1) << 19; + pci_write_reg(chan, data, SH4A_PCIEEXPCAP5); + + /* Set the completion timer timeout to the maximum 32ms. */ + data = pci_read_reg(chan, SH4A_PCIETLCTLR); + data &= ~0x3f00; + data |= 0x32 << 8; + pci_write_reg(chan, data, SH4A_PCIETLCTLR); + + /* + * Set fast training sequences to the maximum 255, + * and enable MAC data scrambling. + */ + data = pci_read_reg(chan, SH4A_PCIEMACCTLR); + data &= ~PCIEMACCTLR_SCR_DIS; + data |= (0xff << 16); + pci_write_reg(chan, data, SH4A_PCIEMACCTLR); + + memphys = __pa(memory_start); + memsize = roundup_pow_of_two(memory_end - memory_start); + + /* + * 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, ((memsize - SZ_512M) - SZ_256) | 1, + SH4A_PCIELAMR1); + memsize = SZ_512M; + } else { + /* + * Otherwise just zero it out and disable it. + */ + pci_write_reg(chan, 0, SH4A_PCIELAR1); + pci_write_reg(chan, 0, SH4A_PCIELAMR1); + } + + /* + * 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, (memsize - SZ_256) | 1, SH4A_PCIELAMR0); + + /* Finish initialization */ + data = pci_read_reg(chan, SH4A_PCIETCTLR); + data |= 0x1; + pci_write_reg(chan, data, SH4A_PCIETCTLR); + + /* Let things settle down a bit.. */ + mdelay(100); + + /* Enable DL_Active Interrupt generation */ + data = pci_read_reg(chan, SH4A_PCIEDLINTENR); + data |= PCIEDLINTENR_DLL_ACT_ENABLE; + pci_write_reg(chan, data, SH4A_PCIEDLINTENR); + + /* Disable MAC data scrambling. */ + data = pci_read_reg(chan, SH4A_PCIEMACCTLR); + data |= PCIEMACCTLR_SCR_DIS | (0xff << 16); + pci_write_reg(chan, data, SH4A_PCIEMACCTLR); + + /* + * This will timeout if we don't have a link, but we permit the + * port to register anyways in order to support hotplug on future + * hardware. + */ + ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL); + + data = pci_read_reg(chan, SH4A_PCIEPCICONF1); + data &= ~(PCI_STATUS_DEVSEL_MASK << 16); + data |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + (PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST) << 16; + pci_write_reg(chan, data, SH4A_PCIEPCICONF1); + + pci_write_reg(chan, 0x80888000, SH4A_PCIETXVC0DCTLR); + pci_write_reg(chan, 0x00222000, SH4A_PCIERXVC0DCTLR); + + wmb(); + + if (ret == 0) { + data = pci_read_reg(chan, SH4A_PCIEMACSR); + printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n", + port->index, (data >> 20) & 0x3f); + } else + printk(KERN_NOTICE "PCI: PCIe#%d link down\n", + port->index); + + for (i = win = 0; i < chan->nr_resources; i++) { + struct resource *res = chan->resources + i; + resource_size_t size; + u32 mask; + + /* + * We can't use the 32-bit mode windows in legacy 29-bit + * mode, so just skip them entirely. + */ + if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) + continue; + + pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win)); + + /* + * The PAMR mask is calculated in units of 256kB, which + * keeps things pretty simple. + */ + size = resource_size(res); + mask = (roundup_pow_of_two(size) / SZ_256K) - 1; + pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win)); + + pci_write_reg(chan, upper_32_bits(res->start), + SH4A_PCIEPARH(win)); + pci_write_reg(chan, lower_32_bits(res->start), + SH4A_PCIEPARL(win)); + + mask = MASK_PARE; + if (res->flags & IORESOURCE_IO) + mask |= MASK_SPC; + + pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win)); + + win++; + } + + return 0; +} + +int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + return evt2irq(0xae0); +} + +static int __init sh7786_pcie_core_init(void) +{ + /* Return the number of ports */ + return test_mode_pin(MODE_PIN12) ? 3 : 2; +} + +static void __init sh7786_pcie_init_hw(void *data, async_cookie_t cookie) +{ + struct sh7786_pcie_port *port = data; + int ret; + + /* + * Check if we are configured in endpoint or root complex mode, + * this is a fixed pin setting that applies to all PCIe ports. + */ + port->endpoint = test_mode_pin(MODE_PIN11); + + /* + * Setup clocks, needed both for PHY and PCIe registers. + */ + ret = pcie_clk_init(port); + if (unlikely(ret < 0)) { + pr_err("clock initialization failed for port#%d\n", + port->index); + return; + } + + ret = phy_init(port); + if (unlikely(ret < 0)) { + pr_err("phy initialization failed for port#%d\n", + port->index); + return; + } + + ret = pcie_init(port); + if (unlikely(ret < 0)) { + pr_err("core initialization failed for port#%d\n", + port->index); + return; + } + + /* In the interest of preserving device ordering, synchronize */ + async_synchronize_cookie(cookie); + + register_pci_controller(port->hose); +} + +static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = { + .core_init = sh7786_pcie_core_init, + .port_init_hw = sh7786_pcie_init_hw, +}; + +static int __init sh7786_pcie_init(void) +{ + struct clk *platclk; + int i; + + printk(KERN_NOTICE "PCI: Starting initialization.\n"); + + sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops; + + nr_ports = sh7786_pcie_hwops->core_init(); + BUG_ON(nr_ports > ARRAY_SIZE(sh7786_pci_channels)); + + if (unlikely(nr_ports == 0)) + return -ENODEV; + + sh7786_pcie_ports = kzalloc(nr_ports * sizeof(struct sh7786_pcie_port), + GFP_KERNEL); + if (unlikely(!sh7786_pcie_ports)) + return -ENOMEM; + + /* + * Fetch any optional platform clock associated with this block. + * + * This is a rather nasty hack for boards with spec-mocking FPGAs + * that have a secondary set of clocks outside of the on-chip + * ones that need to be accounted for before there is any chance + * of touching the existing MSTP bits or CPG clocks. + */ + platclk = clk_get(NULL, "pcie_plat_clk"); + if (IS_ERR(platclk)) { + /* Sane hardware should probably get a WARN_ON.. */ + platclk = NULL; + } + + clk_enable(platclk); + + printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports); + + for (i = 0; i < nr_ports; i++) { + struct sh7786_pcie_port *port = sh7786_pcie_ports + i; + + port->index = i; + port->hose = sh7786_pci_channels + i; + port->hose->io_map_base = port->hose->resources[0].start; + + async_schedule(sh7786_pcie_hwops->port_init_hw, port); + } + + async_synchronize_full(); + + return 0; +} +arch_initcall(sh7786_pcie_init); diff --git a/arch/sh/drivers/pci/pcie-sh7786.h b/arch/sh/drivers/pci/pcie-sh7786.h new file mode 100644 index 00000000000..4a6ff55f759 --- /dev/null +++ b/arch/sh/drivers/pci/pcie-sh7786.h @@ -0,0 +1,580 @@ +/* + * SH7786 PCI-Express controller definitions. + * + * Copyright (C) 2008, 2009 Renesas Technology Corp. + * All rights reserved. + * + * 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. + */ +#ifndef __PCI_SH7786_H +#define __PCI_SH7786_H + +/* PCIe bus-0(x4) on SH7786 */ // Rev1.171 +#define SH4A_PCIE_SPW_BASE 0xFE000000 /* spw config address for controller 0 */ +#define SH4A_PCIE_SPW_BASE1 0xFE200000 /* spw config address for controller 1 (Rev1.14)*/ +#define SH4A_PCIE_SPW_BASE2 0xFCC00000 /* spw config address for controller 2 (Rev1.171)*/ +#define SH4A_PCIE_SPW_BASE_LEN 0x00080000 + +#define SH4A_PCI_CNFG_BASE 0xFE040000 /* pci config address for controller 0 */ +#define SH4A_PCI_CNFG_BASE1 0xFE240000 /* pci config address for controller 1 (Rev1.14)*/ +#define SH4A_PCI_CNFG_BASE2 0xFCC40000 /* pci config address for controller 2 (Rev1.171)*/ +#define SH4A_PCI_CNFG_BASE_LEN 0x00040000 + +#define SH4A_PCIPIO_ADDR_OFFSET 0x000001c0 /* offset to pci config_address */ +#define SH4A_PCIPIO_DATA_OFFSET 0x00000220 /* offset to pci config_data */ + +/* + * for PEX8111(Max Payload Size=128B,PCIIO_SIZE=64K), + * for other(Max Payload Size=4096B,PCIIO_SIZE=8M) + */ + +/* PCI0: PCI memory target transfer 32-bit address translation value(Rev1.11T)*/ +#define SH4A_PCIBMSTR_TRANSLATION 0x20000000 + +/* SPVCR0 */ +#define SH4A_PCIEVCR0 (0x000000) /* R - 0x0000 0000 32 */ +#define BITS_TOP_MB (24) +#define MASK_TOP_MB (0xff<<BITS_TOP_MB) +#define BITS_BOT_MB (16) +#define MASK_BOT_MB (0xff<<BITS_BOT_MB) +#define BITS_VC_ID (0) +#define MASK_VC_ID (0xffff<<BITS_VC_ID) + +/* SPVCR1 */ +#define SH4A_PCIEVCR1 (0x000004) /* R - 0x0000 0000 32*/ +#define BITS_BADOPC (5) /* 5 BADOPC 0 R/W */ +#define MASK_BADOPC (1<<BITS_BADOPC) +#define BITS_BADDEST (4) /*4 BADDEST 0 R/W */ +#define MASK_BADDEST (1<<BITS_BADDEST) +#define BITS_UNSOLRESP (3) /* 3 UNSOLRESP 0 R/W */ +#define MASK_UNSOLRESP (1<<BITS_UNSOLRESP) +#define BITS_ERRSNT (1) /* 1 ERRSNT 0 */ +#define MASK_ERRSNT (1<<BITS_ERRSNT) +#define BITS_ERRRCV (0) /* 0 ERRRCV 0 */ +#define MASK_ERRRCV (1<<BITS_ERRRCV) + +/* PCIEENBLR */ +#define SH4A_PCIEENBLR (0x000008) /* R/W - 0x0000 0001 32 */ + +/* PCIEECR */ +#define SH4A_PCIEECR (0x00000C) /* R/W - 0x0000 0000 32 */ +#define BITS_ENBL (0) /* 0 ENBL 0 R/W */ +#define MASK_ENBL (1<<BITS_ENBL) + +/* PCIEPAR */ +#define SH4A_PCIEPAR (0x000010) /* R/W - 0x0000 0000 32 */ +#define BITS_BN (24) +#define MASK_BN (0xff<<BITS_BN) +#define BITS_DN (19) +#define MASK_DN (0x1f<<BITS_DN) +#define BITS_FN (16) +#define MASK_FN (0x7<<BITS_FN) +#define BITS_EREGNO (8) +#define MASK_EREGNO (0xff<<BITS_EREGNO) +#define BITS_REGNO (2) +#define MASK_REGNO (0x3f<<BITS_REGNO) + +/* PCIEPCTLR */ +#define SH4A_PCIEPCTLR (0x000018) /* R/W - 0x0000 0000 32 */ +#define BITS_CCIE (31) /* 31 CCIE */ +#define MASK_CCIE (1<<BITS_CCIE) +#define BITS_TYPE (8) +#define MASK_TYPE (1<<BITS_TYPE) +#define BITS_C_VC (0) +#define MASK_C_VC (1<<BITS_C_VC) + +/* PCIEPDR */ +#define SH4A_PCIEPDR (0x000020) /* R/W - 0x0000 0000 32 */ +#define BITS_PDR (0) +#define MASK_PDR (0xffffffff<<BITS_PDR) + +/* PCIEMSGALR */ +#define SH4A_PCIEMSGALR (0x000030) /* R/W - 0x0000 0000 32 */ +#define BITS_MSGADRL (0) +#define MASK_MSGADRL (0xffffffff<<BITS_MSGADRL) + +/* PCIEMSGAHR */ +#define SH4A_PCIEMSGAHR (0x000034) /* R/W - 0x0000 0000 32 */ +#define BITS_MSGADRH (0) +#define MASK_MSGADRH (0xffffffff<<BITS_MSGADRH) + +/* PCIEMSGCTLR */ +#define SH4A_PCIEMSGCTLR (0x000038) /* R/W - 0x0000 0000 32 */ +#define BITS_MSGIE (31) +#define MASK_MSGIE (1<<BITS_MSGIE) +#define BITS_MROUTE (16) +#define MASK_MROUTE (0x7<<BITS_MROUTE) +#define BITS_MCODE (8) +#define MASK_MCODE (0xff<<BITS_MCODE) +#define BITS_M_VC (0) +#define MASK_M_VC (1<<BITS_M_VC) + +/* PCIEMSG */ +#define SH4A_PCIEMSG (0x000040) /* W - - 32 */ +#define BITS_MDATA (0) +#define MASK_MDATA (0xffffffff<<BITS_MDATA) + +/* PCIEUNLOCKCR */ +#define SH4A_PCIEUNLOCKCR (0x000048) /* R/W - 0x0000 0000 32 */ + +/* PCIEIDR */ +#define SH4A_PCIEIDR (0x000060) /* R/W - 0x0101 1101 32 */ + +/* PCIEDBGCTLR */ +#define SH4A_PCIEDBGCTLR (0x000100) /* R/W - 0x0000 0000 32 */ + +/* PCIEINTXR */ +#define SH4A_PCIEINTXR (0x004000) /* R/W - 0x0000 0000 32 */ + +/* PCIERMSGR */ +#define SH4A_PCIERMSGR (0x004010) /* R/W - 0x0000 0000 32 */ + +/* PCIERSTR */ +#define SH4A_PCIERSTR(x) (0x008000 + ((x) * 0x4)) /* R/W - 0x0000 0000 32 */ + +/* PCIESRSTR */ +#define SH4A_PCIESRSTR (0x008040) /* R/W - 0x0000 0000 32 */ + +/* PCIEPHYCTLR */ +#define SH4A_PCIEPHYCTLR (0x010000) /* R/W - 0x0000 0000 32 */ +#define BITS_CKE (0) +#define MASK_CKE (1<<BITS_CKE) + +/* PCIERMSGIER */ +#define SH4A_PCIERMSGIER (0x004040) /* R/W - 0x0000 0000 32 */ + +/* PCIEPHYADRR */ +#define SH4A_PCIEPHYADRR (0x010004) /* R/W - 0x0000 0000 32 */ +#define BITS_ACK (24) // Rev1.171 +#define MASK_ACK (1<<BITS_ACK) // Rev1.171 +#define BITS_CMD (16) // Rev1.171 +#define MASK_CMD (0x03<<BITS_CMD) // Rev1.171 +#define BITS_LANE (8) +#define MASK_LANE (0x0f<<BITS_LANE) +#define BITS_ADR (0) +#define MASK_ADR (0xff<<BITS_ADR) + +/* PCIEPHYDINR */ // Rev1.171 start. +#define SH4A_PCIEPHYDINR (0x010008) /* R/W - 0x0000 0000 32 */ + +/* PCIEPHYDOUTR */ +#define SH4A_PCIEPHYDOUTR (0x01000C) /* R/W - 0x0000 0000 32 */ + +/* PCIEPHYSR */ +#define SH4A_PCIEPHYSR (0x010010) /* R/W - 0x0000 0000 32 */ // Rev1.171 end. + +/* PCIEPHYDATAR */ +#define SH4A_PCIEPHYDATAR (0x00008) /* R/W - 0xxxxx xxxx 32 */ +#define BITS_DATA (0) +#define MASK_DATA (0xffffffff<<BITS_DATA) + +/* PCIETCTLR */ +#define SH4A_PCIETCTLR (0x020000) /* R/W R/W 0x0000 0000 32 */ +#define BITS_CFINT (0) +#define MASK_CFINT (1<<BITS_CFINT) + +/* PCIETSTR */ +#define SH4A_PCIETSTR (0x020004) /* R 0x0000 0000 32 */ + +/* PCIEINTR */ +#define SH4A_PCIEINTR (0x020008) /* R/W R/W 0x0000 0000 32 */ +#define BITS_INT_RX_ERP (31) +#define MASK_INT_RX_ERP (1<<BITS_INT_RX_ERP) +#define BITS_INT_RX_VCX_Posted (30) +#define MASK_INT_RX_VCX_Posted (1<<BITS_INT_RX_VCX_Posted) +#define BITS_INT_RX_VCX_NonPosted (29) +#define MASK_INT_RX_VCX_NonPosted (1<<BITS_INT_RX_VCX_NonPosted) +#define BITS_INT_RX_VCX_CPL (28) +#define MASK_INT_RX_VCX_CPL (1<<BITS_INT_RX_VCX_CPL) +#define BITS_INT_TX_VCX_Posted (26) +#define MASK_INT_TX_VCX_Posted (1<<BITS_INT_TX_VCX_Posted) +#define BITS_INT_TX_VCX_NonPosted (25) +#define MASK_INT_TX_VCX_NonPosted (1<<BITS_INT_TX_VCX_NonPosted) +#define BITS_INT_TX_VCX_CPL (24) +#define MASK_INT_TX_VCX_CPL (1<<BITS_INT_TX_VCX_CPL) +#define BITS_INT_RX_VC0_Posted (22) +#define MASK_INT_RX_VC0_Posted (1<<BITS_INT_RX_VC0_Posted) +#define BITS_INT_RX_VC0_NonPosted (21) +#define MASK_INT_RX_VC0_NonPosted (1<<BITS_INT_RX_VC0_NonPosted) +#define BITS_INT_RX_VC0_CPL (20) +#define MASK_INT_RX_VC0_CPL (1<<BITS_INT_RX_VC0_CPL) +#define BITS_INT_TX_VC0_Posted (18) +#define MASK_INT_TX_VC0_Posted (1<<BITS_INT_TX_VC0_Posted) +#define BITS_INT_TX_VC0_NonPosted (17) +#define MASK_INT_TX_VC0_NonPosted (1<<BITS_INT_TX_VC0_NonPosted) +#define BITS_INT_TX_VC0_CPL (16) +#define MASK_INT_TX_VC0_CPL (1<<BITS_INT_TX_VC0_CPL) +#define BITS_INT_RX_CTRL (15) +#define MASK_INT_RX_CTRL (1<<BITS_INT_RX_CTRL) +#define BITS_INT_TX_CTRL (14) +#define MASK_INT_TX_CTRL (1<<BITS_INT_TX_CTRL) +#define BITS_INTTL (11) +#define MASK_INTTL (1<<BITS_INTTL) +#define BITS_INTDL (10) +#define MASK_INTDL (1<<BITS_INTDL) +#define BITS_INTMAC (9) +#define MASK_INTMAC (1<<BITS_INTMAC) +#define BITS_INTPM (8) +#define MASK_INTPM (1<<BITS_INTPM) + +/* PCIEINTER */ +#define SH4A_PCIEINTER (0x02000C) /* R/W R/W 0x0000 0000 32 */ +#define BITS_INT_RX_ERP (31) +#define MASK_INT_RX_ERP (1<<BITS_INT_RX_ERP) +#define BITS_INT_RX_VCX_Posted (30) +#define MASK_INT_RX_VCX_Posted (1<<BITS_INT_RX_VCX_Posted) +#define BITS_INT_RX_VCX_NonPosted (29) +#define MASK_INT_RX_VCX_NonPosted (1<<BITS_INT_RX_VCX_NonPosted) +#define BITS_INT_RX_VCX_CPL (28) +#define MASK_INT_RX_VCX_CPL (1<<BITS_INT_RX_VCX_CPL) +#define BITS_INT_TX_VCX_Posted (26) +#define MASK_INT_TX_VCX_Posted (1<<BITS_INT_TX_VCX_Posted) +#define BITS_INT_TX_VCX_NonPosted (25) +#define MASK_INT_TX_VCX_NonPosted (1<<BITS_INT_TX_VCX_NonPosted) +#define BITS_INT_TX_VCX_CPL (24) +#define MASK_INT_TX_VCX_CPL (1<<BITS_INT_TX_VCX_CPL) +#define BITS_INT_RX_VC0_Posted (22) +#define MASK_INT_RX_VC0_Posted (1<<BITS_INT_RX_VC0_Posted) +#define BITS_INT_RX_VC0_NonPosted (21) +#define MASK_INT_RX_VC0_NonPosted (1<<BITS_INT_RX_VC0_NonPosted) +#define BITS_INT_RX_VC0_CPL (20) +#define MASK_INT_RX_VC0_CPL (1<<BITS_INT_RX_VC0_CPL) +#define BITS_INT_TX_VC0_Posted (18) +#define MASK_INT_TX_VC0_Posted (1<<BITS_INT_TX_VC0_Posted) +#define BITS_INT_TX_VC0_NonPosted (17) +#define MASK_INT_TX_VC0_NonPosted (1<<BITS_INT_TX_VC0_NonPosted) +#define BITS_INT_TX_VC0_CPL (16) +#define MASK_INT_TX_VC0_CPL (1<<BITS_INT_TX_VC0_CPL) +#define BITS_INT_RX_CTRL (15) +#define MASK_INT_RX_CTRL (1<<BITS_INT_RX_CTRL) +#define BITS_INT_TX_CTRL (14) +#define MASK_INT_TX_CTRL (1<<BITS_INT_TX_CTRL) +#define BITS_INTTL (11) +#define MASK_INTTL (1<<BITS_INTTL) +#define BITS_INTDL (10) +#define MASK_INTDL (1<<BITS_INTDL) +#define BITS_INTMAC (9) +#define MASK_INTMAC (1<<BITS_INTMAC) +#define BITS_INTPM (8) +#define MASK_INTPM (1<<BITS_INTPM) + +/* PCIEEH0R */ +#define SH4A_PCIEEHR(x) (0x020010 + ((x) * 0x4)) /* R - 0x0000 0000 32 */ + +/* PCIEAIR */ +#define SH4A_PCIEAIR (SH4A_PCIE_BASE + 0x020010) /* R/W R/W 0xxxxx xxxx 32 */ + +/* PCIECIR */ +#define SH4A_PCIECIR (SH4A_PCIE_BASE) /* R/W R/W 0xxxxx xxxx 32 */ + +/* PCIEERRFR */ // Rev1.18 +#define SH4A_PCIEERRFR (0x020020) /* R/W R/W 0xxxxx xxxx 32 */ // Rev1.18 + +/* PCIEERRFER */ +#define SH4A_PCIEERRFER (0x020024) /* R/W R/W 0x0000 0000 32 */ + +/* PCIEERRFR2 */ +#define SH4A_PCIEERRFR2 (0x020028) /* R/W R/W 0x0000 0000 32 */ + +/* PCIEMSIR */ +#define SH4A_PCIEMSIR (0x020040) /* R/W - 0x0000 0000 32 */ + +/* PCIEMSIFR */ +#define SH4A_PCIEMSIFR (0x020044) /* R/W R/W 0x0000 0000 32 */ + +/* PCIEPWRCTLR */ +#define SH4A_PCIEPWRCTLR (0x020100) /* R/W - 0x0000 0000 32 */ + +/* PCIEPCCTLR */ +#define SH4A_PCIEPCCTLR (0x020180) /* R/W - 0x0000 0000 32 */ + + // Rev1.18 +/* PCIELAR0 */ +#define SH4A_PCIELAR0 (0x020200) /* R/W R/W 0x0000 0000 32 */ +#define BITS_LARn (20) +#define MASK_LARn (0xfff<<BITS_LARn) + +#define SH4A_PCIE_020204 (0x020204) /* R/W R/W 0x0000 0000 32 */ + +/* PCIELAMR0 */ +#define SH4A_PCIELAMR0 (0x020208) /* R/W R/W 0x0000 0000 32 */ +#define BITS_LAMRn (20) +#define MASK_LAMRn (0x1ff<<BITS_LAMRn) +#define BITS_LAREn (0) +#define MASK_LAREn (0x1<<BITS_LAREn) + +/* PCIECSCR0 */ +#define SH4A_PCIECSCR0 (0x020210) /* R/W R/W 0x0000 0000 32 */ +#define BITS_RANGE (2) +#define MASK_RANGE (0x7<<BITS_RANGE) +#define BITS_SNPMD (0) +#define MASK_SNPMD (0x3<<BITS_SNPMD) + +/* PCIECSAR0 */ +#define SH4A_PCIECSAR0 (0x020214) /* R/W R/W 0x0000 0000 32 */ +#define BITS_CSADR (0) +#define MASK_CSADR (0xffffffff<<BITS_CSADR) + +/* PCIESTCTLR0 */ +#define SH4A_PCIESTCTLR0 (0x020218) /* R/W R/W 0x0000 0000 32 */ +#define BITS_SHPRI (8) +#define MASK_SHPRI (0x0f<<BITS_SHPRI) + +#define SH4A_PCIE_020224 (0x020224) /* R/W R/W 0x0000 0000 32 */ + +#define SH4A_PCIELAR1 (0x020220) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIELAMR1 (0x020228) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSCR1 (0x020230) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSAR1 (0x020234) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIESTCTLR1 (0x020238) /* R/W R/W 0x0000 0000 32 */ + +#define SH4A_PCIELAR2 (0x020240) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIE_020244 (0x020244) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIELAMR2 (0x020248) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSCR2 (0x020250) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSAR2 (0x020254) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIESTCTLR2 (0x020258) /* R/W R/W 0x0000 0000 32 */ + +#define SH4A_PCIELAR3 (0x020260) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIE_020264 (0x020264) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIELAMR3 (0x020268) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSCR3 (0x020270) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSAR3 (0x020274) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIESTCTLR3 (0x020278) /* R/W R/W 0x0000 0000 32 */ + +#define SH4A_PCIELAR4 (0x020280) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIE_020284 (0x020284) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIELAMR4 (0x020288) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSCR4 (0x020290) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSAR4 (0x020294) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIESTCTLR4 (0x020298) /* R/W R/W 0x0000 0000 32 */ + +#define SH4A_PCIELAR5 (0x0202A0) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIE_0202A4 (0x0202A4) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIELAMR5 (0x0202A8) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSCR5 (0x0202B0) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIECSAR5 (0x0202B4) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIESTCTLR5 (0x0202B8) /* R/W R/W 0x0000 0000 32 */ + +/* PCIEPARL */ +#define SH4A_PCIEPARL(x) (0x020400 + ((x) * 0x20)) /* R/W R/W 0x0000 0000 32 */ +#define BITS_PAL (18) +#define MASK_PAL (0x3fff<<BITS_PAL) + +/* PCIEPARH */ +#define SH4A_PCIEPARH(x) (0x020404 + ((x) * 0x20)) /* R/W R/W 0x0000 0000 32 */ +#define BITS_PAH (0) +#define MASK_PAH (0xffffffff<<BITS_PAH) + +/* PCIEPAMR */ +#define SH4A_PCIEPAMR(x) (0x020408 + ((x) * 0x20)) /* R/W R/W 0x0000 0000 32 */ +#define BITS_PAM (18) +#define MASK_PAM (0x3fff<<BITS_PAM) + +/* PCIEPTCTLR */ +#define SH4A_PCIEPTCTLR(x) (0x02040C + ((x) * 0x20)) +#define BITS_PARE (31) +#define MASK_PARE (0x1<<BITS_PARE) +#define BITS_TC (20) +#define MASK_TC (0x7<<BITS_TC) +#define BITS_T_VC (16) +#define MASK_T_VC (0x1<<BITS_T_VC) +#define BITS_LOCK (12) +#define MASK_LOCK (0x1<<BITS_LOCK) +#define BITS_SPC (8) +#define MASK_SPC (0x1<<BITS_SPC) + +#define SH4A_PCIEDMAOR (0x021000) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSAR0 (0x021100) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSAHR0 (0x021104) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAR0 (0x021108) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAHR0 (0x02110C) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMBCNTR0 (0x021110) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSBCNTR0 (0x021114) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSTRR0 (0x021118) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCAR0 (0x02111C) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCR0 (0x021120) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCC2R0 (0x021124) /* R/W R/W 0x0000 0000 - */ +#define SH4A_PCIEDMCCCR0 (0x021128) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCHSR0 (0x02112C) /* R/W - 0x0000 0000 32 */ +#define SH4A_PCIEDMSAR1 (0x021140) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSAHR1 (0x021144) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAR1 (0x021148) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAHR1 (0x02114C) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMBCNTR1 (0x021150) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSBCNTR1 (0x021154) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSTRR1 (0x021158) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCAR1 (0x02115C) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCR1 (0x021160) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCC2R1 (0x021164) /* R/W R/W 0x0000 0000 - */ +#define SH4A_PCIEDMCCCR1 (0x021168) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCHSR1 (0x02116C) /* R/W - 0x0000 0000 32 */ +#define SH4A_PCIEDMSAR2 (0x021180) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSAHR2 (0x021184) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAR2 (0x021188) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAHR2 (0x02118C) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMBCNTR2 (0x021190) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSBCNTR2 (0x021194) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSTRR2 (0x021198) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCAR2 (0x02119C) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCR2 (0x0211A0) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCC2R2 (0x0211A4) /* R/W R/W 0x0000 0000 - */ +#define SH4A_PCIEDMCCCR2 (0x0211A8) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSAR3 (0x0211C0) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSAHR3 (0x0211C4) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAR3 (0x0211C8) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMDAHR3 (0x0211CC) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMBCNTR3 (0x0211D0) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSBCNTR3 (0x0211D4) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMSTRR3 (0x0211D8) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCAR3 (0x0211DC) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCCR3 (0x0211E0) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCC2R3 (0x0211E4) /* R/W R/W 0x0000 0000 - */ +#define SH4A_PCIEDMCCCR3 (0x0211E8) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEDMCHSR3 (0x0211EC) /* R/W R/W 0x0000 0000 32 */ +#define SH4A_PCIEPCICONF0 (0x040000) /* R R - 8/16/32 */ +#define SH4A_PCIEPCICONF1 (0x040004) /* R/W R/W 0x0008 0000 8/16/32 */ +#define SH4A_PCIEPCICONF2 (0x040008) /* R/W R/W 0xFF00 0000 8/16/32 */ +#define SH4A_PCIEPCICONF3 (0x04000C) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEPCICONF4 (0x040010) /* - R/W - 8/16/32 */ +#define SH4A_PCIEPCICONF5 (0x040014) /* - R/W - 8/16/32 */ +#define SH4A_PCIEPCICONF6 (0x040018) /* - R/W - 8/16/32 */ +#define SH4A_PCIEPCICONF7 (0x04001C) /* - R/W - 8/16/32 */ +#define SH4A_PCIEPCICONF8 (0x040020) /* - R/W - 8/16/32 */ +#define SH4A_PCIEPCICONF9 (0x040024) /* - R/W - 8/16/32 */ +#define SH4A_PCIEPCICONF10 (0x040028) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEPCICONF11 (0x04002C) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEPCICONF12 (0x040030) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEPCICONF13 (0x040034) /* R/W R/W 0x0000 0040 8/16/32 */ +#define SH4A_PCIEPCICONF14 (0x040038) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEPCICONF15 (0x04003C) /* R/W R/W 0x0000 00FF 8/16/32 */ +#define SH4A_PCIEPMCAP0 (0x040040) /* R/W R 0x0003 5001 8/16/32 */ +#define SH4A_PCIEPMCAP1 (0x040044) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEMSICAP0 (0x040050) /* R/W R/W 0x0180 7005 8/16/32 */ +#define SH4A_PCIEMSICAP1 (0x040054) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEMSICAP2 (0x040058) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEMSICAP3 (0x04005C) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEMSICAP4 (0x040060) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEMSICAP5 (0x040064) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEEXPCAP0 (0x040070) /* R/W R/W 0x0001 0010 8/16/32 */ +#define SH4A_PCIEEXPCAP1 (0x040074) /* R/W R 0x0000 0005 8/16/32 */ +#define SH4A_PCIEEXPCAP2 (0x040078) /* R/W R/W 0x0000 0801 8/16/32 */ +#define SH4A_PCIEEXPCAP3 (0x04007C) /* R/W R 0x0003 F421 8/16/32 */ +#define SH4A_PCIEEXPCAP4 (0x040080) /* R/W R/W 0x0041 0000 8/16/32 */ +#define SH4A_PCIEEXPCAP5 (0x040084) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEEXPCAP6 (0x040088) /* R/W R/W 0x0000 03C0 8/16/32 */ +#define SH4A_PCIEEXPCAP7 (0x04008C) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEEXPCAP8 (0x040090) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEVCCAP0 (0x040100) /* R/W R 0x1B01 0002 8/16/32 */ +#define SH4A_PCIEVCCAP1 (0x040104) /* R R 0x0000 0001 8/16/32 */ +#define SH4A_PCIEVCCAP2 (0x040108) /* R R 0x0000 0000 8/16/32 */ +#define SH4A_PCIEVCCAP3 (0x04010C) /* R R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEVCCAP4 (0x040110) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEVCCAP5 (0x040114) /* R/W R/W 0x8000 00FF 8/16/32 */ +#define SH4A_PCIEVCCAP6 (0x040118) /* R/W R 0x0002 0000 8/16/32 */ +#define SH4A_PCIEVCCAP7 (0x04011C) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEVCCAP8 (0x040120) /* R/W R/W 0x0000 0000 8/16/32 */ +#define SH4A_PCIEVCCAP9 (0x040124) /* R/W R 0x0002 0000 8/16/32 */ +#define SH4A_PCIENUMCAP0 (0x0001B0) /* RW R 0x0001 0003 8/16/32 */ +#define SH4A_PCIENUMCAP1 (0x0001B4) /* R R 0x0000 0000 8/16/32 */ +#define SH4A_PCIENUMCAP2 (0x0001B8) /* R R 0x0000 0000 8/16/32 */ +#define SH4A_PCIEIDSETR0 (0x041000) /* R/W R 0x0000 FFFF 16/32 */ +#define SH4A_PCIEIDSETR1 (0x041004) /* R/W R 0xFF00 0000 16/32 */ +#define SH4A_PCIEBAR0SETR (0x041008) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEBAR1SETR (0x04100C) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEBAR2SETR (0x041010) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEBAR3SETR (0x041014) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEBAR4SETR (0x041018) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEBAR5SETR (0x04101C) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIECISSETR (0x041020) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEIDSETR2 (0x041024) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEEROMSETR (0x041028) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEDSERSETR0 (0x04102C) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEDSERSETR1 (0x041030) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIECTLR (0x041040) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIETLSR (0x041044) /* R/W1C R 0x0000 0000 16/32 */ +#define SH4A_PCIETLCTLR (0x041048) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEDLSR (0x04104C) /* R/W1C R 0x4003 0000 16/32 */ +#define SH4A_PCIEDLCTLR (0x041050) /* R R 0x0000 0000 16/32 */ +#define SH4A_PCIEMACSR (0x041054) /* R/W1C R 0x0041 0000 16/32 */ +#define SH4A_PCIEMACCTLR (0x041058) /* R/W R 0x0000 0000 16/32 */ +#define PCIEMACCTLR_SCR_DIS (1 << 27) /* scramble disable */ +#define SH4A_PCIEPMSTR (0x04105C) /* R/W1C R 0x0000 0000 16/32 */ +#define SH4A_PCIEPMCTLR (0x041060) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIETLINTENR (0x041064) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEDLINTENR (0x041068) /* R/W R 0x0000 0000 16/32 */ +#define PCIEDLINTENR_DLL_ACT_ENABLE (1 << 31) /* DL active irq */ +#define SH4A_PCIEMACINTENR (0x04106C) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIEPMINTENR (0x041070) /* R/W R 0x0000 0000 16/32 */ +#define SH4A_PCIETXDCTLR (0x044000) /* R/W - H'00000000_00000000 32/64 */ +#define SH4A_PCIETXCTLR (0x044020) /* R/W - H'00000000_00000000 32/64 */ +#define SH4A_PCIETXSR (0x044028) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIETXVC0DCTLR (0x044100) /* R/W - H'00000000_00000000 32/64 */ +#define SH4A_PCIETXVC0SR (0x044108) /* R/W - H'00888000_00000000 32/64 */ +#define SH4A_PCIEVC0PDTXR (0x044110) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0PHTXR (0x044118) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0NPDTXR (0x044120) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0NPHTXR (0x044128) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0CDTXR (0x044130) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0CHTXR (0x044138) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIETXVCXDCTLR (0x044200) /* R/W - H'00000000_00000000 32/64 */ +#define SH4A_PCIETXVCXSR (0x044208) /* R/W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXPDTXR (0x044210) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXPHTXR (0x044218) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXNPDTXR (0x044220) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXNPHTXR (0x044228) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXCDTXR (0x044230) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXCHTXR (0x044238) /* W - H'00000000_00000000 32/64 */ +#define SH4A_PCIERDCTLR (0x046000) /* RW - H'00000000_00000000 32/64 */ +#define SH4A_PCIEERPCTLR (0x046008) /* RW - H'00000000_00000000 32/64 */ +#define SH4A_PCIEERPHR (0x046010) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEERPERR (0x046018) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIERXVC0DCTLR (0x046100) /* RW - H'00000000_00000000 32/64 */ +#define SH4A_PCIERXVC0SR (0x046108) /* RW - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0PDRXR (0x046140) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0PHRXR (0x046148) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0PERR (0x046150) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0NPDRXR (0x046158) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0NPHRXR (0x046160) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0NPERR (0x046168) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0CDRXR (0x046170) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0CHRXR (0x046178) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVC0CERR (0x046180) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIERXVCXDCTLR (0x046200) /* RW - H'00000000_00000000 32/64 */ +#define SH4A_PCIERXVCXSR (0x046208) /* RW - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXPDRXR (0x046240) /* R - H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXPHRXR (0x046248) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXPERR (0x046250) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXNPDRXR (0x046258) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXNPHRXR (0x046260) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXNPERR (0x046268) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXCDRXR (0x046270) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXCHRXR (0x046278) /* R H'00000000_00000000 32/64 */ +#define SH4A_PCIEVCXCERR (0x046280) /* R H'00000000_00000000 32/64 */ + +/* SSI Register Definition for MSI WORK AROUND --hamada */ +#define SH4A_PCI_SSI_BASE 0xFFE00000 /* spw config address */ +#define SH4A_PCI_SSI_BASE_LEN 0x00100000 /* 1MB */ + +#define SH4A_SSICR0 (0x000000) +#define SH4A_SSICR1 (0x010000) +#define SH4A_SSICR2 (0x020000) +#define SH4A_SSICR3 (0x030000) + +#define PCI_REG(x) ((x) + 0x40000) + +static inline void +pci_write_reg(struct pci_channel *chan, unsigned long val, unsigned long reg) +{ + __raw_writel(val, chan->reg_base + reg); +} + +static inline unsigned long +pci_read_reg(struct pci_channel *chan, unsigned long reg) +{ + return __raw_readl(chan->reg_base + reg); +} + +#endif /* __PCI_SH7786_H */ |
