Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include <linux/debugfs.h>
  4#include <linux/mtd/spi-nor.h>
  5#include <linux/spi/spi.h>
  6#include <linux/spi/spi-mem.h>
  7
  8#include "core.h"
  9
 10#define SPI_NOR_DEBUGFS_ROOT "spi-nor"
 11
 12#define SNOR_F_NAME(name) [ilog2(SNOR_F_##name)] = #name
 13static const char *const snor_f_names[] = {
 14	SNOR_F_NAME(HAS_SR_TB),
 15	SNOR_F_NAME(NO_OP_CHIP_ERASE),
 16	SNOR_F_NAME(BROKEN_RESET),
 17	SNOR_F_NAME(4B_OPCODES),
 18	SNOR_F_NAME(HAS_4BAIT),
 19	SNOR_F_NAME(HAS_LOCK),
 20	SNOR_F_NAME(HAS_16BIT_SR),
 21	SNOR_F_NAME(NO_READ_CR),
 22	SNOR_F_NAME(HAS_SR_TB_BIT6),
 23	SNOR_F_NAME(HAS_4BIT_BP),
 24	SNOR_F_NAME(HAS_SR_BP3_BIT6),
 25	SNOR_F_NAME(IO_MODE_EN_VOLATILE),
 26	SNOR_F_NAME(SOFT_RESET),
 27	SNOR_F_NAME(SWP_IS_VOLATILE),
 28	SNOR_F_NAME(RWW),
 29	SNOR_F_NAME(ECC),
 30	SNOR_F_NAME(NO_WP),
 31};
 32#undef SNOR_F_NAME
 33
 34static const char *spi_nor_protocol_name(enum spi_nor_protocol proto)
 35{
 36	switch (proto) {
 37	case SNOR_PROTO_1_1_1:     return "1S-1S-1S";
 38	case SNOR_PROTO_1_1_2:     return "1S-1S-2S";
 39	case SNOR_PROTO_1_1_4:     return "1S-1S-4S";
 40	case SNOR_PROTO_1_1_8:     return "1S-1S-8S";
 41	case SNOR_PROTO_1_2_2:     return "1S-2S-2S";
 42	case SNOR_PROTO_1_4_4:     return "1S-4S-4S";
 43	case SNOR_PROTO_1_8_8:     return "1S-8S-8S";
 44	case SNOR_PROTO_2_2_2:     return "2S-2S-2S";
 45	case SNOR_PROTO_4_4_4:     return "4S-4S-4S";
 46	case SNOR_PROTO_8_8_8:     return "8S-8S-8S";
 47	case SNOR_PROTO_1_1_1_DTR: return "1D-1D-1D";
 48	case SNOR_PROTO_1_2_2_DTR: return "1D-2D-2D";
 49	case SNOR_PROTO_1_4_4_DTR: return "1D-4D-4D";
 50	case SNOR_PROTO_1_8_8_DTR: return "1D-8D-8D";
 51	case SNOR_PROTO_8_8_8_DTR: return "8D-8D-8D";
 52	}
 53
 54	return "<unknown>";
 55}
 56
 57static void spi_nor_print_flags(struct seq_file *s, unsigned long flags,
 58				const char *const *names, int names_len)
 59{
 60	bool sep = false;
 61	int i;
 62
 63	for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) {
 64		if (!(flags & BIT(i)))
 65			continue;
 66		if (sep)
 67			seq_puts(s, " | ");
 68		sep = true;
 69		if (i < names_len && names[i])
 70			seq_puts(s, names[i]);
 71		else
 72			seq_printf(s, "1<<%d", i);
 73	}
 74}
 75
 76static int spi_nor_params_show(struct seq_file *s, void *data)
 77{
 78	struct spi_nor *nor = s->private;
 79	struct spi_nor_flash_parameter *params = nor->params;
 80	struct spi_nor_erase_map *erase_map = &params->erase_map;
 81	struct spi_nor_erase_region *region;
 82	const struct flash_info *info = nor->info;
 83	char buf[16], *str;
 84	int i;
 85
 86	seq_printf(s, "name\t\t%s\n", info->name);
 87	seq_printf(s, "id\t\t%*ph\n", SPI_NOR_MAX_ID_LEN, nor->id);
 88	string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
 89	seq_printf(s, "size\t\t%s\n", buf);
 90	seq_printf(s, "write size\t%u\n", params->writesize);
 91	seq_printf(s, "page size\t%u\n", params->page_size);
 92	seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes);
 93
 94	seq_puts(s, "flags\t\t");
 95	spi_nor_print_flags(s, nor->flags, snor_f_names, sizeof(snor_f_names));
 96	seq_puts(s, "\n");
 97
 98	seq_puts(s, "\nopcodes\n");
 99	seq_printf(s, " read\t\t0x%02x\n", nor->read_opcode);
