On 5/26/2011 6:27 AM, Graeme Russ wrote: > Hello Everyone, > > OK - Starting a new thread to discuss implementation details. This is a > heads-up for arch/platform maintainers - Once this is a bit more stable, I > will put it on the wiki > > Assumed Capabilities of the Platform > - Has a 'tick counter' that does not rely on software to increment Hi All, The nios2 with the most basic timer does not meet this requirement. It will not count at all without the 10 ms interrupt. I don't think this requirement matters anyway. We need a 'tick counter' that 'ticks'. If it takes software to make it tick, we don't much care. There may be problems with early use of udelay in that case, but that is a different issue. > - tick interval may by a fixed constant which cannot be controlled > via software, or it could be programmable (PIT) > > API Functions (/lib/timer.c) > - u32 get_timer(u32 start) > - Returns the number of elapsed milliseconds since 'start' > > API Functions (/arch/...) > - void udelay(u32 delay) > - Used for 'short' delays (generally up to several seconds) > - Can use the tick counter if it is fast enough > - MUST NOT RESET THE TICK COUNTER There is a requirement that udelay be available before relocation and before the BSS is available. One can use the tick counter to provide udelay as long as sync_timebase is not called OR sync timebase does not use BSS. It appears many implementations ignore this requirement at present. We should try to fix this, but is should not be a requirement. > 'Helper' Functions (/lib/timer.c) I think this function should be weak, so that it is possible for people to override it with a "custom" function. The fully general sync_timebase has lots of code in it that can be simplified in special cases. We want and need a fully general function to be available, but other users who are real tight on space may want a cut down version. We should make that easily possible. > - void sync_timebase(void) > - Updates the millisecond timer > - Utilises HAL functions to access the platform's tick counter > - Must be called more often than the rollover period of the > platform's tick counter > - Does not need to be called with a regular frequency (immune > to interrupt skew) > - Is always called by get_timer() > - For platforms with short tick counter rollovers it should > be called by an ISR > - Bill Campbell wrote a good example which proved this can be common > and arbitrary (and optionally free of divides and capable of > maintaining accuracy even if the tick frequency is not an even > division of 1ms) > > HAL Functions (/arch/... or /board/...) > - u64 get_ticks(void) For what it's worth, I would like to propose using a (gasp!) typedef here. It seems to me there are a whole lot of cases where the max number of ticks is a u32 or less. In those cases, the wrap at 32 bits helps things a lot. If the tick counter is really 64 bits, the function of sync_timebase is simply to convert the tick value to millisec, and that is it. Otherwise, if it is 32 bits or less then some other actions will be required. I think this is one of those times where a typedef would help, We could define a type called timer_tick_t to describe this quantity. That would allow a pure 32 bit implementation where appropriate.
Another suggestion is that perhaps we want a u32 get_ticks_lsb(void) as well as a regular get_ticks. The lsb version would be used for udelay and could possibly come from another timer if that was necessary/desirable. See the requirement for early udelay early availability. > - Returns a tick count as an unsigned 64-bit integer > - Abstracts the implementation of the platform tick counter > (platform may by 32-bit 3MHz counter, might be a 16-bit > 0-999 microsecond plus 16-bit 0-65535 millisecond etc) > - u64 ticks_per_millisecond() > - Returns the number of ticks (as returned by get_ticks()) per > millisecond I think ticks_per_sec would be a better choice. First, such a function already exists in almost all u-boots. Second, if one wants the best accuracy for things like udelay, you need better accuracy than millisec. Since this function is used only infrequently, when things are initialized, a divide to get ticks_per_millsec (if that is what you really want) is no big deal. Lastly, I think this function can remain u32. Yes, there is a 4 GHz limit on the clock rate. If this ever becomes an issue, we can change the type to timer_tick_t. When the CPU clock rate gets quite high, it is an advantage to divide it down for performance measurement anyway. The AMD/Intel chips already do this. If the hardware doesn't do it, shift the timer value right two bits. I doubt you will miss the 0.4 nanoseconds resolution loss from your 10 GHz timestamp. > - void timer_isr() > - Optional (particularly if tick counter rollover period is > exceptionally log which is usually the case for native 64-bit tick > counters) > - Simply calls sync_timebase() > - For platforms without any tick counter, this can implement one > (but accuracy will be harmed due to usage of disable_interrupts() and > enable_interrupts() in U-Boot > > So to get the new API up and running, only two functions are mandatory: > > get_ticks() which reads the hardware tick counter and deals with any 'funny > stuff' including rollovers, short timers (12-bit for example), composite > counters (16-bit 0-999 microsecond + 16-bit millisecond) and maintains a > 'clean' 64-bit tick counter which rolls over from all 1's to all 0's. The I think it is the task of get_ticks to return the hardware tick counter as an increasing counter, period. The counter may wrap at some final count that is not all ones. That is ok. Sync_timebase deals with the rollovers if necessary. get_ticks is very lightweight. get_ticks should deal with decrementing counters by returning the complement of the counter. The sc520 case is a bit more complex if you intend to use the 0-999 and 16 bit millisec registers, in that you do need to add them to the previous value to make an increasing counter. Sync_timebase "likes" short counters in that they are easy to convert to millisec and tick remainders. > 64-bit tick counter does not need to be reset to zero ever (even on startup > - sync_timebase tacks care of all the details) True, but sync_timebase does have to be initialized (as does the timer itself in most cases, so this is not a restriction). > ticks_per_millisecond() simply return the number of ticks in a millisecond > - This may as simple as: > > inline u64 ticks_per_millisecond(void) > { > return CONFIG_SYS_TICK_PER_MS; > } > > But it may be trickier if you have a programmable tick frequency You will have to call the routine that initializes sync_timebase. This routine should have a name, like void init_sync_timebase(void)? > The optional timer ISR is required if the tick counter has a short roll > over duration (short is up to you - 1 second is short, 1 hour might be, 1 > century is not) > > Regards, > > Graeme > It is probably true that sync_timebase should have a parameter flag. The reason is that if the timer isr is called only when the timer wraps, then the calls to sync_timebase may be slightly more than a full timer period apart. (due to interrupt latency). Therefore, when the timer difference is computed, if the current update is due to a wrap AND the previous update is due to a wrap, the difference should be approximately 1 wrap. If it comes up real short, you must add a wrap. This isn't necessary if the routine is called more often than once per wrap. Also, when sync_timebase is called in get_timer, you must first disable interrupts and then enable interrupts after sync_timebase returns Best Regards, Bill Campbell _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot