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:
parent
250dfc0256
commit
a76e6542d1
|
@ -54,7 +54,7 @@ config TIMER_IMG_PISTACHIO
|
||||||
bool "Timer for IMG Pistachio"
|
bool "Timer for IMG Pistachio"
|
||||||
|
|
||||||
config TIMER_MTK
|
config TIMER_MTK
|
||||||
bool "Timer for MediaTek MT8173"
|
bool "Timer for MediaTek"
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ config TIMER_GENERIC_REG
|
||||||
default 0x004A2000 if TIMER_IPQ40XX
|
default 0x004A2000 if TIMER_IPQ40XX
|
||||||
default 0x0200A028 if TIMER_IPQ806X
|
default 0x0200A028 if TIMER_IPQ806X
|
||||||
default 0x101C0100 if TIMER_MCT
|
default 0x101C0100 if TIMER_MCT
|
||||||
default 0x10008048 if TIMER_MTK
|
default 0x10008068 if TIMER_MTK
|
||||||
default 0xff810028 if TIMER_RK3288
|
default 0xff810028 if TIMER_RK3288
|
||||||
default 0xff850008 if TIMER_RK3399
|
default 0xff850008 if TIMER_RK3399
|
||||||
default 0x60005010 if TIMER_TEGRA_1US
|
default 0x60005010 if TIMER_TEGRA_1US
|
||||||
|
@ -89,6 +89,7 @@ config TIMER_GENERIC_HIGH_REG
|
||||||
hex "Generic Timer High Register Address"
|
hex "Generic Timer High Register Address"
|
||||||
default 0x004A2004 if TIMER_IPQ40XX
|
default 0x004A2004 if TIMER_IPQ40XX
|
||||||
default 0x101C0104 if TIMER_MCT
|
default 0x101C0104 if TIMER_MCT
|
||||||
|
default 0x10008078 if TIMER_MTK
|
||||||
default 0xff81002C if TIMER_RK3288
|
default 0xff81002C if TIMER_RK3288
|
||||||
default 0xff85000C if TIMER_RK3399
|
default 0xff85000C if TIMER_RK3399
|
||||||
default 0x0
|
default 0x0
|
||||||
|
|
|
@ -19,18 +19,21 @@
|
||||||
#include <soc/addressmap.h>
|
#include <soc/addressmap.h>
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
#define GPT4_MHZ 13
|
#define GPT_MHZ 13
|
||||||
|
|
||||||
struct mtk_gpt_regs {
|
struct mtk_gpt_regs {
|
||||||
u32 reserved[16];
|
u32 reserved1[24];
|
||||||
u32 gpt4_con;
|
u32 gpt6_con;
|
||||||
u32 gpt4_clk;
|
u32 gpt6_clk;
|
||||||
u32 gpt4_cnt;
|
u32 gpt6_cnt_l;
|
||||||
|
u32 reserved2[3];
|
||||||
|
u32 gpt6_cnt_h;
|
||||||
};
|
};
|
||||||
|
|
||||||
check_member(mtk_gpt_regs, gpt4_con, 0x0040);
|
check_member(mtk_gpt_regs, gpt6_con, 0x0060);
|
||||||
check_member(mtk_gpt_regs, gpt4_clk, 0x0044);
|
check_member(mtk_gpt_regs, gpt6_clk, 0x0064);
|
||||||
check_member(mtk_gpt_regs, gpt4_cnt, 0x0048);
|
check_member(mtk_gpt_regs, gpt6_cnt_l, 0x0068);
|
||||||
|
check_member(mtk_gpt_regs, gpt6_cnt_h, 0x0078);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GPT_CON_EN = 0x01,
|
GPT_CON_EN = 0x01,
|
||||||
|
|
|
@ -25,21 +25,34 @@ static struct mtk_gpt_regs *const mtk_gpt = (void *)GPT_BASE;
|
||||||
|
|
||||||
__weak void timer_prepare(void) { /* do nothing */ }
|
__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)
|
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)
|
void init_timer(void)
|
||||||
{
|
{
|
||||||
timer_prepare();
|
timer_prepare();
|
||||||
|
|
||||||
/* Disable GPT4 and clear the counter */
|
/* Disable timer and clear the counter */
|
||||||
clrbits_le32(&mtk_gpt->gpt4_con, GPT_CON_EN);
|
clrbits_le32(&mtk_gpt->gpt6_con, GPT_CON_EN);
|
||||||
setbits_le32(&mtk_gpt->gpt4_con, GPT_CON_CLR);
|
setbits_le32(&mtk_gpt->gpt6_con, GPT_CON_CLR);
|
||||||
|
|
||||||
/* Set clock source to system clock and set clock divider to 1 */
|
/* Set clock source to system clock and set clock divider to 1 */
|
||||||
write32(&mtk_gpt->gpt4_clk, GPT_SYS_CLK | GPT_CLK_DIV1);
|
write32(&mtk_gpt->gpt6_clk, GPT_SYS_CLK | GPT_CLK_DIV1);
|
||||||
/* Set operation mode to FREERUN mode and enable GTP4 */
|
/* Set operation mode to FREERUN mode and enable timer */
|
||||||
write32(&mtk_gpt->gpt4_con, GPT_CON_EN | GPT_MODE_FREERUN);
|
write32(&mtk_gpt->gpt6_con, GPT_CON_EN | GPT_MODE_FREERUN);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,5 @@ void timer_prepare(void)
|
||||||
*/
|
*/
|
||||||
write32(&mt8173_mcucfg->xgpt_idx, 0);
|
write32(&mt8173_mcucfg->xgpt_idx, 0);
|
||||||
/* Set clock mode to 13Mhz and enable XGPT */
|
/* 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)));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue