1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/err.h>
26#include <linux/platform_device.h>
27#include <linux/dma-mapping.h>
28#include <linux/remoteproc.h>
29#include <linux/interrupt.h>
30#include <linux/of_irq.h>
31#include <linux/of_gpio.h>
32#include <linux/of_platform.h>
33#include <linux/smp.h>
34#include <linux/irqchip/arm-gic.h>
35#include <asm/outercache.h>
36#include <asm/cacheflush.h>
37#include <linux/slab.h>
38#include <linux/cpu.h>
39#include <linux/gpio.h>
40#include <linux/io.h>
41#include <linux/delay.h>
42
43#include "remoteproc_internal.h"
44
45
46static char *firmware;
47
48
49struct mb_rproc_pdata {
50 struct rproc *rproc;
51 u32 mem_start;
52 u32 mem_end;
53 int reset_gpio;
54 int mb_debug_gpio;
55 int ipi;
56 int vring0;
57 int vring1;
58 void __iomem *vbase;
59 const unsigned char *bootloader;
60};
61
62
63static struct platform_device *remoteprocdev;
64static struct work_struct workqueue;
65
66static void handle_event(struct work_struct *work)
67{
68 struct mb_rproc_pdata *local = platform_get_drvdata(remoteprocdev);
69
70 flush_cache_all();
71 outer_flush_range(local->mem_start, local->mem_end);
72
73 if (rproc_vq_interrupt(local->rproc, 0) == IRQ_NONE)
74 dev_info(&remoteprocdev->dev, "no message found in vqid 0\n");
75}
76
77static irqreturn_t ipi_kick(int irq, void *dev_id)
78{
79 dev_dbg(&remoteprocdev->dev, "KICK Linux because of pending message\n");
80 schedule_work(&workqueue);
81 dev_dbg(&remoteprocdev->dev, "KICK Linux handled\n");
82
83 return IRQ_HANDLED;
84}
85
86static int mb_rproc_start(struct rproc *rproc)
87{
88 struct device *dev = rproc->dev.parent;
89 struct platform_device *pdev = to_platform_device(dev);
90 struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
91 const struct firmware *fw;
92 int ret;
93
94 dev_info(dev, "%s\n", __func__);
95 INIT_WORK(&workqueue, handle_event);
96
97 flush_cache_all();
98 outer_flush_range(local->mem_start, local->mem_end);
99
100 remoteprocdev = pdev;
101
102 ret = request_firmware(&fw, local->bootloader, &pdev->dev);
103 if (ret < 0) {
104 dev_err(&pdev->dev, "request_firmware failed\n");
105 return ret;
106 }
107
108 memcpy(local->vbase, fw->data, fw->size);
109 release_firmware(fw);
110
111
112 dsb();
113
114
115 gpio_set_value(local->reset_gpio, 0);
116
117 return 0;
118}
119
120
121static void mb_rproc_kick(struct rproc *rproc, int vqid)
122{
123 struct device *dev = rproc->dev.parent;
124 struct platform_device *pdev = to_platform_device(dev);
125 struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
126
127 dev_dbg(dev, "KICK Firmware to start send messages vqid %d\n", vqid);
128
129 flush_cache_all();
130 outer_flush_all();
131
132
133 gpio_set_value(local->vring0, 0);
134 gpio_set_value(local->vring1, 0);
135 dsb();
136
137 if (!vqid) {
138 udelay(500);
139 gpio_set_value(local->vring0, 1);
140 dsb();
141 } else {
142 udelay(100);
143 gpio_set_value(local->vring1, 1);
144 dsb();
145 }
146}
147
148
149static int mb_rproc_stop(struct rproc *rproc)
150{
151 struct device *dev = rproc->dev.parent;
152 struct platform_device *pdev = to_platform_device(dev);
153 struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
154
155
156 gpio_set_value(local->mb_debug_gpio, 1);
157 dsb();
158
159
160
161
162 gpio_set_value(local->mb_debug_gpio, 0);
163
164 udelay(1000);
165
166
167 gpio_set_value(local->reset_gpio, 1);
168
169
170 return 0;
171}
172
173static struct rproc_ops mb_rproc_ops = {
174 .start = mb_rproc_start,
175 .stop = mb_rproc_stop,
176 .kick = mb_rproc_kick,
177};
178
179
180static irqreturn_t mb_remoteproc_interrupt(int irq, void *dev_id)
181{
182 struct device *dev = dev_id;
183
184 dev_err(dev, "GIC IRQ %d is not forwarded correctly\n", irq);
185
186 return IRQ_HANDLED;
187}
188
189static int mb_remoteproc_probe(struct platform_device *pdev)
190{
191 const unsigned char *prop;
192 struct platform_device *bram_pdev;
193 struct device_node *bram_dev;
194 struct resource *res;
195 int ret = 0;
196 int count = 0;
197 struct mb_rproc_pdata *local;
198
199 local = devm_kzalloc(&pdev->dev, sizeof(*local), GFP_KERNEL);
200 if (!local)
201 return -ENOMEM;
202
203 platform_set_drvdata(pdev, local);
204
205
206 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
207 if (!res) {
208 dev_err(&pdev->dev, "invalid address\n");
209 return -ENODEV;
210 }
211
212 local->mem_start = res->start;
213 local->mem_end = res->end;
214
215
216 ret = dma_declare_coherent_memory(&pdev->dev, local->mem_start,
217 local->mem_start, local->mem_end - local->mem_start + 1,
218 DMA_MEMORY_IO);
219 if (!ret) {
220 dev_err(&pdev->dev, "dma_declare_coherent_memory failed\n");
221 return -ENOMEM;
222 }
223
224 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
225 if (ret) {
226 dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
227 goto dma_mask_fault;
228 }
229
230
231 while (1) {
232 int irq;
233
234
235 irq = platform_get_irq(pdev, count++);
236 if (irq == -ENXIO || irq == -EINVAL)
237 break;
238 ret = devm_request_irq(&pdev->dev, irq, mb_remoteproc_interrupt,
239 0, dev_name(&pdev->dev), &pdev->dev);
240 if (ret) {
241 dev_err(&pdev->dev, "IRQ %d already allocated\n", irq);
242 goto dma_mask_fault;
243 }
244
245 dev_info(&pdev->dev, "%d: Alloc irq: %d\n", count, irq);
246 }
247
248
249 local->reset_gpio = of_get_named_gpio(pdev->dev.of_node, "reset", 0);
250 if (local->reset_gpio < 0) {
251 dev_err(&pdev->dev, "reset-gpio property not found\n");
252 ret = local->reset_gpio;
253 goto dma_mask_fault;
254 }
255 ret = devm_gpio_request_one(&pdev->dev, local->reset_gpio,
256 GPIOF_OUT_INIT_HIGH, "mb_reset");
257 if (ret) {
258 dev_err(&pdev->dev, "Please specify gpio reset addr\n");
259 goto dma_mask_fault;
260 }
261
262
263 local->mb_debug_gpio = of_get_named_gpio(pdev->dev.of_node, "debug", 0);
264 if (local->mb_debug_gpio < 0) {
265 dev_err(&pdev->dev, "mb-debug-gpio property not found\n");
266 ret = local->mb_debug_gpio;
267 goto dma_mask_fault;
268 }
269 ret = devm_gpio_request_one(&pdev->dev, local->mb_debug_gpio,
270 GPIOF_OUT_INIT_LOW, "mb_debug");
271 if (ret) {
272 dev_err(&pdev->dev, "Please specify gpio debug pin\n");
273 goto dma_mask_fault;
274 }
275
276
277 local->ipi = of_get_named_gpio(pdev->dev.of_node, "ipino", 0);
278 if (local->ipi < 0) {
279 dev_err(&pdev->dev, "ipi-gpio property not found\n");
280 ret = local->ipi;
281 goto dma_mask_fault;
282 }
283 ret = devm_gpio_request_one(&pdev->dev, local->ipi, GPIOF_IN, "mb_ipi");
284 if (ret) {
285 dev_err(&pdev->dev, "Please specify gpio reset addr\n");
286 goto dma_mask_fault;
287 }
288 ret = devm_request_irq(&pdev->dev, gpio_to_irq(local->ipi),
289 ipi_kick, IRQF_SHARED|IRQF_TRIGGER_RISING,
290 dev_name(&pdev->dev), local);
291 if (ret) {
292 dev_err(&pdev->dev, "IRQ %d already allocated\n", local->ipi);
293 goto dma_mask_fault;
294 }
295
296
297 local->vring0 = of_get_named_gpio(pdev->dev.of_node, "vring0", 0);
298 if (local->vring0 < 0) {
299 dev_err(&pdev->dev, "reset-gpio property not found\n");
300 ret = local->vring0;
301 goto dma_mask_fault;
302 }
303 ret = devm_gpio_request_one(&pdev->dev, local->vring0,
304 GPIOF_DIR_OUT, "mb_vring0");
305 if (ret) {
306 dev_err(&pdev->dev, "Please specify gpio reset addr\n");
307 goto dma_mask_fault;
308 }
309
310
311 local->vring1 = of_get_named_gpio(pdev->dev.of_node, "vring1", 0);
312 if (local->vring1 < 0) {
313 dev_err(&pdev->dev, "reset-gpio property not found\n");
314 ret = local->vring1;
315 goto dma_mask_fault;
316 }
317 ret = devm_gpio_request_one(&pdev->dev, local->vring1,
318 GPIOF_DIR_OUT, "mb_vring1");
319 if (ret) {
320 dev_err(&pdev->dev, "Please specify gpio reset addr\n");
321 goto dma_mask_fault;
322 }
323
324
325 bram_dev = of_parse_phandle(pdev->dev.of_node, "bram", 0);
326 if (!bram_dev) {
327 dev_err(&pdev->dev, "Please specify bram connection\n");
328 ret = -ENODEV;
329 goto dma_mask_fault;
330 }
331 bram_pdev = of_find_device_by_node(bram_dev);
332 if (!bram_pdev) {
333 dev_err(&pdev->dev, "BRAM device hasn't found\n");
334 ret = -ENODEV;
335 goto dma_mask_fault;
336 }
337 res = platform_get_resource(bram_pdev, IORESOURCE_MEM, 0);
338 local->vbase = devm_ioremap_resource(&pdev->dev, res);
339 if (!local->vbase) {
340 ret = -ENODEV;
341 goto dma_mask_fault;
342 }
343
344
345 local->bootloader = of_get_property(pdev->dev.of_node,
346 "bram-firmware", NULL);
347 if (!local->bootloader) {
348 dev_err(&pdev->dev, "Please specify BRAM firmware\n");
349 ret = -ENODEV;
350 goto dma_mask_fault;
351 }
352
353 dev_info(&pdev->dev, "Using microblaze BRAM bootloader: %s\n",
354 local->bootloader);
355
356
357 if (firmware)
358 prop = firmware;
359 else
360 prop = of_get_property(pdev->dev.of_node, "firmware", NULL);
361
362 if (prop) {
363 dev_info(&pdev->dev, "Using firmware: %s\n", prop);
364 local->rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev),
365 &mb_rproc_ops, prop, sizeof(struct rproc));
366 if (!local->rproc) {
367 dev_err(&pdev->dev, "rproc allocation failed\n");
368 ret = -ENODEV;
369 goto dma_mask_fault;
370 }
371
372 ret = rproc_add(local->rproc);
373 if (ret) {
374 dev_err(&pdev->dev, "rproc registration failed\n");
375 rproc_put(local->rproc);
376 goto dma_mask_fault;
377 }
378 return 0;
379 }
380
381 ret = -ENODEV;
382
383dma_mask_fault:
384 dma_release_declared_memory(&pdev->dev);
385
386 return ret;
387}
388
389static int mb_remoteproc_remove(struct platform_device *pdev)
390{
391 struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
392
393 dev_info(&pdev->dev, "%s\n", __func__);
394
395 dma_release_declared_memory(&pdev->dev);
396
397 rproc_del(local->rproc);
398 rproc_put(local->rproc);
399
400 return 0;
401}
402
403
404static struct of_device_id mb_remoteproc_match[] = {
405 { .compatible = "xlnx,mb_remoteproc", },
406 { },
407};
408MODULE_DEVICE_TABLE(of, mb_remoteproc_match);
409
410static struct platform_driver mb_remoteproc_driver = {
411 .probe = mb_remoteproc_probe,
412 .remove = mb_remoteproc_remove,
413 .driver = {
414 .name = "mb_remoteproc",
415 .of_match_table = mb_remoteproc_match,
416 },
417};
418module_platform_driver(mb_remoteproc_driver);
419
420module_param(firmware, charp, 0);
421MODULE_PARM_DESC(firmware, "Override the firmware image name. Default value in DTS.");
422
423MODULE_AUTHOR("Michal Simek <monstr@monstr.eu");
424MODULE_LICENSE("GPL v2");
425MODULE_DESCRIPTION("Microblaze remote processor control driver");
426