13b59b6beSTony Lindgren /* 2*7c38cf02STony Lindgren * linux/arch/arm/mach-omap1/irq.c 33b59b6beSTony Lindgren * 43b59b6beSTony Lindgren * Interrupt handler for all OMAP boards 53b59b6beSTony Lindgren * 63b59b6beSTony Lindgren * Copyright (C) 2004 Nokia Corporation 73b59b6beSTony Lindgren * Written by Tony Lindgren <tony@atomide.com> 83b59b6beSTony Lindgren * Major cleanups by Juha Yrj�l� <juha.yrjola@nokia.com> 93b59b6beSTony Lindgren * 103b59b6beSTony Lindgren * Completely re-written to support various OMAP chips with bank specific 113b59b6beSTony Lindgren * interrupt handlers. 123b59b6beSTony Lindgren * 133b59b6beSTony Lindgren * Some snippets of the code taken from the older OMAP interrupt handler 143b59b6beSTony Lindgren * Copyright (C) 2001 RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com> 153b59b6beSTony Lindgren * 163b59b6beSTony Lindgren * GPIO interrupt handler moved to gpio.c by Juha Yrjola 173b59b6beSTony Lindgren * 183b59b6beSTony Lindgren * This program is free software; you can redistribute it and/or modify it 193b59b6beSTony Lindgren * under the terms of the GNU General Public License as published by the 203b59b6beSTony Lindgren * Free Software Foundation; either version 2 of the License, or (at your 213b59b6beSTony Lindgren * option) any later version. 223b59b6beSTony Lindgren * 233b59b6beSTony Lindgren * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 243b59b6beSTony Lindgren * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 253b59b6beSTony Lindgren * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 263b59b6beSTony Lindgren * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 273b59b6beSTony Lindgren * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 283b59b6beSTony Lindgren * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 293b59b6beSTony Lindgren * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 303b59b6beSTony Lindgren * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 313b59b6beSTony Lindgren * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 323b59b6beSTony Lindgren * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 333b59b6beSTony Lindgren * 343b59b6beSTony Lindgren * You should have received a copy of the GNU General Public License along 353b59b6beSTony Lindgren * with this program; if not, write to the Free Software Foundation, Inc., 363b59b6beSTony Lindgren * 675 Mass Ave, Cambridge, MA 02139, USA. 373b59b6beSTony Lindgren */ 383b59b6beSTony Lindgren 393b59b6beSTony Lindgren #include <linux/config.h> 403b59b6beSTony Lindgren #include <linux/init.h> 413b59b6beSTony Lindgren #include <linux/module.h> 423b59b6beSTony Lindgren #include <linux/sched.h> 433b59b6beSTony Lindgren #include <linux/interrupt.h> 443b59b6beSTony Lindgren #include <linux/ptrace.h> 453b59b6beSTony Lindgren 463b59b6beSTony Lindgren #include <asm/hardware.h> 473b59b6beSTony Lindgren #include <asm/irq.h> 483b59b6beSTony Lindgren #include <asm/mach/irq.h> 493b59b6beSTony Lindgren #include <asm/arch/gpio.h> 503b59b6beSTony Lindgren 513b59b6beSTony Lindgren #include <asm/io.h> 523b59b6beSTony Lindgren 533b59b6beSTony Lindgren #define IRQ_BANK(irq) ((irq) >> 5) 543b59b6beSTony Lindgren #define IRQ_BIT(irq) ((irq) & 0x1f) 553b59b6beSTony Lindgren 563b59b6beSTony Lindgren struct omap_irq_bank { 573b59b6beSTony Lindgren unsigned long base_reg; 583b59b6beSTony Lindgren unsigned long trigger_map; 593b59b6beSTony Lindgren unsigned long wake_enable; 603b59b6beSTony Lindgren }; 613b59b6beSTony Lindgren 623b59b6beSTony Lindgren static unsigned int irq_bank_count = 0; 633b59b6beSTony Lindgren static struct omap_irq_bank *irq_banks; 643b59b6beSTony Lindgren 653b59b6beSTony Lindgren static inline unsigned int irq_bank_readl(int bank, int offset) 663b59b6beSTony Lindgren { 673b59b6beSTony Lindgren return omap_readl(irq_banks[bank].base_reg + offset); 683b59b6beSTony Lindgren } 693b59b6beSTony Lindgren 703b59b6beSTony Lindgren static inline void irq_bank_writel(unsigned long value, int bank, int offset) 713b59b6beSTony Lindgren { 723b59b6beSTony Lindgren omap_writel(value, irq_banks[bank].base_reg + offset); 733b59b6beSTony Lindgren } 743b59b6beSTony Lindgren 753b59b6beSTony Lindgren static void omap_ack_irq(unsigned int irq) 763b59b6beSTony Lindgren { 773b59b6beSTony Lindgren if (irq > 31) 783b59b6beSTony Lindgren omap_writel(0x1, OMAP_IH2_BASE + IRQ_CONTROL_REG_OFFSET); 793b59b6beSTony Lindgren 803b59b6beSTony Lindgren omap_writel(0x1, OMAP_IH1_BASE + IRQ_CONTROL_REG_OFFSET); 813b59b6beSTony Lindgren } 823b59b6beSTony Lindgren 833b59b6beSTony Lindgren static void omap_mask_irq(unsigned int irq) 843b59b6beSTony Lindgren { 853b59b6beSTony Lindgren int bank = IRQ_BANK(irq); 863b59b6beSTony Lindgren u32 l; 873b59b6beSTony Lindgren 883b59b6beSTony Lindgren l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); 893b59b6beSTony Lindgren l |= 1 << IRQ_BIT(irq); 903b59b6beSTony Lindgren omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); 913b59b6beSTony Lindgren } 923b59b6beSTony Lindgren 933b59b6beSTony Lindgren static void omap_unmask_irq(unsigned int irq) 943b59b6beSTony Lindgren { 953b59b6beSTony Lindgren int bank = IRQ_BANK(irq); 963b59b6beSTony Lindgren u32 l; 973b59b6beSTony Lindgren 983b59b6beSTony Lindgren l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); 993b59b6beSTony Lindgren l &= ~(1 << IRQ_BIT(irq)); 1003b59b6beSTony Lindgren omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); 1013b59b6beSTony Lindgren } 1023b59b6beSTony Lindgren 1033b59b6beSTony Lindgren static void omap_mask_ack_irq(unsigned int irq) 1043b59b6beSTony Lindgren { 1053b59b6beSTony Lindgren omap_mask_irq(irq); 1063b59b6beSTony Lindgren omap_ack_irq(irq); 1073b59b6beSTony Lindgren } 1083b59b6beSTony Lindgren 1093b59b6beSTony Lindgren static int omap_wake_irq(unsigned int irq, unsigned int enable) 1103b59b6beSTony Lindgren { 1113b59b6beSTony Lindgren int bank = IRQ_BANK(irq); 1123b59b6beSTony Lindgren 1133b59b6beSTony Lindgren if (enable) 1143b59b6beSTony Lindgren irq_banks[bank].wake_enable |= IRQ_BIT(irq); 1153b59b6beSTony Lindgren else 1163b59b6beSTony Lindgren irq_banks[bank].wake_enable &= ~IRQ_BIT(irq); 1173b59b6beSTony Lindgren 1183b59b6beSTony Lindgren return 0; 1193b59b6beSTony Lindgren } 1203b59b6beSTony Lindgren 1213b59b6beSTony Lindgren 1223b59b6beSTony Lindgren /* 1233b59b6beSTony Lindgren * Allows tuning the IRQ type and priority 1243b59b6beSTony Lindgren * 1253b59b6beSTony Lindgren * NOTE: There is currently no OMAP fiq handler for Linux. Read the 1263b59b6beSTony Lindgren * mailing list threads on FIQ handlers if you are planning to 1273b59b6beSTony Lindgren * add a FIQ handler for OMAP. 1283b59b6beSTony Lindgren */ 1293b59b6beSTony Lindgren static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger) 1303b59b6beSTony Lindgren { 1313b59b6beSTony Lindgren signed int bank; 1323b59b6beSTony Lindgren unsigned long val, offset; 1333b59b6beSTony Lindgren 1343b59b6beSTony Lindgren bank = IRQ_BANK(irq); 1353b59b6beSTony Lindgren /* FIQ is only available on bank 0 interrupts */ 1363b59b6beSTony Lindgren fiq = bank ? 0 : (fiq & 0x1); 1373b59b6beSTony Lindgren val = fiq | ((priority & 0x1f) << 2) | ((trigger & 0x1) << 1); 1383b59b6beSTony Lindgren offset = IRQ_ILR0_REG_OFFSET + IRQ_BIT(irq) * 0x4; 1393b59b6beSTony Lindgren irq_bank_writel(val, bank, offset); 1403b59b6beSTony Lindgren } 1413b59b6beSTony Lindgren 1423b59b6beSTony Lindgren #ifdef CONFIG_ARCH_OMAP730 1433b59b6beSTony Lindgren static struct omap_irq_bank omap730_irq_banks[] = { 1443b59b6beSTony Lindgren { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f }, 1453b59b6beSTony Lindgren { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 }, 1463b59b6beSTony Lindgren { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 }, 1473b59b6beSTony Lindgren }; 1483b59b6beSTony Lindgren #endif 1493b59b6beSTony Lindgren 1503b59b6beSTony Lindgren #ifdef CONFIG_ARCH_OMAP1510 1513b59b6beSTony Lindgren static struct omap_irq_bank omap1510_irq_banks[] = { 1523b59b6beSTony Lindgren { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, 1533b59b6beSTony Lindgren { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, 1543b59b6beSTony Lindgren }; 1553b59b6beSTony Lindgren #endif 1563b59b6beSTony Lindgren 1573b59b6beSTony Lindgren #if defined(CONFIG_ARCH_OMAP16XX) 1583b59b6beSTony Lindgren 1593b59b6beSTony Lindgren static struct omap_irq_bank omap1610_irq_banks[] = { 1603b59b6beSTony Lindgren { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, 1613b59b6beSTony Lindgren { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd }, 1623b59b6beSTony Lindgren { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff }, 1633b59b6beSTony Lindgren { .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff }, 1643b59b6beSTony Lindgren }; 1653b59b6beSTony Lindgren #endif 1663b59b6beSTony Lindgren 1673b59b6beSTony Lindgren static struct irqchip omap_irq_chip = { 1683b59b6beSTony Lindgren .ack = omap_mask_ack_irq, 1693b59b6beSTony Lindgren .mask = omap_mask_irq, 1703b59b6beSTony Lindgren .unmask = omap_unmask_irq, 1712be863c9SRussell King .set_wake = omap_wake_irq, 1723b59b6beSTony Lindgren }; 1733b59b6beSTony Lindgren 1743b59b6beSTony Lindgren void __init omap_init_irq(void) 1753b59b6beSTony Lindgren { 1763b59b6beSTony Lindgren int i, j; 1773b59b6beSTony Lindgren 1783b59b6beSTony Lindgren #ifdef CONFIG_ARCH_OMAP730 1793b59b6beSTony Lindgren if (cpu_is_omap730()) { 1803b59b6beSTony Lindgren irq_banks = omap730_irq_banks; 1813b59b6beSTony Lindgren irq_bank_count = ARRAY_SIZE(omap730_irq_banks); 1823b59b6beSTony Lindgren } 1833b59b6beSTony Lindgren #endif 1843b59b6beSTony Lindgren #ifdef CONFIG_ARCH_OMAP1510 1853b59b6beSTony Lindgren if (cpu_is_omap1510()) { 1863b59b6beSTony Lindgren irq_banks = omap1510_irq_banks; 1873b59b6beSTony Lindgren irq_bank_count = ARRAY_SIZE(omap1510_irq_banks); 1883b59b6beSTony Lindgren } 1893b59b6beSTony Lindgren #endif 1903b59b6beSTony Lindgren #if defined(CONFIG_ARCH_OMAP16XX) 1913b59b6beSTony Lindgren if (cpu_is_omap16xx()) { 1923b59b6beSTony Lindgren irq_banks = omap1610_irq_banks; 1933b59b6beSTony Lindgren irq_bank_count = ARRAY_SIZE(omap1610_irq_banks); 1943b59b6beSTony Lindgren } 1953b59b6beSTony Lindgren #endif 1963b59b6beSTony Lindgren printk("Total of %i interrupts in %i interrupt banks\n", 1973b59b6beSTony Lindgren irq_bank_count * 32, irq_bank_count); 1983b59b6beSTony Lindgren 1993b59b6beSTony Lindgren /* Mask and clear all interrupts */ 2003b59b6beSTony Lindgren for (i = 0; i < irq_bank_count; i++) { 2013b59b6beSTony Lindgren irq_bank_writel(~0x0, i, IRQ_MIR_REG_OFFSET); 2023b59b6beSTony Lindgren irq_bank_writel(0x0, i, IRQ_ITR_REG_OFFSET); 2033b59b6beSTony Lindgren } 2043b59b6beSTony Lindgren 2053b59b6beSTony Lindgren /* Clear any pending interrupts */ 2063b59b6beSTony Lindgren irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET); 2073b59b6beSTony Lindgren irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET); 2083b59b6beSTony Lindgren 2093b59b6beSTony Lindgren /* Enable interrupts in global mask */ 2103b59b6beSTony Lindgren if (cpu_is_omap730()) { 2113b59b6beSTony Lindgren irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET); 2123b59b6beSTony Lindgren } 2133b59b6beSTony Lindgren 2143b59b6beSTony Lindgren /* Install the interrupt handlers for each bank */ 2153b59b6beSTony Lindgren for (i = 0; i < irq_bank_count; i++) { 2163b59b6beSTony Lindgren for (j = i * 32; j < (i + 1) * 32; j++) { 2173b59b6beSTony Lindgren int irq_trigger; 2183b59b6beSTony Lindgren 2193b59b6beSTony Lindgren irq_trigger = irq_banks[i].trigger_map >> IRQ_BIT(j); 2203b59b6beSTony Lindgren omap_irq_set_cfg(j, 0, 0, irq_trigger); 2213b59b6beSTony Lindgren 2223b59b6beSTony Lindgren set_irq_chip(j, &omap_irq_chip); 2233b59b6beSTony Lindgren set_irq_handler(j, do_level_IRQ); 2243b59b6beSTony Lindgren set_irq_flags(j, IRQF_VALID); 2253b59b6beSTony Lindgren } 2263b59b6beSTony Lindgren } 2273b59b6beSTony Lindgren 2283b59b6beSTony Lindgren /* Unmask level 2 handler */ 2293b59b6beSTony Lindgren if (cpu_is_omap730()) { 2303b59b6beSTony Lindgren omap_unmask_irq(INT_730_IH2_IRQ); 2313b59b6beSTony Lindgren } else { 2323b59b6beSTony Lindgren omap_unmask_irq(INT_IH2_IRQ); 2333b59b6beSTony Lindgren } 2343b59b6beSTony Lindgren } 235