diff options
Diffstat (limited to 'arch/sh/drivers')
24 files changed, 1124 insertions, 635 deletions
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig index 0f15216cd39..defc13c37d4 100644 --- a/arch/sh/drivers/dma/Kconfig +++ b/arch/sh/drivers/dma/Kconfig @@ -11,6 +11,8 @@ config SH_DMA config NR_ONCHIP_DMA_CHANNELS depends on SH_DMA int "Number of on-chip DMAC channels" + default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R + default "12" if CPU_SUBTYPE_SH7780 default "4" help This allows you to specify the number of channels that the on-chip @@ -52,4 +54,3 @@ config DMA_PAGE_OPS_CHANNEL are dual-address capable. endmenu - diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c index 0f866f8789f..9cb07092418 100644 --- a/arch/sh/drivers/dma/dma-g2.c +++ b/arch/sh/drivers/dma/dma-g2.c @@ -3,7 +3,7 @@ * * G2 bus DMA support * - * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003 - 2006 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 @@ -13,7 +13,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> - +#include <asm/cacheflush.h> #include <asm/mach/sysasic.h> #include <asm/mach/dma.h> #include <asm/dma.h> @@ -47,17 +47,31 @@ struct g2_dma_info { static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800; +#define g2_bytes_remaining(i) \ + ((g2_dma->channel[i].size - \ + g2_dma->status[i].size) & 0x0fffffff) + static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - /* FIXME: Do some meaningful completion work here.. */ - return IRQ_HANDLED; -} + int i; -static struct irqaction g2_dma_irq = { - .name = "g2 DMA handler", - .handler = g2_dma_interrupt, - .flags = IRQF_DISABLED, -}; + for (i = 0; i < G2_NR_DMA_CHANNELS; i++) { + if (g2_dma->status[i].status & 0x20000000) { + unsigned int bytes = g2_bytes_remaining(i); + + if (likely(bytes == 0)) { + struct dma_info *info = dev_id; + struct dma_channel *chan = info->channels + i; + + wake_up(&chan->wait_queue); + + return IRQ_HANDLED; + } + } + } + + return IRQ_NONE; +} static int g2_enable_dma(struct dma_channel *chan) { @@ -135,8 +149,14 @@ static int g2_xfer_dma(struct dma_channel *chan) return 0; } +static int g2_get_residue(struct dma_channel *chan) +{ + return g2_bytes_remaining(chan->chan); +} + static struct dma_ops g2_dma_ops = { .xfer = g2_xfer_dma, + .get_residue = g2_get_residue, }; static struct dma_info g2_dma_info = { @@ -148,13 +168,22 @@ static struct dma_info g2_dma_info = { static int __init g2_dma_init(void) { - setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq); + int ret; + + ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, IRQF_DISABLED, + "g2 DMA handler", &g2_dma_info); + if (unlikely(ret)) + return -EINVAL; /* Magic */ g2_dma->wait_state = 27; g2_dma->magic = 0x4659404f; - return register_dmac(&g2_dma_info); + ret = register_dmac(&g2_dma_info); + if (unlikely(ret != 0)) + free_irq(HW_EVENT_G2_DMA, 0); + + return ret; } static void __exit g2_dma_exit(void) @@ -169,4 +198,3 @@ module_exit(g2_dma_exit); MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); MODULE_DESCRIPTION("G2 bus DMA driver"); MODULE_LICENSE("GPL"); - diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c index 30a580aa7cb..3b0b0f60bb3 100644 --- a/arch/sh/drivers/dma/dma-pvr2.c +++ b/arch/sh/drivers/dma/dma-pvr2.c @@ -18,8 +18,8 @@ #include <asm/dma.h> #include <asm/io.h> -static unsigned int xfer_complete = 0; -static int count = 0; +static unsigned int xfer_complete; +static int count; static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -107,4 +107,3 @@ module_exit(pvr2_dma_exit); MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); MODULE_DESCRIPTION("NEC PowerVR 2 DMA driver"); MODULE_LICENSE("GPL"); - diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index e028a2d2a4e..cbbe8bce3d6 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -11,14 +11,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ - #include <linux/init.h> -#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/module.h> #include <asm/dreamcast/dma.h> -#include <asm/signal.h> -#include <asm/irq.h> #include <asm/dma.h> #include <asm/io.h> #include "dma-sh.h" @@ -84,18 +80,23 @@ static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs) static int sh_dmac_request_dma(struct dma_channel *chan) { - char name[32]; + if (unlikely(!chan->flags & DMA_TEI_CAPABLE)) + return 0; - snprintf(name, sizeof(name), "DMAC Transfer End (Channel %d)", + chan->name = kzalloc(32, GFP_KERNEL); + if (unlikely(chan->name == NULL)) + return -ENOMEM; + snprintf(chan->name, 32, "DMAC Transfer End (Channel %d)", chan->chan); return request_irq(get_dmte_irq(chan->chan), dma_tei, - IRQF_DISABLED, name, chan); + IRQF_DISABLED, chan->name, chan); } static void sh_dmac_free_dma(struct dma_channel *chan) { free_irq(get_dmte_irq(chan->chan), chan); + kfree(chan->name); } static void @@ -259,7 +260,7 @@ static int __init sh_dmac_init(void) #ifdef CONFIG_CPU_SH4 make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY); i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0); - if (i < 0) + if (unlikely(i < 0)) return i; #endif @@ -274,7 +275,7 @@ static int __init sh_dmac_init(void) * been set. */ i = dmaor_reset(); - if (i < 0) + if (unlikely(i != 0)) return i; return register_dmac(info); diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile index 365bc16a4a8..9e00cb8a39e 100644 --- a/arch/sh/drivers/pci/Makefile +++ b/arch/sh/drivers/pci/Makefile @@ -6,7 +6,8 @@ obj-y += pci.o obj-$(CONFIG_PCI_AUTO) += pci-auto.o obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o -obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o +obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o +obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ dma-dreamcast.o @@ -14,3 +15,6 @@ obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o obj-$(CONFIG_SH_BIGSUR) += ops-bigsur.o obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o +obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o +obj-$(CONFIG_SH_TITAN) += ops-titan.o +obj-$(CONFIG_SH_LANDISK) += ops-landisk.o diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c index 63b1c6f4b8d..c0af5f7ef41 100644 --- a/arch/sh/drivers/pci/fixups-dreamcast.c +++ b/arch/sh/drivers/pci/fixups-dreamcast.c @@ -4,7 +4,7 @@ * PCI fixups for the Sega Dreamcast * * Copyright (C) 2001, 2002 M. R. Brown - * Copyright (C) 2002, 2003 Paul Mundt + * Copyright (C) 2002, 2003, 2006 Paul Mundt * * This file originally bore the message (with enclosed-$): * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp @@ -45,36 +45,16 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev) printk("PCI: Failed resource fixup\n"); } } - DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources); -void __init pcibios_fixup_bus(struct pci_bus *bus) +int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) { - /* - * We don't have any sub bus to fix up, and this is a rather - * stupid place to put general device fixups. Don't do it. - * Use the pcibios_fixups table or suffer the consequences. + /* + * The interrupt routing semantics here are quite trivial. + * + * We basically only support one interrupt, so we only bother + * updating a device's interrupt line with this single shared + * interrupt. Keeps routing quite simple, doesn't it? */ + return GAPSPCI_IRQ; } - -void __init pcibios_fixup_irqs(void) -{ - struct pci_dev *dev = 0; - - for_each_pci_dev(dev) { - /* - * The interrupt routing semantics here are quite trivial. - * - * We basically only support one interrupt, so we only bother - * updating a device's interrupt line with this single shared - * interrupt. Keeps routing quite simple, doesn't it? - */ - printk(KERN_NOTICE "PCI: Fixing up IRQ routing for device %s\n", - pci_name(dev)); - - dev->irq = GAPSPCI_IRQ; - - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } -} - diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c new file mode 100644 index 00000000000..3e321df65d2 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-r7780rp.c @@ -0,0 +1,45 @@ +/* + * arch/sh/drivers/pci/fixups-r7780rp.c + * + * Highlander R7780RP-1 PCI fixups + * + * Copyright (C) 2003 Lineo uSolutions, Inc. + * Copyright (C) 2004 - 2006 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. + */ +#include <linux/pci.h> +#include "pci-sh4.h" +#include <asm/io.h> + +int pci_fixup_pcic(void) +{ + 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; +} diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c index 0c590fc7a08..e72ceb560d5 100644 --- a/arch/sh/drivers/pci/fixups-rts7751r2d.c +++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c @@ -10,8 +10,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ -#include "pci-sh7751.h" -#include <asm/io.h> +#include "pci-sh4.h" #define PCIMCR_MRSET_OFF 0xBFFFFFFF #define PCIMCR_RFSH_OFF 0xFFFFFFFB @@ -22,22 +21,23 @@ int pci_fixup_pcic(void) bcr1 = inl(SH7751_BCR1); bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ - outl(bcr1, PCI_REG(SH7751_PCIBCR1)); + pci_write_reg(bcr1, SH4_PCIBCR1); /* Enable all interrupts, so we known what to fix */ - outl(0x0000c3ff, PCI_REG(SH7751_PCIINTM)); - outl(0x0000380f, PCI_REG(SH7751_PCIAINTM)); + pci_write_reg(0x0000c3ff, SH4_PCIINTM); + pci_write_reg(0x0000380f, SH4_PCIAINTM); - outl(0xfb900047, PCI_REG(SH7751_PCICONF1)); - outl(0xab000001, PCI_REG(SH7751_PCICONF4)); + pci_write_reg(0xfb900047, SH7751_PCICONF1); + pci_write_reg(0xab000001, SH7751_PCICONF4); mcr = inl(SH7751_MCR); mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; - outl(mcr, PCI_REG(SH7751_PCIMCR)); + 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); - outl(0x0c000000, PCI_REG(SH7751_PCICONF5)); - outl(0xd0000000, PCI_REG(SH7751_PCICONF6)); - outl(0x0c000000, PCI_REG(SH7751_PCILAR0)); - outl(0x00000000, PCI_REG(SH7751_PCILAR1)); return 0; } diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c index 57ac26c2171..2e8a18b7ee5 100644 --- a/arch/sh/drivers/pci/fixups-sh03.c +++ b/arch/sh/drivers/pci/fixups-sh03.c @@ -3,11 +3,7 @@ #include <linux/types.h> #include <linux/pci.h> -/* - * IRQ functions - */ - -int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev) +int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) { int irq; @@ -17,8 +13,9 @@ int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev) case 8: return 5; /* eth1 */ case 6: return 2; /* PCI bridge */ default: - printk("PCI: Bad IRQ mapping request for slot %d\n", slot); - return 2; + printk(KERN_ERR "PCI: Bad IRQ mapping request " + "for slot %d\n", slot); + return 2; } } else { switch (pin) { @@ -32,30 +29,3 @@ int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev) } return irq; } - -static u8 __init sh03_no_swizzle(struct pci_dev *dev, u8 *pin) -{ - /* no swizzling */ - return PCI_SLOT(dev->devfn); -} - -static int sh03_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq = -1; - - /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ - irq = pcibios_map_platform_irq(slot, pin, dev); - if( irq < 0 ) { - pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); - return irq; - } - - pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); - - return irq; -} - -void __init pcibios_fixup_irqs(void) -{ - pci_fixup_irqs(sh03_no_swizzle, sh03_pci_lookup_irq); -} diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c index ae82c6ca05e..5da501bd77b 100644 --- a/arch/sh/drivers/pci/ops-bigsur.c +++ b/arch/sh/drivers/pci/ops-bigsur.c @@ -10,15 +10,12 @@ * * PCI initialization for the Hitachi Big Sur Evaluation 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" +#include "pci-sh4.h" #include <asm/bigsur/bigsur.h> #define BIGSUR_PCI_IO 0x4000 @@ -41,11 +38,11 @@ static struct resource sh7751_mem_resource = { extern struct pci_ops sh7751_pci_ops; struct pci_channel board_pci_channels[] = { - { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, + { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, { 0, } }; -static struct sh7751_pci_address_map sh7751_pci_map = { +static struct sh4_pci_address_map sh7751_pci_map = { .window0 = { .base = SH7751_CS3_BASE_ADDR, .size = BIGSUR_LSR0_SIZE, @@ -58,7 +55,7 @@ static struct sh7751_pci_address_map sh7751_pci_map = { }; /* - * Initialize the Big Sur PCI interface + * Initialize the Big Sur PCI interface * Setup hardware to be Central Funtion * Copy the BSR regs to the PCI interface * Setup PCI windows into local RAM @@ -68,15 +65,15 @@ int __init pcibios_init_platform(void) return sh7751_pcic_init(&sh7751_pci_map); } -int pcibios_map_platform_irq(u8 slot, u8 pin) +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { - /* + /* * The Big Sur can be used in a CPCI chassis, but the SH7751 PCI * interface is on the wrong end of the board so that it can also * support a V320 CPI interface chip... Therefor the IRQ mapping is * somewhat use dependent... I'l assume a linear map for now, i.e. * INTA=slot0,pin0... INTD=slot3,pin0... - */ + */ int irq = (slot + pin-1) % 4 + BIGSUR_SH7751_PCI_IRQ_BASE; PCIDBG(2, "PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", @@ -84,4 +81,3 @@ int pcibios_map_platform_irq(u8 slot, u8 pin) return irq; } - diff --git a/arch/sh/drivers/pci/ops-landisk.c b/arch/sh/drivers/pci/ops-landisk.c new file mode 100644 index 00000000000..ada301c21fe --- /dev/null +++ b/arch/sh/drivers/pci/ops-landisk.c @@ -0,0 +1,68 @@ +/* + * 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/config.h> +#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 = 0x4000, + .end = 0x4000 + 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-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c new file mode 100644 index 00000000000..554d5ed2c58 --- /dev/null +++ b/arch/sh/drivers/pci/ops-r7780rp.c @@ -0,0 +1,75 @@ +/* + * 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/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <asm/r7780rp/r7780rp.h> +#include <asm/io.h> +#include "pci-sh4.h" + +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) +{ + switch (slot) { + case 0: return IRQ_PCISLOT1; /* PCI Interrupt #1 */ + case 1: return IRQ_PCISLOT2; /* PCI Interrupt #2 */ + case 2: return IRQ_PCISLOT3; /* PCI Interrupt #3 */ + case 3: return IRQ_PCISLOT4; /* PCI Interrupt E4 */ + default: + printk(KERN_ERR "PCI: Bad IRQ mapping " + "request for slot %d, func %d\n", slot, pin-1); + return -1; + } +} + +static struct resource sh7780_io_resource = { + .name = "SH7780_IO", + .start = 0x2000, + .end = 0x2000 + 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 index 83171d10141..88f44e24542 100644 --- a/arch/sh/drivers/pci/ops-rts7751r2d.c +++ b/arch/sh/drivers/pci/ops-rts7751r2d.c @@ -17,12 +17,11 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/module.h> - -#include <asm/io.h> -#include "pci-sh7751.h" #include <asm/rts7751r2d/rts7751r2d.h> +#include <asm/io.h> +#include "pci-sh4.h" -int __init pcibios_map_platform_irq(u8 slot, u8 pin) +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { switch (slot) { case 0: return IRQ_PCISLOT1; /* PCI Extend slot #1 */ @@ -52,12 +51,12 @@ static struct resource sh7751_mem_resource = { extern struct pci_ops sh7751_pci_ops; struct pci_channel board_pci_channels[] = { - { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, + { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, { NULL, NULL, NULL, 0, 0 }, }; EXPORT_SYMBOL(board_pci_channels); -static struct sh7751_pci_address_map sh7751_pci_map = { +static struct sh4_pci_address_map sh7751_pci_map = { .window0 = { .base = SH7751_CS3_BASE_ADDR, .size = 0x04000000, @@ -68,7 +67,7 @@ static struct sh7751_pci_address_map sh7751_pci_map = { .size = 0x00000000, /* Unused */ }, - .flags = SH7751_PCIC_NO_RESET, + .flags = SH4_PCIC_NO_RESET, }; int __init pcibios_init_platform(void) diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c new file mode 100644 index 00000000000..2d4371009a5 --- /dev/null +++ b/arch/sh/drivers/pci/ops-sh4.c @@ -0,0 +1,164 @@ +/* + * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780). + * + * Copyright (C) 2002 - 2006 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 <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); + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ +static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + unsigned long flags; + u32 data; + + /* + * 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); + + switch (size) { + case 1: + *val = (data >> ((where & 3) << 3)) & 0xff; + break; + case 2: + *val = (data >> ((where & 2) << 3)) & 0xffff; + break; + case 4: + *val = data; + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Since SH4 only does 32bit access we'll have to do a read, + * mask,write operation. + * We'll allow an odd byte offset, though it should be illegal. + */ +static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + 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); + + switch (size) { + case 1: + shift = (where & 3) << 3; + data &= ~(0xff << shift); + data |= ((val & 0xff) << shift); + break; + case 2: + shift = (where & 2) << 3; + data &= ~(0xffff << shift); + data |= ((val & 0xffff) << shift); + break; + case 4: + data = val; + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + + pci_write_reg(data, SH4_PCIPDR); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops sh4_pci_ops = { + .read = sh4_pci_read, + .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 * __init pcibios_setup(char *str) +{ + if (!strcmp(str, "off")) { + pci_probe = 0; + return NULL; + } + + return str; +} diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c index 3cbd14dd28f..53dd893d4e5 100644 --- a/arch/sh/drivers/pci/ops-snapgear.c +++ b/arch/sh/drivers/pci/ops-snapgear.c @@ -2,7 +2,7 @@ * 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. @@ -12,15 +12,11 @@ * * PCI initialization for the SnapGear boards */ - #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" +#include "pci-sh4.h" #define SNAPGEAR_PCI_IO 0x4000 #define SNAPGEAR_PCI_MEM 0xfd000000 @@ -43,14 +39,12 @@ static struct resource sh7751_mem_resource = { .flags = IORESOURCE_MEM, }; -extern struct pci_ops sh7751_pci_ops; - struct pci_channel board_pci_channels[] = { - { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, + { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, { 0, } }; -static struct sh7751_pci_address_map sh7751_pci_map = { +static struct sh4_pci_address_map sh7751_pci_map = { .window0 = { .base = SH7751_CS2_BASE_ADDR, .size = SNAPGEAR_LSR0_SIZE, @@ -61,11 +55,11 @@ static struct sh7751_pci_address_map sh7751_pci_map = { .size = SNAPGEAR_LSR1_SIZE, }, - .flags = SH7751_PCIC_NO_RESET, + .flags = SH4_PCIC_NO_RESET, }; /* - * Initialize the SnapGear PCI interface + * 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 @@ -75,7 +69,7 @@ int __init pcibios_init_platform(void) return sh7751_pcic_init(&sh7751_pci_map); } -int __init pcibios_map_platform_irq(u8 slot, u8 pin) +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { int irq = -1; @@ -98,4 +92,3 @@ 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 new file mode 100644 index 00000000000..c6097bcd97f --- /dev/null +++ b/arch/sh/drivers/pci/ops-titan.c @@ -0,0 +1,83 @@ +/* + * 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/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/titan.h> +#include "pci-sh4.h" + +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) +{ + int irq = -1; + + switch (slot) { + case 0: irq = TITAN_IRQ_WAN; break; /* eth0 (WAN) */ + case 1: irq = TITAN_IRQ_LAN; break; /* eth1 (LAN) */ + case 2: irq = TITAN_IRQ_MPCIA; break; /* mPCI A */ + case 3: irq = TITAN_IRQ_MPCIB; break; /* mPCI B */ + case 4: irq = TITAN_IRQ_USB; break; /* USB */ + default: + printk(KERN_INFO "PCI: Bad IRQ mapping " + "request for slot %d\n", slot); + return -1; + } + + 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 index 4cef4d1d8c8..ecf16344f94 100644 --- a/arch/sh/drivers/pci/pci-auto.c +++ b/arch/sh/drivers/pci/pci-auto.c @@ -45,11 +45,11 @@ #include <linux/types.h> #include <linux/pci.h> -#undef DEBUG -#ifdef DEBUG +#define DEBUG +#ifdef DEBUG #define DBG(x...) printk(x) #else -#define DBG(x...) +#define DBG(x...) #endif /* @@ -102,7 +102,7 @@ static u32 pciauto_upper_iospc; static u32 pciauto_lower_memspc; static u32 pciauto_upper_memspc; -static void __init +static void __init pciauto_setup_bars(struct pci_channel *hose, int top_bus, int current_bus, @@ -116,7 +116,6 @@ pciauto_setup_bars(struct pci_channel *hose, int found_mem64 = 0; for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) { -#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) u32 bar_addr; /* Read the old BAR value */ @@ -125,7 +124,6 @@ pciauto_setup_bars(struct pci_channel *hose, pci_devfn, bar, &bar_addr); -#endif /* Tickle the BAR and get the response */ early_write_config_dword(hose, top_bus, @@ -140,8 +138,7 @@ pciauto_setup_bars(struct pci_channel *hose, bar, &bar_response); -#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) - /* + /* * 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. @@ -151,7 +148,6 @@ pciauto_setup_bars(struct pci_channel *hose, pci_devfn, bar, bar_addr); -#endif /* If BAR is not implemented go to the next BAR */ if (!bar_response) @@ -177,7 +173,7 @@ retry: PCI_BASE_ADDRESS_MEM_TYPE_64) found_mem64 = 1; - addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; upper_limit = &pciauto_upper_memspc; lower_limit = &pciauto_lower_memspc; DBG(" Mem"); @@ -193,22 +189,22 @@ retry: 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 = io_resource_inuse->child; - pciauto_lower_iospc = + pciauto_lower_iospc = io_resource_inuse->start; - pciauto_upper_iospc = + pciauto_upper_iospc = io_resource_inuse->end + 1; goto retry; } } else { if (mem_resource_inuse->child) { - mem_resource_inuse = + mem_resource_inuse = mem_resource_inuse->child; - pciauto_lower_memspc = + pciauto_lower_memspc = mem_resource_inuse->start; - pciauto_upper_memspc = + pciauto_upper_memspc = mem_resource_inuse->end + 1; goto retry; } @@ -230,7 +226,7 @@ retry: * 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, @@ -362,7 +358,6 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, { u32 temp; -#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) /* * [jsun] we always bump up baselines a little, so that if there * nothing behind P2P bridge, we don't wind up overlapping IO/MEM @@ -370,7 +365,6 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, */ pciauto_lower_memspc += 1; pciauto_lower_iospc += 1; -#endif /* * Configure subordinate bus number. The PCI subsystem @@ -396,11 +390,6 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, * configured by this routine to happily live behind a * P2P bridge in a system. */ -#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) - pciauto_lower_memspc += 0x00400000; - pciauto_lower_iospc += 0x00004000; -#endif - /* Align memory and I/O to 4KB and 4 byte boundaries. */ pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) & ~(0x1000 - 1); @@ -433,12 +422,12 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) 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) @@ -471,9 +460,6 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { DBG(" Bridge: primary=%.2x, secondary=%.2x\n", current_bus, sub_bus + 1); -#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) - pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1); -#endif 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", @@ -490,10 +476,10 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) 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); diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h new file mode 100644 index 00000000000..5a61d6041f2 --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh4.h @@ -0,0 +1,180 @@ +#ifndef __PCI_SH4_H +#define __PCI_SH4_H + +#ifdef CONFIG_CPU_SUBTYPE_SH7780 +#include "pci-sh7780.h" +#else +#include "pci-sh7751.h" +#endif + +#include <asm/io.h> + +/* startup values */ +#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 + +#define SH4_PCICR 0x100 /* PCI Control Register */ + #define SH4_PCICR_PREFIX 0xA5000000 /* CR prefix for write */ + #define SH4_PCICR_FTO 0x00000400 /* TRDY/IRDY Enable */ + #define SH4_PCICR_TRSB 0x00000200 /* Target Read Single */ + #define SH4_PCICR_BSWP 0x00000100 /* Target Byte Swap */ + #define SH4_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */ + #define SH4_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */ + #define SH4_PCICR_MD 0x00000030 /* MD9 and MD10 status */ + #define SH4_PCICR_SERR 0x00000008 /* SERR output assert */ + #define SH4_PCICR_INTA 0x00000004 /* INTA output assert */ + #define SH4_PCICR_PRST 0x00000002 /* PCI Reset Assert */ + #define SH4_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */ +#define SH4_PCILSR0 0x104 /* PCI Local Space Register0 */ +#define SH4_PCILSR1 0x108 /* PCI Local Space Register1 */ +#define SH4_PCILAR0 0x10C /* PCI Local Addr Register1 */ +#define SH4_PCILAR1 0x110 /* PCI Local Addr Register1 */ +#define SH4_PCIINT 0x114 /* PCI Interrupt Register */ + #define SH4_PCIINT_MLCK 0x00008000 /* Master Lock Error */ + #define SH4_PCIINT_TABT 0x00004000 /* Target Abort Error */ + #define SH4_PCIINT_TRET 0x00000200 /* Target Retry Error */ + #define SH4_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */ + #define SH4_PCIINT_PRTY 0x00000080 /* Address Parity Error */ + #define SH4_PCIINT_SERR 0x00000040 /* SERR Detection Error */ + #define SH4_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */ + #define SH4_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Err Det. */ + #define SH4_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */ + #define SH4_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */ + #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_PCIALR 0x11C /* Error Address Register */ +#define SH4_PCICLR 0x120 /* Error Command/Data */ + #define SH4_PCICLR_MPIO 0x80000000 + #define SH4_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */ + #define SH4_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */ + #define SH4_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */ + #define SH4_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */ + #define SH4_PCICLR_TGT 0x04000000 /* Target Transfer Error */ + #define SH4_PCICLR_CMDL 0x0000000F /* PCI Command at Error */ +#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_TABT 0x00000008 /* Target Abort */ + #define SH4_PCIAINT_MABT 0x00000004 /* Master Abort */ + #define SH4_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */ + #define SH4_PCIAINT_WDPE 0x00000001 /* Write Data Parity Error */ +#define SH4_PCIAINTM 0x134 /* Arbiter Int. Mask Register */ +#define SH4_PCIBMLR 0x138 /* Error Bus Master Register */ + #define SH4_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */ + #define SH4_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */ + #define SH4_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */ + #define SH4_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */ + #define SH4_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */ +#define SH4_PCIDMABT 0x140 /* DMA Transfer Arb. Register */ + #define SH4_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */ +#define SH4_PCIDPA0 0x180 /* DMA0 Transfer Addr. */ +#define SH4_PCIDLA0 0x184 /* DMA0 Local Addr. */ +#define SH4_PCIDTC0 0x188 /* DMA0 Transfer Cnt. */ +#define SH4_PCIDCR0 0x18C /* DMA0 Control Register */ + #define SH4_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */ + #define SH4_PCIDCR_MAST 0x00000100 /* DMA Termination Type */ + #define SH4_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/ + #define SH4_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */ + #define SH4_PCIDCR_LHLD 0x00000020 /* Local Address Control */ + #define SH4_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/ + #define SH4_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */ + #define SH4_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */ + #define SH4_PCIDCR_STOP 0x00000002 /* Force DMA Stop */ + #define SH4_PCIDCR_STRT 0x00000001 /* DMA Start */ +#define SH4_PCIDPA1 0x190 /* DMA1 Transfer Addr. */ +#define SH4_PCIDLA1 0x194 /* DMA1 Local Addr. */ +#define SH4_PCIDTC1 0x198 /* DMA1 Transfer Cnt. */ +#define SH4_PCIDCR1 0x19C /* DMA1 Control Register */ +#define SH4_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. */ +#define SH4_PCIDLA2 0x1A4 /* DMA2 Local Addr. */ +#define SH4_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. */ +#define SH4_PCIDCR2 0x1AC /* DMA2 Control Register */ +#define SH4_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. */ +#define SH4_PCIDLA3 0x1B4 /* DMA3 Local Addr. */ +#define SH4_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. */ +#define SH4_PCIDCR3 0x1BC /* DMA3 Control Register */ +#define SH4_PCIPAR 0x1C0 /* PIO Address Register */ + #define SH4_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */ + #define SH4_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */ + #define SH4_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */ + #define SH4_PCIPAR_REGAD 0x000000FC /* Register Address Number */ +#define SH4_PCIMBR 0x1C4 /* Memory Base Address */ + #define SH4_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */ + #define SH4_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */ +#define SH4_PCIIOBR 0x1C8 /* I/O Base Address Register */ + #define SH4_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */ + #define SH4_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */ +#define SH4_PCIPINT 0x1CC /* Power Mgmnt Int. Register */ + #define SH4_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */ + #define SH4_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */ +#define SH4_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */ +#define SH4_PCICLKR 0x1D4 /* Clock Ctrl. Register */ + #define SH4_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */ + #define SH4_PCICLKR_BCSTP 0x00000001 /* BCLK Clock Stop */ +/* For definitions of BCR, MCR see ... */ +#define SH4_PCIBCR1 0x1E0 /* Memory BCR1 Register */ + #define SH4_PCIMBR0 SH4_PCIBCR1 +#define SH4_PCIBCR2 0x1E4 /* Memory BCR2 Register */ + #define SH4_PCIMBMR0 SH4_PCIBCR2 +#define SH4_PCIWCR1 0x1E8 /* Wait Control 1 Register */ +#define SH4_PCIWCR2 0x1EC /* Wait Control 2 Register */ +#define SH4_PCIWCR3 0x1F0 /* Wait Control 3 Register */ + #define SH4_PCIMBR2 SH4_PCIWCR3 +#define SH4_PCIMCR 0x1F4 /* Memory Control Register */ +#define SH4_PCIBCR3 0x1f8 /* Memory BCR3 Register */ +#define SH4_PCIPCTR 0x200 /* Port Control Register */ + #define SH4_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */ + #define SH4_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */ + #define SH4_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */ + #define SH4_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */ + #define SH4_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */ + #define SH4_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */ + #define SH4_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */ + #define SH4_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */ + #define SH4_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */ +#define SH4_PCIPDTR 0x204 /* Port Data Register */ + #define SH4_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */ + #define SH4_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */ + #define SH4_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */ + #define SH4_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */ + #define SH4_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */ + #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); + +struct sh4_pci_address_space { + unsigned long base; + unsigned long size; +}; + +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) +{ + outl(val, PCI_REG(reg)); +} + +static inline unsigned long pci_read_reg(unsigned long reg) +{ + return inl(PCI_REG(reg)); +} +#endif /* __PCI_SH4_H */ diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 682f3dae305..dbe83788498 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -15,180 +15,14 @@ #undef DEBUG -#include <linux/types.h> -#include <linux/kernel.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/sched.h> -#include <linux/ioport.h> +#include <linux/types.h> #include <linux/errno.h> -#include <linux/irq.h> #include <linux/delay.h> - -#include <asm/machvec.h> +#include "pci-sh4.h" +#include <asm/addrspace.h> #include <asm/io.h> -#include "pci-sh7751.h" - -static unsigned int pci_probe = PCI_PROBE_CONF1; -extern int pci_fixup_pcic(void); - -void pcibios_fixup_irqs(void) __attribute__ ((weak)); - -/* - * Direct access to PCI hardware... - */ - -#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) - -/* - * Functions for accessing PCI configuration space with type 1 accesses - */ -static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - unsigned long flags; - u32 data; - - /* - * PCIPDR may only be accessed as 32 bit words, - * so we must do byte alignment by hand - */ - local_irq_save(flags); - outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); - data = inl(PCI_REG(SH7751_PCIPDR)); - local_irq_restore(flags); - - switch (size) { - case 1: - *val = (data >> ((where & 3) << 3)) & 0xff; - break; - case 2: - *val = (data >> ((where & 2) << 3)) & 0xffff; - break; - case 4: - *val = data; - break; - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } - - return PCIBIOS_SUCCESSFUL; -} - -/* - * Since SH7751 only does 32bit access we'll have to do a read, - * mask,write operation. - * We'll allow an odd byte offset, though it should be illegal. - */ -static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - unsigned long flags; - int shift; - u32 data; - - local_irq_save(flags); - outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); - data = inl(PCI_REG(SH7751_PCIPDR)); - local_irq_restore(flags); - - switch (size) { - case 1: - shift = (where & 3) << 3; - data &= ~(0xff << shift); - data |= ((val & 0xff) << shift); - break; - case 2: - shift = (where & 2) << 3; - data &= ~(0xffff << shift); - data |= ((val & 0xffff) << shift); - break; - case 4: - data = val; - break; - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } - - outl(data, PCI_REG(SH7751_PCIPDR)); - - return PCIBIOS_SUCCESSFUL; -} - -#undef CONFIG_CMD - -struct pci_ops sh7751_pci_ops = { - .read = sh7751_pci_read, - .write = sh7751_pci_write, -}; - -static int __init pci_check_direct(void) -{ - unsigned int tmp, id; - - /* check for SH7751/SH7751R hardware */ - id = inl(SH7751_PCIREG_BASE+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; - } - - /* - * Check if configuration works. - */ - if (pci_probe & PCI_PROBE_CONF1) { - tmp = inl (PCI_REG(SH7751_PCIPAR)); - outl (0x80000000, PCI_REG(SH7751_PCIPAR)); - if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) { - outl (tmp, PCI_REG(SH7751_PCIPAR)); - printk(KERN_INFO "PCI: Using configuration type 1\n"); - request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1"); - return 0; - } - outl (tmp, PCI_REG(SH7751_PCIPAR)); - } - - pr_debug("PCI: pci_check_direct failed\n"); - return -EINVAL; -} - -/***************************************************************************************/ - -/* - * Handle bus scanning and 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); - -/* - * Called after each bus is probed, but before its children - * are examined. - */ - -void __init pcibios_fixup_bus(struct pci_bus *b) -{ - pci_read_bridge_bases(b); -} /* * Initialization. Try all known PCI access methods. Note that we support @@ -196,25 +30,29 @@ void __init pcibios_fixup_bus(struct pci_bus *b) * to access config space. * * Note that the platform specific initialization (BSC registers, and memory - * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it - * exitst and via the platform defined function pcibios_init_platform(). - * See pci_bigsur.c for implementation; - * - * The BIOS version of the pci functions is not yet implemented but it is left - * in for completeness. Currently an error will be genereated at compile time. + * 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"); - if ((ret = pci_check_direct()) != 0) + + /* 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); static int __init __area_sdram_check(unsigned int area) @@ -223,26 +61,26 @@ static int __init __area_sdram_check(unsigned int area) word = inl(SH7751_BCR1); /* check BCR for SDRAM in area */ - if(((word >> area) & 1) == 0) { + if (((word >> area) & 1) == 0) { printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", area, word); return 0; } - outl(word, PCI_REG(SH7751_PCIBCR1)); + pci_write_reg(word, SH4_PCIBCR1); word = (u16)inw(SH7751_BCR2); /* check BCR2 for 32bit SDRAM interface*/ - if(((word >> (area << 1)) & 0x3) != 0x3) { + if (((word >> (area << 1)) & 0x3) != 0x3) { printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", area, word); return 0; } - outl(word, PCI_REG(SH7751_PCIBCR2)); + pci_write_reg(word, SH4_PCIBCR2); return 1; } -int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) +int __init sh7751_pcic_init(struct sh4_pci_address_map *map) { u32 reg; u32 word; @@ -251,39 +89,39 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) reg = inl(SH7751_BCR1); reg |= 0x80000; outl(reg, SH7751_BCR1); - + /* Turn the clocks back on (not done in reset)*/ - outl(0, PCI_REG(SH7751_PCICLKR)); + pci_write_reg(0, SH4_PCICLKR); /* Clear Powerdown IRQ's (not done in reset) */ - word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0; - outl(word, PCI_REG(SH7751_PCIPINT)); + 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 & SH7751_PCIC_NO_RESET)) { + if (!(map->flags & SH4_PCIC_NO_RESET)) { /* toggle PCI reset pin */ - word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST; - outl(word,PCI_REG(SH7751_PCICR)); + 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 = SH7751_PCICR_PREFIX; - outl(word,PCI_REG(SH7751_PCICR)); + word = SH4_PCICR_PREFIX; + pci_write_reg(word, SH4_PCICR); } - + /* set the command/status bits to: * Wait Cycle Control + Parity Enable + Bus Master + * Mem space enable */ word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; - outl(word, PCI_REG(SH7751_PCICONF1)); + pci_write_reg(word, SH7751_PCICONF1); /* define this host as the host bridge */ - word = SH7751_PCI_HOST_BRIDGE << 24; - outl(word, PCI_REG(SH7751_PCICONF2)); + word = PCI_BASE_CLASS_BRIDGE << 24; + pci_write_reg(word, SH7751_PCICONF2); /* Set IO and Mem windows to local address * Make PCI and local address the same for easy 1 to 1 mapping @@ -291,46 +129,49 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) * Window1 = map->window1.size @ cached area base = SDRAM */ word = map->window0.size - 1; - outl(word, PCI_REG(SH7751_PCILSR0)); + pci_write_reg(word, SH4_PCILSR0); word = map->window1.size - 1; - outl(word, PCI_REG(SH7751_PCILSR1)); + pci_write_reg(word, SH4_PCILSR1); /* Set the values on window 0 PCI config registers */ word = P2SEGADDR(map->window0.base); - outl(word, PCI_REG(SH7751_PCILAR0)); - outl(word, PCI_REG(SH7751_PCICONF5)); + 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); - outl(word, PCI_REG(SH7751_PCILAR1)); - outl(word, PCI_REG(SH7751_PCICONF6)); + pci_write_reg(word, SH4_PCILAR1); + pci_write_reg(word, SH7751_PCICONF6); - /* Set the local 16MB PCI memory space window to + /* Set the local 16MB PCI memory space window to * the lowest PCI mapped address */ - word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK; - PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word); - outl(word , PCI_REG(SH7751_PCIMBR)); + word = PCIBIOS_MIN_MEM & 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 + * IO addresses will be translated to the * PCI IO window base address */ - PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO, - (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO); + pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", + PCIBIOS_MIN_IO, (64 << 10), + SH4_PCI_IO_BASE + PCIBIOS_MIN_IO); - /* + /* * XXX: For now, leave this board-specific. In the event we have other * boards that need to do similar work, this can be wrapped. */ #ifdef CONFIG_SH_BIGSUR - bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0); + bigsur_port_map(PCIBIOS_MIN_IO, (64 << 10), + SH4_PCI_IO_BASE + PCIBIOS_MIN_IO, 0); #endif - /* Make sure the MSB's of IO window are set to access PCI space correctly */ - word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK; - PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word); - outl(word, PCI_REG(SH7751_PCIIOBR)); - + /* Make sure the MSB's of IO window are set to access PCI space + * correctly */ + word = PCIBIOS_MIN_IO & SH4_PCIIOBR_MASK; + pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word); + pci_write_reg(word, SH4_PCIIOBR); + /* Set PCI WCRx, BCRx's, copy from BSC locations */ /* check BCR for SDRAM in specified area */ @@ -349,13 +190,13 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) /* configure the wait control registers */ word = inl(SH7751_WCR1); - outl(word, PCI_REG(SH7751_PCIWCR1)); + pci_write_reg(word, SH4_PCIWCR1); word = inl(SH7751_WCR2); - outl(word, PCI_REG(SH7751_PCIWCR2)); + pci_write_reg(word, SH4_PCIWCR2); word = inl(SH7751_WCR3); - outl(word, PCI_REG(SH7751_PCIWCR3)); + pci_write_reg(word, SH4_PCIWCR3); word = inl(SH7751_MCR); - outl(word, PCI_REG(SH7751_PCIMCR)); + pci_write_reg(word, SH4_PCIMCR); /* NOTE: I'm ignoring the PCI error IRQs for now.. * TODO: add support for the internal error interrupts and @@ -368,49 +209,8 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) /* SH7751 init done, set central function init complete */ /* use round robin mode to stop a device starving/overruning */ - word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM; - outl(word,PCI_REG(SH7751_PCICR)); + word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM; + pci_write_reg(word, SH4_PCICR); return 1; } - -char * __init pcibios_setup(char *str) -{ - if (!strcmp(str, "off")) { - pci_probe = 0; - return NULL; - } - - return str; -} - -/* - * IRQ functions - */ -static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin) -{ - /* no swizzling */ - return PCI_SLOT(dev->devfn); -} - -static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq = -1; - - /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ - irq = pcibios_map_platform_irq(slot,pin); - if( irq < 0 ) { - pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); - return irq; - } - - pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); - - return irq; -} - -void __init pcibios_fixup_irqs(void) -{ - pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq); -} - diff --git a/arch/sh/drivers/pci/pci-sh7751.h b/arch/sh/drivers/pci/pci-sh7751.h index 1fee5cae10d..68e3cb5e6be 100644 --- a/arch/sh/drivers/pci/pci-sh7751.h +++ b/arch/sh/drivers/pci/pci-sh7751.h @@ -3,7 +3,7 @@ * * Dustin McIntire (dustin@sensoria.com) (c) 2001 * Paul Mundt (lethal@linux-sh.org) (c) 2003 - * + * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * @@ -12,28 +12,6 @@ #ifndef _PCI_SH7751_H_ #define _PCI_SH7751_H_ -#include <linux/pci.h> - -/* set debug level 4=verbose...1=terse */ -//#define DEBUG_PCI 3 -#undef DEBUG_PCI - -#ifdef DEBUG_PCI -#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); } -#else -#define PCIDBG(n, x...) -#endif - -/* startup values */ -#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 - /* Platform Specific Values */ #define SH7751_VENDOR_ID 0x1054 #define SH7751_DEVICE_ID 0x3505 @@ -128,131 +106,6 @@ #define SH7751_PCICONF17_PMEN 0x00010000 /* PME Enable */ #define SH7751_PCICONF17_PWST 0x00000003 /* Power State */ /* SH7715 Internal PCI Registers */ -#define SH7751_PCICR 0x100 /* PCI Control Register */ - #define SH7751_PCICR_PREFIX 0xA5000000 /* CR prefix for write */ - #define SH7751_PCICR_TRSB 0x00000200 /* Target Read Single */ - #define SH7751_PCICR_BSWP 0x00000100 /* Target Byte Swap */ - #define SH7751_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */ - #define SH7751_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */ - #define SH7751_PCICR_MD 0x00000030 /* MD9 and MD10 status */ - #define SH7751_PCICR_SERR 0x00000008 /* SERR output assert */ - #define SH7751_PCICR_INTA 0x00000004 /* INTA output assert */ - #define SH7751_PCICR_PRST 0x00000002 /* PCI Reset Assert */ - #define SH7751_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */ -#define SH7751_PCILSR0 0x104 /* PCI Local Space Register0 */ -#define SH7751_PCILSR1 0x108 /* PCI Local Space Register1 */ -#define SH7751_PCILAR0 0x10C /* PCI Local Address Register1 */ -#define SH7751_PCILAR1 0x110 /* PCI Local Address Register1 */ -#define SH7751_PCIINT 0x114 /* PCI Interrupt Register */ - #define SH7751_PCIINT_MLCK 0x00008000 /* Master Lock Error */ - #define SH7751_PCIINT_TABT 0x00004000 /* Target Abort Error */ - #define SH7751_PCIINT_TRET 0x00000200 /* Target Retry Error */ - #define SH7751_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */ - #define SH7751_PCIINT_PRTY 0x00000080 /* Address Parity Error */ - #define SH7751_PCIINT_SERR 0x00000040 /* SERR Detection Error */ - #define SH7751_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */ - #define SH7751_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Error Det. */ - #define SH7751_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */ - #define SH7751_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */ - #define SH7751_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */ - #define SH7751_PCIINT_MRPD 0x00000002 /* Master Read PERR Detect */ -#define SH7751_PCIINTM 0x118 /* PCI Interrupt Mask Register */ -#define SH7751_PCIALR 0x11C /* Error Address Register */ -#define SH7751_PCICLR 0x120 /* Error Command/Data Register */ - #define SH7751_PCICLR_MPIO 0x80000000 /* Error Command/Data Register */ - #define SH7751_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */ - #define SH7751_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */ - #define SH7751_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */ - #define SH7751_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */ - #define SH7751_PCICLR_TGT 0x04000000 /* Target Transfer Error */ - #define SH7751_PCICLR_CMDL 0x0000000F /* PCI Command at Error */ -#define SH7751_PCIAINT 0x130 /* Arbiter Interrupt Register */ - #define SH7751_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */ - #define SH7751_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */ - #define SH7751_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */ - #define SH7751_PCIAINT_TABT 0x00000008 /* Target Abort */ - #define SH7751_PCIAINT_MABT 0x00000004 /* Master Abort */ - #define SH7751_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */ - #define SH7751_PCIAINT_WDPE 0x00000002 /* Write Data Parity Error */ -#define SH7751_PCIAINTM 0x134 /* Arbiter Int. Mask Register */ -#define SH7751_PCIBMLR 0x138 /* Error Bus Master Register */ - #define SH7751_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */ - #define SH7751_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */ - #define SH7751_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */ - #define SH7751_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */ - #define SH7751_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */ -#define SH7751_PCIDMABT 0x140 /* DMA Transfer Arb. Register */ - #define SH7751_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */ -#define SH7751_PCIDPA0 0x180 /* DMA0 Transfer Addr. Register */ -#define SH7751_PCIDLA0 0x184 /* DMA0 Local Addr. Register */ -#define SH7751_PCIDTC0 0x188 /* DMA0 Transfer Cnt. Register */ -#define SH7751_PCIDCR0 0x18C /* DMA0 Control Register */ - #define SH7751_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */ - #define SH7751_PCIDCR_MAST 0x00000100 /* DMA Termination Type */ - #define SH7751_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/ - #define SH7751_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */ - #define SH7751_PCIDCR_LHLD 0x00000020 /* Local Address Control */ - #define SH7751_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/ - #define SH7751_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */ - #define SH7751_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */ - #define SH7751_PCIDCR_STOP 0x00000002 /* Force DMA Stop */ - #define SH7751_PCIDCR_STRT 0x00000001 /* DMA Start */ -#define SH7751_PCIDPA1 0x190 /* DMA1 Transfer Addr. Register */ -#define SH7751_PCIDLA1 0x194 /* DMA1 Local Addr. Register */ -#define SH7751_PCIDTC1 0x198 /* DMA1 Transfer Cnt. Register */ -#define SH7751_PCIDCR1 0x19C /* DMA1 Control Register */ -#define SH7751_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. Register */ -#define SH7751_PCIDLA2 0x1A4 /* DMA2 Local Addr. Register */ -#define SH7751_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. Register */ -#define SH7751_PCIDCR2 0x1AC /* DMA2 Control Register */ -#define SH7751_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. Register */ -#define SH7751_PCIDLA3 0x1B4 /* DMA3 Local Addr. Register */ -#define SH7751_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. Register */ -#define SH7751_PCIDCR3 0x1BC /* DMA3 Control Register */ -#define SH7751_PCIPAR 0x1C0 /* PIO Address Register */ - #define SH7751_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */ - #define SH7751_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */ - #define SH7751_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */ - #define SH7751_PCIPAR_REGAD 0x000000FC /* Register Address Number */ -#define SH7751_PCIMBR 0x1C4 /* Memory Base Address Register */ - #define SH7751_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */ - #define SH7751_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */ -#define SH7751_PCIIOBR 0x1C8 /* I/O Base Address Register */ - #define SH7751_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */ - #define SH7751_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */ -#define SH7751_PCIPINT 0x1CC /* Power Mgmnt Int. Register */ - #define SH7751_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */ - #define SH7751_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */ -#define SH7751_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */ -#define SH7751_PCICLKR 0x1D4 /* Clock Ctrl. Register */ - #define SH7751_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */ - #define SH7751_PCICLKR_BCSTP 0x00000002 /* BCLK Clock Stop */ -/* For definitions of BCR, MCR see ... */ -#define SH7751_PCIBCR1 0x1E0 /* Memory BCR1 Register */ -#define SH7751_PCIBCR2 0x1E4 /* Memory BCR2 Register */ -#define SH7751_PCIWCR1 0x1E8 /* Wait Control 1 Register */ -#define SH7751_PCIWCR2 0x1EC /* Wait Control 2 Register */ -#define SH7751_PCIWCR3 0x1F0 /* Wait Control 3 Register */ -#define SH7751_PCIMCR 0x1F4 /* Memory Control Register */ -#define SH7751_PCIBCR3 0x1f8 /* Memory BCR3 Register */ -#define SH7751_PCIPCTR 0x200 /* Port Control Register */ - #define SH7751_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */ - #define SH7751_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */ - #define SH7751_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */ - #define SH7751_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */ - #define SH7751_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */ - #define SH7751_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */ - #define SH7751_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */ - #define SH7751_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */ - #define SH7751_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */ -#define SH7751_PCIPDTR 0x204 /* Port Data Register */ - #define SH7751_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */ - #define SH7751_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */ - #define SH7751_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */ - #define SH7751_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */ - #define SH7751_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */ - #define SH7751_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */ -#define SH7751_PCIPDR 0x220 /* Port IO Data Register */ /* Memory Control Registers */ #define SH7751_BCR1 0xFF800000 /* Memory BCR1 Register */ @@ -274,30 +127,9 @@ #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) -/* General PCI values */ -#define SH7751_PCI_HOST_BRIDGE 0x6 - -/* Flags */ -#define SH7751_PCIC_NO_RESET 0x0001 - -/* External functions defined per platform i.e. Big Sur, SE... (these could be routed - * through the machine vectors... */ -extern int pcibios_init_platform(void); -extern int pcibios_map_platform_irq(u8 slot, u8 pin); - -struct sh7751_pci_address_space { - unsigned long base; - unsigned long size; -}; - -struct sh7751_pci_address_map { - struct sh7751_pci_address_space window0; - struct sh7751_pci_address_space window1; - unsigned long flags; -}; +struct sh4_pci_address_map; /* arch/sh/drivers/pci/pci-sh7751.c */ -extern int sh7751_pcic_init(struct sh7751_pci_address_map *map); +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 new file mode 100644 index 00000000000..bd3064a8208 --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -0,0 +1,139 @@ +/* + * 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. + * + */ + +#undef DEBUG + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include "pci-sh4.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 sh7780_pci_init(void) +{ + unsigned int id; + int ret; + + pr_debug("PCI: Starting intialization.\n"); + + outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ + + /* check for SH7780/SH7780R hardware */ + id = pci_read_reg(SH7780_PCIVID); + if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) && + (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) { + printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); + return -ENODEV; + } + + /* Setup the INTC */ + ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */ + ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */ + ctrl_outl(0x40000000, INTC_INTMSK1); /* disable IRL4-7 Interrupt */ + ctrl_outl(0x0000fffe, INTC_INTMSK2); /* disable IRL4-7 Interrupt */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */ + ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */ + + if ((ret = sh4_pci_check_direct()) != 0) + return ret; + + return pcibios_init_platform(); +} +core_initcall(sh7780_pci_init); + +int __init sh7780_pcic_init(struct sh4_pci_address_map *map) +{ + u32 word; + + /* + * 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); + } + + /* set the command/status bits to: + * Wait Cycle Control + Parity Enable + Bus Master + + * Mem space enable + */ + pci_write_reg(0x00000046, SH7780_PCICMD); + + /* define this host as the host bridge */ + word = PCI_BASE_CLASS_BRIDGE << 24; + pci_write_reg(word, SH7780_PCIRID); + + /* 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) & 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 + */ + 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); + + /* NOTE: I'm ignoring the PCI error IRQs for now.. + * TODO: add support for the internal error interrupts and + * DMA interrupts... + */ + +#ifdef CONFIG_SH_R7780RP + pci_fixup_pcic(); +#endif + + /* 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 1; +} diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h new file mode 100644 index 00000000000..f02d2180a4b --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7780.h @@ -0,0 +1,94 @@ +/* + * Low-Level PCI Support for SH7780 targets + * + * Dustin McIntire (dustin@sensoria.com) (c) 2001 + * Paul Mundt (lethal@linux-sh.org) (c) 2003 + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + */ + +#ifndef _PCI_SH7780_H_ +#define _PCI_SH7780_H_ + +/* Platform Specific Values */ +#define SH7780_VENDOR_ID 0x1912 +#define SH7780_DEVICE_ID 0x0002 +#define SH7781_DEVICE_ID 0x0001 + +/* SH7780 Control Registers */ +#define SH7780_PCI_VCR0 0xFE000000 +#define SH7780_PCI_VCR1 0xFE000004 +#define SH7780_PCI_VCR2 0xFE000008 + +/* 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 0xFE400000 /* 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_PCIMBR0 0x1E0 +#define SH7780_PCIMBMR0 0x1E4 +#define SH7780_PCIMBR2 0x1F0 +#define SH7780_PCIMBMR2 0x1F4 +#define SH7780_PCIIOBR 0x1F8 +#define SH7780_PCIIOBMR 0x1FC +#define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */ +#define SH7780_PCICSCR1 0x214 /* Cache Snoop2 Cnt. Register */ +#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-st40.c b/arch/sh/drivers/pci/pci-st40.c index 7c81b8b65bb..4ab5ea6b35f 100644 --- a/arch/sh/drivers/pci/pci-st40.c +++ b/arch/sh/drivers/pci/pci-st40.c @@ -70,12 +70,6 @@ static void pci_set_rbar_region(unsigned int region, unsigned long localAddr, unsigned long pciOffset, unsigned long regionSize); -/* - * The pcibios_map_platform_irq function is defined in the appropriate - * board specific code and referenced here - */ -extern int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin); - static __init void SetPCIPLL(void) { { @@ -422,13 +416,6 @@ struct pci_ops st40pci_config_ops = { /* Everything hangs off this */ static struct pci_bus *pci_root_bus; - -static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) -{ - return PCI_SLOT(dev->devfn); -} - - static int __init pcibios_init(void) { extern unsigned long memory_start, memory_end; @@ -465,17 +452,11 @@ static int __init pcibios_init(void) /* ok, do the scan man */ pci_root_bus = pci_scan_bus(0, &st40pci_config_ops, NULL); pci_assign_unassigned_resources(); - pci_fixup_irqs(no_swizzle, pcibios_map_platform_irq); return 0; } - subsys_initcall(pcibios_init); -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ -} - /* * Publish a region of local address space over the PCI bus * to other devices. diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 3d546ba329c..d439336d2e1 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -1,21 +1,45 @@ -/* arch/sh/kernel/pci.c - * $Id: pci.c,v 1.1 2003/08/24 19:15:45 lethal Exp $ +/* + * arch/sh/drivers/pci/pci.c * * Copyright (c) 2002 M. R. Brown <mrbrown@linux-sh.org> - * - * + * Copyright (c) 2004 - 2006 Paul Mundt <lethal@linux-sh.org> + * * 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. + * + * 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/pci.h> #include <linux/init.h> +#include <asm/io.h> + +static inline u8 bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin - 1) + slot) % 4) + 1; +} + +static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp) +{ + u8 pin = *pinp; + + while (dev->bus->parent) { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + return PCI_SLOT(dev->devfn); +} static int __init pcibios_init(void) { @@ -26,26 +50,32 @@ static int __init pcibios_init(void) #ifdef CONFIG_PCI_AUTO /* assign resources */ busno = 0; - for (p = board_pci_channels; p->pci_ops != NULL; p++) { + 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++) { + for (p = board_pci_channels; p->pci_ops != NULL; p++) { bus = pci_scan_bus(busno, p->pci_ops, p); - busno = bus->subordinate+1; + busno = bus->subordinate + 1; } - /* board-specific fixups */ - pcibios_fixup_irqs(); + pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq); return 0; } - subsys_initcall(pcibios_init); +/* + * Called after each bus is probed, but before its children + * are examined. + */ +void __init 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) @@ -61,13 +91,17 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, new |= PCI_ROM_ADDRESS_ENABLE; reg = dev->rom_base_reg; } else { - /* Somebody might have asked allocation of a non-standard resource */ + /* + * 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)) { + 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); @@ -145,7 +179,8 @@ void pcibios_set_master(struct pci_dev *dev) lat = pcibios_max_latency; else return; - printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); + 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); } @@ -153,3 +188,39 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) { pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + 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; + + /* + * 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. + */ + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) + return ioremap(start, len); + + return NULL; +} +EXPORT_SYMBOL(pci_iomap); + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + iounmap(addr); +} +EXPORT_SYMBOL(pci_iounmap); |