1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2020, Google LLC. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <common/debug.h> 8*91f16700Schasinglulu #include <lib/mmio.h> 9*91f16700Schasinglulu #include <mt8173_def.h> 10*91f16700Schasinglulu #include <plat_sip_calls.h> 11*91f16700Schasinglulu #include <lib/psci/psci.h> 12*91f16700Schasinglulu #include <smccc_helpers.h> 13*91f16700Schasinglulu #include <wdt.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #define WDT_BASE (RGU_BASE + 0) 16*91f16700Schasinglulu #define WDT_MODE (WDT_BASE + 0x00) 17*91f16700Schasinglulu #define WDT_LENGTH (WDT_BASE + 0x04) 18*91f16700Schasinglulu #define WDT_RESTART (WDT_BASE + 0x08) 19*91f16700Schasinglulu #define WDT_SWRST (WDT_BASE + 0x14) 20*91f16700Schasinglulu 21*91f16700Schasinglulu #define WDT_MODE_DUAL_MODE 0x40 22*91f16700Schasinglulu #define WDT_MODE_IRQ 0x8 23*91f16700Schasinglulu #define WDT_MODE_KEY 0x22000000 24*91f16700Schasinglulu #define WDT_MODE_EXTEN 0x4 25*91f16700Schasinglulu #define WDT_MODE_EN 0x1 26*91f16700Schasinglulu #define WDT_LENGTH_KEY 0x8 27*91f16700Schasinglulu #define WDT_RESTART_KEY 0x1971 28*91f16700Schasinglulu #define WDT_SWRST_KEY 0x1209 29*91f16700Schasinglulu 30*91f16700Schasinglulu 31*91f16700Schasinglulu #define WDT_MIN_TIMEOUT 1 32*91f16700Schasinglulu #define WDT_MAX_TIMEOUT 31 33*91f16700Schasinglulu 34*91f16700Schasinglulu enum smcwd_call { 35*91f16700Schasinglulu SMCWD_INFO = 0, 36*91f16700Schasinglulu SMCWD_SET_TIMEOUT = 1, 37*91f16700Schasinglulu SMCWD_ENABLE = 2, 38*91f16700Schasinglulu SMCWD_PET = 3, 39*91f16700Schasinglulu }; 40*91f16700Schasinglulu 41*91f16700Schasinglulu static int wdt_enabled_before_suspend; 42*91f16700Schasinglulu 43*91f16700Schasinglulu /* 44*91f16700Schasinglulu * We expect the WDT registers to be correctly initialized by BL2 firmware 45*91f16700Schasinglulu * (which may be board specific), so we do not reinitialize them here. 46*91f16700Schasinglulu */ 47*91f16700Schasinglulu 48*91f16700Schasinglulu void wdt_trigger_reset(void) 49*91f16700Schasinglulu { 50*91f16700Schasinglulu mmio_write_32(WDT_SWRST, WDT_SWRST_KEY); 51*91f16700Schasinglulu } 52*91f16700Schasinglulu 53*91f16700Schasinglulu void wdt_pet(void) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu mmio_write_32(WDT_RESTART, WDT_RESTART_KEY); 56*91f16700Schasinglulu } 57*91f16700Schasinglulu 58*91f16700Schasinglulu int wdt_set_timeout(uint32_t timeout) 59*91f16700Schasinglulu { 60*91f16700Schasinglulu /* One tick here equals 512 32KHz ticks. 512 / 32000 * 125 / 2 = 1 */ 61*91f16700Schasinglulu uint32_t ticks = timeout * 125 / 2; 62*91f16700Schasinglulu 63*91f16700Schasinglulu if (timeout < WDT_MIN_TIMEOUT || timeout > WDT_MAX_TIMEOUT) 64*91f16700Schasinglulu return PSCI_E_INVALID_PARAMS; 65*91f16700Schasinglulu 66*91f16700Schasinglulu mmio_write_32(WDT_LENGTH, ticks << 5 | WDT_LENGTH_KEY); 67*91f16700Schasinglulu 68*91f16700Schasinglulu return PSCI_E_SUCCESS; 69*91f16700Schasinglulu } 70*91f16700Schasinglulu 71*91f16700Schasinglulu void wdt_set_enable(int enable) 72*91f16700Schasinglulu { 73*91f16700Schasinglulu if (enable) 74*91f16700Schasinglulu wdt_pet(); 75*91f16700Schasinglulu mmio_clrsetbits_32(WDT_MODE, WDT_MODE_EN, 76*91f16700Schasinglulu WDT_MODE_KEY | (enable ? WDT_MODE_EN : 0)); 77*91f16700Schasinglulu } 78*91f16700Schasinglulu 79*91f16700Schasinglulu void wdt_suspend(void) 80*91f16700Schasinglulu { 81*91f16700Schasinglulu wdt_enabled_before_suspend = mmio_read_32(WDT_MODE) & WDT_MODE_EN; 82*91f16700Schasinglulu if (wdt_enabled_before_suspend) 83*91f16700Schasinglulu wdt_set_enable(0); 84*91f16700Schasinglulu } 85*91f16700Schasinglulu 86*91f16700Schasinglulu void wdt_resume(void) 87*91f16700Schasinglulu { 88*91f16700Schasinglulu if (wdt_enabled_before_suspend) 89*91f16700Schasinglulu wdt_set_enable(1); 90*91f16700Schasinglulu } 91*91f16700Schasinglulu 92*91f16700Schasinglulu uint64_t wdt_smc_handler(uint32_t x1, 93*91f16700Schasinglulu uint32_t x2, 94*91f16700Schasinglulu void *handle) 95*91f16700Schasinglulu { 96*91f16700Schasinglulu int ret; 97*91f16700Schasinglulu 98*91f16700Schasinglulu switch (x1) { 99*91f16700Schasinglulu case SMCWD_INFO: 100*91f16700Schasinglulu SMC_RET3(handle, PSCI_E_SUCCESS, 101*91f16700Schasinglulu WDT_MIN_TIMEOUT, WDT_MAX_TIMEOUT); 102*91f16700Schasinglulu case SMCWD_SET_TIMEOUT: 103*91f16700Schasinglulu ret = wdt_set_timeout(x2); 104*91f16700Schasinglulu SMC_RET1(handle, ret); 105*91f16700Schasinglulu case SMCWD_ENABLE: 106*91f16700Schasinglulu wdt_set_enable(x2 > 0); 107*91f16700Schasinglulu SMC_RET1(handle, PSCI_E_SUCCESS); 108*91f16700Schasinglulu case SMCWD_PET: 109*91f16700Schasinglulu wdt_pet(); 110*91f16700Schasinglulu SMC_RET1(handle, PSCI_E_SUCCESS); 111*91f16700Schasinglulu default: 112*91f16700Schasinglulu ERROR("Unimplemented SMCWD call (%d)\n", x1); 113*91f16700Schasinglulu SMC_RET1(handle, PSCI_E_NOT_SUPPORTED); 114*91f16700Schasinglulu } 115*91f16700Schasinglulu } 116