From 9e8ac4fc7125795ac5e8834aaf454fd45b99c580 Mon Sep 17 00:00:00 2001
From: Weijie Gao <weijie.gao@mediatek.com>
Date: Mon, 25 Jul 2022 10:53:03 +0800
Subject: [PATCH 46/71] mtd: mtk-snand: add NMBM support for SPL

Add NMBM support for mtk-snand SPL loader

Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
---
 drivers/mtd/mtk-snand/mtk-snand-spl.c | 127 ++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

--- a/drivers/mtd/mtk-snand/mtk-snand-spl.c
+++ b/drivers/mtd/mtk-snand/mtk-snand-spl.c
@@ -13,12 +13,134 @@
 #include <mtd.h>
 #include <watchdog.h>
 
+#include <nmbm/nmbm.h>
+
 #include "mtk-snand.h"
 
 static struct mtk_snand *snf;
 static struct mtk_snand_chip_info cinfo;
 static u32 oobavail;
 
+#ifdef CONFIG_ENABLE_NAND_NMBM
+static struct nmbm_instance *ni;
+
+static int nmbm_lower_read_page(void *arg, uint64_t addr, void *buf, void *oob,
+				enum nmbm_oob_mode mode)
+{
+	int ret;
+	bool raw = mode == NMBM_MODE_RAW ? true : false;
+
+	if (mode == NMBM_MODE_AUTO_OOB) {
+		ret = mtk_snand_read_page_auto_oob(snf, addr, buf, oob,
+			oobavail, NULL, false);
+	} else {
+		ret = mtk_snand_read_page(snf, addr, buf, oob, raw);
+	}
+
+	if (ret == -EBADMSG)
+		return 1;
+	else if (ret >= 0)
+		return 0;
+
+	return ret;
+}
+
+static int nmbm_lower_write_page(void *arg, uint64_t addr, const void *buf,
+				 const void *oob, enum nmbm_oob_mode mode)
+{
+	bool raw = mode == NMBM_MODE_RAW ? true : false;
+
+	if (mode == NMBM_MODE_AUTO_OOB) {
+		return mtk_snand_write_page_auto_oob(snf, addr, buf, oob,
+			oobavail, NULL, false);
+	}
+
+	return mtk_snand_write_page(snf, addr, buf, oob, raw);
+}
+
+static int nmbm_lower_erase_block(void *arg, uint64_t addr)
+{
+	return mtk_snand_erase_block(snf, addr);
+}
+
+static int nmbm_lower_is_bad_block(void *arg, uint64_t addr)
+{
+	return mtk_snand_block_isbad(snf, addr);
+}
+
+static int nmbm_lower_mark_bad_block(void *arg, uint64_t addr)
+{
+	return mtk_snand_block_markbad(snf, addr);
+}
+
+static void nmbm_lower_log(void *arg, enum nmbm_log_category level,
+			   const char *fmt, va_list ap)
+{
+	vprintf(fmt, ap);
+}
+
+static int nmbm_init(void)
+{
+	struct nmbm_lower_device nld;
+	size_t ni_size;
+	int ret;
+
+	memset(&nld, 0, sizeof(nld));
+
+	nld.flags = NMBM_F_CREATE;
+	nld.max_ratio = CONFIG_NMBM_MAX_RATIO;
+	nld.max_reserved_blocks = CONFIG_NMBM_MAX_BLOCKS;
+
+	nld.size = cinfo.chipsize;
+	nld.erasesize = cinfo.blocksize;
+	nld.writesize = cinfo.pagesize;
+	nld.oobsize = cinfo.sparesize;
+	nld.oobavail = oobavail;
+
+	nld.read_page = nmbm_lower_read_page;
+	nld.write_page = nmbm_lower_write_page;
+	nld.erase_block = nmbm_lower_erase_block;
+	nld.is_bad_block = nmbm_lower_is_bad_block;
+	nld.mark_bad_block = nmbm_lower_mark_bad_block;
+
+	nld.logprint = nmbm_lower_log;
+
+	ni_size = nmbm_calc_structure_size(&nld);
+	ni = malloc(ni_size);
+	if (!ni) {
+		printf("Failed to allocate memory (0x%u) for NMBM instance\n",
+		       ni_size);
+		return -ENOMEM;
+	}
+
+	memset(ni, 0, ni_size);
+
+	printf("Initializing NMBM ...\n");
+
+	ret = nmbm_attach(&nld, ni);
+	if (ret) {
+		ni = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	size_t retlen;
+
+	if (!ni)
+		return -ENODEV;
+
+	nmbm_read_range(ni, offs, size, dst, NMBM_MODE_PLACE_OOB, &retlen);
+	if (retlen != size)
+		return -EIO;
+
+	return 0;
+}
+
+#else
 static u8 *page_cache;
 
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
@@ -60,6 +182,7 @@ int nand_spl_load_image(uint32_t offs, u
 
 	return ret;
 }
+#endif
 
 void nand_init(void)
 {
@@ -105,11 +228,15 @@ void nand_init(void)
 	printf("SPI-NAND: %s (%uMB)\n", cinfo.model,
 	       (u32)(cinfo.chipsize >> 20));
 
+#ifdef CONFIG_ENABLE_NAND_NMBM
+	nmbm_init();
+#else
 	page_cache = malloc(cinfo.pagesize + cinfo.sparesize);
 	if (!page_cache) {
 		mtk_snand_cleanup(snf);
 		printf("mtk-snand-spl: failed to allocate page cache\n");
 	}
+#endif
 }
 
 void nand_deselect(void)
