diff options
author | Alexandru Gagniuc <mr.nuke.me@gmail.com> | 2013-12-31 00:17:19 -0500 |
---|---|---|
committer | Alexandru Gagniuc <mr.nuke.me@gmail.com> | 2014-01-09 01:02:47 +0100 |
commit | bd09dbe3300eca302b84a8fe64cb302889089ab2 (patch) | |
tree | e3365a8dced52e265a8ca3004e33878e88ebda03 | |
parent | b70a140bd02ef5320c094f555b42dc1875dab2d5 (diff) |
cpu/allwinner/a10: Implement udelay using timer 0
Change-Id: I4825f0d57696cd28751c59ae133b7e3315fb78e5
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Reviewed-on: http://review.coreboot.org/4595
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: David Hendricks <dhendrix@chromium.org>
-rw-r--r-- | src/cpu/allwinner/a10/Kconfig | 1 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/timer.c | 42 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/timer.h | 90 |
3 files changed, 130 insertions, 3 deletions
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 <mr.nuke.me@gmail.com> * Subject to the GNU GPL v2, or (at your option) any later version. */ +#include "timer.h" + +#include <arch/io.h> #include <delay.h> #include <timer.h> +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 <tangliang@allwinnertech.com> + * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> + * 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 <types.h> + +/* 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 */ |