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