0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
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
0043 #define CPM2_IRQ_EXT1 19
0044 #define CPM2_IRQ_EXT7 25
0045
0046
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];
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
0067
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
0127
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
0138
0139
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
0163
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
0206
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
0237
0238
0239
0240
0241
0242 out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
0243 out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
0244
0245 wmb();
0246
0247
0248 out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
0249 out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
0250 wmb();
0251
0252
0253 i = in_be32(&cpm2_intctl->ic_sivec);
0254 rmb();
0255
0256
0257
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
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 }