aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ixp2000
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-ixp2000
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/arm/mach-ixp2000')
-rw-r--r--arch/arm/mach-ixp2000/Kconfig59
-rw-r--r--arch/arm/mach-ixp2000/Makefile14
-rw-r--r--arch/arm/mach-ixp2000/Makefile.boot3
-rw-r--r--arch/arm/mach-ixp2000/core.c390
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c220
-rw-r--r--arch/arm/mach-ixp2000/ixdp2400.c179
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c180
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c304
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c400
-rw-r--r--arch/arm/mach-ixp2000/pci.c235
10 files changed, 1984 insertions, 0 deletions
diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig
new file mode 100644
index 000000000000..9361e05f6fa3
--- /dev/null
+++ b/arch/arm/mach-ixp2000/Kconfig
@@ -0,0 +1,59 @@
1
2if ARCH_IXP2000
3
4config ARCH_SUPPORTS_BIG_ENDIAN
5 bool
6 default y
7
8menu "Intel IXP2400/2800 Implementation Options"
9
10comment "IXP2400/2800 Platforms"
11
12config ARCH_ENP2611
13 bool "Support Radisys ENP-2611"
14 help
15 Say 'Y' here if you want your kernel to support the Radisys
16 ENP2611 PCI network processing card. For more information on
17 this card, see <file:Documentation/arm/ENP2611>.
18
19config ARCH_IXDP2400
20 bool "Support Intel IXDP2400"
21 help
22 Say 'Y' here if you want your kernel to support the Intel
23 IXDP2400 reference platform. For more information on
24 this platform, see <file:Documentation/arm/IXP2000>.
25
26config ARCH_IXDP2800
27 bool "Support Intel IXDP2800"
28 help
29 Say 'Y' here if you want your kernel to support the Intel
30 IXDP2800 reference platform. For more information on
31 this platform, see <file:Documentation/arm/IXP2000>.
32
33config ARCH_IXDP2X00
34 bool
35 depends on ARCH_IXDP2400 || ARCH_IXDP2800
36 default y
37
38config ARCH_IXDP2401
39 bool "Support Intel IXDP2401"
40 help
41 Say 'Y' here if you want your kernel to support the Intel
42 IXDP2401 reference platform. For more information on
43 this platform, see <file:Documentation/arm/IXP2000>.
44
45config ARCH_IXDP2801
46 bool "Support Intel IXDP2801"
47 help
48 Say 'Y' here if you want your kernel to support the Intel
49 IXDP2801 reference platform. For more information on
50 this platform, see <file:Documentation/arm/IXP2000>.
51
52config ARCH_IXDP2X01
53 bool
54 depends on ARCH_IXDP2401 || ARCH_IXDP2801
55 default y
56
57endmenu
58
59endif
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile
new file mode 100644
index 000000000000..1e6139d42a92
--- /dev/null
+++ b/arch/arm/mach-ixp2000/Makefile
@@ -0,0 +1,14 @@
1#
2# Makefile for the linux kernel.
3#
4obj-y := core.o pci.o
5obj-m :=
6obj-n :=
7obj- :=
8
9obj-$(CONFIG_ARCH_ENP2611) += enp2611.o
10obj-$(CONFIG_ARCH_IXDP2400) += ixdp2400.o
11obj-$(CONFIG_ARCH_IXDP2800) += ixdp2800.o
12obj-$(CONFIG_ARCH_IXDP2X00) += ixdp2x00.o
13obj-$(CONFIG_ARCH_IXDP2X01) += ixdp2x01.o
14
diff --git a/arch/arm/mach-ixp2000/Makefile.boot b/arch/arm/mach-ixp2000/Makefile.boot
new file mode 100644
index 000000000000..d84c5807a43d
--- /dev/null
+++ b/arch/arm/mach-ixp2000/Makefile.boot
@@ -0,0 +1,3 @@
1 zreladdr-y := 0x00008000
2params_phys-y := 0x00000100
3
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
new file mode 100644
index 000000000000..4f3c3d5c781c
--- /dev/null
+++ b/arch/arm/mach-ixp2000/core.c
@@ -0,0 +1,390 @@
1/*
2 * arch/arm/mach-ixp2000/common.c
3 *
4 * Common routines used by all IXP2400/2800 based platforms.
5 *
6 * Author: Deepak Saxena <dsaxena@plexity.net>
7 *
8 * Copyright 2004 (C) MontaVista Software, Inc.
9 *
10 * Based on work Copyright (C) 2002-2003 Intel Corporation
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/config.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/sched.h>
22#include <linux/interrupt.h>
23#include <linux/serial.h>
24#include <linux/tty.h>
25#include <linux/bitops.h>
26#include <linux/serial_core.h>
27#include <linux/mm.h>
28
29#include <asm/types.h>
30#include <asm/setup.h>
31#include <asm/memory.h>
32#include <asm/hardware.h>
33#include <asm/mach-types.h>
34#include <asm/irq.h>
35#include <asm/system.h>
36#include <asm/tlbflush.h>
37#include <asm/pgtable.h>
38
39#include <asm/mach/map.h>
40#include <asm/mach/time.h>
41#include <asm/mach/irq.h>
42
43static DEFINE_SPINLOCK(ixp2000_slowport_lock);
44static unsigned long ixp2000_slowport_irq_flags;
45
46/*************************************************************************
47 * Slowport access routines
48 *************************************************************************/
49void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
50{
51
52 spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
53
54 old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
55 old_cfg->WTC = *IXP2000_SLOWPORT_WTC2;
56 old_cfg->RTC = *IXP2000_SLOWPORT_RTC2;
57 old_cfg->PCR = *IXP2000_SLOWPORT_PCR;
58 old_cfg->ADC = *IXP2000_SLOWPORT_ADC;
59
60 ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR);
61 ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
62 ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
63 ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
64 ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
65}
66
67void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
68{
69 ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR);
70 ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
71 ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
72 ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
73 ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
74
75 spin_unlock_irqrestore(&ixp2000_slowport_lock,
76 ixp2000_slowport_irq_flags);
77}
78
79/*************************************************************************
80 * Chip specific mappings shared by all IXP2000 systems
81 *************************************************************************/
82static struct map_desc ixp2000_io_desc[] __initdata = {
83 {
84 .virtual = IXP2000_CAP_VIRT_BASE,
85 .physical = IXP2000_CAP_PHYS_BASE,
86 .length = IXP2000_CAP_SIZE,
87 .type = MT_DEVICE
88 }, {
89 .virtual = IXP2000_INTCTL_VIRT_BASE,
90 .physical = IXP2000_INTCTL_PHYS_BASE,
91 .length = IXP2000_INTCTL_SIZE,
92 .type = MT_DEVICE
93 }, {
94 .virtual = IXP2000_PCI_CREG_VIRT_BASE,
95 .physical = IXP2000_PCI_CREG_PHYS_BASE,
96 .length = IXP2000_PCI_CREG_SIZE,
97 .type = MT_DEVICE
98 }, {
99 .virtual = IXP2000_PCI_CSR_VIRT_BASE,
100 .physical = IXP2000_PCI_CSR_PHYS_BASE,
101 .length = IXP2000_PCI_CSR_SIZE,
102 .type = MT_DEVICE
103 }, {
104 .virtual = IXP2000_PCI_IO_VIRT_BASE,
105 .physical = IXP2000_PCI_IO_PHYS_BASE,
106 .length = IXP2000_PCI_IO_SIZE,
107 .type = MT_DEVICE
108 }, {
109 .virtual = IXP2000_PCI_CFG0_VIRT_BASE,
110 .physical = IXP2000_PCI_CFG0_PHYS_BASE,
111 .length = IXP2000_PCI_CFG0_SIZE,
112 .type = MT_DEVICE
113 }, {
114 .virtual = IXP2000_PCI_CFG1_VIRT_BASE,
115 .physical = IXP2000_PCI_CFG1_PHYS_BASE,
116 .length = IXP2000_PCI_CFG1_SIZE,
117 .type = MT_DEVICE
118 }
119};
120
121static struct uart_port ixp2000_serial_port = {
122 .membase = (char *)(IXP2000_UART_VIRT_BASE + 3),
123 .mapbase = IXP2000_UART_PHYS_BASE + 3,
124 .irq = IRQ_IXP2000_UART,
125 .flags = UPF_SKIP_TEST,
126 .iotype = UPIO_MEM,
127 .regshift = 2,
128 .uartclk = 50000000,
129 .line = 0,
130 .type = PORT_XSCALE,
131 .fifosize = 16
132};
133
134void __init ixp2000_map_io(void)
135{
136 extern unsigned int processor_id;
137
138 /*
139 * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE for
140 * tweaking the PMDs so XCB=101. On IXP2800s we use the normal
141 * PMD flags.
142 */
143 if ((processor_id & 0xfffffff0) == 0x69054190) {
144 int i;
145
146 printk(KERN_INFO "Enabling IXP2400 erratum #66 workaround\n");
147
148 for(i=0;i<ARRAY_SIZE(ixp2000_io_desc);i++)
149 ixp2000_io_desc[i].type = MT_IXP2000_DEVICE;
150 }
151
152 iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
153 early_serial_setup(&ixp2000_serial_port);
154
155 /* Set slowport to 8-bit mode. */
156 ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1);
157}
158
159/*************************************************************************
160 * Timer-tick functions for IXP2000
161 *************************************************************************/
162static unsigned ticks_per_jiffy;
163static unsigned ticks_per_usec;
164static unsigned next_jiffy_time;
165
166unsigned long ixp2000_gettimeoffset (void)
167{
168 unsigned long offset;
169
170 offset = next_jiffy_time - *IXP2000_T4_CSR;
171
172 return offset / ticks_per_usec;
173}
174
175static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
176{
177 write_seqlock(&xtime_lock);
178
179 /* clear timer 1 */
180 ixp2000_reg_write(IXP2000_T1_CLR, 1);
181
182 while ((next_jiffy_time - *IXP2000_T4_CSR) > ticks_per_jiffy) {
183 timer_tick(regs);
184 next_jiffy_time -= ticks_per_jiffy;
185 }
186
187 write_sequnlock(&xtime_lock);
188
189 return IRQ_HANDLED;
190}
191
192static struct irqaction ixp2000_timer_irq = {
193 .name = "IXP2000 Timer Tick",
194 .flags = SA_INTERRUPT,
195 .handler = ixp2000_timer_interrupt
196};
197
198void __init ixp2000_init_time(unsigned long tick_rate)
199{
200 ixp2000_reg_write(IXP2000_T1_CLR, 0);
201 ixp2000_reg_write(IXP2000_T4_CLR, 0);
202
203 ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
204 ticks_per_usec = tick_rate / 1000000;
205
206 ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
207 ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
208
209 /*
210 * We use T4 as a monotonic counter to track missed jiffies
211 */
212 ixp2000_reg_write(IXP2000_T4_CLD, -1);
213 ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7));
214 next_jiffy_time = 0xffffffff;
215
216 /* register for interrupt */
217 setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq);
218}
219
220/*************************************************************************
221 * GPIO helpers
222 *************************************************************************/
223static unsigned long GPIO_IRQ_rising_edge;
224static unsigned long GPIO_IRQ_falling_edge;
225static unsigned long GPIO_IRQ_level_low;
226static unsigned long GPIO_IRQ_level_high;
227
228void gpio_line_config(int line, int style)
229{
230 unsigned long flags;
231
232 local_irq_save(flags);
233
234 if(style == GPIO_OUT) {
235 /* if it's an output, it ain't an interrupt anymore */
236 ixp2000_reg_write(IXP2000_GPIO_PDSR, (1 << line));
237 GPIO_IRQ_falling_edge &= ~(1 << line);
238 GPIO_IRQ_rising_edge &= ~(1 << line);
239 GPIO_IRQ_level_low &= ~(1 << line);
240 GPIO_IRQ_level_high &= ~(1 << line);
241 ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
242 ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
243 ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
244 ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
245 irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0;
246 } else if(style == GPIO_IN) {
247 ixp2000_reg_write(IXP2000_GPIO_PDCR, (1 << line));
248 }
249
250 local_irq_restore(flags);
251}
252
253
254/*************************************************************************
255 * IRQ handling IXP2000
256 *************************************************************************/
257static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
258{
259 int i;
260 unsigned long status = *IXP2000_GPIO_INST;
261
262 for (i = 0; i <= 7; i++) {
263 if (status & (1<<i)) {
264 desc = irq_desc + i + IRQ_IXP2000_GPIO0;
265 desc->handle(i + IRQ_IXP2000_GPIO0, desc, regs);
266 }
267 }
268}
269
270static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
271{
272 ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
273 ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
274}
275
276static void ixp2000_GPIO_irq_mask(unsigned int irq)
277{
278 ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
279}
280
281static void ixp2000_GPIO_irq_unmask(unsigned int irq)
282{
283 ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
284}
285
286static struct irqchip ixp2000_GPIO_irq_chip = {
287 .ack = ixp2000_GPIO_irq_mask_ack,
288 .mask = ixp2000_GPIO_irq_mask,
289 .unmask = ixp2000_GPIO_irq_unmask
290};
291
292static void ixp2000_pci_irq_mask(unsigned int irq)
293{
294 unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
295 if (irq == IRQ_IXP2000_PCIA)
296 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
297 else if (irq == IRQ_IXP2000_PCIB)
298 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
299}
300
301static void ixp2000_pci_irq_unmask(unsigned int irq)
302{
303 unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
304 if (irq == IRQ_IXP2000_PCIA)
305 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26)));
306 else if (irq == IRQ_IXP2000_PCIB)
307 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27)));
308}
309
310static struct irqchip ixp2000_pci_irq_chip = {
311 .ack = ixp2000_pci_irq_mask,
312 .mask = ixp2000_pci_irq_mask,
313 .unmask = ixp2000_pci_irq_unmask
314};
315
316static void ixp2000_irq_mask(unsigned int irq)
317{
318 ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq));
319}
320
321static void ixp2000_irq_unmask(unsigned int irq)
322{
323 ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
324}
325
326static struct irqchip ixp2000_irq_chip = {
327 .ack = ixp2000_irq_mask,
328 .mask = ixp2000_irq_mask,
329 .unmask = ixp2000_irq_unmask
330};
331
332void __init ixp2000_init_irq(void)
333{
334 int irq;
335
336 /*
337 * Mask all sources
338 */
339 ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff);
340 ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff);
341
342 /* clear all GPIO edge/level detects */
343 ixp2000_reg_write(IXP2000_GPIO_REDR, 0);
344 ixp2000_reg_write(IXP2000_GPIO_FEDR, 0);
345 ixp2000_reg_write(IXP2000_GPIO_LSHR, 0);
346 ixp2000_reg_write(IXP2000_GPIO_LSLR, 0);
347 ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
348
349 /* clear PCI interrupt sources */
350 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
351
352 /*
353 * Certain bits in the IRQ status register of the
354 * IXP2000 are reserved. Instead of trying to map
355 * things non 1:1 from bit position to IRQ number,
356 * we mark the reserved IRQs as invalid. This makes
357 * our mask/unmask code much simpler.
358 */
359 for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
360 if((1 << irq) & IXP2000_VALID_IRQ_MASK) {
361 set_irq_chip(irq, &ixp2000_irq_chip);
362 set_irq_handler(irq, do_level_IRQ);
363 set_irq_flags(irq, IRQF_VALID);
364 } else set_irq_flags(irq, 0);
365 }
366
367 /*
368 * GPIO IRQs are invalid until someone sets the interrupt mode
369 * by calling gpio_line_set();
370 */
371 for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
372 set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
373 set_irq_handler(irq, do_level_IRQ);
374 set_irq_flags(irq, 0);
375 }
376 set_irq_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler);
377
378 /*
379 * Enable PCI irqs. The actual PCI[AB] decoding is done in
380 * entry-macro.S, so we don't need a chained handler for the
381 * PCI interrupt source.
382 */
383 ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI));
384 for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) {
385 set_irq_chip(irq, &ixp2000_pci_irq_chip);
386 set_irq_handler(irq, do_level_IRQ);
387 set_irq_flags(irq, IRQF_VALID);
388 }
389}
390
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
new file mode 100644
index 000000000000..04b38bcf9aac
--- /dev/null
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -0,0 +1,220 @@
1/*
2 * arch/arm/mach-ixp2000/enp2611.c
3 *
4 * Radisys ENP-2611 support.
5 *
6 * Created 2004 by Lennert Buytenhek from the ixdp2x01 code. The
7 * original version carries the following notices:
8 *
9 * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
10 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
11 *
12 * Copyright (C) 2002-2003 Intel Corp.
13 * Copyright (C) 2003-2004 MontaVista Software, Inc.
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version.
19 */
20
21#include <linux/config.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/mm.h>
25#include <linux/sched.h>
26#include <linux/interrupt.h>
27#include <linux/bitops.h>
28#include <linux/pci.h>
29#include <linux/ioport.h>
30#include <linux/slab.h>
31#include <linux/delay.h>
32#include <linux/serial.h>
33#include <linux/tty.h>
34#include <linux/serial_core.h>
35#include <linux/device.h>
36
37#include <asm/io.h>
38#include <asm/irq.h>
39#include <asm/pgtable.h>
40#include <asm/page.h>
41#include <asm/system.h>
42#include <asm/hardware.h>
43#include <asm/mach-types.h>
44
45#include <asm/mach/pci.h>
46#include <asm/mach/map.h>
47#include <asm/mach/irq.h>
48#include <asm/mach/time.h>
49#include <asm/mach/arch.h>
50#include <asm/mach/flash.h>
51
52/*************************************************************************
53 * ENP-2611 timer tick configuration
54 *************************************************************************/
55static void __init enp2611_timer_init(void)
56{
57 ixp2000_init_time(50 * 1000 * 1000);
58}
59
60static struct sys_timer enp2611_timer = {
61 .init = enp2611_timer_init,
62 .offset = ixp2000_gettimeoffset,
63};
64
65
66/*************************************************************************
67 * ENP-2611 PCI
68 *************************************************************************/
69static int enp2611_pci_setup(int nr, struct pci_sys_data *sys)
70{
71 sys->mem_offset = 0xe0000000;
72 ixp2000_pci_setup(nr, sys);
73 return 1;
74}
75
76static void __init enp2611_pci_preinit(void)
77{
78 ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
79 ixp2000_pci_preinit();
80}
81
82static inline int enp2611_pci_valid_device(struct pci_bus *bus,
83 unsigned int devfn)
84{
85 /* The 82559 ethernet controller appears at both PCI:1:0:0 and
86 * PCI:1:2:0, so let's pretend the second one isn't there.
87 */
88 if (bus->number == 0x01 && devfn == 0x10)
89 return 0;
90
91 return 1;
92}
93
94static int enp2611_pci_read_config(struct pci_bus *bus, unsigned int devfn,
95 int where, int size, u32 *value)
96{
97 if (enp2611_pci_valid_device(bus, devfn))
98 return ixp2000_pci_read_config(bus, devfn, where, size, value);
99
100 return PCIBIOS_DEVICE_NOT_FOUND;
101}
102
103static int enp2611_pci_write_config(struct pci_bus *bus, unsigned int devfn,
104 int where, int size, u32 value)
105{
106 if (enp2611_pci_valid_device(bus, devfn))
107 return ixp2000_pci_write_config(bus, devfn, where, size, value);
108
109 return PCIBIOS_DEVICE_NOT_FOUND;
110}
111
112static struct pci_ops enp2611_pci_ops = {
113 .read = enp2611_pci_read_config,
114 .write = enp2611_pci_write_config
115};
116
117static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
118 struct pci_sys_data *sys)
119{
120 return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
121}
122
123static int __init enp2611_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
124{
125 int irq;
126
127 if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 0) {
128 /* IXP2400. */
129 irq = IRQ_IXP2000_PCIA;
130 } else if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 1) {
131 /* 21555 non-transparent bridge. */
132 irq = IRQ_IXP2000_PCIB;
133 } else if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 4) {
134 /* PCI2050B transparent bridge. */
135 irq = -1;
136 } else if (dev->bus->number == 1 && PCI_SLOT(dev->devfn) == 0) {
137 /* 82559 ethernet. */
138 irq = IRQ_IXP2000_PCIA;
139 } else if (dev->bus->number == 1 && PCI_SLOT(dev->devfn) == 1) {
140 /* SPI-3 option board. */
141 irq = IRQ_IXP2000_PCIB;
142 } else {
143 printk(KERN_ERR "enp2611_pci_map_irq() called for unknown "
144 "device PCI:%d:%d:%d\n", dev->bus->number,
145 PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
146 irq = -1;
147 }
148
149 return irq;
150}
151
152struct hw_pci enp2611_pci __initdata = {
153 .nr_controllers = 1,
154 .setup = enp2611_pci_setup,
155 .preinit = enp2611_pci_preinit,
156 .scan = enp2611_pci_scan_bus,
157 .map_irq = enp2611_pci_map_irq,
158};
159
160int __init enp2611_pci_init(void)
161{
162 if (machine_is_enp2611())
163 pci_common_init(&enp2611_pci);
164
165 return 0;
166}
167
168subsys_initcall(enp2611_pci_init);
169
170
171/*************************************************************************
172 * ENP-2611 Machine Intialization
173 *************************************************************************/
174static struct flash_platform_data enp2611_flash_platform_data = {
175 .map_name = "cfi_probe",
176 .width = 1,
177};
178
179static struct ixp2000_flash_data enp2611_flash_data = {
180 .platform_data = &enp2611_flash_platform_data,
181 .nr_banks = 1
182};
183
184static struct resource enp2611_flash_resource = {
185 .start = 0xc4000000,
186 .end = 0xc4000000 + 0x00ffffff,
187 .flags = IORESOURCE_MEM,
188};
189
190static struct platform_device enp2611_flash = {
191 .name = "IXP2000-Flash",
192 .id = 0,
193 .dev = {
194 .platform_data = &enp2611_flash_data,
195 },
196 .num_resources = 1,
197 .resource = &enp2611_flash_resource,
198};
199
200static struct platform_device *enp2611_devices[] __initdata = {
201 &enp2611_flash
202};
203
204static void __init enp2611_init_machine(void)
205{
206 platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices));
207}
208
209
210MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
211 MAINTAINER("Lennert Buytenhek <buytenh@wantstofly.org>")
212 BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
213 BOOT_PARAMS(0x00000100)
214 MAPIO(ixp2000_map_io)
215 INITIRQ(ixp2000_init_irq)
216 .timer = &enp2611_timer,
217 INIT_MACHINE(enp2611_init_machine)
218MACHINE_END
219
220
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
new file mode 100644
index 000000000000..df3ff26c8cdd
--- /dev/null
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -0,0 +1,179 @@
1/*
2 * arch/arm/mach-ixp2000/ixdp2400.c
3 *
4 * IXDP2400 platform support
5 *
6 * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
7 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
8 *
9 * Copyright (C) 2002 Intel Corp.
10 * Copyright (C) 2003-2004 MontaVista Software, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17#include <linux/config.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/mm.h>
21#include <linux/sched.h>
22#include <linux/interrupt.h>
23#include <linux/device.h>
24#include <linux/bitops.h>
25#include <linux/pci.h>
26#include <linux/ioport.h>
27#include <linux/slab.h>
28#include <linux/delay.h>
29
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/pgtable.h>
33#include <asm/page.h>
34#include <asm/system.h>
35#include <asm/hardware.h>
36#include <asm/mach-types.h>
37
38#include <asm/mach/pci.h>
39#include <asm/mach/map.h>
40#include <asm/mach/irq.h>
41#include <asm/mach/time.h>
42#include <asm/mach/flash.h>
43#include <asm/mach/arch.h>
44
45/*************************************************************************
46 * IXDP2400 timer tick
47 *************************************************************************/
48static void __init ixdp2400_timer_init(void)
49{
50 int numerator, denominator;
51 int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8};
52
53 numerator = (*(IXDP2400_CPLD_SYS_CLK_M) & 0xFF) *2;
54 denominator = denom_array[(*(IXDP2400_CPLD_SYS_CLK_N) & 0x7)];
55
56 ixp2000_init_time(((3125000 * numerator) / (denominator)) / 2);
57}
58
59static struct sys_timer ixdp2400_timer = {
60 .init = ixdp2400_timer_init,
61 .offset = ixp2000_gettimeoffset,
62};
63
64/*************************************************************************
65 * IXDP2400 PCI
66 *************************************************************************/
67void __init ixdp2400_pci_preinit(void)
68{
69 ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
70 ixp2000_pci_preinit();
71}
72
73int ixdp2400_pci_setup(int nr, struct pci_sys_data *sys)
74{
75 sys->mem_offset = 0xe0000000;
76
77 ixp2000_pci_setup(nr, sys);
78
79 return 1;
80}
81
82static int __init ixdp2400_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
83{
84 if (ixdp2x00_master_npu()) {
85
86 /*
87 * Root bus devices. Slave NPU is only one with interrupt.
88 * Everything else, we just return -1 b/c nothing else
89 * on the root bus has interrupts.
90 */
91 if(!dev->bus->self) {
92 if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
93 return IRQ_IXDP2400_INGRESS_NPU;
94
95 return -1;
96 }
97
98 /*
99 * Bridge behind the PMC slot.
100 * NOTE: Only INTA from the PMC slot is routed. VERY BAD.
101 */
102 if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
103 dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
104 !dev->bus->parent->self->bus->parent)
105 return IRQ_IXDP2400_PMC;
106
107 /*
108 * Device behind the first bridge
109 */
110 if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
111 switch(dev->devfn) {
112 case IXDP2400_MASTER_ENET_DEVFN:
113 return IRQ_IXDP2400_ENET;
114
115 case IXDP2400_MEDIA_DEVFN:
116 return IRQ_IXDP2400_MEDIA_PCI;
117
118 case IXDP2400_SWITCH_FABRIC_DEVFN:
119 return IRQ_IXDP2400_SF_PCI;
120
121 case IXDP2X00_PMC_DEVFN:
122 return IRQ_IXDP2400_PMC;
123 }
124 }
125
126 return -1;
127 } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
128}
129
130
131static void ixdp2400_pci_postinit(void)
132{
133 struct pci_dev *dev;
134
135 if (ixdp2x00_master_npu()) {
136 dev = pci_find_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
137 pci_remove_bus_device(dev);
138 } else {
139 dev = pci_find_slot(1, IXDP2400_MASTER_ENET_DEVFN);
140 pci_remove_bus_device(dev);
141
142 ixdp2x00_slave_pci_postinit();
143 }
144}
145
146static struct hw_pci ixdp2400_pci __initdata = {
147 .nr_controllers = 1,
148 .setup = ixdp2400_pci_setup,
149 .preinit = ixdp2400_pci_preinit,
150 .postinit = ixdp2400_pci_postinit,
151 .scan = ixp2000_pci_scan_bus,
152 .map_irq = ixdp2400_pci_map_irq,
153};
154
155int __init ixdp2400_pci_init(void)
156{
157 if (machine_is_ixdp2400())
158 pci_common_init(&ixdp2400_pci);
159
160 return 0;
161}
162
163subsys_initcall(ixdp2400_pci_init);
164
165void ixdp2400_init_irq(void)
166{
167 ixdp2x00_init_irq(IXDP2400_CPLD_INT_STAT, IXDP2400_CPLD_INT_MASK, IXDP2400_NR_IRQS);
168}
169
170MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
171 MAINTAINER("MontaVista Software, Inc.")
172 BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
173 BOOT_PARAMS(0x00000100)
174 MAPIO(ixdp2x00_map_io)
175 INITIRQ(ixdp2400_init_irq)
176 .timer = &ixdp2400_timer,
177 INIT_MACHINE(ixdp2x00_init_machine)
178MACHINE_END
179
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
new file mode 100644
index 000000000000..c4683aaff84a
--- /dev/null
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -0,0 +1,180 @@
1/*
2 * arch/arm/mach-ixp2000/ixdp2800.c
3 *
4 * IXDP2800 platform support
5 *
6 * Original Author: Jeffrey Daly <jeffrey.daly@intel.com>
7 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
8 *
9 * Copyright (C) 2002 Intel Corp.
10 * Copyright (C) 2003-2004 MontaVista Software, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17#include <linux/config.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/mm.h>
21#include <linux/sched.h>
22#include <linux/interrupt.h>
23#include <linux/device.h>
24#include <linux/bitops.h>
25#include <linux/pci.h>
26#include <linux/ioport.h>
27#include <linux/slab.h>
28#include <linux/delay.h>
29
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/pgtable.h>
33#include <asm/page.h>
34#include <asm/system.h>
35#include <asm/hardware.h>
36#include <asm/mach-types.h>
37
38#include <asm/mach/pci.h>
39#include <asm/mach/map.h>
40#include <asm/mach/irq.h>
41#include <asm/mach/time.h>
42#include <asm/mach/flash.h>
43#include <asm/mach/arch.h>
44
45
46void ixdp2400_init_irq(void)
47{
48 ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2400_NR_IRQS);
49}
50
51/*************************************************************************
52 * IXDP2800 timer tick
53 *************************************************************************/
54
55static void __init ixdp2800_timer_init(void)
56{
57 ixp2000_init_time(50000000);
58}
59
60static struct sys_timer ixdp2800_timer = {
61 .init = ixdp2800_timer_init,
62 .offset = ixp2000_gettimeoffset,
63};
64
65/*************************************************************************
66 * IXDP2800 PCI
67 *************************************************************************/
68void __init ixdp2800_pci_preinit(void)
69{
70 printk("ixdp2x00_pci_preinit called\n");
71
72 *IXP2000_PCI_ADDR_EXT = 0x0000e000;
73
74 *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
75 *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
76
77 ixp2000_pci_preinit();
78}
79
80int ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
81{
82 sys->mem_offset = 0x00000000;
83
84 ixp2000_pci_setup(nr, sys);
85
86 return 1;
87}
88
89static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
90{
91 if (ixdp2x00_master_npu()) {
92
93 /*
94 * Root bus devices. Slave NPU is only one with interrupt.
95 * Everything else, we just return -1 which is invalid.
96 */
97 if(!dev->bus->self) {
98 if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
99 return IRQ_IXDP2800_INGRESS_NPU;
100
101 return -1;
102 }
103
104 /*
105 * Bridge behind the PMC slot.
106 */
107 if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
108 dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
109 !dev->bus->parent->self->bus->parent)
110 return IRQ_IXDP2800_PMC;
111
112 /*
113 * Device behind the first bridge
114 */
115 if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
116 switch(dev->devfn) {
117 case IXDP2X00_PMC_DEVFN:
118 return IRQ_IXDP2800_PMC;
119
120 case IXDP2800_MASTER_ENET_DEVFN:
121 return IRQ_IXDP2800_EGRESS_ENET;
122
123 case IXDP2800_SWITCH_FABRIC_DEVFN:
124 return IRQ_IXDP2800_FABRIC;
125 }
126 }
127
128 return -1;
129 } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
130}
131
132static void ixdp2800_pci_postinit(void)
133{
134 struct pci_dev *dev;
135
136 if (ixdp2x00_master_npu()) {
137 dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
138 pci_remove_bus_device(dev);
139 } else {
140 dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
141 pci_remove_bus_device(dev);
142
143 ixdp2x00_slave_pci_postinit();
144 }
145}
146
147struct hw_pci ixdp2800_pci __initdata = {
148 .nr_controllers = 1,
149 .setup = ixdp2800_pci_setup,
150 .preinit = ixdp2800_pci_preinit,
151 .postinit = ixdp2800_pci_postinit,
152 .scan = ixp2000_pci_scan_bus,
153 .map_irq = ixdp2800_pci_map_irq,
154};
155
156int __init ixdp2800_pci_init(void)
157{
158 if (machine_is_ixdp2800())
159 pci_common_init(&ixdp2800_pci);
160
161 return 0;
162}
163
164subsys_initcall(ixdp2800_pci_init);
165
166void ixdp2800_init_irq(void)
167{
168 ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2800_NR_IRQS);
169}
170
171MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
172 MAINTAINER("MontaVista Software, Inc.")
173 BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
174 BOOT_PARAMS(0x00000100)
175 MAPIO(ixdp2x00_map_io)
176 INITIRQ(ixdp2800_init_irq)
177 .timer = &ixdp2800_timer,
178 INIT_MACHINE(ixdp2x00_init_machine)
179MACHINE_END
180
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
new file mode 100644
index 000000000000..21c41fe15b99
--- /dev/null
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -0,0 +1,304 @@
1/*
2 * arch/arm/mach-ixp2000/ixdp2x00.c
3 *
4 * Code common to IXDP2400 and IXDP2800 platforms.
5 *
6 * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
7 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
8 *
9 * Copyright (C) 2002 Intel Corp.
10 * Copyright (C) 2003-2004 MontaVista Software, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17#include <linux/config.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/mm.h>
21#include <linux/sched.h>
22#include <linux/interrupt.h>
23#include <linux/device.h>
24#include <linux/bitops.h>
25#include <linux/pci.h>
26#include <linux/ioport.h>
27#include <linux/slab.h>
28#include <linux/delay.h>
29
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/pgtable.h>
33#include <asm/page.h>
34#include <asm/system.h>
35#include <asm/hardware.h>
36#include <asm/mach-types.h>
37
38#include <asm/mach/pci.h>
39#include <asm/mach/map.h>
40#include <asm/mach/irq.h>
41#include <asm/mach/time.h>
42#include <asm/mach/flash.h>
43#include <asm/mach/arch.h>
44
45/*************************************************************************
46 * IXDP2x00 IRQ Initialization
47 *************************************************************************/
48static volatile unsigned long *board_irq_mask;
49static volatile unsigned long *board_irq_stat;
50static unsigned long board_irq_count;
51
52#ifdef CONFIG_ARCH_IXDP2400
53/*
54 * Slowport configuration for accessing CPLD registers on IXDP2x00
55 */
56static struct slowport_cfg slowport_cpld_cfg = {
57 .CCR = SLOWPORT_CCR_DIV_2,
58 .WTC = 0x00000070,
59 .RTC = 0x00000070,
60 .PCR = SLOWPORT_MODE_FLASH,
61 .ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8
62};
63#endif
64
65static void ixdp2x00_irq_mask(unsigned int irq)
66{
67 unsigned long dummy;
68 static struct slowport_cfg old_cfg;
69
70 /*
71 * This is ugly in common code but really don't know
72 * of a better way to handle it. :(
73 */
74#ifdef CONFIG_ARCH_IXDP2400
75 if (machine_is_ixdp2400())
76 ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
77#endif
78
79 dummy = *board_irq_mask;
80 dummy |= IXP2000_BOARD_IRQ_MASK(irq);
81 ixp2000_reg_write(board_irq_mask, dummy);
82
83#ifdef CONFIG_ARCH_IXDP2400
84 if (machine_is_ixdp2400())
85 ixp2000_release_slowport(&old_cfg);
86#endif
87}
88
89static void ixdp2x00_irq_unmask(unsigned int irq)
90{
91 unsigned long dummy;
92 static struct slowport_cfg old_cfg;
93
94#ifdef CONFIG_ARCH_IXDP2400
95 if (machine_is_ixdp2400())
96 ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
97#endif
98
99 dummy = *board_irq_mask;
100 dummy &= ~IXP2000_BOARD_IRQ_MASK(irq);
101 ixp2000_reg_write(board_irq_mask, dummy);
102
103 if (machine_is_ixdp2400())
104 ixp2000_release_slowport(&old_cfg);
105}
106
107static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
108{
109 volatile u32 ex_interrupt = 0;
110 static struct slowport_cfg old_cfg;
111 int i;
112
113 desc->chip->mask(irq);
114
115#ifdef CONFIG_ARCH_IXDP2400
116 if (machine_is_ixdp2400())
117 ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
118#endif
119 ex_interrupt = *board_irq_stat & 0xff;
120 if (machine_is_ixdp2400())
121 ixp2000_release_slowport(&old_cfg);
122
123 if(!ex_interrupt) {
124 printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n");
125 return;
126 }
127
128 for(i = 0; i < board_irq_count; i++) {
129 if(ex_interrupt & (1 << i)) {
130 struct irqdesc *cpld_desc;
131 int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
132 cpld_desc = irq_desc + cpld_irq;
133 cpld_desc->handle(cpld_irq, cpld_desc, regs);
134 }
135 }
136
137 desc->chip->unmask(irq);
138}
139
140static struct irqchip ixdp2x00_cpld_irq_chip = {
141 .ack = ixdp2x00_irq_mask,
142 .mask = ixdp2x00_irq_mask,
143 .unmask = ixdp2x00_irq_unmask
144};
145
146void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs)
147{
148 unsigned int irq;
149
150 ixp2000_init_irq();
151
152 if (!ixdp2x00_master_npu())
153 return;
154
155 board_irq_stat = stat_reg;
156 board_irq_mask = mask_reg;
157 board_irq_count = nr_irqs;
158
159 *board_irq_mask = 0xffffffff;
160
161 for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) {
162 set_irq_chip(irq, &ixdp2x00_cpld_irq_chip);
163 set_irq_handler(irq, do_level_IRQ);
164 set_irq_flags(irq, IRQF_VALID);
165 }
166
167 /* Hook into PCI interrupt */
168 set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x00_irq_handler);
169}
170
171/*************************************************************************
172 * IXDP2x00 memory map
173 *************************************************************************/
174static struct map_desc ixdp2x00_io_desc __initdata = {
175 .virtual = IXDP2X00_VIRT_CPLD_BASE,
176 .physical = IXDP2X00_PHYS_CPLD_BASE,
177 .length = IXDP2X00_CPLD_SIZE,
178 .type = MT_DEVICE
179};
180
181void __init ixdp2x00_map_io(void)
182{
183 ixp2000_map_io();
184
185 iotable_init(&ixdp2x00_io_desc, 1);
186}
187
188/*************************************************************************
189 * IXDP2x00-common PCI init
190 *
191 * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board
192 * contains two NPUs (ingress and egress) connected over PCI, both running
193 * instances of the kernel. So far so good. Peers on the PCI bus running
194 * Linux is a common design in telecom systems. The problem is that instead
195 * of all the devices being controlled by a single host, different
196 * devices are controlles by different NPUs on the same bus, leading to
197 * multiple hosts on the bus. The exact bus layout looks like:
198 *
199 * Bus 0
200 * Master NPU <-------------------+-------------------> Slave NPU
201 * |
202 * |
203 * P2P
204 * |
205 *
206 * Bus 1 |
207 * <--+------+---------+---------+------+-->
208 * | | | | |
209 * | | | | |
210 * ... Dev PMC Media Eth0 Eth1 ...
211 *
212 * The master controlls all but Eth1, which is controlled by the
213 * slave. What this means is that the both the master and the slave
214 * have to scan the bus, but only one of them can enumerate the bus.
215 * In addition, after the bus is scanned, each kernel must remove
216 * the device(s) it does not control from the PCI dev list otherwise
217 * a driver on each NPU will try to manage it and we will have horrible
218 * conflicts. Oh..and the slave NPU needs to see the master NPU
219 * for Intel's drivers to work properly. Closed source drivers...
220 *
221 * The way we deal with this is fairly simple but ugly:
222 *
223 * 1) Let master scan and enumerate the bus completely.
224 * 2) Master deletes Eth1 from device list.
225 * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave)
226 * from device list.
227 * 4) Find HW designers and LART them.
228 *
229 * The boards also do not do normal PCI IRQ routing, or any sort of
230 * sensical swizzling, so we just need to check where on the bus a
231 * device sits and figure out to which CPLD pin the interrupt is routed.
232 * See ixdp2[48]00.c files.
233 *
234 *************************************************************************/
235void ixdp2x00_slave_pci_postinit(void)
236{
237 struct pci_dev *dev;
238
239 /*
240 * Remove PMC device is there is one
241 */
242 if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN)))
243 pci_remove_bus_device(dev);
244
245 dev = pci_find_slot(0, IXDP2X00_21555_DEVFN);
246 pci_remove_bus_device(dev);
247}
248
249/**************************************************************************
250 * IXDP2x00 Machine Setup
251 *************************************************************************/
252static struct flash_platform_data ixdp2x00_platform_data = {
253 .map_name = "cfi_probe",
254 .width = 1,
255};
256
257static struct ixp2000_flash_data ixdp2x00_flash_data = {
258 .platform_data = &ixdp2x00_platform_data,
259 .nr_banks = 1
260};
261
262static struct resource ixdp2x00_flash_resource = {
263 .start = 0xc4000000,
264 .end = 0xc4000000 + 0x00ffffff,
265 .flags = IORESOURCE_MEM,
266};
267
268static struct platform_device ixdp2x00_flash = {
269 .name = "IXP2000-Flash",
270 .id = 0,
271 .dev = {
272 .platform_data = &ixdp2x00_flash_data,
273 },
274 .num_resources = 1,
275 .resource = &ixdp2x00_flash_resource,
276};
277
278static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = {
279 .sda_pin = IXDP2X00_GPIO_SDA,
280 .scl_pin = IXDP2X00_GPIO_SCL,
281};
282
283static struct platform_device ixdp2x00_i2c_controller = {
284 .name = "IXP2000-I2C",
285 .id = 0,
286 .dev = {
287 .platform_data = &ixdp2x00_i2c_gpio_pins,
288 },
289 .num_resources = 0
290};
291
292static struct platform_device *ixdp2x00_devices[] __initdata = {
293 &ixdp2x00_flash,
294 &ixdp2x00_i2c_controller
295};
296
297void __init ixdp2x00_init_machine(void)
298{
299 gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1);
300 gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
301
302 platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
303}
304
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
new file mode 100644
index 000000000000..e94dace3d412
--- /dev/null
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -0,0 +1,400 @@
1/*
2 * arch/arm/mach-ixp2000/ixdp2x01.c
3 *
4 * Code common to Intel IXDP2401 and IXDP2801 platforms
5 *
6 * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
7 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
8 *
9 * Copyright (C) 2002-2003 Intel Corp.
10 * Copyright (C) 2003-2004 MontaVista Software, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17
18#include <linux/config.h>
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/mm.h>
22#include <linux/sched.h>
23#include <linux/interrupt.h>
24#include <linux/bitops.h>
25#include <linux/pci.h>
26#include <linux/ioport.h>
27#include <linux/slab.h>
28#include <linux/delay.h>
29#include <linux/serial.h>
30#include <linux/tty.h>
31#include <linux/serial_core.h>
32#include <linux/device.h>
33
34#include <asm/io.h>
35#include <asm/irq.h>
36#include <asm/pgtable.h>
37#include <asm/page.h>
38#include <asm/system.h>
39#include <asm/hardware.h>
40#include <asm/mach-types.h>
41
42#include <asm/mach/pci.h>
43#include <asm/mach/map.h>
44#include <asm/mach/irq.h>
45#include <asm/mach/time.h>
46#include <asm/mach/arch.h>
47#include <asm/mach/flash.h>
48
49/*************************************************************************
50 * IXDP2x01 IRQ Handling
51 *************************************************************************/
52static void ixdp2x01_irq_mask(unsigned int irq)
53{
54 ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG,
55 IXP2000_BOARD_IRQ_MASK(irq));
56}
57
58static void ixdp2x01_irq_unmask(unsigned int irq)
59{
60 ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG,
61 IXP2000_BOARD_IRQ_MASK(irq));
62}
63
64static u32 valid_irq_mask;
65
66static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
67{
68 u32 ex_interrupt;
69 int i;
70
71 desc->chip->mask(irq);
72
73 ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask;
74
75 if (!ex_interrupt) {
76 printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n");
77 return;
78 }
79
80 for (i = 0; i < IXP2000_BOARD_IRQS; i++) {
81 if (ex_interrupt & (1 << i)) {
82 struct irqdesc *cpld_desc;
83 int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
84 cpld_desc = irq_desc + cpld_irq;
85 cpld_desc->handle(cpld_irq, cpld_desc, regs);
86 }
87 }
88
89 desc->chip->unmask(irq);
90}
91
92static struct irqchip ixdp2x01_irq_chip = {
93 .mask = ixdp2x01_irq_mask,
94 .ack = ixdp2x01_irq_mask,
95 .unmask = ixdp2x01_irq_unmask
96};
97
98/*
99 * We only do anything if we are the master NPU on the board.
100 * The slave NPU only has the ethernet chip going directly to
101 * the PCIB interrupt input.
102 */
103void __init ixdp2x01_init_irq(void)
104{
105 int irq = 0;
106
107 /* initialize chip specific interrupts */
108 ixp2000_init_irq();
109
110 if (machine_is_ixdp2401())
111 valid_irq_mask = IXDP2401_VALID_IRQ_MASK;
112 else
113 valid_irq_mask = IXDP2801_VALID_IRQ_MASK;
114
115 /* Mask all interrupts from CPLD, disable simulation */
116 ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff);
117 ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0);
118
119 for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
120 if (irq & valid_irq_mask) {
121 set_irq_chip(irq, &ixdp2x01_irq_chip);
122 set_irq_handler(irq, do_level_IRQ);
123 set_irq_flags(irq, IRQF_VALID);
124 } else {
125 set_irq_flags(irq, 0);
126 }
127 }
128
129 /* Hook into PCI interrupts */
130 set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler);
131}
132
133
134/*************************************************************************
135 * IXDP2x01 memory map and serial ports
136 *************************************************************************/
137static struct map_desc ixdp2x01_io_desc __initdata = {
138 .virtual = IXDP2X01_VIRT_CPLD_BASE,
139 .physical = IXDP2X01_PHYS_CPLD_BASE,
140 .length = IXDP2X01_CPLD_REGION_SIZE,
141 .type = MT_DEVICE
142};
143
144static struct uart_port ixdp2x01_serial_ports[2] = {
145 {
146 .membase = (char *)(IXDP2X01_UART1_VIRT_BASE),
147 .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE,
148 .irq = IRQ_IXDP2X01_UART1,
149 .flags = UPF_SKIP_TEST,
150 .iotype = UPIO_MEM32,
151 .regshift = 2,
152 .uartclk = IXDP2X01_UART_CLK,
153 .line = 1,
154 .type = PORT_16550A,
155 .fifosize = 16
156 }, {
157 .membase = (char *)(IXDP2X01_UART2_VIRT_BASE),
158 .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE,
159 .irq = IRQ_IXDP2X01_UART2,
160 .flags = UPF_SKIP_TEST,
161 .iotype = UPIO_MEM32,
162 .regshift = 2,
163 .uartclk = IXDP2X01_UART_CLK,
164 .line = 2,
165 .type = PORT_16550A,
166 .fifosize = 16
167 },
168};
169
170static void __init ixdp2x01_map_io(void)
171{
172 ixp2000_map_io();
173
174 iotable_init(&ixdp2x01_io_desc, 1);
175
176 early_serial_setup(&ixdp2x01_serial_ports[0]);
177 early_serial_setup(&ixdp2x01_serial_ports[1]);
178}
179
180
181/*************************************************************************
182 * IXDP2x01 timer tick configuration
183 *************************************************************************/
184static unsigned int ixdp2x01_clock;
185
186static int __init ixdp2x01_clock_setup(char *str)
187{
188 ixdp2x01_clock = simple_strtoul(str, NULL, 10);
189
190 return 1;
191}
192
193__setup("ixdp2x01_clock=", ixdp2x01_clock_setup);
194
195static void __init ixdp2x01_timer_init(void)
196{
197 if (!ixdp2x01_clock)
198 ixdp2x01_clock = 50000000;
199
200 ixp2000_init_time(ixdp2x01_clock);
201}
202
203static struct sys_timer ixdp2x01_timer = {
204 .init = ixdp2x01_timer_init,
205 .offset = ixp2000_gettimeoffset,
206};
207
208/*************************************************************************
209 * IXDP2x01 PCI
210 *************************************************************************/
211void __init ixdp2x01_pci_preinit(void)
212{
213 ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000);
214 ixp2000_pci_preinit();
215}
216
217#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
218
219static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
220{
221 u8 bus = dev->bus->number;
222 u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
223 struct pci_bus *tmp_bus = dev->bus;
224
225 /* Primary bus, no interrupts here */
226 if (bus == 0) {
227 return -1;
228 }
229
230 /* Lookup first leaf in bus tree */
231 while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) {
232 tmp_bus = tmp_bus->parent;
233 }
234
235 /* Select between known bridges */
236 switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
237 /* Device is located after first MB bridge */
238 case 0x0008:
239 if (tmp_bus == dev->bus) {
240 /* Device is located directy after first MB bridge */
241 switch (devpin) {
242 case DEVPIN(1, 1): /* Onboard 82546 ch 0 */
243 if (machine_is_ixdp2401())
244 return IRQ_IXDP2401_INTA_82546;
245 return -1;
246 case DEVPIN(1, 2): /* Onboard 82546 ch 1 */
247 if (machine_is_ixdp2401())
248 return IRQ_IXDP2401_INTB_82546;
249 return -1;
250 case DEVPIN(0, 1): /* PMC INTA# */
251 return IRQ_IXDP2X01_SPCI_PMC_INTA;
252 case DEVPIN(0, 2): /* PMC INTB# */
253 return IRQ_IXDP2X01_SPCI_PMC_INTB;
254 case DEVPIN(0, 3): /* PMC INTC# */
255 return IRQ_IXDP2X01_SPCI_PMC_INTC;
256 case DEVPIN(0, 4): /* PMC INTD# */
257 return IRQ_IXDP2X01_SPCI_PMC_INTD;
258 }
259 }
260 break;
261 case 0x0010:
262 if (tmp_bus == dev->bus) {
263 /* Device is located directy after second MB bridge */
264 /* Secondary bus of second bridge */
265 switch (devpin) {
266 case DEVPIN(0, 1): /* DB#0 */
267 return IRQ_IXDP2X01_SPCI_DB_0;
268 case DEVPIN(1, 1): /* DB#1 */
269 return IRQ_IXDP2X01_SPCI_DB_1;
270 }
271 } else {
272 /* Device is located indirectly after second MB bridge */
273 /* Not supported now */
274 }
275 break;
276 }
277
278 return -1;
279}
280
281
282static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys)
283{
284 sys->mem_offset = 0xe0000000;
285
286 if (machine_is_ixdp2801())
287 sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16);
288
289 return ixp2000_pci_setup(nr, sys);
290}
291
292struct hw_pci ixdp2x01_pci __initdata = {
293 .nr_controllers = 1,
294 .setup = ixdp2x01_pci_setup,
295 .preinit = ixdp2x01_pci_preinit,
296 .scan = ixp2000_pci_scan_bus,
297 .map_irq = ixdp2x01_pci_map_irq,
298};
299
300int __init ixdp2x01_pci_init(void)
301{
302
303 pci_common_init(&ixdp2x01_pci);
304 return 0;
305}
306
307subsys_initcall(ixdp2x01_pci_init);
308
309/*************************************************************************
310 * IXDP2x01 Machine Intialization
311 *************************************************************************/
312static struct flash_platform_data ixdp2x01_flash_platform_data = {
313 .map_name = "cfi_probe",
314 .width = 1,
315};
316
317static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
318{
319 ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
320 ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN));
321 return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
322}
323
324static struct ixp2000_flash_data ixdp2x01_flash_data = {
325 .platform_data = &ixdp2x01_flash_platform_data,
326 .bank_setup = ixdp2x01_flash_bank_setup
327};
328
329static struct resource ixdp2x01_flash_resource = {
330 .start = 0xc4000000,
331 .end = 0xc4000000 + 0x01ffffff,
332 .flags = IORESOURCE_MEM,
333};
334
335static struct platform_device ixdp2x01_flash = {
336 .name = "IXP2000-Flash",
337 .id = 0,
338 .dev = {
339 .platform_data = &ixdp2x01_flash_data,
340 },
341 .num_resources = 1,
342 .resource = &ixdp2x01_flash_resource,
343};
344
345static struct ixp2000_i2c_pins ixdp2x01_i2c_gpio_pins = {
346 .sda_pin = IXDP2X01_GPIO_SDA,
347 .scl_pin = IXDP2X01_GPIO_SCL,
348};
349
350static struct platform_device ixdp2x01_i2c_controller = {
351 .name = "IXP2000-I2C",
352 .id = 0,
353 .dev = {
354 .platform_data = &ixdp2x01_i2c_gpio_pins,
355 },
356 .num_resources = 0
357};
358
359static struct platform_device *ixdp2x01_devices[] __initdata = {
360 &ixdp2x01_flash,
361 &ixdp2x01_i2c_controller
362};
363
364static void __init ixdp2x01_init_machine(void)
365{
366 ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
367 (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN));
368
369 ixdp2x01_flash_data.nr_banks =
370 ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
371
372 platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
373}
374
375
376#ifdef CONFIG_ARCH_IXDP2401
377MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
378 MAINTAINER("MontaVista Software, Inc.")
379 BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
380 BOOT_PARAMS(0x00000100)
381 MAPIO(ixdp2x01_map_io)
382 INITIRQ(ixdp2x01_init_irq)
383 .timer = &ixdp2x01_timer,
384 INIT_MACHINE(ixdp2x01_init_machine)
385MACHINE_END
386#endif
387
388#ifdef CONFIG_ARCH_IXDP2801
389MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
390 MAINTAINER("MontaVista Software, Inc.")
391 BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
392 BOOT_PARAMS(0x00000100)
393 MAPIO(ixdp2x01_map_io)
394 INITIRQ(ixdp2x01_init_irq)
395 .timer = &ixdp2x01_timer,
396 INIT_MACHINE(ixdp2x01_init_machine)
397MACHINE_END
398#endif
399
400
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
new file mode 100644
index 000000000000..831f8ffb6b61
--- /dev/null
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -0,0 +1,235 @@
1/*
2 * arch/arm/mach-ixp2000/pci.c
3 *
4 * PCI routines for IXDP2400/IXDP2800 boards
5 *
6 * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
7 * Maintained by: Deepak Saxena <dsaxena@plexity.net>
8 *
9 * Copyright 2002 Intel Corp.
10 * Copyright (C) 2003-2004 MontaVista Software, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/pci.h>
21#include <linux/interrupt.h>
22#include <linux/mm.h>
23#include <linux/init.h>
24#include <linux/ioport.h>
25#include <linux/slab.h>
26#include <linux/delay.h>
27
28#include <asm/io.h>
29#include <asm/irq.h>
30#include <asm/system.h>
31#include <asm/mach-types.h>
32#include <asm/hardware.h>
33
34#include <asm/mach/pci.h>
35
36static int pci_master_aborts = 0;
37
38static int clear_master_aborts(void);
39
40static u32 *
41ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
42{
43 u32 *paddress;
44
45 if (PCI_SLOT(devfn) > 7)
46 return 0;
47
48 /* Must be dword aligned */
49 where &= ~3;
50
51 /*
52 * For top bus, generate type 0, else type 1
53 */
54 if (!bus_nr) {
55 /* only bits[23:16] are used for IDSEL */
56 paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE
57 | (1 << (PCI_SLOT(devfn) + 16))
58 | (PCI_FUNC(devfn) << 8) | where);
59 } else {
60 paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE
61 | (bus_nr << 16)
62 | (PCI_SLOT(devfn) << 11)
63 | (PCI_FUNC(devfn) << 8) | where);
64 }
65
66 return paddress;
67}
68
69/*
70 * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
71 * 0 and 3 are not valid indexes...
72 */
73static u32 bytemask[] = {
74 /*0*/ 0,
75 /*1*/ 0xff,
76 /*2*/ 0xffff,
77 /*3*/ 0,
78 /*4*/ 0xffffffff,
79};
80
81
82int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where,
83 int size, u32 *value)
84{
85 u32 n;
86 u32 *addr;
87
88 n = where % 4;
89
90 addr = ixp2000_pci_config_addr(bus->number, devfn, where);
91 if (!addr)
92 return PCIBIOS_DEVICE_NOT_FOUND;
93
94 pci_master_aborts = 0;
95 *value = (*addr >> (8*n)) & bytemask[size];
96 if (pci_master_aborts) {
97 pci_master_aborts = 0;
98 *value = 0xffffffff;
99 return PCIBIOS_DEVICE_NOT_FOUND;
100 }
101
102 return PCIBIOS_SUCCESSFUL;
103}
104
105/*
106 * We don't do error checks by callling clear_master_aborts() b/c the
107 * assumption is that the caller did a read first to make sure a device
108 * exists.
109 */
110int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where,
111 int size, u32 value)
112{
113 u32 mask;
114 u32 *addr;
115 u32 temp;
116
117 mask = ~(bytemask[size] << ((where % 0x4) * 8));
118 addr = ixp2000_pci_config_addr(bus->number, devfn, where);
119 if (!addr)
120 return PCIBIOS_DEVICE_NOT_FOUND;
121 temp = (u32) (value) << ((where % 0x4) * 8);
122 *addr = (*addr & mask) | temp;
123
124 clear_master_aborts();
125
126 return PCIBIOS_SUCCESSFUL;
127}
128
129
130static struct pci_ops ixp2000_pci_ops = {
131 .read = ixp2000_pci_read_config,
132 .write = ixp2000_pci_write_config
133};
134
135struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
136{
137 return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
138}
139
140
141int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
142{
143
144 volatile u32 temp;
145 unsigned long flags;
146
147 pci_master_aborts = 1;
148
149 local_irq_save(flags);
150 temp = *(IXP2000_PCI_CONTROL);
151 if (temp & ((1 << 8) | (1 << 5))) {
152 ixp2000_reg_write(IXP2000_PCI_CONTROL, temp);
153 }
154
155 temp = *(IXP2000_PCI_CMDSTAT);
156 if (temp & (1 << 29)) {
157 while (temp & (1 << 29)) {
158 ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
159 temp = *(IXP2000_PCI_CMDSTAT);
160 }
161 }
162 local_irq_restore(flags);
163
164 /*
165 * If it was an imprecise abort, then we need to correct the
166 * return address to be _after_ the instruction.
167 */
168 if (fsr & (1 << 10))
169 regs->ARM_pc += 4;
170
171 return 0;
172}
173
174int
175clear_master_aborts(void)
176{
177 volatile u32 temp;
178 unsigned long flags;
179
180 local_irq_save(flags);
181 temp = *(IXP2000_PCI_CONTROL);
182 if (temp & ((1 << 8) | (1 << 5))) {
183 ixp2000_reg_write(IXP2000_PCI_CONTROL, temp);
184 }
185
186 temp = *(IXP2000_PCI_CMDSTAT);
187 if (temp & (1 << 29)) {
188 while (temp & (1 << 29)) {
189 ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
190 temp = *(IXP2000_PCI_CMDSTAT);
191 }
192 }
193 local_irq_restore(flags);
194
195 return 0;
196}
197
198void __init
199ixp2000_pci_preinit(void)
200{
201 hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
202 "PCI config cycle to non-existent device");
203}
204
205
206/*
207 * IXP2000 systems often have large resource requirements, so we just
208 * use our own resource space.
209 */
210static struct resource ixp2000_pci_mem_space = {
211 .start = 0x00000000,
212 .end = 0xffffffff,
213 .flags = IORESOURCE_MEM,
214 .name = "PCI Mem Space"
215};
216
217static struct resource ixp2000_pci_io_space = {
218 .start = 0x00000000,
219 .end = 0xffffffff,
220 .flags = IORESOURCE_IO,
221 .name = "PCI I/O Space"
222};
223
224int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
225{
226 if (nr >= 1)
227 return 0;
228
229 sys->resource[0] = &ixp2000_pci_io_space;
230 sys->resource[1] = &ixp2000_pci_mem_space;
231 sys->resource[2] = NULL;
232
233 return 1;
234}
235