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