Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Platform information definitions.
0003  *
0004  * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates
0005  * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek.
0006  *
0007  * Author:  Vitaly Bordug <vbordug@ru.mvista.com>
0008  *
0009  * 1999-2001 (c) Dan Malek <dan@embeddedalley.com>
0010  * 2006 (c) MontaVista Software, Inc.
0011  *
0012  * This file is licensed under the terms of the GNU General Public License
0013  * version 2. This program is licensed "as is" without any warranty of any
0014  * kind, whether express or implied.
0015  */
0016 
0017 /* The CPM2 internal interrupt controller.  It is usually
0018  * the only interrupt controller.
0019  * There are two 32-bit registers (high/low) for up to 64
0020  * possible interrupts.
0021  *
0022  * Now, the fun starts.....Interrupt Numbers DO NOT MAP
0023  * in a simple arithmetic fashion to mask or pending registers.
0024  * That is, interrupt 4 does not map to bit position 4.
0025  * We create two tables, indexed by vector number, to indicate
0026  * which register to use and which bit in the register to use.
0027  */
0028 
0029 #include <linux/stddef.h>
0030 #include <linux/sched.h>
0031 #include <linux/signal.h>
0032 #include <linux/irq.h>
0033 #include <linux/irqdomain.h>
0034 
0035 #include <asm/immap_cpm2.h>
0036 #include <asm/mpc8260.h>
0037 #include <asm/io.h>
0038 #include <asm/fs_pd.h>
0039 
0040 #include "cpm2_pic.h"
0041 
0042 /* External IRQS */
0043 #define CPM2_IRQ_EXT1       19
0044 #define CPM2_IRQ_EXT7       25
0045 
0046 /* Port C IRQS */
0047 #define CPM2_IRQ_PORTC15    48
0048 #define CPM2_IRQ_PORTC0     63
0049 
0050 static intctl_cpm2_t __iomem *cpm2_intctl;
0051 
0052 static struct irq_domain *cpm2_pic_host;
0053 static unsigned long ppc_cached_irq_mask[2]; /* 2 32-bit registers */
0054 
0055 static const u_char irq_to_siureg[] = {
0056     1, 1, 1, 1, 1, 1, 1, 1,
0057     1, 1, 1, 1, 1, 1, 1, 1,
0058     0, 0, 0, 0, 0, 0, 0, 0,
0059     0, 0, 0, 0, 0, 0, 0, 0,
0060     1, 1, 1, 1, 1, 1, 1, 1,
0061     1, 1, 1, 1, 1, 1, 1, 1,
0062     0, 0, 0, 0, 0, 0, 0, 0,
0063     0, 0, 0, 0, 0, 0, 0, 0
0064 };
0065 
0066 /* bit numbers do not match the docs, these are precomputed so the bit for
0067  * a given irq is (1 << irq_to_siubit[irq]) */
0068 static const u_char irq_to_siubit[] = {
0069      0, 15, 14, 13, 12, 11, 10,  9,
0070      8,  7,  6,  5,  4,  3,  2,  1,
0071      2,  1,  0, 14, 13, 12, 11, 10,
0072      9,  8,  7,  6,  5,  4,  3,  0,
0073     31, 30, 29, 28, 27, 26, 25, 24,
0074     23, 22, 21, 20, 19, 18, 17, 16,
0075     16, 17, 18, 19, 20, 21, 22, 23,
0076     24, 25, 26, 27, 28, 29, 30, 31,
0077 };
0078 
0079 static void cpm2_mask_irq(struct irq_data *d)
0080 {
0081     int bit, word;
0082     unsigned int irq_nr = irqd_to_hwirq(d);
0083 
0084     bit = irq_to_siubit[irq_nr];
0085     word = irq_to_siureg[irq_nr];
0086 
0087     ppc_cached_irq_mask[word] &= ~(1 << bit);
0088     out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
0089 }
0090 
0091 static void cpm2_unmask_irq(struct irq_data *d)
0092 {
0093     int bit, word;
0094     unsigned int irq_nr = irqd_to_hwirq(d);
0095 
0096     bit = irq_to_siubit[irq_nr];
0097     word = irq_to_siureg[irq_nr];
0098 
0099     ppc_cached_irq_mask[word] |= 1 << bit;
0100     out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
0101 }
0102 
0103 static void cpm2_ack(struct irq_data *d)
0104 {
0105     int bit, word;
0106     unsigned int irq_nr = irqd_to_hwirq(d);
0107 
0108     bit = irq_to_siubit[irq_nr];
0109     word = irq_to_siureg[irq_nr];
0110 
0111     out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
0112 }
0113 
0114 static void cpm2_end_irq(struct irq_data *d)
0115 {
0116     int bit, word;
0117     unsigned int irq_nr = irqd_to_hwirq(d);
0118 
0119     bit = irq_to_siubit[irq_nr];
0120     word = irq_to_siureg[irq_nr];
0121 
0122     ppc_cached_irq_mask[word] |= 1 << bit;
0123     out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
0124 
0125     /*
0126      * Work around large numbers of spurious IRQs on PowerPC 82xx
0127      * systems.
0128      */
0129     mb();
0130 }
0131 
0132 static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type)
0133 {
0134     unsigned int src = irqd_to_hwirq(d);
0135     unsigned int vold, vnew, edibit;
0136 
0137     /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or
0138      * IRQ_TYPE_EDGE_BOTH (default).  All others are IRQ_TYPE_EDGE_FALLING
0139      * or IRQ_TYPE_LEVEL_LOW (default)
0140      */
0141     if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) {
0142         if (flow_type == IRQ_TYPE_NONE)
0143             flow_type = IRQ_TYPE_EDGE_BOTH;
0144 
0145         if (flow_type != IRQ_TYPE_EDGE_BOTH &&
0146             flow_type != IRQ_TYPE_EDGE_FALLING)
0147             goto err_sense;
0148     } else {
0149         if (flow_type == IRQ_TYPE_NONE)
0150             flow_type = IRQ_TYPE_LEVEL_LOW;
0151 
0152         if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
0153             goto err_sense;
0154     }
0155 
0156     irqd_set_trigger_type(d, flow_type);
0157     if (flow_type & IRQ_TYPE_LEVEL_LOW)
0158         irq_set_handler_locked(d, handle_level_irq);
0159     else
0160         irq_set_handler_locked(d, handle_edge_irq);
0161 
0162     /* internal IRQ senses are LEVEL_LOW
0163      * EXT IRQ and Port C IRQ senses are programmable
0164      */
0165     if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
0166             edibit = (14 - (src - CPM2_IRQ_EXT1));
0167     else
0168         if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
0169             edibit = (31 - (CPM2_IRQ_PORTC0 - src));
0170         else
0171             return (flow_type & IRQ_TYPE_LEVEL_LOW) ?
0172                 IRQ_SET_MASK_OK_NOCOPY : -EINVAL;
0173 
0174     vold = in_be32(&cpm2_intctl->ic_siexr);
0175 
0176     if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
0177         vnew = vold | (1 << edibit);
0178     else
0179         vnew = vold & ~(1 << edibit);
0180 
0181     if (vold != vnew)
0182         out_be32(&cpm2_intctl->ic_siexr, vnew);
0183     return IRQ_SET_MASK_OK_NOCOPY;
0184 
0185 err_sense:
0186     pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type);
0187     return -EINVAL;
0188 }
0189 
0190 static struct irq_chip cpm2_pic = {
0191     .name = "CPM2 SIU",
0192     .irq_mask = cpm2_mask_irq,
0193     .irq_unmask = cpm2_unmask_irq,
0194     .irq_ack = cpm2_ack,
0195     .irq_eoi = cpm2_end_irq,
0196     .irq_set_type = cpm2_set_irq_type,
0197     .flags = IRQCHIP_EOI_IF_HANDLED,
0198 };
0199 
0200 unsigned int cpm2_get_irq(void)
0201 {
0202     int irq;
0203     unsigned long bits;
0204 
0205        /* For CPM2, read the SIVEC register and shift the bits down
0206          * to get the irq number.         */
0207         bits = in_be32(&cpm2_intctl->ic_sivec);
0208         irq = bits >> 26;
0209 
0210     if (irq == 0)
0211         return(-1);
0212     return irq_linear_revmap(cpm2_pic_host, irq);
0213 }
0214 
0215 static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq,
0216               irq_hw_number_t hw)
0217 {
0218     pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
0219 
0220     irq_set_status_flags(virq, IRQ_LEVEL);
0221     irq_set_chip_and_handler(virq, &cpm2_pic, handle_level_irq);
0222     return 0;
0223 }
0224 
0225 static const struct irq_domain_ops cpm2_pic_host_ops = {
0226     .map = cpm2_pic_host_map,
0227     .xlate = irq_domain_xlate_onetwocell,
0228 };
0229 
0230 void cpm2_pic_init(struct device_node *node)
0231 {
0232     int i;
0233 
0234     cpm2_intctl = cpm2_map(im_intctl);
0235 
0236     /* Clear the CPM IRQ controller, in case it has any bits set
0237      * from the bootloader
0238      */
0239 
0240     /* Mask out everything */
0241 
0242     out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
0243     out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
0244 
0245     wmb();
0246 
0247     /* Ack everything */
0248     out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
0249     out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
0250     wmb();
0251 
0252     /* Dummy read of the vector */
0253     i = in_be32(&cpm2_intctl->ic_sivec);
0254     rmb();
0255 
0256     /* Initialize the default interrupt mapping priorities,
0257      * in case the boot rom changed something on us.
0258      */
0259     out_be16(&cpm2_intctl->ic_sicr, 0);
0260     out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
0261     out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
0262 
0263     /* create a legacy host */
0264     cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);
0265     if (cpm2_pic_host == NULL) {
0266         printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
0267         return;
0268     }
0269 }