diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-footbridge |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/arm/mach-footbridge')
23 files changed, 2666 insertions, 0 deletions
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig new file mode 100644 index 00000000000..1090c680b6d --- /dev/null +++ b/arch/arm/mach-footbridge/Kconfig @@ -0,0 +1,80 @@ +if ARCH_FOOTBRIDGE + +menu "Footbridge Implementations" + +config ARCH_CATS + bool "CATS" + select FOOTBRIDGE_HOST + help + Say Y here if you intend to run this kernel on the CATS. + + Saying N will reduce the size of the Footbridge kernel. + +config ARCH_PERSONAL_SERVER + bool "Compaq Personal Server" + select FOOTBRIDGE_HOST + ---help--- + Say Y here if you intend to run this kernel on the Compaq + Personal Server. + + Saying N will reduce the size of the Footbridge kernel. + + The Compaq Personal Server is not available for purchase. + There are no product plans beyond the current research + prototypes at this time. Information is available at: + + <http://www.crl.hpl.hp.com/projects/personalserver/> + + If you have any questions or comments about the Compaq Personal + Server, send e-mail to <skiff@crl.dec.com>. + +config ARCH_EBSA285_ADDIN + bool "EBSA285 (addin mode)" + select ARCH_EBSA285 + select FOOTBRIDGE_ADDIN + help + Say Y here if you intend to run this kernel on the EBSA285 card + in addin mode. + + Saying N will reduce the size of the Footbridge kernel. + +config ARCH_EBSA285_HOST + bool "EBSA285 (host mode)" + select ARCH_EBSA285 + select FOOTBRIDGE_HOST + help + Say Y here if you intend to run this kernel on the EBSA285 card + in host ("central function") mode. + + Saying N will reduce the size of the Footbridge kernel. + +config ARCH_NETWINDER + bool "NetWinder" + select FOOTBRIDGE_HOST + help + Say Y here if you intend to run this kernel on the Rebel.COM + NetWinder. Information about this machine can be found at: + + <http://www.netwinder.org/> + + Saying N will reduce the size of the Footbridge kernel. + +endmenu + +# Footbridge support +config FOOTBRIDGE + bool + +# Footbridge in host mode +config FOOTBRIDGE_HOST + bool + +# Footbridge in addin mode +config FOOTBRIDGE_ADDIN + bool + +# EBSA285 board in either host or addin mode +config ARCH_EBSA285 + bool + +endif diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile new file mode 100644 index 00000000000..0694ad6b647 --- /dev/null +++ b/arch/arm/mach-footbridge/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := common.o dc21285.o dma.o isa-irq.o time.o +obj-m := +obj-n := +obj- := + +pci-$(CONFIG_ARCH_CATS) += cats-pci.o +pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o +pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o +pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o + +leds-$(CONFIG_ARCH_CO285) += ebsa285-leds.o +leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o +leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o + +obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o +obj-$(CONFIG_ARCH_CO285) += co285.o dc21285-timer.o +obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o +obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o +obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o + +obj-$(CONFIG_PCI) +=$(pci-y) +obj-$(CONFIG_LEDS) +=$(leds-y) + +obj-$(CONFIG_ISA) += isa.o diff --git a/arch/arm/mach-footbridge/Makefile.boot b/arch/arm/mach-footbridge/Makefile.boot new file mode 100644 index 00000000000..c7e75acfe6c --- /dev/null +++ b/arch/arm/mach-footbridge/Makefile.boot @@ -0,0 +1,4 @@ + zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 + diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c new file mode 100644 index 00000000000..d1ced86c379 --- /dev/null +++ b/arch/arm/mach-footbridge/cats-hw.c @@ -0,0 +1,95 @@ +/* + * linux/arch/arm/mach-footbridge/cats-hw.c + * + * CATS machine fixup + * + * Copyright (C) 1998, 1999 Russell King, Phil Blundell + */ +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> + +#include <asm/hardware/dec21285.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/setup.h> + +#include <asm/mach/arch.h> + +#include "common.h" + +#define CFG_PORT 0x370 +#define INDEX_PORT (CFG_PORT) +#define DATA_PORT (CFG_PORT + 1) + +static int __init cats_hw_init(void) +{ + if (machine_is_cats()) { + /* Set Aladdin to CONFIGURE mode */ + outb(0x51, CFG_PORT); + outb(0x23, CFG_PORT); + + /* Select logical device 3 */ + outb(0x07, INDEX_PORT); + outb(0x03, DATA_PORT); + + /* Set parallel port to DMA channel 3, ECP+EPP1.9, + enable EPP timeout */ + outb(0x74, INDEX_PORT); + outb(0x03, DATA_PORT); + + outb(0xf0, INDEX_PORT); + outb(0x0f, DATA_PORT); + + outb(0xf1, INDEX_PORT); + outb(0x07, DATA_PORT); + + /* Select logical device 4 */ + outb(0x07, INDEX_PORT); + outb(0x04, DATA_PORT); + + /* UART1 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Select logical device 5 */ + outb(0x07, INDEX_PORT); + outb(0x05, DATA_PORT); + + /* UART2 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Set Aladdin to RUN mode */ + outb(0xbb, CFG_PORT); + } + + return 0; +} + +__initcall(cats_hw_init); + +/* + * CATS uses soft-reboot by default, since + * hard reboots fail on early boards. + */ +static void __init +fixup_cats(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + ORIG_VIDEO_LINES = 25; + ORIG_VIDEO_POINTS = 16; + ORIG_Y = 24; +} + +MACHINE_START(CATS, "Chalice-CATS") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) + SOFT_REBOOT + FIXUP(fixup_cats) + MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) + .timer = &isa_timer, +MACHINE_END diff --git a/arch/arm/mach-footbridge/cats-pci.c b/arch/arm/mach-footbridge/cats-pci.c new file mode 100644 index 00000000000..4f984fde737 --- /dev/null +++ b/arch/arm/mach-footbridge/cats-pci.c @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mach-footbridge/cats-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/irq.h> +#include <asm/mach/pci.h> +#include <asm/mach-types.h> + +/* cats host-specific stuff */ +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; + +static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->irq >= 128) + return dev->irq & 0x1f; + + if (dev->irq >= 1 && dev->irq <= 4) + return irqmap_cats[dev->irq - 1]; + + if (dev->irq != 0) + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + + return -1; +} + +/* + * why not the standard PCI swizzle? does this prevent 4-port tulip + * cards being used (ie, pci-pci bridge based cards)? + */ +static struct hw_pci cats_pci __initdata = { + .swizzle = NULL, + .map_irq = cats_map_irq, + .nr_controllers = 1, + .setup = dc21285_setup, + .scan = dc21285_scan_bus, + .preinit = dc21285_preinit, + .postinit = dc21285_postinit, +}; + +static int cats_pci_init(void) +{ + if (machine_is_cats()) + pci_common_init(&cats_pci); + return 0; +} + +subsys_initcall(cats_pci_init); diff --git a/arch/arm/mach-footbridge/co285.c b/arch/arm/mach-footbridge/co285.c new file mode 100644 index 00000000000..e1541914fdc --- /dev/null +++ b/arch/arm/mach-footbridge/co285.c @@ -0,0 +1,38 @@ +/* + * linux/arch/arm/mach-footbridge/co285.c + * + * CO285 machine fixup + */ +#include <linux/init.h> + +#include <asm/hardware/dec21285.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> + +#include "common.h" + +static void __init +fixup_coebsa285(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + extern unsigned long boot_memory_end; + extern char boot_command_line[]; + + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = boot_memory_end; + mi->bank[0].node = 0; + + *cmdline = boot_command_line; +} + +MACHINE_START(CO285, "co-EBSA285") + MAINTAINER("Mark van Doesburg") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) + FIXUP(fixup_coebsa285) + MAPIO(footbridge_map_io) + INITIRQ(footbridge_init_irq) + .timer = &footbridge_timer, +MACHINE_END + diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c new file mode 100644 index 00000000000..eb8238c1ef0 --- /dev/null +++ b/arch/arm/mach-footbridge/common.c @@ -0,0 +1,205 @@ +/* + * linux/arch/arm/mach-footbridge/common.c + * + * Copyright (C) 1998-2000 Russell King, Dave Gilbert. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/list.h> +#include <linux/init.h> + +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/setup.h> +#include <asm/hardware/dec21285.h> + +#include <asm/mach/irq.h> +#include <asm/mach/map.h> + +#include "common.h" + +extern void __init isa_init_irq(unsigned int irq); + +unsigned int mem_fclk_21285 = 50000000; + +EXPORT_SYMBOL(mem_fclk_21285); + +static int __init parse_tag_memclk(const struct tag *tag) +{ + mem_fclk_21285 = tag->u.memclk.fmemclk; + return 0; +} + +__tagtable(ATAG_MEMCLK, parse_tag_memclk); + +/* + * Footbridge IRQ translation table + * Converts from our IRQ numbers into FootBridge masks + */ +static const int fb_irq_mask[] = { + IRQ_MASK_UART_RX, /* 0 */ + IRQ_MASK_UART_TX, /* 1 */ + IRQ_MASK_TIMER1, /* 2 */ + IRQ_MASK_TIMER2, /* 3 */ + IRQ_MASK_TIMER3, /* 4 */ + IRQ_MASK_IN0, /* 5 */ + IRQ_MASK_IN1, /* 6 */ + IRQ_MASK_IN2, /* 7 */ + IRQ_MASK_IN3, /* 8 */ + IRQ_MASK_DOORBELLHOST, /* 9 */ + IRQ_MASK_DMA1, /* 10 */ + IRQ_MASK_DMA2, /* 11 */ + IRQ_MASK_PCI, /* 12 */ + IRQ_MASK_SDRAMPARITY, /* 13 */ + IRQ_MASK_I2OINPOST, /* 14 */ + IRQ_MASK_PCI_ABORT, /* 15 */ + IRQ_MASK_PCI_SERR, /* 16 */ + IRQ_MASK_DISCARD_TIMER, /* 17 */ + IRQ_MASK_PCI_DPERR, /* 18 */ + IRQ_MASK_PCI_PERR, /* 19 */ +}; + +static void fb_mask_irq(unsigned int irq) +{ + *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)]; +} + +static void fb_unmask_irq(unsigned int irq) +{ + *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)]; +} + +static struct irqchip fb_chip = { + .ack = fb_mask_irq, + .mask = fb_mask_irq, + .unmask = fb_unmask_irq, +}; + +static void __init __fb_init_irq(void) +{ + unsigned int irq; + + /* + * setup DC21285 IRQs + */ + *CSR_IRQ_DISABLE = -1; + *CSR_FIQ_DISABLE = -1; + + for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { + set_irq_chip(irq, &fb_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } +} + +void __init footbridge_init_irq(void) +{ + __fb_init_irq(); + + if (!footbridge_cfn_mode()) + return; + + if (machine_is_ebsa285()) + /* The following is dependent on which slot + * you plug the Southbridge card into. We + * currently assume that you plug it into + * the right-hand most slot. + */ + isa_init_irq(IRQ_PCI); + + if (machine_is_cats()) + isa_init_irq(IRQ_IN2); + + if (machine_is_netwinder()) + isa_init_irq(IRQ_IN3); +} + +/* + * Common mapping for all systems. Note that the outbound write flush is + * commented out since there is a "No Fix" problem with it. Not mapping + * it means that we have extra bullet protection on our feet. + */ +static struct map_desc fb_common_io_desc[] __initdata = { + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, MT_DEVICE }, + { XBUS_BASE, 0x40000000, XBUS_SIZE, MT_DEVICE } +}; + +/* + * The mapping when the footbridge is in host mode. We don't map any of + * this when we are in add-in mode. + */ +static struct map_desc ebsa285_host_io_desc[] __initdata = { +#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE }, + { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, MT_DEVICE }, + { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, MT_DEVICE }, + { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, MT_DEVICE }, + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE } +#endif +}; + +/* + * The CO-ebsa285 mapping. + */ +static struct map_desc co285_io_desc[] __initdata = { +#ifdef CONFIG_ARCH_CO285 + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE }, + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE } +#endif +}; + +void __init footbridge_map_io(void) +{ + /* + * Set up the common mapping first; we need this to + * determine whether we're in host mode or not. + */ + iotable_init(fb_common_io_desc, ARRAY_SIZE(fb_common_io_desc)); + + /* + * Now, work out what we've got to map in addition on this + * platform. + */ + if (machine_is_co285()) + iotable_init(co285_io_desc, ARRAY_SIZE(co285_io_desc)); + if (footbridge_cfn_mode()) + iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc)); +} + +#ifdef CONFIG_FOOTBRIDGE_ADDIN + +/* + * These two functions convert virtual addresses to PCI addresses and PCI + * addresses to virtual addresses. Note that it is only legal to use these + * on memory obtained via get_zeroed_page or kmalloc. + */ +unsigned long __virt_to_bus(unsigned long res) +{ + WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); + + return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); +} +EXPORT_SYMBOL(__virt_to_bus); + +unsigned long __bus_to_virt(unsigned long res) +{ + res -= (*CSR_PCISDRAMBASE & 0xfffffff0); + res += PAGE_OFFSET; + + WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); + + return res; +} +EXPORT_SYMBOL(__bus_to_virt); + +#endif diff --git a/arch/arm/mach-footbridge/common.h b/arch/arm/mach-footbridge/common.h new file mode 100644 index 00000000000..580e31bbc71 --- /dev/null +++ b/arch/arm/mach-footbridge/common.h @@ -0,0 +1,9 @@ + +extern struct sys_timer footbridge_timer; +extern struct sys_timer isa_timer; + +extern void isa_rtc_init(void); + +extern void footbridge_map_io(void); +extern void footbridge_init_irq(void); + diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c new file mode 100644 index 00000000000..580e1d4bce0 --- /dev/null +++ b/arch/arm/mach-footbridge/dc21285-timer.c @@ -0,0 +1,68 @@ +/* + * linux/arch/arm/mach-footbridge/dc21285-timer.c + * + * Copyright (C) 1998 Russell King. + * Copyright (C) 1998 Phil Blundell + */ +#include <linux/init.h> +#include <linux/interrupt.h> + +#include <asm/irq.h> + +#include <asm/hardware/dec21285.h> +#include <asm/mach/time.h> + +#include "common.h" + +/* + * Footbridge timer 1 support. + */ +static unsigned long timer1_latch; + +static unsigned long timer1_gettimeoffset (void) +{ + unsigned long value = timer1_latch - *CSR_TIMER1_VALUE; + + return ((tick_nsec / 1000) * value) / timer1_latch; +} + +static irqreturn_t +timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + write_seqlock(&xtime_lock); + + *CSR_TIMER1_CLR = 0; + + timer_tick(regs); + + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction footbridge_timer_irq = { + .name = "Timer1 timer tick", + .handler = timer1_interrupt, + .flags = SA_INTERRUPT, +}; + +/* + * Set up timer interrupt. + */ +static void __init footbridge_timer_init(void) +{ + isa_rtc_init(); + + timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ); + + *CSR_TIMER1_CLR = 0; + *CSR_TIMER1_LOAD = timer1_latch; + *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; + + setup_irq(IRQ_TIMER1, &footbridge_timer_irq); +} + +struct sys_timer footbridge_timer = { + .init = footbridge_timer_init, + .offset = timer1_gettimeoffset, +}; diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c new file mode 100644 index 00000000000..e79884eea1f --- /dev/null +++ b/arch/arm/mach-footbridge/dc21285.c @@ -0,0 +1,384 @@ +/* + * linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285 + * + * Copyright (C) 1998-2001 Russell King + * Copyright (C) 1998-2000 Phil Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ptrace.h> +#include <linux/interrupt.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/mach/pci.h> +#include <asm/hardware/dec21285.h> + +#define MAX_SLOTS 21 + +#define PCICMD_ABORT ((PCI_STATUS_REC_MASTER_ABORT| \ + PCI_STATUS_REC_TARGET_ABORT)<<16) + +#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_PARITY) << 16) + +extern int setup_arm_irq(int, struct irqaction *); +extern void pcibios_report_status(u_int status_mask, int warn); +extern void register_isa_ports(unsigned int, unsigned int, unsigned int); + +static unsigned long +dc21285_base_address(struct pci_bus *bus, unsigned int devfn) +{ + unsigned long addr = 0; + + if (bus->number == 0) { + if (PCI_SLOT(devfn) == 0) + /* + * For devfn 0, point at the 21285 + */ + addr = ARMCSR_BASE; + else { + devfn -= 1 << 3; + + if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) + addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); + } + } else + addr = PCICFG1_BASE | (bus->number << 16) | (devfn << 8); + + return addr; +} + +static int +dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + unsigned long addr = dc21285_base_address(bus, devfn); + u32 v = 0xffffffff; + + if (addr) + switch (size) { + case 1: + asm("ldr%?b %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); + break; + case 2: + asm("ldr%?h %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); + break; + case 4: + asm("ldr%? %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); + break; + } + + *value = v; + + v = *CSR_PCICMD; + if (v & PCICMD_ABORT) { + *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); + return -1; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int +dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + unsigned long addr = dc21285_base_address(bus, devfn); + u32 v; + + if (addr) + switch (size) { + case 1: + asm("str%?b %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + break; + case 2: + asm("str%?h %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + break; + case 4: + asm("str%? %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + break; + } + + v = *CSR_PCICMD; + if (v & PCICMD_ABORT) { + *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); + return -1; + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops dc21285_ops = { + .read = dc21285_read_config, + .write = dc21285_write_config, +}; + +static struct timer_list serr_timer; +static struct timer_list perr_timer; + +static void dc21285_enable_error(unsigned long __data) +{ + switch (__data) { + case IRQ_PCI_SERR: + del_timer(&serr_timer); + break; + + case IRQ_PCI_PERR: + del_timer(&perr_timer); + break; + } + + enable_irq(__data); +} + +/* + * Warn on PCI errors. + */ +static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int cmd; + unsigned int status; + + cmd = *CSR_PCICMD; + status = cmd >> 16; + cmd = cmd & 0xffff; + + if (status & PCI_STATUS_REC_MASTER_ABORT) { + printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", + instruction_pointer(regs)); + cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; + } + + if (status & PCI_STATUS_REC_TARGET_ABORT) { + printk(KERN_DEBUG "PCI: target abort: "); + pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT, 1); + printk("\n"); + + cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; + } + + *CSR_PCICMD = cmd; + + return IRQ_HANDLED; +} + +static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct timer_list *timer = dev_id; + unsigned int cntl; + + printk(KERN_DEBUG "PCI: system error received: "); + pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); + printk("\n"); + + cntl = *CSR_SA110_CNTL & 0xffffdf07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + + /* + * back off this interrupt + */ + disable_irq(irq); + timer->expires = jiffies + HZ; + add_timer(timer); + + return IRQ_HANDLED; +} + +static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_DEBUG "PCI: discard timer expired\n"); + *CSR_SA110_CNTL &= 0xffffde07; + + return IRQ_HANDLED; +} + +static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int cmd; + + printk(KERN_DEBUG "PCI: data parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd = *CSR_PCICMD & 0xffff; + *CSR_PCICMD = cmd | 1 << 24; + + return IRQ_HANDLED; +} + +static irqreturn_t dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct timer_list *timer = dev_id; + unsigned int cmd; + + printk(KERN_DEBUG "PCI: parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd = *CSR_PCICMD & 0xffff; + *CSR_PCICMD = cmd | 1 << 31; + + /* + * back off this interrupt + */ + disable_irq(irq); + timer->expires = jiffies + HZ; + add_timer(timer); + + return IRQ_HANDLED; +} + +int __init dc21285_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if (nr || !footbridge_cfn_mode()) + return 0; + + res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) { + printk("out of memory for root bus resources"); + return 0; + } + + memset(res, 0, sizeof(struct resource) * 2); + + res[0].flags = IORESOURCE_MEM; + res[0].name = "Footbridge non-prefetch"; + res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; + res[1].name = "Footbridge prefetch"; + + allocate_resource(&iomem_resource, &res[1], 0x20000000, + 0xa0000000, 0xffffffff, 0x20000000, NULL, NULL); + allocate_resource(&iomem_resource, &res[0], 0x40000000, + 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); + + sys->resource[0] = &ioport_resource; + sys->resource[1] = &res[0]; + sys->resource[2] = &res[1]; + sys->mem_offset = DC21285_PCI_MEM; + + return 1; +} + +struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(0, &dc21285_ops, sys); +} + +void __init dc21285_preinit(void) +{ + unsigned int mem_size, mem_mask; + int cfn_mode; + + mem_size = (unsigned int)high_memory - PAGE_OFFSET; + for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) + if (mem_mask >= mem_size) + break; + + /* + * These registers need to be set up whether we're the + * central function or not. + */ + *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_PCIADDR_EXTN = 0; + + cfn_mode = __footbridge_cfn_mode(); + + printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in " + "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? + "central function" : "addin"); + + if (footbridge_cfn_mode()) { + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | + SA110_CNTL_RXSERR; + *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; + } + + init_timer(&serr_timer); + init_timer(&perr_timer); + + serr_timer.data = IRQ_PCI_SERR; + serr_timer.function = dc21285_enable_error; + perr_timer.data = IRQ_PCI_PERR; + perr_timer.function = dc21285_enable_error; + + /* + * We don't care if these fail. + */ + request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, + "PCI system error", &serr_timer); + request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, + "PCI parity error", &perr_timer); + request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, + "PCI abort", NULL); + request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, + "Discard timer", NULL); + request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, + "PCI data parity", NULL); + + if (cfn_mode) { + static struct resource csrio; + + csrio.flags = IORESOURCE_IO; + csrio.name = "Footbridge"; + + allocate_resource(&ioport_resource, &csrio, 128, + 0xff00, 0xffff, 128, NULL, NULL); + + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + */ + *CSR_PCICSRBASE = 0xf4000000; + *CSR_PCICSRIOBASE = csrio.start; + *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS; |