diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index e5871e5ac428..58a54e1075c9 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3442,13 +3442,74 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor) mtd->_put_device = spi_nor_put_device; } +/** + * spi_nor_everspin_reboot_fix - Forces Everspin MRAM out of Octal mode + * @nor: pointer to 'struct spi_nor' + * + * This function sends a "blind" Software Reset sequence in Octal-STR (8-8-8). + * It is required for warm reboots because the MRAM stays in Octal mode + * while the controller restarts in Single-SPI mode. + */ +/** + * spi_nor_everspin_reboot_fix - Blind reset for MRAM Octal-STR escape + * @nor: pointer to 'struct spi_nor' + */ +static void spi_nor_everspin_reboot_fix(struct spi_nor *nor) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(0x66, 8), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + int ret; + + if (!nor->spimem || !nor->dev) + return; + + /* + * Logging as dev_info so it appears in dmesg during boot. + * This helps verify if the fix is being executed. + */ + dev_info(nor->dev, "MRAM Reboot-Fix: Sending blind Octal-STR reset (0x66->0x99)...\n"); + + /* 1. Reset Enable (0x66) in Octal-STR */ + ret = spi_mem_exec_op(nor->spimem, &op); + + /* 2. Reset (0x99) in Octal-STR */ + op.cmd.opcode = 0x99; + ret |= spi_mem_exec_op(nor->spimem, &op); + + if (ret) { + /* + * Note: A failure here is expected if the controller is + * not yet ready for 8-lane commands or if the chip + * is already in Single-SPI mode. + */ + dev_dbg(nor->dev, "MRAM Reboot-Fix: Octal reset op returned %d (normal for Single-SPI)\n", ret); + } + + /* Essential delay: allow MRAM internal state machine to recover */ + usleep_range(1000, 2000); + + dev_info(nor->dev, "MRAM Reboot-Fix: Completed. Chip should be in Single-SPI mode now.\n"); +} + static int spi_nor_hw_reset(struct spi_nor *nor) { struct gpio_desc *reset; reset = devm_gpiod_get_optional(nor->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR_OR_NULL(reset)) - return PTR_ERR_OR_ZERO(reset); + if (IS_ERR(reset)) + return PTR_ERR(reset); + + if (!reset) { + /* + * FALLBACK: No dedicated reset-pin found in DT. + * Execute the blind Octal-STR reset to recover from warm reboots. + */ + spi_nor_everspin_reboot_fix(nor); + return 0; + } /* * Experimental delay values by looking at different flash device