diff options
| author | Bjorn Andersson <bjorn.andersson@linaro.org> | 2016-09-01 18:28:09 -0400 |
|---|---|---|
| committer | Bjorn Andersson <bjorn.andersson@linaro.org> | 2016-09-09 01:15:26 -0400 |
| commit | 53e2822e56c7bc67e5dc19acb1e5fbb8ebff8614 (patch) | |
| tree | a4efd40cf47668eed047c1e8cfef7d8da0f03ef2 | |
| parent | 4b83c52a21cf5a7421b7c28bebf8ff28ba96ceb9 (diff) | |
rpmsg: Introduce Qualcomm SMD backend
This introduces a new rpmsg backend for the Qualcomm SMD system,
allowing communication with various remote processors found in Qualcomm
platforms. The implementation is based on, and intends to replace,
drivers/soc/qcom/smd.c with the necessary adaptions for fitting with the
rpmsg core.
Based on original work by Sricharan R <sricharan@codeaurora.org>
Cc: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
| -rw-r--r-- | drivers/rpmsg/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/rpmsg/Makefile | 1 | ||||
| -rw-r--r-- | drivers/rpmsg/qcom_smd.c | 1434 |
3 files changed, 1445 insertions, 0 deletions
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 40614be88c97..9ba5a2e5c930 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig | |||
| @@ -4,6 +4,16 @@ menu "Rpmsg drivers" | |||
| 4 | config RPMSG | 4 | config RPMSG |
| 5 | tristate | 5 | tristate |
| 6 | 6 | ||
| 7 | config RPMSG_QCOM_SMD | ||
| 8 | tristate "Qualcomm Shared Memory Driver (SMD)" | ||
| 9 | depends on QCOM_SMEM | ||
| 10 | depends on !QCOM_SMD | ||
| 11 | select RPMSG | ||
| 12 | help | ||
| 13 | Say y here to enable support for the Qualcomm Shared Memory Driver | ||
| 14 | providing communication channels to remote processors in Qualcomm | ||
| 15 | platforms. | ||
| 16 | |||
| 7 | config RPMSG_VIRTIO | 17 | config RPMSG_VIRTIO |
| 8 | tristate | 18 | tristate |
| 9 | select RPMSG | 19 | select RPMSG |
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index c48ea55ad380..ae9c9132cf76 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile | |||
| @@ -1,2 +1,3 @@ | |||
| 1 | obj-$(CONFIG_RPMSG) += rpmsg_core.o | 1 | obj-$(CONFIG_RPMSG) += rpmsg_core.o |
| 2 | obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o | ||
| 2 | obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o | 3 | obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o |
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c new file mode 100644 index 000000000000..06fef2b4c814 --- /dev/null +++ b/drivers/rpmsg/qcom_smd.c | |||
| @@ -0,0 +1,1434 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2015, Sony Mobile Communications AB. | ||
| 3 | * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 and | ||
| 7 | * only version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/mfd/syscon.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/of_irq.h> | ||
| 20 | #include <linux/of_platform.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/regmap.h> | ||
| 23 | #include <linux/sched.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/soc/qcom/smem.h> | ||
| 26 | #include <linux/wait.h> | ||
| 27 | #include <linux/rpmsg.h> | ||
| 28 | |||
| 29 | #include "rpmsg_internal.h" | ||
| 30 | |||
| 31 | /* | ||
| 32 | * The Qualcomm Shared Memory communication solution provides point-to-point | ||
| 33 | * channels for clients to send and receive streaming or packet based data. | ||
| 34 | * | ||
| 35 | * Each channel consists of a control item (channel info) and a ring buffer | ||
| 36 | * pair. The channel info carry information related to channel state, flow | ||
| 37 | * control and the offsets within the ring buffer. | ||
| 38 | * | ||
| 39 | * All allocated channels are listed in an allocation table, identifying the | ||
| 40 | * pair of items by name, type and remote processor. | ||
| 41 | * | ||
| 42 | * Upon creating a new channel the remote processor allocates channel info and | ||
| 43 | * ring buffer items from the smem heap and populate the allocation table. An | ||
| 44 | * interrupt is sent to the other end of the channel and a scan for new | ||
| 45 | * channels should be done. A channel never goes away, it will only change | ||
| 46 | * state. | ||
| 47 | * | ||
| 48 | * The remote processor signals it intent for bring up the communication | ||
| 49 | * channel by setting the state of its end of the channel to "opening" and | ||
| 50 | * sends out an interrupt. We detect this change and register a smd device to | ||
| 51 | * consume the channel. Upon finding a consumer we finish the handshake and the | ||
| 52 | * channel is up. | ||
| 53 | * | ||
| 54 | * Upon closing a channel, the remote processor will update the state of its | ||
| 55 | * end of the channel and signal us, we will then unregister any attached | ||
| 56 | * device and close our end of the channel. | ||
| 57 | * | ||
| 58 | * Devices attached to a channel can use the qcom_smd_send function to push | ||
| 59 | * data to the channel, this is done by copying the data into the tx ring | ||
| 60 | * buffer, updating the pointers in the channel info and signaling the remote | ||
| 61 | * processor. | ||
| 62 | * | ||
| 63 | * The remote processor does the equivalent when it transfer data and upon | ||
| 64 | * receiving the interrupt we check the channel info for new data and delivers | ||
| 65 | * this to the attached device. If the device is not ready to receive the data | ||
| 66 | * we leave it in the ring buffer for now. | ||
| 67 | */ | ||
| 68 | |||
| 69 | struct smd_channel_info; | ||
| 70 | struct smd_channel_info_pair; | ||
| 71 | struct smd_channel_info_word; | ||
| 72 | struct smd_channel_info_word_pair; | ||
| 73 | |||
| 74 | static const struct rpmsg_endpoint_ops qcom_smd_endpoint_ops; | ||
| 75 | |||
| 76 | #define SMD_ALLOC_TBL_COUNT 2 | ||
| 77 | #define SMD_ALLOC_TBL_SIZE 64 | ||
| 78 | |||
| 79 | /* | ||
| 80 | * This lists the various smem heap items relevant for the allocation table and | ||
| 81 | * smd channel entries. | ||
| 82 | */ | ||
| 83 | static const struct { | ||
| 84 | unsigned alloc_tbl_id; | ||
| 85 | unsigned info_base_id; | ||
| 86 | unsigned fifo_base_id; | ||
| 87 | } smem_items[SMD_ALLOC_TBL_COUNT] = { | ||
| 88 | { | ||
| 89 | .alloc_tbl_id = 13, | ||
| 90 | .info_base_id = 14, | ||
| 91 | .fifo_base_id = 338 | ||
| 92 | }, | ||
| 93 | { | ||
| 94 | .alloc_tbl_id = 266, | ||
| 95 | .info_base_id = 138, | ||
| 96 | .fifo_base_id = 202, | ||
| 97 | }, | ||
| 98 | }; | ||
| 99 | |||
| 100 | /** | ||
| 101 | * struct qcom_smd_edge - representing a remote processor | ||
| 102 | * @of_node: of_node handle for information related to this edge | ||
| 103 | * @edge_id: identifier of this edge | ||
| 104 | * @remote_pid: identifier of remote processor | ||
| 105 | * @irq: interrupt for signals on this edge | ||
| 106 | * @ipc_regmap: regmap handle holding the outgoing ipc register | ||
| 107 | * @ipc_offset: offset within @ipc_regmap of the register for ipc | ||
| 108 | * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap | ||
| 109 | * @channels: list of all channels detected on this edge | ||
| 110 | * @channels_lock: guard for modifications of @channels | ||
| 111 | * @allocated: array of bitmaps representing already allocated channels | ||
| 112 | * @smem_available: last available amount of smem triggering a channel scan | ||
| 113 | * @scan_work: work item for discovering new channels | ||
| 114 | * @state_work: work item for edge state changes | ||
| 115 | */ | ||
| 116 | struct qcom_smd_edge { | ||
| 117 | struct device dev; | ||
| 118 | |||
| 119 | struct device_node *of_node; | ||
| 120 | unsigned edge_id; | ||
| 121 | unsigned remote_pid; | ||
| 122 | |||
| 123 | int irq; | ||
| 124 | |||
| 125 | struct regmap *ipc_regmap; | ||
| 126 | int ipc_offset; | ||
| 127 | int ipc_bit; | ||
| 128 | |||
| 129 | struct list_head channels; | ||
| 130 | spinlock_t channels_lock; | ||
| 131 | |||
| 132 | DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE); | ||
| 133 | |||
| 134 | unsigned smem_available; | ||
| 135 | |||
| 136 | wait_queue_head_t new_channel_event; | ||
| 137 | |||
| 138 | struct work_struct scan_work; | ||
| 139 | struct work_struct state_work; | ||
| 140 | }; | ||
| 141 | |||
| 142 | /* | ||
| 143 | * SMD channel states. | ||
| 144 | */ | ||
| 145 | enum smd_channel_state { | ||
| 146 | SMD_CHANNEL_CLOSED, | ||
| 147 | SMD_CHANNEL_OPENING, | ||
| 148 | SMD_CHANNEL_OPENED, | ||
| 149 | SMD_CHANNEL_FLUSHING, | ||
| 150 | SMD_CHANNEL_CLOSING, | ||
| 151 | SMD_CHANNEL_RESET, | ||
| 152 | SMD_CHANNEL_RESET_OPENING | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct qcom_smd_device { | ||
| 156 | struct rpmsg_device rpdev; | ||
| 157 | |||
| 158 | struct qcom_smd_edge *edge; | ||
| 159 | }; | ||
| 160 | |||
| 161 | struct qcom_smd_endpoint { | ||
| 162 | struct rpmsg_endpoint ept; | ||
| 163 | |||
| 164 | struct qcom_smd_channel *qsch; | ||
| 165 | }; | ||
| 166 | |||
| 167 | #define to_smd_device(_rpdev) container_of(_rpdev, struct qcom_smd_device, rpdev) | ||
| 168 | #define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev) | ||
| 169 | #define to_smd_endpoint(ept) container_of(ept, struct qcom_smd_endpoint, ept) | ||
| 170 | |||
| 171 | /** | ||
| 172 | * struct qcom_smd_channel - smd channel struct | ||
| 173 | * @edge: qcom_smd_edge this channel is living on | ||
| 174 | * @qsdev: reference to a associated smd client device | ||
| 175 | * @name: name of the channel | ||
| 176 | * @state: local state of the channel | ||
| 177 | * @remote_state: remote state of the channel | ||
| 178 | * @info: byte aligned outgoing/incoming channel info | ||
| 179 | * @info_word: word aligned outgoing/incoming channel info | ||
| 180 | * @tx_lock: lock to make writes to the channel mutually exclusive | ||
| 181 | * @fblockread_event: wakeup event tied to tx fBLOCKREADINTR | ||
