diff options
author | Felix Fietkau <nbd@openwrt.org> | 2007-07-04 03:55:23 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2007-07-04 03:55:23 +0000 |
commit | e062f4185e15b1f04098580a85f4d39cb0a43f8e (patch) | |
tree | 87384d7d1063a07eb6c6a3699bdbcf953a4df366 | |
parent | ce4fbcf3f40ca7f05faca1cb72318cd25dc3a0ae (diff) | |
download | upstream-e062f4185e15b1f04098580a85f4d39cb0a43f8e.tar.gz upstream-e062f4185e15b1f04098580a85f4d39cb0a43f8e.tar.bz2 upstream-e062f4185e15b1f04098580a85f4d39cb0a43f8e.zip |
refactor atheros system code - also add support for the reset button (sends netlink messages in the same format as broadcom-diag)
SVN-Revision: 7869
13 files changed, 707 insertions, 461 deletions
diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile b/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile index aff65d723a..2c2b991bc4 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/Makefile @@ -3,20 +3,11 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. # Copyright (C) 2006 FON Technology, SL. # Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> # Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> # -# Makefile for Atheros ar531x boards -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# - -obj-y += board.o prom.o irq.o -obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o -obj-$(CONFIG_ATHEROS_AR5315) += ar5315.o - +obj-y += board.o prom.o reset.o +obj-$(CONFIG_ATHEROS_AR5312) += ar5312/ +obj-$(CONFIG_ATHEROS_AR5315) += ar5315/ diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/Makefile b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/Makefile new file mode 100644 index 0000000000..6c50d9931d --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/Makefile @@ -0,0 +1,11 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2007 FON Technology, SL. +# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org> +# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> +# + +obj-y := board.o irq.o diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.h b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/ar5312.h index 2b6b875b4f..2b6b875b4f 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.h +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/ar5312.h diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/board.c index 57d56eb0e5..21073dbbbb 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312.c +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/board.c @@ -27,7 +27,7 @@ #include <asm/time.h> #include <asm/irq.h> #include <asm/io.h> -#include "ar531x.h" +#include "../ar531x.h" #define NO_PHY 0x1f @@ -312,47 +312,6 @@ int __init ar5312_init_devices(void) } -/* - * Called when an interrupt is received, this function - * determines exactly which interrupt it was, and it - * invokes the appropriate handler. - * - * Implicitly, we also define interrupt priority by - * choosing which to dispatch first. - */ -asmlinkage void ar5312_irq_dispatch(void) -{ - int pending = read_c0_status() & read_c0_cause(); - - if (pending & CAUSEF_IP2) - do_IRQ(AR5312_IRQ_WLAN0_INTRS); - else if (pending & CAUSEF_IP3) - do_IRQ(AR5312_IRQ_ENET0_INTRS); - else if (pending & CAUSEF_IP4) - do_IRQ(AR5312_IRQ_ENET1_INTRS); - else if (pending & CAUSEF_IP5) - do_IRQ(AR5312_IRQ_WLAN1_INTRS); - else if (pending & CAUSEF_IP6) { - unsigned int ar531x_misc_intrs = sysRegRead(AR531X_ISR) & sysRegRead(AR531X_IMR); - - if (ar531x_misc_intrs & AR531X_ISR_TIMER) { - do_IRQ(AR531X_MISC_IRQ_TIMER); - (void)sysRegRead(AR531X_TIMER); - } else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC) - do_IRQ(AR531X_MISC_IRQ_AHB_PROC); - else if ((ar531x_misc_intrs & AR531X_ISR_UART0)) - do_IRQ(AR531X_MISC_IRQ_UART0); - else if (ar531x_misc_intrs & AR531X_ISR_WD) - do_IRQ(AR531X_MISC_IRQ_WATCHDOG); - else - do_IRQ(AR531X_MISC_IRQ_NONE); - } else if (pending & CAUSEF_IP7) { - do_IRQ(AR531X_IRQ_CPU_CLOCK); - } - else - do_IRQ(AR531X_IRQ_NONE); -} - static void ar5312_halt(void) { while (1); @@ -451,110 +410,6 @@ static void __init ar5312_time_init(void) } -/* Enable the specified AR531X_MISC_IRQ interrupt */ -static void -ar5312_misc_intr_enable(unsigned int irq) -{ - unsigned int imr; - - imr = sysRegRead(AR531X_IMR); - imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1)); - sysRegWrite(AR531X_IMR, imr); - sysRegRead(AR531X_IMR); /* flush write buffer */ -} - -/* Disable the specified AR531X_MISC_IRQ interrupt */ -static void -ar5312_misc_intr_disable(unsigned int irq) -{ - unsigned int imr; - - imr = sysRegRead(AR531X_IMR); - imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1)); - sysRegWrite(AR531X_IMR, imr); - sysRegRead(AR531X_IMR); /* flush write buffer */ -} - -/* Turn on the specified AR531X_MISC_IRQ interrupt */ -static unsigned int -ar5312_misc_intr_startup(unsigned int irq) -{ - ar5312_misc_intr_enable(irq); - return 0; -} - -/* Turn off the specified AR531X_MISC_IRQ interrupt */ -static void -ar5312_misc_intr_shutdown(unsigned int irq) -{ - ar5312_misc_intr_disable(irq); -} - -static void -ar5312_misc_intr_ack(unsigned int irq) -{ - ar5312_misc_intr_disable(irq); -} - -static void -ar5312_misc_intr_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - ar5312_misc_intr_enable(irq); -} - -static struct irq_chip ar5312_misc_intr_controller = { - .typename = "AR5312 misc", - .startup = ar5312_misc_intr_startup, - .shutdown = ar5312_misc_intr_shutdown, - .enable = ar5312_misc_intr_enable, - .disable = ar5312_misc_intr_disable, - .ack = ar5312_misc_intr_ack, - .end = ar5312_misc_intr_end, -}; - -static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id) -{ - u32 proc1 = sysRegRead(AR531X_PROC1); - u32 procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */ - u32 dma1 = sysRegRead(AR531X_DMA1); - u32 dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */ - - printk("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", - procAddr, proc1, dmaAddr, dma1); - - machine_restart("AHB error"); /* Catastrophic failure */ - return IRQ_HANDLED; -} - - -static struct irqaction ar5312_ahb_proc_interrupt = { - .handler = ar5312_ahb_proc_handler, - .flags = SA_INTERRUPT, - .name = "ar5312_ahb_proc_interrupt", -}; - - -static struct irqaction cascade = { - .handler = no_action, - .flags = SA_INTERRUPT, - .name = "cascade", -}; - -void __init ar5312_misc_intr_init(int irq_base) -{ - int i; - - for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].chip = &ar5312_misc_intr_controller; - } - setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt); - setup_irq(AR5312_IRQ_MISC_INTRS, &cascade); -} - void __init ar5312_prom_init(void) { u32 memsize, memcfg, bank0AC, bank1AC; diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/irq.c new file mode 100644 index 0000000000..8345a31eb1 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5312/irq.c @@ -0,0 +1,174 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + */ + +/* + * Platform devices for Atheros SoCs + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/reboot.h> +#include <asm/bootinfo.h> +#include <asm/time.h> +#include <asm/irq.h> +#include <asm/io.h> +#include "../ar531x.h" + +/* + * Called when an interrupt is received, this function + * determines exactly which interrupt it was, and it + * invokes the appropriate handler. + * + * Implicitly, we also define interrupt priority by + * choosing which to dispatch first. + */ +asmlinkage void ar5312_irq_dispatch(void) +{ + int pending = read_c0_status() & read_c0_cause(); + + if (pending & CAUSEF_IP2) + do_IRQ(AR5312_IRQ_WLAN0_INTRS); + else if (pending & CAUSEF_IP3) + do_IRQ(AR5312_IRQ_ENET0_INTRS); + else if (pending & CAUSEF_IP4) + do_IRQ(AR5312_IRQ_ENET1_INTRS); + else if (pending & CAUSEF_IP5) + do_IRQ(AR5312_IRQ_WLAN1_INTRS); + else if (pending & CAUSEF_IP6) { + unsigned int ar531x_misc_intrs = sysRegRead(AR531X_ISR) & sysRegRead(AR531X_IMR); + + if (ar531x_misc_intrs & AR531X_ISR_TIMER) { + do_IRQ(AR531X_MISC_IRQ_TIMER); + (void)sysRegRead(AR531X_TIMER); + } else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC) + do_IRQ(AR531X_MISC_IRQ_AHB_PROC); + else if ((ar531x_misc_intrs & AR531X_ISR_UART0)) + do_IRQ(AR531X_MISC_IRQ_UART0); + else if (ar531x_misc_intrs & AR531X_ISR_WD) + do_IRQ(AR531X_MISC_IRQ_WATCHDOG); + else + do_IRQ(AR531X_MISC_IRQ_NONE); + } else if (pending & CAUSEF_IP7) { + do_IRQ(AR531X_IRQ_CPU_CLOCK); + } + else + do_IRQ(AR531X_IRQ_NONE); +} + + +/* Enable the specified AR531X_MISC_IRQ interrupt */ +static void +ar5312_misc_intr_enable(unsigned int irq) +{ + unsigned int imr; + + imr = sysRegRead(AR531X_IMR); + imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1)); + sysRegWrite(AR531X_IMR, imr); + sysRegRead(AR531X_IMR); /* flush write buffer */ +} + +/* Disable the specified AR531X_MISC_IRQ interrupt */ +static void +ar5312_misc_intr_disable(unsigned int irq) +{ + unsigned int imr; + + imr = sysRegRead(AR531X_IMR); + imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1)); + sysRegWrite(AR531X_IMR, imr); + sysRegRead(AR531X_IMR); /* flush write buffer */ +} + +/* Turn on the specified AR531X_MISC_IRQ interrupt */ +static unsigned int +ar5312_misc_intr_startup(unsigned int irq) +{ + ar5312_misc_intr_enable(irq); + return 0; +} + +/* Turn off the specified AR531X_MISC_IRQ interrupt */ +static void +ar5312_misc_intr_shutdown(unsigned int irq) +{ + ar5312_misc_intr_disable(irq); +} + +static void +ar5312_misc_intr_ack(unsigned int irq) +{ + ar5312_misc_intr_disable(irq); +} + +static void +ar5312_misc_intr_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ar5312_misc_intr_enable(irq); +} + +static struct irq_chip ar5312_misc_intr_controller = { + .typename = "AR5312 misc", + .startup = ar5312_misc_intr_startup, + .shutdown = ar5312_misc_intr_shutdown, + .enable = ar5312_misc_intr_enable, + .disable = ar5312_misc_intr_disable, + .ack = ar5312_misc_intr_ack, + .end = ar5312_misc_intr_end, +}; + +static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id) +{ + u32 proc1 = sysRegRead(AR531X_PROC1); + u32 procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */ + u32 dma1 = sysRegRead(AR531X_DMA1); + u32 dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */ + + printk("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", + procAddr, proc1, dmaAddr, dma1); + + machine_restart("AHB error"); /* Catastrophic failure */ + return IRQ_HANDLED; +} + + +static struct irqaction ar5312_ahb_proc_interrupt = { + .handler = ar5312_ahb_proc_handler, + .flags = SA_INTERRUPT, + .name = "ar5312_ahb_proc_interrupt", +}; + + +static struct irqaction cascade = { + .handler = no_action, + .flags = SA_INTERRUPT, + .name = "cascade", +}; + +void __init ar5312_misc_intr_init(int irq_base) +{ + int i; + + for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].chip = &ar5312_misc_intr_controller; + } + setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt); + setup_irq(AR5312_IRQ_MISC_INTRS, &cascade); +} + + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/Makefile b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/Makefile new file mode 100644 index 0000000000..6c50d9931d --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/Makefile @@ -0,0 +1,11 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2007 FON Technology, SL. +# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org> +# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> +# + +obj-y := board.o irq.o diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.h b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/ar5315.h index c3eeed18b8..567141cb76 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.h +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/ar5315.h @@ -342,12 +342,12 @@ #define AR5315_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ #define AR5315_GPIO_CR_O(x) (1 << (x)) /* output */ -#define AR5315_GPIO_CR_I(x) (0 << (x)) /* input */ +#define AR5315_GPIO_CR_I(x) (0) /* input */ -#define AR5315_GPIO_INT_S(x,Y) ((x) << (8 * (Y))) /* interrupt enable */ -#define AR5315_GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */ -#define AR5315_GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */ -#define AR5315_GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */ +#define AR5315_GPIO_INT_S(x) (x) /* interrupt enable */ +#define AR5315_GPIO_INT_M (0x3F) /* mask for int */ +#define AR5315_GPIO_INT_LVL(x) ((x) << 6) /* interrupt level */ +#define AR5315_GPIO_INT_LVL_M ((0x3) << 6) /* mask for int level */ #define AR5315_RESET_GPIO 5 #define AR5315_NUM_GPIO 22 diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/board.c index 0255ae3246..8247d8548c 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315.c +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/board.c @@ -26,9 +26,10 @@ #include <asm/time.h> #include <asm/irq.h> #include <asm/io.h> -#include "ar531x.h" +#include "../ar531x.h" static int is_5315 = 0; + static struct resource ar5315_eth_res[] = { { .name = "eth0_membase", @@ -182,7 +183,6 @@ int __init ar5315_init_devices(void) { struct ar531x_config *config; struct ar531x_boarddata *bcfg; - u32 devid; int dev = 0; if (!is_5315) @@ -193,9 +193,10 @@ int __init ar5315_init_devices(void) bcfg = (struct ar531x_boarddata *) board_config; #if 0 + { /* Detect the hardware based on the device ID */ - devid = sysRegRead(AR5315_SREV) & AR5315_REV_MAJ >> AR5315_REV_MAJ_S; - switch(devid) { + u32 devid = sysRegRead(AR5315_SREV) & AR5315_REV_MAJ >> AR5315_REV_MAJ_S; + switch(devid) { case 0x9: mips_machtype = MACH_ATHEROS_AR2317; break; @@ -204,6 +205,7 @@ int __init ar5315_init_devices(void) default: mips_machtype = MACH_ATHEROS_AR2315; break; + } } #endif @@ -220,48 +222,11 @@ int __init ar5315_init_devices(void) ar5315_devs[dev++] = &ar5315_eth; ar5315_devs[dev++] = &ar5315_wmac; ar5315_devs[dev++] = &ar5315_spiflash; + return platform_add_devices(ar5315_devs, dev); } - -/* - * Called when an interrupt is received, this function - * determines exactly which interrupt it was, and it - * invokes the appropriate handler. - * - * Implicitly, we also define interrupt priority by - * choosing which to dispatch first. - */ -asmlinkage void ar5315_irq_dispatch(void) -{ - int pending = read_c0_status() & read_c0_cause(); - - if (pending & CAUSEF_IP3) - do_IRQ(AR5315_IRQ_WLAN0_INTRS); - else if (pending & CAUSEF_IP4) - do_IRQ(AR5315_IRQ_ENET0_INTRS); - else if (pending & CAUSEF_IP2) { - unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR); - - if (ar531x_misc_intrs & AR5315_ISR_TIMER) - do_IRQ(AR531X_MISC_IRQ_TIMER); - else if (ar531x_misc_intrs & AR5315_ISR_AHB) - do_IRQ(AR531X_MISC_IRQ_AHB_PROC); - else if (ar531x_misc_intrs & AR5315_ISR_GPIO) { - sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO); - } else if (ar531x_misc_intrs & AR5315_ISR_UART0) - do_IRQ(AR531X_MISC_IRQ_UART0); - else if (ar531x_misc_intrs & AR5315_ISR_WD) - do_IRQ(AR531X_MISC_IRQ_WATCHDOG); - else - do_IRQ(AR531X_MISC_IRQ_NONE); - } else if (pending & CAUSEF_IP7) - do_IRQ(AR531X_IRQ_CPU_CLOCK); - else - do_IRQ(AR531X_IRQ_NONE); -} - static void ar5315_halt(void) { while (1); @@ -362,169 +327,6 @@ static void __init ar5315_time_init(void) mips_hpt_frequency = ar5315_cpu_frequency() / 2; } - - -/* Enable the specified AR531X_MISC_IRQ interrupt */ -static void -ar5315_misc_intr_enable(unsigned int irq) -{ - unsigned int imr; - - imr = sysRegRead(AR5315_IMR); - switch(irq) - { - case AR531X_MISC_IRQ_TIMER: - imr |= AR5315_ISR_TIMER; - break; - - case AR531X_MISC_IRQ_AHB_PROC: - imr |= AR5315_ISR_AHB; - break; - - case AR531X_MISC_IRQ_AHB_DMA: - imr |= 0/* ?? */; - break; - - case AR531X_MISC_IRQ_GPIO: - imr |= AR5315_ISR_GPIO; - break; - - case AR531X_MISC_IRQ_UART0: - imr |= AR5315_ISR_UART0; - break; - - - case AR531X_MISC_IRQ_WATCHDOG: - imr |= AR5315_ISR_WD; - break; - - case AR531X_MISC_IRQ_LOCAL: - imr |= 0/* ?? */; - break; - - } - sysRegWrite(AR5315_IMR, imr); - imr=sysRegRead(AR5315_IMR); /* flush write buffer */ -} - -/* Disable the specified AR531X_MISC_IRQ interrupt */ -static void -ar5315_misc_intr_disable(unsigned int irq) -{ - unsigned int imr; - - imr = sysRegRead(AR5315_IMR); - switch(irq) - { - case AR531X_MISC_IRQ_TIMER: - imr &= (~AR5315_ISR_TIMER); - break; - - case AR531X_MISC_IRQ_AHB_PROC: - imr &= (~AR5315_ISR_AHB); - break; - - case AR531X_MISC_IRQ_AHB_DMA: - imr &= 0/* ?? */; - break; - - case AR531X_MISC_IRQ_GPIO: - imr &= ~AR5315_ISR_GPIO; - break; - - case AR531X_MISC_IRQ_UART0: - imr &= (~AR5315_ISR_UART0); - break; - - case AR531X_MISC_IRQ_WATCHDOG: - imr &= (~AR5315_ISR_WD); - break; - - case AR531X_MISC_IRQ_LOCAL: - imr &= ~0/* ?? */; - break; - - } - sysRegWrite(AR5315_IMR, imr); - sysRegRead(AR5315_IMR); /* flush write buffer */ -} - -/* Turn on the specified AR531X_MISC_IRQ interrupt */ -static unsigned int -ar5315_misc_intr_startup(unsigned int irq) -{ - ar5315_misc_intr_enable(irq); - return 0; -} - -/* Turn off the specified AR531X_MISC_IRQ interrupt */ -static void -ar5315_misc_intr_shutdown(unsigned int irq) -{ - ar5315_misc_intr_disable(irq); -} - -static void -ar5315_misc_intr_ack(unsigned int irq) -{ - ar5315_misc_intr_disable(irq); -} - -static void -ar5315_misc_intr_end(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - ar5315_misc_intr_enable(irq); -} - -static struct irq_chip ar5315_misc_intr_controller = { - .typename = "AR5315 misc", - .startup = ar5315_misc_intr_startup, - .shutdown = ar5315_misc_intr_shutdown, - .enable = ar5315_misc_intr_enable, - .disable = ar5315_misc_intr_disable, - .ack = ar5315_misc_intr_ack, - .end = ar5315_misc_intr_end, -}; - -static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id) -{ - sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET); - sysRegRead(AR5315_AHB_ERR1); - - printk("AHB fatal error\n"); - machine_restart("AHB error"); /* Catastrophic failure */ - - return IRQ_HANDLED; -} - -static struct irqaction ar5315_ahb_proc_interrupt = { - .handler = ar5315_ahb_proc_handler, - .flags = SA_INTERRUPT, - .name = "ar5315_ahb_proc_interrupt", -}; - - -static struct irqaction cascade = { - .handler = no_action, - .flags = SA_INTERRUPT, - .name = "cascade", -}; - -void ar5315_misc_intr_init(int irq_base) -{ - int i; - - for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].chip = &ar5315_misc_intr_controller; - } - setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt); - setup_irq(AR5315_IRQ_MISC_INTRS, &cascade); -} - void __init ar5315_prom_init(void) { u32 memsize, memcfg; diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/irq.c new file mode 100644 index 0000000000..3713ebd660 --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar5315/irq.c @@ -0,0 +1,330 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + */ + +/* + * Platform devices for Atheros SoCs + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/reboot.h> +#include <linux/interrupt.h> +#include <asm/bootinfo.h> +#include <asm/irq_cpu.h> +#include <asm/io.h> +#include "../ar531x.h" + +static u32 gpiointmask = 0, gpiointval = 0; + +static inline void ar5315_gpio_irq(void) +{ + u32 pend; + sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO); + + /* only do one gpio interrupt at a time */ + pend = (sysRegRead(AR5315_GPIO_DI) ^ gpiointval) & gpiointmask; + if (!pend) + return; + + do_IRQ(AR531X_GPIO_IRQ_BASE + 31 - clz(pend)); +} + + +/* + * Called when an interrupt is received, this function + * determines exactly which interrupt it was, and it + * invokes the appropriate handler. + * + * Implicitly, we also define interrupt priority by + * choosing which to dispatch first. + */ +asmlinkage void ar5315_irq_dispatch(void) +{ + int pending = read_c0_status() & read_c0_cause(); + + if (pending & CAUSEF_IP3) + do_IRQ(AR5315_IRQ_WLAN0_INTRS); + else if (pending & CAUSEF_IP4) + do_IRQ(AR5315_IRQ_ENET0_INTRS); + else if (pending & CAUSEF_IP2) { + unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR); + + if (ar531x_misc_intrs & AR5315_ISR_SPI) + do_IRQ(AR531X_MISC_IRQ_SPI); + else if (ar531x_misc_intrs & AR5315_ISR_TIMER) + do_IRQ(AR531X_MISC_IRQ_TIMER); + else if (ar531x_misc_intrs & AR5315_ISR_AHB) + do_IRQ(AR531X_MISC_IRQ_AHB_PROC); + else if (ar531x_misc_intrs & AR5315_ISR_GPIO) + ar5315_gpio_irq(); + else if (ar531x_misc_intrs & AR5315_ISR_UART0) + do_IRQ(AR531X_MISC_IRQ_UART0); + else if (ar531x_misc_intrs & AR5315_ISR_WD) + do_IRQ(AR531X_MISC_IRQ_WATCHDOG); + else + do_IRQ(AR531X_MISC_IRQ_NONE); + } else if (pending & CAUSEF_IP7) + do_IRQ(AR531X_IRQ_CPU_CLOCK); + else + do_IRQ(AR531X_IRQ_NONE); +} + +static void ar5315_gpio_intr_enable(unsigned int irq) +{ + u32 gpio, mask; + gpio = irq - AR531X_GPIO_IRQ_BASE; + mask = 1 << gpio; + gpiointmask |= mask; + + /* reconfigure GPIO line as input */ + sysRegMask(AR5315_GPIO_CR, AR5315_GPIO_CR_M(gpio), AR5315_GPIO_CR_I(gpio)); + + /* Enable interrupt with edge detection */ + sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(3)); +} + +static void ar5315_gpio_intr_disable(unsigned int irq) +{ + u32 gpio, mask; + gpio = irq - AR531X_GPIO_IRQ_BASE; + mask = 1 << gpio; + + gpiointmask &= ~mask; + + /* Disable interrupt with edge detection */ + sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(0)); +} + +/* Turn on the specified AR531X_MISC_IRQ interrupt */ +static unsigned int ar5315_gpio_intr_startup(unsigned int irq) +{ + ar5315_gpio_intr_enable(irq); + return 0; +} + +/* Turn off the specified AR531X_MISC_IRQ interrupt */ +static void +ar5315_gpio_intr_shutdown(unsigned int irq) +{ + ar5315_gpio_intr_disable(irq); +} + +static void +ar5315_gpio_intr_ack(unsigned int irq) +{ + ar5315_gpio_intr_disable(irq); +} + +static void +ar5315_gpio_intr_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ar5315_gpio_intr_enable(irq); +} + +static struct irq_chip ar5315_gpio_intr_controller = { + .typename = "AR5315 GPIO", + .startup = ar5315_gpio_intr_startup, + .shutdown = ar5315_gpio_intr_shutdown, + .enable = ar5315_gpio_intr_enable, + .disable = ar5315_gpio_intr_disable, + .ack = ar5315_gpio_intr_ack, + .end = ar5315_gpio_intr_end, +}; + + +/* Enable the specified AR531X_MISC_IRQ interrupt */ +static void +ar5315_misc_intr_enable(unsigned int irq) +{ + unsigned int imr; + + imr = sysRegRead(AR5315_IMR); + switch(irq) + { + case AR531X_MISC_IRQ_SPI: + imr |= AR5315_ISR_SPI; + break; + + case AR531X_MISC_IRQ_TIMER: + imr |= AR5315_ISR_TIMER; + break; + + case AR531X_MISC_IRQ_AHB_PROC: + imr |= AR5315_ISR_AHB; + break; + + case AR531X_MISC_IRQ_AHB_DMA: + imr |= 0/* ?? */; + break; + + case AR531X_MISC_IRQ_GPIO: + imr |= AR5315_ISR_GPIO; + break; + + case AR531X_MISC_IRQ_UART0: + imr |= AR5315_ISR_UART0; + break; + + + case AR531X_MISC_IRQ_WATCHDOG: + imr |= AR5315_ISR_WD; + break; + + case AR531X_MISC_IRQ_LOCAL: + imr |= 0/* ?? */; + break; + + } + sysRegWrite(AR5315_IMR, imr); + imr=sysRegRead(AR5315_IMR); /* flush write buffer */ +} + +/* Disable the specified AR531X_MISC_IRQ interrupt */ +static void +ar5315_misc_intr_disable(unsigned int irq) +{ + unsigned int imr; + + imr = sysRegRead(AR5315_IMR); + switch(irq) + { + case AR531X_MISC_IRQ_SPI: + imr &= ~AR5315_ISR_SPI; + break; + + case AR531X_MISC_IRQ_TIMER: + imr &= (~AR5315_ISR_TIMER); + break; + + case AR531X_MISC_IRQ_AHB_PROC: + imr &= (~AR5315_ISR_AHB); + break; + + case AR531X_MISC_IRQ_AHB_DMA: + imr &= 0/* ?? */; + break; + + case AR531X_MISC_IRQ_GPIO: + imr &= ~AR5315_ISR_GPIO; + break; + + case AR531X_MISC_IRQ_UART0: + imr &= (~AR5315_ISR_UART0); + break; + + case AR531X_MISC_IRQ_WATCHDOG: + imr &= (~AR5315_ISR_WD); + break; + + case AR531X_MISC_IRQ_LOCAL: + imr &= ~0/* ?? */; + break; + + } + sysRegWrite(AR5315_IMR, imr); + sysRegRead(AR5315_IMR); /* flush write buffer */ +} + +/* Turn on the specified AR531X_MISC_IRQ interrupt */ +static unsigned int +ar5315_misc_intr_startup(unsigned int irq) +{ + ar5315_misc_intr_enable(irq); + return 0; +} + +/* Turn off the specified AR531X_MISC_IRQ interrupt */ +static void +ar5315_misc_intr_shutdown(unsigned int irq) +{ + ar5315_misc_intr_disable(irq); +} + +static void +ar5315_misc_intr_ack(unsigned int irq) +{ + ar5315_misc_intr_disable(irq); +} + +static void +ar5315_misc_intr_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ar5315_misc_intr_enable(irq); +} + +static struct irq_chip ar5315_misc_intr_controller = { + .typename = "AR5315 misc", + .startup = ar5315_misc_intr_startup, + .shutdown = ar5315_misc_intr_shutdown, + .enable = ar5315_misc_intr_enable, + .disable = ar5315_misc_intr_disable, + .ack = ar5315_misc_intr_ack, + .end = ar5315_misc_intr_end, +}; + +static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id) +{ + sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET); + sysRegRead(AR5315_AHB_ERR1); + + printk("AHB fatal error\n"); + machine_restart("AHB error"); /* Catastrophic failure */ + + return IRQ_HANDLED; +} + +static struct irqaction ar5315_ahb_proc_interrupt = { + .handler = ar5315_ahb_proc_handler, + .flags = SA_INTERRUPT, + .name = "ar5315_ahb_proc_interrupt", +}; + + +static struct irqaction cascade = { + .handler = no_action, + .flags = SA_INTERRUPT, + .name = "cascade", +}; + +static void ar5315_gpio_intr_init(int irq_base) +{ + int i; + + for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].chip = &ar5315_gpio_intr_controller; + } + setup_irq(AR531X_MISC_IRQ_GPIO, &cascade); + gpiointval = sysRegRead(AR5315_GPIO_DI); +} + +void ar5315_misc_intr_init(int irq_base) +{ + int i; + + for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].chip = &ar5315_misc_intr_controller; + } + setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt); + setup_irq(AR5315_IRQ_MISC_INTRS, &cascade); + ar5315_gpio_intr_init(AR531X_GPIO_IRQ_BASE); +} + diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h b/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h index 56f63030ce..5256a548ce 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/ar531x.h @@ -3,8 +3,32 @@ #include <asm/cpu-info.h> #include <ar531x_platform.h> -#include "ar5312.h" -#include "ar5315.h" +#include "ar5312/ar5312.h" +#include "ar5315/ar5315.h" + + +/* + * C access to CLZ instruction + * (count leading zeroes). + */ +static inline int clz(unsigned long val) +{ + int ret; + + __asm__ volatile ( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips32\n\t" + "clz\t%0,%1\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (ret) + : "r" (val) + ); + + return ret; +} /* * Atheros CPUs before the AR2315 are using MIPS 4Kc core, later designs are @@ -27,11 +51,8 @@ #define DO_AR5315(...) #endif -#include <irq.h> - -#define AR531X_HIGH_PRIO 0x10 #define AR531X_MISC_IRQ_BASE 0x20 -#define AR531X_GPIO_IRQ_BASE 0x30 +#define AR531X_GPIO_IRQ_BASE 0x30 /* Software's idea of interrupts handled by "CPU Interrupt Controller" */ #define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 @@ -47,7 +68,8 @@ #define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6 #define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7 #define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8 -#define AR531X_MISC_IRQ_COUNT 9 +#define AR531X_MISC_IRQ_SPI AR531X_MISC_IRQ_BASE+9 +#define AR531X_MISC_IRQ_COUNT 10 /* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */ #define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0 @@ -127,5 +149,18 @@ extern void ar5315_prom_init(void); extern void ar5315_misc_intr_init(int irq_base); extern void ar5315_plat_setup(void); extern asmlinkage void ar5315_irq_dispatch(void); +extern void ar5315_pci_irq(int irq); +static inline u32 sysRegMask(u32 phys, u32 mask, u32 value) +{ + u32 reg; + + reg = sysRegRead(phys); + reg &= ~mask; + reg |= value & mask; + sysRegWrite(phys, reg); + reg = sysRegRead(phys); /* flush write to the hardware */ + + return reg; +} #endif diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/board.c b/target/linux/atheros-2.6/files/arch/mips/atheros/board.c index d26eda4d08..1ea66c0c19 100644 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/board.c +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/board.c @@ -23,6 +23,7 @@ #include <linux/serial.h> #include <linux/serial_core.h> #include <asm/bootinfo.h> +#include <asm/irq_cpu.h> #include <asm/io.h> #include "ar531x.h" @@ -189,4 +190,18 @@ void __init plat_timer_setup(struct irqaction *irq) write_c0_compare(count + 1000); } +asmlinkage void plat_irq_dispatch(void) +{ + DO_AR5312(ar5312_irq_dispatch();) + DO_AR5315(ar5315_irq_dispatch();) +} +void __init arch_init_irq(void) +{ + clear_c0_status(ST0_IM); + mips_cpu_irq_init(); + + /* Initialize interrupt controllers */ + DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);) + DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);) +} diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c b/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c deleted file mode 100644 index 5665aa3b93..0000000000 --- a/target/linux/atheros-2.6/files/arch/mips/atheros/irq.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. - * Copyright (C) 2006 FON Technology, SL. - * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> - */ - -/* - * Interrupt support for AR531X WiSOC. - */ - -#include <linux/autoconf.h> -#include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/pm.h> -#include <linux/delay.h> -#include <linux/reboot.h> -#include <linux/irq.h> -#include <asm/bootinfo.h> -#include <asm/mipsregs.h> -#include <asm/irq_cpu.h> -#include "ar531x.h" - - -/* ARGSUSED */ -irqreturn_t -spurious_irq_handler(int cpl, void *dev_id) -{ - /* - printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n", - cpl, cause_intrs, status_intrs); - */ - return IRQ_NONE; -} - -/* ARGSUSED */ -irqreturn_t -spurious_misc_handler(int cpl, void *dev_id) -{ - /* - printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n", - cpl, ar531x_isr, ar531x_imr); - */ - return IRQ_NONE; -} - -static struct irqaction spurious_irq = { - .handler = spurious_irq_handler, - .flags = SA_INTERRUPT, - .name = "spurious_irq", -}; - -static struct irqaction spurious_misc = { - .handler = spurious_misc_handler, - .flags = SA_INTERRUPT, - .name = "spurious_misc", -}; - -asmlinkage void plat_irq_dispatch(void) -{ - DO_AR5312(ar5312_irq_dispatch();) - DO_AR5315(ar5315_irq_dispatch();) -} - -void __init arch_init_irq(void) -{ - clear_c0_status(ST0_IM); - mips_cpu_irq_init(); - - /* Initialize interrupt controllers */ - DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);) - DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);) - - /* Default "spurious interrupt" handlers */ - setup_irq(AR531X_IRQ_NONE, &spurious_irq); - setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc); -} diff --git a/target/linux/atheros-2.6/files/arch/mips/atheros/reset.c b/target/linux/atheros-2.6/files/arch/mips/atheros/reset.c new file mode 100644 index 0000000000..d62c5e1c4e --- /dev/null +++ b/target/linux/atheros-2.6/files/arch/mips/atheros/reset.c @@ -0,0 +1,108 @@ +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/kobject.h> +#include <linux/workqueue.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <net/sock.h> +#include <asm/uaccess.h> +#include "ar531x.h" +#include "ar5315/ar5315.h" + +struct event_t { + struct work_struct wq; + int set; + long int jiffies; +}; + +extern struct sock *uevent_sock; +extern u64 uevent_next_seqnum(void); +static int seen; + +static inline void add_msg(struct sk_buff *skb, char *msg) +{ + char *scratch; + scratch = skb_put(skb, strlen(msg) + 1); + sprintf(scratch, msg); +} + +static void hotplug_button(struct work_struct *wq) +{ + struct sk_buff *skb; + struct event_t *event; + size_t len; + char *scratch, *s; + char buf[128]; + + event = container_of(wq, struct event_t, wq); + if (!uevent_sock) + goto done; + + /* allocate message with the maximum possible size */ + s = event->set ? "pressed" : "released"; + len = strlen(s) + 2; + skb = alloc_skb(len + 2048, GFP_KERNEL); + if (!skb) + goto done; + + /* add header */ + scratch = skb_put(skb, len); + sprintf(scratch, "%s@",s); + + /* copy keys to our continuous event payload buffer */ + add_msg(skb, "HOME=/"); + add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); + add_msg(skb, "SUBSYSTEM=button"); + add_msg(skb, "BUTTON=reset"); + add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released")); + sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ); + add_msg(skb, buf); + snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum()); + add_msg(skb, buf); + + NETLINK_CB(skb).dst_group = 1; + netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL); + +done: + kfree(event); +} + +static irqreturn_t button_handler(int irq, void *dev_id) +{ + static int pressed = 0; + struct event_t *event; + u32 gpio = ~0; + + event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC); + if (!event) + return IRQ_NONE; + + pressed = !pressed; + + DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);) + gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE); + + event->set = gpio; + event->jiffies = jiffies; + + INIT_WORK(&event->wq, (void *)(void *)hotplug_button); + schedule_work(&event->wq); + + seen = jiffies; + + return IRQ_HANDLED; +} + +int __init ar531x_init_reset(void) +{ + struct ar531x_boarddata *bcfg; + bcfg = (struct ar531x_boarddata *) board_config; + + seen = jiffies; + request_irq(AR531X_GPIO_IRQ_BASE + bcfg->resetConfigGpio, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL); + + return 0; +} + +module_init(ar531x_init_reset); |