1/* 2 * TI Common Platform Interrupt Controller (cp_intc) driver 3 * 4 * Author: Steve Chen <schen@mvista.com> 5 * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.com> 6 * 7 * This file is licensed under the terms of the GNU General Public License 8 * version 2. This program is licensed "as is" without any warranty of any 9 * kind, whether express or implied. 10 */ 11 12#include <linux/init.h> 13#include <linux/irq.h> 14#include <linux/io.h> 15 16#include <mach/common.h> 17#include <mach/cp_intc.h> 18 19static inline unsigned int cp_intc_read(unsigned offset) 20{ 21 return __raw_readl(davinci_intc_base + offset); 22} 23 24static inline void cp_intc_write(unsigned long value, unsigned offset) 25{ 26 __raw_writel(value, davinci_intc_base + offset); 27} 28 29static void cp_intc_ack_irq(unsigned int irq) 30{ 31 cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR); 32} 33 34/* Disable interrupt */ 35static void cp_intc_mask_irq(unsigned int irq) 36{ 37 cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); 38 cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR); 39 cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); 40} 41 42/* Enable interrupt */ 43static void cp_intc_unmask_irq(unsigned int irq) 44{ 45 cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET); 46} 47 48static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type) 49{ 50 unsigned reg = BIT_WORD(irq); 51 unsigned mask = BIT_MASK(irq); 52 unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); 53 unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); 54 55 switch (flow_type) { 56 case IRQ_TYPE_EDGE_RISING: 57 polarity |= mask; 58 type |= mask; 59 break; 60 case IRQ_TYPE_EDGE_FALLING: 61 polarity &= ~mask; 62 type |= mask; 63 break; 64 case IRQ_TYPE_LEVEL_HIGH: 65 polarity |= mask; 66 type &= ~mask; 67 break; 68 case IRQ_TYPE_LEVEL_LOW: 69 polarity &= ~mask; 70 type &= ~mask; 71 break; 72 default: 73 return -EINVAL; 74 } 75 76 cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg)); 77 cp_intc_write(type, CP_INTC_SYS_TYPE(reg)); 78 79 return 0; 80} 81 82/* 83 * Faking this allows us to to work with suspend functions of 84 * generic drivers which call {enable|disable}_irq_wake for 85 * wake up interrupt sources (eg RTC on DA850). 86 */ 87static int cp_intc_set_wake(unsigned int irq, unsigned int on) 88{ 89 return 0; 90} 91 92static struct irq_chip cp_intc_irq_chip = { 93 .name = "cp_intc", 94 .ack = cp_intc_ack_irq, 95 .mask = cp_intc_mask_irq, 96 .unmask = cp_intc_unmask_irq, 97 .set_type = cp_intc_set_irq_type, 98 .set_wake = cp_intc_set_wake, 99}; 100 101void __init cp_intc_init(void) 102{ 103 unsigned long num_irq = davinci_soc_info.intc_irq_num; 104 u8 *irq_prio = davinci_soc_info.intc_irq_prios; 105 u32 *host_map = davinci_soc_info.intc_host_map; 106 unsigned num_reg = BITS_TO_LONGS(num_irq); 107 int i; 108 109 davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; 110 davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); 111 if (WARN_ON(!davinci_intc_base)) 112 return; 113 114 cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); 115 116 /* Disable all host interrupts */ 117 cp_intc_write(0, CP_INTC_HOST_ENABLE(0)); 118 119 /* Disable system interrupts */ 120 for (i = 0; i < num_reg; i++) 121 cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i)); 122 123 /* Set to normal mode, no nesting, no priority hold */ 124 cp_intc_write(0, CP_INTC_CTRL); 125 cp_intc_write(0, CP_INTC_HOST_CTRL); 126 127 /* Clear system interrupt status */ 128 for (i = 0; i < num_reg; i++) 129 cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i)); 130 131 /* Enable nIRQ (what about nFIQ?) */ 132 cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); 133 134 /* 135 * Priority is determined by host channel: lower channel number has 136 * higher priority i.e. channel 0 has highest priority and channel 31 137 * had the lowest priority. 138 */ 139 num_reg = (num_irq + 3) >> 2; /* 4 channels per register */ 140 if (irq_prio) { 141 unsigned j, k; 142 u32 val; 143 144 for (k = i = 0; i < num_reg; i++) { 145 for (val = j = 0; j < 4; j++, k++) { 146 val >>= 8; 147 if (k < num_irq) 148 val |= irq_prio[k] << 24; 149 } 150 151 cp_intc_write(val, CP_INTC_CHAN_MAP(i)); 152 } 153 } else { 154 /* 155 * Default everything to channel 15 if priority not specified. 156 * Note that channel 0-1 are mapped to nFIQ and channels 2-31 157 * are mapped to nIRQ. 158 */ 159 for (i = 0; i < num_reg; i++) 160 cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i)); 161 } 162 163 if (host_map) 164 for (i = 0; host_map[i] != -1; i++) 165 cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); 166 167 /* Set up genirq dispatching for cp_intc */ 168 for (i = 0; i < num_irq; i++) { 169 set_irq_chip(i, &cp_intc_irq_chip); 170 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 171 set_irq_handler(i, handle_edge_irq); 172 } 173 174 /* Enable global interrupt */ 175 cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); 176} 177