ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / pci / ops-ddb5476.c
1 /*
2  * Copyright 2001 MontaVista Software Inc.
3  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4  *
5  * arch/mips/ddb5xxx/ddb5476/pci_ops.c
6  *     Define the pci_ops for DB5477.
7  *
8  * Much of the code is derived from the original DDB5074 port by
9  * Geert Uytterhoeven <geert@sonycom.com>
10  *
11  * This program is free software; you can redistribute  it and/or modify it
12  * under  the terms of  the GNU General  Public License as published by the
13  * Free Software Foundation;  either version 2 of the  License, or (at your
14  * option) any later version.
15  *
16  */
17 #include <linux/pci.h>
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20
21 #include <asm/addrspace.h>
22 #include <asm/debug.h>
23
24 #include <asm/ddb5xxx/ddb5xxx.h>
25
26 /*
27  * config_swap structure records what set of pdar/pmr are used
28  * to access pci config space.  It also provides a place hold the
29  * original values for future restoring.
30  */
31 struct pci_config_swap {
32         u32 pdar;
33         u32 pmr;
34         u32 config_base;
35         u32 config_size;
36         u32 pdar_backup;
37         u32 pmr_backup;
38 };
39
40 /*
41  * On DDB5476, we have one set of swap registers
42  */
43 struct pci_config_swap ext_pci_swap = {
44         DDB_PCIW0,
45         DDB_PCIINIT0,
46         DDB_PCI_CONFIG_BASE,
47         DDB_PCI_CONFIG_SIZE
48 };
49
50 static int pci_config_workaround = 1;
51
52 /*
53  * access config space
54  */
55 static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus, /* 0 means top level bus */
56                                          u32 slot_num)
57 {
58         u32 pci_addr = 0;
59         u32 pciinit_offset = 0;
60         u32 virt_addr = swap->config_base;
61         u32 option;
62
63         if (pci_config_workaround) {
64                 /* [jsun] work around Vrc5476 controller itself, returnning
65                  * slot 0 essentially makes vrc5476 invisible
66                  */
67                 if (slot_num == 12)
68                         slot_num = 0;
69
70 #if 0
71                 /* BUG : skip P2P bridge for now */
72                 if (slot_num == 5)
73                         slot_num = 0;
74 #endif
75
76         } else {
77                 /* now we have to be hornest, returning the true
78                  * PCI config headers for vrc5476
79                  */
80                 if (slot_num == 12) {
81                         swap->pdar_backup = ddb_in32(swap->pdar);
82                         swap->pmr_backup = ddb_in32(swap->pmr);
83                         return DDB_BASE + DDB_PCI_BASE;
84                 }
85         }
86
87         /* minimum pdar (window) size is 2MB */
88         db_assert(swap->config_size >= (2 << 20));
89
90         db_assert(slot_num < (1 << 5));
91         db_assert(bus < (1 << 8));
92
93         /* backup registers */
94         swap->pdar_backup = ddb_in32(swap->pdar);
95         swap->pmr_backup = ddb_in32(swap->pmr);
96
97         /* set the pdar (pci window) register */
98         ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32,      /* 32 bit wide */
99                      0,         /* not on local memory bus */
100                      0);        /* not visible from PCI bus (N/A) */
101
102         /*
103          * calcuate the absolute pci config addr;
104          * according to the spec, we start scanning from adr:11 (0x800)
105          */
106         if (bus == 0) {
107                 /* type 0 config */
108                 pci_addr = 0x800 << slot_num;
109         } else {
110                 /* type 1 config */
111                 pci_addr = (bus << 16) | (slot_num << 11);
112                 /* panic("ddb_access_config_base: we don't support type 1 config Yet"); */
113         }
114
115         /*
116          * if pci_addr is less than pci config window size,  we set
117          * pciinit_offset to 0 and adjust the virt_address.
118          * Otherwise we will try to adjust pciinit_offset.
119          */
120         if (pci_addr < swap->config_size) {
121                 virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
122                 pciinit_offset = 0;
123         } else {
124                 db_assert((pci_addr & (swap->config_size - 1)) == 0);
125                 virt_addr = KSEG1ADDR(swap->config_base);
126                 pciinit_offset = pci_addr;
127         }
128
129         /* set the pmr register */
130         option = DDB_PCI_ACCESS_32;
131         if (bus != 0)
132                 option |= DDB_PCI_CFGTYPE1;
133         ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
134
135         return virt_addr;
136 }
137
138 static inline void ddb_close_config_base(struct pci_config_swap *swap)
139 {
140         ddb_out32(swap->pdar, swap->pdar_backup);
141         ddb_out32(swap->pmr, swap->pmr_backup);
142 }
143
144 static int read_config_dword(struct pci_config_swap *swap,
145                              struct pci_dev *dev, u32 where, u32 * val)
146 {
147         u32 bus, slot_num, func_num;
148         u32 base;
149
150         db_assert((where & 3) == 0);
151         db_assert(where < (1 << 8));
152
153         /* check if the bus is top-level */
154         if (dev->bus->parent != NULL) {
155                 bus = dev->bus->number;
156                 db_assert(bus != 0);
157         } else {
158                 bus = 0;
159         }
160
161         slot_num = PCI_SLOT(dev->devfn);
162         func_num = PCI_FUNC(dev->devfn);
163         base = ddb_access_config_base(swap, bus, slot_num);
164         *val = *(volatile u32 *) (base + (func_num << 8) + where);
165         ddb_close_config_base(swap);
166         return PCIBIOS_SUCCESSFUL;
167 }
168
169 static int read_config_word(struct pci_config_swap *swap,
170                             struct pci_dev *dev, u32 where, u16 * val)
171 {
172         int status;
173         u32 result;
174
175         db_assert((where & 1) == 0);
176
177         status = read_config_dword(swap, dev, where & ~3, &result);
178         if (where & 2)
179                 result >>= 16;
180         *val = result & 0xffff;
181         return status;
182 }
183
184 static int read_config_byte(struct pci_config_swap *swap,
185                             struct pci_dev *dev, u32 where, u8 * val)
186 {
187         int status;
188         u32 result;
189
190         status = read_config_dword(swap, dev, where & ~3, &result);
191         if (where & 1)
192                 result >>= 8;
193         if (where & 2)
194                 result >>= 16;
195         *val = result & 0xff;
196         return status;
197 }
198
199 static int write_config_dword(struct pci_config_swap *swap,
200                               struct pci_dev *dev, u32 where, u32 val)
201 {
202         u32 bus, slot_num, func_num;
203         u32 base;
204
205         db_assert((where & 3) == 0);
206         db_assert(where < (1 << 8));
207
208         /* check if the bus is top-level */
209         if (dev->bus->parent != NULL) {
210                 bus = dev->bus->number;
211                 db_assert(bus != 0);
212         } else {
213                 bus = 0;
214         }
215
216         slot_num = PCI_SLOT(dev->devfn);
217         func_num = PCI_FUNC(dev->devfn);
218         base = ddb_access_config_base(swap, bus, slot_num);
219         *(volatile u32 *) (base + (func_num << 8) + where) = val;
220         ddb_close_config_base(swap);
221         return PCIBIOS_SUCCESSFUL;
222 }
223
224 static int write_config_word(struct pci_config_swap *swap,
225                              struct pci_dev *dev, u32 where, u16 val)
226 {
227         int status, shift = 0;
228         u32 result;
229
230         db_assert((where & 1) == 0);
231
232         status = read_config_dword(swap, dev, where & ~3, &result);
233         if (status != PCIBIOS_SUCCESSFUL)
234                 return status;
235
236         if (where & 2)
237                 shift += 16;
238         result &= ~(0xffff << shift);
239         result |= val << shift;
240         return write_config_dword(swap, dev, where & ~3, result);
241 }
242
243 static int write_config_byte(struct pci_config_swap *swap,
244                              struct pci_dev *dev, u32 where, u8 val)
245 {
246         int status, shift = 0;
247         u32 result;
248
249         status = read_config_dword(swap, dev, where & ~3, &result);
250         if (status != PCIBIOS_SUCCESSFUL)
251                 return status;
252
253         if (where & 2)
254                 shift += 16;
255         if (where & 1)
256                 shift += 8;
257         result &= ~(0xff << shift);
258         result |= val << shift;
259         return write_config_dword(swap, dev, where & ~3, result);
260 }
261
262 #define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
263 static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \
264 { \
265      return rw##_config_##unitname(pciswap, \
266                                    dev, \
267                                    where, \
268                                    val); \
269 }
270
271 MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap)
272     MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap)
273     MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap)
274
275     MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap)
276     MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap)
277     MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap)
278
279 struct pci_ops ddb5476_ext_pci_ops = {
280         extpci_read_config_byte,
281         extpci_read_config_word,
282         extpci_read_config_dword,
283         extpci_write_config_byte,
284         extpci_write_config_word,
285         extpci_write_config_dword
286 };