Commit 8c927809ea960596345c33b02294af6e236d4ad4
Committed by
Jagan Teki
1 parent
0c6f187cdb
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
mtd: spi: spi-nor-core: Add back U-Boot specific features
For legacy reasons, we will have to keep around U-Boot specific SPI_FLASH_BAR and SPI_TX_BYTE. Add them back to the new framework Signed-off-by: Vignesh R <vigneshr@ti.com> Reviewed-by: Jagan Teki <jagan@openedev.com> Tested-by: Jagan Teki <jagan@amarulasolutions.com> #zynq-microzed
Showing 2 changed files with 168 additions and 3 deletions Side-by-side Diff
drivers/mtd/spi/spi-nor-core.c
... | ... | @@ -291,6 +291,7 @@ |
291 | 291 | return mtd->priv; |
292 | 292 | } |
293 | 293 | |
294 | +#ifndef CONFIG_SPI_FLASH_BAR | |
294 | 295 | static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) |
295 | 296 | { |
296 | 297 | size_t i; |
... | ... | @@ -365,6 +366,7 @@ |
365 | 366 | nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); |
366 | 367 | nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); |
367 | 368 | } |
369 | +#endif /* !CONFIG_SPI_FLASH_BAR */ | |
368 | 370 | |
369 | 371 | /* Enable/disable 4-byte addressing mode. */ |
370 | 372 | static int set_4byte(struct spi_nor *nor, const struct flash_info *info, |
371 | 373 | |
... | ... | @@ -499,7 +501,80 @@ |
499 | 501 | DEFAULT_READY_WAIT_JIFFIES); |
500 | 502 | } |
501 | 503 | |
504 | +#ifdef CONFIG_SPI_FLASH_BAR | |
502 | 505 | /* |
506 | + * This "clean_bar" is necessary in a situation when one was accessing | |
507 | + * spi flash memory > 16 MiB by using Bank Address Register's BA24 bit. | |
508 | + * | |
509 | + * After it the BA24 bit shall be cleared to allow access to correct | |
510 | + * memory region after SW reset (by calling "reset" command). | |
511 | + * | |
512 | + * Otherwise, the BA24 bit may be left set and then after reset, the | |
513 | + * ROM would read/write/erase SPL from 16 MiB * bank_sel address. | |
514 | + */ | |
515 | +static int clean_bar(struct spi_nor *nor) | |
516 | +{ | |
517 | + u8 cmd, bank_sel = 0; | |
518 | + | |
519 | + if (nor->bank_curr == 0) | |
520 | + return 0; | |
521 | + cmd = nor->bank_write_cmd; | |
522 | + nor->bank_curr = 0; | |
523 | + write_enable(nor); | |
524 | + | |
525 | + return nor->write_reg(nor, cmd, &bank_sel, 1); | |
526 | +} | |
527 | + | |
528 | +static int write_bar(struct spi_nor *nor, u32 offset) | |
529 | +{ | |
530 | + u8 cmd, bank_sel; | |
531 | + int ret; | |
532 | + | |
533 | + bank_sel = offset / SZ_16M; | |
534 | + if (bank_sel == nor->bank_curr) | |
535 | + goto bar_end; | |
536 | + | |
537 | + cmd = nor->bank_write_cmd; | |
538 | + write_enable(nor); | |
539 | + ret = nor->write_reg(nor, cmd, &bank_sel, 1); | |
540 | + if (ret < 0) { | |
541 | + debug("SF: fail to write bank register\n"); | |
542 | + return ret; | |
543 | + } | |
544 | + | |
545 | +bar_end: | |
546 | + nor->bank_curr = bank_sel; | |
547 | + return nor->bank_curr; | |
548 | +} | |
549 | + | |
550 | +static int read_bar(struct spi_nor *nor, const struct flash_info *info) | |
551 | +{ | |
552 | + u8 curr_bank = 0; | |
553 | + int ret; | |
554 | + | |
555 | + switch (JEDEC_MFR(info)) { | |
556 | + case SNOR_MFR_SPANSION: | |
557 | + nor->bank_read_cmd = SPINOR_OP_BRRD; | |
558 | + nor->bank_write_cmd = SPINOR_OP_BRWR; | |
559 | + break; | |
560 | + default: | |
561 | + nor->bank_read_cmd = SPINOR_OP_RDEAR; | |
562 | + nor->bank_write_cmd = SPINOR_OP_WREAR; | |
563 | + } | |
564 | + | |
565 | + ret = nor->read_reg(nor, nor->bank_read_cmd, | |
566 | + &curr_bank, 1); | |
567 | + if (ret) { | |
568 | + debug("SF: fail to read bank addr register\n"); | |
569 | + return ret; | |
570 | + } | |
571 | + nor->bank_curr = curr_bank; | |
572 | + | |
573 | + return 0; | |
574 | +} | |
575 | +#endif | |
576 | + | |
577 | +/* | |
503 | 578 | * Initiate the erasure of a single sector |
504 | 579 | */ |
505 | 580 | static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) |
... | ... | @@ -543,6 +618,11 @@ |
543 | 618 | len = instr->len; |
544 | 619 | |
545 | 620 | while (len) { |
621 | +#ifdef CONFIG_SPI_FLASH_BAR | |
622 | + ret = write_bar(nor, addr); | |
623 | + if (ret < 0) | |
624 | + return ret; | |
625 | +#endif | |
546 | 626 | write_enable(nor); |
547 | 627 | |
548 | 628 | ret = spi_nor_erase_sector(nor, addr); |
549 | 629 | |
... | ... | @@ -557,9 +637,12 @@ |
557 | 637 | goto erase_err; |
558 | 638 | } |
559 | 639 | |
640 | +erase_err: | |
641 | +#ifdef CONFIG_SPI_FLASH_BAR | |
642 | + ret = clean_bar(nor); | |
643 | +#endif | |
560 | 644 | write_disable(nor); |
561 | 645 | |
562 | -erase_err: | |
563 | 646 | return ret; |
564 | 647 | } |
565 | 648 | |
566 | 649 | |
... | ... | @@ -1144,8 +1227,23 @@ |
1144 | 1227 | |
1145 | 1228 | while (len) { |
1146 | 1229 | loff_t addr = from; |
1230 | + size_t read_len = len; | |
1147 | 1231 | |
1148 | - ret = nor->read(nor, addr, len, buf); | |
1232 | +#ifdef CONFIG_SPI_FLASH_BAR | |
1233 | + u32 remain_len; | |
1234 | + | |
1235 | + ret = write_bar(nor, addr); | |
1236 | + if (ret < 0) | |
1237 | + return log_ret(ret); | |
1238 | + remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr; | |
1239 | + | |
1240 | + if (len < remain_len) | |
1241 | + read_len = len; | |
1242 | + else | |
1243 | + read_len = remain_len; | |
1244 | +#endif | |
1245 | + | |
1246 | + ret = nor->read(nor, addr, read_len, buf); | |
1149 | 1247 | if (ret == 0) { |
1150 | 1248 | /* We shouldn't see 0-length reads */ |
1151 | 1249 | ret = -EIO; |
1152 | 1250 | |
1153 | 1251 | |
1154 | 1252 | |
... | ... | @@ -1162,18 +1260,49 @@ |
1162 | 1260 | ret = 0; |
1163 | 1261 | |
1164 | 1262 | read_err: |
1263 | +#ifdef CONFIG_SPI_FLASH_BAR | |
1264 | + ret = clean_bar(nor); | |
1265 | +#endif | |
1165 | 1266 | return ret; |
1166 | 1267 | } |
1167 | 1268 | |
1168 | 1269 | #ifdef CONFIG_SPI_FLASH_SST |
1270 | +static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len, | |
1271 | + size_t *retlen, const u_char *buf) | |
1272 | +{ | |
1273 | + size_t actual; | |
1274 | + int ret = 0; | |
1275 | + | |
1276 | + for (actual = 0; actual < len; actual++) { | |
1277 | + nor->program_opcode = SPINOR_OP_BP; | |
1278 | + | |
1279 | + write_enable(nor); | |
1280 | + /* write one byte. */ | |
1281 | + ret = nor->write(nor, to, 1, buf + actual); | |
1282 | + if (ret < 0) | |
1283 | + goto sst_write_err; | |
1284 | + ret = spi_nor_wait_till_ready(nor); | |
1285 | + if (ret) | |
1286 | + goto sst_write_err; | |
1287 | + to++; | |
1288 | + } | |
1289 | + | |
1290 | +sst_write_err: | |
1291 | + write_disable(nor); | |
1292 | + return ret; | |
1293 | +} | |
1294 | + | |
1169 | 1295 | static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, |
1170 | 1296 | size_t *retlen, const u_char *buf) |
1171 | 1297 | { |
1172 | 1298 | struct spi_nor *nor = mtd_to_spi_nor(mtd); |
1299 | + struct spi_slave *spi = nor->spi; | |
1173 | 1300 | size_t actual; |
1174 | 1301 | int ret; |
1175 | 1302 | |
1176 | 1303 | dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); |
1304 | + if (spi->mode & SPI_TX_BYTE) | |
1305 | + return sst_write_byteprogram(nor, to, len, retlen, buf); | |
1177 | 1306 | |
1178 | 1307 | write_enable(nor); |
1179 | 1308 | |
... | ... | @@ -1271,6 +1400,11 @@ |
1271 | 1400 | page_remain = min_t(size_t, |
1272 | 1401 | nor->page_size - page_offset, len - i); |
1273 | 1402 | |
1403 | +#ifdef CONFIG_SPI_FLASH_BAR | |
1404 | + ret = write_bar(nor, addr); | |
1405 | + if (ret < 0) | |
1406 | + return ret; | |
1407 | +#endif | |
1274 | 1408 | write_enable(nor); |
1275 | 1409 | ret = nor->write(nor, addr, page_remain, buf + i); |
1276 | 1410 | if (ret < 0) |
... | ... | @@ -1289,6 +1423,9 @@ |
1289 | 1423 | } |
1290 | 1424 | |
1291 | 1425 | write_err: |
1426 | +#ifdef CONFIG_SPI_FLASH_BAR | |
1427 | + ret = clean_bar(nor); | |
1428 | +#endif | |
1292 | 1429 | return ret; |
1293 | 1430 | } |
1294 | 1431 | |
1295 | 1432 | |
... | ... | @@ -2532,12 +2669,20 @@ |
2532 | 2669 | /* already configured from SFDP */ |
2533 | 2670 | } else if (info->addr_width) { |
2534 | 2671 | nor->addr_width = info->addr_width; |
2535 | - } else if (mtd->size > 0x1000000) { | |
2672 | + } else if (mtd->size > SZ_16M) { | |
2673 | +#ifndef CONFIG_SPI_FLASH_BAR | |
2536 | 2674 | /* enable 4-byte addressing if the device exceeds 16MiB */ |
2537 | 2675 | nor->addr_width = 4; |
2538 | 2676 | if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || |
2539 | 2677 | info->flags & SPI_NOR_4B_OPCODES) |
2540 | 2678 | spi_nor_set_4byte_opcodes(nor, info); |
2679 | +#else | |
2680 | + /* Configure the BAR - discover bank cmds and read current bank */ | |
2681 | + nor->addr_width = 3; | |
2682 | + ret = read_bar(nor, info); | |
2683 | + if (ret < 0) | |
2684 | + return ret; | |
2685 | +#endif | |
2541 | 2686 | } else { |
2542 | 2687 | nor->addr_width = 3; |
2543 | 2688 | } |
... | ... | @@ -2568,5 +2713,16 @@ |
2568 | 2713 | #endif |
2569 | 2714 | |
2570 | 2715 | return 0; |
2716 | +} | |
2717 | + | |
2718 | +/* U-Boot specific functions, need to extend MTD to support these */ | |
2719 | +int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor) | |
2720 | +{ | |
2721 | + int sr = read_sr(nor); | |
2722 | + | |
2723 | + if (sr < 0) | |
2724 | + return sr; | |
2725 | + | |
2726 | + return (sr >> 2) & 7; | |
2571 | 2727 | } |
include/linux/mtd/spi-nor.h
... | ... | @@ -105,6 +105,7 @@ |
105 | 105 | |
106 | 106 | /* Used for Spansion flashes only. */ |
107 | 107 | #define SPINOR_OP_BRWR 0x17 /* Bank register write */ |
108 | +#define SPINOR_OP_BRRD 0x16 /* Bank register read */ | |
108 | 109 | #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ |
109 | 110 | |
110 | 111 | /* Used for Micron flashes only. */ |
... | ... | @@ -256,6 +257,9 @@ |
256 | 257 | * @read_opcode: the read opcode |
257 | 258 | * @read_dummy: the dummy needed by the read operation |
258 | 259 | * @program_opcode: the program opcode |
260 | + * @bank_read_cmd: Bank read cmd | |
261 | + * @bank_write_cmd: Bank write cmd | |
262 | + * @bank_curr: Current flash bank | |
259 | 263 | * @sst_write_second: used by the SST write operation |
260 | 264 | * @flags: flag options for the current SPI-NOR (SNOR_F_*) |
261 | 265 | * @read_proto: the SPI protocol for read operations |
... | ... | @@ -291,6 +295,11 @@ |
291 | 295 | u8 read_opcode; |
292 | 296 | u8 read_dummy; |
293 | 297 | u8 program_opcode; |
298 | +#ifdef CONFIG_SPI_FLASH_BAR | |
299 | + u8 bank_read_cmd; | |
300 | + u8 bank_write_cmd; | |
301 | + u8 bank_curr; | |
302 | +#endif | |
294 | 303 | enum spi_nor_protocol read_proto; |
295 | 304 | enum spi_nor_protocol write_proto; |
296 | 305 | enum spi_nor_protocol reg_proto; |