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 |
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 |
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) | |
34 | ((devfn & 0xff) << 8) | |
35 | (reg & 0xfc); |
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(busno: bus->number, devfn, reg))) |
46 | return res; |
47 | |
48 | switch (size) { |
49 | case 1: |
50 | *val = inb(port: PCIMT_CONFIG_DATA + (reg & 3)); |
51 | break; |
52 | case 2: |
53 | *val = inw(port: PCIMT_CONFIG_DATA + (reg & 2)); |
54 | break; |
55 | case 4: |
56 | *val = inl(port: PCIMT_CONFIG_DATA); |
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(busno: bus->number, devfn, reg))) |
69 | return res; |
70 | |
71 | switch (size) { |
72 | case 1: |
73 | outb(value: val, port: PCIMT_CONFIG_DATA + (reg & 3)); |
74 | break; |
75 | case 2: |
76 | outw(value: val, port: PCIMT_CONFIG_DATA + (reg & 2)); |
77 | break; |
78 | case 4: |
79 | outl(value: val, port: PCIMT_CONFIG_DATA); |
80 | break; |
81 | } |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | struct pci_ops sni_pcimt_ops = { |
87 | .read = pcimt_read, |
88 | .write = pcimt_write, |
89 | }; |
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 | |
96 | outl(value: (1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), port: 0xcf8); |
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) { |
111 | pcit_set_config_address(busno: 0, devfn: 0, reg: 0x68); |
112 | outl(inl(port: 0xcfc) | 0xc0000000, port: 0xcfc); |
113 | if ((res = pcit_set_config_address(busno: 0, devfn, reg: 0))) |
114 | return res; |
115 | outl(value: 0xffffffff, port: 0xcfc); |
116 | pcit_set_config_address(busno: 0, devfn: 0, reg: 0x68); |
117 | if (inl(port: 0xcfc) & 0x100000) |
118 | return PCIBIOS_DEVICE_NOT_FOUND; |
119 | } |
120 | if ((res = pcit_set_config_address(busno: bus->number, devfn, reg))) |
121 | return res; |
122 | |
123 | switch (size) { |
124 | case 1: |
125 | *val = inb(port: PCIMT_CONFIG_DATA + (reg & 3)); |
126 | break; |
127 | case 2: |
128 | *val = inw(port: PCIMT_CONFIG_DATA + (reg & 2)); |
129 | break; |
130 | case 4: |
131 | *val = inl(port: 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(busno: bus->number, devfn, reg))) |
143 | return res; |
144 | |
145 | switch (size) { |
146 | case 1: |
147 | outb(value: val, port: PCIMT_CONFIG_DATA + (reg & 3)); |
148 | break; |
149 | case 2: |
150 | outw(value: val, port: PCIMT_CONFIG_DATA + (reg & 2)); |
151 | break; |
152 | case 4: |
153 | outl(value: val, port: PCIMT_CONFIG_DATA); |
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 | }; |
165 | |