OpenWrt 32mb flash size. migration from 16 Mb. Development story.

Here described steps to migrate NetSoM from 16 Mb to 32 Mb flash IC. OpenWrt 32mb flash size migration story. The thing looked simple at first glance became to kernel patching.

Few weeks ago we added Amazon voice SDK and Tensorflow-lite to our development process roadmap. After making first steps we faced an issue of huge memory requirements to deal with that libraries so we decided to switch from 16 Mb flash IC on board of NetSoM to 32 Mb. We already had an experience of migration from 8Mb to 16Mb few months ago and it was pretty simple: here, here and here. So our first steps was similar in a case of migration to 32 Mb. But warning u-boot message on power up:

COM: SF: Detected w25q256 with page size 256 Bytes, erase size 4 KiB, total 32 MiB
COM: SF: Warning — Only lower 16MiB accessible, Full access #define CONFIG_SPI_FLASH_BAR

and hang up on reboot when device logs:

[ 2310.966953] reboot: Restarting system

but not followed with U-boot loading log messages lead to an additional investigation.

First issue was fixed by simple enabling mentioned macro:


But second one forced as for few hours of googling for the whole internet. Finally we found an issue description looking very similar to our and moreover solution by kernel patching. So we tried to make similar patch for our sources considering the fact of using newer kernel version (4.14.199). The issue of described bug was modification SPI flash IC registers to switch from 3-bit addressing to 4-bit addressing to cover upper half of memory while fsbl communicates with SPI flash IC using 3-bit addressing mode. So after rebooting IC keeps in 4-bit addressing mode and FSBL doesn’t have any chance to read memory to load U-boot. So the fix is resetting flash IC registers on rebooting.


Kernel patching.

Preferred way to implement OpenWrt source patching is using quilt utility. Quite simple and straightforward process described well. In our case it was looked like this.

First environment need to be prepared:

# make target/linux/{clean,prepare} V=s QUILT=1
# cd build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-imx6ull_cortexa7/linux-4.14.199/
# /home/al/imx6ull-openwrt/staging_dir/host/bin/quilt series
# /home/al/imx6ull-openwrt/staging_dir/host/bin/quilt new patches/platform/430-spi-flash-ic-on-reboot.patch



is path to folder with repository was cloned.

Next step is code modification we need to be done:

# /home/al/imx6ull-openwrt/staging_dir/host/bin/quilt edit drivers/mtd/devices/m25p80.c

and final step is registration of patch:

# /home/al/imx6ull-openwrt/staging_dir/host/bin/quilt files
# home/al/imx6ull-openwrt/staging_dir/host/bin/quilt diff
# /home/al/imx6ull-openwrt/staging_dir/host/bin/quilt refresh

so here is changes made in m25p80.c:

Index: linux-4.14.199/drivers/mtd/devices/m25p80.c
— linux-4.14.199.orig/drivers/mtd/devices/m25p80.c
+++ linux-4.14.199/drivers/mtd/devices/m25p80.c
@@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/reboot.h>

#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -226,6 +227,32 @@ static ssize_t m25p80_read(struct spi_no
return ret;

+static int m25p_reboot(struct notifier_block *nb, unsigned long val, void *v)
+ struct mtd_info *mtd;
+ struct spi_nor *sp;
+ struct m25p *flash;
+ u8 code;
+ int rc;
+ mtd = container_of(nb, struct mtd_info, reboot_notifier);
+ sp = container_of(mtd, struct spi_nor, mtd);
+ flash = container_of(sp, struct m25p, spi_nor);
+printk(«m25p_reboot JEDEC\n»);
+code = 0x66; // OPCODE_RESET_ENABLE
+rc = spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+printk(«m25p reset enable = %d\n», rc);
+code = 0x99; // OPCODE_RESET_MEMORY
+rc = spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+printk(«m25p reset memory = %d\n», rc);
+return NOTIFY_DONE;
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -243,6 +270,7 @@ static int m25p_probe(struct spi_device
char *flash_name;
int ret;
+int rc;

data = dev_get_platdata(&spi->dev);

@@ -265,6 +293,8 @@ static int m25p_probe(struct spi_device
spi_set_drvdata(spi, flash);
flash->spi = spi;

+nor->mtd.reboot_notifier.notifier_call = m25p_reboot;
if (spi->mode & SPI_RX_QUAD) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;

@@ -298,8 +328,12 @@ static int m25p_probe(struct spi_device
if (ret)
return ret;

return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
+ rc = mtd_device_register(&nor->mtd, data ? data->parts : NULL,
data ? data->nr_parts : 0);
+return rc;

final patch might be found here.

And it helped! Device started to reboot properly. It gave as properly working 32 Mb flash IC that opens door for more complex SW/HW solutions that might be implemented using NetSoM.