linux/arch/mips/txx9/generic/irq_tx4939.c
<<
>>
Prefs
   1/*
   2 * TX4939 irq routines
   3 * Based on linux/arch/mips/kernel/irq_txx9.c,
   4 *          and RBTX49xx patch from CELF patch archive.
   5 *
   6 * Copyright 2001, 2003-2005 MontaVista Software Inc.
   7 * Author: MontaVista Software, Inc.
   8 *         ahennessy@mvista.com
   9 *         source@mvista.com
  10 * Copyright (C) 2000-2001,2005-2007 Toshiba Corporation
  11 *
  12 * This file is subject to the terms and conditions of the GNU General Public
  13 * License.  See the file "COPYING" in the main directory of this archive
  14 * for more details.
  15 */
  16/*
  17 * TX4939 defines 64 IRQs.
  18 * Similer to irq_txx9.c but different register layouts.
  19 */
  20#include <linux/init.h>
  21#include <linux/interrupt.h>
  22#include <linux/irq.h>
  23#include <linux/types.h>
  24#include <asm/irq_cpu.h>
  25#include <asm/txx9irq.h>
  26#include <asm/txx9/tx4939.h>
  27
  28/* IRCER : Int. Control Enable */
  29#define TXx9_IRCER_ICE  0x00000001
  30
  31/* IRCR : Int. Control */
  32#define TXx9_IRCR_LOW   0x00000000
  33#define TXx9_IRCR_HIGH  0x00000001
  34#define TXx9_IRCR_DOWN  0x00000002
  35#define TXx9_IRCR_UP    0x00000003
  36#define TXx9_IRCR_EDGE(cr)      ((cr) & 0x00000002)
  37
  38/* IRSCR : Int. Status Control */
  39#define TXx9_IRSCR_EIClrE       0x00000100
  40#define TXx9_IRSCR_EIClr_MASK   0x0000000f
  41
  42/* IRCSR : Int. Current Status */
  43#define TXx9_IRCSR_IF   0x00010000
  44
  45#define irc_dlevel      0
  46#define irc_elevel      1
  47
  48static struct {
  49        unsigned char level;
  50        unsigned char mode;
  51} tx4939irq[TX4939_NUM_IR] __read_mostly;
  52
  53static void tx4939_irq_unmask(struct irq_data *d)
  54{
  55        unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
  56        u32 __iomem *lvlp;
  57        int ofs;
  58        if (irq_nr < 32) {
  59                irq_nr--;
  60                lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r;
  61        } else {
  62                irq_nr -= 32;
  63                lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r;
  64        }
  65        ofs = (irq_nr & 16) + (irq_nr & 1) * 8;
  66        __raw_writel((__raw_readl(lvlp) & ~(0xff << ofs))
  67                     | (tx4939irq[irq_nr].level << ofs),
  68                     lvlp);
  69}
  70
  71static inline void tx4939_irq_mask(struct irq_data *d)
  72{
  73        unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
  74        u32 __iomem *lvlp;
  75        int ofs;
  76        if (irq_nr < 32) {
  77                irq_nr--;
  78                lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r;
  79        } else {
  80                irq_nr -= 32;
  81                lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r;
  82        }
  83        ofs = (irq_nr & 16) + (irq_nr & 1) * 8;
  84        __raw_writel((__raw_readl(lvlp) & ~(0xff << ofs))
  85                     | (irc_dlevel << ofs),
  86                     lvlp);
  87        mmiowb();
  88}
  89
  90static void tx4939_irq_mask_ack(struct irq_data *d)
  91{
  92        unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
  93
  94        tx4939_irq_mask(d);
  95        if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) {
  96                irq_nr--;
  97                /* clear edge detection */
  98                __raw_writel((TXx9_IRSCR_EIClrE | (irq_nr & 0xf))
  99                             << (irq_nr & 0x10),
 100                             &tx4939_ircptr->edc.r);
 101        }
 102}
 103
 104static int tx4939_irq_set_type(struct irq_data *d, unsigned int flow_type)
 105{
 106        unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
 107        u32 cr;
 108        u32 __iomem *crp;
 109        int ofs;
 110        int mode;
 111
 112        if (flow_type & IRQF_TRIGGER_PROBE)
 113                return 0;
 114        switch (flow_type & IRQF_TRIGGER_MASK) {
 115        case IRQF_TRIGGER_RISING:
 116                mode = TXx9_IRCR_UP;
 117                break;
 118        case IRQF_TRIGGER_FALLING:
 119                mode = TXx9_IRCR_DOWN;
 120                break;
 121        case IRQF_TRIGGER_HIGH:
 122                mode = TXx9_IRCR_HIGH;
 123                break;
 124        case IRQF_TRIGGER_LOW:
 125                mode = TXx9_IRCR_LOW;
 126                break;
 127        default:
 128                return -EINVAL;
 129        }
 130        if (irq_nr < 32) {
 131                irq_nr--;
 132                crp = &tx4939_ircptr->dm[(irq_nr & 8) >> 3].r;
 133        } else {
 134                irq_nr -= 32;
 135                crp = &tx4939_ircptr->dm2[((irq_nr & 8) >> 3)].r;
 136        }
 137        ofs = (((irq_nr & 16) >> 1) | (irq_nr & (8 - 1))) * 2;
 138        cr = __raw_readl(crp);
 139        cr &= ~(0x3 << ofs);
 140        cr |= (mode & 0x3) << ofs;
 141        __raw_writel(cr, crp);
 142        tx4939irq[irq_nr].mode = mode;
 143        return 0;
 144}
 145
 146static struct irq_chip tx4939_irq_chip = {
 147        .name           = "TX4939",
 148        .irq_ack        = tx4939_irq_mask_ack,
 149        .irq_mask       = tx4939_irq_mask,
 150        .irq_mask_ack   = tx4939_irq_mask_ack,
 151        .irq_unmask     = tx4939_irq_unmask,
 152        .irq_set_type   = tx4939_irq_set_type,
 153};
 154
 155static int tx4939_irq_set_pri(int irc_irq, int new_pri)
 156{
 157        int old_pri;
 158
 159        if ((unsigned int)irc_irq >= TX4939_NUM_IR)
 160                return 0;
 161        old_pri = tx4939irq[irc_irq].level;
 162        tx4939irq[irc_irq].level = new_pri;
 163        return old_pri;
 164}
 165
 166void __init tx4939_irq_init(void)
 167{
 168        int i;
 169
 170        mips_cpu_irq_init();
 171        /* disable interrupt control */
 172        __raw_writel(0, &tx4939_ircptr->den.r);
 173        __raw_writel(0, &tx4939_ircptr->maskint.r);
 174        __raw_writel(0, &tx4939_ircptr->maskext.r);
 175        /* irq_base + 0 is not used */
 176        for (i = 1; i < TX4939_NUM_IR; i++) {
 177                tx4939irq[i].level = 4; /* middle level */
 178                tx4939irq[i].mode = TXx9_IRCR_LOW;
 179                irq_set_chip_and_handler(TXX9_IRQ_BASE + i, &tx4939_irq_chip,
 180                                         handle_level_irq);
 181        }
 182
 183        /* mask all IRC interrupts */
 184        __raw_writel(0, &tx4939_ircptr->msk.r);
 185        for (i = 0; i < 16; i++)
 186                __raw_writel(0, &tx4939_ircptr->lvl[i].r);
 187        /* setup IRC interrupt mode (Low Active) */
 188        for (i = 0; i < 2; i++)
 189                __raw_writel(0, &tx4939_ircptr->dm[i].r);
 190        for (i = 0; i < 2; i++)
 191                __raw_writel(0, &tx4939_ircptr->dm2[i].r);
 192        /* enable interrupt control */
 193        __raw_writel(TXx9_IRCER_ICE, &tx4939_ircptr->den.r);
 194        __raw_writel(irc_elevel, &tx4939_ircptr->msk.r);
 195
 196        irq_set_chained_handler(MIPS_CPU_IRQ_BASE + TX4939_IRC_INT,
 197                                handle_simple_irq);
 198
 199        /* raise priority for errors, timers, sio */
 200        tx4939_irq_set_pri(TX4939_IR_WTOERR, 7);
 201        tx4939_irq_set_pri(TX4939_IR_PCIERR, 7);
 202        tx4939_irq_set_pri(TX4939_IR_PCIPME, 7);
 203        for (i = 0; i < TX4939_NUM_IR_TMR; i++)
 204                tx4939_irq_set_pri(TX4939_IR_TMR(i), 6);
 205        for (i = 0; i < TX4939_NUM_IR_SIO; i++)
 206                tx4939_irq_set_pri(TX4939_IR_SIO(i), 5);
 207}
 208
 209int tx4939_irq(void)
 210{
 211        u32 csr = __raw_readl(&tx4939_ircptr->cs.r);
 212
 213        if (likely(!(csr & TXx9_IRCSR_IF)))
 214                return TXX9_IRQ_BASE + (csr & (TX4939_NUM_IR - 1));
 215        return -1;
 216}
 217