Linux Audio

Check our new training course

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