Path: blob/master/arch/sh/boards/mach-cayman/irq.c
15126 views
/*1* arch/sh/mach-cayman/irq.c - SH-5 Cayman Interrupt Support2*3* This file handles the board specific parts of the Cayman interrupt system4*5* Copyright (C) 2002 Stuart Menefy6*7* This file is subject to the terms and conditions of the GNU General Public8* License. See the file "COPYING" in the main directory of this archive9* for more details.10*/11#include <linux/io.h>12#include <linux/irq.h>13#include <linux/interrupt.h>14#include <linux/signal.h>15#include <cpu/irq.h>16#include <asm/page.h>1718/* Setup for the SMSC FDC37C935 / LAN91C100FD */19#define SMSC_IRQ IRQ_IRL12021/* Setup for PCI Bus 2, which transmits interrupts via the EPLD */22#define PCI2_IRQ IRQ_IRL32324unsigned long epld_virt;2526#define EPLD_BASE 0x0400200027#define EPLD_STATUS_BASE (epld_virt + 0x10)28#define EPLD_MASK_BASE (epld_virt + 0x20)2930/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto31the same SH-5 interrupt */3233static irqreturn_t cayman_interrupt_smsc(int irq, void *dev_id)34{35printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n");36return IRQ_NONE;37}3839static irqreturn_t cayman_interrupt_pci2(int irq, void *dev_id)40{41printk(KERN_INFO "CAYMAN: spurious PCI interrupt, IRQ %d\n", irq);42return IRQ_NONE;43}4445static struct irqaction cayman_action_smsc = {46.name = "Cayman SMSC Mux",47.handler = cayman_interrupt_smsc,48.flags = IRQF_DISABLED,49};5051static struct irqaction cayman_action_pci2 = {52.name = "Cayman PCI2 Mux",53.handler = cayman_interrupt_pci2,54.flags = IRQF_DISABLED,55};5657static void enable_cayman_irq(struct irq_data *data)58{59unsigned int irq = data->irq;60unsigned long flags;61unsigned long mask;62unsigned int reg;63unsigned char bit;6465irq -= START_EXT_IRQS;66reg = EPLD_MASK_BASE + ((irq / 8) << 2);67bit = 1<<(irq % 8);68local_irq_save(flags);69mask = __raw_readl(reg);70mask |= bit;71__raw_writel(mask, reg);72local_irq_restore(flags);73}7475static void disable_cayman_irq(struct irq_data *data)76{77unsigned int irq = data->irq;78unsigned long flags;79unsigned long mask;80unsigned int reg;81unsigned char bit;8283irq -= START_EXT_IRQS;84reg = EPLD_MASK_BASE + ((irq / 8) << 2);85bit = 1<<(irq % 8);86local_irq_save(flags);87mask = __raw_readl(reg);88mask &= ~bit;89__raw_writel(mask, reg);90local_irq_restore(flags);91}9293struct irq_chip cayman_irq_type = {94.name = "Cayman-IRQ",95.irq_unmask = enable_cayman_irq,96.irq_mask = disable_cayman_irq,97};9899int cayman_irq_demux(int evt)100{101int irq = intc_evt_to_irq[evt];102103if (irq == SMSC_IRQ) {104unsigned long status;105int i;106107status = __raw_readl(EPLD_STATUS_BASE) &108__raw_readl(EPLD_MASK_BASE) & 0xff;109if (status == 0) {110irq = -1;111} else {112for (i=0; i<8; i++) {113if (status & (1<<i))114break;115}116irq = START_EXT_IRQS + i;117}118}119120if (irq == PCI2_IRQ) {121unsigned long status;122int i;123124status = __raw_readl(EPLD_STATUS_BASE + 3 * sizeof(u32)) &125__raw_readl(EPLD_MASK_BASE + 3 * sizeof(u32)) & 0xff;126if (status == 0) {127irq = -1;128} else {129for (i=0; i<8; i++) {130if (status & (1<<i))131break;132}133irq = START_EXT_IRQS + (3 * 8) + i;134}135}136137return irq;138}139140void init_cayman_irq(void)141{142int i;143144epld_virt = (unsigned long)ioremap_nocache(EPLD_BASE, 1024);145if (!epld_virt) {146printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n");147return;148}149150for (i = 0; i < NR_EXT_IRQS; i++) {151irq_set_chip_and_handler(START_EXT_IRQS + i,152&cayman_irq_type, handle_level_irq);153}154155/* Setup the SMSC interrupt */156setup_irq(SMSC_IRQ, &cayman_action_smsc);157setup_irq(PCI2_IRQ, &cayman_action_pci2);158}159160161