aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ixp2000
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ixp2000')
-rw-r--r--arch/arm/mach-ixp2000/Kconfig8
-rw-r--r--arch/arm/mach-ixp2000/core.c128
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c17
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c6
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c3
-rw-r--r--arch/arm/mach-ixp2000/pci.c13
6 files changed, 140 insertions, 35 deletions
diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig
index 9361e05f6fa3..ecb58d83478e 100644
--- a/arch/arm/mach-ixp2000/Kconfig
+++ b/arch/arm/mach-ixp2000/Kconfig
@@ -54,6 +54,14 @@ config ARCH_IXDP2X01
54 depends on ARCH_IXDP2401 || ARCH_IXDP2801 54 depends on ARCH_IXDP2401 || ARCH_IXDP2801
55 default y 55 default y
56 56
57config IXP2000_SUPPORT_BROKEN_PCI_IO
58 bool "Support broken PCI I/O on older IXP2000s"
59 default y
60 help
61 Say 'N' here if you only intend to run your kernel on an
62 IXP2000 B0 or later model and do not need the PCI I/O
63 byteswap workaround. Say 'Y' otherwise.
64
57endmenu 65endmenu
58 66
59endif 67endif
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 4f3c3d5c781c..4b9d841e04c1 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -40,6 +40,8 @@
40#include <asm/mach/time.h> 40#include <asm/mach/time.h>
41#include <asm/mach/irq.h> 41#include <asm/mach/irq.h>
42 42
43#include <asm/arch/gpio.h>
44
43static DEFINE_SPINLOCK(ixp2000_slowport_lock); 45static DEFINE_SPINLOCK(ixp2000_slowport_lock);
44static unsigned long ixp2000_slowport_irq_flags; 46static unsigned long ixp2000_slowport_irq_flags;
45 47
@@ -101,6 +103,11 @@ static struct map_desc ixp2000_io_desc[] __initdata = {
101 .length = IXP2000_PCI_CSR_SIZE, 103 .length = IXP2000_PCI_CSR_SIZE,
102 .type = MT_DEVICE 104 .type = MT_DEVICE
103 }, { 105 }, {
106 .virtual = IXP2000_MSF_VIRT_BASE,
107 .physical = IXP2000_MSF_PHYS_BASE,
108 .length = IXP2000_MSF_SIZE,
109 .type = MT_DEVICE
110 }, {
104 .virtual = IXP2000_PCI_IO_VIRT_BASE, 111 .virtual = IXP2000_PCI_IO_VIRT_BASE,
105 .physical = IXP2000_PCI_IO_PHYS_BASE, 112 .physical = IXP2000_PCI_IO_PHYS_BASE,
106 .length = IXP2000_PCI_IO_SIZE, 113 .length = IXP2000_PCI_IO_SIZE,
@@ -162,12 +169,13 @@ void __init ixp2000_map_io(void)
162static unsigned ticks_per_jiffy; 169static unsigned ticks_per_jiffy;
163static unsigned ticks_per_usec; 170static unsigned ticks_per_usec;
164static unsigned next_jiffy_time; 171static unsigned next_jiffy_time;
172static volatile unsigned long *missing_jiffy_timer_csr;
165 173
166unsigned long ixp2000_gettimeoffset (void) 174unsigned long ixp2000_gettimeoffset (void)
167{ 175{
168 unsigned long offset; 176 unsigned long offset;
169 177
170 offset = next_jiffy_time - *IXP2000_T4_CSR; 178 offset = next_jiffy_time - *missing_jiffy_timer_csr;
171 179
172 return offset / ticks_per_usec; 180 return offset / ticks_per_usec;
173} 181}
@@ -178,8 +186,8 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
178 186
179 /* clear timer 1 */ 187 /* clear timer 1 */
180 ixp2000_reg_write(IXP2000_T1_CLR, 1); 188 ixp2000_reg_write(IXP2000_T1_CLR, 1);
181 189
182 while ((next_jiffy_time - *IXP2000_T4_CSR) > ticks_per_jiffy) { 190 while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
183 timer_tick(regs); 191 timer_tick(regs);
184 next_jiffy_time -= ticks_per_jiffy; 192 next_jiffy_time -= ticks_per_jiffy;
185 } 193 }
@@ -191,26 +199,43 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
191 199
192static struct irqaction ixp2000_timer_irq = { 200static struct irqaction ixp2000_timer_irq = {
193 .name = "IXP2000 Timer Tick", 201 .name = "IXP2000 Timer Tick",
194 .flags = SA_INTERRUPT, 202 .flags = SA_INTERRUPT | SA_TIMER,
195 .handler = ixp2000_timer_interrupt 203 .handler = ixp2000_timer_interrupt,
196}; 204};
197 205
198void __init ixp2000_init_time(unsigned long tick_rate) 206void __init ixp2000_init_time(unsigned long tick_rate)
199{ 207{
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; 208 ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
204 ticks_per_usec = tick_rate / 1000000; 209 ticks_per_usec = tick_rate / 1000000;
205 210
211 /*
212 * We use timer 1 as our timer interrupt.
213 */
214 ixp2000_reg_write(IXP2000_T1_CLR, 0);
206 ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1); 215 ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
207 ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); 216 ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
208 217
209 /* 218 /*
210 * We use T4 as a monotonic counter to track missed jiffies 219 * We use a second timer as a monotonic counter for tracking
220 * missed jiffies. The IXP2000 has four timers, but if we're
221 * on an A-step IXP2800, timer 2 and 3 don't work, so on those
222 * chips we use timer 4. Timer 4 is the only timer that can
223 * be used for the watchdog, so we use timer 2 if we're on a
224 * non-buggy chip.
211 */ 225 */
212 ixp2000_reg_write(IXP2000_T4_CLD, -1); 226 if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
213 ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); 227 printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n");
228
229 ixp2000_reg_write(IXP2000_T4_CLR, 0);
230 ixp2000_reg_write(IXP2000_T4_CLD, -1);
231 ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7));
232 missing_jiffy_timer_csr = IXP2000_T4_CSR;
233 } else {
234 ixp2000_reg_write(IXP2000_T2_CLR, 0);
235 ixp2000_reg_write(IXP2000_T2_CLD, -1);
236 ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7));
237 missing_jiffy_timer_csr = IXP2000_T2_CSR;
238 }
214 next_jiffy_time = 0xffffffff; 239 next_jiffy_time = 0xffffffff;
215 240
216 /* register for interrupt */ 241 /* register for interrupt */
@@ -220,35 +245,40 @@ void __init ixp2000_init_time(unsigned long tick_rate)
220/************************************************************************* 245/*************************************************************************
221 * GPIO helpers 246 * GPIO helpers
222 *************************************************************************/ 247 *************************************************************************/
223static unsigned long GPIO_IRQ_rising_edge;
224static unsigned long GPIO_IRQ_falling_edge; 248static unsigned long GPIO_IRQ_falling_edge;
249static unsigned long GPIO_IRQ_rising_edge;
225static unsigned long GPIO_IRQ_level_low; 250static unsigned long GPIO_IRQ_level_low;
226static unsigned long GPIO_IRQ_level_high; 251static unsigned long GPIO_IRQ_level_high;
227 252
228void gpio_line_config(int line, int style) 253static void update_gpio_int_csrs(void)
254{
255 ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
256 ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
257 ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
258 ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
259}
260
261void gpio_line_config(int line, int direction)
229{ 262{
230 unsigned long flags; 263 unsigned long flags;
231 264
232 local_irq_save(flags); 265 local_irq_save(flags);
266 if (direction == GPIO_OUT) {
267 irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0;
233 268
234 if(style == GPIO_OUT) {
235 /* if it's an output, it ain't an interrupt anymore */ 269 /* 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); 270 GPIO_IRQ_falling_edge &= ~(1 << line);
238 GPIO_IRQ_rising_edge &= ~(1 << line); 271 GPIO_IRQ_rising_edge &= ~(1 << line);
239 GPIO_IRQ_level_low &= ~(1 << line); 272 GPIO_IRQ_level_low &= ~(1 << line);
240 GPIO_IRQ_level_high &= ~(1 << line); 273 GPIO_IRQ_level_high &= ~(1 << line);
241 ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); 274 update_gpio_int_csrs();
242 ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); 275
243 ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); 276 ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line);
244 ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); 277 } else if (direction == GPIO_IN) {
245 irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0; 278 ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
246 } else if(style == GPIO_IN) {
247 ixp2000_reg_write(IXP2000_GPIO_PDCR, (1 << line));
248 } 279 }
249
250 local_irq_restore(flags); 280 local_irq_restore(flags);
251} 281}
252 282
253 283
254/************************************************************************* 284/*************************************************************************
@@ -267,9 +297,50 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str
267 } 297 }
268} 298}
269 299
300static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type)
301{
302 int line = irq - IRQ_IXP2000_GPIO0;
303
304 /*
305 * First, configure this GPIO line as an input.
306 */
307 ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
308
309 /*
310 * Then, set the proper trigger type.
311 */
312 if (type & IRQT_FALLING)
313 GPIO_IRQ_falling_edge |= 1 << line;
314 else
315 GPIO_IRQ_falling_edge &= ~(1 << line);
316 if (type & IRQT_RISING)
317 GPIO_IRQ_rising_edge |= 1 << line;
318 else
319 GPIO_IRQ_rising_edge &= ~(1 << line);
320 if (type & IRQT_LOW)
321 GPIO_IRQ_level_low |= 1 << line;
322 else
323 GPIO_IRQ_level_low &= ~(1 << line);
324 if (type & IRQT_HIGH)
325 GPIO_IRQ_level_high |= 1 << line;
326 else
327 GPIO_IRQ_level_high &= ~(1 << line);
328 update_gpio_int_csrs();
329
330 /*
331 * Finally, mark the corresponding IRQ as valid.
332 */
333 irq_desc[irq].valid = 1;
334
335 return 0;
336}
337
270static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) 338static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
271{ 339{
272 ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); 340 ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
341
342 ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
343 ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
273 ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); 344 ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
274} 345}
275 346
@@ -284,6 +355,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq)
284} 355}
285 356
286static struct irqchip ixp2000_GPIO_irq_chip = { 357static struct irqchip ixp2000_GPIO_irq_chip = {
358 .type = ixp2000_GPIO_irq_type,
287 .ack = ixp2000_GPIO_irq_mask_ack, 359 .ack = ixp2000_GPIO_irq_mask_ack,
288 .mask = ixp2000_GPIO_irq_mask, 360 .mask = ixp2000_GPIO_irq_mask,
289 .unmask = ixp2000_GPIO_irq_unmask 361 .unmask = ixp2000_GPIO_irq_unmask
@@ -320,7 +392,7 @@ static void ixp2000_irq_mask(unsigned int irq)
320 392
321static void ixp2000_irq_unmask(unsigned int irq) 393static void ixp2000_irq_unmask(unsigned int irq)
322{ 394{
323 ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq)); 395 ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
324} 396}
325 397
326static struct irqchip ixp2000_irq_chip = { 398static struct irqchip ixp2000_irq_chip = {
@@ -357,16 +429,16 @@ void __init ixp2000_init_irq(void)
357 * our mask/unmask code much simpler. 429 * our mask/unmask code much simpler.
358 */ 430 */
359 for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) { 431 for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
360 if((1 << irq) & IXP2000_VALID_IRQ_MASK) { 432 if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
361 set_irq_chip(irq, &ixp2000_irq_chip); 433 set_irq_chip(irq, &ixp2000_irq_chip);
362 set_irq_handler(irq, do_level_IRQ); 434 set_irq_handler(irq, do_level_IRQ);
363 set_irq_flags(irq, IRQF_VALID); 435 set_irq_flags(irq, IRQF_VALID);
364 } else set_irq_flags(irq, 0); 436 } else set_irq_flags(irq, 0);
365 } 437 }
366 438
367 /* 439 /*
368 * GPIO IRQs are invalid until someone sets the interrupt mode 440 * GPIO IRQs are invalid until someone sets the interrupt mode
369 * by calling gpio_line_set(); 441 * by calling set_irq_type().
370 */ 442 */
371 for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) { 443 for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
372 set_irq_chip(irq, &ixp2000_GPIO_irq_chip); 444 set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index 04b38bcf9aac..f3a291b6a9fb 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -197,8 +197,23 @@ static struct platform_device enp2611_flash = {
197 .resource = &enp2611_flash_resource, 197 .resource = &enp2611_flash_resource,
198}; 198};
199 199
200static struct ixp2000_i2c_pins enp2611_i2c_gpio_pins = {
201 .sda_pin = ENP2611_GPIO_SDA,
202 .scl_pin = ENP2611_GPIO_SCL,
203};
204
205static struct platform_device enp2611_i2c_controller = {
206 .name = "IXP2000-I2C",
207 .id = 0,
208 .dev = {
209 .platform_data = &enp2611_i2c_gpio_pins
210 },
211 .num_resources = 0
212};
213
200static struct platform_device *enp2611_devices[] __initdata = { 214static struct platform_device *enp2611_devices[] __initdata = {
201 &enp2611_flash 215 &enp2611_flash,
216 &enp2611_i2c_controller
202}; 217};
203 218
204static void __init enp2611_init_machine(void) 219static void __init enp2611_init_machine(void)
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index aec13c7108a9..468a4bbfb724 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -42,12 +42,6 @@
42#include <asm/mach/flash.h> 42#include <asm/mach/flash.h>
43#include <asm/mach/arch.h> 43#include <asm/mach/arch.h>
44 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/************************************************************************* 45/*************************************************************************
52 * IXDP2800 timer tick 46 * IXDP2800 timer tick
53 *************************************************************************/ 47 *************************************************************************/
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 21c41fe15b99..5e4380747b53 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -42,6 +42,9 @@
42#include <asm/mach/flash.h> 42#include <asm/mach/flash.h>
43#include <asm/mach/arch.h> 43#include <asm/mach/arch.h>
44 44
45#include <asm/arch/gpio.h>
46
47
45/************************************************************************* 48/*************************************************************************
46 * IXDP2x00 IRQ Initialization 49 * IXDP2x00 IRQ Initialization
47 *************************************************************************/ 50 *************************************************************************/
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 5ff2f2718c58..0788fb2b5c10 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -198,6 +198,19 @@ clear_master_aborts(void)
198void __init 198void __init
199ixp2000_pci_preinit(void) 199ixp2000_pci_preinit(void)
200{ 200{
201#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
202 /*
203 * Configure the PCI unit to properly byteswap I/O transactions,
204 * and verify that it worked.
205 */
206 ixp2000_reg_write(IXP2000_PCI_CONTROL,
207 (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE));
208
209 if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0)
210 panic("IXP2000: PCI I/O is broken on this ixp model, and "
211 "the needed workaround has not been configured in");
212#endif
213
201 hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, 214 hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
202 "PCI config cycle to non-existent device"); 215 "PCI config cycle to non-existent device");
203} 216}