diff options
-rw-r--r-- | arch/arm/plat-omap/include/plat/remoteproc.h | 57 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 21 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 1 | ||||
-rw-r--r-- | drivers/remoteproc/omap_remoteproc.c | 249 | ||||
-rw-r--r-- | drivers/remoteproc/omap_remoteproc.h | 69 |
5 files changed, 397 insertions, 0 deletions
diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h new file mode 100644 index 000000000000..b10eac89e2e9 --- /dev/null +++ b/arch/arm/plat-omap/include/plat/remoteproc.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Remote Processor - omap-specific bits | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2011 Google, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _PLAT_REMOTEPROC_H | ||
18 | #define _PLAT_REMOTEPROC_H | ||
19 | |||
20 | struct rproc_ops; | ||
21 | struct platform_device; | ||
22 | |||
23 | /* | ||
24 | * struct omap_rproc_pdata - omap remoteproc's platform data | ||
25 | * @name: the remoteproc's name | ||
26 | * @oh_name: omap hwmod device | ||
27 | * @oh_name_opt: optional, secondary omap hwmod device | ||
28 | * @firmware: name of firmware file to load | ||
29 | * @mbox_name: name of omap mailbox device to use with this rproc | ||
30 | * @ops: start/stop rproc handlers | ||
31 | * @device_enable: omap-specific handler for enabling a device | ||
32 | * @device_shutdown: omap-specific handler for shutting down a device | ||
33 | */ | ||
34 | struct omap_rproc_pdata { | ||
35 | const char *name; | ||
36 | const char *oh_name; | ||
37 | const char *oh_name_opt; | ||
38 | const char *firmware; | ||
39 | const char *mbox_name; | ||
40 | const struct rproc_ops *ops; | ||
41 | int (*device_enable) (struct platform_device *pdev); | ||
42 | int (*device_shutdown) (struct platform_device *pdev); | ||
43 | }; | ||
44 | |||
45 | #if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE) | ||
46 | |||
47 | void __init omap_rproc_reserve_cma(void); | ||
48 | |||
49 | #else | ||
50 | |||
51 | void __init omap_rproc_reserve_cma(void) | ||
52 | { | ||
53 | } | ||
54 | |||
55 | #endif | ||
56 | |||
57 | #endif /* _PLAT_REMOTEPROC_H */ | ||
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index b250b15c0686..396c97a2661f 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig | |||
@@ -1,3 +1,24 @@ | |||
1 | # REMOTEPROC gets selected by whoever wants it | 1 | # REMOTEPROC gets selected by whoever wants it |
2 | config REMOTEPROC | 2 | config REMOTEPROC |
3 | tristate | 3 | tristate |
4 | |||
5 | config OMAP_REMOTEPROC | ||
6 | tristate "OMAP remoteproc support" | ||
7 | depends on ARCH_OMAP4 | ||
8 | select OMAP_IOMMU | ||
9 | select REMOTEPROC | ||
10 | select OMAP_MBOX_FWK | ||
11 | select RPMSG | ||
12 | default m | ||
13 | help | ||
14 | Say y here to support OMAP's remote processors (dual M3 | ||
15 | and DSP on OMAP4) via the remote processor framework. | ||
16 | |||
17 | Currently only supported on OMAP4. | ||
18 | |||
19 | Usually you want to say y here, in order to enable multimedia | ||
20 | use-cases to run on your platform (multimedia codecs are | ||
21 | offloaded to remote DSP processors using this framework). | ||
22 | |||
23 | It's safe to say n here if you're not interested in multimedia | ||
24 | offloading or just want a bare minimum kernel. | ||
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 370dffd54fee..df0897f69e16 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o | |||
6 | remoteproc-y := remoteproc_core.o | 6 | remoteproc-y := remoteproc_core.o |
7 | remoteproc-y += remoteproc_debugfs.o | 7 | remoteproc-y += remoteproc_debugfs.o |
8 | remoteproc-y += remoteproc_rpmsg.o | 8 | remoteproc-y += remoteproc_rpmsg.o |
9 | obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o | ||
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c new file mode 100644 index 000000000000..b49ecbb91ef3 --- /dev/null +++ b/drivers/remoteproc/omap_remoteproc.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * OMAP Remote Processor driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2011 Google, Inc. | ||
6 | * | ||
7 | * Ohad Ben-Cohen <ohad@wizery.com> | ||
8 | * Brian Swetland <swetland@google.com> | ||
9 | * Fernando Guzman Lugo <fernando.lugo@ti.com> | ||
10 | * Mark Grosen <mgrosen@ti.com> | ||
11 | * Suman Anna <s-anna@ti.com> | ||
12 | * Hari Kanigeri <h-kanigeri2@ti.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * version 2 as published by the Free Software Foundation. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
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 | |||
31 | #include <plat/mailbox.h> | ||
32 | #include <plat/remoteproc.h> | ||
33 | |||
34 | #include "omap_remoteproc.h" | ||
35 | #include "remoteproc_internal.h" | ||
36 | |||
37 | /** | ||
38 | * struct omap_rproc - omap remote processor state | ||
39 | * @mbox: omap mailbox handle | ||
40 | * @nb: notifier block that will be invoked on inbound mailbox messages | ||
41 | * @rproc: rproc handle | ||
42 | */ | ||
43 | struct omap_rproc { | ||
44 | struct omap_mbox *mbox; | ||
45 | struct notifier_block nb; | ||
46 | struct rproc *rproc; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * omap_rproc_mbox_callback() - inbound mailbox message handler | ||
51 | * @this: notifier block | ||
52 | * @index: unused | ||
53 | * @data: mailbox payload | ||
54 | * | ||
55 | * This handler is invoked by omap's mailbox driver whenever a mailbox | ||
56 | * message is received. Usually, the mailbox payload simply contains | ||
57 | * the index of the virtqueue that is kicked by the remote processor, | ||
58 | * and we let remoteproc core handle it. | ||
59 | * | ||
60 | * In addition to virtqueue indices, we also have some out-of-band values | ||
61 | * that indicates different events. Those values are deliberately very | ||
62 | * big so they don't coincide with virtqueue indices. | ||
63 | */ | ||
64 | static int omap_rproc_mbox_callback(struct notifier_block *this, | ||
65 | unsigned long index, void *data) | ||
66 | { | ||
67 | mbox_msg_t msg = (mbox_msg_t) data; | ||
68 | struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb); | ||
69 | struct device *dev = oproc->rproc->dev; | ||
70 | const char *name = oproc->rproc->name; | ||
71 | |||
72 | dev_dbg(dev, "mbox msg: 0x%x\n", msg); | ||
73 | |||
74 | switch (msg) { | ||
75 | case RP_MBOX_CRASH: | ||
76 | /* just log this for now. later, we'll also do recovery */ | ||
77 | dev_err(dev, "omap rproc %s crashed\n", name); | ||
78 | break; | ||
79 | case RP_MBOX_ECHO_REPLY: | ||
80 | dev_info(dev, "received echo reply from %s\n", name); | ||
81 | break; | ||
82 | default: | ||
83 | /* ignore vq indices which are too large to be valid */ | ||
84 | if (msg >= 2) { | ||
85 | dev_warn(dev, "invalid mbox msg: 0x%x\n", msg); | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * At this point, 'msg' contains the index of the vring | ||
91 | * which was just triggered. | ||
92 | */ | ||
93 | if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE) | ||
94 | dev_dbg(dev, "no message was found in vqid %d\n", msg); | ||
95 | } | ||
96 | |||
97 | return NOTIFY_DONE; | ||
98 | } | ||
99 | |||
100 | /* kick a virtqueue */ | ||
101 | static void omap_rproc_kick(struct rproc *rproc, int vqid) | ||
102 | { | ||
103 | struct omap_rproc *oproc = rproc->priv; | ||
104 | int ret; | ||
105 | |||
106 | /* send the index of the triggered virtqueue in the mailbox payload */ | ||
107 | ret = omap_mbox_msg_send(oproc->mbox, vqid); | ||
108 | if (ret) | ||
109 | dev_err(rproc->dev, "omap_mbox_msg_send failed: %d\n", ret); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Power up the remote processor. | ||
114 | * | ||
115 | * This function will be invoked only after the firmware for this rproc | ||
116 | * was loaded, parsed successfully, and all of its resource requirements | ||
117 | * were met. | ||
118 | */ | ||
119 | static int omap_rproc_start(struct rproc *rproc) | ||
120 | { | ||
121 | struct omap_rproc *oproc = rproc->priv; | ||
122 | struct platform_device *pdev = to_platform_device(rproc->dev); | ||
123 | struct omap_rproc_pdata *pdata = pdev->dev.platform_data; | ||
124 | int ret; | ||
125 | |||
126 | oproc->nb.notifier_call = omap_rproc_mbox_callback; | ||
127 | |||
128 | /* every omap rproc is assigned a mailbox instance for messaging */ | ||
129 | oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb); | ||
130 | if (IS_ERR(oproc->mbox)) { | ||
131 | ret = PTR_ERR(oproc->mbox); | ||
132 | dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * Ping the remote processor. this is only for sanity-sake; | ||
138 | * there is no functional effect whatsoever. | ||
139 | * | ||
140 | * Note that the reply will _not_ arrive immediately: this message | ||
141 | * will wait in the mailbox fifo until the remote processor is booted. | ||
142 | */ | ||
143 | ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST); | ||
144 | if (ret) { | ||
145 | dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret); | ||
146 | goto put_mbox; | ||
147 | } | ||
148 | |||
149 | ret = pdata->device_enable(pdev); | ||
150 | if (ret) { | ||
151 | dev_err(rproc->dev, "omap_device_enable failed: %d\n", ret); | ||
152 | goto put_mbox; | ||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | put_mbox: | ||
158 | omap_mbox_put(oproc->mbox, &oproc->nb); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | /* power off the remote processor */ | ||
163 | static int omap_rproc_stop(struct rproc *rproc) | ||
164 | { | ||
165 | struct platform_device *pdev = to_platform_device(rproc->dev); | ||
166 | struct omap_rproc_pdata *pdata = pdev->dev.platform_data; | ||
167 | struct omap_rproc *oproc = rproc->priv; | ||
168 | int ret; | ||
169 | |||
170 | ret = pdata->device_shutdown(pdev); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | omap_mbox_put(oproc->mbox, &oproc->nb); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static struct rproc_ops omap_rproc_ops = { | ||
180 | .start = omap_rproc_start, | ||
181 | .stop = omap_rproc_stop, | ||
182 | .kick = omap_rproc_kick, | ||
183 | }; | ||
184 | |||
185 | static int __devinit omap_rproc_probe(struct platform_device *pdev) | ||
186 | { | ||
187 | struct omap_rproc_pdata *pdata = pdev->dev.platform_data; | ||
188 | struct omap_rproc *oproc; | ||
189 | struct rproc *rproc; | ||
190 | int ret; | ||
191 | |||
192 | ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | ||
193 | if (ret) { | ||
194 | dev_err(pdev->dev.parent, "dma_set_coherent_mask: %d\n", ret); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops, | ||
199 | pdata->firmware, sizeof(*oproc)); | ||
200 | if (!rproc) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | oproc = rproc->priv; | ||
204 | oproc->rproc = rproc; | ||
205 | |||
206 | platform_set_drvdata(pdev, rproc); | ||
207 | |||
208 | ret = rproc_register(rproc); | ||
209 | if (ret) | ||
210 | goto free_rproc; | ||
211 | |||
212 | return 0; | ||
213 | |||
214 | free_rproc: | ||
215 | rproc_free(rproc); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int __devexit omap_rproc_remove(struct platform_device *pdev) | ||
220 | { | ||
221 | struct rproc *rproc = platform_get_drvdata(pdev); | ||
222 | |||
223 | return rproc_unregister(rproc); | ||
224 | } | ||
225 | |||
226 | static struct platform_driver omap_rproc_driver = { | ||
227 | .probe = omap_rproc_probe, | ||
228 | .remove = __devexit_p(omap_rproc_remove), | ||
229 | .driver = { | ||
230 | .name = "omap-rproc", | ||
231 | .owner = THIS_MODULE, | ||
232 | }, | ||
233 | }; | ||
234 | |||
235 | /* most of the below will go when module_platform_driver is merged */ | ||
236 | static int __init omap_rproc_init(void) | ||
237 | { | ||
238 | return platform_driver_register(&omap_rproc_driver); | ||
239 | } | ||
240 | module_init(omap_rproc_init); | ||
241 | |||
242 | static void __exit omap_rproc_exit(void) | ||
243 | { | ||
244 | platform_driver_unregister(&omap_rproc_driver); | ||
245 | } | ||
246 | module_exit(omap_rproc_exit); | ||
247 | |||
248 | MODULE_LICENSE("GPL v2"); | ||
249 | MODULE_DESCRIPTION("OMAP Remote Processor control driver"); | ||
diff --git a/drivers/remoteproc/omap_remoteproc.h b/drivers/remoteproc/omap_remoteproc.h new file mode 100644 index 000000000000..f6d2036d383d --- /dev/null +++ b/drivers/remoteproc/omap_remoteproc.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Remote processor messaging | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2011 Google, Inc. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer. | ||
14 | * * Redistributions in binary form must reproduce the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer in | ||
16 | * the documentation and/or other materials provided with the | ||
17 | * distribution. | ||
18 | * * Neither the name Texas Instruments nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #ifndef _OMAP_RPMSG_H | ||
36 | #define _OMAP_RPMSG_H | ||
37 | |||
38 | /* | ||
39 | * enum - Predefined Mailbox Messages | ||
40 | * | ||
41 | * @RP_MBOX_READY: informs the M3's that we're up and running. this is | ||
42 | * part of the init sequence sent that the M3 expects to see immediately | ||
43 | * after it is booted. | ||
44 | * | ||
45 | * @RP_MBOX_PENDING_MSG: informs the receiver that there is an inbound | ||
46 | * message waiting in its own receive-side vring. please note that currently | ||
47 | * this message is optional: alternatively, one can explicitly send the index | ||
48 | * of the triggered virtqueue itself. the preferred approach will be decided | ||
49 | * as we progress and experiment with those two different approaches. | ||
50 | * | ||
51 | * @RP_MBOX_CRASH: this message is sent if BIOS crashes | ||
52 | * | ||
53 | * @RP_MBOX_ECHO_REQUEST: a mailbox-level "ping" message. | ||
54 | * | ||
55 | * @RP_MBOX_ECHO_REPLY: a mailbox-level reply to a "ping" | ||
56 | * | ||
57 | * @RP_MBOX_ABORT_REQUEST: a "please crash" request, used for testing the | ||
58 | * recovery mechanism (to some extent). | ||
59 | */ | ||
60 | enum omap_rp_mbox_messages { | ||
61 | RP_MBOX_READY = 0xFFFFFF00, | ||
62 | RP_MBOX_PENDING_MSG = 0xFFFFFF01, | ||
63 | RP_MBOX_CRASH = 0xFFFFFF02, | ||
64 | RP_MBOX_ECHO_REQUEST = 0xFFFFFF03, | ||
65 | RP_MBOX_ECHO_REPLY = 0xFFFFFF04, | ||
66 | RP_MBOX_ABORT_REQUEST = 0xFFFFFF05, | ||
67 | }; | ||
68 | |||
69 | #endif /* _OMAP_RPMSG_H */ | ||