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:
		
				
					committed by
					
						
						Julius Werner
					
				
			
			
				
	
			
			
			
						parent
						
							250dfc0256
						
					
				
				
					commit
					a76e6542d1
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user