1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) Siemens AG, 2020
4  *
5  * Authors:
6  *   Jan Kiszka <jan.kiszka@siemens.com>
7  *
8  * Derived from linux/drivers/watchdog/rti_wdt.c
9  */
10 
11 #include <common.h>
12 #include <clk.h>
13 #include <dm.h>
14 #include <dm/device_compat.h>
15 #include <power-domain.h>
16 #include <wdt.h>
17 #include <asm/io.h>
18 #include <remoteproc.h>
19 
20 /* Timer register set definition */
21 #define RTIDWDCTRL		0x90
22 #define RTIDWDPRLD		0x94
23 #define RTIWDSTATUS		0x98
24 #define RTIWDKEY		0x9c
25 #define RTIDWDCNTR		0xa0
26 #define RTIWWDRXCTRL		0xa4
27 #define RTIWWDSIZECTRL		0xa8
28 
29 #define RTIWWDRX_NMI		0xa
30 
31 #define RTIWWDSIZE_50P		0x50
32 
33 #define WDENABLE_KEY		0xa98559da
34 
35 #define WDKEY_SEQ0		0xe51a
36 #define WDKEY_SEQ1		0xa35c
37 
38 #define WDT_PRELOAD_SHIFT	13
39 
40 #define WDT_PRELOAD_MAX		0xfff
41 
42 struct rti_wdt_priv {
43 	phys_addr_t regs;
44 	unsigned int clk_khz;
45 };
46 
47 #ifdef CONFIG_WDT_K3_RTI_LOAD_FW
48 #define RTI_WDT_FIT_PATH	"/fit-images/k3-rti-wdt-firmware"
49 
rti_wdt_load_fw(struct udevice * dev)50 static int rti_wdt_load_fw(struct udevice *dev)
51 {
52 	struct udevice *rproc_dev;
53 	int primary_core, ret;
54 	u32 cluster_mode;
55 	ofnode node;
56 	u64 rti_wdt_fw;
57 	u32 rti_wdt_fw_size;
58 
59 	node = ofnode_path(RTI_WDT_FIT_PATH);
60 	if (!ofnode_valid(node))
61 		goto fit_error;
62 
63 	ret = ofnode_read_u64(node, "load", &rti_wdt_fw);
64 	if (ret)
65 		goto fit_error;
66 	ret = ofnode_read_u32(node, "size", &rti_wdt_fw_size);
67 	if (ret)
68 		goto fit_error;
69 
70 	node = ofnode_by_compatible(ofnode_null(), "ti,am654-r5fss");
71 	if (!ofnode_valid(node))
72 		goto dt_error;
73 
74 	ret = ofnode_read_u32(node, "ti,cluster-mode", &cluster_mode);
75 	if (ret)
76 		cluster_mode = 1;
77 
78 	node = ofnode_by_compatible(node, "ti,am654-r5f");
79 	if (!ofnode_valid(node))
80 		goto dt_error;
81 
82 	ret = uclass_get_device_by_ofnode(UCLASS_REMOTEPROC, node, &rproc_dev);
83 	if (ret)
84 		return ret;
85 
86 	primary_core = dev_seq(rproc_dev);
87 
88 	ret = rproc_dev_init(primary_core);
89 	if (ret)
90 		goto fw_error;
91 
92 	if (cluster_mode == 1) {
93 		ret = rproc_dev_init(primary_core + 1);
94 		if (ret)
95 			goto fw_error;
96 	}
97 
98 	ret = rproc_load(primary_core, (ulong)rti_wdt_fw,
99 			 rti_wdt_fw_size);
100 	if (ret)
101 		goto fw_error;
102 
103 	ret = rproc_start(primary_core);
104 	if (ret)
105 		goto fw_error;
106 
107 	return 0;
108 
109 fit_error:
110 	dev_err(dev, "No loadable firmware found under %s\n", RTI_WDT_FIT_PATH);
111 	return -ENOENT;
112 
113 dt_error:
114 	dev_err(dev, "No compatible firmware target processor found\n");
115 	return -ENODEV;
116 
117 fw_error:
118 	dev_err(dev, "Failed to load watchdog firmware into remote processor %d\n",
119 		primary_core);
120 	return ret;
121 }
122 #else
rti_wdt_load_fw(struct udevice * dev)123 static inline int rti_wdt_load_fw(struct udevice *dev)
124 {
125 	return 0;
126 }
127 #endif
128 
rti_wdt_start(struct udevice * dev,u64 timeout_ms,ulong flags)129 static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
130 {
131 	struct rti_wdt_priv *priv = dev_get_priv(dev);
132 	u32 timer_margin;
133 	int ret;
134 
135 	if (readl(priv->regs + RTIDWDCTRL) == WDENABLE_KEY)
136 		return -EBUSY;
137 
138 	ret = rti_wdt_load_fw(dev);
139 	if (ret < 0)
140 		return ret;
141 
142 	timer_margin = timeout_ms * priv->clk_khz / 1000;
143 	timer_margin >>= WDT_PRELOAD_SHIFT;
144 	if (timer_margin > WDT_PRELOAD_MAX)
145 		timer_margin = WDT_PRELOAD_MAX;
146 
147 	writel(timer_margin, priv->regs + RTIDWDPRLD);
148 	writel(RTIWWDRX_NMI, priv->regs + RTIWWDRXCTRL);
149 	writel(RTIWWDSIZE_50P, priv->regs + RTIWWDSIZECTRL);
150 
151 	readl(priv->regs + RTIWWDSIZECTRL);
152 
153 	writel(WDENABLE_KEY, priv->regs + RTIDWDCTRL);
154 
155 	return 0;
156 }
157 
rti_wdt_reset(struct udevice * dev)158 static int rti_wdt_reset(struct udevice *dev)
159 {
160 	struct rti_wdt_priv *priv = dev_get_priv(dev);
161 	u32 prld;
162 
163 	/* Make sure we do not reset too early */
164 	prld = readl(priv->regs + RTIDWDPRLD) << WDT_PRELOAD_SHIFT;
165 	if (readl(priv->regs + RTIDWDCNTR) >= prld / 2)
166 		return -EPERM;
167 
168 	writel(WDKEY_SEQ0, priv->regs + RTIWDKEY);
169 	writel(WDKEY_SEQ1, priv->regs + RTIWDKEY);
170 
171 	return 0;
172 }
173 
rti_wdt_probe(struct udevice * dev)174 static int rti_wdt_probe(struct udevice *dev)
175 {
176 	struct rti_wdt_priv *priv = dev_get_priv(dev);
177 	struct clk clk;
178 	int ret;
179 
180 	priv->regs = devfdt_get_addr(dev);
181 	if (!priv->regs)
182 		return -EINVAL;
183 
184 	ret = clk_get_by_index(dev, 0, &clk);
185 	if (ret)
186 		return ret;
187 
188 	priv->clk_khz = clk_get_rate(&clk);
189 
190 	return 0;
191 }
192 
193 static const struct wdt_ops rti_wdt_ops = {
194 	.start = rti_wdt_start,
195 	.reset = rti_wdt_reset,
196 };
197 
198 static const struct udevice_id rti_wdt_ids[] = {
199 	{ .compatible = "ti,j7-rti-wdt" },
200 	{ }
201 };
202 
203 U_BOOT_DRIVER(rti_wdt) = {
204 	.name = "rti_wdt",
205 	.id = UCLASS_WDT,
206 	.of_match = rti_wdt_ids,
207 	.ops = &rti_wdt_ops,
208 	.probe = rti_wdt_probe,
209 	.priv_auto	= sizeof(struct rti_wdt_priv),
210 	.flags = DM_FLAG_LEAVE_PD_ON,
211 };
212