Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rpmsg: add rpmsg support for mt8183 SCP.

Add a simple rpmsg support for mt8183 SCP, that use IPI / IPC directly.

Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
Link: https://lore.kernel.org/r/20191112110330.179649-4-pihsun@chromium.org
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

authored by

Pi-Hsun Shih and committed by
Bjorn Andersson
70179969 63c13d61

+525 -5
+1
drivers/remoteproc/Kconfig
··· 26 26 config MTK_SCP 27 27 tristate "Mediatek SCP support" 28 28 depends on ARCH_MEDIATEK 29 + select RPMSG_MTK_SCP 29 30 help 30 31 Say y here to support Mediatek's System Companion Processor (SCP) via 31 32 the remote processor framework.
+2
drivers/remoteproc/mtk_common.h
··· 70 70 void __iomem *cpu_addr; 71 71 phys_addr_t phys_addr; 72 72 size_t dram_size; 73 + 74 + struct rproc_subdev *rpmsg_subdev; 73 75 }; 74 76 75 77 /**
+57 -4
drivers/remoteproc/mtk_scp.c
··· 15 15 #include <linux/platform_device.h> 16 16 #include <linux/remoteproc.h> 17 17 #include <linux/remoteproc/mtk_scp.h> 18 + #include <linux/rpmsg/mtk_rpmsg.h> 18 19 19 20 #include "mtk_common.h" 20 21 #include "remoteproc_internal.h" ··· 465 464 of_reserved_mem_device_release(scp->dev); 466 465 } 467 466 467 + static int scp_register_ipi(struct platform_device *pdev, u32 id, 468 + ipi_handler_t handler, void *priv) 469 + { 470 + struct mtk_scp *scp = platform_get_drvdata(pdev); 471 + 472 + return scp_ipi_register(scp, id, handler, priv); 473 + } 474 + 475 + static void scp_unregister_ipi(struct platform_device *pdev, u32 id) 476 + { 477 + struct mtk_scp *scp = platform_get_drvdata(pdev); 478 + 479 + scp_ipi_unregister(scp, id); 480 + } 481 + 482 + static int scp_send_ipi(struct platform_device *pdev, u32 id, void *buf, 483 + unsigned int len, unsigned int wait) 484 + { 485 + struct mtk_scp *scp = platform_get_drvdata(pdev); 486 + 487 + return scp_ipi_send(scp, id, buf, len, wait); 488 + } 489 + 490 + static struct mtk_rpmsg_info mtk_scp_rpmsg_info = { 491 + .send_ipi = scp_send_ipi, 492 + .register_ipi = scp_register_ipi, 493 + .unregister_ipi = scp_unregister_ipi, 494 + .ns_ipi_id = SCP_IPI_NS_SERVICE, 495 + }; 496 + 497 + static void scp_add_rpmsg_subdev(struct mtk_scp *scp) 498 + { 499 + scp->rpmsg_subdev = 500 + mtk_rpmsg_create_rproc_subdev(to_platform_device(scp->dev), 501 + &mtk_scp_rpmsg_info); 502 + if (scp->rpmsg_subdev) 503 + rproc_add_subdev(scp->rproc, scp->rpmsg_subdev); 504 + } 505 + 506 + static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) 507 + { 508 + if (scp->rpmsg_subdev) { 509 + rproc_remove_subdev(scp->rproc, scp->rpmsg_subdev); 510 + mtk_rpmsg_destroy_rproc_subdev(scp->rpmsg_subdev); 511 + scp->rpmsg_subdev = NULL; 512 + } 513 + } 514 + 468 515 static int scp_probe(struct platform_device *pdev) 469 516 { 470 517 struct device *dev = &pdev->dev; ··· 593 544 init_waitqueue_head(&scp->run.wq); 594 545 init_waitqueue_head(&scp->ack_wq); 595 546 547 + scp_add_rpmsg_subdev(scp); 548 + 596 549 ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), NULL, 597 550 scp_irq_handler, IRQF_ONESHOT, 598 551 pdev->name, scp); 599 552 600 553 if (ret) { 601 554 dev_err(dev, "failed to request irq\n"); 602 - goto unregister_ipi; 555 + goto remove_subdev; 603 556 } 604 557 605 558 ret = rproc_add(rproc); 606 559 if (ret) 607 - goto unregister_ipi; 560 + goto remove_subdev; 608 561 609 - return ret; 562 + return 0; 610 563 611 - unregister_ipi: 564 + remove_subdev: 565 + scp_remove_rpmsg_subdev(scp); 612 566 scp_ipi_unregister(scp, SCP_IPI_INIT); 613 567 release_dev_mem: 614 568 scp_unmap_memory_region(scp); ··· 631 579 int i; 632 580 633 581 rproc_del(scp->rproc); 582 + scp_remove_rpmsg_subdev(scp); 634 583 scp_ipi_unregister(scp, SCP_IPI_INIT); 635 584 scp_unmap_memory_region(scp); 636 585 for (i = 0; i < SCP_IPI_MAX; i++)
+1
drivers/remoteproc/mtk_scp_ipi.c
··· 162 162 int ret; 163 163 164 164 if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) || 165 + WARN_ON(id == SCP_IPI_NS_SERVICE) || 165 166 WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf)) 166 167 return -EINVAL; 167 168
+9
drivers/rpmsg/Kconfig
··· 15 15 in /dev. They make it possible for user-space programs to send and 16 16 receive rpmsg packets. 17 17 18 + config RPMSG_MTK_SCP 19 + tristate "MediaTek SCP" 20 + depends on MTK_SCP 21 + select RPMSG 22 + help 23 + Say y here to enable support providing communication channels to 24 + remote processors in MediaTek platforms. 25 + This use IPI and IPC to communicate with remote processors. 26 + 18 27 config RPMSG_QCOM_GLINK_NATIVE 19 28 tristate 20 29 select RPMSG
+1
drivers/rpmsg/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_RPMSG) += rpmsg_core.o 3 3 obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o 4 + obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o 4 5 obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o 5 6 obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o 6 7 obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
+414
drivers/rpmsg/mtk_rpmsg.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // Copyright 2019 Google LLC. 4 + 5 + #include <linux/kernel.h> 6 + #include <linux/module.h> 7 + #include <linux/of.h> 8 + #include <linux/platform_device.h> 9 + #include <linux/remoteproc.h> 10 + #include <linux/rpmsg/mtk_rpmsg.h> 11 + #include <linux/workqueue.h> 12 + 13 + #include "rpmsg_internal.h" 14 + 15 + struct mtk_rpmsg_rproc_subdev { 16 + struct platform_device *pdev; 17 + struct mtk_rpmsg_info *info; 18 + struct rpmsg_endpoint *ns_ept; 19 + struct rproc_subdev subdev; 20 + 21 + struct work_struct register_work; 22 + struct list_head channels; 23 + struct mutex channels_lock; 24 + }; 25 + 26 + #define to_mtk_subdev(d) container_of(d, struct mtk_rpmsg_rproc_subdev, subdev) 27 + 28 + struct mtk_rpmsg_channel_info { 29 + struct rpmsg_channel_info info; 30 + bool registered; 31 + struct list_head list; 32 + }; 33 + 34 + /** 35 + * struct rpmsg_ns_msg - dynamic name service announcement message 36 + * @name: name of remote service that is published 37 + * @addr: address of remote service that is published 38 + * 39 + * This message is sent across to publish a new service. When we receive these 40 + * messages, an appropriate rpmsg channel (i.e device) is created. In turn, the 41 + * ->probe() handler of the appropriate rpmsg driver will be invoked 42 + * (if/as-soon-as one is registered). 43 + */ 44 + struct rpmsg_ns_msg { 45 + char name[RPMSG_NAME_SIZE]; 46 + u32 addr; 47 + } __packed; 48 + 49 + struct mtk_rpmsg_device { 50 + struct rpmsg_device rpdev; 51 + struct mtk_rpmsg_rproc_subdev *mtk_subdev; 52 + }; 53 + 54 + struct mtk_rpmsg_endpoint { 55 + struct rpmsg_endpoint ept; 56 + struct mtk_rpmsg_rproc_subdev *mtk_subdev; 57 + }; 58 + 59 + #define to_mtk_rpmsg_device(r) container_of(r, struct mtk_rpmsg_device, rpdev) 60 + #define to_mtk_rpmsg_endpoint(r) container_of(r, struct mtk_rpmsg_endpoint, ept) 61 + 62 + static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops; 63 + 64 + static void __mtk_ept_release(struct kref *kref) 65 + { 66 + struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint, 67 + refcount); 68 + kfree(to_mtk_rpmsg_endpoint(ept)); 69 + } 70 + 71 + static void mtk_rpmsg_ipi_handler(void *data, unsigned int len, void *priv) 72 + { 73 + struct mtk_rpmsg_endpoint *mept = priv; 74 + struct rpmsg_endpoint *ept = &mept->ept; 75 + int ret; 76 + 77 + ret = (*ept->cb)(ept->rpdev, data, len, ept->priv, ept->addr); 78 + if (ret) 79 + dev_warn(&ept->rpdev->dev, "rpmsg handler return error = %d", 80 + ret); 81 + } 82 + 83 + static struct rpmsg_endpoint * 84 + __mtk_create_ept(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 85 + struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, 86 + u32 id) 87 + { 88 + struct mtk_rpmsg_endpoint *mept; 89 + struct rpmsg_endpoint *ept; 90 + struct platform_device *pdev = mtk_subdev->pdev; 91 + int ret; 92 + 93 + mept = kzalloc(sizeof(*mept), GFP_KERNEL); 94 + if (!mept) 95 + return NULL; 96 + mept->mtk_subdev = mtk_subdev; 97 + 98 + ept = &mept->ept; 99 + kref_init(&ept->refcount); 100 + 101 + ept->rpdev = rpdev; 102 + ept->cb = cb; 103 + ept->priv = priv; 104 + ept->ops = &mtk_rpmsg_endpoint_ops; 105 + ept->addr = id; 106 + 107 + ret = mtk_subdev->info->register_ipi(pdev, id, mtk_rpmsg_ipi_handler, 108 + mept); 109 + if (ret) { 110 + dev_err(&pdev->dev, "IPI register failed, id = %d", id); 111 + kref_put(&ept->refcount, __mtk_ept_release); 112 + return NULL; 113 + } 114 + 115 + return ept; 116 + } 117 + 118 + static struct rpmsg_endpoint * 119 + mtk_rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, 120 + struct rpmsg_channel_info chinfo) 121 + { 122 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = 123 + to_mtk_rpmsg_device(rpdev)->mtk_subdev; 124 + 125 + return __mtk_create_ept(mtk_subdev, rpdev, cb, priv, chinfo.src); 126 + } 127 + 128 + static void mtk_rpmsg_destroy_ept(struct rpmsg_endpoint *ept) 129 + { 130 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = 131 + to_mtk_rpmsg_endpoint(ept)->mtk_subdev; 132 + 133 + mtk_subdev->info->unregister_ipi(mtk_subdev->pdev, ept->addr); 134 + kref_put(&ept->refcount, __mtk_ept_release); 135 + } 136 + 137 + static int mtk_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) 138 + { 139 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = 140 + to_mtk_rpmsg_endpoint(ept)->mtk_subdev; 141 + 142 + return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data, 143 + len, 0); 144 + } 145 + 146 + static int mtk_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) 147 + { 148 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = 149 + to_mtk_rpmsg_endpoint(ept)->mtk_subdev; 150 + 151 + /* 152 + * TODO: This currently is same as mtk_rpmsg_send, and wait until SCP 153 + * received the last command. 154 + */ 155 + return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data, 156 + len, 0); 157 + } 158 + 159 + static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops = { 160 + .destroy_ept = mtk_rpmsg_destroy_ept, 161 + .send = mtk_rpmsg_send, 162 + .trysend = mtk_rpmsg_trysend, 163 + }; 164 + 165 + static void mtk_rpmsg_release_device(struct device *dev) 166 + { 167 + struct rpmsg_device *rpdev = to_rpmsg_device(dev); 168 + struct mtk_rpmsg_device *mdev = to_mtk_rpmsg_device(rpdev); 169 + 170 + kfree(mdev); 171 + } 172 + 173 + static const struct rpmsg_device_ops mtk_rpmsg_device_ops = { 174 + .create_ept = mtk_rpmsg_create_ept, 175 + }; 176 + 177 + static struct device_node * 178 + mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel) 179 + { 180 + struct device_node *child; 181 + const char *name; 182 + int ret; 183 + 184 + for_each_available_child_of_node(node, child) { 185 + ret = of_property_read_string(child, "mtk,rpmsg-name", &name); 186 + if (ret) 187 + continue; 188 + 189 + if (strcmp(name, channel) == 0) 190 + return child; 191 + } 192 + 193 + return NULL; 194 + } 195 + 196 + static int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 197 + struct rpmsg_channel_info *info) 198 + { 199 + struct rpmsg_device *rpdev; 200 + struct mtk_rpmsg_device *mdev; 201 + struct platform_device *pdev = mtk_subdev->pdev; 202 + int ret; 203 + 204 + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 205 + if (!mdev) 206 + return -ENOMEM; 207 + 208 + mdev->mtk_subdev = mtk_subdev; 209 + 210 + rpdev = &mdev->rpdev; 211 + rpdev->ops = &mtk_rpmsg_device_ops; 212 + rpdev->src = info->src; 213 + rpdev->dst = info->dst; 214 + strscpy(rpdev->id.name, info->name, RPMSG_NAME_SIZE); 215 + 216 + rpdev->dev.of_node = 217 + mtk_rpmsg_match_device_subnode(pdev->dev.of_node, info->name); 218 + rpdev->dev.parent = &pdev->dev; 219 + rpdev->dev.release = mtk_rpmsg_release_device; 220 + 221 + ret = rpmsg_register_device(rpdev); 222 + if (ret) { 223 + kfree(mdev); 224 + return ret; 225 + } 226 + 227 + return 0; 228 + } 229 + 230 + static void mtk_register_device_work_function(struct work_struct *register_work) 231 + { 232 + struct mtk_rpmsg_rproc_subdev *subdev = container_of( 233 + register_work, struct mtk_rpmsg_rproc_subdev, register_work); 234 + struct platform_device *pdev = subdev->pdev; 235 + struct mtk_rpmsg_channel_info *info; 236 + int ret; 237 + 238 + mutex_lock(&subdev->channels_lock); 239 + list_for_each_entry(info, &subdev->channels, list) { 240 + if (info->registered) 241 + continue; 242 + 243 + ret = mtk_rpmsg_register_device(subdev, &info->info); 244 + if (ret) { 245 + dev_err(&pdev->dev, "Can't create rpmsg_device\n"); 246 + continue; 247 + } 248 + 249 + info->registered = true; 250 + } 251 + mutex_unlock(&subdev->channels_lock); 252 + } 253 + 254 + static int mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 255 + char *name, u32 addr) 256 + { 257 + struct mtk_rpmsg_channel_info *info; 258 + 259 + info = kzalloc(sizeof(*info), GFP_KERNEL); 260 + if (!info) 261 + return -ENOMEM; 262 + 263 + strscpy(info->info.name, name, RPMSG_NAME_SIZE); 264 + info->info.src = addr; 265 + info->info.dst = RPMSG_ADDR_ANY; 266 + mutex_lock(&mtk_subdev->channels_lock); 267 + list_add(&info->list, &mtk_subdev->channels); 268 + mutex_unlock(&mtk_subdev->channels_lock); 269 + 270 + schedule_work(&mtk_subdev->register_work); 271 + return 0; 272 + } 273 + 274 + static int mtk_rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len, 275 + void *priv, u32 src) 276 + { 277 + struct rpmsg_ns_msg *msg = data; 278 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = priv; 279 + struct device *dev = &mtk_subdev->pdev->dev; 280 + 281 + int ret; 282 + 283 + if (len != sizeof(*msg)) { 284 + dev_err(dev, "malformed ns msg (%d)\n", len); 285 + return -EINVAL; 286 + } 287 + 288 + /* 289 + * the name service ept does _not_ belong to a real rpmsg channel, 290 + * and is handled by the rpmsg bus itself. 291 + * for sanity reasons, make sure a valid rpdev has _not_ sneaked 292 + * in somehow. 293 + */ 294 + if (rpdev) { 295 + dev_err(dev, "anomaly: ns ept has an rpdev handle\n"); 296 + return -EINVAL; 297 + } 298 + 299 + /* don't trust the remote processor for null terminating the name */ 300 + msg->name[RPMSG_NAME_SIZE - 1] = '\0'; 301 + 302 + dev_info(dev, "creating channel %s addr 0x%x\n", msg->name, msg->addr); 303 + 304 + ret = mtk_rpmsg_create_device(mtk_subdev, msg->name, msg->addr); 305 + if (ret) { 306 + dev_err(dev, "create rpmsg device failed\n"); 307 + return ret; 308 + } 309 + 310 + return 0; 311 + } 312 + 313 + static int mtk_rpmsg_prepare(struct rproc_subdev *subdev) 314 + { 315 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 316 + 317 + /* a dedicated endpoint handles the name service msgs */ 318 + if (mtk_subdev->info->ns_ipi_id >= 0) { 319 + mtk_subdev->ns_ept = 320 + __mtk_create_ept(mtk_subdev, NULL, mtk_rpmsg_ns_cb, 321 + mtk_subdev, 322 + mtk_subdev->info->ns_ipi_id); 323 + if (!mtk_subdev->ns_ept) { 324 + dev_err(&mtk_subdev->pdev->dev, 325 + "failed to create name service endpoint\n"); 326 + return -ENOMEM; 327 + } 328 + } 329 + 330 + return 0; 331 + } 332 + 333 + static void mtk_rpmsg_unprepare(struct rproc_subdev *subdev) 334 + { 335 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 336 + 337 + if (mtk_subdev->ns_ept) { 338 + mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); 339 + mtk_subdev->ns_ept = NULL; 340 + } 341 + } 342 + 343 + static void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed) 344 + { 345 + struct mtk_rpmsg_channel_info *info, *next; 346 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 347 + struct device *dev = &mtk_subdev->pdev->dev; 348 + 349 + /* 350 + * Destroy the name service endpoint here, to avoid new channel being 351 + * created after the rpmsg_unregister_device loop below. 352 + */ 353 + if (mtk_subdev->ns_ept) { 354 + mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); 355 + mtk_subdev->ns_ept = NULL; 356 + } 357 + 358 + cancel_work_sync(&mtk_subdev->register_work); 359 + 360 + mutex_lock(&mtk_subdev->channels_lock); 361 + list_for_each_entry(info, &mtk_subdev->channels, list) { 362 + if (!info->registered) 363 + continue; 364 + if (rpmsg_unregister_device(dev, &info->info)) { 365 + dev_warn( 366 + dev, 367 + "rpmsg_unregister_device failed for %s.%d.%d\n", 368 + info->info.name, info->info.src, 369 + info->info.dst); 370 + } 371 + } 372 + 373 + list_for_each_entry_safe(info, next, 374 + &mtk_subdev->channels, list) { 375 + list_del(&info->list); 376 + kfree(info); 377 + } 378 + mutex_unlock(&mtk_subdev->channels_lock); 379 + } 380 + 381 + struct rproc_subdev * 382 + mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev, 383 + struct mtk_rpmsg_info *info) 384 + { 385 + struct mtk_rpmsg_rproc_subdev *mtk_subdev; 386 + 387 + mtk_subdev = kzalloc(sizeof(*mtk_subdev), GFP_KERNEL); 388 + if (!mtk_subdev) 389 + return NULL; 390 + 391 + mtk_subdev->pdev = pdev; 392 + mtk_subdev->subdev.prepare = mtk_rpmsg_prepare; 393 + mtk_subdev->subdev.stop = mtk_rpmsg_stop; 394 + mtk_subdev->subdev.unprepare = mtk_rpmsg_unprepare; 395 + mtk_subdev->info = info; 396 + INIT_LIST_HEAD(&mtk_subdev->channels); 397 + INIT_WORK(&mtk_subdev->register_work, 398 + mtk_register_device_work_function); 399 + mutex_init(&mtk_subdev->channels_lock); 400 + 401 + return &mtk_subdev->subdev; 402 + } 403 + EXPORT_SYMBOL_GPL(mtk_rpmsg_create_rproc_subdev); 404 + 405 + void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev) 406 + { 407 + struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 408 + 409 + kfree(mtk_subdev); 410 + } 411 + EXPORT_SYMBOL_GPL(mtk_rpmsg_destroy_rproc_subdev); 412 + 413 + MODULE_LICENSE("GPL v2"); 414 + MODULE_DESCRIPTION("MediaTek scp rpmsg driver");
+2 -1
include/linux/remoteproc/mtk_scp.h
··· 41 41 SCP_IPI_ISP_FRAME, 42 42 SCP_IPI_FD_CMD, 43 43 SCP_IPI_CROS_HOST_CMD, 44 - SCP_IPI_MAX, 44 + SCP_IPI_NS_SERVICE = 0xFF, 45 + SCP_IPI_MAX = 0x100, 45 46 }; 46 47 47 48 struct mtk_scp *scp_get(struct platform_device *pdev);
+38
include/linux/rpmsg/mtk_rpmsg.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright 2019 Google LLC. 4 + */ 5 + 6 + #ifndef __LINUX_RPMSG_MTK_RPMSG_H 7 + #define __LINUX_RPMSG_MTK_RPMSG_H 8 + 9 + #include <linux/platform_device.h> 10 + #include <linux/remoteproc.h> 11 + 12 + typedef void (*ipi_handler_t)(void *data, unsigned int len, void *priv); 13 + 14 + /* 15 + * struct mtk_rpmsg_info - IPI functions tied to the rpmsg device. 16 + * @register_ipi: register IPI handler for an IPI id. 17 + * @unregister_ipi: unregister IPI handler for a registered IPI id. 18 + * @send_ipi: send IPI to an IPI id. wait is the timeout (in msecs) to wait 19 + * until response, or 0 if there's no timeout. 20 + * @ns_ipi_id: the IPI id used for name service, or -1 if name service isn't 21 + * supported. 22 + */ 23 + struct mtk_rpmsg_info { 24 + int (*register_ipi)(struct platform_device *pdev, u32 id, 25 + ipi_handler_t handler, void *priv); 26 + void (*unregister_ipi)(struct platform_device *pdev, u32 id); 27 + int (*send_ipi)(struct platform_device *pdev, u32 id, 28 + void *buf, unsigned int len, unsigned int wait); 29 + int ns_ipi_id; 30 + }; 31 + 32 + struct rproc_subdev * 33 + mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev, 34 + struct mtk_rpmsg_info *info); 35 + 36 + void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev); 37 + 38 + #endif