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);
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;
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;
#include "arch_proto.h"
#include "kernel/proto.h"
#include "kernel/debug.h"
+#include "omap_timer.h"
phys_bytes device_mem_vaddr = 0;
}
static int device_mem_mapping_index = -1,
+ frclock_index = -1,
usermapped_glo_index = -1,
usermapped_index = -1, first_um_idx = -1;
(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++;
}
*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;
}
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)
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;
}
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;
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
#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);
--- /dev/null
+#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 */
(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++;
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)
.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}/
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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;
+}
#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)