From bd09dbe3300eca302b84a8fe64cb302889089ab2 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Tue, 31 Dec 2013 00:17:19 -0500 Subject: [PATCH] cpu/allwinner/a10: Implement udelay using timer 0 Change-Id: I4825f0d57696cd28751c59ae133b7e3315fb78e5 Signed-off-by: Alexandru Gagniuc Reviewed-on: http://review.coreboot.org/4595 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel Reviewed-by: David Hendricks --- src/cpu/allwinner/a10/Kconfig | 1 + src/cpu/allwinner/a10/timer.c | 42 ++++++++++++++-- src/cpu/allwinner/a10/timer.h | 90 +++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 src/cpu/allwinner/a10/timer.h diff --git a/src/cpu/allwinner/a10/Kconfig b/src/cpu/allwinner/a10/Kconfig index 3df1cebdfc..b782b9a92e 100644 --- a/src/cpu/allwinner/a10/Kconfig +++ b/src/cpu/allwinner/a10/Kconfig @@ -6,6 +6,7 @@ if CPU_ALLWINNER_A10 config CPU_SPECIFIC_OPTIONS def_bool y + select HAVE_INIT_TIMER select HAVE_MONOTONIC_TIMER select HAVE_UART_SPECIAL select HAVE_UART_MEMORY_MAPPED diff --git a/src/cpu/allwinner/a10/timer.c b/src/cpu/allwinner/a10/timer.c index e156398be3..60cc60c4d1 100644 --- a/src/cpu/allwinner/a10/timer.c +++ b/src/cpu/allwinner/a10/timer.c @@ -1,19 +1,55 @@ /* - * Placeholder for code to come(needed to complete build) + * Timer control and delays for Allwinner CPUs * * Copyright (C) 2013 Alexandru Gagniuc * Subject to the GNU GPL v2, or (at your option) any later version. */ +#include "timer.h" + +#include #include #include +struct a1x_timer *const tmr0 = + &((struct a1x_timer_module *)A1X_TIMER_BASE)->timer[0]; + +static inline u32 read_timer(void) +{ + return read32(&tmr0->val); +} + void init_timer(void) { - /* Stub */ + u32 reg32; + /* Load the timer rollover value */ + write32(0xffffffff, &tmr0->interval); + /* Configure the timer to run from 24MHz oscillator, no prescaler */ + reg32 = TIMER_CTRL_PRESC_DIV_EXP(0); + reg32 |= TIMER_CTRL_CLK_SRC_OSC24M; + reg32 |= TIMER_CTRL_RELOAD; + reg32 |= TIMER_CTRL_TMR_EN; + write32(reg32, &tmr0->ctrl); } void udelay(unsigned usec) { - /* Stub */ + u32 curr_tick, last_tick; + s32 ticks_left; + + last_tick = read_timer(); + /* 24 timer ticks per microsecond (24 MHz, divided by 1) */ + ticks_left = usec * 24; + + /* FIXME: Should we consider timer rollover? + * From when we start the timer, we have almost three minutes before it + * rolls over, so we should be long into having booted our payload. + */ + while (ticks_left > 0) { + curr_tick = read_timer(); + /* Timer value decreases with each tick */ + ticks_left -= last_tick - curr_tick; + last_tick = curr_tick; + } + } diff --git a/src/cpu/allwinner/a10/timer.h b/src/cpu/allwinner/a10/timer.h new file mode 100644 index 0000000000..9c0c0d158d --- /dev/null +++ b/src/cpu/allwinner/a10/timer.h @@ -0,0 +1,90 @@ +/* + * Definitions for timer control on Allwinner CPUs + * + * Copyright (C) 2007-2011 Allwinner Technology Co., Ltd. + * Tom Cubie + * Copyright (C) 2013 Alexandru Gagniuc + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#ifndef CPU_ALLWINNER_A10_TIMER_H +#define CPU_ALLWINNER_A10_TIMER_H + +#include "memmap.h" +#include + +/* TMRx_CTRL values */ +#define TIMER_CTRL_MODE_SINGLE (1 << 7) +#define TIMER_CTRL_PRESC_MASK (0x7 << 4) +#define TIMER_CTRL_PRESC_DIV_EXP(ep) ((ep << 4) & TIMER_CTRL_PRESC_MASK) +#define TIMER_CTRL_CLK_SRC_MASK (0x3 << 2) +#define TIMER_CTRL_CLK_SRC_LOSC (0x0 << 2) +#define TIMER_CTRL_CLK_SRC_OSC24M (0x1 << 2) +#define TIMER_CTRL_CLK_SRC_PLL6 (0x2 << 2) +#define TIMER_CTRL_RELOAD (1 << 1) +#define TIMER_CTRL_TMR_EN (1 << 0) + +/* General purpose timer */ +struct a1x_timer { + u32 ctrl; + u32 interval; + u32 val; + u8 res[4]; +} __attribute__ ((packed)); + +/* Audio video sync*/ +struct a1x_avs { + u32 ctrl; /* 0x80 */ + u32 cnt0; /* 0x84 */ + u32 cnt1; /* 0x88 */ + u32 div; /* 0x8c */ +} __attribute__ ((packed)); + +/* Watchdog */ +struct a1x_wdog { + u32 ctrl; /* 0x90 */ + u32 mode; /* 0x94 */ +} __attribute__ ((packed)); + +/* 64 bit counter */ +struct a1x_64cnt { + u32 ctrl; /* 0xa0 */ + u32 lo; /* 0xa4 */ + u32 hi; /* 0xa8 */ +} __attribute__ ((packed)); + +/* Rtc */ +struct a1x_rtc { + u32 ctrl; /* 0x100 */ + u32 yymmdd; /* 0x104 */ + u32 hhmmss; /* 0x108 */ +} __attribute__ ((packed)); + +/* Alarm */ +struct a1x_alarm { + u32 ddhhmmss; /* 0x10c */ + u32 hhmmss; /* 0x110 */ + u32 en; /* 0x114 */ + u32 irq_en; /* 0x118 */ + u32 irq_sta; /* 0x11c */ +} __attribute__ ((packed)); + +struct a1x_timer_module { + u32 irq_en; /* 0x00 */ + u32 irq_sta; /* 0x04 */ + u8 res1[8]; + struct a1x_timer timer[6]; /* We have 6 timers */ + u8 res2[16]; + struct a1x_avs avs; + struct a1x_wdog wdog; + u8 res3[8]; + struct a1x_64cnt cnt64; + u8 res4[0x58]; + struct a1x_rtc rtc; + struct a1x_alarm alarm; + u32 gp_data[4]; + u8 res5[8]; + u32 cpu_cfg; +} __attribute__ ((packed)); + +#endif /* CPU_ALLWINNER_A10_TIMER_H */