• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/sparc/kernel/
1#include <linux/kernel.h>
2#include <linux/string.h>
3#include <linux/init.h>
4#include <linux/of.h>
5#include <linux/of_platform.h>
6
7#include <asm/oplib.h>
8#include <asm/prom.h>
9#include <asm/irq.h>
10#include <asm/upa.h>
11
12#include "prom.h"
13
14#ifdef CONFIG_PCI
15/* PSYCHO interrupt mapping support. */
16#define PSYCHO_IMAP_A_SLOT0	0x0c00UL
17#define PSYCHO_IMAP_B_SLOT0	0x0c20UL
18static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
19{
20	unsigned int bus =  (ino & 0x10) >> 4;
21	unsigned int slot = (ino & 0x0c) >> 2;
22
23	if (bus == 0)
24		return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
25	else
26		return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
27}
28
29#define PSYCHO_OBIO_IMAP_BASE	0x1000UL
30
31#define PSYCHO_ONBOARD_IRQ_BASE		0x20
32#define psycho_onboard_imap_offset(__ino) \
33	(PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
34
35#define PSYCHO_ICLR_A_SLOT0	0x1400UL
36#define PSYCHO_ICLR_SCSI	0x1800UL
37
38#define psycho_iclr_offset(ino)					      \
39	((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
40			(PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
41
42static unsigned int psycho_irq_build(struct device_node *dp,
43				     unsigned int ino,
44				     void *_data)
45{
46	unsigned long controller_regs = (unsigned long) _data;
47	unsigned long imap, iclr;
48	unsigned long imap_off, iclr_off;
49	int inofixup = 0;
50
51	ino &= 0x3f;
52	if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
53		/* PCI slot */
54		imap_off = psycho_pcislot_imap_offset(ino);
55	} else {
56		/* Onboard device */
57		imap_off = psycho_onboard_imap_offset(ino);
58	}
59
60	/* Now build the IRQ bucket. */
61	imap = controller_regs + imap_off;
62
63	iclr_off = psycho_iclr_offset(ino);
64	iclr = controller_regs + iclr_off;
65
66	if ((ino & 0x20) == 0)
67		inofixup = ino & 0x03;
68
69	return build_irq(inofixup, iclr, imap);
70}
71
72static void __init psycho_irq_trans_init(struct device_node *dp)
73{
74	const struct linux_prom64_registers *regs;
75
76	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
77	dp->irq_trans->irq_build = psycho_irq_build;
78
79	regs = of_get_property(dp, "reg", NULL);
80	dp->irq_trans->data = (void *) regs[2].phys_addr;
81}
82
83#define sabre_read(__reg) \
84({	u64 __ret; \
85	__asm__ __volatile__("ldxa [%1] %2, %0" \
86			     : "=r" (__ret) \
87			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
88			     : "memory"); \
89	__ret; \
90})
91
92struct sabre_irq_data {
93	unsigned long controller_regs;
94	unsigned int pci_first_busno;
95};
96#define SABRE_CONFIGSPACE	0x001000000UL
97#define SABRE_WRSYNC		0x1c20UL
98
99#define SABRE_CONFIG_BASE(CONFIG_SPACE)	\
100	(CONFIG_SPACE | (1UL << 24))
101#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
102	(((unsigned long)(BUS)   << 16) |	\
103	 ((unsigned long)(DEVFN) << 8)  |	\
104	 ((unsigned long)(REG)))
105
106/* When a device lives behind a bridge deeper in the PCI bus topology
107 * than APB, a special sequence must run to make sure all pending DMA
108 * transfers at the time of IRQ delivery are visible in the coherency
109 * domain by the cpu.  This sequence is to perform a read on the far
110 * side of the non-APB bridge, then perform a read of Sabre's DMA
111 * write-sync register.
112 */
113static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
114{
115	unsigned int phys_hi = (unsigned int) (unsigned long) _arg1;
116	struct sabre_irq_data *irq_data = _arg2;
117	unsigned long controller_regs = irq_data->controller_regs;
118	unsigned long sync_reg = controller_regs + SABRE_WRSYNC;
119	unsigned long config_space = controller_regs + SABRE_CONFIGSPACE;
120	unsigned int bus, devfn;
121	u16 _unused;
122
123	config_space = SABRE_CONFIG_BASE(config_space);
124
125	bus = (phys_hi >> 16) & 0xff;
126	devfn = (phys_hi >> 8) & 0xff;
127
128	config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00);
129
130	__asm__ __volatile__("membar #Sync\n\t"
131			     "lduha [%1] %2, %0\n\t"
132			     "membar #Sync"
133			     : "=r" (_unused)
134			     : "r" ((u16 *) config_space),
135			       "i" (ASI_PHYS_BYPASS_EC_E_L)
136			     : "memory");
137
138	sabre_read(sync_reg);
139}
140
141#define SABRE_IMAP_A_SLOT0	0x0c00UL
142#define SABRE_IMAP_B_SLOT0	0x0c20UL
143#define SABRE_ICLR_A_SLOT0	0x1400UL
144#define SABRE_ICLR_B_SLOT0	0x1480UL
145#define SABRE_ICLR_SCSI		0x1800UL
146#define SABRE_ICLR_ETH		0x1808UL
147#define SABRE_ICLR_BPP		0x1810UL
148#define SABRE_ICLR_AU_REC	0x1818UL
149#define SABRE_ICLR_AU_PLAY	0x1820UL
150#define SABRE_ICLR_PFAIL	0x1828UL
151#define SABRE_ICLR_KMS		0x1830UL
152#define SABRE_ICLR_FLPY		0x1838UL
153#define SABRE_ICLR_SHW		0x1840UL
154#define SABRE_ICLR_KBD		0x1848UL
155#define SABRE_ICLR_MS		0x1850UL
156#define SABRE_ICLR_SER		0x1858UL
157#define SABRE_ICLR_UE		0x1870UL
158#define SABRE_ICLR_CE		0x1878UL
159#define SABRE_ICLR_PCIERR	0x1880UL
160
161static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
162{
163	unsigned int bus =  (ino & 0x10) >> 4;
164	unsigned int slot = (ino & 0x0c) >> 2;
165
166	if (bus == 0)
167		return SABRE_IMAP_A_SLOT0 + (slot * 8);
168	else
169		return SABRE_IMAP_B_SLOT0 + (slot * 8);
170}
171
172#define SABRE_OBIO_IMAP_BASE	0x1000UL
173#define SABRE_ONBOARD_IRQ_BASE	0x20
174#define sabre_onboard_imap_offset(__ino) \
175	(SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
176
177#define sabre_iclr_offset(ino)					      \
178	((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
179			(SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
180
181static int sabre_device_needs_wsync(struct device_node *dp)
182{
183	struct device_node *parent = dp->parent;
184	const char *parent_model, *parent_compat;
185
186	/* This traversal up towards the root is meant to
187	 * handle two cases:
188	 *
189	 * 1) non-PCI bus sitting under PCI, such as 'ebus'
190	 * 2) the PCI controller interrupts themselves, which
191	 *    will use the sabre_irq_build but do not need
192	 *    the DMA synchronization handling
193	 */
194	while (parent) {
195		if (!strcmp(parent->type, "pci"))
196			break;
197		parent = parent->parent;
198	}
199
200	if (!parent)
201		return 0;
202
203	parent_model = of_get_property(parent,
204				       "model", NULL);
205	if (parent_model &&
206	    (!strcmp(parent_model, "SUNW,sabre") ||
207	     !strcmp(parent_model, "SUNW,simba")))
208		return 0;
209
210	parent_compat = of_get_property(parent,
211					"compatible", NULL);
212	if (parent_compat &&
213	    (!strcmp(parent_compat, "pci108e,a000") ||
214	     !strcmp(parent_compat, "pci108e,a001")))
215		return 0;
216
217	return 1;
218}
219
220static unsigned int sabre_irq_build(struct device_node *dp,
221				    unsigned int ino,
222				    void *_data)
223{
224	struct sabre_irq_data *irq_data = _data;
225	unsigned long controller_regs = irq_data->controller_regs;
226	const struct linux_prom_pci_registers *regs;
227	unsigned long imap, iclr;
228	unsigned long imap_off, iclr_off;
229	int inofixup = 0;
230	int virt_irq;
231
232	ino &= 0x3f;
233	if (ino < SABRE_ONBOARD_IRQ_BASE) {
234		/* PCI slot */
235		imap_off = sabre_pcislot_imap_offset(ino);
236	} else {
237		/* onboard device */
238		imap_off = sabre_onboard_imap_offset(ino);
239	}
240
241	/* Now build the IRQ bucket. */
242	imap = controller_regs + imap_off;
243
244	iclr_off = sabre_iclr_offset(ino);
245	iclr = controller_regs + iclr_off;
246
247	if ((ino & 0x20) == 0)
248		inofixup = ino & 0x03;
249
250	virt_irq = build_irq(inofixup, iclr, imap);
251
252	/* If the parent device is a PCI<->PCI bridge other than
253	 * APB, we have to install a pre-handler to ensure that
254	 * all pending DMA is drained before the interrupt handler
255	 * is run.
256	 */
257	regs = of_get_property(dp, "reg", NULL);
258	if (regs && sabre_device_needs_wsync(dp)) {
259		irq_install_pre_handler(virt_irq,
260					sabre_wsync_handler,
261					(void *) (long) regs->phys_hi,
262					(void *) irq_data);
263	}
264
265	return virt_irq;
266}
267
268static void __init sabre_irq_trans_init(struct device_node *dp)
269{
270	const struct linux_prom64_registers *regs;
271	struct sabre_irq_data *irq_data;
272	const u32 *busrange;
273
274	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
275	dp->irq_trans->irq_build = sabre_irq_build;
276
277	irq_data = prom_early_alloc(sizeof(struct sabre_irq_data));
278
279	regs = of_get_property(dp, "reg", NULL);
280	irq_data->controller_regs = regs[0].phys_addr;
281
282	busrange = of_get_property(dp, "bus-range", NULL);
283	irq_data->pci_first_busno = busrange[0];
284
285	dp->irq_trans->data = irq_data;
286}
287
288/* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the
289 * imap/iclr registers are per-PBM.
290 */
291#define SCHIZO_IMAP_BASE	0x1000UL
292#define SCHIZO_ICLR_BASE	0x1400UL
293
294static unsigned long schizo_imap_offset(unsigned long ino)
295{
296	return SCHIZO_IMAP_BASE + (ino * 8UL);
297}
298
299static unsigned long schizo_iclr_offset(unsigned long ino)
300{
301	return SCHIZO_ICLR_BASE + (ino * 8UL);
302}
303
304static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
305					unsigned int ino)
306{
307
308	return pbm_regs + schizo_iclr_offset(ino);
309}
310
311static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
312					unsigned int ino)
313{
314	return pbm_regs + schizo_imap_offset(ino);
315}
316
317#define schizo_read(__reg) \
318({	u64 __ret; \
319	__asm__ __volatile__("ldxa [%1] %2, %0" \
320			     : "=r" (__ret) \
321			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
322			     : "memory"); \
323	__ret; \
324})
325#define schizo_write(__reg, __val) \
326	__asm__ __volatile__("stxa %0, [%1] %2" \
327			     : /* no outputs */ \
328			     : "r" (__val), "r" (__reg), \
329			       "i" (ASI_PHYS_BYPASS_EC_E) \
330			     : "memory")
331
332static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
333{
334	unsigned long sync_reg = (unsigned long) _arg2;
335	u64 mask = 1UL << (ino & IMAP_INO);
336	u64 val;
337	int limit;
338
339	schizo_write(sync_reg, mask);
340
341	limit = 100000;
342	val = 0;
343	while (--limit) {
344		val = schizo_read(sync_reg);
345		if (!(val & mask))
346			break;
347	}
348	if (limit <= 0) {
349		printk("tomatillo_wsync_handler: DMA won't sync [%llx:%llx]\n",
350		       val, mask);
351	}
352
353	if (_arg1) {
354		static unsigned char cacheline[64]
355			__attribute__ ((aligned (64)));
356
357		__asm__ __volatile__("rd %%fprs, %0\n\t"
358				     "or %0, %4, %1\n\t"
359				     "wr %1, 0x0, %%fprs\n\t"
360				     "stda %%f0, [%5] %6\n\t"
361				     "wr %0, 0x0, %%fprs\n\t"
362				     "membar #Sync"
363				     : "=&r" (mask), "=&r" (val)
364				     : "0" (mask), "1" (val),
365				     "i" (FPRS_FEF), "r" (&cacheline[0]),
366				     "i" (ASI_BLK_COMMIT_P));
367	}
368}
369
370struct schizo_irq_data {
371	unsigned long pbm_regs;
372	unsigned long sync_reg;
373	u32 portid;
374	int chip_version;
375};
376
377static unsigned int schizo_irq_build(struct device_node *dp,
378				     unsigned int ino,
379				     void *_data)
380{
381	struct schizo_irq_data *irq_data = _data;
382	unsigned long pbm_regs = irq_data->pbm_regs;
383	unsigned long imap, iclr;
384	int ign_fixup;
385	int virt_irq;
386	int is_tomatillo;
387
388	ino &= 0x3f;
389
390	/* Now build the IRQ bucket. */
391	imap = schizo_ino_to_imap(pbm_regs, ino);
392	iclr = schizo_ino_to_iclr(pbm_regs, ino);
393
394	/* On Schizo, no inofixup occurs.  This is because each
395	 * INO has it's own IMAP register.  On Psycho and Sabre
396	 * there is only one IMAP register for each PCI slot even
397	 * though four different INOs can be generated by each
398	 * PCI slot.
399	 *
400	 * But, for JBUS variants (essentially, Tomatillo), we have
401	 * to fixup the lowest bit of the interrupt group number.
402	 */
403	ign_fixup = 0;
404
405	is_tomatillo = (irq_data->sync_reg != 0UL);
406
407	if (is_tomatillo) {
408		if (irq_data->portid & 1)
409			ign_fixup = (1 << 6);
410	}
411
412	virt_irq = build_irq(ign_fixup, iclr, imap);
413
414	if (is_tomatillo) {
415		irq_install_pre_handler(virt_irq,
416					tomatillo_wsync_handler,
417					((irq_data->chip_version <= 4) ?
418					 (void *) 1 : (void *) 0),
419					(void *) irq_data->sync_reg);
420	}
421
422	return virt_irq;
423}
424
425static void __init __schizo_irq_trans_init(struct device_node *dp,
426					   int is_tomatillo)
427{
428	const struct linux_prom64_registers *regs;
429	struct schizo_irq_data *irq_data;
430
431	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
432	dp->irq_trans->irq_build = schizo_irq_build;
433
434	irq_data = prom_early_alloc(sizeof(struct schizo_irq_data));
435
436	regs = of_get_property(dp, "reg", NULL);
437	dp->irq_trans->data = irq_data;
438
439	irq_data->pbm_regs = regs[0].phys_addr;
440	if (is_tomatillo)
441		irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
442	else
443		irq_data->sync_reg = 0UL;
444	irq_data->portid = of_getintprop_default(dp, "portid", 0);
445	irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
446}
447
448static void __init schizo_irq_trans_init(struct device_node *dp)
449{
450	__schizo_irq_trans_init(dp, 0);
451}
452
453static void __init tomatillo_irq_trans_init(struct device_node *dp)
454{
455	__schizo_irq_trans_init(dp, 1);
456}
457
458static unsigned int pci_sun4v_irq_build(struct device_node *dp,
459					unsigned int devino,
460					void *_data)
461{
462	u32 devhandle = (u32) (unsigned long) _data;
463
464	return sun4v_build_irq(devhandle, devino);
465}
466
467static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
468{
469	const struct linux_prom64_registers *regs;
470
471	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
472	dp->irq_trans->irq_build = pci_sun4v_irq_build;
473
474	regs = of_get_property(dp, "reg", NULL);
475	dp->irq_trans->data = (void *) (unsigned long)
476		((regs->phys_addr >> 32UL) & 0x0fffffff);
477}
478
479struct fire_irq_data {
480	unsigned long pbm_regs;
481	u32 portid;
482};
483
484#define FIRE_IMAP_BASE	0x001000
485#define FIRE_ICLR_BASE	0x001400
486
487static unsigned long fire_imap_offset(unsigned long ino)
488{
489	return FIRE_IMAP_BASE + (ino * 8UL);
490}
491
492static unsigned long fire_iclr_offset(unsigned long ino)
493{
494	return FIRE_ICLR_BASE + (ino * 8UL);
495}
496
497static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
498					    unsigned int ino)
499{
500	return pbm_regs + fire_iclr_offset(ino);
501}
502
503static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
504					    unsigned int ino)
505{
506	return pbm_regs + fire_imap_offset(ino);
507}
508
509static unsigned int fire_irq_build(struct device_node *dp,
510					 unsigned int ino,
511					 void *_data)
512{
513	struct fire_irq_data *irq_data = _data;
514	unsigned long pbm_regs = irq_data->pbm_regs;
515	unsigned long imap, iclr;
516	unsigned long int_ctrlr;
517
518	ino &= 0x3f;
519
520	/* Now build the IRQ bucket. */
521	imap = fire_ino_to_imap(pbm_regs, ino);
522	iclr = fire_ino_to_iclr(pbm_regs, ino);
523
524	/* Set the interrupt controller number.  */
525	int_ctrlr = 1 << 6;
526	upa_writeq(int_ctrlr, imap);
527
528	/* The interrupt map registers do not have an INO field
529	 * like other chips do.  They return zero in the INO
530	 * field, and the interrupt controller number is controlled
531	 * in bits 6 to 9.  So in order for build_irq() to get
532	 * the INO right we pass it in as part of the fixup
533	 * which will get added to the map register zero value
534	 * read by build_irq().
535	 */
536	ino |= (irq_data->portid << 6);
537	ino -= int_ctrlr;
538	return build_irq(ino, iclr, imap);
539}
540
541static void __init fire_irq_trans_init(struct device_node *dp)
542{
543	const struct linux_prom64_registers *regs;
544	struct fire_irq_data *irq_data;
545
546	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
547	dp->irq_trans->irq_build = fire_irq_build;
548
549	irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
550
551	regs = of_get_property(dp, "reg", NULL);
552	dp->irq_trans->data = irq_data;
553
554	irq_data->pbm_regs = regs[0].phys_addr;
555	irq_data->portid = of_getintprop_default(dp, "portid", 0);
556}
557#endif /* CONFIG_PCI */
558
559#ifdef CONFIG_SBUS
560/* INO number to IMAP register offset for SYSIO external IRQ's.
561 * This should conform to both Sunfire/Wildfire server and Fusion
562 * desktop designs.
563 */
564#define SYSIO_IMAP_SLOT0	0x2c00UL
565#define SYSIO_IMAP_SLOT1	0x2c08UL
566#define SYSIO_IMAP_SLOT2	0x2c10UL
567#define SYSIO_IMAP_SLOT3	0x2c18UL
568#define SYSIO_IMAP_SCSI		0x3000UL
569#define SYSIO_IMAP_ETH		0x3008UL
570#define SYSIO_IMAP_BPP		0x3010UL
571#define SYSIO_IMAP_AUDIO	0x3018UL
572#define SYSIO_IMAP_PFAIL	0x3020UL
573#define SYSIO_IMAP_KMS		0x3028UL
574#define SYSIO_IMAP_FLPY		0x3030UL
575#define SYSIO_IMAP_SHW		0x3038UL
576#define SYSIO_IMAP_KBD		0x3040UL
577#define SYSIO_IMAP_MS		0x3048UL
578#define SYSIO_IMAP_SER		0x3050UL
579#define SYSIO_IMAP_TIM0		0x3060UL
580#define SYSIO_IMAP_TIM1		0x3068UL
581#define SYSIO_IMAP_UE		0x3070UL
582#define SYSIO_IMAP_CE		0x3078UL
583#define SYSIO_IMAP_SBERR	0x3080UL
584#define SYSIO_IMAP_PMGMT	0x3088UL
585#define SYSIO_IMAP_GFX		0x3090UL
586#define SYSIO_IMAP_EUPA		0x3098UL
587
588#define bogon     ((unsigned long) -1)
589static unsigned long sysio_irq_offsets[] = {
590	/* SBUS Slot 0 --> 3, level 1 --> 7 */
591	SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
592	SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
593	SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
594	SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
595	SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
596	SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
597	SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
598	SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
599
600	/* Onboard devices (not relevant/used on SunFire). */
601	SYSIO_IMAP_SCSI,
602	SYSIO_IMAP_ETH,
603	SYSIO_IMAP_BPP,
604	bogon,
605	SYSIO_IMAP_AUDIO,
606	SYSIO_IMAP_PFAIL,
607	bogon,
608	bogon,
609	SYSIO_IMAP_KMS,
610	SYSIO_IMAP_FLPY,
611	SYSIO_IMAP_SHW,
612	SYSIO_IMAP_KBD,
613	SYSIO_IMAP_MS,
614	SYSIO_IMAP_SER,
615	bogon,
616	bogon,
617	SYSIO_IMAP_TIM0,
618	SYSIO_IMAP_TIM1,
619	bogon,
620	bogon,
621	SYSIO_IMAP_UE,
622	SYSIO_IMAP_CE,
623	SYSIO_IMAP_SBERR,
624	SYSIO_IMAP_PMGMT,
625	SYSIO_IMAP_GFX,
626	SYSIO_IMAP_EUPA,
627};
628
629#undef bogon
630
631#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
632
633/* Convert Interrupt Mapping register pointer to associated
634 * Interrupt Clear register pointer, SYSIO specific version.
635 */
636#define SYSIO_ICLR_UNUSED0	0x3400UL
637#define SYSIO_ICLR_SLOT0	0x3408UL
638#define SYSIO_ICLR_SLOT1	0x3448UL
639#define SYSIO_ICLR_SLOT2	0x3488UL
640#define SYSIO_ICLR_SLOT3	0x34c8UL
641static unsigned long sysio_imap_to_iclr(unsigned long imap)
642{
643	unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
644	return imap + diff;
645}
646
647static unsigned int sbus_of_build_irq(struct device_node *dp,
648				      unsigned int ino,
649				      void *_data)
650{
651	unsigned long reg_base = (unsigned long) _data;
652	const struct linux_prom_registers *regs;
653	unsigned long imap, iclr;
654	int sbus_slot = 0;
655	int sbus_level = 0;
656
657	ino &= 0x3f;
658
659	regs = of_get_property(dp, "reg", NULL);
660	if (regs)
661		sbus_slot = regs->which_io;
662
663	if (ino < 0x20)
664		ino += (sbus_slot * 8);
665
666	imap = sysio_irq_offsets[ino];
667	if (imap == ((unsigned long)-1)) {
668		prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
669			    ino);
670		prom_halt();
671	}
672	imap += reg_base;
673
674	/* SYSIO inconsistency.  For external SLOTS, we have to select
675	 * the right ICLR register based upon the lower SBUS irq level
676	 * bits.
677	 */
678	if (ino >= 0x20) {
679		iclr = sysio_imap_to_iclr(imap);
680	} else {
681		sbus_level = ino & 0x7;
682
683		switch(sbus_slot) {
684		case 0:
685			iclr = reg_base + SYSIO_ICLR_SLOT0;
686			break;
687		case 1:
688			iclr = reg_base + SYSIO_ICLR_SLOT1;
689			break;
690		case 2:
691			iclr = reg_base + SYSIO_ICLR_SLOT2;
692			break;
693		default:
694		case 3:
695			iclr = reg_base + SYSIO_ICLR_SLOT3;
696			break;
697		};
698
699		iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
700	}
701	return build_irq(sbus_level, iclr, imap);
702}
703
704static void __init sbus_irq_trans_init(struct device_node *dp)
705{
706	const struct linux_prom64_registers *regs;
707
708	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
709	dp->irq_trans->irq_build = sbus_of_build_irq;
710
711	regs = of_get_property(dp, "reg", NULL);
712	dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr;
713}
714#endif /* CONFIG_SBUS */
715
716
717static unsigned int central_build_irq(struct device_node *dp,
718				      unsigned int ino,
719				      void *_data)
720{
721	struct device_node *central_dp = _data;
722	struct platform_device *central_op = of_find_device_by_node(central_dp);
723	struct resource *res;
724	unsigned long imap, iclr;
725	u32 tmp;
726
727	if (!strcmp(dp->name, "eeprom")) {
728		res = &central_op->resource[5];
729	} else if (!strcmp(dp->name, "zs")) {
730		res = &central_op->resource[4];
731	} else if (!strcmp(dp->name, "clock-board")) {
732		res = &central_op->resource[3];
733	} else {
734		return ino;
735	}
736
737	imap = res->start + 0x00UL;
738	iclr = res->start + 0x10UL;
739
740	/* Set the INO state to idle, and disable.  */
741	upa_writel(0, iclr);
742	upa_readl(iclr);
743
744	tmp = upa_readl(imap);
745	tmp &= ~0x80000000;
746	upa_writel(tmp, imap);
747
748	return build_irq(0, iclr, imap);
749}
750
751static void __init central_irq_trans_init(struct device_node *dp)
752{
753	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
754	dp->irq_trans->irq_build = central_build_irq;
755
756	dp->irq_trans->data = dp;
757}
758
759struct irq_trans {
760	const char *name;
761	void (*init)(struct device_node *);
762};
763
764#ifdef CONFIG_PCI
765static struct irq_trans __initdata pci_irq_trans_table[] = {
766	{ "SUNW,sabre", sabre_irq_trans_init },
767	{ "pci108e,a000", sabre_irq_trans_init },
768	{ "pci108e,a001", sabre_irq_trans_init },
769	{ "SUNW,psycho", psycho_irq_trans_init },
770	{ "pci108e,8000", psycho_irq_trans_init },
771	{ "SUNW,schizo", schizo_irq_trans_init },
772	{ "pci108e,8001", schizo_irq_trans_init },
773	{ "SUNW,schizo+", schizo_irq_trans_init },
774	{ "pci108e,8002", schizo_irq_trans_init },
775	{ "SUNW,tomatillo", tomatillo_irq_trans_init },
776	{ "pci108e,a801", tomatillo_irq_trans_init },
777	{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
778	{ "pciex108e,80f0", fire_irq_trans_init },
779};
780#endif
781
782static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
783					 unsigned int devino,
784					 void *_data)
785{
786	u32 devhandle = (u32) (unsigned long) _data;
787
788	return sun4v_build_irq(devhandle, devino);
789}
790
791static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
792{
793	const struct linux_prom64_registers *regs;
794
795	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
796	dp->irq_trans->irq_build = sun4v_vdev_irq_build;
797
798	regs = of_get_property(dp, "reg", NULL);
799	dp->irq_trans->data = (void *) (unsigned long)
800		((regs->phys_addr >> 32UL) & 0x0fffffff);
801}
802
803void __init irq_trans_init(struct device_node *dp)
804{
805#ifdef CONFIG_PCI
806	const char *model;
807	int i;
808#endif
809
810#ifdef CONFIG_PCI
811	model = of_get_property(dp, "model", NULL);
812	if (!model)
813		model = of_get_property(dp, "compatible", NULL);
814	if (model) {
815		for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
816			struct irq_trans *t = &pci_irq_trans_table[i];
817
818			if (!strcmp(model, t->name)) {
819				t->init(dp);
820				return;
821			}
822		}
823	}
824#endif
825#ifdef CONFIG_SBUS
826	if (!strcmp(dp->name, "sbus") ||
827	    !strcmp(dp->name, "sbi")) {
828		sbus_irq_trans_init(dp);
829		return;
830	}
831#endif
832	if (!strcmp(dp->name, "fhc") &&
833	    !strcmp(dp->parent->name, "central")) {
834		central_irq_trans_init(dp);
835		return;
836	}
837	if (!strcmp(dp->name, "virtual-devices") ||
838	    !strcmp(dp->name, "niu")) {
839		sun4v_vdev_irq_trans_init(dp);
840		return;
841	}
842}
843