100	seq_printf(s, "  dummy cycles\t%u\n", nor->read_dummy);
101	seq_printf(s, " erase\t\t0x%02x\n", nor->erase_opcode);
102	seq_printf(s, " program\t0x%02x\n", nor->program_opcode);
103
104	switch (nor->cmd_ext_type) {
105	case SPI_NOR_EXT_NONE:
106		str = "none";
107		break;
108	case SPI_NOR_EXT_REPEAT:
109		str = "repeat";
110		break;
111	case SPI_NOR_EXT_INVERT:
112		str = "invert";
113		break;
114	default:
115		str = "<unknown>";
116		break;
117	}
118	seq_printf(s, " 8D extension\t%s\n", str);
119
120	seq_puts(s, "\nprotocols\n");
121	seq_printf(s, " read\t\t%s\n",
122		   spi_nor_protocol_name(nor->read_proto));
123	seq_printf(s, " write\t\t%s\n",
124		   spi_nor_protocol_name(nor->write_proto));
125	seq_printf(s, " register\t%s\n",
126		   spi_nor_protocol_name(nor->reg_proto));
127
128	seq_puts(s, "\nerase commands\n");
129	for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
130		struct spi_nor_erase_type *et = &erase_map->erase_type[i];
131
132		if (et->size) {
133			string_get_size(et->size, 1, STRING_UNITS_2, buf,
134					sizeof(buf));
135			seq_printf(s, " %02x (%s) [%d]\n", et->opcode, buf, i);
136		}
137	}
138
139	if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
140		string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
141		seq_printf(s, " %02x (%s)\n", nor->params->die_erase_opcode, buf);
142	}
143
144	seq_puts(s, "\nsector map\n");
145	seq_puts(s, " region (in hex)   | erase mask | flags\n");
146	seq_puts(s, " ------------------+------------+----------\n");
147	for (region = erase_map->regions;
148	     region;
149	     region = spi_nor_region_next(region)) {
150		u64 start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
151		u64 flags = region->offset & SNOR_ERASE_FLAGS_MASK;
152		u64 end = start + region->size - 1;
153
154		seq_printf(s, " %08llx-%08llx |     [%c%c%c%c] | %s\n",
155			   start, end,
156			   flags & BIT(0) ? '0' : ' ',
157			   flags & BIT(1) ? '1' : ' ',
158			   flags & BIT(2) ? '2' : ' ',
159			   flags & BIT(3) ? '3' : ' ',
160			   flags & SNOR_OVERLAID_REGION ? "overlaid" : "");
161	}
162
163	return 0;
164}
165DEFINE_SHOW_ATTRIBUTE(spi_nor_params);
166
167static void spi_nor_print_read_cmd(struct seq_file *s, u32 cap,
168				   struct spi_nor_read_command *cmd)
169{
170	seq_printf(s, " %s%s\n", spi_nor_protocol_name(cmd->proto),
171		   cap == SNOR_HWCAPS_READ_FAST ? " (fast read)" : "");
172	seq_printf(s, "  opcode\t0x%02x\n", cmd->opcode);
173	seq_printf(s, "  mode cycles\t%u\n", cmd->num_mode_clocks);
174	seq_printf(s, "  dummy cycles\t%u\n", cmd->num_wait_states);
175}
176
177static void spi_nor_print_pp_cmd(struct seq_file *s,
178				 struct spi_nor_pp_command *cmd)
179{
180	seq_printf(s, " %s\n", spi_nor_protocol_name(cmd->proto));
181	seq_printf(s, "  opcode\t0x%02x\n", cmd->opcode);
182}
183
184static int spi_nor_capabilities_show(struct seq_file *s, void *data)
185{
186	struct spi_nor *nor = s->private;
187	struct spi_nor_flash_parameter *params = nor->params;
188	u32 hwcaps = params->hwcaps.mask;
189	int i, cmd;
190
191	seq_puts(s, "Supported read modes by the flash\n");
192	for (i = 0; i < sizeof(hwcaps) * BITS_PER_BYTE; i++) {
193		if (!(hwcaps & BIT(i)))
194			continue;
195
196		cmd = spi_nor_hwcaps_read2cmd(BIT(i));
197		if (cmd < 0)
198			continue;
199
200		spi_nor_print_read_cmd(s, BIT(i), &params->reads[cmd]);
201		hwcaps &= ~BIT(i);
202	}
203
204	seq_puts(s, "\nSupported page program modes by the flash\n");
205	for (i = 0; i < sizeof(hwcaps) * BITS_PER_BYTE; i++) {
206		if (!(hwcaps & BIT(i)))
207			continue;
208
209		cmd = spi_nor_hwcaps_pp2cmd(BIT(i));
210		if (cmd < 0)
211			continue;
212
213		spi_nor_print_pp_cmd(s, &params->page_programs[cmd]);
214		hwcaps &= ~BIT(i);
215	}
216
217	if (hwcaps)
218		seq_printf(s, "\nunknown hwcaps 0x%x\n", hwcaps);
219
220	return 0;
221}
222DEFINE_SHOW_ATTRIBUTE(spi_nor_capabilities);
223
224static void spi_nor_debugfs_unregister(void *data)
225{
226	struct spi_nor *nor = data;
227
228	debugfs_remove(nor->debugfs_root);
229	nor->debugfs_root = NULL;
230}
231
232static struct dentry *rootdir;
233
234void spi_nor_debugfs_register(struct spi_nor *nor)
235{
236	struct dentry *d;
237	int ret;
238
239	if (!rootdir)
240		rootdir = debugfs_create_dir(SPI_NOR_DEBUGFS_ROOT, NULL);
241
242	ret = devm_add_action(nor->dev, spi_nor_debugfs_unregister, nor);
243	if (ret)
244		return;
245
246	d = debugfs_create_dir(dev_name(nor->dev), rootdir);
247	nor->debugfs_root = d;
248
249	debugfs_create_file("params", 0444, d, nor, &spi_nor_params_fops);
250	debugfs_create_file("capabilities", 0444, d, nor,
251			    &spi_nor_capabilities_fops);
252}
253
254void spi_nor_debugfs_shutdown(void)
255{
256	debugfs_remove(rootdir);
257}