]> Zhao Yanbai Git Server - minix.git/commitdiff
ARM: provide free running clock to replace ccnt 84/284/2
authorThomas Veerman <thomas@minix3.org>
Tue, 29 Jan 2013 19:58:00 +0000 (20:58 +0100)
committerThomas Veerman <thomas@minix3.org>
Thu, 31 Jan 2013 15:19:11 +0000 (15:19 +0000)
The Cycle CouNTer on ARM cannot be used reliably as it wraps around
rather quickly and can be altered by user space (on Minix). Furthermore,
it's buggy when wrapping and is not implemented at all on the Linaro
Beagleboard emulator.

This patch programs GPTIMER10 as a free running clock at 1.625 MHz (it
doesn't generate interrupts). It's memory mapped into every process,
which enables libsys to provide micro_delay().

Change-Id: Iba004c6c62976762fe154ea390d69e518eec1531

12 files changed:
include/minix/sysutil.h
include/minix/type.h
kernel/arch/earm/arch_clock.c
kernel/arch/earm/memory.c
kernel/arch/earm/omap_timer.c
kernel/arch/earm/omap_timer.h
kernel/arch/earm/omap_timer_registers.h [new file with mode: 0644]
kernel/arch/i386/memory.c
lib/libsys/arch/earm/Makefile.inc
lib/libsys/arch/earm/frclock_util.c [new file with mode: 0644]
lib/libsys/arch/earm/spin.c [new file with mode: 0644]
lib/libsys/arch/earm/tsc_util.c

index cd32e953c3a570c2fdeea9b7bbee5896a7e2470c..56a6d795292168d6ba0e2778d750c61794466d11 100644 (file)
@@ -61,6 +61,12 @@ u32_t tsc_64_to_micros(u64_t tsc);
 u32_t tsc_to_micros(u32_t low, u32_t high);
 u32_t tsc_get_khz(void);
 u32_t micros_to_ticks(u32_t micros);
+#if defined(__arm__)
+u32_t read_frclock(void);
+u32_t delta_frclock(u32_t base, u32_t cur);
+u64_t read_frclock_64(void);
+u64_t delta_frclock_64(u64_t base, u64_t cur);
+#endif
 void ser_putc(char c);
 void get_randomness(struct k_randomness *, int);
 u32_t sqrt_approx(u32_t);
index 7dc11f1610e5466aca09da635f3e89204c7aff8b..29e59bcba0bb6526f2c426c05d7cff6b156e385f 100644 (file)
@@ -168,7 +168,7 @@ struct minix_kerninfo {
        u32_t kerninfo_magic;
        u32_t minix_feature_flags;      /* features in minix kernel */
        u32_t ki_flags;                 /* what is present in this struct */
-       u32_t flags_unused2;
+       u32_t minix_frclock;
        u32_t flags_unused3;
        u32_t flags_unused4;
        struct kinfo            *kinfo;
index 5a514414037fe1723e7d9b4834bcf69fc69f882e..96d8811b2903c076dd9b5b934bacbc54fcb64774 100644 (file)
@@ -25,6 +25,7 @@ static unsigned tsc_per_ms[CONFIG_MAX_CPUS];
 int init_local_timer(unsigned freq)
 {
        omap3_timer_init(freq);
+       omap3_frclock_init();
        /* always only 1 cpu in the system */
        tsc_per_ms[0] = 1;
 
index 2f22bb5b7d5551b2bcf08db2fe00b29b27bae965..f422d43be2d2e0e16a46a209744fb58efa8f54d7 100644 (file)
@@ -18,6 +18,7 @@
 #include "arch_proto.h"
 #include "kernel/proto.h"
 #include "kernel/debug.h"
+#include "omap_timer.h"
 
 phys_bytes device_mem_vaddr = 0;
 
@@ -667,6 +668,7 @@ void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name)
 }
 
 static int device_mem_mapping_index = -1,
+       frclock_index = -1,
        usermapped_glo_index = -1,
        usermapped_index = -1, first_um_idx = -1;
 
@@ -685,7 +687,9 @@ int arch_phys_map(const int index,
                        (u32_t) &usermapped_start;
 
        if(first) {
+               memset(&minix_kerninfo, 0, sizeof(minix_kerninfo));
                device_mem_mapping_index = freeidx++;
+               frclock_index = freeidx++;
                if(glo_len > 0) {
                        usermapped_glo_index = freeidx++;
                }
@@ -717,6 +721,12 @@ int arch_phys_map(const int index,
                *flags = VMMF_UNCACHED | VMMF_WRITE;
                return OK;
        }
+       else if (index == frclock_index) {
+               *addr = OMAP3_GPTIMER10_BASE;
+               *len = ARM_PAGE_SIZE;
+               *flags = VMMF_USER;
+               return OK;
+       }
 
        return EINVAL;
 }
@@ -727,7 +737,6 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
                u32_t usermapped_offset;
                assert(addr > (u32_t) &usermapped_start);
                usermapped_offset = addr - (u32_t) &usermapped_start;
-               memset(&minix_kerninfo, 0, sizeof(minix_kerninfo));
 #define FIXEDPTR(ptr) (void *) ((u32_t)ptr + usermapped_offset)
 #define FIXPTR(ptr) ptr = FIXEDPTR(ptr)
 #define ASSIGN(minixstruct) minix_kerninfo.minixstruct = FIXEDPTR(&minixstruct)
@@ -746,10 +755,15 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
                return OK;
        }
 
-       if(index == usermapped_index) return OK;
-
-       if (index == device_mem_mapping_index) {
-               device_mem_vaddr =  addr;
+       if (index == usermapped_index) {
+               return OK;
+       }
+       else if (index == device_mem_mapping_index) {
+               device_mem_vaddr = addr;
+               return OK;
+       }
+       else if (index == frclock_index) {
+               minix_kerninfo.minix_frclock = addr;
                return OK;
        }
 
index f106dc0925711c2c94ed266e91e0ebdb4cddad78..a5bac65a9fef0f19883351e1b021f9a1729ed8f9 100644 (file)
@@ -21,6 +21,42 @@ int omap3_register_timer_handler(const irq_handler_t handler)
        return 0;
 }
 
+void omap3_frclock_init(void)
+{
+    u32_t tisr;
+
+    /* Stop timer */
+    mmio_clear(OMAP3_GPTIMER10_TCLR, OMAP3_TCLR_ST);
+
+    /* Use functional clock source for GPTIMER10 */
+    mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10);
+
+    /* Scale timer down to 13/8 = 1.625 Mhz to roughly get microsecond ticks */
+    /* The scale is computed as 2^(PTV+1). So if PTV == 2, we get 2^3 = 8.
+     */
+    mmio_set(OMAP3_GPTIMER10_TCLR, (2 << OMAP3_TCLR_PTV));
+
+    /* Start and auto-reload at 0 */
+    mmio_write(OMAP3_GPTIMER10_TLDR, 0x0);
+    mmio_write(OMAP3_GPTIMER10_TCRR, 0x0);
+
+    /* Set up overflow interrupt */
+    tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
+          OMAP3_TISR_TCAR_IT_FLAG;
+    mmio_write(OMAP3_GPTIMER10_TISR, tisr); /* Clear interrupt status */
+    mmio_write(OMAP3_GPTIMER10_TIER, OMAP3_TIER_OVF_IT_ENA);
+
+    /* Start timer */
+    mmio_set(OMAP3_GPTIMER10_TCLR,
+            OMAP3_TCLR_OVF_TRG|OMAP3_TCLR_AR|OMAP3_TCLR_ST|OMAP3_TCLR_PRE);
+}
+
+void omap3_frclock_stop()
+{
+    mmio_clear(OMAP3_GPTIMER10_TCLR, OMAP3_TCLR_ST);
+}
+
+
 void omap3_timer_init(unsigned freq)
 {
     u32_t tisr;
@@ -63,6 +99,7 @@ void omap3_timer_int_handler()
            OMAP3_TISR_TCAR_IT_FLAG;
     mmio_write(OMAP3_GPTIMER1_TISR, tisr);
     tsc++;
+
 }
 
 /* Don't use libminlib's read_tsc_64, but our own version instead. We emulate
index 5317b0e28d288a6ca297c7a9cea79e695fde955e..948139bfb9bbdb550f71c7fd52b3957a53efc0f0 100644 (file)
@@ -1,92 +1,14 @@
 #ifndef _OMAP_TIMER_H
 #define _OMAP_TIMER_H
 
-/* General-purpose timer register map */
-#define OMAP3_GPTIMER1_BASE  0x48318000 /* GPTIMER1 physical address */
-#define OMAP3_GPTIMER2_BASE  0x49032000 /* GPTIMER2 physical address */
-#define OMAP3_GPTIMER3_BASE  0x49034000 /* GPTIMER3 physical address */
-#define OMAP3_GPTIMER4_BASE  0x49036000 /* GPTIMER4 physical address */
-#define OMAP3_GPTIMER5_BASE  0x49038000 /* GPTIMER5 physical address */
-#define OMAP3_GPTIMER6_BASE  0x4903A000 /* GPTIMER6 physical address */
-#define OMAP3_GPTIMER7_BASE  0x4903C000 /* GPTIMER7 physical address */
-#define OMAP3_GPTIMER8_BASE  0x4903E000 /* GPTIMER8 physical address */
-#define OMAP3_GPTIMER9_BASE  0x49040000 /* GPTIMER9 physical address */
-#define OMAP3_GPTIMER10_BASE 0x48086000 /* GPTIMER10 physical address */
-#define OMAP3_GPTIMER11_BASE 0x48088000 /* GPTIMER11 physical address */
-
-/* General-purpose timer registers */
-#define OMAP3_TIDR      0x000 /* IP revision code */
-#define OMAP3_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */
-#define OMAP3_TISTAT    0x014 /* Status (excl. interrupt status) */
-#define OMAP3_TISR      0x018 /* Pending interrupt status */
-#define OMAP3_TIER      0x01C /* Interrupt enable */
-#define OMAP3_TWER      0x020 /* Wakeup enable */
-#define OMAP3_TCLR      0x024 /* Controls optional features */
-#define OMAP3_TCRR      0x028 /* Internal counter value */
-#define OMAP3_TLDR      0x02C /* Timer load value */
-#define OMAP3_TTGR      0x030 /* Triggers counter reload */
-#define OMAP3_TWPS      0x034 /* Indicates if Write-Posted pending */
-#define OMAP3_TMAR      0x038 /* Value to be compared with counter */
-#define OMAP3_TCAR1     0x03C /* First captured value of counter register */
-#define OMAP3_TSICR     0x040 /* Control posted mode and functional SW reset */
-#define OMAP3_TCAR2     0x044 /* Second captured value of counter register */
-#define OMAP3_TPIR      0x048 /* Positive increment (1 ms tick) */
-#define OMAP3_TNIR      0x04C /* Negative increment (1 ms tick) */
-#define OMAP3_TCVR      0x050 /* Defines TCRR is sub/over-period (1 ms tick) */
-#define OMAP3_TOCR      0x054 /* Masks tick interrupt */
-#define OMAP3_TOWR      0x058 /* Number of masked overflow interrupts */
-
-/* Interrupt status register fields */
-#define OMAP3_TISR_MAT_IT_FLAG  (1 << 0) /* Pending match interrupt status */
-#define OMAP3_TISR_OVF_IT_FLAG  (1 << 1) /* Pending overflow interrupt status */
-#define OMAP3_TISR_TCAR_IT_FLAG (1 << 2) /* Pending capture interrupt status */
-
-/* Interrupt enable register fields */
-#define OMAP3_TIER_MAT_IT_ENA  (1 << 0) /* Enable match interrupt */
-#define OMAP3_TIER_OVF_IT_ENA  (1 << 1) /* Enable overflow interrupt */
-#define OMAP3_TIER_TCAR_IT_ENA (1 << 2) /* Enable capture interrupt */
-
-/* Timer control fields */
-#define OMAP3_TCLR_ST       (1 << 0)  /* Start/stop timer */
-#define OMAP3_TCLR_AR       (1 << 1)  /* Autoreload or one-shot mode */
-#define OMAP3_TCLR_OVF_TRG  (1 << 10) /* Overflow trigger */
-
-#define OMAP3_GPTIMER1_TIDR      (OMAP3_GPTIMER1_BASE + OMAP3_TIDR)
-#define OMAP3_GPTIMER1_TIOCP_CFG (OMAP3_GPTIMER1_BASE + OMAP3_TIOCP_CFG)
-#define OMAP3_GPTIMER1_TISTAT    (OMAP3_GPTIMER1_BASE + OMAP3_TISTAT)
-#define OMAP3_GPTIMER1_TISR      (OMAP3_GPTIMER1_BASE + OMAP3_TISR)
-#define OMAP3_GPTIMER1_TIER      (OMAP3_GPTIMER1_BASE + OMAP3_TIER)
-#define OMAP3_GPTIMER1_TWER      (OMAP3_GPTIMER1_BASE + OMAP3_TWER)
-#define OMAP3_GPTIMER1_TCLR      (OMAP3_GPTIMER1_BASE + OMAP3_TCLR)
-#define OMAP3_GPTIMER1_TCRR      (OMAP3_GPTIMER1_BASE + OMAP3_TCRR)
-#define OMAP3_GPTIMER1_TLDR      (OMAP3_GPTIMER1_BASE + OMAP3_TLDR)
-#define OMAP3_GPTIMER1_TTGR      (OMAP3_GPTIMER1_BASE + OMAP3_TTGR)
-#define OMAP3_GPTIMER1_TWPS      (OMAP3_GPTIMER1_BASE + OMAP3_TWPS)
-#define OMAP3_GPTIMER1_TMAR      (OMAP3_GPTIMER1_BASE + OMAP3_TMAR)
-#define OMAP3_GPTIMER1_TCAR1     (OMAP3_GPTIMER1_BASE + OMAP3_TCAR1)
-#define OMAP3_GPTIMER1_TSICR     (OMAP3_GPTIMER1_BASE + OMAP3_TSICR)
-#define OMAP3_GPTIMER1_TCAR2     (OMAP3_GPTIMER1_BASE + OMAP3_TCAR2)
-#define OMAP3_GPTIMER1_TPIR      (OMAP3_GPTIMER1_BASE + OMAP3_TPIR)
-#define OMAP3_GPTIMER1_TNIR      (OMAP3_GPTIMER1_BASE + OMAP3_TNIR)
-#define OMAP3_GPTIMER1_TCVR      (OMAP3_GPTIMER1_BASE + OMAP3_TCVR)
-#define OMAP3_GPTIMER1_TOCR      (OMAP3_GPTIMER1_BASE + OMAP3_TOCR)
-#define OMAP3_GPTIMER1_TOWR      (OMAP3_GPTIMER1_BASE + OMAP3_TOWR)
-
-#define OMAP3_CM_CLKSEL_WKUP 0x48004c40 /* source clock selection */
-#define OMAP3_CLKSEL_GPT1    (1 << 0)   /* Selects GPTIMER 1 source
-                                        * clock:
-                                        *
-                                        *  0: use 32KHz clock
-                                        *  1: sys clock)
-                                        */
-
-#define TIMER_FREQ  1000    /* clock frequency for OMAP timer (1ms) */
-#define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/
+#include "omap_timer_registers.h"
 
 #ifndef __ASSEMBLY__
 
 void omap3_timer_init(unsigned freq);
 void omap3_timer_stop(void);
