18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * intc.c -- support for the old ColdFire interrupt controller 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 78c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 88c2ecf20Sopenharmony_ci * for more details. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/irq.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <asm/traps.h> 188c2ecf20Sopenharmony_ci#include <asm/coldfire.h> 198c2ecf20Sopenharmony_ci#include <asm/mcfsim.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * The mapping of irq number to a mask register bit is not one-to-one. 238c2ecf20Sopenharmony_ci * The irq numbers are either based on "level" of interrupt or fixed 248c2ecf20Sopenharmony_ci * for an autovector-able interrupt. So we keep a local data structure 258c2ecf20Sopenharmony_ci * that maps from irq to mask register. Not all interrupts will have 268c2ecf20Sopenharmony_ci * an IMR bit. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ciunsigned char mcf_irq2imr[NR_IRQS]; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Define the miniumun and maximum external interrupt numbers. 328c2ecf20Sopenharmony_ci * This is also used as the "level" interrupt numbers. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci#define EIRQ1 25 358c2ecf20Sopenharmony_ci#define EIRQ7 31 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * In the early version 2 core ColdFire parts the IMR register was 16 bits 398c2ecf20Sopenharmony_ci * in size. Version 3 (and later version 2) core parts have a 32 bit 408c2ecf20Sopenharmony_ci * sized IMR register. Provide some size independent methods to access the 418c2ecf20Sopenharmony_ci * IMR register. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci#ifdef MCFSIM_IMR_IS_16BITS 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_civoid mcf_setimr(int index) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci u16 imr; 488c2ecf20Sopenharmony_ci imr = __raw_readw(MCFSIM_IMR); 498c2ecf20Sopenharmony_ci __raw_writew(imr | (0x1 << index), MCFSIM_IMR); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_civoid mcf_clrimr(int index) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u16 imr; 558c2ecf20Sopenharmony_ci imr = __raw_readw(MCFSIM_IMR); 568c2ecf20Sopenharmony_ci __raw_writew(imr & ~(0x1 << index), MCFSIM_IMR); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid mcf_maskimr(unsigned int mask) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci u16 imr; 628c2ecf20Sopenharmony_ci imr = __raw_readw(MCFSIM_IMR); 638c2ecf20Sopenharmony_ci imr |= mask; 648c2ecf20Sopenharmony_ci __raw_writew(imr, MCFSIM_IMR); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#else 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid mcf_setimr(int index) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci u32 imr; 728c2ecf20Sopenharmony_ci imr = __raw_readl(MCFSIM_IMR); 738c2ecf20Sopenharmony_ci __raw_writel(imr | (0x1 << index), MCFSIM_IMR); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid mcf_clrimr(int index) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci u32 imr; 798c2ecf20Sopenharmony_ci imr = __raw_readl(MCFSIM_IMR); 808c2ecf20Sopenharmony_ci __raw_writel(imr & ~(0x1 << index), MCFSIM_IMR); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid mcf_maskimr(unsigned int mask) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci u32 imr; 868c2ecf20Sopenharmony_ci imr = __raw_readl(MCFSIM_IMR); 878c2ecf20Sopenharmony_ci imr |= mask; 888c2ecf20Sopenharmony_ci __raw_writel(imr, MCFSIM_IMR); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#endif 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * Interrupts can be "vectored" on the ColdFire cores that support this old 958c2ecf20Sopenharmony_ci * interrupt controller. That is, the device raising the interrupt can also 968c2ecf20Sopenharmony_ci * supply the vector number to interrupt through. The AVR register of the 978c2ecf20Sopenharmony_ci * interrupt controller enables or disables this for each external interrupt, 988c2ecf20Sopenharmony_ci * so provide generic support for this. Setting this up is out-of-band for 998c2ecf20Sopenharmony_ci * the interrupt system API's, and needs to be done by the driver that 1008c2ecf20Sopenharmony_ci * supports this device. Very few devices actually use this. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_civoid mcf_autovector(int irq) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci#ifdef MCFSIM_AVR 1058c2ecf20Sopenharmony_ci if ((irq >= EIRQ1) && (irq <= EIRQ7)) { 1068c2ecf20Sopenharmony_ci u8 avec; 1078c2ecf20Sopenharmony_ci avec = __raw_readb(MCFSIM_AVR); 1088c2ecf20Sopenharmony_ci avec |= (0x1 << (irq - EIRQ1 + 1)); 1098c2ecf20Sopenharmony_ci __raw_writeb(avec, MCFSIM_AVR); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void intc_irq_mask(struct irq_data *d) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci if (mcf_irq2imr[d->irq]) 1178c2ecf20Sopenharmony_ci mcf_setimr(mcf_irq2imr[d->irq]); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void intc_irq_unmask(struct irq_data *d) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci if (mcf_irq2imr[d->irq]) 1238c2ecf20Sopenharmony_ci mcf_clrimr(mcf_irq2imr[d->irq]); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int intc_irq_set_type(struct irq_data *d, unsigned int type) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic struct irq_chip intc_irq_chip = { 1328c2ecf20Sopenharmony_ci .name = "CF-INTC", 1338c2ecf20Sopenharmony_ci .irq_mask = intc_irq_mask, 1348c2ecf20Sopenharmony_ci .irq_unmask = intc_irq_unmask, 1358c2ecf20Sopenharmony_ci .irq_set_type = intc_irq_set_type, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_civoid __init init_IRQ(void) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int irq; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci mcf_maskimr(0xffffffff); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (irq = 0; (irq < NR_IRQS); irq++) { 1458c2ecf20Sopenharmony_ci irq_set_chip(irq, &intc_irq_chip); 1468c2ecf20Sopenharmony_ci irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); 1478c2ecf20Sopenharmony_ci irq_set_handler(irq, handle_level_irq); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 151