diff options
| author | Loic Pallardy <loic.pallardy@st.com> | 2017-01-31 07:35:54 -0500 |
|---|---|---|
| committer | Bjorn Andersson <bjorn.andersson@linaro.org> | 2017-02-06 16:10:12 -0500 |
| commit | 231c8dfd1a9ff530869e1327ba4168dbe592f3f9 (patch) | |
| tree | 9d94a97973571c838159cbd8bb70e40c692244d2 | |
| parent | 3e49ecf6b49c31b70235d260b957376c00265c1e (diff) | |
remoteproc: st: add virtio communication support
This patch provides virtio communication support based on mailbox
for ST co-processors.
Signed-off-by: Loic Pallardy <loic.pallardy@st.com>
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
| -rw-r--r-- | drivers/remoteproc/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/remoteproc/st_remoteproc.c | 113 |
2 files changed, 114 insertions, 2 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 402de7089302..65f86bc24c07 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig | |||
| @@ -118,6 +118,9 @@ config ST_REMOTEPROC | |||
| 118 | tristate "ST remoteproc support" | 118 | tristate "ST remoteproc support" |
| 119 | depends on ARCH_STI | 119 | depends on ARCH_STI |
| 120 | depends on REMOTEPROC | 120 | depends on REMOTEPROC |
| 121 | select MAILBOX | ||
| 122 | select STI_MBOX | ||
| 123 | select RPMSG_VIRTIO | ||
| 121 | help | 124 | help |
| 122 | Say y here to support ST's adjunct processors via the remote | 125 | Say y here to support ST's adjunct processors via the remote |
| 123 | processor framework. | 126 | processor framework. |
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index 1468ba213811..d534bf23dc56 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/mailbox_client.h> | ||
| 18 | #include <linux/mfd/syscon.h> | 19 | #include <linux/mfd/syscon.h> |
| 19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 20 | #include <linux/of.h> | 21 | #include <linux/of.h> |
| @@ -25,6 +26,16 @@ | |||
| 25 | #include <linux/remoteproc.h> | 26 | #include <linux/remoteproc.h> |
| 26 | #include <linux/reset.h> | 27 | #include <linux/reset.h> |
| 27 | 28 | ||
| 29 | #include "remoteproc_internal.h" | ||
| 30 | |||
| 31 | #define ST_RPROC_VQ0 0 | ||
| 32 | #define ST_RPROC_VQ1 1 | ||
| 33 | #define ST_RPROC_MAX_VRING 2 | ||
| 34 | |||
| 35 | #define MBOX_RX 0 | ||
| 36 | #define MBOX_TX 1 | ||
| 37 | #define MBOX_MAX 2 | ||
| 38 | |||
| 28 | struct st_rproc_config { | 39 | struct st_rproc_config { |
| 29 | bool sw_reset; | 40 | bool sw_reset; |
| 30 | bool pwr_reset; | 41 | bool pwr_reset; |
| @@ -39,8 +50,47 @@ struct st_rproc { | |||
| 39 | u32 clk_rate; | 50 | u32 clk_rate; |
| 40 | struct regmap *boot_base; | 51 | struct regmap *boot_base; |
| 41 | u32 boot_offset; | 52 | u32 boot_offset; |
| 53 | struct mbox_chan *mbox_chan[ST_RPROC_MAX_VRING * MBOX_MAX]; | ||
| 54 | struct mbox_client mbox_client_vq0; | ||
| 55 | struct mbox_client mbox_client_vq1; | ||
| 42 | }; | 56 | }; |
| 43 | 57 | ||
| 58 | static void st_rproc_mbox_callback(struct device *dev, u32 msg) | ||
| 59 | { | ||
| 60 | struct rproc *rproc = dev_get_drvdata(dev); | ||
| 61 | |||
| 62 | if (rproc_vq_interrupt(rproc, msg) == IRQ_NONE) | ||
| 63 | dev_dbg(dev, "no message was found in vqid %d\n", msg); | ||
| 64 | } | ||
| 65 | |||
| 66 | static | ||
| 67 | void st_rproc_mbox_callback_vq0(struct mbox_client *mbox_client, void *data) | ||
| 68 | { | ||
| 69 | st_rproc_mbox_callback(mbox_client->dev, 0); | ||
| 70 | } | ||
| 71 | |||
| 72 | static | ||
| 73 | void st_rproc_mbox_callback_vq1(struct mbox_client *mbox_client, void *data) | ||
| 74 | { | ||
| 75 | st_rproc_mbox_callback(mbox_client->dev, 1); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void st_rproc_kick(struct rproc *rproc, int vqid) | ||
| 79 | { | ||
| 80 | struct st_rproc *ddata = rproc->priv; | ||
| 81 | struct device *dev = rproc->dev.parent; | ||
| 82 | int ret; | ||
| 83 | |||
| 84 | /* send the index of the triggered virtqueue in the mailbox payload */ | ||
| 85 | if (WARN_ON(vqid >= ST_RPROC_MAX_VRING)) | ||
| 86 | return; | ||
| 87 | |||
| 88 | ret = mbox_send_message(ddata->mbox_chan[vqid * MBOX_MAX + MBOX_TX], | ||
| 89 | (void *)&vqid); | ||
| 90 | if (ret < 0) | ||
| 91 | dev_err(dev, "failed to send message via mbox: %d\n", ret); | ||
| 92 | } | ||
| 93 | |||
| 44 | static int st_rproc_start(struct rproc *rproc) | 94 | static int st_rproc_start(struct rproc *rproc) |
| 45 | { | 95 | { |
| 46 | struct st_rproc *ddata = rproc->priv; | 96 | struct st_rproc *ddata = rproc->priv; |
| @@ -108,6 +158,7 @@ static int st_rproc_stop(struct rproc *rproc) | |||
| 108 | } | 158 | } |
| 109 | 159 | ||
| 110 | static const struct rproc_ops st_rproc_ops = { | 160 | static const struct rproc_ops st_rproc_ops = { |
| 161 | .kick = st_rproc_kick, | ||
| 111 | .start = st_rproc_start, | 162 | .start = st_rproc_start, |
| 112 | .stop = st_rproc_stop, | 163 | .stop = st_rproc_stop, |
| 113 | }; | 164 | }; |
| @@ -221,8 +272,9 @@ static int st_rproc_probe(struct platform_device *pdev) | |||
| 221 | struct st_rproc *ddata; | 272 | struct st_rproc *ddata; |
| 222 | struct device_node *np = dev->of_node; | 273 | struct device_node *np = dev->of_node; |
| 223 | struct rproc *rproc; | 274 | struct rproc *rproc; |
| 275 | struct mbox_chan *chan; | ||
| 224 | int enabled; | 276 | int enabled; |
| 225 | int ret; | 277 | int ret, i; |
| 226 | 278 | ||
| 227 | match = of_match_device(st_rproc_match, dev); | 279 | match = of_match_device(st_rproc_match, dev); |
| 228 | if (!match || !match->data) { | 280 | if (!match || !match->data) { |
| @@ -257,12 +309,65 @@ static int st_rproc_probe(struct platform_device *pdev) | |||
| 257 | clk_set_rate(ddata->clk, ddata->clk_rate); | 309 | clk_set_rate(ddata->clk, ddata->clk_rate); |
| 258 | } | 310 | } |
| 259 | 311 | ||
| 312 | if (of_get_property(np, "mbox-names", NULL)) { | ||
| 313 | ddata->mbox_client_vq0.dev = dev; | ||
| 314 | ddata->mbox_client_vq0.tx_done = NULL; | ||
| 315 | ddata->mbox_client_vq0.tx_block = false; | ||
| 316 | ddata->mbox_client_vq0.knows_txdone = false; | ||
| 317 | ddata->mbox_client_vq0.rx_callback = st_rproc_mbox_callback_vq0; | ||
| 318 | |||
| 319 | ddata->mbox_client_vq1.dev = dev; | ||
| 320 | ddata->mbox_client_vq1.tx_done = NULL; | ||
| 321 | ddata->mbox_client_vq1.tx_block = false; | ||
| 322 | ddata->mbox_client_vq1.knows_txdone = false; | ||
| 323 | ddata->mbox_client_vq1.rx_callback = st_rproc_mbox_callback_vq1; | ||
| 324 | |||
| 325 | /* | ||
| 326 | * To control a co-processor without IPC mechanism. | ||
| 327 | * This driver can be used without mbox and rpmsg. | ||
| 328 | */ | ||
| 329 | chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_rx"); | ||
| 330 | if (IS_ERR(chan)) { | ||
| 331 | dev_err(&rproc->dev, "failed to request mbox chan 0\n"); | ||
| 332 | ret = PTR_ERR(chan); | ||
| 333 | goto free_clk; | ||
| 334 | } | ||
| 335 | ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_RX] = chan; | ||
| 336 | |||
| 337 | chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_tx"); | ||
| 338 | if (IS_ERR(chan)) { | ||
| 339 | dev_err(&rproc->dev, "failed to request mbox chan 0\n"); | ||
| 340 | ret = PTR_ERR(chan); | ||
| 341 | goto free_mbox; | ||
| 342 | } | ||
| 343 | ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_TX] = chan; | ||
| 344 | |||
| 345 | chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_rx"); | ||
| 346 | if (IS_ERR(chan)) { | ||
| 347 | dev_err(&rproc->dev, "failed to request mbox chan 1\n"); | ||
| 348 | ret = PTR_ERR(chan); | ||
| 349 | goto free_mbox; | ||
| 350 | } | ||
| 351 | ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_RX] = chan; | ||
| 352 | |||
| 353 | chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_tx"); | ||
| 354 | if (IS_ERR(chan)) { | ||
| 355 | dev_err(&rproc->dev, "failed to request mbox chan 1\n"); | ||
| 356 | ret = PTR_ERR(chan); | ||
| 357 | goto free_mbox; | ||
| 358 | } | ||
| 359 | ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_TX] = chan; | ||
| 360 | } | ||
| 361 | |||
| 260 | ret = rproc_add(rproc); | 362 | ret = rproc_add(rproc); |
| 261 | if (ret) | 363 | if (ret) |
| 262 | goto free_clk; | 364 | goto free_mbox; |
| 263 | 365 | ||
| 264 | return 0; | 366 | return 0; |
| 265 | 367 | ||
| 368 | free_mbox: | ||
| 369 | for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) | ||
| 370 | mbox_free_channel(ddata->mbox_chan[i]); | ||
| 266 | free_clk: | 371 | free_clk: |
| 267 | clk_unprepare(ddata->clk); | 372 | clk_unprepare(ddata->clk); |
| 268 | free_rproc: | 373 | free_rproc: |
| @@ -274,6 +379,7 @@ static int st_rproc_remove(struct platform_device *pdev) | |||
| 274 | { | 379 | { |
| 275 | struct rproc *rproc = platform_get_drvdata(pdev); | 380 | struct rproc *rproc = platform_get_drvdata(pdev); |
| 276 | struct st_rproc *ddata = rproc->priv; | 381 | struct st_rproc *ddata = rproc->priv; |
| 382 | int i; | ||
| 277 | 383 | ||
| 278 | rproc_del(rproc); | 384 | rproc_del(rproc); |
| 279 | 385 | ||
| @@ -281,6 +387,9 @@ static int st_rproc_remove(struct platform_device *pdev) | |||
| 281 | 387 | ||
| 282 | of_reserved_mem_device_release(&pdev->dev); | 388 | of_reserved_mem_device_release(&pdev->dev); |
| 283 | 389 | ||
| 390 | for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) | ||
| 391 | mbox_free_channel(ddata->mbox_chan[i]); | ||
| 392 | |||
| 284 | rproc_free(rproc); | 393 | rproc_free(rproc); |
| 285 | 394 | ||
| 286 | return 0; | 395 | return 0; |
