Blame view

drivers/mtd/spi/sf_probe.c 9.26 KB
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
1
2
3
4
5
6
7
  /*
   * SPI flash probing
   *
   * Copyright (C) 2008 Atmel Corporation
   * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
   * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
   *
0c88a84ac   Jagannadha Sutradharudu Teki   sf: Add GPL-2.0+ ...
8
   * SPDX-License-Identifier:	GPL-2.0+
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
9
10
11
12
13
14
15
   */
  
  #include <common.h>
  #include <fdtdec.h>
  #include <malloc.h>
  #include <spi.h>
  #include <spi_flash.h>
ffdb20bea   Mike Frysinger   sandbox: spi: Add...
16
  #include <asm/io.h>
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
17

898e76c93   Jagannadha Sutradharudu Teki   sf: Rename spi_fl...
18
  #include "sf_internal.h"
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
19
20
  
  DECLARE_GLOBAL_DATA_PTR;
4e09cc1e2   Jagannadha Sutradharudu Teki   sf: Add extended ...
21
22
23
24
25
  /* Read commands array */
  static u8 spi_read_cmds_array[] = {
  	CMD_READ_ARRAY_SLOW,
  	CMD_READ_DUAL_OUTPUT_FAST,
  	CMD_READ_DUAL_IO_FAST,
3163aaa63   Jagannadha Sutradharudu Teki   sf: Add quad read...
26
  	CMD_READ_QUAD_OUTPUT_FAST,
c4ba0d82d   Jagannadha Sutradharudu Teki   sf: Add QUAD_IO_F...
27
  	CMD_READ_QUAD_IO_FAST,
4e09cc1e2   Jagannadha Sutradharudu Teki   sf: Add extended ...
28
  };
9f4322fd2   Jagannadha Sutradharudu Teki   sf: Divide flash ...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  #ifdef CONFIG_SPI_FLASH_MACRONIX
  static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
  {
  	u8 qeb_status;
  	int ret;
  
  	ret = spi_flash_cmd_read_status(flash, &qeb_status);
  	if (ret < 0)
  		return ret;
  
  	if (qeb_status & STATUS_QEB_MXIC) {
  		debug("SF: mxic: QEB is already set
  ");
  	} else {
  		ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC);
  		if (ret < 0)
  			return ret;
  	}
  
  	return ret;
  }
  #endif
  
  #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
  static int spi_flash_set_qeb_winspan(struct spi_flash *flash)
  {
  	u8 qeb_status;
  	int ret;
  
  	ret = spi_flash_cmd_read_config(flash, &qeb_status);
  	if (ret < 0)
  		return ret;
  
  	if (qeb_status & STATUS_QEB_WINSPAN) {
  		debug("SF: winspan: QEB is already set
  ");
  	} else {
  		ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN);
  		if (ret < 0)
  			return ret;
  	}
  
  	return ret;
  }
  #endif
