From e230345bbce2f7045989ccf388fa8aa9a9e962d1 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 3 Feb 2021 19:34:29 +0100
Subject: [PATCH] mediatek: add support for configuring BMT table size via
 device tree

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 .../dts/mt7622-elecom-wrc-2533gent.dts        |  2 -
 .../patches-5.10/330-mtk-bmt-support.patch    | 59 ++++++++++++-------
 2 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts b/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts
index d41bca6305..2f3e5b1fb0 100644
--- a/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts
+++ b/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts
@@ -506,8 +506,6 @@
 	pinctrl-0 = <&serial_nand_pins>;
 	status = "okay";
 
-	mediatek,bmt-v2;
-
 	spi_nand@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
diff --git a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch
index 5c20952611..504c602c50 100644
--- a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch
+++ b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch
@@ -23,7 +23,7 @@
  obj-y	+= raw/
 --- /dev/null
 +++ b/drivers/mtd/nand/mtk_bmt.c
-@@ -0,0 +1,766 @@
+@@ -0,0 +1,781 @@
 +/*
 + * Copyright (c) 2017 MediaTek Inc.
 + * Author: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
@@ -56,7 +56,7 @@
 +#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__)
 +
 +/* Maximum 8k blocks */
-+#define BB_TABLE_MAX	0x2000U
++#define BB_TABLE_MAX	bmtd.table_size
 +#define BMT_TABLE_MAX	(BB_TABLE_MAX * BBPOOL_RATIO / 100)
 +#define BMT_TBL_DEF_VAL	0x0
 +
@@ -71,14 +71,15 @@
 +#define BBMT_VERSION		2
 +	unsigned char version;
 +	/* Below 2 tables will be written in SLC */
-+	u16 bb_tbl[BB_TABLE_MAX];
-+	struct bbmt {
-+		u16 block;
++	u16 bb_tbl[];
++};
++
++struct bbmt {
++	u16 block;
 +#define NO_MAPPED		0
 +#define NORMAL_MAPPED	1
 +#define BMT_MAPPED		2
-+		u16 mapped;
-+	} bmt_tbl[BMT_TABLE_MAX];
++	u16 mapped;
 +};
 +
 +static struct bmt_desc {
@@ -94,6 +95,7 @@
 +
 +	struct dentry *debugfs_dir;
 +
++	u32 table_size;
 +	u32 pg_size;
 +	u32 blk_size;
 +	u16 pg_shift;
@@ -152,6 +154,11 @@
 +}
 +
 +/* -------- Bad Blocks Management -------- */
