[PATCH v2 02/11] rockchip: idb: add basic functions

Johan Jonker jbx6244 at gmail.com
Sat Jul 9 11:49:04 PDT 2022


On Rockchip SoCs with a NAND as boot device the
information data base (IDB) loaded by the boot ROM
is stored at the beginning of several erase blocks.
Add basic functions for reading and writing.

Signed-off-by: Johan Jonker <jbx6244 at gmail.com>
---

Changed V2:
  remove CamelCases
  remove randomizer
  remove sector1 info
  remove stop and info cmd
  remove block driver
---
 arch/arm/mach-rockchip/Kconfig        |   12 +
 arch/arm/mach-rockchip/Makefile       |    1 +
 arch/arm/mach-rockchip/rockchip_idb.c | 1074 +++++++++++++++++++++++++
 3 files changed, 1087 insertions(+)
 create mode 100644 arch/arm/mach-rockchip/rockchip_idb.c

diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 18aff548..0f464f1b 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -425,6 +425,18 @@ config ROCKCHIP_SPI_IMAGE
 config LNX_KRNL_IMG_TEXT_OFFSET_BASE
 	default SYS_TEXT_BASE
 
+config ROCKCHIP_IDB
+	bool "Use Rockchip IDB block device"
+	depends on BLK
+	help
+	  This option enables the Rockchip IDB block device
+
+config SPL_ROCKCHIP_IDB
+	bool "Use rockchip IDB block device in SPL"
+	depends on SPL_BLK
+	help
+	  This option enables the Rockchip IDB block device in SPL
+
 source "arch/arm/mach-rockchip/px30/Kconfig"
 source "arch/arm/mach-rockchip/rk3036/Kconfig"
 source "arch/arm/mach-rockchip/rk3066/Kconfig"
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index ebe0afa2..36c33ba4 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ROCKCHIP_COMMON_BOARD) += board.o
 
 ifeq ($(CONFIG_TPL_BUILD),)
 obj-$(CONFIG_DISPLAY_CPUINFO) += cpu-info.o
+obj-$(CONFIG_$(SPL_)ROCKCHIP_IDB) += rockchip_idb.o
 endif
 
 obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram.o
