make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / arch / arm / kernel / dec21285.c
1 /*
2  *  linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285
3  *
4  *  Copyright (C) 1998-2000 Russell King, Phil Blundell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/sched.h>
11 #include <linux/kernel.h>
12 #include <linux/pci.h>
13 #include <linux/ptrace.h>
14 #include <linux/interrupt.h>
15 #include <linux/mm.h>
16 #include <linux/slab.h>
17 #include <linux/init.h>
18 #include <linux/ioport.h>
19
20 #include <asm/io.h>
21 #include <asm/irq.h>
22 #include <asm/system.h>
23 #include <asm/mach/pci.h>
24 #include <asm/hardware/dec21285.h>
25
26 #define MAX_SLOTS               21
27
28 #define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \
29                         PCI_STATUS_REC_MASTER_ABORT | \
30                         PCI_STATUS_REC_TARGET_ABORT | \
31                         PCI_STATUS_PARITY) << 16)
32
33 extern int setup_arm_irq(int, struct irqaction *);
34 extern void pcibios_report_status(u_int status_mask, int warn);
35 extern void register_isa_ports(unsigned int, unsigned int, unsigned int);
36
37 static unsigned long
38 dc21285_base_address(struct pci_dev *dev)
39 {
40         unsigned long addr = 0;
41         unsigned int devfn = dev->devfn;
42
43         if (dev->bus->number == 0) {
44                 if (PCI_SLOT(devfn) == 0)
45                         /*
46                          * For devfn 0, point at the 21285
47                          */
48                         addr = ARMCSR_BASE;
49                 else {
50                         devfn -= 1 << 3;
51
52                         if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
53                                 addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
54                 }
55         } else
56                 addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8);
57
58         return addr;
59 }
60
61 static int
62 dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value)
63 {
64         unsigned long addr = dc21285_base_address(dev);
65         u8 v;
66
67         if (addr)
68                 asm("ldr%?b     %0, [%1, %2]"
69                         : "=r" (v) : "r" (addr), "r" (where));
70         else
71                 v = 0xff;
72
73         *value = v;
74
75         return PCIBIOS_SUCCESSFUL;
76 }
77
78 static int
79 dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value)
80 {
81         unsigned long addr = dc21285_base_address(dev);
82         u16 v;
83
84         if (addr)
85                 asm("ldr%?h     %0, [%1, %2]"
86                         : "=r" (v) : "r" (addr), "r" (where));
87         else
88                 v = 0xffff;
89
90         *value = v;
91
92         return PCIBIOS_SUCCESSFUL;
93 }
94
95 static int
96 dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value)
97 {
98         unsigned long addr = dc21285_base_address(dev);
99         u32 v;
100
101         if (addr)
102                 asm("ldr%?      %0, [%1, %2]"
103                         : "=r" (v) : "r" (addr), "r" (where));
104         else
105                 v = 0xffffffff;
106
107         *value = v;
108
109         return PCIBIOS_SUCCESSFUL;
110 }
111
112 static int
113 dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value)
114 {
115         unsigned long addr = dc21285_base_address(dev);
116
117         if (addr)
118                 asm("str%?b     %0, [%1, %2]"
119                         : : "r" (value), "r" (addr), "r" (where));
120
121         return PCIBIOS_SUCCESSFUL;
122 }
123
124 static int
125 dc21285_write_config_word(struct pci_dev *dev, int where, u16 value)
126 {
127         unsigned long addr = dc21285_base_address(dev);
128
129         if (addr)
130                 asm("str%?h     %0, [%1, %2]"
131                         : : "r" (value), "r" (addr), "r" (where));
132
133         return PCIBIOS_SUCCESSFUL;
134 }
135
136 static int
137 dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value)
138 {
139         unsigned long addr = dc21285_base_address(dev);
140
141         if (addr)
142                 asm("str%?      %0, [%1, %2]"
143                         : : "r" (value), "r" (addr), "r" (where));
144
145         return PCIBIOS_SUCCESSFUL;
146 }
147
148 static struct pci_ops dc21285_ops = {
149         dc21285_read_config_byte,
150         dc21285_read_config_word,
151         dc21285_read_config_dword,
152         dc21285_write_config_byte,
153         dc21285_write_config_word,
154         dc21285_write_config_dword,
155 };
156
157 static struct timer_list serr_timer;
158 static struct timer_list perr_timer;
159
160 static void dc21285_enable_error(unsigned long __data)
161 {
162         switch (__data) {
163         case IRQ_PCI_SERR:
164                 del_timer(&serr_timer);
165                 break;
166
167         case IRQ_PCI_PERR:
168                 del_timer(&perr_timer);
169                 break;
170         }
171
172         enable_irq(__data);
173 }
174
175 /*
176  * Warn on PCI errors.
177  */
178 static void dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs)
179 {
180         unsigned int cmd;
181         unsigned int status;
182
183         cmd = *CSR_PCICMD;
184         status = cmd >> 16;
185         cmd = cmd & 0xffff;
186
187         if (status & PCI_STATUS_REC_MASTER_ABORT) {
188                 printk(KERN_DEBUG "PCI: master abort: ");
189                 pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1);
190                 printk("\n");
191
192                 cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
193         }
194
195         if (status & PCI_STATUS_REC_TARGET_ABORT) {
196                 printk(KERN_DEBUG "PCI: target abort: ");
197                 pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1);
198                 printk("\n");
199
200                 cmd |= PCI_STATUS_REC_TARGET_ABORT << 16;
201         }
202
203         *CSR_PCICMD = cmd;
204 }
205
206 static void dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
207 {
208         struct timer_list *timer = dev_id;
209         unsigned int cntl;
210
211         printk(KERN_DEBUG "PCI: system error received: ");
212         pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1);
213         printk("\n");
214
215         cntl = *CSR_SA110_CNTL & 0xffffdf07;
216         *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
217
218         /*
219          * back off this interrupt
220          */
221         disable_irq(irq);
222         timer->expires = jiffies + HZ;
223         add_timer(timer);
224 }
225
226 static void dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs)
227 {
228         printk(KERN_DEBUG "PCI: discard timer expired\n");
229         *CSR_SA110_CNTL &= 0xffffde07;
230 }
231
232 static void dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs)
233 {
234         unsigned int cmd;
235
236         printk(KERN_DEBUG "PCI: data parity error detected: ");
237         pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
238         printk("\n");
239
240         cmd = *CSR_PCICMD & 0xffff;
241         *CSR_PCICMD = cmd | 1 << 24;
242 }
243
244 static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs)
245 {
246         struct timer_list *timer = dev_id;
247         unsigned int cmd;
248
249         printk(KERN_DEBUG "PCI: parity error detected: ");
250         pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
251         printk("\n");
252
253         cmd = *CSR_PCICMD & 0xffff;
254         *CSR_PCICMD = cmd | 1 << 31;
255
256         /*
257          * back off this interrupt
258          */
259         disable_irq(irq);
260         timer->expires = jiffies + HZ;
261         add_timer(timer);
262 }
263
264 void __init dc21285_setup_resources(struct resource **resource)
265 {
266         struct resource *busmem, *busmempf;
267
268         busmem = kmalloc(sizeof(*busmem), GFP_KERNEL);
269         busmempf = kmalloc(sizeof(*busmempf), GFP_KERNEL);
270         memset(busmem, 0, sizeof(*busmem));
271         memset(busmempf, 0, sizeof(*busmempf));
272
273         busmem->flags = IORESOURCE_MEM;
274         busmem->name  = "Footbridge non-prefetch";
275         busmempf->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
276         busmempf->name  = "Footbridge prefetch";
277
278         allocate_resource(&iomem_resource, busmempf, 0x20000000,
279                           0x80000000, 0xffffffff, 0x20000000, NULL, NULL);
280         allocate_resource(&iomem_resource, busmem, 0x40000000,
281                           0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
282
283         resource[0] = &ioport_resource;
284         resource[1] = busmem;
285         resource[2] = busmempf;
286 }
287
288 void __init dc21285_init(void *sysdata)
289 {
290         unsigned int mem_size, mem_mask;
291         int cfn_mode;
292
293         mem_size = (unsigned int)high_memory - PAGE_OFFSET;
294         for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
295                 if (mem_mask >= mem_size)
296                         break;          
297
298         /*
299          * These registers need to be set up whether we're the
300          * central function or not.
301          */
302         *CSR_SDRAMBASEMASK    = (mem_mask - 1) & 0x0ffc0000;
303         *CSR_SDRAMBASEOFFSET  = 0;
304         *CSR_ROMBASEMASK      = 0x80000000;
305         *CSR_CSRBASEMASK      = 0;
306         *CSR_CSRBASEOFFSET    = 0;
307         *CSR_PCIADDR_EXTN     = 0;
308
309         cfn_mode = __footbridge_cfn_mode();
310
311         printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in "
312                 "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ?
313                 "central function" : "addin");
314
315         if (cfn_mode) {
316                 static struct resource csrmem, csrio;
317
318                 csrio.flags  = IORESOURCE_IO;
319                 csrio.name   = "Footbridge";
320                 csrmem.flags = IORESOURCE_MEM;
321                 csrmem.name  = "Footbridge";
322
323                 allocate_resource(&ioport_resource, &csrio, 128,
324                                   0xff00, 0xffff, 128, NULL, NULL);
325                 allocate_resource(&iomem_resource, &csrmem, 128,
326                                   0xf4000000, 0xf8000000, 128, NULL, NULL);
327
328                 /*
329                  * Map our SDRAM at a known address in PCI space, just in case
330                  * the firmware had other ideas.  Using a nonzero base is
331                  * necessary, since some VGA cards forcefully use PCI addresses
332                  * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
333                  */
334                 *CSR_PCICSRBASE       = csrmem.start;
335                 *CSR_PCICSRIOBASE     = csrio.start;
336                 *CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
337                 *CSR_PCIROMBASE       = 0;
338                 *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
339                               PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS;
340
341                 pci_scan_bus(0, &dc21285_ops, sysdata);
342
343                 /*
344                  * Clear any existing errors - we aren't
345                  * interested in historical data...
346                  */
347                 *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) |
348                                   SA110_CNTL_RXSERR;
349                 *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
350         } else if (footbridge_cfn_mode() != 0) {
351                 /*
352                  * If we are not compiled to accept "add-in" mode, then
353                  * we are using a constant virt_to_bus translation which
354                  * can not hope to cater for the way the host BIOS  has
355                  * set up the machine.
356                  */
357                 panic("PCI: this kernel is compiled for central "
358                         "function mode only");
359         }
360
361         /*
362          * Initialise PCI error IRQ after we've finished probing
363          */
364         request_irq(IRQ_PCI_ABORT,     dc21285_abort_irq,   SA_INTERRUPT, "PCI abort",       NULL);
365         request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer",   NULL);
366         request_irq(IRQ_PCI_DPERR,     dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL);
367
368         init_timer(&serr_timer);
369         init_timer(&perr_timer);
370
371         serr_timer.data = IRQ_PCI_SERR;
372         serr_timer.function = dc21285_enable_error;
373         perr_timer.data = IRQ_PCI_PERR;
374         perr_timer.function = dc21285_enable_error;
375
376         request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT,
377                     "PCI system error", &serr_timer);
378         request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT,
379                     "PCI parity error", &perr_timer);
380
381         register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
382 }