aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pci/fixup-sni.c
blob: 5c8a79bb26613a23cdbffd6319d6d90d3dee59dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * SNI specific PCI support for RM200/RM300.
 *
 * Copyright (C) 1997 - 2000, 2003, 04 Ralf Baechle (ralf@linux-mips.org)
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>

#include <asm/mipsregs.h>
#include <asm/sni.h>

#include <irq.h>

/*
 * PCIMT Shortcuts ...
 */
#define SCSI	PCIMT_IRQ_SCSI
#define ETH	PCIMT_IRQ_ETHERNET
#define INTA	PCIMT_IRQ_INTA
#define INTB	PCIMT_IRQ_INTB
#define INTC	PCIMT_IRQ_INTC
#define INTD	PCIMT_IRQ_INTD

/*
 * Device 0: PCI EISA Bridge	(directly routed)
 * Device 1: NCR53c810 SCSI	(directly routed)
 * Device 2: PCnet32 Ethernet	(directly routed)
 * Device 3: VGA		(routed to INTB)
 * Device 4: Unused
 * Device 5: Slot 2
 * Device 6: Slot 3
 * Device 7: Slot 4
 *
 * Documentation says the VGA is device 5 and device 3 is unused but that
 * seem to be a documentation error.  At least on my RM200C the Cirrus
 * Logic CL-GD5434 VGA is device 3.
 */
static char irq_tab_rm200[8][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,    0,    0,    0,    0 },	/* EISA bridge */
	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */
	{   ETH,  ETH,  ETH,  ETH,  ETH },	/* Ethernet */
	{  INTB, INTB, INTB, INTB, INTB },	/* VGA */
	{     0,    0,    0,    0,    0 },	/* Unused */
	{     0, INTB, INTC, INTD, INTA },	/* Slot 2 */
	{     0, INTC, INTD, INTA, INTB },	/* Slot 3 */
	{     0, INTD, INTA, INTB, INTC },	/* Slot 4 */
};

/*
 * In Revision D of the RM300 Device 2 has become a normal purpose Slot 1
 *
 * The VGA card is optional for RM300 systems.
 */
static char irq_tab_rm300d[8][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,    0,    0,    0,    0 },	/* EISA bridge */
	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */
	{     0, INTC, INTD, INTA, INTB },	/* Slot 1 */
	{  INTB, INTB, INTB, INTB, INTB },	/* VGA */
	{     0,    0,    0,    0,    0 },	/* Unused */
	{     0, INTB, INTC, INTD, INTA },	/* Slot 2 */
	{     0, INTC, INTD, INTA, INTB },	/* Slot 3 */
	{     0, INTD, INTA, INTB, INTC },	/* Slot 4 */
};

static char irq_tab_rm300e[5][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,    0,    0,    0,    0 },	/* HOST bridge */
	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */
	{     0, INTC, INTD, INTA, INTB },	/* Bridge/i960 */
	{     0, INTD, INTA, INTB, INTC },	/* Slot 1 */
	{     0, INTA, INTB, INTC, INTD },	/* Slot 2 */
};
#undef SCSI
#undef ETH
#undef INTA
#undef INTB
#undef INTC
#undef INTD


/*
 * PCIT Shortcuts ...
 */
#define SCSI0	PCIT_IRQ_SCSI0
#define SCSI1	PCIT_IRQ_SCSI1
#define ETH	PCIT_IRQ_ETHERNET
#define INTA	PCIT_IRQ_INTA
#define INTB	PCIT_IRQ_INTB
#define INTC	PCIT_IRQ_INTC
#define INTD	PCIT_IRQ_INTD

static char irq_tab_pcit[13][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,     0,     0,     0,     0 },	/* HOST bridge */
	{ SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 },	/* SCSI */
	{ SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 },	/* SCSI */
	{   ETH,   ETH,   ETH,   ETH,   ETH },	/* Ethernet */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* PCI-PCI bridge */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 1 */
	{     0,  INTB,  INTC,  INTD,  INTA },	/* Slot 2 */
	{     0,  INTC,  INTD,  INTA,  INTB },	/* Slot 3 */
	{     0,  INTD,  INTA,  INTB,  INTC },	/* Slot 4 */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 5 */
};

static char irq_tab_pcit_cplus[13][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,     0,     0,     0,     0 },	/* HOST bridge */
	{     0,  INTB,  INTC,  INTD,  INTA },	/* PCI Slot 9 */
	{     0,     0,     0,     0,     0 },	/* PCI-EISA */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* PCI-PCI bridge */
	{     0,  INTB,  INTC,  INTD,  INTA },	/* fixup */
};

static inline int is_rm300_revd(void)
{
	unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR;

	return (csmsr & 0xa0) == 0x20;
}

int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
	switch (sni_brd_type) {
	case SNI_BRD_PCI_TOWER_CPLUS:
		if (slot == 4) {
			/*
			 * SNI messed up interrupt wiring for onboard
			 * PCI bus 1; we need to fix this up here
			 */
			while (dev && dev->bus->number != 1)
				dev = dev->bus->self;
			if (dev && dev->devfn >= PCI_DEVFN(4, 0))
				slot = 5;
		}
		return irq_tab_pcit_cplus[slot][pin];
	case SNI_BRD_PCI_TOWER:
	        return irq_tab_pcit[slot][pin];

	case SNI_BRD_PCI_MTOWER:
	        if (is_rm300_revd())
		        return irq_tab_rm300d[slot][pin];
	        /* fall through */

	case SNI_BRD_PCI_DESKTOP:
	        return irq_tab_rm200[slot][pin];

	case SNI_BRD_PCI_MTOWER_CPLUS:
	        return irq_tab_rm300e[slot][pin];
	}

	return 0;
}

/* Do platform specific device initialization at pci_enable_device() time */
int pcibios_plat_dev_init(struct pci_dev *dev)
{
	return 0;
}