+void omap3_frclock_init(void);
+void omap3_frclock_stop(void);
 int omap3_register_timer_handler(const irq_handler_t handler);
 void omap3_timer_int_handler(void);
 
diff --git a/kernel/arch/earm/omap_timer_registers.h b/kernel/arch/earm/omap_timer_registers.h
new file mode 100644 (file)
index 0000000..21e8b9d
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef _OMAP_TIMER_REGISTERS_H
+#define _OMAP_TIMER_REGISTERS_H
+
+/* General-purpose timer register map */
+#define OMAP3_GPTIMER1_BASE  0x48318000 /* GPTIMER1 physical address */
+#define OMAP3_GPTIMER2_BASE  0x49032000 /* GPTIMER2 physical address */
+#define OMAP3_GPTIMER3_BASE  0x49034000 /* GPTIMER3 physical address */
+#define OMAP3_GPTIMER4_BASE  0x49036000 /* GPTIMER4 physical address */
+#define OMAP3_GPTIMER5_BASE  0x49038000 /* GPTIMER5 physical address */
+#define OMAP3_GPTIMER6_BASE  0x4903A000 /* GPTIMER6 physical address */
+#define OMAP3_GPTIMER7_BASE  0x4903C000 /* GPTIMER7 physical address */
+#define OMAP3_GPTIMER8_BASE  0x4903E000 /* GPTIMER8 physical address */
+#define OMAP3_GPTIMER9_BASE  0x49040000 /* GPTIMER9 physical address */
+#define OMAP3_GPTIMER10_BASE 0x48086000 /* GPTIMER10 physical address */
+#define OMAP3_GPTIMER11_BASE 0x48088000 /* GPTIMER11 physical address */
+
+/* General-purpose timer registers */
+#define OMAP3_TIDR      0x000 /* IP revision code */
+#define OMAP3_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */
+#define OMAP3_TISTAT    0x014 /* Status (excl. interrupt status) */
+#define OMAP3_TISR      0x018 /* Pending interrupt status */
+#define OMAP3_TIER      0x01C /* Interrupt enable */
+#define OMAP3_TWER      0x020 /* Wakeup enable */
+#define OMAP3_TCLR      0x024 /* Controls optional features */
+#define OMAP3_TCRR      0x028 /* Internal counter value */
+#define OMAP3_TLDR      0x02C /* Timer load value */
+#define OMAP3_TTGR      0x030 /* Triggers counter reload */
+#define OMAP3_TWPS      0x034 /* Indicates if Write-Posted pending */
+#define OMAP3_TMAR      0x038 /* Value to be compared with counter */
+#define OMAP3_TCAR1     0x03C /* First captured value of counter register */
+#define OMAP3_TSICR     0x040 /* Control posted mode and functional SW reset */
+#define OMAP3_TCAR2     0x044 /* Second captured value of counter register */
+#define OMAP3_TPIR      0x048 /* Positive increment (1 ms tick) */
+#define OMAP3_TNIR      0x04C /* Negative increment (1 ms tick) */
+#define OMAP3_TCVR      0x050 /* Defines TCRR is sub/over-period (1 ms tick) */
+#define OMAP3_TOCR      0x054 /* Masks tick interrupt */
+#define OMAP3_TOWR      0x058 /* Number of masked overflow interrupts */
+
+/* Interrupt status register fields */
+#define OMAP3_TISR_MAT_IT_FLAG  (1 << 0) /* Pending match interrupt status */
+#define OMAP3_TISR_OVF_IT_FLAG  (1 << 1) /* Pending overflow interrupt status */
+#define OMAP3_TISR_TCAR_IT_FLAG (1 << 2) /* Pending capture interrupt status */
+
+/* Interrupt enable register fields */
+#define OMAP3_TIER_MAT_IT_ENA  (1 << 0) /* Enable match interrupt */
+#define OMAP3_TIER_OVF_IT_ENA  (1 << 1) /* Enable overflow interrupt */
+#define OMAP3_TIER_TCAR_IT_ENA (1 << 2) /* Enable capture interrupt */
+
+/* Timer control fields */
+#define OMAP3_TCLR_ST       (1 << 0)  /* Start/stop timer */
+#define OMAP3_TCLR_AR       (1 << 1)  /* Autoreload or one-shot mode */
+#define OMAP3_TCLR_PRE      (1 << 5)  /* Prescaler on */
+#define OMAP3_TCLR_PTV            2
+#define OMAP3_TCLR_OVF_TRG  (1 << 10) /* Overflow trigger */
+
+#define OMAP3_GPTIMER1_TIDR      (OMAP3_GPTIMER1_BASE + OMAP3_TIDR)
+#define OMAP3_GPTIMER1_TIOCP_CFG (OMAP3_GPTIMER1_BASE + OMAP3_TIOCP_CFG)
+#define OMAP3_GPTIMER1_TISTAT    (OMAP3_GPTIMER1_BASE + OMAP3_TISTAT)
+#define OMAP3_GPTIMER1_TISR      (OMAP3_GPTIMER1_BASE + OMAP3_TISR)
+#define OMAP3_GPTIMER1_TIER      (OMAP3_GPTIMER1_BASE + OMAP3_TIER)
+#define OMAP3_GPTIMER1_TWER      (OMAP3_GPTIMER1_BASE + OMAP3_TWER)
+#define OMAP3_GPTIMER1_TCLR      (OMAP3_GPTIMER1_BASE + OMAP3_TCLR)
+#define OMAP3_GPTIMER1_TCRR      (OMAP3_GPTIMER1_BASE + OMAP3_TCRR)
+#define OMAP3_GPTIMER1_TLDR      (OMAP3_GPTIMER1_BASE + OMAP3_TLDR)
+#define OMAP3_GPTIMER1_TTGR      (OMAP3_GPTIMER1_BASE + OMAP3_TTGR)
+#define OMAP3_GPTIMER1_TWPS      (OMAP3_GPTIMER1_BASE + OMAP3_TWPS)
+#define OMAP3_GPTIMER1_TMAR      (OMAP3_GPTIMER1_BASE + OMAP3_TMAR)
+#define OMAP3_GPTIMER1_TCAR1     (OMAP3_GPTIMER1_BASE + OMAP3_TCAR1)
+#define OMAP3_GPTIMER1_TSICR     (OMAP3_GPTIMER1_BASE + OMAP3_TSICR)
+#define OMAP3_GPTIMER1_TCAR2     (OMAP3_GPTIMER1_BASE + OMAP3_TCAR2)
+#define OMAP3_GPTIMER1_TPIR      (OMAP3_GPTIMER1_BASE + OMAP3_TPIR)
+#define OMAP3_GPTIMER1_TNIR      (OMAP3_GPTIMER1_BASE + OMAP3_TNIR)
+#define OMAP3_GPTIMER1_TCVR      (OMAP3_GPTIMER1_BASE + OMAP3_TCVR)
+#define OMAP3_GPTIMER1_TOCR      (OMAP3_GPTIMER1_BASE + OMAP3_TOCR)
+#define OMAP3_GPTIMER1_TOWR      (OMAP3_GPTIMER1_BASE + OMAP3_TOWR)
+
+#define OMAP3_GPTIMER10_TIDR      (OMAP3_GPTIMER10_BASE + OMAP3_TIDR)
+#define OMAP3_GPTIMER10_TIOCP_CFG (OMAP3_GPTIMER10_BASE + OMAP3_TIOCP_CFG)
+#define OMAP3_GPTIMER10_TISTAT    (OMAP3_GPTIMER10_BASE + OMAP3_TISTAT)
+#define OMAP3_GPTIMER10_TISR      (OMAP3_GPTIMER10_BASE + OMAP3_TISR)
+#define OMAP3_GPTIMER10_TIER      (OMAP3_GPTIMER10_BASE + OMAP3_TIER)
+#define OMAP3_GPTIMER10_TWER      (OMAP3_GPTIMER10_BASE + OMAP3_TWER)
+#define OMAP3_GPTIMER10_TCLR      (OMAP3_GPTIMER10_BASE + OMAP3_TCLR)
+#define OMAP3_GPTIMER10_TCRR      (OMAP3_GPTIMER10_BASE + OMAP3_TCRR)
+#define OMAP3_GPTIMER10_TLDR      (OMAP3_GPTIMER10_BASE + OMAP3_TLDR)
+#define OMAP3_GPTIMER10_TTGR      (OMAP3_GPTIMER10_BASE + OMAP3_TTGR)
+#define OMAP3_GPTIMER10_TWPS      (OMAP3_GPTIMER10_BASE + OMAP3_TWPS)
+#define OMAP3_GPTIMER10_TMAR      (OMAP3_GPTIMER10_BASE + OMAP3_TMAR)
+#define OMAP3_GPTIMER10_TCAR1     (OMAP3_GPTIMER10_BASE + OMAP3_TCAR1)
+#define OMAP3_GPTIMER10_TSICR     (OMAP3_GPTIMER10_BASE + OMAP3_TSICR)
+#define OMAP3_GPTIMER10_TCAR2     (OMAP3_GPTIMER10_BASE + OMAP3_TCAR2)
+#define OMAP3_GPTIMER10_TPIR      (OMAP3_GPTIMER10_BASE + OMAP3_TPIR)
+#define OMAP3_GPTIMER10_TNIR      (OMAP3_GPTIMER10_BASE + OMAP3_TNIR)
+#define OMAP3_GPTIMER10_TCVR      (OMAP3_GPTIMER10_BASE + OMAP3_TCVR)
+#define OMAP3_GPTIMER10_TOCR      (OMAP3_GPTIMER10_BASE + OMAP3_TOCR)
+#define OMAP3_GPTIMER10_TOWR      (OMAP3_GPTIMER10_BASE + OMAP3_TOWR)
+
+#define OMAP3_CM_CLKSEL_GFX            0x48004b40
+#define OMAP3_CM_CLKEN_PLL             0x48004d00
+#define OMAP3_CM_FCLKEN1_CORE          0x48004A00
+#define OMAP3_CM_CLKSEL_CORE           0x48004A40 /* GPT10 src clock sel. */
+#define OMAP3_CM_FCLKEN_PER            0x48005000
+#define OMAP3_CM_CLKSEL_PER            0x48005040
+#define OMAP3_CM_CLKSEL_WKUP 0x48004c40 /* GPT1 source clock selection */
+
+#define OMAP3_CLKSEL_GPT1    (1 << 0)   /* Selects GPTIMER 1 source
+                                        * clock:
+                                        *
+                                        *  0: use 32KHz clock
+                                        *  1: sys clock)
+                                        */
+#define OMAP3_CLKSEL_GPT10    (1 << 6)
+#define OMAP3_CLKSEL_GPT11    (1 << 7)
+
+
+#define TIMER_FREQ  1000    /* clock frequency for OMAP timer (1ms) */
+#define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/
+
+#endif /* _OMAP_TIMER_REGISTERS_H */
index eb87a9d9204f99ae61148c75da0c2e643454922d..3eca8bbba1048992f8a3535c4da69ae4bce1a300 100644 (file)
@@ -804,6 +804,7 @@ int arch_phys_map(const int index,
                        (u32_t) &usermapped_start;
 
        if(first) {
+               memset(&minix_kerninfo, 0, sizeof(minix_kerninfo));
                video_mem_mapping_index = freeidx++;
                if(glo_len > 0) {
                        usermapped_glo_index = freeidx++;
@@ -921,7 +922,6 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
                extern u32_t usermapped_offset;
                assert(addr > (u32_t) &usermapped_start);
                usermapped_offset = addr - (u32_t) &usermapped_start;
-               memset(&minix_kerninfo, 0, sizeof(minix_kerninfo));
 #define FIXEDPTR(ptr) (void *) ((u32_t)ptr + usermapped_offset)
 #define FIXPTR(ptr) ptr = FIXEDPTR(ptr)
 #define ASSIGN(minixstruct) minix_kerninfo.minixstruct = FIXEDPTR(&minixstruct)
index 8a998177421c8e3cd0665074985cb8641cee847c..55fd2bced898811cee06d3ce197e851630958a4c 100644 (file)
@@ -5,8 +5,11 @@ HERE=${.CURDIR}/arch/${MACHINE_ARCH}
 .PATH:  ${HERE}
 
 SRCS+=  \
+       frclock_util.c \
+       spin.c \
         tsc_util.c
 
-CPPFLAGS+=        -I${HERE}/../../
+CPPFLAGS+=     -I${HERE}/../../
+CPPFLAGS+=     -I${NETBSDSRCDIR} -I${NETBSDSRCDIR}/kernel/arch/${MACHINE_ARCH}/
 
 
diff --git a/lib/libsys/arch/earm/frclock_util.c b/lib/libsys/arch/earm/frclock_util.c
new file mode 100644 (file)
index 0000000..8d81e78
--- /dev/null
@@ -0,0 +1,89 @@
+/* Some utility functions around the free running clock on ARM. The clock is
+ * 32-bits wide, but we provide 64-bit wrapper functions to make it look
+ * similar to the read_tsc functions. On hardware we could actually make use
+ * of the timer overflow counter, but emulator doesn't emulate it. */
+
+#include "omap_timer_registers.h"
+#include <minix/minlib.h>
+#include <minix/sysutil.h>
+#include <minix/type.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+
+
+static u64_t calib_hz = 1625000, Hz;
+#define MICROHZ         1000000ULL     /* number of micros per second */
+#define MICROSPERTICK(h)       (MICROHZ/(h)) /* number of micros per HZ tick */
+
+int
+micro_delay(u32_t micros)
+{
+        u64_t start, delta, delta_end;
+
+       Hz = sys_hz();
+
+        /* Start of delay. */
+        start = read_frclock_64();
+       delta_end = (calib_hz * micros) / MICROHZ;
+
+        /* If we have to wait for at least one HZ tick, use the regular
+         * tickdelay first. Round downwards on purpose, so the average
+         * half-tick we wait short (depending on where in the current tick
+         * we call tickdelay). We can correct for both overhead of tickdelay
+         * itself and the short wait in the busywait later.
+         */
+        if (micros >= MICROSPERTICK(Hz))
+                tickdelay(micros*Hz/MICROHZ);
+
+        /* Wait (the rest) of the delay time using busywait. */
+       do {
+                delta = read_frclock_64();
+       } while (delta_frclock_64(start, delta) < delta_end);
+
+
+        return 0;
+}
+
+u32_t frclock_64_to_micros(u64_t tsc)
+{
+        return (u32_t) tsc / calib_hz;
+}
+
+u32_t
+read_frclock(void)
+{
+       extern struct minix_kerninfo *_minix_kerninfo;
+       volatile u32_t *frclock;
+       frclock = (u32_t *)((u8_t *) _minix_kerninfo->minix_frclock+OMAP3_TCRR);
+       return (u64_t) *frclock;
+}
+
+u32_t
+delta_frclock(u32_t base, u32_t cur)
+{
+       u32_t delta;
+
+       if (cur < base) {
+               /* We have wrapped around, so delta is base to wrapping point
+                * plus starting point (0) to cur. This supports wrapping once
+                * only. */
+               delta = (UINT_MAX - base) + cur;
+       } else {
+               delta = cur - base;
+       }
+
+       return delta;
+}
+
+u64_t
+read_frclock_64(void)
+{
+       return (u64_t) read_frclock();
+}
+
+u64_t
+delta_frclock_64(u64_t base, u64_t cur)
+{
+       return delta_frclock((u32_t) base, (u32_t) cur);
+}
+
diff --git a/lib/libsys/arch/earm/spin.c b/lib/libsys/arch/earm/spin.c
new file mode 100644 (file)
index 0000000..1033a2f
--- /dev/null
@@ -0,0 +1,98 @@
+/* Helper functions that allow driver writers to easily busy-wait (spin) for a
+ * condition to become satisfied within a certain maximum time span.
+ */
+/* This implementation first spins without making any system calls for a
+ * while, and then starts using system calls (specifically, the system call to
+ * obtain the current time) while spinning. The reason for this is that in
+ * many cases, the condition to be checked will become satisfied rather
+ * quickly, and we want to avoid getting descheduled in that case. However,
+ * after a while, running out of scheduling quantum will cause our priority to
+ * be lowered, and we can avoid this by voluntarily giving up the CPU, by
+ * making a system call.
+ */
+#include "sysutil.h"
+#include <minix/spin.h>
+#include <minix/minlib.h>
+
+/* Number of microseconds to keep spinning initially, without performing a
+ * system call. We pick a value somewhat smaller than a typical clock tick.
+ * Note that for the above reasons, we want to avoid using sys_hz() here.
+ */
+#define TSC_SPIN               1000            /* in microseconds */
+
+/* Internal spin states. */
+enum {
+       STATE_INIT,             /* simply check the condition (once) */
+       STATE_BASE_TS,          /* get the initial TSC value (once) */
+       STATE_TS,               /* use the TSC to spin (up to TSC_SPIN us) */
+       STATE_UPTIME            /* use the clock to spin */
+};
+
+void spin_init(spin_t *s, u32_t usecs)
+{
+       /* Initialize the given spin state structure, set to spin at most the
+        * given number of microseconds.
+        */
+       s->s_state = STATE_INIT;
+       s->s_usecs = usecs;
+       s->s_timeout = FALSE;
+}
+
+int spin_check(spin_t *s)
+{
+       /* Check whether a timeout has taken place. Return TRUE if the caller
+        * should continue spinning, and FALSE if a timeout has occurred. The
+        * implementation assumes that it is okay to spin a little bit too long
+        * (up to a full clock tick extra).
+        */
+       u64_t cur_tsc, tsc_delta;
+       clock_t now, micro_delta;
+
+       switch (s->s_state) {
+       case STATE_INIT:
+               s->s_state = STATE_BASE_TS;
+               break;
+
+       case STATE_BASE_TS:
+               s->s_state = STATE_TS;
+               s->s_base_tsc = read_frclock_64();
+               break;
+
+       case STATE_TS:
+               cur_tsc = read_frclock_64();
+               tsc_delta = delta_frclock_64(s->s_base_tsc, cur_tsc);
+               micro_delta = frclock_64_to_micros(tsc_delta);
+
+               if (micro_delta >= s->s_usecs) {
+                       s->s_timeout = TRUE;
+                       return FALSE;
+               }
+
+               if (micro_delta >= TSC_SPIN) {
+                       s->s_usecs -= micro_delta;
+                       getuptime(&s->s_base_uptime);
+                       s->s_state = STATE_UPTIME;
+               }
+
+               break;
+
+       case STATE_UPTIME:
+               getuptime(&now);
+
+               /* We assume that sys_hz() caches its return value. */
+               micro_delta = ((now - s->s_base_uptime) * 1000 / sys_hz()) *
+                       1000;
+
+               if (micro_delta >= s->s_usecs) {
+                       s->s_timeout = TRUE;
+                       return FALSE;
+               }
+
+               break;
+
+       default:
+               panic("spin_check: invalid state %d", s->s_state);
+       }
+
+       return TRUE;
+}
index 045d079cb61e66dab832bdce0f3fc202dc636ac2..4f973e9a16cc6f43bc832ee197c4c107782b4a9a 100644 (file)
 #define MICROHZ                1000000         /* number of micros per second */
 #define MICROSPERTICK(h)       (MICROHZ/(h))   /* number of micros per HZ tick */
 
-static u32_t calib_mhz = 1000, Hz = 1000;
-
-int
-micro_delay(u32_t micros)
-{
-       return OK;
-}
+static u32_t calib_hz = 600000000;
 
 u32_t tsc_64_to_micros(u64_t tsc)
 {
        u64_t tmp;
 
-       tmp = div64u64(tsc, calib_mhz);
-       if (ex64hi(tmp)) {
-               printf("tsc_64_to_micros: more than 2^32ms\n");
-               return ~0UL;
-       } else {
-               return ex64lo(tmp);
-       }
+       tmp =  tsc / calib_hz;
+       return (u32_t) tmp;
 }
 
 u32_t tsc_to_micros(u32_t low, u32_t high)