linux-mips
[Top] [All Lists]

[PATCH 02/10] Alchemy: Au1300 new interrupt controller

To: ralf@linux-mips.org, linux-mips@linux-mips.org
Subject: [PATCH 02/10] Alchemy: Au1300 new interrupt controller
From: Kevin Hickey <khickey@rmicorp.com>
Date: Fri, 6 Mar 2009 10:20:01 -0600
Cc: Kevin Hickey <khickey@rmicorp.com>
In-reply-to: <788248524efc28ba2608ed79bfb7080ee476b12d.1236354153.git.khickey@rmicorp.com>
In-reply-to: <788248524efc28ba2608ed79bfb7080ee476b12d.1236354153.git.khickey@rmicorp.com>
Original-recipient: rfc822;linux-mips@linux-mips.org
References: <> <1236356409-32357-1-git-send-email-khickey@rmicorp.com> <788248524efc28ba2608ed79bfb7080ee476b12d.1236354153.git.khickey@rmicorp.com>
References: <788248524efc28ba2608ed79bfb7080ee476b12d.1236354153.git.khickey@rmicorp.com>
Sender: linux-mips-bounce@linux-mips.org
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@rmicorp.com>
---
 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@rmicorp.com>
+ *
+ *  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@rmicorp.com>
+ *
+ *  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@rmicorp.com>
+ *
+ *  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@rmicorp.com>
+ *
+ * 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@rmicorp.com>
+ *
+ * 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


<Prev in Thread] Current Thread [Next in Thread>