blob: 9944ea22f79d4066b6164b5c00b838965dc85f25 [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: Ren-Ting Wang <ren-ting.wang@mediatek.com>
6 */
7
developer6a0a7102023-09-18 18:03:07 +08008#include <linux/debugfs.h>
developere5e687d2023-08-08 16:05:33 +08009#include <linux/device.h>
developer6a0a7102023-09-18 18:03:07 +080010#include <linux/err.h>
11#include <linux/io.h>
developere5e687d2023-08-08 16:05:33 +080012#include <linux/module.h>
developer6a0a7102023-09-18 18:03:07 +080013#include <linux/of.h>
14#include <linux/of_address.h>
developere5e687d2023-08-08 16:05:33 +080015#include <linux/of_platform.h>
16#include <linux/platform_device.h>
17
developer0fb30d52023-12-04 09:51:36 +080018#include "tops/ctrl.h"
19#include "tops/debugfs.h"
20#include "tops/firmware.h"
21#include "tops/hpdma.h"
22#include "tops/hwspinlock.h"
23#include "tops/internal.h"
24#include "tops/mbox.h"
25#include "tops/mcu.h"
26#include "tops/netsys.h"
27#include "tops/net-event.h"
28#include "tops/ser.h"
29#include "tops/tdma.h"
30#include "tops/trm-mcu.h"
31#include "tops/trm.h"
32#include "tops/tunnel.h"
33#include "tops/wdt.h"
developer5d86c142023-12-06 14:18:27 +080034#include "tops/seq_gen.h"
developere5e687d2023-08-08 16:05:33 +080035
developer6a0a7102023-09-18 18:03:07 +080036#define EFUSE_TOPS_POWER_OFF (0xD08)
37
developere5e687d2023-08-08 16:05:33 +080038struct device *tops_dev;
developerfbdb5112023-08-21 15:12:14 +080039struct dentry *tops_debugfs_root;
developere5e687d2023-08-08 16:05:33 +080040
41static int mtk_tops_post_init(struct platform_device *pdev)
42{
43 int ret = 0;
44
45 /* kick core */
46 ret = mtk_tops_mcu_bring_up(pdev);
47 if (ret) {
48 TOPS_ERR("mcu post init failed: %d\n", ret);
49 return ret;
50 }
51
52 /* offload tunnel protocol initialization */
53 ret = mtk_tops_tnl_offload_proto_setup(pdev);
54 if (ret) {
55 TOPS_ERR("tnl offload protocol init failed: %d\n", ret);
56 goto err_mcu_tear_down;
57 }
58
59 ret = mtk_tops_netevent_register(pdev);
60 if (ret) {
61 TOPS_ERR("netevent register fail: %d\n", ret);
62 goto err_offload_proto_tear_down;
63 }
64
65 /* create sysfs file */
66 ret = mtk_tops_ctrl_init(pdev);
67 if (ret) {
68 TOPS_ERR("ctrl init failed: %d\n", ret);
69 goto err_netevent_unregister;
70 }
71
72 ret = mtk_tops_ser_init(pdev);
73 if (ret) {
74 TOPS_ERR("ser init failed: %d\n", ret);
75 goto err_ctrl_deinit;
76 }
77
78 ret = mtk_tops_wdt_init(pdev);
79 if (ret) {
80 TOPS_ERR("wdt init failed: %d\n", ret);
81 goto err_ser_deinit;
82 }
83
developer0fb30d52023-12-04 09:51:36 +080084 ret = mtk_tops_debugfs_init(pdev);
85 if (ret) {
86 TOPS_ERR("debugfs init failed: %d\n", ret);
87 goto err_wdt_deinit;
88 }
89
developere5e687d2023-08-08 16:05:33 +080090 return ret;
91
developer0fb30d52023-12-04 09:51:36 +080092err_wdt_deinit:
93 mtk_tops_wdt_deinit(pdev);
94
developere5e687d2023-08-08 16:05:33 +080095err_ser_deinit:
96 mtk_tops_ser_deinit(pdev);
97
98err_ctrl_deinit:
99 mtk_tops_ctrl_deinit(pdev);
100
101err_netevent_unregister:
102 mtk_tops_netevent_unregister(pdev);
103
104err_offload_proto_tear_down:
105 mtk_tops_tnl_offload_proto_teardown(pdev);
106
107err_mcu_tear_down:
108 mtk_tops_mcu_tear_down(pdev);
109
110 return ret;
111}
112
113static int mtk_tops_probe(struct platform_device *pdev)
114{
115 int ret = 0;
116
117 tops_dev = &pdev->dev;
118
119 ret = mtk_tops_hwspinlock_init(pdev);
120 if (ret) {
121 TOPS_ERR("hwspinlock init failed: %d\n", ret);
122 return ret;
123 }
124
125 ret = mtk_tops_fw_init(pdev);
126 if (ret) {
127 TOPS_ERR("firmware init failed: %d\n", ret);
128 return ret;
129 }
130
131 ret = mtk_tops_mcu_init(pdev);
132 if (ret) {
133 TOPS_ERR("mcu init failed: %d\n", ret);
134 return ret;
135 }
136
137 ret = mtk_tops_netsys_init(pdev);
138 if (ret) {
139 TOPS_ERR("netsys init failed: %d\n", ret);
140 goto err_mcu_deinit;
141 }
142
143 ret = mtk_tops_tdma_init(pdev);
144 if (ret) {
145 TOPS_ERR("tdma init failed: %d\n", ret);
146 goto err_netsys_deinit;
147 }
148
developer5d86c142023-12-06 14:18:27 +0800149 ret = mtk_tops_seq_gen_init(pdev);
150 if (ret) {
151 TOPS_ERR("sequence generator init failed: %d\n", ret);
152 goto err_tdma_deinit;
153 }
154
developere5e687d2023-08-08 16:05:33 +0800155 ret = mtk_tops_tnl_offload_init(pdev);
156 if (ret) {
157 TOPS_ERR("tunnel table init failed: %d\n", ret);
158 goto err_tdma_deinit;
159 }
160
161 ret = mtk_tops_post_init(pdev);
162 if (ret)
163 goto err_tnl_offload_deinit;
164
165 TOPS_ERR("init done\n");
166 return ret;
167
168err_tnl_offload_deinit:
169 mtk_tops_tnl_offload_deinit(pdev);
170
171err_tdma_deinit:
172 mtk_tops_tdma_deinit(pdev);
173
174err_netsys_deinit:
175 mtk_tops_netsys_deinit(pdev);
176
177err_mcu_deinit:
178 mtk_tops_mcu_deinit(pdev);
179
180 return ret;
181}
182
183static int mtk_tops_remove(struct platform_device *pdev)
184{
developer0fb30d52023-12-04 09:51:36 +0800185 mtk_tops_debugfs_init(pdev);
186
developere5e687d2023-08-08 16:05:33 +0800187 mtk_tops_wdt_deinit(pdev);
188
189 mtk_tops_ser_deinit(pdev);
190
191 mtk_tops_ctrl_deinit(pdev);
192
193 mtk_tops_netevent_unregister(pdev);
194
195 mtk_tops_tnl_offload_proto_teardown(pdev);
196
197 mtk_tops_mcu_tear_down(pdev);
198
199 mtk_tops_tnl_offload_deinit(pdev);
200
201 mtk_tops_tdma_deinit(pdev);
202
203 mtk_tops_netsys_deinit(pdev);
204
205 mtk_tops_mcu_deinit(pdev);
206
207 return 0;
208}
209
210static const struct of_device_id tops_match[] = {
211 { .compatible = "mediatek,tops", },
212 { },
213};
214MODULE_DEVICE_TABLE(of, tops_match);
215
216static struct platform_driver mtk_tops_driver = {
217 .probe = mtk_tops_probe,
218 .remove = mtk_tops_remove,
219 .driver = {
220 .name = "mediatek,tops",
221 .owner = THIS_MODULE,
222 .of_match_table = tops_match,
223 },
224};
225
developer6a0a7102023-09-18 18:03:07 +0800226static int __init mtk_tops_hw_disabled(void)
227{
228 struct platform_device *efuse_pdev;
229 struct device_node *efuse_node;
230 struct resource res;
231 void __iomem *efuse_base;
232 int ret = 0;
233
234 efuse_node = of_find_compatible_node(NULL, NULL, "mediatek,efuse");
235 if (!efuse_node)
236 return -ENODEV;
237
238 efuse_pdev = of_find_device_by_node(efuse_node);
239 if (!efuse_pdev) {
240 ret = -ENODEV;
241 goto out;
242 }
243
244 if (of_address_to_resource(efuse_node, 0, &res)) {
245 ret = -ENXIO;
246 goto out;
247 }
248
249 /* since we are not probed yet, we cannot use devm_* API */
250 efuse_base = ioremap(res.start, resource_size(&res));
251 if (!efuse_base) {
252 ret = -ENOMEM;
253 goto out;
254 }
255
256 if (readl(efuse_base + EFUSE_TOPS_POWER_OFF))
257 ret = -ENODEV;
258
259 iounmap(efuse_base);
260
261out:
262 of_node_put(efuse_node);
263
264 return ret;
265}
266
developere5e687d2023-08-08 16:05:33 +0800267static int __init mtk_tops_init(void)
268{
developer6a0a7102023-09-18 18:03:07 +0800269 if (mtk_tops_hw_disabled())
270 return -ENODEV;
271
developerfbdb5112023-08-21 15:12:14 +0800272 tops_debugfs_root = debugfs_create_dir("tops", NULL);
273 if (IS_ERR(tops_debugfs_root)) {
274 TOPS_ERR("create tops debugfs root directory failed\n");
275 return PTR_ERR(tops_debugfs_root);
276 }
277
developere5e687d2023-08-08 16:05:33 +0800278 mtk_tops_mbox_init();
279
280 mtk_tops_hpdma_init();
281
282 mtk_tops_trm_init();
283
284 return platform_driver_register(&mtk_tops_driver);
285}
286
287static void __exit mtk_tops_exit(void)
288{
289 platform_driver_unregister(&mtk_tops_driver);
290
291 mtk_tops_trm_exit();
292
293 mtk_tops_hpdma_exit();
294
295 mtk_tops_mbox_exit();
developerfbdb5112023-08-21 15:12:14 +0800296
297 debugfs_remove_recursive(tops_debugfs_root);
developere5e687d2023-08-08 16:05:33 +0800298}
299
300module_init(mtk_tops_init);
301module_exit(mtk_tops_exit);
302
303MODULE_LICENSE("GPL v2");
304MODULE_DESCRIPTION("MediaTek TOPS Driver");
305MODULE_AUTHOR("Ren-Ting Wang <ren-ting.wang@mediatek.com>");