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/export.h> 13#include <linux/init.h> 14#include <linux/irq.h> 15#include <linux/irqdomain.h> 16#include <linux/io.h> 17#include <linux/of.h> 18#include <linux/of_address.h> 19#include <linux/of_irq.h> 20 21#include <mach/common.h> 22#include <mach/cp_intc.h> 23 24static inline unsigned int cp_intc_read(unsigned offset) 25{ 26 return __raw_readl(davinci_intc_base + offset); 27} 28 29static inline void cp_intc_write(unsigned long value, unsigned offset) 30{ 31 __raw_writel(value, davinci_intc_base + offset); 32} 33 34static void cp_intc_ack_irq(struct irq_data *d) 35{ 36 cp_intc_write(d->hwirq, CP_INTC_SYS_STAT_IDX_CLR); 37} 38 39/* Disable interrupt */ 40static void cp_intc_mask_irq(struct irq_data *d) 41{ 42 /* XXX don't know why we need to disable nIRQ here... */ 43 cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); 44 cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_CLR); 45 cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); 46} 47 48/* Enable interrupt */ 49static void cp_intc_unmask_irq(struct irq_data *d) 50{ 51 cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_SET); 52} 53 54static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) 55{ 56 unsigned reg = BIT_WORD(d->hwirq); 57 unsigned mask = BIT_MASK(d->hwirq); 58 unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); 59 unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); 60 61 switch (flow_type) { 62 case IRQ_TYPE_EDGE_RISING: 63 polarity |= mask; 64 type |= mask; 65 break; 66 case IRQ_TYPE_EDGE_FALLING: 67 polarity &= ~mask; 68 type |= mask; 69 break; 70 case IRQ_TYPE_LEVEL_HIGH: 71 polarity |= mask; 72 type &= ~mask; 73 break; 74 case IRQ_TYPE_LEVEL_LOW: 75 polarity &= ~mask; 76 type &= ~mask; 77 break; 78 default: 79 return -EINVAL; 80 } 81 82 cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg)); 83 cp_intc_write(type, CP_INTC_SYS_TYPE(reg)); 84 85 return 0; 86} 87 88/* 89 * Faking this allows us to to work with suspend functions of 90 * generic drivers which call {enable|disable}_irq_wake for 91 * wake up interrupt sources (eg RTC on DA850). 92 */ 93static int cp_intc_set_wake(struct irq_data *d, unsigned int on) 94{ 95 return 0; 96} 97 98static struct irq_chip cp_intc_irq_chip = { 99 .name = "cp_intc", 100 .irq_ack = cp_intc_ack_irq, 101 .irq_mask = cp_intc_mask_irq, 102 .irq_unmask = cp_intc_unmask_irq, 103 .irq_set_type = cp_intc_set_irq_type, 104 .irq_set_wake = cp_intc_set_wake, 105}; 106 107static struct irq_domain *cp_intc_domain; 108 109static int cp_intc_host_map(struct irq_domain *h, unsigned int virq, 110 irq_hw_number_t hw) 111{ 112 pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw); 113 114 irq_set_chip(virq, &cp_intc_irq_chip); 115 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); 116 irq_set_handler(virq, handle_edge_irq); 117 return 0; 118} 119 120static const struct irq_domain_ops cp_intc_host_ops = { 121 .map = cp_intc_host_map, 122 .xlate = irq_domain_xlate_onetwocell, 123}; 124 125int __init cp_intc_of_init(struct device_node *node, struct device_node *parent) 126{ 127 u32 num_irq = davinci_soc_info.intc_irq_num; 128 u8 *irq_prio = davinci_soc_info.intc_irq_prios; 129 u32 *host_map = davinci_soc_info.intc_host_map; 130 unsigned num_reg = BITS_TO_LONGS(num_irq); 131 int i, irq_base; 132 133 davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; 134 if (node) { 135 davinci_intc_base = of_iomap(node, 0); 136 if (of_property_read_u32(node, "ti,intc-size", &num_irq)) 137 pr_warn("unable to get intc-size, default to %d\n", 138 num_irq); 139 } else { 140 davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); 141 } 142 if (WARN_ON(!davinci_intc_base)) 143 return -EINVAL; 144 145 cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); 146 147 /* Disable all host interrupts */ 148 cp_intc_write(0, CP_INTC_HOST_ENABLE(0)); 149 150 /* Disable system interrupts */ 151 for (i = 0; i < num_reg; i++) 152 cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i)); 153 154 /* Set to normal mode, no nesting, no priority hold */ 155 cp_intc_write(0, CP_INTC_CTRL); 156 cp_intc_write(0, CP_INTC_HOST_CTRL); 157 158 /* Clear system interrupt status */ 159 for (i = 0; i < num_reg; i++) 160 cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i)); 161 162 /* Enable nIRQ (what about nFIQ?) */ 163 cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); 164 165 /* 166 * Priority is determined by host channel: lower channel number has 167 * higher priority i.e. channel 0 has highest priority and channel 31 168 * had the lowest priority. 169 */ 170 num_reg = (num_irq + 3) >> 2; /* 4 channels per register */ 171 if (irq_prio) { 172 unsigned j, k; 173 u32 val; 174 175 for (k = i = 0; i < num_reg; i++) { 176 for (val = j = 0; j < 4; j++, k++) { 177 val >>= 8; 178 if (k < num_irq) 179 val |= irq_prio[k] << 24; 180 } 181 182 cp_intc_write(val, CP_INTC_CHAN_MAP(i)); 183 } 184 } else { 185 /* 186 * Default everything to channel 15 if priority not specified. 187 * Note that channel 0-1 are mapped to nFIQ and channels 2-31 188 * are mapped to nIRQ. 189 */ 190 for (i = 0; i < num_reg; i++) 191 cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i)); 192 } 193 194 if (host_map) 195 for (i = 0; host_map[i] != -1; i++) 196 cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); 197 198 irq_base = irq_alloc_descs(-1, 0, num_irq, 0); 199 if (irq_base < 0) { 200 pr_warn("Couldn't allocate IRQ numbers\n"); 201 irq_base = 0; 202 } 203 204 /* create a legacy host */ 205 cp_intc_domain = irq_domain_add_legacy(node, num_irq, 206 irq_base, 0, &cp_intc_host_ops, NULL); 207 208 if (!cp_intc_domain) { 209 pr_err("cp_intc: failed to allocate irq host!\n"); 210 return -EINVAL; 211 } 212 213 /* Enable global interrupt */ 214 cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); 215 216 return 0; 217} 218 219void __init cp_intc_init(void) 220{ 221 cp_intc_of_init(NULL, NULL); 222} 223