Fix IXP code to work after relocation was added
authorMichael Schwingen <michael@schwingen.org>
Sun, 22 May 2011 22:00:00 +0000 (00:00 +0200)
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>
Thu, 23 Jun 2011 06:24:55 +0000 (08:24 +0200)
 - jump to real flash location after reset before turning off flash mirror
 - fix timer system to use HZ == 1000, remove broken interrupt-based code

Signed-off-by: Michael Schwingen <michael@schwingen.org>
arch/arm/cpu/ixp/cpu.c
arch/arm/cpu/ixp/start.S
arch/arm/cpu/ixp/timer.c
arch/arm/include/asm/arch-ixp/ixp425.h
arch/arm/include/asm/global_data.h

index ce275e5f3c713cf5ee4d8d7ca2ea5a0d463ec1fa..942845d5441a16981ccde771b3e0d5ef1abd0cb8 100644 (file)
@@ -36,8 +36,6 @@
 #include <asm/arch/ixp425.h>
 #include <asm/system.h>
 
-ulong loops_per_jiffy;
-
 static void cache_flush(void);
 
 #if defined(CONFIG_DISPLAY_CPUINFO)
@@ -51,17 +49,14 @@ int print_cpuinfo (void)
        puts("CPU:   Intel IXP425 at ");
        switch ((id & 0x000003f0) >> 4) {
        case 0x1c:
-               loops_per_jiffy = 887467;
                speed = 533;
                break;
 
        case 0x1d:
-               loops_per_jiffy = 666016;
                speed = 400;
                break;
 
        case 0x1f:
-               loops_per_jiffy = 442901;
                speed = 266;
                break;
        }
index 561c1f4795d7cacff637c603f4af23e8e28f9a43..faa9a8ff994dfd6a2af54b58774b7058bb6526f4 100644 (file)
@@ -65,7 +65,8 @@
        .endm
 
 .globl _start
-_start: b      reset
+_start:
+       ldr     pc, _reset
        ldr     pc, _undefined_instruction
        ldr     pc, _software_interrupt
        ldr     pc, _prefetch_abort
@@ -74,6 +75,7 @@ _start: b     reset
        ldr     pc, _irq
        ldr     pc, _fiq
 
+_reset:                 .word reset
 _undefined_instruction: .word undefined_instruction
 _software_interrupt:   .word software_interrupt
 _prefetch_abort:       .word prefetch_abort
@@ -167,12 +169,6 @@ reset:
        str     r1, [r2]
 
        /* make sure flash is visible at 0 */
-#if 0
-       ldr     r2, =IXP425_EXP_CFG0
-       ldr     r1, [r2]
-       orr     r1, r1, #0x80000000
-       str     r1, [r2]
-#endif
        mov     r1, #CONFIG_SYS_SDR_CONFIG
        ldr     r2, =IXP425_SDR_CONFIG
        str     r1, [r2]
@@ -216,19 +212,6 @@ reset:
        str     r1, [r4]
        DELAY_FOR 0x4000, r0
 
-       /* copy */
-       mov     r0, #0
-       mov     r4, r0
-       add     r2, r0, #CONFIG_SYS_MONITOR_LEN
-       mov     r1, #0x10000000
-       mov     r5, r1
-
-    30:
-       ldr     r3, [r0], #4
-       str     r3, [r1], #4
-       cmp     r0, r2
-       bne     30b
-
        /* invalidate I & D caches & BTB */
        mcr     p15, 0, r0, c7, c7, 0
        CPWAIT  r0
@@ -241,19 +224,12 @@ reset:
        mcr     p15, 0, r0, c7, c10, 4
        CPWAIT  r0
 
-       /* move flash to 0x50000000 */
+       /* remove flash mirror at 0x00000000 */
        ldr     r2, =IXP425_EXP_CFG0
        ldr     r1, [r2]
        bic     r1, r1, #0x80000000
        str     r1, [r2]
 
-       nop
-       nop
-       nop
-       nop
-       nop
-       nop
-
        /* invalidate I & Data TLB */
        mcr     p15, 0, r0, c8, c7, 0
        CPWAIT r0
@@ -269,7 +245,7 @@ reset:
        orr     r0,r0,#0x13
        msr     cpsr,r0
 
