blob: f134192922e086423e22c0b1721159da809c4981 [file] [log] [blame]
Robert Tivy13be5432013-04-09 14:20:21 -07001/*
2 * Remote processor machine-specific module for DA8XX
3 *
4 * Copyright (C) 2013 Texas Instruments, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 */
10
11#include <linux/bitops.h>
12#include <linux/clk.h>
13#include <linux/err.h>
14#include <linux/interrupt.h>
15#include <linux/io.h>
16#include <linux/irq.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
Suman Anna61696582017-08-01 10:48:44 -050019#include <linux/of_reserved_mem.h>
Robert Tivy13be5432013-04-09 14:20:21 -070020#include <linux/platform_device.h>
21#include <linux/remoteproc.h>
22
23#include <mach/clock.h> /* for davinci_clk_reset_assert/deassert() */
24
25#include "remoteproc_internal.h"
26
27static char *da8xx_fw_name;
28module_param(da8xx_fw_name, charp, S_IRUGO);
29MODULE_PARM_DESC(da8xx_fw_name,
Suman Annae17aee32015-02-27 17:18:22 -060030 "Name of DSP firmware file in /lib/firmware (if not specified defaults to 'rproc-dsp-fw')");
Robert Tivy13be5432013-04-09 14:20:21 -070031
32/*
33 * OMAP-L138 Technical References:
34 * http://www.ti.com/product/omap-l138
35 */
36#define SYSCFG_CHIPSIG0 BIT(0)
37#define SYSCFG_CHIPSIG1 BIT(1)
38#define SYSCFG_CHIPSIG2 BIT(2)
39#define SYSCFG_CHIPSIG3 BIT(3)
40#define SYSCFG_CHIPSIG4 BIT(4)
41
Suman Anna59b23552017-08-01 10:48:42 -050042#define DA8XX_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1)
43
44/**
45 * struct da8xx_rproc_mem - internal memory structure
46 * @cpu_addr: MPU virtual address of the memory region
47 * @bus_addr: Bus address used to access the memory region
48 * @dev_addr: Device address of the memory region from DSP view
49 * @size: Size of the memory region
50 */
51struct da8xx_rproc_mem {
52 void __iomem *cpu_addr;
53 phys_addr_t bus_addr;
54 u32 dev_addr;
55 size_t size;
56};
57
Robert Tivy13be5432013-04-09 14:20:21 -070058/**
59 * struct da8xx_rproc - da8xx remote processor instance state
60 * @rproc: rproc handle
Suman Anna59b23552017-08-01 10:48:42 -050061 * @mem: internal memory regions data
62 * @num_mems: number of internal memory regions
Robert Tivy13be5432013-04-09 14:20:21 -070063 * @dsp_clk: placeholder for platform's DSP clk
64 * @ack_fxn: chip-specific ack function for ack'ing irq
65 * @irq_data: ack_fxn function parameter
66 * @chipsig: virt ptr to DSP interrupt registers (CHIPSIG & CHIPSIG_CLR)
67 * @bootreg: virt ptr to DSP boot address register (HOST1CFG)
68 * @irq: irq # used by this instance
69 */
70struct da8xx_rproc {
71 struct rproc *rproc;
Suman Anna59b23552017-08-01 10:48:42 -050072 struct da8xx_rproc_mem *mem;
73 int num_mems;
Robert Tivy13be5432013-04-09 14:20:21 -070074 struct clk *dsp_clk;
75 void (*ack_fxn)(struct irq_data *data);
76 struct irq_data *irq_data;
77 void __iomem *chipsig;
78 void __iomem *bootreg;
79 int irq;
80};
81
82/**
83 * handle_event() - inbound virtqueue message workqueue function
84 *
85 * This function is registered as a kernel thread and is scheduled by the
86 * kernel handler.
87 */
88static irqreturn_t handle_event(int irq, void *p)
89{
90 struct rproc *rproc = (struct rproc *)p;
91
92 /* Process incoming buffers on all our vrings */
93 rproc_vq_interrupt(rproc, 0);
94 rproc_vq_interrupt(rproc, 1);
95
96 return IRQ_HANDLED;
97}
98
99/**
100 * da8xx_rproc_callback() - inbound virtqueue message handler
101 *
102 * This handler is invoked directly by the kernel whenever the remote
103 * core (DSP) has modified the state of a virtqueue. There is no
104 * "payload" message indicating the virtqueue index as is the case with
105 * mailbox-based implementations on OMAP4. As such, this handler "polls"
106 * each known virtqueue index for every invocation.
107 */
108static irqreturn_t da8xx_rproc_callback(int irq, void *p)
109{
110 struct rproc *rproc = (struct rproc *)p;
111 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
112 u32 chipsig;
113
114 chipsig = readl(drproc->chipsig);
115 if (chipsig & SYSCFG_CHIPSIG0) {
116 /* Clear interrupt level source */
117 writel(SYSCFG_CHIPSIG0, drproc->chipsig + 4);
118
119 /*
120 * ACK intr to AINTC.
121 *
122 * It has already been ack'ed by the kernel before calling
123 * this function, but since the ARM<->DSP interrupts in the
124 * CHIPSIG register are "level" instead of "pulse" variety,
125 * we need to ack it after taking down the level else we'll
126 * be called again immediately after returning.
127 */
128 drproc->ack_fxn(drproc->irq_data);
129
130 return IRQ_WAKE_THREAD;
131 }
132
133 return IRQ_HANDLED;
134}
135
136static int da8xx_rproc_start(struct rproc *rproc)
137{
138 struct device *dev = rproc->dev.parent;
139 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
140 struct clk *dsp_clk = drproc->dsp_clk;
Bartosz Golaszewski2310eae2018-05-02 11:56:57 +0200141 int ret;
Robert Tivy13be5432013-04-09 14:20:21 -0700142
143 /* hw requires the start (boot) address be on 1KB boundary */
144 if (rproc->bootaddr & 0x3ff) {
145 dev_err(dev, "invalid boot address: must be aligned to 1KB\n");
146
147 return -EINVAL;
148 }
149
150 writel(rproc->bootaddr, drproc->bootreg);
151
Bartosz Golaszewski5d26f062018-05-02 11:56:58 +0200152 ret = clk_prepare_enable(dsp_clk);
Bartosz Golaszewski2310eae2018-05-02 11:56:57 +0200153 if (ret) {
Bartosz Golaszewski5d26f062018-05-02 11:56:58 +0200154 dev_err(dev, "clk_prepare_enable() failed: %d\n", ret);
Bartosz Golaszewski2310eae2018-05-02 11:56:57 +0200155 return ret;
156 }
157
Robert Tivy13be5432013-04-09 14:20:21 -0700158 davinci_clk_reset_deassert(dsp_clk);
159
160 return 0;
161}
162
163static int da8xx_rproc_stop(struct rproc *rproc)
164{
165 struct da8xx_rproc *drproc = rproc->priv;
166
Suman Annaa63c70d2017-05-18 17:09:01 -0500167 davinci_clk_reset_assert(drproc->dsp_clk);
Bartosz Golaszewski5d26f062018-05-02 11:56:58 +0200168 clk_disable_unprepare(drproc->dsp_clk);
Robert Tivy13be5432013-04-09 14:20:21 -0700169
170 return 0;
171}
172
173/* kick a virtqueue */
174static void da8xx_rproc_kick(struct rproc *rproc, int vqid)
175{
176 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
177
Anna, Suman56324d72016-08-12 18:42:17 -0500178 /* Interrupt remote proc */
Robert Tivy13be5432013-04-09 14:20:21 -0700179 writel(SYSCFG_CHIPSIG2, drproc->chipsig);
180}
181
Bhumika Goyalc008fad2017-01-01 16:13:37 +0530182static const struct rproc_ops da8xx_rproc_ops = {
Robert Tivy13be5432013-04-09 14:20:21 -0700183 .start = da8xx_rproc_start,
184 .stop = da8xx_rproc_stop,
185 .kick = da8xx_rproc_kick,
186};
187
Suman Anna59b23552017-08-01 10:48:42 -0500188static int da8xx_rproc_get_internal_memories(struct platform_device *pdev,
189 struct da8xx_rproc *drproc)
190{
191 static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"};
192 int num_mems = ARRAY_SIZE(mem_names);
193 struct device *dev = &pdev->dev;
194 struct resource *res;
195 int i;
196
197 drproc->mem = devm_kcalloc(dev, num_mems, sizeof(*drproc->mem),
198 GFP_KERNEL);
199 if (!drproc->mem)
200 return -ENOMEM;
201
202 for (i = 0; i < num_mems; i++) {
203 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
204 mem_names[i]);
205 drproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
206 if (IS_ERR(drproc->mem[i].cpu_addr)) {
207 dev_err(dev, "failed to parse and map %s memory\n",
208 mem_names[i]);
209 return PTR_ERR(drproc->mem[i].cpu_addr);
210 }
211 drproc->mem[i].bus_addr = res->start;
212 drproc->mem[i].dev_addr =
213 res->start & DA8XX_RPROC_LOCAL_ADDRESS_MASK;
214 drproc->mem[i].size = resource_size(res);
215
216 dev_dbg(dev, "memory %8s: bus addr %pa size 0x%x va %p da 0x%x\n",
217 mem_names[i], &drproc->mem[i].bus_addr,
218 drproc->mem[i].size, drproc->mem[i].cpu_addr,
219 drproc->mem[i].dev_addr);
220 }
221 drproc->num_mems = num_mems;
222
223 return 0;
224}
225
Robert Tivy13be5432013-04-09 14:20:21 -0700226static int da8xx_rproc_probe(struct platform_device *pdev)
227{
228 struct device *dev = &pdev->dev;
229 struct da8xx_rproc *drproc;
230 struct rproc *rproc;
231 struct irq_data *irq_data;
232 struct resource *bootreg_res;
233 struct resource *chipsig_res;
234 struct clk *dsp_clk;
235 void __iomem *chipsig;
236 void __iomem *bootreg;
237 int irq;
238 int ret;
239
240 irq = platform_get_irq(pdev, 0);
241 if (irq < 0) {
242 dev_err(dev, "platform_get_irq(pdev, 0) error: %d\n", irq);
243 return irq;
244 }
245
246 irq_data = irq_get_irq_data(irq);
247 if (!irq_data) {
248 dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq);
249 return -EINVAL;
250 }
251
Suman Anna6fb9a8f2017-08-01 10:48:41 -0500252 bootreg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
253 "host1cfg");
Robert Tivy13be5432013-04-09 14:20:21 -0700254 bootreg = devm_ioremap_resource(dev, bootreg_res);
255 if (IS_ERR(bootreg))
256 return PTR_ERR(bootreg);
257
Suman Anna6fb9a8f2017-08-01 10:48:41 -0500258 chipsig_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
259 "chipsig");
Robert Tivy13be5432013-04-09 14:20:21 -0700260 chipsig = devm_ioremap_resource(dev, chipsig_res);
261 if (IS_ERR(chipsig))
262 return PTR_ERR(chipsig);
263
264 dsp_clk = devm_clk_get(dev, NULL);
265 if (IS_ERR(dsp_clk)) {
266 dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk));
267
268 return PTR_ERR(dsp_clk);
269 }
270
Suman Anna61696582017-08-01 10:48:44 -0500271 if (dev->of_node) {
272 ret = of_reserved_mem_device_init(dev);
273 if (ret) {
274 dev_err(dev, "device does not have specific CMA pool: %d\n",
275 ret);
276 return ret;
277 }
278 }
279
Robert Tivy13be5432013-04-09 14:20:21 -0700280 rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name,
281 sizeof(*drproc));
Suman Anna61696582017-08-01 10:48:44 -0500282 if (!rproc) {
283 ret = -ENOMEM;
284 goto free_mem;
285 }
Robert Tivy13be5432013-04-09 14:20:21 -0700286
287 drproc = rproc->priv;
288 drproc->rproc = rproc;
Suman Anna470ac622017-05-18 17:09:00 -0500289 drproc->dsp_clk = dsp_clk;
Suman Anna315491e2015-01-09 15:21:58 -0600290 rproc->has_iommu = false;
Robert Tivy13be5432013-04-09 14:20:21 -0700291
Suman Anna59b23552017-08-01 10:48:42 -0500292 ret = da8xx_rproc_get_internal_memories(pdev, drproc);
293 if (ret)
294 goto free_rproc;
295
Robert Tivy13be5432013-04-09 14:20:21 -0700296 platform_set_drvdata(pdev, rproc);
297
298 /* everything the ISR needs is now setup, so hook it up */
299 ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback,
300 handle_event, 0, "da8xx-remoteproc",
301 rproc);
302 if (ret) {
303 dev_err(dev, "devm_request_threaded_irq error: %d\n", ret);
304 goto free_rproc;
305 }
306
307 /*
308 * rproc_add() can end up enabling the DSP's clk with the DSP
309 * *not* in reset, but da8xx_rproc_start() needs the DSP to be
310 * held in reset at the time it is called.
311 */
Suman Anna470ac622017-05-18 17:09:00 -0500312 ret = davinci_clk_reset_assert(drproc->dsp_clk);
Robert Tivy13be5432013-04-09 14:20:21 -0700313 if (ret)
314 goto free_rproc;
315
316 drproc->chipsig = chipsig;
317 drproc->bootreg = bootreg;
318 drproc->ack_fxn = irq_data->chip->irq_ack;
319 drproc->irq_data = irq_data;
320 drproc->irq = irq;
Robert Tivy13be5432013-04-09 14:20:21 -0700321
322 ret = rproc_add(rproc);
323 if (ret) {
324 dev_err(dev, "rproc_add failed: %d\n", ret);
325 goto free_rproc;
326 }
327
328 return 0;
329
330free_rproc:
Bjorn Andersson433c0e02016-10-02 17:46:38 -0700331 rproc_free(rproc);
Suman Anna61696582017-08-01 10:48:44 -0500332free_mem:
333 if (dev->of_node)
334 of_reserved_mem_device_release(dev);
Robert Tivy13be5432013-04-09 14:20:21 -0700335 return ret;
336}
337
338static int da8xx_rproc_remove(struct platform_device *pdev)
339{
Robert Tivy13be5432013-04-09 14:20:21 -0700340 struct rproc *rproc = platform_get_drvdata(pdev);
341 struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
Suman Anna61696582017-08-01 10:48:44 -0500342 struct device *dev = &pdev->dev;
Robert Tivy13be5432013-04-09 14:20:21 -0700343
344 /*
Robert Tivy13be5432013-04-09 14:20:21 -0700345 * The devm subsystem might end up releasing things before
346 * freeing the irq, thus allowing an interrupt to sneak in while
347 * the device is being removed. This should prevent that.
348 */
349 disable_irq(drproc->irq);
350
Robert Tivy13be5432013-04-09 14:20:21 -0700351 rproc_del(rproc);
Bjorn Andersson433c0e02016-10-02 17:46:38 -0700352 rproc_free(rproc);
Suman Anna61696582017-08-01 10:48:44 -0500353 if (dev->of_node)
354 of_reserved_mem_device_release(dev);
Robert Tivy13be5432013-04-09 14:20:21 -0700355
356 return 0;
357}
358
Suman Anna61696582017-08-01 10:48:44 -0500359static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = {
360 { .compatible = "ti,da850-dsp", },
361 { /* sentinel */ },
362};
363MODULE_DEVICE_TABLE(of, davinci_rproc_of_match);
364
Robert Tivy13be5432013-04-09 14:20:21 -0700365static struct platform_driver da8xx_rproc_driver = {
366 .probe = da8xx_rproc_probe,
367 .remove = da8xx_rproc_remove,
368 .driver = {
369 .name = "davinci-rproc",
Suman Anna61696582017-08-01 10:48:44 -0500370 .of_match_table = of_match_ptr(davinci_rproc_of_match),
Robert Tivy13be5432013-04-09 14:20:21 -0700371 },
372};
373
374module_platform_driver(da8xx_rproc_driver);
375
376MODULE_LICENSE("GPL v2");
377MODULE_DESCRIPTION("DA8XX Remote Processor control driver");