From 55204189b65035bdf3716894bc8d594eeff41288 Mon Sep 17 00:00:00 2001 From: Dmitry Ermakov Date: Sun, 26 Feb 2023 18:55:55 +0300 Subject: [PATCH] [Hi3516ev200] SPI NOR force global unlock and SR clear --- .../patches/18-spi-nor-global-unlock.patch | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 br-ext-chip-hisilicon/board/hi3516ev200/kernel/patches/18-spi-nor-global-unlock.patch diff --git a/br-ext-chip-hisilicon/board/hi3516ev200/kernel/patches/18-spi-nor-global-unlock.patch b/br-ext-chip-hisilicon/board/hi3516ev200/kernel/patches/18-spi-nor-global-unlock.patch new file mode 100644 index 00000000..782f55ff --- /dev/null +++ b/br-ext-chip-hisilicon/board/hi3516ev200/kernel/patches/18-spi-nor-global-unlock.patch @@ -0,0 +1,196 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -107,6 +107,34 @@ + return val; + } + ++static int read_sr2(struct spi_nor *nor) ++{ ++ int ret; ++ u8 val; ++ ++ ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &val, 1); ++ if (ret < 0) { ++ pr_err("error %d reading SR2\n", (int) ret); ++ return ret; ++ } ++ ++ return val; ++} ++ ++static int read_sr3(struct spi_nor *nor) ++{ ++ int ret; ++ u8 val; ++ ++ ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1); ++ if (ret < 0) { ++ pr_err("error %d reading SR3\n", (int) ret); ++ return ret; ++ } ++ ++ return val; ++} ++ + /* + * Read the flag status register, returning its value in the location + * Return the status register value. +@@ -155,6 +183,18 @@ + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); + } + ++static inline int write_sr2(struct spi_nor *nor, u8 val) ++{ ++ nor->cmd_buf[0] = val; ++ return nor->write_reg(nor, SPINOR_OP_WRSR2, nor->cmd_buf, 1); ++} ++ ++static inline int write_sr3(struct spi_nor *nor, u8 val) ++{ ++ nor->cmd_buf[0] = val; ++ return nor->write_reg(nor, SPINOR_OP_WRSR3, nor->cmd_buf, 1); ++} ++ + /* + * Set write enable latch with Write Enable command. + * Returns negative if error occurred. +@@ -1964,7 +2004,7 @@ + + if (!nor->level) { + nor->end_addr = 0; +- dev_warn(nor->dev, "all blocks is unlocked.\n"); ++ dev_warn(nor->dev, "all blocks are unlocked.\n"); + return; + } + +@@ -2047,6 +2087,47 @@ + return level; + } + ++static void hisi_global_unlock(struct spi_nor *nor) { ++ int val; ++ ++ dev_info(nor->dev, "Force global unlock\n"); ++ write_enable(nor); ++ /* Global Block/Sector Unlock, ++ * see 8.2.42 Global Block/Sector Unlock (98h) */ ++ nor->write_reg(nor, 0x98, NULL, 0); ++ spi_nor_wait_till_ready(nor); ++ ++ val = read_sr(nor); ++ if (val) { ++ dev_info(nor->dev, "SR1:[%02x]->[00] ", val); ++ val = 0; ++ write_enable(nor); ++ write_sr(nor, val); ++ if (spi_nor_wait_till_ready(nor)) ++ dev_err(nor->dev, "error while writing SR1.\n"); ++ } ++ ++ val = read_sr2(nor); ++ if (val) { ++ dev_info(nor->dev, "SR2:[%02x]->[00]", val); ++ val = 0; ++ write_enable(nor); ++ write_sr2(nor, val); ++ if (spi_nor_wait_till_ready(nor)) ++ dev_err(nor->dev, "error while writing SR2.\n"); ++ } ++ ++ val = read_sr3(nor); ++ if (val & 4) { ++ dev_info(nor->dev, "SR3:[%02x]->[%02x]", val, val ^ 4); ++ val ^= 4; // Remove SR3_WPS ++ write_enable(nor); ++ write_sr3(nor, val); ++ if (spi_nor_wait_till_ready(nor)) ++ dev_err(nor->dev, "error while writing SR3.\n"); ++ } ++} ++ + static void hisi_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info) + { + unsigned int chipsize; +@@ -2057,6 +2138,7 @@ + /* read the BP bit in RDSR to check whether nor is lock or not */ + switch (JEDEC_MFR(info)) { + case SNOR_MFR_GD: ++ case SNOR_MFR_FM: + case SNOR_MFR_ESMT: + case SNOR_MFR_EON: + case SNOR_MFR_SPANSION: +@@ -2064,7 +2146,6 @@ + nor->level = hisi_bp_to_level(nor, info, BP_NUM_3); + break; + case SNOR_MFR_WINBOND: +- case SNOR_MFR_XTX: + /* BP bit convert to lock level */ + if (chipsize <= _16M) + nor->level = hisi_bp_to_level(nor, info, BP_NUM_3); +@@ -2072,16 +2153,23 @@ + nor->level = hisi_bp_to_level(nor, info, BP_NUM_4); + break; + case SNOR_MFR_MACRONIX: ++ case SNOR_MFR_XMC: + /* BP bit convert to lock level */ + if (chipsize <= _8M) + nor->level = hisi_bp_to_level(nor, info, BP_NUM_3); + else + nor->level = hisi_bp_to_level(nor, info, BP_NUM_4); + break; ++ case SNOR_MFR_XTX: ++ /* BP bit convert to lock level */ ++ nor->level = hisi_bp_to_level(nor, info, BP_NUM_4); ++ break; + default: + goto usage; + } + ++ hisi_global_unlock(nor); ++ + spi_lock_update_address(nor, info); + if (nor->end_addr) + dev_info(dev, "Address range [0 => %#x] is locked.\n", +@@ -2245,6 +2333,7 @@ + { + int ret; + unsigned char cval,val; ++ unsigned char sr1, sr2, sr3; + + if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX){ + val = read_sr(nor); +@@ -2268,7 +2357,18 @@ + } + } + +- if (params) { ++ sr1 = read_sr(nor); ++ if (sr1 < 0) ++ return sr1; ++ sr2 = read_sr2(nor); ++ if (sr2 < 0) ++ return sr2; ++ sr3 = read_sr3(nor); ++ if (sr3 < 0) ++ return sr3; ++ dev_info(nor->dev, "SR1 [%02x], SR2 [%02x], SR3 [%02x]\n", sr1, sr2, sr3); ++ ++ if (params) { + ret = spi_nor_setup(nor, info, params, modes); + if (ret) + return ret; +--- a/include/linux/mtd/spi-nor.h ++++ b/include/linux/mtd/spi-nor.h +@@ -28,8 +28,10 @@ + #define SNOR_MFR_EON CFI_MFR_EON + #define SNOR_MFR_WINBOND 0xef + #define SNOR_MFR_ESMT 0x8c +-#define SNOR_MFR_GD 0xc8 +-#define SNOR_MFR_XTX 0x0b ++#define SNOR_MFR_GD 0xc8 ++#define SNOR_MFR_FM 0xa1 ++#define SNOR_MFR_XTX 0x0b ++#define SNOR_MFR_XMC 0x20 + + /* Flash set the RESET# from */ + #define SPI_NOR_SR_RST_MASK BIT(7)