diff mbox series

[v1,1/6] rockchip: block: add Rockchip IDB block device

Message ID 1816d342-1bd1-ff1e-efe6-af4595850946@gmail.com (mailing list archive)
State New, archived
Headers show
Series Add Rockchip IDB device | expand

Commit Message

Johan Jonker July 5, 2022, 1:04 p.m. UTC
From: Johan Jonker <jbx6244@gmail.com>

The Rockchip SoCs with a NAND as boot device need
a special Rockchip IDB block device to transfer the data
from the rockusb gadget to the NAND driver.

Signed-off-by: Johan Jonker <jbx6244@gmail.com>
---
 arch/arm/mach-rockchip/Kconfig        |   12 +
 arch/arm/mach-rockchip/Makefile       |    1 +
 arch/arm/mach-rockchip/rockchip_idb.c | 1694 +++++++++++++++++++++++++
 drivers/block/blk-uclass.c            |    2 +
 include/blk.h                         |    1 +
 include/dm/uclass-id.h                |    1 +
 include/efi_loader.h                  |    4 +
 lib/efi_loader/efi_device_path.c      |   30 +
 8 files changed, 1745 insertions(+)
 create mode 100644 arch/arm/mach-rockchip/rockchip_idb.c

Comments

Xavier Drudis Ferran July 5, 2022, 2:17 p.m. UTC | #1
Thanks for your work. 

El Tue, Jul 05, 2022 at 03:04:15PM +0200, Johan Jonker deia:
> From: Johan Jonker <jbx6244@gmail.com>
> 
> The Rockchip SoCs with a NAND as boot device need
> a special Rockchip IDB block device to transfer the data
> from the rockusb gadget to the NAND driver.
>

Sorry for the fast browsing, lack of experience and possibly wrong and
noisy comment (I'm no U-Boot expert), but if you have patience for my
curiosity... This isn't a review, I haven't read it all, just some
small parts.

> diff --git a/arch/arm/mach-rockchip/rockchip_idb.c b/arch/arm/mach-rockchip/rockchip_idb.c
> new file mode 100644
> index 00000000..6243131d
> --- /dev/null
> +++ b/arch/arm/mach-rockchip/rockchip_idb.c
[...]
> +struct NandParaInfo {
> +	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];
> +};
> +

Is part of this info already represented in 
nand_flash_dev in include/linux/mtd/rawnand.h ?

And is it worth merging somehow ? Or should 
this be synced to something external and the 
.h file I mentioned be synced to linux, so merging
would be more trouble than it is worth ? 

> +
> +u16 random_seed[] = {
> +	0x576a, 0x05e8, 0x629d, 0x45a3,
> +	0x649c, 0x4bf0, 0x2342, 0x272e,
> +	0x7358, 0x4ff3, 0x73ec, 0x5f70,
[...]
> +	0x3b2e, 0x7ec7, 0x4fd2, 0x5d28,
> +	0x751f, 0x3ef8, 0x39b1, 0x4e49,
> +	0x746b, 0x6ef6, 0x44be, 0x6db7,
> +};

Where does this come from ? Is it copyrightable ? If so, is it
licensed ?  fair use ? Does it need to be synced every so often with
some external source ?

> +
> +struct NandParaInfo NandFlashParaTbl[] = {
> +	{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}},
[...]
> +	{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, {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}},
> +};
> +

Is this info partially duplicated in drivers/mtd/nand/raw/nand_ids.c ?
Should it be merged and this added there somehow ?  It seems to have
more data, but I don't know if some items are deductible from others.
Could some constants be used to make it easier to read ?
Johan Jonker July 6, 2022, 9:09 p.m. UTC | #2
Hi Xavier,

Thank you for your comments.

This driver in it's current form does not seek to comply with the MTD frame work.

Goal is to write boot blocks to NAND the Rockchip way in a memory limited environment (usbplug) and to get rid of all the closed source tools !!

In this particular case with MTD nand_flash_ids of no use and no bch settings it does makes sense to load a whole frame work for only page_op's.


On 7/5/22 16:17, Xavier Drudis Ferran wrote:
> 
> Thanks for your work. 
> 
> El Tue, Jul 05, 2022 at 03:04:15PM +0200, Johan Jonker deia:
>> From: Johan Jonker <jbx6244@gmail.com>
>>
>> The Rockchip SoCs with a NAND as boot device need
>> a special Rockchip IDB block device to transfer the data
>> from the rockusb gadget to the NAND driver.
>>
> 
> Sorry for the fast browsing, lack of experience and possibly wrong and
> noisy comment (I'm no U-Boot expert), but if you have patience for my
> curiosity... This isn't a review, I haven't read it all, just some
> small parts.
> 
>> diff --git a/arch/arm/mach-rockchip/rockchip_idb.c b/arch/arm/mach-rockchip/rockchip_idb.c
>> new file mode 100644
>> index 00000000..6243131d
>> --- /dev/null
>> +++ b/arch/arm/mach-rockchip/rockchip_idb.c
> [...]
>> +struct NandParaInfo {
>> +	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];
>> +};
>> +
> 

> Is part of this info already represented in 
> nand_flash_dev in include/linux/mtd/rawnand.h ?

See answer below.

> 
> And is it worth merging somehow ?

> Or should 
> this be synced to something external and the 
> .h file I mentioned be synced to linux, so merging
> would be more trouble than it is worth ? 

