diff --git a/plat/mediatek/mt8173/drivers/wdt/wdt.c b/plat/mediatek/mt8173/drivers/wdt/wdt.c new file mode 100644 index 0000000..40f57ee --- /dev/null +++ b/plat/mediatek/mt8173/drivers/wdt/wdt.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020, Google LLC. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WDT_BASE (RGU_BASE + 0) +#define WDT_MODE (WDT_BASE + 0x00) +#define WDT_LENGTH (WDT_BASE + 0x04) +#define WDT_RESTART (WDT_BASE + 0x08) +#define WDT_SWRST (WDT_BASE + 0x14) + +#define WDT_MODE_DUAL_MODE 0x40 +#define WDT_MODE_IRQ 0x8 +#define WDT_MODE_KEY 0x22000000 +#define WDT_MODE_EXTEN 0x4 +#define WDT_MODE_EN 0x1 +#define WDT_LENGTH_KEY 0x8 +#define WDT_RESTART_KEY 0x1971 +#define WDT_SWRST_KEY 0x1209 + + +#define WDT_MIN_TIMEOUT 1 +#define WDT_MAX_TIMEOUT 31 + +enum smcwd_call { + SMCWD_INFO = 0, + SMCWD_SET_TIMEOUT = 1, + SMCWD_ENABLE = 2, + SMCWD_PET = 3, +}; + +static int wdt_enabled_before_suspend; + +/* + * We expect the WDT registers to be correctly initialized by BL2 firmware + * (which may be board specific), so we do not reinitialize them here. + */ + +void wdt_trigger_reset(void) +{ + mmio_write_32(WDT_SWRST, WDT_SWRST_KEY); +} + +void wdt_pet(void) +{ + mmio_write_32(WDT_RESTART, WDT_RESTART_KEY); +} + +int wdt_set_timeout(uint32_t timeout) +{ + /* One tick here equals 512 32KHz ticks. 512 / 32000 * 125 / 2 = 1 */ + uint32_t ticks = timeout * 125 / 2; + + if (timeout < WDT_MIN_TIMEOUT || timeout > WDT_MAX_TIMEOUT) + return PSCI_E_INVALID_PARAMS; + + mmio_write_32(WDT_LENGTH, ticks << 5 | WDT_LENGTH_KEY); + + return PSCI_E_SUCCESS; +} + +void wdt_set_enable(int enable) +{ + if (enable) + wdt_pet(); + mmio_clrsetbits_32(WDT_MODE, WDT_MODE_EN, + WDT_MODE_KEY | (enable ? WDT_MODE_EN : 0)); +} + +void wdt_suspend(void) +{ + wdt_enabled_before_suspend = mmio_read_32(WDT_MODE) & WDT_MODE_EN; + if (wdt_enabled_before_suspend) + wdt_set_enable(0); +} + +void wdt_resume(void) +{ + if (wdt_enabled_before_suspend) + wdt_set_enable(1); +} + +uint64_t wdt_smc_handler(uint32_t x1, + uint32_t x2, + void *handle) +{ + int ret; + + switch (x1) { + case SMCWD_INFO: + SMC_RET3(handle, PSCI_E_SUCCESS, + WDT_MIN_TIMEOUT, WDT_MAX_TIMEOUT); + case SMCWD_SET_TIMEOUT: + ret = wdt_set_timeout(x2); + SMC_RET1(handle, ret); + case SMCWD_ENABLE: + wdt_set_enable(x2 > 0); + SMC_RET1(handle, PSCI_E_SUCCESS); + case SMCWD_PET: + wdt_pet(); + SMC_RET1(handle, PSCI_E_SUCCESS); + default: + ERROR("Unimplemented SMCWD call (%d)\n", x1); + SMC_RET1(handle, PSCI_E_NOT_SUPPORTED); + } +} diff --git a/plat/mediatek/mt8173/drivers/wdt/wdt.h b/plat/mediatek/mt8173/drivers/wdt/wdt.h new file mode 100644 index 0000000..7262a57 --- /dev/null +++ b/plat/mediatek/mt8173/drivers/wdt/wdt.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020, Google LLC. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef WDT_H +#define WDT_H + +#include "stdint.h" + +void wdt_pet(void); +void wdt_resume(void); +void wdt_set_enable(int enable); +int wdt_set_timeout(uint32_t timeout); +uint64_t wdt_smc_handler(uint32_t x1, uint32_t x2, void *handle); +void wdt_suspend(void); +void wdt_trigger_reset(void); + +#endif /* WDT_H */ diff --git a/plat/mediatek/mt8173/include/mt8173_def.h b/plat/mediatek/mt8173/include/mt8173_def.h index 58962f0..378b4da 100644 --- a/plat/mediatek/mt8173/include/mt8173_def.h +++ b/plat/mediatek/mt8173/include/mt8173_def.h @@ -80,18 +80,6 @@ #define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX 4 #define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX 3 -/******************************************************************************* - * WDT related constants - ******************************************************************************/ -#define MTK_WDT_BASE (RGU_BASE + 0) -#define MTK_WDT_SWRST (MTK_WDT_BASE + 0x0014) - -#define MTK_WDT_MODE_DUAL_MODE 0x0040 -#define MTK_WDT_MODE_IRQ 0x0008 -#define MTK_WDT_MODE_KEY 0x22000000 -#define MTK_WDT_MODE_EXTEN 0x0004 -#define MTK_WDT_SWRST_KEY 0x1209 - /* FIQ platform related define */ #define MT_IRQ_SEC_SGI_0 8 #define MT_IRQ_SEC_SGI_1 9 diff --git a/plat/mediatek/mt8173/include/plat_sip_calls.h b/plat/mediatek/mt8173/include/plat_sip_calls.h index 88202cc..ce9951a 100644 --- a/plat/mediatek/mt8173/include/plat_sip_calls.h +++ b/plat/mediatek/mt8173/include/plat_sip_calls.h @@ -10,7 +10,7 @@ /******************************************************************************* * Plat SiP function constants ******************************************************************************/ -#define MTK_PLAT_SIP_NUM_CALLS 6 +#define MTK_PLAT_SIP_NUM_CALLS 7 #define MTK_SIP_PWR_ON_MTCMOS 0x82000402 #define MTK_SIP_PWR_OFF_MTCMOS 0x82000403 @@ -18,5 +18,6 @@ #define MTK_SIP_SET_HDCP_KEY_NUM 0x82000405 #define MTK_SIP_CLR_HDCP_KEY 0x82000406 #define MTK_SIP_SET_HDCP_KEY_EX 0x82000407 +#define MTK_SIP_SMC_WATCHDOG 0x82003D06 #endif /* PLAT_SIP_CALLS_H */ diff --git a/plat/mediatek/mt8173/plat_pm.c b/plat/mediatek/mt8173/plat_pm.c index 67f1c73..e72a343 100644 --- a/plat/mediatek/mt8173/plat_pm.c +++ b/plat/mediatek/mt8173/plat_pm.c @@ -27,6 +27,7 @@ #include #include #include +#include #define MTK_PWR_LVL0 0 #define MTK_PWR_LVL1 1 @@ -350,6 +351,7 @@ } if (MTK_SYSTEM_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) { + wdt_suspend(); disable_scu(mpidr); generic_timer_backup(); spm_system_suspend(); @@ -409,6 +411,7 @@ plat_arm_gic_init(); spm_system_suspend_finish(); enable_scu(mpidr); + wdt_resume(); } /* Perform the common cluster specific operations */ @@ -455,11 +458,7 @@ /* Write the System Configuration Control Register */ INFO("MTK System Reset\n"); - mmio_clrsetbits_32(MTK_WDT_BASE, - (MTK_WDT_MODE_DUAL_MODE | MTK_WDT_MODE_IRQ), - MTK_WDT_MODE_KEY); - mmio_setbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN)); - mmio_setbits_32(MTK_WDT_SWRST, MTK_WDT_SWRST_KEY); + wdt_trigger_reset(); wfi(); ERROR("MTK System Reset: operation not handled.\n"); diff --git a/plat/mediatek/mt8173/plat_sip_calls.c b/plat/mediatek/mt8173/plat_sip_calls.c index 102feb2..da9b91d 100644 --- a/plat/mediatek/mt8173/plat_sip_calls.c +++ b/plat/mediatek/mt8173/plat_sip_calls.c @@ -12,6 +12,7 @@ #include #include #include +#include /* Authorized secure register list */ enum { @@ -102,6 +103,9 @@ ret = crypt_clear_hdcp_key(); SMC_RET1(handle, ret); + case MTK_SIP_SMC_WATCHDOG: + return wdt_smc_handler(x1, x2, handle); + default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; diff --git a/plat/mediatek/mt8173/platform.mk b/plat/mediatek/mt8173/platform.mk index a66c49b..f62802c 100644 --- a/plat/mediatek/mt8173/platform.mk +++ b/plat/mediatek/mt8173/platform.mk @@ -15,6 +15,7 @@ -I${MTK_PLAT_SOC}/drivers/rtc/ \ -I${MTK_PLAT_SOC}/drivers/spm/ \ -I${MTK_PLAT_SOC}/drivers/timer/ \ + -I${MTK_PLAT_SOC}/drivers/wdt/ \ -I${MTK_PLAT_SOC}/include/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ @@ -50,6 +51,7 @@ ${MTK_PLAT_SOC}/drivers/spm/spm_mcdi.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c \ ${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c \ + ${MTK_PLAT_SOC}/drivers/wdt/wdt.c \ ${MTK_PLAT_SOC}/plat_pm.c \ ${MTK_PLAT_SOC}/plat_sip_calls.c \ ${MTK_PLAT_SOC}/plat_topology.c \