Commit 3d4fed87a5fa3ffedf64ff2811cd95c5ac4503ac

Authored by Eugeniy Paltsev
Committed by Jagan Teki
1 parent 40df6b3e18

mtd: sf: Add support of sst26wf* flash ICs protection ops

sst26wf flash series block protection implementation differs
from other SST series, so add specific implementation
flash_lock/flash_unlock/flash_is_locked functions for sst26wf
flash ICs.

Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>

Showing 2 changed files with 181 additions and 0 deletions Side-by-side Diff

drivers/mtd/spi/sf_internal.h
... ... @@ -87,6 +87,19 @@
87 87  
88 88 /* SST specific */
89 89 #ifdef CONFIG_SPI_FLASH_SST
  90 +#define SST26_CMD_READ_BPR 0x72
  91 +#define SST26_CMD_WRITE_BPR 0x42
  92 +
  93 +#define SST26_BPR_8K_NUM 4
  94 +#define SST26_MAX_BPR_REG_LEN (18 + 1)
  95 +#define SST26_BOUND_REG_SIZE ((32 + SST26_BPR_8K_NUM * 8) * SZ_1K)
  96 +
  97 +enum lock_ctl {
  98 + SST26_CTL_LOCK,
  99 + SST26_CTL_UNLOCK,
  100 + SST26_CTL_CHECK
  101 +};
  102 +
90 103 # define CMD_SST_BP 0x02 /* Byte Program */
91 104 # define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
92 105  
drivers/mtd/spi/spi_flash.c
... ... @@ -16,6 +16,7 @@
16 16 #include <spi.h>
17 17 #include <spi_flash.h>
18 18 #include <linux/log2.h>
  19 +#include <linux/sizes.h>
