aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2016-09-01 18:28:09 -0400
committerBjorn Andersson <bjorn.andersson@linaro.org>2016-09-09 01:15:26 -0400
commit53e2822e56c7bc67e5dc19acb1e5fbb8ebff8614 (patch)
treea4efd40cf47668eed047c1e8cfef7d8da0f03ef2
parent4b83c52a21cf5a7421b7c28bebf8ff28ba96ceb9 (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/Kconfig10
-rw-r--r--drivers/rpmsg/Makefile1
-rw-r--r--drivers/rpmsg/qcom_smd.c1434
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"
4config RPMSG 4config RPMSG
5 tristate 5 tristate
6 6
7config 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
7config RPMSG_VIRTIO 17config 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 @@
1obj-$(CONFIG_RPMSG) += rpmsg_core.o 1obj-$(CONFIG_RPMSG) += rpmsg_core.o
2obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
2obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o 3obj-$(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
69struct smd_channel_info;
70struct smd_channel_info_pair;
71struct smd_channel_info_word;
72struct smd_channel_info_word_pair;
73
74static 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 */
83static 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 */
116struct 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 */
145enum 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
155struct qcom_smd_device {
156 struct rpmsg_device rpdev;
157
158 struct qcom_smd_edge *edge;
159};
160
161struct 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