ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / pci / ops-ddb5074.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                 if (slot_num == 5)
65                         slot_num = 14;
66         } else {
67                 if (slot_num == 5)
68                         return DDB_BASE + DDB_PCI_BASE;
69         }
70
71         /* minimum pdar (window) size is 2MB */
72         db_assert(swap->config_size >= (2 << 20));
73
74         db_assert(slot_num < (1 << 5));
75         db_assert(bus < (1 << 8));
76
77         /* backup registers */
78         swap->pdar_backup = ddb_in32(swap->pdar);
79         swap->pmr_backup = ddb_in32(swap->pmr);
80
81         /* set the pdar (pci window) register */
82         ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32,      /* 32 bit wide */
83                      0,         /* not on local memory bus */
84                      0);        /* not visible from PCI bus (N/A) */
85
86         /*
87          * calcuate the absolute pci config addr;
88          * according to the spec, we start scanning from adr:11 (0x800)
89          */
90         if (bus == 0) {
91                 /* type 0 config */
92                 pci_addr = 0x00040000 << slot_num;
93         } else {
94                 /* type 1 config */
95                 pci_addr = 0x00040000 << slot_num;
96                 panic
97                     ("ddb_access_config_base: we don't support type 1 config Yet");
98         }
99
100         /*
101          * if pci_addr is less than pci config window size,  we set
102          * pciinit_offset to 0 and adjust the virt_address.
103          * Otherwise we will try to adjust pciinit_offset.
104          */
105         if (pci_addr < swap->config_size) {
106                 virt_addr = KSEG1ADDR(swap->config_base + pci_addr);
107                 pciinit_offset = 0;
108         } else {
109                 db_assert((pci_addr & (swap->config_size - 1)) == 0);
110                 virt_addr = KSEG1ADDR(swap->config_base);
111                 pciinit_offset = pci_addr;
112         }
113
114         /* set the pmr register */
115         option = DDB_PCI_ACCESS_32;
116         if (bus != 0)
117                 option |= DDB_PCI_CFGTYPE1;
118         ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option);
119
120         return virt_addr;
121 }
122
123 static inline void ddb_close_config_base(struct pci_config_swap *swap)
124 {
125         ddb_out32(swap->pdar, swap->pdar_backup);
126         ddb_out32(swap->pmr, swap->pmr_backup);
127 }
128
129 static int read_config_dword(struct pci_config_swap *swap,
130                              struct pci_dev *dev, u32 where, u32 * val)
131 {
132         u32 bus, slot_num, func_num;
133         u32 base;
134
135         db_assert((where & 3) == 0);
136         db_assert(where < (1 << 8));
137
138         /* check if the bus is top-level */
139         if (dev->bus->parent != NULL) {
140                 bus = dev->bus->number;
141                 db_assert(bus != 0);
142         } else {
143                 bus = 0;
144         }
145
146         slot_num = PCI_SLOT(dev->devfn);
147         func_num = PCI_FUNC(dev->devfn);
148         base = ddb_access_config_base(swap, bus, slot_num);
149         *val = *(volatile u32 *) (base + (func_num << 8) + where);
150         ddb_close_config_base(swap);
151         return PCIBIOS_SUCCESSFUL;
152 }
153
154 static int read_config_word(struct pci_config_swap *swap,
155                             struct pci_dev *dev, u32 where, u16 * val)
156 {
157         int status;
158         u32 result;
159
160         db_assert((where & 1) == 0);
161
162         status = read_config_dword(swap, dev, where & ~3, &result);
163         if (where & 2)
164                 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, u32 where, u8 * val)
171 {
172         int status;
173         u32 result;
174
175         status = read_config_dword(swap, dev, where & ~3, &result);
176         if (where & 1)
177                 result >>= 8;
178         if (where & 2)
179                 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, u32 where, u32 val)
186 {
187         u32 bus, slot_num, func_num;
188         u32 base;
189
190         db_assert((where & 3) == 0);
191         db_assert(where < (1 << 8));
192
193         /* check if the bus is top-level */
194         if (dev->bus->parent != NULL) {
195                 bus = dev->bus->number;
196                 db_assert(bus != 0);
197         } else {
198                 bus = 0;
199         }
200
201         slot_num = PCI_SLOT(dev->devfn);
202         func_num = PCI_FUNC(dev->devfn);
203         base = ddb_access_config_base(swap, bus, slot_num);
204         *(volatile u32 *) (base + (func_num << 8) + where) = val;
205         ddb_close_config_base(swap);
206         return PCIBIOS_SUCCESSFUL;
207 }
208
209 static int write_config_word(struct pci_config_swap *swap,
210                              struct pci_dev *dev, u32 where, u16 val)
211 {
212         int status, shift = 0;
213         u32 result;
214
215         db_assert((where & 1) == 0);
216
217         status = read_config_dword(swap, dev, where & ~3, &result);
218         if (status != PCIBIOS_SUCCESSFUL)
219                 return status;
220
221         if (where & 2)
222                 shift += 16;
223         result &= ~(0xffff << shift);
224         result |= val << shift;
225         return write_config_dword(swap, dev, where & ~3, result);
226 }
227
228 static int write_config_byte(struct pci_config_swap *swap,
229                              struct pci_dev *dev, u32 where, u8 val)
230 {
231         int status, shift = 0;
232         u32 result;
233
234         status = read_config_dword(swap, dev, where & ~3, &result);
235         if (status != PCIBIOS_SUCCESSFUL)
236                 return status;
237
238         if (where & 2)
239                 shift += 16;
240         if (where & 1)
241                 shift += 8;
242         result &= ~(0xff << shift);
243         result |= val << shift;
244         return write_config_dword(swap, dev, where & ~3, result);
245 }
246
247 #define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \
248 static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \
249 { \
250      return rw##_config_##unitname(pciswap, \
251                                    dev, \
252                                    where, \
253                                    val); \
254 }
255
256 MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap)
257     MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap)
258     MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap)
259
260     MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap)
261     MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap)
262     MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap)
263
264 struct pci_ops ddb5476_ext_pci_ops = {
265         extpci_read_config_byte,
266         extpci_read_config_word,
267         extpci_read_config_dword,
268         extpci_write_config_byte,
269         extpci_write_config_word,
270         extpci_write_config_dword
271 };