more changes on original files
[linux-2.4.git] / arch / mips / momentum / ocelot_c / pci.c
1 /*
2  * Copyright 2002 Momentum Computer
3  * Author: Matthew Dharm <mdharm@momenco.com>
4  *
5  *  This program is free software; you can redistribute  it and/or modify it
6  *  under  the terms of  the GNU General  Public License as published by the
7  *  Free Software Foundation;  either version 2 of the  License, or (at your
8  *  option) any later version.
9  *
10  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
11  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
12  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
13  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
14  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
15  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
16  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
17  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
18  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
19  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20  *
21  *  You should have received a copy of the  GNU General Public License along
22  *  with this program; if not, write  to the Free Software Foundation, Inc.,
23  *  675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 #include <linux/config.h>
26 #include <linux/types.h>
27 #include <linux/pci.h>
28 #include <linux/kernel.h>
29 #include <linux/slab.h>
30 #include <linux/version.h>
31 #include <asm/pci.h>
32 #include <asm/io.h>
33 #include <asm/mv64340.h>
34
35 #include <linux/init.h>
36
37 #ifdef CONFIG_PCI
38
39 /*
40  * These functions and structures provide the BIOS scan and mapping of the PCI
41  * devices.
42  */
43
44 #define MAX_PCI_DEVS 10
45
46 void mv64340_board_pcibios_fixup_bus(struct pci_bus* c);
47
48 /*  Functions to implement "pci ops"  */
49 static int marvell_pcibios_read_config_word(struct pci_dev *dev,
50                                             int offset, u16 * val);
51 static int marvell_pcibios_read_config_byte(struct pci_dev *dev,
52                                             int offset, u8 * val);
53 static int marvell_pcibios_read_config_dword(struct pci_dev *dev,
54                                              int offset, u32 * val);
55 static int marvell_pcibios_write_config_byte(struct pci_dev *dev,
56                                              int offset, u8 val);
57 static int marvell_pcibios_write_config_word(struct pci_dev *dev,
58                                              int offset, u16 val);
59 static int marvell_pcibios_write_config_dword(struct pci_dev *dev,
60                                               int offset, u32 val);
61
62 /*
63  *  General-purpose PCI functions.
64  */
65
66
67 /*
68  * pci_range_ck -
69  *
70  * Check if the pci device that are trying to access does really exists
71  * on the evaluation board.  
72  *
73  * Inputs :
74  * bus - bus number (0 for PCI 0 ; 1 for PCI 1)
75  * dev - number of device on the specific pci bus
76  *
77  * Outpus :
78  * 0 - if OK , 1 - if failure
79  */
80 static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
81 {
82         /* Accessing device 31 crashes the MV-64340. */
83         if (dev < 5)
84                 return 0;
85         return -1;
86 }
87
88 /*
89  * marvell_pcibios_(read/write)_config_(dword/word/byte) -
90  *
91  * reads/write a dword/word/byte register from the configuration space
92  * of a device.
93  *
94  * Note that bus 0 and bus 1 are local, and we assume all other busses are
95  * bridged from bus 1.  This is a safe assumption, since any other
96  * configuration will require major modifications to the CP7000G
97  *
98  * Inputs :
99  * bus - bus number
100  * dev - device number
101  * offset - register offset in the configuration space
102  * val - value to be written / read
103  *
104  * Outputs :
105  * PCIBIOS_SUCCESSFUL when operation was succesfull
106  * PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
107  * PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
108  */
109
110 static int marvell_pcibios_read_config_dword(struct pci_dev *device,
111                                               int offset, u32* val)
112 {
113         int dev, bus, func;
114         uint32_t address_reg, data_reg;
115         uint32_t address;
116
117         bus = device->bus->number;
118         dev = PCI_SLOT(device->devfn);
119         func = PCI_FUNC(device->devfn);
120
121         /* verify the range */
122         if (pci_range_ck(bus, dev))
123                 return PCIBIOS_DEVICE_NOT_FOUND;
124
125         /* select the MV-64340 registers to communicate with the PCI bus */
126         if (bus == 0) {
127                 address_reg = MV64340_PCI_0_CONFIG_ADDR;
128                 data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
129         } else {
130                 address_reg = MV64340_PCI_1_CONFIG_ADDR;
131                 data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
132         }
133
134         address = (bus << 16) | (dev << 11) | (func << 8) |
135                 (offset & 0xfc) | 0x80000000;
136
137         /* start the configuration cycle */
138         MV_WRITE(address_reg, address);
139
140         /* read the data */
141         MV_READ(data_reg, val);
142
143         return PCIBIOS_SUCCESSFUL;
144 }
145
146
147 static int marvell_pcibios_read_config_word(struct pci_dev *device,
148                                              int offset, u16* val)
149 {
150         int dev, bus, func;
151         uint32_t address_reg, data_reg;
152         uint32_t address;
153
154         bus = device->bus->number;
155         dev = PCI_SLOT(device->devfn);
156         func = PCI_FUNC(device->devfn);
157
158         /* verify the range */
159         if (pci_range_ck(bus, dev))
160                 return PCIBIOS_DEVICE_NOT_FOUND;
161
162         /* select the MV-64340 registers to communicate with the PCI bus */
163         if (bus == 0) {
164                 address_reg = MV64340_PCI_0_CONFIG_ADDR;
165                 data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
166         } else {
167                 address_reg = MV64340_PCI_1_CONFIG_ADDR;
168                 data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
169         }
170
171         address = (bus << 16) | (dev << 11) | (func << 8) |
172                 (offset & 0xfc) | 0x80000000;
173
174         /* start the configuration cycle */
175         MV_WRITE(address_reg, address);
176
177         /* read the data */
178         MV_READ_16(data_reg + (offset & 0x3), val);
179
180         return PCIBIOS_SUCCESSFUL;
181 }
182
183 static int marvell_pcibios_read_config_byte(struct pci_dev *device,
184                                              int offset, u8* val)
185 {
186         int dev, bus, func;
187         uint32_t address_reg, data_reg;
188         uint32_t address;
189
190         bus = device->bus->number;
191         dev = PCI_SLOT(device->devfn);
192         func = PCI_FUNC(device->devfn);
193
194         /* verify the range */
195         if (pci_range_ck(bus, dev))
196                 return PCIBIOS_DEVICE_NOT_FOUND;
197
198         /* select the MV-64340 registers to communicate with the PCI bus */
199         if (bus == 0) {
200                 address_reg = MV64340_PCI_0_CONFIG_ADDR;
201                 data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
202         } else {
203                 address_reg = MV64340_PCI_1_CONFIG_ADDR;
204                 data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
205         }
206
207         address = (bus << 16) | (dev << 11) | (func << 8) |
208                 (offset & 0xfc) | 0x80000000;
209
210         /* start the configuration cycle */
211         MV_WRITE(address_reg, address);
212
213         /* write the data */
214         MV_READ_8(data_reg + (offset & 0x3), val);
215
216         return PCIBIOS_SUCCESSFUL;
217 }
218
219 static int marvell_pcibios_write_config_dword(struct pci_dev *device,
220                                               int offset, u32 val)
221 {
222         int dev, bus, func;
223         uint32_t address_reg, data_reg;
224         uint32_t address;
225
226         bus = device->bus->number;
227         dev = PCI_SLOT(device->devfn);
228         func = PCI_FUNC(device->devfn);
229
230         /* verify the range */
231         if (pci_range_ck(bus, dev))
232                 return PCIBIOS_DEVICE_NOT_FOUND;
233
234         /* select the MV-64340 registers to communicate with the PCI bus */
235         if (bus == 0) {
236                 address_reg = MV64340_PCI_0_CONFIG_ADDR;
237                 data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
238         } else {
239                 address_reg = MV64340_PCI_1_CONFIG_ADDR;
240                 data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
241         }
242
243         address = (bus << 16) | (dev << 11) | (func << 8) |
244                 (offset & 0xfc) | 0x80000000;
245
246         /* start the configuration cycle */
247         MV_WRITE(address_reg, address);
248
249         /* write the data */
250         MV_WRITE(data_reg, val);
251
252         return PCIBIOS_SUCCESSFUL;
253 }
254
255
256 static int marvell_pcibios_write_config_word(struct pci_dev *device,
257                                              int offset, u16 val)
258 {
259         int dev, bus, func;
260         uint32_t address_reg, data_reg;
261         uint32_t address;
262
263         bus = device->bus->number;
264         dev = PCI_SLOT(device->devfn);
265         func = PCI_FUNC(device->devfn);
266
267         /* verify the range */
268         if (pci_range_ck(bus, dev))
269                 return PCIBIOS_DEVICE_NOT_FOUND;
270
271         /* select the MV-64340 registers to communicate with the PCI bus */
272         if (bus == 0) {
273                 address_reg = MV64340_PCI_0_CONFIG_ADDR;
274                 data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
275         } else {
276                 address_reg = MV64340_PCI_1_CONFIG_ADDR;
277                 data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
278         }
279
280         address = (bus << 16) | (dev << 11) | (func << 8) |
281                 (offset & 0xfc) | 0x80000000;
282
283         /* start the configuration cycle */
284         MV_WRITE(address_reg, address);
285
286         /* write the data */
287         MV_WRITE_16(data_reg + (offset & 0x3), val);
288
289         return PCIBIOS_SUCCESSFUL;
290 }
291
292 static int marvell_pcibios_write_config_byte(struct pci_dev *device,
293                                              int offset, u8 val)
294 {
295         int dev, bus, func;
296         uint32_t address_reg, data_reg;
297         uint32_t address;
298
299         bus = device->bus->number;
300         dev = PCI_SLOT(device->devfn);
301         func = PCI_FUNC(device->devfn);
302
303         /* verify the range */
304         if (pci_range_ck(bus, dev))
305                 return PCIBIOS_DEVICE_NOT_FOUND;
306
307         /* select the MV-64340 registers to communicate with the PCI bus */
308         if (bus == 0) {
309                 address_reg = MV64340_PCI_0_CONFIG_ADDR;
310                 data_reg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG;
311         } else {
312                 address_reg = MV64340_PCI_1_CONFIG_ADDR;
313                 data_reg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG;
314         }
315
316         address = (bus << 16) | (dev << 11) | (func << 8) |
317                 (offset & 0xfc) | 0x80000000;
318
319         /* start the configuration cycle */
320         MV_WRITE(address_reg, address);
321
322         /* write the data */
323         MV_WRITE_8(data_reg + (offset & 0x3), val);
324
325         return PCIBIOS_SUCCESSFUL;
326 }
327
328 struct pci_ops marvell_pci_ops = {
329         marvell_pcibios_read_config_byte,
330         marvell_pcibios_read_config_word,
331         marvell_pcibios_read_config_dword,
332         marvell_pcibios_write_config_byte,
333         marvell_pcibios_write_config_word,
334         marvell_pcibios_write_config_dword
335 };
336
337 struct pci_fixup pcibios_fixups[] = {
338         {0}
339 };
340
341 void __init pcibios_fixup_bus(struct pci_bus *c)
342 {
343         mv64340_board_pcibios_fixup_bus(c);
344 }
345
346 void __init pcibios_init(void)
347 {
348         /* Reset PCI I/O and PCI MEM values */
349         ioport_resource.start = 0xe0000000;
350         ioport_resource.end   = 0xe0000000 + 0x20000000 - 1;
351         iomem_resource.start  = 0xc0000000;
352         iomem_resource.end    = 0xc0000000 + 0x20000000 - 1;
353
354         pci_scan_bus(0, &marvell_pci_ops, NULL);
355         pci_scan_bus(1, &marvell_pci_ops, NULL);
356 }
357
358 unsigned __init int pcibios_assign_all_busses(void)
359 {
360         return 1;
361 }
362
363 #endif  /* CONFIG_PCI */