blob: 71238a6058a4c711764817b53de9e6ff7b6ea061 [file] [log] [blame]
Lokesh Vutla7eb13572018-08-27 15:57:51 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Texas Instruments' K3 System Controller Driver
4 *
Nishanth Menoneaa39c62023-11-01 15:56:03 -05005 * Copyright (C) 2017-2018 Texas Instruments Incorporated - https://www.ti.com/
Lokesh Vutla7eb13572018-08-27 15:57:51 +05306 * Lokesh Vutla <lokeshvutla@ti.com>
7 */
8
Lokesh Vutla7eb13572018-08-27 15:57:51 +05309#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Lokesh Vutla7eb13572018-08-27 15:57:51 +053011#include <remoteproc.h>
12#include <errno.h>
13#include <mailbox.h>
Simon Glass9bc15642020-02-03 07:36:16 -070014#include <dm/device_compat.h>
Lokesh Vutla7eb13572018-08-27 15:57:51 +053015#include <linux/soc/ti/k3-sec-proxy.h>
16
17#define K3_MSG_R5_TO_M3_M3FW 0x8105
18#define K3_MSG_M3_TO_R5_CERT_RESULT 0x8805
19#define K3_MSG_M3_TO_R5_BOOT_NOTIFICATION 0x000A
20
21#define K3_FLAGS_MSG_CERT_AUTH_PASS 0x555555
22#define K3_FLAGS_MSG_CERT_AUTH_FAIL 0xffffff
23
24/**
25 * struct k3_sysctrler_msg_hdr - Generic Header for Messages and responses.
26 * @cmd_id: Message ID. One of K3_MSG_*
27 * @host_id: Host ID of the message
28 * @seq_ne: Message identifier indicating a transfer sequence.
29 * @flags: Flags for the message.
30 */
31struct k3_sysctrler_msg_hdr {
32 u16 cmd_id;
33 u8 host_id;
34 u8 seq_nr;
35 u32 flags;
36} __packed;
37
38/**
39 * struct k3_sysctrler_load_msg - Message format for Firmware loading
40 * @hdr: Generic message hdr
41 * @buffer_address: Address at which firmware is located.
42 * @buffer_size: Size of the firmware.
43 */
44struct k3_sysctrler_load_msg {
45 struct k3_sysctrler_msg_hdr hdr;
46 u32 buffer_address;
47 u32 buffer_size;
48} __packed;
49
50/**
51 * struct k3_sysctrler_boot_notification_msg - Message format for boot
52 * notification
53 * @checksum: Checksum for the entire message
54 * @reserved: Reserved for future use.
55 * @hdr: Generic message hdr
56 */
57struct k3_sysctrler_boot_notification_msg {
58 u16 checksum;
59 u16 reserved;
60 struct k3_sysctrler_msg_hdr hdr;
61} __packed;
62
63/**
64 * struct k3_sysctrler_desc - Description of SoC integration.
65 * @host_id: Host identifier representing the compute entity
66 * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
67 * @max_msg_size: Maximum size of data per message that can be handled.
68 */
69struct k3_sysctrler_desc {
70 u8 host_id;
71 int max_rx_timeout_us;
72 int max_msg_size;
73};
74
75/**
76 * struct k3_sysctrler_privdata - Structure representing System Controller data.
77 * @chan_tx: Transmit mailbox channel
78 * @chan_rx: Receive mailbox channel
Nishanth Menondd050c42022-01-25 20:56:27 +053079 * @chan_boot_notify: Boot notification channel
Lokesh Vutla7eb13572018-08-27 15:57:51 +053080 * @desc: SoC description for this instance
81 * @seq_nr: Counter for number of messages sent.
Nishanth Menondd050c42022-01-25 20:56:27 +053082 * @has_boot_notify: Has separate boot notification channel
Lokesh Vutla7eb13572018-08-27 15:57:51 +053083 */
84struct k3_sysctrler_privdata {
85 struct mbox_chan chan_tx;
86 struct mbox_chan chan_rx;
Nishanth Menondd050c42022-01-25 20:56:27 +053087 struct mbox_chan chan_boot_notify;
Lokesh Vutla7eb13572018-08-27 15:57:51 +053088 struct k3_sysctrler_desc *desc;
89 u32 seq_nr;
Nishanth Menondd050c42022-01-25 20:56:27 +053090 bool has_boot_notify;
Lokesh Vutla7eb13572018-08-27 15:57:51 +053091};
92
93static inline
94void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw,
95 struct k3_sysctrler_privdata *priv,
96 ulong addr, ulong size)
97{
98 fw->hdr.cmd_id = K3_MSG_R5_TO_M3_M3FW;
99 fw->hdr.host_id = priv->desc->host_id;
100 fw->hdr.seq_nr = priv->seq_nr++;
101 fw->hdr.flags = 0x0;
102 fw->buffer_address = addr;
103 fw->buffer_size = size;
104}
105
Sean Andersonb35d5d22020-09-15 10:45:09 -0400106static int k3_sysctrler_load_response(struct udevice *dev, u32 *buf)
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530107{
108 struct k3_sysctrler_load_msg *fw;
109
110 fw = (struct k3_sysctrler_load_msg *)buf;
111
112 /* Check for proper response ID */
113 if (fw->hdr.cmd_id != K3_MSG_M3_TO_R5_CERT_RESULT) {
114 dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
115 __func__, K3_MSG_M3_TO_R5_CERT_RESULT, fw->hdr.cmd_id);
116 return -EINVAL;
117 }
118
119 /* Check for certificate authentication result */
120 if (fw->hdr.flags == K3_FLAGS_MSG_CERT_AUTH_FAIL) {
121 dev_err(dev, "%s: Firmware certificate authentication failed\n",
122 __func__);
123 return -EINVAL;
124 } else if (fw->hdr.flags != K3_FLAGS_MSG_CERT_AUTH_PASS) {
125 dev_err(dev, "%s: Firmware Load response Invalid %d\n",
126 __func__, fw->hdr.flags);
127 return -EINVAL;
128 }
129
130 debug("%s: Firmware authentication passed\n", __func__);
131
132 return 0;
133}
134
Sean Andersonb35d5d22020-09-15 10:45:09 -0400135static int k3_sysctrler_boot_notification_response(struct udevice *dev,
136 u32 *buf)
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530137{
138 struct k3_sysctrler_boot_notification_msg *boot;
139
140 boot = (struct k3_sysctrler_boot_notification_msg *)buf;
141
142 /* ToDo: Verify checksum */
143
144 /* Check for proper response ID */
145 if (boot->hdr.cmd_id != K3_MSG_M3_TO_R5_BOOT_NOTIFICATION) {
146 dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
147 __func__, K3_MSG_M3_TO_R5_BOOT_NOTIFICATION,
148 boot->hdr.cmd_id);
149 return -EINVAL;
150 }
151
152 debug("%s: Boot notification received\n", __func__);
153
154 return 0;
155}
156
157/**
158 * k3_sysctrler_load() - Loadup the K3 remote processor
159 * @dev: corresponding K3 remote processor device
160 * @addr: Address in memory where image binary is stored
161 * @size: Size in bytes of the image binary
162 *
163 * Return: 0 if all goes good, else appropriate error message.
164 */
165static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size)
166{
167 struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
168 struct k3_sysctrler_load_msg firmware;
169 struct k3_sec_proxy_msg msg;
170 int ret;
171
172 debug("%s: Loading binary from 0x%08lX, size 0x%08lX\n",
173 __func__, addr, size);
174
175 memset(&firmware, 0, sizeof(firmware));
176 memset(&msg, 0, sizeof(msg));
177
178 /* Setup the message */
179 k3_sysctrler_load_msg_setup(&firmware, priv, addr, size);
180 msg.len = sizeof(firmware);
181 msg.buf = (u32 *)&firmware;
182
183 /* Send the message */
184 ret = mbox_send(&priv->chan_tx, &msg);
185 if (ret) {
186 dev_err(dev, "%s: Firmware Loading failed. ret = %d\n",
187 __func__, ret);
188 return ret;
189 }
190
191 /* Receive the response */
192 ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
193 if (ret) {
194 dev_err(dev, "%s: Firmware Load response failed. ret = %d\n",
195 __func__, ret);
196 return ret;
197 }
198
199 /* Process the response */
Sean Andersonb35d5d22020-09-15 10:45:09 -0400200 ret = k3_sysctrler_load_response(dev, msg.buf);
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530201 if (ret)
202 return ret;
203
204 debug("%s: Firmware Loaded successfully on dev %s\n",
205 __func__, dev->name);
206
207 return 0;
208}
209
210/**
211 * k3_sysctrler_start() - Start the remote processor
212 * Note that while technically the K3 system controller starts up
213 * automatically after its firmware got loaded we still want to
214 * utilize the rproc start operation for other startup-related
215 * tasks.
216 * @dev: device to operate upon
217 *
218 * Return: 0 if all went ok, else return appropriate error
219 */
220static int k3_sysctrler_start(struct udevice *dev)
221{
222 struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
223 struct k3_sec_proxy_msg msg;
224 int ret;
225
226 debug("%s(dev=%p)\n", __func__, dev);
227
228 /* Receive the boot notification. Note that it is sent only once. */
Nishanth Menondd050c42022-01-25 20:56:27 +0530229 ret = mbox_recv(priv->has_boot_notify ? &priv->chan_boot_notify :
230 &priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530231 if (ret) {
232 dev_err(dev, "%s: Boot Notification response failed. ret = %d\n",
233 __func__, ret);
234 return ret;
235 }
236
237 /* Process the response */
Sean Andersonb35d5d22020-09-15 10:45:09 -0400238 ret = k3_sysctrler_boot_notification_response(dev, msg.buf);
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530239 if (ret)
240 return ret;
241
242 debug("%s: Boot notification received successfully on dev %s\n",
243 __func__, dev->name);
244
245 return 0;
246}
247
248static const struct dm_rproc_ops k3_sysctrler_ops = {
249 .load = k3_sysctrler_load,
250 .start = k3_sysctrler_start,
251};
252
253/**
254 * k3_of_to_priv() - generate private data from device tree
255 * @dev: corresponding k3 remote processor device
256 * @priv: pointer to driver specific private data
257 *
258 * Return: 0 if all goes good, else appropriate error message.
259 */
260static int k3_of_to_priv(struct udevice *dev,
261 struct k3_sysctrler_privdata *priv)
262{
263 int ret;
264
265 ret = mbox_get_by_name(dev, "tx", &priv->chan_tx);
266 if (ret) {
267 dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
268 __func__, ret);
269 return ret;
270 }
271
272 ret = mbox_get_by_name(dev, "rx", &priv->chan_rx);
273 if (ret) {
274 dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
275 __func__, ret);
276 return ret;
277 }
278
Nishanth Menondd050c42022-01-25 20:56:27 +0530279 /* Some SoCs may have a optional channel for boot notification. */
280 priv->has_boot_notify = 1;
281 ret = mbox_get_by_name(dev, "boot_notify", &priv->chan_boot_notify);
282 if (ret == -ENODATA) {
283 dev_dbg(dev, "%s: Acquiring optional Boot_notify failed. ret = %d. Using Rx\n",
284 __func__, ret);
285 priv->has_boot_notify = 0;
286 } else if (ret) {
287 dev_err(dev, "%s: Acquiring boot_notify channel failed. ret = %d\n",
288 __func__, ret);
289 return ret;
290 }
291
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530292 return 0;
293}
294
295/**
296 * k3_sysctrler_probe() - Basic probe
297 * @dev: corresponding k3 remote processor device
298 *
299 * Return: 0 if all goes good, else appropriate error message.
300 */
301static int k3_sysctrler_probe(struct udevice *dev)
302{
303 struct k3_sysctrler_privdata *priv;
304 int ret;
305
306 debug("%s(dev=%p)\n", __func__, dev);
307
308 priv = dev_get_priv(dev);
309
310 ret = k3_of_to_priv(dev, priv);
311 if (ret) {
312 dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
313 return ret;
314 }
315
316 priv->desc = (void *)dev_get_driver_data(dev);
317 priv->seq_nr = 0;
318
319 return 0;
320}
321
322static const struct k3_sysctrler_desc k3_sysctrler_am654_desc = {
323 .host_id = 4, /* HOST_ID_R5_1 */
Lokesh Vutlac8d9dfe2019-05-02 15:35:52 +0530324 .max_rx_timeout_us = 800000,
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530325 .max_msg_size = 60,
326};
327
328static const struct udevice_id k3_sysctrler_ids[] = {
329 {
330 .compatible = "ti,am654-system-controller",
331 .data = (ulong)&k3_sysctrler_am654_desc,
332 },
333 {}
334};
335
336U_BOOT_DRIVER(k3_sysctrler) = {
337 .name = "k3_system_controller",
338 .of_match = k3_sysctrler_ids,
339 .id = UCLASS_REMOTEPROC,
340 .ops = &k3_sysctrler_ops,
341 .probe = k3_sysctrler_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700342 .priv_auto = sizeof(struct k3_sysctrler_privdata),
Lokesh Vutla7eb13572018-08-27 15:57:51 +0530343};