Commit | Line | Data |
---|---|---|
6edbe024 SA |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * TI K3 DSP Remote Processor(s) driver | |
4 | * | |
2eab5efe | 5 | * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ |
6edbe024 SA |
6 | * Suman Anna <s-anna@ti.com> |
7 | */ | |
8 | ||
9 | #include <linux/io.h> | |
10 | #include <linux/mailbox_client.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/of_device.h> | |
13 | #include <linux/of_reserved_mem.h> | |
14 | #include <linux/omap-mailbox.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/remoteproc.h> | |
17 | #include <linux/reset.h> | |
18 | #include <linux/slab.h> | |
19 | ||
20 | #include "omap_remoteproc.h" | |
21 | #include "remoteproc_internal.h" | |
22 | #include "ti_sci_proc.h" | |
23 | ||
24 | #define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1) | |
25 | ||
26 | /** | |
27 | * struct k3_dsp_mem - internal memory structure | |
28 | * @cpu_addr: MPU virtual address of the memory region | |
29 | * @bus_addr: Bus address used to access the memory region | |
30 | * @dev_addr: Device address of the memory region from DSP view | |
31 | * @size: Size of the memory region | |
32 | */ | |
33 | struct k3_dsp_mem { | |
34 | void __iomem *cpu_addr; | |
35 | phys_addr_t bus_addr; | |
36 | u32 dev_addr; | |
37 | size_t size; | |
38 | }; | |
39 | ||
40 | /** | |
41 | * struct k3_dsp_mem_data - memory definitions for a DSP | |
42 | * @name: name for this memory entry | |
43 | * @dev_addr: device address for the memory entry | |
44 | */ | |
45 | struct k3_dsp_mem_data { | |
46 | const char *name; | |
47 | const u32 dev_addr; | |
48 | }; | |
49 | ||
50 | /** | |
51 | * struct k3_dsp_dev_data - device data structure for a DSP | |
52 | * @mems: pointer to memory definitions for a DSP | |
53 | * @num_mems: number of memory regions in @mems | |
54 | * @boot_align_addr: boot vector address alignment granularity | |
55 | * @uses_lreset: flag to denote the need for local reset management | |
56 | */ | |
57 | struct k3_dsp_dev_data { | |
58 | const struct k3_dsp_mem_data *mems; | |
59 | u32 num_mems; | |
60 | u32 boot_align_addr; | |
61 | bool uses_lreset; | |
62 | }; | |
63 | ||
64 | /** | |
65 | * struct k3_dsp_rproc - k3 DSP remote processor driver structure | |
66 | * @dev: cached device pointer | |
67 | * @rproc: remoteproc device handle | |
68 | * @mem: internal memory regions data | |
69 | * @num_mems: number of internal memory regions | |
70 | * @rmem: reserved memory regions data | |
71 | * @num_rmems: number of reserved memory regions | |
72 | * @reset: reset control handle | |
73 | * @data: pointer to DSP-specific device data | |
74 | * @tsp: TI-SCI processor control handle | |
75 | * @ti_sci: TI-SCI handle | |
76 | * @ti_sci_id: TI-SCI device identifier | |
77 | * @mbox: mailbox channel handle | |
78 | * @client: mailbox client to request the mailbox channel | |
79 | */ | |
80 | struct k3_dsp_rproc { | |
81 | struct device *dev; | |
82 | struct rproc *rproc; | |
83 | struct k3_dsp_mem *mem; | |
84 | int num_mems; | |
85 | struct k3_dsp_mem *rmem; | |
86 | int num_rmems; | |
87 | struct reset_control *reset; | |
88 | const struct k3_dsp_dev_data *data; | |
89 | struct ti_sci_proc *tsp; | |
90 | const struct ti_sci_handle *ti_sci; | |
91 | u32 ti_sci_id; | |
92 | struct mbox_chan *mbox; | |
93 | struct mbox_client client; | |
94 | }; | |
95 | ||
96 | /** | |
97 | * k3_dsp_rproc_mbox_callback() - inbound mailbox message handler | |
98 | * @client: mailbox client pointer used for requesting the mailbox channel | |
99 | * @data: mailbox payload | |
100 | * | |
101 | * This handler is invoked by the OMAP mailbox driver whenever a mailbox | |
102 | * message is received. Usually, the mailbox payload simply contains | |
103 | * the index of the virtqueue that is kicked by the remote processor, | |
104 | * and we let remoteproc core handle it. | |
105 | * | |
106 | * In addition to virtqueue indices, we also have some out-of-band values | |
107 | * that indicate different events. Those values are deliberately very | |
108 | * large so they don't coincide with virtqueue indices. | |
109 | */ | |
110 | static void k3_dsp_rproc_mbox_callback(struct mbox_client *client, void *data) | |
111 | { | |
112 | struct k3_dsp_rproc *kproc = container_of(client, struct k3_dsp_rproc, | |
113 | client); | |
114 | struct device *dev = kproc->rproc->dev.parent; | |
115 | const char *name = kproc->rproc->name; | |
116 | u32 msg = omap_mbox_message(data); | |
117 | ||
118 | dev_dbg(dev, "mbox msg: 0x%x\n", msg); | |
119 | ||
120 | switch (msg) { | |
121 | case RP_MBOX_CRASH: | |
122 | /* | |
123 | * remoteproc detected an exception, but error recovery is not | |
124 | * supported. So, just log this for now | |
125 | */ | |
126 | dev_err(dev, "K3 DSP rproc %s crashed\n", name); | |
127 | break; | |
128 | case RP_MBOX_ECHO_REPLY: | |
129 | dev_info(dev, "received echo reply from %s\n", name); | |
130 | break; | |
131 | default: | |
132 | /* silently handle all other valid messages */ | |
133 | if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) | |
134 | return; | |
135 | if (msg > kproc->rproc->max_notifyid) { | |
136 | dev_dbg(dev, "dropping unknown message 0x%x", msg); | |
137 | return; | |
138 | } | |
139 | /* msg contains the index of the triggered vring */ | |
140 | if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE) | |
141 | dev_dbg(dev, "no message was found in vqid %d\n", msg); | |
142 | } | |
143 | } | |
144 | ||
145 | /* | |
146 | * Kick the remote processor to notify about pending unprocessed messages. | |
147 | * The vqid usage is not used and is inconsequential, as the kick is performed | |
148 | * through a simulated GPIO (a bit in an IPC interrupt-triggering register), | |
149 | * the remote processor is expected to process both its Tx and Rx virtqueues. | |
150 | */ | |
151 | static void k3_dsp_rproc_kick(struct rproc *rproc, int vqid) | |
152 | { | |
153 | struct k3_dsp_rproc *kproc = rproc->priv; | |
154 | struct device *dev = rproc->dev.parent; | |
155 | mbox_msg_t msg = (mbox_msg_t)vqid; | |
156 | int ret; | |
157 | ||
158 | /* send the index of the triggered virtqueue in the mailbox payload */ | |
159 | ret = mbox_send_message(kproc->mbox, (void *)msg); | |
160 | if (ret < 0) | |
161 | dev_err(dev, "failed to send mailbox message, status = %d\n", | |
162 | ret); | |
163 | } | |
164 | ||
165 | /* Put the DSP processor into reset */ | |
166 | static int k3_dsp_rproc_reset(struct k3_dsp_rproc *kproc) | |
167 | { | |
168 | struct device *dev = kproc->dev; | |
169 | int ret; | |
170 | ||
171 | ret = reset_control_assert(kproc->reset); | |
172 | if (ret) { | |
173 | dev_err(dev, "local-reset assert failed, ret = %d\n", ret); | |
174 | return ret; | |
175 | } | |
176 | ||
21a4d738 SA |
177 | if (kproc->data->uses_lreset) |
178 | return ret; | |
179 | ||
6edbe024 SA |
180 | ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, |
181 | kproc->ti_sci_id); | |
182 | if (ret) { | |
183 | dev_err(dev, "module-reset assert failed, ret = %d\n", ret); | |
184 | if (reset_control_deassert(kproc->reset)) | |
185 | dev_warn(dev, "local-reset deassert back failed\n"); | |
186 | } | |
187 | ||
188 | return ret; | |
189 | } | |
190 | ||
191 | /* Release the DSP processor from reset */ | |
192 | static int k3_dsp_rproc_release(struct k3_dsp_rproc *kproc) | |
193 | { | |
194 | struct device *dev = kproc->dev; | |
195 | int ret; | |
196 | ||
21a4d738 SA |
197 | if (kproc->data->uses_lreset) |
198 | goto lreset; | |
199 | ||
6edbe024 SA |
200 | ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, |
201 | kproc->ti_sci_id); | |
202 | if (ret) { | |
203 | dev_err(dev, "module-reset deassert failed, ret = %d\n", ret); | |
204 | return ret; | |
205 | } | |
206 | ||
21a4d738 | 207 | lreset: |
6edbe024 SA |
208 | ret = reset_control_deassert(kproc->reset); |
209 | if (ret) { | |
210 | dev_err(dev, "local-reset deassert failed, ret = %d\n", ret); | |
211 | if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, | |
212 | kproc->ti_sci_id)) | |
213 | dev_warn(dev, "module-reset assert back failed\n"); | |
214 | } | |
215 | ||
216 | return ret; | |
217 | } | |
218 | ||
2eab5efe SA |
219 | static int k3_dsp_rproc_request_mbox(struct rproc *rproc) |
220 | { | |
221 | struct k3_dsp_rproc *kproc = rproc->priv; | |
222 | struct mbox_client *client = &kproc->client; | |
223 | struct device *dev = kproc->dev; | |
224 | int ret; | |
225 | ||
226 | client->dev = dev; | |
227 | client->tx_done = NULL; | |
228 | client->rx_callback = k3_dsp_rproc_mbox_callback; | |
229 | client->tx_block = false; | |
230 | client->knows_txdone = false; | |
231 | ||
232 | kproc->mbox = mbox_request_channel(client, 0); | |
233 | if (IS_ERR(kproc->mbox)) { | |
234 | ret = -EBUSY; | |
235 | dev_err(dev, "mbox_request_channel failed: %ld\n", | |
236 | PTR_ERR(kproc->mbox)); | |
237 | return ret; | |
238 | } | |
239 | ||
240 | /* | |
241 | * Ping the remote processor, this is only for sanity-sake for now; | |
242 | * there is no functional effect whatsoever. | |
243 | * | |
244 | * Note that the reply will _not_ arrive immediately: this message | |
245 | * will wait in the mailbox fifo until the remote processor is booted. | |
246 | */ | |
247 | ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); | |
248 | if (ret < 0) { | |
249 | dev_err(dev, "mbox_send_message failed: %d\n", ret); | |
250 | mbox_free_channel(kproc->mbox); | |
251 | return ret; | |
252 | } | |
253 | ||
254 | return 0; | |
255 | } | |
21a4d738 SA |
256 | /* |
257 | * The C66x DSP cores have a local reset that affects only the CPU, and a | |
258 | * generic module reset that powers on the device and allows the DSP internal | |
259 | * memories to be accessed while the local reset is asserted. This function is | |
260 | * used to release the global reset on C66x DSPs to allow loading into the DSP | |
261 | * internal RAMs. The .prepare() ops is invoked by remoteproc core before any | |
262 | * firmware loading, and is followed by the .start() ops after loading to | |
b8431920 SA |
263 | * actually let the C66x DSP cores run. This callback is invoked only in |
264 | * remoteproc mode. | |
21a4d738 SA |
265 | */ |
266 | static int k3_dsp_rproc_prepare(struct rproc *rproc) | |
267 | { | |
268 | struct k3_dsp_rproc *kproc = rproc->priv; | |
269 | struct device *dev = kproc->dev; | |
270 | int ret; | |
271 | ||
272 | ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, | |
273 | kproc->ti_sci_id); | |
274 | if (ret) | |
275 | dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading, ret = %d\n", | |
276 | ret); | |
277 | ||
278 | return ret; | |
279 | } | |
280 | ||
281 | /* | |
282 | * This function implements the .unprepare() ops and performs the complimentary | |
283 | * operations to that of the .prepare() ops. The function is used to assert the | |
284 | * global reset on applicable C66x cores. This completes the second portion of | |
285 | * powering down the C66x DSP cores. The cores themselves are only halted in the | |
286 | * .stop() callback through the local reset, and the .unprepare() ops is invoked | |
287 | * by the remoteproc core after the remoteproc is stopped to balance the global | |
b8431920 | 288 | * reset. This callback is invoked only in remoteproc mode. |
21a4d738 SA |
289 | */ |
290 | static int k3_dsp_rproc_unprepare(struct rproc *rproc) | |
291 | { | |
292 | struct k3_dsp_rproc *kproc = rproc->priv; | |
293 | struct device *dev = kproc->dev; | |
294 | int ret; | |
295 | ||
296 | ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, | |
297 | kproc->ti_sci_id); | |
298 | if (ret) | |
299 | dev_err(dev, "module-reset assert failed, ret = %d\n", ret); | |
300 | ||
301 | return ret; | |
302 | } | |
303 | ||
6edbe024 SA |
304 | /* |
305 | * Power up the DSP remote processor. | |
306 | * | |
307 | * This function will be invoked only after the firmware for this rproc | |
308 | * was loaded, parsed successfully, and all of its resource requirements | |
b8431920 | 309 | * were met. This callback is invoked only in remoteproc mode. |
6edbe024 SA |
310 | */ |
311 | static int k3_dsp_rproc_start(struct rproc *rproc) | |
312 | { | |
313 | struct k3_dsp_rproc *kproc = rproc->priv; | |
6edbe024 SA |
314 | struct device *dev = kproc->dev; |
315 | u32 boot_addr; | |
316 | int ret; | |
317 | ||
2eab5efe SA |
318 | ret = k3_dsp_rproc_request_mbox(rproc); |
319 | if (ret) | |
6edbe024 | 320 | return ret; |
6edbe024 SA |
321 | |
322 | boot_addr = rproc->bootaddr; | |
323 | if (boot_addr & (kproc->data->boot_align_addr - 1)) { | |
324 | dev_err(dev, "invalid boot address 0x%x, must be aligned on a 0x%x boundary\n", | |
325 | boot_addr, kproc->data->boot_align_addr); | |
326 | ret = -EINVAL; | |
327 | goto put_mbox; | |
328 | } | |
329 | ||
330 | dev_err(dev, "booting DSP core using boot addr = 0x%x\n", boot_addr); | |
331 | ret = ti_sci_proc_set_config(kproc->tsp, boot_addr, 0, 0); | |
332 | if (ret) | |
333 | goto put_mbox; | |
334 | ||
335 | ret = k3_dsp_rproc_release(kproc); | |
336 | if (ret) | |
337 | goto put_mbox; | |
338 | ||
339 | return 0; | |
340 | ||
341 | put_mbox: | |
342 | mbox_free_channel(kproc->mbox); | |
343 | return ret; | |
344 | } | |
345 | ||
346 | /* | |
347 | * Stop the DSP remote processor. | |
348 | * | |
349 | * This function puts the DSP processor into reset, and finishes processing | |
b8431920 | 350 | * of any pending messages. This callback is invoked only in remoteproc mode. |
6edbe024 SA |
351 | */ |
352 | static int k3_dsp_rproc_stop(struct rproc *rproc) | |
353 | { | |
354 | struct k3_dsp_rproc *kproc = rproc->priv; | |
355 | ||
356 | mbox_free_channel(kproc->mbox); | |
357 | ||
358 | k3_dsp_rproc_reset(kproc); | |
359 | ||
360 | return 0; | |
361 | } | |
362 | ||
b8431920 SA |
363 | /* |
364 | * Attach to a running DSP remote processor (IPC-only mode) | |
365 | * | |
366 | * This rproc attach callback only needs to request the mailbox, the remote | |
367 | * processor is already booted, so there is no need to issue any TI-SCI | |
368 | * commands to boot the DSP core. This callback is invoked only in IPC-only | |
369 | * mode. | |
370 | */ | |
371 | static int k3_dsp_rproc_attach(struct rproc *rproc) | |
372 | { | |
373 | struct k3_dsp_rproc *kproc = rproc->priv; | |
374 | struct device *dev = kproc->dev; | |
375 | int ret; | |
376 | ||
377 | ret = k3_dsp_rproc_request_mbox(rproc); | |
378 | if (ret) | |
379 | return ret; | |
380 | ||
381 | dev_info(dev, "DSP initialized in IPC-only mode\n"); | |
382 | return 0; | |
383 | } | |
384 | ||
385 | /* | |
386 | * Detach from a running DSP remote processor (IPC-only mode) | |
387 | * | |
388 | * This rproc detach callback performs the opposite operation to attach callback | |
389 | * and only needs to release the mailbox, the DSP core is not stopped and will | |
390 | * be left to continue to run its booted firmware. This callback is invoked only | |
391 | * in IPC-only mode. | |
392 | */ | |
393 | static int k3_dsp_rproc_detach(struct rproc *rproc) | |
394 | { | |
395 | struct k3_dsp_rproc *kproc = rproc->priv; | |
396 | struct device *dev = kproc->dev; | |
397 | ||
398 | mbox_free_channel(kproc->mbox); | |
399 | dev_info(dev, "DSP deinitialized in IPC-only mode\n"); | |
400 | return 0; | |
401 | } | |
402 | ||
403 | /* | |
404 | * This function implements the .get_loaded_rsc_table() callback and is used | |
405 | * to provide the resource table for a booted DSP in IPC-only mode. The K3 DSP | |
406 | * firmwares follow a design-by-contract approach and are expected to have the | |
407 | * resource table at the base of the DDR region reserved for firmware usage. | |
408 | * This provides flexibility for the remote processor to be booted by different | |
409 | * bootloaders that may or may not have the ability to publish the resource table | |
410 | * address and size through a DT property. This callback is invoked only in | |
411 | * IPC-only mode. | |
412 | */ | |
413 | static struct resource_table *k3_dsp_get_loaded_rsc_table(struct rproc *rproc, | |
414 | size_t *rsc_table_sz) | |
415 | { | |
416 | struct k3_dsp_rproc *kproc = rproc->priv; | |
417 | struct device *dev = kproc->dev; | |
418 | ||
419 | if (!kproc->rmem[0].cpu_addr) { | |
420 | dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); | |
421 | return ERR_PTR(-ENOMEM); | |
422 | } | |
423 | ||
424 | /* | |
425 | * NOTE: The resource table size is currently hard-coded to a maximum | |
426 | * of 256 bytes. The most common resource table usage for K3 firmwares | |
427 | * is to only have the vdev resource entry and an optional trace entry. | |
428 | * The exact size could be computed based on resource table address, but | |
429 | * the hard-coded value suffices to support the IPC-only mode. | |
430 | */ | |
431 | *rsc_table_sz = 256; | |
432 | return (struct resource_table *)kproc->rmem[0].cpu_addr; | |
433 | } | |
434 | ||
6edbe024 SA |
435 | /* |
436 | * Custom function to translate a DSP device address (internal RAMs only) to a | |
437 | * kernel virtual address. The DSPs can access their RAMs at either an internal | |
438 | * address visible only from a DSP, or at the SoC-level bus address. Both these | |
439 | * addresses need to be looked through for translation. The translated addresses | |
440 | * can be used either by the remoteproc core for loading (when using kernel | |
441 | * remoteproc loader), or by any rpmsg bus drivers. | |
442 | */ | |
40df0a91 | 443 | static void *k3_dsp_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) |
6edbe024 SA |
444 | { |
445 | struct k3_dsp_rproc *kproc = rproc->priv; | |
446 | void __iomem *va = NULL; | |
447 | phys_addr_t bus_addr; | |
448 | u32 dev_addr, offset; | |
449 | size_t size; | |
450 | int i; | |
451 | ||
452 | if (len == 0) | |
453 | return NULL; | |
454 | ||
455 | for (i = 0; i < kproc->num_mems; i++) { | |
456 | bus_addr = kproc->mem[i].bus_addr; | |
457 | dev_addr = kproc->mem[i].dev_addr; | |
458 | size = kproc->mem[i].size; | |
459 | ||
460 | if (da < KEYSTONE_RPROC_LOCAL_ADDRESS_MASK) { | |
461 | /* handle DSP-view addresses */ | |
462 | if (da >= dev_addr && | |
463 | ((da + len) <= (dev_addr + size))) { | |
464 | offset = da - dev_addr; | |
465 | va = kproc->mem[i].cpu_addr + offset; | |
466 | return (__force void *)va; | |
467 | } | |
468 | } else { | |
469 | /* handle SoC-view addresses */ | |
470 | if (da >= bus_addr && | |
471 | (da + len) <= (bus_addr + size)) { | |
472 | offset = da - bus_addr; | |
473 | va = kproc->mem[i].cpu_addr + offset; | |
474 | return (__force void *)va; | |
475 | } | |
476 | } | |
477 | } | |
478 | ||
479 | /* handle static DDR reserved memory regions */ | |
480 | for (i = 0; i < kproc->num_rmems; i++) { | |
481 | dev_addr = kproc->rmem[i].dev_addr; | |
482 | size = kproc->rmem[i].size; | |
483 | ||
484 | if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { | |
485 | offset = da - dev_addr; | |
486 | va = kproc->rmem[i].cpu_addr + offset; | |
487 | return (__force void *)va; | |
488 | } | |
489 | } | |
490 | ||
491 | return NULL; | |
492 | } | |
493 | ||
494 | static const struct rproc_ops k3_dsp_rproc_ops = { | |
495 | .start = k3_dsp_rproc_start, | |
496 | .stop = k3_dsp_rproc_stop, | |
497 | .kick = k3_dsp_rproc_kick, | |
498 | .da_to_va = k3_dsp_rproc_da_to_va, | |
499 | }; | |
500 | ||
501 | static int k3_dsp_rproc_of_get_memories(struct platform_device *pdev, | |
502 | struct k3_dsp_rproc *kproc) | |
503 | { | |
504 | const struct k3_dsp_dev_data *data = kproc->data; | |
505 | struct device *dev = &pdev->dev; | |
506 | struct resource *res; | |
507 | int num_mems = 0; | |
508 | int i; | |
509 | ||
510 | num_mems = kproc->data->num_mems; | |
511 | kproc->mem = devm_kcalloc(kproc->dev, num_mems, | |
512 | sizeof(*kproc->mem), GFP_KERNEL); | |
513 | if (!kproc->mem) | |
514 | return -ENOMEM; | |
515 | ||
516 | for (i = 0; i < num_mems; i++) { | |
517 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
518 | data->mems[i].name); | |
519 | if (!res) { | |
520 | dev_err(dev, "found no memory resource for %s\n", | |
521 | data->mems[i].name); | |
522 | return -EINVAL; | |
523 | } | |
524 | if (!devm_request_mem_region(dev, res->start, | |
525 | resource_size(res), | |
526 | dev_name(dev))) { | |
527 | dev_err(dev, "could not request %s region for resource\n", | |
528 | data->mems[i].name); | |
529 | return -EBUSY; | |
530 | } | |
531 | ||
532 | kproc->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, | |
533 | resource_size(res)); | |
6dfdf6e4 | 534 | if (!kproc->mem[i].cpu_addr) { |
6edbe024 SA |
535 | dev_err(dev, "failed to map %s memory\n", |
536 | data->mems[i].name); | |
6dfdf6e4 | 537 | return -ENOMEM; |
6edbe024 SA |
538 | } |
539 | kproc->mem[i].bus_addr = res->start; | |
540 | kproc->mem[i].dev_addr = data->mems[i].dev_addr; | |
541 | kproc->mem[i].size = resource_size(res); | |
542 | ||
543 | dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %pK da 0x%x\n", | |
544 | data->mems[i].name, &kproc->mem[i].bus_addr, | |
545 | kproc->mem[i].size, kproc->mem[i].cpu_addr, | |
546 | kproc->mem[i].dev_addr); | |
547 | } | |
548 | kproc->num_mems = num_mems; | |
549 | ||
550 | return 0; | |
551 | } | |
552 | ||
553 | static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc) | |
554 | { | |
555 | struct device *dev = kproc->dev; | |
556 | struct device_node *np = dev->of_node; | |
557 | struct device_node *rmem_np; | |
558 | struct reserved_mem *rmem; | |
559 | int num_rmems; | |
560 | int ret, i; | |
561 | ||
562 | num_rmems = of_property_count_elems_of_size(np, "memory-region", | |
563 | sizeof(phandle)); | |
564 | if (num_rmems <= 0) { | |
565 | dev_err(dev, "device does not reserved memory regions, ret = %d\n", | |
566 | num_rmems); | |
567 | return -EINVAL; | |
568 | } | |
569 | if (num_rmems < 2) { | |
d6a33c5b | 570 | dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", |
6edbe024 SA |
571 | num_rmems); |
572 | return -EINVAL; | |
573 | } | |
574 | ||
575 | /* use reserved memory region 0 for vring DMA allocations */ | |
576 | ret = of_reserved_mem_device_init_by_idx(dev, np, 0); | |
577 | if (ret) { | |
578 | dev_err(dev, "device cannot initialize DMA pool, ret = %d\n", | |
579 | ret); | |
580 | return ret; | |
581 | } | |
582 | ||
583 | num_rmems--; | |
584 | kproc->rmem = kcalloc(num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); | |
585 | if (!kproc->rmem) { | |
586 | ret = -ENOMEM; | |
587 | goto release_rmem; | |
588 | } | |
589 | ||
590 | /* use remaining reserved memory regions for static carveouts */ | |
591 | for (i = 0; i < num_rmems; i++) { | |
592 | rmem_np = of_parse_phandle(np, "memory-region", i + 1); | |
593 | if (!rmem_np) { | |
594 | ret = -EINVAL; | |
595 | goto unmap_rmem; | |
596 | } | |
597 | ||
598 | rmem = of_reserved_mem_lookup(rmem_np); | |
599 | if (!rmem) { | |
600 | of_node_put(rmem_np); | |
601 | ret = -EINVAL; | |
602 | goto unmap_rmem; | |
603 | } | |
604 | of_node_put(rmem_np); | |
605 | ||
606 | kproc->rmem[i].bus_addr = rmem->base; | |
607 | /* 64-bit address regions currently not supported */ | |
608 | kproc->rmem[i].dev_addr = (u32)rmem->base; | |
609 | kproc->rmem[i].size = rmem->size; | |
610 | kproc->rmem[i].cpu_addr = ioremap_wc(rmem->base, rmem->size); | |
611 | if (!kproc->rmem[i].cpu_addr) { | |
612 | dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", | |
613 | i + 1, &rmem->base, &rmem->size); | |
614 | ret = -ENOMEM; | |
615 | goto unmap_rmem; | |
616 | } | |
617 | ||
618 | dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", | |
619 | i + 1, &kproc->rmem[i].bus_addr, | |
620 | kproc->rmem[i].size, kproc->rmem[i].cpu_addr, | |
621 | kproc->rmem[i].dev_addr); | |
622 | } | |
623 | kproc->num_rmems = num_rmems; | |
624 | ||
625 | return 0; | |
626 | ||
627 | unmap_rmem: | |
628 | for (i--; i >= 0; i--) | |
629 | iounmap(kproc->rmem[i].cpu_addr); | |
630 | kfree(kproc->rmem); | |
631 | release_rmem: | |
632 | of_reserved_mem_device_release(kproc->dev); | |
633 | return ret; | |
634 | } | |
635 | ||
636 | static void k3_dsp_reserved_mem_exit(struct k3_dsp_rproc *kproc) | |
637 | { | |
638 | int i; | |
639 | ||
640 | for (i = 0; i < kproc->num_rmems; i++) | |
641 | iounmap(kproc->rmem[i].cpu_addr); | |
642 | kfree(kproc->rmem); | |
643 | ||
644 | of_reserved_mem_device_release(kproc->dev); | |
645 | } | |
646 | ||
647 | static | |
648 | struct ti_sci_proc *k3_dsp_rproc_of_get_tsp(struct device *dev, | |
649 | const struct ti_sci_handle *sci) | |
650 | { | |
651 | struct ti_sci_proc *tsp; | |
652 | u32 temp[2]; | |
653 | int ret; | |
654 | ||
655 | ret = of_property_read_u32_array(dev->of_node, "ti,sci-proc-ids", | |
656 | temp, 2); | |
657 | if (ret < 0) | |
658 | return ERR_PTR(ret); | |
659 | ||
660 | tsp = kzalloc(sizeof(*tsp), GFP_KERNEL); | |
661 | if (!tsp) | |
662 | return ERR_PTR(-ENOMEM); | |
663 | ||
664 | tsp->dev = dev; | |
665 | tsp->sci = sci; | |
666 | tsp->ops = &sci->ops.proc_ops; | |
667 | tsp->proc_id = temp[0]; | |
668 | tsp->host_id = temp[1]; | |
669 | ||
670 | return tsp; | |
671 | } | |
672 | ||
673 | static int k3_dsp_rproc_probe(struct platform_device *pdev) | |
674 | { | |
675 | struct device *dev = &pdev->dev; | |
676 | struct device_node *np = dev->of_node; | |
677 | const struct k3_dsp_dev_data *data; | |
678 | struct k3_dsp_rproc *kproc; | |
679 | struct rproc *rproc; | |
680 | const char *fw_name; | |
b8431920 | 681 | bool p_state = false; |
6edbe024 SA |
682 | int ret = 0; |
683 | int ret1; | |
684 | ||
685 | data = of_device_get_match_data(dev); | |
686 | if (!data) | |
687 | return -ENODEV; | |
688 | ||
689 | ret = rproc_of_parse_firmware(dev, 0, &fw_name); | |
690 | if (ret) { | |
691 | dev_err(dev, "failed to parse firmware-name property, ret = %d\n", | |
692 | ret); | |
693 | return ret; | |
694 | } | |
695 | ||
696 | rproc = rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, fw_name, | |
697 | sizeof(*kproc)); | |
698 | if (!rproc) | |
699 | return -ENOMEM; | |
700 | ||
701 | rproc->has_iommu = false; | |
702 | rproc->recovery_disabled = true; | |
87218f96 SA |
703 | if (data->uses_lreset) { |
704 | rproc->ops->prepare = k3_dsp_rproc_prepare; | |
705 | rproc->ops->unprepare = k3_dsp_rproc_unprepare; | |
706 | } | |
6edbe024 SA |
707 | kproc = rproc->priv; |
708 | kproc->rproc = rproc; | |
709 | kproc->dev = dev; | |
710 | kproc->data = data; | |
711 | ||
712 | kproc->ti_sci = ti_sci_get_by_phandle(np, "ti,sci"); | |
713 | if (IS_ERR(kproc->ti_sci)) { | |
714 | ret = PTR_ERR(kproc->ti_sci); | |
715 | if (ret != -EPROBE_DEFER) { | |
716 | dev_err(dev, "failed to get ti-sci handle, ret = %d\n", | |
717 | ret); | |
718 | } | |
719 | kproc->ti_sci = NULL; | |
720 | goto free_rproc; | |
721 | } | |
722 | ||
723 | ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id); | |
724 | if (ret) { | |
725 | dev_err(dev, "missing 'ti,sci-dev-id' property\n"); | |
726 | goto put_sci; | |
727 | } | |
728 | ||
729 | kproc->reset = devm_reset_control_get_exclusive(dev, NULL); | |
730 | if (IS_ERR(kproc->reset)) { | |
731 | ret = PTR_ERR(kproc->reset); | |
732 | dev_err(dev, "failed to get reset, status = %d\n", ret); | |
733 | goto put_sci; | |
734 | } | |
735 | ||
736 | kproc->tsp = k3_dsp_rproc_of_get_tsp(dev, kproc->ti_sci); | |
737 | if (IS_ERR(kproc->tsp)) { | |
738 | dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", | |
739 | ret); | |
740 | ret = PTR_ERR(kproc->tsp); | |
741 | goto put_sci; | |
742 | } | |
743 | ||
744 | ret = ti_sci_proc_request(kproc->tsp); | |
745 | if (ret < 0) { | |
746 | dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret); | |
747 | goto free_tsp; | |
748 | } | |
749 | ||
750 | ret = k3_dsp_rproc_of_get_memories(pdev, kproc); | |
751 | if (ret) | |
752 | goto release_tsp; | |
753 | ||
754 | ret = k3_dsp_reserved_mem_init(kproc); | |
755 | if (ret) { | |
756 | dev_err(dev, "reserved memory init failed, ret = %d\n", ret); | |
757 | goto release_tsp; | |
758 | } | |
759 | ||
b8431920 SA |
760 | ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id, |
761 | NULL, &p_state); | |
762 | if (ret) { | |
763 | dev_err(dev, "failed to get initial state, mode cannot be determined, ret = %d\n", | |
764 | ret); | |
765 | goto release_mem; | |
766 | } | |
767 | ||
768 | /* configure J721E devices for either remoteproc or IPC-only mode */ | |
769 | if (p_state) { | |
770 | dev_info(dev, "configured DSP for IPC-only mode\n"); | |
771 | rproc->state = RPROC_DETACHED; | |
772 | /* override rproc ops with only required IPC-only mode ops */ | |
773 | rproc->ops->prepare = NULL; | |
774 | rproc->ops->unprepare = NULL; | |
775 | rproc->ops->start = NULL; | |
776 | rproc->ops->stop = NULL; | |
777 | rproc->ops->attach = k3_dsp_rproc_attach; | |
778 | rproc->ops->detach = k3_dsp_rproc_detach; | |
779 | rproc->ops->get_loaded_rsc_table = k3_dsp_get_loaded_rsc_table; | |
780 | } else { | |
781 | dev_info(dev, "configured DSP for remoteproc mode\n"); | |
782 | /* | |
783 | * ensure the DSP local reset is asserted to ensure the DSP | |
784 | * doesn't execute bogus code in .prepare() when the module | |
785 | * reset is released. | |
786 | */ | |
787 | if (data->uses_lreset) { | |
788 | ret = reset_control_status(kproc->reset); | |
789 | if (ret < 0) { | |
790 | dev_err(dev, "failed to get reset status, status = %d\n", | |
791 | ret); | |
792 | goto release_mem; | |
793 | } else if (ret == 0) { | |
794 | dev_warn(dev, "local reset is deasserted for device\n"); | |
795 | k3_dsp_rproc_reset(kproc); | |
796 | } | |
21a4d738 SA |
797 | } |
798 | } | |
799 | ||
6edbe024 SA |
800 | ret = rproc_add(rproc); |
801 | if (ret) { | |
802 | dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", | |
803 | ret); | |
804 | goto release_mem; | |
805 | } | |
806 | ||
807 | platform_set_drvdata(pdev, kproc); | |
808 | ||
809 | return 0; | |
810 | ||
811 | release_mem: | |
812 | k3_dsp_reserved_mem_exit(kproc); | |
813 | release_tsp: | |
814 | ret1 = ti_sci_proc_release(kproc->tsp); | |
815 | if (ret1) | |
816 | dev_err(dev, "failed to release proc, ret = %d\n", ret1); | |
817 | free_tsp: | |
818 | kfree(kproc->tsp); | |
819 | put_sci: | |
820 | ret1 = ti_sci_put_handle(kproc->ti_sci); | |
821 | if (ret1) | |
822 | dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret1); | |
823 | free_rproc: | |
824 | rproc_free(rproc); | |
825 | return ret; | |
826 | } | |
827 | ||
828 | static int k3_dsp_rproc_remove(struct platform_device *pdev) | |
829 | { | |
830 | struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev); | |
b8431920 | 831 | struct rproc *rproc = kproc->rproc; |
6edbe024 SA |
832 | struct device *dev = &pdev->dev; |
833 | int ret; | |
834 | ||
b8431920 SA |
835 | if (rproc->state == RPROC_ATTACHED) { |
836 | ret = rproc_detach(rproc); | |
837 | if (ret) { | |
838 | dev_err(dev, "failed to detach proc, ret = %d\n", ret); | |
839 | return ret; | |
840 | } | |
841 | } | |
842 | ||
6edbe024 SA |
843 | rproc_del(kproc->rproc); |
844 | ||
845 | ret = ti_sci_proc_release(kproc->tsp); | |
846 | if (ret) | |
847 | dev_err(dev, "failed to release proc, ret = %d\n", ret); | |
848 | ||
849 | kfree(kproc->tsp); | |
850 | ||
851 | ret = ti_sci_put_handle(kproc->ti_sci); | |
852 | if (ret) | |
853 | dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret); | |
854 | ||
855 | k3_dsp_reserved_mem_exit(kproc); | |
856 | rproc_free(kproc->rproc); | |
857 | ||
858 | return 0; | |
859 | } | |
860 | ||
861 | static const struct k3_dsp_mem_data c66_mems[] = { | |
862 | { .name = "l2sram", .dev_addr = 0x800000 }, | |
863 | { .name = "l1pram", .dev_addr = 0xe00000 }, | |
864 | { .name = "l1dram", .dev_addr = 0xf00000 }, | |
865 | }; | |
866 | ||
87218f96 SA |
867 | /* C71x cores only have a L1P Cache, there are no L1P SRAMs */ |
868 | static const struct k3_dsp_mem_data c71_mems[] = { | |
869 | { .name = "l2sram", .dev_addr = 0x800000 }, | |
870 | { .name = "l1dram", .dev_addr = 0xe00000 }, | |
871 | }; | |
872 | ||
41909ba6 JL |
873 | static const struct k3_dsp_mem_data c7xv_mems[] = { |
874 | { .name = "l2sram", .dev_addr = 0x800000 }, | |
875 | }; | |
876 | ||
6edbe024 SA |
877 | static const struct k3_dsp_dev_data c66_data = { |
878 | .mems = c66_mems, | |
879 | .num_mems = ARRAY_SIZE(c66_mems), | |
880 | .boot_align_addr = SZ_1K, | |
881 | .uses_lreset = true, | |
882 | }; | |
883 | ||
87218f96 SA |
884 | static const struct k3_dsp_dev_data c71_data = { |
885 | .mems = c71_mems, | |
886 | .num_mems = ARRAY_SIZE(c71_mems), | |
887 | .boot_align_addr = SZ_2M, | |
888 | .uses_lreset = false, | |
889 | }; | |
890 | ||
41909ba6 JL |
891 | static const struct k3_dsp_dev_data c7xv_data = { |
892 | .mems = c7xv_mems, | |
893 | .num_mems = ARRAY_SIZE(c7xv_mems), | |
894 | .boot_align_addr = SZ_2M, | |
895 | .uses_lreset = false, | |
896 | }; | |
897 | ||
6edbe024 SA |
898 | static const struct of_device_id k3_dsp_of_match[] = { |
899 | { .compatible = "ti,j721e-c66-dsp", .data = &c66_data, }, | |
87218f96 | 900 | { .compatible = "ti,j721e-c71-dsp", .data = &c71_data, }, |
3b918d8e | 901 | { .compatible = "ti,j721s2-c71-dsp", .data = &c71_data, }, |
41909ba6 | 902 | { .compatible = "ti,am62a-c7xv-dsp", .data = &c7xv_data, }, |
6edbe024 SA |
903 | { /* sentinel */ }, |
904 | }; | |
905 | MODULE_DEVICE_TABLE(of, k3_dsp_of_match); | |
906 | ||
907 | static struct platform_driver k3_dsp_rproc_driver = { | |
908 | .probe = k3_dsp_rproc_probe, | |
909 | .remove = k3_dsp_rproc_remove, | |
910 | .driver = { | |
911 | .name = "k3-dsp-rproc", | |
912 | .of_match_table = k3_dsp_of_match, | |
913 | }, | |
914 | }; | |
915 | ||
916 | module_platform_driver(k3_dsp_rproc_driver); | |
917 | ||
918 | MODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); | |
919 | MODULE_LICENSE("GPL v2"); | |
920 | MODULE_DESCRIPTION("TI K3 DSP Remoteproc driver"); |