]>
Commit | Line | Data |
---|---|---|
6716e221 CC |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
3 | * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. | |
4 | * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. | |
5 | */ | |
6 | ||
5f791b81 CC |
7 | #define pr_fmt(fmt) "cmd-db: " fmt |
8 | ||
a9cbf76e | 9 | #include <asm/system.h> |
5f791b81 CC |
10 | #include <dm.h> |
11 | #include <dm/ofnode.h> | |
12 | #include <dm/device_compat.h> | |
6716e221 | 13 | #include <linux/kernel.h> |
6716e221 | 14 | #include <linux/types.h> |
5f791b81 CC |
15 | #include <linux/ioport.h> |
16 | #include <linux/byteorder/generic.h> | |
6716e221 CC |
17 | |
18 | #include <soc/qcom/cmd-db.h> | |
19 | ||
20 | #define NUM_PRIORITY 2 | |
21 | #define MAX_SLV_ID 8 | |
22 | #define SLAVE_ID_MASK 0x7 | |
23 | #define SLAVE_ID_SHIFT 16 | |
24 | #define SLAVE_ID(addr) FIELD_GET(GENMASK(19, 16), addr) | |
25 | #define VRM_ADDR(addr) FIELD_GET(GENMASK(19, 4), addr) | |
26 | ||
27 | /** | |
28 | * struct entry_header: header for each entry in cmddb | |
29 | * | |
30 | * @id: resource's identifier | |
31 | * @priority: unused | |
32 | * @addr: the address of the resource | |
33 | * @len: length of the data | |
34 | * @offset: offset from :@data_offset, start of the data | |
35 | */ | |
36 | struct entry_header { | |
37 | u8 id[8]; | |
38 | __le32 priority[NUM_PRIORITY]; | |
39 | __le32 addr; | |
40 | __le16 len; | |
41 | __le16 offset; | |
42 | }; | |
43 | ||
44 | /** | |
45 | * struct rsc_hdr: resource header information | |
46 | * | |
47 | * @slv_id: id for the resource | |
48 | * @header_offset: entry's header at offset from the end of the cmd_db_header | |
49 | * @data_offset: entry's data at offset from the end of the cmd_db_header | |
50 | * @cnt: number of entries for HW type | |
51 | * @version: MSB is major, LSB is minor | |
52 | * @reserved: reserved for future use. | |
53 | */ | |
54 | struct rsc_hdr { | |
55 | __le16 slv_id; | |
56 | __le16 header_offset; | |
57 | __le16 data_offset; | |
58 | __le16 cnt; | |
59 | __le16 version; | |
60 | __le16 reserved[3]; | |
61 | }; | |
62 | ||
63 | /** | |
64 | * struct cmd_db_header: The DB header information | |
65 | * | |
66 | * @version: The cmd db version | |
67 | * @magic: constant expected in the database | |
68 | * @header: array of resources | |
69 | * @checksum: checksum for the header. Unused. | |
70 | * @reserved: reserved memory | |
71 | * @data: driver specific data | |
72 | */ | |
73 | struct cmd_db_header { | |
74 | __le32 version; | |
75 | u8 magic[4]; | |
76 | struct rsc_hdr header[MAX_SLV_ID]; | |
77 | __le32 checksum; | |
78 | __le32 reserved; | |
79 | u8 data[]; | |
80 | }; | |
81 | ||
82 | /** | |
83 | * DOC: Description of the Command DB database. | |
84 | * | |
85 | * At the start of the command DB memory is the cmd_db_header structure. | |
86 | * The cmd_db_header holds the version, checksum, magic key as well as an | |
87 | * array for header for each slave (depicted by the rsc_header). Each h/w | |
88 | * based accelerator is a 'slave' (shared resource) and has slave id indicating | |
89 | * the type of accelerator. The rsc_header is the header for such individual | |
90 | * slaves of a given type. The entries for each of these slaves begin at the | |
91 | * rsc_hdr.header_offset. In addition each slave could have auxiliary data | |
92 | * that may be needed by the driver. The data for the slave starts at the | |
93 | * entry_header.offset to the location pointed to by the rsc_hdr.data_offset. | |
94 | * | |
95 | * Drivers have a stringified key to a slave/resource. They can query the slave | |
96 | * information and get the slave id and the auxiliary data and the length of the | |
97 | * data. Using this information, they can format the request to be sent to the | |
98 | * h/w accelerator and request a resource state. | |
99 | */ | |
100 | ||
101 | static const u8 CMD_DB_MAGIC[] = { 0xdb, 0x30, 0x03, 0x0c }; | |
102 | ||
103 | static bool cmd_db_magic_matches(const struct cmd_db_header *header) | |
104 | { | |
105 | const u8 *magic = header->magic; | |
106 | ||
107 | return memcmp(magic, CMD_DB_MAGIC, ARRAY_SIZE(CMD_DB_MAGIC)) == 0; | |
108 | } | |
109 | ||
1a2df137 | 110 | static struct cmd_db_header *cmd_db_header __section(".data") = NULL; |
6716e221 CC |
111 | |
112 | static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr) | |
113 | { | |
114 | u16 offset = le16_to_cpu(hdr->header_offset); | |
115 | ||
116 | return cmd_db_header->data + offset; | |
117 | } | |
118 | ||
119 | static inline void * | |
120 | rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent) | |
121 | { | |
122 | u16 offset = le16_to_cpu(hdr->data_offset); | |
123 | u16 loffset = le16_to_cpu(ent->offset); | |
124 | ||
125 | return cmd_db_header->data + offset + loffset; | |
126 | } | |
127 | ||
6716e221 CC |
128 | static int cmd_db_get_header(const char *id, const struct entry_header **eh, |
129 | const struct rsc_hdr **rh) | |
130 | { | |
131 | const struct rsc_hdr *rsc_hdr; | |
132 | const struct entry_header *ent; | |
fb0fd32a | 133 | int i, j; |
6716e221 CC |
134 | u8 query[sizeof(ent->id)] __nonstring; |
135 | ||
fb0fd32a | 136 | strncpy(query, id, sizeof(query)); |
6716e221 CC |
137 | |
138 | for (i = 0; i < MAX_SLV_ID; i++) { | |
139 | rsc_hdr = &cmd_db_header->header[i]; | |
140 | if (!rsc_hdr->slv_id) | |
141 | break; | |
142 | ||
143 | ent = rsc_to_entry_header(rsc_hdr); | |
144 | for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) { | |
75acc511 | 145 | if (strncmp(ent->id, query, sizeof(ent->id)) == 0) { |
6716e221 CC |
146 | if (eh) |
147 | *eh = ent; | |
148 | if (rh) | |
149 | *rh = rsc_hdr; | |
150 | return 0; | |
151 | } | |
152 | } | |
153 | } | |
154 | ||
155 | return -ENODEV; | |
156 | } | |
157 | ||
158 | /** | |
159 | * cmd_db_read_addr() - Query command db for resource id address. | |
160 | * | |
161 | * @id: resource id to query for address | |
162 | * | |
163 | * Return: resource address on success, 0 on error | |
164 | * | |
165 | * This is used to retrieve resource address based on resource | |
166 | * id. | |
167 | */ | |
168 | u32 cmd_db_read_addr(const char *id) | |
169 | { | |
170 | int ret; | |
171 | const struct entry_header *ent; | |
172 | ||
fb0fd32a CC |
173 | debug("%s(%s)\n", __func__, id); |
174 | ||
175 | if (!cmd_db_header) { | |
176 | log_err("%s: Command DB not initialized\n", __func__); | |
177 | return 0; | |
178 | } | |
179 | ||
6716e221 CC |
180 | ret = cmd_db_get_header(id, &ent, NULL); |
181 | ||
182 | return ret < 0 ? 0 : le32_to_cpu(ent->addr); | |
183 | } | |
184 | EXPORT_SYMBOL_GPL(cmd_db_read_addr); | |
185 | ||
a9cbf76e | 186 | static int cmd_db_bind(struct udevice *dev) |
6716e221 | 187 | { |
1a2df137 | 188 | void __iomem *base; |
a9cbf76e | 189 | fdt_size_t size; |
1a2df137 | 190 | ofnode node; |
6716e221 | 191 | |
1a2df137 CC |
192 | if (cmd_db_header) |
193 | return 0; | |
6716e221 | 194 | |
1a2df137 CC |
195 | node = dev_ofnode(dev); |
196 | ||
197 | debug("%s(%s)\n", __func__, ofnode_get_name(node)); | |
198 | ||
a9cbf76e | 199 | base = (void __iomem *)ofnode_get_addr_size(node, "reg", &size); |
1a2df137 CC |
200 | if ((fdt_addr_t)base == FDT_ADDR_T_NONE) { |
201 | log_err("%s: Failed to read base address\n", __func__); | |
202 | return -ENOENT; | |
6716e221 CC |
203 | } |
204 | ||
a9cbf76e CC |
205 | /* On SM8550/SM8650 and newer SoCs cmd-db might not be mapped */ |
206 | mmu_map_region((phys_addr_t)base, (phys_size_t)size, false); | |
207 | ||
1a2df137 | 208 | cmd_db_header = base; |
6716e221 | 209 | if (!cmd_db_magic_matches(cmd_db_header)) { |
1a2df137 | 210 | log_err("%s: Invalid Command DB Magic\n", __func__); |
6716e221 CC |
211 | return -EINVAL; |
212 | } | |
213 | ||
6716e221 CC |
214 | return 0; |
215 | } | |
216 | ||
1a2df137 | 217 | static const struct udevice_id cmd_db_ids[] = { |
6716e221 CC |
218 | { .compatible = "qcom,cmd-db" }, |
219 | { } | |
220 | }; | |
6716e221 | 221 | |
1a2df137 CC |
222 | U_BOOT_DRIVER(qcom_cmd_db) = { |
223 | .name = "qcom_cmd_db", | |
224 | .id = UCLASS_MISC, | |
fb0fd32a | 225 | .bind = cmd_db_bind, |
1a2df137 CC |
226 | .of_match = cmd_db_ids, |
227 | }; | |
6716e221 CC |
228 | |
229 | MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver"); | |
230 | MODULE_LICENSE("GPL v2"); |