From fb946cdca90da3f23a88d184b1e1c69fb252815f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Sun, 5 Sep 2004 22:32:12 +0100 Subject: [PATCH] [ARM PATCH] 2048/1: Patch 2036/1 (2033/4) resubmission Patch from Dave Jiang arch/arm/mach-iop3xx update Removed busy while loop and replaced with mdelay() from patch 2036/1 --- arch/arm/mach-iop3xx/Kconfig | 46 ++++-- arch/arm/mach-iop3xx/Makefile | 13 +- arch/arm/mach-iop3xx/arch.c | 30 ++-- arch/arm/mach-iop3xx/common.c | 75 ++++++++++ arch/arm/mach-iop3xx/iop321-irq.c | 3 +- arch/arm/mach-iop3xx/iop321-mm.c | 43 ++++++ arch/arm/mach-iop3xx/iop321-pci.c | 65 +++------ arch/arm/mach-iop3xx/iop321-setup.c | 63 ++++++++ arch/arm/mach-iop3xx/iop321-time.c | 64 ++++++-- arch/arm/mach-iop3xx/iop331-irq.c | 127 ++++++++++++++++ arch/arm/mach-iop3xx/iop331-mm.c | 43 ++++++ arch/arm/mach-iop3xx/iop331-pci.c | 219 ++++++++++++++++++++++++++++ arch/arm/mach-iop3xx/iop331-setup.c | 102 +++++++++++++ arch/arm/mach-iop3xx/iop331-time.c | 141 ++++++++++++++++++ arch/arm/mach-iop3xx/iq31244-mm.c | 44 ++++++ arch/arm/mach-iop3xx/iq31244-pci.c | 134 +++++++++++++++++ arch/arm/mach-iop3xx/iq80321-mm.c | 44 ++++++ arch/arm/mach-iop3xx/iq80321-pci.c | 83 ++++++++--- arch/arm/mach-iop3xx/iq80331-mm.c | 36 +++++ arch/arm/mach-iop3xx/iq80331-pci.c | 138 ++++++++++++++++++ 20 files changed, 1399 insertions(+), 114 deletions(-) create mode 100644 arch/arm/mach-iop3xx/common.c create mode 100644 arch/arm/mach-iop3xx/iop321-mm.c create mode 100644 arch/arm/mach-iop3xx/iop321-setup.c create mode 100644 arch/arm/mach-iop3xx/iop331-irq.c create mode 100644 arch/arm/mach-iop3xx/iop331-mm.c create mode 100644 arch/arm/mach-iop3xx/iop331-pci.c create mode 100644 arch/arm/mach-iop3xx/iop331-setup.c create mode 100644 arch/arm/mach-iop3xx/iop331-time.c create mode 100644 arch/arm/mach-iop3xx/iq31244-mm.c create mode 100644 arch/arm/mach-iop3xx/iq31244-pci.c create mode 100644 arch/arm/mach-iop3xx/iq80321-mm.c create mode 100644 arch/arm/mach-iop3xx/iq80331-mm.c create mode 100644 arch/arm/mach-iop3xx/iq80331-pci.c diff --git a/arch/arm/mach-iop3xx/Kconfig b/arch/arm/mach-iop3xx/Kconfig index 8d4919f43ad04..26be7e0c6f4f4 100644 --- a/arch/arm/mach-iop3xx/Kconfig +++ b/arch/arm/mach-iop3xx/Kconfig @@ -1,35 +1,49 @@ -if ARCH_IOP3XX menu "IOP3xx Implementation Options" -choice - prompt "IOP3xx System Type" - default ARCH_IQ80321 +comment "IOP3xx Platform Types" config ARCH_IQ80321 - bool "IQ80321" + bool "Enable support for IQ80321" + select ARCH_IOP321 help Say Y here if you want to run your kernel on the Intel IQ80321 evaluation kit for the IOP321 chipset. -endchoice + +config ARCH_IQ31244 + bool "Enable support for IQ31244" + select ARCH_IOP321 + help + Say Y here if you want to run your kernel on the Intel IQ31244 + evaluation kit for the IOP321 chipset. + +config ARCH_IQ80331 + bool "Enable support for IQ80331" + select ARCH_IOP331 + help + Say Y here if you want to run your kernel on the Intel IQ80331 + evaluation kit for the IOP331 chipset. + +config ARCH_EP80219 + bool "Enable support for EP80219" + select ARCH_IOP321 + select ARCH_IQ31244 # Which IOP variant are we running? config ARCH_IOP321 bool - default ARCH_IQ80321 help The IQ80321 uses the IOP321 variant. + The IQ31244 and EP80219 uses the IOP321 variant. -comment "IOP3xx Chipset Features" - -config IOP3XX_AAU - bool "Support Intel IOP3xx Application Accelerator Unit (EXPERIMENTAL)" - depends on EXPERIMENTAL +config ARCH_IOP331 + bool + default ARCH_IQ80331 + help + The IQ80331 uses the IOP331 variant. -config IOP3XX_DMA - bool "Support Intel IOP3xx DMA (EXPERIMENTAL)" - depends on EXPERIMENTAL +comment "IOP3xx Chipset Features" endmenu -endif + diff --git a/arch/arm/mach-iop3xx/Makefile b/arch/arm/mach-iop3xx/Makefile index 30a2895c9caa3..dcbffb66d8deb 100644 --- a/arch/arm/mach-iop3xx/Makefile +++ b/arch/arm/mach-iop3xx/Makefile @@ -4,15 +4,18 @@ # Object file lists. -obj-y := arch.o +obj-y := common.o obj-m := obj-n := obj- := -obj-$(CONFIG_ARCH_IOP321) += iop321-irq.o iop321-pci.o mm-321.o iop321-time.o +obj-$(CONFIG_ARCH_IOP321) += iop321-setup.o iop321-irq.o iop321-pci.o iop321-mm.o iop321-time.o -obj-$(CONFIG_ARCH_IQ80321) += iq80321-pci.o +obj-$(CONFIG_ARCH_IOP331) += iop331-setup.o iop331-irq.o iop331-pci.o iop331-time.o -obj-$(CONFIG_IOP3XX_AAU) += aau.o -obj-$(CONFIG_IOP3XX_DMA) += dma.o +obj-$(CONFIG_ARCH_IQ80321) += iq80321-mm.o iq80321-pci.o + +obj-$(CONFIG_ARCH_IQ31244) += iq31244-mm.o iq31244-pci.o + +obj-$(CONFIG_ARCH_IQ80331) += iq80331-mm.o iq80331-pci.o diff --git a/arch/arm/mach-iop3xx/arch.c b/arch/arm/mach-iop3xx/arch.c index bdda3f1051cb2..3aca6671f4c03 100644 --- a/arch/arm/mach-iop3xx/arch.c +++ b/arch/arm/mach-iop3xx/arch.c @@ -21,30 +21,30 @@ #include #include -#ifdef CONFIG_ARCH_IQ80321 -extern void iq80321_map_io(void); -extern void iop321_init_irq(void); -extern void iop321_init_time(void); +#ifdef CONFIG_ARCH_IQ80331 +extern void iq80331_map_io(void); +extern void iop331_init_irq(void); +extern void iop331_init_time(void); #endif -#ifdef CONFIG_ARCH_IQ80321 +#ifdef CONFIG_ARCH_IQ80331 static void __init -fixup_iop321(struct machine_desc *desc, struct tag *tags, +fixup_iop331(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { } #endif -#if defined(CONFIG_ARCH_IQ80321) -MACHINE_START(IQ80321, "Intel IQ80321") - MAINTAINER("Intel Corporation") - BOOT_MEM(PHYS_OFFSET, IQ80321_UART1, 0xfe800000) - FIXUP(fixup_iop321) - MAPIO(iq80321_map_io) - INITIRQ(iop321_init_irq) - INITTIME(iop321_init_time) +#if defined(CONFIG_ARCH_IQ80331) +MACHINE_START(IQ80331, "Intel IQ80331") + MAINTAINER("Intel Corp.") + BOOT_MEM(PHYS_OFFSET, 0xfff01000, 0xfffff000) // virtual, physical +// BOOT_MEM(PHYS_OFFSET, IQ80331_UART0_VIRT, IQ80331_UART0_PHYS) + MAPIO(iq80331_map_io) + INITIRQ(iop331_init_irq) + INITTIME(iop331_init_time) + BOOT_PARAMS(0x0100) MACHINE_END - #else #error No machine descriptor defined for this IOP3xx implementation #endif diff --git a/arch/arm/mach-iop3xx/common.c b/arch/arm/mach-iop3xx/common.c new file mode 100644 index 0000000000000..c0bbe5a18b934 --- /dev/null +++ b/arch/arm/mach-iop3xx/common.c @@ -0,0 +1,75 @@ +/* + * arch/arm/mach-iop3xx/common.c + * + * Common routines shared across all IOP3xx implementations + * + * Author: Deepak Saxena + * + * Copyright 2003 (c) MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include + +/* + * Shared variables + */ +unsigned long iop3xx_pcibios_min_io = 0; +unsigned long iop3xx_pcibios_min_mem = 0; + +#ifdef CONFIG_ARCH_EP80219 +#include +/* + * Default power-off for EP80219 + */ +#include +#include + +static inline void ep80219_send_to_pic(__u8 c) { +} + +void ep80219_power_off(void) +{ + /* + * This function will send a SHUTDOWN_COMPLETE message to the PIC controller + * over I2C. We are not using the i2c subsystem since we are going to power + * off and it may be removed + */ + + /* Send the Address byte w/ the start condition */ + *IOP321_IDBR1 = 0x60; + *IOP321_ICR1 = 0xE9; + mdelay(1); + + /* Send the START_MSG byte w/ no start or stop condition */ + *IOP321_IDBR1 = 0x0F; + *IOP321_ICR1 = 0xE8; + mdelay(1); + + /* Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or stop condition */ + *IOP321_IDBR1 = 0x03; + *IOP321_ICR1 = 0xE8; + mdelay(1); + + /* Send an ignored byte w/ stop condition */ + *IOP321_IDBR1 = 0x00; + *IOP321_ICR1 = 0xEA; + + while (1) ; +} + +#include +#include + +static int __init ep80219_init(void) +{ + pm_power_off = ep80219_power_off; + return 0; +} +arch_initcall(ep80219_init); +#endif diff --git a/arch/arm/mach-iop3xx/iop321-irq.c b/arch/arm/mach-iop3xx/iop321-irq.c index 472faf58256c9..d42aae6aef03c 100644 --- a/arch/arm/mach-iop3xx/iop321-irq.c +++ b/arch/arm/mach-iop3xx/iop321-irq.c @@ -81,7 +81,8 @@ void __init iop321_init_irq(void) intctl_write(0); // disable all interrupts intstr_write(0); // treat all as IRQ - if(machine_is_iq80321()) // all interrupts are inputs to chip + if(machine_is_iq80321() || + machine_is_iq31244()) // all interrupts are inputs to chip *IOP321_PCIIRSR = 0x0f; for(i = IOP321_IRQ_OFS; i < NR_IOP321_IRQS; i++) diff --git a/arch/arm/mach-iop3xx/iop321-mm.c b/arch/arm/mach-iop3xx/iop321-mm.c new file mode 100644 index 0000000000000..818a54872c7aa --- /dev/null +++ b/arch/arm/mach-iop3xx/iop321-mm.c @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-iop3xx/mm.c + * + * Low level memory initialization for IOP321 based systems + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + + +/* + * Standard IO mapping for all IOP321 based systems + */ +static struct map_desc iop321_std_desc[] __initdata = { + /* virtual physical length type */ + + /* mem mapped registers */ + { IOP321_VIRT_MEM_BASE, IOP321_PHY_MEM_BASE, 0x00002000, MT_DEVICE }, + + /* PCI IO space */ + { 0xfe000000, 0x90000000, 0x00020000, MT_DEVICE } +}; + +void __init iop321_map_io(void) +{ + iotable_init(iop321_std_desc, ARRAY_SIZE(iop321_std_desc)); +} diff --git a/arch/arm/mach-iop3xx/iop321-pci.c b/arch/arm/mach-iop3xx/iop321-pci.c index be36f53836d36..8fdfc3a8fe0c3 100644 --- a/arch/arm/mach-iop3xx/iop321-pci.c +++ b/arch/arm/mach-iop3xx/iop321-pci.c @@ -44,7 +44,7 @@ static u32 iop321_cfg_address(struct pci_bus *bus, int devfn, int where) u32 addr; if (sys->busnr == bus->number) - addr = 1 << (PCI_SLOT(devfn) + 16); + addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11); else addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1; @@ -158,7 +158,8 @@ iop321_write_config(struct pci_bus *bus, unsigned int devfn, int where, : "r" (value), "r" (addr), "r" (IOP321_OCCAR), "r" (IOP321_OCCDR)); } - return PCIBIOS_SUCCESSFUL; + + return PCIBIOS_SUCCESSFUL; } static struct pci_ops iop321_ops = { @@ -194,53 +195,16 @@ struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *sys) return pci_scan_bus(sys->busnr, &iop321_ops, sys); } -/* - * Setup the system data for controller 'nr'. Return 0 if none found, - * 1 if found, or negative error. - */ -int iop321_setup(int nr, struct pci_sys_data *sys) -{ - struct resource *res; - - if (nr >= 1) - return 0; - - res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); - if (!res) - panic("PCI: unable to alloc resources"); - - memset(res, 0, sizeof(struct resource) * 2); - - switch (nr) { - case 0: - res[0].start = IOP321_PCI_IO_BASE + 0x6e000000; - res[0].end = IOP321_PCI_IO_BASE + IOP321_PCI_IO_SIZE-1 + 0x6e000000; - res[0].name = "PCI IO Primary"; - res[0].flags = IORESOURCE_IO; - - res[1].start = IOP321_PCI_MEM_BASE; - res[1].end = IOP321_PCI_MEM_BASE + IOP321_PCI_MEM_SIZE; - res[1].name = "PCI Memory Primary"; - res[1].flags = IORESOURCE_MEM; - break; - } - - request_resource(&ioport_resource, &res[0]); - request_resource(&iomem_resource, &res[1]); - - sys->resource[0] = &res[0]; - sys->resource[1] = &res[1]; - sys->resource[2] = NULL; - sys->io_offset = 0x6e000000; - - return 1; -} - - - - void iop321_init(void) { +#if CONFIG_ARCH_EP80219 + *IOP321_ATUCR = 0x2; + *IOP321_OIOWTVR = 0x90000000; + *IOP321_IABAR0 = 0x00000004; + *IOP321_IABAR2 = 0xa000000c; + *IOP321_IALR2 = 0xe0000000; +#endif + DBG("PCI: Intel 80321 PCI init code.\n"); DBG("\tATU: IOP321_ATUCMD=0x%04x\n", *IOP321_ATUCMD); DBG("\tATU: IOP321_OMWTVR0=0x%04x, IOP321_OIOWTVR=0x%04x\n", @@ -252,7 +216,12 @@ void iop321_init(void) DBG("\tATU: IOP321_IABAR2=0x%08x IOP321_IALR2=0x%08x IOP321_IATVR2=%08x\n", *IOP321_IABAR2, *IOP321_IALR2, *IOP321_IATVR2); DBG("\tATU: IOP321_IABAR3=0x%08x IOP321_IALR3=0x%08x IOP321_IATVR3=%08x\n", *IOP321_IABAR3, *IOP321_IALR3, *IOP321_IATVR3); +#if 0 + hook_fault_code(4, iop321_pci_abort, SIGBUS, "external abort on linefetch"); + hook_fault_code(6, iop321_pci_abort, SIGBUS, "external abort on linefetch"); + hook_fault_code(8, iop321_pci_abort, SIGBUS, "external abort on non-linefetch"); + hook_fault_code(10, iop321_pci_abort, SIGBUS, "external abort on non-linefetch"); +#endif hook_fault_code(16+6, iop321_pci_abort, SIGBUS, "imprecise external abort"); - } diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c new file mode 100644 index 0000000000000..e92f77fbbf317 --- /dev/null +++ b/arch/arm/mach-iop3xx/iop321-setup.c @@ -0,0 +1,63 @@ +/* + * linux/arch/arm/mach-iop3xx/iop321-setup.c + * + * Author: Nicolas Pitre + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARCH_IQ80321 +extern void iq80321_map_io(void); +extern void iop321_init_irq(void); +extern void iop321_init_time(void); +#endif + +#ifdef CONFIG_ARCH_IQ31244 +extern void iq31244_map_io(void); +extern void iop321_init_irq(void); +extern void iop321_init_time(void); +#endif + +static void __init +fixup_iop321(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +#if defined(CONFIG_ARCH_IQ80321) +MACHINE_START(IQ80321, "Intel IQ80321") + MAINTAINER("Intel Corporation") + BOOT_MEM(PHYS_OFFSET, IQ80321_UART, 0xfe800000) + FIXUP(fixup_iop321) + MAPIO(iq80321_map_io) + INITIRQ(iop321_init_irq) + INITTIME(iop321_init_time) + BOOT_PARAMS(0xa0000100) +MACHINE_END +#elif defined(CONFIG_ARCH_IQ31244) + MACHINE_START(IQ31244, "Intel IQ31244") + MAINTAINER("Intel Corp.") + BOOT_MEM(PHYS_OFFSET, IQ31244_UART, IQ31244_UART) + MAPIO(iq31244_map_io) + INITIRQ(iop321_init_irq) + INITTIME(iop321_init_time) + BOOT_PARAMS(0xa0000100) +MACHINE_END +#else +#error No machine descriptor defined for this IOP3XX implementation +#endif diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c index 7d4e812457942..b2135e18e1962 100644 --- a/arch/arm/mach-iop3xx/iop321-time.c +++ b/arch/arm/mach-iop3xx/iop321-time.c @@ -5,7 +5,7 @@ * * Author: Deepak Saxena * - * Copyright 2002 MontaVista Software Inc. + * Copyright 2002-2003 MontaVista Software Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -23,17 +23,25 @@ #include #include #include - +#include #include #include +#define IOP321_TIME_SYNC 0 + +static unsigned long iop321_latch; + +static inline unsigned long get_elapsed(void) +{ + return iop321_latch - *IOP321_TU_TCR0; +} + static unsigned long iop321_gettimeoffset(void) { unsigned long elapsed, usec; + u32 tisr1, tisr2; /* - * FIXME: Implement what is described in this comment. - * * If an interrupt was pending before we read the timer, * we've already wrapped. Factor this into the time. * If an interrupt was pending after we read the timer, @@ -42,12 +50,19 @@ static unsigned long iop321_gettimeoffset(void) * be sure its value is after the wrap. */ - elapsed = *IOP321_TU_TCR0; + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1)); + elapsed = get_elapsed(); + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2)); + + if(tisr1 & 1) + elapsed += iop321_latch; + else if (tisr2 & 1) + elapsed = iop321_latch + get_elapsed(); /* * Now convert them to usec. */ - usec = (unsigned long)((LATCH - elapsed) * (tick_nsec / 1000)) / LATCH; + usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / iop321_latch; return usec; } @@ -56,6 +71,10 @@ static irqreturn_t iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { u32 tisr; +#ifdef IOP321_TIME_SYNC + u32 passed; +#define TM_THRESH (iop321_latch*2) +#endif asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr)); @@ -63,7 +82,24 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr)); - timer_tick(regs); +#ifdef IOP321_TIME_SYNC + passed = 0xffffffff - *IOP321_TU_TCR1; + + do + { + do_timer(regs); + if(passed < TM_THRESH) + break; + if(passed > iop321_latch) + passed -= iop321_latch; + else + passed = 0; + } while(1); + + asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff)); +#else + do_timer(regs); +#endif return IRQ_HANDLED; } @@ -79,17 +115,27 @@ extern int setup_arm_irq(int, struct irqaction*); void __init iop321_init_time(void) { u32 timer_ctl; -/* u32 latch = LATCH; */ + iop321_latch = (CLOCK_TICK_RATE + HZ / 2) / HZ; gettimeoffset = iop321_gettimeoffset; setup_irq(IRQ_IOP321_TIMER0, &iop321_timer_irq); timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD | IOP321_TMR_RATIO_1_1; - asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH)); + asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (iop321_latch)); asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl)); + +#ifdef IOP321_TIME_SYNC + /* Setup second timer */ + /* setup counter */ + timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | + IOP321_TMR_RATIO_1_1; + asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff)); + /* setup control */ + asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl)); +#endif } diff --git a/arch/arm/mach-iop3xx/iop331-irq.c b/arch/arm/mach-iop3xx/iop331-irq.c new file mode 100644 index 0000000000000..f4d4321737a4b --- /dev/null +++ b/arch/arm/mach-iop3xx/iop331-irq.c @@ -0,0 +1,127 @@ +/* + * linux/arch/arm/mach-iop3xx/iop331-irq.c + * + * Generic IOP331 IRQ handling functionality + * + * Author: Dave Jiang + * Copyright (C) 2003 Intel Corp. + * + * 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 +#include +#include + +#include +#include +#include + +#include + +static u32 iop331_mask0 = 0; +static u32 iop331_mask1 = 0; + +static inline void intctl_write0(u32 val) +{ + // INTCTL0 + asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val)); +} + +static inline void intctl_write1(u32 val) +{ + // INTCTL1 + asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val)); +} + +static inline void intstr_write0(u32 val) +{ + // INTSTR0 + asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val)); +} + +static inline void intstr_write1(u32 val) +{ + // INTSTR1 + asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val)); +} + +static void +iop331_irq_mask1 (unsigned int irq) +{ + iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS)); + intctl_write0(iop331_mask0); +} + +static void +iop331_irq_mask2 (unsigned int irq) +{ + iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32)); + intctl_write1(iop331_mask1); +} + +static void +iop331_irq_unmask1(unsigned int irq) +{ + iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS)); + intctl_write0(iop331_mask0); +} + +static void +iop331_irq_unmask2(unsigned int irq) +{ + iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32)); + intctl_write1(iop331_mask1); +} + +struct irqchip iop331_irqchip1 = { + .ack = iop331_irq_mask1, + .mask = iop331_irq_mask1, + .unmask = iop331_irq_unmask1, +}; + +struct irqchip iop331_irqchip2 = { + .ack = iop331_irq_mask2, + .mask = iop331_irq_mask2, + .unmask = iop331_irq_unmask2, +}; + +void __init iop331_init_irq(void) +{ + unsigned int i, tmp; + + /* Enable access to coprocessor 6 for dealing with IRQs. + * From RMK: + * Basically, the Intel documentation here is poor. It appears that + * you need to set the bit to be able to access the coprocessor from + * SVC mode. Whether that allows access from user space or not is + * unclear. + */ + asm volatile ( + "mrc p15, 0, %0, c15, c1, 0\n\t" + "orr %0, %0, %1\n\t" + "mcr p15, 0, %0, c15, c1, 0\n\t" + /* The action is delayed, so we have to do this: */ + "mrc p15, 0, %0, c15, c1, 0\n\t" + "mov %0, %0\n\t" + "sub pc, pc, #4" + : "=r" (tmp) : "i" (1 << 6) ); + + intctl_write0(0); // disable all interrupts + intctl_write1(0); + intstr_write0(0); // treat all as IRQ + intstr_write1(0); + if(machine_is_iq80331()) // all interrupts are inputs to chip + *IOP331_PCIIRSR = 0x0f; + + for(i = IOP331_IRQ_OFS; i < NR_IOP331_IRQS; i++) + { + set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } +} + diff --git a/arch/arm/mach-iop3xx/iop331-mm.c b/arch/arm/mach-iop3xx/iop331-mm.c new file mode 100644 index 0000000000000..8a43d4dc3d7bf --- /dev/null +++ b/arch/arm/mach-iop3xx/iop331-mm.c @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-iop3xx/mm.c + * + * Low level memory initialization for IOP331 based systems + * + * Author: Dave Jiang + * Copyright (C) 2003 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + + +/* + * Standard IO mapping for all IOP331 based systems + */ +static struct map_desc iop331_std_desc[] __initdata = { + /* virtual physical length type */ + + /* mem mapped registers */ + { IOP331_VIRT_MEM_BASE, IOP331_PHYS_MEM_BASE, 0x00002000, MT_DEVICE }, + + /* PCI IO space */ + { 0xfe000000, 0x90000000, 0x00020000, MT_DEVICE } +}; + +void __init iop331_map_io(void) +{ + iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc)); +} diff --git a/arch/arm/mach-iop3xx/iop331-pci.c b/arch/arm/mach-iop3xx/iop331-pci.c new file mode 100644 index 0000000000000..cf1e633d5bc4e --- /dev/null +++ b/arch/arm/mach-iop3xx/iop331-pci.c @@ -0,0 +1,219 @@ +/* + * arch/arm/mach-iop3xx/iop331-pci.c + * + * PCI support for the Intel IOP331 chipset + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2003 Intel Corp. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +//#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) do { } while (0) +#endif + +/* + * This routine builds either a type0 or type1 configuration command. If the + * bus is on the 80331 then a type0 made, else a type1 is created. + */ +static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where) +{ + struct pci_sys_data *sys = bus->sysdata; + u32 addr; + + if (sys->busnr == bus->number) + addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11); + else + addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1; + + addr |= PCI_FUNC(devfn) << 8 | (where & ~3); + + return addr; +} + +/* + * This routine checks the status of the last configuration cycle. If an error + * was detected it returns a 1, else it returns a 0. The errors being checked + * are parity, master abort, target abort (master and target). These types of + * errors occure during a config cycle where there is no device, like during + * the discovery stage. + */ +static int iop331_pci_status(void) +{ + unsigned int status; + int ret = 0; + + /* + * Check the status registers. + */ + status = *IOP331_ATUSR; + if (status & 0xf900) + { + DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status); + *IOP331_ATUSR = status & 0xf900; + ret = 1; + } + status = *IOP331_ATUISR; + if (status & 0x679f) + { + DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status); + *IOP331_ATUISR = status & 0x679f; + ret = 1; + } + return ret; +} + +/* + * Simply write the address register and read the configuration + * data. Note that the 4 nop's ensure that we are able to handle + * a delayed abort (in theory.) + */ +static inline u32 iop331_read(unsigned long addr) +{ + u32 val; + + __asm__ __volatile__( + "str %1, [%2]\n\t" + "ldr %0, [%3]\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + : "=r" (val) + : "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR)); + + return val; +} + +/* + * The read routines must check the error status of the last configuration + * cycle. If there was an error, the routine returns all hex f's. + */ +static int +iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + unsigned long addr = iop331_cfg_address(bus, devfn, where); + u32 val = iop331_read(addr) >> ((where & 3) * 8); + + if( iop331_pci_status() ) + val = 0xffffffff; + + *value = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + unsigned long addr = iop331_cfg_address(bus, devfn, where); + u32 val; + + if (size != 4) { + val = iop331_read(addr); + if (!iop331_pci_status() == 0) + return PCIBIOS_SUCCESSFUL; + + where = (where & 3) * 8; + + if (size == 1) + val &= ~(0xff << where); + else + val &= ~(0xffff << where); + + *IOP331_OCCDR = val | value << where; + } else { + asm volatile( + "str %1, [%2]\n\t" + "str %0, [%3]\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + : + : "r" (value), "r" (addr), + "r" (IOP331_OCCAR), "r" (IOP331_OCCDR)); + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops iop331_ops = { + .read = iop331_read_config, + .write = iop331_write_config, +}; + +/* + * When a PCI device does not exist during config cycles, the XScale gets a + * bus error instead of returning 0xffffffff. This handler simply returns. + */ +int +iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n", + addr, fsr, regs->ARM_pc, regs->ARM_lr); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +/* + * Scan an IOP331 PCI bus. sys->bus defines which bus we scan. + */ +struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &iop331_ops, sys); +} + +void iop331_init(void) +{ + DBG("PCI: Intel 80331 PCI init code.\n"); + DBG("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD); + DBG("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n", + *IOP331_OMWTVR0, + *IOP331_OIOWTVR); + DBG("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR); + DBG("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0); + DBG("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR); + DBG("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2); + DBG("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3); + +#if 0 + hook_fault_code(4, iop331_pci_abort, SIGBUS, "external abort on linefetch"); + hook_fault_code(6, iop331_pci_abort, SIGBUS, "external abort on linefetch"); + hook_fault_code(8, iop331_pci_abort, SIGBUS, "external abort on non-linefetch"); + hook_fault_code(10, iop331_pci_abort, SIGBUS, "external abort on non-linefetch"); +#endif + hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort"); +} + diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c new file mode 100644 index 0000000000000..681e1ce78442e --- /dev/null +++ b/arch/arm/mach-iop3xx/iop331-setup.c @@ -0,0 +1,102 @@ +/* + * linux/arch/arm/mach-iop3xx/iop331-setup.c + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2004 Intel Corporation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IOP331_UART_XTAL 33334000 + +/* + * Standard IO mapping for all IOP331 based systems + */ +static struct map_desc iop331_std_desc[] __initdata = { + /* virtual physical length type */ + + /* mem mapped registers */ + { IOP331_VIRT_MEM_BASE, IOP331_PHYS_MEM_BASE, 0x00002000, MT_DEVICE }, + + /* PCI IO space */ + { 0xfe000000, 0x90000000, 0x00020000, MT_DEVICE } +}; + +static struct uart_port iop331_serial_ports[] = { + { + .membase = (char*)(IQ80331_UART0_VIRT), + .mapbase = (IQ80331_UART0_PHYS), + .irq = IRQ_IOP331_UART0, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IOP331_UART_XTAL, + .line = 0, + .type = PORT_XSCALE, + .fifosize = 32 + } , { + .membase = (char*)(IQ80331_UART1_VIRT), + .mapbase = (IQ80331_UART1_PHYS), + .irq = IRQ_IOP331_UART1, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IOP331_UART_XTAL, + .line = 1, + .type = PORT_XSCALE, + .fifosize = 32 + } +}; + +void __init iop331_map_io(void) +{ + iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc)); + early_serial_setup(&iop331_serial_ports[0]); + early_serial_setup(&iop331_serial_ports[1]); +} + +#ifdef CONFIG_ARCH_IQ80331 +extern void iop331_init_irq(void); +extern void iop331_init_time(void); +extern void iq80331_map_io(void); +#endif + +#if defined(CONFIG_ARCH_IQ80331) +MACHINE_START(IQ80331, "Intel IQ80331") + MAINTAINER("Intel Corp.") + BOOT_MEM(PHYS_OFFSET, 0xfefff000, 0xfffff000) // virtual, physical + //BOOT_MEM(PHYS_OFFSET, IQ80331_UART0_VIRT, IQ80331_UART0_PHYS) + MAPIO(iq80331_map_io) + INITIRQ(iop331_init_irq) + INITTIME(iop331_init_time) + BOOT_PARAMS(0x0100) +MACHINE_END +#else +#error No machine descriptor defined for this IOP3XX implementation +#endif + + diff --git a/arch/arm/mach-iop3xx/iop331-time.c b/arch/arm/mach-iop3xx/iop331-time.c new file mode 100644 index 0000000000000..c90a0c9bd3dd2 --- /dev/null +++ b/arch/arm/mach-iop3xx/iop331-time.c @@ -0,0 +1,141 @@ +/* + * arch/arm/mach-iop3xx/iop331-time.c + * + * Timer code for IOP331 based systems + * + * Author: Dave Jiang + * + * Copyright 2003 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef IOP331_TIME_SYNC + +static unsigned long iop331_latch; + +static inline unsigned long get_elapsed(void) +{ + return iop331_latch - *IOP331_TU_TCR0; +} + +static unsigned long iop331_gettimeoffset(void) +{ + unsigned long elapsed, usec; + u32 tisr1, tisr2; + + /* + * If an interrupt was pending before we read the timer, + * we've already wrapped. Factor this into the time. + * If an interrupt was pending after we read the timer, + * it may have wrapped between checking the interrupt + * status and reading the timer. Re-read the timer to + * be sure its value is after the wrap. + */ + + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1)); + elapsed = get_elapsed(); + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2)); + + if(tisr1 & 1) + elapsed += iop331_latch; + else if (tisr2 & 1) + elapsed = iop331_latch + get_elapsed(); + + /* + * Now convert them to usec. + */ + usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / iop331_latch; + + return usec; +} + +static irqreturn_t +iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 tisr; +#ifdef IOP331_TIME_SYNC + u32 passed; +#define TM_THRESH (iop331_latch*2) +#endif + + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr)); + + tisr |= 1; + + asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr)); + +#ifdef IOP331_TIME_SYNC + passed = 0xffffffff - *IOP331_TU_TCR1; + + do + { + do_timer(regs); + if(passed < TM_THRESH) + break; + if(passed > iop331_latch) + passed -= iop331_latch; + else + passed = 0; + } while(1); + + asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff)); +#else + do_timer(regs); +#endif + + return IRQ_HANDLED; +} + +static struct irqaction iop331_timer_irq = { + .name = "IOP331 Timer Tick", + .handler = iop331_timer_interrupt, + .flags = SA_INTERRUPT +}; + +extern int setup_arm_irq(int, struct irqaction*); + +void __init iop331_init_time(void) +{ + u32 timer_ctl; + + iop331_latch = (CLOCK_TICK_RATE + HZ / 2) / HZ; + gettimeoffset = iop331_gettimeoffset; + setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq); + + timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD | + IOP331_TMR_RATIO_1_1; + + asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (iop331_latch)); + + asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl)); + +#ifdef IOP331_TIME_SYNC + /* Setup second timer */ + /* setup counter */ + timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | + IOP331_TMR_RATIO_1_1; + asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff)); + /* setup control */ + asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl)); +#endif +} + + diff --git a/arch/arm/mach-iop3xx/iq31244-mm.c b/arch/arm/mach-iop3xx/iq31244-mm.c new file mode 100644 index 0000000000000..b01042f7de71f --- /dev/null +++ b/arch/arm/mach-iop3xx/iq31244-mm.c @@ -0,0 +1,44 @@ +/* + * linux/arch/arm/mach-iop3xx/mm.c + * + * Low level memory initialization for iq80321 platform + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + + +/* + * IQ80321 specific IO mappings + * + * We use RedBoot's setup for the onboard devices. + */ +static struct map_desc iq31244_io_desc[] __initdata = { + /* virtual physical length type */ + + /* on-board devices */ + { IQ31244_UART, IQ31244_UART, 0x00100000, MT_DEVICE } +}; + +void __init iq31244_map_io(void) +{ + iop321_map_io(); + + iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc)); +} diff --git a/arch/arm/mach-iop3xx/iq31244-pci.c b/arch/arm/mach-iop3xx/iq31244-pci.c new file mode 100644 index 0000000000000..5eac93eb9d3d9 --- /dev/null +++ b/arch/arm/mach-iop3xx/iq31244-pci.c @@ -0,0 +1,134 @@ +/* + * arch/arm/mach-iop3xx/iq80321-pci.c + * + * PCI support for the Intel IQ80321 reference board + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * 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 +#include +#include + +#include +#include +#include +#include + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. We assume 1 <= pin <= 4 + */ +#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \ +({ int _ctl_ = -1; \ + unsigned int _idsel = idsel - minid; \ + if (_idsel <= maxid) \ + _ctl_ = pci_irq_table[_idsel][pin-1]; \ + _ctl_; }) + +#define INTA IRQ_IQ31244_INTA +#define INTB IRQ_IQ31244_INTB +#define INTC IRQ_IQ31244_INTC +#define INTD IRQ_IQ31244_INTD + +#define INTE IRQ_IQ31244_I82546 + +static inline int __init +iq31244_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + static int pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ +#ifdef CONFIG_ARCH_EP80219 + {INTB, INTB, INTB, INTB}, /* CFlash */ + {INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */ + {INTD, INTD, INTD, INTD}, /* PCI-X Slot */ + {INTC, INTC, INTC, INTC}, /* SATA */ +#else + {INTB, INTB, INTB, INTB}, /* CFlash */ + {INTC, INTC, INTC, INTC}, /* SATA */ + {INTD, INTD, INTD, INTD}, /* PCI-X Slot */ + {INTE, INTE, INTE, INTE}, /* 82546 GigE */ +#endif // CONFIG_ARCH_EP80219 + }; + + BUG_ON(pin < 1 || pin > 4); + + return PCI_IRQ_TABLE_LOOKUP(0, 7); +} + +static int iq31244_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if(nr != 0) + return 0; + + res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + panic("PCI: unable to alloc resources"); + + memset(res, 0, sizeof(struct resource) * 2); + + res[0].start = IQ31244_PCI_IO_BASE + 0x6e000000; + res[0].end = IQ31244_PCI_IO_BASE + IQ31244_PCI_IO_SIZE - 1 + IQ31244_PCI_IO_OFFSET; + res[0].name = "IQ31244 PCI I/O Space"; + res[0].flags = IORESOURCE_IO; + + res[1].start = IQ31244_PCI_MEM_BASE; + res[1].end = IQ31244_PCI_MEM_BASE + IQ31244_PCI_MEM_SIZE; + res[1].name = "IQ31244 PCI Memory Space"; + res[1].flags = IORESOURCE_MEM; + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + sys->io_offset = IQ31244_PCI_IO_OFFSET; + sys->mem_offset = IQ80321_PCI_MEM_BASE - + (*IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK); + + iop3xx_pcibios_min_io = IQ31244_PCI_IO_BASE; + iop3xx_pcibios_min_mem = IQ31244_PCI_MEM_BASE; + + return 1; +} + +static void iq31244_preinit(void) +{ + iop321_init(); + /* setting up the second translation window */ + *IOP321_OMWTVR1 = IQ31244_PCI_MEM_BASE + 0x04000000; + *IOP321_OUMWTVR1 = 0x0; +} + +static struct hw_pci iq31244_pci __initdata = { + .swizzle = pci_std_swizzle, + .nr_controllers = 1, + .setup = iq31244_setup, + .scan = iop321_scan_bus, + .preinit = iq31244_preinit, + .map_irq = iq31244_map_irq +}; + +static int __init iq31244_pci_init(void) +{ + if (machine_is_iq31244()) + pci_common_init(&iq31244_pci); + return 0; +} + +subsys_initcall(iq31244_pci_init); + + + + diff --git a/arch/arm/mach-iop3xx/iq80321-mm.c b/arch/arm/mach-iop3xx/iq80321-mm.c new file mode 100644 index 0000000000000..1580c7ed2b9d2 --- /dev/null +++ b/arch/arm/mach-iop3xx/iq80321-mm.c @@ -0,0 +1,44 @@ +/* + * linux/arch/arm/mach-iop3xx/mm.c + * + * Low level memory initialization for iq80321 platform + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + + +/* + * IQ80321 specific IO mappings + * + * We use RedBoot's setup for the onboard devices. + */ +static struct map_desc iq80321_io_desc[] __initdata = { + /* virtual physical length type */ + + /* on-board devices */ + { IQ80321_UART, IQ80321_UART, 0x00100000, MT_DEVICE } +}; + +void __init iq80321_map_io(void) +{ + iop321_map_io(); + + iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc)); +} diff --git a/arch/arm/mach-iop3xx/iq80321-pci.c b/arch/arm/mach-iop3xx/iq80321-pci.c index 7dce5dfa627ea..5d9624863e4ee 100644 --- a/arch/arm/mach-iop3xx/iq80321-pci.c +++ b/arch/arm/mach-iop3xx/iq80321-pci.c @@ -38,37 +38,79 @@ #define INTE IRQ_IQ80321_I82544 -typedef u8 irq_table[4]; - -static irq_table pci_irq_table[] = { - /* - * PCI IDSEL/INTPIN->INTLINE - * A B C D - */ - {INTE, INTE, INTE, INTE}, /* Gig-E */ - {INTD, INTC, INTD, INTA}, /* Unused */ - {INTC, INTD, INTA, INTB}, /* PCI-X Slot */ -}; - static inline int __init iq80321_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) { + static int pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTE, INTE, INTE, INTE}, /* Gig-E */ + {-1, -1, -1, -1}, /* Unused */ + {INTC, INTD, INTA, INTB}, /* PCI-X Slot */ + {-1, -1, -1, -1}, + }; + BUG_ON(pin < 1 || pin > 4); - return PCI_IRQ_TABLE_LOOKUP(2, 3); +// return PCI_IRQ_TABLE_LOOKUP(4, 7); + return pci_irq_table[idsel%4][pin-1]; } static int iq80321_setup(int nr, struct pci_sys_data *sys) { - switch (nr) { - case 0: - sys->map_irq = iq80321_map_irq; - break; - default: + struct resource *res; + + if(nr != 0) return 0; - } - return iop321_setup(nr, sys); + res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + panic("PCI: unable to alloc resources"); + + memset(res, 0, sizeof(struct resource) * 2); + + res[0].start = IQ80321_PCI_IO_BASE + IQ80321_PCI_IO_OFFSET; + res[0].end = IQ80321_PCI_IO_BASE + IQ80321_PCI_IO_SIZE - 1 + IQ80321_PCI_IO_OFFSET; + res[0].name = "IQ80321 PCI I/O Space"; + res[0].flags = IORESOURCE_IO; + + res[1].start = IQ80321_PCI_MEM_BASE; + res[1].end = IQ80321_PCI_MEM_BASE + IQ80321_PCI_MEM_SIZE; + res[1].name = "IQ80321 PCI Memory Space"; + res[1].flags = IORESOURCE_MEM; + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + /* + * Since the IQ80321 is a slave card on a PCI backplane, + * it uses BAR1 to reserve a portion of PCI memory space for + * use with the private devices on the secondary bus + * (GigE and PCI-X slot). We read BAR1 and configure + * our outbound translation windows to target that + * address range and assign all devices in that + * address range. W/O this, certain BIOSes will fail + * to boot as the IQ80321 claims addresses that are + * in use by other devices. + * + * Note that the same cannot be done with I/O space, + * so hopefully the host will stick to the lower 64K for + * PCI I/O and leave us alone. + */ + sys->mem_offset = IQ80321_PCI_MEM_BASE - + (*IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK); + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + sys->io_offset = IQ80321_PCI_IO_OFFSET; + + iop3xx_pcibios_min_io = IQ80321_PCI_IO_BASE; + iop3xx_pcibios_min_mem = IQ80321_PCI_MEM_BASE; + + return 1; } static void iq80321_preinit(void) @@ -82,6 +124,7 @@ static struct hw_pci iq80321_pci __initdata = { .setup = iq80321_setup, .scan = iop321_scan_bus, .preinit = iq80321_preinit, + .map_irq = iq80321_map_irq }; static int __init iq80321_pci_init(void) diff --git a/arch/arm/mach-iop3xx/iq80331-mm.c b/arch/arm/mach-iop3xx/iq80331-mm.c new file mode 100644 index 0000000000000..ee8c333e115f6 --- /dev/null +++ b/arch/arm/mach-iop3xx/iq80331-mm.c @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/mach-iop3xx/mm.c + * + * Low level memory initialization for iq80331 platform + * + * Author: Dave Jiang + * Copyright (C) 2003 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + + +/* + * IQ80331 specific IO mappings + * + * We use RedBoot's setup for the onboard devices. + */ + +void __init iq80331_map_io(void) +{ + iop331_map_io(); +} diff --git a/arch/arm/mach-iop3xx/iq80331-pci.c b/arch/arm/mach-iop3xx/iq80331-pci.c new file mode 100644 index 0000000000000..1eff5573d7bad --- /dev/null +++ b/arch/arm/mach-iop3xx/iq80331-pci.c @@ -0,0 +1,138 @@ +/* + * arch/arm/mach-iop3xx/iq80331-pci.c + * + * PCI support for the Intel IQ80331 reference board + * + * Author: Dave Jiang + * Copyright (C) 2003 Intel Corp. + * + * 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 +#include +#include + +#include +#include +#include +#include + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. We assume 1 <= pin <= 4 + */ +#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \ +({ int _ctl_ = -1; \ + unsigned int _idsel = idsel - minid; \ + if (_idsel <= maxid) \ + _ctl_ = pci_irq_table[_idsel][pin-1]; \ + _ctl_; }) + +#define INTA IRQ_IQ80331_INTA +#define INTB IRQ_IQ80331_INTB +#define INTC IRQ_IQ80331_INTC +#define INTD IRQ_IQ80331_INTD + +//#define INTE IRQ_IQ80331_I82544 + +static inline int __init +iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + static int pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTB, INTC, INTD, INTA}, /* PCI-X Slot */ + {INTC, INTC, INTC, INTC}, /* GigE */ + }; + + BUG_ON(pin < 1 || pin > 4); + + return PCI_IRQ_TABLE_LOOKUP(1, 7); +} + +static int iq80331_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if(nr != 0) + return 0; + + res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + panic("PCI: unable to alloc resources"); + + memset(res, 0, sizeof(struct resource) * 2); + + res[0].start = IQ80331_PCI_IO_BASE + 0x6e000000; + res[0].end = IQ80331_PCI_IO_BASE + IQ80331_PCI_IO_SIZE - 1 + IQ80331_PCI_IO_OFFSET; + res[0].name = "IQ80331 PCI I/O Space"; + res[0].flags = IORESOURCE_IO; + + res[1].start = IQ80331_PCI_MEM_BASE; + res[1].end = IQ80331_PCI_MEM_BASE + IQ80331_PCI_MEM_SIZE; + res[1].name = "IQ80331 PCI Memory Space"; + res[1].flags = IORESOURCE_MEM; + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + /* + * Since the IQ80331 is a slave card on a PCI backplane, + * it uses BAR1 to reserve a portion of PCI memory space for + * use with the private devices on the secondary bus + * (GigE and PCI-X slot). We read BAR1 and configure + * our outbound translation windows to target that + * address range and assign all devices in that + * address range. W/O this, certain BIOSes will fail + * to boot as the IQ80331 claims addresses that are + * in use by other devices. + * + * Note that the same cannot be done with I/O space, + * so hopefully the host will stick to the lower 64K for + * PCI I/O and leave us alone. + */ + sys->mem_offset = IQ80331_PCI_MEM_BASE - + (*IOP331_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK); + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + sys->io_offset = IQ80331_PCI_IO_OFFSET; + + iop3xx_pcibios_min_io = IQ80331_PCI_IO_BASE; + iop3xx_pcibios_min_mem = IQ80331_PCI_MEM_BASE; + + return 1; +} + +static void iq80331_preinit(void) +{ + iop331_init(); +} + +static struct hw_pci iq80331_pci __initdata = { + .swizzle = pci_std_swizzle, + .nr_controllers = 1, + .setup = iq80331_setup, + .scan = iop331_scan_bus, + .preinit = iq80331_preinit, + .map_irq = iq80331_map_irq +}; + +static int __init iq80331_pci_init(void) +{ + if (machine_is_iq80331()) + pci_common_init(&iq80331_pci); + return 0; +} + +subsys_initcall(iq80331_pci_init); + + + + -- 2.53.0