++static inline struct bbmt *bmt_tbl(struct bbbt *bbbt)
++{
++	return (struct bbmt *)&bbbt->bb_tbl[bmtd.table_size];
++}
++
 +static int
 +read_bmt(u16 block, unsigned char *dat, unsigned char *fdm, int fdm_len)
 +{
@@ -269,8 +276,8 @@
 +	 *		BMT always in the last valid block in pool
 +	 */
 +	while ((block = find_valid_block(block)) != 0) {
-+		bbt->bmt_tbl[i].block = block;
-+		bbt->bmt_tbl[i].mapped = NO_MAPPED;
++		bmt_tbl(bbt)[i].block = block;
++		bmt_tbl(bbt)[i].mapped = NO_MAPPED;
 +		BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block);
 +		block++;
 +		i++;
@@ -280,7 +287,7 @@
 +	 * bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block
 +	 */
 +	bmtd.bmt_blk_idx = i - 1;
-+	bbt->bmt_tbl[bmtd.bmt_blk_idx].mapped = BMT_MAPPED;
++	bmt_tbl(bbt)[bmtd.bmt_blk_idx].mapped = BMT_MAPPED;
 +
 +	if (i < 1) {
 +		pr_info("nand: FATAL ERR: no space to store BMT!!\n");
@@ -332,7 +339,7 @@
 +		return scan_bmt(block - 1);
 +
 +	if (is_valid_bmt(nand_bbt_buf, fdm)) {
-+		bmtd.bmt_blk_idx = get_bmt_index(((struct bbbt *)nand_bbt_buf)->bmt_tbl);
++		bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)nand_bbt_buf));
 +		if (bmtd.bmt_blk_idx == 0) {
 +			pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n");
 +			return NULL;
@@ -351,15 +358,15 @@
 +	u16 block;
 +
 +retry:
-+	if (n < 0 || bbt->bmt_tbl[n].mapped == NORMAL_MAPPED) {
++	if (n < 0 || bmt_tbl(bbt)[n].mapped == NORMAL_MAPPED) {
 +		pr_info("nand: FATAL ERR: no space to store BMT!\n");
 +		return (u16)-1;
 +	}
 +
-+	block = bbt->bmt_tbl[n].block;
++	block = bmt_tbl(bbt)[n].block;
 +	BBT_LOG("n = 0x%x, block = 0x%x", n, block);
 +	if (bbt_nand_erase(block)) {
-+		bbt->bmt_tbl[n].block = 0;
++		bmt_tbl(bbt)[n].block = 0;
 +		/* erase failed, try the previous block: bmt_tbl[n - 1].block */
 +		n--;
 +		goto retry;
@@ -372,7 +379,7 @@
 +	bbt->version = BBMT_VERSION;
 +
 +	if (write_bmt(block, (unsigned char *)bbt)) {
-+		bbt->bmt_tbl[n].block = 0;
++		bmt_tbl(bbt)[n].block = 0;
 +
 +		/* write failed, try the previous block in bmt_tbl[n - 1] */
 +		n--;
@@ -391,9 +398,9 @@
 +		goto error;
 +
 +	for (i = 0; i < bmtd.bmt_blk_idx; i++) {
-+		if (bbt->bmt_tbl[i].block != 0 && bbt->bmt_tbl[i].mapped == NO_MAPPED) {
-+			bbt->bmt_tbl[i].mapped = NORMAL_MAPPED;
-+			return bbt->bmt_tbl[i].block;
++		if (bmt_tbl(bbt)[i].block != 0 && bmt_tbl(bbt)[i].mapped == NO_MAPPED) {
++			bmt_tbl(bbt)[i].mapped = NORMAL_MAPPED;
++			return bmt_tbl(bbt)[i].block;
 +		}
 +	}
 +
@@ -471,6 +478,7 @@
 +		ops->retlen += cur_ops.retlen;
 +		ops->oobretlen += cur_ops.oobretlen;
 +
++		cur_ops.ooboffs = 0;
 +		cur_ops.datbuf += cur_ops.retlen;
 +		cur_ops.oobbuf += cur_ops.oobretlen;
 +		cur_ops.ooblen -= cur_ops.oobretlen;
@@ -521,6 +529,7 @@
 +		ops->retlen += cur_ops.retlen;
 +		ops->oobretlen += cur_ops.oobretlen;
 +
++		cur_ops.ooboffs = 0;
 +		cur_ops.datbuf += cur_ops.retlen;
 +		cur_ops.oobbuf += cur_ops.oobretlen;
 +		cur_ops.ooblen -= cur_ops.oobretlen;
@@ -673,7 +682,7 @@
 +	u32 block;
 +	u16 total_blocks, pmt_block;
 +	int ret = 0;
-+	u32 bmt_pool_size;
++	u32 bmt_pool_size, bmt_table_size;
 +
 +	if (bmtd.mtd)
 +		return -ENOSPC;
@@ -693,9 +702,14 @@
 +				 &bmtd.oob_offset) != 0)
 +		bmtd.oob_offset = 8;
 +
++	if (of_property_read_u32(np, "mediatek,bmt-table-size",
++				 &bmt_table_size) != 0)
++		bmt_table_size = 0x2000U;
++
 +	bmtd.mtd = mtd;
 +	mtk_bmt_replace_ops(mtd);
 +
++	bmtd.table_size = bmt_table_size;
 +	bmtd.blk_size = mtd->erasesize;
 +	bmtd.blk_shift = ffs(bmtd.blk_size) - 1;
 +	bmtd.pg_size = mtd->writesize;
@@ -723,7 +737,8 @@
 +	bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100;
 +
 +	/* 3 buffers we need */
-+	bufsz = round_up(sizeof(struct bbbt), bmtd.pg_size);
++	bufsz = round_up(sizeof(struct bbbt) +
++			 bmt_table_size * sizeof(struct bbmt), bmtd.pg_size);
 +	bmtd.bmt_pgs = bufsz >> bmtd.pg_shift;
 +
 +	nand_bbt_buf = kzalloc(bufsz, GFP_KERNEL);
@@ -756,7 +771,7 @@
 +		}
 +
 +		bbt = (struct bbbt *)nand_bbt_buf;
-+		memset(bbt->bmt_tbl, BMT_TBL_DEF_VAL, sizeof(bbt->bmt_tbl));
++		memset(bmt_tbl(bbt), BMT_TBL_DEF_VAL, bmtd.table_size * sizeof(struct bbmt));
 +
 +		if (scan_bad_blocks(bbt)) {
 +			ret = -1;
@@ -765,7 +780,7 @@
 +
 +		/* BMT always in the last valid block in pool */
 +		bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx);
-+		block = bbt->bmt_tbl[bmtd.bmt_blk_idx].block;
++		block = bmt_tbl(bbt)[bmtd.bmt_blk_idx].block;
 +		pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block);
 +
 +		if (bmtd.bmt_blk_idx == 0)
-- 
2.30.2