This is a structure used by the manufacturer tools, ko modules and usbplugs. 
For now this is only used here. If more users appear a .h file might be better. 

> 
>> +
>> +u16 random_seed[] = {

Although Linux rockchip-nand-controller.c and U-boot rockchip_nfc.c don't have it,

on MK808 with "H27UCG8T2ATR-BC" it has a NAND_NEED_SCRAMBLING flag.
In order to read anything written by a Rockchip tools after/beyond the boot blocks.

Not sure how to enable/disable this? With a DT property? PLease advice!

rockchip,enable-randomizer ???
 

For writing boot blocks only it's not needed for now. 
Please advice on whether to keep or remove the randomizer? Thanks!


	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
		  NAND_ECC_INFO(40, SZ_1K)},


>> +	0x576a, 0x05e8, 0x629d, 0x45a3,
>> +	0x649c, 0x4bf0, 0x2342, 0x272e,
>> +	0x7358, 0x4ff3, 0x73ec, 0x5f70,
> [...]
>> +	0x3b2e, 0x7ec7, 0x4fd2, 0x5d28,
>> +	0x751f, 0x3ef8, 0x39b1, 0x4e49,
>> +	0x746b, 0x6ef6, 0x44be, 0x6db7,
>> +};
> 

> Where does this come from ? Is it copyrightable ? If so, is it
> licensed ?  fair use ? Does it need to be synced every so often with
> some external source ?

random_seed is a constant value for Rockchip only. See:

https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/rk_nand/rk_ftl_arm_v7.S#L25550
GPL-2.0+

> 
>> +
>> +struct NandParaInfo NandFlashParaTbl[] = {

https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/rk_nand/rk_ftl_arm_v7.S#L25936
GPL-2.0+

>> +	{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}},
> [...]
>> +	{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, {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}},
>> +};
>> +
> 

> Is this info partially duplicated in drivers/mtd/nand/raw/nand_ids.c ?
> Should it be merged and this added there somehow ?  It seems to have
> more data, but I don't know if some items are deductible from others.

Reasons not to use nand_ids.c:

1:
From the NandFlashParaTbl array only "4" NAND nand_flash_ids types are recognized.
That not enough given the support list from the manufacturer.

2:
struct nand_flash_dev nand_flash_ids[] contains insufficient data to decide what page pattern lsb_mode [0 to 12] should be used.
See test program below, there no relation between "pages per erase block", "sec_per_page" and lsb_mode.

3:
We can re-use/combine the source with a usbplug or RK NAND FTL driver.

4:
The MTD frame work does not have a mtd-abi.h ioctl to set different bch settings.
This driver must be "generic" and expect all possible options when scanning.

========================

int main(void)
{
	struct tagNandParaInfo *gpNandParaInfo;
	struct nand_flash_dev *type;
	uint8_t id[8];
	int i, j;

	int size = sizeof(NandFlashParaTbl)/sizeof(struct tagNandParaInfo);
	int size2 = sizeof(struct tagNandParaInfo);

	printf("NandFlashParaTbl size %d\n", size);
	printf("tagNandParaInfo  size %d\n", size2);

	for (i = 0; i < size; i++) {
		struct tagNandParaInfo *p = (struct tagNandParaInfo*)&NandFlashParaTbl[i];
		gpNandParaInfo = p;
		id[0] = p->nand_id[0];
		id[1] = p->nand_id[1];
		id[2] = p->nand_id[2];
		id[3] = p->nand_id[3];
		id[4] = p->nand_id[4];
		id[5] = p->nand_id[5];
		id[6] = 0;
		id[7] = 0;
		for (type = nand_flash_ids; type->name; type++)
			if (type->id_len) {
				if (!strncmp((char *)type->id, (char *)id, type->id_len))
					break;
			} else {
				if (type->dev_id == id[1])
					break;
			}

		if (!type->name || !type->pagesize) {
			//printf("\n----\n");
		} else {
			printf("\nNAND: %s\n", type->name);
			printf("FLASH ID:%02x %02x %02x %02x %02x %02x\n",p->nand_id[0],p->nand_id[1],p->nand_id[2],p->nand_id[3],p->nand_id[4],p->nand_id[5]);
		}
	}

	printf("\n----\n");

	char lsb_mode[] = {0,1,2,3,4,5,6,9};
	for (j = 0; j < sizeof(lsb_mode); j++) {
		printf("lsb_mode: %d:", lsb_mode[j]);
		for (i = 0; i < size; i++) {
			struct tagNandParaInfo *p = (struct tagNandParaInfo*)&NandFlashParaTbl[i];
			if (lsb_mode[j] == p->lsb_mode) {
				printf("%d ", p->page_per_blk);
			}
		}
		printf("\n");
	}

	return 0;
}
=================================

NAND: H27UBG8T2BTR-BC 32G 3.3V 8-bit
FLASH ID:ad d7 94 da 74 c3

NAND: H27UCG8T2ATR-BC 64G 3.3V 8-bit
FLASH ID:ad de 94 da 74 c4

NAND: H27QCG8T2E5R‐BCF 64G 3.3V 8-bit
FLASH ID:ad de 14 a7 42 4a

NAND: SDTNRGAMA 64G 3.3V 8-bit
FLASH ID:45 de 94 93 76 50

