[PATCH v4 0/8] Add rkmtd command

The command rkmtd creates a virtual block device to transfer Rockchip boot block data to and from NAND with block orientated tools like "ums" and "rockusb".
It uses the Rockchip MTD driver to scan for boot blocks and copies data from the first block in a GPT formatted virtual disk. Data must be written in U-boot "idbloader.img" format and start at partition "loader1" offset 64. The data header is parsed for length and offset. When the last sector is received it erases up to 5 erase blocks on NAND and writes boot blocks in a pattern depending on the NAND ID. Data is then verified. When a block turns out bad the block header is discarded.
Changed V4: Sort includes Replace constant by define Enable rkmtd command in sandbox defconfig Fix minor things in test
Changed V3: Add documetation Add test Split driver from command Split header Use devm_kzalloc Remove out of memory debug Restyle
Changed V2: Rename to rkmtd
Johan Jonker (8): mtd: nand: raw: rockchip_nfc: add NAND_SKIP_BBTSCAN option rockchip: dm: prepare rkmtd UCLASS rockchip: block: add rkmtd class and drivers rockchip: block: blk-uclass: disable bounce buffer support for rkmtd rockchip: cmd: add rkmtd command rockchip: test: dm: add rkmtd test rockchip: doc: add rkmtd.rst rockchip: configs: sandbox: enable rkmtd command
cmd/Kconfig | 8 + cmd/Makefile | 1 + cmd/rkmtd.c | 204 +++++ configs/sandbox64_defconfig | 1 + configs/sandbox_defconfig | 1 + disk/part.c | 4 + doc/board/rockchip/index.rst | 1 + doc/board/rockchip/rkmtd.rst | 105 +++ drivers/block/Kconfig | 7 + drivers/block/Makefile | 2 + drivers/block/blk-uclass.c | 7 +- drivers/block/rkmtd.c | 1135 +++++++++++++++++++++++++++ drivers/mtd/nand/raw/Kconfig | 9 + drivers/mtd/nand/raw/rockchip_nfc.c | 3 + include/dm/uclass-id.h | 1 + include/rkmtd.h | 191 +++++ test/dm/Makefile | 1 + test/dm/rkmtd.c | 200 +++++ 18 files changed, 1878 insertions(+), 3 deletions(-) create mode 100644 cmd/rkmtd.c create mode 100644 doc/board/rockchip/rkmtd.rst create mode 100644 drivers/block/rkmtd.c create mode 100644 include/rkmtd.h create mode 100644 test/dm/rkmtd.c
-- 2.39.2

On Rockchip SoCs the first boot stages are written on NAND with help of manufacturer software that uses a different format then the MTD framework. Skip the automatic BBT scan with the NAND_SKIP_BBTSCAN option to be able to pass the driver probe function and to let the original data unchanged.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com --- drivers/mtd/nand/raw/Kconfig | 9 +++++++++ drivers/mtd/nand/raw/rockchip_nfc.c | 3 +++ 2 files changed, 12 insertions(+)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index d624589a892b..72547f00fbec 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -611,6 +611,15 @@ config ROCKCHIP_NAND NFC v800: RK3308, RV1108 NFC v900: PX30, RK3326
+config ROCKCHIP_NAND_SKIP_BBTSCAN + bool "Skip the automatic BBT scan with Rockchip NAND controllers" + depends on ROCKCHIP_NAND + default n + help + Skip the automatic BBT scan with the NAND_SKIP_BBTSCAN + option when data content is not in MTD format or + must remain unchanged. + config TEGRA_NAND bool "Support for NAND controller on Tegra SoCs" depends on ARCH_TEGRA diff --git a/drivers/mtd/nand/raw/rockchip_nfc.c b/drivers/mtd/nand/raw/rockchip_nfc.c index 6ad51df4acff..df6742c2f9bb 100644 --- a/drivers/mtd/nand/raw/rockchip_nfc.c +++ b/drivers/mtd/nand/raw/rockchip_nfc.c @@ -981,6 +981,9 @@ static int rk_nfc_nand_chip_init(ofnode node, struct rk_nfc *nfc, int devnum) chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
+ if (IS_ENABLED(CONFIG_ROCKCHIP_NAND_SKIP_BBTSCAN)) + chip->options |= NAND_SKIP_BBTSCAN; + rk_nfc_hw_init(nfc); ret = nand_scan_ident(mtd, nsels, NULL); if (ret) -- 2.39.2

