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