| .. | .. |
|---|
| 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"); |
|---|