The (new) U-Boot Timer API

The 'Old' API

Overview

U-Boot currently has a timer API consisting of the following functions:

void udelay(u32 usec)

Delays execution foy 'usec' microseconds

Intended for sub-second delays

u32 get_timer(u32 base)

Returns the number of milliseconds since the epoch 'base'

u32 set_timer(u32 msec)

Sets the internal millisecond timer to a value of 'msec'

get_timer(msec) called immediately after set_timer(msec) returns 0 (assuming the internal timer has not 'ticked' between the two calls)

void reset_timer()

Sets the internal millisecond timer to a value of 0

On some platforms (Nios2 in particular), the low-level timer is also reset resulting in subsequent calls to get_timer(0) that are guaranteed to return at most the number of milliseconds elapsed since reset_timer()

Problems and Limitations

The time base for the API is not clearly defined. It is assumed to be milliseconds, but not all platforms are known to guarantee this. The issue is further confounded by CONFIG_SYS_HZ

Use of set_timer() and reset_timer() prohibit mult-level timing loops. If an inner timing loop uses set_timer() or reset_timer(), the outer timing loop will be impacted - This particularly prohibits timing of operations involving the CFI Flash driver

Many implementations of udelay() call reset_timer() which can break timeout loops which invoke udelay()

For ARM, [get,set,reset]_timer() are mostly thin wrappers around the platform specific [get,set,reset]_timer_masked() - This in itself is not a problem, however there is platform independent code in /drivers/ which call the [get,set,reset]_timer_masked() functions directly

A lot of code duplication exists (particularly in arch/arm/)

Lots of other nigglies at the platform specific level

The 'New' API Proposal

At the core of the new API is two user-level functions per defined time
base:

u32 time_<time base>_now() returns the current number of 'time base' 'ticks' that have elapsed since the timer subsystem was initialised

u32 time_<time base>_delta(u32 from, u32 to, u8 delta_type) returns the number of 'time base' 'ticks' between 'from' and 'to' taking into account the limitations of the platforms available resolution of 'time base'

Three 'time bases' are initially proposed:

ms - milliseconds

us - microseconds

ticks - raw ticks

User API (/lib/timer.c)

u32 time_ms_now(void)

Returns the current value of the millisecond timer

u32 time_ms_delta(u32 from, u32 to, u8 delta_type)

Returns the time difference, in milliseconds, between two arbitrary millisecond times

Maximum delta is ~49 days

Utilizes weak function u32 time_ms_resolution(void) (defaults to 1)

delta_type is one of:

TIME_DELTA_RAW - Returns the raw number of milliseconds between 'from' and 'to'

TIME_DELTA_MAX - Returns the maximum number of milliseconds between 'from' and 'to'

TIME_DELTA_MIN - Returns the minimum number of milliseconds between 'from' and 'to'

A Note about Accuracy and 'Recursion'

The U-Boot Timer API make no guarantees regarding accuracy - It is provided as a means of performing operations that are known to require a minimum amount of time (hardware timeouts such as Flash operations in particular). Platform implementors must ensure that for any two calls to time_ms_now(), AT LEAST x milliseconds pass (in real time) where 'x' is the difference in the return value of the two calls - It is acceptable for the underlying hardware timer to run slow, but not fast.

Any further accuracy guarantees are highly platform specific. Individual platform implementors are free to document accuracy claims, but this is by no means a requirement.

Another important aspect of the Timer API is the ability to run timing loops inside other timing loops (recursive timing)