mirror of https://github.com/OpenIPC/firmware.git
197 lines
4.5 KiB
Diff
197 lines
4.5 KiB
Diff
--- 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)
|