diff --git a/arch/arm/mach-rockchip/rockchip_idb.c b/arch/arm/mach-rockchip/rockchip_idb.c
new file mode 100644
index 00000000..6a2af329
--- /dev/null
+++ b/arch/arm/mach-rockchip/rockchip_idb.c
@@ -0,0 +1,1074 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Johan Jonker <jbx6244 at gmail.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <memalign.h>
+#include <linux/iopoll.h>
+
+#define NFC_DEF_TIMEOUT		20000
+#define NFC_ECC_MAX_MODES	4
+#define NFC_READ		0
+#define NFC_WRITE		1
+
+#define NFC_FMCTL		0x00
+#define  FMCTL_WP		BIT(8)
+#define  FMCTRL_CE_SEL_M	0xFF
+#define  FMCTL_RDY		BIT(9)
+
+#define NFC_FMWAIT		0x04
+
+#define  FLCTL_RST		BIT(0)
+#define  FLCTL_WR		0x1
+#define  FLCTL_XFER_ST		BIT(2)
+#define  FLCTL_XFER_EN		BIT(3)
+#define  FLCTL_ST_BUF_S		0x4
+#define  FLCTL_XFER_COUNT	BIT(5)
+#define  FLCTL_ACORRECT		BIT(10)
+#define  FLCTL_XFER_READY	BIT(20)
+
+#define  BCHCTL_BANK_M		(7 << 5)
+#define  BCHCTL_BANK		(5)
+
+#define ECC_ERR_CNT(x, e)	((((x) >> (e).low) & (e).low_mask) | \
+				(((x) >> (e).high) & (e).high_mask) << (e).low_bn)
+
+#define NFC_BANK		0x800
+#define NFC_BANK_STEP		0x100
+#define  BANK_DATA		0x00
+#define  BANK_ADDR		0x04
+#define  BANK_CMD		0x08
+
+#define NFC_SRAM0		0x1000
+#define NFC_SRAM_SIZE		0x400
+
+#define NAND_CMD_READ0		0
+#define NAND_CMD_PAGEPROG	0x10
+#define NAND_CMD_READSTART	0x30
+#define NAND_CMD_ERASE1		0x60
+#define NAND_CMD_SEQIN		0x80
+#define NAND_CMD_READID		0x90
+#define NAND_CMD_ERASE2		0xd0
+#define NAND_CMD_RESET		0xff
+
+#define DATA_STEP		1024
+#define OOB_STEP		4
+#define LBA			64 + 512 + 33
+
+#define DEFAULT_BLKS		8
+#define DEFAULT_STRENGTH	24
+
+#define RK_MAGIC		0xFCDC8C3B
+
+struct sector0 {
+	u32 magic;
+	u8  reserved[4];
+	u32 rc4_flag;
+	u16 boot_code1_offset;
+	u16 boot_code2_offset;
+	u8  reserved1[490];
+	u16 flash_data_size;
+	u16 flash_boot_size;
+	u8  reserved2[2];
+} __packed;
+
+struct nand_para_info {
+	u8 id_bytes;
+	u8 nand_id[6];
+	u8 vendor;
+	u8 die_per_chip;
+	u8 sec_per_page;
+	u16 page_per_blk;
+	u8 cell;
+	u8 plane_per_die;
+	u16 blk_per_plane;
+	u16 operation_opt;
+	u8 lsb_mode;
+	u8 read_retry_mode;
+	u8 ecc_bits;
+	u8 access_freq;
+	u8 opt_mode;
+	u8 die_gap;
+	u8 bad_block_mode;
+	u8 multi_plane_mode;
+	u8 slc_mode;
+	u8 reserved[5];
+};
+
+struct idb {
+	int blk;
+	int ecc;
+	int sectors;
+};
+
+enum nfc_type {
+	NFC_V6,
+	NFC_V8,
+	NFC_V9,
+};
+
+struct ecc_cnt_status {
+	u8 err_flag_bit;
+	u8 low;
+	u8 low_mask;
+	u8 low_bn;
+	u8 high;
+	u8 high_mask;
+};
+
+struct nfc_cfg {
+	enum nfc_type type;
+	u8 ecc_strengths[NFC_ECC_MAX_MODES];
+	u32 ecc_cfgs[NFC_ECC_MAX_MODES];
+	u32 flctl_off;
+	u32 bchctl_off;
+	u32 dma_cfg_off;
+	u32 dma_data_buf_off;
+	u32 dma_oob_buf_off;
+	u32 dma_st_off;
+	u32 bch_st_off;
+	u32 randmz_off;
+	u32 int_en_off;
+	u32 int_clr_off;
+	u32 int_st_off;
+	u32 oob0_off;
+	u32 oob1_off;
+	struct ecc_cnt_status ecc0;
+	struct ecc_cnt_status ecc1;
+};
+
+struct rk_idb {
+	void __iomem *regs;
+	struct clk nfc_clk;
+	struct clk ahb_clk;
+	const struct nfc_cfg *cfg;
+	int selected_bank;
+	u32 bank_offset;
+	struct nand_para_info *info;
+	u32 boot_blks;
+	u32 boot_ecc;
+	u32 pages_per_blk;
+	struct idb idblock[5];
+	u32 blk_counter;
+	u32 sectors;
+	u16 page_table[512];
+	char *check;
+	char *idb;
+};
+
+struct nand_para_info nand_para_tbl[] = {
+	{6, {0x2c, 0x64, 0x44, 0x4b, 0xa9, 0x00}, 4, 1, 16,  256, 2, 2, 2048, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x44, 0x44, 0x4b, 0xa9, 0x00}, 4, 1, 16,  256, 2, 2, 1064, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x68, 0x04, 0x4a, 0xa9, 0x00}, 4, 1,  8,  256, 2, 2, 2048, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x88, 0x04, 0x4b, 0xa9, 0x00}, 4, 1, 16,  256, 2, 2, 2048, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0xa8, 0x05, 0xcb, 0xa9, 0x00}, 4, 2, 16,  256, 2, 2, 2048, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x68, 0x04, 0x46, 0x89, 0x00}, 4, 1,  8,  256, 2, 2, 2048, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x48, 0x04, 0x4a, 0xa5, 0x00}, 4, 1,  8,  256, 2, 2, 1024, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x84, 0x64, 0x3c, 0xa5, 0x00}, 4, 1, 32,  512, 2, 2, 1024, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0x64, 0x54, 0xa9, 0x00}, 4, 1, 32,  512, 2, 2, 1024, 0x01df,  4, 18, 60, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0xd7, 0x94, 0x3e, 0x84, 0x00}, 4, 1,  8,  128, 2, 2, 4096, 0x0117,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x48, 0x04, 0x46, 0x85, 0x00}, 4, 1,  8,  256, 2, 2, 1024, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x88, 0x05, 0xc6, 0x89, 0x00}, 4, 2,  8,  256, 2, 2, 2048, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x88, 0x24, 0x4b, 0xa9, 0x00}, 4, 1, 16,  256, 2, 2, 2048, 0x011f,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x68, 0x00, 0x27, 0xa9, 0x00}, 4, 1, 16,  128, 1, 2, 2048, 0x011f,  0,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x64, 0x64, 0x56, 0xa5, 0x00}, 4, 1, 24,  512, 2, 2,  700, 0x01df,  4, 18, 60, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0x84, 0xc5, 0x4b, 0xa9, 0x00}, 4, 2, 16,  256, 2, 2, 2048, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0xd5, 0xd1, 0xa6, 0x68, 0x00}, 4, 2,  8,   64, 1, 2, 2048, 0x0117,  0,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0xdc, 0x90, 0xa6, 0x54, 0x00}, 4, 1,  8,   64, 1, 2, 1024, 0x0117,  0,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x64, 0x64, 0x54, 0xa4, 0x00}, 4, 1, 32,  512, 2, 1, 1024, 0x01df,  4, 18, 60, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0x44, 0x32, 0xaa, 0x00}, 4, 1, 32,  512, 2, 1, 2184, 0x05c7,  5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x64, 0x44, 0x32, 0xa5, 0x00}, 4, 1, 32,  512, 2, 1, 1048, 0x05c7,  5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x64, 0x64, 0x3c, 0xa5, 0x00}, 4, 1, 32,  512, 2, 1, 1044, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0x44, 0x32, 0xaa, 0x00}, 4, 1, 32,  512, 2, 1, 2184, 0x05c7,  5, 19, 60, 32, 1, 0, 4, 0, 1, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0x44, 0x34, 0xaa, 0x00}, 4, 1, 32,  512, 2, 1, 2184, 0x05c7,  5, 19, 60, 32, 1, 0, 4, 0, 1, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0xc4, 0x34, 0xaa, 0x00}, 4, 1, 32,  512, 2, 1, 2184, 0x05c7,  5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0x44, 0x34, 0xa4, 0x00}, 4, 1, 32,  512, 2, 1, 2184, 0x05c7,  5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+	{5, {0x2c, 0x84, 0x64, 0x3c, 0xa9, 0x00}, 4, 1, 32,  512, 2, 2, 1024, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x2c, 0xa4, 0x64, 0x32, 0xaa, 0x04}, 4, 1, 32, 1024, 2, 1, 2192, 0x05c7, 10, 19, 60, 32, 1, 0, 4, 0, 1, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xde, 0x94, 0xd2, 0x04, 0x43}, 2, 1, 16,  256, 2, 2, 2048, 0x01d9,  1,  1, 24, 32, 4, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xd7, 0x94, 0xda, 0x74, 0xc3}, 2, 1, 16,  256, 2, 2, 1024, 0x01d9,  1,  2, 40, 32, 4, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xd7, 0x94, 0x91, 0x60, 0x44}, 2, 1, 16,  256, 2, 2, 1046, 0x01d9,  1,  3, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4}, 2, 1, 16,  256, 2, 2, 2090, 0x01d9,  1,  4, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xde, 0x94, 0xeb, 0x74, 0x44}, 2, 1, 32,  256, 2, 2, 1066, 0x01d9,  1,  7, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xd5, 0x94, 0xda, 0x74, 0xc4}, 2, 1, 16,  256, 2, 2,  530, 0x01d9,  1,  3, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xd7, 0x94, 0x9a, 0x74, 0x42}, 2, 1, 16,  256, 2, 2, 1024, 0x0119,  1,  0, 24, 32, 4, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xde, 0x14, 0xa7, 0x42, 0x4a}, 2, 1, 32,  256, 2, 2, 1060, 0x01d9,  2,  5, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xd7, 0x14, 0x9e, 0x34, 0x4a}, 2, 1, 16,  256, 2, 2, 1056, 0x01d9,  2,  5, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xde, 0x94, 0xa7, 0x42, 0x48}, 2, 1, 32,  256, 2, 2, 1060, 0x01d9,  2,  5, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xde, 0x14, 0xab, 0x42, 0x4a}, 2, 1, 32,  256, 2, 2, 1056, 0x01d9,  2,  6, 40, 32, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0x3a, 0x14, 0xab, 0x42, 0x4a}, 2, 1, 32,  256, 2, 2, 2092, 0x01d9,  2,  5, 40, 32, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0xd5, 0x94, 0x9a, 0x74, 0x42}, 2, 1, 16,  256, 2, 1, 1024, 0x0111,  1,  0, 24, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xad, 0x3a, 0x14, 0x03, 0x08, 0x50}, 2, 1, 32,  388, 2, 2, 1362, 0x01d9,  9,  8, 40, 32, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x64, 0x44, 0x4b, 0xa9, 0x00}, 7, 1, 16,  256, 2, 2, 2048, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x88, 0x24, 0x4b, 0xa9, 0x84}, 7, 1, 16,  256, 2, 2, 2048, 0x01df,  3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x88, 0x24, 0x4b, 0xa9, 0x00}, 7, 1, 16,  256, 2, 2, 2048, 0x0117,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x68, 0x24, 0x4a, 0xa9, 0x00}, 7, 1,  8,  256, 2, 2, 2048, 0x0117,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x68, 0x04, 0x4a, 0xa9, 0x00}, 7, 1,  8,  256, 2, 2, 2048, 0x0117,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0xd7, 0x94, 0x3e, 0x84, 0x00}, 7, 1,  8,  256, 2, 2, 2048, 0x0117,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x68, 0x04, 0x46, 0xa9, 0x00}, 7, 1,  8,  256, 2, 2, 2048, 0x0117,  1,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x89, 0x64, 0x64, 0x3c, 0xa1, 0x00}, 7, 1, 32,  512, 2, 1, 1024, 0x01c7,  4, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0x89, 0x84, 0x64, 0x3c, 0xa5, 0x00}, 7, 1, 32,  512, 2, 2, 1024, 0x01c7,  4, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x89, 0x88, 0x24, 0x3b, 0xa9, 0x00}, 7, 1, 16,  192, 2, 2, 2048, 0x0117, 12,  0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xd7, 0x84, 0x93, 0x72, 0x57}, 1, 1, 32,  256, 2, 1, 1060, 0x05c1,  2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xde, 0x84, 0x93, 0x72, 0x57}, 1, 1, 32,  256, 2, 1, 2092, 0x05c1,  2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0x3a, 0x85, 0x93, 0x76, 0x57}, 1, 2, 32,  256, 2, 1, 2092, 0x05e1,  2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xd5, 0x84, 0x32, 0x72, 0x56}, 1, 1, 16,  128, 2, 1, 2056, 0x05c1,  2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56}, 1, 1, 16,  128, 2, 2, 2058, 0x05d1,  2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xde, 0x94, 0x82, 0x76, 0x56}, 1, 1, 16,  256, 2, 2, 2062, 0x05d1,  1, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xde, 0x94, 0x93, 0x76, 0x50}, 1, 1, 32,  256, 2, 2, 1066, 0x05d9,  2, 34, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0x3a, 0x95, 0x93, 0x7a, 0x50}, 1, 2, 32,  256, 2, 2, 1066, 0x05d9,  2, 34, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xd7, 0x94, 0x32, 0x76, 0x55}, 1, 1, 16,  128, 2, 2, 2050, 0x0191,  2,  0, 24, 32, 1, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xde, 0x94, 0x93, 0x76, 0x57}, 1, 1, 32,  256, 2, 2, 1058, 0x05d9,  2, 33, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xd7, 0x84, 0x93, 0x72, 0x50}, 1, 1, 32,  256, 2, 1, 1060, 0x05c1,  2, 34, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xde, 0x94, 0x93, 0x76, 0x51}, 1, 1, 32,  256, 2, 2, 1074, 0x05d9,  2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0x3a, 0x94, 0x93, 0x76, 0x51}, 1, 1, 32,  256, 2, 2, 2106, 0x05d9,  2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xd7, 0x84, 0x93, 0x72, 0x51}, 1, 1, 32,  256, 2, 1, 1056, 0x05d9,  2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x98, 0xde, 0x94, 0x93, 0x76, 0xd1}, 1, 1, 32,  256, 2, 2, 1074, 0x05d9,  2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0x94, 0x93, 0x76, 0x57}, 8, 1, 32,  256, 2, 2, 1058, 0x05d9,  2, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xd7, 0x84, 0x93, 0x72, 0x57}, 8, 1, 32,  256, 2, 1, 1060, 0x05c1,  2, 66, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0xa4, 0x82, 0x76, 0x56}, 8, 1, 16,  256, 2, 2, 2082, 0x01d9,  1, 65, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0x94, 0x93, 0x76, 0x50}, 8, 1, 32,  256, 2, 2, 1066, 0x05d9,  2, 67, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xd7, 0x84, 0x93, 0x72, 0x50}, 8, 1, 32,  256, 2, 1, 1060, 0x05c1,  2, 67, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0xa4, 0x82, 0x76, 0xd7}, 8, 1, 16,  256, 2, 2, 2090, 0x04d9,  1, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0x84, 0x93, 0x72, 0x57}, 8, 1, 32,  256, 2, 1, 2092, 0x05c1,  2, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0x3a, 0x94, 0x93, 0x76, 0x51}, 8, 1, 32,  256, 2, 2, 2106, 0x01d9,  2, 68, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0x94, 0x93, 0x76, 0x51}, 8, 1, 32,  256, 2, 2, 1074, 0x01d9,  2, 68, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0x3a, 0xa4, 0x93, 0x7a, 0x50}, 8, 1, 32,  256, 2, 2, 2138, 0x05d9,  2,  0, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0x94, 0x82, 0x76, 0x56}, 8, 1, 16,  256, 2, 2, 2062, 0x01d9,  1,  0, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0x45, 0xde, 0x94, 0x93, 0x76, 0xd7}, 8, 1, 32,  256, 2, 2, 1058, 0x05d9,  2, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+	{5, {0xec, 0xd7, 0x94, 0x7e, 0x64, 0x44}, 0, 1, 16,  128, 2, 2, 2048, 0x01d9,  2, 49, 60, 36, 3, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xec, 0xde, 0xd5, 0x7e, 0x68, 0x44}, 0, 2, 16,  128, 2, 2, 2048, 0x01f9,  2, 49, 60, 36, 3, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xec, 0xd7, 0x94, 0x7a, 0x54, 0x43}, 0, 1, 16,  128, 2, 2, 2076, 0x0199,  2,  0, 40, 36, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xec, 0xde, 0xd5, 0x7a, 0x58, 0x43}, 0, 2, 16,  128, 2, 2, 2076, 0x01b9,  2,  0, 40, 36, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xec, 0xd5, 0x94, 0x76, 0x54, 0x43}, 0, 1, 16,  128, 2, 2, 1038, 0x0119,  2,  0, 24, 36, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xec, 0xd7, 0x14, 0x76, 0x54, 0xc2}, 0, 1, 16,  128, 2, 2, 2076, 0x0491,  2,  0, 24, 40, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+	{6, {0xec, 0xde, 0x94, 0xc3, 0xa4, 0xca}, 0, 1, 32,  792, 2, 1,  688, 0x04c1, 11, 50, 40, 32, 3, 1, 1, 0, 1, {0, 0, 0, 0, 0}},
+};
+
+void rk_idb_build_page_table(struct rk_idb *plat, u32 lsb_mode)
+{
+	u32 counter;
+	u32 counter2;
+
+	switch (lsb_mode) {
+	case 0:
+		counter = 0;
+		do {
+			u16 val = counter;
+
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	case 1:
+		counter = 0;
+		do {
+			u16 val = counter;
+
+			if (counter > 3) {
+				u16 offset;
+
+				if (counter & 1)
+					offset = 3;
+				else
+					offset = 2;
+				val = 2 * counter - offset;
+			}
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	case 2:
+		counter = 0;
+		do {
+			u16 val = counter;
+
+			if (counter > 1)
+				val = 2 * counter - 1;
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	case 3:
+		counter = 0;
+		do {
+			u16 val = counter;
+
+			if (counter > 5) {
+				u16 offset;
+
+				if (counter & 1)
+					offset = 5;
+				else
+					offset = 4;
+				val = 2 * counter - offset;
+			}
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	case 4:
+		counter = 8;
+		plat->page_table[0] = 0;
+		plat->page_table[1] = 1;
+		plat->page_table[2] = 2;
+		plat->page_table[3] = 3;
+		plat->page_table[4] = 4;
+		plat->page_table[5] = 5;
+		plat->page_table[6] = 7;
+		plat->page_table[7] = 8;
+		do {
+			u32 offset;
+			u32 val;
+
+			if (counter & 1)
+				offset = 7;
+			else
+				offset = 6;
+			val = 2 * counter - offset;
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	case 5:
+		counter = 0;
+		counter2 = 16;
+		do {
+			u16 val = counter;
+
+			plat->page_table[counter++] = val;
+		} while (counter != 16);
+		do {
+			plat->page_table[counter++] = counter2;
+			counter2 = counter2 + 2;
+		} while (counter != 512);
+		break;
+	case 6:
+		counter = 0;
+		counter2 = 0;
+		do {
+			u16 val = counter;
+
+			if (counter > 5) {
+				u16 offset;
+
+				if (counter & 1)
+					offset = 12;
+				else
+					offset = 10;
+				val = counter2 - offset;
+			}
+			plat->page_table[counter++] = val;
+			counter2 = counter2 + 3;
+		} while (counter != 512);
+		break;
+	case 9:
+		counter = 3;
+		counter2 = 3;
+		plat->page_table[0] = 0;
+		plat->page_table[1] = 1;
+		plat->page_table[2] = 2;
+		do {
+			plat->page_table[counter++] = counter2;
+			counter2 = counter2 + 2;
+		} while (counter != 512);
+		break;
+	case 10:
+		counter = 0;
+		counter2 = 63;
+		do {
+			u16 val = counter;
+
+			plat->page_table[counter++] = val;
+		} while (counter != 63);
+		do {
+			plat->page_table[counter++] = counter2;
+			counter2 = counter2 + 2;
+		} while (counter != 512);
+		break;
+	case 11:
+		counter = 0;
+		do {
+			u16 val = counter;
+
+			plat->page_table[counter++] = val;
+		} while (counter != 8);
+		do {
+			u32 offset;
+			u32 val;
+
+			if (counter & 1)
+				offset = 7;
+			else
+				offset = 6;
+			val = 2 * counter - offset;
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	case 12:
+		counter = 4;
+		plat->page_table[0] = 0;
+		plat->page_table[1] = 1;
+		plat->page_table[2] = 2;
+		plat->page_table[3] = 3;
+		do {
+			u32 val = counter - 1 + (counter >> 1);
+
+			plat->page_table[counter++] = val;
+		} while (counter != 512);
+		break;
+	}
+}
+
+void rk_idb_rc4(u8 *buf, u32 len)
+{
+	u8 S[256], K[256], temp;
+	u32 i, j, t, x;
+	u8 key[16] = { 124, 78, 3, 4, 85, 5, 9, 7, 45, 44, 123, 56, 23, 13, 23, 17};
+
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		S[i] = (u8)i;
+		j &= 0x0f;
+		K[i] = key[j];
+		j++;
+	}
+
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		j = (j + S[i] + K[i]) % 256;
+		temp = S[i];
+		S[i] = S[j];
+		S[j] = temp;
+	}
+
+	i = 0;
+	j = 0;
+	for (x = 0; x < len; x++) {
+		i = (i + 1) % 256;
+		j = (j + S[i]) % 256;
+		temp = S[i];
+		S[i] = S[j];
+		S[j] = temp;
+		t = (S[i] + (S[j] % 256)) % 256;
+		buf[x] = buf[x] ^ S[t];
+	}
+}
+
+void rk_idb_wait_dev_ready(struct rk_idb *plat)
+{
+	void __iomem *regs = plat->regs;
+	u32 reg;
+
+	readl_poll_sleep_timeout(regs + NFC_FMCTL,
+				 reg,
+				 reg & FMCTL_RDY,
+				 1,
+				 NFC_DEF_TIMEOUT);
+}
+
+int rk_idb_wait_pio_xfer_done(struct rk_idb *plat)
+{
+	void __iomem *regs = plat->regs;
+	u32 reg;
+
+	return readl_poll_sleep_timeout(regs + plat->cfg->flctl_off,
+					reg,
+					reg & FLCTL_XFER_READY,
+					1,
+					NFC_DEF_TIMEOUT);
+}
+
+int rk_idb_hw_ecc_setup(struct rk_idb *plat, u32 strength)
+{
+	void __iomem *regs = plat->regs;
+	u32 reg, i;
+
+	for (i = 0; i < NFC_ECC_MAX_MODES; i++) {
+		if (strength == plat->cfg->ecc_strengths[i]) {
+			reg = plat->cfg->ecc_cfgs[i];
+			break;
+		}
+	}
+
+	if (i >= NFC_ECC_MAX_MODES)
+		return -EINVAL;
+
+	writel(reg, regs + plat->cfg->bchctl_off);
+
+	return 0;
+}
+
+void rk_idb_select_chip(struct rk_idb *plat, int chipnr)
+{
+	void __iomem *regs = plat->regs;
+	u32 reg;
+
+	if (chipnr < 0) {
+		plat->selected_bank = -1;
+	} else {
+		plat->selected_bank = chipnr;
+		plat->bank_offset = NFC_BANK + plat->selected_bank * NFC_BANK_STEP;
+	}
+
+	reg = readl(regs + NFC_FMCTL);
+	reg &= ~FMCTRL_CE_SEL_M;
+	if (plat->selected_bank != -1)
+		reg |= 1 << plat->selected_bank;
+	writel(reg, regs + NFC_FMCTL);
+}
+
+void rk_idb_pio_xfer_start(struct rk_idb *plat, u8 dir, u8 st_buf)
+{
+	void __iomem *regs = plat->regs;
+	u32 reg;
+
+	if (plat->cfg->type == NFC_V6 || plat->cfg->type == NFC_V8) {
+		reg = readl(regs + plat->cfg->bchctl_off);
+		reg = (reg & (~(BCHCTL_BANK_M))) |
+		      (plat->selected_bank << BCHCTL_BANK);
+		writel(reg, regs + plat->cfg->bchctl_off);
+	}
+
+	reg = (dir << FLCTL_WR) | (st_buf << FLCTL_ST_BUF_S) |
+	      FLCTL_XFER_EN | FLCTL_XFER_COUNT |
+	      FLCTL_ACORRECT;
+	writel(reg, regs + plat->cfg->flctl_off);
+
+	reg |= FLCTL_XFER_ST;
+	writel(reg, regs + plat->cfg->flctl_off);
+}
+
+void rk_idb_init(struct rk_idb *plat)
+{
+	void __iomem *regs = plat->regs;
+
+	writel(FMCTL_WP, regs + NFC_FMCTL);
+	/* Config default timing 40ns at 150 Mhz NFC clock. */
+	writel(0x1081, regs + NFC_FMWAIT);
+	writel(0, regs + plat->cfg->randmz_off);
+	writel(0, regs + plat->cfg->dma_cfg_off);
+	writeb(NAND_CMD_RESET, regs + NFC_BANK + BANK_CMD);
+	rk_idb_wait_dev_ready(plat);
+}
+
+void rk_idb_read_id(struct rk_idb *plat, u8 *id, int len)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *bank_base = regs + plat->bank_offset;
+
+	writeb(NAND_CMD_READID, bank_base + BANK_CMD);
+	writeb(0x0, bank_base + BANK_ADDR);
+	udelay(1);
+
+	debug("FLASH ID               :");
+
+	for (int i = 0; i < len; i++) {
+		id[i] = readb(bank_base);
+		debug(" %x", id[i]);
+	}
+
+	debug("\n");
+}
+
+void rk_idb_erase_op(struct rk_idb *plat, int page)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *bank_base = regs + plat->bank_offset;
+
+	writeb(NAND_CMD_ERASE1, bank_base + BANK_CMD);
+	writeb(page, bank_base + BANK_ADDR);
+	writeb(page >> 8, bank_base + BANK_ADDR);
+	writeb(page >> 16, bank_base + BANK_ADDR);
+	writeb(NAND_CMD_ERASE2, bank_base + BANK_CMD);
+}
+
+void rk_idb_read_page_op(struct rk_idb *plat, int page, int col)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *bank_base = regs + plat->bank_offset;
+
+	writeb(NAND_CMD_READ0, bank_base + BANK_CMD);
+	writeb(col, bank_base + BANK_ADDR);
+	writeb(col >> 8, bank_base + BANK_ADDR);
+	writeb(page, bank_base + BANK_ADDR);
+	writeb(page >> 8, bank_base + BANK_ADDR);
+	writeb(page >> 16, bank_base + BANK_ADDR);
+	writeb(NAND_CMD_READSTART, bank_base + BANK_CMD);
+}
+
+void rk_idb_write_page_op_begin(struct rk_idb *plat, int page, int col)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *bank_base = regs + plat->bank_offset;
+
+	writeb(NAND_CMD_SEQIN, bank_base + BANK_CMD);
+	writeb(col, bank_base + BANK_ADDR);
+	writeb(col >> 8, bank_base + BANK_ADDR);
+	writeb(page, bank_base + BANK_ADDR);
+	writeb(page >> 8, bank_base + BANK_ADDR);
+	writeb(page >> 16, bank_base + BANK_ADDR);
+}
+
+void rk_idb_write_page_op_end(struct rk_idb *plat)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *bank_base = regs + plat->bank_offset;
+
+	writeb(NAND_CMD_PAGEPROG, bank_base + BANK_CMD);
+}
+
+int rk_idb_read_page(struct rk_idb *plat, unsigned int page, u8 *buf, u8 *spare, u8 steps)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *sram_base = regs + NFC_SRAM0;
+	unsigned int max_bitflips = 0;
+	int bch_st;
+	int ret;
+
+	rk_idb_read_page_op(plat, page, 0);
+	rk_idb_wait_dev_ready(plat);
+	rk_idb_pio_xfer_start(plat, NFC_READ, 0);
+
+	for (int step = 0; step < steps / 2; step++) {
+		u8 *data = buf + step * DATA_STEP;
+		u8 *oob = spare + step * OOB_STEP;
+
+		ret = rk_idb_wait_pio_xfer_done(plat);
+		if (ret) {
+			debug("read timeout\n");
+			max_bitflips = -1;
+			break;
+		}
+
+		bch_st = readl(regs + plat->cfg->bch_st_off);
+
+		if (bch_st & BIT(plat->cfg->ecc0.err_flag_bit)) {
+			max_bitflips = -1;
+			break;
+		} else {
+			ret = ECC_ERR_CNT(bch_st, plat->cfg->ecc0);
+			max_bitflips = max_t(unsigned int, max_bitflips, ret);
+		}
+
+		if ((step + 1) < steps / 2)
+			rk_idb_pio_xfer_start(plat, NFC_READ, (step + 1) & 0x1);
+
+		memcpy_fromio(data, sram_base + NFC_SRAM_SIZE * (step & 0x1), DATA_STEP);
+
+		if (step & 1)
+			memcpy_fromio(oob, regs + plat->cfg->oob1_off, OOB_STEP);
+		else
+			memcpy_fromio(oob, regs + plat->cfg->oob0_off, OOB_STEP);
+	}
+
+	u32 *p_spare = (u32 *)spare;
+
+	debug("read_page page_addr: %d spare[0]:%d\n", page, *p_spare);
+
+	return max_bitflips;
+}
+
+int rk_idb_write_page(struct rk_idb *plat, unsigned int page, u8 *buf, u8 *spare, u8 steps)
+{
+	void __iomem *regs = plat->regs;
+	void __iomem *sram_base = regs + NFC_SRAM0;
+	int ret = 0;
+
+	u32 *p_spare = (u32 *)spare;
+
+	debug("write_page page_addr: %d spare[0]:%d\n", page, *p_spare);
+
+	rk_idb_write_page_op_begin(plat, page, 0);
+
+	memcpy_toio(sram_base, buf, DATA_STEP);
+	memcpy_toio(regs + plat->cfg->oob0_off, spare, OOB_STEP);
+
+	for (int step = 1; step <= steps / 2; step++) {
+		rk_idb_pio_xfer_start(plat, NFC_WRITE, (step - 1) & 0x1);
+
+		u8 *data = buf + step * DATA_STEP;
+		u8 *oob = spare + step * OOB_STEP;
+
+		if (step < steps / 2) {
+			memcpy_toio(sram_base + NFC_SRAM_SIZE * (step & 1), data, DATA_STEP);
+
+			if (step & 1)
+				memcpy_fromio(regs + plat->cfg->oob1_off, oob, OOB_STEP);
+			else
+				memcpy_fromio(regs + plat->cfg->oob0_off, oob, OOB_STEP);
+		}
+
+		ret = rk_idb_wait_pio_xfer_done(plat);
+		if (ret) {
+			debug("write timeout\n");
+			ret = -1;
+			break;
+		}
+	}
+
+	rk_idb_write_page_op_end(plat);
+	rk_idb_wait_dev_ready(plat);
+
+	return ret;
+}
+
+void rk_idb_scan_block(struct rk_idb *plat, u32 *data, u32 *spare)
+{
+	u32 blk;
+	u32 bch_counter;
+	int status;
+
+	plat->blk_counter = 0;
+
+	for (blk = 0; blk < plat->boot_blks; blk++) {
+		for (bch_counter = 0; bch_counter < NFC_ECC_MAX_MODES; bch_counter++) {
+			rk_idb_hw_ecc_setup(plat, plat->cfg->ecc_strengths[bch_counter]);
+
+			status = rk_idb_read_page(plat, blk * plat->pages_per_blk,
+						  (u8 *)data, (u8 *)spare, 4);
+			if (status != -1 && *data == RK_MAGIC) {
+				u32 boot_size;
+
+				rk_idb_rc4((char *)data, 512);
+
+				struct sector0 *sec0 = (struct sector0 *)data;
+
+				if ((sec0->flash_boot_size -
+				     sec0->flash_data_size) != 1024) {
+					boot_size = sec0->flash_boot_size -
+						    sec0->flash_data_size;
+				} else {
+					boot_size = 0;
+				}
+
+				int sectors = sec0->boot_code1_offset +
+					      sec0->flash_data_size +
+					      boot_size;
+
+				plat->idblock[plat->blk_counter].blk = blk;
+				plat->idblock[plat->blk_counter].ecc =
+					plat->cfg->ecc_strengths[bch_counter];
+				plat->idblock[plat->blk_counter].sectors = sectors;
+
+				debug("\nblk     : %d\n", plat->idblock[plat->blk_counter].blk);
+				debug("ecc     : %d\n", plat->idblock[plat->blk_counter].ecc);
+				debug("sectors : %d\n", plat->idblock[plat->blk_counter].sectors);
+
+				plat->blk_counter += 1;
+
+				if (plat->blk_counter >= ARRAY_SIZE(plat->idblock))
+					return;
+				break;
+			}
+		}
+	}
+}
+
+void rk_idb_read_block(struct rk_idb *plat, u32 idb, u32 sectors, u32 *data, u32 *spare)
+{
+	int page = plat->idblock[idb].blk * plat->pages_per_blk;
+	int j;
+
+	rk_idb_hw_ecc_setup(plat, plat->idblock[idb].ecc);
+
+	for (j = 0; j < sectors / 4; j++) {
+		rk_idb_read_page(plat, page + plat->page_table[j],
+				 (u8 *)data + j * 512 * 4, (u8 *)spare, 4);
+	}
+}
+
+void rk_idb_write_block(struct rk_idb *plat, u32 idb, u32 sectors, u32 *data, u32 *spare)
+{
+	int page = plat->idblock[idb].blk * plat->pages_per_blk;
+	int j;
+
+	plat->idblock[idb].sectors = sectors;
+
+	rk_idb_hw_ecc_setup(plat, plat->idblock[idb].ecc);
+	rk_idb_erase_op(plat, page);
+	rk_idb_wait_dev_ready(plat);
+
+	for (j = 0; j < sectors / 4; j++) {
+		spare[0] = (plat->page_table[j + 1] - 1) * 4;
+		spare[1] = 0xFFFFFFFF;
+		rk_idb_write_page(plat, page + plat->page_table[j],
+				  (u8 *)data + j * 512 * 4, (u8 *)spare, 4);
+	}
+
+	for (j = 0; j < sectors / 4; j++) {
+		rk_idb_read_page(plat, page + plat->page_table[j],
+				 (u8 *)plat->check + j * 512 * 4, (u8 *)spare, 4);
+	}
+
+	for (j = 0; j < (sectors * 512); j++) {
+		int w = *((u8 *)data + j);
+		int r = *((u8 *)plat->check + j);
+
+		if (r != w) {
+			debug("write and check error:%d r=%x w=%x\n", j, r, w);
+
+			memset((u8 *)plat->check, 0, 4 * 512);
+			spare[0] = 0xFFFFFFFF;
+			spare[1] = 0xFFFFFFFF;
+			rk_idb_write_page(plat, page, (u8 *)plat->check, (u8 *)spare, 4);
+
+			plat->idblock[idb].sectors = 0;
+			break;
+		}
+	}
+}
+
+void rk_idb_block_align(struct rk_idb *plat, u32 pages_per_blk)
+{
+	plat->pages_per_blk = pages_per_blk;
+	if (pages_per_blk > 512)
+		plat->pages_per_blk = 1024;
+	else if (pages_per_blk > 256)
+		plat->pages_per_blk = 512;
+	else if (pages_per_blk > 128)
+		plat->pages_per_blk = 256;
+}
+
+int rk_idb_init_plat(struct udevice *dev)
+{
+	struct rk_idb *plat = dev_get_plat(dev);
+
+	plat->idb = malloc_cache_aligned(512 * 512);
+
+	if (!plat->idb) {
+		debug("idb malloc failed\n");
+		return -1;
+	}
+
+	plat->check = malloc_cache_aligned(512 * 512);
+
+	if (!plat->check) {
+		debug("check malloc failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int rk_idb_probe(struct udevice *dev)
+{
+	struct rk_idb *plat = dev_get_plat(dev);
+	const char *node_name;
+	ofnode subnode;
+	u8 id[8];
+	int ret;
+	int i;
+
+	plat->cfg = (void *)dev_get_driver_data(dev);
+
+	plat->regs = (void *)dev_read_addr(dev);
+
+	ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
+		node_name = ofnode_get_name(subnode);
+
+		if (ofnode_read_bool(subnode, "nand-is-boot-medium"))
+			break;
+	}
+
+	if (!ofnode_valid(subnode))
+		return -ENODEV;
+
+	plat->boot_blks = ofnode_read_u32_default(subnode, "rockchip,boot-blks",
+						  DEFAULT_BLKS);
+	plat->boot_ecc = ofnode_read_u32_default(subnode, "rockchip,boot-ecc-strength",
+						 DEFAULT_STRENGTH);
+
+	ret = clk_get_by_index(dev, 0, &plat->ahb_clk);
+	if (ret < 0) {
+		debug("no ahb clk\n");
+		return -ENODEV;
+	}
+
+	ret = clk_prepare_enable(&plat->ahb_clk);
+	if (ret) {
+		debug("failed to enable ahb clk\n");
+		return -ENODEV;
+	}
+
+	ret = clk_get_by_index(dev, 1, &plat->nfc_clk);
+	if (ret < 0) {
+		debug("no nfc clk\n");
+		/* Some earlier models, such as rk3066, have no nfc clk. */
+	} else {
+		ret = clk_prepare_enable(&plat->nfc_clk);
+		if (ret) {
+			debug("failed to enable nfc clk\n");
+			clk_disable_unprepare(&plat->ahb_clk);
+			return -ENODEV;
+		}
+	}
+
+	rk_idb_init(plat);
+
+	rk_idb_select_chip(plat, 0);
+
+	rk_idb_read_id(plat, id, 8);
+
+	int size = ARRAY_SIZE(nand_para_tbl);
+
+	for (i = 0; i < size; i++) {
+		plat->info = (struct nand_para_info *)&nand_para_tbl[i];
+		if (plat->info->nand_id[0] == id[0] &&
+		    plat->info->nand_id[1] == id[1] &&
+		    plat->info->nand_id[2] == id[2] &&
+		    plat->info->nand_id[3] == id[3] &&
+		    plat->info->nand_id[4] == id[4] &&
+		    plat->info->nand_id[5] == id[5])
+			break;
+	}
+
+	if (i == size) {
+		debug("no nand_para_info found\n");
+		return -ENODEV;
+	}
+
+	rk_idb_block_align(plat, plat->info->page_per_blk);
+
+	rk_idb_build_page_table(plat, plat->info->lsb_mode);
+
+	ret = rk_idb_init_plat(dev);
+	if (ret) {
+		debug("rk_idb_init_plat failed\n");
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static struct nfc_cfg nfc_v6_cfg = {
+	.type			= NFC_V6,
+	.ecc_strengths		= {60, 40, 24, 16},
+	.ecc_cfgs		= {
+		0x00040011, 0x00040001, 0x00000011, 0x00000001,
+	},
+	.flctl_off		= 0x08,
+	.bchctl_off		= 0x0C,
+	.dma_cfg_off		= 0x10,
+	.dma_data_buf_off	= 0x14,
+	.dma_oob_buf_off	= 0x18,
+	.dma_st_off		= 0x1C,
+	.bch_st_off		= 0x20,
+	.randmz_off		= 0x150,
+	.int_en_off		= 0x16C,
+	.int_clr_off		= 0x170,
+	.int_st_off		= 0x174,
+	.oob0_off		= 0x200,
+	.oob1_off		= 0x230,
+	.ecc0			= {
+		.err_flag_bit	= 2,
+		.low		= 3,
+		.low_mask	= 0x1F,
+		.low_bn		= 5,
+		.high		= 27,
+		.high_mask	= 0x1,
+	},
+	.ecc1			= {
+		.err_flag_bit	= 15,
+		.low		= 16,
+		.low_mask	= 0x1F,
+		.low_bn		= 5,
+		.high		= 29,
+		.high_mask	= 0x1,
+	},
+};
+
+static struct nfc_cfg nfc_v8_cfg = {
+	.type			= NFC_V8,
+	.ecc_strengths		= {16, 16, 16, 16},
+	.ecc_cfgs		= {
+		0x00000001, 0x00000001, 0x00000001, 0x00000001,
+	},
+	.flctl_off		= 0x08,
+	.bchctl_off		= 0x0C,
+	.dma_cfg_off		= 0x10,
+	.dma_data_buf_off	= 0x14,
+	.dma_oob_buf_off	= 0x18,
+	.dma_st_off		= 0x1C,
+	.bch_st_off		= 0x20,
+	.randmz_off		= 0x150,
+	.int_en_off		= 0x16C,
+	.int_clr_off		= 0x170,
+	.int_st_off		= 0x174,
+	.oob0_off		= 0x200,
+	.oob1_off		= 0x230,
+	.ecc0			= {
+		.err_flag_bit	= 2,
+		.low		= 3,
+		.low_mask	= 0x1F,
+		.low_bn		= 5,
+		.high		= 27,
+		.high_mask	= 0x1,
+	},
+	.ecc1			= {
+		.err_flag_bit	= 15,
+		.low		= 16,
+		.low_mask	= 0x1F,
+		.low_bn		= 5,
+		.high		= 29,
+		.high_mask	= 0x1,
+	},
+};
+
+static struct nfc_cfg nfc_v9_cfg = {
+	.type			= NFC_V9,
+	.ecc_strengths		= {70, 60, 40, 16},
+	.ecc_cfgs		= {
+		0x00000001, 0x06000001, 0x04000001, 0x02000001,
+	},
+	.flctl_off		= 0x10,
+	.bchctl_off		= 0x20,
+	.dma_cfg_off		= 0x30,
+	.dma_data_buf_off	= 0x34,
+	.dma_oob_buf_off	= 0x38,
+	.dma_st_off		= 0x3C,
+	.bch_st_off		= 0x150,
+	.randmz_off		= 0x208,
+	.int_en_off		= 0x120,
+	.int_clr_off		= 0x124,
+	.int_st_off		= 0x128,
+	.oob0_off		= 0x200,
+	.oob1_off		= 0x204,
+	.ecc0			= {
+		.err_flag_bit	= 2,
+		.low		= 3,
+		.low_mask	= 0x7F,
+		.low_bn		= 7,
+		.high		= 0,
+		.high_mask	= 0x0,
+	},
+	.ecc1			= {
+		.err_flag_bit	= 18,
+		.low		= 19,
+		.low_mask	= 0x7F,
+		.low_bn		= 7,
+		.high		= 0,
+		.high_mask	= 0x0,
+	},
+};
+
+static const struct udevice_id rk_idb_ids[] = {
+	{
+		.compatible = "rockchip,px30-nfc",
+		.data = (unsigned long)&nfc_v9_cfg
+	},
+	{
+		.compatible = "rockchip,rk2928-nfc",
+		.data = (unsigned long)&nfc_v6_cfg
+	},
+	{
+		.compatible = "rockchip,rv1108-nfc",
+		.data = (unsigned long)&nfc_v8_cfg
+	},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(rockchip_idb) = {
+	.name		= "rockchip_idb",
+	.id		= UCLASS_RK_IDB,
+	.of_match	= rk_idb_ids,
+	.probe		= rk_idb_probe,
+	.plat_auto	= sizeof(struct rk_idb),
+};
-- 
2.20.1




More information about the Linux-rockchip mailing list