linux/arch/mips/kernel/irq_txx9.c
<<
>>
Prefs
   1/*
   2 * linux/arch/mips/kernel/irq_txx9.c
   3 *
   4 * Based on linux/arch/mips/jmr3927/rbhma3100/irq.c,
   5 *          linux/arch/mips/tx4927/common/tx4927_irq.c,
   6 *          linux/arch/mips/tx4938/common/irq.c
   7 *
   8 * Copyright 2001, 2003-2005 MontaVista Software Inc.
   9 * Author: MontaVista Software, Inc.
  10 *         ahennessy@mvista.com
  11 *         source@mvista.com
  12 * Copyright (C) 2000-2001 Toshiba Corporation
  13 *
  14 * This file is subject to the terms and conditions of the GNU General Public
  15 * License.  See the file "COPYING" in the main directory of this archive
  16 * for more details.
  17 */
  18#include <linux/init.h>
  19#include <linux/interrupt.h>
  20#include <linux/types.h>
  21#include <asm/txx9irq.h>
  22
  23struct txx9_irc_reg {
  24        u32 cer;
  25        u32 cr[2];
  26        u32 unused0;
  27        u32 ilr[8];
  28        u32 unused1[4];
  29        u32 imr;
  30        u32 unused2[7];
  31        u32 scr;
  32        u32 unused3[7];
  33        u32 ssr;
  34        u32 unused4[7];
  35        u32 csr;
  36};
  37
  38/* IRCER : Int. Control Enable */
  39#define TXx9_IRCER_ICE  0x00000001
  40
  41/* IRCR : Int. Control */
  42#define TXx9_IRCR_LOW   0x00000000
  43#define TXx9_IRCR_HIGH  0x00000001
  44#define TXx9_IRCR_DOWN  0x00000002
  45#define TXx9_IRCR_UP    0x00000003
  46#define TXx9_IRCR_EDGE(cr)      ((cr) & 0x00000002)
  47
  48/* IRSCR : Int. Status Control */
  49#define TXx9_IRSCR_EIClrE       0x00000100
  50#define TXx9_IRSCR_EIClr_MASK   0x0000000f
  51
  52/* IRCSR : Int. Current Status */
  53#define TXx9_IRCSR_IF   0x00010000
  54#define TXx9_IRCSR_ILV_MASK     0x00000700
  55#define TXx9_IRCSR_IVL_MASK     0x0000001f
  56
  57#define irc_dlevel      0
  58#define irc_elevel      1
  59
  60static struct txx9_irc_reg __iomem *txx9_ircptr __read_mostly;
  61
  62static struct {
  63        unsigned char level;
  64        unsigned char mode;
  65} txx9irq[TXx9_MAX_IR] __read_mostly;
  66
  67static void txx9_irq_unmask(unsigned int irq)
  68{
  69        unsigned int irq_nr = irq - TXX9_IRQ_BASE;
  70        u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2];
  71        int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8;
  72
  73        __raw_writel((__raw_readl(ilrp) & ~(0xff << ofs))
  74                     | (txx9irq[irq_nr].level << ofs),
  75                     ilrp);
  76#ifdef CONFIG_CPU_TX39XX
  77        /* update IRCSR */
  78        __raw_writel(0, &txx9_ircptr->imr);
  79        __raw_writel(irc_elevel, &txx9_ircptr->imr);
  80#endif
  81}
  82
  83static inline void txx9_irq_mask(unsigned int irq)
  84{
  85        unsigned int irq_nr = irq - TXX9_IRQ_BASE;
  86        u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2];
  87        int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8;
  88
  89        __raw_writel((__raw_readl(ilrp) & ~(0xff << ofs))
  90                     | (irc_dlevel << ofs),
  91                     ilrp);
  92#ifdef CONFIG_CPU_TX39XX
  93        /* update IRCSR */
  94        __raw_writel(0, &txx9_ircptr->imr);
  95        __raw_writel(irc_elevel, &txx9_ircptr->imr);
  96        /* flush write buffer */
  97        __raw_readl(&txx9_ircptr->ssr);
  98#else
  99        mmiowb();
 100#endif
 101}
 102
 103static void txx9_irq_mask_ack(unsigned int irq)
 104{
 105        unsigned int irq_nr = irq - TXX9_IRQ_BASE;
 106
 107        txx9_irq_mask(irq);
 108        /* clear edge detection */
 109        if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode)))
 110                __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr);
 111}
 112
 113static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type)
 114{
 115        unsigned int irq_nr = irq - TXX9_IRQ_BASE;
 116        u32 cr;
 117        u32 __iomem *crp;
 118        int ofs;
 119        int mode;
 120
 121        if (flow_type & IRQF_TRIGGER_PROBE)
 122                return 0;
 123        switch (flow_type & IRQF_TRIGGER_MASK) {
 124        case IRQF_TRIGGER_RISING:       mode = TXx9_IRCR_UP;    break;
 125        case IRQF_TRIGGER_FALLING:      mode = TXx9_IRCR_DOWN;  break;
 126        case IRQF_TRIGGER_HIGH: mode = TXx9_IRCR_HIGH;  break;
 127        case IRQF_TRIGGER_LOW:  mode = TXx9_IRCR_LOW;   break;
 128        default:
 129                return -EINVAL;
 130        }
 131        crp = &txx9_ircptr->cr[(unsigned int)irq_nr / 8];
 132        cr = __raw_readl(crp);
 133        ofs = (irq_nr & (8 - 1)) * 2;
 134        cr &= ~(0x3 << ofs);
 135        cr |= (mode & 0x3) << ofs;
 136        __raw_writel(cr, crp);
 137        txx9irq[irq_nr].mode = mode;
 138        return 0;
 139}
 140
 141static struct irq_chip txx9_irq_chip = {
 142        .name           = "TXX9",
 143        .ack            = txx9_irq_mask_ack,
 144        .mask           = txx9_irq_mask,
 145        .mask_ack       = txx9_irq_mask_ack,
 146        .unmask         = txx9_irq_unmask,
 147        .set_type       = txx9_irq_set_type,
 148};
 149
 150void __init txx9_irq_init(unsigned long baseaddr)
 151{
 152        int i;
 153
 154        txx9_ircptr = ioremap(baseaddr, sizeof(struct txx9_irc_reg));
 155        for (i = 0; i < TXx9_MAX_IR; i++) {
 156                txx9irq[i].level = 4; /* middle level */
 157                txx9irq[i].mode = TXx9_IRCR_LOW;
 158                set_irq_chip_and_handler(TXX9_IRQ_BASE + i,
 159                                         &txx9_irq_chip, handle_level_irq);
 160        }
 161
 162        /* mask all IRC interrupts */
 163        __raw_writel(0, &txx9_ircptr->imr);
 164        for (i = 0; i < 8; i++)
 165                __raw_writel(0, &txx9_ircptr->ilr[i]);
 166        /* setup IRC interrupt mode (Low Active) */
 167        for (i = 0; i < 2; i++)
 168                __raw_writel(0, &txx9_ircptr->cr[i]);
 169        /* enable interrupt control */
 170        __raw_writel(TXx9_IRCER_ICE, &txx9_ircptr->cer);
 171        __raw_writel(irc_elevel, &txx9_ircptr->imr);
 172}
 173
 174int __init txx9_irq_set_pri(int irc_irq, int new_pri)
 175{
 176        int old_pri;
 177
 178        if ((unsigned int)irc_irq >= TXx9_MAX_IR)
 179                return 0;
 180        old_pri = txx9irq[irc_irq].level;
 181        txx9irq[irc_irq].level = new_pri;
 182        return old_pri;
 183}
 184
 185int txx9_irq(void)
 186{
 187        u32 csr = __raw_readl(&txx9_ircptr->csr);
 188
 189        if (likely(!(csr & TXx9_IRCSR_IF)))
 190                return TXX9_IRQ_BASE + (csr & (TXx9_MAX_IR - 1));
 191        return -1;
 192}
 193