.. | .. |
---|
1 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
---|
2 | | -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ |
---|
| 2 | +/* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. */ |
---|
3 | 3 | |
---|
| 4 | +#include <linux/debugfs.h> |
---|
4 | 5 | #include <linux/kernel.h> |
---|
5 | 6 | #include <linux/module.h> |
---|
6 | 7 | #include <linux/of.h> |
---|
7 | 8 | #include <linux/of_address.h> |
---|
8 | | -#include <linux/of_platform.h> |
---|
9 | 9 | #include <linux/of_reserved_mem.h> |
---|
10 | 10 | #include <linux/platform_device.h> |
---|
| 11 | +#include <linux/seq_file.h> |
---|
11 | 12 | #include <linux/types.h> |
---|
12 | 13 | |
---|
13 | 14 | #include <soc/qcom/cmd-db.h> |
---|
.. | .. |
---|
102 | 103 | |
---|
103 | 104 | static struct cmd_db_header *cmd_db_header; |
---|
104 | 105 | |
---|
105 | | - |
---|
106 | | -static inline void *rsc_to_entry_header(struct rsc_hdr *hdr) |
---|
| 106 | +static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr) |
---|
107 | 107 | { |
---|
108 | 108 | u16 offset = le16_to_cpu(hdr->header_offset); |
---|
109 | 109 | |
---|
.. | .. |
---|
111 | 111 | } |
---|
112 | 112 | |
---|
113 | 113 | static inline void * |
---|
114 | | -rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent) |
---|
| 114 | +rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent) |
---|
115 | 115 | { |
---|
116 | 116 | u16 offset = le16_to_cpu(hdr->data_offset); |
---|
117 | 117 | u16 loffset = le16_to_cpu(ent->offset); |
---|
.. | .. |
---|
135 | 135 | } |
---|
136 | 136 | EXPORT_SYMBOL(cmd_db_ready); |
---|
137 | 137 | |
---|
138 | | -static int cmd_db_get_header(const char *id, struct entry_header *eh, |
---|
139 | | - struct rsc_hdr *rh) |
---|
| 138 | +static int cmd_db_get_header(const char *id, const struct entry_header **eh, |
---|
| 139 | + const struct rsc_hdr **rh) |
---|
140 | 140 | { |
---|
141 | | - struct rsc_hdr *rsc_hdr; |
---|
142 | | - struct entry_header *ent; |
---|
| 141 | + const struct rsc_hdr *rsc_hdr; |
---|
| 142 | + const struct entry_header *ent; |
---|
143 | 143 | int ret, i, j; |
---|
144 | 144 | u8 query[8]; |
---|
145 | 145 | |
---|
146 | 146 | ret = cmd_db_ready(); |
---|
147 | 147 | if (ret) |
---|
148 | 148 | return ret; |
---|
149 | | - |
---|
150 | | - if (!eh || !rh) |
---|
151 | | - return -EINVAL; |
---|
152 | 149 | |
---|
153 | 150 | /* Pad out query string to same length as in DB */ |
---|
154 | 151 | strncpy(query, id, sizeof(query)); |
---|
.. | .. |
---|
160 | 157 | |
---|
161 | 158 | ent = rsc_to_entry_header(rsc_hdr); |
---|
162 | 159 | for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) { |
---|
163 | | - if (memcmp(ent->id, query, sizeof(ent->id)) == 0) |
---|
164 | | - break; |
---|
165 | | - } |
---|
166 | | - |
---|
167 | | - if (j < le16_to_cpu(rsc_hdr->cnt)) { |
---|
168 | | - memcpy(eh, ent, sizeof(*ent)); |
---|
169 | | - memcpy(rh, rsc_hdr, sizeof(*rh)); |
---|
170 | | - return 0; |
---|
| 160 | + if (memcmp(ent->id, query, sizeof(ent->id)) == 0) { |
---|
| 161 | + if (eh) |
---|
| 162 | + *eh = ent; |
---|
| 163 | + if (rh) |
---|
| 164 | + *rh = rsc_hdr; |
---|
| 165 | + return 0; |
---|
| 166 | + } |
---|
171 | 167 | } |
---|
172 | 168 | } |
---|
173 | 169 | |
---|
.. | .. |
---|
187 | 183 | u32 cmd_db_read_addr(const char *id) |
---|
188 | 184 | { |
---|
189 | 185 | int ret; |
---|
190 | | - struct entry_header ent; |
---|
191 | | - struct rsc_hdr rsc_hdr; |
---|
| 186 | + const struct entry_header *ent; |
---|
192 | 187 | |
---|
193 | | - ret = cmd_db_get_header(id, &ent, &rsc_hdr); |
---|
| 188 | + ret = cmd_db_get_header(id, &ent, NULL); |
---|
194 | 189 | |
---|
195 | | - return ret < 0 ? 0 : le32_to_cpu(ent.addr); |
---|
| 190 | + return ret < 0 ? 0 : le32_to_cpu(ent->addr); |
---|
196 | 191 | } |
---|
197 | 192 | EXPORT_SYMBOL(cmd_db_read_addr); |
---|
198 | 193 | |
---|
199 | 194 | /** |
---|
200 | 195 | * cmd_db_read_aux_data() - Query command db for aux data. |
---|
201 | 196 | * |
---|
202 | | - * @id: Resource to retrieve AUX Data on. |
---|
203 | | - * @data: Data buffer to copy returned aux data to. Returns size on NULL |
---|
204 | | - * @len: Caller provides size of data buffer passed in. |
---|
| 197 | + * @id: Resource to retrieve AUX Data on |
---|
| 198 | + * @len: size of data buffer returned |
---|
205 | 199 | * |
---|
206 | | - * Return: size of data on success, errno otherwise |
---|
| 200 | + * Return: pointer to data on success, error pointer otherwise |
---|
207 | 201 | */ |
---|
208 | | -int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) |
---|
| 202 | +const void *cmd_db_read_aux_data(const char *id, size_t *len) |
---|
209 | 203 | { |
---|
210 | 204 | int ret; |
---|
211 | | - struct entry_header ent; |
---|
212 | | - struct rsc_hdr rsc_hdr; |
---|
213 | | - u16 ent_len; |
---|
214 | | - |
---|
215 | | - if (!data) |
---|
216 | | - return -EINVAL; |
---|
| 205 | + const struct entry_header *ent; |
---|
| 206 | + const struct rsc_hdr *rsc_hdr; |
---|
217 | 207 | |
---|
218 | 208 | ret = cmd_db_get_header(id, &ent, &rsc_hdr); |
---|
219 | 209 | if (ret) |
---|
220 | | - return ret; |
---|
| 210 | + return ERR_PTR(ret); |
---|
221 | 211 | |
---|
222 | | - ent_len = le16_to_cpu(ent.len); |
---|
223 | | - if (len < ent_len) |
---|
224 | | - return -EINVAL; |
---|
| 212 | + if (len) |
---|
| 213 | + *len = le16_to_cpu(ent->len); |
---|
225 | 214 | |
---|
226 | | - len = min_t(u16, ent_len, len); |
---|
227 | | - memcpy(data, rsc_offset(&rsc_hdr, &ent), len); |
---|
228 | | - |
---|
229 | | - return len; |
---|
| 215 | + return rsc_offset(rsc_hdr, ent); |
---|
230 | 216 | } |
---|
231 | 217 | EXPORT_SYMBOL(cmd_db_read_aux_data); |
---|
232 | | - |
---|
233 | | -/** |
---|
234 | | - * cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB. |
---|
235 | | - * |
---|
236 | | - * @id: Resource to retrieve AUX Data. |
---|
237 | | - * |
---|
238 | | - * Return: size on success, 0 on error |
---|
239 | | - */ |
---|
240 | | -size_t cmd_db_read_aux_data_len(const char *id) |
---|
241 | | -{ |
---|
242 | | - int ret; |
---|
243 | | - struct entry_header ent; |
---|
244 | | - struct rsc_hdr rsc_hdr; |
---|
245 | | - |
---|
246 | | - ret = cmd_db_get_header(id, &ent, &rsc_hdr); |
---|
247 | | - |
---|
248 | | - return ret < 0 ? 0 : le16_to_cpu(ent.len); |
---|
249 | | -} |
---|
250 | | -EXPORT_SYMBOL(cmd_db_read_aux_data_len); |
---|
251 | 218 | |
---|
252 | 219 | /** |
---|
253 | 220 | * cmd_db_read_slave_id - Get the slave ID for a given resource address |
---|
.. | .. |
---|
259 | 226 | enum cmd_db_hw_type cmd_db_read_slave_id(const char *id) |
---|
260 | 227 | { |
---|
261 | 228 | int ret; |
---|
262 | | - struct entry_header ent; |
---|
263 | | - struct rsc_hdr rsc_hdr; |
---|
| 229 | + const struct entry_header *ent; |
---|
264 | 230 | u32 addr; |
---|
265 | 231 | |
---|
266 | | - ret = cmd_db_get_header(id, &ent, &rsc_hdr); |
---|
| 232 | + ret = cmd_db_get_header(id, &ent, NULL); |
---|
267 | 233 | if (ret < 0) |
---|
268 | 234 | return CMD_DB_HW_INVALID; |
---|
269 | 235 | |
---|
270 | | - addr = le32_to_cpu(ent.addr); |
---|
| 236 | + addr = le32_to_cpu(ent->addr); |
---|
271 | 237 | return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK; |
---|
272 | 238 | } |
---|
273 | 239 | EXPORT_SYMBOL(cmd_db_read_slave_id); |
---|
| 240 | + |
---|
| 241 | +#ifdef CONFIG_DEBUG_FS |
---|
| 242 | +static int cmd_db_debugfs_dump(struct seq_file *seq, void *p) |
---|
| 243 | +{ |
---|
| 244 | + int i, j; |
---|
| 245 | + const struct rsc_hdr *rsc; |
---|
| 246 | + const struct entry_header *ent; |
---|
| 247 | + const char *name; |
---|
| 248 | + u16 len, version; |
---|
| 249 | + u8 major, minor; |
---|
| 250 | + |
---|
| 251 | + seq_puts(seq, "Command DB DUMP\n"); |
---|
| 252 | + |
---|
| 253 | + for (i = 0; i < MAX_SLV_ID; i++) { |
---|
| 254 | + rsc = &cmd_db_header->header[i]; |
---|
| 255 | + if (!rsc->slv_id) |
---|
| 256 | + break; |
---|
| 257 | + |
---|
| 258 | + switch (le16_to_cpu(rsc->slv_id)) { |
---|
| 259 | + case CMD_DB_HW_ARC: |
---|
| 260 | + name = "ARC"; |
---|
| 261 | + break; |
---|
| 262 | + case CMD_DB_HW_VRM: |
---|
| 263 | + name = "VRM"; |
---|
| 264 | + break; |
---|
| 265 | + case CMD_DB_HW_BCM: |
---|
| 266 | + name = "BCM"; |
---|
| 267 | + break; |
---|
| 268 | + default: |
---|
| 269 | + name = "Unknown"; |
---|
| 270 | + break; |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + version = le16_to_cpu(rsc->version); |
---|
| 274 | + major = version >> 8; |
---|
| 275 | + minor = version; |
---|
| 276 | + |
---|
| 277 | + seq_printf(seq, "Slave %s (v%u.%u)\n", name, major, minor); |
---|
| 278 | + seq_puts(seq, "-------------------------\n"); |
---|
| 279 | + |
---|
| 280 | + ent = rsc_to_entry_header(rsc); |
---|
| 281 | + for (j = 0; j < le16_to_cpu(rsc->cnt); j++, ent++) { |
---|
| 282 | + seq_printf(seq, "0x%05x: %*pEp", le32_to_cpu(ent->addr), |
---|
| 283 | + (int)sizeof(ent->id), ent->id); |
---|
| 284 | + |
---|
| 285 | + len = le16_to_cpu(ent->len); |
---|
| 286 | + if (len) { |
---|
| 287 | + seq_printf(seq, " [%*ph]", |
---|
| 288 | + len, rsc_offset(rsc, ent)); |
---|
| 289 | + } |
---|
| 290 | + seq_putc(seq, '\n'); |
---|
| 291 | + } |
---|
| 292 | + } |
---|
| 293 | + |
---|
| 294 | + return 0; |
---|
| 295 | +} |
---|
| 296 | + |
---|
| 297 | +static int open_cmd_db_debugfs(struct inode *inode, struct file *file) |
---|
| 298 | +{ |
---|
| 299 | + return single_open(file, cmd_db_debugfs_dump, inode->i_private); |
---|
| 300 | +} |
---|
| 301 | +#endif |
---|
| 302 | + |
---|
| 303 | +static const struct file_operations cmd_db_debugfs_ops = { |
---|
| 304 | +#ifdef CONFIG_DEBUG_FS |
---|
| 305 | + .open = open_cmd_db_debugfs, |
---|
| 306 | +#endif |
---|
| 307 | + .read = seq_read, |
---|
| 308 | + .llseek = seq_lseek, |
---|
| 309 | + .release = single_release, |
---|
| 310 | +}; |
---|
274 | 311 | |
---|
275 | 312 | static int cmd_db_dev_probe(struct platform_device *pdev) |
---|
276 | 313 | { |
---|
.. | .. |
---|
295 | 332 | return -EINVAL; |
---|
296 | 333 | } |
---|
297 | 334 | |
---|
| 335 | + debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops); |
---|
| 336 | + |
---|
298 | 337 | return 0; |
---|
299 | 338 | } |
---|
300 | 339 | |
---|
301 | 340 | static const struct of_device_id cmd_db_match_table[] = { |
---|
302 | 341 | { .compatible = "qcom,cmd-db" }, |
---|
303 | | - { }, |
---|
| 342 | + { } |
---|
304 | 343 | }; |
---|
| 344 | +MODULE_DEVICE_TABLE(of, cmd_db_match_table); |
---|
305 | 345 | |
---|
306 | 346 | static struct platform_driver cmd_db_dev_driver = { |
---|
307 | 347 | .probe = cmd_db_dev_probe, |
---|
308 | 348 | .driver = { |
---|
309 | 349 | .name = "cmd-db", |
---|
310 | 350 | .of_match_table = cmd_db_match_table, |
---|
| 351 | + .suppress_bind_attrs = true, |
---|
311 | 352 | }, |
---|
312 | 353 | }; |
---|
313 | 354 | |
---|
.. | .. |
---|
316 | 357 | return platform_driver_register(&cmd_db_dev_driver); |
---|
317 | 358 | } |
---|
318 | 359 | arch_initcall(cmd_db_device_init); |
---|
319 | | -MODULE_DESCRIPTION("Qualcomm Command DB"); |
---|
| 360 | + |
---|
| 361 | +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver"); |
---|
320 | 362 | MODULE_LICENSE("GPL v2"); |
---|