The Au1300 has a new interrupt controller (relative to the rest of the Alchemy line). The differences were great enough to justify adding a whole new module. Included in this patch is the new interrupt controller, a new implementation of the cascade interrupt controller on the DB1300 board and some code to drive LEDs on the DB1300 that is used by the interrupt controller. A small change was made to the existing interrupt controller; it is "ifdef'd out" for Au1300. Since the cascade interrupt controller is virtually indentical (with the exception of some constants) between the DB1300 and DB1200, a future optimization may be to use the same code for both boards. Signed-off-by: Kevin Hickey <khickey@xxxxxxxxxxx> --- arch/mips/alchemy/Kconfig | 4 + arch/mips/alchemy/common/Makefile | 4 +- arch/mips/alchemy/common/gpio_int.c | 268 ++++++++++++++++++++++++++ arch/mips/alchemy/common/irq.c | 3 + arch/mips/alchemy/devboards/Makefile | 5 + arch/mips/alchemy/devboards/cascade_irq.c | 142 ++++++++++++++ arch/mips/alchemy/devboards/leds.c | 58 ++++++ arch/mips/include/asm/mach-au1x00/gpio_int.h | 239 +++++++++++++++++++++++ arch/mips/include/asm/mach-au1x00/irq.h | 34 ++++ 9 files changed, 756 insertions(+), 1 deletions(-) create mode 100644 arch/mips/alchemy/common/gpio_int.c create mode 100644 arch/mips/alchemy/devboards/cascade_irq.c create mode 100644 arch/mips/alchemy/devboards/leds.c create mode 100644 arch/mips/include/asm/mach-au1x00/gpio_int.h create mode 100644 arch/mips/include/asm/mach-au1x00/irq.h diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig index 7198a88..2e189c2 100644 --- a/arch/mips/alchemy/Kconfig +++ b/arch/mips/alchemy/Kconfig @@ -114,18 +114,22 @@ endchoice config SOC_AU1000 bool select SOC_AU1X00 + select AU_INT_CNTLR config SOC_AU1100 bool select SOC_AU1X00 + select AU_INT_CNTLR config SOC_AU1500 bool select SOC_AU1X00 + select AU_INT_CNTLR config SOC_AU1550 bool select SOC_AU1X00 + select AU_INT_CNTLR config SOC_AU1200 bool diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index d50d476..85ffa2e 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -7,7 +7,9 @@ obj-y += prom.o irq.o puts.o time.o reset.o \ clocks.o platform.o power.o setup.o \ - sleeper.o dma.o dbdma.o gpio.o + sleeper.o dma.o dbdma.o gpio.o gpio_int.o + +obj-$(CONFIG_SOC_AU13XX) += au13xx_res.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/mips/alchemy/common/gpio_int.c b/arch/mips/alchemy/common/gpio_int.c new file mode 100644 index 0000000..c09b793 --- /dev/null +++ b/arch/mips/alchemy/common/gpio_int.c @@ -0,0 +1,268 @@ +/* + * Copyright 2008 RMI Corporation + * Author: Kevin Hickey <khickey@xxxxxxxxxxx> + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef CONFIG_AU_GPIO_INT_CNTLR + +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/interrupt.h> /* For functions called by do_IRQ */ +#include <asm/irq_cpu.h> + +#include <asm/mach-au1x00/gpio_int.h> +#include <asm/mach-au1x00/au1000.h> + +#include <dev_boards.h> + +volatile struct gpio_int_regs *const gpio_int = + (struct gpio_int_regs *)(GPIO_INT_CTRLR_BASE + KSEG1_OFFSET); + +static struct gpio_int_cfg __initdata basic_irqs[]; + +#ifdef CONFIG_SOC_AU13XX +static struct gpio_int_cfg __initdata basic_irqs[] = { + { AU1300_IRQ_DDMA, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_RTC_TICK, 1, RISING, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_TOY_TICK, 1, RISING, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_LCD, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_UART1, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_UART1, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_UART2, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_UART3, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_SD1, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_SD2, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_USB, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_BSA, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_MPE, 1, RISING, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_ITE, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL }, + + { AU1300_IRQ_RTCMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_RTCMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_RTCMATCH_2, 0, RISING, HW_INT_0, DEV_CTRL }, + + { AU1300_IRQ_TOYMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_TOYMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL }, + { AU1300_IRQ_TOYMATCH_2, 1, RISING, HW_INT_1, DEV_CTRL }, + + + // KH: TODO - Move this to the board file. + { 5, 0, LEVEL_HIGH, HW_INT_0, GPIO_IN }, +}; + +/* + * KH: TODO - Consider moving to board specific location... + */ +static struct gpio_int_cfg __initdata basic_gpios[] = { + { 32, 0, DISABLED, HW_INT_0, DEV_CTRL }, + { 33, 0, DISABLED, HW_INT_0, DEV_CTRL }, + { 34, 0, DISABLED, HW_INT_0, DEV_CTRL }, + { 35, 0, DISABLED, HW_INT_0, DEV_CTRL }, + { 36, 0, DISABLED, HW_INT_0, DEV_CTRL }, + { 37, 0, DISABLED, HW_INT_0, DEV_CTRL }, +}; +#endif + +int __initdata nr_basic_irqs = ARRAY_SIZE(basic_irqs); + +/* + **************************************************************************** + * Functions and delcaration for irq_chip + **************************************************************************** + */ +void gpio_int_ack(unsigned int irq) +{ + u32 intr = irq - GPINT_LINUX_IRQ_OFFSET; + u32 bank = GPINT_BANK_FROM_INT(intr); + u32 bit = GPINT_BIT_FROM_INT(bank, intr); + + au_iowrite32(bit, &gpio_int->int_pend[bank]); +} + +void gpio_int_mask(unsigned int irq) +{ + u32 intr = irq - GPINT_LINUX_IRQ_OFFSET; + u32 bank = GPINT_BANK_FROM_INT(intr); + u32 bit = GPINT_BIT_FROM_INT(bank, intr); + + au_iowrite32(bit, &gpio_int->int_maskclr[bank]); +} + +void gpio_int_unmask(unsigned int irq) +{ + u32 intr = irq - GPINT_LINUX_IRQ_OFFSET; + u32 bank = GPINT_BANK_FROM_INT(intr); + u32 bit = GPINT_BIT_FROM_INT(bank, intr); + + au_iowrite32(bit, &gpio_int->int_mask[bank]); +} + +void gpio_int_mask_ack(unsigned int irq) +{ + u32 intr = irq - GPINT_LINUX_IRQ_OFFSET; + u32 bank = GPINT_BANK_FROM_INT(intr); + u32 bit = GPINT_BIT_FROM_INT(bank, intr); + + au_iowrite32(bit, &gpio_int->int_maskclr[bank]); + au_iowrite32(bit, &gpio_int->int_pend[bank]); +} + +static struct irq_chip gpio_int_irq_type = { + .name = "Au GPIO/INT", + .ack = gpio_int_ack, + .mask = gpio_int_mask, + .unmask = gpio_int_unmask, + .mask_ack = gpio_int_mask_ack +}; +/*****************************************************************************/ + +void set_pin_cfg(const struct gpio_int_cfg *cfg) +{ + u32 tmp; + tmp = GPINT_PINCTL_N(cfg->pinctl); + tmp |= GPINT_INTLINE_N(cfg->intline); + tmp |= GPINT_INTCFG_N(cfg->intcfg); + tmp |= cfg->intwake ? GPINT_INTWAKE_ENABLE : 0; + au_iowrite32(tmp, &gpio_int->gp_int[cfg->number]); +} + +void set_gpio(u8 gpio, u8 value) +{ + u32 bank = GPINT_BANK_FROM_GPIO(gpio); + u32 bit = GPINT_BIT_FROM_GPIO(bank, gpio); + + if (value == 0) + au_iowrite32(1 << bit, &gpio_int->pin_valclr[bank]); + else + au_iowrite32(1 << bit, &gpio_int->pin_val[bank]); +} + +u8 get_gpio(u8 gpio) +{ + u32 bank = GPINT_BANK_FROM_GPIO(gpio); + u32 bit = GPINT_BIT_FROM_GPIO(bank, gpio); + u32 tmp; + + tmp = au_ioread32(&gpio_int->pin_val[bank]); + return tmp >> bit; +} + + +void __init arch_init_irq(void) +{ + int i; + + /* + * Initialize the basic MIPS interrupt components. + */ + mips_cpu_irq_init(); + + for (i = 0; i < GPINT_NUM_BANKS; ++i) + gpio_int->int_maskclr[i] = ~0UL; + + + for (i = 0; i < ARRAY_SIZE(basic_gpios); ++i) { + set_pin_cfg(&basic_gpios[i]); + } + + for (i = 0; i < nr_basic_irqs; ++i) { + printk("Initializing IRQ %d\n", basic_irqs[i].number); + set_pin_cfg(&basic_irqs[i]); + if (basic_irqs[i].intcfg == LEVEL_LOW) + set_irq_chip_and_handler_name( + basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET, + &gpio_int_irq_type, + handle_level_irq, + "lowlevel"); + else if (basic_irqs[i].intcfg == LEVEL_HIGH) + set_irq_chip_and_handler_name( + basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET, + &gpio_int_irq_type, + handle_level_irq, + "highlevel"); + else if (basic_irqs[i].intcfg == FALLING) + set_irq_chip_and_handler_name( + basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET, + &gpio_int_irq_type, + handle_edge_irq, + "fallingedge"); + else if (basic_irqs[i].intcfg == RISING) + set_irq_chip_and_handler_name( + basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET, + &gpio_int_irq_type, + handle_edge_irq, + "risingedge"); + else if (basic_irqs[i].intcfg == ANY_CHANGE) + set_irq_chip_and_handler_name( + basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET, + &gpio_int_irq_type, + handle_edge_irq, + "bothedge"); + else + set_irq_chip( + basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET, + &gpio_int_irq_type); + } + + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); + + board_init_irq(); +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int intr; + u32 bank; + u32 reg_msk; + unsigned int pending = read_c0_status() & read_c0_cause(); + /* + * C0 timer tick + */ + if (pending & CAUSEF_IP7) + do_IRQ(MIPS_CPU_IRQ_BASE + 7); + else if (pending & (CAUSEF_IP2 | CAUSEF_IP3)) { + intr = au_ioread32(&gpio_int->pri_enc); + bank = GPINT_BANK_FROM_INT(intr); + reg_msk = GPINT_BIT_FROM_INT(bank, intr); + + if (intr != 127) { + if (pending & CAUSEF_IP3) + board_irq_dispatch(intr); + + do_IRQ(GPINT_LINUX_IRQ_OFFSET + intr); + } + } else { + printk(KERN_WARNING + "ALCHEMY GPIO_INT: Unexpected cause was set. %08x\n", + pending); + } + +} + +#endif diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index c88c821..f8742dd 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -24,6 +24,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifdef CONFIG_AU_INT_CNTLR #include <linux/bitops.h> #include <linux/init.h> @@ -609,3 +610,5 @@ void __init arch_init_irq(void) set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); } + +#endif diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile index 0d2d224..8cce4d0 100644 --- a/arch/mips/alchemy/devboards/Makefile +++ b/arch/mips/alchemy/devboards/Makefile @@ -17,3 +17,8 @@ obj-$(CONFIG_MIPS_DB1500) += db1x00/ obj-$(CONFIG_MIPS_DB1550) += db1x00/ obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/ obj-$(CONFIG_MIPS_MIRAGE) += db1x00/ + +# These two files are used only by DB1300 today but will be used by DB1200 and +# possibly others in the future. +obj-$(CONFIG_MIPS_DB1300) += cascade_irq.o +obj-$(CONFIG_MIPS_DB1300) += leds.o diff --git a/arch/mips/alchemy/devboards/cascade_irq.c b/arch/mips/alchemy/devboards/cascade_irq.c new file mode 100644 index 0000000..6d0a965 --- /dev/null +++ b/arch/mips/alchemy/devboards/cascade_irq.c @@ -0,0 +1,142 @@ +/* + * Copyright 2003-2008 RMI Corporation. All rights reserved. + * Author: Kevin Hickey <khickey@xxxxxxxxxxx> + * + * 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 SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/semaphore.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mips-boards/db1300.h> + +#include <asm/mach-au1x00/dev_boards.h> + +/* + * The following must be declared/defined in an included file: + * - volatile struct bcsr_regs (declared) + * (which much include fields int_status, intset_mask, intclr_mask, intset, + * and intclr) + * - volatile struct bcsr_regs *const bcsr (defined) + * - CASCADE_IRQ_MIN + * - CASCADE_IRQ_MAX + * - CASCADE_IRQ_TYPE_STRING + * - CASCADE_IRQ (System IRQ to which the cascade is connected) + */ + +void __init board_init_irq(void); + +irqreturn_t cascade_handler(int irq, void *dev_id) +{ + u16 int_status = au_ioread16(&db_bcsr->int_status); + int irq_in_service; + + au_iowrite16(int_status, &db_bcsr->int_status); + for ( ; int_status; int_status &= int_status - 1) { + irq_in_service = CASCADE_IRQ_MIN + __ffs(int_status); + db_set_hex((u8)(irq_in_service)); + do_IRQ(irq_in_service); + } + + return IRQ_RETVAL(1); +} + +DEFINE_MUTEX(cascade_use_count_mutex); +static int cascade_use_count = 0; + +static void cascade_mask(unsigned int irq) +{ + au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intclr_mask); +} + +static void cascade_unmask(unsigned int irq) +{ + au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intset_mask); +} + +static void cascade_enable(unsigned int irq) +{ + au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intset); + cascade_unmask(irq); +} + +static void cascade_disable(unsigned int irq) +{ + au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intclr); + cascade_mask(irq); +} + + +static unsigned int cascade_startup(unsigned int irq) +{ + int retval = 0; + + mutex_lock(&cascade_use_count_mutex); + ++cascade_use_count; + if (cascade_use_count == 1) + retval = request_irq(CASCADE_IRQ, + &cascade_handler, 0, "Cascade", + &cascade_handler); + mutex_unlock(&cascade_use_count_mutex); + + cascade_enable(irq); + cascade_unmask(irq); + + return retval; +} + +static void cascade_shutdown(unsigned int irq) +{ + cascade_mask(irq); + cascade_disable(irq); + + mutex_lock(&cascade_use_count_mutex); + --cascade_use_count; + if (cascade_use_count == 0) + free_irq(CASCADE_IRQ, &cascade_handler); + mutex_unlock(&cascade_use_count_mutex); +} + +static struct irq_chip cascade_irq_type = { + .name = CASCADE_IRQ_TYPE_STRING, + .startup = cascade_startup, + .shutdown = cascade_shutdown, + .mask = cascade_mask, + .enable = cascade_enable, + .disable = cascade_disable, + .unmask = cascade_unmask, + .mask_ack = cascade_mask +}; + +void __init board_init_irq(void) +{ + int irq; + + for (irq = CASCADE_IRQ_MIN; + irq < CASCADE_IRQ_MAX; ++irq ) { + printk("Initializing IRQ %d\n", irq); + set_irq_chip_and_handler(irq, &cascade_irq_type, + handle_level_irq); + cascade_disable(irq); + } +} diff --git a/arch/mips/alchemy/devboards/leds.c b/arch/mips/alchemy/devboards/leds.c new file mode 100644 index 0000000..75be345 --- /dev/null +++ b/arch/mips/alchemy/devboards/leds.c @@ -0,0 +1,58 @@ +/* + * Copyright 2003-2008 RMI Corporation. All rights reserved. + * Author: Kevin Hickey <khickey@xxxxxxxxxxx> + * + * 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 SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/dev_boards.h> + +/* + * Requires the following to be defined in the board-specifc .h file: + * - HEX_REGS_KSEG1_ADDR + * - struct hex_regs with members: + * - hex (set the hex value) + * - BCSR_REGS_KSEG1_ADDR + * - struct bcsr_regs + */ + +static volatile hex_regs *const hex = (hex_regs *)(HEX_REGS_KSEG1_ADDR); + +/* + * Takes a u8 because though the register is 16 bits, only 8 appear + */ +void db_set_hex(u8 val) +{ + au_iowrite16((u16)val, &hex->hex); +} + +/* + * 2 dots use the least significant 2 bits + * Setting a bit lights the LED (opposite of the register) + */ +void db_set_hex_dots(u8 val) +{ + u16 leds = au_ioread16(&db_bcsr->disk_leds); + leds |= 0x3; + leds &= (~(val & 0x3)); + au_iowrite16(leds, &db_bcsr->disk_leds); +} diff --git a/arch/mips/include/asm/mach-au1x00/gpio_int.h b/arch/mips/include/asm/mach-au1x00/gpio_int.h new file mode 100644 index 0000000..85df296 --- /dev/null +++ b/arch/mips/include/asm/mach-au1x00/gpio_int.h @@ -0,0 +1,239 @@ +/* + * Copyright 2008 RMI Corporation + * Author: Kevin Hickey <khickey@xxxxxxxxxxx> + * + * Defines and macros for the GPIO and Interrupt controller for Alchemy, + * introduced in the Au13xx series. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _GPIO_INT_H +#define _GPIO_INT_H + +#include <linux/types.h> + +/* + * There are a total 128 'channels' defined by the Au13xx databook. However, + * this requires 4 sperate 32bit registers for programming. Each register is + * called a 'bank' for ease of use. + */ +#define GPINT_BANK0 0 +#define GPINT_BANK1 1 +#define GPINT_BANK2 2 +#define GPINT_BANK3 3 + +#define GPINT_NUM_BANKS 4 /* 0-3 */ +#define GPINT_MAX_BANK (GPINT_BANK3) + +#define GPINT_GPIO_PER_BANK 32 +#define GPINT_INTS_PER_BANK GPINT_GPIO_PER_BANK + +/* Total number of interrupts our architecture allows */ +#define GPINT_MAX_INTS (GPINT_NUM_BANKS*GPINT_INTS_PER_BANK) + +/* Current maximum supported GPIO/INTERRUPTs */ +#define GPINT_NUM_GPIO GPINT_MAX_INTS +#define GPINT_NUM_INTERRUPTS GPINT_MAX_INTS + +/* Starting GPIO/INTERRUPT for each bank */ +#define GPINT_BANK0_START 0 +#define GPINT_BANK1_START 32 +#define GPINT_BANK2_START 64 +#define GPINT_BANK3_START 96 + +/* divide by 32 to get bank */ +#define GPINT_BANK_FROM_GPIO(n) (n>>5) +#define GPINT_BANK_FROM_INT(n) GPINT_BANK_FROM_GPIO(n) +/* multiply by 32 to get base */ +#define GPINT_BIT_FROM_GPIO(b, n) (1<<(n-(b<<5))) +#define GPINT_BIT_FROM_INT(b, n) GPINT_BIT_FROM_GPIO(b, n) + +struct gpio_int_regs { + /* R/W1S */ + /* u32 pin_val0; 0x00 */ + /* u32 pin_val1; 0x04 */ + /* u32 pin_val2; 0x08 */ + /* u32 pin_val3; 0x0C */ + u32 pin_val[GPINT_NUM_BANKS]; + + /* W1C */ + /* u32 pin_valclr0 0x10 */ + /* u32 pin_valclr1; 0x14 */ + /* u32 pin_valclr2; 0x18 */ + /* u32 pin_valclr3; 0x1C */ + u32 pin_valclr[GPINT_NUM_BANKS]; + + /* R/W1C */ + /* u32 int_pend0; 0x20 */ + /* u32 int_pend1; 0x24 */ + /* u32 int_pend2; 0x28 */ + /* u32 int_pend3; 0x2c */ + u32 int_pend[GPINT_NUM_BANKS]; + + u32 pri_enc; /* 0x30 */ + u32 _resvd0[3]; /* 0x34-0x3c */ + + /* R/W1S */ + /* u32 int_mask0; 0x40 */ + /* u32 int_mask1; 0x44 */ + /* u32 int_mask2; 0x48 */ + /* u32 int_mask3; 0x4c */ + u32 int_mask[GPINT_NUM_BANKS]; + + /* W1C */ + /* u32 int_maskclr0; 0x50 */ + /* u32 int_maskclr1; 0x54 */ + /* u32 int_maskclr2; 0x58 */ + /* u32 int_maskclr3; 0x5C */ + u32 int_maskclr[GPINT_NUM_BANKS]; + + /* R/W */ + u32 dma_sel; /* 0x60 */ + u32 _resvd1[(0x80-0x64)/4]; /* 0x64-0x7C */ + + /* W */ + /* u32 dev_sel0; 0x80 */ + /* u32 dev_sel1; 0x84 */ + /* u32 dev_sel2; 0x88 */ + /* u32 dev_sel3; 0x8C */ + u32 dev_sel[GPINT_NUM_BANKS]; + + /* W */ + /* u32 dev_selclr0; 0x90 */ + /* u32 dev_selclr1; 0x94 */ + /* u32 dev_selclr2; 0x98 */ + /* u32 dev_selclr3; 0x9C */ + u32 dev_selclr[GPINT_NUM_BANKS]; + + /* R */ + /* u32 reset_val0; 0xA0 */ + /* u32 reset_val1; 0xA4 */ + /* u32 reset_val2; 0xA8 */ + /* u32 reset_val3; 0xAC */ + u32 reset_val[GPINT_NUM_BANKS]; + + /* 0xB0 - 0xFFC */ + u32 _resvd2[(0x1000-0xB0)/4]; + + /* R/W -- when interrupt mask is clear */ + /* R -- when interrupt mask is set */ + /* u32 gp_int0; 0x1000 */ + /* u32 gp_int1; 0x1004 */ + /* u32 gp_int2; 0x1008 */ + /* u32 gp_int2; 0x100C */ + /* u32 gp_intN; 0x1000 + (N*4) */ + u32 gp_int[GPINT_MAX_INTS]; +}; + +extern volatile struct gpio_int_regs *const gpio_int; + +#define GPINT_DMASEL_DMA0 (0) +#define GPINT_DMASEL_DMA0_N(n) (((n)&0xFF)<<GPINT_DMASEL_DMA0) +#define GPINT_DMASEL_DMA1 (8) +#define GPINT_DMASEL_DMA1_N(n) (((n)&0xFF)<<GPINT_DMASEL_DMA1) + +#define GPINT_PINCTL (0) +#define GPINT_PINCTL_N(n) (((n)&0x3)<<GPINT_PINCTL) +#define GPINT_PINCTL_GPIOINPUT GPINT_PINCTL_N(0) +#define GPINT_PINCTL_INTERRUPT GPINT_PINCTL_N(1) +#define GPINT_PINCTL_GPIOOUT_0 GPINT_PINCTL_N(2) +#define GPINT_PINCTL_GPIOOUT_1 GPINT_PINCTL_N(3) + +#define GPINT_INTLINE (2) +#define GPINT_INTLINE_N(n) (((n)&0x3)<<GPINT_INTLINE) +#define GPINT_INTLINE_CPUINT_0 GPINT_INTLINE_N(0) +#define GPINT_INTLINE_CPUINT_1 GPINT_INTLINE_N(1) +#define GPINT_INTLINE_CPUINT_2 GPINT_INTLINE_N(2) +#define GPINT_INTLINE_CPUINT_3 GPINT_INTLINE_N(3) + +#define GPINT_INTCFG (4) +#define GPINT_INTCFG_N(n) (((n)&0x7)<<GPINT_INTCFG) +#define GPINT_INTCFG_DISABLE GPINT_INTCFG_N(0) +#define GPINT_INTCFG_LL GPINT_INTCFG_N(1) +#define GPINT_INTCFG_HL GPINT_INTCFG_N(2) +#define GPINT_INTCFG_FE GPINT_INTCFG_N(5) +#define GPINT_INTCFG_RE GPINT_INTCFG_N(6) +#define GPINT_INTCFG_CHANGE GPINT_INTCFG_N(7) + +#define GPINT_INTWAKE (7) +#define GPINT_INTWAKE_ENABLE ((1)<<GPINT_INTWAKE) + +/* GPIO */ +#define GPIO_N(N) (1 << (N)) + +/* + * Take caution when reordering or changing values; used directly in pin + * configuration register + */ +enum intcfg_vals { DISABLED = 0, LEVEL_LOW, LEVEL_HIGH, + FALLING = 5, RISING, ANY_CHANGE }; +enum intline_vals { HW_INT_0 = 0, HW_INT_1, HW_INT_2, HW_INT_3 }; +enum pinctl_vals { GPIO_IN = 0, DEV_CTRL, GPIO_OUT_0, GPIO_OUT_1 }; + +/* + * Defines the settings for a given interrupt "channel" + */ +struct gpio_int_cfg { + int number; + bool intwake; + enum intcfg_vals intcfg; + enum intline_vals intline; + enum pinctl_vals pinctl; +}; + +/* + * Linux uses IRQ 0-7 for the 8 causes. That means that all of our channel + * bits need to be offset by 8 either when passed to do_IRQ or when received + * through the irq_chip calls + */ +#define GPINT_LINUX_IRQ_OFFSET 8 + +void board_irq_dispatch(unsigned int irq); + +/* + * Configure a GPIO/Interrupt pin. Many of the defined interrupt pins as + * decribed in the Au1300 data book are configured during platform + * initialization, however drivers may wish to repurpose those or other GPIO + * pins later. + * + * Changing the behavior of an interrupt pin after a handler has been + * installed is ill advised and should be avoided. + */ +void set_pin_cfg(const struct gpio_int_cfg *cfg); + +/* + * Set the GPIO to the specified value. The value must be 0 or 1. Any other + * value results in a no-op. + * + * This call will implicitly reconfigure the pin to be a GPIO if it is + * configured as a device pin. + */ +void set_gpio(u8 gpio, u8 value); + +/* + * Get the value of any GPIO pin (including those controlled by devices). + * + * This will not change the pin configuration + */ +u8 get_gpio(u8 gpio); + +#endif /* _GPIO_INT_H */ + diff --git a/arch/mips/include/asm/mach-au1x00/irq.h b/arch/mips/include/asm/mach-au1x00/irq.h new file mode 100644 index 0000000..91d06a5 --- /dev/null +++ b/arch/mips/include/asm/mach-au1x00/irq.h @@ -0,0 +1,34 @@ +/* + * Copyright 2008 RMI Corporation + * Author: Kevin Hickey <khickey@xxxxxxxxxxx> + * + * Defines and macros for the GPIO and Interrupt controller for Alchemy, + * introduced in the Au13xx series. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _MACH_AU1X00_INT_H +#define _MACH_AU1X00_INT_H + +#define NR_IRQS 255 +#define MIPS_CPU_IRQ_BASE 0 + +#endif /* _MACH_AU1X00_INT_H */ -- 1.5.4.3