--page_per_blk--
lsb_mode: 0:128 64 64 
lsb_mode: 1:256 256 256 256 256 128 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 
lsb_mode: 2:256 256 256 256 256 256 256 256 128 128 256 256 128 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 128 128 128 128 128 128 
lsb_mode: 3:256 256 512 256 512 512 256 256 
lsb_mode: 4:512 512 512 512 512 
lsb_mode: 5:512 512 512 512 512 512 
lsb_mode: 6:
lsb_mode: 9:388

--sec_per_page--
lsb_mode: 0:16 8 8 
lsb_mode: 1:8 16 16 8 8 8 8 8 16 16 16 16 16 32 16 16 16 16 8 8 8 8 16 16 16 16 
lsb_mode: 2:32 16 32 32 32 32 32 32 16 16 32 32 16 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 16 16 16 16 16 16 
lsb_mode: 3:16 16 32 16 32 32 16 16 
lsb_mode: 4:32 24 32 32 32 
lsb_mode: 5:32 32 32 32 32 32 
lsb_mode: 6:
lsb_mode: 9:32 


===================================

The manufacturer tree gives us a little clue about the lsb_mode.

Is there an other way to obtain this then from NandFlashParaTbl?

Could someone from Rockchip or a maintainer give/disclose the relation between the lsb_mode and the page write pattern? Thanks!


https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/rkflash/flash.h#L74
GPL-2.0

/*  0 1 2 3 4 5 6 7 8 9 slc */
#define LSB_0	0
/*  0 1 2 3 6 7 A B E F hynix, micron 74A */
#define LSB_1	1
/*  0 1 3 5 7 9 B D toshiba samsung sandisk */
#define LSB_2	2
/*  0 1 2 3 4 5 8 9 C D 10 11 micron 84A */
#define LSB_3	3
/*  0 1 2 3 4 5 7 8 A B E F micron L95B */
#define LSB_4	4
/*  0 1 2 3 4 5 8 9 14 15 20 21 26 27 micron B74A TLC */
#define LSB_6	6
/*  0 3 6 9 C F 12 15 18 15 1B 1E 21 24 K9ABGD8U0C TLC */
#define LSB_7	7

> Could some constants be used to make it easier to read ?

For now this is most compact readable form that passes through ./scripts/checkpatch.pl --strict
Any macro would make this line even more longer.
Suggestions welcome of course.


Johan
diff mbox series

