~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-davinci/cp_intc.c

Version: ~ [ linux-5.6 ] ~ [ linux-5.5.13 ] ~ [ linux-5.4.28 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.113 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.174 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.217 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.217 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp