]>
Commit | Line | Data |
---|---|---|
4d5e29a6 JT |
1 | /* |
2 | * SPI flash probing | |
3 | * | |
4 | * Copyright (C) 2008 Atmel Corporation | |
5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik | |
6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | |
7 | * | |
0c88a84a | 8 | * SPDX-License-Identifier: GPL-2.0+ |
4d5e29a6 JT |
9 | */ |
10 | ||
11 | #include <common.h> | |
fbb09918 | 12 | #include <dm.h> |
ae242cbf | 13 | #include <errno.h> |
4d5e29a6 JT |
14 | #include <fdtdec.h> |
15 | #include <malloc.h> | |
0eb25b61 | 16 | #include <mapmem.h> |
4d5e29a6 JT |
17 | #include <spi.h> |
18 | #include <spi_flash.h> | |
ffdb20be | 19 | #include <asm/io.h> |
4d5e29a6 | 20 | |
898e76c9 | 21 | #include "sf_internal.h" |
4d5e29a6 JT |
22 | |
23 | DECLARE_GLOBAL_DATA_PTR; | |
24 | ||
4e09cc1e JT |
25 | /* Read commands array */ |
26 | static u8 spi_read_cmds_array[] = { | |
27 | CMD_READ_ARRAY_SLOW, | |
6dd6e90e | 28 | CMD_READ_ARRAY_FAST, |
4e09cc1e JT |
29 | CMD_READ_DUAL_OUTPUT_FAST, |
30 | CMD_READ_DUAL_IO_FAST, | |
3163aaa6 | 31 | CMD_READ_QUAD_OUTPUT_FAST, |
c4ba0d82 | 32 | CMD_READ_QUAD_IO_FAST, |
4e09cc1e JT |
33 | }; |
34 | ||
9f4322fd JT |
35 | #ifdef CONFIG_SPI_FLASH_MACRONIX |
36 | static int spi_flash_set_qeb_mxic(struct spi_flash *flash) | |
37 | { | |
38 | u8 qeb_status; | |
39 | int ret; | |
40 | ||
41 | ret = spi_flash_cmd_read_status(flash, &qeb_status); | |
42 | if (ret < 0) | |
43 | return ret; | |
44 | ||
45 | if (qeb_status & STATUS_QEB_MXIC) { | |
46 | debug("SF: mxic: QEB is already set\n"); | |
47 | } else { | |
48 | ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); | |
49 | if (ret < 0) | |
50 | return ret; | |
51 | } | |
52 | ||
53 | return ret; | |
54 | } | |
55 | #endif | |
56 | ||
57 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | |
58 | static int spi_flash_set_qeb_winspan(struct spi_flash *flash) | |
59 | { | |
60 | u8 qeb_status; | |
61 | int ret; | |
62 | ||
63 | ret = spi_flash_cmd_read_config(flash, &qeb_status); | |
64 | if (ret < 0) | |
65 | return ret; | |
66 | ||
67 | if (qeb_status & STATUS_QEB_WINSPAN) { | |
68 | debug("SF: winspan: QEB is already set\n"); | |
69 | } else { | |
70 | ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); | |
71 | if (ret < 0) | |
72 | return ret; | |
73 | } | |
74 | ||
75 | return ret; | |
76 | } | |
77 | #endif | |
78 | ||
d08a1baf JT |
79 | static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) |
80 | { | |
81 | switch (idcode0) { | |
06795122 JT |
82 | #ifdef CONFIG_SPI_FLASH_MACRONIX |
83 | case SPI_FLASH_CFI_MFR_MACRONIX: | |
84 | return spi_flash_set_qeb_mxic(flash); | |
85 | #endif | |
d08a1baf JT |
86 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) |
87 | case SPI_FLASH_CFI_MFR_SPANSION: | |
88 | case SPI_FLASH_CFI_MFR_WINBOND: | |
89 | return spi_flash_set_qeb_winspan(flash); | |
90 | #endif | |
91 | #ifdef CONFIG_SPI_FLASH_STMICRO | |
92 | case SPI_FLASH_CFI_MFR_STMICRO: | |
93 | debug("SF: QEB is volatile for %02x flash\n", idcode0); | |
94 | return 0; | |
95 | #endif | |
96 | default: | |
97 | printf("SF: Need set QEB func for %02x flash\n", idcode0); | |
98 | return -1; | |
99 | } | |
100 | } | |
101 | ||
234a9e1c JT |
102 | #ifdef CONFIG_SPI_FLASH_BAR |
103 | static int spi_flash_read_bank(struct spi_flash *flash, u8 idcode0) | |
104 | { | |
105 | u8 curr_bank = 0; | |
106 | int ret; | |
107 | ||
108 | if (flash->size <= SPI_FLASH_16MB_BOUN) | |
109 | goto bank_end; | |
110 | ||
111 | switch (idcode0) { | |
112 | case SPI_FLASH_CFI_MFR_SPANSION: | |
113 | flash->bank_read_cmd = CMD_BANKADDR_BRRD; | |
114 | flash->bank_write_cmd = CMD_BANKADDR_BRWR; | |
115 | default: | |
116 | flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; | |
117 | flash->bank_write_cmd = CMD_EXTNADDR_WREAR; | |
118 | } | |
119 | ||
120 | ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, | |
121 | &curr_bank, 1); | |
122 | if (ret) { | |
123 | debug("SF: fail to read bank addr register\n"); | |
124 | return ret; | |
125 | } | |
126 | ||
127 | bank_end: | |
128 | flash->bank_curr = curr_bank; | |
129 | return 0; | |
130 | } | |
131 | #endif | |
132 | ||
ae242cbf SG |
133 | static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, |
134 | struct spi_flash *flash) | |
4d4ec992 JT |
135 | { |
136 | const struct spi_flash_params *params; | |
4e09cc1e | 137 | u8 cmd; |
4d4ec992 | 138 | u16 jedec = idcode[1] << 8 | idcode[2]; |
74bec16e | 139 | u16 ext_jedec = idcode[3] << 8 | idcode[4]; |
4d4ec992 | 140 | |
ae242cbf | 141 | /* Validate params from spi_flash_params table */ |
33adfb5f JT |
142 | params = spi_flash_params_table; |
143 | for (; params->name != NULL; params++) { | |
4d4ec992 | 144 | if ((params->jedec >> 16) == idcode[0]) { |
74bec16e JT |
145 | if ((params->jedec & 0xFFFF) == jedec) { |
146 | if (params->ext_jedec == 0) | |
147 | break; | |
148 | else if (params->ext_jedec == ext_jedec) | |
149 | break; | |
150 | } | |
4d4ec992 JT |
151 | } |
152 | } | |
153 | ||
33adfb5f | 154 | if (!params->name) { |
74bec16e JT |
155 | printf("SF: Unsupported flash IDs: "); |
156 | printf("manuf %02x, jedec %04x, ext_jedec %04x\n", | |
157 | idcode[0], jedec, ext_jedec); | |
ae242cbf | 158 | return -EPROTONOSUPPORT; |
4d4ec992 | 159 | } |
4d4ec992 | 160 | |
469146c0 | 161 | /* Assign spi data */ |
4d4ec992 JT |
162 | flash->spi = spi; |
163 | flash->name = params->name; | |
ce22b922 | 164 | flash->memory_map = spi->memory_map; |
f77f4691 | 165 | flash->dual_flash = flash->spi->option; |
4d4ec992 JT |
166 | |
167 | /* Assign spi_flash ops */ | |
fbb09918 | 168 | #ifndef CONFIG_DM_SPI_FLASH |
a5e8199a | 169 | flash->write = spi_flash_cmd_write_ops; |
fbb09918 | 170 | #if defined(CONFIG_SPI_FLASH_SST) |
1fabefdd JT |
171 | if (params->flags & SST_WR) |
172 | flash->flags |= SNOR_F_SST_WR; | |
173 | ||
174 | if (params->flags & SNOR_F_SST_WR) { | |
54ba653a JT |
175 | if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) |
176 | flash->write = sst_write_bp; | |
177 | else | |
178 | flash->write = sst_write_wp; | |
179 | } | |
10ca45d0 | 180 | #endif |
a5e8199a JT |
181 | flash->erase = spi_flash_cmd_erase_ops; |
182 | flash->read = spi_flash_cmd_read_ops; | |
fbb09918 | 183 | #endif |
4d4ec992 | 184 | |
c3c016cf FE |
185 | /* lock hooks are flash specific - assign them based on idcode0 */ |
186 | switch (idcode[0]) { | |
187 | #ifdef CONFIG_SPI_FLASH_STMICRO | |
188 | case SPI_FLASH_CFI_MFR_STMICRO: | |
189 | flash->flash_lock = stm_lock; | |
190 | flash->flash_unlock = stm_unlock; | |
191 | flash->flash_is_locked = stm_is_locked; | |
192 | #endif | |
193 | break; | |
194 | default: | |
195 | debug("SF: Lock ops not supported for %02x flash\n", idcode[0]); | |
196 | } | |
197 | ||
4d4ec992 | 198 | /* Compute the flash size */ |
056fbc73 | 199 | flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; |
bf64035a MV |
200 | /* |
201 | * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the | |
202 | * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with | |
203 | * the 0x4d00 Extended JEDEC code have 512b pages. All of the others | |
204 | * have 256b pages. | |
205 | */ | |
206 | if (ext_jedec == 0x4d00) { | |
207 | if ((jedec == 0x0215) || (jedec == 0x216)) | |
208 | flash->page_size = 256; | |
209 | else | |
210 | flash->page_size = 512; | |
211 | } else { | |
212 | flash->page_size = 256; | |
213 | } | |
214 | flash->page_size <<= flash->shift; | |
056fbc73 JT |
215 | flash->sector_size = params->sector_size << flash->shift; |
216 | flash->size = flash->sector_size * params->nr_sectors << flash->shift; | |
b902e07c | 217 | #ifdef CONFIG_SF_DUAL_FLASH |
f77f4691 JT |
218 | if (flash->dual_flash & SF_DUAL_STACKED_FLASH) |
219 | flash->size <<= 1; | |
b902e07c | 220 | #endif |
4d4ec992 | 221 | |
f4f51a8f JT |
222 | /* Compute erase sector and command */ |
223 | if (params->flags & SECT_4K) { | |
224 | flash->erase_cmd = CMD_ERASE_4K; | |
056fbc73 | 225 | flash->erase_size = 4096 << flash->shift; |
f4f51a8f JT |
226 | } else if (params->flags & SECT_32K) { |
227 | flash->erase_cmd = CMD_ERASE_32K; | |
056fbc73 | 228 | flash->erase_size = 32768 << flash->shift; |
f4f51a8f JT |
229 | } else { |
230 | flash->erase_cmd = CMD_ERASE_64K; | |
231 | flash->erase_size = flash->sector_size; | |
232 | } | |
233 | ||
c650ca7b JT |
234 | /* Now erase size becomes valid sector size */ |
235 | flash->sector_size = flash->erase_size; | |
236 | ||
4e09cc1e JT |
237 | /* Look for the fastest read cmd */ |
238 | cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); | |
239 | if (cmd) { | |
240 | cmd = spi_read_cmds_array[cmd - 1]; | |
241 | flash->read_cmd = cmd; | |
242 | } else { | |
2ba863fa | 243 | /* Go for default supported read cmd */ |
4e09cc1e JT |
244 | flash->read_cmd = CMD_READ_ARRAY_FAST; |
245 | } | |
246 | ||
3163aaa6 JT |
247 | /* Not require to look for fastest only two write cmds yet */ |
248 | if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) | |
249 | flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; | |
250 | else | |
251 | /* Go for default supported write cmd */ | |
252 | flash->write_cmd = CMD_PAGE_PROGRAM; | |
253 | ||
ff063ed4 JT |
254 | /* Read dummy_byte: dummy byte is determined based on the |
255 | * dummy cycles of a particular command. | |
256 | * Fast commands - dummy_byte = dummy_cycles/8 | |
257 | * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 | |
258 | * For I/O commands except cmd[0] everything goes on no.of lines | |
259 | * based on particular command but incase of fast commands except | |
260 | * data all go on single line irrespective of command. | |
261 | */ | |
262 | switch (flash->read_cmd) { | |
263 | case CMD_READ_QUAD_IO_FAST: | |
264 | flash->dummy_byte = 2; | |
265 | break; | |
266 | case CMD_READ_ARRAY_SLOW: | |
267 | flash->dummy_byte = 0; | |
268 | break; | |
269 | default: | |
270 | flash->dummy_byte = 1; | |
271 | } | |
272 | ||
0f623280 JT |
273 | #ifdef CONFIG_SPI_FLASH_STMICRO |
274 | if (params->flags & E_FSR) | |
baaaa753 | 275 | flash->flags |= SNOR_F_USE_FSR; |
0f623280 JT |
276 | #endif |
277 | ||
ce22b922 | 278 | /* Configure the BAR - discover bank cmds and read current bank */ |
4d5e29a6 | 279 | #ifdef CONFIG_SPI_FLASH_BAR |
234a9e1c JT |
280 | int ret = spi_flash_read_bank(flash, idcode[0]); |
281 | if (ret < 0) | |
282 | return ret; | |
32ebd1a7 | 283 | #endif |
4d5e29a6 | 284 | |
32ebd1a7 JT |
285 | /* Flash powers up read-only, so clear BP# bits */ |
286 | #if defined(CONFIG_SPI_FLASH_ATMEL) || \ | |
287 | defined(CONFIG_SPI_FLASH_MACRONIX) || \ | |
288 | defined(CONFIG_SPI_FLASH_SST) | |
289 | spi_flash_cmd_write_status(flash, 0); | |
4d5e29a6 JT |
290 | #endif |
291 | ||
ae242cbf | 292 | return 0; |
32ebd1a7 JT |
293 | } |
294 | ||
0f925822 | 295 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
4d5e29a6 JT |
296 | int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) |
297 | { | |
298 | fdt_addr_t addr; | |
299 | fdt_size_t size; | |
300 | int node; | |
301 | ||
302 | /* If there is no node, do nothing */ | |
303 | node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); | |
304 | if (node < 0) | |
305 | return 0; | |
306 | ||
307 | addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); | |
308 | if (addr == FDT_ADDR_T_NONE) { | |
309 | debug("%s: Cannot decode address\n", __func__); | |
310 | return 0; | |
311 | } | |
312 | ||
313 | if (flash->size != size) { | |
314 | debug("%s: Memory map must cover entire device\n", __func__); | |
315 | return -1; | |
316 | } | |
ffdb20be | 317 | flash->memory_map = map_sysmem(addr, size); |
4d5e29a6 JT |
318 | |
319 | return 0; | |
320 | } | |
0f925822 | 321 | #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ |
4d5e29a6 | 322 | |
ae242cbf SG |
323 | /** |
324 | * spi_flash_probe_slave() - Probe for a SPI flash device on a bus | |
325 | * | |
326 | * @spi: Bus to probe | |
327 | * @flashp: Pointer to place to put flash info, which may be NULL if the | |
328 | * space should be allocated | |
329 | */ | |
330 | int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) | |
4d5e29a6 | 331 | { |
32ebd1a7 | 332 | u8 idcode[5]; |
4d4ec992 | 333 | int ret; |
4d5e29a6 | 334 | |
4d4ec992 | 335 | /* Setup spi_slave */ |
4d5e29a6 JT |
336 | if (!spi) { |
337 | printf("SF: Failed to set up slave\n"); | |
ae242cbf | 338 | return -ENODEV; |
4d5e29a6 JT |
339 | } |
340 | ||
4d4ec992 | 341 | /* Claim spi bus */ |
4d5e29a6 JT |
342 | ret = spi_claim_bus(spi); |
343 | if (ret) { | |
344 | debug("SF: Failed to claim SPI bus: %d\n", ret); | |
ae242cbf | 345 | return ret; |
4d5e29a6 JT |
346 | } |
347 | ||
348 | /* Read the ID codes */ | |
349 | ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); | |
4d4ec992 JT |
350 | if (ret) { |
351 | printf("SF: Failed to get idcodes\n"); | |
4d5e29a6 | 352 | goto err_read_id; |
4d4ec992 | 353 | } |
4d5e29a6 JT |
354 | |
355 | #ifdef DEBUG | |
356 | printf("SF: Got idcodes\n"); | |
357 | print_buffer(0, idcode, 1, sizeof(idcode), 0); | |
358 | #endif | |
359 | ||
ae242cbf SG |
360 | if (spi_flash_validate_params(spi, idcode, flash)) { |
361 | ret = -EINVAL; | |
4d4ec992 | 362 | goto err_read_id; |
ae242cbf | 363 | } |
4d5e29a6 | 364 | |
1f436a6d PS |
365 | /* Set the quad enable bit - only for quad commands */ |
366 | if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || | |
367 | (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || | |
368 | (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { | |
369 | if (spi_flash_set_qeb(flash, idcode[0])) { | |
370 | debug("SF: Fail to set QEB for %02x\n", idcode[0]); | |
ae242cbf SG |
371 | ret = -EINVAL; |
372 | goto err_read_id; | |
1f436a6d PS |
373 | } |
374 | } | |
375 | ||
0f925822 | 376 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
4d5e29a6 JT |
377 | if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { |
378 | debug("SF: FDT decode error\n"); | |
ae242cbf | 379 | ret = -EINVAL; |
4d4ec992 | 380 | goto err_read_id; |
4d5e29a6 JT |
381 | } |
382 | #endif | |
383 | #ifndef CONFIG_SPL_BUILD | |
384 | printf("SF: Detected %s with page size ", flash->name); | |
3ea708f0 JT |
385 | print_size(flash->page_size, ", erase size "); |
386 | print_size(flash->erase_size, ", total "); | |
4d5e29a6 JT |
387 | print_size(flash->size, ""); |
388 | if (flash->memory_map) | |
389 | printf(", mapped at %p", flash->memory_map); | |
390 | puts("\n"); | |
391 | #endif | |
392 | #ifndef CONFIG_SPI_FLASH_BAR | |
f77f4691 JT |
393 | if (((flash->dual_flash == SF_SINGLE_FLASH) && |
394 | (flash->size > SPI_FLASH_16MB_BOUN)) || | |
395 | ((flash->dual_flash > SF_SINGLE_FLASH) && | |
396 | (flash->size > SPI_FLASH_16MB_BOUN << 1))) { | |
4d5e29a6 JT |
397 | puts("SF: Warning - Only lower 16MiB accessible,"); |
398 | puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | |
399 | } | |
400 | #endif | |
9fe6d871 DS |
401 | #ifdef CONFIG_SPI_FLASH_MTD |
402 | ret = spi_flash_mtd_register(flash); | |
403 | #endif | |
4d5e29a6 | 404 | |
4d5e29a6 JT |
405 | err_read_id: |
406 | spi_release_bus(spi); | |
ae242cbf SG |
407 | return ret; |
408 | } | |
409 | ||
fbb09918 SG |
410 | #ifndef CONFIG_DM_SPI_FLASH |
411 | struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) | |
ae242cbf SG |
412 | { |
413 | struct spi_flash *flash; | |
414 | ||
415 | /* Allocate space if needed (not used by sf-uclass */ | |
416 | flash = calloc(1, sizeof(*flash)); | |
417 | if (!flash) { | |
418 | debug("SF: Failed to allocate spi_flash\n"); | |
419 | return NULL; | |
420 | } | |
421 | ||
422 | if (spi_flash_probe_slave(bus, flash)) { | |
423 | spi_free_slave(bus); | |
424 | free(flash); | |
425 | return NULL; | |
426 | } | |
427 | ||
428 | return flash; | |
4d5e29a6 JT |
429 | } |
430 | ||
ae242cbf | 431 | struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, |
0efc0249 SG |
432 | unsigned int max_hz, unsigned int spi_mode) |
433 | { | |
ae242cbf | 434 | struct spi_slave *bus; |
0efc0249 | 435 | |
ae242cbf | 436 | bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); |
4fbad92e PF |
437 | if (!bus) |
438 | return NULL; | |
ae242cbf | 439 | return spi_flash_probe_tail(bus); |
0efc0249 SG |
440 | } |
441 | ||
442 | #ifdef CONFIG_OF_SPI_FLASH | |
443 | struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, | |
444 | int spi_node) | |
445 | { | |
ae242cbf | 446 | struct spi_slave *bus; |
0efc0249 | 447 | |
ae242cbf | 448 | bus = spi_setup_slave_fdt(blob, slave_node, spi_node); |
4fbad92e PF |
449 | if (!bus) |
450 | return NULL; | |
ae242cbf | 451 | return spi_flash_probe_tail(bus); |
0efc0249 SG |
452 | } |
453 | #endif | |
454 | ||
4d5e29a6 JT |
455 | void spi_flash_free(struct spi_flash *flash) |
456 | { | |
9fe6d871 DS |
457 | #ifdef CONFIG_SPI_FLASH_MTD |
458 | spi_flash_mtd_unregister(); | |
459 | #endif | |
4d5e29a6 JT |
460 | spi_free_slave(flash->spi); |
461 | free(flash); | |
462 | } | |
fbb09918 SG |
463 | |
464 | #else /* defined CONFIG_DM_SPI_FLASH */ | |
465 | ||
466 | static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, | |
467 | void *buf) | |
468 | { | |
e564f054 | 469 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
fbb09918 SG |
470 | |
471 | return spi_flash_cmd_read_ops(flash, offset, len, buf); | |
472 | } | |
473 | ||
474 | int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, | |
475 | const void *buf) | |
476 | { | |
e564f054 | 477 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
fbb09918 | 478 | |
074eed51 | 479 | #if defined(CONFIG_SPI_FLASH_SST) |
1fabefdd | 480 | if (flash->flags & SNOR_F_SST_WR) { |
074eed51 BM |
481 | if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) |
482 | return sst_write_bp(flash, offset, len, buf); | |
483 | else | |
484 | return sst_write_wp(flash, offset, len, buf); | |
485 | } | |
486 | #endif | |
487 | ||
fbb09918 SG |
488 | return spi_flash_cmd_write_ops(flash, offset, len, buf); |
489 | } | |
490 | ||
491 | int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) | |
492 | { | |
e564f054 | 493 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
fbb09918 SG |
494 | |
495 | return spi_flash_cmd_erase_ops(flash, offset, len); | |
496 | } | |
497 | ||
498 | int spi_flash_std_probe(struct udevice *dev) | |
499 | { | |
bcbe3d15 | 500 | struct spi_slave *slave = dev_get_parent_priv(dev); |
d0cff03e | 501 | struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); |
fbb09918 SG |
502 | struct spi_flash *flash; |
503 | ||
e564f054 | 504 | flash = dev_get_uclass_priv(dev); |
fbb09918 | 505 | flash->dev = dev; |
d0cff03e | 506 | debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs); |
fbb09918 SG |
507 | return spi_flash_probe_slave(slave, flash); |
508 | } | |
509 | ||
510 | static const struct dm_spi_flash_ops spi_flash_std_ops = { | |
511 | .read = spi_flash_std_read, | |
512 | .write = spi_flash_std_write, | |
513 | .erase = spi_flash_std_erase, | |
514 | }; | |
515 | ||
516 | static const struct udevice_id spi_flash_std_ids[] = { | |
517 | { .compatible = "spi-flash" }, | |
518 | { } | |
519 | }; | |
520 | ||
521 | U_BOOT_DRIVER(spi_flash_std) = { | |
522 | .name = "spi_flash_std", | |
523 | .id = UCLASS_SPI_FLASH, | |
524 | .of_match = spi_flash_std_ids, | |
525 | .probe = spi_flash_std_probe, | |
526 | .priv_auto_alloc_size = sizeof(struct spi_flash), | |
527 | .ops = &spi_flash_std_ops, | |
528 | }; | |
529 | ||
530 | #endif /* CONFIG_DM_SPI_FLASH */ |