修改spif和uboot,加上写保护与解除保护

This commit is contained in:
张兆鹏 2025-01-21 15:58:55 +08:00
parent a10ff1b209
commit 10e6767b22
10 changed files with 456 additions and 15 deletions

View File

@ -757,6 +757,7 @@ CONFIG_MTD_SPI_NOR=y
# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
# CONFIG_SPI_CADENCE_QUADSPI is not set
# CONFIG_SPI_FLASH_SR is not set
# CONFIG_SPI_FLASH_DEFAULT_LOCK is not set
# CONFIG_MTD_UBI is not set
CONFIG_DTC=y
CONFIG_OF=y

View File

@ -757,6 +757,7 @@ CONFIG_MTD_SPI_NOR=y
# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
# CONFIG_SPI_CADENCE_QUADSPI is not set
# CONFIG_SPI_FLASH_SR is not set
# CONFIG_SPI_FLASH_DEFAULT_LOCK is not set
# CONFIG_MTD_UBI is not set
CONFIG_DTC=y
CONFIG_OF=y

View File

@ -24,7 +24,7 @@
/*bootargs = "earlyprintk=sunxi-uart,0x02500000 clk_ignore_unused initcall_debug=0 console=ttyS0,115200 loglevel=6 lpj=240000 root=/dev/mtdblock4 rootwait init=/files/pseudo_init rdinit=/rdinit partitions=env@mtdblock1:env-redund@mtdblock2:boot@mtdblock3:rootfs@mtdblock4:extend@mtdblock5:rootfs_data@mtdblock6:UDISK@mtdblock7 coherent_pool=16K androidboot.hardware=sun8iw21p1 boot_type=3 androidboot.boot_type=3 gpt=1 mbr_offset=2080768 bootreason=unknow";*/
/* for OTA recovery system:(kernel rootfs extend) */
bootargs = "earlyprintk=sunxi-uart,0x02500000 clk_ignore_unused initcall_debug=0 console=ttyS0,115200 loglevel=1 lpj=240000 root=/dev/mtdblock4 rootwait init=/files/pseudo_init rdinit=/rdinit partitions=env@mtdblock1:env-redund@mtdblock2:boot@mtdblock3:rootfs@mtdblock4:extend@mtdblock5:recovery@mtdblock6:rootfs_data@mtdblock7:UDISK@mtdblock8 coherent_pool=16K androidboot.hardware=sun8iw21p1 boot_type=3 androidboot.boot_type=3 gpt=1 mbr_offset=2080768 bootreason=unknow";
bootargs = "earlyprintk=sunxi-uart,0x02500000 clk_ignore_unused initcall_debug=0 console=ttyS0,115200 loglevel=1 lpj=240000 root=/dev/mtdblock4 rootwait init=/files/pseudo_init rdinit=/rdinit partitions=env@mtdblock1:env-redund@mtdblock2:boot@mtdblock3:rootfs@mtdblock4:extend@mtdblock5:recovery@mtdblock6:UDISK@mtdblock7 coherent_pool=16K androidboot.hardware=sun8iw21p1 boot_type=3 androidboot.boot_type=3 gpt=1 mbr_offset=2080768 bootreason=unknow";
/* for OTA recovery system:(kernel rootfs extend appImg recoveryImg) */

View File

@ -762,6 +762,7 @@ CONFIG_MTD_SPI_NOR=y
# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
# CONFIG_SPI_CADENCE_QUADSPI is not set
# CONFIG_SPI_FLASH_SR is not set
CONFIG_SPI_FLASH_DEFAULT_LOCK=y
# CONFIG_MTD_UBI is not set
CONFIG_DTC=y
CONFIG_OF=y

View File

@ -765,6 +765,7 @@ CONFIG_MTD_SPI_NOR=y
# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
# CONFIG_SPI_CADENCE_QUADSPI is not set
# CONFIG_SPI_FLASH_SR is not set
# CONFIG_SPI_FLASH_DEFAULT_LOCK is not set
# CONFIG_MTD_UBI is not set
CONFIG_DTC=y
CONFIG_OF=y

View File

