From 11e2ed1bc7bc96bd2b094fef5f57acec4efae952 Mon Sep 17 00:00:00 2001
From: Tianling Shen <cnsztl@immortalwrt.org>
Date: Sun, 9 Mar 2025 02:02:24 +0800
Subject: [PATCH] : mtk_spi_nand: add support for dosilicon fmsh gsto spi nand

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
---
 .../drivers/spi_nand/mtk_spi_nand.c           | 28 ++++++++++++++-----
 1 file changed, 21 insertions(+), 7 deletions(-)

--- a/plat/mediatek/apsoc_common/drivers/spi_nand/mtk_spi_nand.c
+++ b/plat/mediatek/apsoc_common/drivers/spi_nand/mtk_spi_nand.c
@@ -20,8 +20,11 @@
 
 #define SPI_NAND_MAX_ID_LEN		4U
 #define DELAY_US_400MS			400000U
+#define DOSILICON_ID			0xE5U
 #define ETRON_ID			0xD5U
+#define FMSH_ID				0xA1U
 #define GIGADEVICE_ID			0xC8U
+#define GSTO_ID				0x52U
 #define MACRONIX_ID			0xC2U
 #define MICRON_ID			0x2CU
 #define TOSHIBA_ID			0x98U
@@ -145,7 +148,10 @@ static int spi_nand_quad_enable(uint8_t
 
 	if (manufacturer_id != MACRONIX_ID &&
 	    manufacturer_id != GIGADEVICE_ID &&
+	    manufacturer_id != GSTO_ID &&
+	    manufacturer_id != DOSILICON_ID &&
 	    manufacturer_id != ETRON_ID &&
+	    manufacturer_id != FMSH_ID &&
 	    manufacturer_id != FORESEE_ID) {
 		return 0;
 	}
@@ -543,6 +549,10 @@ static int spi_nand_check_pp(struct para
 		INFO("PP COPY %d CRC read: 0x%x, compute: 0x%x\n",
 		     i, crc, crc_compute);
 
+		// Integrity CRC (bytes 254-255) on FMSH was reversed
+		if (crc != crc_compute)
+			crc = htobe16(pp->integrity_crc);
+
 		if (crc != crc_compute) {
 			ret = -EBADMSG;
 			continue;
@@ -634,8 +644,9 @@ restore:
 	return valid ? valid: 0;
 }
 
-static int spi_nand_read_pp(struct parameter_page *pp, uint8_t *sel)
+static int spi_nand_read_pp(uint8_t *id, struct parameter_page *pp, uint8_t *sel)
 {
+	const bool is_dosilicon = (id[1] == DOSILICON_ID);
 	uint8_t pp_offset[3] = {0x0, 0x1, 0x4};
 	int valid = -EINVAL;
 	int ret, last_ret;
@@ -648,7 +659,7 @@ static int spi_nand_read_pp(struct param
 		return ret;
 	}
 
-	ret = spi_nand_write_reg(SPI_NAND_REG_CFG, cfg_reg | BIT(6));
+	ret = spi_nand_write_reg(SPI_NAND_REG_CFG, is_dosilicon ? BIT(6) : (cfg_reg | BIT(6)));
 	if (ret != 0) {
 		return ret;
 	}
@@ -677,7 +688,7 @@ static int spi_nand_read_pp(struct param
 	}
 
 restore:
-	last_ret = spi_nand_write_reg(SPI_NAND_REG_CFG, cfg_reg);
+	last_ret = spi_nand_write_reg(SPI_NAND_REG_CFG, is_dosilicon ? 0x10 : cfg_reg);
 	if (last_ret) {
 		return last_ret;
 	}
@@ -909,9 +920,13 @@ int spi_nand_init(unsigned long long *si
 	goto success;
 
 fallback_pp:
+	ret = spi_nand_read_id(id);
+	if (ret) {
+		return ret;
+	}
 	sel = 0;
 	pp = (struct parameter_page *)buf;
-	ret = spi_nand_read_pp(pp, &sel);
+	ret = spi_nand_read_pp(id, pp, &sel);
 	if (ret) {
 		goto fallback_id;
 	}
@@ -920,11 +935,6 @@ fallback_pp:
 	goto success;
 
 fallback_id:
-	ret = spi_nand_read_id(id);
-	if (ret) {
-		return ret;
-	}
-
 	ret = spi_nand_set_data_via_id(&spinand_dev, id, &vendor_id);
 	if (ret)
 		return ret;
