From 1a161c4be2fdba4d7c65a1054953dbb28bd4f67f Mon Sep 17 00:00:00 2001 From: Heinrich Toews Date: Tue, 17 Feb 2026 13:05:36 +0100 Subject: [PATCH] spi: spi-cadence-quadspi: mram: check if unlock succeeded Signed-off-by: Heinrich Toews --- drivers/mtd/spi-nor/everspin.c | 76 ++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/spi-nor/everspin.c b/drivers/mtd/spi-nor/everspin.c index cf94251e149c..d1f77d1abbd1 100644 --- a/drivers/mtd/spi-nor/everspin.c +++ b/drivers/mtd/spi-nor/everspin.c @@ -28,14 +28,30 @@ static int everspin_mram_write_reg(struct spi_nor *nor, u32 addr, u8 val) return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); } -static void everspin_mram_default_init(struct spi_nor *nor) +/** + * everspin_mram_unlock - Clears Block Protection bits in Status Register 1 + */ +static int everspin_mram_unlock(struct spi_nor *nor) { struct spi_mem_op op; int ret; - dev_info(nor->dev, "Starting Everspin MRAM initialization (STR Octal)...\n"); + /* Send Write Enable (WREN) */ + spi_nor_write_enable(nor); - /* 1. Read Status Register 1 (SR1) to diagnose BP bits */ + /* Write 0x00 to Status Register 1 (Opcode 01h) */ + nor->bouncebuf[0] = 0x00; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); + + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + /* Verify: Read back SR1 */ op = (struct spi_mem_op) SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), SPI_MEM_OP_NO_ADDR, @@ -43,32 +59,48 @@ static void everspin_mram_default_init(struct spi_nor *nor) SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); - if (ret) { - dev_err(nor->dev, "Error reading SR1 register (%d)\n", ret); - } else { + if (ret) + return ret; + + /* Check value at pointer address */ + if (nor->bouncebuf[0] & GENMASK(5, 2)) { + dev_err(nor->dev, "Unlock failed! SR1 still 0x%02x\n", nor->bouncebuf[0]); + return -EACCES; + } + + dev_info(nor->dev, "Unlock successful. SR1 is now 0x%02x\n", nor->bouncebuf[0]); + return 0; +} + +static void everspin_mram_default_init(struct spi_nor *nor) +{ + struct spi_mem_op op; + int ret; + + dev_info(nor->dev, "Starting Everspin MRAM initialization (STR Octal)...\n"); + + /* 1. Read SR1 and unlock if necessary */ + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); + + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (!ret) { u8 sr1 = nor->bouncebuf[0]; - u8 bp_bits = (sr1 & GENMASK(5, 2)) >> 2; - dev_info(nor->dev, "SR1: 0x%02x | BP bits: 0x%x (0 = no protection)\n", sr1, bp_bits); - if (bp_bits) { - dev_info(nor->dev, "Unlocking MRAM (clearing BP bits)...\n"); - spi_nor_write_enable(nor); - nor->bouncebuf[0] = 0; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); - spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (sr1 & GENMASK(5, 2)) { + dev_info(nor->dev, "SR1: 0x%02x | Protection detected, unlocking...\n", sr1); + everspin_mram_unlock(nor); + } else { + dev_info(nor->dev, "SR1: 0x%02x | No protection active.\n", sr1); } } /* 2. Switch to Octal Mode via CFR1V */ - dev_info(nor->dev, "Setting CFR1V to Octal STR (Addr 0x%x)...\n", SPINOR_REG_EVERSPIN_CFR1V); ret = everspin_mram_write_reg(nor, SPINOR_REG_EVERSPIN_CFR1V, EVERSPIN_OCTAL_STR_ENABLE); if (ret) - dev_err(nor->dev, "Error writing CFR1V mode register (%d)\n", ret); - else - dev_info(nor->dev, "CFR1V successfully set to Octal STR.\n"); + dev_err(nor->dev, "Error writing CFR1V register (%d)\n", ret); /* 3. Synchronize kernel parameters */ nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;