root/arch/powerpc/sysdev/cpm2_pic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cpm2_mask_irq
  2. cpm2_unmask_irq
  3. cpm2_ack
  4. cpm2_end_irq
  5. cpm2_set_irq_type
  6. cpm2_get_irq
  7. cpm2_pic_host_map
  8. cpm2_pic_init

   1 /*
   2  * Platform information definitions.
   3  *
   4  * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates
   5  * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek.
   6  *
   7  * Author:  Vitaly Bordug <vbordug@ru.mvista.com>
   8  *
   9  * 1999-2001 (c) Dan Malek <dan@embeddedalley.com>
  10  * 2006 (c) MontaVista Software, Inc.
  11  *
  12  * This file is licensed under the terms of the GNU General Public License
  13  * version 2. This program is licensed "as is" without any warranty of any
  14  * kind, whether express or implied.
  15  */
  16 
  17 /* The CPM2 internal interrupt controller.  It is usually
  18  * the only interrupt controller.
  19  * There are two 32-bit registers (high/low) for up to 64
  20  * possible interrupts.
  21  *
  22  * Now, the fun starts.....Interrupt Numbers DO NOT MAP
  23  * in a simple arithmetic fashion to mask or pending registers.
  24  * That is, interrupt 4 does not map to bit position 4.
  25  * We create two tables, indexed by vector number, to indicate
  26  * which register to use and which bit in the register to use.
  27  */
  28 
  29 #include <linux/stddef.h>
  30 #include <linux/sched.h>
  31 #include <linux/signal.h>
  32 #include <linux/irq.h>
  33 
  34 #include <asm/immap_cpm2.h>
  35 #include <asm/mpc8260.h>
  36 #include <asm/io.h>
  37 #include <asm/prom.h>
  38 #include <asm/fs_pd.h>
  39 
  40 #include "cpm2_pic.h"
  41 
  42 /* External IRQS */
  43 #define CPM2_IRQ_EXT1           19
  44 #define CPM2_IRQ_EXT7           25
  45 
  46 /* Port C IRQS */
  47 #define CPM2_IRQ_PORTC15        48
  48 #define CPM2_IRQ_PORTC0         63
  49 
  50 static intctl_cpm2_t __iomem *cpm2_intctl;
  51 
  52 static struct irq_domain *cpm2_pic_host;
  53 static unsigned long ppc_cached_irq_mask[2]; /* 2 32-bit registers */
  54 
  55 static const u_char irq_to_siureg[] = {
  56         1, 1, 1, 1, 1, 1, 1, 1,
  57         1, 1, 1, 1, 1, 1, 1, 1,
  58         0, 0, 0, 0, 0, 0, 0, 0,
  59         0, 0, 0, 0, 0, 0, 0, 0,
  60         1, 1, 1, 1, 1, 1, 1, 1,
  61         1, 1, 1, 1, 1, 1, 1, 1,
  62         0, 0, 0, 0, 0, 0, 0, 0,
  63         0, 0, 0, 0, 0, 0, 0, 0
  64 };
  65 
  66 /* bit numbers do not match the docs, these are precomputed so the bit for
  67  * a given irq is (1 << irq_to_siubit[irq]) */
  68 static const u_char irq_to_siubit[] = {
  69          0, 15, 14, 13, 12, 11, 10,  9,
  70          8,  7,  6,  5,  4,  3,  2,  1,
  71          2,  1,  0, 14, 13, 12, 11, 10,
  72          9,  8,  7,  6,  5,  4,  3,  0,
  73         31, 30, 29, 28, 27, 26, 25, 24,
  74         23, 22, 21, 20, 19, 18, 17, 16,
  75         16, 17, 18, 19, 20, 21, 22, 23,
  76         24, 25, 26, 27, 28, 29, 30, 31,
  77 };
  78 
  79 static void cpm2_mask_irq(struct irq_data *d)
  80 {
  81         int     bit, word;
  82         unsigned int irq_nr = irqd_to_hwirq(d);
  83 
  84         bit = irq_to_siubit[irq_nr];
  85         word = irq_to_siureg[irq_nr];
  86 
  87         ppc_cached_irq_mask[word] &= ~(1 << bit);
  88         out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
  89 }
  90 
  91 static void cpm2_unmask_irq(struct irq_data *d)
  92 {
  93         int     bit, word;
  94         unsigned int irq_nr = irqd_to_hwirq(d);
  95 
  96         bit = irq_to_siubit[irq_nr];
  97         word = irq_to_siureg[irq_nr];
  98 
  99         ppc_cached_irq_mask[word] |= 1 << bit;
 100         out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
 101 }
 102 
 103 static void cpm2_ack(struct irq_data *d)
 104 {
 105         int     bit, word;
 106         unsigned int irq_nr = irqd_to_hwirq(d);
 107 
 108         bit = irq_to_siubit[irq_nr];
 109         word = irq_to_siureg[irq_nr];
 110 
 111         out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
 112 }
 113 
 114 static void cpm2_end_irq(struct irq_data *d)
 115 {
 116         int     bit, word;
 117         unsigned int irq_nr = irqd_to_hwirq(d);
 118 
 119         bit = irq_to_siubit[irq_nr];
 120         word = irq_to_siureg[irq_nr];
 121 
 122         ppc_cached_irq_mask[word] |= 1 << bit;
 123         out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
 124 
 125         /*
 126          * Work around large numbers of spurious IRQs on PowerPC 82xx
 127          * systems.
 128          */
 129         mb();
 130 }
 131 
 132 static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type)
 133 {
 134         unsigned int src = irqd_to_hwirq(d);
 135         unsigned int vold, vnew, edibit;
 136 
 137         /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or
 138          * IRQ_TYPE_EDGE_BOTH (default).  All others are IRQ_TYPE_EDGE_FALLING
 139          * or IRQ_TYPE_LEVEL_LOW (default)
 140          */
 141         if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) {
 142                 if (flow_type == IRQ_TYPE_NONE)
 143                         flow_type = IRQ_TYPE_EDGE_BOTH;
 144 
 145                 if (flow_type != IRQ_TYPE_EDGE_BOTH &&
 146                     flow_type != IRQ_TYPE_EDGE_FALLING)
 147                         goto err_sense;
 148         } else {
 149                 if (flow_type == IRQ_TYPE_NONE)
 150                         flow_type = IRQ_TYPE_LEVEL_LOW;
 151 
 152                 if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
 153                         goto err_sense;
 154         }
 155 
 156         irqd_set_trigger_type(d, flow_type);
 157         if (flow_type & IRQ_TYPE_LEVEL_LOW)
 158                 irq_set_handler_locked(d, handle_level_irq);
 159         else
 160                 irq_set_handler_locked(d, handle_edge_irq);
 161 
 162         /* internal IRQ senses are LEVEL_LOW
 163          * EXT IRQ and Port C IRQ senses are programmable
 164          */
 165         if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
 166                         edibit = (14 - (src - CPM2_IRQ_EXT1));
 167         else
 168                 if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
 169                         edibit = (31 - (CPM2_IRQ_PORTC0 - src));
 170                 else
 171                         return (flow_type & IRQ_TYPE_LEVEL_LOW) ?
 172                                 IRQ_SET_MASK_OK_NOCOPY : -EINVAL;
 173 
 174         vold = in_be32(&cpm2_intctl->ic_siexr);
 175 
 176         if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
 177                 vnew = vold | (1 << edibit);
 178         else
 179                 vnew = vold & ~(1 << edibit);
 180 
 181         if (vold != vnew)
 182                 out_be32(&cpm2_intctl->ic_siexr, vnew);
 183         return IRQ_SET_MASK_OK_NOCOPY;
 184 
 185 err_sense:
 186         pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type);
 187         return -EINVAL;
 188 }
 189 
 190 static struct irq_chip cpm2_pic = {
 191         .name = "CPM2 SIU",
 192         .irq_mask = cpm2_mask_irq,
 193         .irq_unmask = cpm2_unmask_irq,
 194         .irq_ack = cpm2_ack,
 195         .irq_eoi = cpm2_end_irq,
 196         .irq_set_type = cpm2_set_irq_type,
 197         .flags = IRQCHIP_EOI_IF_HANDLED,
 198 };
 199 
 200 unsigned int cpm2_get_irq(void)
 201 {
 202         int irq;
 203         unsigned long bits;
 204 
 205        /* For CPM2, read the SIVEC register and shift the bits down
 206          * to get the irq number.         */
 207         bits = in_be32(&cpm2_intctl->ic_sivec);
 208         irq = bits >> 26;
 209 
 210         if (irq == 0)
 211                 return(-1);
 212         return irq_linear_revmap(cpm2_pic_host, irq);
 213 }
 214 
 215 static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq,
 216                           irq_hw_number_t hw)
 217 {
 218         pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
 219 
 220         irq_set_status_flags(virq, IRQ_LEVEL);
 221         irq_set_chip_and_handler(virq, &cpm2_pic, handle_level_irq);
 222         return 0;
 223 }
 224 
 225 static const struct irq_domain_ops cpm2_pic_host_ops = {
 226         .map = cpm2_pic_host_map,
 227         .xlate = irq_domain_xlate_onetwocell,
 228 };
 229 
 230 void cpm2_pic_init(struct device_node *node)
 231 {
 232         int i;
 233 
 234         cpm2_intctl = cpm2_map(im_intctl);
 235 
 236         /* Clear the CPM IRQ controller, in case it has any bits set
 237          * from the bootloader
 238          */
 239 
 240         /* Mask out everything */
 241 
 242         out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
 243         out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
 244 
 245         wmb();
 246 
 247         /* Ack everything */
 248         out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
 249         out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
 250         wmb();
 251 
 252         /* Dummy read of the vector */
 253         i = in_be32(&cpm2_intctl->ic_sivec);
 254         rmb();
 255 
 256         /* Initialize the default interrupt mapping priorities,
 257          * in case the boot rom changed something on us.
 258          */
 259         out_be16(&cpm2_intctl->ic_sicr, 0);
 260         out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
 261         out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
 262 
 263         /* create a legacy host */
 264         cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);
 265         if (cpm2_pic_host == NULL) {
 266                 printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
 267                 return;
 268         }
 269 }

/* [<][>][^][v][top][bottom][index][help] */