soc/ti/am335x: Fix timer implementation
Implements the monotonic timer using the am335x dmtimer peripheral. Change-Id: I4736b6d3b6e26370be9e8f369fc02285ad519223 Signed-off-by: Sam Lewis <sam.vr.lewis@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/44383 Reviewed-by: Arthur Heymans <arthur@aheymans.xyz> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
b5353965e1
commit
fde084bc49
|
@ -1,18 +1,15 @@
|
||||||
ifeq ($(CONFIG_SOC_TI_AM335X),y)
|
ifeq ($(CONFIG_SOC_TI_AM335X),y)
|
||||||
bootblock-y += bootblock.c
|
bootblock-y += bootblock.c
|
||||||
bootblock-y += bootblock_media.c
|
bootblock-y += bootblock_media.c
|
||||||
bootblock-y += dmtimer.c
|
bootblock-y += timer.c
|
||||||
bootblock-y += gpio.c
|
bootblock-y += gpio.c
|
||||||
bootblock-y += pinmux.c
|
bootblock-y += pinmux.c
|
||||||
bootblock-y += monotonic_timer.c
|
|
||||||
|
|
||||||
romstage-y += nand.c
|
romstage-y += nand.c
|
||||||
romstage-y += cbmem.c
|
romstage-y += cbmem.c
|
||||||
romstage-y += dmtimer.c
|
romstage-y += timer.c
|
||||||
romstage-y += monotonic_timer.c
|
|
||||||
|
|
||||||
ramstage-y += dmtimer.c
|
ramstage-y += timer.c
|
||||||
ramstage-y += monotonic_timer.c
|
|
||||||
ramstage-y += nand.c
|
ramstage-y += nand.c
|
||||||
ramstage-y += soc.c
|
ramstage-y += soc.c
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
||||||
|
|
||||||
#include "dmtimer.h"
|
|
||||||
|
|
||||||
void dmtimer_start(int num)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t dmtimer_raw_value(int num)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -5,9 +5,33 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define OSC_HZ 24000000
|
#define M_OSC_MHZ (24)
|
||||||
|
|
||||||
void dmtimer_start(int num);
|
struct am335x_dmtimer {
|
||||||
uint64_t dmtimer_raw_value(int num);
|
uint32_t tidr;
|
||||||
|
uint8_t res1[12];
|
||||||
|
uint32_t tiocp_cfg;
|
||||||
|
uint8_t res2[12];
|
||||||
|
uint32_t irq_eoi;
|
||||||
|
uint32_t irqstatus_raw;
|
||||||
|
uint32_t irqstatus;
|
||||||
|
uint32_t irqenable_set;
|
||||||
|
uint32_t irqenable_clr;
|
||||||
|
uint32_t irqwakeen;
|
||||||
|
uint32_t tclr;
|
||||||
|
uint32_t tcrr;
|
||||||
|
uint32_t tldr;
|
||||||
|
uint32_t ttgr;
|
||||||
|
uint32_t twps;
|
||||||
|
uint32_t tmar;
|
||||||
|
uint32_t tcar1;
|
||||||
|
uint32_t tsicr;
|
||||||
|
uint32_t tcar2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TCLR_ST (0x01 << 0)
|
||||||
|
#define TCLR_AR (0x01 << 1)
|
||||||
|
|
||||||
|
#define DMTIMER_2 (0x48040000)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <delay.h>
|
|
||||||
#include <timer.h>
|
|
||||||
|
|
||||||
#include "dmtimer.h"
|
|
||||||
|
|
||||||
static struct monotonic_counter {
|
|
||||||
int initialized;
|
|
||||||
struct mono_time time;
|
|
||||||
uint64_t last_value;
|
|
||||||
} mono_counter;
|
|
||||||
|
|
||||||
static const uint32_t clocks_per_usec = OSC_HZ/1000000;
|
|
||||||
|
|
||||||
void timer_monotonic_get(struct mono_time *mt)
|
|
||||||
{
|
|
||||||
uint64_t current_tick;
|
|
||||||
uint64_t usecs_elapsed;
|
|
||||||
|
|
||||||
if (!mono_counter.initialized) {
|
|
||||||
init_timer();
|
|
||||||
mono_counter.last_value = dmtimer_raw_value(0);
|
|
||||||
mono_counter.initialized = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_tick = dmtimer_raw_value(0);
|
|
||||||
usecs_elapsed = (current_tick - mono_counter.last_value) /
|
|
||||||
clocks_per_usec;
|
|
||||||
|
|
||||||
/* Update current time and tick values only if a full tick occurred. */
|
|
||||||
if (usecs_elapsed) {
|
|
||||||
mono_time_add_usecs(&mono_counter.time, usecs_elapsed);
|
|
||||||
mono_counter.last_value = current_tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save result. */
|
|
||||||
*mt = mono_counter.time;
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#include <timer.h>
|
||||||
|
#include <delay.h>
|
||||||
|
#include <device/mmio.h>
|
||||||
|
|
||||||
|
#include "dmtimer.h"
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
|
struct am335x_dmtimer *dmtimer_2 = (struct am335x_dmtimer *)DMTIMER_2;
|
||||||
|
|
||||||
|
#define CLKSEL_M_OSC (0x01 << 0)
|
||||||
|
|
||||||
|
static uint32_t timer_raw_value(void)
|
||||||
|
{
|
||||||
|
return read32(&dmtimer_2->tcrr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_monotonic_get(struct mono_time *mt)
|
||||||
|
{
|
||||||
|
mono_time_set_usecs(mt, timer_raw_value() / M_OSC_MHZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_timer(void)
|
||||||
|
{
|
||||||
|
write32(&am335x_cm_dpll->clksel_timer2_clk, CLKSEL_M_OSC);
|
||||||
|
|
||||||
|
// Start the dmtimer in autoreload mode without any prescalers
|
||||||
|
// With M_OSC at 24MHz, this gives a few minutes before the timer overflows
|
||||||
|
write32(&dmtimer_2->tclr, TCLR_ST | TCLR_AR);
|
||||||
|
}
|
Loading…
Reference in New Issue