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