Skip to content

Instantly share code, notes, and snippets.

@dmke
Created November 17, 2016 14:58
Show Gist options
  • Save dmke/d389bc364b3f73f525076eaee0019dc1 to your computer and use it in GitHub Desktop.
Save dmke/d389bc364b3f73f525076eaee0019dc1 to your computer and use it in GitHub Desktop.
mt7261 32M reset patch

"Frozen soft reset" on MT7261 SoCs with 32M flash

This hack is derived from this mail by Paul Fertser on openwrt-devel.

  • When using 32M flash, the SPI bus needs to be reconfigured to use 4-byte addressing mode, instead of the usual (?) 3-byte mode.
  • Issueing a soft reset without this patch leaves the bus in 4-byte mode, which then crashes the system because the SoC tries (and fails) to communicate in 3-byte addressing mode.
  • Writing the opcodes brings the SPI back into 3-byte addressing mode, so the SoC can continue communicating after issueing a soft reset.

What I'm not sure about is, whether this causes any issues on boards with 16M flash or less. Leaving the 32bit addressing mode twice doesn't seem to cause any harm.

It is tested on both a ZBT-WG3526 (16M) and Digineo AC1200 Pro (32M), using LEDE master (8459d85). While it fixes the reboot on the AC1200 Pro, it doesn't break the WG3526.

Ideally I'd like to detect the current mode and execute the spi_writes conditionally. Also, JESD216B implies in 6.4.19 (JEDEC Basic Flash Parameter Table) for bits 13:8 (Soft Reset and Rescue Sequence Support), that the reset sequence used here may not be available (i.e. bit 12 == 0).

(Obviously this needs some cleanup before it can be used anywhere.)

--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -27,6 +27,9 @@
#include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>
+#define OPCODE_RESET_ENABLE 0x66
+#define OPCODE_RESET 0x99
+
#define MAX_CMD_SIZE 6
struct m25p {
struct spi_device *spi;
@@ -261,6 +264,11 @@ static int m25p_remove(struct spi_device
{
struct m25p *flash = spi_get_drvdata(spi);
+ flash->command[0] = OPCODE_RESET_ENABLE;
+ spi_write(flash->spi, flash->command, 1);
+ flash->command[0] = OPCODE_RESET;
+ spi_write(flash->spi, flash->command, 1);
+
/* Clean up MTD stuff. */
return mtd_device_unregister(&flash->spi_nor.mtd);
}
@@ -328,6 +336,7 @@ static struct spi_driver m25p80_driver =
.id_table = m25p_ids,
.probe = m25p_probe,
.remove = m25p_remove,
+ .shutdown = m25p_remove,
/* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use.
@dmke
Copy link
Author

dmke commented Dec 8, 2016

[PATCH v2 0/2] mtd: spi-nor: add a stateless method to support memory size above 128Mib
http://lists.infradead.org/pipermail/linux-mtd/2016-December/070889.html

@cstratton
Copy link

cstratton commented Jan 21, 2017

This is unsafe - it may make an intentional soft reset work, but hardware or watchdog reset occurring when the chip is in a boot-incompatible addressing mode will still result in a hang!

If the flash chip is expected to be in 3-byte mode on boot in a particular system, then it needs to stay in 3-byte mode, and the extended address register used to access the full space (though how that register gets cleared may still be an issue); conversely if it expected to be in 4-byte mode on boot, it can never safely leave that mode.

Some SoCs have the ability to drive a reset to the rest of the board; ultimately that or fixing boot addressing mode to the size of the chip actually used may be the best solution, but those are hardware changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment