From c879774b35a935881ad9780d355caa4d5c865336 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 2 Jun 2007 23:13:51 +0000 Subject: [PATCH] IRQ handler rewrite by Gabor Juhos, uses C no longer assembly SVN-Revision: 7464 --- .../files/arch/mips/adm5120/Makefile | 5 +- .../files/arch/mips/adm5120/int-handler.S | 135 -------- .../adm5120-2.6/files/arch/mips/adm5120/irq.c | 288 ++++++++++-------- .../files/arch/mips/adm5120/setup.c | 38 +-- .../files/arch/mips/pci/fixup-adm5120.c | 99 ++++++ .../files/arch/mips/pci/ops-adm5120.c | 64 ++-- .../files/arch/mips/pci/pci-adm5120.c | 76 ++--- .../adm5120-2.6/files/drivers/net/adm5120sw.c | 9 +- .../adm5120-2.6/files/drivers/net/adm5120sw.h | 1 - .../files/drivers/serial/adm5120_uart.c | 28 +- .../asm-mips/mach-adm5120/adm5120_intc.h | 73 +++++ .../asm-mips/mach-adm5120/adm5120_irq.h | 55 ++++ .../adm5120-2.6/patches/001-adm5120.patch | 11 +- .../adm5120-2.6/patches/007-adm5120_pci.patch | 20 ++ 14 files changed, 518 insertions(+), 384 deletions(-) delete mode 100644 target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S create mode 100644 target/linux/adm5120-2.6/files/arch/mips/pci/fixup-adm5120.c create mode 100644 target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_intc.h create mode 100644 target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_irq.h create mode 100644 target/linux/adm5120-2.6/patches/007-adm5120_pci.patch diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile index f3e0e7f988..deb1adf7e1 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile @@ -2,7 +2,8 @@ # Makefile for the ADMtek ADM5120 SoC specific parts of the kernel # -obj-y := setup.o prom.o irq.o memory.o int-handler.o adm5120_info.o -obj-y += gpio.o +obj-y := setup.o prom.o irq.o memory.o adm5120_info.o +obj-y += gpio.o +obj-y += time.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S b/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S deleted file mode 100644 index f118fb402b..0000000000 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Interrupt exception dispatch code. - * - */ -#include - -#include -#include -#include -#include - -#define STATUS_IE 0x00000001 - -/* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop and moving across - * all the pending IRQ bits in the cause register is _NOT_ the answer, the - * common case is one pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register IRQ mask, that - * would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in - * between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the MIPS board look basically (barring software - * IRQs which we don't use at all and all external interrupt sources are - * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Combined hardware interrupt (hw0) - * 3 Hardware (ignored) - * 4 Hardware (ignored) - * 5 Hardware (ignored) - * 6 Hardware (ignored) - * 7 R4k timer (what we use) - * - * Note: On the SEAD board thing are a little bit different. - * Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired - * wired to UART1. - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Lowest ---- Combined hardware interrupt - * - * then we just return, if multiple IRQs are pending then we will just take - * another exception, big deal. - */ - - .text - .set noreorder - .set noat - .align 5 - -NESTED(mipsIRQ, PT_SIZE, sp) - SAVE_ALL - CLI - .set at - - mfc0 s0, CP0_CAUSE - mfc0 s1, CP0_STATUS - and s0, s0, s1 - - /* First we check for r4k counter/timer IRQ. */ - andi a0, s0, CAUSEF_IP7 - beq a0, zero, 1f - nop - - move a0, sp - jal mips_timer_interrupt - nop - - j ret_from_irq - nop - -1: - andi a0, s0, CAUSEF_IP2 - beq a0, zero, 1f - nop - - move a0, sp - jal adm5120_hw0_irqdispatch - nop -1: - j ret_from_irq - nop - -END(mipsIRQ) - - -LEAF(mips_int_lock) - .set noreorder - mfc0 v0, CP0_STATUS - li v1, ~STATUS_IE - and v1, v1, v0 - mtc0 v1, CP0_STATUS - j ra - and v0, v0, STATUS_IE - .set reorder -END(mips_int_lock) - - -LEAF(mips_int_unlock) - mfc0 v0, CP0_STATUS - and a0, a0, STATUS_IE - or v0, v0, a0 - mtc0 v0, CP0_STATUS - j ra - nop -END(mips_int_unlock) - diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c index c53272e1e0..3e14c92f11 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c @@ -1,157 +1,203 @@ /* - * Copyright (C) ADMtek Incorporated. - * Creator : daniell@admtek.com.tw - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000, 2001 MIPS Technologies, Inc. - * Copyright (C) 2001 Ralf Baechle - * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * $Id$ + * + * ADM5120 specific interrupt handlers + * + * Copyright (C) 2007 Gabor Juhos + * Copyright (C) 2007 OpenWrt.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * */ -#include #include -#include -#include -#include +#include +#include #include -#include -#include -#include +#include #include -#include -#include -#include #include +#include +#include -#define MIPS_CPU_TIMER_IRQ 7 +#include +#include -extern int setup_irq(unsigned int irq, struct irqaction *irqaction); -extern irq_desc_t irq_desc[]; -extern asmlinkage void mipsIRQ(void); +#define INTC_REG(r) (*(volatile u32 *)(KSEG1ADDR(ADM5120_INTC_BASE) + r)) -int mips_int_lock(void); -void mips_int_unlock(int); +static void adm5120_intc_irq_unmask(unsigned int irq); +static void adm5120_intc_irq_mask(unsigned int irq); +static int adm5120_intc_irq_set_type(unsigned int irq, unsigned int flow_type); -unsigned int mips_counter_frequency; +static struct irq_chip adm5120_intc_irq_chip = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + .name = "INTC", +#else + .typename = "INTC", +#endif + .unmask = adm5120_intc_irq_unmask, + .mask = adm5120_intc_irq_mask, + .mask_ack = adm5120_intc_irq_mask, + .set_type = adm5120_intc_irq_set_type +}; -#define ADM5120_INTC_REG(reg) (*(volatile u32 *)(KSEG1ADDR(0x12200000+(reg)))) -#define ADM5120_INTC_STATUS ADM5120_INTC_REG(0x00) -#define ADM5120_INTC_ENABLE ADM5120_INTC_REG(0x08) -#define ADM5120_INTC_DISABLE ADM5120_INTC_REG(0x0c) -#define ADM5120_IRQ_MAX 9 -#define ADM5120_IRQ_MASK 0x3ff +static struct irqaction adm5120_intc_irq_action = { + .handler = no_action, + .name = "cascade [INTC]" +}; -void adm5120_hw0_irqdispatch(struct pt_regs *regs) +static void adm5120_intc_irq_unmask(unsigned int irq) { - unsigned long intsrc; - int i; + unsigned long flags; - intsrc = ADM5120_INTC_STATUS & ADM5120_IRQ_MASK; - - if (intsrc) { - for (i = 0; intsrc; intsrc >>= 1, i++) - if (intsrc & 0x1) - do_IRQ(i); - } else - spurious_interrupt(); + irq -= ADM5120_INTC_IRQ_BASE; + local_irq_save(flags); + INTC_REG(INTC_REG_IRQ_ENABLE) = (1 << irq); + local_irq_restore(flags); } -void mips_timer_interrupt(struct pt_regs *regs) +static void adm5120_intc_irq_mask(unsigned int irq) { - write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); - ll_timer_interrupt(MIPS_CPU_TIMER_IRQ); + unsigned long flags; + + irq -= ADM5120_INTC_IRQ_BASE; + local_irq_save(flags); + INTC_REG(INTC_REG_IRQ_DISABLE) = (1 << irq); + local_irq_restore(flags); } -/* Main interrupt dispatcher */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +static int adm5120_intc_irq_set_type(unsigned int irq, unsigned int flow_type) { - unsigned int cp0_cause = read_c0_cause() & read_c0_status(); + /* TODO: not yet tested */ +#if 1 + unsigned int sense; + unsigned long mode; + int err; - if (cp0_cause & CAUSEF_IP7) { - mips_timer_interrupt( regs); - } else if (cp0_cause & CAUSEF_IP2) { - adm5120_hw0_irqdispatch( regs); - } -} - -void enable_adm5120_irq(unsigned int irq) -{ - int s; - - /* Disable all interrupts (FIQ/IRQ) */ - s = mips_int_lock(); - - if ((irq < 0) || (irq > ADM5120_IRQ_MAX)) - goto err_exit; - - ADM5120_INTC_ENABLE = (1< ADM5120_IRQ_MAX)) - goto err_exit; - - ADM5120_INTC_DISABLE = (1<>=1) { + if ((status & 1) == 1) + do_IRQ(irq); + } + } else + spurious_interrupt(); +#endif } -static inline void ack_adm5120_irq(unsigned int irq_nr) +asmlinkage void plat_irq_dispatch(void) { - ADM5120_INTC_DISABLE = (1 << irq_nr); + unsigned long pending; + + pending = read_c0_status() & read_c0_cause(); + + if (pending & STATUSF_IP7) + do_IRQ(ADM5120_IRQ_COUNTER); + else if (pending & STATUSF_IP2) + adm5120_intc_irq_dispatch(); + else + spurious_interrupt(); } - -static void end_adm5120_irq(unsigned int irq_nr) -{ - ADM5120_INTC_ENABLE = (1 << irq_nr); -} - -static hw_irq_controller adm5120_irq_type = { - .typename = "MIPS", - .startup = startup_adm5120_irq, - .shutdown = shutdown_adm5120_irq, - .enable = enable_adm5120_irq, - .disable = disable_adm5120_irq, - .ack = ack_adm5120_irq, - .end = end_adm5120_irq, - .set_affinity = NULL, -}; - - -void __init arch_init_irq(void) +#define INTC_IRQ_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED) +static void __init adm5120_intc_irq_init(int base) { int i; - - for (i = 0; i <= ADM5120_IRQ_MAX; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - irq_desc[i].chip = &adm5120_irq_type; + + /* disable all interrupts */ + INTC_REG(INTC_REG_IRQ_DISABLE) = INTC_INT_ALL; + /* setup all interrupts to generate IRQ instead of FIQ */ + INTC_REG(INTC_REG_INT_MODE) = 0; + /* set active level for all external interrupts to HIGH */ + INTC_REG(INTC_REG_INT_LEVEL) = 0; + /* disable usage of the TEST_SOURCE register */ + INTC_REG(INTC_REG_IRQ_SOURCE_SELECT) = 0; + + for(i=ADM5120_INTC_IRQ_BASE; i <= ADM5120_INTC_IRQ_BASE+INTC_IRQ_LAST; + i++) { + irq_desc[i].status = INTC_IRQ_STATUS; + set_irq_chip_and_handler(i, &adm5120_intc_irq_chip, + handle_level_irq); } + + setup_irq(ADM5120_IRQ_INTC, &adm5120_intc_irq_action); +} + +void __init arch_init_irq(void) { + mips_cpu_irq_init(); + adm5120_intc_irq_init(ADM5120_INTC_IRQ_BASE); } diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c index 5767df8b23..aa30dc5c83 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c @@ -15,15 +15,13 @@ #include #include -#include +#include +#include +#include + +extern void adm5120_time_init(void) __init; #define ADM5120_SOFTRESET 0x12000004 -#define STATUS_IE 0x00000001 -#define ALLINTS (IE_IRQ0 | IE_IRQ5 | STATUS_IE) - -void mips_time_init(void); - -extern unsigned int mips_counter_frequency; void adm5120_restart(char *command) { @@ -43,25 +41,11 @@ void adm5120_power_off(void) adm5120_halt(); } -void __init adm5120_time_init(void) -{ - mips_counter_frequency = adm5120_speed >> 1; -} - -void __init plat_timer_setup(struct irqaction *irq) -{ - /* to generate the first timer interrupt */ - write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); - clear_c0_status(ST0_BEV); - set_c0_status(ALLINTS); -} - void __init plat_mem_setup(void) { printk(KERN_INFO "ADM5120 board setup\n"); board_time_init = adm5120_time_init; - //board_timer_setup = mips_timer_setup; _machine_restart = adm5120_restart; _machine_halt = adm5120_halt; @@ -75,16 +59,15 @@ const char *get_system_type(void) return adm5120_board_name(); } -#ifdef CONFIG_USB static struct resource adm5120_hcd_resources[] = { [0] = { - .start = 0x11200000, - .end = 0x11200084, + .start = ADM5120_USBC_BASE, + .end = ADM5120_USBC_BASE+ADM5120_USBC_SIZE-1, .flags = IORESOURCE_MEM, }, [1] = { - .start = 0x3, - .end = 0x3, + .start = ADM5120_IRQ_USBC, + .end = ADM5120_IRQ_USBC, .flags = IORESOURCE_IRQ, }, }; @@ -105,5 +88,4 @@ static int __init adm5120_init(void) return platform_add_devices(devices, ARRAY_SIZE(devices)); } -arch_initcall(adm5120_init); -#endif +subsys_initcall(adm5120_init); diff --git a/target/linux/adm5120-2.6/files/arch/mips/pci/fixup-adm5120.c b/target/linux/adm5120-2.6/files/arch/mips/pci/fixup-adm5120.c new file mode 100644 index 0000000000..9f65e350ad --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/pci/fixup-adm5120.c @@ -0,0 +1,99 @@ +/* + * $Id$ + * + * ADM5120 specific PCI fixups + * + * Copyright (C) ADMtek Incorporated. + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * Copyright (C) 2007 Gabor Juhos + * Copyright (C) 2007 OpenWrt.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static void adm5120_pci_fixup(struct pci_dev *dev) +{ + if (dev->devfn !=0) + return; + + /* setup COMMAND register */ + pci_write_config_word(dev, PCI_COMMAND, + (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)); + + /* setup CACHE_LINE_SIZE register */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4); + + /* setting up BARS */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_ADM5120, + adm5120_pci_fixup); + + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + irq = -1; +#if 1 + /* FIXME: this code should be working on all boards? */ + if (slot > 0 && slot < 4) + irq = ADM5120_IRQ_PCI0+slot-1; +#else + switch (mips_machtype) { + case MACH_ADM5120_RB_111: + case MACH_ADM5120_RB_112: + case MACH_ADM5120_RB_133: + case MACH_ADM5120_RB_133C: + case MACH_ADM5120_RB_153: + if (slot > 0 && slot < 4) + irq = ADM5120_IRQ_PCI0+slot-1; + break; + default: + if (slot > 1 && slot < 5) + irq = ADM5120_IRQ_PCI0+slot-2; + break; + } +#endif + printk(KERN_INFO "PCI: mapping irq for device %s, slot:%u, pin:%u, " + "irq:%d\n", pci_name(dev), slot, pin, irq); + + return irq; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + diff --git a/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c b/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c index 91dae89999..ff768033ec 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c +++ b/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c @@ -1,17 +1,36 @@ /* - * Copyright (C) ADMtek Incorporated. - * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * Copyright (C) 2007 Gabor Juhos - * Copyright (C) 2007 OpenWrt.org + * $Id$ + * + * ADM5120 specific PCI operations + * + * Copyright (C) ADMtek Incorporated. + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * Copyright (C) 2007 Gabor Juhos + * Copyright (C) 2007 OpenWrt.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * */ -#include #include #include #include #include -#include +#include volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(ADM5120_PCICFG_ADDR); volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(ADM5120_PCICFG_DATA); @@ -24,14 +43,15 @@ static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, *pci_config_address_reg = ((bus->number & 0xff) << 0x10) | ((devfn & 0xff) << 0x08) | (where & 0xfc) | PCI_ENABLE; switch (size) { - case 1: - *val = ((*pci_config_data_reg)>>((where&3)<<3))&0xff; - break; - case 2: - *val = ((*pci_config_data_reg)>>((where&3)<<3))&0xffff; - break; - default: - *val = (*pci_config_data_reg); + case 1: + *val = ((*pci_config_data_reg)>>((where&3)<<3))&0xff; + break; + case 2: + *val = ((*pci_config_data_reg)>>((where&3)<<3))&0xffff; + break; + default: + *val = (*pci_config_data_reg); + break; } return PCIBIOS_SUCCESSFUL; } @@ -42,16 +62,16 @@ static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, *pci_config_address_reg = ((bus->number & 0xff) << 0x10) | ((devfn & 0xff) << 0x08) | (where & 0xfc) | PCI_ENABLE; switch (size) { - case 1: - *(volatile u8 *)(((int)pci_config_data_reg) + + case 1: + *(volatile u8 *)(((int)pci_config_data_reg) + (where & 3)) = val; - break; - case 2: - *(volatile u16 *)(((int)pci_config_data_reg) + + break; + case 2: + *(volatile u16 *)(((int)pci_config_data_reg) + (where & 2)) = (val); - break; - default: - *pci_config_data_reg = (val); + break; + default: + *pci_config_data_reg = (val); } return PCIBIOS_SUCCESSFUL; diff --git a/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c b/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c index 0fa3986e19..f104221046 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c +++ b/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c @@ -1,38 +1,48 @@ /* - * Copyright (C) ADMtek Incorporated. - * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * Copyright (C) 2007 Gabor Juhos - * Copyright (C) 2007 OpenWrt.org + * $Id$ + * + * ADM5120 PCI Host Controller driver + * + * Copyright (C) ADMtek Incorporated. + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * Copyright (C) 2007 Gabor Juhos + * Copyright (C) 2007 OpenWrt.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * */ - -#include #include #include #include #include -#include -#include +#include +#include +#include extern struct pci_ops adm5120_pci_ops; -#define PCI_CMM_IOACC_EN 0x1 -#define PCI_CMM_MEMACC_EN 0x2 -#define PCI_CMM_MASTER_EN 0x4 -#define PCI_CMM_DEF \ - (PCI_CMM_IOACC_EN | PCI_CMM_MEMACC_EN | PCI_CMM_MASTER_EN) - -#define PCI_DEF_CACHE_LINE_SZ 4 - - -struct resource pci_io_resource = { +static struct resource pci_io_resource = { .name = "ADM5120 PCI I/O", .start = ADM5120_PCIIO_BASE, .end = ADM5120_PCICFG_ADDR-1, .flags = IORESOURCE_IO }; -struct resource pci_mem_resource = { +static struct resource pci_mem_resource = { .name = "ADM5120 PCI MEM", .start = ADM5120_PCIMEM_BASE, .end = ADM5120_PCIIO_BASE-1, @@ -45,32 +55,6 @@ static struct pci_controller adm5120_controller = { .mem_resource = &pci_mem_resource, }; -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - if (slot < 2 || slot > 4) - return -1; - return slot + 4; -} - -static void adm5120_pci_fixup(struct pci_dev *dev) -{ - if (dev->devfn == 0) { - pci_write_config_word(dev, PCI_COMMAND, PCI_CMM_DEF); - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - PCI_DEF_CACHE_LINE_SZ); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); - } -} - -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, adm5120_pci_fixup); - - -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} - static int __init adm5120_pci_setup(void) { int pci_bios; @@ -79,7 +63,7 @@ static int __init adm5120_pci_setup(void) printk("adm5120: system has %sPCI BIOS\n", pci_bios ? "" : "no "); if (pci_bios == 0) - return 1; + return -1; /* Avoid ISA compat ranges. */ PCIBIOS_MIN_IO = 0x00000000; diff --git a/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.c b/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.c index 1391bbe8c7..33489e50f0 100644 --- a/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.c +++ b/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.c @@ -21,6 +21,7 @@ #include "adm5120sw.h" #include +#include MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)"); MODULE_DESCRIPTION("ADM5120 ethernet switch driver"); @@ -385,7 +386,7 @@ static int __init adm5120_sw_init(void) int i, err; struct net_device *dev; - err = request_irq(SW_IRQ, adm5120_sw_irq, 0, "ethernet switch", NULL); + err = request_irq(ADM5120_IRQ_SWITCH, adm5120_sw_irq, 0, "ethernet switch", NULL); if (err) goto out; @@ -434,7 +435,7 @@ static int __init adm5120_sw_init(void) memset(netdev_priv(dev), 0, sizeof(struct adm5120_sw)); ((struct adm5120_sw*)netdev_priv(dev))->port = i; dev->base_addr = SW_BASE; - dev->irq = SW_IRQ; + dev->irq = ADM5120_IRQ_SWITCH; dev->open = adm5120_sw_open; dev->hard_start_xmit = adm5120_sw_tx; dev->stop = adm5120_sw_stop; @@ -469,7 +470,7 @@ out_int: unregister_netdev(adm5120_devs[i-1]); free_netdev(adm5120_devs[i-1]); } - free_irq(SW_IRQ, NULL); + free_irq(ADM5120_IRQ_SWITCH, NULL); out: printk(KERN_ERR "ADM5120 Ethernet switch init failed\n"); return err; @@ -484,7 +485,7 @@ static void __exit adm5120_sw_exit(void) free_netdev(adm5120_devs[i-1]); } - free_irq(SW_IRQ, NULL); + free_irq(ADM5120_IRQ_SWITCH, NULL); for (i = 0; i < ADM5120_DMA_RXH; i++) { if (!adm5120_skb_rxh[i]) diff --git a/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.h b/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.h index 19388a9064..ed9836e224 100644 --- a/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.h +++ b/target/linux/adm5120-2.6/files/drivers/net/adm5120sw.h @@ -12,7 +12,6 @@ #define SW_BASE KSEG1ADDR(0x12000000) #define SW_DEVS 6 -#define SW_IRQ 9 #define ETH_TX_TIMEOUT HZ/4 #define ETH_FCS 4; diff --git a/target/linux/adm5120-2.6/files/drivers/serial/adm5120_uart.c b/target/linux/adm5120-2.6/files/drivers/serial/adm5120_uart.c index ea1010cca1..8a2adaa9c4 100644 --- a/target/linux/adm5120-2.6/files/drivers/serial/adm5120_uart.c +++ b/target/linux/adm5120-2.6/files/drivers/serial/adm5120_uart.c @@ -24,12 +24,8 @@ #include #include -#define ADM5120_UART_BASE0 0x12600000 -#define ADM5120_UART_BASE1 0x12800000 -#define ADM5120_UART_SIZE 0x20 - -#define ADM5120_UART_IRQ0 1 -#define ADM5120_UART_IRQ1 2 +#include +#include #define ADM5120_UART_REG(base, reg) \ (*(volatile u32 *)KSEG1ADDR((base)+(reg))) @@ -421,9 +417,9 @@ static struct uart_ops adm5120ser_ops = { static void adm5120console_put(const char c) { - while ((ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_FR) & + while ((ADM5120_UART_REG(ADM5120_UART0_BASE, ADM5120_UART_FR) & ADM5120_UART_TXFF) != 0); - ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_DATA) = c; + ADM5120_UART_REG(ADM5120_UART0_BASE, ADM5120_UART_DATA) = c; } static void adm5120console_write(struct console *con, const char *s, @@ -440,14 +436,14 @@ static void adm5120console_write(struct console *con, const char *s, static int __init adm5120console_setup(struct console *con, char *options) { /* Set to 115200 baud, 8N1 and enable FIFO */ - ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_L) = + ADM5120_UART_REG(ADM5120_UART0_BASE, ADM5120_UART_LCR_L) = ADM5120_UART_BAUD115200 & 0xff; - ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_M) = + ADM5120_UART_REG(ADM5120_UART0_BASE, ADM5120_UART_LCR_M) = ADM5120_UART_BAUD115200 >> 8; - ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_H) = + ADM5120_UART_REG(ADM5120_UART0_BASE, ADM5120_UART_LCR_H) = ADM5120_UART_W8 | ADM5120_UART_FIFO_EN; /* Enable port */ - ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_CR) = + ADM5120_UART_REG(ADM5120_UART0_BASE, ADM5120_UART_CR) = ADM5120_UART_EN; return 0; @@ -477,8 +473,8 @@ console_initcall(adm5120console_init); static struct uart_port adm5120ser_ports[] = { { - .iobase = ADM5120_UART_BASE0, - .irq = ADM5120_UART_IRQ0, + .iobase = ADM5120_UART0_BASE, + .irq = ADM5120_IRQ_UART0, .uartclk = ADM5120_UARTCLK_FREQ, .fifosize = 16, .ops = &adm5120ser_ops, @@ -487,8 +483,8 @@ static struct uart_port adm5120ser_ports[] = { }, #if (CONFIG_ADM5120_NR_UARTS > 1) { - .iobase = ADM5120_UART_BASE1, - .irq = ADM5120_UART_IRQ1, + .iobase = ADM5120_UART1_BASE, + .irq = ADM5120_IRQ_UART1, .uartclk = ADM5120_UARTCLK_FREQ, .fifosize = 16, .ops = &adm5120ser_ops, diff --git a/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_intc.h b/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_intc.h new file mode 100644 index 0000000000..1d16fdcda9 --- /dev/null +++ b/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_intc.h @@ -0,0 +1,73 @@ +/* + * ADM5120 interrupt controller definitions + * + * This header file defines the hardware registers of the ADM5120 SoC + * built-in interrupt controller. + * + * Copyright (C) 2007 OpenWrt.org + * Copyright (C) 2007 Gabor Juhos + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef _ADM5120_INTC_H_ +#define _ADM5120_INTC_H_ + +/* + * INTC register offsets + */ +#define INTC_REG_IRQ_STATUS 0x00 /* Interrupt status after masking */ +#define INTC_REG_IRQ_RAW_STATUS 0x04 /* Interrupt status before masking */ +#define INTC_REG_IRQ_ENABLE 0x08 /* Used to enable the interrupt sources */ +#define INTC_REG_IRQ_ENABLE_CLEAR 0x0C /* Used to disable the interrupt sources */ +#define INTC_REG_IRQ_DISABLE INTC_REG_IRQ_ENABLE_CLEAR +#define INTC_REG_INT_MODE 0x14 /* The interrupt mode of the sources */ +#define INTC_REG_FIQ_STATUS 0x18 /* FIQ status */ +#define INTC_REG_IRQ_TEST_SOURCE 0x1C +#define INTC_REG_IRQ_SOURCE_SELECT 0x20 +#define INTC_REG_INT_LEVEL 0x24 + +/* + * INTC IRQ numbers + */ +#define INTC_IRQ_TIMER 0 /* built in timer */ +#define INTC_IRQ_UART0 1 /* built-in UART0 */ +#define INTC_IRQ_UART1 2 /* built-in UART1 */ +#define INTC_IRQ_USBC 3 /* USB Host Controller */ +#define INTC_IRQ_GPIO2 4 /* GPIO line 2 */ +#define INTC_IRQ_GPIO4 5 /* GPIO line 4 */ +#define INTC_IRQ_PCI0 6 /* PCI slot 2 */ +#define INTC_IRQ_PCI1 7 /* PCI slot 3 */ +#define INTC_IRQ_PCI2 8 /* PCI slot 4 */ +#define INTC_IRQ_SWITCH 9 /* built-in ethernet switch */ +#define INTC_IRQ_LAST INTC_IRQ_SWITCH +#define INTC_IRQ_COUNT 10 + +/* + * INTC register bits + */ +#define INTC_INT_TIMER ( 1 << INTC_IRQ_TIMER ) +#define INTC_INT_UART0 ( 1 << INTC_IRQ_UART0 ) +#define INTC_INT_UART1 ( 1 << INTC_IRQ_UART1 ) +#define INTC_INT_USBC ( 1 << INTC_IRQ_USBC ) +#define INTC_INT_INTX0 ( 1 << INTC_IRQ_INTX0 ) +#define INTC_INT_INTX1 ( 1 << INTC_IRQ_INTX1 ) +#define INTC_INT_PCI0 ( 1 << INTC_IRQ_PCI0 ) +#define INTC_INT_PCI1 ( 1 << INTC_IRQ_PCI1 ) +#define INTC_INT_PCI2 ( 1 << INTC_IRQ_PCI2 ) +#define INTC_INT_SWITCH ( 1 << INTC_IRQ_SWITCH ) +#define INTC_INT_ALL (( 1 << INTC_IRQ_COUNT)-1) + +#endif /* _ADM5120_INTC_H_ */ diff --git a/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_irq.h b/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_irq.h new file mode 100644 index 0000000000..655df32bf7 --- /dev/null +++ b/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/adm5120_irq.h @@ -0,0 +1,55 @@ +/* + * $Id$ + * + * ADM5120 specific IRQ numbers + * + * Copyright (C) 2007 OpenWrt.org + * Copyright (C) 2007 Gabor Juhos + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ +#ifndef _ADM5120_IRQ_H_ +#define _ADM5120_IRQ_H_ + +#include + +#define MIPS_IRQ_HW0 2 +#define MIPS_IRQ_COUNTER 7 +#define MIPS_IRQ_COUNT 8 + +#define ADM5120_CPU_IRQ_BASE 0 +#define ADM5120_INTC_IRQ_BASE (ADM5120_CPU_IRQ_BASE+MIPS_IRQ_COUNT) +#define ADM5120_SWITCH_IRQ_BASE (ADM5120_INTC_IRQ_BASE+INTC_IRQ_COUNT) + +#define ADM5120_CPU_IRQ(x) (ADM5120_CPU_IRQ_BASE + (x)) +#define ADM5120_INTC_IRQ(x) (ADM5120_INTC_IRQ_BASE + (x)) + +#define ADM5120_IRQ_INTC ADM5120_CPU_IRQ(MIPS_IRQ_HW0) +#define ADM5120_IRQ_COUNTER ADM5120_CPU_IRQ(MIPS_IRQ_COUNTER) + +#define ADM5120_IRQ_TIMER ADM5120_INTC_IRQ(INTC_IRQ_TIMER) +#define ADM5120_IRQ_UART0 ADM5120_INTC_IRQ(INTC_IRQ_UART0) +#define ADM5120_IRQ_UART1 ADM5120_INTC_IRQ(INTC_IRQ_UART1) +#define ADM5120_IRQ_USBC ADM5120_INTC_IRQ(INTC_IRQ_USBC) +#define ADM5120_IRQ_GPIO2 ADM5120_INTC_IRQ(INTC_IRQ_GPIO2) +#define ADM5120_IRQ_GPIO4 ADM5120_INTC_IRQ(INTC_IRQ_GPIO4) +#define ADM5120_IRQ_PCI0 ADM5120_INTC_IRQ(INTC_IRQ_PCI0) +#define ADM5120_IRQ_PCI1 ADM5120_INTC_IRQ(INTC_IRQ_PCI1) +#define ADM5120_IRQ_PCI2 ADM5120_INTC_IRQ(INTC_IRQ_PCI2) +#define ADM5120_IRQ_SWITCH ADM5120_INTC_IRQ(INTC_IRQ_SWITCH) + +#endif diff --git a/target/linux/adm5120-2.6/patches/001-adm5120.patch b/target/linux/adm5120-2.6/patches/001-adm5120.patch index cc8739e217..70129373f8 100644 --- a/target/linux/adm5120-2.6/patches/001-adm5120.patch +++ b/target/linux/adm5120-2.6/patches/001-adm5120.patch @@ -1,7 +1,7 @@ diff -urN linux-2.6.19.2/arch/mips/Kconfig linux-2.6.19.2.new/arch/mips/Kconfig --- linux-2.6.19.2/arch/mips/Kconfig 2007-01-10 20:10:37.000000000 +0100 +++ linux-2.6.19.2.new/arch/mips/Kconfig 2007-01-23 14:49:38.000000000 +0100 -@@ -12,6 +12,20 @@ +@@ -12,6 +12,21 @@ prompt "System type" default SGI_IP22 @@ -10,6 +10,7 @@ diff -urN linux-2.6.19.2/arch/mips/Kconfig linux-2.6.19.2.new/arch/mips/Kconfig + select SYS_HAS_CPU_MIPS32_R1 + select DMA_NONCOHERENT + select HW_HAS_PCI ++ select IRQ_CPU + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_32BIT_KERNEL @@ -40,14 +41,6 @@ diff -urN linux-2.6.19.2/arch/mips/Makefile linux-2.6.19.2.new/arch/mips/Makefil # Common Alchemy Au1x00 stuff # core-$(CONFIG_SOC_AU1X00) += arch/mips/au1000/common/ -diff -urN linux-2.6.19.2/arch/mips/pci/Makefile linux-2.6.19.2.new/arch/mips/pci/Makefile ---- linux-2.6.19.2/arch/mips/pci/Makefile 2007-01-10 20:10:37.000000000 +0100 -+++ linux-2.6.19.2.new/arch/mips/pci/Makefile 2007-01-23 14:49:40.000000000 +0100 -@@ -53,3 +53,4 @@ - obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o - obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o - obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o -+obj-$(CONFIG_PCI_ADM5120) += ops-adm5120.o pci-adm5120.o diff -urN linux-2.6.19.2/include/asm-mips/bootinfo.h linux-2.6.19.2.new/include/asm-mips/bootinfo.h --- linux-2.6.19.2/include/asm-mips/bootinfo.h 2007-01-10 20:10:37.000000000 +0100 +++ linux-2.6.19.2.new/include/asm-mips/bootinfo.h 2007-01-23 14:49:40.000000000 +0100 diff --git a/target/linux/adm5120-2.6/patches/007-adm5120_pci.patch b/target/linux/adm5120-2.6/patches/007-adm5120_pci.patch new file mode 100644 index 0000000000..25ec59a390 --- /dev/null +++ b/target/linux/adm5120-2.6/patches/007-adm5120_pci.patch @@ -0,0 +1,20 @@ +diff -urN linux-2.6.21.1/arch/mips/pci/Makefile linux-2.6.21.1-adm5120/arch/mips/pci/Makefile +--- linux-2.6.21.1/arch/mips/pci/Makefile 2007-01-10 20:10:37.000000000 +0100 ++++ linux-2.6.21.1-adm5120/arch/mips/pci/Makefile 2007-01-23 14:49:40.000000000 +0100 +@@ -53,3 +53,4 @@ + obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o + obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o + obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o ++obj-$(CONFIG_PCI_ADM5120) += fixup-adm5120.o ops-adm5120.o pci-adm5120.o +--- linux-2.6.21.1.old/include/linux/pci_ids.h 2007-04-27 23:49:26.000000000 +0200 ++++ linux-2.6.21.1/include/linux/pci_ids.h 2007-05-31 09:36:56.000000000 +0200 +@@ -1701,6 +1701,9 @@ + #define PCI_VENDOR_ID_ESDGMBH 0x12fe + #define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111 + ++#define PCI_VENDOR_ID_ADMTEK 0x1317 ++#define PCI_DEVICE_ID_ADMTEK_ADM5120 0x5120 ++ + #define PCI_VENDOR_ID_SIIG 0x131f + #define PCI_SUBVENDOR_ID_SIIG 0x131f + #define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000