Add M28F parallel flash driver
Add just enough code to erase & write STMicro M28F chips. Similar
chip series that should be compatible include CAT28F and TK28F.
Probing should be fully compatible to the already supported Intel
28F series (82802AB probing).
Datasheets used:
https://www.mouser.com/catalog/specsheets/STMicroelectronics_M28F256.pdf
https://tekmos.com/docmandocuments/products/flash-memory/100-tk28f010
https://www.onsemi.com/download/data-sheet/pdf/cat28f010-d.pdf
Change-Id: Iab4860558a8ddc48b529bb3d8392d48473191769
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/521
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/Makefile b/Makefile
index 088606c..b0f6cbf 100644
--- a/Makefile
+++ b/Makefile
@@ -385,7 +385,7 @@
# Flash chip drivers and bus support infrastructure.
CHIP_OBJS = memory_bus.o jedec.o stm50.o w39.o w29ee011.o \
- sst28sf040.o 82802ab.o \
+ sst28sf040.o 82802ab.o m28f.o \
sst49lfxxxc.o sst_fwhub.o edi.o flashchips.o \
spi.o spi25.o spi25_prepare.o spi25_statusreg.o \
spi95.o opaque.o sfdp.o en29lv640b.o at45db.o \
diff --git a/include/chipdrivers/memory_bus.h b/include/chipdrivers/memory_bus.h
index 6ffa367..b4eede4 100644
--- a/include/chipdrivers/memory_bus.h
+++ b/include/chipdrivers/memory_bus.h
@@ -53,6 +53,10 @@
int printlock_regspace2_block_eraser_0(struct flashprog_flashctx *);
int printlock_regspace2_block_eraser_1(struct flashprog_flashctx *);
+/* m28f.c */
+int write_m28f(struct flashprog_flashctx *, const uint8_t *src, unsigned int pos, unsigned int len);
+int erase_m28f(struct flashprog_flashctx *, unsigned int addr, unsigned int blocksize);
+
/* sst28sf040.c */
int erase_chip_28sf040(struct flashprog_flashctx *, unsigned int addr, unsigned int blocklen);
int erase_sector_28sf040(struct flashprog_flashctx *, unsigned int address, unsigned int sector_size);
diff --git a/m28f.c b/m28f.c
new file mode 100644
index 0000000..97224ed
--- /dev/null
+++ b/m28f.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the flashprog project.
+ *
+ * Copyright (C) 2026 Nico Huber <nico.h@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdint.h>
+
+#include "flash.h"
+#include "chipdrivers/memory_bus.h"
+
+static int write_m28f_1(struct flashctx *flash, unsigned int pos, uint8_t val)
+{
+ const chipaddr base = flash->virtual_memory;
+ unsigned int tries;
+
+ for (tries = 25; tries > 0; --tries) {
+ chip_writeb(flash, 0x40, base);
+ chip_writeb(flash, val, base + pos);
+ programmer_delay(10);
+
+ chip_writeb(flash, 0xc0, base);
+ programmer_delay(6);
+
+ if (chip_readb(flash, base) == val)
+ return 0;
+ }
+
+ msg_cerr("Write failed at 0x%06x.\n", pos);
+ return 1;
+}
+
+int write_m28f(struct flashctx *flash, const uint8_t *src, unsigned int pos, unsigned int len)
+{
+ const chipaddr base = flash->virtual_memory;
+ const unsigned int limit = pos + len;
+ int ret;
+
+ for (; pos < limit; ++pos, ++src) {
+ if (*src == 0xff) /* skip no-op writes */
+ continue;
+
+ ret = write_m28f_1(flash, pos, *src);
+ if (ret)
+ goto return_to_read_mode;
+ }
+
+return_to_read_mode:
+ chip_writeb(flash, 0x00, base);
+ return ret;
+}
+
+int erase_m28f(struct flashctx *flash, unsigned int addr, unsigned int blocksize)
+{
+ const chipaddr base = flash->virtual_memory;
+ unsigned int tries, pos;
+ int ret;
+
+ /* Programming everything to 0 is required. */
+ for (pos = 0; pos < blocksize; ++pos) {
+ ret = write_m28f_1(flash, pos, 0x00);
+ if (ret)
+ goto return_to_read_mode;
+ }
+
+ for (pos = 0, tries = 1000; tries > 0; --tries) {
+ chip_writeb(flash, 0x20, base);
+ chip_writeb(flash, 0x20, base);
+ programmer_delay(10*1000);
+
+ for (; pos < blocksize; ++pos) {
+ chip_writeb(flash, 0xa0, base + pos);
+ programmer_delay(6);
+
+ if (chip_readb(flash, base) != 0xff)
+ break;
+ }
+ if (pos == blocksize)
+ goto return_to_read_mode;
+ }
+
+ msg_cerr("Erase failed at 0x%06x.\n", pos);
+ ret = 1;
+
+return_to_read_mode:
+ chip_writeb(flash, 0x00, base);
+ return ret;
+}
diff --git a/meson.build b/meson.build
index f9f860c..026a804 100644
--- a/meson.build
+++ b/meson.build
@@ -60,6 +60,7 @@
'jedec.c',
'layout.c',
'libflashprog.c',
+ 'm28f.c',
'memory_bus.c',
'opaque.c',
'parallel.c',