]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * SNI specific PCI support for RM200/RM300. | |
7 | * | |
8 | * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org> | |
9 | */ | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/pci.h> | |
12 | #include <linux/types.h> | |
13 | #include <asm/sni.h> | |
14 | ||
15 | /* | |
16 | * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device | |
70342287 RB |
17 | * address are decoded. We therefore manually have to reject attempts at |
18 | * reading outside this range. Being on the paranoid side we only do this | |
1da177e4 LT |
19 | * test for bus 0 and hope forwarding and decoding work properly for any |
20 | * subordinated busses. | |
21 | * | |
22 | * ASIC PCI only supports type 1 config cycles. | |
23 | */ | |
24 | static int set_config_address(unsigned int busno, unsigned int devfn, int reg) | |
25 | { | |
26 | if ((devfn > 255) || (reg > 255)) | |
27 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
28 | ||
29 | if (busno == 0 && devfn >= PCI_DEVFN(8, 0)) | |
30 | return PCIBIOS_DEVICE_NOT_FOUND; | |
31 | ||
32 | *(volatile u32 *)PCIMT_CONFIG_ADDRESS = | |
33 | ((busno & 0xff) << 16) | | |
70342287 RB |
34 | ((devfn & 0xff) << 8) | |
35 | (reg & 0xfc); | |
1da177e4 LT |
36 | |
37 | return PCIBIOS_SUCCESSFUL; | |
38 | } | |
39 | ||
40 | static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg, | |
41 | int size, u32 * val) | |
42 | { | |
43 | int res; | |
44 | ||
45 | if ((res = set_config_address(bus->number, devfn, reg))) | |
46 | return res; | |
47 | ||
48 | switch (size) { | |
49 | case 1: | |
4a0312fc | 50 | *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); |
1da177e4 LT |
51 | break; |
52 | case 2: | |
4a0312fc | 53 | *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); |
1da177e4 LT |
54 | break; |
55 | case 4: | |
4a0312fc | 56 | *val = inl(PCIMT_CONFIG_DATA); |
1da177e4 LT |
57 | break; |
58 | } | |
59 | ||
60 | return 0; | |
61 | } | |
62 | ||
63 | static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, | |
64 | int size, u32 val) | |
65 | { | |
66 | int res; | |
67 | ||
68 | if ((res = set_config_address(bus->number, devfn, reg))) | |
69 | return res; | |
70 | ||
71 | switch (size) { | |
72 | case 1: | |
49a89efb | 73 | outb(val, PCIMT_CONFIG_DATA + (reg & 3)); |
1da177e4 LT |
74 | break; |
75 | case 2: | |
49a89efb | 76 | outw(val, PCIMT_CONFIG_DATA + (reg & 2)); |
1da177e4 LT |
77 | break; |
78 | case 4: | |
49a89efb | 79 | outl(val, PCIMT_CONFIG_DATA); |
1da177e4 LT |
80 | break; |
81 | } | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
c066a32a | 86 | struct pci_ops sni_pcimt_ops = { |
1da177e4 LT |
87 | .read = pcimt_read, |
88 | .write = pcimt_write, | |
89 | }; | |
c066a32a TB |
90 | |
91 | static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg) | |
92 | { | |
93 | if ((devfn > 255) || (reg > 255) || (busno > 255)) | |
94 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
95 | ||
49a89efb | 96 | outl((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8); |
c066a32a TB |
97 | return PCIBIOS_SUCCESSFUL; |
98 | } | |
99 | ||
100 | static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg, | |
101 | int size, u32 * val) | |
102 | { | |
103 | int res; | |
104 | ||
105 | /* | |
106 | * on bus 0 we need to check, whether there is a device answering | |
107 | * for the devfn by doing a config write and checking the result. If | |
108 | * we don't do it, we will get a data bus error | |
109 | */ | |
110 | if (bus->number == 0) { | |
49a89efb RB |
111 | pcit_set_config_address(0, 0, 0x68); |
112 | outl(inl(0xcfc) | 0xc0000000, 0xcfc); | |
c066a32a TB |
113 | if ((res = pcit_set_config_address(0, devfn, 0))) |
114 | return res; | |
49a89efb RB |
115 | outl(0xffffffff, 0xcfc); |
116 | pcit_set_config_address(0, 0, 0x68); | |
c066a32a TB |
117 | if (inl(0xcfc) & 0x100000) |
118 | return PCIBIOS_DEVICE_NOT_FOUND; | |
119 | } | |
120 | if ((res = pcit_set_config_address(bus->number, devfn, reg))) | |
121 | return res; | |
122 | ||
123 | switch (size) { | |
124 | case 1: | |
125 | *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); | |
126 | break; | |
127 | case 2: | |
128 | *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); | |
129 | break; | |
130 | case 4: | |
131 | *val = inl(PCIMT_CONFIG_DATA); | |
132 | break; | |
133 | } | |
134 | return 0; | |
135 | } | |
136 | ||
137 | static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg, | |
138 | int size, u32 val) | |
139 | { | |
140 | int res; | |
141 | ||
142 | if ((res = pcit_set_config_address(bus->number, devfn, reg))) | |
143 | return res; | |
144 | ||
145 | switch (size) { | |
146 | case 1: | |
49a89efb | 147 | outb(val, PCIMT_CONFIG_DATA + (reg & 3)); |
c066a32a TB |
148 | break; |
149 | case 2: | |
49a89efb | 150 | outw(val, PCIMT_CONFIG_DATA + (reg & 2)); |
c066a32a TB |
151 | break; |
152 | case 4: | |
49a89efb | 153 | outl(val, PCIMT_CONFIG_DATA); |
c066a32a TB |
154 | break; |
155 | } | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | ||
161 | struct pci_ops sni_pcit_ops = { | |
162 | .read = pcit_read, | |
163 | .write = pcit_write, | |
164 | }; |