xref: /arm-trusted-firmware/plat/mediatek/mt8173/drivers/wdt/wdt.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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