linux-bk/arch/mips/ite-boards/generic/irq.c
<<
>>
Prefs
   1/*
   2 * BRIEF MODULE DESCRIPTION
   3 *      ITE 8172G interrupt/setup routines.
   4 *
   5 * Copyright 2000,2001 MontaVista Software Inc.
   6 * Author: MontaVista Software, Inc.
   7 *              ppopov@mvista.com or source@mvista.com
   8 *
   9 * Part of this file was derived from Carsten Langgaard's
  10 * arch/mips/mips-boards/atlas/atlas_int.c.
  11 *
  12 * Carsten Langgaard, carstenl@mips.com
  13 * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
  14 *
  15 *  This program is free software; you can redistribute  it and/or modify it
  16 *  under  the terms of  the GNU General  Public License as published by the
  17 *  Free Software Foundation;  either version 2 of the  License, or (at your
  18 *  option) any later version.
  19 *
  20 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  21 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  22 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  23 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  24 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  26 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  27 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  28 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  29 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30 *
  31 *  You should have received a copy of the  GNU General Public License along
  32 *  with this program; if not, write  to the Free Software Foundation, Inc.,
  33 *  675 Mass Ave, Cambridge, MA 02139, USA.
  34 */
  35#include <linux/errno.h>
  36#include <linux/init.h>
  37#include <linux/irq.h>
  38#include <linux/kernel_stat.h>
  39#include <linux/module.h>
  40#include <linux/signal.h>
  41#include <linux/sched.h>
  42#include <linux/types.h>
  43#include <linux/interrupt.h>
  44#include <linux/ioport.h>
  45#include <linux/timex.h>
  46#include <linux/slab.h>
  47#include <linux/random.h>
  48#include <linux/serial_reg.h>
  49#include <linux/bitops.h>
  50
  51#include <asm/bootinfo.h>
  52#include <asm/io.h>
  53#include <asm/mipsregs.h>
  54#include <asm/system.h>
  55#include <asm/it8172/it8172.h>
  56#include <asm/it8172/it8172_int.h>
  57#include <asm/it8172/it8172_dbg.h>
  58
  59/* revisit */
  60#define EXT_IRQ0_TO_IP 2 /* IP 2 */
  61#define EXT_IRQ5_TO_IP 7 /* IP 7 */
  62
  63#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
  64
  65void disable_it8172_irq(unsigned int irq_nr);
  66void enable_it8172_irq(unsigned int irq_nr);
  67
  68extern void set_debug_traps(void);
  69extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
  70extern asmlinkage void it8172_IRQ(void);
  71
  72struct it8172_intc_regs volatile *it8172_hw0_icregs =
  73        (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
  74
  75static void disable_it8172_irq(unsigned int irq_nr)
  76{
  77        if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
  78                /* LPC interrupt */
  79                it8172_hw0_icregs->lpc_mask |=
  80                        (1 << (irq_nr - IT8172_LPC_IRQ_BASE));
  81        } else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
  82                /* Local Bus interrupt */
  83                it8172_hw0_icregs->lb_mask |=
  84                        (1 << (irq_nr - IT8172_LB_IRQ_BASE));
  85        } else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
  86                /* PCI and other interrupts */
  87                it8172_hw0_icregs->pci_mask |=
  88                        (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
  89        } else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
  90                /* NMI interrupts */
  91                it8172_hw0_icregs->nmi_mask |=
  92                        (1 << (irq_nr - IT8172_NMI_IRQ_BASE));
  93        } else {
  94                panic("disable_it8172_irq: bad irq %d", irq_nr);
  95        }
  96}
  97
  98static void enable_it8172_irq(unsigned int irq_nr)
  99{
 100        if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
 101                /* LPC interrupt */
 102                it8172_hw0_icregs->lpc_mask &=
 103                        ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE));
 104        }
 105        else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
 106                /* Local Bus interrupt */
 107                it8172_hw0_icregs->lb_mask &=
 108                        ~(1 << (irq_nr - IT8172_LB_IRQ_BASE));
 109        }
 110        else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
 111                /* PCI and other interrupts */
 112                it8172_hw0_icregs->pci_mask &=
 113                        ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
 114        }
 115        else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
 116                /* NMI interrupts */
 117                it8172_hw0_icregs->nmi_mask &=
 118                        ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE));
 119        }
 120        else {
 121                panic("enable_it8172_irq: bad irq %d", irq_nr);
 122        }
 123}
 124
 125static unsigned int startup_ite_irq(unsigned int irq)
 126{
 127        enable_it8172_irq(irq);
 128        return 0;
 129}
 130
 131#define shutdown_ite_irq        disable_it8172_irq
 132#define mask_and_ack_ite_irq    disable_it8172_irq
 133
 134static void end_ite_irq(unsigned int irq)
 135{
 136        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
 137                enable_it8172_irq(irq);
 138}
 139
 140static struct hw_interrupt_type it8172_irq_type = {
 141        "ITE8172",
 142        startup_ite_irq,
 143        shutdown_ite_irq,
 144        enable_it8172_irq,
 145        disable_it8172_irq,
 146        mask_and_ack_ite_irq,
 147        end_ite_irq,
 148        NULL
 149};
 150
 151
 152static void enable_none(unsigned int irq) { }
 153static unsigned int startup_none(unsigned int irq) { return 0; }
 154static void disable_none(unsigned int irq) { }
 155static void ack_none(unsigned int irq) { }
 156
 157/* startup is the same as "enable", shutdown is same as "disable" */
 158#define shutdown_none   disable_none
 159#define end_none        enable_none
 160
 161static struct hw_interrupt_type cp0_irq_type = {
 162        "CP0 Count",
 163        startup_none,
 164        shutdown_none,
 165        enable_none,
 166        disable_none,
 167        ack_none,
 168        end_none
 169};
 170
 171void enable_cpu_timer(void)
 172{
 173        unsigned long flags;
 174
 175        local_irq_save(flags);
 176        set_c0_status(0x100 << EXT_IRQ5_TO_IP);
 177        local_irq_restore(flags);
 178}
 179
 180void __init arch_init_irq(void)
 181{
 182        int i;
 183        unsigned long flags;
 184
 185        memset(irq_desc, 0, sizeof(irq_desc));
 186        set_except_vector(0, it8172_IRQ);
 187
 188        /* mask all interrupts */
 189        it8172_hw0_icregs->lb_mask  = 0xffff;
 190        it8172_hw0_icregs->lpc_mask = 0xffff;
 191        it8172_hw0_icregs->pci_mask = 0xffff;
 192        it8172_hw0_icregs->nmi_mask = 0xffff;
 193
 194        /* make all interrupts level triggered */
 195        it8172_hw0_icregs->lb_trigger  = 0;
 196        it8172_hw0_icregs->lpc_trigger = 0;
 197        it8172_hw0_icregs->pci_trigger = 0;
 198        it8172_hw0_icregs->nmi_trigger = 0;
 199
 200        /* active level setting */
 201        /* uart, keyboard, and mouse are active high */
 202        it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000);
 203        it8172_hw0_icregs->lb_level |= 0x20;
 204
 205        /* keyboard and mouse are edge triggered */
 206        it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000);
 207
 208
 209#if 0
 210        // Enable this piece of code to make internal USB interrupt
 211        // edge triggered.
 212        it8172_hw0_icregs->pci_trigger |=
 213                (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
 214        it8172_hw0_icregs->pci_level &=
 215                ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
 216#endif
 217
 218        for (i = 0; i <= IT8172_LAST_IRQ; i++) {
 219                irq_desc[i].handler = &it8172_irq_type;
 220                spin_lock_init(&irq_desc[i].lock);
 221        }
 222        irq_desc[MIPS_CPU_TIMER_IRQ].handler = &cp0_irq_type;
 223        set_c0_status(ALLINTS_NOTIMER);
 224}
 225
 226void mips_spurious_interrupt(struct pt_regs *regs)
 227{
 228#if 1
 229        return;
 230#else
 231        unsigned long status, cause;
 232
 233        printk("got spurious interrupt\n");
 234        status = read_c0_status();
 235        cause = read_c0_cause();
 236        printk("status %x cause %x\n", status, cause);
 237        printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr);
 238#endif
 239}
 240
 241void it8172_hw0_irqdispatch(struct pt_regs *regs)
 242{
 243        int irq;
 244        unsigned short intstatus = 0, status = 0;
 245
 246        intstatus = it8172_hw0_icregs->intstatus;
 247        if (intstatus & 0x8) {
 248                panic("Got NMI interrupt");
 249        } else if (intstatus & 0x4) {
 250                /* PCI interrupt */
 251                irq = 0;
 252                status |= it8172_hw0_icregs->pci_req;
 253                while (!(status & 0x1)) {
 254                        irq++;
 255                        status >>= 1;
 256                }
 257                irq += IT8172_PCI_DEV_IRQ_BASE;
 258        } else if (intstatus & 0x1) {
 259                /* Local Bus interrupt */
 260                irq = 0;
 261                status |= it8172_hw0_icregs->lb_req;
 262                while (!(status & 0x1)) {
 263                        irq++;
 264                        status >>= 1;
 265                }
 266                irq += IT8172_LB_IRQ_BASE;
 267        } else if (intstatus & 0x2) {
 268                /* LPC interrupt */
 269                /* Since some lpc interrupts are edge triggered,
 270                 * we could lose an interrupt this way because
 271                 * we acknowledge all ints at onces. Revisit.
 272                 */
 273                status |= it8172_hw0_icregs->lpc_req;
 274                it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */
 275                irq = 0;
 276                while (!(status & 0x1)) {
 277                        irq++;
 278                        status >>= 1;
 279                }
 280                irq += IT8172_LPC_IRQ_BASE;
 281        } else
 282                return;
 283
 284        do_IRQ(irq, regs);
 285}
 286
 287void show_pending_irqs(void)
 288{
 289        fputs("intstatus:  ");
 290        put32(it8172_hw0_icregs->intstatus);
 291        puts("");
 292
 293        fputs("pci_req:  ");
 294        put32(it8172_hw0_icregs->pci_req);
 295        puts("");
 296
 297        fputs("lb_req:  ");
 298        put32(it8172_hw0_icregs->lb_req);
 299        puts("");
 300
 301        fputs("lpc_req:  ");
 302        put32(it8172_hw0_icregs->lpc_req);
 303        puts("");
 304}
 305
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.