cleanup PCI code
[librecmc/librecmc.git] / target / linux / adm5120 / files / arch / mips / pci / pci-adm5120.c
1 /*
2  *  $Id$
3  *
4  *  ADM5120 PCI Host Controller driver
5  *
6  *  Copyright (C) ADMtek Incorporated.
7  *  Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
8  *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
9  *  Copyright (C) 2007 OpenWrt.org
10  *
11  *  This program is free software; you can redistribute it and/or
12  *  modify it under the terms of the GNU General Public License
13  *  as published by the Free Software Foundation; either version 2
14  *  of the License, or (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the
23  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  *  Boston, MA  02110-1301, USA.
25  *
26  */
27 #include <linux/types.h>
28 #include <linux/kernel.h>
29 #include <linux/init.h>
30 #include <linux/spinlock.h>
31
32 #include <linux/pci.h>
33 #include <linux/pci_ids.h>
34 #include <linux/pci_regs.h>
35
36 #include <asm/io.h>
37 #include <asm/delay.h>
38 #include <asm/bootinfo.h>
39
40 #include <adm5120_defs.h>
41 #include <adm5120_info.h>
42 #include <adm5120_defs.h>
43 #include <adm5120_irq.h>
44
45 #undef DEBUG
46
47 #ifdef DEBUG
48 #define DBG(f, a...)    printk(KERN_DEBUG f, ## a )
49 #else
50 #define DBG(f, a...)    do {} while (0)
51 #endif
52
53 #define PCI_ENABLE 0x80000000
54
55 static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
56
57 /* -------------------------------------------------------------------------*/
58
59 static inline void write_cfgaddr(u32 addr)
60 {
61         __raw_writel((addr | PCI_ENABLE),
62                 (void __iomem *)(KSEG1ADDR(ADM5120_PCICFG_ADDR)));
63 }
64
65 static inline void write_cfgdata(u32 data)
66 {
67         __raw_writel(data, (void __iomem *)KSEG1ADDR(ADM5120_PCICFG_DATA));
68 }
69
70 static inline u32 read_cfgdata(void)
71 {
72         return __raw_readl((void __iomem *)KSEG1ADDR(ADM5120_PCICFG_DATA));
73 }
74
75 static inline u32 mkaddr(struct pci_bus *bus, unsigned int devfn, int where)
76 {
77         return (((bus->number & 0xFF) << 16) | ((devfn & 0xFF) << 8) | \
78                 (where & 0xFC));
79 }
80
81 /* -------------------------------------------------------------------------*/
82
83 static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
84                 int size, u32 *val)
85 {
86         unsigned long flags;
87         u32 data;
88
89         spin_lock_irqsave(&pci_lock, flags);
90
91         write_cfgaddr(mkaddr(bus,devfn,where));
92         data = read_cfgdata();
93
94         DBG("PCI: cfg_read  %02u.%02u.%01u/%02X:%01d, cfg:0x%08X",
95                 bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
96                 where, size, data);
97
98         switch (size) {
99         case 1:
100                 if (where & 1)
101                         data >>= 8;
102                 if (where & 2)
103                         data >>= 16;
104                 data &= 0xFF;
105                 break;
106         case 2:
107                 if (where & 2)
108                         data >>= 16;
109                 data &= 0xFFFF;
110                 break;
111         }
112
113         *val = data;
114         DBG(", 0x%08X returned\n", data);
115
116         spin_unlock_irqrestore(&pci_lock, flags);
117
118         return PCIBIOS_SUCCESSFUL;
119 }
120
121 static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
122                 int size, u32 val)
123 {
124         unsigned long flags;
125         u32 data;
126         int s;
127
128         spin_lock_irqsave(&pci_lock, flags);
129
130         write_cfgaddr(mkaddr(bus,devfn,where));
131         data = read_cfgdata();
132
133         DBG("PCI: cfg_write %02u.%02u.%01u/%02X:%01d, cfg:0x%08X",
134                 bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
135                 where, size, data);
136
137         switch (size) {
138         case 1:
139                 s = ((where & 3) << 3);
140                 data &= ~(0xFF << s);
141                 data |= ((val & 0xFF) << s);
142                 break;
143         case 2:
144                 s = ((where & 2) << 4);
145                 data &= ~(0xFFFF << s);
146                 data |= ((val & 0xFFFF) << s);
147                 break;
148         case 4:
149                 data = val;
150                 break;
151         }
152
153         write_cfgdata(data);
154         DBG(", 0x%08X written\n", data);
155
156         spin_unlock_irqrestore(&pci_lock, flags);
157
158         return PCIBIOS_SUCCESSFUL;
159 }
160
161 struct pci_ops adm5120_pci_ops = {
162         .read   = pci_config_read,
163         .write  = pci_config_write,
164 };
165
166 /* -------------------------------------------------------------------------*/
167
168 static void adm5120_pci_fixup(struct pci_dev *dev)
169 {
170         if (dev->devfn != 0)
171                 return;
172
173         /* setup COMMAND register */
174         pci_write_config_word(dev, PCI_COMMAND,
175                 (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
176
177         /* setup CACHE_LINE_SIZE register */
178         pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4);
179
180         /* setup BARS */
181         pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);
182         pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
183 }
184
185 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_ADM5120,
186         adm5120_pci_fixup);
187
188 /* -------------------------------------------------------------------------*/
189
190 struct adm5120_pci_irq {
191         u8      slot;
192         u8      func;
193         u8      pin;
194         unsigned irq;
195 };
196
197 #define PCIIRQ(s,f,p,i) {       \
198         .slot = (s),            \
199         .func = (f),            \
200         .pin  = (p),            \
201         .irq  = (i)             \
202         }
203
204 static struct adm5120_pci_irq default_pci_irqs[] __initdata = {
205         PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI0),
206 };
207
208 static struct adm5120_pci_irq rb1xx_pci_irqs[] __initdata = {
209         PCIIRQ(1, 0, 1, ADM5120_IRQ_PCI0),
210         PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI1),
211         PCIIRQ(3, 0, 1, ADM5120_IRQ_PCI2)
212 };
213
214 static struct adm5120_pci_irq cas771_pci_irqs[] __initdata = {
215         PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI0),
216         PCIIRQ(3, 0, 1, ADM5120_IRQ_PCI1),
217         PCIIRQ(3, 2, 3, ADM5120_IRQ_PCI2)
218 };
219
220 static struct adm5120_pci_irq np28g_pci_irqs[] __initdata = {
221         PCIIRQ(2, 0, 1, ADM5120_IRQ_PCI0),
222         PCIIRQ(3, 0, 1, ADM5120_IRQ_PCI0),
223         PCIIRQ(3, 1, 2, ADM5120_IRQ_PCI1),
224         PCIIRQ(3, 2, 3, ADM5120_IRQ_PCI2)
225 };
226
227 #define GETMAP(n) do {                          \
228                 nr_irqs = ARRAY_SIZE(n ## _pci_irqs);   \
229                 p = n ## _pci_irqs;                     \
230         } while (0)
231
232 int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
233 {
234         struct adm5120_pci_irq  *p;
235         int nr_irqs;
236         int i;
237         int irq;
238
239         irq = -1;
240         if (slot < 1 || slot > 3) {
241                 printk(KERN_ALERT "PCI: slot number %u is not supported\n",
242                         slot);
243                 goto out;
244         }
245
246         GETMAP(default);
247
248         switch (mips_machtype) {
249         case MACH_ADM5120_RB_111:
250         case MACH_ADM5120_RB_112:
251         case MACH_ADM5120_RB_133:
252         case MACH_ADM5120_RB_133C:
253         case MACH_ADM5120_RB_153:
254                 GETMAP(rb1xx);
255                 break;
256         case MACH_ADM5120_NP28G:
257                 GETMAP(np28g);
258                 break;
259         case MACH_ADM5120_P335:
260         case MACH_ADM5120_P334WT:
261                 /* using default mapping */
262                 break;
263         case MACH_ADM5120_CAS771:
264                 GETMAP(cas771);
265                 break;
266
267         case MACH_ADM5120_NP27G:
268         case MACH_ADM5120_NP28GHS:
269         case MACH_ADM5120_WP54AG:
270         case MACH_ADM5120_WP54G:
271         case MACH_ADM5120_WP54G_WRT:
272         case MACH_ADM5120_WPP54AG:
273         case MACH_ADM5120_WPP54G:
274         default:
275                 printk(KERN_ALERT "PCI: irq map is unknown, using defaults.\n");
276                 break;
277         }
278
279         for (i = 0; i < nr_irqs; i++, p++) {
280                 if ((p->slot == slot) && (PCI_FUNC(dev->devfn) == p->func) &&
281                     (p->pin == pin)) {
282                         irq = p->irq;
283                         break;
284                 }
285         }
286
287         if (irq < 0) {
288                 printk(KERN_ALERT "PCI: no irq found for %s pin:%u\n",
289                         pci_name(dev), pin);
290         } else {
291                 printk(KERN_INFO "PCI: mapping irq for %s pin:%u, irq:%d\n",
292                         pci_name(dev), pin, irq);
293         }
294
295 out:
296         return irq;
297 }
298
299 int pcibios_plat_dev_init(struct pci_dev *dev)
300 {
301         return 0;
302 }
303
304 /* -------------------------------------------------------------------------*/
305
306 static struct resource pci_io_resource = {
307         .name   = "ADM5120 PCI I/O",
308         .start  = ADM5120_PCIIO_BASE,
309         .end    = ADM5120_PCICFG_ADDR-1,
310         .flags  = IORESOURCE_IO
311 };
312
313 static struct resource pci_mem_resource = {
314         .name   = "ADM5120 PCI MEM",
315         .start  = ADM5120_PCIMEM_BASE,
316         .end    = ADM5120_PCIIO_BASE-1,
317         .flags  = IORESOURCE_MEM
318 };
319
320 static struct pci_controller adm5120_controller = {
321         .pci_ops        = &adm5120_pci_ops,
322         .io_resource    = &pci_io_resource,
323         .mem_resource   = &pci_mem_resource,
324 };
325
326 static int __init adm5120_pci_setup(void)
327 {
328         int pci_bios;
329
330         pci_bios = adm5120_has_pci();
331
332         printk(KERN_INFO "adm5120: system has %sPCI BIOS\n",
333                 pci_bios ? "" : "no ");
334         if (pci_bios == 0)
335                 return -1;
336
337         /* Avoid ISA compat ranges.  */
338         PCIBIOS_MIN_IO = 0x00000000;
339         PCIBIOS_MIN_MEM = 0x00000000;
340
341         /* Set I/O resource limits.  */
342         ioport_resource.end = 0x1fffffff;
343         iomem_resource.end = 0xffffffff;
344
345         register_pci_controller(&adm5120_controller);
346         return 0;
347 }
348
349 arch_initcall(adm5120_pci_setup);