@ -30,6 +30,7 @@ size = 16
; 2、name最大12个字符
; 3、size = 0, 将创建一个无大小的空分区
; 4、为了安全和效率考虑分区大小最好保证为16M字节的整数倍
; 5、size 128 = 64KB 扇区512byte py_nor_flash
;********************************************************************************************************
[partition_start]
@ -47,13 +48,13 @@ size = 16
[partition]
name = boot
size = 6144
size = 9728
downloadfile = "boot.fex"
user_type = 0x8000
[partition]
name = rootfs
size = 20480
size = 24064
downloadfile = "rootfs.fex"
user_type = 0x8000
@ -81,10 +82,10 @@ size = 16
; downloadfile = "recoveryimg.fex"
; user_type = 0x8000
[partition]
name = rootfs_data
size = 2048
user_type = 0x8000
;[partition]
; name = rootfs_data
; size = 2048
; user_type = 0x8000

View File

@ -3873,6 +3873,9 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
static int sunxi_lock_init(struct spi_nor *nor)
{
uint8_t mask = 0;
uint8_t status1 = 0;
uint8_t status2 = 0;
struct mtd_info *mtd = &nor->mtd;
const struct flash_info *info = nor->info;
@ -3884,6 +3887,67 @@ static int sunxi_lock_init(struct spi_nor *nor)
if (sunxi_individual_lock_is_enable(nor))
sunxi_individual_unlock_global(nor);
if (JEDEC_MFR(nor->info) == SNOR_MFR_PUYA)
{
if (nor->info->id[2] == 0x19) // py25q256hb id:0x852019
{
status1 = (uint8_t)read_sr(nor);
/* check cmp first */
status2 = (uint8_t)read_sr2(nor);
// if ((status2 < 0) || (status1 < 0))
// {
// printf("read err!:%x %x\n", status1, status2);
// }
if (status2 & (SR2_CMP_GD)) // cmp=1
{
mask = (SR_BP2 | SR_BP3);
status1 |= mask;
printf("cmp=1\n");
}
else // cmp=0
{
printf("cmp=0\n");
mask = (uint8_t) ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3);
status1 &= mask;
}
if (write_sr_and_check(nor, status1, mask) != 0)
{
printf("py_unlock sr err!:%x\n", status1);
return -1;
}
return 0;
}
else if (nor->info->id[2] == 0x18) // py25q128ha id:0x852018
{
status1 = (uint8_t)read_sr(nor);
/* check cmp first */
status2 = (uint8_t)read_sr2(nor);
// if ((status2 < 0) || (status1 < 0))
// {
// printf("read err!:%x %x\n", status1, status2);
// }
if (status2 & (SR2_CMP_GD)) // cmp=1
{
mask = (SR_BP0 | SR_BP1 | SR_BP2);
status1 |= mask;
printf("cmp=1\n");
}
else // cmp=0
{
printf("cmp=0\n");
mask = (uint8_t) ~(SR_BP0 | SR_BP1 | SR_BP2);
status1 &= mask;
}
if (write_sr_and_check(nor, status1, mask) != 0)
{
printf("py_unlock sr err!:%x\n", status1);
return -1;
}
return 0;
}
}
if (JEDEC_MFR(info) == SNOR_MFR_ST ||
JEDEC_MFR(info) == SNOR_MFR_MICRON ||
JEDEC_MFR(info) == SNOR_MFR_SST)

View File

@ -81,4 +81,10 @@ config SPI_FLASH_SR
help
when set, enable security register write, read, earse functions.
config SPI_FLASH_DEFAULT_LOCK
bool "SPI FLASH default lock"
default n
help
when set, norflash will be protected after kernel run
endif # MTD_SPI_NOR

View File