d08a1baf6   Jagannadha Sutradharudu Teki   sf: Set quad enab...
74
75
76
  static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
  {
  	switch (idcode0) {
067951223   Jagannadha Sutradharudu Teki   sf: Add macronix ...
77
78
79
80
  #ifdef CONFIG_SPI_FLASH_MACRONIX
  	case SPI_FLASH_CFI_MFR_MACRONIX:
  		return spi_flash_set_qeb_mxic(flash);
  #endif
d08a1baf6   Jagannadha Sutradharudu Teki   sf: Set quad enab...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
  	case SPI_FLASH_CFI_MFR_SPANSION:
  	case SPI_FLASH_CFI_MFR_WINBOND:
  		return spi_flash_set_qeb_winspan(flash);
  #endif
  #ifdef CONFIG_SPI_FLASH_STMICRO
  	case SPI_FLASH_CFI_MFR_STMICRO:
  		debug("SF: QEB is volatile for %02x flash
  ", idcode0);
  		return 0;
  #endif
  	default:
  		printf("SF: Need set QEB func for %02x flash
  ", idcode0);
  		return -1;
  	}
  }
ce22b922d   Jagannadha Sutradharudu Teki   sf: Minor cleanups
98
99
  static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
  		u8 *idcode)
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
100
101
102
  {
  	const struct spi_flash_params *params;
  	struct spi_flash *flash;
4e09cc1e2   Jagannadha Sutradharudu Teki   sf: Add extended ...
103
  	u8 cmd;
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
104
  	u16 jedec = idcode[1] << 8 | idcode[2];
74bec16eb   Jagannadha Sutradharudu Teki   sf: probe: Add su...
105
  	u16 ext_jedec = idcode[3] << 8 | idcode[4];
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
106

33adfb5f9   Jagannadha Sutradharudu Teki   sf: Separate the ...
107
108
  	params = spi_flash_params_table;
  	for (; params->name != NULL; params++) {
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
109
  		if ((params->jedec >> 16) == idcode[0]) {
74bec16eb   Jagannadha Sutradharudu Teki   sf: probe: Add su...
110
111
112
113
114
115
  			if ((params->jedec & 0xFFFF) == jedec) {
  				if (params->ext_jedec == 0)
  					break;
  				else if (params->ext_jedec == ext_jedec)
  					break;
  			}
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
116
117
  		}
  	}
33adfb5f9   Jagannadha Sutradharudu Teki   sf: Separate the ...
118
  	if (!params->name) {
74bec16eb   Jagannadha Sutradharudu Teki   sf: probe: Add su...
119
120
121
122
  		printf("SF: Unsupported flash IDs: ");
  		printf("manuf %02x, jedec %04x, ext_jedec %04x
  ",
  		       idcode[0], jedec, ext_jedec);
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
123
124
125
126
127
128
129
130
131
132
  		return NULL;
  	}
  
  	flash = malloc(sizeof(*flash));
  	if (!flash) {
  		debug("SF: Failed to allocate spi_flash
  ");
  		return NULL;
  	}
  	memset(flash, '\0', sizeof(*flash));
469146c09   Jagannadha Sutradharudu Teki   sf: Minor cleanups.
133
  	/* Assign spi data */
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
134
135
  	flash->spi = spi;
  	flash->name = params->name;
ce22b922d   Jagannadha Sutradharudu Teki   sf: Minor cleanups
136
  	flash->memory_map = spi->memory_map;
f77f46911   Jagannadha Sutradharudu Teki   sf: Add dual memo...
137
  	flash->dual_flash = flash->spi->option;
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
138
139
  
  	/* Assign spi_flash ops */
a5e8199a1   Jagannadha Sutradharudu Teki   sf: spi_flash cle...
140
  	flash->write = spi_flash_cmd_write_ops;
10ca45d00   Jagannadha Sutradharudu Teki   sf: probe: Add su...
141
142
143
144
  #ifdef CONFIG_SPI_FLASH_SST
  	if (params->flags & SST_WP)
  		flash->write = sst_write_wp;
  #endif
a5e8199a1   Jagannadha Sutradharudu Teki   sf: spi_flash cle...
145
146
  	flash->erase = spi_flash_cmd_erase_ops;
  	flash->read = spi_flash_cmd_read_ops;
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
147
148
  
  	/* Compute the flash size */
056fbc73d   Jagannadha Sutradharudu Teki   sf: Add dual memo...
149
150
151
152
  	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
  	flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift;
  	flash->sector_size = params->sector_size << flash->shift;
  	flash->size = flash->sector_size * params->nr_sectors << flash->shift;
b902e07ce   Jagannadha Sutradharudu Teki   sf: Add CONFIG_SF...
153
  #ifdef CONFIG_SF_DUAL_FLASH
f77f46911   Jagannadha Sutradharudu Teki   sf: Add dual memo...
154
155
  	if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
  		flash->size <<= 1;
b902e07ce   Jagannadha Sutradharudu Teki   sf: Add CONFIG_SF...
156
  #endif
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
157

f4f51a8ff   Jagannadha Sutradharudu Teki   sf: probe: Add su...
158
159
160
  	/* Compute erase sector and command */
  	if (params->flags & SECT_4K) {
  		flash->erase_cmd = CMD_ERASE_4K;
056fbc73d   Jagannadha Sutradharudu Teki   sf: Add dual memo...
161
  		flash->erase_size = 4096 << flash->shift;
f4f51a8ff   Jagannadha Sutradharudu Teki   sf: probe: Add su...
162
163
  	} else if (params->flags & SECT_32K) {
  		flash->erase_cmd = CMD_ERASE_32K;
056fbc73d   Jagannadha Sutradharudu Teki   sf: Add dual memo...
164
  		flash->erase_size = 32768 << flash->shift;
f4f51a8ff   Jagannadha Sutradharudu Teki   sf: probe: Add su...
165
166
167
168
  	} else {
  		flash->erase_cmd = CMD_ERASE_64K;
  		flash->erase_size = flash->sector_size;
  	}
4e09cc1e2   Jagannadha Sutradharudu Teki   sf: Add extended ...
169
170
171
172
173
174
  	/* Look for the fastest read cmd */
  	cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx);
  	if (cmd) {
  		cmd = spi_read_cmds_array[cmd - 1];
  		flash->read_cmd = cmd;
  	} else {
2ba863fae   Jagannadha Sutradharudu Teki   sf: Code cleanups
175
  		/* Go for default supported read cmd */
4e09cc1e2   Jagannadha Sutradharudu Teki   sf: Add extended ...
176
177
  		flash->read_cmd = CMD_READ_ARRAY_FAST;
  	}
3163aaa63   Jagannadha Sutradharudu Teki   sf: Add quad read...
178
179
180
181
182
183
  	/* Not require to look for fastest only two write cmds yet */
  	if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP)
  		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
  	else
  		/* Go for default supported write cmd */
  		flash->write_cmd = CMD_PAGE_PROGRAM;
d08a1baf6   Jagannadha Sutradharudu Teki   sf: Set quad enab...
184
185
  	/* Set the quad enable bit - only for quad commands */
  	if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
c4ba0d82d   Jagannadha Sutradharudu Teki   sf: Add QUAD_IO_F...
186
  	    (flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
d08a1baf6   Jagannadha Sutradharudu Teki   sf: Set quad enab...
187
188
189
190
191
192
193
  	    (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
  		if (spi_flash_set_qeb(flash, idcode[0])) {
  			debug("SF: Fail to set QEB for %02x
  ", idcode[0]);
  			return NULL;
  		}
  	}
ff063ed48   Jagannadha Sutradharudu Teki   sf: Discover read...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  	/* Read dummy_byte: dummy byte is determined based on the
  	 * dummy cycles of a particular command.
  	 * Fast commands - dummy_byte = dummy_cycles/8
  	 * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
  	 * For I/O commands except cmd[0] everything goes on no.of lines
  	 * based on particular command but incase of fast commands except
  	 * data all go on single line irrespective of command.
  	 */
  	switch (flash->read_cmd) {
  	case CMD_READ_QUAD_IO_FAST:
  		flash->dummy_byte = 2;
  		break;
  	case CMD_READ_ARRAY_SLOW:
  		flash->dummy_byte = 0;
  		break;
  	default:
  		flash->dummy_byte = 1;
  	}
2ba863fae   Jagannadha Sutradharudu Teki   sf: Code cleanups
212
  	/* Poll cmd selection */
0f6232801   Jagannadha Sutradharudu Teki   sf: probe: Add su...
213
214
215
216
217
  	flash->poll_cmd = CMD_READ_STATUS;
  #ifdef CONFIG_SPI_FLASH_STMICRO
  	if (params->flags & E_FSR)
  		flash->poll_cmd = CMD_FLAG_STATUS;
  #endif
ce22b922d   Jagannadha Sutradharudu Teki   sf: Minor cleanups
218
  	/* Configure the BAR - discover bank cmds and read current bank */
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
219
  #ifdef CONFIG_SPI_FLASH_BAR
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
220
  	u8 curr_bank = 0;
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
221
  	if (flash->size > SPI_FLASH_16MB_BOUN) {
32ebd1a7d   Jagannadha Sutradharudu Teki   sf: probe: Simply...
222
223
224
225
226
227
228
  		flash->bank_read_cmd = (idcode[0] == 0x01) ?
  					CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR;
  		flash->bank_write_cmd = (idcode[0] == 0x01) ?
  					CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR;
  
  		if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
  					  &curr_bank, 1)) {
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
229
230
  			debug("SF: fail to read bank addr register
  ");
32ebd1a7d   Jagannadha Sutradharudu Teki   sf: probe: Simply...
231
  			return NULL;
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
232
233
234
235
236
  		}
  		flash->bank_curr = curr_bank;
  	} else {
  		flash->bank_curr = curr_bank;
  	}
32ebd1a7d   Jagannadha Sutradharudu Teki   sf: probe: Simply...
237
  #endif
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
238

32ebd1a7d   Jagannadha Sutradharudu Teki   sf: probe: Simply...
239
240
241
242
243
  	/* Flash powers up read-only, so clear BP# bits */
  #if defined(CONFIG_SPI_FLASH_ATMEL) || \
  	defined(CONFIG_SPI_FLASH_MACRONIX) || \
  	defined(CONFIG_SPI_FLASH_SST)
  		spi_flash_cmd_write_status(flash, 0);
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
244
  #endif
32ebd1a7d   Jagannadha Sutradharudu Teki   sf: probe: Simply...
245
246
  	return flash;
  }
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  #ifdef CONFIG_OF_CONTROL
  int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
  {
  	fdt_addr_t addr;
  	fdt_size_t size;
  	int node;
  
  	/* If there is no node, do nothing */
  	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
  	if (node < 0)
  		return 0;
  
  	addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
  	if (addr == FDT_ADDR_T_NONE) {
  		debug("%s: Cannot decode address
  ", __func__);
  		return 0;
  	}
  
  	if (flash->size != size) {
  		debug("%s: Memory map must cover entire device
  ", __func__);
  		return -1;
  	}
ffdb20bea   Mike Frysinger   sandbox: spi: Add...
271
  	flash->memory_map = map_sysmem(addr, size);
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
272
273
274
275
  
  	return 0;
  }
  #endif /* CONFIG_OF_CONTROL */
0efc02499   Simon Glass   spi_flash: Add sp...
276
  static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
277
  {
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
278
  	struct spi_flash *flash = NULL;
32ebd1a7d   Jagannadha Sutradharudu Teki   sf: probe: Simply...
279
  	u8 idcode[5];
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
280
  	int ret;
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
281

4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
282
  	/* Setup spi_slave */
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
283
284
285
286
287
  	if (!spi) {
  		printf("SF: Failed to set up slave
  ");
  		return NULL;
  	}
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
288
  	/* Claim spi bus */
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
289
290
291
292
293
294
295
296
297
  	ret = spi_claim_bus(spi);
  	if (ret) {
  		debug("SF: Failed to claim SPI bus: %d
  ", ret);
  		goto err_claim_bus;
  	}
  
  	/* Read the ID codes */
  	ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
298
299
300
  	if (ret) {
  		printf("SF: Failed to get idcodes
  ");
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
301
  		goto err_read_id;
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
302
  	}
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
303
304
305
306
307
308
  
  #ifdef DEBUG
  	printf("SF: Got idcodes
  ");
  	print_buffer(0, idcode, 1, sizeof(idcode), 0);
  #endif
a5e8199a1   Jagannadha Sutradharudu Teki   sf: spi_flash cle...
309
310
  	/* Validate params from spi_flash_params table */
  	flash = spi_flash_validate_params(spi, idcode);
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
311
312
  	if (!flash)
  		goto err_read_id;
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
313

4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
314
315
316
317
  #ifdef CONFIG_OF_CONTROL
  	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
  		debug("SF: FDT decode error
  ");
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
318
  		goto err_read_id;
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
319
320
321
322
  	}
  #endif
  #ifndef CONFIG_SPL_BUILD
  	printf("SF: Detected %s with page size ", flash->name);
3ea708f0d   Jagannadha Sutradharudu Teki   sf: probe: Print ...
323
324
  	print_size(flash->page_size, ", erase size ");
  	print_size(flash->erase_size, ", total ");
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
325
326
327
328
329
330
331
  	print_size(flash->size, "");
  	if (flash->memory_map)
  		printf(", mapped at %p", flash->memory_map);
  	puts("
  ");
  #endif
  #ifndef CONFIG_SPI_FLASH_BAR
f77f46911   Jagannadha Sutradharudu Teki   sf: Add dual memo...
332
333
334
335
  	if (((flash->dual_flash == SF_SINGLE_FLASH) &&
  	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
  	     ((flash->dual_flash > SF_SINGLE_FLASH) &&
  	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
336
337
338
339
340
  		puts("SF: Warning - Only lower 16MiB accessible,");
  		puts(" Full access #define CONFIG_SPI_FLASH_BAR
  ");
  	}
  #endif
4d4ec9927   Jagannadha Sutradharudu Teki   sf: probe: Add ne...
341
  	/* Release spi bus */
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
342
343
344
  	spi_release_bus(spi);
  
  	return flash;
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
345
346
347
348
349
350
  err_read_id:
  	spi_release_bus(spi);
  err_claim_bus:
  	spi_free_slave(spi);
  	return NULL;
  }
0efc02499   Simon Glass   spi_flash: Add sp...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
  		unsigned int max_hz, unsigned int spi_mode)
  {
  	struct spi_slave *spi;
  
  	spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
  	return spi_flash_probe_slave(spi);
  }
  
  #ifdef CONFIG_OF_SPI_FLASH
  struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
  				      int spi_node)
  {
  	struct spi_slave *spi;
  
  	spi = spi_setup_slave_fdt(blob, slave_node, spi_node);
  	return spi_flash_probe_slave(spi);
  }
  #endif
4d5e29a68   Jagannadha Sutradharudu Teki   sf: Divide spi_fl...
370
371
372
373
374
  void spi_flash_free(struct spi_flash *flash)
  {
  	spi_free_slave(flash->spi);
  	free(flash);
  }