Path: blob/master/arch/mips/txx9/generic/irq_tx4939.c
10818 views
/*1* TX4939 irq routines2* Based on linux/arch/mips/kernel/irq_txx9.c,3* and RBTX49xx patch from CELF patch archive.4*5* Copyright 2001, 2003-2005 MontaVista Software Inc.6* Author: MontaVista Software, Inc.7* [email protected]8* [email protected]9* Copyright (C) 2000-2001,2005-2007 Toshiba Corporation10*11* This file is subject to the terms and conditions of the GNU General Public12* License. See the file "COPYING" in the main directory of this archive13* for more details.14*/15/*16* TX4939 defines 64 IRQs.17* Similer to irq_txx9.c but different register layouts.18*/19#include <linux/init.h>20#include <linux/interrupt.h>21#include <linux/irq.h>22#include <linux/types.h>23#include <asm/irq_cpu.h>24#include <asm/txx9irq.h>25#include <asm/txx9/tx4939.h>2627/* IRCER : Int. Control Enable */28#define TXx9_IRCER_ICE 0x000000012930/* IRCR : Int. Control */31#define TXx9_IRCR_LOW 0x0000000032#define TXx9_IRCR_HIGH 0x0000000133#define TXx9_IRCR_DOWN 0x0000000234#define TXx9_IRCR_UP 0x0000000335#define TXx9_IRCR_EDGE(cr) ((cr) & 0x00000002)3637/* IRSCR : Int. Status Control */38#define TXx9_IRSCR_EIClrE 0x0000010039#define TXx9_IRSCR_EIClr_MASK 0x0000000f4041/* IRCSR : Int. Current Status */42#define TXx9_IRCSR_IF 0x000100004344#define irc_dlevel 045#define irc_elevel 14647static struct {48unsigned char level;49unsigned char mode;50} tx4939irq[TX4939_NUM_IR] __read_mostly;5152static void tx4939_irq_unmask(struct irq_data *d)53{54unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;55u32 __iomem *lvlp;56int ofs;57if (irq_nr < 32) {58irq_nr--;59lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r;60} else {61irq_nr -= 32;62lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r;63}64ofs = (irq_nr & 16) + (irq_nr & 1) * 8;65__raw_writel((__raw_readl(lvlp) & ~(0xff << ofs))66| (tx4939irq[irq_nr].level << ofs),67lvlp);68}6970static inline void tx4939_irq_mask(struct irq_data *d)71{72unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;73u32 __iomem *lvlp;74int ofs;75if (irq_nr < 32) {76irq_nr--;77lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r;78} else {79irq_nr -= 32;80lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r;81}82ofs = (irq_nr & 16) + (irq_nr & 1) * 8;83__raw_writel((__raw_readl(lvlp) & ~(0xff << ofs))84| (irc_dlevel << ofs),85lvlp);86mmiowb();87}8889static void tx4939_irq_mask_ack(struct irq_data *d)90{91unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;9293tx4939_irq_mask(d);94if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) {95irq_nr--;96/* clear edge detection */97__raw_writel((TXx9_IRSCR_EIClrE | (irq_nr & 0xf))98<< (irq_nr & 0x10),99&tx4939_ircptr->edc.r);100}101}102103static int tx4939_irq_set_type(struct irq_data *d, unsigned int flow_type)104{105unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;106u32 cr;107u32 __iomem *crp;108int ofs;109int mode;110111if (flow_type & IRQF_TRIGGER_PROBE)112return 0;113switch (flow_type & IRQF_TRIGGER_MASK) {114case IRQF_TRIGGER_RISING:115mode = TXx9_IRCR_UP;116break;117case IRQF_TRIGGER_FALLING:118mode = TXx9_IRCR_DOWN;119break;120case IRQF_TRIGGER_HIGH:121mode = TXx9_IRCR_HIGH;122break;123case IRQF_TRIGGER_LOW:124mode = TXx9_IRCR_LOW;125break;126default:127return -EINVAL;128}129if (irq_nr < 32) {130irq_nr--;131crp = &tx4939_ircptr->dm[(irq_nr & 8) >> 3].r;132} else {133irq_nr -= 32;134crp = &tx4939_ircptr->dm2[((irq_nr & 8) >> 3)].r;135}136ofs = (((irq_nr & 16) >> 1) | (irq_nr & (8 - 1))) * 2;137cr = __raw_readl(crp);138cr &= ~(0x3 << ofs);139cr |= (mode & 0x3) << ofs;140__raw_writel(cr, crp);141tx4939irq[irq_nr].mode = mode;142return 0;143}144145static struct irq_chip tx4939_irq_chip = {146.name = "TX4939",147.irq_ack = tx4939_irq_mask_ack,148.irq_mask = tx4939_irq_mask,149.irq_mask_ack = tx4939_irq_mask_ack,150.irq_unmask = tx4939_irq_unmask,151.irq_set_type = tx4939_irq_set_type,152};153154static int tx4939_irq_set_pri(int irc_irq, int new_pri)155{156int old_pri;157158if ((unsigned int)irc_irq >= TX4939_NUM_IR)159return 0;160old_pri = tx4939irq[irc_irq].level;161tx4939irq[irc_irq].level = new_pri;162return old_pri;163}164165void __init tx4939_irq_init(void)166{167int i;168169mips_cpu_irq_init();170/* disable interrupt control */171__raw_writel(0, &tx4939_ircptr->den.r);172__raw_writel(0, &tx4939_ircptr->maskint.r);173__raw_writel(0, &tx4939_ircptr->maskext.r);174/* irq_base + 0 is not used */175for (i = 1; i < TX4939_NUM_IR; i++) {176tx4939irq[i].level = 4; /* middle level */177tx4939irq[i].mode = TXx9_IRCR_LOW;178irq_set_chip_and_handler(TXX9_IRQ_BASE + i, &tx4939_irq_chip,179handle_level_irq);180}181182/* mask all IRC interrupts */183__raw_writel(0, &tx4939_ircptr->msk.r);184for (i = 0; i < 16; i++)185__raw_writel(0, &tx4939_ircptr->lvl[i].r);186/* setup IRC interrupt mode (Low Active) */187for (i = 0; i < 2; i++)188__raw_writel(0, &tx4939_ircptr->dm[i].r);189for (i = 0; i < 2; i++)190__raw_writel(0, &tx4939_ircptr->dm2[i].r);191/* enable interrupt control */192__raw_writel(TXx9_IRCER_ICE, &tx4939_ircptr->den.r);193__raw_writel(irc_elevel, &tx4939_ircptr->msk.r);194195irq_set_chained_handler(MIPS_CPU_IRQ_BASE + TX4939_IRC_INT,196handle_simple_irq);197198/* raise priority for errors, timers, sio */199tx4939_irq_set_pri(TX4939_IR_WTOERR, 7);200tx4939_irq_set_pri(TX4939_IR_PCIERR, 7);201tx4939_irq_set_pri(TX4939_IR_PCIPME, 7);202for (i = 0; i < TX4939_NUM_IR_TMR; i++)203tx4939_irq_set_pri(TX4939_IR_TMR(i), 6);204for (i = 0; i < TX4939_NUM_IR_SIO; i++)205tx4939_irq_set_pri(TX4939_IR_SIO(i), 5);206}207208int tx4939_irq(void)209{210u32 csr = __raw_readl(&tx4939_ircptr->cs.r);211212if (likely(!(csr & TXx9_IRCSR_IF)))213return TXX9_IRQ_BASE + (csr & (TX4939_NUM_IR - 1));214return -1;215}216217218