@ -507,6 +507,42 @@ static int read_sr(struct spi_nor *nor)
return nor->bouncebuf[0];
}
/*
* Read the PUYA status register 2, returning its value in the location
* Return the status register value.
* Returns negative if error occurred.
*/
static int read_puya_sr2(struct spi_nor *nor)
{
int ret;
ret = nor->read_reg(nor, SPINOR_OP_RDSR2, nor->bouncebuf, 1);
if (ret < 0) {
pr_err("error %d reading SR\n", (int) ret);
return ret;
}
return nor->bouncebuf[0];
}
/*
* Read the PUYA configuration register, returning its value in the location
* Return the status register value.
* Returns negative if error occurred.
*/
static int read_puya_cr(struct spi_nor *nor)
{
int ret;
ret = nor->read_reg(nor, SPINOR_OP_RDSR3, nor->bouncebuf, 1);
if (ret < 0) {
pr_err("error %d reading SR\n", (int) ret);
return ret;
}
return nor->bouncebuf[0];
}
/*
* Read the flag status register, returning its value in the location
* Return the status register value.
@ -553,6 +589,26 @@ static int write_sr(struct spi_nor *nor, u8 val)
return nor->write_reg(nor, SPINOR_OP_WRSR, nor->bouncebuf, 1);
}
/*
* Write status register2 1 byte
* Returns negative if error occurred.
*/
static int write_puya_sr2(struct spi_nor *nor, u8 val)
{
nor->bouncebuf[0] = val;
return nor->write_reg(nor, SPINOR_OP_WRSR2, nor->bouncebuf, 1);
}
/*
* Write configuration register 1 byte
* Returns negative if error occurred.
*/
static int write_puya_cr(struct spi_nor *nor, u8 val)
{
nor->bouncebuf[0] = val;
return nor->write_reg(nor, SPINOR_OP_WRSR3, nor->bouncebuf, 1);
}
/*
* Set write enable latch with Write Enable command.
* Returns negative if error occurred.
@ -1401,6 +1457,48 @@ static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
}
/* Write status register2 and ensure bits in mask match written values */
static int write_sr2_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
{
int ret;
write_enable(nor);
ret = write_puya_sr2(nor, status_new);
if (ret)
return ret;
ret = spi_nor_wait_till_ready(nor);
if (ret)
return ret;
ret = read_puya_sr2(nor);
if (ret < 0)
return ret;
return ((ret & status_new) != (status_new & status_new)) ? -EIO : 0;
}
/* Write configuration register and ensure bits in mask match written values */
static int write_cr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
{
int ret;
write_enable(nor);
ret = write_puya_cr(nor, status_new);
if (ret)
return ret;
ret = spi_nor_wait_till_ready(nor);
if (ret)
return ret;
ret = read_puya_cr(nor);
if (ret < 0)
return ret;
return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
}
static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
uint64_t *len)
{
@ -1672,6 +1770,175 @@ static const struct spi_nor_locking_ops stm_locking_ops = {
.is_locked = stm_is_locked,
};
/* unlock except UDISK */
/* 解锁先判断CMP位再决定sr2应该写什么 */
static int py_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
uint8_t mask = 0;
uint8_t status1 = 0;
uint8_t status2 = 0;
if (nor->info->id[2] == 0x19) // py25q256hb id:0x852019
{
status1 = (uint8_t)read_sr(nor);
/* check cmp first */
status2 = (uint8_t)read_puya_sr2(nor);
// if ((status2 < 0) || (status1 < 0))
// {
// pr_emerg("py_lock read err!:%x %x\n", status1, status2);
// return -1;
// }
if (status2 & (SR2_CMP_GD)) // cmp=1
{
mask = (SR_BP2 | SR_BP3);
status1 |= mask;
}
else // cmp=0
{
mask = (uint8_t) ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3);
status1 &= mask;
}
if (write_sr_and_check(nor, status1, mask) != 0)
{
pr_emerg("py_unlock sr err!:%x\n", status1);
return -1;
}
return 0;
}
else if (nor->info->id[2] == 0x18) // py25q128ha id:0x852018
{
pr_emerg("not support py25q128ha yet\n");
return -1;
}
return -1;
}
/* lock except UDISK */
/* 上锁先判断CMP位然后配置CMP位确保为1cmp default值需要改变再写sr2 */
/* 第一次上电会调用这个函数更改CMP位只要上电过一次flash就会改成CMP=1 */
static int py_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
uint8_t status1 = 0;
uint8_t status2 = 0;
uint8_t status_cr = 0;
uint8_t mask = 0;
if (nor->info->id[2] == 0x19) // py25q256hb id:0x852019
{
/* read old sr1 and sr2 */
status2 = (uint8_t)read_puya_sr2(nor);
status1 = (uint8_t)read_sr(nor);
status_cr = (uint8_t)read_puya_cr(nor);
// if ((status2 < 0) || (status1 < 0) || (status_cr < 0))
// {
// pr_emerg("py_lock read err!:%x %x %x\n", status1, status2, status_cr);
// return -1;
// }
if ((status2 & SR2_CMP_GD) == 0) // set cmp=1 if it's not 1
{
/* first write sr2 CMP=1 */
status2 |= (SR2_CMP_GD);
if (write_sr2_and_check(nor, status2, status2) != 0)
{
pr_emerg("py_lock sr2 err!:%x\n", status2);
return -1;
}
}
if ((status_cr & SR_WPS_EN_WINBOND) != 0) // set wps=0 if it's not 0
{
/* first write CR WPS=0 */
status_cr &= ~(SR_WPS_EN_WINBOND);
if (write_cr_and_check(nor, status_cr, status_cr) != 0)
{
pr_emerg("py_lock cr err!:%x\n", status_cr);
return -1;
}
}
/* sr1 lower 3/4 24MB except UDISK */
mask |= (SR_BP3);
mask &= ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_BP4);
// 0x7c 0111 1100 Status Register BP0~BP4,只判断这几位
if ((status1 & 0x7c) != mask)
{
status1 |= (SR_BP3);
status1 &= ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_BP4);
if (write_sr_and_check(nor, status1, mask) != 0)
{
pr_emerg("py_lock sr err!:%x\n", status1);
return -1;
}
}
return 0;
}
else if (nor->info->id[2] == 0x18) // py25q128ha id:0x852018
{
// pr_emerg("not support py25q128ha yet\n");
return -1;
}
return -1;
}
/*
* Check if the flash is locked. py_is_locked for
* more info.
*
* Returns 1 if entire region is locked, 0 is unlocked, and
* negative on errors.
*/
static int py_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
uint8_t mask = 0;
uint8_t status1 = 0;
uint8_t status2 = 0;
if (nor->info->id[2] == 0x19) // py25q256hb id:0x852019
{
status1 = (uint8_t)read_sr(nor);
/* check cmp first */
status2 = (uint8_t)read_puya_sr2(nor);
// if ((status2 < 0) || (status1 < 0))
// {
// pr_emerg("py_lock read err!:%x %x\n", status1, status2);
// return -1;
// }
/* unlock status mask */
if (status2 & (SR2_CMP_GD)) // cmp=1
{
mask = (SR_BP2 | SR_BP3);
/* TODO:还有一种情况也算unlock但是暂时未使用 */
}
else // cmp=0
{
mask &= ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3);
}
if ((status1 & 0x7c) != mask)
{
// printk(KERN_EMERG "lock\n");
return 1;
}
else
{
// printk(KERN_EMERG "unlock\n");
return 0;
}
}
else if (nor->info->id[2] == 0x18) // py25q128ha id:0x852018
{
pr_emerg("not support py25q128ha yet\n");
return -1;
}
return -1;
}
static const struct spi_nor_locking_ops puya_locking_ops = {
.lock = py_lock,
.unlock = py_unlock,
.is_locked = py_is_locked,
};
static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
@ -2091,6 +2358,78 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
return spi_nor_clear_sr_bp(nor);
}
/**
* HAS : spi_nor_puya_clear_sr_bp() - clear the Status Register Block Protection
* bits on puya flashes.
* @nor: pointer to a 'struct spi_nor'
* WPS=0sr寄存器CMP位
*
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_puya_clear_sr_bp(struct spi_nor *nor)
{
uint8_t mask = 0;
uint8_t status1 = 0;
uint8_t status2 = 0;
if (nor->info->id[2] == 0x19) // py25q256hb id:0x852019
{
status1 = (uint8_t)read_sr(nor);
/* check cmp first */
status2 = (uint8_t)read_puya_sr2(nor);
// if ((status1 < 0) || (status2 < 0))
// {
// pr_emerg("clear_sr_bp read err!:%x %x\n", status1, status2);
// return -1;
// }
if (status2 & (SR2_CMP_GD)) // cmp=1
{
mask = (SR_BP2 | SR_BP3);
status1 |= mask;
}
else // cmp=0
{
mask = (uint8_t) ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3);
status1 &= mask;
}
if (write_sr_and_check(nor, status1, status1) != 0)
{
pr_emerg("clear_sr_bp sr err!:%x\n", status1);
return -1;
}
return 0;
}
else if (nor->info->id[2] == 0x18) // py25q128ha id:0x852018
{
status1 = (uint8_t)read_sr(nor);
/* check cmp first */
status2 = (uint8_t)read_puya_sr2(nor);
// if ((status2 < 0) || (status1 < 0))
// {
// printf("clear_sr_bp err!:%x %x\n", status1, status2);
// }
if (status2 & (SR2_CMP_GD)) // cmp=1
{
mask = (SR_BP0 | SR_BP1 | SR_BP2);
status1 |= mask;
}
else // cmp=0
{
mask = (uint8_t) ~(SR_BP0 | SR_BP1 | SR_BP2);
status1 &= mask;
}
if (write_sr_and_check(nor, status1, mask) != 0)
{
pr_emerg("clear_sr_bp sr err!:%x\n", status1);
return -1;
}
return 0;
}
return -1;
}
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
@ -2575,11 +2914,11 @@ static const struct flash_info spi_nor_ids[] = {
{ "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
/* PUYA */
{ "py25q128ha", INFO(0x852018, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_IO_MODE | USE_RX_DTR) },
{ "py25q128ha", INFO(0x852018, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_IO_MODE | USE_RX_DTR | SPI_NOR_HAS_LOCK) },
{ "p25q128", INFO(0x856018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "p25q64h", INFO(0x856017, 0x0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "p25q32h", INFO(0x856016, 0x0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "py25q256hb", INFO(0x852019, 0x0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_IO_MODE | USE_RX_DTR) },
{ "py25q256hb", INFO(0x852019, 0x0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_IO_MODE | USE_RX_DTR | SPI_NOR_HAS_LOCK) },
/*Zetta*/
{ "zd25q64b", INFO(0xba3217, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
@ -4696,7 +5035,16 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
* the default ones.
*/
if (nor->flags & SNOR_F_HAS_LOCK && !nor->params.locking_ops)
nor->params.locking_ops = &stm_locking_ops;
{
if (JEDEC_MFR(nor->info) == SNOR_MFR_PUYA)
{
nor->params.locking_ops = &puya_locking_ops;
}
else // use default
{
nor->params.locking_ops = &stm_locking_ops;
}
}
}
/**
@ -4773,6 +5121,7 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
#ifndef CONFIG_SPI_FLASH_DEFAULT_LOCK
if (nor->clear_sr_bp) {
if (nor->params.quad_enable == spansion_quad_enable)
nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
@ -4784,12 +5133,17 @@ static int spi_nor_init(struct spi_nor *nor)
return err;
}
}
#endif
err = spi_nor_quad_enable(nor);
if (err) {
dev_err(nor->dev, "quad mode not supported\n");
return err;
}
#if defined(CONFIG_SPI_FLASH_DEFAULT_LOCK)
/* 上电就给flash特定区域上锁 */
nor->mtd._lock(&nor->mtd, 0, 0);
#endif
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES)) {
/*
@ -5419,11 +5773,23 @@ int spif_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
* with the software protection bits set.
*/
if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
nor->info->flags & SPI_NOR_HAS_LOCK)
nor->clear_sr_bp = spi_nor_clear_sr_bp;
if (nor->info->flags & SPI_NOR_HAS_LOCK)
{
if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
JEDEC_MFR(nor->info) == SNOR_MFR_SST)
{
nor->clear_sr_bp = spi_nor_clear_sr_bp;
}
else if (JEDEC_MFR(nor->info) == SNOR_MFR_PUYA)
{
nor->clear_sr_bp = spi_nor_puya_clear_sr_bp;
}
else
{
nor->clear_sr_bp = NULL;
}
}
/* Init flash parameters based on flash_info struct and SFDP */
spi_nor_init_params(nor);