summaryrefslogtreecommitdiffstats
path: root/arch/mips/ddb5xxx/ddb5477/pci.c
blob: c17413fddf86e4b888fc2f36f5bfd8fd4cad5984 (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
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>

#include <asm/ddb5xxx/ddb5xxx.h>
#include <asm/ddb5xxx/debug.h>
#include <asm/ddb5xxx/pci.h>

static struct resource extpci_io_resource = {
	"ext pci IO space", 
	DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE,
	DDB_PCI0_IO_BASE - DDB_PCI_IO_BASE + DDB_PCI0_IO_SIZE -1,
	IORESOURCE_IO};

static struct resource extpci_mem_resource = {
	"ext pci memory space", 
	DDB_PCI0_MEM_BASE,
	DDB_PCI0_MEM_BASE + DDB_PCI0_MEM_SIZE -1,
	IORESOURCE_MEM};

static struct resource iopci_io_resource = {
	"io pci IO space", 
	DDB_PCI1_IO_BASE - DDB_PCI_IO_BASE,
	DDB_PCI1_IO_BASE - DDB_PCI_IO_BASE + DDB_PCI1_IO_SIZE -1,
	IORESOURCE_IO};

static struct resource iopci_mem_resource = {
	"ext pci memory space", 
	DDB_PCI1_MEM_BASE,
	DDB_PCI1_MEM_BASE + DDB_PCI1_MEM_SIZE -1,
	IORESOURCE_MEM};

extern struct pci_ops ddb5477_ext_pci_ops;
extern struct pci_ops ddb5477_io_pci_ops;

struct pci_channel mips_pci_channels[] = {
	{ &ddb5477_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource },
	{ &ddb5477_io_pci_ops, &iopci_io_resource, &iopci_mem_resource },
	{ NULL, NULL, NULL}
};


/*
 * we fix up irqs based on the slot number.
 * The first entry is at AD:11.
 * Fortunately this works because, although we have two pci buses,
 * they all have different slot numbers.
 * 
 * This does not work for devices on sub-buses.
 *
 * Note that the irq number in the array is relative number in vrc5477.
 * We need to translate it to global irq number.
 */

/*
 * irq mapping : PCI int # -> vrc5477 irq #
 * based on vrc5477 manual page 46
 */
#define		PCI_EXT_INTA		8
#define		PCI_EXT_INTB		9
#define		PCI_EXT_INTC		10
#define		PCI_EXT_INTD		11
#define		PCI_EXT_INTE		12

#define		PCI_IO_INTA		16
#define		PCI_IO_INTB		17
#define		PCI_IO_INTC		18
#define		PCI_IO_INTD		19

/* 
 * irq mapping : device -> pci int #, 
 * ddb5477 board manual page 4  and vrc5477 manual page 46
 */
#define		INT_ONBOARD_TULIP	PCI_EXT_INTA
#define		INT_SLOT1		PCI_EXT_INTB
#define		INT_SLOT2		PCI_EXT_INTC
#define		INT_SLOT3		PCI_EXT_INTD
#define		INT_SLOT4		PCI_EXT_INTE

#define		INT_USB_HOST		PCI_IO_INTA
#define		INT_USB_PERI		PCI_IO_INTB
#define		INT_AC97		PCI_IO_INTC

/*
 * based on ddb5477 manual page 11
 */
#define		MAX_SLOT_NUM		21
static unsigned char irq_map[MAX_SLOT_NUM] = {
	/* AD:11 */ 0xff, 0xff, 0xff, 0xff, 
	/* AD:15 */ INT_ONBOARD_TULIP, INT_SLOT1, INT_SLOT2, INT_SLOT3,
	/* AD:19 */ INT_SLOT4, 0xff, 0xff, 0xff,
	/* AD:23 */ 0xff, 0xff, 0xff, 0xff,
	/* AD:27 */ 0xff, 0xff, INT_AC97, INT_USB_PERI, 
	/* AD:31 */ INT_USB_HOST
};

extern int vrc5477_irq_to_irq(int irq);
void __init pcibios_fixup_irqs(void)
{
        struct pci_dev *dev;
        int slot_num;

	pci_for_each_dev(dev) {
		slot_num = PCI_SLOT(dev->devfn);
		MIPS_ASSERT(slot_num < MAX_SLOT_NUM);
		MIPS_ASSERT(irq_map[slot_num] != 0xff);

		pci_write_config_byte(dev, 
				      PCI_INTERRUPT_LINE,
				      irq_map[slot_num]);
		dev->irq = vrc5477_irq_to_irq(irq_map[slot_num]);
	}
}

#if defined(CONFIG_LL_DEBUG)
extern void jsun_scan_pci_bus(void);
extern void jsun_assign_pci_resource(void);
#endif
void __init ddb_pci_reset_bus(void)
{	
	u32 temp;

	/*
	 * I am not sure about the "official" procedure, the following
	 * steps work as far as I know:
	 * We first set PCI cold reset bit (bit 31) in PCICTRL-H.
	 * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H.
	 * The same is true for both PCI channels.
	 */
	temp = ddb_in32(DDB_PCICTL0_H);
	temp |= 0x80000000;
	ddb_out32(DDB_PCICTL0_H, temp);
	temp &= ~0xc0000000;
	ddb_out32(DDB_PCICTL0_H, temp);

	temp = ddb_in32(DDB_PCICTL1_H);
	temp |= 0x80000000;
	ddb_out32(DDB_PCICTL1_H, temp);
	temp &= ~0xc0000000;
	ddb_out32(DDB_PCICTL1_H, temp);
}