/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2008 Rafaël Carré * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #ifndef SYSTEM_TARGET_H #define SYSTEM_TARGET_H #include "system-arm.h" #include "mmu-arm.h" #include "panic.h" #include "clock-target.h" /* CPUFREQ_* are defined here */ /* We can use a interrupt-based mechanism on the fuzev2 */ #define INCREASED_SCROLLWHEEL_POLLING \ (defined(HAVE_SCROLLWHEEL) && (CONFIG_CPU == AS3525)) #if INCREASED_SCROLLWHEEL_POLLING /* let the timer interrupt twice as often for the scrollwheel polling */ #define KERNEL_TIMER_FREQ (TIMER_FREQ/2) #else #define KERNEL_TIMER_FREQ TIMER_FREQ #endif #ifdef BOOTLOADER #define UNCACHED_ADDR(a) (a) #else #define UNCACHED_ADDR(a) ((typeof(a)) ((uintptr_t)(a) + 0x10000000)) #endif #ifdef SANSA_C200V2 /* 0: Backlight on A5, 1: Backlight on A7 */ extern int c200v2_variant; /* c200v2 changes the timer interval often due to software pwm */ #define TIMER_PERIOD TIMER2_BGLOAD #else #define TIMER_PERIOD (KERNEL_TIMER_FREQ/HZ) #endif /* * This function is not overly accurate, so rather call it with an usec more * than less (see below comment) * * if inlined it expands to a really small and fast function if it's called * with compile time constants */ static inline void udelay(unsigned usecs) __attribute__((always_inline)); static inline void udelay(unsigned usecs) { unsigned now; int end; /** * we're limited to 0.666us multiplies due to the odd timer frequency (1.5MHz), * to avoid calculating which is safer (need to round up for small values) * and saves spending time in the divider we have a lut for * small us values, it should be roughly us*3/2 **/ static const unsigned char udelay_lut[] = { 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, 24, 26, 27, 29, }; now = TIMER2_VALUE; /* we don't want to handle multiple overflows, so limit the numbers * (if you want to wait more than a tick just poll current_tick, or * call sleep()) */ if (UNLIKELY(usecs >= (TIMER_PERIOD*2/3))) panicf("%s(): %d too high!", __func__, usecs); if (UNLIKELY(usecs <= 0)) return; if (usecs < ARRAYLEN(udelay_lut)) { /* the timer decrements */ end = now - udelay_lut[usecs]; } else { /* to usecs */ int delay = usecs * 3 / 2; /* us * 0.666 = us*timer_period */ end = now - delay; } unsigned old; /* underrun ? */ if (end < 0) { do { old = now; now = TIMER2_VALUE; } while(now <= old); /* if the new value is higher then we wrapped */ end += TIMER_PERIOD; } do { /* if timer wraps then we missed our end value */ old = now; now = TIMER2_VALUE; } while(now > (unsigned)end && now <= old); } #endif /* SYSTEM_TARGET_H */