mediatek: Use the 64-bit timer

GPT4 is a 32-bit timer and the counter of GPT4 will overflow in about
330 seconds (0xffffffff / 13MHz). Timer and delay functions will not
work properly if the counter overflows. To fix that we should use the
64-bit timer (GPT6).

BUG=b:80501386
BRANCH=none
Test=emerge-elm coreboot; emerge-kukui coreboot

Change-Id: I9f080e47253a1b1bab4636a45cb86c8666a25302
Signed-off-by: Tristan Shieh <tristan.shieh@mediatek.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/32245
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Reviewed-by: You-Cheng Syu <youcheng@google.com>
This commit is contained in:
Tristan Shieh 2019-04-08 11:01:40 +08:00 committed by Julius Werner
parent 250dfc0256
commit a76e6542d1
4 changed files with 35 additions and 18 deletions

View File

@ -54,7 +54,7 @@ config TIMER_IMG_PISTACHIO
bool "Timer for IMG Pistachio"
config TIMER_MTK
bool "Timer for MediaTek MT8173"
bool "Timer for MediaTek"
endchoice
@ -77,7 +77,7 @@ config TIMER_GENERIC_REG
default 0x004A2000 if TIMER_IPQ40XX
default 0x0200A028 if TIMER_IPQ806X
default 0x101C0100 if TIMER_MCT
default 0x10008048 if TIMER_MTK
default 0x10008068 if TIMER_MTK
default 0xff810028 if TIMER_RK3288
default 0xff850008 if TIMER_RK3399
default 0x60005010 if TIMER_TEGRA_1US
@ -89,6 +89,7 @@ config TIMER_GENERIC_HIGH_REG
hex "Generic Timer High Register Address"
default 0x004A2004 if TIMER_IPQ40XX
default 0x101C0104 if TIMER_MCT
default 0x10008078 if TIMER_MTK
default 0xff81002C if TIMER_RK3288
default 0xff85000C if TIMER_RK3399
default 0x0

View File

@ -19,18 +19,21 @@
#include <soc/addressmap.h>
#include <types.h>
#define GPT4_MHZ 13
#define GPT_MHZ 13
struct mtk_gpt_regs {
u32 reserved[16];
u32 gpt4_con;
u32 gpt4_clk;
u32 gpt4_cnt;
u32 reserved1[24];
u32 gpt6_con;
u32 gpt6_clk;
u32 gpt6_cnt_l;
u32 reserved2[3];
u32 gpt6_cnt_h;
};
check_member(mtk_gpt_regs, gpt4_con, 0x0040);
check_member(mtk_gpt_regs, gpt4_clk, 0x0044);
check_member(mtk_gpt_regs, gpt4_cnt, 0x0048);
check_member(mtk_gpt_regs, gpt6_con, 0x0060);
check_member(mtk_gpt_regs, gpt6_clk, 0x0064);
check_member(mtk_gpt_regs, gpt6_cnt_l, 0x0068);
check_member(mtk_gpt_regs, gpt6_cnt_h, 0x0078);
enum {
GPT_CON_EN = 0x01,

View File

@ -25,21 +25,34 @@ static struct mtk_gpt_regs *const mtk_gpt = (void *)GPT_BASE;
__weak void timer_prepare(void) { /* do nothing */ }
static uint64_t timer_raw_value(void)
{
/*
* According to "General-Purpose Timer (GPT).pdf", The read operation of
* gpt6_cnt_l will make gpt6_cnt_h fixed until the next read operation
* of gpt6_cnt_l. Therefore, we must read gpt6_cnt_l before gpt6_cnt_h.
*/
uint32_t low = read32(&mtk_gpt->gpt6_cnt_l);
uint32_t high = read32(&mtk_gpt->gpt6_cnt_h);
return low | (uint64_t)high << 32;
}
void timer_monotonic_get(struct mono_time *mt)
{
mono_time_set_usecs(mt, read32(&mtk_gpt->gpt4_cnt) / GPT4_MHZ);
mono_time_set_usecs(mt, timer_raw_value() / GPT_MHZ);
}
void init_timer(void)
{
timer_prepare();
/* Disable GPT4 and clear the counter */
clrbits_le32(&mtk_gpt->gpt4_con, GPT_CON_EN);
setbits_le32(&mtk_gpt->gpt4_con, GPT_CON_CLR);
/* Disable timer and clear the counter */
clrbits_le32(&mtk_gpt->gpt6_con, GPT_CON_EN);
setbits_le32(&mtk_gpt->gpt6_con, GPT_CON_CLR);
/* Set clock source to system clock and set clock divider to 1 */
write32(&mtk_gpt->gpt4_clk, GPT_SYS_CLK | GPT_CLK_DIV1);
/* Set operation mode to FREERUN mode and enable GTP4 */
write32(&mtk_gpt->gpt4_con, GPT_CON_EN | GPT_MODE_FREERUN);
write32(&mtk_gpt->gpt6_clk, GPT_SYS_CLK | GPT_CLK_DIV1);
/* Set operation mode to FREERUN mode and enable timer */
write32(&mtk_gpt->gpt6_con, GPT_CON_EN | GPT_MODE_FREERUN);
}

View File

@ -31,5 +31,5 @@ void timer_prepare(void)
*/
write32(&mt8173_mcucfg->xgpt_idx, 0);
/* Set clock mode to 13Mhz and enable XGPT */
write32(&mt8173_mcucfg->xgpt_ctl, (0x1 | ((26 / GPT4_MHZ) << 8)));
write32(&mt8173_mcucfg->xgpt_ctl, (0x1 | ((26 / GPT_MHZ) << 8)));
}