diff options
author | Julius Werner <jwerner@chromium.org> | 2018-11-02 14:48:24 -0700 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2018-11-07 06:17:37 +0000 |
commit | 5132570845443767539fc00b502f6eafbfa37ba2 (patch) | |
tree | 5955e1e6a9a69df23e81b70c264c30a44d1e86dc | |
parent | 55a972236ee93d36bd3df4e8e5680ba447242bd7 (diff) | |
download | coreboot-5132570845443767539fc00b502f6eafbfa37ba2.tar.xz |
timer: Add wait_us/wait_ms helper macros to wait for conditions
A very common pattern in drivers is that we need to wait for a condition
to become true (e.g. for a lock bit in a PLL status register to become
set), but we still want to have a maximum timeout before we treat it as
an error. coreboot uses the stopwatch API for this, but it's still a
little verbose for the most simple cases. This patch introduces two new
helper macros that wrap this common application of the stopwatch API in
a single line: wait_ms(XXX, YYY) waits for up to XXX milliseconds to see
if the C condition 'if (YYY)' becomes true. The return value is 0 on
failure (i.e. timeout expires without the condition becoming true) and
the amount of elapsed time on success, so it can be used both in a
boolean context and to log the amount of time waited.
Replace the custom version used in an MTK ADC driver with this new
generic version.
Change-Id: I6de38ee00673c46332ae92b8a11099485de5327a
Signed-off-by: Tristan Shieh <tristan.shieh@mediatek.com>
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/29315
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
-rw-r--r-- | src/include/timer.h | 34 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/auxadc.c | 22 |
2 files changed, 37 insertions, 19 deletions
diff --git a/src/include/timer.h b/src/include/timer.h index 49eae5ec40..d3afb19646 100644 --- a/src/include/timer.h +++ b/src/include/timer.h @@ -15,6 +15,8 @@ #ifndef TIMER_H #define TIMER_H +#include <types.h> + #define NSECS_PER_SEC 1000000000 #define USECS_PER_SEC 1000000 #define MSECS_PER_SEC 1000 @@ -195,4 +197,36 @@ static inline long stopwatch_duration_msecs(struct stopwatch *sw) return stopwatch_duration_usecs(sw) / USECS_PER_MSEC; } +/* + * Helper macro to wait until a condition becomes true or a timeout elapses. + * + * condition: a C expression to wait for + * timeout: timeout, in microseconds + * + * Returns: + * 0 if the condition still evaluates to false after the timeout elapsed, + * >0 if the condition evaluates to true. The return value is the amount of + * microseconds waited (at least 1). + */ +#define wait_us(timeout_us, condition) \ +({ \ + long __ret = 0; \ + struct stopwatch __sw; \ + stopwatch_init_usecs_expire(&__sw, timeout_us); \ + do { \ + if (condition) { \ + stopwatch_tick(&__sw); \ + __ret = stopwatch_duration_usecs(&__sw); \ + if (!__ret) /* make sure it evaluates to true */\ + __ret = 1; \ + break; \ + } \ + } while (!stopwatch_expired(&__sw)); \ + __ret; \ +}) + +#define wait_ms(timeout_ms, condition) \ + DIV_ROUND_UP(wait_us((timeout_ms) * USECS_PER_MSEC, condition), \ + USECS_PER_MSEC) + #endif /* TIMER_H */ diff --git a/src/soc/mediatek/mt8183/auxadc.c b/src/soc/mediatek/mt8183/auxadc.c index af88efb3b9..87574ba791 100644 --- a/src/soc/mediatek/mt8183/auxadc.c +++ b/src/soc/mediatek/mt8183/auxadc.c @@ -24,33 +24,17 @@ static struct mtk_auxadc_regs *const mtk_auxadc = (void *)AUXADC_BASE; -/* - * Wait until a condition becomes true or times out - * - * cond : a C expression to wait for - * timeout : msecs - */ -#define wait_ms(cond, timeout) \ -({ \ - struct stopwatch sw; \ - int expired = 0; \ - stopwatch_init_msecs_expire(&sw, timeout); \ - while (!(cond) && !(expired = stopwatch_expired(&sw))) \ - ; /* wait */ \ - assert(!expired); \ -}) - static uint32_t auxadc_get_rawdata(int channel) { setbits_le32(&mt8183_infracfg->module_sw_cg_1_clr, 1 << 10); - wait_ms(!(read32(&mtk_auxadc->con2) & 0x1), 300); + assert(wait_ms(300, !(read32(&mtk_auxadc->con2) & 0x1))); clrbits_le32(&mtk_auxadc->con1, 1 << channel); - wait_ms(!(read32(&mtk_auxadc->data[channel]) & (1 << 12)), 300); + assert(wait_ms(300, !(read32(&mtk_auxadc->data[channel]) & (1 << 12)))); setbits_le32(&mtk_auxadc->con1, 1 << channel); udelay(25); - wait_ms(read32(&mtk_auxadc->data[channel]) & (1 << 12), 300); + assert(wait_ms(300, read32(&mtk_auxadc->data[channel]) & (1 << 12))); uint32_t value = read32(&mtk_auxadc->data[channel]) & 0x0FFF; |