as3525v2: fix udelay()
[kugel-rb.git] / firmware / target / arm / as3525 / system-target.h
blobee46e7c7a591fb21e00432ad14a2d8b936d2d50b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Rafaël Carré
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #ifndef SYSTEM_TARGET_H
22 #define SYSTEM_TARGET_H
24 #include "system-arm.h"
25 #include "mmu-arm.h"
26 #include "panic.h"
28 #include "clock-target.h" /* CPUFREQ_* are defined here */
30 /* We can use a interrupt-based mechanism on the fuzev2 */
31 #define INCREASED_SCROLLWHEEL_POLLING \
32 (defined(HAVE_SCROLLWHEEL) && (CONFIG_CPU == AS3525))
34 #if INCREASED_SCROLLWHEEL_POLLING
35 /* let the timer interrupt twice as often for the scrollwheel polling */
36 #define KERNEL_TIMER_FREQ (TIMER_FREQ/2)
37 #else
38 #define KERNEL_TIMER_FREQ TIMER_FREQ
39 #endif
41 #ifdef BOOTLOADER
42 #define UNCACHED_ADDR(a) (a)
43 #else
44 #define UNCACHED_ADDR(a) ((typeof(a)) ((uintptr_t)(a) + 0x10000000))
45 #endif
47 #ifdef SANSA_C200V2
48 /* 0: Backlight on A5, 1: Backlight on A7 */
49 extern int c200v2_variant;
50 /* c200v2 changes the timer interval often due to software pwm */
51 #define TIMER_PERIOD TIMER2_BGLOAD
52 #else
53 #define TIMER_PERIOD (KERNEL_TIMER_FREQ/HZ)
54 #endif
57 * This function is not overly accurate, so rather call it with an usec more
58 * than less (see below comment)
60 * if inlined it expands to a really small and fast function if it's called
61 * with compile time constants */
62 static inline void udelay(unsigned usecs) __attribute__((always_inline));
63 static inline void udelay(unsigned usecs)
65 unsigned now;
66 int end;
68 /**
69 * we're limited to 1.5us multiplies due to the odd timer frequency (1.5MHz),
70 * to avoid calculating which is safer (need to round up for small values)
71 * and saves spending time in the divider we have a lut for
72 * small us values, it should be roughly us*2/3
73 **/
74 static const unsigned char udelay_lut[] =
76 0, 1, 2, 2, 3, 4, 4, 5, 6, 6,
77 7, 8, 8, 9, 10, 10, 11, 12, 12, 13,
81 now = TIMER2_VALUE;
82 /* we don't want to handle multiple overflows, so limit the numbers
83 * (if you want to wait more than a tick just poll current_tick, or
84 * call sleep()) */
85 if (UNLIKELY(usecs >= TIMER_PERIOD))
86 panicf("%s(): %d too high!", __func__, usecs);
87 if (UNLIKELY(usecs <= 0))
88 return;
89 if (usecs < ARRAYLEN(udelay_lut))
90 { /* the timer decrements */
91 end = now - udelay_lut[usecs];
93 else
94 { /* to usecs */
95 int delay = usecs * 2 / 3; /* us * 1.5 = us*timer_period */
96 end = now - delay;
99 unsigned old;
101 /* underrun ? */
102 if (end < 0)
104 do {
105 old = now;
106 now = TIMER2_VALUE;
107 } while(now <= old); /* if the new value is higher then we wrapped */
109 end += TIMER_PERIOD;
112 do {
113 /* if timer wraps then we missed our end value */
114 old = now;
115 now = TIMER2_VALUE;
116 } while(now > (unsigned)end && now <= old);
118 #endif /* SYSTEM_TARGET_H */