blob: b7cf7abff2eb4ffc807982a39c6d6ee7fc403d46 [file] [log] [blame]
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +03001#include <linux/kernel.h>
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +03002#include <linux/stddef.h>
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +03003#include <linux/sched.h>
4#include <linux/signal.h>
5#include <linux/irq.h>
6#include <linux/dma-mapping.h>
7#include <asm/prom.h>
8#include <asm/irq.h>
9#include <asm/io.h>
10#include <asm/8xx_immap.h>
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030011
12#include "mpc8xx_pic.h"
13
14
15#define PIC_VEC_SPURRIOUS 15
16
17extern int cpm_get_irq(struct pt_regs *regs);
18
Grant Likelybae1d8f2012-02-14 14:06:50 -070019static struct irq_domain *mpc8xx_pic_host;
Grant Likely8751ed12012-04-23 12:30:01 +000020static unsigned long mpc8xx_cached_irq_mask;
Scott Woodfb533d02007-09-14 14:22:36 -050021static sysconf8xx_t __iomem *siu_reg;
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030022
Grant Likely8751ed12012-04-23 12:30:01 +000023static inline unsigned long mpc8xx_irqd_to_bit(struct irq_data *d)
24{
25 return 0x80000000 >> irqd_to_hwirq(d);
26}
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030027
Lennert Buytenhekfebd4012011-03-07 14:00:00 +000028static void mpc8xx_unmask_irq(struct irq_data *d)
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030029{
Grant Likely8751ed12012-04-23 12:30:01 +000030 mpc8xx_cached_irq_mask |= mpc8xx_irqd_to_bit(d);
31 out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030032}
33
Lennert Buytenhekfebd4012011-03-07 14:00:00 +000034static void mpc8xx_mask_irq(struct irq_data *d)
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030035{
Grant Likely8751ed12012-04-23 12:30:01 +000036 mpc8xx_cached_irq_mask &= ~mpc8xx_irqd_to_bit(d);
37 out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030038}
39
Lennert Buytenhekfebd4012011-03-07 14:00:00 +000040static void mpc8xx_ack(struct irq_data *d)
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030041{
Grant Likely8751ed12012-04-23 12:30:01 +000042 out_be32(&siu_reg->sc_sipend, mpc8xx_irqd_to_bit(d));
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030043}
44
Lennert Buytenhekfebd4012011-03-07 14:00:00 +000045static void mpc8xx_end_irq(struct irq_data *d)
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030046{
Grant Likely8751ed12012-04-23 12:30:01 +000047 mpc8xx_cached_irq_mask |= mpc8xx_irqd_to_bit(d);
48 out_be32(&siu_reg->sc_simask, mpc8xx_cached_irq_mask);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030049}
50
Lennert Buytenhekfebd4012011-03-07 14:00:00 +000051static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type)
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030052{
Grant Likely8751ed12012-04-23 12:30:01 +000053 /* only external IRQ senses are programmable */
54 if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !(irqd_to_hwirq(d) & 1)) {
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030055 unsigned int siel = in_be32(&siu_reg->sc_siel);
Grant Likely8751ed12012-04-23 12:30:01 +000056 siel |= mpc8xx_irqd_to_bit(d);
57 out_be32(&siu_reg->sc_siel, siel);
Thomas Gleixner9ca86b22015-06-23 15:52:36 +020058 irq_set_handler_locked(d, handle_edge_irq);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030059 }
60 return 0;
61}
62
63static struct irq_chip mpc8xx_pic = {
Christophe Leroy255e8e02015-08-21 13:05:15 +020064 .name = "8XX SIU",
Lennert Buytenhekfebd4012011-03-07 14:00:00 +000065 .irq_unmask = mpc8xx_unmask_irq,
66 .irq_mask = mpc8xx_mask_irq,
67 .irq_ack = mpc8xx_ack,
68 .irq_eoi = mpc8xx_end_irq,
69 .irq_set_type = mpc8xx_set_irq_type,
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030070};
71
72unsigned int mpc8xx_get_irq(void)
73{
74 int irq;
75
76 /* For MPC8xx, read the SIVEC register and shift the bits down
77 * to get the irq number.
78 */
79 irq = in_be32(&siu_reg->sc_sivec) >> 26;
80
81 if (irq == PIC_VEC_SPURRIOUS)
82 irq = NO_IRQ;
83
84 return irq_linear_revmap(mpc8xx_pic_host, irq);
85
86}
87
Grant Likelybae1d8f2012-02-14 14:06:50 -070088static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq,
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030089 irq_hw_number_t hw)
90{
91 pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
92
93 /* Set default irq handle */
Thomas Gleixnerec775d02011-03-25 16:45:20 +010094 irq_set_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +030095 return 0;
96}
97
98
Grant Likelybae1d8f2012-02-14 14:06:50 -070099static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
Roman Fietze40d50cf2009-12-08 02:39:50 +0000100 const u32 *intspec, unsigned int intsize,
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300101 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
102{
103 static unsigned char map_pic_senses[4] = {
104 IRQ_TYPE_EDGE_RISING,
105 IRQ_TYPE_LEVEL_LOW,
106 IRQ_TYPE_LEVEL_HIGH,
107 IRQ_TYPE_EDGE_FALLING,
108 };
109
Grant Likely8751ed12012-04-23 12:30:01 +0000110 if (intspec[0] > 0x1f)
111 return 0;
112
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300113 *out_hwirq = intspec[0];
114 if (intsize > 1 && intspec[1] < 4)
115 *out_flags = map_pic_senses[intspec[1]];
116 else
117 *out_flags = IRQ_TYPE_NONE;
118
119 return 0;
120}
121
122
Krzysztof Kozlowski202648a2015-04-27 21:48:47 +0900123static const struct irq_domain_ops mpc8xx_pic_host_ops = {
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300124 .map = mpc8xx_pic_host_map,
125 .xlate = mpc8xx_pic_host_xlate,
126};
127
128int mpc8xx_pic_init(void)
129{
130 struct resource res;
Scott Woodfb533d02007-09-14 14:22:36 -0500131 struct device_node *np;
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300132 int ret;
133
Scott Woodfb533d02007-09-14 14:22:36 -0500134 np = of_find_compatible_node(NULL, NULL, "fsl,pq1-pic");
135 if (np == NULL)
136 np = of_find_node_by_type(NULL, "mpc8xx-pic");
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300137 if (np == NULL) {
Scott Woodfb533d02007-09-14 14:22:36 -0500138 printk(KERN_ERR "Could not find fsl,pq1-pic node\n");
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300139 return -ENOMEM;
140 }
141
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300142 ret = of_address_to_resource(np, 0, &res);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300143 if (ret)
Michael Ellerman52964f82007-08-28 18:47:54 +1000144 goto out;
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300145
Joe Perches28f65c112011-06-09 09:13:32 -0700146 siu_reg = ioremap(res.start, resource_size(&res));
Julia Lawallb1725c92008-02-04 23:34:59 -0800147 if (siu_reg == NULL) {
148 ret = -EINVAL;
149 goto out;
150 }
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300151
Grant Likelya8db8cf2012-02-14 14:06:54 -0700152 mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300153 if (mpc8xx_pic_host == NULL) {
154 printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
155 ret = -ENOMEM;
Julia Lawallb1725c92008-02-04 23:34:59 -0800156 goto out;
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300157 }
Julia Lawallb1725c92008-02-04 23:34:59 -0800158 return 0;
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300159
Michael Ellerman52964f82007-08-28 18:47:54 +1000160out:
161 of_node_put(np);
Vitaly Bordugf2a0bd32007-01-24 22:41:24 +0300162 return ret;
163}