xref: /linux/arch/powerpc/sysdev/ipic.c (revision 30c404699dd650f213d480d263c775915a0e1297)
11cd8e506SKumar Gala /*
2f30c2269SUwe Zeisberger  * arch/powerpc/sysdev/ipic.c
31cd8e506SKumar Gala  *
41cd8e506SKumar Gala  * IPIC routines implementations.
51cd8e506SKumar Gala  *
61cd8e506SKumar Gala  * Copyright 2005 Freescale Semiconductor, Inc.
71cd8e506SKumar Gala  *
81cd8e506SKumar Gala  * This program is free software; you can redistribute  it and/or modify it
91cd8e506SKumar Gala  * under  the terms of  the GNU General  Public License as published by the
101cd8e506SKumar Gala  * Free Software Foundation;  either version 2 of the  License, or (at your
111cd8e506SKumar Gala  * option) any later version.
121cd8e506SKumar Gala  */
131cd8e506SKumar Gala #include <linux/kernel.h>
141cd8e506SKumar Gala #include <linux/init.h>
151cd8e506SKumar Gala #include <linux/errno.h>
161cd8e506SKumar Gala #include <linux/reboot.h>
171cd8e506SKumar Gala #include <linux/slab.h>
181cd8e506SKumar Gala #include <linux/stddef.h>
191cd8e506SKumar Gala #include <linux/sched.h>
201cd8e506SKumar Gala #include <linux/signal.h>
211cd8e506SKumar Gala #include <linux/sysdev.h>
22b9f0f1bbSKim Phillips #include <linux/device.h>
23b9f0f1bbSKim Phillips #include <linux/bootmem.h>
24b9f0f1bbSKim Phillips #include <linux/spinlock.h>
25d49747bdSScott Wood #include <linux/fsl_devices.h>
261cd8e506SKumar Gala #include <asm/irq.h>
271cd8e506SKumar Gala #include <asm/io.h>
28b9f0f1bbSKim Phillips #include <asm/prom.h>
291cd8e506SKumar Gala #include <asm/ipic.h>
301cd8e506SKumar Gala 
311cd8e506SKumar Gala #include "ipic.h"
321cd8e506SKumar Gala 
331cd8e506SKumar Gala static struct ipic * primary_ipic;
3477d4309eSLi Yang static struct irq_chip ipic_level_irq_chip, ipic_edge_irq_chip;
35b9f0f1bbSKim Phillips static DEFINE_SPINLOCK(ipic_lock);
361cd8e506SKumar Gala 
371cd8e506SKumar Gala static struct ipic_info ipic_info[] = {
38f03ca957SLi Yang 	[1] = {
39f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
40f03ca957SLi Yang 		.prio	= IPIC_SIPRR_C,
41f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
42f03ca957SLi Yang 		.bit	= 16,
43f03ca957SLi Yang 		.prio_mask = 0,
44f03ca957SLi Yang 	},
45f03ca957SLi Yang 	[2] = {
46f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
47f03ca957SLi Yang 		.prio	= IPIC_SIPRR_C,
48f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
49f03ca957SLi Yang 		.bit	= 17,
50f03ca957SLi Yang 		.prio_mask = 1,
51f03ca957SLi Yang 	},
52a7267d67SJohn Rigby 	[3] = {
53a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
54a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_C,
55a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
56a7267d67SJohn Rigby 		.bit	= 18,
57a7267d67SJohn Rigby 		.prio_mask = 2,
58a7267d67SJohn Rigby 	},
59f03ca957SLi Yang 	[4] = {
60f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
61f03ca957SLi Yang 		.prio	= IPIC_SIPRR_C,
62f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
63f03ca957SLi Yang 		.bit	= 19,
64f03ca957SLi Yang 		.prio_mask = 3,
65f03ca957SLi Yang 	},
66a7267d67SJohn Rigby 	[5] = {
67a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
68a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_C,
69a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
70a7267d67SJohn Rigby 		.bit	= 20,
71a7267d67SJohn Rigby 		.prio_mask = 4,
72a7267d67SJohn Rigby 	},
73a7267d67SJohn Rigby 	[6] = {
74a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
75a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_C,
76a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
77a7267d67SJohn Rigby 		.bit	= 21,
78a7267d67SJohn Rigby 		.prio_mask = 5,
79a7267d67SJohn Rigby 	},
80a7267d67SJohn Rigby 	[7] = {
81a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
82a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_C,
83a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
84a7267d67SJohn Rigby 		.bit	= 22,
85a7267d67SJohn Rigby 		.prio_mask = 6,
86a7267d67SJohn Rigby 	},
87a7267d67SJohn Rigby 	[8] = {
88a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
89a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_C,
90a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
91a7267d67SJohn Rigby 		.bit	= 23,
92a7267d67SJohn Rigby 		.prio_mask = 7,
93a7267d67SJohn Rigby 	},
941cd8e506SKumar Gala 	[9] = {
951cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
961cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_D,
971cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
981cd8e506SKumar Gala 		.bit	= 24,
991cd8e506SKumar Gala 		.prio_mask = 0,
1001cd8e506SKumar Gala 	},
1011cd8e506SKumar Gala 	[10] = {
1021cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
1031cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_D,
1041cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
1051cd8e506SKumar Gala 		.bit	= 25,
1061cd8e506SKumar Gala 		.prio_mask = 1,
1071cd8e506SKumar Gala 	},
1081cd8e506SKumar Gala 	[11] = {
1091cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
1101cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_D,
1111cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
1121cd8e506SKumar Gala 		.bit	= 26,
1131cd8e506SKumar Gala 		.prio_mask = 2,
1141cd8e506SKumar Gala 	},
115f03ca957SLi Yang 	[12] = {
116f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
117f03ca957SLi Yang 		.prio	= IPIC_SIPRR_D,
118f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
119f03ca957SLi Yang 		.bit	= 27,
120f03ca957SLi Yang 		.prio_mask = 3,
121f03ca957SLi Yang 	},
122f03ca957SLi Yang 	[13] = {
123f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
124f03ca957SLi Yang 		.prio	= IPIC_SIPRR_D,
125f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
126f03ca957SLi Yang 		.bit	= 28,
127f03ca957SLi Yang 		.prio_mask = 4,
128f03ca957SLi Yang 	},
1291cd8e506SKumar Gala 	[14] = {
1301cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
1311cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_D,
1321cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
1331cd8e506SKumar Gala 		.bit	= 29,
1341cd8e506SKumar Gala 		.prio_mask = 5,
1351cd8e506SKumar Gala 	},
1361cd8e506SKumar Gala 	[15] = {
1371cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
1381cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_D,
1391cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
1401cd8e506SKumar Gala 		.bit	= 30,
1411cd8e506SKumar Gala 		.prio_mask = 6,
1421cd8e506SKumar Gala 	},
1431cd8e506SKumar Gala 	[16] = {
1441cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
1451cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_D,
1461cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
1471cd8e506SKumar Gala 		.bit	= 31,
1481cd8e506SKumar Gala 		.prio_mask = 7,
1491cd8e506SKumar Gala 	},
1501cd8e506SKumar Gala 	[17] = {
15177d4309eSLi Yang 		.ack	= IPIC_SEPNR,
1521cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
1531cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
1541cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
1551cd8e506SKumar Gala 		.bit	= 1,
1561cd8e506SKumar Gala 		.prio_mask = 5,
1571cd8e506SKumar Gala 	},
1581cd8e506SKumar Gala 	[18] = {
15977d4309eSLi Yang 		.ack	= IPIC_SEPNR,
1601cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
1611cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
1621cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
1631cd8e506SKumar Gala 		.bit	= 2,
1641cd8e506SKumar Gala 		.prio_mask = 6,
1651cd8e506SKumar Gala 	},
1661cd8e506SKumar Gala 	[19] = {
16777d4309eSLi Yang 		.ack	= IPIC_SEPNR,
1681cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
1691cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
1701cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
1711cd8e506SKumar Gala 		.bit	= 3,
1721cd8e506SKumar Gala 		.prio_mask = 7,
1731cd8e506SKumar Gala 	},
1741cd8e506SKumar Gala 	[20] = {
17577d4309eSLi Yang 		.ack	= IPIC_SEPNR,
1761cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
1771cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
1781cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
1791cd8e506SKumar Gala 		.bit	= 4,
1801cd8e506SKumar Gala 		.prio_mask = 4,
1811cd8e506SKumar Gala 	},
1821cd8e506SKumar Gala 	[21] = {
18377d4309eSLi Yang 		.ack	= IPIC_SEPNR,
1841cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
1851cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
1861cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
1871cd8e506SKumar Gala 		.bit	= 5,
1881cd8e506SKumar Gala 		.prio_mask = 5,
1891cd8e506SKumar Gala 	},
1901cd8e506SKumar Gala 	[22] = {
19177d4309eSLi Yang 		.ack	= IPIC_SEPNR,
1921cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
1931cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
1941cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
1951cd8e506SKumar Gala 		.bit	= 6,
1961cd8e506SKumar Gala 		.prio_mask = 6,
1971cd8e506SKumar Gala 	},
1981cd8e506SKumar Gala 	[23] = {
19977d4309eSLi Yang 		.ack	= IPIC_SEPNR,
2001cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
2011cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
2021cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
2031cd8e506SKumar Gala 		.bit	= 7,
2041cd8e506SKumar Gala 		.prio_mask = 7,
2051cd8e506SKumar Gala 	},
2061cd8e506SKumar Gala 	[32] = {
2071cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2081cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2091cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2101cd8e506SKumar Gala 		.bit	= 0,
2111cd8e506SKumar Gala 		.prio_mask = 0,
2121cd8e506SKumar Gala 	},
2131cd8e506SKumar Gala 	[33] = {
2141cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2151cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2161cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2171cd8e506SKumar Gala 		.bit	= 1,
2181cd8e506SKumar Gala 		.prio_mask = 1,
2191cd8e506SKumar Gala 	},
2201cd8e506SKumar Gala 	[34] = {
2211cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2221cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2231cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2241cd8e506SKumar Gala 		.bit	= 2,
2251cd8e506SKumar Gala 		.prio_mask = 2,
2261cd8e506SKumar Gala 	},
2271cd8e506SKumar Gala 	[35] = {
2281cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2291cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2301cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2311cd8e506SKumar Gala 		.bit	= 3,
2321cd8e506SKumar Gala 		.prio_mask = 3,
2331cd8e506SKumar Gala 	},
2341cd8e506SKumar Gala 	[36] = {
2351cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2361cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2371cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2381cd8e506SKumar Gala 		.bit	= 4,
2391cd8e506SKumar Gala 		.prio_mask = 4,
2401cd8e506SKumar Gala 	},
2411cd8e506SKumar Gala 	[37] = {
2421cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2431cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2441cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2451cd8e506SKumar Gala 		.bit	= 5,
2461cd8e506SKumar Gala 		.prio_mask = 5,
2471cd8e506SKumar Gala 	},
2481cd8e506SKumar Gala 	[38] = {
2491cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2501cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2511cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2521cd8e506SKumar Gala 		.bit	= 6,
2531cd8e506SKumar Gala 		.prio_mask = 6,
2541cd8e506SKumar Gala 	},
2551cd8e506SKumar Gala 	[39] = {
2561cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_H,
2571cd8e506SKumar Gala 		.prio	= IPIC_SIPRR_A,
2581cd8e506SKumar Gala 		.force	= IPIC_SIFCR_H,
2591cd8e506SKumar Gala 		.bit	= 7,
2601cd8e506SKumar Gala 		.prio_mask = 7,
2611cd8e506SKumar Gala 	},
262a7267d67SJohn Rigby 	[40] = {
263a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
264a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_B,
265a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
266a7267d67SJohn Rigby 		.bit	= 8,
267a7267d67SJohn Rigby 		.prio_mask = 0,
268a7267d67SJohn Rigby 	},
269a7267d67SJohn Rigby 	[41] = {
270a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
271a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_B,
272a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
273a7267d67SJohn Rigby 		.bit	= 9,
274a7267d67SJohn Rigby 		.prio_mask = 1,
275a7267d67SJohn Rigby 	},
276f03ca957SLi Yang 	[42] = {
277f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
278f03ca957SLi Yang 		.prio	= IPIC_SIPRR_B,
279f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
280f03ca957SLi Yang 		.bit	= 10,
281f03ca957SLi Yang 		.prio_mask = 2,
282f03ca957SLi Yang 	},
283a7267d67SJohn Rigby 	[43] = {
284a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_H,
285a7267d67SJohn Rigby 		.prio	= IPIC_SIPRR_B,
286a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_H,
287a7267d67SJohn Rigby 		.bit	= 11,
288a7267d67SJohn Rigby 		.prio_mask = 3,
289a7267d67SJohn Rigby 	},
290f03ca957SLi Yang 	[44] = {
291f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
292f03ca957SLi Yang 		.prio	= IPIC_SIPRR_B,
293f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
294f03ca957SLi Yang 		.bit	= 12,
295f03ca957SLi Yang 		.prio_mask = 4,
296f03ca957SLi Yang 	},
297f03ca957SLi Yang 	[45] = {
298f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
299f03ca957SLi Yang 		.prio	= IPIC_SIPRR_B,
300f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
301f03ca957SLi Yang 		.bit	= 13,
302f03ca957SLi Yang 		.prio_mask = 5,
303f03ca957SLi Yang 	},
304f03ca957SLi Yang 	[46] = {
305f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
306f03ca957SLi Yang 		.prio	= IPIC_SIPRR_B,
307f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
308f03ca957SLi Yang 		.bit	= 14,
309f03ca957SLi Yang 		.prio_mask = 6,
310f03ca957SLi Yang 	},
311f03ca957SLi Yang 	[47] = {
312f03ca957SLi Yang 		.mask	= IPIC_SIMSR_H,
313f03ca957SLi Yang 		.prio	= IPIC_SIPRR_B,
314f03ca957SLi Yang 		.force	= IPIC_SIFCR_H,
315f03ca957SLi Yang 		.bit	= 15,
316f03ca957SLi Yang 		.prio_mask = 7,
317f03ca957SLi Yang 	},
3181cd8e506SKumar Gala 	[48] = {
3191cd8e506SKumar Gala 		.mask	= IPIC_SEMSR,
3201cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
3211cd8e506SKumar Gala 		.force	= IPIC_SEFCR,
3221cd8e506SKumar Gala 		.bit	= 0,
3231cd8e506SKumar Gala 		.prio_mask = 4,
3241cd8e506SKumar Gala 	},
3251cd8e506SKumar Gala 	[64] = {
3261cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3271cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
3281cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3291cd8e506SKumar Gala 		.bit	= 0,
3301cd8e506SKumar Gala 		.prio_mask = 0,
3311cd8e506SKumar Gala 	},
3321cd8e506SKumar Gala 	[65] = {
3331cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3341cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
3351cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3361cd8e506SKumar Gala 		.bit	= 1,
3371cd8e506SKumar Gala 		.prio_mask = 1,
3381cd8e506SKumar Gala 	},
3391cd8e506SKumar Gala 	[66] = {
3401cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3411cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
3421cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3431cd8e506SKumar Gala 		.bit	= 2,
3441cd8e506SKumar Gala 		.prio_mask = 2,
3451cd8e506SKumar Gala 	},
3461cd8e506SKumar Gala 	[67] = {
3471cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3481cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_A,
3491cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3501cd8e506SKumar Gala 		.bit	= 3,
3511cd8e506SKumar Gala 		.prio_mask = 3,
3521cd8e506SKumar Gala 	},
3531cd8e506SKumar Gala 	[68] = {
3541cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3551cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
3561cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3571cd8e506SKumar Gala 		.bit	= 4,
3581cd8e506SKumar Gala 		.prio_mask = 0,
3591cd8e506SKumar Gala 	},
3601cd8e506SKumar Gala 	[69] = {
3611cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3621cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
3631cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3641cd8e506SKumar Gala 		.bit	= 5,
3651cd8e506SKumar Gala 		.prio_mask = 1,
3661cd8e506SKumar Gala 	},
3671cd8e506SKumar Gala 	[70] = {
3681cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3691cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
3701cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3711cd8e506SKumar Gala 		.bit	= 6,
3721cd8e506SKumar Gala 		.prio_mask = 2,
3731cd8e506SKumar Gala 	},
3741cd8e506SKumar Gala 	[71] = {
3751cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3761cd8e506SKumar Gala 		.prio	= IPIC_SMPRR_B,
3771cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3781cd8e506SKumar Gala 		.bit	= 7,
3791cd8e506SKumar Gala 		.prio_mask = 3,
3801cd8e506SKumar Gala 	},
3811cd8e506SKumar Gala 	[72] = {
3821cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3831cd8e506SKumar Gala 		.prio	= 0,
3841cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3851cd8e506SKumar Gala 		.bit	= 8,
3861cd8e506SKumar Gala 	},
3871cd8e506SKumar Gala 	[73] = {
3881cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3891cd8e506SKumar Gala 		.prio	= 0,
3901cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3911cd8e506SKumar Gala 		.bit	= 9,
3921cd8e506SKumar Gala 	},
3931cd8e506SKumar Gala 	[74] = {
3941cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
3951cd8e506SKumar Gala 		.prio	= 0,
3961cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
3971cd8e506SKumar Gala 		.bit	= 10,
3981cd8e506SKumar Gala 	},
3991cd8e506SKumar Gala 	[75] = {
4001cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4011cd8e506SKumar Gala 		.prio	= 0,
4021cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4031cd8e506SKumar Gala 		.bit	= 11,
4041cd8e506SKumar Gala 	},
4051cd8e506SKumar Gala 	[76] = {
4061cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4071cd8e506SKumar Gala 		.prio	= 0,
4081cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4091cd8e506SKumar Gala 		.bit	= 12,
4101cd8e506SKumar Gala 	},
4111cd8e506SKumar Gala 	[77] = {
4121cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4131cd8e506SKumar Gala 		.prio	= 0,
4141cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4151cd8e506SKumar Gala 		.bit	= 13,
4161cd8e506SKumar Gala 	},
4171cd8e506SKumar Gala 	[78] = {
4181cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4191cd8e506SKumar Gala 		.prio	= 0,
4201cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4211cd8e506SKumar Gala 		.bit	= 14,
4221cd8e506SKumar Gala 	},
4231cd8e506SKumar Gala 	[79] = {
4241cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4251cd8e506SKumar Gala 		.prio	= 0,
4261cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4271cd8e506SKumar Gala 		.bit	= 15,
4281cd8e506SKumar Gala 	},
4291cd8e506SKumar Gala 	[80] = {
4301cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4311cd8e506SKumar Gala 		.prio	= 0,
4321cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4331cd8e506SKumar Gala 		.bit	= 16,
4341cd8e506SKumar Gala 	},
435f03ca957SLi Yang 	[81] = {
436f03ca957SLi Yang 		.mask	= IPIC_SIMSR_L,
437f03ca957SLi Yang 		.prio	= 0,
438f03ca957SLi Yang 		.force	= IPIC_SIFCR_L,
439f03ca957SLi Yang 		.bit	= 17,
440f03ca957SLi Yang 	},
441f03ca957SLi Yang 	[82] = {
442f03ca957SLi Yang 		.mask	= IPIC_SIMSR_L,
443f03ca957SLi Yang 		.prio	= 0,
444f03ca957SLi Yang 		.force	= IPIC_SIFCR_L,
445f03ca957SLi Yang 		.bit	= 18,
446f03ca957SLi Yang 	},
447a7267d67SJohn Rigby 	[83] = {
448a7267d67SJohn Rigby 		.mask	= IPIC_SIMSR_L,
449a7267d67SJohn Rigby 		.prio	= 0,
450a7267d67SJohn Rigby 		.force	= IPIC_SIFCR_L,
451a7267d67SJohn Rigby 		.bit	= 19,
452a7267d67SJohn Rigby 	},
4531cd8e506SKumar Gala 	[84] = {
4541cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4551cd8e506SKumar Gala 		.prio	= 0,
4561cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4571cd8e506SKumar Gala 		.bit	= 20,
4581cd8e506SKumar Gala 	},
4591cd8e506SKumar Gala 	[85] = {
4601cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4611cd8e506SKumar Gala 		.prio	= 0,
4621cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4631cd8e506SKumar Gala 		.bit	= 21,
4641cd8e506SKumar Gala 	},
465f03ca957SLi Yang 	[86] = {
466f03ca957SLi Yang 		.mask	= IPIC_SIMSR_L,
467f03ca957SLi Yang 		.prio	= 0,
468f03ca957SLi Yang 		.force	= IPIC_SIFCR_L,
469f03ca957SLi Yang 		.bit	= 22,
470f03ca957SLi Yang 	},
471f03ca957SLi Yang 	[87] = {
472f03ca957SLi Yang 		.mask	= IPIC_SIMSR_L,
473f03ca957SLi Yang 		.prio	= 0,
474f03ca957SLi Yang 		.force	= IPIC_SIFCR_L,
475f03ca957SLi Yang 		.bit	= 23,
476f03ca957SLi Yang 	},
477f03ca957SLi Yang 	[88] = {
478f03ca957SLi Yang 		.mask	= IPIC_SIMSR_L,
479f03ca957SLi Yang 		.prio	= 0,
480f03ca957SLi Yang 		.force	= IPIC_SIFCR_L,
481f03ca957SLi Yang 		.bit	= 24,
482f03ca957SLi Yang 	},
483f03ca957SLi Yang 	[89] = {
484f03ca957SLi Yang 		.mask	= IPIC_SIMSR_L,
485f03ca957SLi Yang 		.prio	= 0,
486f03ca957SLi Yang 		.force	= IPIC_SIFCR_L,
487f03ca957SLi Yang 		.bit	= 25,
488f03ca957SLi Yang 	},
4891cd8e506SKumar Gala 	[90] = {
4901cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4911cd8e506SKumar Gala 		.prio	= 0,
4921cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4931cd8e506SKumar Gala 		.bit	= 26,
4941cd8e506SKumar Gala 	},
4951cd8e506SKumar Gala 	[91] = {
4961cd8e506SKumar Gala 		.mask	= IPIC_SIMSR_L,
4971cd8e506SKumar Gala 		.prio	= 0,
4981cd8e506SKumar Gala 		.force	= IPIC_SIFCR_L,
4991cd8e506SKumar Gala 		.bit	= 27,
5001cd8e506SKumar Gala 	},
5018cf6b195SKim Phillips 	[94] = {
5028cf6b195SKim Phillips 		.mask	= IPIC_SIMSR_L,
5038cf6b195SKim Phillips 		.prio	= 0,
5048cf6b195SKim Phillips 		.force	= IPIC_SIFCR_L,
5058cf6b195SKim Phillips 		.bit	= 30,
5068cf6b195SKim Phillips 	},
5071cd8e506SKumar Gala };
5081cd8e506SKumar Gala 
5091cd8e506SKumar Gala static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg)
5101cd8e506SKumar Gala {
5111cd8e506SKumar Gala 	return in_be32(base + (reg >> 2));
5121cd8e506SKumar Gala }
5131cd8e506SKumar Gala 
5141cd8e506SKumar Gala static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value)
5151cd8e506SKumar Gala {
5161cd8e506SKumar Gala 	out_be32(base + (reg >> 2), value);
5171cd8e506SKumar Gala }
5181cd8e506SKumar Gala 
519b9f0f1bbSKim Phillips static inline struct ipic * ipic_from_irq(unsigned int virq)
5201cd8e506SKumar Gala {
5211cd8e506SKumar Gala 	return primary_ipic;
5221cd8e506SKumar Gala }
5231cd8e506SKumar Gala 
524b9f0f1bbSKim Phillips #define ipic_irq_to_hw(virq)	((unsigned int)irq_map[virq].hwirq)
525b9f0f1bbSKim Phillips 
526b9f0f1bbSKim Phillips static void ipic_unmask_irq(unsigned int virq)
5271cd8e506SKumar Gala {
528b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
529b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
530b9f0f1bbSKim Phillips 	unsigned long flags;
5311cd8e506SKumar Gala 	u32 temp;
5321cd8e506SKumar Gala 
533b9f0f1bbSKim Phillips 	spin_lock_irqsave(&ipic_lock, flags);
534b9f0f1bbSKim Phillips 
5351cd8e506SKumar Gala 	temp = ipic_read(ipic->regs, ipic_info[src].mask);
5361cd8e506SKumar Gala 	temp |= (1 << (31 - ipic_info[src].bit));
5371cd8e506SKumar Gala 	ipic_write(ipic->regs, ipic_info[src].mask, temp);
538b9f0f1bbSKim Phillips 
539b9f0f1bbSKim Phillips 	spin_unlock_irqrestore(&ipic_lock, flags);
5401cd8e506SKumar Gala }
5411cd8e506SKumar Gala 
542b9f0f1bbSKim Phillips static void ipic_mask_irq(unsigned int virq)
5431cd8e506SKumar Gala {
544b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
545b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
546b9f0f1bbSKim Phillips 	unsigned long flags;
5471cd8e506SKumar Gala 	u32 temp;
5481cd8e506SKumar Gala 
549b9f0f1bbSKim Phillips 	spin_lock_irqsave(&ipic_lock, flags);
550b9f0f1bbSKim Phillips 
5511cd8e506SKumar Gala 	temp = ipic_read(ipic->regs, ipic_info[src].mask);
5521cd8e506SKumar Gala 	temp &= ~(1 << (31 - ipic_info[src].bit));
5531cd8e506SKumar Gala 	ipic_write(ipic->regs, ipic_info[src].mask, temp);
554b9f0f1bbSKim Phillips 
55577d4309eSLi Yang 	/* mb() can't guarantee that masking is finished.  But it does finish
55677d4309eSLi Yang 	 * for nearly all cases. */
55777d4309eSLi Yang 	mb();
55877d4309eSLi Yang 
559b9f0f1bbSKim Phillips 	spin_unlock_irqrestore(&ipic_lock, flags);
5601cd8e506SKumar Gala }
5611cd8e506SKumar Gala 
562b9f0f1bbSKim Phillips static void ipic_ack_irq(unsigned int virq)
5631cd8e506SKumar Gala {
564b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
565b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
566b9f0f1bbSKim Phillips 	unsigned long flags;
5671cd8e506SKumar Gala 	u32 temp;
5681cd8e506SKumar Gala 
569b9f0f1bbSKim Phillips 	spin_lock_irqsave(&ipic_lock, flags);
5701cd8e506SKumar Gala 
571*30c40469Sdayu@datangmobile.cn 	temp = 1 << (31 - ipic_info[src].bit);
57277d4309eSLi Yang 	ipic_write(ipic->regs, ipic_info[src].ack, temp);
57377d4309eSLi Yang 
57477d4309eSLi Yang 	/* mb() can't guarantee that ack is finished.  But it does finish
57577d4309eSLi Yang 	 * for nearly all cases. */
57677d4309eSLi Yang 	mb();
577b9f0f1bbSKim Phillips 
578b9f0f1bbSKim Phillips 	spin_unlock_irqrestore(&ipic_lock, flags);
5791cd8e506SKumar Gala }
5801cd8e506SKumar Gala 
581b9f0f1bbSKim Phillips static void ipic_mask_irq_and_ack(unsigned int virq)
5821cd8e506SKumar Gala {
583b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
584b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
585b9f0f1bbSKim Phillips 	unsigned long flags;
586b9f0f1bbSKim Phillips 	u32 temp;
587b9f0f1bbSKim Phillips 
588b9f0f1bbSKim Phillips 	spin_lock_irqsave(&ipic_lock, flags);
589b9f0f1bbSKim Phillips 
590b9f0f1bbSKim Phillips 	temp = ipic_read(ipic->regs, ipic_info[src].mask);
591b9f0f1bbSKim Phillips 	temp &= ~(1 << (31 - ipic_info[src].bit));
592b9f0f1bbSKim Phillips 	ipic_write(ipic->regs, ipic_info[src].mask, temp);
593b9f0f1bbSKim Phillips 
594*30c40469Sdayu@datangmobile.cn 	temp = 1 << (31 - ipic_info[src].bit);
59577d4309eSLi Yang 	ipic_write(ipic->regs, ipic_info[src].ack, temp);
59677d4309eSLi Yang 
59777d4309eSLi Yang 	/* mb() can't guarantee that ack is finished.  But it does finish
59877d4309eSLi Yang 	 * for nearly all cases. */
59977d4309eSLi Yang 	mb();
600b9f0f1bbSKim Phillips 
601b9f0f1bbSKim Phillips 	spin_unlock_irqrestore(&ipic_lock, flags);
6021cd8e506SKumar Gala }
6031cd8e506SKumar Gala 
604b9f0f1bbSKim Phillips static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
605b9f0f1bbSKim Phillips {
606b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
607b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
608b9f0f1bbSKim Phillips 	struct irq_desc *desc = get_irq_desc(virq);
609b9f0f1bbSKim Phillips 	unsigned int vold, vnew, edibit;
610b9f0f1bbSKim Phillips 
611b9f0f1bbSKim Phillips 	if (flow_type == IRQ_TYPE_NONE)
612b9f0f1bbSKim Phillips 		flow_type = IRQ_TYPE_LEVEL_LOW;
613b9f0f1bbSKim Phillips 
614b9f0f1bbSKim Phillips 	/* ipic supports only low assertion and high-to-low change senses
615b9f0f1bbSKim Phillips 	 */
616b9f0f1bbSKim Phillips 	if (!(flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))) {
617b9f0f1bbSKim Phillips 		printk(KERN_ERR "ipic: sense type 0x%x not supported\n",
618b9f0f1bbSKim Phillips 			flow_type);
619b9f0f1bbSKim Phillips 		return -EINVAL;
620b9f0f1bbSKim Phillips 	}
62177d4309eSLi Yang 	/* ipic supports only edge mode on external interrupts */
62277d4309eSLi Yang 	if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !ipic_info[src].ack) {
62377d4309eSLi Yang 		printk(KERN_ERR "ipic: edge sense not supported on internal "
62477d4309eSLi Yang 				"interrupts\n");
62577d4309eSLi Yang 		return -EINVAL;
62677d4309eSLi Yang 	}
627b9f0f1bbSKim Phillips 
628b9f0f1bbSKim Phillips 	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
629b9f0f1bbSKim Phillips 	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
630b9f0f1bbSKim Phillips 	if (flow_type & IRQ_TYPE_LEVEL_LOW)  {
631b9f0f1bbSKim Phillips 		desc->status |= IRQ_LEVEL;
632f49196a5SScott Wood 		desc->handle_irq = handle_level_irq;
63377d4309eSLi Yang 		desc->chip = &ipic_level_irq_chip;
634b9f0f1bbSKim Phillips 	} else {
635f49196a5SScott Wood 		desc->handle_irq = handle_edge_irq;
63677d4309eSLi Yang 		desc->chip = &ipic_edge_irq_chip;
637b9f0f1bbSKim Phillips 	}
638b9f0f1bbSKim Phillips 
639b9f0f1bbSKim Phillips 	/* only EXT IRQ senses are programmable on ipic
640b9f0f1bbSKim Phillips 	 * internal IRQ senses are LEVEL_LOW
641b9f0f1bbSKim Phillips 	 */
642b9f0f1bbSKim Phillips 	if (src == IPIC_IRQ_EXT0)
643b9f0f1bbSKim Phillips 		edibit = 15;
644b9f0f1bbSKim Phillips 	else
645b9f0f1bbSKim Phillips 		if (src >= IPIC_IRQ_EXT1 && src <= IPIC_IRQ_EXT7)
646b9f0f1bbSKim Phillips 			edibit = (14 - (src - IPIC_IRQ_EXT1));
647b9f0f1bbSKim Phillips 		else
648b9f0f1bbSKim Phillips 			return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
649b9f0f1bbSKim Phillips 
650b9f0f1bbSKim Phillips 	vold = ipic_read(ipic->regs, IPIC_SECNR);
651b9f0f1bbSKim Phillips 	if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) {
652b9f0f1bbSKim Phillips 		vnew = vold | (1 << edibit);
653b9f0f1bbSKim Phillips 	} else {
654b9f0f1bbSKim Phillips 		vnew = vold & ~(1 << edibit);
655b9f0f1bbSKim Phillips 	}
656b9f0f1bbSKim Phillips 	if (vold != vnew)
657b9f0f1bbSKim Phillips 		ipic_write(ipic->regs, IPIC_SECNR, vnew);
658b9f0f1bbSKim Phillips 	return 0;
659b9f0f1bbSKim Phillips }
660b9f0f1bbSKim Phillips 
66177d4309eSLi Yang /* level interrupts and edge interrupts have different ack operations */
66277d4309eSLi Yang static struct irq_chip ipic_level_irq_chip = {
66377d4309eSLi Yang 	.typename	= " IPIC  ",
66477d4309eSLi Yang 	.unmask		= ipic_unmask_irq,
66577d4309eSLi Yang 	.mask		= ipic_mask_irq,
66677d4309eSLi Yang 	.mask_ack	= ipic_mask_irq,
66777d4309eSLi Yang 	.set_type	= ipic_set_irq_type,
66877d4309eSLi Yang };
66977d4309eSLi Yang 
67077d4309eSLi Yang static struct irq_chip ipic_edge_irq_chip = {
6711cd8e506SKumar Gala 	.typename	= " IPIC  ",
672b9f0f1bbSKim Phillips 	.unmask		= ipic_unmask_irq,
673b9f0f1bbSKim Phillips 	.mask		= ipic_mask_irq,
674b9f0f1bbSKim Phillips 	.mask_ack	= ipic_mask_irq_and_ack,
675b9f0f1bbSKim Phillips 	.ack		= ipic_ack_irq,
676b9f0f1bbSKim Phillips 	.set_type	= ipic_set_irq_type,
6771cd8e506SKumar Gala };
6781cd8e506SKumar Gala 
679b9f0f1bbSKim Phillips static int ipic_host_match(struct irq_host *h, struct device_node *node)
6801cd8e506SKumar Gala {
681b9f0f1bbSKim Phillips 	/* Exact match, unless ipic node is NULL */
68252964f87SMichael Ellerman 	return h->of_node == NULL || h->of_node == node;
683b9f0f1bbSKim Phillips }
6841cd8e506SKumar Gala 
685b9f0f1bbSKim Phillips static int ipic_host_map(struct irq_host *h, unsigned int virq,
686b9f0f1bbSKim Phillips 			 irq_hw_number_t hw)
687b9f0f1bbSKim Phillips {
688b9f0f1bbSKim Phillips 	struct ipic *ipic = h->host_data;
689b9f0f1bbSKim Phillips 
690b9f0f1bbSKim Phillips 	set_irq_chip_data(virq, ipic);
69177d4309eSLi Yang 	set_irq_chip_and_handler(virq, &ipic_level_irq_chip, handle_level_irq);
692b9f0f1bbSKim Phillips 
693b9f0f1bbSKim Phillips 	/* Set default irq type */
694b9f0f1bbSKim Phillips 	set_irq_type(virq, IRQ_TYPE_NONE);
695b9f0f1bbSKim Phillips 
696b9f0f1bbSKim Phillips 	return 0;
697b9f0f1bbSKim Phillips }
698b9f0f1bbSKim Phillips 
699b9f0f1bbSKim Phillips static int ipic_host_xlate(struct irq_host *h, struct device_node *ct,
700b9f0f1bbSKim Phillips 			   u32 *intspec, unsigned int intsize,
701b9f0f1bbSKim Phillips 			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)
702b9f0f1bbSKim Phillips 
703b9f0f1bbSKim Phillips {
704b9f0f1bbSKim Phillips 	/* interrupt sense values coming from the device tree equal either
705b9f0f1bbSKim Phillips 	 * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change)
706b9f0f1bbSKim Phillips 	 */
707b9f0f1bbSKim Phillips 	*out_hwirq = intspec[0];
708b9f0f1bbSKim Phillips 	if (intsize > 1)
709b9f0f1bbSKim Phillips 		*out_flags = intspec[1];
710b9f0f1bbSKim Phillips 	else
711b9f0f1bbSKim Phillips 		*out_flags = IRQ_TYPE_NONE;
712b9f0f1bbSKim Phillips 	return 0;
713b9f0f1bbSKim Phillips }
714b9f0f1bbSKim Phillips 
715b9f0f1bbSKim Phillips static struct irq_host_ops ipic_host_ops = {
716b9f0f1bbSKim Phillips 	.match	= ipic_host_match,
717b9f0f1bbSKim Phillips 	.map	= ipic_host_map,
718b9f0f1bbSKim Phillips 	.xlate	= ipic_host_xlate,
719b9f0f1bbSKim Phillips };
720b9f0f1bbSKim Phillips 
721126186a0SKumar Gala struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
722b9f0f1bbSKim Phillips {
723b9f0f1bbSKim Phillips 	struct ipic	*ipic;
724b9f0f1bbSKim Phillips 	struct resource res;
725b9f0f1bbSKim Phillips 	u32 temp = 0, ret;
726b9f0f1bbSKim Phillips 
72784f1c1e0SMichael Ellerman 	ret = of_address_to_resource(node, 0, &res);
72884f1c1e0SMichael Ellerman 	if (ret)
72984f1c1e0SMichael Ellerman 		return NULL;
73084f1c1e0SMichael Ellerman 
731b9f0f1bbSKim Phillips 	ipic = alloc_bootmem(sizeof(struct ipic));
732b9f0f1bbSKim Phillips 	if (ipic == NULL)
733126186a0SKumar Gala 		return NULL;
734b9f0f1bbSKim Phillips 
735b9f0f1bbSKim Phillips 	memset(ipic, 0, sizeof(struct ipic));
736b9f0f1bbSKim Phillips 
73719fc65b5SMichael Ellerman 	ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
738b9f0f1bbSKim Phillips 				       NR_IPIC_INTS,
739b9f0f1bbSKim Phillips 				       &ipic_host_ops, 0);
74019fc65b5SMichael Ellerman 	if (ipic->irqhost == NULL)
741126186a0SKumar Gala 		return NULL;
742b9f0f1bbSKim Phillips 
743b9f0f1bbSKim Phillips 	ipic->regs = ioremap(res.start, res.end - res.start + 1);
744b9f0f1bbSKim Phillips 
745b9f0f1bbSKim Phillips 	ipic->irqhost->host_data = ipic;
746b9f0f1bbSKim Phillips 
747b9f0f1bbSKim Phillips 	/* init hw */
748b9f0f1bbSKim Phillips 	ipic_write(ipic->regs, IPIC_SICNR, 0x0);
7491cd8e506SKumar Gala 
7501cd8e506SKumar Gala 	/* default priority scheme is grouped. If spread mode is required
7511cd8e506SKumar Gala 	 * configure SICFR accordingly */
7521cd8e506SKumar Gala 	if (flags & IPIC_SPREADMODE_GRP_A)
7531cd8e506SKumar Gala 		temp |= SICFR_IPSA;
754f03ca957SLi Yang 	if (flags & IPIC_SPREADMODE_GRP_B)
755f03ca957SLi Yang 		temp |= SICFR_IPSB;
756f03ca957SLi Yang 	if (flags & IPIC_SPREADMODE_GRP_C)
757f03ca957SLi Yang 		temp |= SICFR_IPSC;
7581cd8e506SKumar Gala 	if (flags & IPIC_SPREADMODE_GRP_D)
7591cd8e506SKumar Gala 		temp |= SICFR_IPSD;
7601cd8e506SKumar Gala 	if (flags & IPIC_SPREADMODE_MIX_A)
7611cd8e506SKumar Gala 		temp |= SICFR_MPSA;
7621cd8e506SKumar Gala 	if (flags & IPIC_SPREADMODE_MIX_B)
7631cd8e506SKumar Gala 		temp |= SICFR_MPSB;
7641cd8e506SKumar Gala 
765f03ca957SLi Yang 	ipic_write(ipic->regs, IPIC_SICFR, temp);
7661cd8e506SKumar Gala 
7671cd8e506SKumar Gala 	/* handle MCP route */
7681cd8e506SKumar Gala 	temp = 0;
7691cd8e506SKumar Gala 	if (flags & IPIC_DISABLE_MCP_OUT)
7701cd8e506SKumar Gala 		temp = SERCR_MCPR;
771b9f0f1bbSKim Phillips 	ipic_write(ipic->regs, IPIC_SERCR, temp);
7721cd8e506SKumar Gala 
7731cd8e506SKumar Gala 	/* handle routing of IRQ0 to MCP */
774b9f0f1bbSKim Phillips 	temp = ipic_read(ipic->regs, IPIC_SEMSR);
7751cd8e506SKumar Gala 
7761cd8e506SKumar Gala 	if (flags & IPIC_IRQ0_MCP)
7771cd8e506SKumar Gala 		temp |= SEMSR_SIRQ0;
7781cd8e506SKumar Gala 	else
7791cd8e506SKumar Gala 		temp &= ~SEMSR_SIRQ0;
7801cd8e506SKumar Gala 
781b9f0f1bbSKim Phillips 	ipic_write(ipic->regs, IPIC_SEMSR, temp);
7821cd8e506SKumar Gala 
783b9f0f1bbSKim Phillips 	primary_ipic = ipic;
784b9f0f1bbSKim Phillips 	irq_set_default_host(primary_ipic->irqhost);
785b9f0f1bbSKim Phillips 
786b9f0f1bbSKim Phillips 	printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,
787b9f0f1bbSKim Phillips 			primary_ipic->regs);
788126186a0SKumar Gala 
789126186a0SKumar Gala 	return ipic;
7901cd8e506SKumar Gala }
7911cd8e506SKumar Gala 
792b9f0f1bbSKim Phillips int ipic_set_priority(unsigned int virq, unsigned int priority)
7931cd8e506SKumar Gala {
794b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
795b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
7961cd8e506SKumar Gala 	u32 temp;
7971cd8e506SKumar Gala 
7981cd8e506SKumar Gala 	if (priority > 7)
7991cd8e506SKumar Gala 		return -EINVAL;
8001cd8e506SKumar Gala 	if (src > 127)
8011cd8e506SKumar Gala 		return -EINVAL;
8021cd8e506SKumar Gala 	if (ipic_info[src].prio == 0)
8031cd8e506SKumar Gala 		return -EINVAL;
8041cd8e506SKumar Gala 
8051cd8e506SKumar Gala 	temp = ipic_read(ipic->regs, ipic_info[src].prio);
8061cd8e506SKumar Gala 
8071cd8e506SKumar Gala 	if (priority < 4) {
8081cd8e506SKumar Gala 		temp &= ~(0x7 << (20 + (3 - priority) * 3));
8091cd8e506SKumar Gala 		temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);
8101cd8e506SKumar Gala 	} else {
8111cd8e506SKumar Gala 		temp &= ~(0x7 << (4 + (7 - priority) * 3));
8121cd8e506SKumar Gala 		temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);
8131cd8e506SKumar Gala 	}
8141cd8e506SKumar Gala 
8151cd8e506SKumar Gala 	ipic_write(ipic->regs, ipic_info[src].prio, temp);
8161cd8e506SKumar Gala 
8171cd8e506SKumar Gala 	return 0;
8181cd8e506SKumar Gala }
8191cd8e506SKumar Gala 
820b9f0f1bbSKim Phillips void ipic_set_highest_priority(unsigned int virq)
8211cd8e506SKumar Gala {
822b9f0f1bbSKim Phillips 	struct ipic *ipic = ipic_from_irq(virq);
823b9f0f1bbSKim Phillips 	unsigned int src = ipic_irq_to_hw(virq);
8241cd8e506SKumar Gala 	u32 temp;
8251cd8e506SKumar Gala 
8261cd8e506SKumar Gala 	temp = ipic_read(ipic->regs, IPIC_SICFR);
8271cd8e506SKumar Gala 
8281cd8e506SKumar Gala 	/* clear and set HPI */
8291cd8e506SKumar Gala 	temp &= 0x7f000000;
8301cd8e506SKumar Gala 	temp |= (src & 0x7f) << 24;
8311cd8e506SKumar Gala 
8321cd8e506SKumar Gala 	ipic_write(ipic->regs, IPIC_SICFR, temp);
8331cd8e506SKumar Gala }
8341cd8e506SKumar Gala 
8351cd8e506SKumar Gala void ipic_set_default_priority(void)
8361cd8e506SKumar Gala {
837f03ca957SLi Yang 	ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_PRIORITY_DEFAULT);
838f03ca957SLi Yang 	ipic_write(primary_ipic->regs, IPIC_SIPRR_B, IPIC_PRIORITY_DEFAULT);
839f03ca957SLi Yang 	ipic_write(primary_ipic->regs, IPIC_SIPRR_C, IPIC_PRIORITY_DEFAULT);
840f03ca957SLi Yang 	ipic_write(primary_ipic->regs, IPIC_SIPRR_D, IPIC_PRIORITY_DEFAULT);
841f03ca957SLi Yang 	ipic_write(primary_ipic->regs, IPIC_SMPRR_A, IPIC_PRIORITY_DEFAULT);
842f03ca957SLi Yang 	ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_PRIORITY_DEFAULT);
8431cd8e506SKumar Gala }
8441cd8e506SKumar Gala 
8451cd8e506SKumar Gala void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
8461cd8e506SKumar Gala {
8471cd8e506SKumar Gala 	struct ipic *ipic = primary_ipic;
8481cd8e506SKumar Gala 	u32 temp;
8491cd8e506SKumar Gala 
8501cd8e506SKumar Gala 	temp = ipic_read(ipic->regs, IPIC_SERMR);
8511cd8e506SKumar Gala 	temp |= (1 << (31 - mcp_irq));
8521cd8e506SKumar Gala 	ipic_write(ipic->regs, IPIC_SERMR, temp);
8531cd8e506SKumar Gala }
8541cd8e506SKumar Gala 
8551cd8e506SKumar Gala void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
8561cd8e506SKumar Gala {
8571cd8e506SKumar Gala 	struct ipic *ipic = primary_ipic;
8581cd8e506SKumar Gala 	u32 temp;
8591cd8e506SKumar Gala 
8601cd8e506SKumar Gala 	temp = ipic_read(ipic->regs, IPIC_SERMR);
8611cd8e506SKumar Gala 	temp &= (1 << (31 - mcp_irq));
8621cd8e506SKumar Gala 	ipic_write(ipic->regs, IPIC_SERMR, temp);
8631cd8e506SKumar Gala }
8641cd8e506SKumar Gala 
8651cd8e506SKumar Gala u32 ipic_get_mcp_status(void)
8661cd8e506SKumar Gala {
8671cd8e506SKumar Gala 	return ipic_read(primary_ipic->regs, IPIC_SERMR);
8681cd8e506SKumar Gala }
8691cd8e506SKumar Gala 
8701cd8e506SKumar Gala void ipic_clear_mcp_status(u32 mask)
8711cd8e506SKumar Gala {
8721cd8e506SKumar Gala 	ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
8731cd8e506SKumar Gala }
8741cd8e506SKumar Gala 
875b9f0f1bbSKim Phillips /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
87635a84c2fSOlaf Hering unsigned int ipic_get_irq(void)
8771cd8e506SKumar Gala {
8781cd8e506SKumar Gala 	int irq;
8791cd8e506SKumar Gala 
880b9f0f1bbSKim Phillips 	BUG_ON(primary_ipic == NULL);
881b9f0f1bbSKim Phillips 
882b9f0f1bbSKim Phillips #define IPIC_SIVCR_VECTOR_MASK	0x7f
883b9f0f1bbSKim Phillips 	irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK;
8841cd8e506SKumar Gala 
8851cd8e506SKumar Gala 	if (irq == 0)    /* 0 --> no irq is pending */
886b9f0f1bbSKim Phillips 		return NO_IRQ;
8871cd8e506SKumar Gala 
888b9f0f1bbSKim Phillips 	return irq_linear_revmap(primary_ipic->irqhost, irq);
8891cd8e506SKumar Gala }
8901cd8e506SKumar Gala 
891e2a02ba6SMichael Neuling #ifdef CONFIG_SUSPEND
892d49747bdSScott Wood static struct {
893d49747bdSScott Wood 	u32 sicfr;
894d49747bdSScott Wood 	u32 siprr[2];
895d49747bdSScott Wood 	u32 simsr[2];
896d49747bdSScott Wood 	u32 sicnr;
897d49747bdSScott Wood 	u32 smprr[2];
898d49747bdSScott Wood 	u32 semsr;
899d49747bdSScott Wood 	u32 secnr;
900d49747bdSScott Wood 	u32 sermr;
901d49747bdSScott Wood 	u32 sercr;
902d49747bdSScott Wood } ipic_saved_state;
903d49747bdSScott Wood 
904d49747bdSScott Wood static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
905d49747bdSScott Wood {
906d49747bdSScott Wood 	struct ipic *ipic = primary_ipic;
907d49747bdSScott Wood 
908d49747bdSScott Wood 	ipic_saved_state.sicfr = ipic_read(ipic->regs, IPIC_SICFR);
909d49747bdSScott Wood 	ipic_saved_state.siprr[0] = ipic_read(ipic->regs, IPIC_SIPRR_A);
910d49747bdSScott Wood 	ipic_saved_state.siprr[1] = ipic_read(ipic->regs, IPIC_SIPRR_D);
911d49747bdSScott Wood 	ipic_saved_state.simsr[0] = ipic_read(ipic->regs, IPIC_SIMSR_H);
912d49747bdSScott Wood 	ipic_saved_state.simsr[1] = ipic_read(ipic->regs, IPIC_SIMSR_L);
913d49747bdSScott Wood 	ipic_saved_state.sicnr = ipic_read(ipic->regs, IPIC_SICNR);
914d49747bdSScott Wood 	ipic_saved_state.smprr[0] = ipic_read(ipic->regs, IPIC_SMPRR_A);
915d49747bdSScott Wood 	ipic_saved_state.smprr[1] = ipic_read(ipic->regs, IPIC_SMPRR_B);
916d49747bdSScott Wood 	ipic_saved_state.semsr = ipic_read(ipic->regs, IPIC_SEMSR);
917d49747bdSScott Wood 	ipic_saved_state.secnr = ipic_read(ipic->regs, IPIC_SECNR);
918d49747bdSScott Wood 	ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR);
919d49747bdSScott Wood 	ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR);
920d49747bdSScott Wood 
921d49747bdSScott Wood 	if (fsl_deep_sleep()) {
922d49747bdSScott Wood 		/* In deep sleep, make sure there can be no
923d49747bdSScott Wood 		 * pending interrupts, as this can cause
924d49747bdSScott Wood 		 * problems on 831x.
925d49747bdSScott Wood 		 */
926d49747bdSScott Wood 		ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
927d49747bdSScott Wood 		ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
928d49747bdSScott Wood 		ipic_write(ipic->regs, IPIC_SEMSR, 0);
929d49747bdSScott Wood 		ipic_write(ipic->regs, IPIC_SERMR, 0);
930d49747bdSScott Wood 	}
931d49747bdSScott Wood 
932d49747bdSScott Wood 	return 0;
933d49747bdSScott Wood }
934d49747bdSScott Wood 
935d49747bdSScott Wood static int ipic_resume(struct sys_device *sdev)
936d49747bdSScott Wood {
937d49747bdSScott Wood 	struct ipic *ipic = primary_ipic;
938d49747bdSScott Wood 
939d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SICFR, ipic_saved_state.sicfr);
940d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SIPRR_A, ipic_saved_state.siprr[0]);
941d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SIPRR_D, ipic_saved_state.siprr[1]);
942d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SIMSR_H, ipic_saved_state.simsr[0]);
943d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SIMSR_L, ipic_saved_state.simsr[1]);
944d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SICNR, ipic_saved_state.sicnr);
945d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SMPRR_A, ipic_saved_state.smprr[0]);
946d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SMPRR_B, ipic_saved_state.smprr[1]);
947d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SEMSR, ipic_saved_state.semsr);
948d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
949d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
950d49747bdSScott Wood 	ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
951d49747bdSScott Wood 
952d49747bdSScott Wood 	return 0;
953d49747bdSScott Wood }
954d49747bdSScott Wood #else
955d49747bdSScott Wood #define ipic_suspend NULL
956d49747bdSScott Wood #define ipic_resume NULL
957d49747bdSScott Wood #endif
958d49747bdSScott Wood 
9591cd8e506SKumar Gala static struct sysdev_class ipic_sysclass = {
960af5ca3f4SKay Sievers 	.name = "ipic",
961d49747bdSScott Wood 	.suspend = ipic_suspend,
962d49747bdSScott Wood 	.resume = ipic_resume,
9631cd8e506SKumar Gala };
9641cd8e506SKumar Gala 
9651cd8e506SKumar Gala static struct sys_device device_ipic = {
9661cd8e506SKumar Gala 	.id		= 0,
9671cd8e506SKumar Gala 	.cls		= &ipic_sysclass,
9681cd8e506SKumar Gala };
9691cd8e506SKumar Gala 
9701cd8e506SKumar Gala static int __init init_ipic_sysfs(void)
9711cd8e506SKumar Gala {
9721cd8e506SKumar Gala 	int rc;
9731cd8e506SKumar Gala 
9741428a9faSOlaf Hering 	if (!primary_ipic || !primary_ipic->regs)
9751cd8e506SKumar Gala 		return -ENODEV;
9761cd8e506SKumar Gala 	printk(KERN_DEBUG "Registering ipic with sysfs...\n");
9771cd8e506SKumar Gala 
9781cd8e506SKumar Gala 	rc = sysdev_class_register(&ipic_sysclass);
9791cd8e506SKumar Gala 	if (rc) {
9801cd8e506SKumar Gala 		printk(KERN_ERR "Failed registering ipic sys class\n");
9811cd8e506SKumar Gala 		return -ENODEV;
9821cd8e506SKumar Gala 	}
9831cd8e506SKumar Gala 	rc = sysdev_register(&device_ipic);
9841cd8e506SKumar Gala 	if (rc) {
9851cd8e506SKumar Gala 		printk(KERN_ERR "Failed registering ipic sys device\n");
9861cd8e506SKumar Gala 		return -ENODEV;
9871cd8e506SKumar Gala 	}
9881cd8e506SKumar Gala 	return 0;
9891cd8e506SKumar Gala }
9901cd8e506SKumar Gala 
9911cd8e506SKumar Gala subsys_initcall(init_ipic_sysfs);
992