-/* Set stackpointer in internal RAM to call board_init_f */
+/* Set initial stackpointer in SDRAM to call board_init_f */
 call_board_init_f:
        ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
        bic     sp, sp, #7 /* 8-byte alignment for ABI compliance */
@@ -580,28 +556,3 @@ reset_endless:
 
        b       reset_endless
 
-#ifdef CONFIG_USE_IRQ
-
-.LC0:          .word   loops_per_jiffy
-
-/*
- * 0 <= r0 <= 2000
- */
-.globl __udelay
-__udelay:
-       mov     r2,     #0x6800
-       orr     r2, r2, #0x00db
-       mul     r0, r2, r0
-       ldr     r2, .LC0
-       ldr     r2, [r2]                @ max = 0x0fffffff
-       mov     r0, r0, lsr #11         @ max = 0x00003fff
-       mov     r2, r2, lsr #11         @ max = 0x0003ffff
-       mul     r0, r2, r0              @ max = 2^32-1
-       movs    r0, r0, lsr #6
-
-delay_loop:
-       subs    r0, r0, #1
-       bne     delay_loop
-       mov     pc, lr
-
-#endif /* CONFIG_USE_IRQ */
index edf341ff9f9b24dbac9fc7c4b19539b358900be8..9f3ea42ece3705665dd6efb75f5b47ab46b58242 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * (C) Copyright 2010
+ * Michael Schwingen, michael@schwingen.org
+ *
  * (C) Copyright 2006
  * Stefan Roese, DENX Software Engineering, sr@denx.de.
  *
 
 #include <common.h>
 #include <asm/arch/ixp425.h>
+#include <asm/io.h>
+#include <div64.h>
 
-#ifdef CONFIG_TIMER_IRQ
-
-#define FREQ           66666666
-#define CLOCK_TICK_RATE        (((FREQ / CONFIG_SYS_HZ & ~IXP425_OST_RELOAD_MASK) + 1) * CONFIG_SYS_HZ)
-#define LATCH          ((CLOCK_TICK_RATE + CONFIG_SYS_HZ/2) / CONFIG_SYS_HZ)   /* For divider */
+DECLARE_GLOBAL_DATA_PTR;
 
 /*
- * When interrupts are enabled, use timer 2 for time/delay generation...
+ * The IXP42x time-stamp timer runs at 2*OSC_IN (66.666MHz when using a
+ * 33.333MHz crystal).
  */
-
-static volatile ulong timestamp;
-
-static void timer_isr(void *data)
+static inline unsigned long long tick_to_time(unsigned long long tick)
 {
-       unsigned int *pTime = (unsigned int *)data;
-
-       (*pTime)++;
-
-       /*
-        * Reset IRQ source
-        */
-       *IXP425_OSST = IXP425_OSST_TIMER_2_PEND;
+       tick *= CONFIG_SYS_HZ;
+       do_div(tick, CONFIG_IXP425_TIMER_CLK);
+       return tick;
 }
 
-ulong get_timer (ulong base)
+static inline unsigned long long time_to_tick(unsigned long long time)
 {
-       return timestamp - base;
+       time *= CONFIG_IXP425_TIMER_CLK;
+       do_div(time, CONFIG_SYS_HZ);
+       return time;
 }
 
-void reset_timer (void)
+static inline unsigned long long us_to_tick(unsigned long long us)
 {
-       timestamp = 0;
+       us = us * CONFIG_IXP425_TIMER_CLK + 999999;
+       do_div(us, 1000000);
+       return us;
 }
 
-int timer_init (void)
+unsigned long long get_ticks(void)
 {
-       /* install interrupt handler for timer */
-       irq_install_handler(IXP425_TIMER_2_IRQ, timer_isr, (void *)&timestamp);
-
-       /* setup the Timer counter value */
-       *IXP425_OSRT2 = (LATCH & ~IXP425_OST_RELOAD_MASK) | IXP425_OST_ENABLE;
+       ulong now = readl(IXP425_OSTS_B);
+
+       if (readl(IXP425_OSST) & IXP425_OSST_TIMER_TS_PEND) {
+               /* rollover of timestamp timer register */
+               gd->timestamp += (0xFFFFFFFF - gd->lastinc) + now + 1;
+               writel(IXP425_OSST_TIMER_TS_PEND, IXP425_OSST);
+       } else {
+               /* move stamp forward with absolut diff ticks */
+               gd->timestamp += (now - gd->lastinc);
+       }
+       gd->lastinc = now;
+       return gd->timestamp;
+}
 