Prepare a rkmtd UCLASS in use for writing Rockchip boot blocks in combination with existing userspace tools and rockusb command.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com --- disk/part.c | 4 ++++ drivers/block/blk-uclass.c | 1 + include/dm/uclass-id.h | 1 + 3 files changed, 6 insertions(+)
diff --git a/disk/part.c b/disk/part.c index 85244b09f359..36b88205eca7 100644 --- a/disk/part.c +++ b/disk/part.c @@ -197,6 +197,7 @@ void dev_print(struct blk_desc *desc) case UCLASS_PVBLOCK: case UCLASS_HOST: case UCLASS_BLKMAP: + case UCLASS_RKMTD: printf ("Vendor: %s Rev: %s Prod: %s\n", desc->vendor, desc->revision, @@ -330,6 +331,9 @@ static void print_part_header(const char *type, struct blk_desc *desc) case UCLASS_PVBLOCK: puts("PV BLOCK"); break; + case UCLASS_RKMTD: + puts("RKMTD"); + break; case UCLASS_VIRTIO: puts("VirtIO"); break; diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index f126547cc7e6..30ad5bbb0024 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -36,6 +36,7 @@ static struct { { UCLASS_VIRTIO, "virtio" }, { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" }, + { UCLASS_RKMTD, "rkmtd" }, };
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 0432c95c9edc..2fc672df0a3a 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -120,6 +120,7 @@ enum uclass_id { UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */ UCLASS_RESET, /* Reset controller device */ + UCLASS_RKMTD, /* Rockchip MTD device */ UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ UCLASS_SCMI_AGENT, /* Interface with an SCMI server */ -- 2.39.2

On Sun, 15 Oct 2023 at 16:32, Johan Jonker jbx6244@gmail.com wrote:
Prepare a rkmtd UCLASS in use for writing Rockchip boot blocks in combination with existing userspace tools and rockusb command.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com
disk/part.c | 4 ++++ drivers/block/blk-uclass.c | 1 + include/dm/uclass-id.h | 1 + 3 files changed, 6 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

Add rkmtd class and drivers to create a virtual block device to transfer Rockchip boot block data to and from NAND with block orientated tools like "ums" and "rockusb".
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com ---
Changed V4: sort includes replace constant by define
Changed V3: New patch Split driver from command Split header Use devm_kzalloc Remove out of memory debug Restyle --- drivers/block/Kconfig | 7 + drivers/block/Makefile | 2 + drivers/block/rkmtd.c | 1135 ++++++++++++++++++++++++++++++++++++++++ include/rkmtd.h | 191 +++++++ 4 files changed, 1335 insertions(+) create mode 100644 drivers/block/rkmtd.c create mode 100644 include/rkmtd.h
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 1abea3f10db4..048a6caef00f 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -262,3 +262,10 @@ config SYS_64BIT_LBA help Make the block subsystem use 64bit sector addresses, rather than the default of 32bit. + +config RKMTD + bool "Rockchip rkmtd virtual block device" + help + Enable "rkmtd" class and driver to create a virtual block device + to transfer Rockchip boot block data to and from NAND with block + orientate tools like "ums" and "rockusb". diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a161d145fd39..fdcba5c8318f 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,6 +11,7 @@ endif
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_IDE) += ide.o +obj-$(CONFIG_RKMTD) += rkmtd.o endif obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o @@ -19,3 +20,4 @@ obj-$(CONFIG_BLKMAP) += blkmap.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o + diff --git a/drivers/block/rkmtd.c b/drivers/block/rkmtd.c new file mode 100644 index 000000000000..c17d320ebce3 --- /dev/null +++ b/drivers/block/rkmtd.c @@ -0,0 +1,1135 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Some functions are derived from: + * https://github.com/rockchip-linux/u-boot/blob/next-dev/drivers/rknand/rk_ftl... + * Copyright (c) 2016-2018, Fuzhou Rockchip Electronics Co., Ltd + * + * Driver interface derived from: + * /drivers/block/host_dev.c + * /drivers/block/host-uclass.c + * Copyright 2022 Google LLC + * Written by Simon Glass sjg@chromium.org + * + * Copyright (C) 2023 Johan Jonker jbx6244@gmail.com + */ + +#include <blk.h> +#include <dm.h> +#include <nand.h> +#include <part.h> +#include <rkmtd.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <dm/device-internal.h> +#include <dm/devres.h> +#include <dm/lists.h> +#include <dm/root.h> +#include <dm/uclass-internal.h> +#include <linux/mtd/mtd.h> +#if !IS_ENABLED(CONFIG_SANDBOX) +#include <linux/mtd/rawnand.h> +#endif +#include <u-boot/crc.h> + +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}}, + {6, {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}}, +}; + +#if !IS_ENABLED(CONFIG_SANDBOX) +static int rkmtd_write_oob(struct rkmtd_dev *plat, ulong off, u_char *datbuf, u_char *oobbuf) +{ + struct mtd_info *mtd = plat->mtd; + struct mtd_oob_ops ops; + loff_t addr; + int ret; + + off &= ~(mtd->writesize - 1); + addr = (loff_t)off; + + memset(&ops, 0, sizeof(ops)); + ops.datbuf = datbuf; + ops.oobbuf = oobbuf; + ops.len = mtd->writesize; + ops.ooblen = mtd->oobsize; + ops.mode = MTD_OPS_PLACE_OOB; + ret = mtd_write_oob(mtd, addr, &ops); + if (ret < 0) { + debug("Error (%d) writing page %08lx\n", ret, off); + return 1; + } + + return 0; +} + +static int rkmtd_read_oob(struct rkmtd_dev *plat, ulong off, u_char *datbuf, u_char *oobbuf) +{ + struct mtd_info *mtd = plat->mtd; + struct mtd_oob_ops ops; + loff_t addr; + int ret; + + off &= ~(mtd->writesize - 1); + addr = (loff_t)off; + + memset(&ops, 0, sizeof(ops)); + ops.datbuf = datbuf; + ops.oobbuf = oobbuf; + ops.len = mtd->writesize; + ops.ooblen = mtd->oobsize; + ops.mode = MTD_OPS_PLACE_OOB; + ret = mtd_read_oob(mtd, addr, &ops); + if (ret < 0) { + debug("Error (%d) reading page %08lx\n", ret, off); + return 1; + } + + return 0; +} + +static int rkmtd_erase(struct rkmtd_dev *plat, ulong off) +{ + struct mtd_info *mtd = plat->mtd; + struct erase_info info; + loff_t addr; + int ret; + + off &= ~(mtd->writesize - 1); + addr = (loff_t)off; + + memset(&info, 0, sizeof(info)); + info.mtd = mtd; + info.addr = addr; + info.len = mtd->erasesize; + info.scrub = 1; + ret = mtd_erase(mtd, &info); + if (ret) { + debug("Error (%d) erasing page %08lx\n", ret, off); + return 1; + } + + return 0; +} +#endif +void rkmtd_scan_block(struct rkmtd_dev *plat) +{ + plat->blk_counter = 0; + +#if !IS_ENABLED(CONFIG_SANDBOX) + u32 blk; + + for (blk = 0; blk < plat->boot_blks; blk++) { + rkmtd_read_oob(plat, blk * plat->mtd->erasesize, plat->datbuf, plat->oobbuf); + if (*(u32 *)plat->datbuf == RK_TAG) { + struct sector0 *sec0 = (struct sector0 *)plat->datbuf; + + rkmtd_rc4(plat->datbuf, 512); + + plat->idblock[plat->blk_counter].blk = blk; + plat->idblock[plat->blk_counter].offset = sec0->boot_code1_offset; + plat->idblock[plat->blk_counter].boot_size = sec0->flash_boot_size; + + debug("\nblk : %d\n", plat->idblock[plat->blk_counter].blk); + debug("offset : %d\n", plat->idblock[plat->blk_counter].offset); + debug("boot_size : %d\n", plat->idblock[plat->blk_counter].boot_size); + + plat->blk_counter += 1; + + if (plat->blk_counter >= ARRAY_SIZE(plat->idblock)) + return; + } + } +#endif +} + +void rkmtd_read_block(struct rkmtd_dev *plat, u32 idx, u8 *buf) +{ +#if !IS_ENABLED(CONFIG_SANDBOX) + ulong off = plat->idblock[idx].blk * plat->mtd->erasesize; + struct nand_chip *chip = mtd_to_nand(plat->mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int counter = 0; + u32 spare0 = 0; + u32 *p_spare; + int sector; + int page; + + rkmtd_read_oob(plat, off, + plat->datbuf, plat->oobbuf); + + memcpy(buf, plat->datbuf, BLK_SIZE); + + while (counter < plat->idblock[idx].boot_size) { + if (spare0) + page = (plat->idblock[idx].offset + spare0) / 4; + else + page = (plat->idblock[idx].offset + counter) / 4; + + rkmtd_read_oob(plat, + off + page * plat->mtd->writesize, + plat->datbuf, plat->oobbuf); + + sector = plat->idblock[idx].offset + counter; + + memcpy(&buf[(sector / 4) * BLK_SIZE], plat->datbuf, BLK_SIZE); + + p_spare = (u32 *)&plat->oobbuf[(ecc->steps - 1) * NFC_SYS_DATA_SIZE]; + + spare0 = *p_spare; + if (spare0 == -1) + break; + + counter += 4; + } +#endif +} + +void rkmtd_write_block(struct rkmtd_dev *plat, u32 idx, u8 *buf) +{ +#if !IS_ENABLED(CONFIG_SANDBOX) + ulong off = plat->idblock[idx].blk * plat->mtd->erasesize; + struct nand_chip *chip = mtd_to_nand(plat->mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int counter = 0; + u32 *p_spare; + int sector; + int page; + int j, w, r; + + rkmtd_erase(plat, off); + + memset(plat->datbuf, 0xff, plat->mtd->writesize); + memcpy(plat->datbuf, buf, BLK_SIZE); + memset(plat->oobbuf, 0xff, plat->mtd->oobsize); + + rkmtd_write_oob(plat, off, + plat->datbuf, plat->oobbuf); + + while (counter < plat->idblock[idx].boot_size) { + sector = plat->idblock[idx].offset + counter; + + memset(plat->datbuf, 0xff, plat->mtd->writesize); + memcpy(plat->datbuf, &buf[(sector / 4) * BLK_SIZE], BLK_SIZE); + memset(plat->oobbuf, 0xff, plat->mtd->oobsize); + + p_spare = (u32 *)&plat->oobbuf[(ecc->steps - 1) * NFC_SYS_DATA_SIZE]; + + *p_spare = (plat->page_table[sector / 4 + 1] - 1) * 4; + + page = plat->page_table[sector / 4]; + + rkmtd_write_oob(plat, + off + page * plat->mtd->writesize, + plat->datbuf, plat->oobbuf); + + counter += 4; + } + + memset(plat->check, 0, BUF_SIZE); + rkmtd_read_block(plat, idx, plat->check); + + for (j = 0; j < BLK_SIZE; j++) { + w = *(buf + j); + r = *(plat->check + j); + + if (r != w) + goto dumpblock; + } + + for (j = 0; j < (plat->idblock[idx].boot_size * 512); j++) { + w = *(buf + plat->idblock[idx].offset * 512 + j); + r = *(plat->check + plat->idblock[idx].offset * 512 + j); + + if (r != w) + goto dumpblock; + } + + debug("write OK\n"); + return; + +dumpblock: + debug("write and check error:%x r=%x w=%x\n", j, r, w); + + plat->idblock[idx].offset = 0; + plat->idblock[idx].boot_size = 0; + + memset(plat->datbuf, 0xff, plat->mtd->writesize); + memset(plat->datbuf, 0, BLK_SIZE); + memset(plat->oobbuf, 0xff, plat->mtd->oobsize); + + rkmtd_write_oob(plat, off, plat->datbuf, plat->oobbuf); +#endif +} + +ulong rkmtd_bread(struct udevice *udev, lbaint_t start, + lbaint_t blkcnt, void *dst) +{ + struct blk_desc *block_dev = dev_get_uclass_plat(udev); + struct udevice *parent_dev = dev_get_parent(udev); + struct rkmtd_dev *plat = dev_get_plat(parent_dev); + char *buf = dst; + int i; + + if (blkcnt == 0) + return 0; + + if (start > (block_dev->lba - 1) || + (start + blkcnt) > block_dev->lba) + return 0; + + memset(dst, 0, 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("rd : %d\n", i); + + memcpy(&buf[(i - start) * block_dev->blksz], + &plat->idb[(i - 64) * block_dev->blksz], block_dev->blksz); + } + } + + return blkcnt; +} + +ulong rkmtd_bwrite(struct udevice *udev, lbaint_t start, + lbaint_t blkcnt, const void *src) +{ + struct blk_desc *block_dev = dev_get_uclass_plat(udev); + struct udevice *parent_dev = dev_get_parent(udev); + struct rkmtd_dev *plat = dev_get_plat(parent_dev); + struct sector0 *sec0; + int i, j; + + if (blkcnt == 0) + return 0; + + if (start > (block_dev->lba - 1) || + (start + blkcnt) > block_dev->lba) + return 0; + + for (i = start; i < (start + blkcnt); i++) { + debug("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, 0, BUF_SIZE); + } + + if (plat->idb_need_write_back) { + char *buf = (char *)src; + + memcpy(&plat->idb[(i - 64) * block_dev->blksz], + &buf[(i - start) * block_dev->blksz], + block_dev->blksz); + + if (i == 64) { + memcpy(plat->check, plat->idb, 512); + + if (*(u32 *)plat->check == RK_TAG) { + rkmtd_rc4(plat->check, 512); + + sec0 = (struct sector0 *)plat->check; + plat->offset = sec0->boot_code1_offset; + plat->boot_size = sec0->flash_boot_size; + + if (plat->offset + plat->boot_size > 512) { + debug("max size 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->offset + plat->boot_size - 1)) { + debug("last block\n"); + + plat->idb_need_write_back = 0; + + if (!plat->blk_counter) { + plat->idblock[0].blk = 2; + plat->idblock[1].blk = 3; + plat->idblock[2].blk = 4; + plat->idblock[3].blk = 5; + plat->idblock[4].blk = 6; + plat->blk_counter = 5; + } + + for (j = 0; j < plat->blk_counter; j++) { + if (plat->idblock[j].blk < plat->boot_blks) { + plat->idblock[j].offset = plat->offset; + plat->idblock[j].boot_size = plat->boot_size; + rkmtd_write_block(plat, j, plat->idb); + } + } + + rkmtd_scan_block(plat); + + if (!IS_ENABLED(CONFIG_SANDBOX)) + memset(plat->idb, 0, BUF_SIZE); + + if (plat->blk_counter) + rkmtd_read_block(plat, 0, plat->idb); + } + } + } else if (plat->idb_need_write_back) { + plat->idb_need_write_back = 0; + + memset(plat->idb, 0, BUF_SIZE); + + if (plat->blk_counter) + rkmtd_read_block(plat, 0, plat->idb); + } + } + + return blkcnt; +} + +static const struct blk_ops rkmtd_blk_ops = { + .read = rkmtd_bread, + .write = rkmtd_bwrite, +}; + +U_BOOT_DRIVER(rkmtd_blk) = { + .name = "rkmtd_blk", + .id = UCLASS_BLK, + .ops = &rkmtd_blk_ops, +}; + +void rkmtd_build_page_table(struct rkmtd_dev *plat) +{ + u32 counter; + u32 counter2; + + switch (plat->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; + } +} + +static inline u32 efi_crc32(const void *buf, u32 len) +{ + return crc32(0, buf, len); +} + +int rkmtd_init_plat(struct udevice *dev) +{ + static const efi_guid_t partition_basic_data_guid = PARTITION_BASIC_DATA_GUID; + struct rkmtd_dev *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 = devm_kzalloc(plat->dev, BUF_SIZE, GFP_KERNEL); + if (!plat->idb) + return -ENOMEM; + + plat->check = devm_kzalloc(plat->dev, BUF_SIZE, GFP_KERNEL); + if (!plat->check) + return -ENOMEM; + + plat->mbr = devm_kzalloc(plat->dev, sizeof(legacy_mbr), GFP_KERNEL); + if (!plat->mbr) + return -ENOMEM; + + plat->gpt_e = devm_kzalloc(plat->dev, sizeof(gpt_entry), GFP_KERNEL); + if (!plat->gpt_e) + return -ENOMEM; + + plat->gpt_h = devm_kzalloc(plat->dev, sizeof(gpt_header), GFP_KERNEL); + if (!plat->gpt_h) + return -ENOMEM; + + plat->gpt_h2 = devm_kzalloc(plat->dev, sizeof(gpt_header), GFP_KERNEL); + if (!plat->gpt_h2) + return -ENOMEM; + + /* Init 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 */ + 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 */ + 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); + + part_init(plat->desc); + + return 0; +} + +static int rkmtd_bind(struct udevice *dev) +{ + struct rkmtd_dev *plat = dev_get_plat(dev); + struct udevice *bdev; + struct blk_desc *desc; + int ret; + + ret = blk_create_devicef(dev, "rkmtd_blk", "blk", UCLASS_RKMTD, + -1, 512, 0, &bdev); + if (ret) + return log_msg_ret("blk", ret); + + desc = dev_get_uclass_plat(bdev); + desc->lba = LBA; + sprintf(desc->vendor, "0x%.4x", 0x2207); + memcpy(desc->product, "RKMTD", sizeof("RKMTD")); + memcpy(desc->revision, "V1.00", sizeof("V1.00")); + plat->desc = desc; + + return 0; +} + +static int rkmtd_attach_mtd(struct udevice *dev) +{ + struct rkmtd_dev *plat = dev_get_plat(dev); + struct mtd_info *mtd; + struct udevice *blk; + int ret; + + plat->dev = dev; + + /* Sanity check that rkmtd_bind() has been used */ + ret = blk_find_from_parent(dev, &blk); + if (ret) + return ret; + +#if IS_ENABLED(CONFIG_SANDBOX) + plat->mtd = devm_kzalloc(dev, sizeof(struct mtd_info), GFP_KERNEL); + if (!plat->mtd) + return -ENOMEM; + + mtd = plat->mtd; + mtd->erasesize = 2 ^ 3 * BLK_SIZE; + mtd->writesize = BLK_SIZE; + mtd->oobsize = BLK_SIZE / STEP_SIZE * NFC_SYS_DATA_SIZE; + plat->boot_blks = 0; + plat->lsb_mode = 0; +#else + struct nand_chip *chip; + u8 id[6]; + int i, j; + u32 tmp; + + mtd = get_nand_dev_by_index(0); + if (!mtd) + return -ENOSYS; + + chip = mtd_to_nand(mtd); + + ret = ofnode_read_u32(chip->flash_node, "rockchip,boot-blks", &tmp); + plat->boot_blks = ret ? 0 : tmp; + plat->mtd = mtd; + + if (chip->select_chip) + chip->select_chip(mtd, 0); + + nand_readid_op(chip, 0, id, 6); + + if (chip->select_chip) + chip->select_chip(mtd, -1); + + for (i = 0; i < ARRAY_SIZE(nand_para_tbl); i++) { + plat->info = (struct nand_para_info *)&nand_para_tbl[i]; + for (j = 0; j < plat->info->id_bytes; j++) { + if (plat->info->nand_id[j] != id[j]) + break; + if (j == plat->info->id_bytes - 1) + goto valid; + } + } + + debug("no nand_para_info found\n"); + return -ENODEV; +valid: + plat->lsb_mode = plat->info->lsb_mode; + + debug("FLASH ID :"); + + for (j = 0; j < plat->info->id_bytes; j++) + debug(" %x", id[j]); + + debug("\n"); +#endif + + rkmtd_build_page_table(plat); + + plat->datbuf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL); + if (!plat->datbuf) + return -ENOMEM; + + plat->oobbuf = devm_kzalloc(dev, mtd->oobsize, GFP_KERNEL); + if (!plat->oobbuf) + return -ENOMEM; + + debug("erasesize %8d\n", mtd->erasesize); + debug("writesize %8d\n", mtd->writesize); + debug("oobsize %8d\n", mtd->oobsize); + debug("boot_blks %8d\n", plat->boot_blks); + debug("lsb_mode %8d\n", plat->lsb_mode); + + ret = rkmtd_init_plat(dev); + if (ret) { + debug("rkmtd_init_plat failed\n"); + return -ENOENT; + } + + rkmtd_scan_block(plat); + + memset(plat->idb, 0, BUF_SIZE); + + if (plat->blk_counter) + rkmtd_read_block(plat, 0, plat->idb); + + return 0; +} + +int rkmtd_detach_mtd(struct udevice *dev) +{ + int ret; + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return log_msg_ret("rem", ret); + + ret = device_chld_unbind(dev, NULL); + if (ret) + return log_msg_ret("unb", ret); + + return 0; +} + +struct rkmtd_ops rkmtd_ops = { + .attach_mtd = rkmtd_attach_mtd, + .detach_mtd = rkmtd_detach_mtd, +}; + +U_BOOT_DRIVER(rkmtd_drv) = { + .name = "rkmtd_drv", + .id = UCLASS_RKMTD, + .ops = &rkmtd_ops, + .bind = rkmtd_bind, + .plat_auto = sizeof(struct rkmtd_dev), +}; + +struct rkmtd_priv { + struct udevice *cur_dev; +}; + +void rkmtd_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]; + } +} + +struct udevice *rkmtd_get_cur_dev(void) +{ + struct uclass *uc = uclass_find(UCLASS_RKMTD); + + if (uc) { + struct rkmtd_priv *priv = uclass_get_priv(uc); + + return priv->cur_dev; + } + + return NULL; +} + +void rkmtd_set_cur_dev(struct udevice *dev) +{ + struct uclass *uc = uclass_find(UCLASS_RKMTD); + + if (uc) { + struct rkmtd_priv *priv = uclass_get_priv(uc); + + priv->cur_dev = dev; + } +} + +struct udevice *rkmtd_find_by_label(const char *label) +{ + struct udevice *dev; + struct uclass *uc; + + uclass_id_foreach_dev(UCLASS_RKMTD, dev, uc) { + struct rkmtd_dev *plat = dev_get_plat(dev); + + if (plat->label && !strcmp(label, plat->label)) + return dev; + } + + return NULL; +} + +int rkmtd_attach(struct udevice *dev) +{ + struct rkmtd_ops *ops = rkmtd_get_ops(dev); + + if (!ops->attach_mtd) + return -ENOSYS; + + return ops->attach_mtd(dev); +} + +int rkmtd_detach(struct udevice *dev) +{ + struct rkmtd_ops *ops = rkmtd_get_ops(dev); + + if (!ops->detach_mtd) + return -ENOSYS; + + if (dev == rkmtd_get_cur_dev()) + rkmtd_set_cur_dev(NULL); + + return ops->detach_mtd(dev); +} + +static void rkmtd_kmalloc_release(struct udevice *dev, void *res) +{ + /* noop */ +} + +int rkmtd_create_device(const char *label, struct udevice **devp) +{ + char dev_name[30], *str, *label_new; + struct rkmtd_dev *plat; + struct udevice *dev, *blk; + int ret; + + /* unbind any existing device with this label */ + dev = rkmtd_find_by_label(label); + if (dev) { + ret = rkmtd_detach(dev); + if (ret) + return log_msg_ret("det", ret); + + ret = device_unbind(dev); + if (ret) + return log_msg_ret("unb", ret); + } + + snprintf(dev_name, sizeof(dev_name), "rkmtd-%s", label); + + str = devres_alloc(rkmtd_kmalloc_release, strlen(dev_name) + 1, GFP_KERNEL); + if (unlikely(!str)) + return -ENOMEM; + + strcpy(str, dev_name); + + ret = device_bind_driver(dm_root(), "rkmtd_drv", str, &dev); + if (ret) { + free(str); + return ret; + } + + devres_add(dev, str); + + if (!blk_find_from_parent(dev, &blk)) { + struct blk_desc *desc = dev_get_uclass_plat(blk); + + desc->removable = true; + } + + label_new = devm_kzalloc(dev, strlen(label) + 1, GFP_KERNEL); + if (!label_new) + return -ENOMEM; + + strcpy(label_new, label); + + plat = dev_get_plat(dev); + plat->label = label_new; + *devp = dev; + + return 0; +} + +int rkmtd_create_attach_mtd(const char *label, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + ret = rkmtd_create_device(label, &dev); + if (ret) + return log_msg_ret("cre", ret); + + ret = rkmtd_attach(dev); + if (ret) { + device_unbind(dev); + return log_msg_ret("att", ret); + } + *devp = dev; + + return 0; +} + +UCLASS_DRIVER(rkmtd) = { + .name = "rkmtd", + .id = UCLASS_RKMTD, + .post_bind = dm_scan_fdt_dev, + .priv_auto = sizeof(struct rkmtd_priv), +}; diff --git a/include/rkmtd.h b/include/rkmtd.h new file mode 100644 index 000000000000..145fede6c840 --- /dev/null +++ b/include/rkmtd.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Driver interface derived from: + * /include/sandbox_host.h + * Copyright 2022 Google LLC + * + * Copyright 2023 Johan Jonker jbx6244@gmail.com + */ + +#ifndef __RKMTD__ +#define __RKMTD__ + +#include <part_efi.h> +#include <uuid.h> + +#define LBA 64 + 512 + 33 + +#define RK_TAG 0xFCDC8C3B +#define NFC_SYS_DATA_SIZE 4 +#define BLK_SIZE 2048 +#define STEP_SIZE 1024 +#define BUF_SIZE 512 * 512 + +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 bootblk { + int blk; + int boot_size; + int offset; +}; + +struct rkmtd_dev { + struct udevice *dev; + struct blk_desc *desc; + char *label; + 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]; + char *datbuf; + char *oobbuf; + struct mtd_info *mtd; + struct nand_para_info *info; + u16 page_table[512]; + u32 idb_need_write_back; + struct bootblk idblock[5]; + u32 blk_counter; + u32 boot_blks; + u32 offset; + u32 boot_size; + u32 lsb_mode; +}; + +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; + +/** + * rkmtd_rc4() - Rockchip specific RC4 Encryption Algorithm + * + * Encrypt Rockchip boot block header version 1 and data + * + * @buf: Pointer to data buffer + * @len: Data buffer size + */ +void rkmtd_rc4(u8 *buf, u32 len); + +/** + * struct rkmtd_ops - operations supported by UCLASS_RKMTD + */ +struct rkmtd_ops { + /** + * @attach_mtd: - Attach a new rkmtd driver to the device structure + * + * @attach_mtd.dev: Device to update + * @attach_mtd.Returns: 0 if OK, -EEXIST if a driver is already attached, + * other -ve on other error + */ + int (*attach_mtd)(struct udevice *dev); + + /** + * @detach_mtd: - Detach a rkmtd driver from the device structure + * + * @detach_mtd.dev: Device to detach from + * @detach_mtd.Returns: 0 if OK, -ENOENT if no driver is attached, + * other -ve on other error + */ + int (*detach_mtd)(struct udevice *dev); +}; + +#define rkmtd_get_ops(dev) ((struct rkmtd_ops *)(dev)->driver->ops) + +/** + * rkmtd_get_cur_dev() - Get the current device + * + * Returns current device, or NULL if none + */ +struct udevice *rkmtd_get_cur_dev(void); + +/** + * rkmtd_set_cur_dev() - Set the current device + * + * Sets the current device, or clears it if @dev is NULL + * + * @dev: Device to set as the current one + */ +void rkmtd_set_cur_dev(struct udevice *dev); + +/** + * rkmtd_find_by_label() - Find a rkmtd device by label + * + * Searches all rkmtd devices to find one with the given label + * + * @label: Label to find + * Returns: associated device, or NULL if not found + */ +struct udevice *rkmtd_find_by_label(const char *label); + +/** + * rkmtd_attach() - Attach a new rkmtd driver to the device structure + * + * @dev: Device to update + * Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on + * other error + */ +int rkmtd_attach(struct udevice *dev); + +/** + * rkmtd_detach() - Detach a rkmtd driver from the device structure + * + * @dev: Device to detach from + * Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other + * error + */ +int rkmtd_detach(struct udevice *dev); + +/** + * rkmtd_create_device() - Create a new rkmtd device + * + * Any existing device with the same label is removed and unbound first + * + * @label: Label of the attachment, e.g. "test1" + * @devp: Returns the device created, on success + * Returns: 0 if OK, -ve on error + */ +int rkmtd_create_device(const char *label, struct udevice **devp); + +/** + * rkmtd_create_attach_mtd() - Create a new rkmtd device and attach driver + * + * @label: Label of the attachment, e.g. "test1" + * @devp: Returns the device created, on success + * Returns: 0 if OK, -ve on error + */ +int rkmtd_create_attach_mtd(const char *label, struct udevice **devp); + +#endif /* __RKMTD__ */ -- 2.39.2

Disable bounce buffer support for rkmtd.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com ---
Changed V3: New patch --- drivers/block/blk-uclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 30ad5bbb0024..ac1b43d757d8 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -415,7 +415,7 @@ struct blk_bounce_buffer {
static int blk_buffer_aligned(struct bounce_buffer *state) { -#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD) struct blk_bounce_buffer *bbstate = container_of(state, struct blk_bounce_buffer, state); struct udevice *dev = bbstate->dev; @@ -441,7 +441,7 @@ long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf) start, blkcnt, desc->blksz, buf)) return blkcnt;
- if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) { + if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)) { struct blk_bounce_buffer bbstate = { .dev = dev }; int ret;
@@ -478,7 +478,7 @@ long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
blkcache_invalidate(desc->uclass_id, desc->devnum);
- if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) { + if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)) { struct blk_bounce_buffer bbstate = { .dev = dev }; int ret;
-- 2.39.2

Hi Johan,
On Sun, 15 Oct 2023 at 16:33, Johan Jonker jbx6244@gmail.com wrote:
Disable bounce buffer support for rkmtd.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com
Changed V3: New patch
drivers/block/blk-uclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 30ad5bbb0024..ac1b43d757d8 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -415,7 +415,7 @@ struct blk_bounce_buffer {
static int blk_buffer_aligned(struct bounce_buffer *state) { -#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)
We should not have arch-specific code in a generic file. Can you make BOUNCE_BUFFER depend on !RKMTD ?
struct blk_bounce_buffer *bbstate = container_of(state, struct blk_bounce_buffer, state); struct udevice *dev = bbstate->dev;
@@ -441,7 +441,7 @@ long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf) start, blkcnt, desc->blksz, buf)) return blkcnt;
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)) { struct blk_bounce_buffer bbstate = { .dev = dev }; int ret;
@@ -478,7 +478,7 @@ long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
blkcache_invalidate(desc->uclass_id, desc->devnum);
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)) { struct blk_bounce_buffer bbstate = { .dev = dev }; int ret;
-- 2.39.2
Regards, Simon

On 10/16/23 23:54, Simon Glass wrote:
Hi Johan,
On Sun, 15 Oct 2023 at 16:33, Johan Jonker jbx6244@gmail.com wrote:
Disable bounce buffer support for rkmtd.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com
Changed V3: New patch
drivers/block/blk-uclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 30ad5bbb0024..ac1b43d757d8 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -415,7 +415,7 @@ struct blk_bounce_buffer {
static int blk_buffer_aligned(struct bounce_buffer *state) { -#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)
We should not have arch-specific code in a generic file. Can you make BOUNCE_BUFFER depend on !RKMTD ?
Hi Simon, Marek,
No that doesn't work that way.
On Rockchip mainline boards MMC_DW is always our boot device BOOT_DEVICE_MMCx. Therefore BOUNCE_BUFFER is also standard enabled.
The solution in this patch below is wrong as it assumes that if BOUNCE_BUFFER is enabled it must be used all over the place.
blk: Add bounce buffer support to read/write operations https://source.denx.de/u-boot/u-boot/-/commit/75191f75bce45f3b9aff607c88f177...
All implementations of bounce_buffer_start and bounce_buffer_start_extalign are located in the individual drivers
https://elixir.bootlin.com/u-boot/latest/C/ident/bounce_buffer_start https://elixir.bootlin.com/u-boot/latest/C/ident/bounce_buffer_start_extalig...
The use of a bounce_buffer in block devices should only be allowed if needed. Lack of "ops->buffer_aligned" does not prevent the creation of a bounce_buffer and is not a good selector yet.
if (ops->buffer_aligned) return ops->buffer_aligned(dev, state);
Current blk_ops has no option to communicate the needed resources. Please advise how to select the creation of a bounce buffer per device or other solution.
Johan
=== config MMC_DW bool "Synopsys DesignWare Memory Card Interface" select BOUNCE_BUFFER
Without BOUNCE_BUFFER selected /drivers/mmc/dw_mmc.c does not compile even rk3066 only uses "fifo_mode".
arm-linux-gnueabihf-ld.bfd: drivers/mmc/dw_mmc.o: in function `dwmci_send_cmd': /drivers/mmc/dw_mmc.c:285: undefined reference to `bounce_buffer_start'
if (host->fifo_mode) { dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); } else { if (data->flags == MMC_DATA_READ) { ret = bounce_buffer_start(&bbstate, (void*)data->dest, data->blocksize * data->blocks, GEN_BB_WRITE); } else { ret = bounce_buffer_start(&bbstate, (void*)data->src, data->blocksize * data->blocks, GEN_BB_READ); } [..] }
arm-linux-gnueabihf-ld.bfd: /drivers/mmc/dw_mmc.c:393: undefined reference to `bounce_buffer_stop'
/* only dma mode need it */ if (!host->fifo_mode) { [..] bounce_buffer_stop(&bbstate); }
struct blk_bounce_buffer *bbstate = container_of(state, struct blk_bounce_buffer, state); struct udevice *dev = bbstate->dev;
@@ -441,7 +441,7 @@ long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf) start, blkcnt, desc->blksz, buf)) return blkcnt;
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)) { struct blk_bounce_buffer bbstate = { .dev = dev }; int ret;
@@ -478,7 +478,7 @@ long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
blkcache_invalidate(desc->uclass_id, desc->devnum);
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)) { struct blk_bounce_buffer bbstate = { .dev = dev }; int ret;
-- 2.39.2
Regards, Simon

Hi Johan,
On Tue, 17 Oct 2023 at 06:44, Johan Jonker jbx6244@gmail.com wrote:
On 10/16/23 23:54, Simon Glass wrote:
Hi Johan,
On Sun, 15 Oct 2023 at 16:33, Johan Jonker jbx6244@gmail.com wrote:
Disable bounce buffer support for rkmtd.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com
Changed V3: New patch
drivers/block/blk-uclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 30ad5bbb0024..ac1b43d757d8 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -415,7 +415,7 @@ struct blk_bounce_buffer {
static int blk_buffer_aligned(struct bounce_buffer *state) { -#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) && !IS_ENABLED(CONFIG_RKMTD)
We should not have arch-specific code in a generic file. Can you make BOUNCE_BUFFER depend on !RKMTD ?
Hi Simon, Marek,
No that doesn't work that way.
On Rockchip mainline boards MMC_DW is always our boot device BOOT_DEVICE_MMCx. Therefore BOUNCE_BUFFER is also standard enabled.
The solution in this patch below is wrong as it assumes that if BOUNCE_BUFFER is enabled it must be used all over the place.
blk: Add bounce buffer support to read/write operations https://source.denx.de/u-boot/u-boot/-/commit/75191f75bce45f3b9aff607c88f177...
All implementations of bounce_buffer_start and bounce_buffer_start_extalign are located in the individual drivers
https://elixir.bootlin.com/u-boot/latest/C/ident/bounce_buffer_start https://elixir.bootlin.com/u-boot/latest/C/ident/bounce_buffer_start_extalig...
The use of a bounce_buffer in block devices should only be allowed if needed. Lack of "ops->buffer_aligned" does not prevent the creation of a bounce_buffer and is not a good selector yet.
if (ops->buffer_aligned) return ops->buffer_aligned(dev, state);
Current blk_ops has no option to communicate the needed resources. Please advise how to select the creation of a bounce buffer per device or other solution.
OK, I thought you might say that. So what about a flag in blk_desc which you can set for this driver, after the block device is created?
[..]
Regards, Simon

The command rkmtd creates a virtual block device to transfer Rockchip boot block data to and from NAND with block orientated tools like "ums" and "rockusb".
It uses the Rockchip MTD driver to scan for boot blocks and copies data from the first block in a GPT formated virtual disk. Data must be written in U-boot "idbloader.img" format and start at partition "loader1" offset 64. The data header is parsed for length and offset. When the last sector is received it erases up to 5 erase blocks on NAND and writes bootblocks in a pattern depending on the NAND ID. Data is then verified. When a block turns out bad the block header is discarded.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changed V4: Sort includes
Changed V3: Split driver from command Split header Restyle --- cmd/Kconfig | 8 ++ cmd/Makefile | 1 + cmd/rkmtd.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 cmd/rkmtd.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 6470b138d2f8..1979c6c62aa7 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1561,6 +1561,14 @@ config CMD_USB_SDP Enables the command "sdp" which is used to have U-Boot emulating the Serial Download Protocol (SDP) via USB.
+config CMD_RKMTD + bool "rkmtd" + select RKMTD + help + Enable the command "rkmtd" to create a virtual block device to transfer + Rockchip boot block data to and from NAND with block orientated tools + like "ums" and "rockusb". + config CMD_ROCKUSB bool "rockusb" depends on USB_FUNCTION_ROCKUSB diff --git a/cmd/Makefile b/cmd/Makefile index 9bebf321c397..11927a5904e6 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -151,6 +151,7 @@ obj-$(CONFIG_CMD_REISER) += reiser.o obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o obj-$(CONFIG_CMD_RNG) += rng.o obj-$(CONFIG_CMD_KASLRSEED) += kaslrseed.o +obj-$(CONFIG_CMD_RKMTD) += rkmtd.o obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o obj-$(CONFIG_CMD_RTC) += rtc.o obj-$(CONFIG_SANDBOX) += host.o diff --git a/cmd/rkmtd.c b/cmd/rkmtd.c new file mode 100644 index 000000000000..5b80427cb949 --- /dev/null +++ b/cmd/rkmtd.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * + * Driver interface derived from: + * /cmd/host.c + * Copyright (c) 2012, Google Inc. + * + * Copyright (C) 2023 Johan Jonker jbx6244@gmail.com + */ + +#include <common.h> +#include <blk.h> +#include <command.h> +#include <dm.h> +#include <rkmtd.h> +#include <stdio.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> + +static int do_rkmtd_bind(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + const char *label; + int ret; + + argc--; + argv++; + + if (argc < 1) + return CMD_RET_USAGE; + + if (argc > 1) + return CMD_RET_USAGE; + + label = argv[0]; + ret = rkmtd_create_attach_mtd(label, &dev); + if (ret) { + printf("Cannot create device / bind mtd\n"); + return CMD_RET_FAILURE; + } + + return 0; +} + +static struct udevice *parse_rkmtd_label(const char *label) +{ + struct udevice *dev; + + dev = rkmtd_find_by_label(label); + if (!dev) { + int devnum; + char *ep; + + devnum = hextoul(label, &ep); + if (*ep || + uclass_find_device_by_seq(UCLASS_RKMTD, devnum, &dev)) { + printf("No such device '%s'\n", label); + return NULL; + } + } + + return dev; +} + +static int do_rkmtd_unbind(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + const char *label; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + label = argv[1]; + dev = parse_rkmtd_label(label); + if (!dev) + return CMD_RET_FAILURE; + + ret = rkmtd_detach(dev); + if (ret) { + printf("Cannot detach mtd\n"); + return CMD_RET_FAILURE; + } + + ret = device_unbind(dev); + if (ret) { + printf("Cannot unbind device '%s'\n", dev->name); + return CMD_RET_FAILURE; + } + + return 0; +} + +static void show_rkmtd_dev(struct udevice *dev) +{ + struct rkmtd_dev *plat = dev_get_plat(dev); + struct blk_desc *desc; + struct udevice *blk; + int ret; + + printf("%3d ", dev_seq(dev)); + + ret = blk_get_from_parent(dev, &blk); + if (ret) + return; + + desc = dev_get_uclass_plat(blk); + printf("%12lu %-15s\n", (unsigned long)desc->lba, plat->label); +} + +static int do_rkmtd_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + + if (argc < 1) + return CMD_RET_USAGE; + + dev = NULL; + if (argc >= 2) { + dev = parse_rkmtd_label(argv[1]); + if (!dev) + return CMD_RET_FAILURE; + } + + printf("%3s %12s %-15s\n", "dev", "blocks", "label"); + if (dev) { + show_rkmtd_dev(dev); + } else { + struct uclass *uc; + + uclass_id_foreach_dev(UCLASS_RKMTD, dev, uc) + show_rkmtd_dev(dev); + } + + return 0; +} + +static int do_rkmtd_dev(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + const char *label; + + if (argc < 1 || argc > 3) + return CMD_RET_USAGE; + + if (argc == 1) { + struct rkmtd_dev *plat; + + dev = rkmtd_get_cur_dev(); + if (!dev) { + printf("No current rkmtd device\n"); + return CMD_RET_FAILURE; + } + plat = dev_get_plat(dev); + printf("Current rkmtd device: %d: %s\n", dev_seq(dev), + plat->label); + return 0; + } + + label = argv[1]; + dev = parse_rkmtd_label(argv[1]); + if (!dev) + return CMD_RET_FAILURE; + + rkmtd_set_cur_dev(dev); + + return 0; +} + +static struct cmd_tbl cmd_rkmtd_sub[] = { + U_BOOT_CMD_MKENT(bind, 4, 0, do_rkmtd_bind, "", ""), + U_BOOT_CMD_MKENT(unbind, 4, 0, do_rkmtd_unbind, "", ""), + U_BOOT_CMD_MKENT(info, 3, 0, do_rkmtd_info, "", ""), + U_BOOT_CMD_MKENT(dev, 0, 1, do_rkmtd_dev, "", ""), +}; + +static int do_rkmtd(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *c; + + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_rkmtd_sub, ARRAY_SIZE(cmd_rkmtd_sub)); + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +U_BOOT_CMD( + rkmtd, 8, 1, do_rkmtd, + "Rockchip MTD sub-system", + "bind <label> - bind RKMTD device\n" + "rkmtd unbind <label> - unbind RKMTD device\n" + "rkmtd info [<label>] - show all available RKMTD devices\n" + "rkmtd dev [<label>] - show or set current RKMTD device\n" +); -- 2.39.2

Add Rockchip rkmtd test: Create/attach/detach RKMTD device. Send/read data with Rockchip boot block header. Test that reusing the same label should work. Basic test of 'rkmtd' commands.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changed V4: sort includes rename define use '\0' use UT_TESTF_CONSOLE_REC flag check RC4 result
Changed V3: New patch --- test/dm/Makefile | 1 + test/dm/rkmtd.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 test/dm/rkmtd.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 7ed00733c1a6..a5e0a2744375 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o obj-$(CONFIG_DM_RESET) += reset.o obj-$(CONFIG_SYSRESET) += sysreset.o obj-$(CONFIG_DM_REGULATOR) += regulator.o +obj-$(CONFIG_CMD_RKMTD) += rkmtd.o obj-$(CONFIG_DM_RNG) += rng.o obj-$(CONFIG_DM_RTC) += rtc.o obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o diff --git a/test/dm/rkmtd.c b/test/dm/rkmtd.c new file mode 100644 index 000000000000..3c3e8efa92f2 --- /dev/null +++ b/test/dm/rkmtd.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Test derived from: + * /test/dm/host.c + * Copyright 2022 Google LLC + * Written by Simon Glass sjg@chromium.org + * + * Copyright (C) 2023 Johan Jonker jbx6244@gmail.com + */ + +#include <common.h> +#include <blk.h> +#include <dm.h> +#include <fs.h> +#include <rkmtd.h> +#include <asm/test.h> +#include <dm/device-internal.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> + +#define RW_BUF_SIZE 12 * 512 + +/* Basic test of the RKMTD interface */ +static int dm_test_rkmtd(struct unit_test_state *uts) +{ + struct udevice *dev, *part, *chk, *blk; + char write[RW_BUF_SIZE], read[RW_BUF_SIZE]; + static const char label[] = "test"; + struct rkmtd_dev *plat; + struct blk_desc *desc; + struct sector0 *sec0; + int i; + + ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_RKMTD, &dev)); + ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_PARTITION, &part)); + + ut_assertok(rkmtd_create_device(label, &dev)); + + /* Check that the plat data has been allocated */ + plat = dev_get_plat(dev); + ut_asserteq_str("test", plat->label); + ut_assert(label != plat->label); + + /* Attach RKMTD driver */ + ut_assertok(rkmtd_attach(dev)); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &chk)); + ut_asserteq_ptr(chk, dev); + + /* Get RKMTD block device */ + ut_assertok(blk_get_from_parent(dev, &blk)); + ut_assertok(device_probe(blk)); + + /* There should be a GPT partition table in this device */ + ut_asserteq(0, uclass_first_device_err(UCLASS_PARTITION, &part)); + + /* Write a boot block and verify that we get the same data back */ + desc = dev_get_uclass_plat(blk); + ut_asserteq(true, desc->removable); + ut_asserteq(LBA, desc->lba); + + memset(write, '\0', BLK_SIZE); + + for (i = BLK_SIZE; i < sizeof(write); i++) + write[i] = i; + + sec0 = (struct sector0 *)write; + sec0->magic = 0x0FF0AA55; + sec0->rc4_flag = 0; + sec0->boot_code1_offset = 4; + sec0->boot_code2_offset = 4; + sec0->flash_data_size = 4; + sec0->flash_boot_size = 8; + + rkmtd_rc4(write, 512); + ut_asserteq(RK_TAG, sec0->magic); + + ut_asserteq(12, blk_dwrite(desc, 64, 12, write)); + ut_asserteq(12, blk_dread(desc, 64, 12, read)); + ut_asserteq_mem(write, read, RW_BUF_SIZE); + + ut_assertok(rkmtd_detach(dev)); + + ut_asserteq(-ENODEV, blk_get_from_parent(dev, &blk)); + ut_assertok(device_unbind(dev)); + + return 0; +} +DM_TEST(dm_test_rkmtd, UT_TESTF_SCAN_FDT); + +/* Reusing the same label should work */ +static int dm_test_rkmtd_dup(struct unit_test_state *uts) +{ + static const char label[] = "test"; + struct udevice *dev, *chk; + + /* Create a RKMTD device with label "test" */ + ut_asserteq(0, uclass_id_count(UCLASS_RKMTD)); + ut_assertok(rkmtd_create_device(label, &dev)); + ut_assertok(rkmtd_attach(dev)); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &chk)); + ut_asserteq_ptr(chk, dev); + ut_asserteq(1, uclass_id_count(UCLASS_RKMTD)); + + /* Create another device with the same label (should remove old one) */ + ut_assertok(rkmtd_create_device(label, &dev)); + ut_assertok(rkmtd_attach(dev)); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &chk)); + ut_asserteq_ptr(chk, dev); + + /* Make sure there is still only one device */ + ut_asserteq(1, uclass_id_count(UCLASS_RKMTD)); + + return 0; +} +DM_TEST(dm_test_rkmtd_dup, UT_TESTF_SCAN_FDT); + +/* Basic test of the 'rkmtd' command */ +static int dm_test_rkmtd_cmd(struct unit_test_state *uts) +{ + struct udevice *dev, *blk; + struct blk_desc *desc; + + /* First check 'rkmtd info' with binding */ + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_console_end(); + + /* Bind device 1 */ + ut_assertok(run_commandf("rkmtd bind test1")); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &dev)); + ut_assertok(blk_get_from_parent(dev, &blk)); + desc = dev_get_uclass_plat(blk); + + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 0 609 test1 "); + ut_assert_console_end(); + + /* Bind device 2 */ + ut_assertok(run_commandf("rkmtd bind test2")); + ut_assertok(uclass_next_device_err(&dev)); + ut_assertok(blk_get_from_parent(dev, &blk)); + desc = dev_get_uclass_plat(blk); + + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 0 609 test1 "); + ut_assert_nextline(" 1 609 test2 "); + ut_assert_console_end(); + + ut_asserteq(1, run_command("rkmtd info test", 0)); + ut_assert_nextline("No such device 'test'"); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd info test2", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 1 609 test2 "); + ut_assert_console_end(); + + /* Check 'rkmtd dev' */ + ut_asserteq(1, run_command("rkmtd dev", 0)); + ut_assert_nextline("No current rkmtd device"); + ut_assert_console_end(); + + ut_asserteq(1, run_command("rkmtd dev missing", 0)); + ut_assert_nextline("No such device 'missing'"); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd dev test2", 0)); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd dev", 0)); + ut_assert_nextline("Current rkmtd device: 1: test2"); + ut_assert_console_end(); + + /* Try a numerical label */ + ut_assertok(run_command("rkmtd dev 0", 0)); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd dev", 0)); + ut_assert_nextline("Current rkmtd device: 0: test1"); + ut_assert_console_end(); + + /* Remove one of the bindings */ + ut_assertok(run_commandf("rkmtd unbind test1")); + + /* There should now be no current device */ + ut_asserteq(1, run_command("rkmtd dev", 0)); + ut_assert_nextline("No current rkmtd device"); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 1 609 test2 "); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_rkmtd_cmd, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC); -- 2.39.2

Add documention for Rockchip rkmtd virtual block device.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Kever Yang kever.yang@rock-chips.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changed V3: New patch --- doc/board/rockchip/index.rst | 1 + doc/board/rockchip/rkmtd.rst | 105 +++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 doc/board/rockchip/rkmtd.rst
diff --git a/doc/board/rockchip/index.rst b/doc/board/rockchip/index.rst index 0c377e9bbba0..9a87a035e95e 100644 --- a/doc/board/rockchip/index.rst +++ b/doc/board/rockchip/index.rst @@ -8,3 +8,4 @@ Rockchip :maxdepth: 2
rockchip + rkmtd diff --git a/doc/board/rockchip/rkmtd.rst b/doc/board/rockchip/rkmtd.rst new file mode 100644 index 000000000000..1481380ba6c5 --- /dev/null +++ b/doc/board/rockchip/rkmtd.rst @@ -0,0 +1,105 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2023 Johan Jonker jbx6244@gmail.com + +RKMTD +===== + +Info +---- + +The command rkmtd creates a virtual block device to transfer +Rockchip boot block data to and from NAND with block orientated +tools like "ums" and "rockusb". + +It uses the Rockchip MTD driver to scan for boot blocks and copies +data from the first block in a GPT formatted virtual disk. +Data must be written in U-boot "idbloader.img" format and start at +partition "loader1" offset 64. The data header is parsed +for length and offset. When the last sector is received +it erases up to 5 erase blocks on NAND and writes boot blocks +in a pattern depending on the NAND ID. Data is then verified. +When a block turns out bad the block header is discarded. + +Limitations +----------- + +- Support with CONFIG_ROCKCHIP_NAND MTD driver only. +- Support for Rockchip boot block header type 1 only. +- Pattern for listed NAND IDs only. (Logic still not disclosed by Rockchip) +- The MTD framework driver data and NAND ID must be extracted at a lower level. + +Available rkmtd commands +------------------------ + +.. code-block:: bash + + rkmtd bind <label> - bind RKMTD device + rkmtd unbind <label> - unbind RKMTD device + rkmtd info [<label>] - show all available RKMTD devices + rkmtd dev [<label>] - show or set current RKMTD device + +U-boot settings +--------------- + +Config to enable Rockchip MTD support: + +.. code-block:: bash + + CONFIG_MTD=y + CONFIG_MTD_RAW_NAND=y + CONFIG_SYS_NAND_DRIVER_ECC_LAYOUT=y + CONFIG_SYS_NAND_USE_FLASH_BBT=y + CONFIG_ROCKCHIP_NAND=y + +Option to keep existing NAND data unchanged: + +.. code-block:: bash + + CONFIG_ROCKCHIP_NAND_SKIP_BBTSCAN=y + +Commands to enable: + +.. code-block:: bash + + CONFIG_CMD_USB=y + CONFIG_CMD_RKMTD=y + CONFIG_CMD_ROCKUSB=y + CONFIG_CMD_USB_MASS_STORAGE=y + +Linux Host (PC) tool commands combinations that work +---------------------------------------------------- + +.. table:: + :widths: 20 44 + + ==================== ============================================ + U-boot Linux + ==================== ============================================ + rkmtd bind 0 + rockusb 0 rkmtd 0 + upgrade_tool pl + + upgrade_tool rl 64 512 idbloader_backup.img + + upgrade_tool wl 64 idbloader.img + + upgrade_tool rd + + rkdeveloptool ppt + + rkdeveloptool rl 64 512 idbloader_backup.img + + rkdeveloptool wlx loader1 idbloader.img + + rkdeveloptool wl 64 idbloader.img + + rkdeveloptool rd + + rkflashtool r 64 512 > idbloader_backup.img + + rkflashtool w 64 512 < idbloader.img + ums 0 rkmtd 0 + dd if=/dev/sda1 of=idbloader_backup.img + + dd if=idbloader.img of=/dev/sda1 + ==================== ============================================ -- 2.39.2

Enable rkmtd command for testing with sandbox_defconfig and sandbox64_defconfig.
Signed-off-by: Johan Jonker jbx6244@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changed V3: New patch --- configs/sandbox64_defconfig | 1 + configs/sandbox_defconfig | 1 + 2 files changed, 2 insertions(+)
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 1a033b22018b..1a01f51a0b75 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -58,6 +58,7 @@ CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SPI=y CONFIG_CMD_TEMPERATURE=y CONFIG_CMD_USB=y +CONFIG_CMD_RKMTD=y CONFIG_CMD_WDT=y CONFIG_CMD_WRITE=y CONFIG_CMD_CAT=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 01830c7bd255..cc54e6dec5af 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -84,6 +84,7 @@ CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SPI=y CONFIG_CMD_TEMPERATURE=y CONFIG_CMD_USB=y +CONFIG_CMD_RKMTD=y CONFIG_CMD_WDT=y CONFIG_CMD_WRITE=y CONFIG_CMD_AXI=y -- 2.39.2
participants (2)
-
Johan Jonker
-
Simon Glass