blob: 40f57eed26c9be75fe9de95c85590cb66bc4d04e [file] [log] [blame]
Julius Wernere3a000d2018-03-12 13:26:49 -07001/*
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
34enum smcwd_call {
35 SMCWD_INFO = 0,
36 SMCWD_SET_TIMEOUT = 1,
37 SMCWD_ENABLE = 2,
38 SMCWD_PET = 3,
39};
40
41static 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
48void wdt_trigger_reset(void)
49{
50 mmio_write_32(WDT_SWRST, WDT_SWRST_KEY);
51}
52
53void wdt_pet(void)
54{
55 mmio_write_32(WDT_RESTART, WDT_RESTART_KEY);
56}
57
58int 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
71void 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
79void 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
86void wdt_resume(void)
87{
88 if (wdt_enabled_before_suspend)
89 wdt_set_enable(1);
90}
91
92uint64_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}