Blame view
drivers/mtd/spi/sf_probe.c
9.26 KB
4d5e29a68 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 sf: Add GPL-2.0+ ... |
8 |
* SPDX-License-Identifier: GPL-2.0+ |
4d5e29a68 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 sandbox: spi: Add... |
16 |
#include <asm/io.h> |
4d5e29a68 sf: Divide spi_fl... |
17 |
|
898e76c93 sf: Rename spi_fl... |
18 |
#include "sf_internal.h" |
4d5e29a68 sf: Divide spi_fl... |
19 20 |
DECLARE_GLOBAL_DATA_PTR; |
4e09cc1e2 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 sf: Add quad read... |
26 |
CMD_READ_QUAD_OUTPUT_FAST, |
c4ba0d82d sf: Add QUAD_IO_F... |
27 |
CMD_READ_QUAD_IO_FAST, |
4e09cc1e2 sf: Add extended ... |
28 |
}; |
9f4322fd2 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 sf: Set quad enab... |
74 75 76 |
static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) { switch (idcode0) { |
067951223 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 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 sf: Minor cleanups |
98 99 |
static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) |
4d4ec9927 sf: probe: Add ne... |
100 101 102 |
{ const struct spi_flash_params *params; struct spi_flash *flash; |
4e09cc1e2 sf: Add extended ... |
103 |
u8 cmd; |
4d4ec9927 sf: probe: Add ne... |
104 |
u16 jedec = idcode[1] << 8 | idcode[2]; |
74bec16eb sf: probe: Add su... |
105 |
u16 ext_jedec = idcode[3] << 8 | idcode[4]; |
4d4ec9927 sf: probe: Add ne... |
106 |
|
33adfb5f9 sf: Separate the ... |
107 108 |
params = spi_flash_params_table; for (; params->name != NULL; params++) { |
4d4ec9927 sf: probe: Add ne... |
109 |
if ((params->jedec >> 16) == idcode[0]) { |
74bec16eb 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 sf: probe: Add ne... |
116 117 |
} } |
33adfb5f9 sf: Separate the ... |
118 |
if (!params->name) { |
74bec16eb 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 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 sf: Minor cleanups. |
133 |
/* Assign spi data */ |
4d4ec9927 sf: probe: Add ne... |
134 135 |
flash->spi = spi; flash->name = params->name; |
ce22b922d sf: Minor cleanups |
136 |
flash->memory_map = spi->memory_map; |
f77f46911 sf: Add dual memo... |
137 |
flash->dual_flash = flash->spi->option; |
4d4ec9927 sf: probe: Add ne... |
138 139 |
/* Assign spi_flash ops */ |
a5e8199a1 sf: spi_flash cle... |
140 |
flash->write = spi_flash_cmd_write_ops; |
10ca45d00 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 sf: spi_flash cle... |
145 146 |
flash->erase = spi_flash_cmd_erase_ops; flash->read = spi_flash_cmd_read_ops; |
4d4ec9927 sf: probe: Add ne... |
147 148 |
/* Compute the flash size */ |
056fbc73d 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 sf: Add CONFIG_SF... |
153 |
#ifdef CONFIG_SF_DUAL_FLASH |
f77f46911 sf: Add dual memo... |
154 155 |
if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1; |
b902e07ce sf: Add CONFIG_SF... |
156 |
#endif |
4d4ec9927 sf: probe: Add ne... |
157 |
|
f4f51a8ff sf: probe: Add su... |
158 159 160 |
/* Compute erase sector and command */ if (params->flags & SECT_4K) { flash->erase_cmd = CMD_ERASE_4K; |
056fbc73d sf: Add dual memo... |
161 |
flash->erase_size = 4096 << flash->shift; |
f4f51a8ff sf: probe: Add su... |
162 163 |
} else if (params->flags & SECT_32K) { flash->erase_cmd = CMD_ERASE_32K; |
056fbc73d sf: Add dual memo... |
164 |
flash->erase_size = 32768 << flash->shift; |
f4f51a8ff sf: probe: Add su... |
165 166 167 168 |
} else { flash->erase_cmd = CMD_ERASE_64K; flash->erase_size = flash->sector_size; } |
4e09cc1e2 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 sf: Code cleanups |
175 |
/* Go for default supported read cmd */ |
4e09cc1e2 sf: Add extended ... |
176 177 |
flash->read_cmd = CMD_READ_ARRAY_FAST; } |
3163aaa63 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 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 sf: Add QUAD_IO_F... |
186 |
(flash->read_cmd == CMD_READ_QUAD_IO_FAST) || |
d08a1baf6 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 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 sf: Code cleanups |
212 |
/* Poll cmd selection */ |
0f6232801 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 sf: Minor cleanups |
218 |
/* Configure the BAR - discover bank cmds and read current bank */ |
4d5e29a68 sf: Divide spi_fl... |
219 |
#ifdef CONFIG_SPI_FLASH_BAR |
4d5e29a68 sf: Divide spi_fl... |
220 |
u8 curr_bank = 0; |
4d5e29a68 sf: Divide spi_fl... |
221 |
if (flash->size > SPI_FLASH_16MB_BOUN) { |
32ebd1a7d 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 sf: Divide spi_fl... |
229 230 |
debug("SF: fail to read bank addr register "); |
32ebd1a7d sf: probe: Simply... |
231 |
return NULL; |
4d5e29a68 sf: Divide spi_fl... |
232 233 234 235 236 |
} flash->bank_curr = curr_bank; } else { flash->bank_curr = curr_bank; } |
32ebd1a7d sf: probe: Simply... |
237 |
#endif |
4d5e29a68 sf: Divide spi_fl... |
238 |
|
32ebd1a7d 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 sf: Divide spi_fl... |
244 |
#endif |
32ebd1a7d sf: probe: Simply... |
245 246 |
return flash; } |
4d5e29a68 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 sandbox: spi: Add... |
271 |
flash->memory_map = map_sysmem(addr, size); |
4d5e29a68 sf: Divide spi_fl... |
272 273 274 275 |
return 0; } #endif /* CONFIG_OF_CONTROL */ |
0efc02499 spi_flash: Add sp... |
276 |
static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) |
4d5e29a68 sf: Divide spi_fl... |
277 |
{ |
4d5e29a68 sf: Divide spi_fl... |
278 |
struct spi_flash *flash = NULL; |
32ebd1a7d sf: probe: Simply... |
279 |
u8 idcode[5]; |
4d4ec9927 sf: probe: Add ne... |
280 |
int ret; |
4d5e29a68 sf: Divide spi_fl... |
281 |
|
4d4ec9927 sf: probe: Add ne... |
282 |
/* Setup spi_slave */ |
4d5e29a68 sf: Divide spi_fl... |
283 284 285 286 287 |
if (!spi) { printf("SF: Failed to set up slave "); return NULL; } |
4d4ec9927 sf: probe: Add ne... |
288 |
/* Claim spi bus */ |
4d5e29a68 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 sf: probe: Add ne... |
298 299 300 |
if (ret) { printf("SF: Failed to get idcodes "); |
4d5e29a68 sf: Divide spi_fl... |
301 |
goto err_read_id; |
4d4ec9927 sf: probe: Add ne... |
302 |
} |
4d5e29a68 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 sf: spi_flash cle... |
309 310 |
/* Validate params from spi_flash_params table */ flash = spi_flash_validate_params(spi, idcode); |
4d4ec9927 sf: probe: Add ne... |
311 312 |
if (!flash) goto err_read_id; |
4d5e29a68 sf: Divide spi_fl... |
313 |
|
4d5e29a68 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 sf: probe: Add ne... |
318 |
goto err_read_id; |
4d5e29a68 sf: Divide spi_fl... |
319 320 321 322 |
} #endif #ifndef CONFIG_SPL_BUILD printf("SF: Detected %s with page size ", flash->name); |
3ea708f0d sf: probe: Print ... |
323 324 |
print_size(flash->page_size, ", erase size "); print_size(flash->erase_size, ", total "); |
4d5e29a68 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 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 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 sf: probe: Add ne... |
341 |
/* Release spi bus */ |
4d5e29a68 sf: Divide spi_fl... |
342 343 344 |
spi_release_bus(spi); return flash; |
4d5e29a68 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 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 sf: Divide spi_fl... |
370 371 372 373 374 |
void spi_flash_free(struct spi_flash *flash) { spi_free_slave(flash->spi); free(flash); } |