1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/err.h>
27#include <linux/platform_device.h>
28#include <linux/dma-mapping.h>
29#include <linux/remoteproc.h>
30#include <linux/interrupt.h>
31#include <linux/of_irq.h>
32#include <linux/of_platform.h>
33#include <linux/slab.h>
34#include <linux/cpu.h>
35#include <linux/delay.h>
36
37#include "remoteproc_internal.h"
38
39
40#define RPU_GLBL_CNTL_OFFSET 0x00000000
41#define RPU_0_CFG_OFFSET 0x00000100
42#define RPU_1_CFG_OFFSET 0x00000200
43
44#define VINITHI_BIT BIT(2)
45
46#define nCPUHALT_BIT BIT(0)
47
48#define SLSPLIT_BIT BIT(3)
49
50#define SLCLAMP_BIT BIT(4)
51
52#define TCM_COMB_BIT BIT(6)
53
54
55#define CPU_R5_CTRL_OFFSET 0x00000090
56#define RST_LPD_TOP_OFFSET 0x0000023C
57#define RPU0_RESET_BIT BIT(0)
58#define RPU_AMBA_RST_MASK BIT(2)
59#define RPU_CLKACT_MASK BIT(24)
60
61
62#define TRIG_OFFSET 0x00000000
63#define OBS_OFFSET 0x00000004
64#define ISR_OFFSET 0x00000010
65#define IMR_OFFSET 0x00000014
66#define IER_OFFSET 0x00000018
67#define IDR_OFFSET 0x0000001C
68#define IPI_ALL_MASK 0x0F0F0301
69
70#define MAX_INSTANCES 2
71
72
73#define RPU_IPI_INIT_MASK 0x00000100
74#define RPU_IPI_MASK(n) (RPU_IPI_INIT_MASK << n)
75#define RPU_0_IPI_MASK RPU_IPI_MASK(0)
76#define RPU_1_IPI_MASK RPU_IPI_MASK(1)
77
78
79static struct platform_device *remoteprocdev[MAX_INSTANCES];
80
81
82#define reg_read(base, reg) \
83 readl(((void __iomem *)(base)) + (reg))
84#define reg_write(base, reg, val) \
85 writel((val), ((void __iomem *)(base)) + (reg))
86
87#define DEFAULT_FIRMWARE_NAME "rproc-rpu-fw"
88
89
90static char *firmware = "r5_0_firmware";
91static char *firmware1 = "r5_1_firmware";
92
93struct zynqmp_r5_rproc_pdata;
94
95
96enum control_method {
97 SMC = 0,
98 HVC,
99 HW,
100};
101
102
103enum rpu_bootmem {
104 TCM = 0,
105 OCM,
106};
107
108
109enum rpu_core_conf {
110 LOCK_STEP = 0,
111 SPLIT,
112};
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127struct zynqmp_r5_rproc_pdata {
128 struct rproc *rproc;
129 struct work_struct workqueue;
130 void __iomem *rpu_base;
131 void __iomem *crl_apb_base;
132 void __iomem *ipi_base;
133 enum rpu_core_conf rpu_mode;
134 enum rpu_bootmem bootmem;
135 u32 ipi_dest_mask;
136 u32 rpu_id;
137 u32 vring0;
138};
139
140
141static int get_firmware_entry_addr(struct zynqmp_r5_rproc_pdata *pdata,
142 u32 *elf_entry_p)
143{
144 struct elf32_hdr *ehdr = 0;
145 const struct firmware *firmware_p;
146 struct rproc *rproc = pdata->rproc;
147 int ret;
148
149 ret = request_firmware(&firmware_p, rproc->firmware, &rproc->dev);
150 if (ret < 0) {
151 dev_err(&rproc->dev, "%s: request_firmware failed: %d\n",
152 __func__, ret);
153 return ret;
154 }
155 ehdr = (struct elf32_hdr *)firmware_p->data;
156 *elf_entry_p = (unsigned int)ehdr->e_entry;
157 release_firmware(firmware_p);
158 return 0;
159}
160
161
162
163
164
165
166
167
168static void r5_boot_addr_config(struct zynqmp_r5_rproc_pdata *pdata)
169{
170 u32 tmp;
171 u32 offset = RPU_1_CFG_OFFSET;
172
173 pr_debug("%s: R5 ID: %d, boot_dev %d\n",
174 __func__, pdata->rpu_id, pdata->bootmem);
175 if (pdata->rpu_id == 0)
176 offset = RPU_0_CFG_OFFSET;
177
178 tmp = reg_read(pdata->rpu_base, offset);
179 if (pdata->bootmem == OCM)
180 tmp |= VINITHI_BIT;
181 else
182 tmp &= ~VINITHI_BIT;
183 reg_write(pdata->rpu_base, offset, tmp);
184}
185
186
187
188
189
190
191
192
193
194
195static void r5_reset(struct zynqmp_r5_rproc_pdata *pdata,
196 bool do_reset)
197{
198 u32 tmp;
199
200 pr_debug("%s: R5 ID: %d, reset %d\n", __func__, pdata->rpu_id,
201 do_reset);
202 tmp = reg_read(pdata->crl_apb_base, RST_LPD_TOP_OFFSET);
203 if (do_reset)
204 tmp |= (RPU0_RESET_BIT << pdata->rpu_id);
205 else
206 tmp &= ~((RPU0_RESET_BIT << pdata->rpu_id) | RPU_AMBA_RST_MASK);
207 reg_write(pdata->crl_apb_base, RST_LPD_TOP_OFFSET, tmp);
208}
209
210
211
212
213
214
215
216
217
218
219static void r5_halt(struct zynqmp_r5_rproc_pdata *pdata,
220 bool do_halt)
221{
222 u32 tmp;
223 u32 offset = RPU_1_CFG_OFFSET;
224
225 pr_debug("%s: R5 ID: %d, halt %d\n", __func__, pdata->rpu_id,
226 do_halt);
227 if (pdata->rpu_id == 0)
228 offset = RPU_0_CFG_OFFSET;
229
230 tmp = reg_read(pdata->rpu_base, offset);
231 if (do_halt)
232 tmp &= ~nCPUHALT_BIT;
233 else
234 tmp |= nCPUHALT_BIT;
235 reg_write(pdata->rpu_base, offset, tmp);
236}
237
238
239
240
241
242
243
244
245static void r5_mode_config(struct zynqmp_r5_rproc_pdata *pdata)
246{
247 u32 tmp;
248
249 pr_debug("%s: mode: %d\n", __func__, pdata->rpu_mode);
250 tmp = reg_read(pdata->rpu_base, 0);
251 if (pdata->rpu_mode == SPLIT) {
252 tmp |= SLSPLIT_BIT;
253 tmp &= ~TCM_COMB_BIT;
254 tmp &= ~SLCLAMP_BIT;
255 } else {
256 tmp &= ~SLSPLIT_BIT;
257 tmp |= TCM_COMB_BIT;
258 tmp |= SLCLAMP_BIT;
259 }
260 reg_write(pdata->rpu_base, 0, tmp);
261}
262
263
264
265
266
267
268
269static void r5_enable_clock(struct zynqmp_r5_rproc_pdata *pdata)
270{
271 u32 tmp;
272
273 pr_debug("%s: mode: %d\n", __func__, pdata->rpu_mode);
274 tmp = reg_read(pdata->crl_apb_base, CPU_R5_CTRL_OFFSET);
275 if (!(tmp & RPU_CLKACT_MASK)) {
276 tmp |= RPU_CLKACT_MASK;
277 reg_write(pdata->crl_apb_base, CPU_R5_CTRL_OFFSET, tmp);
278
279 udelay(500);
280 }
281}
282
283
284
285
286
287
288
289static void ipi_init(struct zynqmp_r5_rproc_pdata *pdata)
290{
291 pr_debug("%s\n", __func__);
292
293 reg_write(pdata->ipi_base, IDR_OFFSET, pdata->ipi_dest_mask);
294
295 reg_write(pdata->ipi_base, ISR_OFFSET, pdata->ipi_dest_mask);
296
297 reg_write(pdata->ipi_base, IER_OFFSET, pdata->ipi_dest_mask);
298}
299
300static void handle_event(struct zynqmp_r5_rproc_pdata *local)
301{
302 if (rproc_vq_interrupt(local->rproc, 0) == IRQ_NONE)
303 dev_dbg(&remoteprocdev[local->rpu_id]->dev, \
304 "no message found in vqid 0\n");
305}
306
307static void handle_event0(struct work_struct *work)
308{
309 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(remoteprocdev[0]);
310
311 handle_event(local);
312}
313
314static void handle_event1(struct work_struct *work)
315{
316 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(remoteprocdev[1]);
317
318 handle_event(local);
319}
320
321static int zynqmp_r5_rproc_start(struct rproc *rproc)
322{
323 struct device *dev = rproc->dev.parent;
324 struct platform_device *pdev = to_platform_device(dev);
325 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(pdev);
326 u32 bootaddr = 0;
327 int ret;
328
329 dev_dbg(dev, "%s\n", __func__);
330
331 if (local->rpu_id == 0)
332 INIT_WORK(&local->workqueue, handle_event0);
333 else
334 INIT_WORK(&local->workqueue, handle_event1);
335
336 remoteprocdev[local->rpu_id] = pdev;
337
338
339
340
341
342 wmb();
343
344 ret = get_firmware_entry_addr(local, &bootaddr);
345 if (ret < 0) {
346 dev_err(dev, "%s: failed to get RPU boot addr.\n", __func__);
347 return ret;
348 }
349 if (!bootaddr)
350 local->bootmem = TCM;
351 else
352 local->bootmem = OCM;
353 dev_info(dev, "RPU boot from %s.",
354 local->bootmem == OCM ? "OCM" : "TCM");
355
356 r5_mode_config(local);
357 r5_halt(local, true);
358 r5_reset(local, true);
359 r5_boot_addr_config(local);
360
361 udelay(500);
362 r5_reset(local, false);
363 r5_halt(local, false);
364
365 ipi_init(local);
366 return 0;
367}
368
369
370static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid)
371{
372 struct device *dev = rproc->dev.parent;
373 struct platform_device *pdev = to_platform_device(dev);
374 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(pdev);
375
376 dev_dbg(dev, "KICK Firmware to start send messages vqid %d\n", vqid);
377
378
379
380
381
382 wmb();
383
384
385
386
387 reg_write(local->ipi_base, TRIG_OFFSET, local->ipi_dest_mask);
388}
389
390
391static int zynqmp_r5_rproc_stop(struct rproc *rproc)
392{
393 struct device *dev = rproc->dev.parent;
394 struct platform_device *pdev = to_platform_device(dev);
395 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(pdev);
396
397 dev_dbg(dev, "%s\n", __func__);
398
399 r5_halt(local, true);
400 r5_reset(local, true);
401
402 reg_write(local->ipi_base, IDR_OFFSET, local->ipi_dest_mask);
403 reg_write(local->ipi_base, ISR_OFFSET, local->ipi_dest_mask);
404 return 0;
405}
406
407static struct rproc_ops zynqmp_r5_rproc_ops = {
408 .start = zynqmp_r5_rproc_start,
409 .stop = zynqmp_r5_rproc_stop,
410 .kick = zynqmp_r5_rproc_kick,
411};
412
413
414
415
416
417static void zynqmp_r5_rproc_init(struct rproc *rproc)
418{
419 struct device *dev = rproc->dev.parent;
420 struct platform_device *pdev = to_platform_device(dev);
421 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(pdev);
422
423 dev_dbg(dev, "%s\n", __func__);
424
425 r5_mode_config(local);
426 r5_halt(local, true);
427 r5_reset(local, false);
428 r5_enable_clock(local);
429}
430
431static irqreturn_t r5_remoteproc_interrupt(int irq, void *dev_id)
432{
433 struct device *dev = dev_id;
434 struct platform_device *pdev = to_platform_device(dev);
435 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(pdev);
436 u32 ipi_reg;
437
438
439 ipi_reg = reg_read(local->ipi_base, ISR_OFFSET);
440 if (!(ipi_reg & local->ipi_dest_mask))
441 return IRQ_NONE;
442
443 dev_dbg(dev, "KICK Linux because of pending message(irq%d)\n", irq);
444 reg_write(local->ipi_base, ISR_OFFSET, local->ipi_dest_mask);
445 schedule_work(&local->workqueue);
446
447 return IRQ_HANDLED;
448}
449
450static int zynqmp_r5_remoteproc_probe(struct platform_device *pdev)
451{
452 const unsigned char *prop;
453 struct resource *res;
454 int ret = 0;
455 int method = 0;
456 char *rproc_firmware = 0;
457 struct zynqmp_r5_rproc_pdata *local;
458
459 local = devm_kzalloc(&pdev->dev, sizeof(struct zynqmp_r5_rproc_pdata),
460 GFP_KERNEL);
461 if (!local)
462 return -ENOMEM;
463
464 platform_set_drvdata(pdev, local);
465
466
467 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
468 if (ret) {
469 dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
470 goto dma_mask_fault;
471 }
472
473 prop = of_get_property(pdev->dev.of_node, "core_conf", NULL);
474 if (!prop) {
475 dev_warn(&pdev->dev, "default core_conf used: lock-step\n");
476 prop = "lock-step";
477 }
478
479 dev_info(&pdev->dev, "RPU core_conf: %s\n", prop);
480 if (!strcmp(prop, "split0")) {
481 local->rpu_mode = SPLIT;
482 local->rpu_id = 0;
483 } else if (!strcmp(prop, "split1")) {
484 local->rpu_mode = SPLIT;
485 local->rpu_id = 1;
486 } else if (!strcmp(prop, "lock-step")) {
487 local->rpu_mode = LOCK_STEP;
488 local->rpu_id = 0;
489 } else {
490 dev_err(&pdev->dev, "Invalid core_conf mode provided - %s , %d\n",
491 prop, local->rpu_mode);
492 ret = -EINVAL;
493 goto dma_mask_fault;
494 }
495
496 prop = of_get_property(pdev->dev.of_node, "method", NULL);
497 if (!prop) {
498 dev_warn(&pdev->dev, "default method used: smc\n");
499 prop = "direct";
500 }
501
502
503
504 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
505 "rpu_base");
506 local->rpu_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
507 if (IS_ERR(local->rpu_base)) {
508 dev_err(&pdev->dev, "Unable to map RPU I/O memory\n");
509 ret = PTR_ERR(local->rpu_base);
510 goto dma_mask_fault;
511 }
512
513 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
514 "apb_base");
515 local->crl_apb_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
516 if (IS_ERR(local->crl_apb_base)) {
517 dev_err(&pdev->dev, "Unable to map CRL_APB I/O memory\n");
518 ret = PTR_ERR(local->crl_apb_base);
519 goto dma_mask_fault;
520 }
521
522 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ipi");
523 local->ipi_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
524 if (IS_ERR(local->ipi_base)) {
525 pr_err("%s: Unable to map IPI\n", __func__);
526 ret = PTR_ERR(local->ipi_base);
527 goto dma_mask_fault;
528 }
529
530
531 local->vring0 = platform_get_irq(pdev, 0);
532 if (local->vring0 < 0) {
533 ret = local->vring0;
534 dev_err(&pdev->dev, "unable to find IPI IRQ\n");
535 goto dma_mask_fault;
536 }
537 ret = devm_request_irq(&pdev->dev, local->vring0,
538 r5_remoteproc_interrupt, IRQF_SHARED, dev_name(&pdev->dev),
539 &pdev->dev);
540 if (ret) {
541 dev_err(&pdev->dev, "IRQ %d already allocated\n",
542 local->vring0);
543 goto dma_mask_fault;
544 }
545 dev_dbg(&pdev->dev, "vring0 irq: %d\n", local->vring0);
546
547 if (local->rpu_id == 0) {
548 local->ipi_dest_mask = RPU_0_IPI_MASK;
549 rproc_firmware = firmware;
550 } else {
551 local->ipi_dest_mask = RPU_1_IPI_MASK;
552 rproc_firmware = firmware1;
553 }
554
555 dev_dbg(&pdev->dev, "Using firmware: %s\n", rproc_firmware);
556 local->rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev),
557 &zynqmp_r5_rproc_ops, rproc_firmware, sizeof(struct rproc));
558 if (!local->rproc) {
559 dev_err(&pdev->dev, "rproc allocation failed\n");
560 goto rproc_fault;
561 }
562
563 zynqmp_r5_rproc_init(local->rproc);
564 ret = rproc_add(local->rproc);
565 if (ret) {
566 dev_err(&pdev->dev, "rproc registration failed\n");
567 goto rproc_fault;
568 }
569
570 return ret;
571
572rproc_fault:
573 rproc_put(local->rproc);
574
575dma_mask_fault:
576 dma_release_declared_memory(&pdev->dev);
577
578 return ret;
579}
580
581static int zynqmp_r5_remoteproc_remove(struct platform_device *pdev)
582{
583 struct zynqmp_r5_rproc_pdata *local = platform_get_drvdata(pdev);
584
585 dev_info(&pdev->dev, "%s\n", __func__);
586
587 rproc_del(local->rproc);
588 rproc_put(local->rproc);
589
590 dma_release_declared_memory(&pdev->dev);
591
592 return 0;
593}
594
595
596static const struct of_device_id zynqmp_r5_remoteproc_match[] = {
597 { .compatible = "xlnx,zynqmp-r5-remoteproc-1.0", },
598 { },
599};
600MODULE_DEVICE_TABLE(of, zynqmp_r5_remoteproc_match);
601
602static struct platform_driver zynqmp_r5_remoteproc_driver = {
603 .probe = zynqmp_r5_remoteproc_probe,
604 .remove = zynqmp_r5_remoteproc_remove,
605 .driver = {
606 .name = "zynqmp_r5_remoteproc",
607 .of_match_table = zynqmp_r5_remoteproc_match,
608 },
609};
610module_platform_driver(zynqmp_r5_remoteproc_driver);
611
612module_param(firmware, charp, 0);
613module_param(firmware1, charp, 0);
614MODULE_PARM_DESC(firmware, "Override the RPU-0 firmware image name.");
615MODULE_PARM_DESC(firmware1, "Override the RPU-1 firmware image name.");
616
617MODULE_AUTHOR("Jason Wu <j.wu@xilinx.com>");
618MODULE_LICENSE("GPL v2");
619MODULE_DESCRIPTION("ZynqMP R5 remote processor control driver");
620