19 20 #include <dma.h>
20 21  
21 22 #include "sf_internal.h"
... ... @@ -541,6 +542,164 @@
541 542 }
542 543  
543 544 #ifdef CONFIG_SPI_FLASH_SST
  545 +static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
  546 +{
  547 + switch (ctl) {
  548 + case SST26_CTL_LOCK:
  549 + cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8);
  550 + break;
  551 + case SST26_CTL_UNLOCK:
  552 + cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8);
  553 + break;
  554 + case SST26_CTL_CHECK:
  555 + return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8));
  556 + }
  557 +
  558 + return false;
  559 +}
  560 +
  561 +/*
  562 + * sst26wf016/sst26wf032/sst26wf064 have next block protection:
  563 + * 4x - 8 KByte blocks - read & write protection bits - upper addresses
  564 + * 1x - 32 KByte blocks - write protection bits
  565 + * rest - 64 KByte blocks - write protection bits
  566 + * 1x - 32 KByte blocks - write protection bits
  567 + * 4x - 8 KByte blocks - read & write protection bits - lower addresses
  568 + *
  569 + * We'll support only per 64k lock/unlock so lower and upper 64 KByte region
  570 + * will be treated as single block.
  571 + */
  572 +
  573 +/*
  574 + * Lock, unlock or check lock status of the flash region of the flash (depending
  575 + * on the lock_ctl value)
  576 + */
  577 +static int sst26_lock_ctl(struct spi_flash *flash, u32 ofs, size_t len, enum lock_ctl ctl)
  578 +{
  579 + u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size;
  580 + bool lower_64k = false, upper_64k = false;
  581 + u8 cmd, bpr_buff[SST26_MAX_BPR_REG_LEN] = {};
  582 + int ret;
  583 +
  584 + /* Check length and offset for 64k alignment */
  585 + if ((ofs & (SZ_64K - 1)) || (len & (SZ_64K - 1)))
  586 + return -EINVAL;
  587 +
  588 + if (ofs + len > flash->size)
  589 + return -EINVAL;
  590 +
  591 + /* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */
  592 + if (flash->size != SZ_2M &&
  593 + flash->size != SZ_4M &&
  594 + flash->size != SZ_8M)
  595 + return -EINVAL;
  596 +
  597 + bpr_size = 2 + (flash->size / SZ_64K / 8);
  598 +
  599 + cmd = SST26_CMD_READ_BPR;
  600 + ret = spi_flash_read_common(flash, &cmd, 1, bpr_buff, bpr_size);
  601 + if (ret < 0) {
  602 + printf("SF: fail to read block-protection register\n");
  603 + return ret;
  604 + }
  605 +
  606 + rptr_64k = min_t(u32, ofs + len , flash->size - SST26_BOUND_REG_SIZE);
  607 + lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE);
  608 +
  609 + upper_64k = ((ofs + len) > (flash->size - SST26_BOUND_REG_SIZE));
  610 + lower_64k = (ofs < SST26_BOUND_REG_SIZE);
  611 +
  612 + /* Lower bits in block-protection register are about 64k region */
  613 + bpr_ptr = lptr_64k / SZ_64K - 1;
  614 +
  615 + /* Process 64K blocks region */
  616 + while (lptr_64k < rptr_64k) {
  617 + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
  618 + return EACCES;
  619 +
  620 + bpr_ptr++;
  621 + lptr_64k += SZ_64K;
  622 + }
  623 +
  624 + /* 32K and 8K region bits in BPR are after 64k region bits */
  625 + bpr_ptr = (flash->size - 2 * SST26_BOUND_REG_SIZE) / SZ_64K;
  626 +
  627 + /* Process lower 32K block region */
  628 + if (lower_64k)
  629 + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
  630 + return EACCES;
  631 +
  632 + bpr_ptr++;
  633 +
  634 + /* Process upper 32K block region */
  635 + if (upper_64k)
  636 + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
  637 + return EACCES;
  638 +
  639 + bpr_ptr++;
  640 +
  641 + /* Process lower 8K block regions */
  642 + for (i = 0; i < SST26_BPR_8K_NUM; i++) {
  643 + if (lower_64k)
  644 + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
  645 + return EACCES;
  646 +
  647 + /* In 8K area BPR has both read and write protection bits */
  648 + bpr_ptr += 2;
  649 + }
  650 +
  651 + /* Process upper 8K block regions */
  652 + for (i = 0; i < SST26_BPR_8K_NUM; i++) {
  653 + if (upper_64k)
  654 + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
  655 + return EACCES;
  656 +
  657 + /* In 8K area BPR has both read and write protection bits */
  658 + bpr_ptr += 2;
  659 + }
  660 +
  661 + /* If we check region status we don't need to write BPR back */
  662 + if (ctl == SST26_CTL_CHECK)
  663 + return 0;
  664 +
  665 + cmd = SST26_CMD_WRITE_BPR;
  666 + ret = spi_flash_write_common(flash, &cmd, 1, bpr_buff, bpr_size);
  667 + if (ret < 0) {
  668 + printf("SF: fail to write block-protection register\n");
  669 + return ret;
  670 + }
  671 +
  672 + return 0;
  673 +}
  674 +
  675 +static int sst26_unlock(struct spi_flash *flash, u32 ofs, size_t len)
  676 +{
  677 + return sst26_lock_ctl(flash, ofs, len, SST26_CTL_UNLOCK);
  678 +}
  679 +
  680 +static int sst26_lock(struct spi_flash *flash, u32 ofs, size_t len)
  681 +{
  682 + return sst26_lock_ctl(flash, ofs, len, SST26_CTL_LOCK);
  683 +}
  684 +
  685 +/*
  686 + * Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
  687 + * and negative on errors.
  688 + */
  689 +static int sst26_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
  690 +{
  691 + /*
  692 + * is_locked function is used for check before reading or erasing flash
  693 + * region, so offset and length might be not 64k allighned, so adjust
  694 + * them to be 64k allighned as sst26_lock_ctl works only with 64k
  695 + * allighned regions.
  696 + */
  697 + ofs -= ofs & (SZ_64K - 1);
  698 + len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
  699 +
  700 + return sst26_lock_ctl(flash, ofs, len, SST26_CTL_CHECK);
  701 +}
  702 +
544 703 static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
545 704 {
546 705 struct spi_slave *spi = flash->spi;
... ... @@ -1030,6 +1189,15 @@
1030 1189 flash->flash_lock = stm_lock;
1031 1190 flash->flash_unlock = stm_unlock;
1032 1191 flash->flash_is_locked = stm_is_locked;
  1192 + }
  1193 +#endif
  1194 +
  1195 +/* sst26wf series block protection implementation differs from other series */
  1196 +#if defined(CONFIG_SPI_FLASH_SST)
  1197 + if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST && info->id[1] == 0x26) {
  1198 + flash->flash_lock = sst26_lock;
  1199 + flash->flash_unlock = sst26_unlock;
  1200 + flash->flash_is_locked = sst26_is_locked;
1033 1201 }
1034 1202 #endif
1035 1203