18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * TX4939 irq routines 38c2ecf20Sopenharmony_ci * Based on linux/arch/mips/kernel/irq_txx9.c, 48c2ecf20Sopenharmony_ci * and RBTX49xx patch from CELF patch archive. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2001, 2003-2005 MontaVista Software Inc. 78c2ecf20Sopenharmony_ci * Author: MontaVista Software, Inc. 88c2ecf20Sopenharmony_ci * ahennessy@mvista.com 98c2ecf20Sopenharmony_ci * source@mvista.com 108c2ecf20Sopenharmony_ci * Copyright (C) 2000-2001,2005-2007 Toshiba Corporation 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 138c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 148c2ecf20Sopenharmony_ci * for more details. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * TX4939 defines 64 IRQs. 188c2ecf20Sopenharmony_ci * Similer to irq_txx9.c but different register layouts. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/irq.h> 238c2ecf20Sopenharmony_ci#include <linux/types.h> 248c2ecf20Sopenharmony_ci#include <asm/irq_cpu.h> 258c2ecf20Sopenharmony_ci#include <asm/txx9irq.h> 268c2ecf20Sopenharmony_ci#include <asm/txx9/tx4939.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* IRCER : Int. Control Enable */ 298c2ecf20Sopenharmony_ci#define TXx9_IRCER_ICE 0x00000001 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* IRCR : Int. Control */ 328c2ecf20Sopenharmony_ci#define TXx9_IRCR_LOW 0x00000000 338c2ecf20Sopenharmony_ci#define TXx9_IRCR_HIGH 0x00000001 348c2ecf20Sopenharmony_ci#define TXx9_IRCR_DOWN 0x00000002 358c2ecf20Sopenharmony_ci#define TXx9_IRCR_UP 0x00000003 368c2ecf20Sopenharmony_ci#define TXx9_IRCR_EDGE(cr) ((cr) & 0x00000002) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* IRSCR : Int. Status Control */ 398c2ecf20Sopenharmony_ci#define TXx9_IRSCR_EIClrE 0x00000100 408c2ecf20Sopenharmony_ci#define TXx9_IRSCR_EIClr_MASK 0x0000000f 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* IRCSR : Int. Current Status */ 438c2ecf20Sopenharmony_ci#define TXx9_IRCSR_IF 0x00010000 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define irc_dlevel 0 468c2ecf20Sopenharmony_ci#define irc_elevel 1 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic struct { 498c2ecf20Sopenharmony_ci unsigned char level; 508c2ecf20Sopenharmony_ci unsigned char mode; 518c2ecf20Sopenharmony_ci} tx4939irq[TX4939_NUM_IR] __read_mostly; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void tx4939_irq_unmask(struct irq_data *d) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; 568c2ecf20Sopenharmony_ci u32 __iomem *lvlp; 578c2ecf20Sopenharmony_ci int ofs; 588c2ecf20Sopenharmony_ci if (irq_nr < 32) { 598c2ecf20Sopenharmony_ci irq_nr--; 608c2ecf20Sopenharmony_ci lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r; 618c2ecf20Sopenharmony_ci } else { 628c2ecf20Sopenharmony_ci irq_nr -= 32; 638c2ecf20Sopenharmony_ci lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci ofs = (irq_nr & 16) + (irq_nr & 1) * 8; 668c2ecf20Sopenharmony_ci __raw_writel((__raw_readl(lvlp) & ~(0xff << ofs)) 678c2ecf20Sopenharmony_ci | (tx4939irq[irq_nr].level << ofs), 688c2ecf20Sopenharmony_ci lvlp); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic inline void tx4939_irq_mask(struct irq_data *d) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; 748c2ecf20Sopenharmony_ci u32 __iomem *lvlp; 758c2ecf20Sopenharmony_ci int ofs; 768c2ecf20Sopenharmony_ci if (irq_nr < 32) { 778c2ecf20Sopenharmony_ci irq_nr--; 788c2ecf20Sopenharmony_ci lvlp = &tx4939_ircptr->lvl[(irq_nr % 16) / 2].r; 798c2ecf20Sopenharmony_ci } else { 808c2ecf20Sopenharmony_ci irq_nr -= 32; 818c2ecf20Sopenharmony_ci lvlp = &tx4939_ircptr->lvl[8 + (irq_nr % 16) / 2].r; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci ofs = (irq_nr & 16) + (irq_nr & 1) * 8; 848c2ecf20Sopenharmony_ci __raw_writel((__raw_readl(lvlp) & ~(0xff << ofs)) 858c2ecf20Sopenharmony_ci | (irc_dlevel << ofs), 868c2ecf20Sopenharmony_ci lvlp); 878c2ecf20Sopenharmony_ci mmiowb(); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void tx4939_irq_mask_ack(struct irq_data *d) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci tx4939_irq_mask(d); 958c2ecf20Sopenharmony_ci if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) { 968c2ecf20Sopenharmony_ci irq_nr--; 978c2ecf20Sopenharmony_ci /* clear edge detection */ 988c2ecf20Sopenharmony_ci __raw_writel((TXx9_IRSCR_EIClrE | (irq_nr & 0xf)) 998c2ecf20Sopenharmony_ci << (irq_nr & 0x10), 1008c2ecf20Sopenharmony_ci &tx4939_ircptr->edc.r); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int tx4939_irq_set_type(struct irq_data *d, unsigned int flow_type) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; 1078c2ecf20Sopenharmony_ci u32 cr; 1088c2ecf20Sopenharmony_ci u32 __iomem *crp; 1098c2ecf20Sopenharmony_ci int ofs; 1108c2ecf20Sopenharmony_ci int mode; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (flow_type & IRQF_TRIGGER_PROBE) 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci switch (flow_type & IRQF_TRIGGER_MASK) { 1158c2ecf20Sopenharmony_ci case IRQF_TRIGGER_RISING: 1168c2ecf20Sopenharmony_ci mode = TXx9_IRCR_UP; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case IRQF_TRIGGER_FALLING: 1198c2ecf20Sopenharmony_ci mode = TXx9_IRCR_DOWN; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case IRQF_TRIGGER_HIGH: 1228c2ecf20Sopenharmony_ci mode = TXx9_IRCR_HIGH; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci case IRQF_TRIGGER_LOW: 1258c2ecf20Sopenharmony_ci mode = TXx9_IRCR_LOW; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci default: 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci if (irq_nr < 32) { 1318c2ecf20Sopenharmony_ci irq_nr--; 1328c2ecf20Sopenharmony_ci crp = &tx4939_ircptr->dm[(irq_nr & 8) >> 3].r; 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci irq_nr -= 32; 1358c2ecf20Sopenharmony_ci crp = &tx4939_ircptr->dm2[((irq_nr & 8) >> 3)].r; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci ofs = (((irq_nr & 16) >> 1) | (irq_nr & (8 - 1))) * 2; 1388c2ecf20Sopenharmony_ci cr = __raw_readl(crp); 1398c2ecf20Sopenharmony_ci cr &= ~(0x3 << ofs); 1408c2ecf20Sopenharmony_ci cr |= (mode & 0x3) << ofs; 1418c2ecf20Sopenharmony_ci __raw_writel(cr, crp); 1428c2ecf20Sopenharmony_ci tx4939irq[irq_nr].mode = mode; 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic struct irq_chip tx4939_irq_chip = { 1478c2ecf20Sopenharmony_ci .name = "TX4939", 1488c2ecf20Sopenharmony_ci .irq_ack = tx4939_irq_mask_ack, 1498c2ecf20Sopenharmony_ci .irq_mask = tx4939_irq_mask, 1508c2ecf20Sopenharmony_ci .irq_mask_ack = tx4939_irq_mask_ack, 1518c2ecf20Sopenharmony_ci .irq_unmask = tx4939_irq_unmask, 1528c2ecf20Sopenharmony_ci .irq_set_type = tx4939_irq_set_type, 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int tx4939_irq_set_pri(int irc_irq, int new_pri) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int old_pri; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if ((unsigned int)irc_irq >= TX4939_NUM_IR) 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci old_pri = tx4939irq[irc_irq].level; 1628c2ecf20Sopenharmony_ci tx4939irq[irc_irq].level = new_pri; 1638c2ecf20Sopenharmony_ci return old_pri; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid __init tx4939_irq_init(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int i; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mips_cpu_irq_init(); 1718c2ecf20Sopenharmony_ci /* disable interrupt control */ 1728c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->den.r); 1738c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->maskint.r); 1748c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->maskext.r); 1758c2ecf20Sopenharmony_ci /* irq_base + 0 is not used */ 1768c2ecf20Sopenharmony_ci for (i = 1; i < TX4939_NUM_IR; i++) { 1778c2ecf20Sopenharmony_ci tx4939irq[i].level = 4; /* middle level */ 1788c2ecf20Sopenharmony_ci tx4939irq[i].mode = TXx9_IRCR_LOW; 1798c2ecf20Sopenharmony_ci irq_set_chip_and_handler(TXX9_IRQ_BASE + i, &tx4939_irq_chip, 1808c2ecf20Sopenharmony_ci handle_level_irq); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* mask all IRC interrupts */ 1848c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->msk.r); 1858c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 1868c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->lvl[i].r); 1878c2ecf20Sopenharmony_ci /* setup IRC interrupt mode (Low Active) */ 1888c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 1898c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->dm[i].r); 1908c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 1918c2ecf20Sopenharmony_ci __raw_writel(0, &tx4939_ircptr->dm2[i].r); 1928c2ecf20Sopenharmony_ci /* enable interrupt control */ 1938c2ecf20Sopenharmony_ci __raw_writel(TXx9_IRCER_ICE, &tx4939_ircptr->den.r); 1948c2ecf20Sopenharmony_ci __raw_writel(irc_elevel, &tx4939_ircptr->msk.r); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + TX4939_IRC_INT, 1978c2ecf20Sopenharmony_ci handle_simple_irq); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* raise priority for errors, timers, sio */ 2008c2ecf20Sopenharmony_ci tx4939_irq_set_pri(TX4939_IR_WTOERR, 7); 2018c2ecf20Sopenharmony_ci tx4939_irq_set_pri(TX4939_IR_PCIERR, 7); 2028c2ecf20Sopenharmony_ci tx4939_irq_set_pri(TX4939_IR_PCIPME, 7); 2038c2ecf20Sopenharmony_ci for (i = 0; i < TX4939_NUM_IR_TMR; i++) 2048c2ecf20Sopenharmony_ci tx4939_irq_set_pri(TX4939_IR_TMR(i), 6); 2058c2ecf20Sopenharmony_ci for (i = 0; i < TX4939_NUM_IR_SIO; i++) 2068c2ecf20Sopenharmony_ci tx4939_irq_set_pri(TX4939_IR_SIO(i), 5); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciint tx4939_irq(void) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci u32 csr = __raw_readl(&tx4939_ircptr->cs.r); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (likely(!(csr & TXx9_IRCSR_IF))) 2148c2ecf20Sopenharmony_ci return TXX9_IRQ_BASE + (csr & (TX4939_NUM_IR - 1)); 2158c2ecf20Sopenharmony_ci return -1; 2168c2ecf20Sopenharmony_ci} 217