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