aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/soc/qcom/cmd-db.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-11 21:19:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-11 21:19:45 -0400
commit8efcf34a263965e471e3999904f94d1f6799d42a (patch)
treea1fe88517cb8a4eb54b50c3ce32eaa1954518b9c /drivers/soc/qcom/cmd-db.c
parent32bcbf8b6d09428907fd045a4ea90562ec7dc4a2 (diff)
parent14321604c82c5415a72e894b83b587a345f5bdf2 (diff)
Merge tag 'armsoc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC late updates from Olof Johansson: "This is a branch with a few merge requests that either came in late, or took a while longer for us to review and merge than usual and thus cut it a bit close to the merge window. We stage them in a separate branch and if things look good, we still send them up -- and that's the case here. This is mostly DT additions for Renesas platforms, adding IP block descriptions for existing and new SoCs. There are also some driver updates for Qualcomm platforms for SMEM/QMI and GENI, which is their generalized serial protocol interface" * tag 'armsoc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (186 commits) soc: qcom: smem: introduce qcom_smem_virt_to_phys() soc: qcom: qmi: fix a buffer sizing bug MAINTAINERS: Update pattern for qcom_scm soc: Unconditionally include qcom Makefile soc: qcom: smem: check sooner in qcom_smem_set_global_partition() soc: qcom: smem: fix qcom_smem_set_global_partition() soc: qcom: smem: fix off-by-one error in qcom_smem_alloc_private() soc: qcom: smem: byte swap values properly soc: qcom: smem: return proper type for cached entry functions soc: qcom: smem: fix first cache entry calculation soc: qcom: cmd-db: Make endian-agnostic drivers: qcom: add command DB driver arm64: dts: renesas: salvator-common: Add ADV7482 support ARM: dts: r8a7740: Add CEU1 ARM: dts: r8a7740: Add CEU0 arm64: dts: renesas: salvator-common: enable VIN arm64: dts: renesas: r8a77970: add VIN and CSI-2 nodes arm64: dts: renesas: r8a77965: add VIN and CSI-2 nodes arm64: dts: renesas: r8a7796: add VIN and CSI-2 nodes arm64: dts: renesas: r8a7795-es1: add CSI-2 node ...
Diffstat (limited to 'drivers/soc/qcom/cmd-db.c')
-rw-r--r--drivers/soc/qcom/cmd-db.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
new file mode 100644
index 000000000000..a6f646295f06
--- /dev/null
+++ b/drivers/soc/qcom/cmd-db.c
@@ -0,0 +1,317 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
3
4#include <linux/kernel.h>
5#include <linux/of.h>
6#include <linux/of_address.h>
7#include <linux/of_platform.h>
8#include <linux/of_reserved_mem.h>
9#include <linux/platform_device.h>
10#include <linux/types.h>
11
12#include <soc/qcom/cmd-db.h>
13
14#define NUM_PRIORITY 2
15#define MAX_SLV_ID 8
16#define SLAVE_ID_MASK 0x7
17#define SLAVE_ID_SHIFT 16
18
19/**
20 * struct entry_header: header for each entry in cmddb
21 *
22 * @id: resource's identifier
23 * @priority: unused
24 * @addr: the address of the resource
25 * @len: length of the data
26 * @offset: offset from :@data_offset, start of the data
27 */
28struct entry_header {
29 u8 id[8];
30 __le32 priority[NUM_PRIORITY];
31 __le32 addr;
32 __le16 len;
33 __le16 offset;
34};
35
36/**
37 * struct rsc_hdr: resource header information
38 *
39 * @slv_id: id for the resource
40 * @header_offset: entry's header at offset from the end of the cmd_db_header
41 * @data_offset: entry's data at offset from the end of the cmd_db_header
42 * @cnt: number of entries for HW type
43 * @version: MSB is major, LSB is minor
44 * @reserved: reserved for future use.
45 */
46struct rsc_hdr {
47 __le16 slv_id;
48 __le16 header_offset;
49 __le16 data_offset;
50 __le16 cnt;
51 __le16 version;
52 __le16 reserved[3];
53};
54
55/**
56 * struct cmd_db_header: The DB header information
57 *
58 * @version: The cmd db version
59 * @magic: constant expected in the database
60 * @header: array of resources
61 * @checksum: checksum for the header. Unused.
62 * @reserved: reserved memory
63 * @data: driver specific data
64 */
65struct cmd_db_header {
66 __le32 version;
67 u8 magic[4];
68 struct rsc_hdr header[MAX_SLV_ID];
69 __le32 checksum;
70 __le32 reserved;
71 u8 data[];
72};
73
74/**
75 * DOC: Description of the Command DB database.
76 *
77 * At the start of the command DB memory is the cmd_db_header structure.
78 * The cmd_db_header holds the version, checksum, magic key as well as an
79 * array for header for each slave (depicted by the rsc_header). Each h/w
80 * based accelerator is a 'slave' (shared resource) and has slave id indicating
81 * the type of accelerator. The rsc_header is the header for such individual
82 * slaves of a given type. The entries for each of these slaves begin at the
83 * rsc_hdr.header_offset. In addition each slave could have auxiliary data
84 * that may be needed by the driver. The data for the slave starts at the
85 * entry_header.offset to the location pointed to by the rsc_hdr.data_offset.
86 *
87 * Drivers have a stringified key to a slave/resource. They can query the slave
88 * information and get the slave id and the auxiliary data and the length of the
89 * data. Using this information, they can format the request to be sent to the
90 * h/w accelerator and request a resource state.
91 */
92
93static const u8 CMD_DB_MAGIC[] = { 0xdb, 0x30, 0x03, 0x0c };
94
95static bool cmd_db_magic_matches(const struct cmd_db_header *header)
96{
97 const u8 *magic = header->magic;
98
99 return memcmp(magic, CMD_DB_MAGIC, ARRAY_SIZE(CMD_DB_MAGIC)) == 0;
100}
101
102static struct cmd_db_header *cmd_db_header;
103
104
105static inline void *rsc_to_entry_header(struct rsc_hdr *hdr)
106{
107 u16 offset = le16_to_cpu(hdr->header_offset);
108
109 return cmd_db_header->data + offset;
110}
111
112static inline void *
113rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent)
114{
115 u16 offset = le16_to_cpu(hdr->data_offset);
116 u16 loffset = le16_to_cpu(ent->offset);
117
118 return cmd_db_header->data + offset + loffset;
119}
120
121/**
122 * cmd_db_ready - Indicates if command DB is available
123 *
124 * Return: 0 on success, errno otherwise
125 */
126int cmd_db_ready(void)
127{
128 if (cmd_db_header == NULL)
129 return -EPROBE_DEFER;
130 else if (!cmd_db_magic_matches(cmd_db_header))
131 return -EINVAL;
132
133 return 0;
134}
135EXPORT_SYMBOL(cmd_db_ready);
136
137static int cmd_db_get_header(const char *id, struct entry_header *eh,
138 struct rsc_hdr *rh)
139{
140 struct rsc_hdr *rsc_hdr;
141 struct entry_header *ent;
142 int ret, i, j;
143 u8 query[8];
144
145 ret = cmd_db_ready();
146 if (ret)
147 return ret;
148
149 if (!eh || !rh)
150 return -EINVAL;
151
152 /* Pad out query string to same length as in DB */
153 strncpy(query, id, sizeof(query));
154
155 for (i = 0; i < MAX_SLV_ID; i++) {
156 rsc_hdr = &cmd_db_header->header[i];
157 if (!rsc_hdr->slv_id)
158 break;
159
160 ent = rsc_to_entry_header(rsc_hdr);
161 for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) {
162 if (memcmp(ent->id, query, sizeof(ent->id)) == 0)
163 break;
164 }
165
166 if (j < le16_to_cpu(rsc_hdr->cnt)) {
167 memcpy(eh, ent, sizeof(*ent));
168 memcpy(rh, rsc_hdr, sizeof(*rh));
169 return 0;
170 }
171 }
172
173 return -ENODEV;
174}
175
176/**
177 * cmd_db_read_addr() - Query command db for resource id address.
178 *
179 * @id: resource id to query for address
180 *
181 * Return: resource address on success, 0 on error
182 *
183 * This is used to retrieve resource address based on resource
184 * id.
185 */
186u32 cmd_db_read_addr(const char *id)
187{
188 int ret;
189 struct entry_header ent;
190 struct rsc_hdr rsc_hdr;
191
192 ret = cmd_db_get_header(id, &ent, &rsc_hdr);
193
194 return ret < 0 ? 0 : le32_to_cpu(ent.addr);
195}
196EXPORT_SYMBOL(cmd_db_read_addr);
197
198/**
199 * cmd_db_read_aux_data() - Query command db for aux data.
200 *
201 * @id: Resource to retrieve AUX Data on.
202 * @data: Data buffer to copy returned aux data to. Returns size on NULL
203 * @len: Caller provides size of data buffer passed in.
204 *
205 * Return: size of data on success, errno otherwise
206 */
207int cmd_db_read_aux_data(const char *id, u8 *data, size_t len)
208{
209 int ret;
210 struct entry_header ent;
211 struct rsc_hdr rsc_hdr;
212 u16 ent_len;
213
214 if (!data)
215 return -EINVAL;
216
217 ret = cmd_db_get_header(id, &ent, &rsc_hdr);
218 if (ret)
219 return ret;
220
221 ent_len = le16_to_cpu(ent.len);
222 if (len < ent_len)
223 return -EINVAL;
224
225 len = min_t(u16, ent_len, len);
226 memcpy(data, rsc_offset(&rsc_hdr, &ent), len);
227
228 return len;
229}
230EXPORT_SYMBOL(cmd_db_read_aux_data);
231
232/**
233 * cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB.
234 *
235 * @id: Resource to retrieve AUX Data.
236 *
237 * Return: size on success, 0 on error
238 */
239size_t cmd_db_read_aux_data_len(const char *id)
240{
241 int ret;
242 struct entry_header ent;
243 struct rsc_hdr rsc_hdr;
244
245 ret = cmd_db_get_header(id, &ent, &rsc_hdr);
246
247 return ret < 0 ? 0 : le16_to_cpu(ent.len);
248}
249EXPORT_SYMBOL(cmd_db_read_aux_data_len);
250
251/**
252 * cmd_db_read_slave_id - Get the slave ID for a given resource address
253 *
254 * @id: Resource id to query the DB for version
255 *
256 * Return: cmd_db_hw_type enum on success, CMD_DB_HW_INVALID on error
257 */
258enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
259{
260 int ret;
261 struct entry_header ent;
262 struct rsc_hdr rsc_hdr;
263 u32 addr;
264
265 ret = cmd_db_get_header(id, &ent, &rsc_hdr);
266 if (ret < 0)
267 return CMD_DB_HW_INVALID;
268
269 addr = le32_to_cpu(ent.addr);
270 return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
271}
272EXPORT_SYMBOL(cmd_db_read_slave_id);
273
274static int cmd_db_dev_probe(struct platform_device *pdev)
275{
276 struct reserved_mem *rmem;
277 int ret = 0;
278
279 rmem = of_reserved_mem_lookup(pdev->dev.of_node);
280 if (!rmem) {
281 dev_err(&pdev->dev, "failed to acquire memory region\n");
282 return -EINVAL;
283 }
284
285 cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
286 if (IS_ERR_OR_NULL(cmd_db_header)) {
287 ret = PTR_ERR(cmd_db_header);
288 cmd_db_header = NULL;
289 return ret;
290 }
291
292 if (!cmd_db_magic_matches(cmd_db_header)) {
293 dev_err(&pdev->dev, "Invalid Command DB Magic\n");
294 return -EINVAL;
295 }
296
297 return 0;
298}
299
300static const struct of_device_id cmd_db_match_table[] = {
301 { .compatible = "qcom,cmd-db" },
302 { },
303};
304
305static struct platform_driver cmd_db_dev_driver = {
306 .probe = cmd_db_dev_probe,
307 .driver = {
308 .name = "cmd-db",
309 .of_match_table = cmd_db_match_table,
310 },
311};
312
313static int __init cmd_db_device_init(void)
314{
315 return platform_driver_register(&cmd_db_dev_driver);
316}
317arch_initcall(cmd_db_device_init);