blob: b632d4e3f33c7ed1c8e6c675f67ccd45143519b7 [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Alvin Kuo <alvin.kuog@mediatek.com>,
6 */
7
8#include <linux/interrupt.h>
9#include <linux/io.h>
10
developer0fb30d52023-12-04 09:51:36 +080011#include "tops/internal.h"
12#include "tops/mbox.h"
13#include "tops/ser.h"
14#include "tops/trm.h"
15#include "tops/wdt.h"
developere5e687d2023-08-08 16:05:33 +080016
17#define WDT_IRQ_STATUS 0x0140B0
18#define TOP_WDT_MODE 0x012000
19#define CLUST_WDT_MODE(x) (0x512000 + 0x100 * (x))
20
21#define WDT_MODE_KEY 0x22000000
22
23struct watchdog_hw {
24 void __iomem *base;
25 struct mailbox_dev mgmt_mdev;
26 struct mailbox_dev offload_mdev[CORE_OFFLOAD_NUM];
27};
28
29static struct watchdog_hw wdt = {
30 .mgmt_mdev = MBOX_SEND_MGMT_DEV(WDT),
31 .offload_mdev = {
32 [CORE_OFFLOAD_0] = MBOX_SEND_OFFLOAD_DEV(0, WDT),
33 [CORE_OFFLOAD_1] = MBOX_SEND_OFFLOAD_DEV(1, WDT),
34 [CORE_OFFLOAD_2] = MBOX_SEND_OFFLOAD_DEV(2, WDT),
35 [CORE_OFFLOAD_3] = MBOX_SEND_OFFLOAD_DEV(3, WDT),
36 },
37};
38
39static inline void wdt_write(u32 reg, u32 val)
40{
41 writel(val, wdt.base + reg);
42}
43
44static inline void wdt_set(u32 reg, u32 mask)
45{
46 setbits(wdt.base + reg, mask);
47}
48
49static inline void wdt_clr(u32 reg, u32 mask)
50{
51 clrbits(wdt.base + reg, mask);
52}
53
54static inline void wdt_rmw(u32 reg, u32 mask, u32 val)
55{
56 clrsetbits(wdt.base + reg, mask, val);
57}
58
59static inline u32 wdt_read(u32 reg)
60{
61 return readl(wdt.base + reg);
62}
63
64static inline void wdt_irq_clr(u32 wdt_mode_reg)
65{
66 wdt_set(wdt_mode_reg, WDT_MODE_KEY);
67}
68
69static void wdt_ser_callback(struct tops_ser_params *ser_params)
70{
71 if (ser_params->type != TOPS_SER_WDT_TO)
72 WARN_ON(1);
73
74 mtk_trm_dump(ser_params->data.wdt.timeout_cores);
75}
76
77static void wdt_ser_mcmd_setup(struct tops_ser_params *ser_params,
78 struct mcu_ctrl_cmd *mcmd)
79{
80 mcmd->core_mask = (~ser_params->data.wdt.timeout_cores) & CORE_TOPS_MASK;
81}
82
83static irqreturn_t wdt_irq_handler(int irq, void *dev_id)
84{
85 struct tops_ser_params ser_params = {
86 .type = TOPS_SER_WDT_TO,
87 .ser_callback = wdt_ser_callback,
88 .ser_mcmd_setup = wdt_ser_mcmd_setup,
89 };
90 u32 status;
91 u32 i;
92
93 status = wdt_read(WDT_IRQ_STATUS);
94 if (status) {
95 ser_params.data.wdt.timeout_cores = status;
96 mtk_tops_ser(&ser_params);
97
98 /* clear wdt irq */
99 if (status & BIT(CORE_MGMT))
100 wdt_irq_clr(TOP_WDT_MODE);
101
102 for (i = 0; i < CORE_OFFLOAD_NUM; i++)
103 if (status & BIT(i))
104 wdt_irq_clr(CLUST_WDT_MODE(i));
105 }
106 TOPS_ERR("WDT Timeout: 0x%x\n", status);
107
108 return IRQ_HANDLED;
109}
110
111int mtk_tops_wdt_trigger_timeout(enum core_id core)
112{
113 struct mailbox_msg msg = {
114 .msg1 = WDT_CMD_TRIGGER_TIMEOUT,
115 };
116
117 if (core == CORE_MGMT)
118 mbox_send_msg_no_wait(&wdt.mgmt_mdev, &msg);
119 else
120 mbox_send_msg_no_wait(&wdt.offload_mdev[core], &msg);
121
122 return 0;
123}
124
125static int mtk_tops_wdt_register_mbox(void)
126{
127 int ret;
128 int i;
129
130 ret = register_mbox_dev(MBOX_SEND, &wdt.mgmt_mdev);
131 if (ret) {
132 TOPS_ERR("register wdt mgmt mbox send failed: %d\n", ret);
133 return ret;
134 }
135
136 for (i = 0; i < CORE_OFFLOAD_NUM; i++) {
137 ret = register_mbox_dev(MBOX_SEND, &wdt.offload_mdev[i]);
138 if (ret) {
139 TOPS_ERR("register wdt offload %d mbox send failed: %d\n",
140 i, ret);
141 goto err_unregister_offload_mbox;
142 }
143 }
144
145 return ret;
146
147err_unregister_offload_mbox:
148 for (i -= 1; i >= 0; i--)
149 unregister_mbox_dev(MBOX_SEND, &wdt.offload_mdev[i]);
150
151 unregister_mbox_dev(MBOX_SEND, &wdt.mgmt_mdev);
152
153 return ret;
154}
155
156static void mtk_tops_wdt_unregister_mbox(void)
157{
158 int i;
159
160 unregister_mbox_dev(MBOX_SEND, &wdt.mgmt_mdev);
161
162 for (i = 0; i < CORE_OFFLOAD_NUM; i++)
163 unregister_mbox_dev(MBOX_SEND, &wdt.offload_mdev[i]);
164}
165
166int mtk_tops_wdt_init(struct platform_device *pdev)
167{
168 struct resource *res = NULL;
169 int ret;
170 int irq;
171
172 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
173 if (!res)
174 return -ENXIO;
175
176 wdt.base = devm_ioremap(tops_dev, res->start, resource_size(res));
177 if (!wdt.base)
178 return -ENOMEM;
179
180 irq = platform_get_irq_byname(pdev, "wdt");
181 if (irq < 0) {
182 TOPS_ERR("get wdt irq failed\n");
183 return irq;
184 }
185
186 ret = devm_request_irq(tops_dev, irq,
187 wdt_irq_handler,
188 IRQF_ONESHOT,
189 pdev->name, NULL);
190 if (ret) {
191 TOPS_ERR("request wdt irq failed\n");
192 return ret;
193 }
194
195 ret = mtk_tops_wdt_register_mbox();
196 if (ret)
197 return ret;
198
199 return ret;
200}
201
202int mtk_tops_wdt_deinit(struct platform_device *pdev)
203{
204 mtk_tops_wdt_unregister_mbox();
205
206 return 0;
207}