Patch

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..6243131d
--- /dev/null
+++ b/arch/arm/mach-rockchip/rockchip_idb.c
@@ -0,0 +1,1694 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Johan Jonker <jbx6244@gmail.com>
+ */
+
+#include <blk.h>
+#include <clk.h>
+#include <command.h>
+#include <dm.h>
+#include <memalign.h>
+#include <part.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <linux/iopoll.h>
+#include <u-boot/crc.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 BCD2INT(num)		(((((num) >> 12) & 0x0F) * 1000) + \
+				((((num) >> 8) & 0x0F) * 100) + \
+				((((num) >> 4) & 0x0F) * 10) + \
+				((num) & 0x0F))
+
+#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 fwSig;
+	u8  reserved[4];
+	u32 ucRc4Flag;
+	u16 usBootCode1Offset;
+	u16 usBootCode2Offset;
+	u8  reserved1[490];
+	u16 usFlashDataSize;
+	u16 ucFlashBootSize;
+	u8  reserved2[2];
+} __packed;
+
+struct sector1 {
+	u16 usSysReservedBlock;
+	u16 usDisk0Size;
+	u16 usDisk1Size;
+	u16 usDisk2Size;
+	u16 usDisk3Size;
+	u32 uiChipTag;
+	u32 uiMachineId;
+	u16 usLoaderYear;
+	u16 usLoaderDate;
+	u16 usLoaderVer;
+	u8  reserved[72];
+	u16 usFlashDataOffset;
+	u16 usFlashDataLen;
+	u8  reserved2[384];
+	u32 uiFlashChipSize;
+	u8  reserved1;
+	u8  bAccessTime;
+	u16 usPhyBlockSize;
+	u8  bPhyPageSize;
+	u8  bECCBits;
+	u8  reserved3[8];
+	u16 usIdBlock0;
+	u16 usIdBlock1;
+	u16 usIdBlock2;
+	u16 usIdBlock3;
+	u16 usIdBlock4;
+} __packed;
+
+struct NandParaInfo {
+	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 NandParaInfo *info;
+	u32 boot_blks;
+	u32 boot_ecc;
+	u32 pages_per_blk;
+	u32 randomizer;
+	struct idb idblock[5];
+	u32 blk_counter;
+	u32 idb_need_write_back;
+	u32 sectors;
+	u16 page_table[512];
+	legacy_mbr *mbr;
+	gpt_header *gpt_h;
+	gpt_header *gpt_h2;
+	gpt_entry *gpt_e;
+	char *check;
+	char *idb;
+	char *str;
+	char uuid_part_str[UUID_STR_LEN + 1];
+	char uuid_disk_str[UUID_STR_LEN + 1];
+};
+
+u16 random_seed[] = {
+	0x576a, 0x05e8, 0x629d, 0x45a3,
+	0x649c, 0x4bf0, 0x2342, 0x272e,
+	0x7358, 0x4ff3, 0x73ec, 0x5f70,
+	0x7a60, 0x1ad8, 0x3472, 0x3612,
+	0x224f, 0x0454, 0x030e, 0x70a5,
+	0x7809, 0x2521, 0x48f4, 0x5a2d,
+	0x492a, 0x043d, 0x7f61, 0x3969,
+	0x517a, 0x3b42, 0x769d, 0x0647,
+	0x7e2a, 0x1383, 0x49d9, 0x07b8,
+	0x2578, 0x4eec, 0x4423, 0x352f,
+	0x5b22, 0x72b9, 0x367b, 0x24b6,
+	0x7e8e, 0x2318, 0x6bd0, 0x5519,
+	0x1783, 0x18a7, 0x7b6e, 0x7602,
+	0x4b7f, 0x3648, 0x2c53, 0x6b99,
+	0x0c23, 0x67cf, 0x7e0e, 0x4d8c,
+	0x5079, 0x209d, 0x244a, 0x747b,
+	0x350b, 0x0e4d, 0x7004, 0x6ac3,
+	0x7f3e, 0x21f5, 0x7a15, 0x2379,
+	0x1517, 0x1aba, 0x4e77, 0x15a1,
+	0x04fa, 0x2d61, 0x253a, 0x1302,
+	0x1f63, 0x5ab3, 0x049a, 0x5ae8,
+	0x1cd7, 0x4a00, 0x30c8, 0x3247,
+	0x729c, 0x5034, 0x2b0e, 0x57f2,
+	0x00e4, 0x575b, 0x6192, 0x38f8,
+	0x2f6a, 0x0c14, 0x45fc, 0x41df,
+	0x38da, 0x7ae1, 0x7322, 0x62df,
+	0x5e39, 0x0e64, 0x6d85, 0x5951,
+	0x5937, 0x6281, 0x33a1, 0x6a32,
+	0x3a5a, 0x2bac, 0x743a, 0x5e74,
+	0x3b2e, 0x7ec7, 0x4fd2, 0x5d28,
+	0x751f, 0x3ef8, 0x39b1, 0x4e49,
+	0x746b, 0x6ef6, 0x44be, 0x6db7,
+};
+
+struct NandParaInfo NandFlashParaTbl[] = {
+	{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_P_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);
+
+	u32 seed = random_seed[page & 0x7F];
+
+	if (plat->randomizer) {
+		if (!(page < plat->pages_per_blk * plat->boot_blks))
+			seed |= 0xC0000000;
+	}
+
+	writel(seed, regs + plat->cfg->randmz_off);
+}
+
+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);
+
+	u32 seed = random_seed[page & 0x7F];
+
+	if (plat->randomizer) {
+		if (!(page < plat->pages_per_blk * plat->boot_blks))
+			seed |= 0xC0000000;
+	}
+
+	writel(seed, regs + plat->cfg->randmz_off);
+}
+
+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_P_RC4((char *)data, 512);
+
+				struct sector0 *sec0 = (struct sector0 *)data;
+
+				if ((sec0->ucFlashBootSize -
+				     sec0->usFlashDataSize) != 1024) {
+					boot_size = sec0->ucFlashBootSize -
+						    sec0->usFlashDataSize;
+				} else {
+					boot_size = 0;
+				}
+
+				int sectors = sec0->usBootCode1Offset +
+					      sec0->usFlashDataSize +
+					      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;
+		}
+	}
+}
+
+unsigned long rk_idb_read(struct udevice *dev,
+			  unsigned long start, lbaint_t blkcnt,
+			  void *buffer)
+{
+	struct rk_idb *plat = dev_get_plat(dev->parent);
+	struct blk_desc *block_dev = dev_get_uclass_plat(dev);
+	char *buf = buffer;
+	int i;
+
+	debug("start   : %lu blkcnt: %lu\n", start, blkcnt);
+
+	if (start > (block_dev->lba - 1) || (start + blkcnt) > block_dev->lba) {
+		debug("invalid block\n");
+		return -1;
+	}
+
+	memset(buffer, 0xff, blkcnt * block_dev->blksz);
+
+	for (i = start; i < (start + blkcnt); i++) {
+		if (i == 0)  {
+			debug("mbr     : %d\n", i);
+
+			memcpy(&buf[(i - start) * block_dev->blksz],
+			       plat->mbr, sizeof(legacy_mbr));
+		} else if (i == 1) {
+			debug("gpt_h   : %d\n", i);
+
+			memcpy(&buf[(i - start) * block_dev->blksz],
+			       plat->gpt_h, sizeof(gpt_header));
+		} else if (i == (block_dev->lba - 1)) {
+			debug("gpt_h2  : %d\n", i);
+
+			memcpy(&buf[(i - start) * block_dev->blksz],
+			       plat->gpt_h2, sizeof(gpt_header));
+		} else if (i == 2 || i == (block_dev->lba - 33)) {
+			debug("gpt_e   : %d\n", i);
+
+			memcpy(&buf[(i - start) * block_dev->blksz],
+			       plat->gpt_e, sizeof(gpt_entry));
+		} else if (i >= 64 && i < (block_dev->lba - 33)) {
+			debug("idb rd  : %d\n", i);
+
+			memcpy(&buf[(i - start) * block_dev->blksz],
+			       &plat->idb[(i - 64) * block_dev->blksz], block_dev->blksz);
+		}
+	}
+
+	return blkcnt;
+}
+
+unsigned long rk_idb_write(struct udevice *dev,
+			   unsigned long start, lbaint_t blkcnt,
+			   const void *buffer)
+{
+	struct rk_idb *plat = dev_get_plat(dev->parent);
+	struct blk_desc *block_dev = dev_get_uclass_plat(dev);
+	u32 data[512];
+	u32 spare[2];
+	int i, j;
+
+	if (start > (block_dev->lba - 1) || (start + blkcnt) > block_dev->lba) {
+		debug("invalid block\n");
+		return -1;
+	}
+
+	debug("start   : %lu blkcnt: %lu\n", start, blkcnt);
+
+	for (i = start; i < (start + blkcnt); i++) {
+		debug("idb wr  : %d\n", i);
+
+		if (i >= 64 && i < (block_dev->lba - 33)) {
+			if (i == 64) {
+				debug("first block\n");
+
+				plat->idb_need_write_back = 1;
+				memset(plat->idb, 0xff, 512 * 512);
+			}
+
+			if (plat->idb_need_write_back) {
+				char *buf = (char *)buffer;
+
+				memcpy(&plat->idb[(i - 64) * block_dev->blksz],
+				       &buf[(i - start) * block_dev->blksz],
+				       block_dev->blksz);
+
+				if (i == 64) {
+					memcpy(data, plat->idb, 512);
+
+					if (*data == RK_MAGIC) {
+						u32 boot_size;
+
+						rk_idb_P_RC4((char *)data, 512);
+
+						struct sector0 *sec0 = (struct sector0 *)data;
+
+						if ((sec0->ucFlashBootSize -
+						     sec0->usFlashDataSize) != 1024) {
+							boot_size = sec0->ucFlashBootSize -
+								    sec0->usFlashDataSize;
+						} else {
+							boot_size = 0;
+						}
+
+						plat->sectors = sec0->usBootCode1Offset +
+								sec0->usFlashDataSize +
+								boot_size;
+
+						if (plat->sectors > 512) {
+							debug("max sector limit\n");
+							plat->idb_need_write_back = 0;
+						}
+					} else {
+						debug("no IDB block found\n");
+						plat->idb_need_write_back = 0;
+					}
+				}
+
+				if (i == (64 + plat->sectors - 1)) {
+					debug("last block\n");
+
+					plat->idb_need_write_back = 0;
+
+					if (!plat->blk_counter) {
+						plat->idblock[0].blk = 2;
+						plat->idblock[0].ecc = plat->boot_ecc;
+						plat->idblock[1].blk = 3;
+						plat->idblock[1].ecc = plat->boot_ecc;
+						plat->idblock[2].blk = 4;
+						plat->idblock[2].ecc = plat->boot_ecc;
+						plat->idblock[3].blk = 5;
+						plat->idblock[3].ecc = plat->boot_ecc;
+						plat->idblock[4].blk = 6;
+						plat->idblock[4].ecc = plat->boot_ecc;
+						plat->blk_counter = 5;
+					}
+
+					for (j = 0; j < plat->blk_counter; j++) {
+						if (plat->idblock[j].blk < plat->boot_blks)
+							rk_idb_write_block(plat, j, plat->sectors,
+									   (u32 *)plat->idb, spare);
+					}
+
+					rk_idb_scan_block(plat, data, spare);
+
+					memset(plat->idb, 0xff, 512 * 512);
+
+					if (plat->blk_counter)
+						rk_idb_read_block(plat, 0, plat->idblock[0].sectors,
+								  (u32 *)plat->idb, spare);
+				}
+			}
+		} else if (plat->idb_need_write_back) {
+			plat->idb_need_write_back = 0;
+
+			memset(plat->idb, 0xff, 512 * 512);
+
+			if (plat->blk_counter)
+				rk_idb_read_block(plat, 0, plat->idblock[0].sectors,
+						  (u32 *)plat->idb, spare);
+		}
+	}
+
+	return blkcnt;
+}
+
+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;
+}
+
+static inline u32 efi_crc32(const void *buf, u32 len)
+{
+	return crc32(0, buf, len);
+}
+
+int rk_idb_init_plat(struct udevice *dev)
+{
+	static const efi_guid_t partition_basic_data_guid = PARTITION_BASIC_DATA_GUID;
+	struct rk_idb *plat = dev_get_plat(dev);
+	size_t efiname_len, dosname_len;
+	uchar name[] = "loader1";
+	u32 calc_crc32;
+	int k;
+
+	gen_rand_uuid_str(plat->uuid_disk_str, UUID_STR_FORMAT_GUID);
+	gen_rand_uuid_str(plat->uuid_part_str, UUID_STR_FORMAT_GUID);
+
+	debug("uuid_part_str          : %s\n", plat->uuid_part_str);
+	debug("uuid_disk_str          : %s\n", plat->uuid_disk_str);
+
+	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;
+	}
+
+	plat->mbr = malloc_cache_aligned(sizeof(legacy_mbr));
+
+	if (!plat->mbr) {
+		debug("mbr malloc failed\n");
+		free(plat->idb);
+		free(plat->check);
+		return -1;
+	}
+
+	plat->gpt_e = malloc_cache_aligned(sizeof(gpt_entry));
+
+	if (!plat->gpt_e) {
+		debug("gpt_e malloc failed\n");
+		free(plat->idb);
+		free(plat->check);
+		free(plat->mbr);
+		return -1;
+	}
+
+	plat->gpt_h = malloc_cache_aligned(sizeof(gpt_header));
+
+	if (!plat->gpt_h) {
+		debug("gpt_h malloc failed\n");
+		free(plat->idb);
+		free(plat->check);
+		free(plat->mbr);
+		free(plat->gpt_e);
+		return -1;
+	}
+
+	plat->gpt_h2 = malloc_cache_aligned(sizeof(gpt_header));
+
+	if (!plat->gpt_h2) {
+		debug("gpt_h2 malloc failed\n");
+		free(plat->idb);
+		free(plat->check);
+		free(plat->mbr);
+		free(plat->gpt_e);
+		free(plat->gpt_h);
+		return -1;
+	}
+
+	/* Init idb */
+	memset(plat->idb, 0xff, 512 * 512);
+
+	/* Init mbr */
+	memset((char *)plat->mbr, 0, sizeof(legacy_mbr));
+
+	plat->mbr->signature = MSDOS_MBR_SIGNATURE;
+	plat->mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+	plat->mbr->partition_record[0].start_sect = 1;
+	plat->mbr->partition_record[0].nr_sects = LBA - 1;
+
+	/* Init gpt_e */
+	memset(plat->gpt_e, 0, sizeof(gpt_entry));
+
+	plat->gpt_e->starting_lba = cpu_to_le64(64);
+	plat->gpt_e->ending_lba = cpu_to_le64(LBA - 34);
+
+	debug("starting_lba           : %llu\n", le64_to_cpu(plat->gpt_e->starting_lba));
+	debug("ending_lba             : %llu\n", le64_to_cpu(plat->gpt_e->ending_lba));
+
+	memcpy(plat->gpt_e->partition_type_guid.b, &partition_basic_data_guid, 16);
+
+	uuid_str_to_bin(plat->uuid_part_str, plat->gpt_e->unique_partition_guid.b,
+			UUID_STR_FORMAT_GUID);
+
+	efiname_len = sizeof(plat->gpt_e->partition_name) / sizeof(efi_char16_t);
+	dosname_len = sizeof(name);
+
+	for (k = 0; k < min(dosname_len, efiname_len); k++)
+		plat->gpt_e->partition_name[k] = (efi_char16_t)(name[k]);
+
+	/* Init gpt_h */
+	memset(plat->gpt_h, 0, sizeof(gpt_header));
+
+	plat->gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE_UBOOT);
+	plat->gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
+	plat->gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
+	plat->gpt_h->first_usable_lba = cpu_to_le64(64);
+	plat->gpt_h->last_usable_lba = cpu_to_le64(LBA - 34);
+	plat->gpt_h->num_partition_entries = cpu_to_le32(1);
+	plat->gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
+
+	uuid_str_to_bin(plat->uuid_disk_str, plat->gpt_h->disk_guid.b,
+			UUID_STR_FORMAT_GUID);
+
+	plat->gpt_h->partition_entry_array_crc32 = 0;
+	calc_crc32 = efi_crc32((const unsigned char *)plat->gpt_e,
+			       le32_to_cpu(plat->gpt_h->num_partition_entries) *
+			       le32_to_cpu(plat->gpt_h->sizeof_partition_entry));
+	plat->gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);
+
+	debug("partition crc32        : 0x%08x\n", calc_crc32);
+
+	plat->gpt_h->my_lba = cpu_to_le64(1);
+	plat->gpt_h->partition_entry_lba = cpu_to_le64(2);
+	plat->gpt_h->alternate_lba = cpu_to_le64(LBA - 1);
+
+	plat->gpt_h->header_crc32 = 0;
+	calc_crc32 = efi_crc32((const unsigned char *)plat->gpt_h,
+			       le32_to_cpu(plat->gpt_h->header_size));
+	plat->gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+	debug("header h1 crc32        : 0x%08x\n", calc_crc32);
+
+	/* Init gpt_h2 */
+	memcpy(plat->gpt_h2, plat->gpt_h, sizeof(gpt_header));
+
+	plat->gpt_h2->my_lba = cpu_to_le64(LBA - 1);
+	plat->gpt_h2->partition_entry_lba =
+		cpu_to_le64(le64_to_cpu(plat->gpt_h2->last_usable_lba) + 1);
+	plat->gpt_h2->alternate_lba = cpu_to_le64(1);
+
+	plat->gpt_h2->header_crc32 = 0;
+	calc_crc32 = efi_crc32((const unsigned char *)plat->gpt_h2,
+			       le32_to_cpu(plat->gpt_h2->header_size));
+	plat->gpt_h2->header_crc32 = cpu_to_le32(calc_crc32);
+
+	debug("header h2 crc32        : 0x%08x\n", calc_crc32);
+
+	return 0;
+}
+
+int rk_idb_probe(struct udevice *dev)
+{
+	struct rk_idb *plat = dev_get_plat(dev);
+	const char *node_name;
+	ofnode subnode;
+	u32 data[512];
+	u32 spare[2];
+	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(NandFlashParaTbl);
+
+	for (i = 0; i < size; i++) {
+		plat->info = (struct NandParaInfo *)&NandFlashParaTbl[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 NandParaInfo found\n");
+		return -ENODEV;
+	}
+
+	plat->randomizer = (plat->info->operation_opt >> 7) & 1;
+
+	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;
+	}
+
+	rk_idb_scan_block(plat, data, spare);
+
+	if (plat->blk_counter)
+		rk_idb_read_block(plat, 0, plat->idblock[0].sectors, (u32 *)plat->idb, spare);
+
+	return 0;
+}
+
+static int rk_idb_blk_probe(struct udevice *udev)
+{
+	struct blk_desc *desc = dev_get_uclass_plat(udev);
+
+	desc->removable = true;
+	snprintf(desc->vendor, BLK_VEN_SIZE, "Rockchip");
+	snprintf(desc->product, BLK_PRD_SIZE, "IDB");
+	snprintf(desc->revision, BLK_REV_SIZE, "1.0");
+
+	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 */ }
+};
+
+static const struct blk_ops rk_idb_ops = {
+	.read	= rk_idb_read,
+	.write	= rk_idb_write,
+};
+
+U_BOOT_DRIVER(idb_blk) = {
+	.name		= "idb_blk",
+	.id		= UCLASS_BLK,
+	.ops		= &rk_idb_ops,
+	.probe		= rk_idb_blk_probe,
+};
+
+UCLASS_DRIVER(idb) = {
+	.id		= UCLASS_RK_IDB,
+	.name		= "idb",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+};
+
+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),
+};
+
+int rk_idb_start(void)
+{
+	struct udevice *dev;
+	struct udevice *bdev;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_RK_IDB, 0, &dev);
+	if (ret) {
+		printf("no IDB device found\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = blk_get_device(IF_TYPE_RK_IDB, 0, &bdev);
+	if (ret) {
+		ret = blk_create_device(dev, "idb_blk", "blk",
+					IF_TYPE_RK_IDB, 0, 512,
+					LBA, &bdev);
+		if (ret)
+			return ret;
+
+		ret = blk_probe_or_unbind(bdev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+
+int rk_idb_stop(void)
+{
+	struct udevice *bdev;
+	int ret;
+
+	ret = blk_find_device(IF_TYPE_RK_IDB, 0, &bdev);
+	if (ret) {
+		printf("no IDB blk device found\n");
+		return 0;
+	}
+
+	device_remove(bdev, DM_REMOVE_NORMAL);
+	device_unbind(bdev);
+
+	return 0;
+}
+
+void rk_idb_print_idb_data(u32 *data)
+{
+	struct sector1 *sec1 = (struct sector1 *)((u8 *)data + 512);
+	struct sector0 *sec0 = (struct sector0 *)data;
+
+	printf("\n");
+
+	printf("DATE    : %d-%d-%d\n",
+	       BCD2INT(sec1->usLoaderYear),
+	       BCD2INT(sec1->usLoaderDate >> 8),
+	       BCD2INT(sec1->usLoaderDate & 0xff));
+
+	printf("VERSION : %d.%d\n",
+	       BCD2INT(sec1->usLoaderVer >> 8),
+	       BCD2INT(sec1->usLoaderVer & 0xff));
+
+	printf("\n");
+
+	printf("fwSig            : %08x\n"
+	       "ucRc4Flag        : %08x\n"
+	       "usBootCode1Offset: %d\n"
+	       "usFlashDataSize  : %d\n"
+	       "ucFlashBootSize  : %d\n",
+	       sec0->fwSig,
+	       sec0->ucRc4Flag,
+	       sec0->usBootCode1Offset,
+	       sec0->usFlashDataSize,
+	       sec0->ucFlashBootSize);
+
+	printf("\n");
+}
+
+static int rk_idb_info(void)
+{
+	struct rk_idb *plat;
+	struct udevice *dev;
+	u32 data[512];
+	u32 spare[2];
+	int ret;
+	int i, j;
+
+	ret = uclass_find_device(UCLASS_RK_IDB, 0, &dev);
+	if (ret) {
+		printf("no IDB device found\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (!device_active(dev)) {
+		printf("IDB device present but not probed\n");
+		return CMD_RET_FAILURE;
+	}
+
+	plat = dev_get_plat(dev);
+
+	printf("\n##### HARDWARE #####\n");
+
+	printf("REG              : 0x%08x\n", (u32)plat->regs);
+
+	printf("FLASH ID         : %02x %02x %02x %02x %02x %02x\n",
+	       plat->info->nand_id[0],
+	       plat->info->nand_id[1],
+	       plat->info->nand_id[2],
+	       plat->info->nand_id[3],
+	       plat->info->nand_id[4],
+	       plat->info->nand_id[5]);
+
+	printf("page_per_blk     : %d\n", plat->info->page_per_blk);
+	printf("lsb_mode         : %d\n", plat->info->lsb_mode);
+	printf("randomizer       : %d\n", (plat->info->operation_opt >> 7) & 1);
+
+	printf("\n##### BLOCK DEVICE #####\n");
+
+	ret = blk_find_device(IF_TYPE_RK_IDB, 0, &dev);
+	if (ret) {
+		printf("no IDB blk device found\n");
+	} else {
+		struct blk_desc *blk_dev = dev_get_uclass_plat(dev);
+
+		printf("blocks           : %lu\n", (unsigned long)blk_dev->lba);
+	}
+
+	printf("uuid_part_str    : %s\n", plat->uuid_part_str);
+	printf("uuid_disk_str    : %s\n", plat->uuid_disk_str);
+
+	printf("\n##### IDB #####\n");
+	for (i = 0; i < plat->blk_counter; i++) {
+		rk_idb_read_block(plat, j, 4, data, spare);
+
+		for (j = 0; j < 4; j++) {
+			if (j != 1)
+				rk_idb_P_RC4((char *)data + j * 512, 512);
+		}
+
+		printf("\nblk     : %d\n", plat->idblock[i].blk);
+		printf("ecc     : %d\n", plat->idblock[i].ecc);
+		printf("sectors : %d\n", plat->idblock[i].sectors);
+
+		rk_idb_print_idb_data(data);
+	}
+
+	return 0;
+}
+
+static int rk_idb_do(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[])
+{
+	if (argc == 2) {
+		if (!strcmp(argv[1], "info"))
+			return rk_idb_info();
+
+		if (!strcmp(argv[1], "stop"))
+			return rk_idb_stop();
+
+		if (!strcmp(argv[1], "start"))
+			return rk_idb_start();
+	}
+
+	return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+	idb, 5, 1, rk_idb_do,
+	"Rockchip IDB block device",
+	"start - start IDB device\n"
+	"idb stop  - stop IDB blk device\n"
+	"idb info  - show IDB device info\n"
+);
+
+#endif
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 21c5209b..0b5f219d 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -32,6 +32,7 @@  static const char *if_typename_str[IF_TYPE_COUNT] = {
 	[IF_TYPE_EFI_LOADER]	= "efiloader",
 	[IF_TYPE_VIRTIO]	= "virtio",
 	[IF_TYPE_PVBLOCK]	= "pvblock",
+	[IF_TYPE_RK_IDB]	= "idb",
 };
 
 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
@@ -49,6 +50,7 @@  static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
 	[IF_TYPE_EFI_LOADER]	= UCLASS_EFI_LOADER,
 	[IF_TYPE_VIRTIO]	= UCLASS_VIRTIO,
 	[IF_TYPE_PVBLOCK]	= UCLASS_PVBLOCK,
+	[IF_TYPE_RK_IDB]	= UCLASS_RK_IDB,
 };
 
 static enum if_type if_typename_to_iftype(const char *if_typename)
diff --git a/include/blk.h b/include/blk.h
index 9503369d..a73cc577 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -38,6 +38,7 @@  enum if_type {
 	IF_TYPE_PVBLOCK,
 	IF_TYPE_VIRTIO,
 	IF_TYPE_EFI_MEDIA,
+	IF_TYPE_RK_IDB,
 
 	IF_TYPE_COUNT,			/* Number of interface types */
 };
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 3ba69ad9..38a227f0 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -104,6 +104,7 @@  enum uclass_id {
 	UCLASS_REGULATOR,	/* Regulator device */
 	UCLASS_REMOTEPROC,	/* Remote Processor device */
 	UCLASS_RESET,		/* Reset controller device */
+	UCLASS_RK_IDB,		/* Rockchip IDB device */
 	UCLASS_RNG,		/* Random Number Generator */
 	UCLASS_RTC,		/* Real time clock device */
 	UCLASS_SCMI_AGENT,	/* Interface with an SCMI server */
diff --git a/include/efi_loader.h b/include/efi_loader.h
index c1e00eba..44d42603 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -141,6 +141,10 @@  static inline efi_status_t efi_launch_capsules(void)
 #define U_BOOT_VIRTIO_DEV_GUID \
 	EFI_GUID(0x63293792, 0xadf5, 0x9325, \
 		 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e)
+/* GUID used as root for Rockchip IDB devices */
+#define U_BOOT_IDB_DEV_GUID \
+	EFI_GUID(0xadc021df, 0x5f24, 0x464f, \
+		 0x9a, 0x88, 0xdb, 0xee, 0x3f, 0x1d, 0x14, 0x0f)
 
 /* Use internal device tree when starting UEFI application */
 #define EFI_FDT_USE_INTERNAL NULL
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 171661b8..b7535373 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -28,6 +28,9 @@  const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
 #ifdef CONFIG_VIRTIO_BLK
 const efi_guid_t efi_guid_virtio_dev = U_BOOT_VIRTIO_DEV_GUID;
 #endif
+#if CONFIG_IS_ENABLED(ROCKCHIP_IDB)
+const efi_guid_t efi_guid_idb_dev = U_BOOT_IDB_DEV_GUID;
+#endif
 
 /* template END node: */
 static const struct efi_device_path END = {
@@ -574,6 +577,16 @@  __maybe_unused static unsigned int dp_size(struct udevice *dev)
 			  */
 			return dp_size(dev->parent)
 				+ sizeof(struct efi_device_path_vendor) + 1;
+#endif
+#if CONFIG_IS_ENABLED(ROCKCHIP_IDB)
+		case UCLASS_RK_IDB:
+			 /*
+			  * Rockchip IDB device will be represented
+			  * as vendor device with extra one byte for
+			  * device number
+			  */
+			return dp_size(dev->parent)
+				+ sizeof(struct efi_device_path_vendor) + 1;
 #endif
 		default:
 			return dp_size(dev->parent);
@@ -667,6 +680,23 @@  __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
 			return &dp->vendor_data[1];
 			}
 #endif
+#if CONFIG_IS_ENABLED(ROCKCHIP_IDB)
+		case UCLASS_RK_IDB: {
+			struct efi_device_path_vendor *dp;
+			struct blk_desc *desc = dev_get_uclass_plat(dev);
+
+			dp_fill(buf, dev->parent);
+			dp = buf;
+			++dp;
+			dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+			dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+			dp->dp.length = sizeof(*dp) + 1;
+			memcpy(&dp->guid, &efi_guid_idb_dev,
+			       sizeof(efi_guid_t));
+			dp->vendor_data[0] = desc->devnum;
+			return &dp->vendor_data[1];
+			}
+#endif
 #ifdef CONFIG_IDE
 		case UCLASS_IDE: {
 			struct efi_device_path_atapi *dp =