-       /* enable timer irq */
-       *IXP425_ICMR = (1 << IXP425_TIMER_2_IRQ);
 
-       return 0;
-}
-#else
-ulong get_timer (ulong base)
+void reset_timer_masked(void)
 {
-       return get_timer_masked () - base;
+       /* capture current timestamp counter */
+       gd->lastinc = readl(IXP425_OSTS_B);
+       /* start "advancing" time stamp from 0 */
+       gd->timestamp = 0;
 }
 
-void ixp425_udelay(unsigned long usec)
+void reset_timer(void)
 {
-       /*
-        * This function has a max usec, but since it is called from udelay
-        * we should not have to worry... be happy
-        */
-       unsigned long usecs = CONFIG_SYS_HZ/1000000L & ~IXP425_OST_RELOAD_MASK;
-
-       *IXP425_OSST = IXP425_OSST_TIMER_1_PEND;
-       usecs |= IXP425_OST_ONE_SHOT | IXP425_OST_ENABLE;
-       *IXP425_OSRT1 = usecs;
-       while (!(*IXP425_OSST & IXP425_OSST_TIMER_1_PEND));
+       reset_timer_masked();
 }
 
-void __udelay (unsigned long usec)
+ulong get_timer_masked(void)
 {
-       while (usec--) ixp425_udelay(1);
+       return tick_to_time(get_ticks());
 }
 
-static ulong reload_constant = 0xfffffff0;
-
-void reset_timer_masked (void)
+ulong get_timer(ulong base)
 {
-       ulong reload = reload_constant | IXP425_OST_ONE_SHOT | IXP425_OST_ENABLE;
+       return get_timer_masked() - base;
+}
 
-       *IXP425_OSST = IXP425_OSST_TIMER_1_PEND;
-       *IXP425_OSRT1 = reload;
+void set_timer(ulong t)
+{
+       gd->timestamp = time_to_tick(t);
 }
 
-ulong get_timer_masked (void)
+/* delay x useconds AND preserve advance timestamp value */
+void __udelay(unsigned long usec)
 {
-       /*
-        * Note that it is possible for this to wrap!
-        * In this case we return max.
-        */
-       ulong current = *IXP425_OST1;
-       if (*IXP425_OSST & IXP425_OSST_TIMER_1_PEND)
-       {
-               return reload_constant;
-       }
-       return (reload_constant - current);
+       unsigned long long tmp;
+
+       tmp = get_ticks() + us_to_tick(usec);
+
+       while (get_ticks() < tmp)
+               ;
 }
 
 int timer_init(void)
 {
+       writel(IXP425_OSST_TIMER_TS_PEND, IXP425_OSST);
        return 0;
 }
-#endif
index 2114437dc75e2f3c0c1d363d77d1ad13d4050635..5132607c6a74a408bd085d649d6fa48a848b9317 100644 (file)
 #define IXP425_TIMER_REG(x) (IXP425_TIMER_BASE_PHYS+(x))
 #endif
 
-#if 0 /* test-only: also defined in npe/include/... */
-#define IXP425_OSTS    IXP425_TIMER_REG(IXP425_OSTS_OFFSET)
-#endif
+/* _B to avoid collision: also defined in npe/include/... */
+#define IXP425_OSTS_B  IXP425_TIMER_REG(IXP425_OSTS_OFFSET)
 #define IXP425_OST1    IXP425_TIMER_REG(IXP425_OST1_OFFSET)
 #define IXP425_OSRT1   IXP425_TIMER_REG(IXP425_OSRT1_OFFSET)
 #define IXP425_OST2    IXP425_TIMER_REG(IXP425_OST2_OFFSET)
index 2a84d27a4e15e10a86cc5842eae25e80d21981e1..c1a59f2c938d181a813b1762018e11869508c0d8 100644 (file)
@@ -63,6 +63,9 @@ typedef       struct  global_data {
        unsigned long   tbu;
        unsigned long long      timer_reset_value;
        unsigned long   lastinc;
+#endif
+#ifdef CONFIG_IXP425
+       unsigned long   timestamp;
 #endif
        unsigned long   relocaddr;      /* Start address of U-Boot in RAM */
        phys_size_t     ram_size;       /* RAM size */