diff --git a/u-boot/Kconfig b/u-boot/Kconfig
index 548950970a..7c0af1e5ca 100644
--- a/u-boot/Kconfig
+++ b/u-boot/Kconfig
@@ -168,6 +168,12 @@ endmenu		# General setup
 
 menu "Boot images"
 
+config IMAGE_GZIP
+	bool "U-Boot Image with gzip compression"
+	default n
+	help
+	  This enables gzip compression on U-Boot Image.
+
 config ANDROID_BOOT_IMAGE
 	bool "Enable support for Android Boot Images"
 	default y if FASTBOOT
diff --git a/u-boot/Makefile b/u-boot/Makefile
index 590fd4c1f2..1012b065ad 100644
--- a/u-boot/Makefile
+++ b/u-boot/Makefile
@@ -85,6 +85,13 @@ else
   Q = @
 endif
 
+ifeq ("$(origin FWVER)", "command line")
+  PLAT_FW_VERSION := $(FWVER)
+endif
+ifeq ("$(origin SPL_FWVER)", "command line")
+  PLAT_SPL_FW_VERSION := $(SPL_FWVER)
+endif
+
 # If the user is running make -s (silent mode), suppress echoing of
 # commands
 
@@ -1369,6 +1376,12 @@ ifeq ($(CONFIG_SUPPORT_USBPLUG),)
 define filechk_version.h
 	(echo \#define PLAIN_VERSION \"$(UBOOTRELEASE)\"; \
 	echo \#define U_BOOT_VERSION \"U-Boot \" PLAIN_VERSION; \
+	if [ -n "$(PLAT_SPL_FW_VERSION)" ]; then \
+		echo \#define BUILD_SPL_TAG \"$(PLAT_SPL_FW_VERSION)\"; \
+	fi; \
+	if [ -n "$(PLAT_FW_VERSION)" ]; then \
+        echo \#define BUILD_TAG \"$(PLAT_FW_VERSION)\"; \
+	fi; \
 	echo \#define CC_VERSION_STRING \"$$(LC_ALL=C $(CC) --version | head -n 1)\"; \
 	echo \#define LD_VERSION_STRING \"$$(LC_ALL=C $(LD) --version | head -n 1)\"; )
 endef
@@ -1376,6 +1389,12 @@ else
 define filechk_version.h
         (echo \#define PLAIN_VERSION \"$(UBOOTRELEASE)\"; \
         echo \#define U_BOOT_VERSION \"USB-PLUG \" PLAIN_VERSION; \
+        if [ -n "$(PLAT_SPL_FW_VERSION)" ]; then \
+            echo \#define BUILD_SPL_TAG \"$(PLAT_SPL_FW_VERSION)\"; \
+        fi; \
+        if [ -n "$(PLAT_FW_VERSION)" ]; then \
+            echo \#define BUILD_TAG \"$(PLAT_FW_VERSION)\"; \
+        fi; \
         echo \#define CC_VERSION_STRING \"$$(LC_ALL=C $(CC) --version | head -n 1)\"; \
         echo \#define LD_VERSION_STRING \"$$(LC_ALL=C $(LD) --version | head -n 1)\"; )
 endef
diff --git a/u-boot/arch/arm/cpu/armv7/arch_timer.c b/u-boot/arch/arm/cpu/armv7/arch_timer.c
index 545c518506..c4400a061c 100644
--- a/u-boot/arch/arm/cpu/armv7/arch_timer.c
+++ b/u-boot/arch/arm/cpu/armv7/arch_timer.c
@@ -41,5 +41,5 @@ ulong timer_get_boot_us(void)
 
 ulong get_tbclk(void)
 {
-	return gd->arch.timer_rate_hz;
+	return gd->arch.timer_rate_hz ? : CONFIG_SYS_HZ_CLOCK;
 }
diff --git a/u-boot/arch/arm/dts/rk3308.dtsi b/u-boot/arch/arm/dts/rk3308.dtsi
index acdb47f55d..e646bddb13 100644
--- a/u-boot/arch/arm/dts/rk3308.dtsi
+++ b/u-boot/arch/arm/dts/rk3308.dtsi
@@ -300,7 +300,7 @@
 		#pwm-cells = <3>;
 		pinctrl-names = "active";
 		pinctrl-0 = <&pwm0_pin>;
-		clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
+		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM>;
 		clock-names = "pwm", "pclk";
 		status = "disabled";
 	};
@@ -311,7 +311,7 @@
 		#pwm-cells = <3>;
 		pinctrl-names = "active";
 		pinctrl-0 = <&pwm1_pin>;
-		clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
+		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM>;
 		clock-names = "pwm", "pclk";
 		status = "disabled";
 	};
@@ -322,7 +322,7 @@
 		#pwm-cells = <3>;
 		pinctrl-names = "active";
 		pinctrl-0 = <&pwm2_pin>;
-		clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
+		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM>;
 		clock-names = "pwm", "pclk";
 		status = "disabled";
 	};
@@ -333,7 +333,7 @@
 		#pwm-cells = <3>;
 		pinctrl-names = "active";
 		pinctrl-0 = <&pwm3_pin>;
-		clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
+		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM>;
 		clock-names = "pwm", "pclk";
 		status = "disabled";
 	};
diff --git a/u-boot/arch/arm/dts/rk3528-u-boot.dtsi b/u-boot/arch/arm/dts/rk3528-u-boot.dtsi
index 7d093617e7..405af02872 100644
--- a/u-boot/arch/arm/dts/rk3528-u-boot.dtsi
+++ b/u-boot/arch/arm/dts/rk3528-u-boot.dtsi
@@ -37,6 +37,11 @@
 	status = "okay";
 };
 
+&combphy_pu {
+	u-boot,dm-pre-reloc;
+	status = "okay";
+};
+
 &cru {
 	/delete-property/ assigned-clocks;
 	/delete-property/ assigned-clock-rates;
diff --git a/u-boot/arch/arm/dts/rk3568-u-boot.dtsi b/u-boot/arch/arm/dts/rk3568-u-boot.dtsi
index a0678e35db..77abf24a3e 100644
--- a/u-boot/arch/arm/dts/rk3568-u-boot.dtsi
+++ b/u-boot/arch/arm/dts/rk3568-u-boot.dtsi
@@ -387,7 +387,7 @@
 };
 
 &pinctrl {
-	u-boot,dm-pre-reloc;
+	u-boot,dm-spl;
 	status = "okay";
 };
 
diff --git a/u-boot/arch/arm/dts/rk3588-u-boot.dtsi b/u-boot/arch/arm/dts/rk3588-u-boot.dtsi
index d0b82f64b7..8dbc5d688e 100644
--- a/u-boot/arch/arm/dts/rk3588-u-boot.dtsi
+++ b/u-boot/arch/arm/dts/rk3588-u-boot.dtsi
@@ -193,6 +193,24 @@
 	status = "okay";
 };
 
+&usb_grf{
+	u-boot,dm-pre-reloc;
+};
+
+&usbdpphy0_grf{
+	u-boot,dm-pre-reloc;
+};
+
+&usbdp_phy0{
+	u-boot,dm-pre-reloc;
+	status = "okay";
+};
+
+&usbdp_phy0_u3{
+	u-boot,dm-pre-reloc;
+	status = "okay";
+};
+
 /* Support SPL-PINCTRL:
  * 1. ioc
  * 2. pinctrl(sdmmc)
diff --git a/u-boot/arch/arm/dts/rk3588.dtsi b/u-boot/arch/arm/dts/rk3588.dtsi
index fbffe36daf..c75f661bee 100644
--- a/u-boot/arch/arm/dts/rk3588.dtsi
+++ b/u-boot/arch/arm/dts/rk3588.dtsi
@@ -467,6 +467,7 @@
 	usbdp_phy1: phy@fed90000 {
 		compatible = "rockchip,rk3588-usbdp-phy";
 		reg = <0x0 0xfed90000 0x0 0x10000>;
+		rockchip,u2phy-grf = <&usb2phy1_grf>;
 		rockchip,usb-grf = <&usb_grf>;
 		rockchip,usbdpphy-grf = <&usbdpphy1_grf>;
 		rockchip,vo-grf = <&vo0_grf>;
diff --git a/u-boot/arch/arm/dts/rk3588s.dtsi b/u-boot/arch/arm/dts/rk3588s.dtsi
index ebe8761ac1..d97ed1b4d5 100644
--- a/u-boot/arch/arm/dts/rk3588s.dtsi
+++ b/u-boot/arch/arm/dts/rk3588s.dtsi
@@ -2260,6 +2260,7 @@
 	usbdp_phy0: phy@fed80000 {
 		compatible = "rockchip,rk3588-usbdp-phy";
 		reg = <0x0 0xfed80000 0x0 0x10000>;
+		rockchip,u2phy-grf = <&usb2phy0_grf>;
 		rockchip,usb-grf = <&usb_grf>;
 		rockchip,usbdpphy-grf = <&usbdpphy0_grf>;
 		rockchip,vo-grf = <&vo0_grf>;
diff --git a/u-boot/arch/arm/dts/rv1106-evb.dts b/u-boot/arch/arm/dts/rv1106-evb.dts
index 344558f8f9..06a03d3329 100644
--- a/u-boot/arch/arm/dts/rv1106-evb.dts
+++ b/u-boot/arch/arm/dts/rv1106-evb.dts
@@ -30,3 +30,7 @@
 	};
 };
 
+&hw_decompress {
+	u-boot,dm-spl;
+	status = "okay";
+};
diff --git a/u-boot/arch/arm/dts/rv1106-evb2.dts b/u-boot/arch/arm/dts/rv1106-evb2.dts
index 71ad07be7c..7b9d9dc68b 100644
--- a/u-boot/arch/arm/dts/rv1106-evb2.dts
+++ b/u-boot/arch/arm/dts/rv1106-evb2.dts
@@ -22,7 +22,7 @@
 		compatible = "adc-keys";
 		io-channels = <&saradc 0>;
 		io-channel-names = "buttons";
-		keyup-threshold-microvolt = <1800000>;
+		keyup-threshold-microvolt = <893000>;
 		u-boot,dm-spl;
 		status = "okay";
 
@@ -30,6 +30,13 @@
 			u-boot,dm-spl;
 			linux,code = <KEY_VOLUMEUP>;
 			label = "volume up";
+			press-threshold-microvolt = <339589>;
+		};
+
+		volumedown-key {
+			u-boot,dm-spl;
+			linux,code = <KEY_VOLUMEDOWN>;
+			label = "volume down";
 			press-threshold-microvolt = <17578>;
 		};
 	};
diff --git a/u-boot/arch/arm/dts/rv1106.dtsi b/u-boot/arch/arm/dts/rv1106.dtsi
index dba1d8c865..7a88bb13eb 100644
--- a/u-boot/arch/arm/dts/rv1106.dtsi
+++ b/u-boot/arch/arm/dts/rv1106.dtsi
@@ -861,8 +861,11 @@
 	wdt: watchdog@ff5a0000 {
 		compatible = "rockchip,rv1106-wdt", "snps,dw-wdt";
 		reg = <0xff5a0000 0x100>;
-		clocks = <&cru PCLK_WDT_NS>;
+		clocks = <&cru TCLK_WDT_NS>, <&cru PCLK_WDT_NS>;
+		clock-names = "tclk", "pclk";
 		interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+		resets = <&cru SRST_P_WDT_NS>;
+		reset-names = "reset";
 		status = "disabled";
 	};
 
diff --git a/u-boot/arch/arm/include/asm/arch-rockchip/cru_rk3528.h b/u-boot/arch/arm/include/asm/arch-rockchip/cru_rk3528.h
index 3576b03c21..6be2648d5b 100644
--- a/u-boot/arch/arm/include/asm/arch-rockchip/cru_rk3528.h
+++ b/u-boot/arch/arm/include/asm/arch-rockchip/cru_rk3528.h
@@ -124,10 +124,10 @@ struct pll_rate_table {
 #define RK3528_PCIE_CLKSEL_CON(x)		((x) * 0x4 + 0x300 + RK3528_PCIE_CRU_BASE)
 #define RK3528_DDRPHY_MODE_CON			(0x280 + RK3528_DDRPHY_CRU_BASE)
 
-#define RK3528_DIV_ACLK_M_CORE_MASK		0x1f
 #define RK3528_DIV_ACLK_M_CORE_SHIFT		11
-#define RK3528_DIV_PCLK_DBG_MASK		0x1f
+#define RK3528_DIV_ACLK_M_CORE_MASK		(0x1f << RK3528_DIV_ACLK_M_CORE_SHIFT)
 #define RK3528_DIV_PCLK_DBG_SHIFT		1
+#define RK3528_DIV_PCLK_DBG_MASK		(0x1f << RK3528_DIV_PCLK_DBG_SHIFT)
 
 enum {
 	/* CRU_CLKSEL_CON00 */
diff --git a/u-boot/arch/arm/include/asm/arch-rockchip/rk_atags.h b/u-boot/arch/arm/include/asm/arch-rockchip/rk_atags.h
index 5b9a17d515..efc0189f41 100644
--- a/u-boot/arch/arm/include/asm/arch-rockchip/rk_atags.h
+++ b/u-boot/arch/arm/include/asm/arch-rockchip/rk_atags.h
@@ -21,6 +21,7 @@
 #define ATAG_SOC_INFO		0x54410057
 #define ATAG_BOOT1_PARAM	0x54410058
 #define ATAG_PSTORE		0x54410059
+#define ATAG_FWVER		0x5441005a
 #define ATAG_MAX		0x544100ff
 
 /* Tag size and offset */
@@ -75,6 +76,17 @@
 /* tag_ddr_mem.flags */
 #define DDR_MEM_FLG_EXT_TOP	1
 
+/* tag_fwver.ver[fwid][] */
+#define FWVER_LEN		36
+
+enum fwid {
+	FW_DDR,
+	FW_SPL,
+	FW_ATF,
+	FW_TEE,
+	FW_MAX,
+};
+
 struct tag_serial {
 	u32 version;
 	u32 enable;
@@ -183,6 +195,12 @@ struct tag_pstore {
 	u32 hash;
 } __packed;
 
+struct tag_fwver {
+	u32 version;
+	char ver[8][FWVER_LEN];
+	u32 hash;
+} __packed;
+
 struct tag_core {
 	u32 flags;
 	u32 pagesize;
@@ -209,6 +227,7 @@ struct tag {
 		struct tag_soc_info	soc;
 		struct tag_boot1p	boot1p;
 		struct tag_pstore	pstore;
+		struct tag_fwver	fwver;
 	} u;
 } __aligned(4);
 
@@ -266,6 +285,13 @@ int atags_overflow(struct tag *t);
  */
 int atags_bad_magic(u32 magic);
 
+/*
+ * atags_set_shared_fwver - set fwver tag.
+ *
+ * return: 0 on success, otherwise failed.
+ */
+int atags_set_shared_fwver(u32 fwid, char *ver);
+
 #ifdef CONFIG_SPL_BUILD
 /*
  * get_bootdev_by_brom_bootsource
diff --git a/u-boot/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h b/u-boot/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h
index 39bafbc0a3..afe6c5e9df 100644
--- a/u-boot/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h
+++ b/u-boot/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h
@@ -95,6 +95,7 @@ typedef enum {
 	SHARE_PAGE_TYPE_DDR_ADDRMAP,
 	SHARE_PAGE_TYPE_LAST_LOG,
 	SHARE_PAGE_TYPE_HDCP,
+	SHARE_PAGE_TYPE_SLEEP,
 	SHARE_PAGE_TYPE_MAX,
 } share_page_type_t;
 
diff --git a/u-boot/arch/arm/lib/interrupts_64.c b/u-boot/arch/arm/lib/interrupts_64.c
index 17271d061f..e51d38a8a4 100644
--- a/u-boot/arch/arm/lib/interrupts_64.c
+++ b/u-boot/arch/arm/lib/interrupts_64.c
@@ -10,6 +10,9 @@
 #include <efi_loader.h>
 #include <iomem.h>
 #include <stacktrace.h>
+#ifdef CONFIG_ROCKCHIP_MINIDUMP
+#include <rk_mini_dump.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -181,6 +184,13 @@ void do_bad_error(struct pt_regs *pt_regs, unsigned int esr)
 void do_sync(struct pt_regs *pt_regs, unsigned int esr)
 {
 	efi_restore_gd();
+#ifdef CONFIG_ROCKCHIP_MINIDUMP
+	if (md_no_fault_handler(pt_regs, esr)) {
+		/* Return to next instruction */
+		pt_regs->elr += 4;
+		return;
+	}
+#endif
 	printf("\"Synchronous Abort\" handler, esr 0x%08x\n", esr);
 	show_regs(pt_regs);
 	panic("Resetting CPU ...\n");
@@ -219,6 +229,13 @@ void do_fiq(struct pt_regs *pt_regs, unsigned int esr)
 void __weak do_error(struct pt_regs *pt_regs, unsigned int esr)
 {
 	efi_restore_gd();
+#ifdef CONFIG_ROCKCHIP_MINIDUMP
+	if (md_no_fault_handler(pt_regs, esr)) {
+		/* Return to next instruction */
+		pt_regs->elr += 4;
+		return;
+	}
+#endif
 	printf("\"Error\" handler, esr 0x%08x\n", esr);
 	show_regs(pt_regs);
 	panic("Resetting CPU ...\n");
diff --git a/u-boot/arch/arm/mach-rockchip/Kconfig b/u-boot/arch/arm/mach-rockchip/Kconfig
index 383503ddeb..f76eb1868e 100644
--- a/u-boot/arch/arm/mach-rockchip/Kconfig
+++ b/u-boot/arch/arm/mach-rockchip/Kconfig
@@ -487,7 +487,7 @@ config TPL_LDSCRIPT
 	default "arch/arm/mach-rockchip/u-boot-tpl-v8.lds"
 
 config TPL_TEXT_BASE
-	default 0xfdcc1000
+	default 0xff001000
 
 config TPL_MAX_SIZE
 	default 61440
@@ -846,7 +846,7 @@ config ROCKCHIP_HWID_DTB
 
 config ROCKCHIP_VENDOR_PARTITION
 	bool "Rockchip vendor storage partition support"
-	depends on RKIMG_BOOTLOADER
+	depends on (RKIMG_BOOTLOADER || SUPPORT_USBPLUG)
 	help
 	  This enable support to read/write vendor configuration data from/to
 	  this partition.
@@ -1101,6 +1101,33 @@ config PERSISTENT_RAM_SIZE
 	  This select linux pstore buffer size for U-Boot, the value must be
 	  set if PERSISTENT_RAM_ADDR != 0.
 
+config ROCKCHIP_MINIDUMP
+	bool "Minidump Save Linux Debug Data To Ram Elf"
+	default n
+	help
+	  This enable saving linux debug data to a reserved memory as a elf file.
+
+config ROCKCHIP_MINIDUMP_SMEM_BASE
+	hex "The base of share memory between Uboot and Linux"
+	default 0x1f0000
+	depends on ROCKCHIP_MINIDUMP
+	help
+	  This select the base address of share memory, which is behind PSTORE.
+
+config ROCKCHIP_MINIDUMP_MAX_ELF_SIZE
+	hex "The max size of minidump elf"
+	default 0x2000000
+	depends on ROCKCHIP_MINIDUMP
+	help
+	  This is used to judge the elf program size and section size.
+
+config ROCKCHIP_MINIDUMP_MAX_ENTRIES
+	hex "The max entries of minidump region"
+	default 0x200
+	depends on ROCKCHIP_MINIDUMP
+	help
+	  This sets the max entries of minidump region.
+
 source "arch/arm/mach-rockchip/px30/Kconfig"
 source "arch/arm/mach-rockchip/rk3036/Kconfig"
 source "arch/arm/mach-rockchip/rk3066/Kconfig"
diff --git a/u-boot/arch/arm/mach-rockchip/Makefile b/u-boot/arch/arm/mach-rockchip/Makefile
index 75de030b8f..095f99d907 100644
--- a/u-boot/arch/arm/mach-rockchip/Makefile
+++ b/u-boot/arch/arm/mach-rockchip/Makefile
@@ -92,3 +92,5 @@ obj-$(CONFIG_TPL_BUILD) += $(obj-tpl-y)
 obj-$(CONFIG_ROCKCHIP_PRELOADER_ATAGS) += rk_atags.o
 obj-$(CONFIG_SET_DFU_ALT_INFO) += dfu_alt_info.o
 obj-$(CONFIG_PSTORE) += pstore.o
+obj-$(CONFIG_ROCKCHIP_MINIDUMP) += rk_mini_dump.o
+
diff --git a/u-boot/arch/arm/mach-rockchip/board.c b/u-boot/arch/arm/mach-rockchip/board.c
index 00a705c208..6121bb8ce5 100644
--- a/u-boot/arch/arm/mach-rockchip/board.c
+++ b/u-boot/arch/arm/mach-rockchip/board.c
@@ -5,6 +5,8 @@
  */
 
 #include <common.h>
+#include <version.h>
+#include <abuf.h>
 #include <amp.h>
 #include <android_ab.h>
 #include <android_bootloader.h>
@@ -26,6 +28,7 @@
 #include <of_live.h>
 #include <mtd_blk.h>
 #include <ram.h>
+#include <rng.h>
 #include <rockchip_debugger.h>
 #include <syscon.h>
 #include <sysmem.h>
@@ -53,8 +56,9 @@
 #ifdef CONFIG_ROCKCHIP_EINK_DISPLAY
 #include <rk_eink.h>
 #endif
-
-DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_ROCKCHIP_MINIDUMP
+#include <rk_mini_dump.h>
+#endif
 
 #ifdef CONFIG_ARM64
 static ulong orig_images_ep;
@@ -98,7 +102,6 @@ __weak int rk_board_init(void)
  */
 #define VENDOR_SN_MAX	513
 #define CPUID_LEN	0x10
-#define CPUID_OFF	0x07
 
 #define MAX_ETHERNET	0x2
 
@@ -175,10 +178,13 @@ static int rockchip_set_serialno(void)
 		for (i = 0; i < j; i++) {
 			if ((serialno_str[i] >= 'a' && serialno_str[i] <= 'z') ||
 			    (serialno_str[i] >= 'A' && serialno_str[i] <= 'Z') ||
-			    (serialno_str[i] >= '0' && serialno_str[i] <= '9'))
+			    (serialno_str[i] >= '0' && serialno_str[i] <= '9')) {
 				continue;
-			else
+			} else {
+				if (i > 0)
+					serialno_str[i] = 0x0;
 				break;
+			}
 		}
 
 		/* valid character count > 0 */
@@ -208,7 +214,7 @@ static int rockchip_set_serialno(void)
 		}
 
 		/* read the cpu_id range from the efuses */
-		ret = misc_read(dev, CPUID_OFF, &cpuid, sizeof(cpuid));
+		ret = misc_read(dev, CFG_CPUID_OFFSET, &cpuid, sizeof(cpuid));
 		if (ret) {
 			printf("%s: read cpuid from efuse/otp failed, ret=%d\n",
 			       __func__, ret);
@@ -461,6 +467,11 @@ int board_late_init(void)
 #ifdef CONFIG_DM_CHARGE_DISPLAY
 	charge_display();
 #endif
+
+#ifdef CONFIG_ROCKCHIP_MINIDUMP
+	rk_minidump_init();
+#endif
+
 #ifdef CONFIG_DRM_ROCKCHIP
 	if (rockchip_get_boot_mode() != BOOT_MODE_QUIESCENT)
 		rockchip_show_logo();
@@ -544,7 +555,6 @@ int board_init(void)
 	if (ab_decrease_tries())
 		printf("Decrease ab tries count fail!\n");
 #endif
-
 	return rk_board_init();
 }
 
@@ -894,7 +904,7 @@ int bootm_board_start(void)
 	 * we switch to uart debug function in order to print it after loading
 	 * images.
 	 */
-#if defined(CONFIG_CONSOLE_RECORD)
+#if 0
 	if (!strcmp("mmc", env_get("devtype")) &&
 	    !strcmp("1", env_get("devnum"))) {
 		printf("IOMUX: sdmmc => uart debug");
@@ -1115,47 +1125,142 @@ void board_quiesce_devices(void *images)
 #endif
 }
 
-char *board_fdt_chosen_bootargs(void *fdt)
+/*
+ * Use hardware rng to seed Linux random
+ *
+ * 'Android_14 + GKI' requires this information.
+ */
+int board_rng_seed(struct abuf *buf)
 {
-	/* bootargs_ext is used when dtbo is applied. */
-	const char *arr_bootargs[] = { "bootargs", "bootargs_ext" };
-	const char *bootargs;
-	int nodeoffset;
-	int i, dump;
-	char *msg = "kernel";
-
-	/* debug */
-	hotkey_run(HK_INITCALL);
-	dump = is_hotkey(HK_CMDLINE);
-	if (dump)
-		printf("## bootargs(u-boot): %s\n\n", env_get("bootargs"));
-
-	/* find or create "/chosen" node. */
-	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-	if (nodeoffset < 0)
-		return NULL;
-
-	for (i = 0; i < ARRAY_SIZE(arr_bootargs); i++) {
-		bootargs = fdt_getprop(fdt, nodeoffset, arr_bootargs[i], NULL);
-		if (!bootargs)
-			continue;
-		if (dump)
-			printf("## bootargs(%s-%s): %s\n\n",
-			       msg, arr_bootargs[i], bootargs);
-		/*
-		 * Append kernel bootargs
-		 * If use AB system, delete default "root=" which route
-		 * to rootfs. Then the ab bootctl will choose the
-		 * high priority system to boot and add its UUID
-		 * to cmdline. The format is "roo=PARTUUID=xxxx...".
-		 */
-#ifdef CONFIG_ANDROID_AB
-		env_update_filter("bootargs", bootargs, "root=");
-#else
-		env_update("bootargs", bootargs);
+#ifdef CONFIG_DM_RNG
+	struct udevice *dev;
 #endif
+	size_t len = 32;
+	u8 *data;
+	int i;
+
+	data = malloc(len);
+	if (!data) {
+	        printf("Out of memory\n");
+	        return -ENOMEM;
 	}
 
+#ifdef CONFIG_DM_RNG
+	if (uclass_get_device(UCLASS_RNG, 0, &dev) || dm_rng_read(dev, data, len))
+#endif
+	{
+		printf("board seed: Pseudo\n");
+		for (i = 0; i < len; i++)
+			data[i] = (u8)rand();
+	}
+
+	abuf_init_set(buf, data, len);
+
+	return 0;
+}
+
+/*
+ * Pass fwver when any available.
+ */
+static void bootargs_add_fwver(bool verbose)
+{
+#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
+	struct tag *t;
+	char *list1 = NULL;
+	char *list2 = NULL;
+	char *fwver = NULL;
+	char *p = PLAIN_VERSION;
+	int i, end;
+
+	t = atags_get_tag(ATAG_FWVER);
+	if (t) {
+		list1 = calloc(1, sizeof(struct tag_fwver));
+		if (!list1)
+			return;
+		for (i = 0; i < FW_MAX; i++) {
+			if (t->u.fwver.ver[i][0] != '\0') {
+				strcat(list1, t->u.fwver.ver[i]);
+				strcat(list1, ",");
+			}
+		}
+	}
+
+	list2 = calloc(1, FWVER_LEN);
+	if (!list2)
+		goto out;
+	strcat(list2, "uboot-");
+	/* optional */
+#ifdef BUILD_TAG
+	strcat(list2, BUILD_TAG);
+	strcat(list2, "-");
+#endif
+	/* optional */
+	if (strcmp(PLAIN_VERSION, "2017.09")) {
+		strncat(list2, p + strlen("2017.09-g"), 10);
+		strcat(list2, "-");
+	}
+	strcat(list2, U_BOOT_DMI_DATE);
+
+	/* merge ! */
+	if (list1 || list2) {
+		fwver = calloc(1, sizeof(struct tag_fwver));
+		if (!fwver)
+			goto out;
+
+		strcat(fwver, "androidboot.fwver=");
+		if (list1)
+			strcat(fwver, list1);
+		if (list2) {
+			strcat(fwver, list2);
+		} else {
+			end = strlen(fwver) - 1;
+			fwver[end] = '\0'; /* omit last ',' */
+		}
+		if (verbose)
+			printf("## fwver: %s\n\n", fwver);
+		env_update("bootargs", fwver);
+		env_set("fwver", fwver + strlen("androidboot."));
+	}
+out:
+	if (list1)
+		free(list1);
+	if (list2)
+		free(list2);
+	if (fwver)
+		free(fwver);
+#endif
+}
+
+static void bootargs_add_android(bool verbose)
+{
+#ifdef CONFIG_ANDROID_AB
+	ab_update_root_partition();
+#endif
+
+	/* Android header v4+ need this handle */
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	struct andr_img_hdr *hdr;
+	char *fwver;
+
+	hdr = (void *)env_get_ulong("android_addr_r", 16, 0);
+	if (hdr && !android_image_check_header(hdr) && hdr->header_version >= 4) {
+		if (env_update_extract_subset("bootargs", "andr_bootargs", "androidboot."))
+			printf("extract androidboot.xxx error\n");
+		if (verbose)
+			printf("## bootargs(android): %s\n\n", env_get("andr_bootargs"));
+
+		/* for kernel cmdline can be read */
+		fwver = env_get("fwver");
+		if (fwver) {
+			env_update("bootargs", fwver);
+			env_set("fwver", NULL);
+		}
+	}
+#endif
+}
+
+static void bootargs_add_partition(bool verbose)
+{
 #if defined(CONFIG_ENVF) || defined(CONFIG_ENV_PARTITION)
 	char *part_type[] = { "mtdparts", "blkdevparts" };
 	char *part_list;
@@ -1177,14 +1282,14 @@ char *board_fdt_chosen_bootargs(void *fdt)
 			part_list = env;
 		}
 		env_update("bootargs", part_list);
-		if (dump)
+		if (verbose)
 			printf("## parts: %s\n\n", part_list);
 	}
 
 	env = env_get("sys_bootargs");
 	if (env) {
 		env_update("bootargs", env);
-		if (dump)
+		if (verbose)
 			printf("## sys_bootargs: %s\n\n", env);
 	}
 #endif
@@ -1199,10 +1304,58 @@ char *board_fdt_chosen_bootargs(void *fdt)
 		}
 	}
 #endif
+}
 
+static void bootargs_add_dtb_dtbo(void *fdt, bool verbose)
+{
+	/* bootargs_ext is used when dtbo is applied. */
+	const char *arr_bootargs[] = { "bootargs", "bootargs_ext" };
+	const char *bootargs;
+	char *msg = "kernel";
+	int i, noffset;
+
+	/* find or create "/chosen" node. */
+	noffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
+	if (noffset < 0)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(arr_bootargs); i++) {
+		bootargs = fdt_getprop(fdt, noffset, arr_bootargs[i], NULL);
+		if (!bootargs)
+			continue;
+		if (verbose)
+			printf("## bootargs(%s-%s): %s\n\n",
+			       msg, arr_bootargs[i], bootargs);
+		/*
+		 * Append kernel bootargs
+		 * If use AB system, delete default "root=" which route
+		 * to rootfs. Then the ab bootctl will choose the
+		 * high priority system to boot and add its UUID
+		 * to cmdline. The format is "roo=PARTUUID=xxxx...".
+		 */
 #ifdef CONFIG_ANDROID_AB
-	ab_update_root_partition();
+		env_update_filter("bootargs", bootargs, "root=");
+#else
+		env_update("bootargs", bootargs);
 #endif
+	}
+}
+
+char *board_fdt_chosen_bootargs(void *fdt)
+{
+	int verbose = is_hotkey(HK_CMDLINE);
+	const char *bootargs;
+
+	/* debug */
+	hotkey_run(HK_INITCALL);
+	if (verbose)
+		printf("## bootargs(u-boot): %s\n\n", env_get("bootargs"));
+
+	bootargs_add_dtb_dtbo(fdt, verbose);
+	bootargs_add_partition(verbose);
+	bootargs_add_fwver(verbose);
+	bootargs_add_android(verbose);
+
 	/*
 	 * Initrd fixup: remove unused "initrd=0x...,0x...",
 	 * this for compatible with legacy parameter.txt
@@ -1225,20 +1378,8 @@ char *board_fdt_chosen_bootargs(void *fdt)
 	if (gd->flags & GD_FLG_DISABLE_CONSOLE)
 		env_delete("bootargs", "earlycon=", 0);
 
-	/* Android header v4+ need this handle */
-#ifdef CONFIG_ANDROID_BOOT_IMAGE
-	struct andr_img_hdr *hdr;
-
-	hdr = (void *)env_get_ulong("android_addr_r", 16, 0);
-	if (hdr && !android_image_check_header(hdr) && hdr->header_version >= 4) {
-		if (env_update_extract_subset("bootargs", "andr_bootargs", "androidboot."))
-			printf("extract androidboot.xxx error\n");
-		if (dump)
-			printf("## bootargs(android): %s\n\n", env_get("andr_bootargs"));
-	}
-#endif
 	bootargs = env_get("bootargs");
-	if (dump)
+	if (verbose)
 		printf("## bootargs(merged): %s\n\n", bootargs);
 
 	return (char *)bootargs;
diff --git a/u-boot/arch/arm/mach-rockchip/fit_nodes.sh b/u-boot/arch/arm/mach-rockchip/fit_nodes.sh
index 4d39ea0554..9639a06e1c 100755
--- a/u-boot/arch/arm/mach-rockchip/fit_nodes.sh
+++ b/u-boot/arch/arm/mach-rockchip/fit_nodes.sh
@@ -347,6 +347,10 @@ if grep -q '^CONFIG_FIT_ENABLE_RSA4096_SUPPORT=y' .config ; then
 else
 	ALGO_NAME="				algo = \"sha256,rsa2048\";"
 fi
+if [ -z "${LOADABLE_ATF}" ]; then
+	LOADABLE_UBOOT="\"uboot\""
+fi
+
 echo "	};
 
 	configurations {
diff --git a/u-boot/arch/arm/mach-rockchip/memblk.c b/u-boot/arch/arm/mach-rockchip/memblk.c
index efbde42625..ac7c2a8957 100644
--- a/u-boot/arch/arm/mach-rockchip/memblk.c
+++ b/u-boot/arch/arm/mach-rockchip/memblk.c
@@ -41,7 +41,7 @@ const static struct memblk_attr plat_mem_attr[MEM_MAX] = {
 	MEM_DEFINE(ANDROID,	F_HOFC | F_OFC | F_KMEM_CAN_OVERLAP),
 	MEM_DEFINE(FDT,		F_OFC),
 	MEM_DEFINE(FDT_DTBO,	F_OFC),
-	MEM_DEFINE_1(SHM,	F_NONE, "ramoops"),
+	MEM_DEFINE_2(SHM,	F_NONE, "ramoops", "minidump"),
 	MEM_DEFINE_2(RAMDISK,	F_OFC,  "boot", "recovery"),
 	MEM_DEFINE(UNCOMP_KERNEL,F_IGNORE_INVISIBLE),
 	MEM_DEFINE(FIT_USER,	F_OFC | F_KMEM_CAN_OVERLAP),
diff --git a/u-boot/arch/arm/mach-rockchip/pstore.c b/u-boot/arch/arm/mach-rockchip/pstore.c
index 18e452c938..4f0df73dac 100644
--- a/u-boot/arch/arm/mach-rockchip/pstore.c
+++ b/u-boot/arch/arm/mach-rockchip/pstore.c
@@ -138,15 +138,18 @@ void putc_to_ram(const char c)
 	if (!rb || pstore_size == 0)
 		return;
 
+	if (rb->start >= pstore_size)
+		rb->start = 0;
+
 	dst = rb->data + rb->start;
 	*dst = c;
 
 	if (rb->size < pstore_size)
 		rb->size++;
+	else
+		rb->size = pstore_size;
 
 	rb->start++;
-	if (rb->start >= pstore_size)
-		rb->start = 0;
 }
 
 void puts_to_ram(const char *str)
diff --git a/u-boot/arch/arm/mach-rockchip/rk3308/rk3308.c b/u-boot/arch/arm/mach-rockchip/rk3308/rk3308.c
index bc271015d3..95556c6e54 100644
--- a/u-boot/arch/arm/mach-rockchip/rk3308/rk3308.c
+++ b/u-boot/arch/arm/mach-rockchip/rk3308/rk3308.c
@@ -187,6 +187,10 @@ int rk_board_init(void)
 #define QOS_PRIORITY_P1_P0(p1, p0)	((((p1) & 0x3) << 8) |\
 					(((p0) & 0x3) << 0))
 
+#define CRU_CLKGATE_CON10		0x0328
+#define CRU_CLKGATE_CON11		0x032c
+#define CRU_CLKGATE_CON12		0x0330
+
 enum {
 	IOVSEL4_SHIFT           = 4,
 	IOVSEL4_MASK            = BIT(4),
@@ -202,6 +206,18 @@ int arch_cpu_init(void)
 
 	/* Set CRYPTO SDMMC EMMC NAND SFC USB master bus to be secure access */
 	rk_clrreg(&sgrf->con_secure0, 0x2b83);
+#else /* uboot */
+
+	/*
+	 * Gate I2Sx_MCLK default
+	 *
+	 * It's safe to gate mclk default to avoid high freq glitch
+	 * which may make devices work unexpected. And then enabled by
+	 * kernel stage or any state where user use it.
+	 */
+	writel(0x80008000, CRU_BASE + CRU_CLKGATE_CON10);
+	writel(0x88888888, CRU_BASE + CRU_CLKGATE_CON11);
+	writel(0x88888888, CRU_BASE + CRU_CLKGATE_CON12);
 #endif
 #else /* defined(CONFIG_TPL_BUILD) */
 	static struct rk3308_cru * const cru = (void *)CRU_BASE;
diff --git a/u-boot/arch/arm/mach-rockchip/rk3562/rk3562.c b/u-boot/arch/arm/mach-rockchip/rk3562/rk3562.c
index b678451dd4..0dae0fc003 100644
--- a/u-boot/arch/arm/mach-rockchip/rk3562/rk3562.c
+++ b/u-boot/arch/arm/mach-rockchip/rk3562/rk3562.c
@@ -96,6 +96,8 @@ DECLARE_GLOBAL_DATA_PTR;
 #define VICAP_PRIORITY_REG	0xfee70108
 #define VOP_PRIORITY_REG	0xfee80008
 
+#define PCIE_SHAPING_REG	0xfeea0088
+
 #define QOS_PRIORITY_LEVEL(h, l)	((((h) & 7) << 8) | ((l) & 7))
 
 #ifdef CONFIG_ARM64
@@ -506,16 +508,17 @@ int fit_standalone_release(char *id, uintptr_t entry_point)
 	/* open bus m0 sclk / bus m0 hclk / bus m0 dclk */
 	writel(0x00070000, TOP_CRU_BASE + TOP_CRU_CM0_GATEMASK);
 
-	/* mcu_cache_peripheral_addr */
-	writel(0xa0000000, SYS_GRF_BASE + SYS_GRF_SOC_CON5);
+	/*
+	 * mcu_cache_peripheral_addr
+	 * The uncache area ranges from 0x7c00000 to 0xffb400000
+	 * and contains rpmsg shared memory
+	 */
+	writel(0x07c00000, SYS_GRF_BASE + SYS_GRF_SOC_CON5);
 	writel(0xffb40000, SYS_GRF_BASE + SYS_GRF_SOC_CON6);
 
 	sip_smc_mcu_config(ROCKCHIP_SIP_CONFIG_BUSMCU_0_ID,
 			   ROCKCHIP_SIP_CONFIG_MCU_CODE_START_ADDR,
 			   0xffff0000 | (entry_point >> 16));
-	/* 0x07c00000 is mapped to 0xa0000000 and used as shared memory for rpmsg */
-	sip_smc_mcu_config(ROCKCHIP_SIP_CONFIG_BUSMCU_0_ID,
-			   ROCKCHIP_SIP_CONFIG_MCU_EXPERI_START_ADDR, 0xffff07c0);
 
 	/* release dcache / icache / bus m0 jtag / bus m0 */
 	writel(0x03280000, TOP_CRU_BASE + TOP_CRU_SOFTRST_CON23);
@@ -532,7 +535,7 @@ static void qos_priority_init(void)
 	u32 delay;
 	u32 i;
 
-	/* power up vo,vi,gpu */
+	/* power up vo,vi */
 	rk_clrreg(PMU_BASE_ADDR + PMU2_PWR_GATE_SFTCON0,
 		  PD_VO_DWN_SFTENA | PD_VI_DWN_SFTENA);
 	delay = 1000;
@@ -605,6 +608,8 @@ static void qos_priority_init(void)
 	writel(QOS_PRIORITY_LEVEL(2, 2), DCF_PRIORITY_REG);
 	writel(QOS_PRIORITY_LEVEL(2, 2), DMA2DDR_PRIORITY_REG);
 	writel(QOS_PRIORITY_LEVEL(2, 2), PCIE_PRIORITY_REG);
+
+	writel(0x5, PCIE_SHAPING_REG);
 }
 
 int arch_cpu_init(void)
@@ -631,6 +636,13 @@ int arch_cpu_init(void)
 	/* Assert reset the pipe phy to save power and de-assert when in use */
 	writel(0x00030001, PIPEPHY_GRF_BASE + PIPEPHY_PIPE_CON5);
 
+#if defined(CONFIG_SUPPORT_USBPLUG)
+	/* Set emmc iomux */
+	writel(0xffff1111, GPIO1_IOC_BASE + GPIO1A_IOMUX_SEL_L);
+	writel(0xffff1111, GPIO1_IOC_BASE + GPIO1A_IOMUX_SEL_H);
+	writel(0xffff1111, GPIO1_IOC_BASE + GPIO1B_IOMUX_SEL_L);
+#endif
+
 #if defined(CONFIG_ROCKCHIP_SFC)
 	/* Set the fspi to access ddr memory */
 	val = readl(FIREWALL_DDR_BASE + FW_DDR_MST5_REG);
diff --git a/u-boot/arch/arm/mach-rockchip/rk3588/rk3588.c b/u-boot/arch/arm/mach-rockchip/rk3588/rk3588.c
index 678d558fc9..78ae302f23 100644
--- a/u-boot/arch/arm/mach-rockchip/rk3588/rk3588.c
+++ b/u-boot/arch/arm/mach-rockchip/rk3588/rk3588.c
@@ -5,6 +5,7 @@
  */
 #include <common.h>
 #include <dm.h>
+#include <fdt_support.h>
 #include <misc.h>
 #include <mmc.h>
 #include <spl.h>
@@ -58,10 +59,14 @@ DECLARE_GLOBAL_DATA_PTR;
 
 #define BUS_IOC_BASE			0xfd5f8000
 #define BUS_IOC_GPIO2A_IOMUX_SEL_L	0x40
+#define BUS_IOC_GPIO2A_IOMUX_SEL_H	0x44
 #define BUS_IOC_GPIO2B_IOMUX_SEL_L	0x48
+#define BUS_IOC_GPIO2B_IOMUX_SEL_H	0x4c
 #define BUS_IOC_GPIO2D_IOMUX_SEL_L	0x58
 #define BUS_IOC_GPIO2D_IOMUX_SEL_H	0x5c
 #define BUS_IOC_GPIO3A_IOMUX_SEL_L	0x60
+#define BUS_IOC_GPIO3A_IOMUX_SEL_H	0x64
+#define BUS_IOC_GPIO3C_IOMUX_SEL_H	0x74
 
 #define VCCIO3_5_IOC_BASE		0xfd5fa000
 #define IOC_VCCIO3_5_GPIO2A_DS_H	0x44
@@ -110,7 +115,13 @@ static struct mm_region rk3588_mem_map[] = {
 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
 			 PTE_BLOCK_NON_SHARE |
 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
-	},  {
+	}, {
+		.virt = 0x100000000UL,
+		.phys = 0x100000000UL,
+		.size = 0x700000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_INNER_SHARE
+	}, {
 		.virt = 0x900000000,
 		.phys = 0x900000000,
 		.size = 0x150000000,
@@ -844,6 +855,57 @@ void spl_board_storages_fixup(struct spl_image_loader *loader)
 }
 #endif
 
+void board_set_iomux(enum if_type if_type, int devnum, int routing)
+{
+	switch (if_type) {
+	case IF_TYPE_MMC:
+		/*
+		* set the emmc io drive strength:
+		* data and cmd: 50ohm
+		* clock: 25ohm
+		*/
+		writel(0x00770052, EMMC_IOC_BASE + EMMC_IOC_GPIO2A_DS_L);
+		writel(0x77772222, EMMC_IOC_BASE + EMMC_IOC_GPIO2D_DS_L);
+		writel(0x77772222, EMMC_IOC_BASE + EMMC_IOC_GPIO2D_DS_H);
+
+		/* set emmc iomux */
+		writel(0xffff1111, BUS_IOC_BASE + BUS_IOC_GPIO2A_IOMUX_SEL_L);
+		writel(0xffff1111, BUS_IOC_BASE + BUS_IOC_GPIO2D_IOMUX_SEL_L);
+		writel(0xffff1111, BUS_IOC_BASE + BUS_IOC_GPIO2D_IOMUX_SEL_H);
+		break;
+
+	case IF_TYPE_MTD:
+		if (routing == 0) {
+			writel(0x000f0002, BUS_IOC_BASE + BUS_IOC_GPIO2A_IOMUX_SEL_L);
+			writel(0xffff2222, BUS_IOC_BASE + BUS_IOC_GPIO2D_IOMUX_SEL_L);
+			writel(0x00f00020, BUS_IOC_BASE + BUS_IOC_GPIO2D_IOMUX_SEL_H);
+			/* Set the fspi m0 io ds level to 55ohm */
+			writel(0x00070002, EMMC_IOC_BASE + EMMC_IOC_GPIO2A_DS_L);
+			writel(0x77772222, EMMC_IOC_BASE + EMMC_IOC_GPIO2D_DS_L);
+			writel(0x07000200, EMMC_IOC_BASE + EMMC_IOC_GPIO2D_DS_H);
+		} else if (routing == 1) {
+			writel(0xff003300, BUS_IOC_BASE + BUS_IOC_GPIO2A_IOMUX_SEL_H);
+			writel(0xf0ff3033, BUS_IOC_BASE + BUS_IOC_GPIO2B_IOMUX_SEL_L);
+			writel(0x000f0003, BUS_IOC_BASE + BUS_IOC_GPIO2B_IOMUX_SEL_H);
+			/* Set the fspi m1 io ds level to 55ohm */
+			writel(0x33002200, VCCIO3_5_IOC_BASE + IOC_VCCIO3_5_GPIO2A_DS_H);
+			writel(0x30332022, VCCIO3_5_IOC_BASE + IOC_VCCIO3_5_GPIO2B_DS_L);
+			writel(0x00030002, VCCIO3_5_IOC_BASE + IOC_VCCIO3_5_GPIO2B_DS_H);
+		} else if (routing == 2) {
+			writel(0xffff5555, BUS_IOC_BASE + BUS_IOC_GPIO3A_IOMUX_SEL_L);
+			writel(0x00f00050, BUS_IOC_BASE + BUS_IOC_GPIO3A_IOMUX_SEL_H);
+			writel(0x00ff0022, BUS_IOC_BASE + BUS_IOC_GPIO3C_IOMUX_SEL_H);
+			/* Set the fspi m2 io ds level to 55ohm */
+			writel(0x77772222, VCCIO3_5_IOC_BASE + IOC_VCCIO3_5_GPIO3A_DS_L);
+			writel(0x00700020, VCCIO3_5_IOC_BASE + IOC_VCCIO3_5_GPIO3A_DS_H);
+			writel(0x00070002, VCCIO3_5_IOC_BASE + IOC_VCCIO3_5_GPIO3C_DS_H);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
 #ifndef CONFIG_TPL_BUILD
 int arch_cpu_init(void)
 {
@@ -939,6 +1001,41 @@ int arch_cpu_init(void)
 	writel(0x00030003, PMU1CRU_BASE + PMU1CRU_SOFTRST_CON04);
 
 	spl_board_sd_iomux_save();
+#elif defined(CONFIG_SUPPORT_USBPLUG)
+	int secure_reg;
+
+	/* Set the SDMMC eMMC crypto_ns FSPI access secure area */
+	secure_reg = readl(FIREWALL_DDR_BASE + FW_DDR_MST5_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_DDR_BASE + FW_DDR_MST5_REG);
+	secure_reg = readl(FIREWALL_DDR_BASE + FW_DDR_MST13_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_DDR_BASE + FW_DDR_MST13_REG);
+	secure_reg = readl(FIREWALL_DDR_BASE + FW_DDR_MST21_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_DDR_BASE + FW_DDR_MST21_REG);
+	secure_reg = readl(FIREWALL_DDR_BASE + FW_DDR_MST26_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_DDR_BASE + FW_DDR_MST26_REG);
+	secure_reg = readl(FIREWALL_DDR_BASE + FW_DDR_MST27_REG);
+	secure_reg &= 0xffff0000;
+	writel(secure_reg, FIREWALL_DDR_BASE + FW_DDR_MST27_REG);
+
+	secure_reg = readl(FIREWALL_SYSMEM_BASE + FW_SYSM_MST5_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_SYSMEM_BASE + FW_SYSM_MST5_REG);
+	secure_reg = readl(FIREWALL_SYSMEM_BASE + FW_SYSM_MST13_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_SYSMEM_BASE + FW_SYSM_MST13_REG);
+	secure_reg = readl(FIREWALL_SYSMEM_BASE + FW_SYSM_MST21_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_SYSMEM_BASE + FW_SYSM_MST21_REG);
+	secure_reg = readl(FIREWALL_SYSMEM_BASE + FW_SYSM_MST26_REG);
+	secure_reg &= 0xffff;
+	writel(secure_reg, FIREWALL_SYSMEM_BASE + FW_SYSM_MST26_REG);
+	secure_reg = readl(FIREWALL_SYSMEM_BASE + FW_SYSM_MST27_REG);
+	secure_reg &= 0xffff0000;
+	writel(secure_reg, FIREWALL_SYSMEM_BASE + FW_SYSM_MST27_REG);
 #else /* U-Boot */
 	/* uboot: config iomux */
 #ifdef CONFIG_ROCKCHIP_EMMC_IOMUX
@@ -966,12 +1063,24 @@ int arch_cpu_init(void)
 
 #define BAD_CPU(mask, n)	((mask) & (1 << (n)))
 #define BAD_RKVENC(mask, n)	((mask) & (1 << (n)))
+#define BAD_RKVDEC(mask, n)	((mask) & (1 << (n)))
 
 static void fdt_rm_path(void *blob, const char *path)
 {
 	fdt_del_node(blob, fdt_path_offset(blob, path));
 }
 
+static void fdt_rename_path(void *blob, const char *path, const char *name)
+{
+	int noffset;
+
+	noffset = fdt_path_offset(blob, path);
+	if (noffset < 0)
+		return;
+
+	fdt_set_name(blob, noffset, name);
+}
+
 static void fdt_rm_cooling_map(const void *blob, u8 cpu_mask)
 {
 	int map1, map2;
@@ -1104,7 +1213,7 @@ static void fdt_rm_cpu(const void *blob, u8 cpu_mask)
 	}
 }
 
-static void fdt_rm_cpus(const void *blob, u8 cpu_mask)
+static void rk3582_fdt_rm_cpus(const void *blob, u8 cpu_mask)
 {
 	/*
 	 * policy:
@@ -1127,7 +1236,7 @@ static void fdt_rm_cpus(const void *blob, u8 cpu_mask)
 	fdt_rm_cpu(blob, cpu_mask);
 }
 
-static void fdt_rm_gpu(void *blob)
+static void rk3582_fdt_rm_gpu(void *blob)
 {
 	/*
 	 * policy:
@@ -1139,7 +1248,7 @@ static void fdt_rm_gpu(void *blob)
 	debug("rm: gpu\n");
 }
 
-static void fdt_rm_rkvdec01(void *blob)
+static void rk3582_fdt_rm_rkvdec01(void *blob)
 {
 	/*
 	 * policy:
@@ -1153,13 +1262,15 @@ static void fdt_rm_rkvdec01(void *blob)
 	debug("rm: rkvdec0, rkvdec1\n");
 }
 
-static void fdt_rm_rkvenc01(void *blob, u8 mask)
+static void rk3582_fdt_rm_rkvenc01(void *blob, u8 mask)
 {
 	/*
 	 * policy:
 	 *
 	 * 1. remove bad.
 	 * 2. if both of rkvenc0 and rkvenc1 are normal, remove rkvenc1 by default.
+	 * 3. disable '*-ccu' node
+	 * 4. rename '*-core@' node
 	 */
 	if (!BAD_RKVENC(mask, 0) && !BAD_RKVENC(mask, 1)) {
 		/* rkvenc1 */
@@ -1179,6 +1290,50 @@ static void fdt_rm_rkvenc01(void *blob, u8 mask)
 			debug("rm: rkvenv1\n");
 		}
 	}
+
+	do_fixup_by_path((void *)blob, "/rkvenc-ccu",
+			 "status", "disabled", sizeof("disabled"), 0);
+
+	/* rename node name if the node exist, actually only one exist  */
+	fdt_rename_path(blob, "/rkvenc-core@fdbd0000", "rkvenc@fdbd0000");
+	fdt_rename_path(blob, "/rkvenc-core@fdbe0000", "rkvenc@fdbe0000");
+}
+
+static void rk3583_fdt_rm_rkvdec01(void *blob, u8 mask)
+{
+	/*
+	 * policy:
+	 *
+	 * 1. remove bad.
+	 * 2. if both of rkvdec0 and rkvdec1 are normal, remove rkvdec1 by default.
+	 * 3. disable '*-ccu' node
+	 * 4. rename '*-core@' node
+	 */
+	if (!BAD_RKVDEC(mask, 0) && !BAD_RKVDEC(mask, 1)) {
+		/* rkvdec1 */
+		fdt_rm_path(blob, "/rkvdec-core@fdc48000");
+		fdt_rm_path(blob, "/iommu@fdc48700");
+		debug("rm: rkvdec1\n");
+	} else {
+		if (BAD_RKVDEC(mask, 0)) {
+			fdt_rm_path(blob, "/rkvdec-core@fdc38000");
+			fdt_rm_path(blob, "/iommu@fdc38700");
+			debug("rm: rkvdec0\n");
+
+		}
+		if (BAD_RKVDEC(mask, 1)) {
+			fdt_rm_path(blob, "/rkvdec-core@fdc48000");
+			fdt_rm_path(blob, "/iommu@fdc48700");
+			debug("rm: rkvdec1\n");
+		}
+	}
+
+	do_fixup_by_path((void *)blob, "/rkvdec-ccu@fdc30000",
+			 "status", "disabled", sizeof("disabled"), 0);
+
+	/* rename node name if the node exist, actually only one exist  */
+	fdt_rename_path(blob, "/rkvdec-core@fdc38000", "rkvdec@fdc38000");
+	fdt_rename_path(blob, "/rkvdec-core@fdc48000", "rkvdec@fdc48000");
 }
 
 #define CHIP_ID_OFF	2
@@ -1190,6 +1345,7 @@ static int fdt_fixup_modules(void *blob)
 	u8 ip_state[3];
 	u8 chip_id[2];
 	u8 rkvenc_mask;
+	u8 rkvdec_mask;
 	u8 cpu_mask;
 	int ret;
 
@@ -1208,8 +1364,9 @@ static int fdt_fixup_modules(void *blob)
 
 	debug("# chip: rk%02x%02x\n", chip_id[0], chip_id[1]);
 
-	/* only rk3582 goes further */
-	if (!(chip_id[0] == 0x35 && chip_id[1] == 0x82))
+	/* only rk3582/rk3583 goes further */
+	if (!(chip_id[0] == 0x35 && chip_id[1] == 0x82) &&
+	    !(chip_id[0] == 0x35 && chip_id[1] == 0x83))
 		return 0;
 
 	ret = misc_read(dev, IP_STATE_OFF, &ip_state, sizeof(ip_state));
@@ -1222,33 +1379,42 @@ static int fdt_fixup_modules(void *blob)
 	cpu_mask = ip_state[0];
 	/* ip_state[2]: bit0,2 */
 	rkvenc_mask = (ip_state[2] & 0x1) | ((ip_state[2] & 0x4) >> 1);
+	/* ip_state[1]: bit6,7 */
+	rkvdec_mask = (ip_state[1] & 0xc0) >> 6;
 #if 0
 	/* ip_state[1]: bit1~4 */
 	gpu_mask = (ip_state[1] & 0x1e) >> 1;
-	/* ip_state[1]: bit6,7 */
-	rkvdec_mask = (ip_state[1] & 0xc0) >> 6;
 #endif
-
-	debug("hwmask: 0x%02x, 0x%02x, 0x%02x\n", ip_state[0], ip_state[1], ip_state[2]);
-	debug("swmask: 0x%02x, 0x%02x\n", cpu_mask, rkvenc_mask);
+	debug("hw-mask: 0x%02x, 0x%02x, 0x%02x\n", ip_state[0], ip_state[1], ip_state[2]);
+	debug("sw-mask: 0x%02x, 0x%02x, 0x%02x\n", cpu_mask, rkvenc_mask, rkvdec_mask);
 
 	/*
-	 * RK3582 Policy: gpu/rkvdec are removed by default, the same for other
-	 * IP under some condition.
-	 *
-	 * So don't use pattern like "if (rkvenc_mask) then fdt_rm_rkvenc01()",
-	 * just go through all of them as this chip is rk3582.
-	 *
 	 *		FIXUP WARNING!
 	 *
 	 * The node delete changes the fdt structure, a node offset you already
 	 * got before maybe not right by now. Make sure always reading the node
 	 * offset exactly before you are going to use.
 	 */
-	fdt_rm_gpu(blob);
-	fdt_rm_rkvdec01(blob);
-	fdt_rm_rkvenc01(blob, rkvenc_mask);
-	fdt_rm_cpus(blob, cpu_mask);
+	if (chip_id[0] == 0x35 && chip_id[1] == 0x82) {
+		/*
+		 * RK3582 Policy: gpu/rkvdec are removed by default, the same for other
+		 * IP under some condition.
+		 *
+		 * So don't use pattern like "if (rkvenc_mask) then rk3582_fdt_rm_rkvenc01()",
+		 * just go through all of them as this chip is rk3582.
+		 */
+		rk3582_fdt_rm_gpu(blob);
+		rk3582_fdt_rm_rkvdec01(blob);
+		rk3582_fdt_rm_rkvenc01(blob, rkvenc_mask);
+		rk3582_fdt_rm_cpus(blob, cpu_mask);
+	} else if (chip_id[0] == 0x35 && chip_id[1] == 0x83) {
+		/*
+		 * RK3583 Policy: some rules are the same as rk3582.
+		 */
+		rk3583_fdt_rm_rkvdec01(blob, rkvdec_mask);
+		rk3582_fdt_rm_rkvenc01(blob, rkvenc_mask);
+		rk3582_fdt_rm_cpus(blob, cpu_mask);
+	}
 
 	return 0;
 }
diff --git a/u-boot/arch/arm/mach-rockchip/rk_atags.c b/u-boot/arch/arm/mach-rockchip/rk_atags.c
index 26f8507011..37f8a974c7 100644
--- a/u-boot/arch/arm/mach-rockchip/rk_atags.c
+++ b/u-boot/arch/arm/mach-rockchip/rk_atags.c
@@ -179,8 +179,9 @@ int atags_is_available(void)
 
 int atags_set_tag(u32 magic, void *tagdata)
 {
-	u32 length, size = 0, hash;
 	struct tag *t = (struct tag *)ATAGS_PHYS_BASE;
+	u32 length, size = 0, hash;
+	int append = 1; /* 0: override */
 
 #if !defined(CONFIG_TPL_BUILD) && !defined(CONFIG_FPGA_ROCKCHIP)
 	if (!atags_is_available())
@@ -216,8 +217,10 @@ int atags_set_tag(u32 magic, void *tagdata)
 				return -EINVAL;
 
 			/* This is an old tag, override it */
-			if (t->hdr.magic == magic)
+			if (t->hdr.magic == magic) {
+				append = 0;
 				break;
+			}
 
 			if (t->hdr.magic == ATAG_NONE)
 				break;
@@ -256,6 +259,9 @@ int atags_set_tag(u32 magic, void *tagdata)
 	case ATAG_PSTORE:
 		size = tag_size(tag_pstore);
 		break;
+	case ATAG_FWVER:
+		size = tag_size(tag_fwver);
+		break;
 	};
 
 	if (!size)
@@ -264,7 +270,7 @@ int atags_set_tag(u32 magic, void *tagdata)
 	if (atags_size_overflow(t, size))
 		return -ENOMEM;
 
-	/* It's okay to setup a new tag */
+	/* It's okay to setup a new tag or override tag */
 	t->hdr.magic = magic;
 	t->hdr.size = size;
 	length = (t->hdr.size << 2) - sizeof(struct tag_header) - HASH_LEN;
@@ -272,17 +278,41 @@ int atags_set_tag(u32 magic, void *tagdata)
 	hash = js_hash(t, (size << 2) - HASH_LEN);
 	memcpy((char *)&t->u + length, &hash, HASH_LEN);
 
-	/* Next tag */
-	t = tag_next(t);
+	if (append) {
+		/* Next tag */
+		t = tag_next(t);
 
-	/* Setup done */
-	t->hdr.magic = ATAG_NONE;
-	t->hdr.size = 0;
+		/* Setup done */
+		t->hdr.magic = ATAG_NONE;
+		t->hdr.size = 0;
+	}
 
 	return 0;
 }
 
 #ifndef CONFIG_TPL_BUILD
+int atags_set_shared_fwver(u32 fwid, char *ver)
+{
+	struct tag_fwver fw = {}, *pfw;
+	struct tag *t;
+
+	if (!ver || (strlen(ver) >= FWVER_LEN) || fwid >= FW_MAX)
+		return -EINVAL;
+
+	t = atags_get_tag(ATAG_FWVER);
+	if (!t) {
+		pfw = &fw;
+		pfw->version = 0;
+	} else {
+		pfw = &t->u.fwver;
+	}
+
+	strcpy(pfw->ver[fwid], ver);
+	atags_set_tag(ATAG_FWVER, pfw);
+
+	return 0;
+}
+
 struct tag *atags_get_tag(u32 magic)
 {
 	u32 *hash, calc_hash, size;
diff --git a/u-boot/arch/arm/mach-rockchip/rk_mini_dump.c b/u-boot/arch/arm/mach-rockchip/rk_mini_dump.c
new file mode 100644
index 0000000000..ef52b76057
--- /dev/null
+++ b/u-boot/arch/arm/mach-rockchip/rk_mini_dump.c
@@ -0,0 +1,535 @@
+/*
+ * (C) Copyright 2023 Rockchip Electronics Co., Ltd.
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <rk_mini_dump.h>
+
+/* don't modify it, it is behind pstore memory space */
+#ifdef CONFIG_ROCKCHIP_MINIDUMP_SMEM_BASE
+#define SMEM_BASE		CONFIG_ROCKCHIP_MINIDUMP_SMEM_BASE
+#else
+#define SMEM_BASE		0x1f0000
+#endif
+
+#ifdef CONFIG_ROCKCHIP_MINIDUMP_MAX_ELF_SIZE
+#define MAX_ELF_SIZE		CONFIG_ROCKCHIP_MINIDUMP_MAX_ELF_SIZE
+#else
+#define MAX_ELF_SIZE		0x2000000
+#endif
+
+#ifdef CONFIG_ROCKCHIP_MINIDUMP_MAX_ENTRIES
+#define MAX_NUM_ENTRIES		(CONFIG_ROCKCHIP_MINIDUMP_MAX_ENTRIES + 1)
+#else
+#define MAX_NUM_ENTRIES		129
+#endif
+
+/* Bootloader has 16 byte support, 4 bytes reserved for itself */
+#define MAX_REGION_NAME_LENGTH	16
+#define MAX_STRTBL_SIZE		(MAX_NUM_ENTRIES * MAX_REGION_NAME_LENGTH)
+
+/**
+ * md_table : Local Minidump toc holder
+ * @num_regions : Number of regions requested
+ * @md_ss_toc  : HLOS toc pointer
+ * @md_gbl_toc : Global toc pointer
+ * @md_regions : HLOS regions base pointer
+ * @entry : array of HLOS regions requested
+ */
+struct md_table {
+	u32			revision;
+	u32                     num_regions;
+	struct md_ss_toc	*md_ss_toc;
+	struct md_global_toc	*md_gbl_toc;
+	struct md_ss_region	*md_regions;
+	struct md_region	entry[MAX_NUM_ENTRIES];
+};
+
+#define MAX_NUM_OF_SS		2
+
+/**
+ * md_ss_toc: Sub system SMEM Table of content
+ * @md_ss_toc_init : SS toc init status
+ * @md_ss_enable_status : if set to 1, Bootloader would dump this SS regions
+ * @encryption_status: Encryption status for this subsystem
+ * @encryption_required : Decides to encrypt the SS regions or not
+ * @ss_region_count : Number of regions added in this SS toc
+ * @md_ss_smem_regions_baseptr : regions base pointer of the Subsystem
+ * @elf_header : base pointer of the minidump elf header
+ * @minidump_table : base pointer of the minidump_table
+ */
+struct md_ss_toc {
+	u32			md_ss_toc_init;
+	u32			md_ss_enable_status;
+	u32			encryption_status;
+	u32			encryption_required;
+	u32			ss_region_count;
+	u64			md_ss_smem_regions_baseptr;
+	u64			elf_header;
+	u64			elf_size;
+	u64			minidump_table;
+};
+
+/**
+ * md_global_toc: Global Table of Content
+ * @md_toc_init : Global Minidump init status
+ * @md_revision : Minidump revision
+ * @md_enable_status : Minidump enable status
+ * @md_ss_toc : Array of subsystems toc
+ */
+struct md_global_toc {
+	u32			md_toc_init;
+	u32			md_revision;
+	u32			md_enable_status;
+	struct md_ss_toc	md_ss_toc[MAX_NUM_OF_SS];
+};
+
+/* Bootloader has 16 byte support, 4 bytes reserved for itself */
+#define MAX_REGION_NAME_LENGTH	16
+
+#define MD_REGION_VALID		('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0)
+#define MD_REGION_INVALID	('I' << 24 | 'N' << 16 | 'V' << 8 | 'A' << 0)
+#define MD_REGION_INIT		('I' << 24 | 'N' << 16 | 'I' << 8 | 'T' << 0)
+#define MD_REGION_NOINIT	0
+
+#define MD_SS_ENCR_REQ		(0 << 24 | 'Y' << 16 | 'E' << 8 | 'S' << 0)
+#define MD_SS_ENCR_NOTREQ	(0 << 24 | 0 << 16 | 'N' << 8 | 'R' << 0)
+#define MD_SS_ENCR_NONE		('N' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0)
+#define MD_SS_ENCR_DONE		('D' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0)
+#define MD_SS_ENCR_START	('S' << 24 | 'T' << 16 | 'R' << 8 | 'T' << 0)
+#define MD_SS_ENABLED		('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0)
+#define MD_SS_DISABLED		('D' << 24 | 'S' << 16 | 'B' << 8 | 'L' << 0)
+
+#define EM_AARCH64	183	/* ARM 64 bit */
+
+/**
+ * md_ss_region - Minidump region
+ * @name		: Name of the region to be dumped
+ * @seq_num:		: Use to differentiate regions with same name.
+ * @md_valid		: This entry to be dumped (if set to 1)
+ * @region_base_address	: Physical address of region to be dumped
+ * @region_size		: Size of the region
+ */
+struct md_ss_region {
+	char	name[MAX_REGION_NAME_LENGTH];
+	u32	seq_num;
+	u32	md_valid;
+	u64	region_base_address;
+	u64	region_size;
+};
+
+#define NO_FAULT_TAG 0x55aa55aa
+static u32 no_fault;
+static struct md_table *minidump_table;
+
+u32 md_no_fault_handler(struct pt_regs *pt_regs, unsigned int esr)
+{
+	if (no_fault == NO_FAULT_TAG) {
+		no_fault = 0;
+		return 1;
+	}
+	return 0;
+}
+
+#if defined(CONFIG_ROCKCHIP_RK3588)
+static u32 md_is_ddr_addr(void *addr)
+{
+	/* peripheral address space */
+	if (addr >= (void *)0xf0000000 && addr <= (void *)0x100000000)
+		return 0;
+	/* pcie address space */
+	if (addr > (void *)0x800000000)
+		return 0;
+	return 1;
+}
+#else
+static u32 md_is_ddr_addr(void *addr)
+{
+	return 1;
+}
+#endif
+
+static u32 md_is_uboot_addr(void *addr)
+{
+	volatile u32 *p_no_fault = &no_fault;
+
+	if(!md_is_ddr_addr(addr))
+		return 0;
+
+	*p_no_fault = NO_FAULT_TAG;
+	readb(addr);
+	return *p_no_fault;
+}
+
+struct md_region *md_get_region(char *name)
+{
+	struct md_region *mdr;
+	int i, regno;
+
+	if (!md_is_uboot_addr((void *)minidump_table))
+		return NULL;
+
+	regno = minidump_table->num_regions;
+	for (i = 0; i < regno; i++) {
+		mdr = &minidump_table->entry[i];
+		if (!strcmp(mdr->name, name))
+			return mdr;
+	}
+	return NULL;
+}
+
+#ifdef CONFIG_ARM64
+static Elf64_Xword rk_dump_elf64_image_phdr(void *ram_image,
+					    Elf64_Addr ehaddr, Elf64_Xword ehsize)
+{
+	Elf64_Ehdr *ehdr = (Elf64_Ehdr *)ehaddr;
+	Elf64_Phdr *phdr = NULL, *phdr_next = NULL;
+	Elf64_Shdr *shdr = NULL, *shdr_next = NULL;
+	unsigned int i = 0, error = 0, phdr_off = 0, strtbl_off = 0;
+	unsigned int size = 0, elf_size = ehsize;
+
+	if (!md_is_uboot_addr((void *)ehdr))
+		return 0;
+
+	if (!md_is_uboot_addr((void *)ram_image) ||
+	    !md_is_uboot_addr((void *)ram_image + MAX_ELF_SIZE - 4))
+		return 0;
+
+	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+	ehdr->e_ident[EI_CLASS] = ELFCLASS64;
+	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+
+	if (ehdr->e_type != ET_CORE) {
+		error++;
+		ehdr->e_type = ET_CORE;
+	}
+	if (ehdr->e_machine != EM_AARCH64) {
+		error++;
+		ehdr->e_machine = EM_AARCH64;
+	}
+	if (ehdr->e_version != EV_CURRENT) {
+		error++;
+		ehdr->e_version = EV_CURRENT;
+	}
+	if (ehdr->e_ehsize != sizeof(*ehdr)) {
+		error++;
+		ehdr->e_ehsize = sizeof(*ehdr);
+	}
+	if (ehdr->e_phentsize != sizeof(*phdr)) {
+		error++;
+		ehdr->e_phentsize = sizeof(*phdr);
+	}
+	if (ehdr->e_shentsize != sizeof(*shdr)) {
+		error++;
+		ehdr->e_shentsize = sizeof(*shdr);
+	}
+	if (ehdr->e_shoff != sizeof(*ehdr)) {
+		error++;
+		ehdr->e_shoff = sizeof(*ehdr);
+	}
+
+	phdr_off = sizeof(*ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES);
+
+	if (ehdr->e_phoff != phdr_off) {
+		error++;
+		ehdr->e_phoff = phdr_off;
+	}
+
+	printf("Minidump header error:0x%x\n", error);
+	/* If there are much error, maybe ehdr address is wrong */
+	if (error > 6)
+		return 0;
+
+	ehdr->e_shstrndx = 1;
+	phdr = (Elf64_Phdr *)(ehaddr + ehdr->e_phoff);
+	shdr = (Elf64_Shdr *)(ehaddr + ehdr->e_shoff);
+
+	shdr->sh_name = 0;
+	shdr->sh_type = 0;
+	shdr->sh_flags = 0;
+	shdr->sh_addr = 0;
+	shdr->sh_offset = 0;
+	shdr->sh_size = 0;
+	shdr->sh_link = 0;
+	shdr->sh_info = 0;
+	shdr->sh_addralign = 0;
+	shdr->sh_entsize = 0;
+
+	shdr++;
+	if (shdr->sh_name >= MAX_STRTBL_SIZE)
+		shdr->sh_name = 0;
+	shdr->sh_type = SHT_STRTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_addr = 0;
+	shdr->sh_offset = phdr_off + (sizeof(*phdr) * MAX_NUM_ENTRIES);
+	shdr->sh_size = MAX_STRTBL_SIZE;
+	shdr->sh_link = 0;
+	shdr->sh_info = 0;
+	shdr->sh_addralign = 0;
+	shdr->sh_entsize = 0;
+
+	shdr++;
+	/* 3rd section is for minidump_table VA, used by parsers */
+	if (shdr->sh_name >= MAX_STRTBL_SIZE)
+		shdr->sh_name = 0;
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_flags = 0;
+	shdr->sh_offset = 0;
+	shdr->sh_size = 0;
+	shdr->sh_link = 0;
+	shdr->sh_info = 0;
+	shdr->sh_addralign = 0;
+	shdr->sh_entsize = 0;
+
+	shdr++;
+	shdr->sh_flags = 0;
+	shdr->sh_link = 0;
+	shdr->sh_info = 0;
+	shdr->sh_addralign = 0;
+	shdr->sh_entsize = 0;
+
+	strtbl_off = phdr_off + (sizeof(*phdr) * MAX_NUM_ENTRIES);
+	strtbl_off += MAX_STRTBL_SIZE;
+
+	if (phdr->p_offset != strtbl_off)
+		phdr->p_offset = strtbl_off;
+	if (shdr->sh_offset != strtbl_off)
+		shdr->sh_offset = strtbl_off;
+
+	phdr->p_filesz &= GENMASK(23, 0);	/* 16MB */
+	phdr->p_memsz &= GENMASK(23, 0);	/* 16MB */
+	shdr->sh_size &= GENMASK(23, 0);	/* 16MB */
+
+	if (phdr->p_filesz == phdr->p_memsz) {
+		size = phdr->p_filesz;
+		shdr->sh_size = size;
+	} else if (phdr->p_filesz == shdr->sh_size) {
+		size = phdr->p_filesz;
+		phdr->p_memsz = size;
+	} else if (phdr->p_memsz == shdr->sh_size) {
+		size = phdr->p_memsz;
+		phdr->p_filesz = size;
+	} else {
+		printf("Minidump error first phdr p_filesz:0x%llx p_memsz:0x%llx sh_size:0x%llx\n",
+		       phdr->p_filesz, phdr->p_memsz, shdr->sh_size);
+		return 0;
+	}
+
+	phdr++;
+	shdr++;
+	phdr_next = phdr + 1;
+	shdr_next = shdr + 1;
+
+	memset(ram_image, 0x0, 0x18000);
+
+	phdr->p_offset &= MAX_ELF_SIZE - 1;
+	shdr->sh_offset &= MAX_ELF_SIZE - 1;
+	elf_size &= MAX_ELF_SIZE - 1;
+	if (phdr->p_offset == shdr->sh_offset) {
+		elf_size = phdr->p_offset;
+	} else if (phdr->p_offset == elf_size) {
+		shdr->sh_offset = phdr->p_offset;
+	} else if (elf_size == shdr->sh_offset) {
+		phdr->p_offset = shdr->sh_offset;
+	} else {
+		printf("Minidump error phdr[1] p_offset:0x%llx sh_offset:0x%llx elf_size:0x%x\n",
+		       phdr->p_offset, shdr->sh_offset, elf_size);
+		return 0;
+	}
+
+	/* save phdr space */
+	for (i = 1; i < MAX_NUM_ENTRIES; i++) {
+		void *src = NULL;
+		void *dst = NULL;
+
+		if (phdr->p_vaddr == 0 || shdr->sh_addr == 0)
+			break;
+
+		phdr->p_offset &= MAX_ELF_SIZE - 1;
+		shdr->sh_offset &= MAX_ELF_SIZE - 1;
+
+		if (phdr->p_offset != elf_size)
+			phdr->p_offset = elf_size;
+
+		if (shdr->sh_offset != elf_size)
+			shdr->sh_offset = elf_size;
+
+		phdr->p_paddr &= GENMASK(34, 0);	/* 32GB */
+		phdr->p_align &= GENMASK(34, 0);	/* 32GB */
+		shdr->sh_info &= GENMASK(34, 0);	/* 32GB */
+
+		if (phdr->p_paddr != phdr->p_align && phdr->p_align == shdr->sh_entsize)
+			phdr->p_paddr = phdr->p_align;
+
+		phdr->p_type &= 0xf;
+		phdr->p_flags &= 0xf;
+		phdr->p_filesz &= GENMASK(23, 0);	/* 16MB */
+		phdr->p_memsz &= GENMASK(23, 0);	/* 16MB */
+		phdr->p_align = 0;
+
+		if (phdr->p_vaddr != shdr->sh_addr) {
+			if (shdr->sh_addr == shdr->sh_addralign)
+				phdr->p_vaddr = shdr->sh_addr;
+			else if (phdr->p_vaddr == shdr->sh_addralign)
+				shdr->sh_addr = phdr->p_vaddr;
+			else
+				printf("Minidump error phdr[%d] p_vaddr:0x%llx sh_addr:0x%llx sh_addralign:0x%llx\n",
+				       i, phdr->p_vaddr, shdr->sh_addr, shdr->sh_addralign);
+		}
+
+		if (shdr->sh_name >= MAX_STRTBL_SIZE)
+			shdr->sh_name = 0;
+		shdr->sh_type = SHT_PROGBITS;
+		shdr->sh_flags = SHF_WRITE;
+		shdr->sh_size &= GENMASK(23, 0);	/* 16MB */
+		shdr->sh_link = 0;
+		shdr->sh_info = 0;
+		shdr->sh_addralign = 0;
+		shdr->sh_entsize = 0;
+
+		if (phdr->p_filesz == phdr->p_memsz) {
+			size = phdr->p_filesz;
+			shdr->sh_size = size;
+		} else if (phdr->p_filesz == shdr->sh_size) {
+			size = phdr->p_filesz;
+			phdr->p_memsz = size;
+		} else if (phdr->p_memsz == shdr->sh_size) {
+			size = phdr->p_memsz;
+			phdr->p_filesz = size;
+		} else {
+			if ((phdr_next->p_offset == shdr_next->sh_offset) &&
+			    (phdr_next->p_offset != 0)) {
+				size = phdr_next->p_offset - phdr->p_offset;
+				phdr->p_filesz = size;
+				phdr->p_memsz = size;
+				shdr->sh_size = size;
+			} else {
+				printf("Minidump error phdr[%d] p_filesz:0x%llx p_memsz:0x%llx sh_size:0x%llx",
+				       i, phdr->p_filesz, phdr->p_memsz, shdr->sh_size);
+				printf("p_offset:0x%llx sh_offset:0x%llx\n", phdr_next->p_offset,
+				       shdr_next->sh_offset);
+				return 0;
+			}
+		}
+
+		elf_size += size;
+		src = (void *)(Elf64_Addr)phdr->p_paddr;
+		dst = ram_image + phdr->p_offset;
+
+		if (size > MAX_ELF_SIZE / 2)
+			goto donot_cpy;
+
+		if (!md_is_uboot_addr(src) || !md_is_uboot_addr(src + size - 1)) {
+			printf("Minidump error src 0x%p-0x%p\n", src, src + size - 1);
+			goto donot_cpy;
+		}
+		if (!md_is_uboot_addr(dst) || !md_is_uboot_addr(dst + size - 1)) {
+			printf("Minidump error dst 0x%p-0x%p\n", dst, dst + size - 1);
+			goto donot_cpy;
+		}
+		if (size)
+			memcpy(dst, src, size);
+donot_cpy:
+		phdr++;
+		shdr++;
+		phdr_next++;
+		shdr_next++;
+	}
+
+	if (ehdr->e_phnum != i)
+		ehdr->e_phnum = i;
+	if ((ehdr->e_phnum + 3) != ehdr->e_shnum)
+		ehdr->e_shnum = ehdr->e_phnum + 3;
+
+	/* copy ehdr to ram image */
+	memcpy(ram_image, (void *)ehdr, ehsize);
+	flush_cache((unsigned long)ram_image, elf_size);
+	printf("Minidump.elf 0x%x@0x%p\n", elf_size, ram_image);
+	return elf_size;
+}
+#else
+static Elf32_Word rk_dump_elf32_image_phdr(void *ram_image, Elf32_Addr ehaddr,
+					   Elf32_Word ehsize)
+{
+	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)ehaddr;
+	Elf32_Phdr *phdr = (Elf32_Phdr *)(ehaddr + ehdr->e_phoff);
+	Elf32_Word ram_image_size = 0;
+	int i;
+
+	/* copy ehdr to ram image */
+	memcpy(ram_image, (void *)ehdr, ehsize);
+
+	/* save phdr space */
+	for (i = 0; i < ehdr->e_phnum; ++i) {
+		void *src = (void *)(Elf32_Addr)phdr->p_paddr;
+		void *dst = ram_image + phdr->p_offset;
+
+		if (phdr->p_filesz)
+			memcpy(dst, src, phdr->p_filesz);
+		if (phdr->p_filesz != phdr->p_memsz)
+			memset(dst + phdr->p_filesz, 0x00,
+			       phdr->p_memsz - phdr->p_filesz);
+		++phdr;
+	}
+
+	phdr--;
+	ram_image_size = phdr->p_memsz + phdr->p_offset;
+	printf("Minidump.elf 0x%llx@0x%p\n", ram_image_size, ram_image);
+	return ram_image_size;
+}
+#endif
+
+void rk_minidump_init(void)
+{
+	struct md_global_toc *mdg_toc = (struct md_global_toc *)SMEM_BASE;
+	struct md_ss_toc *md_ss_toc = &mdg_toc->md_ss_toc[0];
+	struct md_ss_region *mdreg;
+
+	printf("Minidump: init...\n");
+	mdg_toc->md_toc_init = 1;
+	mdg_toc->md_revision = 1;
+	mdg_toc->md_enable_status = 0;
+
+	if (md_ss_toc->md_ss_enable_status == MD_SS_ENABLED) {
+		/* linux would set it 1, so we set it 0 here */
+		md_ss_toc->md_ss_enable_status = 0;
+		flush_cache((unsigned long)md_ss_toc, 8);
+		mdreg = (struct md_ss_region *)md_ss_toc->md_ss_smem_regions_baseptr;
+		minidump_table = (struct md_table *)md_ss_toc->minidump_table;
+#ifdef CONFIG_ARM64
+		md_ss_toc->elf_size = rk_dump_elf64_image_phdr((void *)md_ss_toc->elf_header,
+					 (Elf64_Addr)mdreg->region_base_address,
+					 (Elf64_Xword)mdreg->region_size);
+#else
+		md_ss_toc->elf_size = rk_dump_elf32_image_phdr((void *)md_ss_toc->elf_header,
+					 (Elf32_Addr)mdreg->region_base_address,
+					 (Elf32_Word)mdreg->region_size);
+#endif
+	}
+}
+
+#ifdef CONFIG_ARM64
+void rk_minidump_get_el64(void **ram_image_addr, Elf64_Xword *ram_image_size)
+{
+	struct md_global_toc *mdg_toc = (struct md_global_toc *)SMEM_BASE;
+	struct md_ss_toc *md_ss_toc = &mdg_toc->md_ss_toc[0];
+
+	*ram_image_addr = (void *)md_ss_toc->elf_header;
+	*ram_image_size = md_ss_toc->elf_size;
+}
+#else
+void rk_minidump_get_el32(void **ram_image_addr, Elf32_Word *ram_image_size)
+{
+	struct md_global_toc *mdg_toc = (struct md_global_toc *)SMEM_BASE;
+	struct md_ss_toc *md_ss_toc = &mdg_toc->md_ss_toc[0];
+
+	*ram_image_addr = (void *)md_ss_toc->elf_header;
+	*ram_image_size = md_ss_toc->elf_size;
+}
+#endif
diff --git a/u-boot/arch/arm/mach-rockchip/rv1106/rv1106.c b/u-boot/arch/arm/mach-rockchip/rv1106/rv1106.c
index af28e4c33b..5be93f077f 100644
--- a/u-boot/arch/arm/mach-rockchip/rv1106/rv1106.c
+++ b/u-boot/arch/arm/mach-rockchip/rv1106/rv1106.c
@@ -404,9 +404,32 @@ void board_debug_uart_init(void)
 #endif
 }
 
+#ifdef CONFIG_SUPPORT_USBPLUG
+void board_set_iomux(enum if_type if_type, int devnum, int routing)
+{
+	switch (if_type) {
+	case IF_TYPE_MMC:
+		/* emmc iomux */
+		writel(0xffff1111, GPIO4_IOC_BASE + GPIO4A_IOMUX_SEL_L);
+		writel(0xffff1111, GPIO4_IOC_BASE + GPIO4A_IOMUX_SEL_H);
+		writel(0x00ff0011, GPIO4_IOC_BASE + GPIO4B_IOMUX_SEL_L);
+		break;
+	case IF_TYPE_MTD:
+		/* fspi iomux */
+		writel(0x0f000700, GPIO4_IOC_BASE + 0x0030);
+		writel(0xff002200, GPIO4_IOC_BASE + GPIO4A_IOMUX_SEL_L);
+		writel(0x0f0f0202, GPIO4_IOC_BASE + GPIO4A_IOMUX_SEL_H);
+		writel(0x00ff0022, GPIO4_IOC_BASE + GPIO4B_IOMUX_SEL_L);
+		break;
+	default:
+		break;
+	}
+}
+#endif
+
 int arch_cpu_init(void)
 {
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_SUPPORT_USBPLUG)
 	/* Save chip version to OS_REG1[2:0] */
 	if (readl(ROM_VER_REG) == ROM_V2)
 		writel((readl(CHIP_VER_REG) & ~CHIP_VER_MSK) | V(2), CHIP_VER_REG);
diff --git a/u-boot/arch/arm/mach-rockchip/spl.c b/u-boot/arch/arm/mach-rockchip/spl.c
index 85911687fd..bdb2a7c242 100644
--- a/u-boot/arch/arm/mach-rockchip/spl.c
+++ b/u-boot/arch/arm/mach-rockchip/spl.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <version.h>
 #include <boot_rkimg.h>
 #include <debug_uart.h>
 #include <dm.h>
@@ -153,7 +154,7 @@ void *memset(void *s, int c, size_t count)
 #ifdef CONFIG_SPL_DM_RESET
 static void brom_download(void)
 {
-	if (debug_uart_tstc() && debug_uart_getc() == 0x02) {
+	if (gd->console_evt == 0x02) {
 		printf("ctrl+b: Bootrom download!\n");
 		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
 		do_reset(NULL, 0, 0, NULL);
@@ -161,6 +162,30 @@ static void brom_download(void)
 }
 #endif
 
+static void spl_hotkey_init(void)
+{
+	/* If disable console, skip getting uart reg */
+	if (!gd || gd->flags & GD_FLG_DISABLE_CONSOLE)
+		return;
+	if (!gd->have_console)
+		return;
+
+	/* serial uclass only exists when enable CONFIG_SPL_FRAMEWORK */
+#ifdef CONFIG_SPL_FRAMEWORK
+	if (serial_tstc()) {
+		gd->console_evt = serial_getc();
+#else
+	if (debug_uart_tstc()) {
+		gd->console_evt = debug_uart_getc();
+#endif
+		if (gd->console_evt <= 0x1a) /* 'z' */
+			printf("SPL Hotkey: ctrl+%c\n",
+				gd->console_evt + 'a' - 1);
+	}
+
+	return;
+}
+
 void board_init_f(ulong dummy)
 {
 #ifdef CONFIG_SPL_FRAMEWORK
@@ -209,12 +234,14 @@ void board_init_f(ulong dummy)
 	/* Some SoCs like rk3036 does not use any frame work */
 	sdram_init();
 #endif
+	/* Get hotkey and store in gd */
+	spl_hotkey_init();
 #ifdef CONFIG_SPL_DM_RESET
 	brom_download();
 #endif
 	arch_cpu_init();
 	rk_board_init_f();
-#ifdef CONFIG_SPL_RAM_DEVICE
+#if defined(CONFIG_SPL_RAM_DEVICE) && defined(CONFIG_SPL_PCIE_EP_SUPPORT)
 	rockchip_pcie_ep_get_firmware();
 #endif
 #if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM) && !defined(CONFIG_SPL_BOARD_INIT)
@@ -329,6 +356,9 @@ void spl_perform_fixups(struct spl_image_info *spl_image)
 {
 #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
 	atags_set_bootdev_by_spl_bootdevice(spl_image->boot_device);
+  #ifdef BUILD_SPL_TAG
+	atags_set_shared_fwver(FW_SPL, "spl-"BUILD_SPL_TAG);
+  #endif
 #endif
 	return;
 }
@@ -365,16 +395,27 @@ bool spl_is_low_power(void)
 
 void spl_next_stage(struct spl_image_info *spl)
 {
+	const char *reason[] = { "Recovery key", "Ctrl+c", "LowPwr", "Unknown" };
 	uint32_t reg_boot_mode;
+	int i = 0;
 
 	if (spl_rockchip_dnl_key_pressed()) {
+		i = 0;
 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
-		return;
+		goto out;
 	}
+
+	if (gd->console_evt == 0x03) {
+		i = 1;
+		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
+		goto out;
+	}
+
 #ifdef CONFIG_SPL_DM_FUEL_GAUGE
 	if (spl_is_low_power()) {
+		i = 2;
 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
-		return;
+		goto out;
 	}
 #endif
 
@@ -388,11 +429,19 @@ void spl_next_stage(struct spl_image_info *spl)
 		spl->next_stage = SPL_NEXT_STAGE_KERNEL;
 		break;
 	default:
-		if ((reg_boot_mode & REBOOT_FLAG) != REBOOT_FLAG)
+		if ((reg_boot_mode & REBOOT_FLAG) != REBOOT_FLAG) {
 			spl->next_stage = SPL_NEXT_STAGE_KERNEL;
-		else
+		} else {
+			i = 3;
 			spl->next_stage = SPL_NEXT_STAGE_UBOOT;
+		}
 	}
+
+out:
+	if (spl->next_stage == SPL_NEXT_STAGE_UBOOT)
+		printf("Enter uboot reason: %s\n", reason[i]);
+
+	return;
 }
 #endif
 
diff --git a/u-boot/arch/arm/mach-rockchip/spl_pcie_ep_boot.c b/u-boot/arch/arm/mach-rockchip/spl_pcie_ep_boot.c
index 9d3a6a1364..7a24a1d192 100644
--- a/u-boot/arch/arm/mach-rockchip/spl_pcie_ep_boot.c
+++ b/u-boot/arch/arm/mach-rockchip/spl_pcie_ep_boot.c
@@ -186,6 +186,7 @@ static int rockchip_pcie_ep_set_bar_flag(void *dbi_base, u32 barno, int flags)
 static void pcie_bar_init(void *dbi_base)
 {
 	void *resbar_base;
+	u32 val;
 
 	writel(0, dbi_base + 0x10);
 	writel(0, dbi_base + 0x14);
@@ -194,15 +195,20 @@ static void pcie_bar_init(void *dbi_base)
 	writel(0, dbi_base + 0x20);
 	writel(0, dbi_base + 0x24);
 
+	/* Disable ASPM */
+	val = readl(dbi_base + 0x7c);
+	val &= ~(3 << 10);
+	writel(val, dbi_base + 0x7c);
+
 	/* Resize BAR0 to support 4M 32bits */
 	resbar_base = dbi_base + PCI_RESBAR;
-	writel(0xfffff0, resbar_base + 0x4);
+	writel(0x40, resbar_base + 0x4);
 	writel(0x2c0, resbar_base + 0x8);
 	/* BAR2: 64M 64bits */
-	writel(0xfffff0, resbar_base + 0x14);
+	writel(0x400, resbar_base + 0x14);
 	writel(0x6c0, resbar_base + 0x18);
 	/* BAR4: Fixed for EP wired register, 1M 32bits */
-	writel(0xfffff0, resbar_base + 0x24);
+	writel(0x10, resbar_base + 0x24);
 	writel(0xc0, resbar_base + 0x28);
 	/* Set flags */
 	rockchip_pcie_ep_set_bar_flag(dbi_base, 0, PCI_BASE_ADDRESS_MEM_TYPE_32);
@@ -333,7 +339,7 @@ static void pcie_update_atags(void)
 	struct tag_ram_partition t_ram_part;
 
 	if (!atags_is_available()) {
-		printf("RKEP: No ATAGS data found, create new!\n");
+		printep("RKEP: No ATAGS data found, create new!\n");
 		atags_destroy();
 	}
 
@@ -401,7 +407,27 @@ static void pcie_board_init(void)
 #define FIREWALL_PCIE_MASTER_SEC	0xfe0300f0
 #define FIREWALL_PCIE_ACCESS		0xfe586040
 #define CRU_PHYREF_ALT_GATE_CON		(CRU_BASE_ADDR + 0x0c38)
+#define PMU1_GRF_BASE			0xfd58a000
 #define PMU_PWR_GATE_SFTCON1		0xfd8d8150
+#define PMU1_IOC_BASE			0xfd5F0000
+#define CRU_GLB_RST_CON_OFFSET		(0xC10U)
+#define CRU_GLB_SRST_FST_VALUE_OFFSET	(0xC08U)
+
+void pcie_first_reset(void)
+{
+	printep("Fst Reset\n");
+	mdelay(1);
+
+	writel(0xFFDF, CRU_BASE_ADDR + CRU_GLB_RST_CON_OFFSET);
+	writel(0xffffffff, PMU1_GRF_BASE + 0x4); // reset width
+	writel(0x30003000, PMU1_GRF_BASE + 0x1c); // pmu1_grf pmu1_ioc hiold
+	writel(0x00f00020, PMU1_IOC_BASE + 0x0);   //select tsad_shut_m0 iomux
+	writel(0xFDB9, CRU_BASE_ADDR + CRU_GLB_SRST_FST_VALUE_OFFSET);
+
+	while (1)
+		;
+}
+
 static void pcie_cru_init(void)
 {
 	u32 phy0_mplla, phy1_mplla, t0 = 0, t1 = 0;
@@ -463,7 +489,7 @@ static void pcie_cru_init(void)
 		phy1_mplla = readl(PCIE3PHY_GRF_BASE + 0xA04);
 
 		if (phy0_mplla != t0 || phy1_mplla != t1) {
-			printf("RKEP: GRF:904=%x, a04=%x...\n", phy0_mplla, phy1_mplla);
+			printep("RKEP: GRF:904=%x, a04=%x...\n", phy0_mplla, phy1_mplla);
 
 			t0 = phy0_mplla;
 			t1 = phy1_mplla;
@@ -474,8 +500,17 @@ static void pcie_cru_init(void)
 		udelay(10);
 	}
 
-	/* PHY config: no config need for snps3.0phy */
+	if (i >= timeout) {
+		printep("lock fail\n");
+		mdelay(1);
+		pcie_first_reset();
+	}
 
+	/* PHY config: no config need for snps3.0phy */
+}
+
+static void pcie_firewall_init(void)
+{
 	/* Enable PCIe Access in firewall and master secure mode */
 	writel(0xffff0000, FIREWALL_PCIE_MASTER_SEC);
 	writel(0x01800000, FIREWALL_PCIE_ACCESS);
@@ -509,13 +544,31 @@ static const u16 phy_fw[] = {
 #define CRU_GATE_CON33			(CRU_BASE + 0x384)
 #define CRU_SOFTRST_CON12		(CRU_BASE + 0x430)
 #define CRU_SOFTRST_CON27		(CRU_BASE + 0x46c)
+#define CRU_GLB_SRST_FST_OFFSET		(0xD4U)
 
 #define PCIE30_PHY_GRF			0xFDCB8000
 
+#define SYS_GRF_BASE			0xFDC60000
+
+void pcie_first_reset(void)
+{
+	printep("Fst Reset\n");
+	mdelay(1);
+
+	writel(0x00040004, CRU_BASE + 0x104);
+	writel(0x00700010, CRU_BASE);
+	writel(0x00100010, SYS_GRF_BASE + 0x508);
+	writel(0xFDB9, CRU_BASE + CRU_GLB_SRST_FST_OFFSET);
+
+	while (1)
+		;
+}
+
 void pcie_cru_init(void)
 {
-	u32 i, reg;
+	u32 i, reg, timeout = 500;
 	void __iomem *mmio = (void __iomem *)0xFE8C0000;
+	u32 phy0_status0, phy0_status1, t0 = 0, t1 = 0;
 
 	/* Enable phy and controoler clk */
 	writel(0xffff0000, PMUCRU_PMUGATE_CON02);
@@ -548,20 +601,20 @@ void pcie_cru_init(void)
 	writel(0x40000000, CRU_SOFTRST_CON27);
 
 	udelay(5);
-	printf("RKEP: sram initial\n");
+	printep("RKEP: sram initial\n");
 	while (1) {
 		reg = readl(PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_STATUS0);
 		if (RK3568_SRAM_INIT_DONE(reg))
 			break;
 	}
-	printf("RKEP: sram init done\n");
+	printep("RKEP: sram init done\n");
 
 	writel((0x3 << 8) | (0x3 << (8 + 16)),
 	       PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON9); //map to access sram
 	for (i = 0; i < ARRAY_SIZE(phy_fw); i++)
 		writel(phy_fw[i], mmio + (i << 2));
 
-	printf("RKEP: snps pcie3phy FW update! size %ld\n", ARRAY_SIZE(phy_fw));
+	printep("RKEP: snps pcie3phy FW update! size %ld\n", ARRAY_SIZE(phy_fw));
 	writel((0x0 << 8) | (0x3 << (8 + 16)),
 	       PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON9);
 	writel((0x1 << 14) | (0x1 << (14 + 16)),
@@ -570,8 +623,35 @@ void pcie_cru_init(void)
 	writel(0xffff0000, CRU_SOFTRST_CON12);
 	writel(0x100010, PCIE_SNPS_APB_BASE + 0x180);
 
+	/* S-Phy: waiting for phy locked */
+	for (i = 0; i < timeout; i++) {
+		phy0_status0 = readl(PCIE30_PHY_GRF + 0x80);
+		phy0_status1 = readl(PCIE30_PHY_GRF + 0x84);
+
+		if (phy0_status0 != t0 || phy0_status1 != t1) {
+			printep("RKEP: GRF:0x80=%x, 0x84=%x...\n", phy0_status0, phy0_status1);
+
+			t0 = phy0_status0;
+			t1 = phy0_status1;
+			if (RK3568_SRAM_INIT_DONE(phy0_status0))
+				break;
+		}
+
+		udelay(10);
+	}
+
+	if (i >= timeout) {
+		printep("lock fail\n");
+		mdelay(1);
+		pcie_first_reset();
+	}
+
 	udelay(1);
 }
+
+static void pcie_firewall_init(void)
+{
+}
 #endif
 
 static void pcie_ep_init(void)
@@ -627,6 +707,12 @@ reinit:
 	val = readl(dbi_base + 0x4);
 	writel(val | 0x6, dbi_base + 0x4);
 
+	val = readl(apb_base + 0x10);
+	if (val & 0x4) {
+		printep("Link is reset, int status misc=%x\n", val);
+		retries++;
+	}
+
 	if (retries)	/* Set app_dly2_done to enable app_ltssm_enable */
 		writel(0x80008, apb_base + 0x180);
 	else		/* Enable LTSSM */
@@ -674,10 +760,13 @@ void rockchip_pcie_ep_init(void)
 	writel(0x1 << 23 | 0x1 << 21, PMU_PWR_GATE_SFTCON1);
 	udelay(10);
 #endif
+
+	pcie_firewall_init();
 	/* Re-in pcie initial */
 	val = readl(PCIE_SNPS_APB_BASE + 0x300);
 	if (((val & 0x3ffff) & ((0x3 << 16))) == 0x30000) {
 		printf("RKEP: already link up\n");
+		pcie_devmode_update(RKEP_MODE_LOADER, RKEP_SMODE_LNKUP);
 		return;
 	}
 
diff --git a/u-boot/arch/arm/mach-rockchip/usbplug.c b/u-boot/arch/arm/mach-rockchip/usbplug.c
index 48794f8f6d..7cc87c6c3d 100644
--- a/u-boot/arch/arm/mach-rockchip/usbplug.c
+++ b/u-boot/arch/arm/mach-rockchip/usbplug.c
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2020 Rockchip Electronics Co., Ltd.
+ * (C) Copyright 2020-2023 Rockchip Electronics Co., Ltd.
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
@@ -12,46 +12,127 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct bootdev_list {
+	u32 if_type;
+	u8 devnum;
+	u8 iomux_routing;
+};
+
+#if CONFIG_IS_ENABLED(ROCKCHIP_RK3588)
+static const struct bootdev_list dev_list[] = {
+	{IF_TYPE_MMC, 0, 0},
+	{IF_TYPE_MTD, 0, 0}, /* BLK_MTD_NAND */
+	{IF_TYPE_MTD, 1, 0}, /* BLK_MTD_SPI_NAND FSPI M0 */
+	{IF_TYPE_MTD, 1, 1}, /* BLK_MTD_SPI_NAND FSPI M1 */
+	{IF_TYPE_MTD, 1, 2}, /* BLK_MTD_SPI_NAND FSPI M2 */
+	{IF_TYPE_MTD, 2, 0}, /* BLK_MTD_SPI_NOR FSPI M0 */
+	{IF_TYPE_MTD, 2, 1}, /* BLK_MTD_SPI_NOR FSPI M1 */
+	{IF_TYPE_MTD, 2, 2}, /* BLK_MTD_SPI_NOR FSPI M2 */
+	{IF_TYPE_RKNAND, 2, 0},
+};
+#else
+static const struct bootdev_list dev_list[] = {
+	{IF_TYPE_MMC, 0, 0},
+	{IF_TYPE_MTD, 0, 0}, /* BLK_MTD_NAND */
+	{IF_TYPE_MTD, 1, 0}, /* BLK_MTD_SPI_NAND */
+	{IF_TYPE_MTD, 2, 0}, /* BLK_MTD_SPI_NOR */
+	{IF_TYPE_RKNAND, 0, 0},
+};
+#endif
+
+static struct blk_desc *boot_blk_desc;
+struct blk_desc *rockchip_get_bootdev(void)
+{
+	return boot_blk_desc;
+}
+
+__weak void board_set_iomux(enum if_type if_type, int devnum, int routing)
+{
+}
+
+struct blk_desc *usbplug_blk_get_devnum_by_type(enum if_type if_type, int devnum)
+{
+	struct blk_desc *blk_desc = NULL;
+	u8 iomux_routing;
+	int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+		if (if_type != dev_list[i].if_type || devnum != dev_list[i].devnum)
+			continue;
+		iomux_routing = dev_list[i].iomux_routing;
+		switch (if_type) {
+#ifdef CONFIG_MMC
+		case IF_TYPE_MMC:
+			board_set_iomux(if_type, devnum, iomux_routing);
+			mmc_initialize(gd->bd);
+			break;
+#endif
+		case IF_TYPE_MTD:
+			board_set_iomux(if_type, devnum, iomux_routing);
+			break;
+		default:
+			printf("Bootdev 0x%x is not support\n", if_type);
+			return NULL;
+		}
+
+		printf("scandev: %s %d m%d\n", blk_get_if_type_name(if_type), devnum, iomux_routing);
+		blk_desc = blk_get_devnum_by_type(if_type, devnum);
+		if (blk_desc)
+			break;
+	}
+
+	boot_blk_desc = blk_desc;
+
+	return blk_desc;
+}
+
 static char *bootdev_rockusb_cmd(void)
 {
-	const char *devtype, *devnum;
-	const char *bootdev_list[] = {
-		"mmc",		"0",
-		"mtd",		"0",
-		"mtd",		"1",
-		"mtd",		"2",
-		"rknand",	"0",
-		NULL,		NULL,
-	};
+	struct blk_desc *blk_desc = NULL;
+	u32 if_type = IF_TYPE_UNKNOWN;
+	u8 devnum, iomux_routing;
 	char *cmd;
 	int i = 0;
 
-	devtype = bootdev_list[0];
-	devnum = bootdev_list[1];
-	while (devtype) {
-		if (!strcmp("mmc", devtype))
+	for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+		if_type = dev_list[i].if_type;
+		devnum = dev_list[i].devnum;
+		iomux_routing = dev_list[i].iomux_routing;
+		switch (if_type) {
+#ifdef CONFIG_MMC
+		case IF_TYPE_MMC:
+			board_set_iomux(if_type, devnum, iomux_routing);
 			mmc_initialize(gd->bd);
-
-		if (blk_get_devnum_by_typename(devtype, atoi(devnum)))
 			break;
+#endif
+		case IF_TYPE_MTD:
+			board_set_iomux(if_type, devnum, iomux_routing);
+			break;
+		default:
+			printf("Bootdev 0x%x is not support\n", if_type);
+			return NULL;
+		}
 
-		i += 2;
-		devtype = bootdev_list[i];
-		devnum = bootdev_list[i + 1];
+		printf("Scandev: %s %d m%d\n", blk_get_if_type_name(if_type), devnum, iomux_routing);
+		blk_desc = blk_get_devnum_by_type(if_type, devnum);
+		if (blk_desc)
+			break;
 	}
 
-	if (!devtype) {
+	boot_blk_desc = blk_desc;
+
+	if (!if_type) {
 		printf("No boot device\n");
 		return NULL;
 	}
 
-	printf("Bootdev: %s %s\n", devtype, devnum);
+	printf("Bootdev: %s %d\n", blk_get_if_type_name(if_type), devnum);
 
 	cmd = malloc(32);
 	if (!cmd)
 		return NULL;
 
-	snprintf(cmd, 32, "rockusb 0 %s %s", devtype, devnum);
+	snprintf(cmd, 32, "rockusb 0 %s %d", blk_get_if_type_name(if_type), devnum);
 
 	return cmd;
 }
diff --git a/u-boot/arch/arm/mach-rockchip/vendor.c b/u-boot/arch/arm/mach-rockchip/vendor.c
index 2a146b75ba..3f9d5df8fb 100644
--- a/u-boot/arch/arm/mach-rockchip/vendor.c
+++ b/u-boot/arch/arm/mach-rockchip/vendor.c
@@ -11,6 +11,7 @@
 #include <nand.h>
 #include <part.h>
 #include <fdt_support.h>
+#include <usbplug.h>
 
 /* tag for vendor check */
 #define VENDOR_TAG		0x524B5644
@@ -649,10 +650,10 @@ int vendor_storage_read(u16 id, void *pbuf, u16 size)
  */
 int vendor_storage_write(u16 id, void *pbuf, u16 size)
 {
-	int cnt, ret = 0;
-	u32 i, next_index, align_size;
-	struct vendor_item *item;
+	u32 i, j, next_index, align_size, alloc_size, next_size;
 	u16 part_size, max_item_num, offset, part_num;
+	struct vendor_item *item;
+	int cnt, ret = 0;
 
 	/* init vendor storage */
 	if (!bootdev_type) {
@@ -703,10 +704,35 @@ int vendor_storage_write(u16 id, void *pbuf, u16 size)
 	/* If item already exist, update the item data */
 	for (i = 0; i < vendor_info.hdr->item_num; i++) {
 		if ((item + i)->id == id) {
-			debug("[Vendor INFO]:Find the matching item, id=%d\n", id);
-			offset = (item + i)->offset;
-			memcpy((vendor_info.data + offset), pbuf, size);
-			(item + i)->size = size;
+			alloc_size = ((item + i)->size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
+			if (size > alloc_size) {
+				if (vendor_info.hdr->free_size < align_size)
+					return -EINVAL;
+				debug("[Vendor INFO]:Find the matching item, id=%d and resize\n", id);
+				offset = (item + i)->offset;
+				for (j = i; j < vendor_info.hdr->item_num - 1; j++) {
+					(item + j)->id = (item + j + 1)->id;
+					(item + j)->size = (item + j + 1)->size;
+					(item + j)->offset = offset;
+
+					next_size = ((item + j + 1)->size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
+					memcpy((vendor_info.data + offset),
+					       (vendor_info.data + (item + j + 1)->offset),
+					       next_size);
+					offset += next_size;
+				}
+				(item + j)->id = id;
+				(item + j)->offset = offset;
+				(item + j)->size = size;
+				memcpy((vendor_info.data + offset), pbuf, size);
+				vendor_info.hdr->free_offset = offset + align_size;
+				vendor_info.hdr->free_size -= align_size - alloc_size;
+			} else {
+				debug("[Vendor INFO]:Find the matching item, id=%d\n", id);
+				offset = (item + i)->offset;
+				memcpy((vendor_info.data + offset), pbuf, size);
+				(item + i)->size = size;
+			}
 			vendor_info.hdr->version++;
 			*(vendor_info.version2) = vendor_info.hdr->version;
 			vendor_info.hdr->next_index++;
diff --git a/u-boot/arch/arm/mach-rockchip/vendor_misc.c b/u-boot/arch/arm/mach-rockchip/vendor_misc.c
index c86d6aace4..8133f116cb 100644
--- a/u-boot/arch/arm/mach-rockchip/vendor_misc.c
+++ b/u-boot/arch/arm/mach-rockchip/vendor_misc.c
@@ -19,6 +19,7 @@ struct hdcpdata {
 	unsigned char data[0];
 };
 
+#ifndef CONFIG_SUPPORT_USBPLUG
 int vendor_handle_hdcp(struct vendor_item *vhead)
 {
 	struct arm_smccc_res res;
@@ -61,4 +62,4 @@ int vendor_handle_hdcp(struct vendor_item *vhead)
 
 	return 0;
 }
-
+#endif
diff --git a/u-boot/board/rockchip/evb_rk3528/evb_rk3528.c b/u-boot/board/rockchip/evb_rk3528/evb_rk3528.c
index d0c1e5507e..df91be38ed 100644
--- a/u-boot/board/rockchip/evb_rk3528/evb_rk3528.c
+++ b/u-boot/board/rockchip/evb_rk3528/evb_rk3528.c
@@ -7,27 +7,79 @@
 #include <common.h>
 #include <dwc3-uboot.h>
 #include <usb.h>
+#include <linux/usb/phy-rockchip-naneng-combphy.h>
+#include <asm/io.h>
+#include <rockusb.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef CONFIG_USB_DWC3
+#define CRU_BASE		0xff4a0000
+#define CRU_SOFTRST_CON33	0x0a84
+
 static struct dwc3_device dwc3_device_data = {
-	.maximum_speed = USB_SPEED_HIGH,
+	.maximum_speed = USB_SPEED_SUPER,
 	.base = 0xfe500000,
 	.dr_mode = USB_DR_MODE_PERIPHERAL,
 	.index = 0,
 	.dis_u2_susphy_quirk = 1,
+	.dis_u1u2_quirk = 1,
 	.usb2_phyif_utmi_width = 16,
 };
 
-int usb_gadget_handle_interrupts(void)
+int usb_gadget_handle_interrupts(int index)
 {
 	dwc3_uboot_handle_interrupt(0);
 	return 0;
 }
 
+bool rkusb_usb3_capable(void)
+{
+	return true;
+}
+
+static void usb_reset_otg_controller(void)
+{
+	writel(0x00020002, CRU_BASE + CRU_SOFTRST_CON33);
+	mdelay(1);
+	writel(0x00020000, CRU_BASE + CRU_SOFTRST_CON33);
+	mdelay(1);
+}
+
 int board_usb_init(int index, enum usb_init_type init)
 {
+	u32 ret = 0;
+
+	usb_reset_otg_controller();
+
+#if defined(CONFIG_SUPPORT_USBPLUG)
+	dwc3_device_data.maximum_speed = USB_SPEED_HIGH;
+
+	if (rkusb_switch_usb3_enabled()) {
+		dwc3_device_data.maximum_speed = USB_SPEED_SUPER;
+		ret = rockchip_combphy_usb3_uboot_init();
+		if (ret) {
+			rkusb_force_to_usb2(true);
+			dwc3_device_data.maximum_speed = USB_SPEED_HIGH;
+		}
+	}
+#else
+	ret = rockchip_combphy_usb3_uboot_init();
+	if (ret) {
+		rkusb_force_to_usb2(true);
+		dwc3_device_data.maximum_speed = USB_SPEED_HIGH;
+	}
+#endif
+
 	return dwc3_uboot_init(&dwc3_device_data);
 }
+
+#if defined(CONFIG_SUPPORT_USBPLUG)
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+	dwc3_uboot_exit(index);
+	return 0;
+}
+#endif
+
 #endif
diff --git a/u-boot/board/rockchip/evb_rk3588/evb_rk3588.c b/u-boot/board/rockchip/evb_rk3588/evb_rk3588.c
index 81c5089944..fa72f37730 100644
--- a/u-boot/board/rockchip/evb_rk3588/evb_rk3588.c
+++ b/u-boot/board/rockchip/evb_rk3588/evb_rk3588.c
@@ -7,27 +7,79 @@
 #include <common.h>
 #include <dwc3-uboot.h>
 #include <usb.h>
+#include <linux/usb/phy-rockchip-usbdp.h>
+#include <asm/io.h>
+#include <rockusb.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef CONFIG_USB_DWC3
+#define CRU_BASE		0xfd7c0000
+#define CRU_SOFTRST_CON42	0x0aa8
+
 static struct dwc3_device dwc3_device_data = {
-	.maximum_speed = USB_SPEED_HIGH,
+	.maximum_speed = USB_SPEED_SUPER,
 	.base = 0xfc000000,
 	.dr_mode = USB_DR_MODE_PERIPHERAL,
 	.index = 0,
 	.dis_u2_susphy_quirk = 1,
+	.dis_u1u2_quirk = 1,
 	.usb2_phyif_utmi_width = 16,
 };
 
-int usb_gadget_handle_interrupts(void)
+int usb_gadget_handle_interrupts(int index)
 {
 	dwc3_uboot_handle_interrupt(0);
 	return 0;
 }
 
+bool rkusb_usb3_capable(void)
+{
+	return true;
+}
+
+static void usb_reset_otg_controller(void)
+{
+	writel(0x00100010, CRU_BASE + CRU_SOFTRST_CON42);
+	mdelay(1);
+	writel(0x00100000, CRU_BASE + CRU_SOFTRST_CON42);
+	mdelay(1);
+}
+
 int board_usb_init(int index, enum usb_init_type init)
 {
+	u32 ret = 0;
+
+	usb_reset_otg_controller();
+
+#if defined(CONFIG_SUPPORT_USBPLUG)
+	dwc3_device_data.maximum_speed = USB_SPEED_HIGH;
+
+	if (rkusb_switch_usb3_enabled()) {
+		dwc3_device_data.maximum_speed = USB_SPEED_SUPER;
+		ret = rockchip_u3phy_uboot_init();
+		if (ret) {
+			rkusb_force_to_usb2(true);
+			dwc3_device_data.maximum_speed = USB_SPEED_HIGH;
+		}
+	}
+#else
+	ret = rockchip_u3phy_uboot_init();
+	if (ret) {
+		rkusb_force_to_usb2(true);
+		dwc3_device_data.maximum_speed = USB_SPEED_HIGH;
+	}
+#endif
+
 	return dwc3_uboot_init(&dwc3_device_data);
 }
+
+#if defined(CONFIG_SUPPORT_USBPLUG)
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+	dwc3_uboot_exit(index);
+	return 0;
+}
+#endif
+
 #endif
diff --git a/u-boot/cmd/Kconfig b/u-boot/cmd/Kconfig
index 1efdeae6c6..5b359ff846 100644
--- a/u-boot/cmd/Kconfig
+++ b/u-boot/cmd/Kconfig
@@ -929,6 +929,15 @@ config CMD_PCMCIA
 	  about 1990. These devices are typically removable memory or network
 	  cards using a standard 68-pin connector.
 
+config CMD_PINMUX
+	bool "pinmux - show pins muxing"
+	depends on PINCTRL
+	default y if PINCTRL
+	help
+	  Parse all available pin-controllers and show pins muxing. This
+	  is useful for debug purpoer to check the pin muxing and to know if
+	  a pin is configured as a GPIO or as an alternate function.
+
 config CMD_READ
 	bool "read - Read binary data from a partition"
 	help
diff --git a/u-boot/cmd/Makefile b/u-boot/cmd/Makefile
index d4c12a3cc3..9a2d5f89d6 100644
--- a/u-boot/cmd/Makefile
+++ b/u-boot/cmd/Makefile
@@ -113,6 +113,7 @@ ifdef CONFIG_PCI
 obj-$(CONFIG_CMD_PCI) += pci.o
 endif
 obj-y += pcmcia.o
+obj-$(CONFIG_CMD_PINMUX) += pinmux.o
 obj-$(CONFIG_CMD_PXE) += pxe.o
 obj-$(CONFIG_CMD_QFW) += qfw.o
 obj-$(CONFIG_CMD_READ) += read.o
diff --git a/u-boot/cmd/atags.c b/u-boot/cmd/atags.c
index 8bcf8b3203..6af5613957 100644
--- a/u-boot/cmd/atags.c
+++ b/u-boot/cmd/atags.c
@@ -179,6 +179,14 @@ static void atags_print_tag(struct tag *t)
 		for (i = 0; i < ARRAY_SIZE(t->u.pstore.buf); i++)
 			printf("  table[%d] = 0x%x@0x%x\n", i, t->u.pstore.buf[i].size, t->u.pstore.buf[i].addr);
 		break;
+	case ATAG_FWVER:
+		printf("[fwver]:\n");
+		printf("     magic = 0x%x\n", t->hdr.magic);
+		printf("      size = 0x%x\n\n", t->hdr.size << 2);
+		printf("   version = 0x%x\n", t->u.fwver.version);
+		for (i = 0; i < FW_MAX; i++)
+			printf("    ver[%d] = %s\n", i, t->u.fwver.ver[i]);
+		break;
 	default:
 		printf("%s: magic(%x) is not support\n", __func__, t->hdr.magic);
 	}
diff --git a/u-boot/cmd/demo.c b/u-boot/cmd/demo.c
index 209dc4a57c..af49845b03 100644
--- a/u-boot/cmd/demo.c
+++ b/u-boot/cmd/demo.c
@@ -67,9 +67,8 @@ int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 	puts("Demo uclass entries:\n");
 
-	for (i = 0, ret = uclass_first_device(UCLASS_DEMO, &dev);
-	     dev;
-	     ret = uclass_next_device(&dev)) {
+	for (i = 0, uclass_first_device(UCLASS_DEMO, &dev); dev;
+	     uclass_next_device(&dev)) {
 		printf("entry %d - instance %08x, ops %08x, platdata %08x\n",
 		       i++, map_to_sysmem(dev),
 		       map_to_sysmem(dev->driver->ops),
diff --git a/u-boot/cmd/gpio.c b/u-boot/cmd/gpio.c
index ecdc453918..878ac7ef21 100644
--- a/u-boot/cmd/gpio.c
+++ b/u-boot/cmd/gpio.c
@@ -68,14 +68,13 @@ static int do_gpio_status(bool all, const char *gpio_name)
 	struct udevice *dev;
 	int banklen;
 	int flags;
-	int ret;
 
 	flags = 0;
 	if (gpio_name && !*gpio_name)
 		gpio_name = NULL;
-	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+	for (uclass_first_device(UCLASS_GPIO, &dev);
 	     dev;
-	     ret = uclass_next_device(&dev)) {
+	     uclass_next_device(&dev)) {
 		const char *bank_name;
 		int num_bits;
 
@@ -111,7 +110,7 @@ static int do_gpio_status(bool all, const char *gpio_name)
 			flags |= FLAG_SHOW_NEWLINE;
 	}
 
-	return ret;
+	return 0;
 }
 #endif
 
diff --git a/u-boot/cmd/pinmux.c b/u-boot/cmd/pinmux.c
new file mode 100644
index 0000000000..de909a163d
--- /dev/null
+++ b/u-boot/cmd/pinmux.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/pinctrl.h>
+#include <dm/uclass-internal.h>
+
+#define LIMIT_DEVNAME	30
+
+static struct udevice *currdev;
+
+static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	const char *name;
+	int ret;
+
+	switch (argc) {
+	case 2:
+		name = argv[1];
+		ret = uclass_get_device_by_name(UCLASS_PINCTRL, name, &currdev);
+		if (ret) {
+			printf("Can't get the pin-controller: %s!\n", name);
+			return CMD_RET_FAILURE;
+		}
+		/* fall through */
+	case 1:
+		if (!currdev) {
+			printf("Pin-controller device is not set!\n");
+			return CMD_RET_USAGE;
+		}
+
+		printf("dev: %s\n", currdev->name);
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int show_pinmux(struct udevice *dev)
+{
+	char pin_name[PINNAME_SIZE];
+	char pin_mux[PINMUX_SIZE];
+	int pins_count;
+	int i;
+	int ret;
+
+	pins_count = pinctrl_get_pins_count(dev);
+
+	if (pins_count == -ENOSYS) {
+		printf("Ops get_pins_count not supported\n");
+		return pins_count;
+	}
+
+	for (i = 0; i < pins_count; i++) {
+		ret = pinctrl_get_pin_name(dev, i, pin_name, PINNAME_SIZE);
+		if (ret == -ENOSYS) {
+			printf("Ops get_pin_name not supported\n");
+			return ret;
+		}
+
+		ret = pinctrl_get_pin_muxing(dev, i, pin_mux, PINMUX_SIZE);
+		if (ret) {
+			printf("Ops get_pin_muxing error (%d)\n", ret);
+			return ret;
+		}
+
+		printf("%-*s: %-*s\n", PINNAME_SIZE, pin_name,
+		       PINMUX_SIZE, pin_mux);
+	}
+
+	return 0;
+}
+
+static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct udevice *dev;
+	int ret = CMD_RET_USAGE;
+
+	if (currdev && (argc < 2 || strcmp(argv[1], "-a")))
+		return show_pinmux(currdev);
+
+	if (argc < 2 || strcmp(argv[1], "-a"))
+		return ret;
+
+	uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) {
+		/* insert a separator between each pin-controller display */
+		printf("--------------------------\n");
+		printf("%s:\n", dev->name);
+		ret = show_pinmux(dev);
+		if (ret < 0)
+			printf("Can't display pin muxing for %s\n",
+			       dev->name);
+	}
+
+	return ret;
+}
+
+static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct udevice *dev;
+
+	printf("| %-*.*s| %-*.*s| %s\n",
+	       LIMIT_DEVNAME, LIMIT_DEVNAME, "Device",
+	       LIMIT_DEVNAME, LIMIT_DEVNAME, "Driver",
+	       "Parent");
+
+	uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) {
+		printf("| %-*.*s| %-*.*s| %s\n",
+		       LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
+		       LIMIT_DEVNAME, LIMIT_DEVNAME, dev->driver->name,
+		       dev->parent->name);
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t pinmux_subcmd[] = {
+	U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
+	U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
+	U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
+};
+
+static int do_pinmux(cmd_tbl_t *cmdtp, int flag, int argc,
+		     char * const argv[])
+{
+	cmd_tbl_t *cmd;
+
+	argc--;
+	argv++;
+
+	cmd = find_cmd_tbl(argv[0], pinmux_subcmd, ARRAY_SIZE(pinmux_subcmd));
+	if (!cmd || argc > cmd->maxargs)
+		return CMD_RET_USAGE;
+
+	return cmd->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(pinmux, CONFIG_SYS_MAXARGS, 1, do_pinmux,
+	   "show pin-controller muxing",
+	   "list                     - list UCLASS_PINCTRL devices\n"
+	   "pinmux dev [pincontroller-name] - select pin-controller device\n"
+	   "pinmux status [-a]              - print pin-controller muxing [for all]\n"
+)
diff --git a/u-boot/cmd/pmic.c b/u-boot/cmd/pmic.c
index 970767cdfa..8c191ab258 100644
--- a/u-boot/cmd/pmic.c
+++ b/u-boot/cmd/pmic.c
@@ -50,27 +50,20 @@ static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	struct udevice *dev;
-	int ret;
 
 	printf("| %-*.*s| %-*.*s| %s @ %s\n",
 	       LIMIT_DEV, LIMIT_DEV, "Name",
 	       LIMIT_PARENT, LIMIT_PARENT, "Parent name",
 	       "Parent uclass", "seq");
 
-	for (ret = uclass_first_device(UCLASS_PMIC, &dev); dev;
-	     ret = uclass_next_device(&dev)) {
-		if (ret)
-			continue;
-
+	for (uclass_first_device(UCLASS_PMIC, &dev); dev;
+	     uclass_next_device(&dev)) {
 		printf("| %-*.*s| %-*.*s| %s @ %d\n",
 		       LIMIT_DEV, LIMIT_DEV, dev->name,
 		       LIMIT_PARENT, LIMIT_PARENT, dev->parent->name,
 		       dev_get_uclass_name(dev->parent), dev->parent->seq);
 	}
 
-	if (ret)
-		return CMD_RET_FAILURE;
-
 	return CMD_RET_SUCCESS;
 }
 
diff --git a/u-boot/cmd/regulator.c b/u-boot/cmd/regulator.c
index b605255180..25aef95b2b 100644
--- a/u-boot/cmd/regulator.c
+++ b/u-boot/cmd/regulator.c
@@ -249,8 +249,8 @@ static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	/* Show all of them in a list, probing them as needed */
 	printf("%-20s %-10s %10s %10s %-10s\n", "Name", "Enabled", "uV", "mA",
 	       "Mode");
-	for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
-	     ret = uclass_next_device(&dev))
+	for (uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+	     uclass_next_device(&dev))
 		do_status_line(dev);
 
 	return CMD_RET_SUCCESS;
diff --git a/u-boot/cmd/rockusb.c b/u-boot/cmd/rockusb.c
index 9792a828bb..38768b724d 100644
--- a/u-boot/cmd/rockusb.c
+++ b/u-boot/cmd/rockusb.c
@@ -151,6 +151,34 @@ cleanup:
 	return ret;
 }
 
+void rkusb_force_to_usb2(bool enable)
+{
+	if (g_rkusb)
+		g_rkusb->force_usb2 = enable;
+}
+
+bool rkusb_force_usb2_enabled(void)
+{
+	if (!g_rkusb)
+		return true;
+
+	return g_rkusb->force_usb2;
+}
+
+void rkusb_switch_to_usb3_enable(bool enable)
+{
+	if (g_rkusb)
+		g_rkusb->switch_usb3 = enable;
+}
+
+bool rkusb_switch_usb3_enabled(void)
+{
+	if (!g_rkusb)
+		return false;
+
+	return g_rkusb->switch_usb3;
+}
+
 static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	const char *usb_controller;
@@ -164,6 +192,7 @@ static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 	if (argc != 4)
 		return CMD_RET_USAGE;
 
+re_enumerate:
 	usb_controller = argv[1];
 	devtype = argv[2];
 	devnum	= argv[3];
@@ -171,7 +200,7 @@ static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 	if (!strcmp(devtype, "mmc") && !strcmp(devnum, "1")) {
 		pr_err("Forbid to flash mmc 1(sdcard)\n");
 		return CMD_RET_FAILURE;
-	} else if (!strcmp(devtype, "nvme") && !strcmp(devnum, "0")) {
+	} else if ((!strcmp(devtype, "nvme") || !strcmp(devtype, "scsi")) && !strcmp(devnum, "0")) {
 		/*
 		 * Add partnum ":0" to active 'allow_whole_dev' partition
 		 * search mechanism on multi storage, where there maybe not
@@ -212,23 +241,34 @@ static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 		goto cleanup_board;
 	}
 
-	s = env_get("serial#");
-	if (s) {
-		char *sn = (char *)calloc(strlen(s) + 1, sizeof(char));
-		char *sn_p = sn;
+	if (rkusb_switch_usb3_enabled()) {
+		/* Maskrom usb3 serialnumber get from upgrade tool */
+		rkusb_switch_to_usb3_enable(false);
+	} else {
+		s = env_get("serial#");
+		if (s) {
+			char *sn = (char *)calloc(strlen(s) + 1, sizeof(char));
+			char *sn_p = sn;
 
-		if (!sn)
-			goto cleanup_board;
+			if (!sn)
+				goto cleanup_board;
 
-		memcpy(sn, s, strlen(s));
-		while (*sn_p) {
-			if (*sn_p == '\\' || *sn_p == '/')
-				*sn_p = '_';
-			sn_p++;
+			memcpy(sn, s, strlen(s));
+			while (*sn_p) {
+				if (*sn_p == '\\' || *sn_p == '/')
+					*sn_p = '_';
+				sn_p++;
+			}
+
+			g_dnl_set_serialnumber(sn);
+			free(sn);
+#if defined(CONFIG_SUPPORT_USBPLUG)
+		} else {
+			char sn[9] = "Rockchip";
+
+			g_dnl_set_serialnumber(sn);
+#endif
 		}
-
-		g_dnl_set_serialnumber(sn);
-		free(sn);
 	}
 
 	rc = g_dnl_register("rkusb_ums_dnl");
@@ -268,6 +308,16 @@ static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 
 		rc = fsg_main_thread(NULL);
 		if (rc) {
+			if (rc == -ENODEV && rkusb_usb3_capable() &&
+			    !rkusb_force_usb2_enabled()) {
+				printf("wait for usb3 connect timeout\n");
+				rkusb_force_to_usb2(true);
+				g_dnl_unregister();
+				usb_gadget_release(controller_index);
+				rkusb_fini();
+				goto re_enumerate;
+			}
+
 			/* Check I/O error */
 			if (rc == -EIO)
 				printf("\rCheck USB cable connection\n");
@@ -279,6 +329,14 @@ static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 			rc = CMD_RET_SUCCESS;
 			goto cleanup_register;
 		}
+
+		if (rkusb_switch_usb3_enabled()) {
+			printf("rockusb switch to usb3\n");
+			g_dnl_unregister();
+			usb_gadget_release(controller_index);
+			rkusb_fini();
+			goto re_enumerate;
+		}
 	}
 
 cleanup_register:
diff --git a/u-boot/common/Kconfig b/u-boot/common/Kconfig
index cc0753cb45..c276f701a8 100644
--- a/u-boot/common/Kconfig
+++ b/u-boot/common/Kconfig
@@ -680,6 +680,20 @@ config HASH
 	  and the algorithms it supports are defined in common/hash.c. See
 	  also CMD_HASH for command-line access.
 
+config BOARD_RNG_SEED
+	bool "Provide /chosen/rng-seed property to the linux kernel"
+	help
+	  Selecting this option requires the board to define a
+	  board_rng_seed() function, which should return a buffer
+	  which will be used to populate the /chosen/rng-seed property
+	  in the device tree for the OS being booted.
+
+	  It is up to the board code (and more generally the whole
+	  BSP) where and how to store (or generate) such a seed, how
+	  to ensure a given seed is only used once, how to create a
+	  new seed for use on subsequent boots, and whether or not the
+	  kernel should account any entropy from the given seed.
+
 endmenu
 
 menu "MT support"
diff --git a/u-boot/common/Makefile b/u-boot/common/Makefile
index e6f1c114c7..52cd612d15 100644
--- a/u-boot/common/Makefile
+++ b/u-boot/common/Makefile
@@ -165,6 +165,7 @@ obj-$(CONFIG_IO_TRACE) += iotrace.o
 obj-$(CONFIG_ANDROID_WRITE_KEYBOX) += write_keybox.o
 obj-$(CONFIG_ANDROID_KEYMASTER_CA) += keymaster.o
 obj-$(CONFIG_ANDROID_KEYMASTER_CA) += attestation_key.o
+obj-$(CONFIG_ANDROID_KEYMASTER_CA) += id_attestation.o
 endif
 
 ifdef CONFIG_MP_BOOT
diff --git a/u-boot/common/board_info.c b/u-boot/common/board_info.c
index b2c6bd5715..1d0155ea24 100644
--- a/u-boot/common/board_info.c
+++ b/u-boot/common/board_info.c
@@ -5,8 +5,6 @@
 #include <common.h>
 #include <linux/libfdt.h>
 #include <linux/compiler.h>
-#include <asm/io.h>
-#include <asm/string.h>
 
 int __weak checkboard(void)
 {
@@ -35,11 +33,5 @@ int __weak show_board_info(void)
 		printf("CPU: AArch32\n");
 #endif
 
-	if (strstr(model, "rk3588") != NULL) {
-		printf("rpdzkj: pull down gpio0_b2 for init wifi\n");
-        	writel(0xFFFF0400, 0xFD8A0008); // direction out
-	        writel(0xFFFE0000, 0xFD8A0000); // output low
-        }
-
 	return checkboard();
 }
diff --git a/u-boot/common/console.c b/u-boot/common/console.c
index 4abe4d150b..629c2a6459 100644
--- a/u-boot/common/console.c
+++ b/u-boot/common/console.c
@@ -524,13 +524,6 @@ void putc(const char c)
 	putc_to_ram(c);
 #endif
 
-#ifdef CONFIG_DEBUG_UART
-	/* if we don't have a console yet, use the debug UART */
-	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
-		printch(c);
-		return;
-	}
-#endif
 #ifdef CONFIG_CONSOLE_RECORD
 	if (gd && (gd->flags & GD_FLG_RECORD) && gd->console_out.start)
 		membuff_putbyte((struct membuff *)&gd->console_out, c);
@@ -540,6 +533,13 @@ void putc(const char c)
 		return;
 #endif
 
+#ifdef CONFIG_DEBUG_UART
+	/* if we don't have a console yet, use the debug UART */
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+		printch(c);
+		return;
+	}
+#endif
 	if (!gd->have_console)
 		return pre_console_putc(c);
 
diff --git a/u-boot/common/edid.c b/u-boot/common/edid.c
index d7d224cc58..0e78c1319d 100644
--- a/u-boot/common/edid.c
+++ b/u-boot/common/edid.c
@@ -2639,8 +2639,8 @@ static bool drm_valid_hdmi_vic(u8 vic)
 	return vic > 0 && vic < ARRAY_SIZE(edid_4k_modes);
 }
 
-static void drm_add_hdmi_modes(struct hdmi_edid_data *data,
-			       const struct drm_display_mode *mode)
+void drm_add_hdmi_modes(struct hdmi_edid_data *data,
+			const struct drm_display_mode *mode)
 {
 	struct drm_display_mode *mode_buf = data->mode_buf;
 
diff --git a/u-boot/common/fdt_support.c b/u-boot/common/fdt_support.c
index fa3d3e7af2..d6370891d7 100644
--- a/u-boot/common/fdt_support.c
+++ b/u-boot/common/fdt_support.c
@@ -8,6 +8,7 @@
  */
 
 #include <common.h>
+#include <abuf.h>
 #include <android_image.h>
 #include <exports.h>
 #include <fdt_support.h>
@@ -354,6 +355,7 @@ __weak char *board_fdt_chosen_bootargs(void *fdt)
 
 int fdt_chosen(void *fdt)
 {
+	struct abuf buf = {};
 	int   nodeoffset;
 	int   err;
 	char  *str;		/* used to set string properties */
@@ -369,6 +371,17 @@ int fdt_chosen(void *fdt)
 	if (nodeoffset < 0)
 		return nodeoffset;
 
+	if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) {
+		err = fdt_setprop(fdt, nodeoffset, "rng-seed",
+				  abuf_data(&buf), abuf_size(&buf));
+		abuf_uninit(&buf);
+		if (err < 0) {
+			printf("WARNING: could not set rng-seed %s.\n",
+			       fdt_strerror(err));
+			return err;
+		}
+	}
+
 	str = board_fdt_chosen_bootargs(fdt);
 	if (str) {
 		err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
diff --git a/u-boot/common/id_attestation.c b/u-boot/common/id_attestation.c
new file mode 100644
index 0000000000..59890e805d
--- /dev/null
+++ b/u-boot/common/id_attestation.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023, Rockchip Electronics Co., Ltd
+ * callen, <callen.cai@rock-chips.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <keymaster.h>
+#include "id_attestation.h"
+
+
+#define ID_ATTESTATION_FILE "attestation_ids"
+/* Maximum file name size.*/
+#define STORAGE_ID_LENGTH_MAX  64
+
+void printAttestationIds(const AttestationIds *ids)
+{
+	printf("AttestationIds:\n");
+	printf("  brand:             %s\n", ids->brand);
+	printf("  device:            %s\n", ids->device);
+	printf("  product:           %s\n", ids->product);
+	printf("  serial:            %s\n", ids->serial);
+	printf("  imei:              %s\n", ids->imei);
+	printf("  second_imei:       %s\n", ids->second_imei);
+	printf("  meid:              %s\n", ids->meid);
+	printf("  manufacturer:      %s\n", ids->manufacturer);
+	printf("  model:             %s\n", ids->model);
+}
+uint32_t write_to_keymaster(u8 *filename, uint32_t filename_size,
+			    u8 *data, uint32_t data_size);
+
+/* read id attestation digest len */
+uint32_t read_id_attestation_digest(const char *ids_digest_file, uint32_t *ids_digest_len)
+{
+	int len = sizeof(AttestationIds);
+	u8 ids_digest[len];
+
+	TEEC_Result ret = read_from_keymaster((u8 *)ids_digest_file, strlen(ids_digest_file),
+					      (u8 *)ids_digest, len);
+	if (ret != TEEC_SUCCESS)
+		*ids_digest_len = 0;
+	else
+		*ids_digest_len = len;
+	MSG("%s file:%s ,digest_len=%d,ret=%x\n", __func__, ids_digest_file, *ids_digest_len, ret);
+	return ret;
+}
+
+uint32_t write_id_attestation(const char *ids_file, AttestationIds *ids, uint32_t ids_len)
+{
+	TEEC_Result ret = write_to_keymaster((u8 *)ids_file, strlen(ids_file),
+					     (u8 *)ids, ids_len);
+	MSG("%s ids_file=%s ret=%0x\n", __func__, ids_file, ret);
+	return ret;
+}
+
+atap_result write_id_attestation_to_secure_storage(u8* received_data, uint32_t len)
+{
+	AttestationIds ids;
+	u32 ids_len;
+	AttestationIds ids_read;
+	char ids_file[STORAGE_ID_LENGTH_MAX] = { 0 };
+
+	ids_len = (received_data[5] << 8) | received_data[4];
+	printf("%s size=%d\n", __func__, ids_len);
+	if (ids_len != sizeof(AttestationIds)) {
+		printf("%s AttestationIds size is %zu)\n", __func__, sizeof(AttestationIds));
+		return ATAP_RESULT_ERROR_INVALID_HEAD;
+	}
+	memcpy(&ids, received_data + 8, len);
+#if DEBUG
+	printAttestationIds(&ids);
+#endif
+	/* now you have got the whole AttestationIds data....*/
+	memcpy(ids_file, ID_ATTESTATION_FILE, sizeof(ID_ATTESTATION_FILE));
+	TEEC_Result ret = read_from_keymaster((u8 *)ids_file,
+					      strlen(ids_file),
+					      (u8*)&ids_read,
+					      sizeof(AttestationIds));
+	MSG("read id attestation   ret=%0x\n", ret);
+	if (ret == TEEC_SUCCESS) {
+		printf("id attestation already exsit,you cannot update it!");
+#if DEBUG
+		printAttestationIds(&ids_read);
+#endif
+		ret = ATAP_RESULT_ERROR_ALREADY_EXSIT;
+		return ret;
+	}
+	ret = write_id_attestation(ids_file, &ids, ids_len);
+	printf("write id attestation : ret=%d\n", ret);
+	return ret;
+}
diff --git a/u-boot/common/image-android.c b/u-boot/common/image-android.c
index a77c0f3510..d580eb61ce 100644
--- a/u-boot/common/image-android.c
+++ b/u-boot/common/image-android.c
@@ -1090,7 +1090,16 @@ extract_boot_image_v34_header(struct blk_desc *dev_desc,
 		return NULL;
 	}
 
-	/* Start from android-13 GKI, it doesn't assign 'os_version' */
+	/*
+	 * [Start from android-13 GKI, it doesn't assign 'os_version']
+	 *
+	 * Android_12 or later are header_version >= 4.
+	 * Android_13(GKI) introduce a new partition named "init_boot" and
+	 * doesn't assign 'os_version' any more(ie. default 0).
+	 *
+	 * We only assign 'os_version' depend on whether there is
+	 * init_boot partition or not.
+	 */
 	if (boot_hdr->header_version >= 4 && boot_hdr->os_version == 0) {
 		if (part_get_info_by_name(dev_desc,
 				ANDROID_PARTITION_INIT_BOOT, &part) > 0)
@@ -1171,7 +1180,25 @@ int populate_boot_info(const struct boot_img_hdr_v34 *boot_hdr,
 	/* fixed in v3 */
 	hdr->page_size = 4096;
 	hdr->header_version = boot_hdr->header_version;
-	hdr->os_version = boot_hdr->os_version;
+	/*
+	 * [Start from android-13 GKI, it doesn't assign 'os_version']
+	 *
+	 * Android_12 or later are header_version >= 4.
+	 * Android_13(GKI) introduce a new partition named "init_boot" and
+	 * doesn't assign 'os_version' any more(ie. default 0).
+	 *
+	 * We only assign 'os_version' depend on whether there is
+	 * init_boot partition or not.
+	 */
+	if (boot_hdr->header_version >= 4 && boot_hdr->os_version == 0) {
+		if (init_boot_hdr)
+			hdr->os_version = 13 << 25;
+
+		if (!hdr->os_version)
+			printf("WARN: it seems to be an invalid Android os_version: 0\n");
+	} else {
+		hdr->os_version = boot_hdr->os_version;
+	}
 
 	memset(hdr->name, 0, ANDR_BOOT_NAME_SIZE);
 	strncpy(hdr->name, (const char *)vendor_boot_hdr->name, ANDR_BOOT_NAME_SIZE);
diff --git a/u-boot/common/image-sig.c b/u-boot/common/image-sig.c
index 4a07e86085..052eab6ef4 100644
--- a/u-boot/common/image-sig.c
+++ b/u-boot/common/image-sig.c
@@ -439,7 +439,7 @@ int fit_config_check_sig(const void *fit, int noffset, int required_keynode,
 #if !defined(USE_HOSTCC)
 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_FIT_HW_CRYPTO) && \
     defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
-	rsa_burn_key_hash(&info);
+	return rsa_burn_key_hash(&info);
 #endif
 #endif
 
diff --git a/u-boot/common/spl/Kconfig b/u-boot/common/spl/Kconfig
index dfa3fcde48..cc4d957195 100644
--- a/u-boot/common/spl/Kconfig
+++ b/u-boot/common/spl/Kconfig
@@ -884,7 +884,9 @@ config SPL_OPTEE
 
 config SPL_AB
 	bool "Support AB system boot"
-	depends on SPL && SPL_EFI_PARTITION
+	depends on SPL && SPL_LIBDISK_SUPPORT
+	select SPL_MTD_WRITE if SPL_MTD_SUPPORT
+	select SPL_MMC_WRITE if SPL_MMC_SUPPORT
 	help
 	  Enable this config to support AB system boot.
 
diff --git a/u-boot/common/spl/Makefile b/u-boot/common/spl/Makefile
index cf9d874f92..f06b4cdc82 100644
--- a/u-boot/common/spl/Makefile
+++ b/u-boot/common/spl/Makefile
@@ -25,10 +25,10 @@ endif
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_$(SPL_TPL_)BOOTROM_SUPPORT) += spl_bootrom.o
 ifdef CONFIG_SPL_KERNEL_BOOT_PREBUILT
-ifdef CONFIG_ARM64
-obj-$(CONFIG_$(SPL_TPL_)LOAD_FIT) += spl_fit_tb_arm64.o
-else
-obj-$(CONFIG_$(SPL_TPL_)LOAD_FIT) += spl_fit_tb_arm32.o
+ifeq ($(CONFIG_$(SPL_TPL_)LOAD_FIT),y)
+obj-$(CONFIG_ARM64) += spl_fit_tb_arm64.o
+obj-$(CONFIG_ROCKCHIP_RV1106) += spl_fit_tb_rv1106.o
+obj-$(CONFIG_ROCKCHIP_RV1126) += spl_fit_tb_rv1126.o
 endif
 else
 obj-$(CONFIG_$(SPL_TPL_)LOAD_FIT) += spl_fit.o
diff --git a/u-boot/common/spl/spl.c b/u-boot/common/spl/spl.c
index bcb37ecb41..36c0f74a81 100644
--- a/u-boot/common/spl/spl.c
+++ b/u-boot/common/spl/spl.c
@@ -661,8 +661,13 @@ void preloader_console_init(void)
 
 	gd->have_console = 1;
 
+#ifdef BUILD_SPL_TAG
+	puts("\nU-Boot SPL " PLAIN_VERSION " (" U_BOOT_DATE " - " \
+			U_BOOT_TIME "), fwver: "BUILD_SPL_TAG"\n");
+#else
 	puts("\nU-Boot SPL " PLAIN_VERSION " (" U_BOOT_DATE " - " \
 			U_BOOT_TIME ")\n");
+#endif
 #ifdef CONFIG_SPL_DISPLAY_PRINT
 	spl_display_print();
 #endif
diff --git a/u-boot/common/spl/spl_ab.c b/u-boot/common/spl/spl_ab.c
index 842c36c9ba..b7fd5f21c0 100644
--- a/u-boot/common/spl/spl_ab.c
+++ b/u-boot/common/spl/spl_ab.c
@@ -284,6 +284,35 @@ static int spl_save_metadata_if_changed(struct blk_desc *dev_desc,
 	return 0;
 }
 
+static void spl_slot_set_unbootable(AvbABSlotData* slot)
+{
+	slot->priority = 0;
+	slot->tries_remaining = 0;
+	slot->successful_boot = 0;
+}
+
+/* Ensure all unbootable and/or illegal states are marked as the
+ * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
+ * and successful_boot=0.
+ */
+static void spl_slot_normalize(AvbABSlotData* slot)
+{
+	if (slot->priority > 0) {
+		if (slot->tries_remaining == 0 && !slot->successful_boot) {
+			/* We've exhausted all tries -> unbootable. */
+			spl_slot_set_unbootable(slot);
+		}
+		if (slot->tries_remaining > 0 && slot->successful_boot) {
+			/* Illegal state - avb_ab_mark_slot_successful() and so on
+			 * will clear tries_remaining when setting successful_boot.
+			 */
+			spl_slot_set_unbootable(slot);
+		}
+	} else {
+		spl_slot_set_unbootable(slot);
+	}
+}
+
 /* If verify fail in a/b system, then decrease 1. */
 int spl_ab_decrease_tries(struct blk_desc *dev_desc)
 {
@@ -309,6 +338,13 @@ int spl_ab_decrease_tries(struct blk_desc *dev_desc)
 
 	memcpy(&ab_data_orig, &ab_data, sizeof(AvbABData));
 
+	/* Ensure data is normalized, e.g. illegal states will be marked as
+	 * unbootable and all unbootable states are represented with
+	 * (priority=0, tries_remaining=0, successful_boot=0).
+	 */
+	spl_slot_normalize(&ab_data.slots[0]);
+	spl_slot_normalize(&ab_data.slots[1]);
+
 	/* ... and decrement tries remaining, if applicable. */
 	if (!ab_data.slots[slot_index].successful_boot &&
 	    ab_data.slots[slot_index].tries_remaining > 0)
diff --git a/u-boot/common/spl/spl_fit_tb_rv1106.S b/u-boot/common/spl/spl_fit_tb_rv1106.S
new file mode 100644
index 0000000000..fc24ececef
--- /dev/null
+++ b/u-boot/common/spl/spl_fit_tb_rv1106.S
@@ -0,0 +1,12882 @@
+	.arch armv7-a
+	.eabi_attribute 20, 1
+	.eabi_attribute 21, 1
+	.eabi_attribute 23, 3
+	.eabi_attribute 24, 1
+	.eabi_attribute 25, 1
+	.eabi_attribute 26, 2
+	.eabi_attribute 30, 4
+	.eabi_attribute 34, 0
+	.eabi_attribute 18, 2
+	.file	"spl_fit_tb.c"
+	.text
+.Ltext0:
+	.cfi_sections	.debug_frame
+	.section	.text.spl_fit_get_image_name.isra.0,"ax",%progbits
+	.align	1
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_fit_get_image_name.isra.0, %function
+spl_fit_get_image_name.isra.0:
+.LFB236:
+	.file 1 "common/spl/spl_fit_tb.c"
+	.loc 1 81 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 8
+	@ frame_needed = 0, uses_anonymous_args = 0
+.LVL0:
+	push	{r0, r1, r4, r5, r6, r7, r8, lr}
+	.cfi_def_cfa_offset 32
+	.cfi_offset 4, -24
+	.cfi_offset 5, -20
+	.cfi_offset 6, -16
+	.cfi_offset 7, -12
+	.cfi_offset 8, -8
+	.cfi_offset 14, -4
+	.loc 1 81 0
+	mov	r5, r0
+	mov	r8, r1
+	mov	r7, r2
+	mov	r6, r3
+	.loc 1 90 0
+	bl	fit_find_config_node
+.LVL1:
+	.loc 1 91 0
+	subs	r4, r0, #0
+	bge	.L2
+	.loc 1 93 0
+	ldr	r0, .L11
+.LVL2:
+	.loc 1 97 0
+	ldr	r7, .L11+4
+.LVL3:
+	.loc 1 98 0
+	ldr	r8, .L11+8
+.LVL4:
+	.loc 1 93 0
+	bl	printf
+.LVL5:
+	.loc 1 94 0
+	mov	r1, r4
+	mov	r0, r5
+	bl	fdt_first_subnode
+.LVL6:
+	mov	r6, r0
+.LVL7:
+.L3:
+	cmp	r6, #0
+	bge	.L4
+.LVL8:
+.L1:
+	.loc 1 121 0
+	mov	r0, r4
+	add	sp, sp, #8
+	.cfi_remember_state
+	.cfi_def_cfa_offset 24
+	@ sp needed
+	pop	{r4, r5, r6, r7, r8, pc}
+.LVL9:
+.L4:
+	.cfi_restore_state
+	.loc 1 97 0
+	add	r3, sp, #4
+	mov	r2, r7
+	mov	r1, r6
+	mov	r0, r5
+.LVL10:
+	bl	fdt_getprop
+.LVL11:
+	.loc 1 98 0
+	mov	r1, r0
+	mov	r0, r8
+.LVL12:
+	bl	printf
+.LVL13:
+	.loc 1 96 0
+	mov	r1, r6
+	mov	r0, r5
+	bl	fdt_next_subnode
+.LVL14:
+	mov	r6, r0
+.LVL15:
+	b	.L3
+.LVL16:
+.L2:
+	.loc 1 104 0
+	mov	r0, r5
+.LVL17:
+	add	r3, sp, #4
+	mov	r2, r8
+	mov	r1, r4
+	bl	fdt_getprop
+.LVL18:
+	.loc 1 105 0
+	mov	r5, r0
+.LVL19:
+	cbz	r0, .L8
+	movs	r4, #0
+.LVL20:
+.L6:
+	.loc 1 111 0
+	cmp	r4, r7
+	blt	.L7
+	.loc 1 119 0
+	str	r0, [r6]
+	.loc 1 120 0
+	movs	r4, #0
+.LVL21:
+	b	.L1
+.LVL22:
+.L7:
+	.loc 1 112 0
+	movs	r1, #0
+	bl	strchr
+.LVL23:
+	.loc 1 113 0
+	adds	r0, r0, #1
+.LVL24:
+	beq	.L10
+	ldr	r2, [sp, #4]
+	subs	r3, r0, r5
+	cmp	r3, r2
+	bge	.L10
+	.loc 1 111 0
+	adds	r4, r4, #1
+.LVL25:
+	b	.L6
+.LVL26:
+.L8:
+	.loc 1 107 0
+	mvn	r4, #21
+.LVL27:
+	b	.L1
+.LVL28:
+.L10:
+	.loc 1 115 0
+	mvn	r4, #6
+.LVL29:
+	b	.L1
+.L12:
+	.align	2
+.L11:
+	.word	.LC4
+	.word	.LC5
+	.word	.LC6
+	.cfi_endproc
+.LFE236:
+	.size	spl_fit_get_image_name.isra.0, .-spl_fit_get_image_name.isra.0
+	.section	.text.spl_fit_get_image_node,"ax",%progbits
+	.align	1
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_fit_get_image_node, %function
+spl_fit_get_image_node:
+.LFB222:
+	.loc 1 137 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 8
+	@ frame_needed = 0, uses_anonymous_args = 0
+.LVL30:
+	push	{r0, r1, r2, r4, r5, lr}
+	.cfi_def_cfa_offset 24
+	.cfi_offset 4, -12
+	.cfi_offset 5, -8
+	.cfi_offset 14, -4
+	.loc 1 137 0
+	mov	r5, r1
+	mov	r1, r2
+.LVL31:
+	mov	r2, r3
+.LVL32:
+	.loc 1 142 0
+	add	r3, sp, #4
+.LVL33:
+	.loc 1 137 0
+	mov	r4, r0
+	.loc 1 142 0
+	bl	spl_fit_get_image_name.isra.0
+.LVL34:
+	.loc 1 143 0
+	cbnz	r0, .L13
+	.loc 1 148 0
+	ldr	r2, [sp, #4]
+	mov	r1, r5
+	mov	r0, r4
+.LVL35:
+	bl	fdt_subnode_offset
+.LVL36:
+	.loc 1 149 0
+	cmp	r0, #0
+	.loc 1 151 0
+	it	lt
+	mvnlt	r0, #21
+.LVL37:
+.L13:
+	.loc 1 155 0
+	add	sp, sp, #12
+	.cfi_def_cfa_offset 12
+	@ sp needed
+	pop	{r4, r5, pc}
+	.cfi_endproc
+.LFE222:
+	.size	spl_fit_get_image_node, .-spl_fit_get_image_node
+	.global	__aeabi_idivmod
+	.global	__aeabi_idiv
+	.section	.text.spl_load_fit_image,"ax",%progbits
+	.align	1
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_load_fit_image, %function
+spl_load_fit_image:
+.LFB226:
+	.loc 1 215 0
+	.cfi_startproc
+	@ args = 8, pretend = 0, frame = 48
+	@ frame_needed = 0, uses_anonymous_args = 0
+.LVL38:
+	push	{r4, r5, r6, r7, r8, r10, fp, lr}
+	.cfi_def_cfa_offset 32
+	.cfi_offset 4, -32
+	.cfi_offset 5, -28
+	.cfi_offset 6, -24
+	.cfi_offset 7, -20
+	.cfi_offset 8, -16
+	.cfi_offset 10, -12
+	.cfi_offset 11, -8
+	.cfi_offset 14, -4
+	sub	sp, sp, #56
+	.cfi_def_cfa_offset 88
+	.loc 1 215 0
+	mov	r4, r2
+	ldr	r5, [sp, #88]
+	.loc 1 225 0
+	add	r2, sp, #56
+.LVL39:
+	.loc 1 215 0
+	mov	r7, r3
+	.loc 1 225 0
+	movs	r3, #255
+.LVL40:
+	.loc 1 215 0
+	str	r1, [sp, #20]
+	.loc 1 225 0
+	strb	r3, [r2, #-29]!
+.LVL41:
+	.loc 1 242 0
+	mov	r1, r5
+.LVL42:
+	.loc 1 229 0
+	ldr	r3, [r0]
+	.loc 1 215 0
+	mov	r8, r0
+	.loc 1 242 0
+	mov	r0, r4
+.LVL43:
+	.loc 1 215 0
+	ldr	r6, [sp, #92]
+	.loc 1 229 0
+	str	r3, [sp, #12]
+.LVL44:
+	.loc 1 242 0
+	bl	fit_image_get_comp
+.LVL45:
+	.loc 1 245 0
+	add	r2, sp, #44
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_get_load
+.LVL46:
+	cbz	r0, .L17
+	.loc 1 246 0
+	ldr	r3, [r6, #8]
+	str	r3, [sp, #44]
+.L17:
+	.loc 1 248 0
+	ldrb	r3, [sp, #27]	@ zero_extendqisi2
+	cmp	r3, #0
+	beq	.L18
+	.loc 1 248 0 is_stmt 0 discriminator 1
+	cmp	r3, #6
+	beq	.L18
+	.loc 1 250 0 is_stmt 1
+	add	r2, sp, #40
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_get_comp_addr
+.LVL47:
+	cbz	r0, .L19
+	.loc 1 251 0
+	ldr	r3, [sp, #44]
+	add	r3, r3, #1048576
+.L70:
+	.loc 1 253 0
+	str	r3, [sp, #40]
+.L19:
+	.loc 1 256 0
+	add	r2, sp, #28
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_get_data_position
+.LVL48:
+	cbz	r0, .L20
+	.loc 1 258 0
+	add	r2, sp, #28
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_get_data_offset
+.LVL49:
+	cmp	r0, #0
+	bne	.L21
+	.loc 1 259 0
+	ldr	r3, [sp, #28]
+	add	r7, r7, r3
+.LVL50:
+	str	r7, [sp, #28]
+.LVL51:
+.L20:
+	.loc 1 265 0
+	add	r2, sp, #36
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_get_data_size
+.LVL52:
+	cmp	r0, #0
+	bne	.L40
+	.loc 1 268 0
+	ldr	r7, [sp, #40]
+	adds	r7, r7, #63
+	bic	r3, r7, #63
+	.loc 1 270 0
+	cmp	r3, #-16777216
+	.loc 1 268 0
+	str	r3, [sp, #8]
+.LVL53:
+	.loc 1 270 0
+	bcc	.L22
+	.loc 1 272 0
+	ldr	r1, [sp, #36]
+	movs	r0, #64
+	bl	memalign_simple
+.LVL54:
+	str	r0, [sp, #8]
+.LVL55:
+.L22:
+.LBB36:
+.LBB37:
+	.loc 1 178 0
+	ldr	r3, [r8, #12]
+.LBE37:
+.LBE36:
+	.loc 1 274 0
+	ldr	r10, [sp, #36]
+	.loc 1 276 0
+	ldr	r0, [sp, #28]
+	.loc 1 274 0
+	str	r10, [sp, #32]
+.LVL56:
+.LBB40:
+.LBB38:
+	.loc 1 178 0
+	cmp	r3, #0
+	beq	.L23
+	.loc 1 179 0
+	and	fp, r0, #63
+.LVL57:
+.L24:
+.LBE38:
+.LBE40:
+.LBB41:
+.LBB42:
+	.loc 1 187 0
+	add	r10, r10, fp
+.LVL58:
+	.loc 1 189 0
+	cbnz	r3, .L25
+	.loc 1 192 0
+	ldr	r1, [r8, #8]
+	add	r0, r10, r1
+	subs	r0, r0, #1
+	bl	__aeabi_idiv
+.LVL59:
+	mov	r10, r0
+.LVL60:
+.L25:
+.LBE42:
+.LBE41:
+	.loc 1 280 0
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_is_preload
+.LVL61:
+	.loc 1 282 0
+	str	r0, [sp, #16]
+	cbz	r0, .L26
+	.loc 1 283 0
+	ldr	r2, [sp, #12]
+	movs	r3, #1
+	strb	r3, [r2, #14]
+.L26:
+	.loc 1 285 0
+	ldr	r3, [r8, #16]
+	.loc 1 286 0
+	ldr	r0, [sp, #28]
+.LVL62:
+	.loc 1 285 0
+	mov	r7, r3
+.LBB43:
+.LBB44:
+	.loc 1 164 0
+	ldr	r3, [r8, #12]
+	cmp	r3, #0
+	beq	.L27
+	.loc 1 165 0
+	bic	r0, r0, #63
+.LVL63:
+.L28:
+.LBE44:
+.LBE43:
+	.loc 1 285 0
+	ldr	r1, [sp, #20]
+	mov	r2, r10
+	ldr	r3, [sp, #8]
+	add	r1, r1, r0
+	mov	r0, r8
+	blx	r7
+.LVL64:
+	cmp	r10, r0
+	bne	.L37
+	.loc 1 292 0
+	ldr	r3, [sp, #8]
+	add	r3, r3, fp
+	str	r3, [sp, #48]
+	.loc 1 293 0
+	ldr	r3, [sp, #16]
+	cbz	r3, .L30
+	.loc 1 294 0
+	ldr	r3, [sp, #12]
+	ldr	r2, [sp, #12]
+	.loc 1 295 0
+	ldr	r0, .L72
+	.loc 1 294 0
+	ldrb	r3, [r3, #14]	@ zero_extendqisi2
+	bic	r3, r3, #1
+	strb	r3, [r2, #14]
+	.loc 1 295 0
+	bl	printf
+.LVL65:
+.L31:
+	.loc 1 348 0
+	cbz	r6, .L71
+	.loc 1 349 0
+	ldr	r3, [sp, #44]
+	.loc 1 351 0
+	mov	r1, r5
+	ldr	r2, .L72+4
+	mov	r0, r4
+	.loc 1 349 0
+	str	r3, [r6, #8]
+	.loc 1 350 0
+	ldr	r3, [sp, #32]
+	str	r3, [r6, #32]
+	.loc 1 351 0
+	bl	fdt_getprop_u32
+.LVL66:
+	str	r0, [r6, #12]
+.L71:
+	.loc 1 354 0
+	movs	r0, #0
+.LVL67:
+.L16:
+	.loc 1 355 0
+	add	sp, sp, #56
+	.cfi_remember_state
+	.cfi_def_cfa_offset 32
+	@ sp needed
+	pop	{r4, r5, r6, r7, r8, r10, fp, pc}
+.LVL68:
+.L18:
+	.cfi_restore_state
+	.loc 1 253 0
+	ldr	r3, [sp, #44]
+	b	.L70
+.LVL69:
+.L23:
+.LBB46:
+.LBB39:
+	.loc 1 181 0
+	ldr	r1, [r8, #8]
+	str	r3, [sp, #16]
+	bl	__aeabi_idivmod
+.LVL70:
+	ldr	r3, [sp, #16]
+	mov	fp, r1
+	b	.L24
+.LVL71:
+.L27:
+.LBE39:
+.LBE46:
+.LBB47:
+.LBB45:
+	.loc 1 167 0
+	ldr	r1, [r8, #8]
+	bl	__aeabi_idiv
+.LVL72:
+	b	.L28
+.LVL73:
+.L68:
+.LBE45:
+.LBE47:
+	.loc 1 306 0
+	ldr	r3, [sp, #52]
+	str	r3, [sp, #48]
+.LVL74:
+.L30:
+	.loc 1 310 0
+	ldrb	r3, [sp, #27]	@ zero_extendqisi2
+.LBB48:
+.LBB49:
+	.file 2 "include/image.h"
+	.loc 2 1006 0
+	movs	r2, #0
+	mov	r1, r5
+	mov	r0, r4
+.LBE49:
+.LBE48:
+	.loc 1 310 0
+	cbz	r3, .L32
+.LVL75:
+	.loc 1 310 0 is_stmt 0 discriminator 1
+	cmp	r3, #6
+	beq	.L32
+.LVL76:
+.LBB52:
+.LBB50:
+	.loc 2 1006 0 is_stmt 1
+	bl	fdt_get_name
+.LVL77:
+.LBE50:
+.LBE52:
+	.loc 1 313 0
+	movs	r3, #0
+.LBB53:
+.LBB51:
+	.loc 2 1006 0
+	mov	r7, r0
+.LVL78:
+.LBE51:
+.LBE53:
+	.loc 1 313 0
+	ldr	r2, .L72+8
+	mov	r1, r5
+	mov	r0, r4
+	.loc 1 311 0
+	ldr	r10, [sp, #44]
+	.loc 1 313 0
+	bl	fdt_getprop
+.LVL79:
+	.loc 1 311 0
+	ldr	r3, [sp, #48]
+	mov	r1, r7
+	mov	r2, r10
+	str	r3, [sp]
+	mov	r3, r0
+	ldr	r0, .L72+12
+	bl	printf
+.LVL80:
+.L33:
+	.loc 1 323 0
+	ldr	r3, [sp, #32]
+	mov	r1, r5
+	ldr	r2, [sp, #48]
+	mov	r0, r4
+	bl	fit_image_verify_with_data
+.LVL81:
+	cbz	r0, .L38
+	.loc 1 328 0
+	add	r3, sp, #32
+	add	r2, sp, #44
+	mov	r1, r5
+	str	r3, [sp]
+	mov	r0, r4
+	add	r3, sp, #48
+	str	r8, [sp, #4]
+	bl	board_fit_image_post_process
+.LVL82:
+	.loc 1 331 0
+	ldr	r0, .L72+16
+	bl	puts
+.LVL83:
+	.loc 1 345 0
+	ldr	r2, [sp, #32]
+	ldr	r1, [sp, #48]
+	ldr	r0, [sp, #44]
+	bl	memcpy
+.LVL84:
+	b	.L31
+.LVL85:
+.L32:
+.LBB54:
+.LBB55:
+	.loc 2 1006 0
+	bl	fdt_get_name
+.LVL86:
+.LBE55:
+.LBE54:
+	.loc 1 316 0
+	ldr	r2, [sp, #44]
+	mov	r1, r0
+	ldr	r0, .L72+20
+	bl	printf
+.LVL87:
+	b	.L33
+.LVL88:
+.L37:
+	.loc 1 288 0
+	mvn	r0, #4
+	b	.L16
+.LVL89:
+.L38:
+	.loc 1 325 0
+	mov	r0, #-1
+	b	.L16
+.LVL90:
+.L21:
+	.loc 1 300 0
+	add	r3, sp, #32
+	add	r2, sp, #52
+	mov	r1, r5
+	mov	r0, r4
+	bl	fit_image_get_data
+.LVL91:
+	cmp	r0, #0
+	beq	.L68
+	.loc 1 301 0
+	ldr	r0, .L72+24
+	bl	puts
+.LVL92:
+.L40:
+	.loc 1 266 0
+	mvn	r0, #1
+.LVL93:
+	b	.L16
+.L73:
+	.align	2
+.L72:
+	.word	.LC7
+	.word	.LC13
+	.word	.LC9
+	.word	.LC10
+	.word	.LC12
+	.word	.LC11
+	.word	.LC8
+	.cfi_endproc
+.LFE226:
+	.size	spl_load_fit_image, .-spl_load_fit_image
+	.section	.text.spl_fit_append_fdt,"ax",%progbits
+	.align	1
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_fit_append_fdt, %function
+spl_fit_append_fdt:
+.LFB227:
+	.loc 1 360 0
+	.cfi_startproc
+	@ args = 8, pretend = 0, frame = 48
+	@ frame_needed = 0, uses_anonymous_args = 0
+.LVL94:
+	push	{r4, r5, r6, r7, lr}
+	.cfi_def_cfa_offset 20
+	.cfi_offset 4, -20
+	.cfi_offset 5, -16
+	.cfi_offset 6, -12
+	.cfi_offset 7, -8
+	.cfi_offset 14, -4
+	mov	r5, r3
+	sub	sp, sp, #60
+	.cfi_def_cfa_offset 80
+	.loc 1 360 0
+	mov	r4, r0
+	mov	r6, r1
+	mov	r7, r2
+	.loc 1 365 0
+	movs	r3, #0
+.LVL95:
+	ldr	r2, .L76
+.LVL96:
+	ldr	r1, [sp, #80]
+.LVL97:
+	mov	r0, r5
+.LVL98:
+	bl	spl_fit_get_image_node
+.LVL99:
+	.loc 1 366 0
+	cmp	r0, #0
+	blt	.L74
+	.loc 1 375 0
+	ldr	r2, [r4, #32]
+	.loc 1 376 0
+	mov	r1, r7
+	.loc 1 375 0
+	ldr	r3, [r4, #8]
+	add	r3, r3, r2
+	.loc 1 376 0
+	mov	r2, r5
+	.loc 1 375 0
+	str	r3, [sp, #20]
+	.loc 1 376 0
+	add	r3, sp, #12
+	stm	sp, {r0, r3}
+	mov	r0, r6
+.LVL100:
+	ldr	r3, [sp, #84]
+	bl	spl_load_fit_image
+.LVL101:
+	.loc 1 379 0
+	cmp	r0, #0
+	blt	.L74
+	.loc 1 383 0
+	ldr	r0, [sp, #20]
+.LVL102:
+	.loc 1 386 0
+	mov	r1, #8192
+	.loc 1 383 0
+	str	r0, [r4, #20]
+	.loc 1 386 0
+	bl	fdt_shrink_to_minimum
+.LVL103:
+.L74:
+	.loc 1 390 0
+	add	sp, sp, #60
+	.cfi_def_cfa_offset 20
+	@ sp needed
+	pop	{r4, r5, r6, r7, pc}
+.LVL104:
+.L77:
+	.align	2
+.L76:
+	.word	.LC0
+	.cfi_endproc
+.LFE227:
+	.size	spl_fit_append_fdt, .-spl_fit_append_fdt
+	.section	.text.spl_fit_load_blob,"ax",%progbits
+	.align	1
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_fit_load_blob, %function
+spl_fit_load_blob:
+.LFB231:
+	.loc 1 432 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+.LVL105:
+	ldr	r2, [r2, #4]
+.LVL106:
+	push	{r3, r4, r5, r6, r7, lr}
+	.cfi_def_cfa_offset 24
+	.cfi_offset 3, -24
+	.cfi_offset 4, -20
+	.cfi_offset 5, -16
+	.cfi_offset 6, -12
+	.cfi_offset 7, -8
+	.cfi_offset 14, -4
+	.loc 1 432 0
+	mov	r4, r0
+	mov	r5, r1
+	rev	r2, r2
+.LVL107:
+	.loc 1 445 0
+	addw	r2, r2, #511
+.LVL108:
+	.loc 1 446 0
+	bic	r0, r2, #510
+.LVL109:
+	bic	r0, r0, #1
+	str	r0, [r3]
+	.loc 1 465 0
+	ldr	r3, .L81
+.LVL110:
+	ldr	r1, [r4, #8]
+.LVL111:
+	subs	r3, r3, r1
+	subs	r3, r3, r0
+	.loc 1 466 0
+	bic	r6, r3, #63
+.LVL112:
+.LBB62:
+.LBB63:
+	.loc 1 189 0
+	ldr	r3, [r4, #12]
+	cbnz	r3, .L79
+	.loc 1 192 0
+	add	r0, r0, r1
+.LVL113:
+	subs	r0, r0, #1
+	bl	__aeabi_idiv
+.LVL114:
+.L79:
+.LBE63:
+.LBE62:
+	.loc 1 468 0
+	mov	r2, r0
+	ldr	r7, [r4, #16]
+	mov	r3, r6
+	mov	r1, r5
+	mov	r0, r4
+	blx	r7
+.LVL115:
+	.loc 1 471 0
+	cmp	r0, #0
+	.loc 1 475 0
+	ite	ne
+	movne	r0, r6
+.LVL116:
+	moveq	r0, #0
+	pop	{r3, r4, r5, r6, r7, pc}
+.LVL117:
+.L82:
+	.align	2
+.L81:
+	.word	2097089
+	.cfi_endproc
+.LFE231:
+	.size	spl_fit_load_blob, .-spl_fit_load_blob
+	.section	.text.fit_config_verify,"ax",%progbits
+	.align	1
+	.weak	fit_config_verify
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	fit_config_verify, %function
+fit_config_verify:
+.LFB213:
+	.loc 1 25 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL118:
+	.loc 1 27 0
+	movs	r0, #0
+.LVL119:
+	bx	lr
+	.cfi_endproc
+.LFE213:
+	.size	fit_config_verify, .-fit_config_verify
+	.section	.text.mtd_part_parse,"ax",%progbits
+	.align	1
+	.weak	mtd_part_parse
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	mtd_part_parse, %function
+mtd_part_parse:
+.LFB214:
+	.loc 1 30 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL120:
+	.loc 1 32 0
+	movs	r0, #0
+.LVL121:
+	bx	lr
+	.cfi_endproc
+.LFE214:
+	.size	mtd_part_parse, .-mtd_part_parse
+	.section	.text.spl_get_current_slot,"ax",%progbits
+	.align	1
+	.weak	spl_get_current_slot
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_get_current_slot, %function
+spl_get_current_slot:
+.LFB215:
+	.loc 1 35 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL122:
+	.loc 1 37 0
+	mov	r0, #-1
+.LVL123:
+	bx	lr
+	.cfi_endproc
+.LFE215:
+	.size	spl_get_current_slot, .-spl_get_current_slot
+	.section	.text.spl_load_meta,"ax",%progbits
+	.align	1
+	.weak	spl_load_meta
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_load_meta, %function
+spl_load_meta:
+.LFB216:
+	.loc 1 40 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+.LVL124:
+	push	{r3, lr}
+	.cfi_def_cfa_offset 8
+	.cfi_offset 3, -8
+	.cfi_offset 14, -4
+	.loc 1 41 0
+	ldr	r0, .L87
+.LVL125:
+	bl	printf
+.LVL126:
+	.loc 1 44 0
+	mov	r0, #-1
+	pop	{r3, pc}
+.L88:
+	.align	2
+.L87:
+	.word	.LC14
+	.cfi_endproc
+.LFE216:
+	.size	spl_load_meta, .-spl_load_meta
+	.section	.text.fdt_bootargs_append_ab,"ax",%progbits
+	.align	1
+	.weak	fdt_bootargs_append_ab
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	fdt_bootargs_append_ab, %function
+fdt_bootargs_append_ab:
+.LFB238:
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+	mov	r0, #-1
+	bx	lr
+	.cfi_endproc
+.LFE238:
+	.size	fdt_bootargs_append_ab, .-fdt_bootargs_append_ab
+	.section	.text.fdt_bootargs_append,"ax",%progbits
+	.align	1
+	.weak	fdt_bootargs_append
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	fdt_bootargs_append, %function
+fdt_bootargs_append:
+.LFB218:
+	.loc 1 52 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL127:
+	.loc 1 54 0
+	mov	r0, #-1
+.LVL128:
+	bx	lr
+	.cfi_endproc
+.LFE218:
+	.size	fdt_bootargs_append, .-fdt_bootargs_append
+	.section	.text.rk_meta_bootargs_append,"ax",%progbits
+	.align	1
+	.weak	rk_meta_bootargs_append
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	rk_meta_bootargs_append, %function
+rk_meta_bootargs_append:
+.LFB219:
+	.loc 1 57 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL129:
+	bx	lr
+	.cfi_endproc
+.LFE219:
+	.size	rk_meta_bootargs_append, .-rk_meta_bootargs_append
+	.section	.text.fit_rollback_index_verify,"ax",%progbits
+	.align	1
+	.weak	fit_rollback_index_verify
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	fit_rollback_index_verify, %function
+fit_rollback_index_verify:
+.LFB220:
+	.loc 1 62 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL130:
+	.loc 1 63 0
+	mov	r1, #-1
+.LVL131:
+	.loc 1 67 0
+	movs	r0, #0
+.LVL132:
+	.loc 1 63 0
+	str	r1, [r2]
+	.loc 1 64 0
+	str	r1, [r3]
+	.loc 1 67 0
+	bx	lr
+	.cfi_endproc
+.LFE220:
+	.size	fit_rollback_index_verify, .-fit_rollback_index_verify
+	.section	.text.spl_fit_standalone_release,"ax",%progbits
+	.align	1
+	.weak	spl_fit_standalone_release
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_fit_standalone_release, %function
+spl_fit_standalone_release:
+.LFB230:
+	.loc 1 425 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL133:
+	.loc 1 427 0
+	movs	r0, #0
+.LVL134:
+	bx	lr
+	.cfi_endproc
+.LFE230:
+	.size	spl_fit_standalone_release, .-spl_fit_standalone_release
+	.section	.text.spl_kernel_partition,"ax",%progbits
+	.align	1
+	.weak	spl_kernel_partition
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_kernel_partition, %function
+spl_kernel_partition:
+.LFB232:
+	.loc 1 481 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 0
+	@ frame_needed = 0, uses_anonymous_args = 0
+	@ link register save eliminated.
+.LVL135:
+	.loc 1 483 0
+	ldr	r0, .L95
+.LVL136:
+	bx	lr
+.L96:
+	.align	2
+.L95:
+	.word	.LC15
+	.cfi_endproc
+.LFE232:
+	.size	spl_kernel_partition, .-spl_kernel_partition
+	.section	.text.spl_load_simple_fit,"ax",%progbits
+	.align	1
+	.global	spl_load_simple_fit
+	.syntax unified
+	.thumb
+	.thumb_func
+	.fpu softvfp
+	.type	spl_load_simple_fit, %function
+spl_load_simple_fit:
+.LFB235:
+	.loc 1 846 0
+	.cfi_startproc
+	@ args = 0, pretend = 0, frame = 184
+	@ frame_needed = 1, uses_anonymous_args = 0
+.LVL137:
+	push	{r4, r5, r6, r7, r8, r10, fp, lr}
+	.cfi_def_cfa_offset 32
+	.cfi_offset 4, -32
+	.cfi_offset 5, -28
+	.cfi_offset 6, -24
+	.cfi_offset 7, -20
+	.cfi_offset 8, -16
+	.cfi_offset 10, -12
+	.cfi_offset 11, -8
+	.cfi_offset 14, -4
+	sub	sp, sp, #200
+	.cfi_def_cfa_offset 232
+	mov	r5, r3
+	add	r7, sp, #16
+	.cfi_def_cfa 7, 216
+.LVL138:
+	.loc 1 846 0
+	mov	r4, r0
+	ldr	r3, [r3]
+.LVL139:
+	mov	fp, r1
+	str	r2, [r7, #24]
+.LVL140:
+	.loc 1 862 0
+	ldr	r2, .L174
+.LVL141:
+	rev	r3, r3
+.LVL142:
+	cmp	r3, r2
+	str	r2, [r7]
+	beq	.L98
+	.loc 1 863 0
+	ldr	r0, .L174+4
+.LVL143:
+.L173:
+.LBB84:
+.LBB85:
+	.loc 1 658 0
+	bl	printf
+.LVL144:
+.L172:
+	.loc 1 680 0
+	mvn	r3, #21
+	b	.L97
+.LVL145:
+.L98:
+.LBE85:
+.LBE84:
+	.loc 1 867 0
+	ldr	r3, [r0, #28]
+	cmp	r3, #2
+	bne	.L100
+	.loc 1 868 0
+	bl	spl_load_meta
+.LVL146:
+.L100:
+.LBB97:
+.LBB93:
+	.loc 1 632 0
+	mov	r2, r5
+	add	r3, r7, #40
+	ldr	r1, [r7, #24]
+	mov	r0, fp
+	bl	spl_fit_load_blob
+.LVL147:
+	.loc 1 633 0
+	mov	r5, r0
+.LVL148:
+	cmp	r0, #0
+	beq	.L101
+	.loc 1 639 0
+	ldr	r1, .L174+8
+	bl	fdt_path_offset
+.LVL149:
+	.loc 1 640 0
+	subs	r3, r0, #0
+	str	r3, [r7, #28]
+	blt	.L101
+	.loc 1 646 0
+	bl	fit_board_verify_required_sigs
+.LVL150:
+	.loc 1 656 0
+	movs	r1, #0
+	mov	r0, r5
+	bl	fit_conf_get_node
+.LVL151:
+	.loc 1 657 0
+	subs	r1, r0, #0
+	bgt	.L102
+	.loc 1 658 0
+	ldr	r0, .L174+12
+.LVL152:
+	b	.L173
+.LVL153:
+.L102:
+	.loc 1 662 0
+	mov	r0, r5
+.LVL154:
+	bl	fit_config_verify
+.LVL155:
+	.loc 1 663 0
+	cbz	r0, .L104
+	.loc 1 664 0
+	mov	r1, r0
+	str	r0, [r7, #28]
+.LVL156:
+	ldr	r0, .L174+16
+.LVL157:
+	bl	printf
+.LVL158:
+	ldr	r3, [r7, #28]
+.LVL159:
+.L97:
+.LBE93:
+.LBE97:
+	.loc 1 881 0
+	mov	r0, r3
+	adds	r7, r7, #184
+	.cfi_remember_state
+	.cfi_def_cfa_offset 32
+	mov	sp, r7
+	.cfi_def_cfa_register 13
+	@ sp needed
+	pop	{r4, r5, r6, r7, r8, r10, fp, pc}
+.LVL160:
+.L104:
+	.cfi_restore_state
+.LBB98:
+.LBB94:
+	.loc 1 667 0
+	ldr	r0, .L174+20
+.LVL161:
+	bl	printf
+.LVL162:
+	.loc 1 672 0
+	add	r3, r7, #48
+	add	r2, r7, #44
+	ldr	r1, .L174+24
+	mov	r0, r5
+	bl	fit_rollback_index_verify
+.LVL163:
+	.loc 1 674 0
+	mov	r6, r0
+	cbz	r0, .L105
+	.loc 1 675 0
+	mov	r1, r0
+	ldr	r0, .L174+28
+.LVL164:
+	bl	printf
+.LVL165:
+	mov	r3, r6
+	b	.L97
+.LVL166:
+.L105:
+	.loc 1 677 0
+	ldr	r1, [r7, #44]
+	ldr	r2, [r7, #48]
+	cmp	r1, r2
+	bcs	.L106
+	.loc 1 678 0
+	ldr	r0, .L174+32
+.LVL167:
+	bl	printf
+.LVL168:
+	b	.L172
+.LVL169:
+.L106:
+	.loc 1 684 0
+	adds	r6, r1, #1
+	bne	.L107
+	adds	r0, r2, #1
+.LVL170:
+	beq	.L108
+.L107:
+	.loc 1 685 0
+	ldr	r0, .L174+36
+	bl	printf
+.LVL171:
+.L108:
+	.loc 1 697 0
+	ldr	r10, .L174+64
+.LBE94:
+.LBE98:
+	.loc 1 846 0
+	movs	r6, #0
+.LVL172:
+.L112:
+.LBB99:
+.LBB95:
+	.loc 1 697 0
+	mov	r3, r6
+	mov	r2, r10
+	ldr	r1, [r7, #28]
+	mov	r0, r5
+	bl	spl_fit_get_image_node
+.LVL173:
+	.loc 1 699 0
+	subs	r8, r0, #0
+	blt	.L109
+	.loc 1 702 0
+	add	r3, r7, #104
+	str	r8, [sp]
+	str	r3, [sp, #4]
+	mov	r2, r5
+	ldr	r3, [r7, #40]
+	mov	r0, fp
+.LVL174:
+	ldr	r1, [r7, #24]
+	bl	spl_load_fit_image
+.LVL175:
+	.loc 1 704 0
+	mov	r3, r0
+	cmp	r0, #0
+	bne	.L97
+	.loc 1 707 0
+	add	r2, r7, #36
+	mov	r1, r8
+	mov	r0, r5
+.LVL176:
+	bl	fit_get_desc
+.LVL177:
+	.loc 1 708 0
+	mov	r3, r0
+	cmp	r0, #0
+	bne	.L97
+	.loc 1 711 0
+	ldr	r3, [r7, #116]
+	.loc 1 714 0
+	ldr	r0, [r7, #36]
+.LVL178:
+	.loc 1 711 0
+	adds	r3, r3, #1
+	.loc 1 712 0
+	itt	eq
+	ldreq	r3, [r7, #112]
+	streq	r3, [r7, #116]
+	.loc 1 714 0
+	ldr	r1, [r7, #116]
+	bl	spl_fit_standalone_release
+.LVL179:
+	.loc 1 715 0
+	mov	r2, r0
+	cbz	r0, .L111
+	.loc 1 716 0
+	ldr	r1, [r7, #36]
+	ldr	r0, .L174+40
+.LVL180:
+	bl	printf
+.LVL181:
+.L111:
+	.loc 1 696 0
+	adds	r6, r6, #1
+.LVL182:
+	b	.L112
+.LVL183:
+.L109:
+	.loc 1 730 0
+	movs	r3, #0
+	ldr	r2, .L174+44
+	ldr	r1, [r7, #28]
+	mov	r0, r5
+	bl	spl_fit_get_image_node
+.LVL184:
+	.loc 1 736 0
+	subs	r8, r0, #0
+	bge	.L140
+	.loc 1 738 0
+	movs	r3, #0
+	ldr	r2, .L174+48
+	ldr	r1, [r7, #28]
+	mov	r0, r5
+.LVL185:
+	bl	spl_fit_get_image_node
+.LVL186:
+	.loc 1 746 0
+	ldr	r3, [r4, #28]
+	.loc 1 738 0
+	mov	r8, r0
+.LVL187:
+	.loc 1 746 0
+	cmp	r3, #2
+	bne	.L114
+	.loc 1 748 0
+	ldr	r0, .L174+52
+.LVL188:
+	bl	atags_get_tag
+.LVL189:
+	.loc 1 749 0
+	cmp	r0, #0
+	beq	.L114
+	.loc 1 750 0
+	ldr	r6, [r0, #16]
+	cmp	r6, #1
+	bne	.L114
+	.loc 1 751 0
+	movs	r3, #5
+	strb	r3, [r4, #4]
+.LVL190:
+.L115:
+.LBB86:
+	.loc 1 793 0
+	movs	r3, #0
+	.loc 1 795 0
+	ldr	r2, .L174+48
+	.loc 1 793 0
+	strb	r3, [r7, #35]
+	.loc 1 795 0
+	mov	r0, r5
+	mov	r3, r6
+	ldr	r1, [r7, #28]
+	bl	spl_fit_get_image_node
+.LVL191:
+	.loc 1 796 0
+	subs	r10, r0, #0
+	blt	.L118
+.LVL192:
+.LBB87:
+.LBB88:
+	.loc 1 420 0
+	add	r2, r7, #35
+.LVL193:
+	mov	r1, r10
+	mov	r0, r5
+.LVL194:
+	bl	fit_image_get_os
+.LVL195:
+.LBE88:
+.LBE87:
+	.loc 1 803 0
+	ldr	r3, [r4, #28]
+	cmp	r3, #2
+	bne	.L119
+	ldrb	r3, [r7, #35]	@ zero_extendqisi2
+	cmp	r3, #17
+	beq	.L126
+.L119:
+	.loc 1 807 0
+	add	r8, r7, #104
+	str	r10, [sp]
+	str	r8, [sp, #4]
+	mov	r2, r5
+	ldr	r3, [r7, #40]
+	mov	r0, fp
+	ldr	r1, [r7, #24]
+	bl	spl_load_fit_image
+.LVL196:
+	.loc 1 809 0
+	cmp	r0, #0
+	blt	.L126
+	.loc 1 812 0
+	ldrb	r3, [r7, #35]	@ zero_extendqisi2
+	cmp	r3, #17
+	bne	.L121
+	.loc 1 813 0
+	ldr	r3, [r7, #40]
+	mov	r1, fp
+	mov	r0, r8
+.LVL197:
+	str	r3, [sp, #4]
+	ldr	r3, [r7, #28]
+	str	r3, [sp]
+	mov	r3, r5
+	ldr	r2, [r7, #24]
+	bl	spl_fit_append_fdt
+.LVL198:
+	.loc 1 815 0
+	ldr	r3, [r7, #124]
+	str	r3, [r4, #20]
+.L121:
+	.loc 1 822 0
+	ldr	r3, [r4, #12]
+	adds	r3, r3, #1
+	bne	.L122
+	.loc 1 823 0
+	ldr	r3, [r7, #116]
+	.loc 1 822 0
+	adds	r2, r3, #1
+	.loc 1 824 0
+	it	ne
+	strne	r3, [r4, #12]
+.L122:
+	.loc 1 827 0
+	ldr	r8, [r4, #20]
+	cmp	r8, #0
+	beq	.L126
+.LVL199:
+.LBB89:
+.LBB90:
+	.loc 1 400 0
+	add	r3, r7, #60
+	mov	r2, r6
+	ldr	r1, .L174+48
+	mov	r0, r5
+	bl	spl_fit_get_image_name.isra.0
+.LVL200:
+	.loc 1 402 0
+	cmp	r0, #0
+	blt	.L126
+	.loc 1 405 0
+	mov	r3, r6
+	ldr	r2, .L174+48
+	ldr	r1, [r7, #28]
+	mov	r0, r5
+.LVL201:
+	bl	spl_fit_get_image_node
+.LVL202:
+	.loc 1 407 0
+	ldr	r3, [r7, #60]
+	.loc 1 409 0
+	mov	r1, r0
+	.loc 1 405 0
+	mov	r10, r0
+.LVL203:
+	.loc 1 409 0
+	ldr	r2, .L174+56
+	mov	r0, r5
+.LVL204:
+	.loc 1 407 0
+	str	r3, [r7, #20]
+	ldr	r3, [r7, #112]
+	str	r3, [r7, #16]
+	ldr	r3, [r7, #136]
+	str	r3, [r7, #12]
+	ldr	r3, [r7, #116]
+	str	r3, [r7, #8]
+	.loc 1 409 0
+	movs	r3, #0
+	bl	fdt_getprop
+.LVL205:
+	.loc 1 410 0
+	movs	r3, #0
+	.loc 1 409 0
+	str	r0, [r7, #4]
+	.loc 1 410 0
+	ldr	r2, .L174+60
+	mov	r1, r10
+	mov	r0, r5
+	bl	fdt_getprop
+.LVL206:
+	.loc 1 407 0
+	str	r0, [sp, #12]
+	mov	r1, r6
+	ldr	r3, [r7, #4]
+	mov	r0, r8
+	str	r3, [sp, #8]
+	ldr	r3, [r7, #8]
+	str	r3, [sp, #4]
+	ldr	r3, [r7, #12]
+	str	r3, [sp]
+	ldr	r3, [r7, #16]
+	ldr	r2, [r7, #20]
+	bl	fdt_record_loadable
+.LVL207:
+.L126:
+.LBE90:
+.LBE89:
+.LBE86:
+	.loc 1 792 0
+	adds	r6, r6, #1
+.LVL208:
+	b	.L115
+.LVL209:
+.L114:
+	.loc 1 758 0
+	cmp	r8, #0
+	blt	.L101
+	movs	r6, #1
+.LVL210:
+.L113:
+	.loc 1 765 0
+	str	r4, [sp, #4]
+	mov	r2, r5
+	str	r8, [sp]
+	mov	r0, fp
+	ldr	r3, [r7, #40]
+	ldr	r1, [r7, #24]
+	bl	spl_load_fit_image
+.LVL211:
+	.loc 1 767 0
+	mov	r3, r0
+	cmp	r0, #0
+	bne	.L97
+.LVL212:
+.LBB91:
+.LBB92:
+	.loc 1 420 0
+	adds	r2, r4, #4
+.LVL213:
+	mov	r1, r8
+	mov	r0, r5
+.LVL214:
+	bl	fit_image_get_os
+.LVL215:
+.LBE92:
+.LBE91:
+	.loc 1 774 0
+	cbz	r0, .L116
+	.loc 1 778 0
+	movs	r3, #17
+	strb	r3, [r4, #4]
+.L116:
+	.loc 1 785 0
+	ldrb	r3, [r4, #4]	@ zero_extendqisi2
+	cmp	r3, #17
+	bne	.L115
+	.loc 1 786 0
+	ldr	r3, [r7, #40]
+	mov	r1, fp
+	mov	r0, r4
+	str	r3, [sp, #4]
+	ldr	r3, [r7, #28]
+	str	r3, [sp]
+	mov	r3, r5
+	ldr	r2, [r7, #24]
+	bl	spl_fit_append_fdt
+.LVL216:
+	b	.L115
+.LVL217:
+.L140:
+	.loc 1 721 0
+	movs	r6, #0
+	b	.L113
+.L175:
+	.align	2
+.L174:
+	.word	-804389139
+	.word	.LC16
+	.word	.LC17
+	.word	.LC18
+	.word	.LC19
+	.word	.LC20
+	.word	-237076478
+	.word	.LC21
+	.word	.LC22
+	.word	.LC23
+	.word	.LC25
+	.word	.LC26
+	.word	.LC27
+	.word	1413546071
+	.word	.LC28
+	.word	.LC29
+	.word	.LC24
+.LVL218:
+.L118:
+	.loc 1 838 0
+	ldr	r3, [r4, #12]
+	subs	r3, r3, #1
+	adds	r3, r3, #3
+	bls	.L125
+	.loc 1 839 0
+	ldr	r3, [r4, #8]
+	str	r3, [r4, #12]
+.L125:
+.LVL219:
+.LBE95:
+.LBE99:
+.LBB100:
+.LBB101:
+	.loc 1 498 0
+	ldr	r3, .L176
+	.loc 1 488 0
+	str	sp, [r7, #20]
+	.loc 1 498 0
+	ldm	r3, {r0, r1, r2}
+	add	r3, r7, #48
+	stm	r3, {r0, r1, r2}
+.LVL220:
+	.loc 1 500 0
+	ldr	r3, [fp, #8]
+	adds	r3, r3, #7
+	bic	r3, r3, #7
+	sub	sp, sp, r3
+.LVL221:
+	.loc 1 507 0
+	ldr	r3, [r4, #28]
+	.loc 1 500 0
+	add	r6, sp, #16
+.LVL222:
+	.loc 1 507 0
+	cmp	r3, #2
+	bne	.L138
+.LVL223:
+	.loc 1 514 0
+	mov	r1, fp
+	mov	r0, r4
+	bl	spl_kernel_partition
+.LVL224:
+	.loc 1 515 0
+	add	r2, r7, #104
+	mov	r1, r0
+	ldr	r0, [fp]
+.LVL225:
+	bl	part_get_info_by_name
+.LVL226:
+	cmp	r0, #0
+	bgt	.L127
+	.loc 1 516 0
+	ldr	r1, .L176+4
+	ldr	r0, .L176+8
+.L170:
+	.loc 1 529 0
+	bl	printf
+.LVL227:
+.L171:
+	.loc 1 530 0
+	mvn	r3, #21
+.LVL228:
+.L128:
+	ldr	sp, [r7, #20]
+.LVL229:
+.LBE101:
+.LBE100:
+	.loc 1 876 0
+	b	.L97
+.LVL230:
+.L127:
+.LBB105:
+.LBB104:
+	.loc 1 519 0
+	ldr	r3, [r7, #104]
+	.loc 1 523 0
+	movs	r2, #1
+	ldr	r5, [fp, #16]
+	mov	r0, fp
+	.loc 1 519 0
+	str	r3, [r7, #28]
+.LVL231:
+	.loc 1 523 0
+	mov	r3, r6
+.LVL232:
+	ldr	r1, [r7, #28]
+	blx	r5
+.LVL233:
+	cmp	r0, #1
+	bne	.L141
+.LVL234:
+	ldr	r3, [r6]
+	.loc 1 528 0
+	ldr	r2, [r7]
+	rev	r3, r3
+.LVL235:
+	cmp	r3, r2
+	beq	.L129
+	.loc 1 529 0
+	ldr	r1, .L176+4
+	ldr	r0, .L176+12
+	b	.L170
+.L129:
+	.loc 1 533 0
+	mov	r2, r6
+	add	r3, r7, #44
+	ldr	r1, [r7, #28]
+	mov	r0, fp
+	bl	spl_fit_load_blob
+.LVL236:
+	.loc 1 534 0
+	mov	r6, r0
+.LVL237:
+	cmp	r0, #0
+	beq	.L142
+	.loc 1 543 0
+	movs	r1, #0
+	bl	fit_conf_get_node
+.LVL238:
+	.loc 1 544 0
+	subs	r1, r0, #0
+	bgt	.L130
+	.loc 1 545 0
+	ldr	r0, .L176+16
+.LVL239:
+	bl	printf
+.LVL240:
+	b	.L171
+.LVL241:
+.L130:
+	.loc 1 549 0
+	mov	r0, r6
+.LVL242:
+	bl	fit_config_verify
+.LVL243:
+	.loc 1 550 0
+	cbz	r0, .L131
+	.loc 1 551 0
+	mov	r1, r0
+	str	r0, [r7, #28]
+.LVL244:
+	ldr	r0, .L176+20
+.LVL245:
+	bl	printf
+.LVL246:
+	ldr	r3, [r7, #28]
+	b	.L128
+.LVL247:
+.L131:
+	str	r0, [r7, #16]
+	.loc 1 554 0
+	ldr	r0, .L176+24
+.LVL248:
+	bl	printf
+.LVL249:
+	.loc 1 556 0
+	ldr	r1, .L176+28
+	mov	r0, r6
+	bl	fdt_path_offset
+.LVL250:
+	.loc 1 557 0
+	subs	r3, r0, #0
+	str	r3, [r7, #24]
+.LVL251:
+	blt	.L143
+	ldr	r3, [r7, #16]
+	mov	r5, r3
+.LVL252:
+.L137:
+.LBB102:
+	.loc 1 564 0
+	add	r3, r7, #48
+	ldr	r1, [r7, #24]
+	ldr	r8, [r3, r5, lsl #2]
+	mov	r0, r6
+	movs	r3, #0
+	mov	r2, r8
+	bl	spl_fit_get_image_node
+.LVL253:
+	.loc 1 569 0
+	cmp	r0, #0
+	blt	.L133
+	.loc 1 574 0
+	add	r3, r7, #60
+	.loc 1 567 0
+	ldr	r10, [fp]
+	.loc 1 574 0
+	mov	r2, r6
+	stm	sp, {r0, r3}
+	mov	r0, fp
+.LVL254:
+	ldr	r3, [r7, #44]
+	ldr	r1, [r7, #28]
+	bl	spl_load_fit_image
+.LVL255:
+	.loc 1 576 0
+	mov	r3, r0
+	cmp	r0, #0
+	bne	.L128
+	.loc 1 580 0
+	ldr	r1, .L176+32
+	mov	r0, r8
+.LVL256:
+	bl	strcmp
+.LVL257:
+	cbnz	r0, .L134
+	.loc 1 590 0
+	ldr	r3, [r10, #4]
+	.loc 1 581 0
+	ldr	r8, [r7, #68]
+	.loc 1 590 0
+	cmp	r3, #1
+	.loc 1 581 0
+	str	r8, [r4, #20]
+	.loc 1 590 0
+	bne	.L135
+	.loc 1 591 0
+	mov	r0, r10
+	bl	mtd_part_parse
+.LVL258:
+	mov	r1, r0
+	mov	r0, r8
+	bl	fdt_bootargs_append
+.LVL259:
+.L135:
+	.loc 1 595 0
+	ldr	r0, [r7, #68]
+	bl	rk_meta_bootargs_append
+.LVL260:
+.L133:
+.LBE102:
+	.loc 1 563 0
+	adds	r5, r5, #1
+.LVL261:
+	cmp	r5, #3
+	bne	.L137
+.LVL262:
+.L138:
+	.loc 1 615 0
+	movs	r3, #0
+	b	.L128
+.LVL263:
+.L134:
+.LBB103:
+	.loc 1 597 0
+	ldr	r1, .L176+36
+	mov	r0, r8
+	bl	strcmp
+.LVL264:
+	cmp	r0, #0
+	bne	.L133
+	.loc 1 601 0
+	ldr	r3, [r7, #68]
+	str	r3, [r4, #16]
+	b	.L133
+.LVL265:
+.L141:
+.LBE103:
+	.loc 1 525 0
+	mvn	r3, #4
+	b	.L128
+.LVL266:
+.L142:
+	.loc 1 536 0
+	mvn	r3, #18
+	b	.L128
+.LVL267:
+.L143:
+	.loc 1 557 0
+	ldr	r3, [r7, #24]
+	b	.L128
+.LVL268:
+.L101:
+.LBE104:
+.LBE105:
+.LBB106:
+.LBB96:
+	.loc 1 635 0
+	mov	r3, #-1
+.LVL269:
+	b	.L97
+.L177:
+	.align	2
+.L176:
+	.word	.LANCHOR1
+	.word	.LANCHOR0
+	.word	.LC30
+	.word	.LC31
+	.word	.LC18
+	.word	.LC19
+	.word	.LC20
+	.word	.LC17
+	.word	.LC0
+	.word	.LC1
+.LBE96:
+.LBE106:
+	.cfi_endproc
+.LFE235:
+	.size	spl_load_simple_fit, .-spl_load_simple_fit
+	.section	.rodata
+	.align	2
+	.set	.LANCHOR1,. + 0
+.LC32:
+	.word	.LC0
+	.word	.LC1
+	.word	.LC2
+	.section	.rodata.__func__.9886,"a",%progbits
+	.set	.LANCHOR0,. + 0
+	.type	__func__.9886, %object
+	.size	__func__.9886, 20
+__func__.9886:
+	.ascii	"spl_load_kernel_fit\000"
+	.section	.rodata.spl_fit_get_image_name.isra.0.str1.1,"aMS",%progbits,1
+.LC4:
+	.ascii	"No matching DT out of these options:\012\000"
+.LC5:
+	.ascii	"description\000"
+.LC6:
+	.ascii	"   %s\012\000"
+	.section	.rodata.spl_kernel_partition.str1.1,"aMS",%progbits,1
+.LC15:
+	.ascii	"boot\000"
+	.section	.rodata.spl_load_fit_image.str1.1,"aMS",%progbits,1
+.LC7:
+	.ascii	"## Preload the image OK.\012\000"
+.LC8:
+	.ascii	"Cannot get image data/size\012\000"
+.LC9:
+	.ascii	"compression\000"
+.LC10:
+	.ascii	"## Checking %s 0x%08lx (%s @0x%08lx) ... \000"
+.LC11:
+	.ascii	"## Checking %s 0x%08lx ... \000"
+.LC12:
+	.ascii	"OK\012\000"
+.LC13:
+	.ascii	"entry\000"
+	.section	.rodata.spl_load_meta.str1.1,"aMS",%progbits,1
+.LC14:
+	.ascii	"No load cfg image.\012\000"
+	.section	.rodata.spl_load_simple_fit.str1.1,"aMS",%progbits,1
+.LC16:
+	.ascii	"Not fit magic\012\000"
+.LC17:
+	.ascii	"/images\000"
+.LC18:
+	.ascii	"No default config node\012\000"
+.LC19:
+	.ascii	"fit verify configure failed, ret=%d\012\000"
+.LC20:
+	.ascii	"\012\000"
+.LC21:
+	.ascii	"fit failed to get rollback index, ret=%d\012\000"
+.LC22:
+	.ascii	"fit reject rollback: %d < %d(min)\012\000"
+.LC23:
+	.ascii	"rollback index: %d >= %d(min), OK\012\000"
+.LC24:
+	.ascii	"standalone\000"
+.LC25:
+	.ascii	"%s: start standalone fail, ret=%d\012\000"
+.LC26:
+	.ascii	"firmware\000"
+.LC27:
+	.ascii	"loadables\000"
+.LC28:
+	.ascii	"type\000"
+.LC29:
+	.ascii	"os\000"
+.LC30:
+	.ascii	"%s: no partition\012\000"
+.LC31:
+	.ascii	"%s: Not fit magic\012\000"
+	.section	.rodata.str1.1,"aMS",%progbits,1
+.LC0:
+	.ascii	"fdt\000"
+.LC1:
+	.ascii	"kernel\000"
+.LC2:
+	.ascii	"ramdisk\000"
+	.text
+.Letext0:
+	.file 3 "include/common.h"
+	.file 4 "./arch/arm/include/asm/types.h"
+	.file 5 "./arch/arm/include/asm/posix_types.h"
+	.file 6 "include/linux/types.h"
+	.file 7 "include/errno.h"
+	.file 8 "include/linux/string.h"
+	.file 9 "include/efi.h"
+	.file 10 "include/blk.h"
+	.file 11 "include/ide.h"
+	.file 12 "include/part.h"
+	.file 13 "include/flash.h"
+	.file 14 "include/lmb.h"
+	.file 15 "include/asm-generic/u-boot.h"
+	.file 16 "./arch/arm/include/asm/u-boot-arm.h"
+	.file 17 "include/linux/libfdt_env.h"
+	.file 18 "include/linux/../../scripts/dtc/libfdt/fdt.h"
+	.file 19 "include/linux/libfdt.h"
+	.file 20 "include/u-boot/sha1.h"
+	.file 21 "include/u-boot/sha256.h"
+	.file 22 "include/net.h"
+	.file 23 "include/malloc.h"
+	.file 24 "./arch/arm/include/asm/spl.h"
+	.file 25 "include/spl.h"
+	.file 26 "./arch/arm/include/asm/arch/rk_atags.h"
+	.file 27 "include/linux/byteorder/swab.h"
+	.file 28 "include/linux/../../scripts/dtc/libfdt/libfdt.h"
+	.file 29 "include/fdt_support.h"
+	.file 30 "include/stdio.h"
+	.section	.debug_info,"",%progbits
+.Ldebug_info0:
+	.4byte	0x3138
+	.2byte	0x4
+	.4byte	.Ldebug_abbrev0
+	.byte	0x4
+	.uleb128 0x1
+	.4byte	.LASF460
+	.byte	0xc
+	.4byte	.LASF461
+	.4byte	.LASF462
+	.4byte	.Ldebug_ranges0+0xb8
+	.4byte	0
+	.4byte	.Ldebug_line0
+	.uleb128 0x2
+	.4byte	.LASF4
+	.byte	0x3
+	.byte	0xd
+	.4byte	0x30
+	.uleb128 0x3
+	.byte	0x1
+	.byte	0x8
+	.4byte	.LASF0
+	.uleb128 0x3
+	.byte	0x4
+	.byte	0x7
+	.4byte	.LASF1
+	.uleb128 0x3
+	.byte	0x2
+	.byte	0x7
+	.4byte	.LASF2
+	.uleb128 0x4
+	.4byte	.LASF24
+	.byte	0x7
+	.byte	0xc
+	.4byte	0x50
+	.uleb128 0x5
+	.byte	0x4
+	.byte	0x5
+	.ascii	"int\000"
+	.uleb128 0x3
+	.byte	0x1
+	.byte	0x6
+	.4byte	.LASF3
+	.uleb128 0x2
+	.4byte	.LASF5
+	.byte	0x4
+	.byte	0xc
+	.4byte	0x30
+	.uleb128 0x3
+	.byte	0x2
+	.byte	0x5
+	.4byte	.LASF6
+	.uleb128 0x2
+	.4byte	.LASF7
+	.byte	0x4
+	.byte	0x12
+	.4byte	0x7b
+	.uleb128 0x3
+	.byte	0x4
+	.byte	0x7
+	.4byte	.LASF8
+	.uleb128 0x3
+	.byte	0x8
+	.byte	0x5
+	.4byte	.LASF9
+	.uleb128 0x3
+	.byte	0x8
+	.byte	0x7
+	.4byte	.LASF10
+	.uleb128 0x6
+	.ascii	"u8\000"
+	.byte	0x4
+	.byte	0x1f
+	.4byte	0x30
+	.uleb128 0x7
+	.4byte	0x90
+	.uleb128 0x6
+	.ascii	"u32\000"
+	.byte	0x4
+	.byte	0x25
+	.4byte	0x7b
+	.uleb128 0x6
+	.ascii	"u64\000"
+	.byte	0x4
+	.byte	0x28
+	.4byte	0x89
+	.uleb128 0x2
+	.4byte	.LASF11
+	.byte	0x4
+	.byte	0x35
+	.4byte	0x37
+	.uleb128 0x2
+	.4byte	.LASF12
+	.byte	0x4
+	.byte	0x36
+	.4byte	0x37
+	.uleb128 0x3
+	.byte	0x4
+	.byte	0x7
+	.4byte	.LASF13
+	.uleb128 0x7
+	.4byte	0xcb
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xe4
+	.uleb128 0x3
+	.byte	0x1
+	.byte	0x8
+	.4byte	.LASF14
+	.uleb128 0x7
+	.4byte	0xdd
+	.uleb128 0x3
+	.byte	0x4
+	.byte	0x5
+	.4byte	.LASF15
+	.uleb128 0x2
+	.4byte	.LASF16
+	.byte	0x5
+	.byte	0x25
+	.4byte	0x7b
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xdd
+	.uleb128 0x2
+	.4byte	.LASF17
+	.byte	0x6
+	.byte	0x1b
+	.4byte	0x37
+	.uleb128 0x2
+	.4byte	.LASF18
+	.byte	0x6
+	.byte	0x35
+	.4byte	0xf0
+	.uleb128 0x2
+	.4byte	.LASF19
+	.byte	0x6
+	.byte	0x59
+	.4byte	0x3e
+	.uleb128 0x2
+	.4byte	.LASF20
+	.byte	0x6
+	.byte	0x5b
+	.4byte	0x37
+	.uleb128 0x2
+	.4byte	.LASF21
+	.byte	0x6
+	.byte	0x69
+	.4byte	0x5e
+	.uleb128 0x7
+	.4byte	0x12d
+	.uleb128 0x2
+	.4byte	.LASF22
+	.byte	0x6
+	.byte	0x6b
+	.4byte	0x70
+	.uleb128 0x2
+	.4byte	.LASF23
+	.byte	0x6
+	.byte	0x97
+	.4byte	0x70
+	.uleb128 0x9
+	.byte	0x4
+	.uleb128 0x4
+	.4byte	.LASF25
+	.byte	0x8
+	.byte	0xb
+	.4byte	0xfb
+	.uleb128 0xa
+	.byte	0x10
+	.byte	0x9
+	.byte	0x1f
+	.4byte	0x173
+	.uleb128 0xb
+	.ascii	"b\000"
+	.byte	0x9
+	.byte	0x20
+	.4byte	0x173
+	.byte	0
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x90
+	.4byte	0x183
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0xf
+	.byte	0
+	.uleb128 0x2
+	.4byte	.LASF26
+	.byte	0x9
+	.byte	0x21
+	.4byte	0x160
+	.uleb128 0xc
+	.4byte	0x9f
+	.4byte	0x19e
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x4
+	.byte	0
+	.uleb128 0x3
+	.byte	0x1
+	.byte	0x2
+	.4byte	.LASF27
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0x1b0
+	.uleb128 0xe
+	.byte	0
+	.uleb128 0xf
+	.4byte	.LASF28
+	.byte	0x9
+	.2byte	0x140
+	.4byte	0x1a5
+	.uleb128 0xf
+	.4byte	.LASF29
+	.byte	0x9
+	.2byte	0x143
+	.4byte	0x1a5
+	.uleb128 0xf
+	.4byte	.LASF30
+	.byte	0x9
+	.2byte	0x143
+	.4byte	0x1a5
+	.uleb128 0x2
+	.4byte	.LASF31
+	.byte	0xa
+	.byte	0x11
+	.4byte	0x122
+	.uleb128 0x10
+	.4byte	.LASF50
+	.byte	0x4
+	.4byte	0x7b
+	.byte	0xa
+	.byte	0x18
+	.4byte	0x25c
+	.uleb128 0x11
+	.4byte	.LASF32
+	.byte	0
+	.uleb128 0x11
+	.4byte	.LASF33
+	.byte	0x1
+	.uleb128 0x11
+	.4byte	.LASF34
+	.byte	0x2
+	.uleb128 0x11
+	.4byte	.LASF35
+	.byte	0x3
+	.uleb128 0x11
+	.4byte	.LASF36
+	.byte	0x4
+	.uleb128 0x11
+	.4byte	.LASF37
+	.byte	0x5
+	.uleb128 0x11
+	.4byte	.LASF38
+	.byte	0x6
+	.uleb128 0x11
+	.4byte	.LASF39
+	.byte	0x7
+	.uleb128 0x11
+	.4byte	.LASF40
+	.byte	0x8
+	.uleb128 0x11
+	.4byte	.LASF41
+	.byte	0x9
+	.uleb128 0x11
+	.4byte	.LASF42
+	.byte	0xa
+	.uleb128 0x11
+	.4byte	.LASF43
+	.byte	0xb
+	.uleb128 0x11
+	.4byte	.LASF44
+	.byte	0xc
+	.uleb128 0x11
+	.4byte	.LASF45
+	.byte	0xd
+	.uleb128 0x11
+	.4byte	.LASF46
+	.byte	0xe
+	.uleb128 0x11
+	.4byte	.LASF47
+	.byte	0xf
+	.uleb128 0x11
+	.4byte	.LASF48
+	.byte	0x10
+	.uleb128 0x11
+	.4byte	.LASF49
+	.byte	0x11
+	.byte	0
+	.uleb128 0x10
+	.4byte	.LASF51
+	.byte	0x4
+	.4byte	0x7b
+	.byte	0xa
+	.byte	0x3d
+	.4byte	0x285
+	.uleb128 0x11
+	.4byte	.LASF52
+	.byte	0
+	.uleb128 0x11
+	.4byte	.LASF53
+	.byte	0x1
+	.uleb128 0x11
+	.4byte	.LASF54
+	.byte	0x2
+	.uleb128 0x11
+	.4byte	.LASF55
+	.byte	0x3
+	.byte	0
+	.uleb128 0x12
+	.byte	0x10
+	.byte	0xa
+	.byte	0x62
+	.4byte	0x2a4
+	.uleb128 0x13
+	.4byte	.LASF56
+	.byte	0xa
+	.byte	0x63
+	.4byte	0x13d
+	.uleb128 0x13
+	.4byte	.LASF57
+	.byte	0xa
+	.byte	0x64
+	.4byte	0x183
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF72
+	.byte	0x7c
+	.byte	0xa
+	.byte	0x49
+	.4byte	0x383
+	.uleb128 0x15
+	.4byte	.LASF50
+	.byte	0xa
+	.byte	0x4e
+	.4byte	0x1df
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF58
+	.byte	0xa
+	.byte	0x4f
+	.4byte	0x50
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF59
+	.byte	0xa
+	.byte	0x50
+	.4byte	0x30
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF60
+	.byte	0xa
+	.byte	0x51
+	.4byte	0x30
+	.byte	0x9
+	.uleb128 0xb
+	.ascii	"lun\000"
+	.byte	0xa
+	.byte	0x52
+	.4byte	0x30
+	.byte	0xa
+	.uleb128 0x15
+	.4byte	.LASF61
+	.byte	0xa
+	.byte	0x53
+	.4byte	0x30
+	.byte	0xb
+	.uleb128 0x15
+	.4byte	.LASF62
+	.byte	0xa
+	.byte	0x54
+	.4byte	0x30
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF63
+	.byte	0xa
+	.byte	0x55
+	.4byte	0x30
+	.byte	0xd
+	.uleb128 0x15
+	.4byte	.LASF64
+	.byte	0xa
+	.byte	0x56
+	.4byte	0x30
+	.byte	0xe
+	.uleb128 0xb
+	.ascii	"lba\000"
+	.byte	0xa
+	.byte	0x5b
+	.4byte	0x1d4
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF65
+	.byte	0xa
+	.byte	0x5c
+	.4byte	0x37
+	.byte	0x14
+	.uleb128 0x15
+	.4byte	.LASF66
+	.byte	0xa
+	.byte	0x5d
+	.4byte	0x50
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF67
+	.byte	0xa
+	.byte	0x5e
+	.4byte	0x383
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF68
+	.byte	0xa
+	.byte	0x5f
+	.4byte	0x393
+	.byte	0x45
+	.uleb128 0x15
+	.4byte	.LASF69
+	.byte	0xa
+	.byte	0x60
+	.4byte	0x3a3
+	.byte	0x5a
+	.uleb128 0x15
+	.4byte	.LASF51
+	.byte	0xa
+	.byte	0x61
+	.4byte	0x25c
+	.byte	0x64
+	.uleb128 0x16
+	.4byte	0x285
+	.byte	0x68
+	.uleb128 0x15
+	.4byte	.LASF70
+	.byte	0xa
+	.byte	0x6c
+	.4byte	0x3b8
+	.byte	0x78
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0x393
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x28
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0x3a3
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x14
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0x3b3
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x8
+	.byte	0
+	.uleb128 0x17
+	.4byte	.LASF84
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x3b3
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x3c4
+	.uleb128 0x18
+	.uleb128 0xc
+	.4byte	0x122
+	.4byte	0x3d0
+	.uleb128 0xe
+	.byte	0
+	.uleb128 0x4
+	.4byte	.LASF71
+	.byte	0xb
+	.byte	0x10
+	.4byte	0x3c5
+	.uleb128 0xc
+	.4byte	0x30
+	.4byte	0x3eb
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x5
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF73
+	.byte	0x8
+	.byte	0xc
+	.byte	0xf
+	.4byte	0x410
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0xc
+	.byte	0x10
+	.4byte	0xfb
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF75
+	.byte	0xc
+	.byte	0x11
+	.4byte	0x429
+	.byte	0x4
+	.byte	0
+	.uleb128 0x7
+	.4byte	0x3eb
+	.uleb128 0x19
+	.4byte	0x50
+	.4byte	0x429
+	.uleb128 0x1a
+	.4byte	0x50
+	.uleb128 0x1a
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x415
+	.uleb128 0x14
+	.4byte	.LASF76
+	.byte	0x50
+	.byte	0xc
+	.byte	0x3e
+	.4byte	0x484
+	.uleb128 0x15
+	.4byte	.LASF77
+	.byte	0xc
+	.byte	0x3f
+	.4byte	0x1d4
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0xc
+	.byte	0x40
+	.4byte	0x1d4
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF65
+	.byte	0xc
+	.byte	0x41
+	.4byte	0x122
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0xc
+	.byte	0x42
+	.4byte	0x484
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF62
+	.byte	0xc
+	.byte	0x43
+	.4byte	0x484
+	.byte	0x2c
+	.uleb128 0x15
+	.4byte	.LASF79
+	.byte	0xc
+	.byte	0x44
+	.4byte	0x50
+	.byte	0x4c
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x25
+	.4byte	0x494
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x1f
+	.byte	0
+	.uleb128 0x2
+	.4byte	.LASF80
+	.byte	0xc
+	.byte	0x4e
+	.4byte	0x42f
+	.uleb128 0xc
+	.4byte	0x410
+	.4byte	0x4aa
+	.uleb128 0xe
+	.byte	0
+	.uleb128 0x7
+	.4byte	0x49f
+	.uleb128 0x4
+	.4byte	.LASF73
+	.byte	0xc
+	.byte	0xe1
+	.4byte	0x4aa
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x2a4
+	.uleb128 0x1b
+	.2byte	0xa10
+	.byte	0xd
+	.byte	0x13
+	.4byte	0x514
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0xd
+	.byte	0x14
+	.4byte	0x122
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF81
+	.byte	0xd
+	.byte	0x15
+	.4byte	0x117
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF82
+	.byte	0xd
+	.byte	0x16
+	.4byte	0x122
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF77
+	.byte	0xd
+	.byte	0x17
+	.4byte	0x514
+	.byte	0xc
+	.uleb128 0x1c
+	.4byte	.LASF83
+	.byte	0xd
+	.byte	0x18
+	.4byte	0x525
+	.2byte	0x80c
+	.uleb128 0x1d
+	.ascii	"mtd\000"
+	.byte	0xd
+	.byte	0x31
+	.4byte	0x53b
+	.2byte	0xa0c
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x122
+	.4byte	0x525
+	.uleb128 0x1e
+	.4byte	0xcb
+	.2byte	0x1ff
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x25
+	.4byte	0x536
+	.uleb128 0x1e
+	.4byte	0xcb
+	.2byte	0x1ff
+	.byte	0
+	.uleb128 0x17
+	.4byte	.LASF85
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x536
+	.uleb128 0x2
+	.4byte	.LASF86
+	.byte	0xd
+	.byte	0x37
+	.4byte	0x4c0
+	.uleb128 0xc
+	.4byte	0x541
+	.4byte	0x557
+	.uleb128 0xe
+	.byte	0
+	.uleb128 0x4
+	.4byte	.LASF87
+	.byte	0xd
+	.byte	0x39
+	.4byte	0x54c
+	.uleb128 0x3
+	.byte	0x8
+	.byte	0x4
+	.4byte	.LASF88
+	.uleb128 0x14
+	.4byte	.LASF89
+	.byte	0x8
+	.byte	0xe
+	.byte	0x10
+	.4byte	0x58e
+	.uleb128 0x15
+	.4byte	.LASF90
+	.byte	0xe
+	.byte	0x11
+	.4byte	0xb5
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0xe
+	.byte	0x12
+	.4byte	0xc0
+	.byte	0x4
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF91
+	.byte	0x90
+	.byte	0xe
+	.byte	0x15
+	.4byte	0x5bf
+	.uleb128 0xb
+	.ascii	"cnt\000"
+	.byte	0xe
+	.byte	0x16
+	.4byte	0x37
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0xe
+	.byte	0x17
+	.4byte	0xc0
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF92
+	.byte	0xe
+	.byte	0x18
+	.4byte	0x5bf
+	.byte	0x8
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x569
+	.4byte	0x5cf
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x10
+	.byte	0
+	.uleb128 0x1f
+	.ascii	"lmb\000"
+	.2byte	0x120
+	.byte	0xe
+	.byte	0x1b
+	.4byte	0x5f5
+	.uleb128 0x15
+	.4byte	.LASF93
+	.byte	0xe
+	.byte	0x1c
+	.4byte	0x58e
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0xe
+	.byte	0x1d
+	.4byte	0x58e
+	.byte	0x90
+	.byte	0
+	.uleb128 0x20
+	.ascii	"lmb\000"
+	.byte	0xe
+	.byte	0x20
+	.4byte	0x5cf
+	.uleb128 0xa
+	.byte	0x10
+	.byte	0xf
+	.byte	0x5b
+	.4byte	0x621
+	.uleb128 0x15
+	.4byte	.LASF77
+	.byte	0xf
+	.byte	0x5c
+	.4byte	0xaa
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0xf
+	.byte	0x5d
+	.4byte	0xaa
+	.byte	0x8
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF95
+	.byte	0x68
+	.byte	0xf
+	.byte	0x1b
+	.4byte	0x712
+	.uleb128 0x15
+	.4byte	.LASF96
+	.byte	0xf
+	.byte	0x1c
+	.4byte	0x37
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF97
+	.byte	0xf
+	.byte	0x1d
+	.4byte	0xc0
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF98
+	.byte	0xf
+	.byte	0x1e
+	.4byte	0x37
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF99
+	.byte	0xf
+	.byte	0x1f
+	.4byte	0x37
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF100
+	.byte	0xf
+	.byte	0x20
+	.4byte	0x37
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF101
+	.byte	0xf
+	.byte	0x21
+	.4byte	0x37
+	.byte	0x14
+	.uleb128 0x15
+	.4byte	.LASF102
+	.byte	0xf
+	.byte	0x22
+	.4byte	0x37
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF103
+	.byte	0xf
+	.byte	0x24
+	.4byte	0x37
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF104
+	.byte	0xf
+	.byte	0x25
+	.4byte	0x37
+	.byte	0x20
+	.uleb128 0x15
+	.4byte	.LASF105
+	.byte	0xf
+	.byte	0x26
+	.4byte	0x37
+	.byte	0x24
+	.uleb128 0x15
+	.4byte	.LASF106
+	.byte	0xf
+	.byte	0x31
+	.4byte	0x37
+	.byte	0x28
+	.uleb128 0x15
+	.4byte	.LASF107
+	.byte	0xf
+	.byte	0x32
+	.4byte	0x37
+	.byte	0x2c
+	.uleb128 0x15
+	.4byte	.LASF108
+	.byte	0xf
+	.byte	0x33
+	.4byte	0x3db
+	.byte	0x30
+	.uleb128 0x15
+	.4byte	.LASF109
+	.byte	0xf
+	.byte	0x34
+	.4byte	0x3e
+	.byte	0x36
+	.uleb128 0x15
+	.4byte	.LASF110
+	.byte	0xf
+	.byte	0x35
+	.4byte	0x37
+	.byte	0x38
+	.uleb128 0x15
+	.4byte	.LASF111
+	.byte	0xf
+	.byte	0x36
+	.4byte	0x37
+	.byte	0x3c
+	.uleb128 0x15
+	.4byte	.LASF112
+	.byte	0xf
+	.byte	0x57
+	.4byte	0x122
+	.byte	0x40
+	.uleb128 0x15
+	.4byte	.LASF113
+	.byte	0xf
+	.byte	0x58
+	.4byte	0x122
+	.byte	0x44
+	.uleb128 0x15
+	.4byte	.LASF114
+	.byte	0xf
+	.byte	0x5e
+	.4byte	0x712
+	.byte	0x48
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x600
+	.4byte	0x722
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x1
+	.byte	0
+	.uleb128 0x2
+	.4byte	.LASF115
+	.byte	0xf
+	.byte	0x60
+	.4byte	0x621
+	.uleb128 0x4
+	.4byte	.LASF116
+	.byte	0x10
+	.byte	0x13
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF117
+	.byte	0x10
+	.byte	0x14
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF118
+	.byte	0x10
+	.byte	0x15
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF119
+	.byte	0x10
+	.byte	0x16
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF120
+	.byte	0x10
+	.byte	0x17
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF121
+	.byte	0x10
+	.byte	0x18
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF122
+	.byte	0x10
+	.byte	0x19
+	.4byte	0x122
+	.uleb128 0x2
+	.4byte	.LASF123
+	.byte	0x11
+	.byte	0x11
+	.4byte	0x148
+	.uleb128 0x14
+	.4byte	.LASF124
+	.byte	0x28
+	.byte	0x12
+	.byte	0x39
+	.4byte	0x80a
+	.uleb128 0x15
+	.4byte	.LASF125
+	.byte	0x12
+	.byte	0x3a
+	.4byte	0x77a
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF126
+	.byte	0x12
+	.byte	0x3b
+	.4byte	0x77a
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF127
+	.byte	0x12
+	.byte	0x3c
+	.4byte	0x77a
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF128
+	.byte	0x12
+	.byte	0x3d
+	.4byte	0x77a
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF129
+	.byte	0x12
+	.byte	0x3e
+	.4byte	0x77a
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x12
+	.byte	0x3f
+	.4byte	0x77a
+	.byte	0x14
+	.uleb128 0x15
+	.4byte	.LASF131
+	.byte	0x12
+	.byte	0x40
+	.4byte	0x77a
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF132
+	.byte	0x12
+	.byte	0x43
+	.4byte	0x77a
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF133
+	.byte	0x12
+	.byte	0x46
+	.4byte	0x77a
+	.byte	0x20
+	.uleb128 0x15
+	.4byte	.LASF134
+	.byte	0x12
+	.byte	0x49
+	.4byte	0x77a
+	.byte	0x24
+	.byte	0
+	.uleb128 0xf
+	.4byte	.LASF135
+	.byte	0x13
+	.2byte	0x136
+	.4byte	0x816
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x785
+	.uleb128 0x21
+	.byte	0x4
+	.4byte	0x7b
+	.byte	0x2
+	.byte	0x83
+	.4byte	0x8d1
+	.uleb128 0x11
+	.4byte	.LASF136
+	.byte	0
+	.uleb128 0x11
+	.4byte	.LASF137
+	.byte	0x1
+	.uleb128 0x11
+	.4byte	.LASF138
+	.byte	0x2
+	.uleb128 0x11
+	.4byte	.LASF139
+	.byte	0x3
+	.uleb128 0x11
+	.4byte	.LASF140
+	.byte	0x4
+	.uleb128 0x11
+	.4byte	.LASF141
+	.byte	0x5
+	.uleb128 0x11
+	.4byte	.LASF142
+	.byte	0x6
+	.uleb128 0x11
+	.4byte	.LASF143
+	.byte	0x7
+	.uleb128 0x11
+	.4byte	.LASF144
+	.byte	0x8
+	.uleb128 0x11
+	.4byte	.LASF145
+	.byte	0x9
+	.uleb128 0x11
+	.4byte	.LASF146
+	.byte	0xa
+	.uleb128 0x11
+	.4byte	.LASF147
+	.byte	0xb
+	.uleb128 0x11
+	.4byte	.LASF148
+	.byte	0xc
+	.uleb128 0x11
+	.4byte	.LASF149
+	.byte	0xd
+	.uleb128 0x11
+	.4byte	.LASF150
+	.byte	0xe
+	.uleb128 0x11
+	.4byte	.LASF151
+	.byte	0xf
+	.uleb128 0x11
+	.4byte	.LASF152
+	.byte	0x10
+	.uleb128 0x11
+	.4byte	.LASF153
+	.byte	0x11
+	.uleb128 0x11
+	.4byte	.LASF154
+	.byte	0x12
+	.uleb128 0x11
+	.4byte	.LASF155
+	.byte	0x13
+	.uleb128 0x11
+	.4byte	.LASF156
+	.byte	0x14
+	.uleb128 0x11
+	.4byte	.LASF157
+	.byte	0x15
+	.uleb128 0x11
+	.4byte	.LASF158
+	.byte	0x16
+	.uleb128 0x11
+	.4byte	.LASF159
+	.byte	0x17
+	.uleb128 0x11
+	.4byte	.LASF160
+	.byte	0x18
+	.uleb128 0x11
+	.4byte	.LASF161
+	.byte	0x19
+	.uleb128 0x11
+	.4byte	.LASF162
+	.byte	0x1a
+	.uleb128 0x11
+	.4byte	.LASF163
+	.byte	0x1b
+	.byte	0
+	.uleb128 0x21
+	.byte	0x4
+	.4byte	0x7b
+	.byte	0x2
+	.byte	0xf3
+	.4byte	0x9b0
+	.uleb128 0x11
+	.4byte	.LASF164
+	.byte	0
+	.uleb128 0x11
+	.4byte	.LASF165
+	.byte	0x1
+	.uleb128 0x11
+	.4byte	.LASF166
+	.byte	0x2
+	.uleb128 0x11
+	.4byte	.LASF167
+	.byte	0x3
+	.uleb128 0x11
+	.4byte	.LASF168
+	.byte	0x4
+	.uleb128 0x11
+	.4byte	.LASF169
+	.byte	0x5
+	.uleb128 0x11
+	.4byte	.LASF170
+	.byte	0x6
+	.uleb128 0x11
+	.4byte	.LASF171
+	.byte	0x7
+	.uleb128 0x11
+	.4byte	.LASF172
+	.byte	0x8
+	.uleb128 0x11
+	.4byte	.LASF173
+	.byte	0x9
+	.uleb128 0x11
+	.4byte	.LASF174
+	.byte	0xa
+	.uleb128 0x11
+	.4byte	.LASF175
+	.byte	0xb
+	.uleb128 0x11
+	.4byte	.LASF176
+	.byte	0xc
+	.uleb128 0x11
+	.4byte	.LASF177
+	.byte	0xd
+	.uleb128 0x11
+	.4byte	.LASF178
+	.byte	0xe
+	.uleb128 0x11
+	.4byte	.LASF179
+	.byte	0xf
+	.uleb128 0x11
+	.4byte	.LASF180
+	.byte	0x10
+	.uleb128 0x11
+	.4byte	.LASF181
+	.byte	0x11
+	.uleb128 0x11
+	.4byte	.LASF182
+	.byte	0x12
+	.uleb128 0x11
+	.4byte	.LASF183
+	.byte	0x13
+	.uleb128 0x11
+	.4byte	.LASF184
+	.byte	0x14
+	.uleb128 0x11
+	.4byte	.LASF185
+	.byte	0x15
+	.uleb128 0x11
+	.4byte	.LASF186
+	.byte	0x16
+	.uleb128 0x11
+	.4byte	.LASF187
+	.byte	0x17
+	.uleb128 0x11
+	.4byte	.LASF188
+	.byte	0x18
+	.uleb128 0x11
+	.4byte	.LASF189
+	.byte	0x19
+	.uleb128 0x11
+	.4byte	.LASF190
+	.byte	0x1a
+	.uleb128 0x11
+	.4byte	.LASF191
+	.byte	0x1b
+	.uleb128 0x11
+	.4byte	.LASF192
+	.byte	0x1c
+	.uleb128 0x11
+	.4byte	.LASF193
+	.byte	0x1d
+	.uleb128 0x11
+	.4byte	.LASF194
+	.byte	0x1e
+	.uleb128 0x11
+	.4byte	.LASF195
+	.byte	0x1f
+	.uleb128 0x11
+	.4byte	.LASF196
+	.byte	0x20
+	.uleb128 0x11
+	.4byte	.LASF197
+	.byte	0x21
+	.uleb128 0x11
+	.4byte	.LASF198
+	.byte	0x22
+	.byte	0
+	.uleb128 0x22
+	.byte	0x4
+	.4byte	0x7b
+	.byte	0x2
+	.2byte	0x121
+	.4byte	0x9ee
+	.uleb128 0x11
+	.4byte	.LASF199
+	.byte	0
+	.uleb128 0x11
+	.4byte	.LASF200
+	.byte	0x1
+	.uleb128 0x11
+	.4byte	.LASF201
+	.byte	0x2
+	.uleb128 0x11
+	.4byte	.LASF202
+	.byte	0x3
+	.uleb128 0x11
+	.4byte	.LASF203
+	.byte	0x4
+	.uleb128 0x11
+	.4byte	.LASF204
+	.byte	0x5
+	.uleb128 0x11
+	.4byte	.LASF205
+	.byte	0x6
+	.uleb128 0x11
+	.4byte	.LASF206
+	.byte	0x7
+	.byte	0
+	.uleb128 0x23
+	.4byte	.LASF207
+	.byte	0x40
+	.byte	0x2
+	.2byte	0x137
+	.4byte	0xa98
+	.uleb128 0x24
+	.4byte	.LASF208
+	.byte	0x2
+	.2byte	0x138
+	.4byte	0x148
+	.byte	0
+	.uleb128 0x24
+	.4byte	.LASF209
+	.byte	0x2
+	.2byte	0x139
+	.4byte	0x148
+	.byte	0x4
+	.uleb128 0x24
+	.4byte	.LASF210
+	.byte	0x2
+	.2byte	0x13a
+	.4byte	0x148
+	.byte	0x8
+	.uleb128 0x24
+	.4byte	.LASF211
+	.byte	0x2
+	.2byte	0x13b
+	.4byte	0x148
+	.byte	0xc
+	.uleb128 0x24
+	.4byte	.LASF212
+	.byte	0x2
+	.2byte	0x13c
+	.4byte	0x148
+	.byte	0x10
+	.uleb128 0x24
+	.4byte	.LASF213
+	.byte	0x2
+	.2byte	0x13d
+	.4byte	0x148
+	.byte	0x14
+	.uleb128 0x24
+	.4byte	.LASF214
+	.byte	0x2
+	.2byte	0x13e
+	.4byte	0x148
+	.byte	0x18
+	.uleb128 0x24
+	.4byte	.LASF215
+	.byte	0x2
+	.2byte	0x13f
+	.4byte	0x12d
+	.byte	0x1c
+	.uleb128 0x24
+	.4byte	.LASF216
+	.byte	0x2
+	.2byte	0x140
+	.4byte	0x12d
+	.byte	0x1d
+	.uleb128 0x24
+	.4byte	.LASF217
+	.byte	0x2
+	.2byte	0x141
+	.4byte	0x12d
+	.byte	0x1e
+	.uleb128 0x24
+	.4byte	.LASF218
+	.byte	0x2
+	.2byte	0x142
+	.4byte	0x12d
+	.byte	0x1f
+	.uleb128 0x24
+	.4byte	.LASF219
+	.byte	0x2
+	.2byte	0x143
+	.4byte	0xa98
+	.byte	0x20
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x12d
+	.4byte	0xaa8
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x1f
+	.byte	0
+	.uleb128 0x25
+	.4byte	.LASF220
+	.byte	0x2
+	.2byte	0x144
+	.4byte	0x9ee
+	.uleb128 0x7
+	.4byte	0xaa8
+	.uleb128 0x23
+	.4byte	.LASF221
+	.byte	0x18
+	.byte	0x2
+	.2byte	0x146
+	.4byte	0xb3b
+	.uleb128 0x24
+	.4byte	.LASF77
+	.byte	0x2
+	.2byte	0x147
+	.4byte	0x122
+	.byte	0
+	.uleb128 0x26
+	.ascii	"end\000"
+	.byte	0x2
+	.2byte	0x147
+	.4byte	0x122
+	.byte	0x4
+	.uleb128 0x24
+	.4byte	.LASF222
+	.byte	0x2
+	.2byte	0x148
+	.4byte	0x122
+	.byte	0x8
+	.uleb128 0x24
+	.4byte	.LASF223
+	.byte	0x2
+	.2byte	0x148
+	.4byte	0x122
+	.byte	0xc
+	.uleb128 0x24
+	.4byte	.LASF224
+	.byte	0x2
+	.2byte	0x149
+	.4byte	0x122
+	.byte	0x10
+	.uleb128 0x24
+	.4byte	.LASF225
+	.byte	0x2
+	.2byte	0x14a
+	.4byte	0x12d
+	.byte	0x14
+	.uleb128 0x24
+	.4byte	.LASF62
+	.byte	0x2
+	.2byte	0x14a
+	.4byte	0x12d
+	.byte	0x15
+	.uleb128 0x26
+	.ascii	"os\000"
+	.byte	0x2
+	.2byte	0x14a
+	.4byte	0x12d
+	.byte	0x16
+	.uleb128 0x24
+	.4byte	.LASF226
+	.byte	0x2
+	.2byte	0x14b
+	.4byte	0x12d
+	.byte	0x17
+	.byte	0
+	.uleb128 0x25
+	.4byte	.LASF227
+	.byte	0x2
+	.2byte	0x14c
+	.4byte	0xab9
+	.uleb128 0x27
+	.4byte	.LASF228
+	.2byte	0x1e4
+	.byte	0x2
+	.2byte	0x152
+	.4byte	0xcda
+	.uleb128 0x24
+	.4byte	.LASF229
+	.byte	0x2
+	.2byte	0x158
+	.4byte	0xcda
+	.byte	0
+	.uleb128 0x24
+	.4byte	.LASF230
+	.byte	0x2
+	.2byte	0x159
+	.4byte	0xaa8
+	.byte	0x4
+	.uleb128 0x24
+	.4byte	.LASF231
+	.byte	0x2
+	.2byte	0x15a
+	.4byte	0x122
+	.byte	0x44
+	.uleb128 0x24
+	.4byte	.LASF232
+	.byte	0x2
+	.2byte	0x15d
+	.4byte	0xd7
+	.byte	0x48
+	.uleb128 0x24
+	.4byte	.LASF233
+	.byte	0x2
+	.2byte	0x15f
+	.4byte	0x153
+	.byte	0x4c
+	.uleb128 0x24
+	.4byte	.LASF234
+	.byte	0x2
+	.2byte	0x160
+	.4byte	0xd7
+	.byte	0x50
+	.uleb128 0x24
+	.4byte	.LASF235
+	.byte	0x2
+	.2byte	0x161
+	.4byte	0x50
+	.byte	0x54
+	.uleb128 0x24
+	.4byte	.LASF236
+	.byte	0x2
+	.2byte	0x163
+	.4byte	0x153
+	.byte	0x58
+	.uleb128 0x24
+	.4byte	.LASF237
+	.byte	0x2
+	.2byte	0x164
+	.4byte	0xd7
+	.byte	0x5c
+	.uleb128 0x24
+	.4byte	.LASF238
+	.byte	0x2
+	.2byte	0x165
+	.4byte	0x50
+	.byte	0x60
+	.uleb128 0x24
+	.4byte	.LASF239
+	.byte	0x2
+	.2byte	0x167
+	.4byte	0x153
+	.byte	0x64
+	.uleb128 0x24
+	.4byte	.LASF240
+	.byte	0x2
+	.2byte	0x168
+	.4byte	0xd7
+	.byte	0x68
+	.uleb128 0x24
+	.4byte	.LASF241
+	.byte	0x2
+	.2byte	0x169
+	.4byte	0x50
+	.byte	0x6c
+	.uleb128 0x24
+	.4byte	.LASF242
+	.byte	0x2
+	.2byte	0x16b
+	.4byte	0x153
+	.byte	0x70
+	.uleb128 0x24
+	.4byte	.LASF243
+	.byte	0x2
+	.2byte	0x16c
+	.4byte	0xd7
+	.byte	0x74
+	.uleb128 0x24
+	.4byte	.LASF244
+	.byte	0x2
+	.2byte	0x16d
+	.4byte	0x50
+	.byte	0x78
+	.uleb128 0x26
+	.ascii	"os\000"
+	.byte	0x2
+	.2byte	0x171
+	.4byte	0xb3b
+	.byte	0x7c
+	.uleb128 0x26
+	.ascii	"ep\000"
+	.byte	0x2
+	.2byte	0x172
+	.4byte	0x122
+	.byte	0x94
+	.uleb128 0x24
+	.4byte	.LASF245
+	.byte	0x2
+	.2byte	0x174
+	.4byte	0x122
+	.byte	0x98
+	.uleb128 0x24
+	.4byte	.LASF246
+	.byte	0x2
+	.2byte	0x174
+	.4byte	0x122
+	.byte	0x9c
+	.uleb128 0x24
+	.4byte	.LASF247
+	.byte	0x2
+	.2byte	0x176
+	.4byte	0xfb
+	.byte	0xa0
+	.uleb128 0x24
+	.4byte	.LASF248
+	.byte	0x2
+	.2byte	0x177
+	.4byte	0x122
+	.byte	0xa4
+	.uleb128 0x24
+	.4byte	.LASF249
+	.byte	0x2
+	.2byte	0x179
+	.4byte	0x122
+	.byte	0xa8
+	.uleb128 0x24
+	.4byte	.LASF250
+	.byte	0x2
+	.2byte	0x17a
+	.4byte	0x122
+	.byte	0xac
+	.uleb128 0x24
+	.4byte	.LASF251
+	.byte	0x2
+	.2byte	0x17b
+	.4byte	0x122
+	.byte	0xb0
+	.uleb128 0x24
+	.4byte	.LASF252
+	.byte	0x2
+	.2byte	0x17c
+	.4byte	0x122
+	.byte	0xb4
+	.uleb128 0x26
+	.ascii	"kbd\000"
+	.byte	0x2
+	.2byte	0x17d
+	.4byte	0xce0
+	.byte	0xb8
+	.uleb128 0x24
+	.4byte	.LASF253
+	.byte	0x2
+	.2byte	0x180
+	.4byte	0x50
+	.byte	0xbc
+	.uleb128 0x24
+	.4byte	.LASF254
+	.byte	0x2
+	.2byte	0x18d
+	.4byte	0x50
+	.byte	0xc0
+	.uleb128 0x26
+	.ascii	"lmb\000"
+	.byte	0x2
+	.2byte	0x190
+	.4byte	0x5cf
+	.byte	0xc4
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xaa8
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x722
+	.uleb128 0x25
+	.4byte	.LASF255
+	.byte	0x2
+	.2byte	0x196
+	.4byte	0xb47
+	.uleb128 0xf
+	.4byte	.LASF256
+	.byte	0x2
+	.2byte	0x198
+	.4byte	0xce6
+	.uleb128 0xc
+	.4byte	0x138
+	.4byte	0xd09
+	.uleb128 0xe
+	.byte	0
+	.uleb128 0x7
+	.4byte	0xcfe
+	.uleb128 0x4
+	.4byte	.LASF257
+	.byte	0x14
+	.byte	0x1a
+	.4byte	0xd09
+	.uleb128 0x4
+	.4byte	.LASF258
+	.byte	0x15
+	.byte	0x7
+	.4byte	0xd09
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x12d
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0xd3a
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x7
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0xd4a
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0xf
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x9f
+	.4byte	0xd5a
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x7
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0xd6b
+	.uleb128 0x1e
+	.4byte	0xcb
+	.2byte	0x3ff
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0xd7b
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x1f
+	.byte	0
+	.uleb128 0x4
+	.4byte	.LASF259
+	.byte	0x3
+	.byte	0xad
+	.4byte	0x122
+	.uleb128 0xc
+	.4byte	0x90
+	.4byte	0xd91
+	.uleb128 0xe
+	.byte	0
+	.uleb128 0x4
+	.4byte	.LASF260
+	.byte	0x3
+	.byte	0xaf
+	.4byte	0xd86
+	.uleb128 0x4
+	.4byte	.LASF261
+	.byte	0x3
+	.byte	0xb0
+	.4byte	0xd86
+	.uleb128 0x4
+	.4byte	.LASF262
+	.byte	0x3
+	.byte	0xfe
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF263
+	.byte	0x3
+	.byte	0xff
+	.4byte	0x122
+	.uleb128 0xf
+	.4byte	.LASF264
+	.byte	0x3
+	.2byte	0x100
+	.4byte	0x122
+	.uleb128 0x14
+	.4byte	.LASF265
+	.byte	0x4
+	.byte	0x16
+	.byte	0x2e
+	.4byte	0xde2
+	.uleb128 0x15
+	.4byte	.LASF266
+	.byte	0x16
+	.byte	0x2f
+	.4byte	0x148
+	.byte	0
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x25
+	.uleb128 0x14
+	.4byte	.LASF267
+	.byte	0x40
+	.byte	0x16
+	.byte	0xa6
+	.4byte	0xe85
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0x16
+	.byte	0xa8
+	.4byte	0xd3a
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF268
+	.byte	0x16
+	.byte	0xa9
+	.4byte	0x3db
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF269
+	.byte	0x16
+	.byte	0xaa
+	.4byte	0xb5
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF254
+	.byte	0x16
+	.byte	0xab
+	.4byte	0x50
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF270
+	.byte	0x16
+	.byte	0xad
+	.4byte	0xe9f
+	.byte	0x20
+	.uleb128 0x15
+	.4byte	.LASF271
+	.byte	0x16
+	.byte	0xae
+	.4byte	0xebe
+	.byte	0x24
+	.uleb128 0x15
+	.4byte	.LASF272
+	.byte	0x16
+	.byte	0xaf
+	.4byte	0xed3
+	.byte	0x28
+	.uleb128 0x15
+	.4byte	.LASF273
+	.byte	0x16
+	.byte	0xb0
+	.4byte	0xee4
+	.byte	0x2c
+	.uleb128 0x15
+	.4byte	.LASF274
+	.byte	0x16
+	.byte	0xb4
+	.4byte	0xed3
+	.byte	0x30
+	.uleb128 0x15
+	.4byte	.LASF275
+	.byte	0x16
+	.byte	0xb5
+	.4byte	0xe99
+	.byte	0x34
+	.uleb128 0x15
+	.4byte	.LASF276
+	.byte	0x16
+	.byte	0xb6
+	.4byte	0x50
+	.byte	0x38
+	.uleb128 0x15
+	.4byte	.LASF277
+	.byte	0x16
+	.byte	0xb7
+	.4byte	0x153
+	.byte	0x3c
+	.byte	0
+	.uleb128 0x19
+	.4byte	0x50
+	.4byte	0xe99
+	.uleb128 0x1a
+	.4byte	0xe99
+	.uleb128 0x1a
+	.4byte	0xce0
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xde8
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xe85
+	.uleb128 0x19
+	.4byte	0x50
+	.4byte	0xebe
+	.uleb128 0x1a
+	.4byte	0xe99
+	.uleb128 0x1a
+	.4byte	0x153
+	.uleb128 0x1a
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xea5
+	.uleb128 0x19
+	.4byte	0x50
+	.4byte	0xed3
+	.uleb128 0x1a
+	.4byte	0xe99
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xec4
+	.uleb128 0x28
+	.4byte	0xee4
+	.uleb128 0x1a
+	.4byte	0xe99
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xed9
+	.uleb128 0x4
+	.4byte	.LASF278
+	.byte	0x16
+	.byte	0xbd
+	.4byte	0xe99
+	.uleb128 0xc
+	.4byte	0x90
+	.4byte	0xf05
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x5
+	.byte	0
+	.uleb128 0xf
+	.4byte	.LASF279
+	.byte	0x16
+	.2byte	0x1fd
+	.4byte	0xdc9
+	.uleb128 0xf
+	.4byte	.LASF280
+	.byte	0x16
+	.2byte	0x1fe
+	.4byte	0xdc9
+	.uleb128 0xf
+	.4byte	.LASF281
+	.byte	0x16
+	.2byte	0x200
+	.4byte	0xdc9
+	.uleb128 0xf
+	.4byte	.LASF282
+	.byte	0x16
+	.2byte	0x205
+	.4byte	0xd6b
+	.uleb128 0xf
+	.4byte	.LASF283
+	.byte	0x16
+	.2byte	0x206
+	.4byte	0xd6b
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0xf51
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x3f
+	.byte	0
+	.uleb128 0xf
+	.4byte	.LASF284
+	.byte	0x16
+	.2byte	0x207
+	.4byte	0xf41
+	.uleb128 0xf
+	.4byte	.LASF285
+	.byte	0x16
+	.2byte	0x209
+	.4byte	0xef5
+	.uleb128 0xf
+	.4byte	.LASF286
+	.byte	0x16
+	.2byte	0x20a
+	.4byte	0xef5
+	.uleb128 0xf
+	.4byte	.LASF287
+	.byte	0x16
+	.2byte	0x20b
+	.4byte	0xdc9
+	.uleb128 0xf
+	.4byte	.LASF288
+	.byte	0x16
+	.2byte	0x20c
+	.4byte	0xdc9
+	.uleb128 0xf
+	.4byte	.LASF289
+	.byte	0x16
+	.2byte	0x20d
+	.4byte	0xde2
+	.uleb128 0xc
+	.4byte	0xde2
+	.4byte	0xfa9
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x3
+	.byte	0
+	.uleb128 0xf
+	.4byte	.LASF290
+	.byte	0x16
+	.2byte	0x20e
+	.4byte	0xf99
+	.uleb128 0xf
+	.4byte	.LASF291
+	.byte	0x16
+	.2byte	0x20f
+	.4byte	0xde2
+	.uleb128 0xf
+	.4byte	.LASF292
+	.byte	0x16
+	.2byte	0x210
+	.4byte	0x50
+	.uleb128 0xc
+	.4byte	0x9a
+	.4byte	0xfdd
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x5
+	.byte	0
+	.uleb128 0x7
+	.4byte	0xfcd
+	.uleb128 0xf
+	.4byte	.LASF293
+	.byte	0x16
+	.2byte	0x211
+	.4byte	0xfdd
+	.uleb128 0xf
+	.4byte	.LASF294
+	.byte	0x16
+	.2byte	0x212
+	.4byte	0xfdd
+	.uleb128 0xf
+	.4byte	.LASF295
+	.byte	0x16
+	.2byte	0x216
+	.4byte	0x117
+	.uleb128 0xf
+	.4byte	.LASF296
+	.byte	0x16
+	.2byte	0x217
+	.4byte	0x117
+	.uleb128 0xf
+	.4byte	.LASF297
+	.byte	0x16
+	.2byte	0x219
+	.4byte	0x50
+	.uleb128 0xf
+	.4byte	.LASF298
+	.byte	0x16
+	.2byte	0x220
+	.4byte	0xd5a
+	.uleb128 0xf
+	.4byte	.LASF299
+	.byte	0x16
+	.2byte	0x222
+	.4byte	0x9f
+	.uleb128 0xf
+	.4byte	.LASF300
+	.byte	0x16
+	.2byte	0x224
+	.4byte	0x9f
+	.uleb128 0x29
+	.4byte	.LASF301
+	.byte	0x4
+	.4byte	0x7b
+	.byte	0x16
+	.2byte	0x286
+	.4byte	0x106c
+	.uleb128 0x11
+	.4byte	.LASF302
+	.byte	0
+	.uleb128 0x11
+	.4byte	.LASF303
+	.byte	0x1
+	.uleb128 0x11
+	.4byte	.LASF304
+	.byte	0x2
+	.uleb128 0x11
+	.4byte	.LASF305
+	.byte	0x3
+	.byte	0
+	.uleb128 0xf
+	.4byte	.LASF306
+	.byte	0x16
+	.2byte	0x28c
+	.4byte	0x1042
+	.uleb128 0xf
+	.4byte	.LASF307
+	.byte	0x17
+	.2byte	0x3ba
+	.4byte	0x122
+	.uleb128 0xf
+	.4byte	.LASF308
+	.byte	0x17
+	.2byte	0x3bb
+	.4byte	0x122
+	.uleb128 0xf
+	.4byte	.LASF309
+	.byte	0x17
+	.2byte	0x3bc
+	.4byte	0x122
+	.uleb128 0x4
+	.4byte	.LASF310
+	.byte	0x18
+	.byte	0x2b
+	.4byte	0x1a5
+	.uleb128 0x4
+	.4byte	.LASF311
+	.byte	0x18
+	.byte	0x2b
+	.4byte	0x1a5
+	.uleb128 0x14
+	.4byte	.LASF312
+	.byte	0x2c
+	.byte	0x19
+	.byte	0x1c
+	.4byte	0x1142
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0x19
+	.byte	0x1d
+	.4byte	0xd7
+	.byte	0
+	.uleb128 0xb
+	.ascii	"os\000"
+	.byte	0x19
+	.byte	0x1e
+	.4byte	0x90
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF262
+	.byte	0x19
+	.byte	0x1f
+	.4byte	0x101
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF313
+	.byte	0x19
+	.byte	0x20
+	.4byte	0x101
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF314
+	.byte	0x19
+	.byte	0x26
+	.4byte	0x101
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF315
+	.byte	0x19
+	.byte	0x28
+	.4byte	0x153
+	.byte	0x14
+	.uleb128 0x15
+	.4byte	.LASF316
+	.byte	0x19
+	.byte	0x29
+	.4byte	0x9f
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF317
+	.byte	0x19
+	.byte	0x2a
+	.4byte	0x9f
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x19
+	.byte	0x2b
+	.4byte	0x9f
+	.byte	0x20
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x19
+	.byte	0x2c
+	.4byte	0x9f
+	.byte	0x24
+	.uleb128 0xb
+	.ascii	"arg\000"
+	.byte	0x19
+	.byte	0x2d
+	.4byte	0x153
+	.byte	0x28
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF319
+	.byte	0x14
+	.byte	0x19
+	.byte	0x39
+	.4byte	0x118b
+	.uleb128 0xb
+	.ascii	"dev\000"
+	.byte	0x19
+	.byte	0x3a
+	.4byte	0x153
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF277
+	.byte	0x19
+	.byte	0x3b
+	.4byte	0x153
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF320
+	.byte	0x19
+	.byte	0x3c
+	.4byte	0x50
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF321
+	.byte	0x19
+	.byte	0x3d
+	.4byte	0xd7
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF322
+	.byte	0x19
+	.byte	0x3e
+	.4byte	0x11af
+	.byte	0x10
+	.byte	0
+	.uleb128 0x19
+	.4byte	0x122
+	.4byte	0x11a9
+	.uleb128 0x1a
+	.4byte	0x11a9
+	.uleb128 0x1a
+	.4byte	0x122
+	.uleb128 0x1a
+	.4byte	0x122
+	.uleb128 0x1a
+	.4byte	0x153
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x1142
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x118b
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x10b2
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x13d
+	.uleb128 0x14
+	.4byte	.LASF323
+	.byte	0x28
+	.byte	0x1a
+	.byte	0x4e
+	.4byte	0x122d
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x4f
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF324
+	.byte	0x1a
+	.byte	0x50
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF325
+	.byte	0x1a
+	.byte	0x51
+	.4byte	0xaa
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF326
+	.byte	0x1a
+	.byte	0x52
+	.4byte	0x9f
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF327
+	.byte	0x1a
+	.byte	0x53
+	.4byte	0x9f
+	.byte	0x14
+	.uleb128 0xb
+	.ascii	"id\000"
+	.byte	0x1a
+	.byte	0x54
+	.4byte	0x9f
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0x55
+	.4byte	0x122d
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x56
+	.4byte	0x9f
+	.byte	0x24
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x9f
+	.4byte	0x123d
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x1
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF329
+	.byte	0x30
+	.byte	0x1a
+	.byte	0x59
+	.4byte	0x129e
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x5a
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF330
+	.byte	0x1a
+	.byte	0x5b
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF58
+	.byte	0x1a
+	.byte	0x5c
+	.4byte	0x9f
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF331
+	.byte	0x1a
+	.byte	0x5d
+	.4byte	0x9f
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF332
+	.byte	0x1a
+	.byte	0x5e
+	.4byte	0x9f
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0x5f
+	.4byte	0x129e
+	.byte	0x14
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x60
+	.4byte	0x9f
+	.byte	0x2c
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x9f
+	.4byte	0x12ae
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x5
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF333
+	.byte	0xb8
+	.byte	0x1a
+	.byte	0x63
+	.4byte	0x1303
+	.uleb128 0x15
+	.4byte	.LASF334
+	.byte	0x1a
+	.byte	0x64
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x65
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF335
+	.byte	0x1a
+	.byte	0x66
+	.4byte	0x1303
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x1a
+	.byte	0x67
+	.4byte	0x9f
+	.byte	0xa8
+	.uleb128 0x15
+	.4byte	.LASF336
+	.byte	0x1a
+	.byte	0x68
+	.4byte	0x122d
+	.byte	0xac
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x69
+	.4byte	0x9f
+	.byte	0xb4
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xaa
+	.4byte	0x1313
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x13
+	.byte	0
+	.uleb128 0xa
+	.byte	0x18
+	.byte	0x1a
+	.byte	0x6e
+	.4byte	0x134c
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0x1a
+	.byte	0x6f
+	.4byte	0xd2a
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF337
+	.byte	0x1a
+	.byte	0x70
+	.4byte	0xaa
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x1a
+	.byte	0x71
+	.4byte	0x9f
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x1a
+	.byte	0x72
+	.4byte	0x9f
+	.byte	0x14
+	.byte	0
+	.uleb128 0xa
+	.byte	0x18
+	.byte	0x1a
+	.byte	0x75
+	.4byte	0x1385
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0x1a
+	.byte	0x76
+	.4byte	0xd2a
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF337
+	.byte	0x1a
+	.byte	0x77
+	.4byte	0xaa
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x1a
+	.byte	0x78
+	.4byte	0x9f
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x1a
+	.byte	0x79
+	.4byte	0x9f
+	.byte	0x14
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF338
+	.byte	0x74
+	.byte	0x1a
+	.byte	0x6c
+	.4byte	0x13da
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x6d
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF339
+	.byte	0x1a
+	.byte	0x73
+	.4byte	0x1313
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF340
+	.byte	0x1a
+	.byte	0x7a
+	.4byte	0x134c
+	.byte	0x1c
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0x7c
+	.4byte	0x13da
+	.byte	0x34
+	.uleb128 0x15
+	.4byte	.LASF341
+	.byte	0x1a
+	.byte	0x7d
+	.4byte	0x9f
+	.byte	0x6c
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x7e
+	.4byte	0x9f
+	.byte	0x70
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xaa
+	.4byte	0x13ea
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x6
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF342
+	.byte	0x20
+	.byte	0x1a
+	.byte	0x81
+	.4byte	0x143f
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x82
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF337
+	.byte	0x1a
+	.byte	0x83
+	.4byte	0xaa
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x1a
+	.byte	0x84
+	.4byte	0x9f
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x1a
+	.byte	0x85
+	.4byte	0x9f
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0x86
+	.4byte	0x122d
+	.byte	0x14
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x87
+	.4byte	0x9f
+	.byte	0x1c
+	.byte	0
+	.uleb128 0x2a
+	.4byte	.LASF343
+	.2byte	0x324
+	.byte	0x1a
+	.byte	0x8a
+	.4byte	0x1498
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x8b
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0xb
+	.ascii	"len\000"
+	.byte	0x1a
+	.byte	0x8c
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF336
+	.byte	0x1a
+	.byte	0x8d
+	.4byte	0x1498
+	.byte	0x8
+	.uleb128 0x1c
+	.4byte	.LASF344
+	.byte	0x1a
+	.byte	0x8e
+	.4byte	0x9f
+	.2byte	0x308
+	.uleb128 0x1c
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0x8f
+	.4byte	0x18e
+	.2byte	0x30c
+	.uleb128 0x1c
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x90
+	.4byte	0x9f
+	.2byte	0x320
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x90
+	.4byte	0x14a9
+	.uleb128 0x1e
+	.4byte	0xcb
+	.2byte	0x2ff
+	.byte	0
+	.uleb128 0xa
+	.byte	0x20
+	.byte	0x1a
+	.byte	0x98
+	.4byte	0x14d6
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0x1a
+	.byte	0x99
+	.4byte	0xd3a
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF77
+	.byte	0x1a
+	.byte	0x9a
+	.4byte	0xaa
+	.byte	0x10
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x1a
+	.byte	0x9b
+	.4byte	0xaa
+	.byte	0x18
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF345
+	.byte	0xe8
+	.byte	0x1a
+	.byte	0x93
+	.4byte	0x152b
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0x94
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF334
+	.byte	0x1a
+	.byte	0x95
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0x96
+	.4byte	0x152b
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF346
+	.byte	0x1a
+	.byte	0x9c
+	.4byte	0x153b
+	.byte	0x18
+	.uleb128 0x15
+	.4byte	.LASF341
+	.byte	0x1a
+	.byte	0x9e
+	.4byte	0x154b
+	.byte	0xd8
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0x9f
+	.4byte	0x9f
+	.byte	0xe4
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x9f
+	.4byte	0x153b
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x3
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x14a9
+	.4byte	0x154b
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x5
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x9f
+	.4byte	0x155b
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x2
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF347
+	.byte	0x28
+	.byte	0x1a
+	.byte	0xa2
+	.4byte	0x15a4
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0xa3
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF74
+	.byte	0x1a
+	.byte	0xa4
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x1a
+	.byte	0xa5
+	.4byte	0x9f
+	.byte	0x8
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0xa6
+	.4byte	0x129e
+	.byte	0xc
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0xa7
+	.4byte	0x9f
+	.byte	0x24
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF348
+	.byte	0x38
+	.byte	0x1a
+	.byte	0xaa
+	.4byte	0x15e1
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0xab
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF349
+	.byte	0x1a
+	.byte	0xac
+	.4byte	0xd4a
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF94
+	.byte	0x1a
+	.byte	0xad
+	.4byte	0x152b
+	.byte	0x24
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0xae
+	.4byte	0x9f
+	.byte	0x34
+	.byte	0
+	.uleb128 0xa
+	.byte	0x8
+	.byte	0x1a
+	.byte	0xb3
+	.4byte	0x1602
+	.uleb128 0x15
+	.4byte	.LASF325
+	.byte	0x1a
+	.byte	0xb4
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x1a
+	.byte	0xb5
+	.4byte	0x9f
+	.byte	0x4
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF350
+	.byte	0x88
+	.byte	0x1a
+	.byte	0xb1
+	.4byte	0x1633
+	.uleb128 0x15
+	.4byte	.LASF130
+	.byte	0x1a
+	.byte	0xb2
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0xb
+	.ascii	"buf\000"
+	.byte	0x1a
+	.byte	0xb6
+	.4byte	0x1633
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF328
+	.byte	0x1a
+	.byte	0xb7
+	.4byte	0x9f
+	.byte	0x84
+	.byte	0
+	.uleb128 0xc
+	.4byte	0x15e1
+	.4byte	0x1643
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0xf
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF351
+	.byte	0xc
+	.byte	0x1a
+	.byte	0xba
+	.4byte	0x1674
+	.uleb128 0x15
+	.4byte	.LASF318
+	.byte	0x1a
+	.byte	0xbb
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF352
+	.byte	0x1a
+	.byte	0xbc
+	.4byte	0x9f
+	.byte	0x4
+	.uleb128 0x15
+	.4byte	.LASF353
+	.byte	0x1a
+	.byte	0xbd
+	.4byte	0x9f
+	.byte	0x8
+	.byte	0
+	.uleb128 0x14
+	.4byte	.LASF354
+	.byte	0x8
+	.byte	0x1a
+	.byte	0xc0
+	.4byte	0x1699
+	.uleb128 0x15
+	.4byte	.LASF78
+	.byte	0x1a
+	.byte	0xc1
+	.4byte	0x9f
+	.byte	0
+	.uleb128 0x15
+	.4byte	.LASF125
+	.byte	0x1a
+	.byte	0xc2
+	.4byte	0x9f
+	.byte	0x4
+	.byte	0
+	.uleb128 0x2b
+	.2byte	0x324
+	.byte	0x1a
+	.byte	0xc8
+	.4byte	0x171c
+	.uleb128 0x13
+	.4byte	.LASF355
+	.byte	0x1a
+	.byte	0xc9
+	.4byte	0x1643
+	.uleb128 0x13
+	.4byte	.LASF356
+	.byte	0x1a
+	.byte	0xca
+	.4byte	0x11c1
+	.uleb128 0x13
+	.4byte	.LASF357
+	.byte	0x1a
+	.byte	0xcb
+	.4byte	0x123d
+	.uleb128 0x13
+	.4byte	.LASF358
+	.byte	0x1a
+	.byte	0xcc
+	.4byte	0x12ae
+	.uleb128 0x13
+	.4byte	.LASF359
+	.byte	0x1a
+	.byte	0xcd
+	.4byte	0x1385
+	.uleb128 0x13
+	.4byte	.LASF360
+	.byte	0x1a
+	.byte	0xce
+	.4byte	0x14d6
+	.uleb128 0x13
+	.4byte	.LASF361
+	.byte	0x1a
+	.byte	0xcf
+	.4byte	0x13ea
+	.uleb128 0x13
+	.4byte	.LASF362
+	.byte	0x1a
+	.byte	0xd0
+	.4byte	0x143f
+	.uleb128 0x2c
+	.ascii	"soc\000"
+	.byte	0x1a
+	.byte	0xd1
+	.4byte	0x155b
+	.uleb128 0x13
+	.4byte	.LASF363
+	.byte	0x1a
+	.byte	0xd2
+	.4byte	0x15a4
+	.uleb128 0x13
+	.4byte	.LASF364
+	.byte	0x1a
+	.byte	0xd3
+	.4byte	0x1602
+	.byte	0
+	.uleb128 0x1f
+	.ascii	"tag\000"
+	.2byte	0x32c
+	.byte	0x1a
+	.byte	0xc6
+	.4byte	0x1740
+	.uleb128 0xb
+	.ascii	"hdr\000"
+	.byte	0x1a
+	.byte	0xc7
+	.4byte	0x1674
+	.byte	0
+	.uleb128 0xb
+	.ascii	"u\000"
+	.byte	0x1a
+	.byte	0xd4
+	.4byte	0x1699
+	.byte	0x8
+	.byte	0
+	.uleb128 0x2d
+	.4byte	.LASF383
+	.byte	0x1
+	.2byte	0x34c
+	.4byte	0x50
+	.4byte	.LFB235
+	.4byte	.LFE235-.LFB235
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2035
+	.uleb128 0x2e
+	.4byte	.LASF365
+	.byte	0x1
+	.2byte	0x34c
+	.4byte	0x11b5
+	.4byte	.LLST67
+	.uleb128 0x2e
+	.4byte	.LASF366
+	.byte	0x1
+	.2byte	0x34d
+	.4byte	0x11a9
+	.4byte	.LLST68
+	.uleb128 0x2e
+	.4byte	.LASF367
+	.byte	0x1
+	.2byte	0x34d
+	.4byte	0x122
+	.4byte	.LLST69
+	.uleb128 0x2f
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x34d
+	.4byte	0x153
+	.4byte	.LLST70
+	.uleb128 0x30
+	.4byte	.LASF368
+	.byte	0x1
+	.2byte	0x34f
+	.4byte	0x122
+	.4byte	.LLST71
+	.uleb128 0x31
+	.ascii	"ret\000"
+	.byte	0x1
+	.2byte	0x350
+	.4byte	0x50
+	.4byte	.LLST72
+	.uleb128 0x32
+	.ascii	"i\000"
+	.byte	0x1
+	.2byte	0x351
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x33
+	.4byte	0x2035
+	.4byte	.LBB84
+	.4byte	.Ldebug_ranges0+0x58
+	.byte	0x1
+	.2byte	0x366
+	.4byte	0x1d8f
+	.uleb128 0x34
+	.4byte	0x206a
+	.4byte	.LLST73
+	.uleb128 0x34
+	.4byte	0x205e
+	.4byte	.LLST74
+	.uleb128 0x34
+	.4byte	0x2052
+	.4byte	.LLST75
+	.uleb128 0x34
+	.4byte	0x2046
+	.4byte	.LLST76
+	.uleb128 0x35
+	.4byte	.Ldebug_ranges0+0x58
+	.uleb128 0x36
+	.4byte	0x2076
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -112
+	.uleb128 0x36
+	.4byte	0x2082
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -180
+	.uleb128 0x36
+	.4byte	0x208e
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -176
+	.uleb128 0x37
+	.4byte	0x209a
+	.4byte	.LLST77
+	.uleb128 0x37
+	.4byte	0x20a6
+	.4byte	.LLST78
+	.uleb128 0x37
+	.4byte	0x20b2
+	.4byte	.LLST79
+	.uleb128 0x37
+	.4byte	0x20be
+	.4byte	.LLST80
+	.uleb128 0x37
+	.4byte	0x20ca
+	.4byte	.LLST81
+	.uleb128 0x37
+	.4byte	0x20d6
+	.4byte	.LLST82
+	.uleb128 0x37
+	.4byte	0x20ed
+	.4byte	.LLST83
+	.uleb128 0x36
+	.4byte	0x20f9
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -172
+	.uleb128 0x36
+	.4byte	0x2105
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -168
+	.uleb128 0x38
+	.4byte	0x2111
+	.uleb128 0x39
+	.4byte	0x20e0
+	.uleb128 0x3a
+	.4byte	.LBB86
+	.4byte	.LBE86-.LBB86
+	.4byte	0x1aad
+	.uleb128 0x36
+	.4byte	0x211a
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -181
+	.uleb128 0x3b
+	.4byte	0x23bc
+	.4byte	.LBB87
+	.4byte	.LBE87-.LBB87
+	.byte	0x1
+	.2byte	0x31f
+	.4byte	0x18db
+	.uleb128 0x34
+	.4byte	0x23e5
+	.4byte	.LLST84
+	.uleb128 0x34
+	.4byte	0x23d9
+	.4byte	.LLST85
+	.uleb128 0x34
+	.4byte	0x23cd
+	.4byte	.LLST86
+	.uleb128 0x3c
+	.4byte	.LVL195
+	.4byte	0x2fc5
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 107
+	.byte	0
+	.byte	0
+	.uleb128 0x3b
+	.4byte	0x23f1
+	.4byte	.LBB89
+	.4byte	.LBE89-.LBB89
+	.byte	0x1
+	.2byte	0x33c
+	.4byte	0x1a24
+	.uleb128 0x34
+	.4byte	0x2432
+	.4byte	.LLST87
+	.uleb128 0x34
+	.4byte	0x2426
+	.4byte	.LLST88
+	.uleb128 0x34
+	.4byte	0x241a
+	.4byte	.LLST89
+	.uleb128 0x3e
+	.4byte	0x240e
+	.uleb128 0x34
+	.4byte	0x2402
+	.4byte	.LLST90
+	.uleb128 0x3f
+	.4byte	.LBB90
+	.4byte	.LBE90-.LBB90
+	.uleb128 0x37
+	.4byte	0x243e
+	.4byte	.LLST91
+	.uleb128 0x36
+	.4byte	0x244a
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -156
+	.uleb128 0x37
+	.4byte	0x2456
+	.4byte	.LLST92
+	.uleb128 0x40
+	.4byte	.LVL200
+	.4byte	0x2e47
+	.4byte	0x1966
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC27
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 132
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL202
+	.4byte	0x2ace
+	.4byte	0x1991
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC27
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL205
+	.4byte	0x2fd1
+	.4byte	0x19b9
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC28
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL206
+	.4byte	0x2fd1
+	.4byte	0x19e1
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC29
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL207
+	.4byte	0x2fdd
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 92
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 88
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 84
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 80
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 8
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 76
+	.byte	0x6
+	.byte	0
+	.byte	0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL191
+	.4byte	0x2ace
+	.4byte	0x1a4f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC27
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL196
+	.4byte	0x2595
+	.4byte	0x1a7f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 96
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL198
+	.4byte	0x2463
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 96
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.byte	0
+	.byte	0
+	.uleb128 0x3b
+	.4byte	0x23bc
+	.4byte	.LBB91
+	.4byte	.LBE91-.LBB91
+	.byte	0x1
+	.2byte	0x306
+	.4byte	0x1af9
+	.uleb128 0x34
+	.4byte	0x23e5
+	.4byte	.LLST93
+	.uleb128 0x34
+	.4byte	0x23d9
+	.4byte	.LLST94
+	.uleb128 0x34
+	.4byte	0x23cd
+	.4byte	.LLST95
+	.uleb128 0x3c
+	.4byte	.LVL215
+	.4byte	0x2fc5
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 4
+	.byte	0
+	.byte	0
+	.uleb128 0x41
+	.4byte	.LVL144
+	.4byte	0x2fe8
+	.uleb128 0x40
+	.4byte	.LVL147
+	.4byte	0x228f
+	.4byte	0x1b2b
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 96
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 112
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL149
+	.4byte	0x2ff3
+	.4byte	0x1b48
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC17
+	.byte	0
+	.uleb128 0x41
+	.4byte	.LVL150
+	.4byte	0x2fff
+	.uleb128 0x40
+	.4byte	.LVL151
+	.4byte	0x300b
+	.4byte	0x1b6a
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL155
+	.4byte	0x2d9d
+	.4byte	0x1b7e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL158
+	.4byte	0x2fe8
+	.4byte	0x1b9d
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC19
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL162
+	.4byte	0x2fe8
+	.4byte	0x1bb4
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC20
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL163
+	.4byte	0x2c24
+	.4byte	0x1be0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x6
+	.byte	0x11
+	.sleb128 -237076478
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 116
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 120
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL165
+	.4byte	0x2fe8
+	.4byte	0x1bfd
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC21
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL168
+	.4byte	0x2fe8
+	.4byte	0x1c14
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC22
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL171
+	.4byte	0x2fe8
+	.4byte	0x1c2b
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC23
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL173
+	.4byte	0x2ace
+	.4byte	0x1c53
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL175
+	.4byte	0x2595
+	.4byte	0x1c84
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 96
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 176
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL177
+	.4byte	0x3017
+	.4byte	0x1ca5
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x3
+	.byte	0x7d
+	.sleb128 108
+	.byte	0
+	.uleb128 0x41
+	.4byte	.LVL179
+	.4byte	0x2384
+	.uleb128 0x40
+	.4byte	.LVL181
+	.4byte	0x2fe8
+	.4byte	0x1cc5
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC25
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL184
+	.4byte	0x2ace
+	.4byte	0x1cef
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC26
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL186
+	.4byte	0x2ace
+	.4byte	0x1d19
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC27
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL189
+	.4byte	0x3023
+	.4byte	0x1d30
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0xc
+	.4byte	0x54410057
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL211
+	.4byte	0x2595
+	.4byte	0x1d60
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 96
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL216
+	.4byte	0x2463
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 96
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x4
+	.byte	0x7d
+	.sleb128 100
+	.byte	0x6
+	.byte	0
+	.byte	0
+	.byte	0
+	.uleb128 0x33
+	.4byte	0x2143
+	.4byte	.LBB100
+	.4byte	.Ldebug_ranges0+0x88
+	.byte	0x1
+	.2byte	0x36a
+	.4byte	0x201b
+	.uleb128 0x34
+	.4byte	0x2160
+	.4byte	.LLST96
+	.uleb128 0x34
+	.4byte	0x2154
+	.4byte	.LLST97
+	.uleb128 0x35
+	.4byte	.Ldebug_ranges0+0x88
+	.uleb128 0x36
+	.4byte	0x216c
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -168
+	.uleb128 0x36
+	.4byte	0x2178
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -156
+	.uleb128 0x42
+	.4byte	0x2184
+	.4byte	0x2fb2
+	.4byte	.LLST99
+	.uleb128 0x37
+	.4byte	0x2190
+	.4byte	.LLST100
+	.uleb128 0x36
+	.4byte	0x219c
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -172
+	.uleb128 0x37
+	.4byte	0x21a8
+	.4byte	.LLST101
+	.uleb128 0x37
+	.4byte	0x21b4
+	.4byte	.LLST102
+	.uleb128 0x37
+	.4byte	0x21c0
+	.4byte	.LLST103
+	.uleb128 0x37
+	.4byte	0x21cc
+	.4byte	.LLST104
+	.uleb128 0x37
+	.4byte	0x21d6
+	.4byte	.LLST105
+	.uleb128 0x37
+	.4byte	0x21e2
+	.4byte	.LLST106
+	.uleb128 0x36
+	.4byte	0x21ee
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -112
+	.uleb128 0x37
+	.4byte	0x2207
+	.4byte	.LLST107
+	.uleb128 0x39
+	.4byte	0x21fa
+	.uleb128 0x43
+	.4byte	.Ldebug_ranges0+0xa0
+	.4byte	0x1eff
+	.uleb128 0x39
+	.4byte	0x2214
+	.uleb128 0x40
+	.4byte	.LVL253
+	.4byte	0x2ace
+	.4byte	0x1e6d
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x77
+	.sleb128 80
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL255
+	.4byte	0x2595
+	.4byte	0x1e97
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x77
+	.sleb128 84
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x3
+	.byte	0x77
+	.sleb128 116
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL257
+	.4byte	0x302e
+	.4byte	0x1eb4
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL258
+	.4byte	0x2d74
+	.4byte	0x1ec8
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL259
+	.4byte	0x2c99
+	.4byte	0x1edc
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.byte	0
+	.uleb128 0x41
+	.4byte	.LVL260
+	.4byte	0x2c76
+	.uleb128 0x3c
+	.4byte	.LVL264
+	.4byte	0x302e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC1
+	.byte	0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL224
+	.4byte	0x2256
+	.4byte	0x1f19
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL226
+	.4byte	0x3039
+	.4byte	0x1f2e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x3
+	.byte	0x77
+	.sleb128 160
+	.byte	0
+	.uleb128 0x41
+	.4byte	.LVL227
+	.4byte	0x2fe8
+	.uleb128 0x44
+	.4byte	.LVL233
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.4byte	0x1f5d
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x77
+	.sleb128 84
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x1
+	.byte	0x31
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL236
+	.4byte	0x228f
+	.4byte	0x1f86
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x7b
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x77
+	.sleb128 84
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x3
+	.byte	0x77
+	.sleb128 100
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL238
+	.4byte	0x300b
+	.4byte	0x1f9f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL240
+	.4byte	0x2fe8
+	.4byte	0x1fb6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC18
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL243
+	.4byte	0x2d9d
+	.4byte	0x1fca
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL246
+	.4byte	0x2fe8
+	.4byte	0x1fe9
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC19
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x4
+	.byte	0x77
+	.sleb128 84
+	.byte	0x6
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL249
+	.4byte	0x2fe8
+	.4byte	0x2000
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC20
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL250
+	.4byte	0x2ff3
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC17
+	.byte	0
+	.byte	0
+	.byte	0
+	.uleb128 0x45
+	.4byte	0xd2
+	.4byte	.LLST98
+	.uleb128 0x3c
+	.4byte	.LVL146
+	.4byte	0x2ce6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.byte	0
+	.byte	0
+	.uleb128 0x46
+	.4byte	.LASF378
+	.byte	0x1
+	.2byte	0x26b
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2128
+	.uleb128 0x47
+	.4byte	.LASF365
+	.byte	0x1
+	.2byte	0x26b
+	.4byte	0x11b5
+	.uleb128 0x47
+	.4byte	.LASF366
+	.byte	0x1
+	.2byte	0x26c
+	.4byte	0x11a9
+	.uleb128 0x47
+	.4byte	.LASF367
+	.byte	0x1
+	.2byte	0x26d
+	.4byte	0x122
+	.uleb128 0x47
+	.4byte	.LASF369
+	.byte	0x1
+	.2byte	0x26d
+	.4byte	0x153
+	.uleb128 0x48
+	.4byte	.LASF221
+	.byte	0x1
+	.2byte	0x26f
+	.4byte	0x10b2
+	.uleb128 0x48
+	.4byte	.LASF370
+	.byte	0x1
+	.2byte	0x270
+	.4byte	0xfb
+	.uleb128 0x48
+	.4byte	.LASF371
+	.byte	0x1
+	.2byte	0x271
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF256
+	.byte	0x1
+	.2byte	0x272
+	.4byte	0x50
+	.uleb128 0x49
+	.ascii	"ret\000"
+	.byte	0x1
+	.2byte	0x272
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF276
+	.byte	0x1
+	.2byte	0x273
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF372
+	.byte	0x1
+	.2byte	0x274
+	.4byte	0x50
+	.uleb128 0x49
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x275
+	.4byte	0x153
+	.uleb128 0x49
+	.ascii	"t\000"
+	.byte	0x1
+	.2byte	0x276
+	.4byte	0x2128
+	.uleb128 0x4a
+	.4byte	.LASF373
+	.4byte	0x213e
+	.4byte	.LASF378
+	.uleb128 0x48
+	.4byte	.LASF374
+	.byte	0x1
+	.2byte	0x28e
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF375
+	.byte	0x1
+	.2byte	0x29e
+	.4byte	0x13d
+	.uleb128 0x48
+	.4byte	.LASF376
+	.byte	0x1
+	.2byte	0x29e
+	.4byte	0x13d
+	.uleb128 0x4b
+	.4byte	.LASF463
+	.byte	0x1
+	.2byte	0x315
+	.uleb128 0x4c
+	.uleb128 0x48
+	.4byte	.LASF377
+	.byte	0x1
+	.2byte	0x319
+	.4byte	0x12d
+	.byte	0
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x171c
+	.uleb128 0xc
+	.4byte	0xe4
+	.4byte	0x213e
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x1c
+	.byte	0
+	.uleb128 0x7
+	.4byte	0x212e
+	.uleb128 0x46
+	.4byte	.LASF379
+	.byte	0x1
+	.2byte	0x1e6
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2222
+	.uleb128 0x47
+	.4byte	.LASF365
+	.byte	0x1
+	.2byte	0x1e6
+	.4byte	0x11b5
+	.uleb128 0x47
+	.4byte	.LASF366
+	.byte	0x1
+	.2byte	0x1e7
+	.4byte	0x11a9
+	.uleb128 0x48
+	.4byte	.LASF256
+	.byte	0x1
+	.2byte	0x1f2
+	.4byte	0x2222
+	.uleb128 0x48
+	.4byte	.LASF221
+	.byte	0x1
+	.2byte	0x1f3
+	.4byte	0x10b2
+	.uleb128 0x48
+	.4byte	.LASF369
+	.byte	0x1
+	.2byte	0x1f4
+	.4byte	0x2232
+	.uleb128 0x48
+	.4byte	.LASF380
+	.byte	0x1
+	.2byte	0x1f5
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF371
+	.byte	0x1
+	.2byte	0x1f6
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF367
+	.byte	0x1
+	.2byte	0x1f7
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF372
+	.byte	0x1
+	.2byte	0x1f8
+	.4byte	0x50
+	.uleb128 0x49
+	.ascii	"ret\000"
+	.byte	0x1
+	.2byte	0x1f8
+	.4byte	0x50
+	.uleb128 0x49
+	.ascii	"i\000"
+	.byte	0x1
+	.2byte	0x1f8
+	.4byte	0x50
+	.uleb128 0x49
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x1f9
+	.4byte	0x153
+	.uleb128 0x48
+	.4byte	.LASF381
+	.byte	0x1
+	.2byte	0x1ff
+	.4byte	0xd7
+	.uleb128 0x48
+	.4byte	.LASF382
+	.byte	0x1
+	.2byte	0x200
+	.4byte	0x494
+	.uleb128 0x4a
+	.4byte	.LASF373
+	.4byte	0x2251
+	.4byte	.LASF379
+	.uleb128 0x48
+	.4byte	.LASF374
+	.byte	0x1
+	.2byte	0x21d
+	.4byte	0x50
+	.uleb128 0x4c
+	.uleb128 0x48
+	.4byte	.LASF370
+	.byte	0x1
+	.2byte	0x237
+	.4byte	0x4ba
+	.byte	0
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xd7
+	.4byte	0x2232
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x2
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0x2241
+	.uleb128 0x4d
+	.4byte	0xcb
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xe4
+	.4byte	0x2251
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x13
+	.byte	0
+	.uleb128 0x7
+	.4byte	0x2241
+	.uleb128 0x2d
+	.4byte	.LASF384
+	.byte	0x1
+	.2byte	0x1df
+	.4byte	0xd7
+	.4byte	.LFB232
+	.4byte	.LFE232-.LFB232
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x228f
+	.uleb128 0x2f
+	.ascii	"spl\000"
+	.byte	0x1
+	.2byte	0x1df
+	.4byte	0x11b5
+	.4byte	.LLST66
+	.uleb128 0x4e
+	.4byte	.LASF366
+	.byte	0x1
+	.2byte	0x1e0
+	.4byte	0x11a9
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0
+	.uleb128 0x4f
+	.4byte	.LASF393
+	.byte	0x1
+	.2byte	0x1ad
+	.4byte	0x153
+	.4byte	.LFB231
+	.4byte	.LFE231-.LFB231
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x237e
+	.uleb128 0x2e
+	.4byte	.LASF366
+	.byte	0x1
+	.2byte	0x1ad
+	.4byte	0x11a9
+	.4byte	.LLST47
+	.uleb128 0x2e
+	.4byte	.LASF367
+	.byte	0x1
+	.2byte	0x1ae
+	.4byte	0x122
+	.4byte	.LLST48
+	.uleb128 0x2e
+	.4byte	.LASF369
+	.byte	0x1
+	.2byte	0x1ae
+	.4byte	0x153
+	.4byte	.LLST49
+	.uleb128 0x2e
+	.4byte	.LASF371
+	.byte	0x1
+	.2byte	0x1af
+	.4byte	0x237e
+	.4byte	.LLST50
+	.uleb128 0x50
+	.4byte	.LASF385
+	.byte	0x1
+	.2byte	0x1b1
+	.4byte	0x50
+	.byte	0x3f
+	.uleb128 0x30
+	.4byte	.LASF334
+	.byte	0x1
+	.2byte	0x1b2
+	.4byte	0x122
+	.4byte	.LLST51
+	.uleb128 0x30
+	.4byte	.LASF78
+	.byte	0x1
+	.2byte	0x1b3
+	.4byte	0x122
+	.4byte	.LLST52
+	.uleb128 0x48
+	.4byte	.LASF386
+	.byte	0x1
+	.2byte	0x1b4
+	.4byte	0x50
+	.uleb128 0x31
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x1b5
+	.4byte	0x153
+	.4byte	.LLST53
+	.uleb128 0x3b
+	.4byte	0x2a4e
+	.4byte	.LBB62
+	.4byte	.LBE62-.LBB62
+	.byte	0x1
+	.2byte	0x1d3
+	.4byte	0x2362
+	.uleb128 0x34
+	.4byte	0x2a74
+	.4byte	.LLST54
+	.uleb128 0x34
+	.4byte	0x2a69
+	.4byte	.LLST55
+	.uleb128 0x34
+	.4byte	0x2a5e
+	.4byte	.LLST56
+	.byte	0
+	.uleb128 0x51
+	.4byte	.LVL115
+	.uleb128 0x2
+	.byte	0x77
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0x50
+	.uleb128 0x2d
+	.4byte	.LASF387
+	.byte	0x1
+	.2byte	0x1a8
+	.4byte	0x50
+	.4byte	.LFB230
+	.4byte	.LFE230-.LFB230
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x23bc
+	.uleb128 0x2f
+	.ascii	"id\000"
+	.byte	0x1
+	.2byte	0x1a8
+	.4byte	0xfb
+	.4byte	.LLST65
+	.uleb128 0x4e
+	.4byte	.LASF313
+	.byte	0x1
+	.2byte	0x1a8
+	.4byte	0x101
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0
+	.uleb128 0x46
+	.4byte	.LASF388
+	.byte	0x1
+	.2byte	0x19f
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x23f1
+	.uleb128 0x52
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x19f
+	.4byte	0x3be
+	.uleb128 0x47
+	.4byte	.LASF389
+	.byte	0x1
+	.2byte	0x19f
+	.4byte	0x50
+	.uleb128 0x52
+	.ascii	"os\000"
+	.byte	0x1
+	.2byte	0x19f
+	.4byte	0xd24
+	.byte	0
+	.uleb128 0x46
+	.4byte	.LASF390
+	.byte	0x1
+	.2byte	0x188
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2463
+	.uleb128 0x52
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x188
+	.4byte	0x3be
+	.uleb128 0x47
+	.4byte	.LASF256
+	.byte	0x1
+	.2byte	0x188
+	.4byte	0x50
+	.uleb128 0x47
+	.4byte	.LASF276
+	.byte	0x1
+	.2byte	0x188
+	.4byte	0x50
+	.uleb128 0x47
+	.4byte	.LASF391
+	.byte	0x1
+	.2byte	0x189
+	.4byte	0x153
+	.uleb128 0x47
+	.4byte	.LASF392
+	.byte	0x1
+	.2byte	0x189
+	.4byte	0x11b5
+	.uleb128 0x49
+	.ascii	"ret\000"
+	.byte	0x1
+	.2byte	0x18b
+	.4byte	0x50
+	.uleb128 0x48
+	.4byte	.LASF74
+	.byte	0x1
+	.2byte	0x18d
+	.4byte	0xfb
+	.uleb128 0x48
+	.4byte	.LASF372
+	.byte	0x1
+	.2byte	0x18e
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x53
+	.4byte	.LASF394
+	.byte	0x1
+	.2byte	0x165
+	.4byte	0x50
+	.4byte	.LFB227
+	.4byte	.LFE227-.LFB227
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2580
+	.uleb128 0x2e
+	.4byte	.LASF365
+	.byte	0x1
+	.2byte	0x165
+	.4byte	0x11b5
+	.4byte	.LLST39
+	.uleb128 0x2e
+	.4byte	.LASF366
+	.byte	0x1
+	.2byte	0x166
+	.4byte	0x11a9
+	.4byte	.LLST40
+	.uleb128 0x2e
+	.4byte	.LASF367
+	.byte	0x1
+	.2byte	0x166
+	.4byte	0x122
+	.4byte	.LLST41
+	.uleb128 0x2f
+	.ascii	"fit\000"
+	.byte	0x1
+	.2byte	0x167
+	.4byte	0x153
+	.4byte	.LLST42
+	.uleb128 0x2e
+	.4byte	.LASF256
+	.byte	0x1
+	.2byte	0x167
+	.4byte	0x50
+	.4byte	.LLST43
+	.uleb128 0x2e
+	.4byte	.LASF371
+	.byte	0x1
+	.2byte	0x167
+	.4byte	0x122
+	.4byte	.LLST44
+	.uleb128 0x54
+	.4byte	.LASF221
+	.byte	0x1
+	.2byte	0x169
+	.4byte	0x10b2
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -68
+	.uleb128 0x30
+	.4byte	.LASF372
+	.byte	0x1
+	.2byte	0x16a
+	.4byte	0x50
+	.4byte	.LLST45
+	.uleb128 0x31
+	.ascii	"ret\000"
+	.byte	0x1
+	.2byte	0x16a
+	.4byte	0x50
+	.4byte	.LLST46
+	.uleb128 0x55
+	.4byte	.LASF373
+	.4byte	0x2590
+	.uleb128 0x40
+	.4byte	.LVL99
+	.4byte	0x2ace
+	.4byte	0x253f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 0
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL101
+	.4byte	0x2595
+	.4byte	0x256e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x77
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 4
+	.byte	0x6
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x3
+	.byte	0x91
+	.sleb128 -68
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL103
+	.4byte	0x3044
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x3
+	.byte	0xa
+	.2byte	0x2000
+	.byte	0
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xe4
+	.4byte	0x2590
+	.uleb128 0xd
+	.4byte	0xcb
+	.byte	0x12
+	.byte	0
+	.uleb128 0x7
+	.4byte	0x2580
+	.uleb128 0x56
+	.4byte	.LASF395
+	.byte	0x1
+	.byte	0xd4
+	.4byte	0x50
+	.4byte	.LFB226
+	.4byte	.LFE226-.LFB226
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2a4e
+	.uleb128 0x57
+	.4byte	.LASF366
+	.byte	0x1
+	.byte	0xd4
+	.4byte	0x11a9
+	.4byte	.LLST15
+	.uleb128 0x57
+	.4byte	.LASF367
+	.byte	0x1
+	.byte	0xd4
+	.4byte	0x122
+	.4byte	.LLST16
+	.uleb128 0x58
+	.ascii	"fit\000"
+	.byte	0x1
+	.byte	0xd5
+	.4byte	0x153
+	.4byte	.LLST17
+	.uleb128 0x57
+	.4byte	.LASF371
+	.byte	0x1
+	.byte	0xd5
+	.4byte	0x122
+	.4byte	.LLST18
+	.uleb128 0x57
+	.4byte	.LASF372
+	.byte	0x1
+	.byte	0xd5
+	.4byte	0x50
+	.4byte	.LLST19
+	.uleb128 0x57
+	.4byte	.LASF221
+	.byte	0x1
+	.byte	0xd6
+	.4byte	0x11b5
+	.4byte	.LLST20
+	.uleb128 0x59
+	.4byte	.LASF396
+	.byte	0x1
+	.byte	0xd8
+	.4byte	0x50
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -60
+	.uleb128 0x59
+	.4byte	.LASF397
+	.byte	0x1
+	.byte	0xd9
+	.4byte	0x10c
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -56
+	.uleb128 0x5a
+	.ascii	"len\000"
+	.byte	0x1
+	.byte	0xda
+	.4byte	0x50
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -52
+	.uleb128 0x5b
+	.4byte	.LASF78
+	.byte	0x1
+	.byte	0xdb
+	.4byte	0x122
+	.uleb128 0x59
+	.4byte	.LASF398
+	.byte	0x1
+	.byte	0xdc
+	.4byte	0x122
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -48
+	.uleb128 0x59
+	.4byte	.LASF262
+	.byte	0x1
+	.byte	0xdc
+	.4byte	0x122
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -44
+	.uleb128 0x5c
+	.4byte	.LASF399
+	.byte	0x1
+	.byte	0xdc
+	.4byte	0x122
+	.4byte	.LLST21
+	.uleb128 0x5a
+	.ascii	"src\000"
+	.byte	0x1
+	.byte	0xdd
+	.4byte	0x153
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -40
+	.uleb128 0x5c
+	.4byte	.LASF400
+	.byte	0x1
+	.byte	0xde
+	.4byte	0x122
+	.4byte	.LLST22
+	.uleb128 0x5b
+	.4byte	.LASF401
+	.byte	0x1
+	.byte	0xdf
+	.4byte	0x50
+	.uleb128 0x5d
+	.4byte	.LASF385
+	.byte	0x1
+	.byte	0xe0
+	.4byte	0x50
+	.byte	0x3f
+	.uleb128 0x59
+	.4byte	.LASF402
+	.byte	0x1
+	.byte	0xe1
+	.4byte	0x12d
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -61
+	.uleb128 0x5c
+	.4byte	.LASF62
+	.byte	0x1
+	.byte	0xe1
+	.4byte	0x12d
+	.4byte	.LLST23
+	.uleb128 0x59
+	.4byte	.LASF336
+	.byte	0x1
+	.byte	0xe2
+	.4byte	0x3be
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -36
+	.uleb128 0x5c
+	.4byte	.LASF403
+	.byte	0x1
+	.byte	0xe3
+	.4byte	0x19e
+	.4byte	.LLST24
+	.uleb128 0x5c
+	.4byte	.LASF404
+	.byte	0x1
+	.byte	0xe4
+	.4byte	0x19e
+	.4byte	.LLST25
+	.uleb128 0x5c
+	.4byte	.LASF370
+	.byte	0x1
+	.byte	0xe5
+	.4byte	0x4ba
+	.4byte	.LLST26
+	.uleb128 0x5e
+	.ascii	"out\000"
+	.byte	0x1
+	.2byte	0x15b
+	.4byte	.L31
+	.uleb128 0x33
+	.4byte	0x2a80
+	.4byte	.LBB36
+	.4byte	.Ldebug_ranges0+0
+	.byte	0x1
+	.2byte	0x114
+	.4byte	0x2727
+	.uleb128 0x34
+	.4byte	0x2a9b
+	.4byte	.LLST27
+	.uleb128 0x34
+	.4byte	0x2a90
+	.4byte	.LLST28
+	.byte	0
+	.uleb128 0x3b
+	.4byte	0x2a4e
+	.4byte	.LBB41
+	.4byte	.LBE41-.LBB41
+	.byte	0x1
+	.2byte	0x115
+	.4byte	0x2753
+	.uleb128 0x3e
+	.4byte	0x2a74
+	.uleb128 0x34
+	.4byte	0x2a69
+	.4byte	.LLST29
+	.uleb128 0x34
+	.4byte	0x2a5e
+	.4byte	.LLST30
+	.byte	0
+	.uleb128 0x33
+	.4byte	0x2aa7
+	.4byte	.LBB43
+	.4byte	.Ldebug_ranges0+0x20
+	.byte	0x1
+	.2byte	0x11e
+	.4byte	0x277a
+	.uleb128 0x34
+	.4byte	0x2ac2
+	.4byte	.LLST31
+	.uleb128 0x34
+	.4byte	0x2ab7
+	.4byte	.LLST32
+	.byte	0
+	.uleb128 0x33
+	.4byte	0x2dd3
+	.4byte	.LBB48
+	.4byte	.Ldebug_ranges0+0x38
+	.byte	0x1
+	.2byte	0x137
+	.4byte	0x27c5
+	.uleb128 0x34
+	.4byte	0x2dfc
+	.4byte	.LLST33
+	.uleb128 0x34
+	.4byte	0x2df0
+	.4byte	.LLST34
+	.uleb128 0x34
+	.4byte	0x2de4
+	.4byte	.LLST35
+	.uleb128 0x3c
+	.4byte	.LVL77
+	.4byte	0x304f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.byte	0
+	.uleb128 0x3b
+	.4byte	0x2dd3
+	.4byte	.LBB54
+	.4byte	.LBE54-.LBB54
+	.byte	0x1
+	.2byte	0x13c
+	.4byte	0x27fe
+	.uleb128 0x34
+	.4byte	0x2dfc
+	.4byte	.LLST36
+	.uleb128 0x34
+	.4byte	0x2df0
+	.4byte	.LLST37
+	.uleb128 0x34
+	.4byte	0x2de4
+	.4byte	.LLST38
+	.uleb128 0x41
+	.4byte	.LVL86
+	.4byte	0x304f
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL45
+	.4byte	0x305b
+	.4byte	0x281e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -61
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL46
+	.4byte	0x3067
+	.4byte	0x283e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -44
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL47
+	.4byte	0x3073
+	.4byte	0x285e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -48
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL48
+	.4byte	0x307f
+	.4byte	0x287e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -60
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL49
+	.4byte	0x308b
+	.4byte	0x289e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -60
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL52
+	.4byte	0x3097
+	.4byte	0x28be
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -52
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL54
+	.4byte	0x30a3
+	.4byte	0x28d2
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x8
+	.byte	0x40
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL61
+	.4byte	0x30af
+	.4byte	0x28ec
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.byte	0
+	.uleb128 0x5f
+	.4byte	.LVL64
+	.4byte	0x290a
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x4
+	.byte	0x91
+	.sleb128 -80
+	.byte	0x6
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL65
+	.4byte	0x2fe8
+	.4byte	0x2921
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC7
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL66
+	.4byte	0x30bb
+	.4byte	0x2944
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC13
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL79
+	.4byte	0x2fd1
+	.4byte	0x296c
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC9
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL80
+	.4byte	0x2fe8
+	.4byte	0x298f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC10
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x77
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x7a
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL81
+	.4byte	0x30c7
+	.4byte	0x29a9
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL82
+	.4byte	0x30d3
+	.4byte	0x29dd
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -44
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -40
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 0
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -56
+	.uleb128 0x3d
+	.uleb128 0x2
+	.byte	0x7d
+	.sleb128 4
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL83
+	.4byte	0x30df
+	.4byte	0x29f4
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC12
+	.byte	0
+	.uleb128 0x41
+	.4byte	.LVL84
+	.4byte	0x30ea
+	.uleb128 0x40
+	.4byte	.LVL87
+	.4byte	0x2fe8
+	.4byte	0x2a14
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC11
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL91
+	.4byte	0x30f6
+	.4byte	0x2a3a
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -36
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -56
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL92
+	.4byte	0x30df
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC8
+	.byte	0
+	.byte	0
+	.uleb128 0x60
+	.4byte	.LASF405
+	.byte	0x1
+	.byte	0xb8
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2a80
+	.uleb128 0x61
+	.4byte	.LASF366
+	.byte	0x1
+	.byte	0xb8
+	.4byte	0x11a9
+	.uleb128 0x61
+	.4byte	.LASF406
+	.byte	0x1
+	.byte	0xb8
+	.4byte	0x50
+	.uleb128 0x61
+	.4byte	.LASF396
+	.byte	0x1
+	.byte	0xb9
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x60
+	.4byte	.LASF407
+	.byte	0x1
+	.byte	0xaa
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2aa7
+	.uleb128 0x61
+	.4byte	.LASF366
+	.byte	0x1
+	.byte	0xaa
+	.4byte	0x11a9
+	.uleb128 0x61
+	.4byte	.LASF396
+	.byte	0x1
+	.byte	0xaa
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x60
+	.4byte	.LASF408
+	.byte	0x1
+	.byte	0x9d
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2ace
+	.uleb128 0x61
+	.4byte	.LASF366
+	.byte	0x1
+	.byte	0x9d
+	.4byte	0x11a9
+	.uleb128 0x61
+	.4byte	.LASF396
+	.byte	0x1
+	.byte	0x9d
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x62
+	.4byte	.LASF409
+	.byte	0x1
+	.byte	0x87
+	.4byte	0x50
+	.4byte	.LFB222
+	.4byte	.LFE222-.LFB222
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2b96
+	.uleb128 0x58
+	.ascii	"fit\000"
+	.byte	0x1
+	.byte	0x87
+	.4byte	0x3be
+	.4byte	.LLST9
+	.uleb128 0x57
+	.4byte	.LASF256
+	.byte	0x1
+	.byte	0x87
+	.4byte	0x50
+	.4byte	.LLST10
+	.uleb128 0x57
+	.4byte	.LASF62
+	.byte	0x1
+	.byte	0x88
+	.4byte	0xd7
+	.4byte	.LLST11
+	.uleb128 0x57
+	.4byte	.LASF276
+	.byte	0x1
+	.byte	0x88
+	.4byte	0x50
+	.4byte	.LLST12
+	.uleb128 0x5a
+	.ascii	"str\000"
+	.byte	0x1
+	.byte	0x8a
+	.4byte	0xfb
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -20
+	.uleb128 0x63
+	.ascii	"err\000"
+	.byte	0x1
+	.byte	0x8b
+	.4byte	0x50
+	.4byte	.LLST13
+	.uleb128 0x5c
+	.4byte	.LASF372
+	.byte	0x1
+	.byte	0x8c
+	.4byte	0x50
+	.4byte	.LLST14
+	.uleb128 0x40
+	.4byte	.LVL34
+	.4byte	0x2e47
+	.4byte	0x2b7f
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x3
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x3
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -20
+	.uleb128 0x64
+	.4byte	0x2bb1
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL36
+	.4byte	0x3102
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.byte	0
+	.byte	0
+	.uleb128 0x60
+	.4byte	.LASF410
+	.byte	0x1
+	.byte	0x51
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2c1e
+	.uleb128 0x65
+	.ascii	"fit\000"
+	.byte	0x1
+	.byte	0x51
+	.4byte	0x3be
+	.uleb128 0x61
+	.4byte	.LASF256
+	.byte	0x1
+	.byte	0x51
+	.4byte	0x50
+	.uleb128 0x61
+	.4byte	.LASF62
+	.byte	0x1
+	.byte	0x52
+	.4byte	0xd7
+	.uleb128 0x61
+	.4byte	.LASF276
+	.byte	0x1
+	.byte	0x52
+	.4byte	0x50
+	.uleb128 0x61
+	.4byte	.LASF411
+	.byte	0x1
+	.byte	0x53
+	.4byte	0x2c1e
+	.uleb128 0x5b
+	.4byte	.LASF74
+	.byte	0x1
+	.byte	0x55
+	.4byte	0xd7
+	.uleb128 0x66
+	.ascii	"str\000"
+	.byte	0x1
+	.byte	0x55
+	.4byte	0xd7
+	.uleb128 0x5b
+	.4byte	.LASF372
+	.byte	0x1
+	.byte	0x56
+	.4byte	0x50
+	.uleb128 0x5b
+	.4byte	.LASF412
+	.byte	0x1
+	.byte	0x57
+	.4byte	0x50
+	.uleb128 0x66
+	.ascii	"len\000"
+	.byte	0x1
+	.byte	0x58
+	.4byte	0x50
+	.uleb128 0x66
+	.ascii	"i\000"
+	.byte	0x1
+	.byte	0x58
+	.4byte	0x50
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xfb
+	.uleb128 0x67
+	.4byte	.LASF413
+	.byte	0x1
+	.byte	0x3c
+	.4byte	0x50
+	.4byte	.LFB220
+	.4byte	.LFE220-.LFB220
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2c76
+	.uleb128 0x58
+	.ascii	"fit\000"
+	.byte	0x1
+	.byte	0x3c
+	.4byte	0x3be
+	.4byte	.LLST63
+	.uleb128 0x57
+	.4byte	.LASF414
+	.byte	0x1
+	.byte	0x3c
+	.4byte	0x13d
+	.4byte	.LLST64
+	.uleb128 0x68
+	.4byte	.LASF415
+	.byte	0x1
+	.byte	0x3d
+	.4byte	0x11bb
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x68
+	.4byte	.LASF416
+	.byte	0x1
+	.byte	0x3d
+	.4byte	0x11bb
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0
+	.uleb128 0x69
+	.4byte	.LASF464
+	.byte	0x1
+	.byte	0x38
+	.4byte	.LFB219
+	.4byte	.LFE219-.LFB219
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2c99
+	.uleb128 0x6a
+	.ascii	"fdt\000"
+	.byte	0x1
+	.byte	0x38
+	.4byte	0x153
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0
+	.uleb128 0x6b
+	.4byte	.LASF465
+	.byte	0x1
+	.byte	0x33
+	.4byte	0x50
+	.byte	0x1
+	.4byte	0x2cc0
+	.uleb128 0x65
+	.ascii	"fdt\000"
+	.byte	0x1
+	.byte	0x33
+	.4byte	0x153
+	.uleb128 0x61
+	.4byte	.LASF336
+	.byte	0x1
+	.byte	0x33
+	.4byte	0xfb
+	.byte	0
+	.uleb128 0x6c
+	.4byte	.LASF466
+	.byte	0x1
+	.byte	0x2e
+	.4byte	0x50
+	.4byte	0x2ce6
+	.uleb128 0x65
+	.ascii	"fdt\000"
+	.byte	0x1
+	.byte	0x2e
+	.4byte	0x153
+	.uleb128 0x61
+	.4byte	.LASF417
+	.byte	0x1
+	.byte	0x2e
+	.4byte	0xfb
+	.byte	0
+	.uleb128 0x67
+	.4byte	.LASF418
+	.byte	0x1
+	.byte	0x27
+	.4byte	0x50
+	.4byte	.LFB216
+	.4byte	.LFE216-.LFB216
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2d31
+	.uleb128 0x57
+	.4byte	.LASF365
+	.byte	0x1
+	.byte	0x27
+	.4byte	0x11b5
+	.4byte	.LLST60
+	.uleb128 0x57
+	.4byte	.LASF366
+	.byte	0x1
+	.byte	0x27
+	.4byte	0x11a9
+	.4byte	.LLST61
+	.uleb128 0x3c
+	.4byte	.LVL126
+	.4byte	0x2fe8
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC14
+	.byte	0
+	.byte	0
+	.uleb128 0x67
+	.4byte	.LASF419
+	.byte	0x1
+	.byte	0x22
+	.4byte	0x50
+	.4byte	.LFB215
+	.4byte	.LFE215-.LFB215
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2d74
+	.uleb128 0x57
+	.4byte	.LASF420
+	.byte	0x1
+	.byte	0x22
+	.4byte	0x4ba
+	.4byte	.LLST59
+	.uleb128 0x68
+	.4byte	.LASF421
+	.byte	0x1
+	.byte	0x22
+	.4byte	0xfb
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x68
+	.4byte	.LASF417
+	.byte	0x1
+	.byte	0x22
+	.4byte	0xfb
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0
+	.uleb128 0x67
+	.4byte	.LASF422
+	.byte	0x1
+	.byte	0x1d
+	.4byte	0xfb
+	.4byte	.LFB214
+	.4byte	.LFE214-.LFB214
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2d9d
+	.uleb128 0x57
+	.4byte	.LASF420
+	.byte	0x1
+	.byte	0x1d
+	.4byte	0x4ba
+	.4byte	.LLST58
+	.byte	0
+	.uleb128 0x67
+	.4byte	.LASF423
+	.byte	0x1
+	.byte	0x18
+	.4byte	0x50
+	.4byte	.LFB213
+	.4byte	.LFE213-.LFB213
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2dd3
+	.uleb128 0x58
+	.ascii	"fit\000"
+	.byte	0x1
+	.byte	0x18
+	.4byte	0x3be
+	.4byte	.LLST57
+	.uleb128 0x68
+	.4byte	.LASF374
+	.byte	0x1
+	.byte	0x18
+	.4byte	0x50
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0
+	.uleb128 0x46
+	.4byte	.LASF424
+	.byte	0x2
+	.2byte	0x3eb
+	.4byte	0xd7
+	.byte	0x3
+	.4byte	0x2e09
+	.uleb128 0x47
+	.4byte	.LASF425
+	.byte	0x2
+	.2byte	0x3eb
+	.4byte	0x3be
+	.uleb128 0x47
+	.4byte	.LASF389
+	.byte	0x2
+	.2byte	0x3ec
+	.4byte	0x50
+	.uleb128 0x52
+	.ascii	"len\000"
+	.byte	0x2
+	.2byte	0x3ec
+	.4byte	0x237e
+	.byte	0
+	.uleb128 0x46
+	.4byte	.LASF426
+	.byte	0x2
+	.2byte	0x2e1
+	.4byte	0x13d
+	.byte	0x3
+	.4byte	0x2e27
+	.uleb128 0x52
+	.ascii	"hdr\000"
+	.byte	0x2
+	.2byte	0x2e1
+	.4byte	0x2e27
+	.byte	0
+	.uleb128 0x8
+	.byte	0x4
+	.4byte	0xab4
+	.uleb128 0x60
+	.4byte	.LASF427
+	.byte	0x1b
+	.byte	0x70
+	.4byte	0x70
+	.byte	0x3
+	.4byte	0x2e47
+	.uleb128 0x65
+	.ascii	"x\000"
+	.byte	0x1b
+	.byte	0x70
+	.4byte	0x70
+	.byte	0
+	.uleb128 0x6d
+	.4byte	0x2b96
+	.4byte	.LFB236
+	.4byte	.LFE236-.LFB236
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2f8e
+	.uleb128 0x34
+	.4byte	0x2ba6
+	.4byte	.LLST0
+	.uleb128 0x34
+	.4byte	0x2bbc
+	.4byte	.LLST1
+	.uleb128 0x34
+	.4byte	0x2bc7
+	.4byte	.LLST2
+	.uleb128 0x34
+	.4byte	0x2bd2
+	.4byte	.LLST3
+	.uleb128 0x6e
+	.4byte	0x2bb1
+	.uleb128 0x6
+	.byte	0xfa
+	.4byte	0x2bb1
+	.byte	0x9f
+	.uleb128 0x37
+	.4byte	0x2bdd
+	.4byte	.LLST4
+	.uleb128 0x37
+	.4byte	0x2be8
+	.4byte	.LLST5
+	.uleb128 0x37
+	.4byte	0x2bf3
+	.4byte	.LLST6
+	.uleb128 0x37
+	.4byte	0x2bfe
+	.4byte	.LLST7
+	.uleb128 0x36
+	.4byte	0x2c09
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -28
+	.uleb128 0x37
+	.4byte	0x2c14
+	.4byte	.LLST8
+	.uleb128 0x40
+	.4byte	.LVL1
+	.4byte	0x310e
+	.4byte	0x2ed3
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL5
+	.4byte	0x2fe8
+	.4byte	0x2eea
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x5
+	.byte	0x3
+	.4byte	.LC4
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL6
+	.4byte	0x311a
+	.4byte	0x2f04
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL11
+	.4byte	0x2fd1
+	.4byte	0x2f2a
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x77
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -28
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL13
+	.4byte	0x2fe8
+	.4byte	0x2f3e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL14
+	.4byte	0x3125
+	.4byte	0x2f58
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x76
+	.sleb128 0
+	.byte	0
+	.uleb128 0x40
+	.4byte	.LVL18
+	.4byte	0x2fd1
+	.4byte	0x2f7e
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x50
+	.uleb128 0x2
+	.byte	0x75
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x2
+	.byte	0x74
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x52
+	.uleb128 0x2
+	.byte	0x78
+	.sleb128 0
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x53
+	.uleb128 0x2
+	.byte	0x91
+	.sleb128 -28
+	.byte	0
+	.uleb128 0x3c
+	.4byte	.LVL23
+	.4byte	0x3130
+	.uleb128 0x3d
+	.uleb128 0x1
+	.byte	0x51
+	.uleb128 0x1
+	.byte	0x30
+	.byte	0
+	.byte	0
+	.uleb128 0x6d
+	.4byte	0x2c99
+	.4byte	.LFB218
+	.4byte	.LFE218-.LFB218
+	.uleb128 0x1
+	.byte	0x9c
+	.4byte	0x2fb2
+	.uleb128 0x34
+	.4byte	0x2ca9
+	.4byte	.LLST62
+	.uleb128 0x6e
+	.4byte	0x2cb4
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0
+	.uleb128 0xc
+	.4byte	0xdd
+	.4byte	0x2fc5
+	.uleb128 0x6f
+	.4byte	0xcb
+	.4byte	0x201b
+	.byte	0
+	.uleb128 0x70
+	.4byte	.LASF428
+	.4byte	.LASF428
+	.byte	0x2
+	.2byte	0x3f6
+	.uleb128 0x70
+	.4byte	.LASF429
+	.4byte	.LASF429
+	.byte	0x1c
+	.2byte	0x2b2
+	.uleb128 0x71
+	.4byte	.LASF430
+	.4byte	.LASF430
+	.byte	0x1d
+	.byte	0xa3
+	.uleb128 0x71
+	.4byte	.LASF431
+	.4byte	.LASF431
+	.byte	0x1e
+	.byte	0x13
+	.uleb128 0x70
+	.4byte	.LASF432
+	.4byte	.LASF432
+	.byte	0x1c
+	.2byte	0x1a8
+	.uleb128 0x70
+	.4byte	.LASF433
+	.4byte	.LASF433
+	.byte	0x2
+	.2byte	0x42f
+	.uleb128 0x70
+	.4byte	.LASF434
+	.4byte	.LASF434
+	.byte	0x2
+	.2byte	0x438
+	.uleb128 0x70
+	.4byte	.LASF435
+	.4byte	.LASF435
+	.byte	0x2
+	.2byte	0x3f1
+	.uleb128 0x71
+	.4byte	.LASF436
+	.4byte	.LASF436
+	.byte	0x1a
+	.byte	0xf5
+	.uleb128 0x71
+	.4byte	.LASF437
+	.4byte	.LASF437
+	.byte	0x8
+	.byte	0x27
+	.uleb128 0x71
+	.4byte	.LASF438
+	.4byte	.LASF438
+	.byte	0xc
+	.byte	0xc2
+	.uleb128 0x71
+	.4byte	.LASF439
+	.4byte	.LASF439
+	.byte	0x1d
+	.byte	0xe4
+	.uleb128 0x70
+	.4byte	.LASF440
+	.4byte	.LASF440
+	.byte	0x1c
+	.2byte	0x1c1
+	.uleb128 0x70
+	.4byte	.LASF441
+	.4byte	.LASF441
+	.byte	0x2
+	.2byte	0x3f9
+	.uleb128 0x70
+	.4byte	.LASF442
+	.4byte	.LASF442
+	.byte	0x2
+	.2byte	0x3fb
+	.uleb128 0x70
+	.4byte	.LASF443
+	.4byte	.LASF443
+	.byte	0x2
+	.2byte	0x3fd
+	.uleb128 0x70
+	.4byte	.LASF444
+	.4byte	.LASF444
+	.byte	0x2
+	.2byte	0x403
+	.uleb128 0x70
+	.4byte	.LASF445
+	.4byte	.LASF445
+	.byte	0x2
+	.2byte	0x402
+	.uleb128 0x70
+	.4byte	.LASF446
+	.4byte	.LASF446
+	.byte	0x2
+	.2byte	0x405
+	.uleb128 0x70
+	.4byte	.LASF447
+	.4byte	.LASF447
+	.byte	0x17
+	.2byte	0x371
+	.uleb128 0x70
+	.4byte	.LASF448
+	.4byte	.LASF448
+	.byte	0x2
+	.2byte	0x3fa
+	.uleb128 0x70
+	.4byte	.LASF449
+	.4byte	.LASF449
+	.byte	0x2
+	.2byte	0x5ab
+	.uleb128 0x70
+	.4byte	.LASF450
+	.4byte	.LASF450
+	.byte	0x2
+	.2byte	0x42a
+	.uleb128 0x70
+	.4byte	.LASF451
+	.4byte	.LASF451
+	.byte	0x2
+	.2byte	0x5a4
+	.uleb128 0x71
+	.4byte	.LASF452
+	.4byte	.LASF452
+	.byte	0x1e
+	.byte	0x11
+	.uleb128 0x70
+	.4byte	.LASF453
+	.4byte	.LASF453
+	.byte	0x17
+	.2byte	0x16d
+	.uleb128 0x70
+	.4byte	.LASF454
+	.4byte	.LASF454
+	.byte	0x2
+	.2byte	0x400
+	.uleb128 0x70
+	.4byte	.LASF455
+	.4byte	.LASF455
+	.byte	0x1c
+	.2byte	0x182
+	.uleb128 0x70
+	.4byte	.LASF456
+	.4byte	.LASF456
+	.byte	0x2
+	.2byte	0x5b9
+	.uleb128 0x71
+	.4byte	.LASF457
+	.4byte	.LASF457
+	.byte	0x1c
+	.byte	0xa9
+	.uleb128 0x71
+	.4byte	.LASF458
+	.4byte	.LASF458
+	.byte	0x1c
+	.byte	0xb6
+	.uleb128 0x71
+	.4byte	.LASF459
+	.4byte	.LASF459
+	.byte	0x8
+	.byte	0x33
+	.byte	0
+	.section	.debug_abbrev,"",%progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1
+	.uleb128 0x11
+	.byte	0x1
+	.uleb128 0x25
+	.uleb128 0xe
+	.uleb128 0x13
+	.uleb128 0xb
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x1b
+	.uleb128 0xe
+	.uleb128 0x55
+	.uleb128 0x17
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x10
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x2
+	.uleb128 0x16
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x24
+	.byte	0
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x3e
+	.uleb128 0xb
+	.uleb128 0x3
+	.uleb128 0xe
+	.byte	0
+	.byte	0
+	.uleb128 0x4
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3c
+	.uleb128 0x19
+	.byte	0
+	.byte	0
+	.uleb128 0x5
+	.uleb128 0x24
+	.byte	0
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x3e
+	.uleb128 0xb
+	.uleb128 0x3
+	.uleb128 0x8
+	.byte	0
+	.byte	0
+	.uleb128 0x6
+	.uleb128 0x16
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x7
+	.uleb128 0x26
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x8
+	.uleb128 0xf
+	.byte	0
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x9
+	.uleb128 0xf
+	.byte	0
+	.uleb128 0xb
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0xa
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0xb
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0xc
+	.uleb128 0x1
+	.byte	0x1
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0xd
+	.uleb128 0x21
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2f
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0xe
+	.uleb128 0x21
+	.byte	0
+	.byte	0
+	.byte	0
+	.uleb128 0xf
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3c
+	.uleb128 0x19
+	.byte	0
+	.byte	0
+	.uleb128 0x10
+	.uleb128 0x4
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x11
+	.uleb128 0x28
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x1c
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x12
+	.uleb128 0x17
+	.byte	0x1
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x13
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x14
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x15
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x16
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x17
+	.uleb128 0x13
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3c
+	.uleb128 0x19
+	.byte	0
+	.byte	0
+	.uleb128 0x18
+	.uleb128 0x26
+	.byte	0
+	.byte	0
+	.byte	0
+	.uleb128 0x19
+	.uleb128 0x15
+	.byte	0x1
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x1a
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x1b
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0xb
+	.uleb128 0x5
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x1c
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0x5
+	.byte	0
+	.byte	0
+	.uleb128 0x1d
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0x5
+	.byte	0
+	.byte	0
+	.uleb128 0x1e
+	.uleb128 0x21
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2f
+	.uleb128 0x5
+	.byte	0
+	.byte	0
+	.uleb128 0x1f
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0xb
+	.uleb128 0x5
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x20
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3c
+	.uleb128 0x19
+	.byte	0
+	.byte	0
+	.uleb128 0x21
+	.uleb128 0x4
+	.byte	0x1
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x22
+	.uleb128 0x4
+	.byte	0x1
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x23
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x24
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x25
+	.uleb128 0x16
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x26
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x38
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x27
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0xb
+	.uleb128 0x5
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x28
+	.uleb128 0x15
+	.byte	0x1
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x29
+	.uleb128 0x4
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0xb
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x2a
+	.uleb128 0x13
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0xb
+	.uleb128 0x5
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x2b
+	.uleb128 0x17
+	.byte	0x1
+	.uleb128 0xb
+	.uleb128 0x5
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x2c
+	.uleb128 0xd
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x2d
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2117
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x2e
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x2f
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x30
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x32
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x1c
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x33
+	.uleb128 0x1d
+	.byte	0x1
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x52
+	.uleb128 0x1
+	.uleb128 0x55
+	.uleb128 0x17
+	.uleb128 0x58
+	.uleb128 0xb
+	.uleb128 0x59
+	.uleb128 0x5
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x34
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x35
+	.uleb128 0xb
+	.byte	0x1
+	.uleb128 0x55
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x36
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x37
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x38
+	.uleb128 0xa
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x39
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x3a
+	.uleb128 0xb
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x3b
+	.uleb128 0x1d
+	.byte	0x1
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x58
+	.uleb128 0xb
+	.uleb128 0x59
+	.uleb128 0x5
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x3c
+	.uleb128 0x4109
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x31
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x3d
+	.uleb128 0x410a
+	.byte	0
+	.uleb128 0x2
+	.uleb128 0x18
+	.uleb128 0x2111
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x3e
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x3f
+	.uleb128 0xb
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.byte	0
+	.byte	0
+	.uleb128 0x40
+	.uleb128 0x4109
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x41
+	.uleb128 0x4109
+	.byte	0
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x31
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x42
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x43
+	.uleb128 0xb
+	.byte	0x1
+	.uleb128 0x55
+	.uleb128 0x17
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x44
+	.uleb128 0x4109
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x2113
+	.uleb128 0x18
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x45
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x34
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x46
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x20
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x47
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x48
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x4a
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x34
+	.uleb128 0x19
+	.uleb128 0x1c
+	.uleb128 0xe
+	.byte	0
+	.byte	0
+	.uleb128 0x4b
+	.uleb128 0xa
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.byte	0
+	.byte	0
+	.uleb128 0x4c
+	.uleb128 0xb
+	.byte	0x1
+	.byte	0
+	.byte	0
+	.uleb128 0x4d
+	.uleb128 0x21
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x4e
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x4f
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2116
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x50
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x1c
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x51
+	.uleb128 0x4109
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x2113
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x52
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x53
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2117
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x54
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x55
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x34
+	.uleb128 0x19
+	.byte	0
+	.byte	0
+	.uleb128 0x56
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2116
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x57
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x58
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x59
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x5a
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x5b
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x5c
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x5d
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x1c
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.uleb128 0x5e
+	.uleb128 0xa
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.uleb128 0x11
+	.uleb128 0x1
+	.byte	0
+	.byte	0
+	.uleb128 0x5f
+	.uleb128 0x4109
+	.byte	0x1
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x60
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x20
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x61
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x62
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2117
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x63
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x17
+	.byte	0
+	.byte	0
+	.uleb128 0x64
+	.uleb128 0x410a
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x2111
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x65
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x66
+	.uleb128 0x34
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x67
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2117
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x68
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x69
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2117
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x6a
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x3
+	.uleb128 0x8
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x6b
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x20
+	.uleb128 0xb
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x6c
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.uleb128 0x27
+	.uleb128 0x19
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x6d
+	.uleb128 0x2e
+	.byte	0x1
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x11
+	.uleb128 0x1
+	.uleb128 0x12
+	.uleb128 0x6
+	.uleb128 0x40
+	.uleb128 0x18
+	.uleb128 0x2117
+	.uleb128 0x19
+	.uleb128 0x1
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x6e
+	.uleb128 0x5
+	.byte	0
+	.uleb128 0x31
+	.uleb128 0x13
+	.uleb128 0x2
+	.uleb128 0x18
+	.byte	0
+	.byte	0
+	.uleb128 0x6f
+	.uleb128 0x21
+	.byte	0
+	.uleb128 0x49
+	.uleb128 0x13
+	.uleb128 0x2f
+	.uleb128 0x13
+	.byte	0
+	.byte	0
+	.uleb128 0x70
+	.uleb128 0x2e
+	.byte	0
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3c
+	.uleb128 0x19
+	.uleb128 0x6e
+	.uleb128 0xe
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0x5
+	.byte	0
+	.byte	0
+	.uleb128 0x71
+	.uleb128 0x2e
+	.byte	0
+	.uleb128 0x3f
+	.uleb128 0x19
+	.uleb128 0x3c
+	.uleb128 0x19
+	.uleb128 0x6e
+	.uleb128 0xe
+	.uleb128 0x3
+	.uleb128 0xe
+	.uleb128 0x3a
+	.uleb128 0xb
+	.uleb128 0x3b
+	.uleb128 0xb
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_loc,"",%progbits
+.Ldebug_loc0:
+.LLST67:
+	.4byte	.LVL137
+	.4byte	.LVL143
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL143
+	.4byte	.LVL145
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL145
+	.4byte	.LVL146-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL146-1
+	.4byte	.LFE235
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST68:
+	.4byte	.LVL137
+	.4byte	.LVL143
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL143
+	.4byte	.LVL145
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	.LVL145
+	.4byte	.LVL146-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL146-1
+	.4byte	.LFE235
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	0
+	.4byte	0
+.LLST69:
+	.4byte	.LVL137
+	.4byte	.LVL141
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL141
+	.4byte	.LVL159
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	.LVL159
+	.4byte	.LVL160
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	.LVL160
+	.4byte	.LVL221
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	.LVL221
+	.4byte	.LVL228
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 80
+	.4byte	.LVL228
+	.4byte	.LVL230
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	.LVL230
+	.4byte	.LVL251
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 80
+	.4byte	.LVL251
+	.4byte	.LVL265
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	.LVL265
+	.4byte	.LVL267
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 80
+	.4byte	.LVL267
+	.4byte	.LVL268
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	.LVL268
+	.4byte	.LFE235
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	0
+	.4byte	0
+.LLST70:
+	.4byte	.LVL137
+	.4byte	.LVL139
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL139
+	.4byte	.LVL143
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL143
+	.4byte	.LVL145
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL145
+	.4byte	.LVL148
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL148
+	.4byte	.LFE235
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST71:
+	.4byte	.LVL138
+	.4byte	.LVL140
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	0
+	.4byte	0
+.LLST72:
+	.4byte	.LVL137
+	.4byte	.LVL159
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xea
+	.byte	0x9f
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xea
+	.byte	0x9f
+	.4byte	.LVL268
+	.4byte	.LVL269
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xea
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST73:
+	.4byte	.LVL146
+	.4byte	.LVL148
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL148
+	.4byte	.LVL159
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL268
+	.4byte	.LVL269
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST74:
+	.4byte	.LVL146
+	.4byte	.LVL159
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	.LVL268
+	.4byte	.LVL269
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 96
+	.4byte	0
+	.4byte	0
+.LLST75:
+	.4byte	.LVL146
+	.4byte	.LVL159
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	.LVL268
+	.4byte	.LVL269
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	0
+	.4byte	0
+.LLST76:
+	.4byte	.LVL146
+	.4byte	.LVL159
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL268
+	.4byte	.LVL269
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST77:
+	.4byte	.LVL149
+	.4byte	.LVL150-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL150-1
+	.4byte	.LVL156
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 100
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 100
+	.4byte	0
+	.4byte	0
+.LLST78:
+	.4byte	.LVL155
+	.4byte	.LVL157
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL157
+	.4byte	.LVL158-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL158-1
+	.4byte	.LVL159
+	.2byte	0x3
+	.byte	0x7d
+	.sleb128 100
+	.4byte	.LVL160
+	.4byte	.LVL161
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL163
+	.4byte	.LVL164
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL164
+	.4byte	.LVL165-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL165-1
+	.4byte	.LVL166
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL166
+	.4byte	.LVL167
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL167
+	.4byte	.LVL169
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL169
+	.4byte	.LVL170
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL175
+	.4byte	.LVL176
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL176
+	.4byte	.LVL177-1
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL177
+	.4byte	.LVL178
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL179
+	.4byte	.LVL180
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL180
+	.4byte	.LVL181-1
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL196
+	.4byte	.LVL197
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL211
+	.4byte	.LVL214
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL214
+	.4byte	.LVL215-1
+	.2byte	0x1
+	.byte	0x53
+	.4byte	0
+	.4byte	0
+.LLST79:
+	.4byte	.LVL146
+	.4byte	.LVL159
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL160
+	.4byte	.LVL172
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL172
+	.4byte	.LVL183
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL183
+	.4byte	.LVL187
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL187
+	.4byte	.LVL190
+	.2byte	0x2
+	.byte	0x31
+	.byte	0x9f
+	.4byte	.LVL190
+	.4byte	.LVL209
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL209
+	.4byte	.LVL210
+	.2byte	0x2
+	.byte	0x31
+	.byte	0x9f
+	.4byte	.LVL210
+	.4byte	.LVL217
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL217
+	.4byte	.LVL218
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL218
+	.4byte	.LVL219
+	.2byte	0x1
+	.byte	0x56
+	.4byte	0
+	.4byte	0
+.LLST80:
+	.4byte	.LVL146
+	.4byte	.LVL159
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xff
+	.byte	0x9f
+	.4byte	.LVL160
+	.4byte	.LVL172
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xff
+	.byte	0x9f
+	.4byte	.LVL173
+	.4byte	.LVL174
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL174
+	.4byte	.LVL183
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL183
+	.4byte	.LVL184
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xff
+	.byte	0x9f
+	.4byte	.LVL184
+	.4byte	.LVL185
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL185
+	.4byte	.LVL187
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL187
+	.4byte	.LVL188
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL188
+	.4byte	.LVL190
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL191
+	.4byte	.LVL194
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL194
+	.4byte	.LVL195-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL195-1
+	.4byte	.LVL203
+	.2byte	0x1
+	.byte	0x5a
+	.4byte	.LVL209
+	.4byte	.LVL217
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL217
+	.4byte	.LVL219
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST81:
+	.4byte	.LVL147
+	.4byte	.LVL149-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL149-1
+	.4byte	.LVL159
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL160
+	.4byte	.LVL219
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL268
+	.4byte	.LVL269
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST82:
+	.4byte	.LVL189
+	.4byte	.LVL190
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST83:
+	.4byte	.LVL151
+	.4byte	.LVL152
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL152
+	.4byte	.LVL153
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL153
+	.4byte	.LVL154
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL154
+	.4byte	.LVL155-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	0
+	.4byte	0
+.LLST84:
+	.4byte	.LVL192
+	.4byte	.LVL193
+	.2byte	0x4
+	.byte	0x7d
+	.sleb128 107
+	.byte	0x9f
+	.4byte	.LVL193
+	.4byte	.LVL195-1
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL195-1
+	.4byte	.LVL195
+	.2byte	0x4
+	.byte	0x7d
+	.sleb128 107
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST85:
+	.4byte	.LVL192
+	.4byte	.LVL194
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL194
+	.4byte	.LVL195-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL195-1
+	.4byte	.LVL195
+	.2byte	0x1
+	.byte	0x5a
+	.4byte	0
+	.4byte	0
+.LLST86:
+	.4byte	.LVL192
+	.4byte	.LVL195
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST87:
+	.4byte	.LVL199
+	.4byte	.LVL207
+	.2byte	0x4
+	.byte	0x7d
+	.sleb128 176
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST88:
+	.4byte	.LVL199
+	.4byte	.LVL207
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST89:
+	.4byte	.LVL199
+	.4byte	.LVL207
+	.2byte	0x1
+	.byte	0x56
+	.4byte	0
+	.4byte	0
+.LLST90:
+	.4byte	.LVL199
+	.4byte	.LVL207
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST91:
+	.4byte	.LVL199
+	.4byte	.LVL200
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL200
+	.4byte	.LVL201
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST92:
+	.4byte	.LVL203
+	.4byte	.LVL204
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL204
+	.4byte	.LVL205-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL205-1
+	.4byte	.LVL207
+	.2byte	0x1
+	.byte	0x5a
+	.4byte	0
+	.4byte	0
+.LLST93:
+	.4byte	.LVL212
+	.4byte	.LVL213
+	.2byte	0x3
+	.byte	0x74
+	.sleb128 4
+	.byte	0x9f
+	.4byte	.LVL213
+	.4byte	.LVL215-1
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL215-1
+	.4byte	.LVL215
+	.2byte	0x3
+	.byte	0x74
+	.sleb128 4
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST94:
+	.4byte	.LVL212
+	.4byte	.LVL215
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST95:
+	.4byte	.LVL212
+	.4byte	.LVL215
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST96:
+	.4byte	.LVL219
+	.4byte	.LVL229
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	.LVL230
+	.4byte	.LVL268
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	0
+	.4byte	0
+.LLST97:
+	.4byte	.LVL219
+	.4byte	.LVL229
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL230
+	.4byte	.LVL268
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST99:
+	.4byte	.LVL222
+	.4byte	.LVL227
+	.2byte	0x2
+	.byte	0x76
+	.sleb128 0
+	.4byte	.LVL227
+	.4byte	.LVL229
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 16
+	.4byte	.LVL230
+	.4byte	.LVL237
+	.2byte	0x2
+	.byte	0x76
+	.sleb128 0
+	.4byte	.LVL237
+	.4byte	.LVL265
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 16
+	.4byte	.LVL265
+	.4byte	.LVL266
+	.2byte	0x2
+	.byte	0x76
+	.sleb128 0
+	.4byte	.LVL266
+	.4byte	.LVL268
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 16
+	.4byte	0
+	.4byte	0
+.LLST100:
+	.4byte	.LVL250
+	.4byte	.LVL252
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL267
+	.4byte	.LVL268
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST101:
+	.4byte	.LVL231
+	.4byte	.LVL232
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL232
+	.4byte	.LVL244
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 84
+	.4byte	.LVL247
+	.4byte	.LVL252
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 84
+	.4byte	.LVL265
+	.4byte	.LVL268
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 84
+	.4byte	0
+	.4byte	0
+.LLST102:
+	.4byte	.LVL253
+	.4byte	.LVL254
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL254
+	.4byte	.LVL255-1
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 0
+	.4byte	0
+	.4byte	0
+.LLST103:
+	.4byte	.LVL243
+	.4byte	.LVL245
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL245
+	.4byte	.LVL246-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL246-1
+	.4byte	.LVL247
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 84
+	.4byte	.LVL247
+	.4byte	.LVL248
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL248
+	.4byte	.LVL252
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 72
+	.4byte	.LVL255
+	.4byte	.LVL256
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL256
+	.4byte	.LVL257-1
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL267
+	.4byte	.LVL268
+	.2byte	0x3
+	.byte	0x77
+	.sleb128 72
+	.4byte	0
+	.4byte	0
+.LLST104:
+	.4byte	.LVL252
+	.4byte	.LVL262
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL263
+	.4byte	.LVL265
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST105:
+	.4byte	.LVL236
+	.4byte	.LVL238-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL238-1
+	.4byte	.LVL262
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL263
+	.4byte	.LVL265
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL266
+	.4byte	.LVL267
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL267
+	.4byte	.LVL268
+	.2byte	0x1
+	.byte	0x56
+	.4byte	0
+	.4byte	0
+.LLST106:
+	.4byte	.LVL223
+	.4byte	.LVL224
+	.2byte	0x6
+	.byte	0x3
+	.4byte	.LC15
+	.byte	0x9f
+	.4byte	.LVL224
+	.4byte	.LVL225
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL225
+	.4byte	.LVL226-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	0
+	.4byte	0
+.LLST107:
+	.4byte	.LVL238
+	.4byte	.LVL239
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL239
+	.4byte	.LVL240-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL241
+	.4byte	.LVL242
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL242
+	.4byte	.LVL243-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	0
+	.4byte	0
+.LLST98:
+	.4byte	.LVL220
+	.4byte	.LVL224-1
+	.2byte	0x6
+	.byte	0x7b
+	.sleb128 8
+	.byte	0x6
+	.byte	0x31
+	.byte	0x1c
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST66:
+	.4byte	.LVL135
+	.4byte	.LVL136
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL136
+	.4byte	.LFE232
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST47:
+	.4byte	.LVL105
+	.4byte	.LVL109
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL109
+	.4byte	.LVL117
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL117
+	.4byte	.LFE231
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST48:
+	.4byte	.LVL105
+	.4byte	.LVL111
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL111
+	.4byte	.LVL117
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL117
+	.4byte	.LFE231
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST49:
+	.4byte	.LVL105
+	.4byte	.LVL106
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL106
+	.4byte	.LFE231
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST50:
+	.4byte	.LVL105
+	.4byte	.LVL110
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL110
+	.4byte	.LFE231
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST51:
+	.4byte	.LVL115
+	.4byte	.LVL116
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST52:
+	.4byte	.LVL107
+	.4byte	.LVL108
+	.2byte	0x2d
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x23
+	.uleb128 0x4
+	.byte	0x6
+	.byte	0x38
+	.byte	0x24
+	.byte	0x8
+	.byte	0xff
+	.byte	0x40
+	.byte	0x24
+	.byte	0x1a
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x23
+	.uleb128 0x4
+	.byte	0x6
+	.byte	0x38
+	.byte	0x25
+	.byte	0xa
+	.2byte	0xff00
+	.byte	0x1a
+	.byte	0x21
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x23
+	.uleb128 0x4
+	.byte	0x6
+	.byte	0x48
+	.byte	0x25
+	.byte	0x21
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x23
+	.uleb128 0x4
+	.byte	0x6
+	.byte	0x48
+	.byte	0x24
+	.byte	0x21
+	.byte	0x9f
+	.4byte	.LVL108
+	.4byte	.LVL114-1
+	.2byte	0x7
+	.byte	0x72
+	.sleb128 0
+	.byte	0xb
+	.2byte	0xfe00
+	.byte	0x1a
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST53:
+	.4byte	.LVL112
+	.4byte	.LVL117
+	.2byte	0x1
+	.byte	0x56
+	.4byte	0
+	.4byte	0
+.LLST54:
+	.4byte	.LVL112
+	.4byte	.LVL114
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST55:
+	.4byte	.LVL112
+	.4byte	.LVL113
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL113
+	.4byte	.LVL114-1
+	.2byte	0x7
+	.byte	0x72
+	.sleb128 0
+	.byte	0xb
+	.2byte	0xfe00
+	.byte	0x1a
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST56:
+	.4byte	.LVL112
+	.4byte	.LVL114
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST65:
+	.4byte	.LVL133
+	.4byte	.LVL134
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL134
+	.4byte	.LFE230
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST39:
+	.4byte	.LVL94
+	.4byte	.LVL98
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL98
+	.4byte	.LVL104
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL104
+	.4byte	.LFE227
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST40:
+	.4byte	.LVL94
+	.4byte	.LVL97
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL97
+	.4byte	.LVL104
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL104
+	.4byte	.LFE227
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST41:
+	.4byte	.LVL94
+	.4byte	.LVL96
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL96
+	.4byte	.LVL104
+	.2byte	0x1
+	.byte	0x57
+	.4byte	.LVL104
+	.4byte	.LFE227
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST42:
+	.4byte	.LVL94
+	.4byte	.LVL95
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL95
+	.4byte	.LVL104
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL104
+	.4byte	.LFE227
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST43:
+	.4byte	.LVL94
+	.4byte	.LVL104
+	.2byte	0x2
+	.byte	0x91
+	.sleb128 0
+	.4byte	.LVL104
+	.4byte	.LFE227
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 0
+	.4byte	0
+	.4byte	0
+.LLST44:
+	.4byte	.LVL94
+	.4byte	.LVL104
+	.2byte	0x2
+	.byte	0x91
+	.sleb128 4
+	.4byte	.LVL104
+	.4byte	.LFE227
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 4
+	.4byte	0
+	.4byte	0
+.LLST45:
+	.4byte	.LVL99
+	.4byte	.LVL100
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL100
+	.4byte	.LVL101-1
+	.2byte	0x2
+	.byte	0x7d
+	.sleb128 0
+	.4byte	0
+	.4byte	0
+.LLST46:
+	.4byte	.LVL101
+	.4byte	.LVL102
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST15:
+	.4byte	.LVL38
+	.4byte	.LVL43
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL43
+	.4byte	.LFE226
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST16:
+	.4byte	.LVL38
+	.4byte	.LVL42
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL42
+	.4byte	.LFE226
+	.2byte	0x3
+	.byte	0x91
+	.sleb128 -68
+	.4byte	0
+	.4byte	0
+.LLST17:
+	.4byte	.LVL38
+	.4byte	.LVL39
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL39
+	.4byte	.LVL75
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL75
+	.4byte	.LVL77-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL77-1
+	.4byte	.LVL85
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL85
+	.4byte	.LVL86-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL86-1
+	.4byte	.LFE226
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST18:
+	.4byte	.LVL38
+	.4byte	.LVL40
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL40
+	.4byte	.LVL50
+	.2byte	0x1
+	.byte	0x57
+	.4byte	.LVL50
+	.4byte	.LVL68
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL68
+	.4byte	.LVL69
+	.2byte	0x1
+	.byte	0x57
+	.4byte	.LVL69
+	.4byte	.LVL73
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL73
+	.4byte	.LVL74
+	.2byte	0x1
+	.byte	0x57
+	.4byte	.LVL74
+	.4byte	.LVL90
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL90
+	.4byte	.LVL92
+	.2byte	0x1
+	.byte	0x57
+	.4byte	.LVL92
+	.4byte	.LFE226
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST19:
+	.4byte	.LVL38
+	.4byte	.LVL68
+	.2byte	0x2
+	.byte	0x91
+	.sleb128 0
+	.4byte	.LVL68
+	.4byte	.LFE226
+	.2byte	0x2
+	.byte	0x91
+	.sleb128 0
+	.4byte	0
+	.4byte	0
+.LLST20:
+	.4byte	.LVL38
+	.4byte	.LVL68
+	.2byte	0x2
+	.byte	0x91
+	.sleb128 4
+	.4byte	.LVL68
+	.4byte	.LFE226
+	.2byte	0x2
+	.byte	0x91
+	.sleb128 4
+	.4byte	0
+	.4byte	0
+.LLST21:
+	.4byte	.LVL53
+	.4byte	.LVL54-1
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL54-1
+	.4byte	.LVL65
+	.2byte	0x3
+	.byte	0x91
+	.sleb128 -80
+	.4byte	.LVL69
+	.4byte	.LVL73
+	.2byte	0x3
+	.byte	0x91
+	.sleb128 -80
+	.4byte	.LVL88
+	.4byte	.LVL89
+	.2byte	0x3
+	.byte	0x91
+	.sleb128 -80
+	.4byte	0
+	.4byte	0
+.LLST22:
+	.4byte	.LVL57
+	.4byte	.LVL65
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	.LVL71
+	.4byte	.LVL73
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	.LVL88
+	.4byte	.LVL89
+	.2byte	0x1
+	.byte	0x5b
+	.4byte	0
+	.4byte	0
+.LLST23:
+	.4byte	.LVL41
+	.4byte	.LVL67
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xff
+	.byte	0x9f
+	.4byte	.LVL68
+	.4byte	.LVL93
+	.2byte	0x3
+	.byte	0x9
+	.byte	0xff
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST24:
+	.4byte	.LVL41
+	.4byte	.LVL51
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL51
+	.4byte	.LVL65
+	.2byte	0x2
+	.byte	0x31
+	.byte	0x9f
+	.4byte	.LVL68
+	.4byte	.LVL69
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL69
+	.4byte	.LVL73
+	.2byte	0x2
+	.byte	0x31
+	.byte	0x9f
+	.4byte	.LVL73
+	.4byte	.LVL74
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL88
+	.4byte	.LVL89
+	.2byte	0x2
+	.byte	0x31
+	.byte	0x9f
+	.4byte	.LVL90
+	.4byte	.LVL92
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST25:
+	.4byte	.LVL41
+	.4byte	.LVL61
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL61
+	.4byte	.LVL62
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL68
+	.4byte	.LVL71
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL73
+	.4byte	.LVL74
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	.LVL90
+	.4byte	.LFE226
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST26:
+	.4byte	.LVL44
+	.4byte	.LVL45-1
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL45-1
+	.4byte	.LFE226
+	.2byte	0x3
+	.byte	0x91
+	.sleb128 -76
+	.4byte	0
+	.4byte	0
+.LLST27:
+	.4byte	.LVL56
+	.4byte	.LVL57
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL69
+	.4byte	.LVL70-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST28:
+	.4byte	.LVL56
+	.4byte	.LVL57
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL69
+	.4byte	.LVL71
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST29:
+	.4byte	.LVL57
+	.4byte	.LVL60
+	.2byte	0x1
+	.byte	0x5a
+	.4byte	0
+	.4byte	0
+.LLST30:
+	.4byte	.LVL57
+	.4byte	.LVL60
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST31:
+	.4byte	.LVL62
+	.4byte	.LVL63
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL71
+	.4byte	.LVL72-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST32:
+	.4byte	.LVL62
+	.4byte	.LVL63
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL71
+	.4byte	.LVL73
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST33:
+	.4byte	.LVL76
+	.4byte	.LVL78
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST34:
+	.4byte	.LVL76
+	.4byte	.LVL77-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL77-1
+	.4byte	.LVL78
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST35:
+	.4byte	.LVL76
+	.4byte	.LVL77-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL77-1
+	.4byte	.LVL78
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST36:
+	.4byte	.LVL85
+	.4byte	.LVL86
+	.2byte	0x2
+	.byte	0x30
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST37:
+	.4byte	.LVL85
+	.4byte	.LVL86-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL86-1
+	.4byte	.LVL86
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST38:
+	.4byte	.LVL85
+	.4byte	.LVL86-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL86-1
+	.4byte	.LVL86
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST9:
+	.4byte	.LVL30
+	.4byte	.LVL34-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL34-1
+	.4byte	.LFE222
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST10:
+	.4byte	.LVL30
+	.4byte	.LVL31
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL31
+	.4byte	.LFE222
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST11:
+	.4byte	.LVL30
+	.4byte	.LVL32
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL32
+	.4byte	.LVL34-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL34-1
+	.4byte	.LFE222
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST12:
+	.4byte	.LVL30
+	.4byte	.LVL33
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL33
+	.4byte	.LVL34-1
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL34-1
+	.4byte	.LFE222
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST13:
+	.4byte	.LVL34
+	.4byte	.LVL35
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST14:
+	.4byte	.LVL36
+	.4byte	.LVL37
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST63:
+	.4byte	.LVL130
+	.4byte	.LVL132
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL132
+	.4byte	.LFE220
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST64:
+	.4byte	.LVL130
+	.4byte	.LVL131
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL131
+	.4byte	.LFE220
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST60:
+	.4byte	.LVL124
+	.4byte	.LVL125
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL125
+	.4byte	.LFE216
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST61:
+	.4byte	.LVL124
+	.4byte	.LVL126-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL126-1
+	.4byte	.LFE216
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST59:
+	.4byte	.LVL122
+	.4byte	.LVL123
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL123
+	.4byte	.LFE215
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST58:
+	.4byte	.LVL120
+	.4byte	.LVL121
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL121
+	.4byte	.LFE214
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST57:
+	.4byte	.LVL118
+	.4byte	.LVL119
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL119
+	.4byte	.LFE213
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST0:
+	.4byte	.LVL0
+	.4byte	.LVL1-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL1-1
+	.4byte	.LVL8
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL8
+	.4byte	.LVL9
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	.LVL9
+	.4byte	.LVL19
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL19
+	.4byte	.LFE236
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+.LLST1:
+	.4byte	.LVL0
+	.4byte	.LVL1-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL1-1
+	.4byte	.LVL4
+	.2byte	0x1
+	.byte	0x58
+	.4byte	.LVL4
+	.4byte	.LVL16
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x51
+	.byte	0x9f
+	.4byte	.LVL16
+	.4byte	.LFE236
+	.2byte	0x1
+	.byte	0x58
+	.4byte	0
+	.4byte	0
+.LLST2:
+	.4byte	.LVL0
+	.4byte	.LVL1-1
+	.2byte	0x1
+	.byte	0x52
+	.4byte	.LVL1-1
+	.4byte	.LVL3
+	.2byte	0x1
+	.byte	0x57
+	.4byte	.LVL3
+	.4byte	.LVL16
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x52
+	.byte	0x9f
+	.4byte	.LVL16
+	.4byte	.LFE236
+	.2byte	0x1
+	.byte	0x57
+	.4byte	0
+	.4byte	0
+.LLST3:
+	.4byte	.LVL0
+	.4byte	.LVL1-1
+	.2byte	0x1
+	.byte	0x53
+	.4byte	.LVL1-1
+	.4byte	.LVL7
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL7
+	.4byte	.LVL16
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x53
+	.byte	0x9f
+	.4byte	.LVL16
+	.4byte	.LFE236
+	.2byte	0x1
+	.byte	0x56
+	.4byte	0
+	.4byte	0
+.LLST4:
+	.4byte	.LVL11
+	.4byte	.LVL12
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL12
+	.4byte	.LVL13-1
+	.2byte	0x1
+	.byte	0x51
+	.4byte	.LVL18
+	.4byte	.LVL20
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL20
+	.4byte	.LVL26
+	.2byte	0x1
+	.byte	0x55
+	.4byte	.LVL26
+	.4byte	.LVL28
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL28
+	.4byte	.LFE236
+	.2byte	0x1
+	.byte	0x55
+	.4byte	0
+	.4byte	0
+.LLST5:
+	.4byte	.LVL20
+	.4byte	.LVL23-1
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL23
+	.4byte	.LVL24
+	.2byte	0x3
+	.byte	0x70
+	.sleb128 1
+	.byte	0x9f
+	.4byte	.LVL24
+	.4byte	.LVL26
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL28
+	.4byte	.LFE236
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST6:
+	.4byte	.LVL7
+	.4byte	.LVL8
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL9
+	.4byte	.LVL10
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL10
+	.4byte	.LVL15
+	.2byte	0x1
+	.byte	0x56
+	.4byte	.LVL15
+	.4byte	.LVL16
+	.2byte	0x1
+	.byte	0x50
+	.4byte	0
+	.4byte	0
+.LLST7:
+	.4byte	.LVL1
+	.4byte	.LVL2
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL2
+	.4byte	.LVL8
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL9
+	.4byte	.LVL16
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL16
+	.4byte	.LVL17
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL17
+	.4byte	.LVL20
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL26
+	.4byte	.LVL27
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST8:
+	.4byte	.LVL20
+	.4byte	.LVL21
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL22
+	.4byte	.LVL26
+	.2byte	0x1
+	.byte	0x54
+	.4byte	.LVL28
+	.4byte	.LVL29
+	.2byte	0x1
+	.byte	0x54
+	.4byte	0
+	.4byte	0
+.LLST62:
+	.4byte	.LVL127
+	.4byte	.LVL128
+	.2byte	0x1
+	.byte	0x50
+	.4byte	.LVL128
+	.4byte	.LFE218
+	.2byte	0x4
+	.byte	0xf3
+	.uleb128 0x1
+	.byte	0x50
+	.byte	0x9f
+	.4byte	0
+	.4byte	0
+	.section	.debug_aranges,"",%progbits
+	.4byte	0x8c
+	.2byte	0x2
+	.4byte	.Ldebug_info0
+	.byte	0x4
+	.byte	0
+	.2byte	0
+	.2byte	0
+	.4byte	.LFB236
+	.4byte	.LFE236-.LFB236
+	.4byte	.LFB222
+	.4byte	.LFE222-.LFB222
+	.4byte	.LFB226
+	.4byte	.LFE226-.LFB226
+	.4byte	.LFB227
+	.4byte	.LFE227-.LFB227
+	.4byte	.LFB231
+	.4byte	.LFE231-.LFB231
+	.4byte	.LFB213
+	.4byte	.LFE213-.LFB213
+	.4byte	.LFB214
+	.4byte	.LFE214-.LFB214
+	.4byte	.LFB215
+	.4byte	.LFE215-.LFB215
+	.4byte	.LFB216
+	.4byte	.LFE216-.LFB216
+	.4byte	.LFB218
+	.4byte	.LFE218-.LFB218
+	.4byte	.LFB219
+	.4byte	.LFE219-.LFB219
+	.4byte	.LFB220
+	.4byte	.LFE220-.LFB220
+	.4byte	.LFB230
+	.4byte	.LFE230-.LFB230
+	.4byte	.LFB232
+	.4byte	.LFE232-.LFB232
+	.4byte	.LFB235
+	.4byte	.LFE235-.LFB235
+	.4byte	0
+	.4byte	0
+	.section	.debug_ranges,"",%progbits
+.Ldebug_ranges0:
+	.4byte	.LBB36
+	.4byte	.LBE36
+	.4byte	.LBB40
+	.4byte	.LBE40
+	.4byte	.LBB46
+	.4byte	.LBE46
+	.4byte	0
+	.4byte	0
+	.4byte	.LBB43
+	.4byte	.LBE43
+	.4byte	.LBB47
+	.4byte	.LBE47
+	.4byte	0
+	.4byte	0
+	.4byte	.LBB48
+	.4byte	.LBE48
+	.4byte	.LBB52
+	.4byte	.LBE52
+	.4byte	.LBB53
+	.4byte	.LBE53
+	.4byte	0
+	.4byte	0
+	.4byte	.LBB84
+	.4byte	.LBE84
+	.4byte	.LBB97
+	.4byte	.LBE97
+	.4byte	.LBB98
+	.4byte	.LBE98
+	.4byte	.LBB99
+	.4byte	.LBE99
+	.4byte	.LBB106
+	.4byte	.LBE106
+	.4byte	0
+	.4byte	0
+	.4byte	.LBB100
+	.4byte	.LBE100
+	.4byte	.LBB105
+	.4byte	.LBE105
+	.4byte	0
+	.4byte	0
+	.4byte	.LBB102
+	.4byte	.LBE102
+	.4byte	.LBB103
+	.4byte	.LBE103
+	.4byte	0
+	.4byte	0
+	.4byte	.LFB236
+	.4byte	.LFE236
+	.4byte	.LFB222
+	.4byte	.LFE222
+	.4byte	.LFB226
+	.4byte	.LFE226
+	.4byte	.LFB227
+	.4byte	.LFE227
+	.4byte	.LFB231
+	.4byte	.LFE231
+	.4byte	.LFB213
+	.4byte	.LFE213
+	.4byte	.LFB214
+	.4byte	.LFE214
+	.4byte	.LFB215
+	.4byte	.LFE215
+	.4byte	.LFB216
+	.4byte	.LFE216
+	.4byte	.LFB218
+	.4byte	.LFE218
+	.4byte	.LFB219
+	.4byte	.LFE219
+	.4byte	.LFB220
+	.4byte	.LFE220
+	.4byte	.LFB230
+	.4byte	.LFE230
+	.4byte	.LFB232
+	.4byte	.LFE232
+	.4byte	.LFB235
+	.4byte	.LFE235
+	.4byte	0
+	.4byte	0
+	.section	.debug_line,"",%progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",%progbits,1
+.LASF45:
+	.ascii	"IF_TYPE_SPINAND\000"
+.LASF82:
+	.ascii	"flash_id\000"
+.LASF307:
+	.ascii	"mem_malloc_start\000"
+.LASF457:
+	.ascii	"fdt_first_subnode\000"
+.LASF283:
+	.ascii	"net_hostname\000"
+.LASF74:
+	.ascii	"name\000"
+.LASF319:
+	.ascii	"spl_load_info\000"
+.LASF44:
+	.ascii	"IF_TYPE_RKNAND\000"
+.LASF303:
+	.ascii	"NETLOOP_RESTART\000"
+.LASF299:
+	.ascii	"net_boot_file_size\000"
+.LASF312:
+	.ascii	"spl_image_info\000"
+.LASF170:
+	.ascii	"IH_TYPE_SCRIPT\000"
+.LASF120:
+	.ascii	"_datarellocal_start_ofs\000"
+.LASF123:
+	.ascii	"fdt32_t\000"
+.LASF417:
+	.ascii	"slot\000"
+.LASF439:
+	.ascii	"fdt_shrink_to_minimum\000"
+.LASF382:
+	.ascii	"part_info\000"
+.LASF313:
+	.ascii	"entry_point\000"
+.LASF108:
+	.ascii	"bi_enetaddr\000"
+.LASF385:
+	.ascii	"align_len\000"
+.LASF384:
+	.ascii	"spl_kernel_partition\000"
+.LASF318:
+	.ascii	"flags\000"
+.LASF434:
+	.ascii	"fit_conf_get_node\000"
+.LASF407:
+	.ascii	"get_aligned_image_overhead\000"
+.LASF238:
+	.ascii	"fit_noffset_rd\000"
+.LASF326:
+	.ascii	"baudrate\000"
+.LASF359:
+	.ascii	"tos_mem\000"
+.LASF24:
+	.ascii	"errno\000"
+.LASF167:
+	.ascii	"IH_TYPE_RAMDISK\000"
+.LASF361:
+	.ascii	"atf_mem\000"
+.LASF8:
+	.ascii	"unsigned int\000"
+.LASF275:
+	.ascii	"next\000"
+.LASF130:
+	.ascii	"version\000"
+.LASF230:
+	.ascii	"legacy_hdr_os_copy\000"
+.LASF354:
+	.ascii	"tag_header\000"
+.LASF174:
+	.ascii	"IH_TYPE_IMXIMAGE\000"
+.LASF365:
+	.ascii	"spl_image\000"
+.LASF219:
+	.ascii	"ih_name\000"
+.LASF291:
+	.ascii	"net_rx_packet\000"
+.LASF403:
+	.ascii	"external_data\000"
+.LASF241:
+	.ascii	"fit_noffset_fdt\000"
+.LASF50:
+	.ascii	"if_type\000"
+.LASF181:
+	.ascii	"IH_TYPE_GPIMAGE\000"
+.LASF333:
+	.ascii	"tag_ddr_mem\000"
+.LASF25:
+	.ascii	"___strtok\000"
+.LASF97:
+	.ascii	"bi_memsize\000"
+.LASF35:
+	.ascii	"IF_TYPE_ATAPI\000"
+.LASF221:
+	.ascii	"image_info\000"
+.LASF387:
+	.ascii	"spl_fit_standalone_release\000"
+.LASF255:
+	.ascii	"bootm_headers_t\000"
+.LASF204:
+	.ascii	"IH_COMP_LZ4\000"
+.LASF430:
+	.ascii	"fdt_record_loadable\000"
+.LASF115:
+	.ascii	"bd_t\000"
+.LASF460:
+	.ascii	"GNU C11 6.3.1 20170404 -mthumb -mthumb-interwork -m"
+	.ascii	"abi=aapcs-linux -mno-unaligned-access -mfloat-abi=s"
+	.ascii	"oft -march=armv7-a -mtune=cortex-a9 -mfpu=vfpv3-d16"
+	.ascii	" -mtls-dialect=gnu -g -Os -fno-builtin -ffreestandi"
+	.ascii	"ng -fshort-wchar -fno-stack-protector -fno-delete-n"
+	.ascii	"ull-pointer-checks -fstack-usage -ffunction-section"
+	.ascii	"s -fdata-sections -fno-common -ffixed-r9\000"
+.LASF188:
+	.ascii	"IH_TYPE_RKSD\000"
+.LASF261:
+	.ascii	"__dtb_dt_spl_begin\000"
+.LASF308:
+	.ascii	"mem_malloc_end\000"
+.LASF38:
+	.ascii	"IF_TYPE_MMC\000"
+.LASF450:
+	.ascii	"fit_image_verify_with_data\000"
+.LASF152:
+	.ascii	"IH_OS_QNX\000"
+.LASF102:
+	.ascii	"bi_sramsize\000"
+.LASF121:
+	.ascii	"_datarelro_start_ofs\000"
+.LASF331:
+	.ascii	"mode\000"
+.LASF53:
+	.ascii	"SIG_TYPE_MBR\000"
+.LASF298:
+	.ascii	"net_boot_file_name\000"
+.LASF55:
+	.ascii	"SIG_TYPE_COUNT\000"
+.LASF231:
+	.ascii	"legacy_hdr_valid\000"
+.LASF79:
+	.ascii	"bootable\000"
+.LASF350:
+	.ascii	"tag_pstore\000"
+.LASF262:
+	.ascii	"load_addr\000"
+.LASF56:
+	.ascii	"mbr_sig\000"
+.LASF279:
+	.ascii	"net_gateway\000"
+.LASF245:
+	.ascii	"rd_start\000"
+.LASF311:
+	.ascii	"__bss_end\000"
+.LASF413:
+	.ascii	"fit_rollback_index_verify\000"
+.LASF449:
+	.ascii	"fdt_getprop_u32\000"
+.LASF211:
+	.ascii	"ih_size\000"
+.LASF43:
+	.ascii	"IF_TYPE_NVME\000"
+.LASF300:
+	.ascii	"net_boot_file_expected_size_in_blocks\000"
+.LASF169:
+	.ascii	"IH_TYPE_FIRMWARE\000"
+.LASF392:
+	.ascii	"image\000"
+.LASF191:
+	.ascii	"IH_TYPE_ZYNQMPIMAGE\000"
+.LASF40:
+	.ascii	"IF_TYPE_SATA\000"
+.LASF271:
+	.ascii	"send\000"
+.LASF3:
+	.ascii	"signed char\000"
+.LASF129:
+	.ascii	"off_mem_rsvmap\000"
+.LASF316:
+	.ascii	"boot_device\000"
+.LASF258:
+	.ascii	"sha256_der_prefix\000"
+.LASF248:
+	.ascii	"ft_len\000"
+.LASF22:
+	.ascii	"uint32_t\000"
+.LASF146:
+	.ascii	"IH_OS_SCO\000"
+.LASF264:
+	.ascii	"save_size\000"
+.LASF163:
+	.ascii	"IH_OS_COUNT\000"
+.LASF309:
+	.ascii	"mem_malloc_brk\000"
+.LASF323:
+	.ascii	"tag_serial\000"
+.LASF242:
+	.ascii	"fit_hdr_setup\000"
+.LASF65:
+	.ascii	"blksz\000"
+.LASF116:
+	.ascii	"IRQ_STACK_START\000"
+.LASF414:
+	.ascii	"rollback_fd\000"
+.LASF16:
+	.ascii	"__kernel_size_t\000"
+.LASF178:
+	.ascii	"IH_TYPE_KERNEL_NOLOAD\000"
+.LASF187:
+	.ascii	"IH_TYPE_RKIMAGE\000"
+.LASF446:
+	.ascii	"fit_image_get_data_size\000"
+.LASF381:
+	.ascii	"part_name\000"
+.LASF456:
+	.ascii	"fit_find_config_node\000"
+.LASF90:
+	.ascii	"base\000"
+.LASF64:
+	.ascii	"op_flag\000"
+.LASF276:
+	.ascii	"index\000"
+.LASF360:
+	.ascii	"ram_part\000"
+.LASF462:
+	.ascii	"/home/lxh/uboot/u-boot\000"
+.LASF285:
+	.ascii	"net_ethaddr\000"
+.LASF432:
+	.ascii	"fdt_path_offset\000"
+.LASF273:
+	.ascii	"halt\000"
+.LASF10:
+	.ascii	"long long unsigned int\000"
+.LASF205:
+	.ascii	"IH_COMP_ZIMAGE\000"
+.LASF416:
+	.ascii	"otp_index\000"
+.LASF346:
+	.ascii	"part\000"
+.LASF377:
+	.ascii	"os_type\000"
+.LASF67:
+	.ascii	"vendor\000"
+.LASF408:
+	.ascii	"get_aligned_image_offset\000"
+.LASF31:
+	.ascii	"lbaint_t\000"
+.LASF425:
+	.ascii	"fit_hdr\000"
+.LASF426:
+	.ascii	"image_get_magic\000"
+.LASF217:
+	.ascii	"ih_type\000"
+.LASF66:
+	.ascii	"log2blksz\000"
+.LASF46:
+	.ascii	"IF_TYPE_SPINOR\000"
+.LASF109:
+	.ascii	"bi_ethspeed\000"
+.LASF76:
+	.ascii	"disk_partition\000"
+.LASF438:
+	.ascii	"part_get_info_by_name\000"
+.LASF329:
+	.ascii	"tag_bootdev\000"
+.LASF442:
+	.ascii	"fit_image_get_load\000"
+.LASF89:
+	.ascii	"lmb_property\000"
+.LASF324:
+	.ascii	"enable\000"
+.LASF193:
+	.ascii	"IH_TYPE_VYBRIDIMAGE\000"
+.LASF141:
+	.ascii	"IH_OS_LINUX\000"
+.LASF355:
+	.ascii	"core\000"
+.LASF347:
+	.ascii	"tag_soc_info\000"
+.LASF201:
+	.ascii	"IH_COMP_BZIP2\000"
+.LASF151:
+	.ascii	"IH_OS_PSOS\000"
+.LASF155:
+	.ascii	"IH_OS_ARTOS\000"
+.LASF132:
+	.ascii	"boot_cpuid_phys\000"
+.LASF232:
+	.ascii	"fit_uname_cfg\000"
+.LASF427:
+	.ascii	"__fswab32\000"
+.LASF218:
+	.ascii	"ih_comp\000"
+.LASF111:
+	.ascii	"bi_busfreq\000"
+.LASF435:
+	.ascii	"fit_get_desc\000"
+.LASF444:
+	.ascii	"fit_image_get_data_position\000"
+.LASF266:
+	.ascii	"s_addr\000"
+.LASF226:
+	.ascii	"arch\000"
+.LASF406:
+	.ascii	"data_size\000"
+.LASF60:
+	.ascii	"target\000"
+.LASF124:
+	.ascii	"fdt_header\000"
+.LASF15:
+	.ascii	"long int\000"
+.LASF391:
+	.ascii	"blob\000"
+.LASF301:
+	.ascii	"net_loop_state\000"
+.LASF441:
+	.ascii	"fit_image_get_comp\000"
+.LASF396:
+	.ascii	"offset\000"
+.LASF101:
+	.ascii	"bi_sramstart\000"
+.LASF176:
+	.ascii	"IH_TYPE_OMAPIMAGE\000"
+.LASF27:
+	.ascii	"_Bool\000"
+.LASF49:
+	.ascii	"IF_TYPE_COUNT\000"
+.LASF310:
+	.ascii	"__bss_start\000"
+.LASF12:
+	.ascii	"phys_size_t\000"
+.LASF288:
+	.ascii	"net_server_ip\000"
+.LASF41:
+	.ascii	"IF_TYPE_HOST\000"
+.LASF356:
+	.ascii	"serial\000"
+.LASF411:
+	.ascii	"outname\000"
+.LASF223:
+	.ascii	"image_len\000"
+.LASF162:
+	.ascii	"IH_OS_OP_TEE\000"
+.LASF281:
+	.ascii	"net_dns_server\000"
+.LASF87:
+	.ascii	"flash_info\000"
+.LASF454:
+	.ascii	"fit_image_get_data\000"
+.LASF371:
+	.ascii	"base_offset\000"
+.LASF208:
+	.ascii	"ih_magic\000"
+.LASF399:
+	.ascii	"load_ptr\000"
+.LASF58:
+	.ascii	"devnum\000"
+.LASF224:
+	.ascii	"load\000"
+.LASF30:
+	.ascii	"_binary_u_boot_bin_end\000"
+.LASF196:
+	.ascii	"IH_TYPE_PMMC\000"
+.LASF463:
+	.ascii	"load_next\000"
+.LASF240:
+	.ascii	"fit_uname_fdt\000"
+.LASF379:
+	.ascii	"spl_load_kernel_fit\000"
+.LASF455:
+	.ascii	"fdt_subnode_offset\000"
+.LASF335:
+	.ascii	"bank\000"
+.LASF338:
+	.ascii	"tag_tos_mem\000"
+.LASF142:
+	.ascii	"IH_OS_SVR4\000"
+.LASF72:
+	.ascii	"blk_desc\000"
+.LASF177:
+	.ascii	"IH_TYPE_AISIMAGE\000"
+.LASF284:
+	.ascii	"net_root_path\000"
+.LASF73:
+	.ascii	"block_drvr\000"
+.LASF192:
+	.ascii	"IH_TYPE_FPGA\000"
+.LASF334:
+	.ascii	"count\000"
+.LASF428:
+	.ascii	"fit_image_get_os\000"
+.LASF393:
+	.ascii	"spl_fit_load_blob\000"
+.LASF59:
+	.ascii	"part_type\000"
+.LASF233:
+	.ascii	"fit_hdr_os\000"
+.LASF263:
+	.ascii	"save_addr\000"
+.LASF277:
+	.ascii	"priv\000"
+.LASF465:
+	.ascii	"fdt_bootargs_append\000"
+.LASF14:
+	.ascii	"char\000"
+.LASF448:
+	.ascii	"fit_image_is_preload\000"
+.LASF372:
+	.ascii	"node\000"
+.LASF61:
+	.ascii	"hwpart\000"
+.LASF182:
+	.ascii	"IH_TYPE_ATMELIMAGE\000"
+.LASF71:
+	.ascii	"ide_bus_offset\000"
+.LASF419:
+	.ascii	"spl_get_current_slot\000"
+.LASF150:
+	.ascii	"IH_OS_VXWORKS\000"
+.LASF81:
+	.ascii	"sector_count\000"
+.LASF321:
+	.ascii	"filename\000"
+.LASF222:
+	.ascii	"image_start\000"
+.LASF206:
+	.ascii	"IH_COMP_COUNT\000"
+.LASF86:
+	.ascii	"flash_info_t\000"
+.LASF69:
+	.ascii	"revision\000"
+.LASF368:
+	.ascii	"sector_offs\000"
+.LASF214:
+	.ascii	"ih_dcrc\000"
+.LASF287:
+	.ascii	"net_ip\000"
+.LASF336:
+	.ascii	"data\000"
+.LASF154:
+	.ascii	"IH_OS_RTEMS\000"
+.LASF9:
+	.ascii	"long long int\000"
+.LASF128:
+	.ascii	"off_dt_strings\000"
+.LASF367:
+	.ascii	"sector\000"
+.LASF48:
+	.ascii	"IF_TYPE_MTD\000"
+.LASF306:
+	.ascii	"net_state\000"
+.LASF437:
+	.ascii	"strcmp\000"
+.LASF234:
+	.ascii	"fit_uname_os\000"
+.LASF21:
+	.ascii	"uint8_t\000"
+.LASF7:
+	.ascii	"__u32\000"
+.LASF305:
+	.ascii	"NETLOOP_FAIL\000"
+.LASF183:
+	.ascii	"IH_TYPE_SOCFPGAIMAGE\000"
+.LASF400:
+	.ascii	"overhead\000"
+.LASF197:
+	.ascii	"IH_TYPE_RKNAND\000"
+.LASF185:
+	.ascii	"IH_TYPE_LPC32XXIMAGE\000"
+.LASF85:
+	.ascii	"mtd_info\000"
+.LASF80:
+	.ascii	"disk_partition_t\000"
+.LASF145:
+	.ascii	"IH_OS_IRIX\000"
+.LASF166:
+	.ascii	"IH_TYPE_KERNEL\000"
+.LASF135:
+	.ascii	"working_fdt\000"
+.LASF228:
+	.ascii	"bootm_headers\000"
+.LASF398:
+	.ascii	"comp_addr\000"
+.LASF195:
+	.ascii	"IH_TYPE_FIRMWARE_IVT\000"
+.LASF117:
+	.ascii	"FIQ_STACK_START\000"
+.LASF352:
+	.ascii	"pagesize\000"
+.LASF161:
+	.ascii	"IH_OS_ARM_TRUSTED_FIRMWARE\000"
+.LASF268:
+	.ascii	"enetaddr\000"
+.LASF259:
+	.ascii	"monitor_flash_len\000"
+.LASF54:
+	.ascii	"SIG_TYPE_GUID\000"
+.LASF237:
+	.ascii	"fit_uname_rd\000"
+.LASF431:
+	.ascii	"printf\000"
+.LASF84:
+	.ascii	"udevice\000"
+.LASF383:
+	.ascii	"spl_load_simple_fit\000"
+.LASF112:
+	.ascii	"bi_arch_number\000"
+.LASF160:
+	.ascii	"IH_OS_OPENRTOS\000"
+.LASF436:
+	.ascii	"atags_get_tag\000"
+.LASF70:
+	.ascii	"bdev\000"
+.LASF404:
+	.ascii	"preload\000"
+.LASF445:
+	.ascii	"fit_image_get_data_offset\000"
+.LASF126:
+	.ascii	"totalsize\000"
+.LASF103:
+	.ascii	"bi_arm_freq\000"
+.LASF340:
+	.ascii	"drm_mem\000"
+.LASF220:
+	.ascii	"image_header_t\000"
+.LASF98:
+	.ascii	"bi_flashstart\000"
+.LASF320:
+	.ascii	"bl_len\000"
+.LASF297:
+	.ascii	"net_restart_wrap\000"
+.LASF57:
+	.ascii	"guid_sig\000"
+.LASF137:
+	.ascii	"IH_OS_OPENBSD\000"
+.LASF294:
+	.ascii	"net_null_ethaddr\000"
+.LASF464:
+	.ascii	"rk_meta_bootargs_append\000"
+.LASF139:
+	.ascii	"IH_OS_FREEBSD\000"
+.LASF345:
+	.ascii	"tag_ram_partition\000"
+.LASF424:
+	.ascii	"fit_get_name\000"
+.LASF215:
+	.ascii	"ih_os\000"
+.LASF63:
+	.ascii	"removable\000"
+.LASF78:
+	.ascii	"size\000"
+.LASF143:
+	.ascii	"IH_OS_ESIX\000"
+.LASF199:
+	.ascii	"IH_COMP_NONE\000"
+.LASF349:
+	.ascii	"param\000"
+.LASF314:
+	.ascii	"entry_point_os\000"
+.LASF421:
+	.ascii	"partition\000"
+.LASF37:
+	.ascii	"IF_TYPE_DOC\000"
+.LASF362:
+	.ascii	"pub_key\000"
+.LASF458:
+	.ascii	"fdt_next_subnode\000"
+.LASF200:
+	.ascii	"IH_COMP_GZIP\000"
+.LASF190:
+	.ascii	"IH_TYPE_ZYNQIMAGE\000"
+.LASF433:
+	.ascii	"fit_board_verify_required_sigs\000"
+.LASF83:
+	.ascii	"protect\000"
+.LASF366:
+	.ascii	"info\000"
+.LASF1:
+	.ascii	"long unsigned int\000"
+.LASF171:
+	.ascii	"IH_TYPE_FILESYSTEM\000"
+.LASF207:
+	.ascii	"image_header\000"
+.LASF131:
+	.ascii	"last_comp_version\000"
+.LASF357:
+	.ascii	"bootdev\000"
+.LASF260:
+	.ascii	"__dtb_dt_begin\000"
+.LASF375:
+	.ascii	"this_index\000"
+.LASF351:
+	.ascii	"tag_core\000"
+.LASF180:
+	.ascii	"IH_TYPE_MXSIMAGE\000"
+.LASF203:
+	.ascii	"IH_COMP_LZO\000"
+.LASF252:
+	.ascii	"cmdline_end\000"
+.LASF278:
+	.ascii	"eth_current\000"
+.LASF47:
+	.ascii	"IF_TYPE_RAMDISK\000"
+.LASF127:
+	.ascii	"off_dt_struct\000"
+.LASF148:
+	.ascii	"IH_OS_NCR\000"
+.LASF173:
+	.ascii	"IH_TYPE_KWBIMAGE\000"
+.LASF280:
+	.ascii	"net_netmask\000"
+.LASF147:
+	.ascii	"IH_OS_DELL\000"
+.LASF95:
+	.ascii	"bd_info\000"
+.LASF251:
+	.ascii	"cmdline_start\000"
+.LASF256:
+	.ascii	"images\000"
+.LASF394:
+	.ascii	"spl_fit_append_fdt\000"
+.LASF88:
+	.ascii	"long double\000"
+.LASF229:
+	.ascii	"legacy_hdr_os\000"
+.LASF452:
+	.ascii	"puts\000"
+.LASF389:
+	.ascii	"noffset\000"
+.LASF18:
+	.ascii	"size_t\000"
+.LASF107:
+	.ascii	"bi_ip_addr\000"
+.LASF420:
+	.ascii	"dev_desc\000"
+.LASF110:
+	.ascii	"bi_intfreq\000"
+.LASF158:
+	.ascii	"IH_OS_OSE\000"
+.LASF461:
+	.ascii	"common/spl/spl_fit_tb.c\000"
+.LASF11:
+	.ascii	"phys_addr_t\000"
+.LASF332:
+	.ascii	"sdupdate\000"
+.LASF153:
+	.ascii	"IH_OS_U_BOOT\000"
+.LASF289:
+	.ascii	"net_tx_packet\000"
+.LASF249:
+	.ascii	"initrd_start\000"
+.LASF459:
+	.ascii	"strchr\000"
+.LASF330:
+	.ascii	"devtype\000"
+.LASF6:
+	.ascii	"short int\000"
+.LASF184:
+	.ascii	"IH_TYPE_X86_SETUP\000"
+.LASF213:
+	.ascii	"ih_ep\000"
+.LASF216:
+	.ascii	"ih_arch\000"
+.LASF32:
+	.ascii	"IF_TYPE_UNKNOWN\000"
+.LASF395:
+	.ascii	"spl_load_fit_image\000"
+.LASF328:
+	.ascii	"hash\000"
+.LASF29:
+	.ascii	"_binary_u_boot_bin_start\000"
+.LASF369:
+	.ascii	"fit_header\000"
+.LASF397:
+	.ascii	"length\000"
+.LASF36:
+	.ascii	"IF_TYPE_USB\000"
+.LASF140:
+	.ascii	"IH_OS_4_4BSD\000"
+.LASF282:
+	.ascii	"net_nis_domain\000"
+.LASF212:
+	.ascii	"ih_load\000"
+.LASF423:
+	.ascii	"fit_config_verify\000"
+.LASF304:
+	.ascii	"NETLOOP_SUCCESS\000"
+.LASF315:
+	.ascii	"fdt_addr\000"
+.LASF202:
+	.ascii	"IH_COMP_LZMA\000"
+.LASF409:
+	.ascii	"spl_fit_get_image_node\000"
+.LASF344:
+	.ascii	"flag\000"
+.LASF374:
+	.ascii	"conf_noffset\000"
+.LASF20:
+	.ascii	"ulong\000"
+.LASF210:
+	.ascii	"ih_time\000"
+.LASF100:
+	.ascii	"bi_flashoffset\000"
+.LASF165:
+	.ascii	"IH_TYPE_STANDALONE\000"
+.LASF269:
+	.ascii	"iobase\000"
+.LASF302:
+	.ascii	"NETLOOP_CONTINUE\000"
+.LASF198:
+	.ascii	"IH_TYPE_COUNT\000"
+.LASF342:
+	.ascii	"tag_atf_mem\000"
+.LASF290:
+	.ascii	"net_rx_packets\000"
+.LASF341:
+	.ascii	"reserved1\000"
+.LASF92:
+	.ascii	"region\000"
+.LASF247:
+	.ascii	"ft_addr\000"
+.LASF410:
+	.ascii	"spl_fit_get_image_name\000"
+.LASF418:
+	.ascii	"spl_load_meta\000"
+.LASF440:
+	.ascii	"fdt_get_name\000"
+.LASF322:
+	.ascii	"read\000"
+.LASF77:
+	.ascii	"start\000"
+.LASF243:
+	.ascii	"fit_uname_setup\000"
+.LASF28:
+	.ascii	"image_base\000"
+.LASF26:
+	.ascii	"efi_guid_t\000"
+.LASF364:
+	.ascii	"pstore\000"
+.LASF125:
+	.ascii	"magic\000"
+.LASF236:
+	.ascii	"fit_hdr_rd\000"
+.LASF239:
+	.ascii	"fit_hdr_fdt\000"
+.LASF17:
+	.ascii	"uintptr_t\000"
+.LASF386:
+	.ascii	"sectors\000"
+.LASF274:
+	.ascii	"write_hwaddr\000"
+.LASF390:
+	.ascii	"spl_fit_record_loadable\000"
+.LASF270:
+	.ascii	"init\000"
+.LASF113:
+	.ascii	"bi_boot_params\000"
+.LASF358:
+	.ascii	"ddr_mem\000"
+.LASF13:
+	.ascii	"sizetype\000"
+.LASF168:
+	.ascii	"IH_TYPE_MULTI\000"
+.LASF172:
+	.ascii	"IH_TYPE_FLATDT\000"
+.LASF189:
+	.ascii	"IH_TYPE_RKSPI\000"
+.LASF5:
+	.ascii	"__u8\000"
+.LASF118:
+	.ascii	"_datarel_start_ofs\000"
+.LASF96:
+	.ascii	"bi_memstart\000"
+.LASF209:
+	.ascii	"ih_hcrc\000"
+.LASF133:
+	.ascii	"size_dt_strings\000"
+.LASF179:
+	.ascii	"IH_TYPE_PBLIMAGE\000"
+.LASF227:
+	.ascii	"image_info_t\000"
+.LASF93:
+	.ascii	"memory\000"
+.LASF134:
+	.ascii	"size_dt_struct\000"
+.LASF246:
+	.ascii	"rd_end\000"
+.LASF265:
+	.ascii	"in_addr\000"
+.LASF250:
+	.ascii	"initrd_end\000"
+.LASF23:
+	.ascii	"__be32\000"
+.LASF122:
+	.ascii	"IRQ_STACK_START_IN\000"
+.LASF412:
+	.ascii	"conf_node\000"
+.LASF62:
+	.ascii	"type\000"
+.LASF380:
+	.ascii	"images_noffset\000"
+.LASF292:
+	.ascii	"net_rx_packet_len\000"
+.LASF0:
+	.ascii	"unsigned char\000"
+.LASF19:
+	.ascii	"ushort\000"
+.LASF39:
+	.ascii	"IF_TYPE_SD\000"
+.LASF194:
+	.ascii	"IH_TYPE_TEE\000"
+.LASF401:
+	.ascii	"nr_sectors\000"
+.LASF105:
+	.ascii	"bi_ddr_freq\000"
+.LASF402:
+	.ascii	"image_comp\000"
+.LASF244:
+	.ascii	"fit_noffset_setup\000"
+.LASF149:
+	.ascii	"IH_OS_LYNXOS\000"
+.LASF52:
+	.ascii	"SIG_TYPE_NONE\000"
+.LASF257:
+	.ascii	"sha1_der_prefix\000"
+.LASF325:
+	.ascii	"addr\000"
+.LASF136:
+	.ascii	"IH_OS_INVALID\000"
+.LASF254:
+	.ascii	"state\000"
+.LASF447:
+	.ascii	"memalign_simple\000"
+.LASF339:
+	.ascii	"tee_mem\000"
+.LASF293:
+	.ascii	"net_bcast_ethaddr\000"
+.LASF235:
+	.ascii	"fit_noffset_os\000"
+.LASF353:
+	.ascii	"rootdev\000"
+.LASF286:
+	.ascii	"net_server_ethaddr\000"
+.LASF451:
+	.ascii	"board_fit_image_post_process\000"
+.LASF343:
+	.ascii	"tag_pub_key\000"
+.LASF157:
+	.ascii	"IH_OS_INTEGRITY\000"
+.LASF175:
+	.ascii	"IH_TYPE_UBLIMAGE\000"
+.LASF267:
+	.ascii	"eth_device\000"
+.LASF415:
+	.ascii	"fit_index\000"
+.LASF272:
+	.ascii	"recv\000"
+.LASF75:
+	.ascii	"select_hwpart\000"
+.LASF466:
+	.ascii	"fdt_bootargs_append_ab\000"
+.LASF4:
+	.ascii	"uchar\000"
+.LASF99:
+	.ascii	"bi_flashsize\000"
+.LASF295:
+	.ascii	"net_our_vlan\000"
+.LASF2:
+	.ascii	"short unsigned int\000"
+.LASF34:
+	.ascii	"IF_TYPE_SCSI\000"
+.LASF104:
+	.ascii	"bi_dsp_freq\000"
+.LASF363:
+	.ascii	"boot1p\000"
+.LASF453:
+	.ascii	"memcpy\000"
+.LASF317:
+	.ascii	"next_stage\000"
+.LASF144:
+	.ascii	"IH_OS_SOLARIS\000"
+.LASF42:
+	.ascii	"IF_TYPE_SYSTEMACE\000"
+.LASF373:
+	.ascii	"__func__\000"
+.LASF94:
+	.ascii	"reserved\000"
+.LASF186:
+	.ascii	"IH_TYPE_LOADABLE\000"
+.LASF51:
+	.ascii	"sig_type\000"
+.LASF68:
+	.ascii	"product\000"
+.LASF119:
+	.ascii	"_datarelrolocal_start_ofs\000"
+.LASF33:
+	.ascii	"IF_TYPE_IDE\000"
+.LASF405:
+	.ascii	"get_aligned_image_size\000"
+.LASF253:
+	.ascii	"verify\000"
+.LASF370:
+	.ascii	"desc\000"
+.LASF388:
+	.ascii	"spl_fit_image_get_os\000"
+.LASF106:
+	.ascii	"bi_bootflags\000"
+.LASF327:
+	.ascii	"m_mode\000"
+.LASF114:
+	.ascii	"bi_dram\000"
+.LASF225:
+	.ascii	"comp\000"
+.LASF296:
+	.ascii	"net_native_vlan\000"
+.LASF159:
+	.ascii	"IH_OS_PLAN9\000"
+.LASF138:
+	.ascii	"IH_OS_NETBSD\000"
+.LASF376:
+	.ascii	"min_index\000"
+.LASF443:
+	.ascii	"fit_image_get_comp_addr\000"
+.LASF378:
+	.ascii	"spl_internal_load_simple_fit\000"
+.LASF348:
+	.ascii	"tag_boot1p\000"
+.LASF156:
+	.ascii	"IH_OS_UNITY\000"
+.LASF164:
+	.ascii	"IH_TYPE_INVALID\000"
+.LASF337:
+	.ascii	"phy_addr\000"
+.LASF422:
+	.ascii	"mtd_part_parse\000"
+.LASF429:
+	.ascii	"fdt_getprop\000"
+.LASF91:
+	.ascii	"lmb_region\000"
+	.ident	"GCC: (Linaro GCC 6.3-2017.05) 6.3.1 20170404"
+	.section	.note.GNU-stack,"",%progbits
diff --git a/u-boot/common/spl/spl_fit_tb_arm32.S b/u-boot/common/spl/spl_fit_tb_rv1126.S
similarity index 100%
rename from u-boot/common/spl/spl_fit_tb_arm32.S
rename to u-boot/common/spl/spl_fit_tb_rv1126.S
diff --git a/u-boot/common/stdio.c b/u-boot/common/stdio.c
index fbf06e29f0..a61a05a147 100644
--- a/u-boot/common/stdio.c
+++ b/u-boot/common/stdio.c
@@ -368,16 +368,11 @@ int stdio_add_devices(void)
 	 */
 #ifndef CONFIG_SYS_CONSOLE_IS_IN_ENV
 	struct udevice *vdev;
-# ifndef CONFIG_DM_KEYBOARD
-	int ret;
-# endif
 
-	for (ret = uclass_first_device(UCLASS_VIDEO, &vdev);
+	for (uclass_first_device(UCLASS_VIDEO, &vdev);
 	     vdev;
-	     ret = uclass_next_device(&vdev))
+	     uclass_next_device(&vdev))
 		;
-	if (ret)
-		printf("%s: Video device failed (ret=%d)\n", __func__, ret);
 #endif /* !CONFIG_SYS_CONSOLE_IS_IN_ENV */
 #else
 # if defined(CONFIG_LCD)
diff --git a/u-boot/common/write_keybox.c b/u-boot/common/write_keybox.c
old mode 100755
new mode 100644
index 15f370fe09..bbb3775293
--- a/u-boot/common/write_keybox.c
+++ b/u-boot/common/write_keybox.c
@@ -7,6 +7,7 @@
 #include <boot_rkimg.h>
 #include <stdlib.h>
 #include <attestation_key.h>
+#include <id_attestation.h>
 #include <write_keybox.h>
 #include <keymaster.h>
 #include <optee_include/OpteeClientApiLib.h>
@@ -18,6 +19,7 @@
 #define	BOOT_FROM_EMMC	(1 << 1)
 #define	WIDEVINE_TAG	"KBOX"
 #define	ATTESTATION_TAG	"ATTE"
+#define	ID_ATTESTATION_TAG "IDAT"
 #define PLAYREADY30_TAG	"SL30"
 
 TEEC_Result write_to_security_storage(uint8_t is_use_rpmb,
@@ -224,6 +226,7 @@ uint32_t write_keybox_to_secure_storage(uint8_t *received_data, uint32_t len)
 {
 	uint8_t *widevine_data;
 	uint8_t *attestation_data;
+	uint8_t *id_attestation_data;
 	uint8_t *playready_sl30_data;
 	uint32_t key_size;
 	uint32_t data_size;
@@ -255,6 +258,8 @@ uint32_t write_keybox_to_secure_storage(uint8_t *received_data, uint32_t len)
 					      WIDEVINE_TAG, len);
 	attestation_data = (uint8_t *)new_strstr((char *)received_data,
 						 ATTESTATION_TAG, len);
+	id_attestation_data = (uint8_t *)new_strstr((char *)received_data,
+						    ID_ATTESTATION_TAG, len);
 	playready_sl30_data = (uint8_t *)new_strstr((char *)received_data,
 						    PLAYREADY30_TAG, len);
 	if (widevine_data) {
@@ -293,6 +298,16 @@ uint32_t write_keybox_to_secure_storage(uint8_t *received_data, uint32_t len)
 			rc = -EIO;
 			printf("write attestation key to secure storage fail\n");
 		}
+	} else if (id_attestation_data) {
+		/* id attestation */
+		ret = write_id_attestation_to_secure_storage(id_attestation_data, len);
+		if (ret == ATAP_RESULT_OK) {
+			rc = 0;
+			printf("write id attestation success!\n");
+		} else {
+			rc = -EIO;
+			printf("write id attestation failed\n");
+		}
 	} else if (playready_sl30_data) {
 		/* PlayReady SL3000 root key */
 		uint32_t ret;
diff --git a/u-boot/configs/gki.config b/u-boot/configs/gki.config
new file mode 100644
index 0000000000..03a7dfea4c
--- /dev/null
+++ b/u-boot/configs/gki.config
@@ -0,0 +1 @@
+CONFIG_ANDROID_AB=y
diff --git a/u-boot/configs/rk-amp.config b/u-boot/configs/rk-amp.config
index b76e182dbc..ab248f8ad5 100644
--- a/u-boot/configs/rk-amp.config
+++ b/u-boot/configs/rk-amp.config
@@ -1,3 +1,2 @@
-# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
 CONFIG_AMP=y
 CONFIG_ROCKCHIP_AMP=y
diff --git a/u-boot/configs/rk322x_defconfig b/u-boot/configs/rk322x_defconfig
index 22621cde4a..82ea3feff6 100644
--- a/u-boot/configs/rk322x_defconfig
+++ b/u-boot/configs/rk322x_defconfig
@@ -86,6 +86,8 @@ CONFIG_ETH_DESIGNWARE=y
 CONFIG_GMAC_ROCKCHIP=y
 CONFIG_PHY_ROCKCHIP_INNO_USB2=y
 CONFIG_PINCTRL=y
+CONFIG_IO_DOMAIN=y
+CONFIG_ROCKCHIP_IO_DOMAIN=y
 CONFIG_DM_PMIC=y
 CONFIG_PMIC_RK8XX=y
 CONFIG_REGULATOR_PWM=y
diff --git a/u-boot/configs/rk3308-ia.config b/u-boot/configs/rk3308-ia.config
new file mode 100644
index 0000000000..a0a498c33b
--- /dev/null
+++ b/u-boot/configs/rk3308-ia.config
@@ -0,0 +1,14 @@
+# CONFIG_CMD_ATAGS is not set
+# CONFIG_CMD_DHCP is not set
+# CONFIG_CMD_MMC is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_PING is not set
+# CONFIG_DM_ETH is not set
+# CONFIG_DM_MMC is not set
+# CONFIG_FIT is not set
+# CONFIG_LED is not set
+# CONFIG_MMC is not set
+# CONFIG_NET is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_REGEX is not set
+# CONFIG_RKNANDC_NAND is not set
diff --git a/u-boot/configs/rk3308_defconfig b/u-boot/configs/rk3308_defconfig
index 6150026c66..db34dd5bc1 100644
--- a/u-boot/configs/rk3308_defconfig
+++ b/u-boot/configs/rk3308_defconfig
@@ -81,6 +81,8 @@ CONFIG_PHY_ROCKCHIP_INNO_USB2=y
 CONFIG_PINCTRL=y
 CONFIG_DM_FUEL_GAUGE=y
 CONFIG_POWER_FG_RK816=y
+CONFIG_IO_DOMAIN=y
+CONFIG_ROCKCHIP_IO_DOMAIN=y
 CONFIG_DM_PMIC=y
 # CONFIG_SPL_PMIC_CHILDREN is not set
 CONFIG_PMIC_RK8XX=y
diff --git a/u-boot/configs/rk3328_defconfig b/u-boot/configs/rk3328_defconfig
index 03de227eb2..45383565fe 100644
--- a/u-boot/configs/rk3328_defconfig
+++ b/u-boot/configs/rk3328_defconfig
@@ -5,7 +5,6 @@ CONFIG_SPL_LIBGENERIC_SUPPORT=y
 CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_SPL_FIT_GENERATOR="arch/arm/mach-rockchip/make_fit_atf.py"
 CONFIG_ROCKCHIP_RK3328=y
-CONFIG_RKIMG_BOOTLOADER=y
 CONFIG_ROCKCHIP_VENDOR_PARTITION=y
 CONFIG_TPL_LIBCOMMON_SUPPORT=y
 CONFIG_TPL_LIBGENERIC_SUPPORT=y
@@ -89,6 +88,8 @@ CONFIG_SF_DEFAULT_SPEED=20000000
 CONFIG_PHY_ROCKCHIP_INNO_USB2=y
 CONFIG_PHY_ROCKCHIP_INNO_USB3=y
 CONFIG_PINCTRL=y
+CONFIG_IO_DOMAIN=y
+CONFIG_ROCKCHIP_IO_DOMAIN=y
 CONFIG_DM_PMIC=y
 CONFIG_PMIC_RK8XX=y
 CONFIG_REGULATOR_PWM=y
@@ -118,11 +119,11 @@ CONFIG_USB_DWC3=y
 CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DWC2_OTG=y
-CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_USB_GADGET_MANUFACTURER="Rockchip"
 CONFIG_USB_GADGET_VENDOR_NUM=0x2207
 CONFIG_USB_GADGET_PRODUCT_NUM=0x330a
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_DM_VIDEO=y
 CONFIG_DISPLAY=y
 CONFIG_DRM_ROCKCHIP=y
@@ -133,7 +134,6 @@ CONFIG_DRM_ROCKCHIP_TVE=y
 CONFIG_LCD=y
 # CONFIG_IRQ is not set
 CONFIG_USE_TINY_PRINTF=y
-CONFIG_PANIC_HANG=y
 CONFIG_SPL_TINY_MEMSET=y
 CONFIG_TPL_TINY_MEMSET=y
 CONFIG_ERRNO_STR=y
diff --git a/u-boot/configs/rk3528-usbplug.config b/u-boot/configs/rk3528-usbplug.config
new file mode 100644
index 0000000000..758a68fc1c
--- /dev/null
+++ b/u-boot/configs/rk3528-usbplug.config
@@ -0,0 +1,25 @@
+CONFIG_BASE_DEFCONFIG="rockchip-usbplug_defconfig"
+# CONFIG_TARGET_EVB_RV1126 is not set
+# CONFIG_ROCKCHIP_RV1126 is not set
+CONFIG_DEBUG_UART_BASE=0xff9f0000
+CONFIG_DEFAULT_DEVICE_TREE="rk3528-evb"
+CONFIG_ROCKCHIP_RK3528=y
+CONFIG_TARGET_EVB_RK3528=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SDMA=y
+CONFIG_MMC_SDHCI_ROCKCHIP=y
+CONFIG_ROCKCHIP_NEW_IDB=y
+# CONFIG_CLK_SCMI is not set
+# CONFIG_SCMI_FIRMWARE is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_DW_ROCKCHIP is not set
+CONFIG_ROCKCHIP_BOOT_MODE_REG=0xff370200
+CONFIG_ROCKCHIP_STIMER_BASE=0xff620000
+CONFIG_ROCKCHIP_IRAM_START_ADDR=0xfe480000
+# CONFIG_ROCKCHIP_SFC is not set
+# CONFIG_MTD is not set
+# CONFIG_MTD_BLK is not set
+# CONFIG_MTD_DEVICE is not set
+# CONFIG_SPI_FLASH is not set
+CONFIG_PHY_ROCKCHIP_NANENG_COMBOPHY=y
+CONFIG_DM_RESET=y
diff --git a/u-boot/configs/rk3562-usbplug.config b/u-boot/configs/rk3562-usbplug.config
new file mode 100644
index 0000000000..f019ef4117
--- /dev/null
+++ b/u-boot/configs/rk3562-usbplug.config
@@ -0,0 +1,25 @@
+CONFIG_BASE_DEFCONFIG="rockchip-usbplug_defconfig"
+# CONFIG_TARGET_EVB_RV1126 is not set
+# CONFIG_ROCKCHIP_RV1126 is not set
+CONFIG_DEBUG_UART_BASE=0xff210000
+CONFIG_DEFAULT_DEVICE_TREE="rk3562-evb"
+CONFIG_ROCKCHIP_RK3562=y
+CONFIG_TARGET_EVB_RK3562=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SDMA=y
+CONFIG_MMC_SDHCI_ROCKCHIP=y
+CONFIG_ROCKCHIP_NEW_IDB=y
+# CONFIG_CLK_SCMI is not set
+# CONFIG_SCMI_FIRMWARE is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_DW_ROCKCHIP is not set
+CONFIG_ROCKCHIP_BOOT_MODE_REG=0xff010220
+CONFIG_ROCKCHIP_STIMER_BASE=0xffa90020
+CONFIG_ROCKCHIP_IRAM_START_ADDR=0xfe480000
+# CONFIG_ROCKCHIP_SFC is not set
+# CONFIG_MTD is not set
+# CONFIG_MTD_BLK is not set
+# CONFIG_MTD_DEVICE is not set
+# CONFIG_SPI_FLASH is not set
+CONFIG_PHY_ROCKCHIP_NANENG_COMBOPHY=y
+CONFIG_DM_RESET=y
diff --git a/u-boot/configs/rk3562_defconfig b/u-boot/configs/rk3562_defconfig
index 229e37b634..cf6fb9ad9a 100644
--- a/u-boot/configs/rk3562_defconfig
+++ b/u-boot/configs/rk3562_defconfig
@@ -32,6 +32,7 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_ANDROID_BOOTLOADER=y
 CONFIG_ANDROID_AVB=y
 CONFIG_ANDROID_BOOT_IMAGE_HASH=y
+CONFIG_BOARD_RNG_SEED=y
 CONFIG_SPL_BOARD_INIT=y
 # CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
 # CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
diff --git a/u-boot/configs/rk3568-pcie-ep_defconfig b/u-boot/configs/rk3568-pcie-ep_defconfig
new file mode 100644
index 0000000000..fc22f81d67
--- /dev/null
+++ b/u-boot/configs/rk3568-pcie-ep_defconfig
@@ -0,0 +1,226 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x80000
+CONFIG_SPL_FIT_GENERATOR="arch/arm/mach-rockchip/make_fit_atf.sh"
+CONFIG_ROCKCHIP_RK3568=y
+CONFIG_ROCKCHIP_FIT_IMAGE=y
+CONFIG_ROCKCHIP_VENDOR_PARTITION=y
+CONFIG_ROCKCHIP_FIT_IMAGE_PACK=y
+CONFIG_ROCKCHIP_NEW_IDB=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_TARGET_EVB_RK3568=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="rk3568-evb"
+CONFIG_DEBUG_UART=y
+CONFIG_FIT=y
+CONFIG_FIT_IMAGE_POST_PROCESS=y
+CONFIG_FIT_HW_CRYPTO=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
+CONFIG_SPL_FIT_HW_CRYPTO=y
+# CONFIG_SPL_SYS_DCACHE_OFF is not set
+CONFIG_BOOTDELAY=0
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_ANDROID_BOOTLOADER=y
+CONFIG_ANDROID_AVB=y
+CONFIG_ANDROID_BOOT_IMAGE_HASH=y
+CONFIG_BOARD_RNG_SEED=y
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
+CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
+CONFIG_SPL_SHA256_SUPPORT=y
+CONFIG_SPL_CRYPTO_SUPPORT=y
+CONFIG_SPL_HASH_SUPPORT=y
+CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_PCIE_EP_SUPPORT=y
+CONFIG_SPL_ATF=y
+CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y
+CONFIG_SPL_AB=y
+CONFIG_FASTBOOT_BUF_ADDR=0xc00800
+CONFIG_FASTBOOT_BUF_SIZE=0x04000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DTIMG=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_LZMADEC is not set
+# CONFIG_CMD_UNZIP is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_GPT=y
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_BOOT_ANDROID=y
+CONFIG_CMD_BOOT_ROCKCHIP=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_NAND=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+# CONFIG_CMD_ITEST is not set
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_TFTP_BOOTM=y
+CONFIG_CMD_TFTP_FLASH=y
+# CONFIG_CMD_MISC is not set
+# CONFIG_CMD_CHARGE_DISPLAY is not set
+CONFIG_CMD_MTD_BLK=y
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_ISO_PARTITION is not set
+CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=64
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_SPL_DTB_MINIMUM=y
+CONFIG_OF_LIVE=y
+CONFIG_OF_SPL_REMOVE_PROPS="clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+# CONFIG_NET_TFTP_VARS is not set
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_CLK_SCMI=y
+CONFIG_DM_CRYPTO=y
+CONFIG_SPL_DM_CRYPTO=y
+CONFIG_ROCKCHIP_CRYPTO_V2=y
+CONFIG_SPL_ROCKCHIP_CRYPTO_V2=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_ROCKCHIP=y
+CONFIG_SCMI_FIRMWARE=y
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_ROCKCHIP_GPIO_V2=y
+CONFIG_SYS_I2C_ROCKCHIP=y
+CONFIG_DM_KEY=y
+CONFIG_RK8XX_PWRKEY=y
+CONFIG_ADC_KEY=y
+CONFIG_MISC=y
+CONFIG_SPL_MISC=y
+CONFIG_ROCKCHIP_OTP=y
+CONFIG_SPL_ROCKCHIP_SECURE_OTP=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SDMA=y
+CONFIG_MMC_SDHCI_ROCKCHIP=y
+CONFIG_MTD=y
+CONFIG_MTD_BLK=y
+CONFIG_MTD_DEVICE=y
+CONFIG_MTD_SPI_NAND=y
+# CONFIG_SPI_NAND_TOSHIBA is not set
+# CONFIG_SPI_NAND_BIWIN is not set
+# CONFIG_SPI_NAND_ETRON is not set
+# CONFIG_SPI_NAND_JSC is not set
+# CONFIG_SPI_NAND_SILICONGO is not set
+# CONFIG_SPI_NAND_UNIM is not set
+# CONFIG_SPI_NAND_SKYHIGH is not set
+# CONFIG_SPI_NAND_GSTO is not set
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_SPEED=20000000
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_XMC=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
+CONFIG_DM_ETH_PHY=y
+CONFIG_DWC_ETH_QOS=y
+CONFIG_GMAC_ROCKCHIP=y
+CONFIG_PHY_ROCKCHIP_INNO_USB2=y
+CONFIG_PHY_ROCKCHIP_NANENG_COMBOPHY=y
+CONFIG_PHY_ROCKCHIP_NANENG_EDP=y
+CONFIG_PINCTRL=y
+CONFIG_SPL_PINCTRL=y
+CONFIG_DM_FUEL_GAUGE=y
+CONFIG_POWER_FG_RK817=y
+CONFIG_IO_DOMAIN=y
+CONFIG_ROCKCHIP_IO_DOMAIN=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_RK8XX=y
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_PWM=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_REGULATOR_RK8XX=y
+CONFIG_DM_CHARGE_DISPLAY=y
+CONFIG_CHARGE_ANIMATION=y
+CONFIG_PWM_ROCKCHIP=y
+CONFIG_RAM=y
+CONFIG_SPL_RAM=y
+CONFIG_TPL_RAM=y
+CONFIG_DM_RAMDISK=y
+CONFIG_RAMDISK_RO=y
+CONFIG_DM_DMC=y
+CONFIG_ROCKCHIP_DMC_FSP=y
+CONFIG_ROCKCHIP_SDRAM_COMMON=y
+CONFIG_ROCKCHIP_TPL_INIT_DRAM_TYPE=0
+CONFIG_DM_RESET=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_RESET_ROCKCHIP=y
+CONFIG_BAUDRATE=1500000
+CONFIG_DEBUG_UART_BASE=0xFE660000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_ROCKCHIP_SFC=y
+CONFIG_SYSRESET=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_GENERIC=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_GENERIC=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="Rockchip"
+CONFIG_USB_GADGET_VENDOR_NUM=0x2207
+CONFIG_USB_GADGET_PRODUCT_NUM=0x350a
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_DM_VIDEO=y
+CONFIG_DISPLAY=y
+CONFIG_DRM_ROCKCHIP=y
+CONFIG_DRM_ROCKCHIP_DW_HDMI=y
+CONFIG_DRM_ROCKCHIP_INNO_MIPI_PHY=y
+CONFIG_DRM_ROCKCHIP_INNO_VIDEO_COMBO_PHY=y
+CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI=y
+CONFIG_DRM_ROCKCHIP_ANALOGIX_DP=y
+CONFIG_DRM_ROCKCHIP_LVDS=y
+CONFIG_DRM_ROCKCHIP_RGB=y
+CONFIG_ROCKCHIP_CUBIC_LUT_SIZE=9
+CONFIG_LCD=y
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_RSA=y
+CONFIG_SPL_RSA=y
+CONFIG_RSA_N_SIZE=0x200
+CONFIG_RSA_E_SIZE=0x10
+CONFIG_RSA_C_SIZE=0x20
+CONFIG_XBC=y
+CONFIG_SHA512=y
+CONFIG_LZ4=y
+CONFIG_LZMA=y
+CONFIG_SPL_GZIP=y
+CONFIG_ERRNO_STR=y
+# CONFIG_EFI_LOADER is not set
+CONFIG_AVB_LIBAVB=y
+CONFIG_AVB_LIBAVB_AB=y
+CONFIG_AVB_LIBAVB_ATX=y
+CONFIG_AVB_LIBAVB_USER=y
+CONFIG_RK_AVB_LIBAVB_USER=y
+CONFIG_OPTEE_CLIENT=y
+CONFIG_OPTEE_V2=y
+CONFIG_OPTEE_ALWAYS_USE_SECURITY_PARTITION=y
diff --git a/u-boot/configs/rk3568-usbplug.config b/u-boot/configs/rk3568-usbplug.config
index 3700d08844..01542bf95f 100644
--- a/u-boot/configs/rk3568-usbplug.config
+++ b/u-boot/configs/rk3568-usbplug.config
@@ -9,3 +9,17 @@ CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_SDMA=y
 CONFIG_MMC_SDHCI_ROCKCHIP=y
 CONFIG_ROCKCHIP_NEW_IDB=y
+# CONFIG_CLK_SCMI is not set
+# CONFIG_SCMI_FIRMWARE is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_DW_ROCKCHIP is not set
+CONFIG_ROCKCHIP_BOOT_MODE_REG=0xfdc20200
+CONFIG_ROCKCHIP_STIMER_BASE=0xfdd1c020
+CONFIG_ROCKCHIP_IRAM_START_ADDR=0xfdcc0000
+# CONFIG_ROCKCHIP_SFC is not set
+# CONFIG_MTD is not set
+# CONFIG_MTD_BLK is not set
+# CONFIG_MTD_DEVICE is not set
+# CONFIG_SPI_FLASH is not set
+CONFIG_PHY_ROCKCHIP_NANENG_COMBOPHY=y
+CONFIG_DM_RESET=y
diff --git a/u-boot/configs/rk3568_defconfig b/u-boot/configs/rk3568_defconfig
index 10e39385a5..acd1fb1816 100644
--- a/u-boot/configs/rk3568_defconfig
+++ b/u-boot/configs/rk3568_defconfig
@@ -20,6 +20,7 @@ CONFIG_SPL_SPI_FLASH_SUPPORT=y
 CONFIG_SPL_SPI_SUPPORT=y
 CONFIG_DEFAULT_DEVICE_TREE="rk3568-evb"
 CONFIG_DEBUG_UART=y
+CONFIG_IMAGE_GZIP=y
 CONFIG_FIT=y
 CONFIG_FIT_IMAGE_POST_PROCESS=y
 CONFIG_FIT_HW_CRYPTO=y
@@ -33,6 +34,7 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_ANDROID_BOOTLOADER=y
 CONFIG_ANDROID_AVB=y
 CONFIG_ANDROID_BOOT_IMAGE_HASH=y
+CONFIG_BOARD_RNG_SEED=y
 CONFIG_SPL_BOARD_INIT=y
 # CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
 # CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
@@ -166,7 +168,7 @@ CONFIG_ROCKCHIP_TPL_INIT_DRAM_TYPE=0
 CONFIG_DM_RESET=y
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_RESET_ROCKCHIP=y
-CONFIG_BAUDRATE=115200
+CONFIG_BAUDRATE=1500000
 CONFIG_DEBUG_UART_BASE=0xFE660000
 CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_DEBUG_UART_SHIFT=2
diff --git a/u-boot/configs/rk3583.config b/u-boot/configs/rk3583.config
new file mode 100644
index 0000000000..9a9b6cfa13
--- /dev/null
+++ b/u-boot/configs/rk3583.config
@@ -0,0 +1,2 @@
+CONFIG_BASE_DEFCONFIG="rk3588_defconfig"
+CONFIG_LOADER_INI="RK3583MINIALL.ini"
diff --git a/u-boot/configs/rk3588-ab-car.config b/u-boot/configs/rk3588-ab-car.config
new file mode 100644
index 0000000000..815d6eec69
--- /dev/null
+++ b/u-boot/configs/rk3588-ab-car.config
@@ -0,0 +1,18 @@
+CONFIG_ANDROID_AB=y
+CONFIG_BASE_DEFCONFIG="rk3588_defconfig"
+# CONFIG_CMD_ANDROID_AB_SELECT is not set
+CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745=y
+CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752=y
+CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755=y
+CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772=y
+CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96789=y
+CONFIG_SERDES_DISPLAY_CHIP_MAXIM=y
+CONFIG_SERDES_DISPLAY_CHIP_NOVO_NCA9539=y
+CONFIG_SERDES_DISPLAY_CHIP_NOVO=y
+CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111=y
+CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121=y
+CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP=y
+CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82=y
+CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82=y
+CONFIG_SERDES_DISPLAY_CHIP_ROHM=y
+CONFIG_SERDES_DISPLAY=y
diff --git a/u-boot/configs/rk3588-qnx_defconfig b/u-boot/configs/rk3588-qnx_defconfig
index 0c42ff1de6..26300813a4 100644
--- a/u-boot/configs/rk3588-qnx_defconfig
+++ b/u-boot/configs/rk3588-qnx_defconfig
@@ -139,7 +139,7 @@ CONFIG_REGULATOR_PWM=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_REGULATOR_RK860X=y
-CONFIG_REGULATOR_RK806=y
+CONFIG_REGULATOR_RK8XX=y
 CONFIG_CHARGER_BQ25700=y
 CONFIG_CHARGER_BQ25890=y
 CONFIG_CHARGER_SC8551=y
diff --git a/u-boot/configs/rk3588-usbplug.config b/u-boot/configs/rk3588-usbplug.config
new file mode 100644
index 0000000000..ad5bfa97d6
--- /dev/null
+++ b/u-boot/configs/rk3588-usbplug.config
@@ -0,0 +1,26 @@
+CONFIG_BASE_DEFCONFIG="rockchip-usbplug_defconfig"
+# CONFIG_TARGET_EVB_RV1126 is not set
+# CONFIG_ROCKCHIP_RV1126 is not set
+CONFIG_DEBUG_UART_BASE=0xFEB50000
+CONFIG_DEFAULT_DEVICE_TREE="rk3588-evb"
+CONFIG_ROCKCHIP_RK3588=y
+CONFIG_TARGET_EVB_RK3588=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SDMA=y
+CONFIG_MMC_SDHCI_ROCKCHIP=y
+CONFIG_ROCKCHIP_NEW_IDB=y
+# CONFIG_CLK_SCMI is not set
+# CONFIG_SCMI_FIRMWARE is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_DW_ROCKCHIP is not set
+CONFIG_ROCKCHIP_BOOT_MODE_REG=0xfd588080
+CONFIG_ROCKCHIP_STIMER_BASE=0xfd8c8000
+CONFIG_ROCKCHIP_IRAM_START_ADDR=0xff000000
+# CONFIG_ROCKCHIP_SFC is not set
+# CONFIG_MTD is not set
+# CONFIG_MTD_BLK is not set
+# CONFIG_MTD_DEVICE is not set
+# CONFIG_SPI_FLASH is not set
+CONFIG_PHY_ROCKCHIP_USBDP=y
+CONFIG_DM_RESET=y
+CONFIG_OF_LIVE=y
diff --git a/u-boot/configs/rk3588_defconfig b/u-boot/configs/rk3588_defconfig
index a1425da15e..b5a8234a71 100644
--- a/u-boot/configs/rk3588_defconfig
+++ b/u-boot/configs/rk3588_defconfig
@@ -13,6 +13,7 @@ CONFIG_USING_KERNEL_DTB_V2=y
 CONFIG_ROCKCHIP_FIT_IMAGE_PACK=y
 CONFIG_ROCKCHIP_NEW_IDB=y
 CONFIG_PSTORE=y
+CONFIG_ROCKCHIP_MINIDUMP=y
 CONFIG_SPL_SERIAL_SUPPORT=y
 CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
 CONFIG_TARGET_EVB_RK3588=y
@@ -21,6 +22,7 @@ CONFIG_SPL_SPI_FLASH_SUPPORT=y
 CONFIG_SPL_SPI_SUPPORT=y
 CONFIG_DEFAULT_DEVICE_TREE="rk3588-evb"
 CONFIG_DEBUG_UART=y
+CONFIG_IMAGE_GZIP=y
 CONFIG_FIT=y
 CONFIG_FIT_IMAGE_POST_PROCESS=y
 CONFIG_FIT_HW_CRYPTO=y
@@ -34,13 +36,14 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_ANDROID_BOOTLOADER=y
 CONFIG_ANDROID_AVB=y
 CONFIG_ANDROID_BOOT_IMAGE_HASH=y
+CONFIG_BOARD_RNG_SEED=y
 CONFIG_SPL_BOARD_INIT=y
 # CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
 # CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
 CONFIG_SPL_SEPARATE_BSS=y
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x1
-CONFIG_SPL_MMC_WRITE=y
+CONFIG_SPL_I2C_SUPPORT=y
 CONFIG_SPL_MTD_SUPPORT=y
 CONFIG_SPL_ATF=y
 CONFIG_SPL_AB=y
@@ -58,6 +61,7 @@ CONFIG_CMD_DTIMG=y
 # CONFIG_CMD_UNZIP is not set
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_FPGA is not set
+CONFIG_CMD_GPIO=y
 CONFIG_CMD_GPT=y
 # CONFIG_CMD_LOADB is not set
 # CONFIG_CMD_LOADS is not set
@@ -104,6 +108,7 @@ CONFIG_SPL_SCMI_FIRMWARE=y
 CONFIG_GPIO_HOG=y
 CONFIG_ROCKCHIP_GPIO=y
 CONFIG_ROCKCHIP_GPIO_V2=y
+CONFIG_NCA9539_GPIO=y
 CONFIG_SYS_I2C_ROCKCHIP=y
 CONFIG_I2C_MUX=y
 CONFIG_DM_KEY=y
@@ -160,7 +165,7 @@ CONFIG_REGULATOR_PWM=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_REGULATOR_RK860X=y
-CONFIG_REGULATOR_RK806=y
+CONFIG_REGULATOR_RK8XX=y
 CONFIG_CHARGER_BQ25700=y
 CONFIG_CHARGER_BQ25890=y
 CONFIG_CHARGER_SC8551=y
@@ -176,7 +181,7 @@ CONFIG_RAMDISK_RO=y
 CONFIG_DM_RESET=y
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_RESET_ROCKCHIP=y
-CONFIG_BAUDRATE=115200
+CONFIG_BAUDRATE=1500000
 CONFIG_DEBUG_UART_BASE=0xFEB50000
 CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_DEBUG_UART_SHIFT=2
@@ -202,11 +207,6 @@ CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_DM_VIDEO=y
 CONFIG_DISPLAY=y
 CONFIG_DRM_ROCKCHIP=y
-CONFIG_DRM_MAXIM_MAX96745=y
-CONFIG_DRM_MAXIM_MAX96755F=y
-CONFIG_DRM_PANEL_ROHM_BU18RL82=y
-CONFIG_DRM_PANEL_MAXIM_MAX96752F=y
-CONFIG_DRM_ROHM_BU18XL82=y
 CONFIG_DRM_ROCKCHIP_DW_HDMI_QP=y
 CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI2=y
 CONFIG_DRM_ROCKCHIP_DW_DP=y
diff --git a/u-boot/configs/rv1106-spi-nand-tb-nofastae_defconfig b/u-boot/configs/rv1106-spi-nand-tb-nofastae_defconfig
new file mode 100644
index 0000000000..c70801249b
--- /dev/null
+++ b/u-boot/configs/rv1106-spi-nand-tb-nofastae_defconfig
@@ -0,0 +1,121 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x80000
+CONFIG_SPL_FIT_GENERATOR="arch/arm/mach-rockchip/make_fit_optee.sh"
+CONFIG_ROCKCHIP_RV1106=y
+CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0
+CONFIG_ROCKCHIP_FIT_IMAGE=y
+CONFIG_USING_KERNEL_DTB_V2=y
+CONFIG_ROCKCHIP_FIT_IMAGE_PACK=y
+# CONFIG_ROCKCHIP_SET_SN is not set
+# CONFIG_ROCKCHIP_SET_ETHADDR is not set
+CONFIG_LOADER_INI="RV1106MINIALL_SPI_NOR_TB_NOMCU.ini"
+CONFIG_TRUST_INI="RV1106TOS_TB.ini"
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_TARGET_EVB_RV1106=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="rv1106-evb"
+CONFIG_DEBUG_UART=y
+# CONFIG_DISTRO_DEFAULTS is not set
+CONFIG_FIT=y
+CONFIG_FIT_IMAGE_POST_PROCESS=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
+CONFIG_SPL_FIT_HW_CRYPTO=y
+# CONFIG_SPL_SYS_DCACHE_OFF is not set
+CONFIG_SPL_FIT_IMAGE_KB=512
+CONFIG_SPL_FIT_IMAGE_MULTIPLE=1
+CONFIG_BOOTDELAY=0
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_SKIP_RELOCATE_UBOOT is not set
+CONFIG_SPL_ADC_SUPPORT=y
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
+CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_KERNEL_BOOT=y
+CONFIG_HUSH_PARSER=y
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_ITEST is not set
+# CONFIG_CMD_SOURCE is not set
+# CONFIG_CMD_SETEXPR is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+# CONFIG_CMD_MISC is not set
+CONFIG_CMD_MTD_BLK=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_SPL_DTB_MINIMUM=y
+CONFIG_OF_LIVE=y
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+CONFIG_OF_U_BOOT_REMOVE_PROPS="interrupt-parent"
+CONFIG_ENVF=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+# CONFIG_SARADC_ROCKCHIP is not set
+CONFIG_SARADC_ROCKCHIP_V2=y
+CONFIG_SPL_BLK_READ_PREPARE=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_SPL_DM_CRYPTO=y
+CONFIG_SPL_ROCKCHIP_CRYPTO_V2=y
+CONFIG_ROCKCHIP_GPIO=y
+# CONFIG_DM_I2C is not set
+CONFIG_SPL_INPUT=y
+CONFIG_DM_KEY=y
+CONFIG_ADC_KEY=y
+CONFIG_SPL_ADC_KEY=y
+CONFIG_SPL_MISC=y
+CONFIG_SPL_MISC_DECOMPRESS=y
+CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS=y
+# CONFIG_MMC is not set
+# CONFIG_DM_MMC is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLK=y
+CONFIG_MTD_DEVICE=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0x1
+CONFIG_SF_DEFAULT_SPEED=50000000
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_XMC=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+# CONFIG_DM_REGULATOR is not set
+# CONFIG_DM_PWM is not set
+CONFIG_RAM=y
+CONFIG_TPL_RAM=y
+CONFIG_ROCKCHIP_SDRAM_COMMON=y
+CONFIG_DM_RESET=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_RESET_ROCKCHIP=y
+CONFIG_BAUDRATE=1500000
+CONFIG_DEBUG_UART_BASE=0xff4c0000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_ROCKCHIP_SFC=y
+CONFIG_SYSRESET=y
+# CONFIG_SYSRESET_SYSCON_REBOOT is not set
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_ERRNO_STR=y
+# CONFIG_EFI_LOADER is not set
diff --git a/u-boot/configs/rv1106-spi-nand-tb_defconfig b/u-boot/configs/rv1106-spi-nand-tb_defconfig
new file mode 100644
index 0000000000..066a58f450
--- /dev/null
+++ b/u-boot/configs/rv1106-spi-nand-tb_defconfig
@@ -0,0 +1,122 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x80000
+CONFIG_SPL_FIT_GENERATOR="arch/arm/mach-rockchip/make_fit_optee.sh"
+CONFIG_ROCKCHIP_RV1106=y
+CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0
+CONFIG_ROCKCHIP_FIT_IMAGE=y
+CONFIG_USING_KERNEL_DTB_V2=y
+CONFIG_ROCKCHIP_META=y
+CONFIG_ROCKCHIP_FIT_IMAGE_PACK=y
+# CONFIG_ROCKCHIP_SET_SN is not set
+# CONFIG_ROCKCHIP_SET_ETHADDR is not set
+CONFIG_LOADER_INI="RV1106MINIALL_SPI_NAND_TB.ini"
+CONFIG_TRUST_INI="RV1106TOS_TB.ini"
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_TARGET_EVB_RV1106=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="rv1106-evb"
+CONFIG_DEBUG_UART=y
+# CONFIG_DISTRO_DEFAULTS is not set
+CONFIG_FIT=y
+CONFIG_FIT_IMAGE_POST_PROCESS=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
+CONFIG_SPL_FIT_HW_CRYPTO=y
+# CONFIG_SPL_SYS_DCACHE_OFF is not set
+CONFIG_SPL_FIT_IMAGE_KB=512
+CONFIG_SPL_FIT_IMAGE_MULTIPLE=1
+CONFIG_BOOTDELAY=0
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_SKIP_RELOCATE_UBOOT is not set
+CONFIG_SPL_ADC_SUPPORT=y
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
+CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_KERNEL_BOOT=y
+CONFIG_HUSH_PARSER=y
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_ITEST is not set
+# CONFIG_CMD_SOURCE is not set
+# CONFIG_CMD_SETEXPR is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+# CONFIG_CMD_MISC is not set
+CONFIG_CMD_MTD_BLK=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_SPL_DTB_MINIMUM=y
+CONFIG_OF_LIVE=y
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+CONFIG_OF_U_BOOT_REMOVE_PROPS="interrupt-parent"
+CONFIG_ENVF=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+# CONFIG_SARADC_ROCKCHIP is not set
+CONFIG_SARADC_ROCKCHIP_V2=y
+CONFIG_SPL_BLK_READ_PREPARE=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_SPL_DM_CRYPTO=y
+CONFIG_SPL_ROCKCHIP_CRYPTO_V2=y
+CONFIG_ROCKCHIP_GPIO=y
+# CONFIG_DM_I2C is not set
+CONFIG_SPL_INPUT=y
+CONFIG_DM_KEY=y
+CONFIG_ADC_KEY=y
+CONFIG_SPL_ADC_KEY=y
+CONFIG_SPL_MISC=y
+CONFIG_SPL_MISC_DECOMPRESS=y
+CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS=y
+# CONFIG_MMC is not set
+# CONFIG_DM_MMC is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLK=y
+CONFIG_MTD_DEVICE=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0x1
+CONFIG_SF_DEFAULT_SPEED=50000000
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_XMC=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+# CONFIG_DM_REGULATOR is not set
+# CONFIG_DM_PWM is not set
+CONFIG_RAM=y
+CONFIG_TPL_RAM=y
+CONFIG_ROCKCHIP_SDRAM_COMMON=y
+CONFIG_DM_RESET=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_RESET_ROCKCHIP=y
+CONFIG_BAUDRATE=1500000
+CONFIG_DEBUG_UART_BASE=0xff4c0000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_ROCKCHIP_SFC=y
+CONFIG_SYSRESET=y
+# CONFIG_SYSRESET_SYSCON_REBOOT is not set
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_ERRNO_STR=y
+# CONFIG_EFI_LOADER is not set
diff --git a/u-boot/configs/rv1106-usbplug.config b/u-boot/configs/rv1106-usbplug.config
new file mode 100755
index 0000000000..3831814216
--- /dev/null
+++ b/u-boot/configs/rv1106-usbplug.config
@@ -0,0 +1,48 @@
+CONFIG_BASE_DEFCONFIG="rockchip-usbplug_defconfig"
+CONFIG_BAUDRATE=115200
+CONFIG_CMD_PINMUX=y
+# CONFIG_CMD_REGULATOR is not set
+CONFIG_CMD_USB=y
+CONFIG_DEBUG_UART_BASE=0xff4c0000
+CONFIG_DEFAULT_DEVICE_TREE="rv1106-evb"
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_DM_REGULATOR=y
+# CONFIG_NOP_PHY is not set
+CONFIG_PHY_ROCKCHIP_INNO_USB2=y
+CONFIG_PHY=y
+# CONFIG_PINCONF is not set
+CONFIG_PINCONF_RECURSIVE=y
+# CONFIG_PINCTRL_AT91 is not set
+# CONFIG_PINCTRL_AT91PIO4 is not set
+CONFIG_PINCTRL_FULL=y
+CONFIG_PINCTRL_GENERIC=y
+CONFIG_PINCTRL_ROCKCHIP=y
+# CONFIG_PINCTRL_SINGLE is not set
+# CONFIG_PINCTRL_STM32 is not set
+CONFIG_PINCTRL=y
+CONFIG_PINMUX=y
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_PWM is not set
+# CONFIG_REGULATOR_RK860X is not set
+CONFIG_ROCKCHIP_BOOT_MODE_REG=0xff020200
+CONFIG_ROCKCHIP_GPIO_V2=y
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_ROCKCHIP_IRAM_START_ADDR=0xff6c0000
+CONFIG_ROCKCHIP_NEW_IDB=y
+CONFIG_ROCKCHIP_RV1106=y
+# CONFIG_ROCKCHIP_RV1126 is not set
+CONFIG_ROCKCHIP_STIMER_BASE=0xff590020
+CONFIG_ROCKCHIP_VENDOR_PARTITION=y
+# CONFIG_SPL_DM_REGULATOR_FIXED is not set
+# CONFIG_SPL_DM_REGULATOR is not set
+CONFIG_SYS_BOARD="evb_rv1106"
+CONFIG_SYS_CONFIG_NAME="evb_rv1106"
+CONFIG_TARGET_EVB_RV1106=y
+CONFIG_USB_GADGET_PRODUCT_NUM=0x110c
+CONFIG_USB_HOST=y
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_XHCI_DWC3 is not set
+# CONFIG_USB_XHCI_DWC3_OF_SIMPLE is not set
+CONFIG_USB_XHCI_HCD=y
+# CONFIG_USB_XHCI_PCI is not set
diff --git a/u-boot/configs/rv1106_defconfig b/u-boot/configs/rv1106_defconfig
index 5dd1bb39e9..f56f5bc565 100644
--- a/u-boot/configs/rv1106_defconfig
+++ b/u-boot/configs/rv1106_defconfig
@@ -42,6 +42,7 @@ CONFIG_SPL_BOARD_INIT=y
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
 CONFIG_SPL_MMC_WRITE=y
 CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_AB=y
 CONFIG_HUSH_PARSER=y
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
@@ -108,14 +109,6 @@ CONFIG_MTD=y
 CONFIG_MTD_BLK=y
 CONFIG_MTD_DEVICE=y
 CONFIG_MTD_SPI_NAND=y
-CONFIG_SPI_FLASH=y
-CONFIG_SF_DEFAULT_MODE=0x3
-CONFIG_SPI_FLASH_GIGADEVICE=y
-CONFIG_SPI_FLASH_MACRONIX=y
-CONFIG_SPI_FLASH_WINBOND=y
-CONFIG_SPI_FLASH_XMC=y
-CONFIG_SPI_FLASH_XTX=y
-CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_RK630=y
 CONFIG_DM_ETH=y
 CONFIG_DM_ETH_PHY=y
diff --git a/u-boot/configs/rv1126-emmc-tb-nofastae.config b/u-boot/configs/rv1126-emmc-tb-nofastae.config
new file mode 100644
index 0000000000..20a6a3900f
--- /dev/null
+++ b/u-boot/configs/rv1126-emmc-tb-nofastae.config
@@ -0,0 +1,35 @@
+CONFIG_BASE_DEFCONFIG="rv1126_defconfig"
+# CONFIG_CMD_MTD_BLK is not set
+# CONFIG_CMD_NAND is not set
+# CONFIG_CMD_SF is not set
+# CONFIG_CMD_SPI is not set
+CONFIG_LOADER_INI="RV1126MINIALL_EMMC_TB.ini"
+CONFIG_MMC_USE_PRE_CONFIG=y
+# CONFIG_MTD_DEVICE is not set
+# CONFIG_MTD is not set
+# CONFIG_MTD_NAND_BBT_USING_FLASH is not set
+# CONFIG_NAND is not set
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+# CONFIG_ROCKCHIP_SFC is not set
+# CONFIG_SPI_FLASH is not set
+# CONFIG_SPI_MEM is not set
+# CONFIG_SPL_AB is not set
+CONFIG_SPL_ADC_KEY=y
+CONFIG_SPL_ADC_SUPPORT=y
+CONFIG_SPL_BLK_READ_PREPARE=y
+# CONFIG_SPL_CROS_EC_KEYB is not set
+CONFIG_SPL_DM_FUEL_GAUGE=y
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_INPUT=y
+CONFIG_SPL_KERNEL_BOOT=y
+# CONFIG_SPL_MTD_SUPPORT is not set
+# CONFIG_SPL_NAND_SUPPORT is not set
+# CONFIG_SPL_PINCTRL is not set
+# CONFIG_SPL_POWER_FG_CW201X is not set
+CONFIG_SPL_POWER_FG_RK817=y
+# CONFIG_SPL_POWER_FG_RK818 is not set
+CONFIG_SPL_POWER_LOW_VOLTAGE_THRESHOLD=3400
+# CONFIG_SPL_SPI_FLASH_SUPPORT is not set
+# CONFIG_SPL_SPI_SUPPORT is not set
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000
+CONFIG_TRUST_INI="RV1126TOS_TB_NOMCU.ini"
diff --git a/u-boot/configs/rv1126-spl-slc-nand_defconfig b/u-boot/configs/rv1126-spl-slc-nand_defconfig
new file mode 100644
index 0000000000..802cba3b86
--- /dev/null
+++ b/u-boot/configs/rv1126-spl-slc-nand_defconfig
@@ -0,0 +1,184 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x80000
+CONFIG_SPL_FIT_GENERATOR="arch/arm/mach-rockchip/make_fit_optee.sh"
+CONFIG_ROCKCHIP_RV1126=y
+CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0
+# CONFIG_SPL_MMC_SUPPORT is not set
+CONFIG_ROCKCHIP_FIT_IMAGE=y
+CONFIG_ROCKCHIP_UIMAGE=y
+CONFIG_ROCKCHIP_FIT_IMAGE_PACK=y
+CONFIG_ROCKCHIP_UART_MUX_SEL_M=2
+CONFIG_ROCKCHIP_SFC_IOMUX=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_TARGET_EVB_RV1126=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_SPL_NAND_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="rv1126-evb"
+CONFIG_DEBUG_UART=y
+CONFIG_FIT=y
+CONFIG_FIT_IMAGE_POST_PROCESS=y
+CONFIG_FIT_HW_CRYPTO=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
+CONFIG_SPL_FIT_HW_CRYPTO=y
+# CONFIG_SPL_SYS_DCACHE_OFF is not set
+CONFIG_BOOTDELAY=0
+# CONFIG_CONSOLE_MUX is not set
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_ANDROID_BOOTLOADER=y
+# CONFIG_ANDROID_WRITE_KEYBOX is not set
+# CONFIG_ANDROID_KEYMASTER_CA is not set
+CONFIG_ANDROID_BOOT_IMAGE_HASH=y
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
+# CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
+CONFIG_SPL_SHA256_SUPPORT=y
+CONFIG_SPL_CRYPTO_SUPPORT=y
+CONFIG_SPL_HASH_SUPPORT=y
+CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD_WRITE=y
+CONFIG_SPL_OPTEE=y
+CONFIG_FASTBOOT_BUF_ADDR=0x800800
+CONFIG_FASTBOOT_BUF_SIZE=0x04000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_GPT=y
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_BOOT_ANDROID=y
+CONFIG_CMD_BOOT_ROCKCHIP=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_NAND=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+# CONFIG_CMD_ITEST is not set
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_TFTP_BOOTM=y
+CONFIG_CMD_TFTP_FLASH=y
+# CONFIG_CMD_NFS is not set
+# CONFIG_CMD_MISC is not set
+# CONFIG_CMD_CHARGE_DISPLAY is not set
+CONFIG_CMD_MTD_BLK=y
+# CONFIG_ISO_PARTITION is not set
+CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=64
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_SPL_DTB_MINIMUM=y
+CONFIG_OF_LIVE=y
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+CONFIG_OF_U_BOOT_REMOVE_PROPS="interrupt-parent"
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_DM_CRYPTO=y
+CONFIG_SPL_DM_CRYPTO=y
+CONFIG_ROCKCHIP_CRYPTO_V2=y
+CONFIG_SPL_ROCKCHIP_CRYPTO_V2=y
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_SYS_I2C_ROCKCHIP=y
+CONFIG_DM_KEY=y
+CONFIG_RK8XX_PWRKEY=y
+CONFIG_ADC_KEY=y
+CONFIG_MISC=y
+CONFIG_SPL_MISC=y
+CONFIG_MISC_DECOMPRESS=y
+CONFIG_SPL_MISC_DECOMPRESS=y
+CONFIG_ROCKCHIP_OTP=y
+CONFIG_ROCKCHIP_HW_DECOMPRESS=y
+CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS=y
+CONFIG_SPL_ROCKCHIP_SECURE_OTP=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_MTD=y
+CONFIG_MTD_BLK=y
+CONFIG_MTD_DEVICE=y
+CONFIG_MTD_NAND_BBT_USING_FLASH=y
+CONFIG_NAND=y
+CONFIG_NAND_ROCKCHIP=y
+CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
+CONFIG_SYS_NAND_U_BOOT_OFFS=0x4000
+CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND=0x10000
+CONFIG_SF_DEFAULT_MODE=0x1
+CONFIG_SF_DEFAULT_SPEED=50000000
+CONFIG_DM_ETH=y
+CONFIG_DM_ETH_PHY=y
+CONFIG_DWC_ETH_QOS=y
+CONFIG_GMAC_ROCKCHIP=y
+CONFIG_PHY_ROCKCHIP_NANENG_USB2=y
+CONFIG_PINCTRL=y
+CONFIG_DM_FUEL_GAUGE=y
+CONFIG_POWER_FG_RK817=y
+CONFIG_IO_DOMAIN=y
+CONFIG_ROCKCHIP_IO_DOMAIN=y
+CONFIG_DM_PMIC=y
+# CONFIG_SPL_PMIC_CHILDREN is not set
+CONFIG_PMIC_RK8XX=y
+CONFIG_REGULATOR_PWM=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_REGULATOR_RK8XX=y
+CONFIG_DM_CHARGE_DISPLAY=y
+CONFIG_CHARGE_ANIMATION=y
+CONFIG_PWM_ROCKCHIP=y
+CONFIG_RAM=y
+CONFIG_SPL_RAM=y
+CONFIG_TPL_RAM=y
+CONFIG_ROCKCHIP_SDRAM_COMMON=y
+CONFIG_DM_RESET=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_RESET_ROCKCHIP=y
+CONFIG_BAUDRATE=1500000
+CONFIG_DEBUG_UART_BASE=0xff570000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_SPI_MEM=y
+CONFIG_ROCKCHIP_SFC=y
+CONFIG_SYSRESET=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="Rockchip"
+CONFIG_USB_GADGET_VENDOR_NUM=0x2207
+CONFIG_USB_GADGET_PRODUCT_NUM=0x110b
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_DM_VIDEO=y
+CONFIG_DISPLAY=y
+CONFIG_DRM_ROCKCHIP=y
+CONFIG_DRM_ROCKCHIP_INNO_MIPI_PHY=y
+CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI=y
+CONFIG_DRM_ROCKCHIP_RGB=y
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_RSA=y
+CONFIG_SPL_RSA=y
+CONFIG_RSA_N_SIZE=0x100
+CONFIG_RSA_E_SIZE=0x100
+CONFIG_RSA_C_SIZE=0x14
+CONFIG_SHA512=y
+CONFIG_ERRNO_STR=y
+# CONFIG_EFI_LOADER is not set
+CONFIG_OPTEE_CLIENT=y
+CONFIG_OPTEE_V2=y
diff --git a/u-boot/disk/part_env.c b/u-boot/disk/part_env.c
index 53c8b39191..8570ce7323 100644
--- a/u-boot/disk/part_env.c
+++ b/u-boot/disk/part_env.c
@@ -157,7 +157,7 @@ static int part_get_info_env(struct blk_desc *dev_desc, int idx,
 {
 	struct env_part *p = NULL;
 	struct list_head *node;
-	int part_num = 1;
+	int part_num = 0;
 	int ret = 0;
 
 	if (idx < 1) {
@@ -175,9 +175,9 @@ static int part_get_info_env(struct blk_desc *dev_desc, int idx,
 
 	list_for_each(node, &parts_head) {
 		p = list_entry(node, struct env_part, node);
+		part_num++;
 		if (idx == part_num)
 			break;
-		part_num++;
 	}
 
 	if (part_num < idx) {
diff --git a/u-boot/disk/part_rkparm.c b/u-boot/disk/part_rkparm.c
index 0d0890a125..302e7faa26 100644
--- a/u-boot/disk/part_rkparm.c
+++ b/u-boot/disk/part_rkparm.c
@@ -176,7 +176,7 @@ static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx,
 {
 	struct list_head *node;
 	struct rkparm_part *p = NULL;
-	int part_num = 1;
+	int part_num = 0;
 	int ret = 0;
 
 	if (idx < 1) {
@@ -195,9 +195,9 @@ static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx,
 
 	list_for_each(node, &parts_head) {
 		p = list_entry(node, struct rkparm_part, node);
+		part_num ++;
 		if (idx == part_num)
 			break;
-		part_num ++;
 	}
 
 	if (part_num < idx) {
diff --git a/u-boot/disk/part_rkram.c b/u-boot/disk/part_rkram.c
index 7398b5e64f..c553b425e0 100644
--- a/u-boot/disk/part_rkram.c
+++ b/u-boot/disk/part_rkram.c
@@ -99,7 +99,7 @@ static int part_get_info_rkram_part(struct blk_desc *dev_desc, int idx,
 {
 	struct rkram_part *p = NULL;
 	struct list_head *node;
-	int part_num = 1;
+	int part_num = 0;
 
 	if (idx < 1) {
 		printf("Invalid partition no.%d\n", idx);
@@ -111,9 +111,9 @@ static int part_get_info_rkram_part(struct blk_desc *dev_desc, int idx,
 
 	list_for_each(node, &parts_head) {
 		p = list_entry(node, struct rkram_part, node);
+		part_num++;
 		if (idx == part_num)
 			break;
-		part_num++;
 	}
 
 	if (part_num < idx) {
diff --git a/u-boot/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt b/u-boot/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt
index b73c96d24f..603796f169 100644
--- a/u-boot/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt
+++ b/u-boot/doc/device-tree-bindings/pinctrl/pinctrl-bindings.txt
@@ -119,7 +119,8 @@ For example:
 
 The contents of each of those pin configuration child nodes is defined
 entirely by the binding for the individual pin controller device. There
-exists no common standard for this content.
+exists no common standard for this content. The pinctrl framework only
+provides generic helper bindings that the pin controller driver can use.
 
 The pin configuration nodes need not be direct children of the pin controller
 device; they may be grandchildren, for example. Whether this is legal, and
@@ -156,6 +157,29 @@ state_2_node_a {
 	pins = "mfio29", "mfio30";
 };
 
+For hardware where pin multiplexing configurations have to be specified for
+each single pin the number of required sub-nodes containing "pin" and
+"function" properties can quickly escalate and become hard to write and
+maintain.
+
+For cases like this, the pin controller driver may use the pinmux helper
+property, where the pin identifier is provided with mux configuration settings
+in a pinmux group. A pinmux group consists of the pin identifier and mux
+settings represented as a single integer or an array of integers.
+
+The pinmux property accepts an array of pinmux groups, each of them describing
+a single pin multiplexing configuration.
+
+pincontroller {
+	state_0_node_a {
+		pinmux = <PINMUX_GROUP>, <PINMUX_GROUP>, ...;
+	};
+};
+
+Each individual pin controller driver bindings documentation shall specify
+how pin IDs and pin multiplexing configuration are defined and assembled
+together in a pinmux group.
+
 == Generic pin configuration node content ==
 
 Many data items that are represented in a pin configuration node are common
@@ -168,12 +192,15 @@ structure of the DT nodes that contain these properties.
 Supported generic properties are:
 
 pins			- the list of pins that properties in the node
-			  apply to (either this or "group" has to be
+			  apply to (either this, "group" or "pinmux" has to be
 			  specified)
 group			- the group to apply the properties to, if the driver
 			  supports configuration of whole groups rather than
-			  individual pins (either this or "pins" has to be
-			  specified)
+			  individual pins (either this, "pins" or "pinmux" has
+			  to be specified)
+pinmux			- the list of numeric pin ids and their mux settings
+			  that properties in the node apply to (either this,
+			  "pins" or "groups" have to be specified)
 bias-disable		- disable any pin bias
 bias-high-impedance	- high impedance mode ("third-state", "floating")
 bias-bus-hold		- latch weakly
@@ -184,17 +211,30 @@ drive-push-pull		- drive actively high and low
 drive-open-drain	- drive with open drain
 drive-open-source	- drive with open source
 drive-strength		- sink or source at most X mA
-input-enable		- enable input on pin (no effect on output)
-input-disable		- disable input on pin (no effect on output)
+drive-strength-microamp	- sink or source at most X uA
+input-enable		- enable input on pin (no effect on output, such as
+			  enabling an input buffer)
+input-disable		- disable input on pin (no effect on output, such as
+			  disabling an input buffer)
 input-schmitt-enable	- enable schmitt-trigger mode
 input-schmitt-disable	- disable schmitt-trigger mode
 input-debounce		- debounce mode with debound time X
 power-source		- select between different power supplies
 low-power-enable	- enable low power mode
 low-power-disable	- disable low power mode
+output-disable		- disable output on a pin (such as disable an output
+			  buffer)
+output-enable		- enable output on a pin without actively driving it
+			  (such as enabling an output buffer)
 output-low		- set the pin to output mode with low level
 output-high		- set the pin to output mode with high level
+sleep-hardware-state	- indicate this is sleep related state which will be programmed
+			  into the registers for the sleep state.
 slew-rate		- set the slew rate
+skew-delay		- this affects the expected clock skew on input pins
+			  and the delay before latching a value to an output
+			  pin. Typically indicates how many double-inverters are
+			  used to delay the signal.
 
 For example:
 
@@ -216,6 +256,12 @@ state_2_node_a {
 		bias-pull-up;
 	};
 };
+state_3_node_a {
+	mux {
+		pinmux = <GPIOx_PINm_MUXn>, <GPIOx_PINj_MUXk)>;
+		input-enable;
+	};
+};
 
 Some of the generic properties take arguments. For those that do, the
 arguments are described below.
@@ -224,11 +270,18 @@ arguments are described below.
   binding for the hardware defines:
   - Whether the entries are integers or strings, and their meaning.
 
+- pinmux takes a list of pin IDs and mux settings as required argument. The
+  specific bindings for the hardware defines:
+  - How pin IDs and mux settings are defined and assembled together in a single
+    integer or an array of integers.
+
 - bias-pull-up, -down and -pin-default take as optional argument on hardware
   supporting it the pull strength in Ohm. bias-disable will disable the pull.
 
 - drive-strength takes as argument the target strength in mA.
 
+- drive-strength-microamp takes as argument the target strength in uA.
+
 - input-debounce takes the debounce time in usec as argument
   or 0 to disable debouncing
 
diff --git a/u-boot/drivers/ata/ahci.c b/u-boot/drivers/ata/ahci.c
index ad952f8ddf..c1327931c6 100644
--- a/u-boot/drivers/ata/ahci.c
+++ b/u-boot/drivers/ata/ahci.c
@@ -115,6 +115,22 @@ int __weak ahci_link_up(struct ahci_uc_priv *uc_priv, u8 port)
 	int j = 0;
 	void __iomem *port_mmio = uc_priv->port[port].port_mmio;
 
+	/*
+	 * Add port reset before link up to fix some device link up
+	 * fail.
+	 */
+	writel(0x4, port_mmio + PORT_SCR_CTL);
+	udelay(10000);
+	writel(0x1, port_mmio + PORT_SCR_CTL);
+	udelay(10000);
+	writel(0x0, port_mmio + PORT_SCR_CTL);
+	udelay(10000);
+
+	writel(0x301, port_mmio + PORT_SCR_CTL);
+	udelay(10000);
+	writel(0x300, port_mmio + PORT_SCR_CTL);
+	udelay(1000);
+
 	/*
 	 * Bring up SATA link.
 	 * SATA link bringup time is usually less than 1 ms; only very
diff --git a/u-boot/drivers/clk/rockchip/clk_pll.c b/u-boot/drivers/clk/rockchip/clk_pll.c
index 49ddcc81a4..9566299c11 100644
--- a/u-boot/drivers/clk/rockchip/clk_pll.c
+++ b/u-boot/drivers/clk/rockchip/clk_pll.c
@@ -155,8 +155,8 @@ rockchip_pll_clk_set_by_auto(ulong fin_hz,
 
 		f_frac = (foutvco % MHZ);
 		fin_64 = fin_hz;
-		fin_64 = fin_64 / rate_table->refdiv;
-		frac_64 = f_frac << 24;
+		fin_64 = fin_64 / (ulong)rate_table->refdiv;
+		frac_64 = (ulong)f_frac << 24;
 		frac_64 = frac_64 / fin_64;
 		rate_table->frac = frac_64;
 		if (rate_table->frac > 0)
@@ -330,10 +330,10 @@ static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll,
 		     RK3036_PLLCON1_REFDIV_MASK),
 		     (rate->postdiv2 << RK3036_PLLCON1_POSTDIV2_SHIFT |
 		     rate->refdiv << RK3036_PLLCON1_REFDIV_SHIFT));
-	if (!rate->dsmpd) {
-		rk_clrsetreg(base + pll->con_offset + 0x4,
+	rk_clrsetreg(base + pll->con_offset + 0x4,
 			     RK3036_PLLCON1_DSMPD_MASK,
 			     rate->dsmpd << RK3036_PLLCON1_DSMPD_SHIFT);
+	if (!rate->dsmpd) {
 		writel((readl(base + pll->con_offset + 0x8) &
 			(~RK3036_PLLCON2_FRAC_MASK)) |
 			    (rate->frac << RK3036_PLLCON2_FRAC_SHIFT),
@@ -372,7 +372,7 @@ static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll,
 {
 	u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac;
 	u32 con = 0, shift, mask;
-	ulong rate;
+	ulong rate, p_rate = OSC_HZ / KHZ;
 	int mode;
 
 	con = readl(base + pll->mode_offset);
@@ -404,14 +404,14 @@ static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll,
 		con = readl(base + pll->con_offset + 0x8);
 		frac = (con & RK3036_PLLCON2_FRAC_MASK) >>
 			RK3036_PLLCON2_FRAC_SHIFT;
-		rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
+		rate = (p_rate * fbdiv / (refdiv * postdiv1 * postdiv2)) * KHZ;
 		if (dsmpd == 0) {
-			u64 frac_rate = OSC_HZ * (u64)frac;
+			u64 frac_rate = p_rate * (u64)frac * KHZ;
 
-			do_div(frac_rate, refdiv);
+			do_div(frac_rate, (u64)refdiv);
 			frac_rate >>= 24;
-			do_div(frac_rate, postdiv1);
-			do_div(frac_rate, postdiv1);
+			do_div(frac_rate, (u64)postdiv1);
+			do_div(frac_rate, (u64)postdiv2);
 			rate += frac_rate;
 		}
 		return rate;
@@ -491,11 +491,10 @@ static int rk3588_pll_set_rate(struct rockchip_pll_clock *pll,
 		     RK3588_PLLCON1_S_MASK),
 		     (rate->p << RK3588_PLLCON1_P_SHIFT |
 		     rate->s << RK3588_PLLCON1_S_SHIFT));
-	if (rate->k) {
-		rk_clrsetreg(base + pll->con_offset + RK3588_PLLCON(2),
-			     RK3588_PLLCON2_K_MASK,
-			     rate->k << RK3588_PLLCON2_K_SHIFT);
-	}
+
+	rk_clrsetreg(base + pll->con_offset + RK3588_PLLCON(2),
+		     RK3588_PLLCON2_K_MASK,
+		     rate->k << RK3588_PLLCON2_K_SHIFT);
 	/* Power up */
 	rk_clrreg(base + pll->con_offset + RK3588_PLLCON(1),
 		  RK3588_PLLCON1_PWRDOWN);
diff --git a/u-boot/drivers/clk/rockchip/clk_rk3036.c b/u-boot/drivers/clk/rockchip/clk_rk3036.c
index a78c4db2b1..2ab8218a65 100644
--- a/u-boot/drivers/clk/rockchip/clk_rk3036.c
+++ b/u-boot/drivers/clk/rockchip/clk_rk3036.c
@@ -255,8 +255,16 @@ static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate,
 		break;
 	case HCLK_SDIO:
 	case SCLK_SDIO:
+		con = readl(&cru->cru_clksel_con[12]);
+		mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT;
+		con = readl(&cru->cru_clksel_con[11]);
+		div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT;
+		break;
+	case HCLK_SDMMC:
+	case SCLK_SDMMC:
 		con = readl(&cru->cru_clksel_con[12]);
 		mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
+		con = readl(&cru->cru_clksel_con[11]);
 		div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
 		break;
 	default:
@@ -296,10 +304,27 @@ static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate,
 		break;
 	case HCLK_SDIO:
 	case SCLK_SDIO:
+		rk_clrsetreg(&cru->cru_clksel_con[12],
+			     SDIO_PLL_MASK,
+			     SDIO_SEL_24M << SDIO_PLL_SHIFT);
 		rk_clrsetreg(&cru->cru_clksel_con[11],
-			     MMC0_PLL_MASK | MMC0_DIV_MASK,
-			     mux << MMC0_PLL_SHIFT |
+			     SDIO_DIV_MASK,
+			     (src_clk_div - 1) << SDIO_DIV_SHIFT);
+		rk_clrsetreg(&cru->cru_clksel_con[12],
+			     SDIO_PLL_MASK,
+			     mux << SDIO_PLL_SHIFT);
+		break;
+	case HCLK_SDMMC:
+	case SCLK_SDMMC:
+		rk_clrsetreg(&cru->cru_clksel_con[12],
+			     MMC0_PLL_MASK,
+			     MMC0_SEL_24M << MMC0_PLL_SHIFT);
+		rk_clrsetreg(&cru->cru_clksel_con[11],
+			     MMC0_DIV_MASK,
 			     (src_clk_div - 1) << MMC0_DIV_SHIFT);
+		rk_clrsetreg(&cru->cru_clksel_con[12],
+			     MMC0_PLL_MASK,
+			     mux << MMC0_PLL_SHIFT);
 		break;
 	default:
 		return -EINVAL;
@@ -464,6 +489,14 @@ static ulong rk3036_clk_get_rate(struct clk *clk)
 	switch (clk->id) {
 	case 0 ... 63:
 		return rkclk_pll_get_rate(priv->cru, clk->id);
+	case SCLK_EMMC:
+	case SCLK_SDMMC:
+	case SCLK_SDIO:
+	case HCLK_EMMC:
+	case HCLK_SDMMC:
+	case HCLK_SDIO:
+		return rockchip_mmc_get_clk(priv->cru, gclk_rate,
+					    clk->id);
 	case SCLK_LCDC:
 		return rockchip_dclk_lcdc_get_clk(priv->cru, gclk_rate);
 	case ACLK_LCDC:
@@ -487,7 +520,11 @@ static ulong rk3036_clk_set_rate(struct clk *clk, ulong rate)
 	case 0 ... 63:
 		return 0;
 	case HCLK_EMMC:
+	case HCLK_SDMMC:
+	case HCLK_SDIO:
 	case SCLK_EMMC:
+	case SCLK_SDMMC:
+	case SCLK_SDIO:
 		new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate,
 						clk->id, rate);
 		break;
diff --git a/u-boot/drivers/clk/rockchip/clk_rk3308.c b/u-boot/drivers/clk/rockchip/clk_rk3308.c
index 725a5e2e05..82a2ac50ed 100644
--- a/u-boot/drivers/clk/rockchip/clk_rk3308.c
+++ b/u-boot/drivers/clk/rockchip/clk_rk3308.c
@@ -974,7 +974,9 @@ static ulong rk3308_clk_get_rate(struct clk *clk)
 	case SCLK_SPI1:
 		rate = rk3308_spi_get_clk(clk);
 		break;
-	case SCLK_PWM:
+	case SCLK_PWM0:
+	case SCLK_PWM1:
+	case SCLK_PWM2:
 		rate = rk3308_pwm_get_clk(clk);
 		break;
 	case DCLK_VOP:
@@ -1059,7 +1061,9 @@ static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
 	case SCLK_SPI1:
 		ret = rk3308_spi_set_clk(clk, rate);
 		break;
-	case SCLK_PWM:
+	case SCLK_PWM0:
+	case SCLK_PWM1:
+	case SCLK_PWM2:
 		ret = rk3308_pwm_set_clk(clk, rate);
 		break;
 	case DCLK_VOP:
diff --git a/u-boot/drivers/clk/rockchip/clk_rk3528.c b/u-boot/drivers/clk/rockchip/clk_rk3528.c
index ada7dd424f..dded6777e6 100644
--- a/u-boot/drivers/clk/rockchip/clk_rk3528.c
+++ b/u-boot/drivers/clk/rockchip/clk_rk3528.c
@@ -1832,6 +1832,52 @@ U_BOOT_DRIVER(rockchip_rk3528_grf_cru) = {
 	.probe		= rk3528_grfclk_probe,
 };
 
+#ifdef CONFIG_SPL_BUILD
+
+#define COREGRF_BASE	0xff300000
+#define PVTPLL_CON0_L	0x0
+#define PVTPLL_CON0_H	0x4
+
+static int rk3528_cpu_pvtpll_set_rate(struct rk3528_clk_priv *priv, ulong rate)
+{
+	struct rk3528_cru *cru = priv->cru;
+	u32 length;
+
+	if (rate >= 1200000000)
+		length = 8;
+	else if (rate >= 1008000000)
+		length = 11;
+	else
+		length = 17;
+
+	/* set pclk dbg div to 9 */
+	rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK,
+		     9 << RK3528_DIV_PCLK_DBG_SHIFT);
+	/* set aclk_m_core div to 1 */
+	rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK,
+		     1 << RK3528_DIV_ACLK_M_CORE_SHIFT);
+
+	/* set ring sel = 1 */
+	writel(0x07000000 | (1 << 8), COREGRF_BASE + PVTPLL_CON0_L);
+	/* set length */
+	writel(0x007f0000 | length, COREGRF_BASE + PVTPLL_CON0_H);
+	/* enable pvtpll */
+	writel(0x00020002, COREGRF_BASE + PVTPLL_CON0_L);
+	/* start monitor */
+	writel(0x00010001, COREGRF_BASE + PVTPLL_CON0_L);
+
+	/* set core mux pvtpll */
+	writel(0x00010001, &cru->clksel_con[40]);
+	writel(0x00100010, &cru->clksel_con[39]);
+
+	/* set pclk dbg div to 8 */
+	rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK,
+		     8 << RK3528_DIV_PCLK_DBG_SHIFT);
+
+	return 0;
+}
+#endif
+
 static int rk3528_clk_init(struct rk3528_clk_priv *priv)
 {
 	int ret;
@@ -1866,7 +1912,13 @@ static int rk3528_clk_init(struct rk3528_clk_priv *priv)
 		if (!ret)
 			priv->armclk_init_hz = APLL_HZ;
 	}
-#else
+
+	if (!rk3528_cpu_pvtpll_set_rate(priv, CPU_PVTPLL_HZ)) {
+		printf("cpu pvtpll %d KHz\n", CPU_PVTPLL_HZ / 1000);
+		priv->armclk_init_hz = CPU_PVTPLL_HZ;
+	}
+
+#elif CONFIG_IS_ENABLED(CLK_SCMI)
 	if (!priv->armclk_enter_hz) {
 		struct clk clk;
 
@@ -1882,9 +1934,7 @@ static int rk3528_clk_init(struct rk3528_clk_priv *priv)
 			printf("Failed to set scmi cpu %dhz\n", CPU_PVTPLL_HZ);
 			return ret;
 		} else {
-			priv->armclk_enter_hz =
-				rockchip_pll_get_rate(&rk3528_pll_clks[APLL],
-						      priv->cru, APLL);
+			priv->armclk_enter_hz = CPU_PVTPLL_HZ;
 			priv->armclk_init_hz = CPU_PVTPLL_HZ;
 		}
 	}
diff --git a/u-boot/drivers/clk/rockchip/clk_rk3562.c b/u-boot/drivers/clk/rockchip/clk_rk3562.c
index 36d8c447a1..ee22b7fa9f 100644
--- a/u-boot/drivers/clk/rockchip/clk_rk3562.c
+++ b/u-boot/drivers/clk/rockchip/clk_rk3562.c
@@ -31,6 +31,8 @@ static struct rockchip_pll_rate_table rk3562_pll_rates[] = {
 	RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0),
 	RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+	RK3036_PLL_RATE(705600000, 2, 235, 4, 1, 0, 3355443),
+	RK3036_PLL_RATE(611520000, 4, 611, 6, 1, 0, 8724152),
 	RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0),
 	RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
 	RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
@@ -1166,7 +1168,7 @@ static ulong rk3562_vop_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
 	return DIV_TO_RATE(prate, div);
 }
 
-#define RK3562_VOP_PLL_LIMIT_FREQ 600000000
+#define RK3562_VOP_PLL_LIMIT_FREQ 594000000
 
 static ulong rk3562_vop_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
 				 ulong rate)
@@ -1198,6 +1200,8 @@ static ulong rk3562_vop_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
 		return rk3562_vop_get_rate(priv, clk_id);
 	case DCLK_VOP:
 		div = DIV_ROUND_UP(RK3562_VOP_PLL_LIMIT_FREQ, rate);
+		if (div % 2)
+			div = div + 1;
 		rk_clrsetreg(&cru->clksel_con[30],
 			     DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
 			     DCLK_VOP_SEL_VPLL << DCLK_VOP_SEL_SHIFT |
@@ -1792,7 +1796,7 @@ static void rk3562_clk_init(struct rk3562_clk_priv *priv)
 					      priv->cru, APLL);
 
 	if (!priv->armclk_init_hz) {
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_SUPPORT_USBPLUG)
 		ret = rk3562_armclk_set_rate(priv, APLL_HZ);
 		if (!ret)
 			priv->armclk_init_hz = APLL_HZ;
diff --git a/u-boot/drivers/clk/rockchip/clk_rk3568.c b/u-boot/drivers/clk/rockchip/clk_rk3568.c
index f917357558..ae33fa2bd2 100644
--- a/u-boot/drivers/clk/rockchip/clk_rk3568.c
+++ b/u-boot/drivers/clk/rockchip/clk_rk3568.c
@@ -1815,7 +1815,7 @@ static ulong rk3568_dclk_vop_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
 	return DIV_TO_RATE(parent, div);
 }
 
-#define RK3568_VOP_PLL_LIMIT_FREQ 600000000
+#define RK3568_VOP_PLL_LIMIT_FREQ 594000000
 
 static ulong rk3568_dclk_vop_set_clk(struct rk3568_clk_priv *priv,
 				     ulong clk_id, ulong rate)
@@ -1850,6 +1850,8 @@ static ulong rk3568_dclk_vop_set_clk(struct rk3568_clk_priv *priv,
 		rk3568_pmu_pll_set_rate(priv, HPLL, div * rate);
 	} else if (sel == DCLK_VOP_SEL_VPLL) {
 		div = DIV_ROUND_UP(RK3568_VOP_PLL_LIMIT_FREQ, rate);
+		if (div % 2)
+			div = div + 1;
 		rk_clrsetreg(&cru->clksel_con[conid],
 			     DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK,
 			     (DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT) |
@@ -1865,6 +1867,9 @@ static ulong rk3568_dclk_vop_set_clk(struct rk3568_clk_priv *priv,
 			case DCLK_VOP_SEL_CPLL:
 				pll_rate = priv->cpll_hz;
 				break;
+			case DCLK_VOP_SEL_HPLL:
+			case DCLK_VOP_SEL_VPLL:
+				continue;
 			default:
 				printf("do not support this vop pll sel\n");
 				return -EINVAL;
diff --git a/u-boot/drivers/clk/rockchip/clk_rk3588.c b/u-boot/drivers/clk/rockchip/clk_rk3588.c
index 715ea04b93..a2aa6e1f26 100644
--- a/u-boot/drivers/clk/rockchip/clk_rk3588.c
+++ b/u-boot/drivers/clk/rockchip/clk_rk3588.c
@@ -1103,7 +1103,7 @@ static ulong rk3588_dclk_vop_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
 	return DIV_TO_RATE(parent, div);
 }
 
-#define RK3588_VOP_PLL_LIMIT_FREQ 600000000
+#define RK3588_VOP_PLL_LIMIT_FREQ 594000000
 
 static ulong rk3588_dclk_vop_set_clk(struct rk3588_clk_priv *priv,
 				     ulong clk_id, ulong rate)
@@ -1164,6 +1164,8 @@ static ulong rk3588_dclk_vop_set_clk(struct rk3588_clk_priv *priv,
 				     ((div - 1) << div_shift));
 		} else {
 			div = DIV_ROUND_UP(RK3588_VOP_PLL_LIMIT_FREQ, rate);
+			if (div % 2)
+				div = div + 1;
 			rk_clrsetreg(&cru->clksel_con[conid],
 				     mask,
 				     DCLK_VOP_SRC_SEL_V0PLL << sel_shift |
@@ -2061,7 +2063,10 @@ static int rk3588_clk_probe(struct udevice *dev)
 {
 	struct rk3588_clk_priv *priv = dev_get_priv(dev);
 	int ret;
+
+#if CONFIG_IS_ENABLED(CLK_SCMI)
 	struct clk clk;
+#endif
 
 	priv->sync_kernel = false;
 
@@ -2080,6 +2085,7 @@ static int rk3588_clk_probe(struct udevice *dev)
 	}
 #endif
 
+#if CONFIG_IS_ENABLED(CLK_SCMI)
 	ret = rockchip_get_scmi_clk(&clk.dev);
 	if (ret) {
 		printf("Failed to get scmi clk dev\n");
@@ -2110,6 +2116,7 @@ static int rk3588_clk_probe(struct udevice *dev)
 	ret = clk_set_rate(&clk, CPU_PVTPLL_HZ);
 	if (ret < 0)
 		printf("Failed to set cpub23\n");
+#endif
 #endif
 
 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
diff --git a/u-boot/drivers/clk/rockchip/clk_rv1106.c b/u-boot/drivers/clk/rockchip/clk_rv1106.c
index dcf02e7170..a99846f4e1 100644
--- a/u-boot/drivers/clk/rockchip/clk_rv1106.c
+++ b/u-boot/drivers/clk/rockchip/clk_rv1106.c
@@ -1131,6 +1131,9 @@ static ulong rv1106_clk_get_rate(struct clk *clk)
 		rate = rv1106_decom_get_clk(priv);
 		break;
 #endif
+	case TCLK_WDT_NS:
+		rate = OSC_HZ;
+		break;
 	default:
 		return -ENOENT;
 	}
diff --git a/u-boot/drivers/core/device.c b/u-boot/drivers/core/device.c
index a8803ee42c..b2df97f1c1 100644
--- a/u-boot/drivers/core/device.c
+++ b/u-boot/drivers/core/device.c
@@ -510,8 +510,10 @@ int device_probe(struct udevice *dev)
 	if (ret)
 		goto fail_uclass;
 
-	if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)
+	if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) {
+		pinctrl_select_state(dev, "init");
 		pinctrl_select_state(dev, "default");
+	}
 
 	return 0;
 fail_uclass:
diff --git a/u-boot/drivers/core/uclass.c b/u-boot/drivers/core/uclass.c
index 02f1bebd80..cfcfdebe05 100644
--- a/u-boot/drivers/core/uclass.c
+++ b/u-boot/drivers/core/uclass.c
@@ -503,23 +503,40 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
 }
 #endif
 
-int uclass_first_device(enum uclass_id id, struct udevice **devp)
+/*
+ * Starting from the given device @dev, return pointer to the first device in
+ * the uclass that probes successfully in @devp.
+ */
+static void _uclass_next_device(struct udevice *dev, struct udevice **devp)
+{
+	for (; dev; uclass_find_next_device(&dev)) {
+		if (!device_probe(dev))
+			break;
+	}
+	*devp = dev;
+}
+
+void uclass_first_device(enum uclass_id id, struct udevice **devp)
 {
 	struct udevice *dev;
-	int ret;
 
-	*devp = NULL;
-	ret = uclass_find_first_device(id, &dev);
-	if (!dev)
-		return 0;
-	return uclass_get_device_tail(dev, ret, devp);
+	uclass_find_first_device(id, &dev);
+	_uclass_next_device(dev, devp);
+}
+
+void uclass_next_device(struct udevice **devp)
+{
+	struct udevice *dev = *devp;
+
+	uclass_find_next_device(&dev);
+	_uclass_next_device(dev, devp);
 }
 
 int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
 {
 	int ret;
 
-	ret = uclass_first_device(id, devp);
+	ret = uclass_first_device_check(id, devp);
 	if (ret)
 		return ret;
 	else if (!*devp)
@@ -528,16 +545,17 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
 	return 0;
 }
 
-int uclass_next_device(struct udevice **devp)
+int uclass_next_device_err(struct udevice **devp)
 {
-	struct udevice *dev = *devp;
 	int ret;
 
-	*devp = NULL;
-	ret = uclass_find_next_device(&dev);
-	if (!dev)
-		return 0;
-	return uclass_get_device_tail(dev, ret, devp);
+	ret = uclass_next_device_check(devp);
+	if (ret)
+		return ret;
+	else if (!*devp)
+		return -ENODEV;
+
+	return 0;
 }
 
 int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
@@ -567,6 +585,23 @@ int uclass_next_device_check(struct udevice **devp)
 	return device_probe(*devp);
 }
 
+int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
+				struct udevice **devp)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+
+	uclass_id_foreach_dev(id, dev, uc) {
+		if (dev_get_driver_data(dev) == driver_data) {
+			*devp = dev;
+
+			return device_probe(dev);
+		}
+	}
+
+	return -ENODEV;
+}
+
 int uclass_bind_device(struct udevice *dev, bool after_u_boot_dev)
 {
 	struct uclass *uc;
diff --git a/u-boot/drivers/cpu/amp.its b/u-boot/drivers/cpu/amp.its
index e1d3ed01ed..44db734fca 100644
--- a/u-boot/drivers/cpu/amp.its
+++ b/u-boot/drivers/cpu/amp.its
@@ -99,6 +99,8 @@
 				thumb        = <0>;
 				hyp          = <0>;
 				udelay       = <1000000>;
+				load         = <0x2000000>; // optional
+				load_c       = <0x4000000>; // optional
 			};
 		};
 	};
diff --git a/u-boot/drivers/cpu/rockchip_amp.c b/u-boot/drivers/cpu/rockchip_amp.c
index 41439305a0..5c7f1592e5 100644
--- a/u-boot/drivers/cpu/rockchip_amp.c
+++ b/u-boot/drivers/cpu/rockchip_amp.c
@@ -248,7 +248,7 @@ static int brought_up_amp(void *fit, int noffset,
 	const char *desc;
 	boot_args_t args;
 	u32 cpu, aarch64, hyp;
-	u32 load, thumb, us;
+	u32 load, load_c, thumb, us;
 	u32 pe_state, entry;
 	int boot_on;
 	int data_size;
@@ -261,6 +261,7 @@ static int brought_up_amp(void *fit, int noffset,
 	hyp = fit_get_u32_default(fit, noffset, "hyp", 0);
 	thumb = fit_get_u32_default(fit, noffset, "thumb", 0);
 	entry = load = fit_get_u32_default(fit, noffset, "load", -ENODATA);
+	load_c = fit_get_u32_default(fit, noffset, "load_c", -ENODATA);
 	us = fit_get_u32_default(fit, noffset, "udelay", 0);
 	boot_on = fit_get_u32_default(fit, noffset, "boot-on", 1);
 	fit_image_get_arch(fit, noffset, &arch);
@@ -283,6 +284,14 @@ static int brought_up_amp(void *fit, int noffset,
 		AMP_E("Property missing!\n");
 		return -EINVAL;
 	}
+
+	if (is_linux) {
+		if (load != -ENODATA)
+			env_set_hex("kernel_addr_r", load);
+		if (load_c != -ENODATA)
+			env_set_hex("kernel_addr_c", load_c);
+	}
+
 	aarch64 = (arch == IH_ARCH_ARM) ? 0 : 1;
 	pe_state = PE_STATE(aarch64, hyp, thumb, 0);
 
@@ -293,6 +302,7 @@ static int brought_up_amp(void *fit, int noffset,
 	AMP_I("        hyp: %d\n", hyp);
 	AMP_I("      thumb: %d\n", thumb);
 	AMP_I("       load: 0x%08x\n", load);
+	AMP_I("     load_c: 0x%08x\n", load_c);
 	AMP_I("   pe_state: 0x%08x\n", pe_state);
 	AMP_I("   linux-os: %d\n\n", is_linux);
 #endif
diff --git a/u-boot/drivers/crypto/rockchip/crypto_v2.c b/u-boot/drivers/crypto/rockchip/crypto_v2.c
index e2135a7b40..78d3952681 100644
--- a/u-boot/drivers/crypto/rockchip/crypto_v2.c
+++ b/u-boot/drivers/crypto/rockchip/crypto_v2.c
@@ -1252,16 +1252,20 @@ int rockchip_crypto_cipher(struct udevice *dev, cipher_context *ctx,
 	case CRYPTO_DES:
 		ret = rk_crypto_des(dev, ctx->mode, ctx->key, ctx->key_len,
 				    ctx->iv, in, out, len, enc);
+		break;
 	case CRYPTO_AES:
 		ret = rk_crypto_aes(dev, ctx->mode,
 				    ctx->key, ctx->twk_key, ctx->key_len,
 				    ctx->iv, ctx->iv_len, in, out, len, enc);
+		break;
 	case CRYPTO_SM4:
 		ret = rk_crypto_sm4(dev, ctx->mode,
 				    ctx->key, ctx->twk_key, ctx->key_len,
 				    ctx->iv, ctx->iv_len, in, out, len, enc);
+		break;
 	default:
 		ret = -EINVAL;
+		break;
 	}
 
 	rk_crypto_disable_clk(dev);
diff --git a/u-boot/drivers/dma/dma-uclass.c b/u-boot/drivers/dma/dma-uclass.c
index 3d0ce22fbc..5d1bf8a437 100644
--- a/u-boot/drivers/dma/dma-uclass.c
+++ b/u-boot/drivers/dma/dma-uclass.c
@@ -21,10 +21,9 @@ DECLARE_GLOBAL_DATA_PTR;
 int dma_get_device(u32 transfer_type, struct udevice **devp)
 {
 	struct udevice *dev;
-	int ret;
 
-	for (ret = uclass_first_device(UCLASS_DMA, &dev); dev && !ret;
-	     ret = uclass_next_device(&dev)) {
+	for (uclass_first_device(UCLASS_DMA, &dev); dev;
+	     uclass_next_device(&dev)) {
 		struct dma_dev_priv *uc_priv;
 
 		uc_priv = dev_get_uclass_priv(dev);
@@ -40,7 +39,7 @@ int dma_get_device(u32 transfer_type, struct udevice **devp)
 
 	*devp = dev;
 
-	return ret;
+	return 0;
 }
 
 int dma_memcpy(void *dst, void *src, size_t len)
diff --git a/u-boot/drivers/gpio/Kconfig b/u-boot/drivers/gpio/Kconfig
index 412df722e0..e50ea11aec 100644
--- a/u-boot/drivers/gpio/Kconfig
+++ b/u-boot/drivers/gpio/Kconfig
@@ -320,4 +320,13 @@ config MPC85XX_GPIO
 
 	  The driver has been tested on MPC85XX, but it is likely that other
 	  PowerQUICC III devices will work as well.
+
+config NCA9539_GPIO
+	bool "NCA9539 GPIO port expander driver"
+	depends on DM_GPIO
+	default n
+	help
+	  Device model driver support for NCA9539 GPIO expander. It should be
+	  usable on many NCA9539 families like NCA9539 & NCA9535.
+	  Tested on NCA9539.
 endmenu
diff --git a/u-boot/drivers/gpio/Makefile b/u-boot/drivers/gpio/Makefile
index 1396467ab6..6dbbb9e67b 100644
--- a/u-boot/drivers/gpio/Makefile
+++ b/u-boot/drivers/gpio/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_MVEBU_GPIO)	+= mvebu_gpio.o
 obj-$(CONFIG_MSM_GPIO)		+= msm_gpio.o
 obj-$(CONFIG_$(SPL_)PCF8575_GPIO)	+= pcf8575_gpio.o
 obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
+obj-$(CONFIG_NCA9539_GPIO)	+= nca9539_gpio.o
diff --git a/u-boot/drivers/gpio/gpio-uclass.c b/u-boot/drivers/gpio/gpio-uclass.c
index a8479b061e..8599ef367e 100644
--- a/u-boot/drivers/gpio/gpio-uclass.c
+++ b/u-boot/drivers/gpio/gpio-uclass.c
@@ -34,11 +34,10 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
 {
 	struct gpio_dev_priv *uc_priv;
 	struct udevice *dev;
-	int ret;
 
-	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+	for (uclass_first_device(UCLASS_GPIO, &dev);
 	     dev;
-	     ret = uclass_next_device(&dev)) {
+	     uclass_next_device(&dev)) {
 		uc_priv = dev_get_uclass_priv(dev);
 		if (gpio >= uc_priv->gpio_base &&
 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
@@ -50,7 +49,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
 	}
 
 	/* No such GPIO */
-	return ret ? ret : -ENOENT;
+	return -ENOENT;
 }
 
 int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
@@ -59,12 +58,11 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
 	struct udevice *dev;
 	ulong offset;
 	int numeric;
-	int ret;
 
 	numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
-	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+	for (uclass_first_device(UCLASS_GPIO, &dev);
 	     dev;
-	     ret = uclass_next_device(&dev)) {
+	     uclass_next_device(&dev)) {
 		int len;
 
 		uc_priv = dev_get_uclass_priv(dev);
@@ -84,7 +82,7 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
 	}
 
 	if (!dev)
-		return ret ? ret : -EINVAL;
+		return -EINVAL;
 
 	desc->dev = dev;
 	desc->offset = offset;
diff --git a/u-boot/drivers/gpio/nca9539_gpio.c b/u-boot/drivers/gpio/nca9539_gpio.c
new file mode 100644
index 0000000000..2eba9f7e4b
--- /dev/null
+++ b/u-boot/drivers/gpio/nca9539_gpio.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  NCA9539 I2C Port Expander I/O
+ *
+ *  Copyright (C) 2023 Cody Xie <cody.xie@rock-chips.com>
+ *
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <linux/bitops.h>
+
+#define NCA9539_REG_INPUT_PORT_BASE 0x00
+#define NCA9539_REG_INPUT_PORT0 (NCA9539_REG_INPUT_PORT_BASE + 0x0)
+#define NCA9539_REG_INPUT_PORT1 (NCA9539_REG_INPUT_PORT_BASE + 0x1)
+#define NCA9539_REG_OUTPUT_PORT_BASE 0x02
+#define NCA9539_REG_OUTPUT_PORT0 (NCA9539_REG_OUTPUT_PORT_BASE + 0x0)
+#define NCA9539_REG_OUTPUT_PORT1 (NCA9539_REG_OUTPUT_PORT_BASE + 0x1)
+#define NCA9539_REG_POLARITY_BASE 0x04
+#define NCA9539_REG_POLARITY_PORT0 (NCA9539_REG_POLARITY_BASE + 0x0)
+#define NCA9539_REG_POLARITY_PORT1 (NCA9539_REG_POLARITY_BASE + 0x1)
+#define NCA9539_REG_CONFIG_BASE 0x06
+#define NCA9539_REG_CONFIG_PORT0 (NCA9539_REG_CONFIG_BASE + 0x0)
+#define NCA9539_REG_CONFIG_PORT1 (NCA9539_REG_CONFIG_BASE + 0x1)
+
+#define NCA9539_BANK_SZ 8
+#define NCA9539_MAX_BANK 2
+
+#define NCA9539_CHIP_ADDR 0x74
+
+#ifndef BIT
+#define BIT(nr) (1UL << (nr))
+#endif
+
+struct nca9539_info {
+	struct udevice *dev;
+	int addr;
+	unsigned int ngpio;
+};
+
+static int nca9539_write_reg(struct udevice *dev, int reg, u8 val)
+{
+	int ret = 0;
+
+	ret = dm_i2c_write(dev, reg, &val, 1);
+	if (ret) {
+		dev_err(dev, "%s error\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int nca9539_read_reg(struct udevice *dev, int reg, u8 *val)
+{
+	int ret;
+	u8 byte;
+
+	ret = dm_i2c_read(dev, reg, &byte, 1);
+	if (ret) {
+		dev_err(dev, "%s error\n", __func__);
+		return ret;
+	}
+
+	*val = byte;
+
+	return 0;
+}
+
+static int nca9539_gpio_get_direction(struct udevice *dev, unsigned int offset)
+{
+	unsigned int port = offset / NCA9539_BANK_SZ;
+	unsigned int pin = offset % NCA9539_BANK_SZ;
+	u8 value;
+	int ret;
+
+	dev_dbg(dev, "%s offset(%d)\n", __func__, offset);
+	ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
+	if (ret < 0) {
+		dev_err(dev, "%s offset(%d) read config failed\n", __func__,
+			offset);
+		return ret;
+	}
+
+	if (value & BIT(pin))
+		return GPIOF_INPUT;
+
+	return GPIOF_OUTPUT;
+}
+
+static int nca9539_gpio_direction_input(struct udevice *dev,
+					unsigned int offset)
+{
+	unsigned int port = offset / NCA9539_BANK_SZ;
+	unsigned int pin = offset % NCA9539_BANK_SZ;
+	u8 val;
+	int ret = 0;
+
+	dev_dbg(dev, "%s offset(%d)\n", __func__, offset);
+
+	ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &val);
+	if (!ret) {
+		val &= ~BIT(pin);
+		val |= BIT(pin);
+		ret = nca9539_write_reg(dev, NCA9539_REG_CONFIG_BASE + port,
+					val);
+	}
+
+	if (ret < 0) {
+		dev_err(dev, "%s offset(%d) read config failed\n", __func__,
+			offset);
+	}
+
+	return ret;
+}
+
+static int nca9539_gpio_direction_output(struct udevice *dev,
+					 unsigned int offset, int val)
+{
+	unsigned int port = offset / NCA9539_BANK_SZ;
+	unsigned int pin = offset % NCA9539_BANK_SZ;
+	u8 value;
+	int ret;
+
+	dev_dbg(dev, "%s offset(%d) val(%d)\n", __func__, offset, val);
+
+	ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
+	if (!ret) {
+		value &= ~BIT(pin);
+		ret = nca9539_write_reg(dev, NCA9539_REG_CONFIG_BASE + port,
+					value);
+	}
+	if (ret < 0) {
+		dev_warn(dev, "%s offset(%d) read config failed\n", __func__,
+			offset);
+	}
+
+	ret = nca9539_read_reg(dev, NCA9539_REG_OUTPUT_PORT_BASE + port,
+			       &value);
+	if (!ret) {
+		value &= ~BIT(pin);
+		value |= val ? BIT(pin) : 0;
+		ret = nca9539_write_reg(
+			dev, NCA9539_REG_OUTPUT_PORT_BASE + port, value);
+	}
+	if (ret < 0) {
+		dev_err(dev, "%s offset(%d) val(%d) update output failed\n",
+			__func__, offset, val);
+	}
+
+	return ret;
+}
+
+static int nca9539_gpio_get(struct udevice *dev, unsigned int offset)
+{
+	unsigned int port = offset / NCA9539_BANK_SZ;
+	unsigned int pin = offset % NCA9539_BANK_SZ;
+	int reg;
+	u8 value;
+	int ret;
+
+	dev_dbg(dev, "%s offset(%d)\n", __func__, offset);
+	ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
+	if (ret < 0) {
+		dev_err(dev, "%s offset(%d) check config failed\n", __func__,
+			offset);
+		return ret;
+	}
+	if (!(BIT(pin) & value))
+		reg = NCA9539_REG_OUTPUT_PORT_BASE + port;
+	else
+		reg = NCA9539_REG_INPUT_PORT_BASE + port;
+	ret = nca9539_read_reg(dev, reg, &value);
+	if (ret < 0) {
+		dev_err(dev, "%s offset(%d) read value failed\n", __func__,
+			offset);
+		return -EIO;
+	}
+
+	return !!(BIT(pin) & value);
+}
+
+static int nca9539_gpio_set(struct udevice *dev, unsigned int offset, int val)
+{
+	unsigned int port = offset / NCA9539_BANK_SZ;
+	unsigned int pin = offset % NCA9539_BANK_SZ;
+	u8 value;
+	int ret;
+
+	dev_dbg(dev, "%s offset(%d) val(%d)\n", __func__, offset, val);
+	ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
+	if (ret < 0 || !!(BIT(pin) & value)) {
+		dev_warn(dev, "%s offset(%d) val(%d) check config failed\n",
+			__func__, offset, val);
+	}
+
+	ret = nca9539_read_reg(dev, NCA9539_REG_OUTPUT_PORT_BASE + port,
+			       &value);
+	if (!ret) {
+		value &= ~BIT(pin);
+		value |= val ? BIT(pin) : 0;
+		ret = nca9539_write_reg(
+			dev, NCA9539_REG_OUTPUT_PORT_BASE + port, value);
+	}
+	if (ret < 0) {
+		dev_err(dev, "%s offset(%d) val(%d) read input failed\n",
+			__func__, offset, val);
+	}
+
+	return ret;
+}
+
+static int nca9539_get_function(struct udevice *dev, unsigned offset)
+{
+	return nca9539_gpio_get_direction(dev, offset);
+}
+
+static int nca9539_xlate(struct udevice *dev, struct gpio_desc *desc,
+			 struct ofnode_phandle_args *args)
+{
+	desc->offset = args->args[0];
+	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+	return 0;
+}
+
+static const struct dm_gpio_ops nca9539_ops = {
+	.direction_input = nca9539_gpio_direction_input,
+	.direction_output = nca9539_gpio_direction_output,
+	.get_value = nca9539_gpio_get,
+	.set_value = nca9539_gpio_set,
+	.get_function = nca9539_get_function,
+	.xlate = nca9539_xlate,
+};
+
+static int nca9539_probe(struct udevice *dev)
+{
+	struct nca9539_info *info = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+	char name[32], *str;
+	ulong driver_data;
+
+	if (!info) {
+		dev_err(dev, "platdata not ready\n");
+		return -ENOMEM;
+	}
+
+	if (!chip) {
+		dev_err(dev, "i2c not ready\n");
+		return -ENODEV;
+	}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	info->addr = chip->chip_addr;
+#else
+	info->addr = NCA9539_CHIP_ADDR;
+#endif
+
+	driver_data = dev_get_driver_data(dev);
+	info->ngpio = driver_data;
+	if (info->ngpio > NCA9539_MAX_BANK * NCA9539_BANK_SZ) {
+		dev_err(dev, "Max support %d pins now\n",
+			NCA9539_MAX_BANK * NCA9539_BANK_SZ);
+		return -EINVAL;
+	}
+
+	snprintf(name, sizeof(name), "gpio@%x_", info->addr);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	uc_priv->bank_name = str;
+	uc_priv->gpio_count = info->ngpio;
+
+	dev_dbg(dev, "%s is ready\n", str);
+
+	return 0;
+}
+
+static const struct udevice_id nca9539_ids[] = {
+	{
+		.compatible = "novo,nca9539-gpio",
+		.data = (ulong)16,
+	},
+	{ /* sentinel */ },
+};
+
+U_BOOT_DRIVER(nca9539) = {
+	.name = "nca9539",
+	.id = UCLASS_GPIO,
+	.ops = &nca9539_ops,
+	.probe = nca9539_probe,
+	.platdata_auto_alloc_size = sizeof(struct nca9539_info),
+	.of_match = nca9539_ids,
+};
diff --git a/u-boot/drivers/irq/irq-gpio-switch.c b/u-boot/drivers/irq/irq-gpio-switch.c
index 3c5b92f36e..10acd9f331 100644
--- a/u-boot/drivers/irq/irq-gpio-switch.c
+++ b/u-boot/drivers/irq/irq-gpio-switch.c
@@ -42,7 +42,8 @@ static struct gpio_bank gpio_banks[GPIO_BANK_NUM] = {
 #endif
 };
 
-static const char *gpio_alias[GPIO_BANK_NUM];
+static const char *aliases_gpios[GPIO_BANK_NUM];
+static const char *order_gpios[GPIO_BANK_NUM];
 
 static int gpio_is_valid(u32 gpio)
 {
@@ -80,14 +81,92 @@ static int __hard_gpio_to_irq(u32 gpio)
 	return -EINVAL;
 }
 
+static int init_order_gpios(void)
+{
+	const void *fdt = gd->fdt_blob;
+	static int initialized;
+	int node, offset;
+	int i = 0;
+
+	if (initialized)
+		return 0;
+
+	node = fdt_path_offset(fdt, "/pinctrl");
+	if (node < 0)
+		return -EINVAL;
+
+	for (offset = fdt_first_subnode(fdt, node);
+	     offset >= 0 && i < GPIO_BANK_NUM;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		if (i >= GPIO_BANK_NUM)
+			break;
+
+		order_gpios[i++] = fdt_get_name(fdt, offset, NULL);
+		IRQ_D("order gpio: %s\n", order_gpios[i - 1]);
+	}
+
+	initialized = 1;
+
+	return 0;
+}
+
+static int init_aliases_gpios(void)
+{
+	static int initialized;
+	char alias_name[6];
+	int i;
+
+	if (initialized)
+		return 0;
+
+	for (i = 0; i < GPIO_BANK_NUM; i++) {
+		snprintf(alias_name, 6, "gpio%d", i);
+		aliases_gpios[i] = fdt_get_alias(gd->fdt_blob, alias_name);
+		if (!aliases_gpios[i])
+			return -EINVAL;
+
+		IRQ_D("aliases gpio: %s\n", aliases_gpios[i]);
+	}
+
+	initialized = 1;
+
+	return 0;
+}
+
+static int lookup_gpio_bank(const char *name)
+{
+	int bank, ret;
+
+	for (bank = 0; bank < GPIO_BANK_NUM; bank++) {
+		if (strstr(name, gpio_banks[bank].name))
+			return bank;
+	}
+
+	ret = init_aliases_gpios();
+	for (bank = 0; !ret && bank < GPIO_BANK_NUM; bank++) {
+		/*
+		 * @name pattern can be:
+		 *	/pinctrl/gpio@fd8a0000 or gpio@fd8a0000
+		 */
+		if (strstr(aliases_gpios[bank], name))
+			return bank;
+	}
+
+	ret = init_order_gpios();
+	for (bank = 0; !ret && bank < GPIO_BANK_NUM; bank++) {
+		if (!strcmp(name, order_gpios[bank]))
+			return bank;
+	}
+
+	return -ENOENT;
+}
+
 static int __phandle_gpio_to_irq(u32 gpio_phandle, u32 offset)
 {
 	const void *blob = gd->fdt_blob;
 	const char *gpio_name;
-	char alias_name[6];
 	int irq, node;
-	int i, bank;
-	bool found = false;
+	int bank;
 
 	node = fdt_node_offset_by_phandle(blob, gpio_phandle);
 	if (node < 0) {
@@ -99,36 +178,8 @@ static int __phandle_gpio_to_irq(u32 gpio_phandle, u32 offset)
 	if (!gpio_name)
 		return EINVAL_GPIO;
 
-	for (bank = 0; bank < GPIO_BANK_NUM; bank++) {
-		if (strstr(gpio_name, gpio_banks[bank].name)) {
-			found = true;
-			break;
-		}
-	}
-
-	if (!found) {
-		/* initial getting all gpio alias */
-		if (!gpio_alias[0]) {
-			for (i = 0; i < GPIO_BANK_NUM; i++) {
-				snprintf(alias_name, 6, "gpio%d", i);
-				gpio_alias[i] = fdt_get_alias(blob, alias_name);
-				if (!gpio_alias[i]) {
-					IRQ_D("No gpio alias %s\n", alias_name);
-					return EINVAL_GPIO;
-				}
-			}
-		}
-
-		/* match alias ? */
-		for (bank = 0; bank < ARRAY_SIZE(gpio_banks); bank++) {
-			if (strstr(gpio_alias[bank], gpio_name)) {
-				found = true;
-				break;
-			}
-		}
-	}
-
-	if (!found) {
+	bank = lookup_gpio_bank(gpio_name);
+	if (bank < 0) {
 		IRQ_E("IRQ Framework can't find: %s\n", gpio_name);
 		return EINVAL_GPIO;
 	}
diff --git a/u-boot/drivers/irq/irq-gpio-v2.c b/u-boot/drivers/irq/irq-gpio-v2.c
index 9ad58d611a..ba19074adb 100644
--- a/u-boot/drivers/irq/irq-gpio-v2.c
+++ b/u-boot/drivers/irq/irq-gpio-v2.c
@@ -117,7 +117,7 @@ static void generic_gpio_handle_irq(int irq, void *data __always_unused)
 			h_pin = pin - 16;
 			if (ilr_h & (1 << h_pin)) {
 				unmasked = 1;
-				gpio_irq_unmask(bank->regbase, offset_to_bit(h_pin));
+				gpio_irq_unmask(bank->regbase, offset_to_bit(pin));
 			}
 		}
 		__generic_gpio_handle_irq(gpio_irq + pin);
diff --git a/u-boot/drivers/misc/Kconfig b/u-boot/drivers/misc/Kconfig
index 9b238e077f..fe288ad6bd 100644
--- a/u-boot/drivers/misc/Kconfig
+++ b/u-boot/drivers/misc/Kconfig
@@ -85,6 +85,12 @@ config ROCKCHIP_HW_DECOMPRESS
 	  This driver support Decompress IP built-in Rockchip SoC, support
 	  LZ4, GZIP, PNG, ZLIB.
 
+config ROCKCHIP_PM_CONFIG
+	bool "Rockchip PM Config Support"
+	depends on ARM_CPU_SUSPEND
+	help
+	  This driver supports to configure parameters of system sleep.
+
 config SPL_ROCKCHIP_HW_DECOMPRESS
 	bool "Rockchip HardWare Decompress Support"
 	depends on SPL_MISC_DECOMPRESS
diff --git a/u-boot/drivers/misc/Makefile b/u-boot/drivers/misc/Makefile
index df1fee87f1..4d6b1f7188 100644
--- a/u-boot/drivers/misc/Makefile
+++ b/u-boot/drivers/misc/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
 obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
 obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
 obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_ROCKCHIP_PM_CONFIG) += rockchip_pm_config.o
 endif
 obj-$(CONFIG_FSL_IIM) += fsl_iim.o
 obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
diff --git a/u-boot/drivers/misc/rockchip_decompress.c b/u-boot/drivers/misc/rockchip_decompress.c
index 85edf6e9f2..bbd74a2063 100644
--- a/u-boot/drivers/misc/rockchip_decompress.c
+++ b/u-boot/drivers/misc/rockchip_decompress.c
@@ -98,6 +98,7 @@ static int rockchip_decom_start(struct udevice *dev, void *buf)
 	struct decom_param *param = (struct decom_param *)buf;
 	unsigned int limit_lo = param->size_dst & 0xffffffff;
 	unsigned int limit_hi = param->size_dst >> 32;
+	u32 irq_status;
 
 #if CONFIG_IS_ENABLED(DM_RESET)
 	reset_assert(&priv->rst);
@@ -118,6 +119,11 @@ static int rockchip_decom_start(struct udevice *dev, void *buf)
 
 	priv->done = false;
 
+	irq_status = readl(priv->base + DECOM_ISR);
+	/* clear interrupts */
+	if (irq_status)
+		writel(irq_status, priv->base + DECOM_ISR);
+
 	if (param->mode == DECOM_LZ4)
 		writel(LZ4_CONT_CSUM_CHECK_EN |
 		       LZ4_HEAD_CSUM_CHECK_EN |
@@ -137,6 +143,8 @@ static int rockchip_decom_start(struct udevice *dev, void *buf)
 	writel(limit_lo, priv->base + DECOM_LMTSL);
 	writel(limit_hi, priv->base + DECOM_LMTSH);
 
+	if (param->flags && DCOMP_FLG_IRQ_ONESHOT)
+		writel(DECOM_INT_MASK, priv->base + DECOM_IEN);
 	writel(DECOM_ENABLE, priv->base + DECOM_ENR);
 
 	priv->idle_check_once = true;
diff --git a/u-boot/drivers/misc/rockchip_pm_config.c b/u-boot/drivers/misc/rockchip_pm_config.c
new file mode 100644
index 0000000000..e586336c15
--- /dev/null
+++ b/u-boot/drivers/misc/rockchip_pm_config.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier:     GPL-2.0+
+/*
+ * Copyright (C) 2023 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <misc.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <asm/arch/rockchip_smccc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define RK_ATAG_MCU_SLP_CORE		0x526b0001
+#define RK_ATAG_MCU_SLP_MAX		0x526b00ff
+#define RK_ATAG_NONE			0x00000000
+
+/* rk_tag related defines */
+#define sleep_tag_next(t)	\
+	((struct rk_sleep_tag *)((__u32 *)(t) + (t)->hdr.size))
+
+struct rk_tag_header {
+	u32 size;
+	u32 tag;
+};
+
+struct rk_sleep_tag {
+	struct rk_tag_header hdr;
+	u32 params[];
+};
+
+struct rk_mcu_sleep_core_tag {
+	struct rk_tag_header hdr;
+	u32 total_size;
+	u32 reserve[13];
+};
+
+struct rk_mcu_sleep_tags {
+	struct rk_mcu_sleep_core_tag core;
+	struct rk_sleep_tag slp_tags;
+};
+
+static int rockchip_pm_config_ioctl(struct udevice *dev,
+				    unsigned long request,
+				    void *buf)
+{
+	int ret = -EINVAL;
+
+	switch (request) {
+	case IOCTL_REQ_START:
+		break;
+	default:
+		printf("Unsupported ioctl: %ld\n", (ulong)request);
+		break;
+	}
+
+	return ret;
+}
+
+static const struct misc_ops rockchip_pm_config_ops = {
+	.ioctl = rockchip_pm_config_ioctl,
+};
+
+static int parse_mcu_sleep_config(ofnode node)
+{
+	int ret, len;
+	ofnode mcu_sleep_node;
+	ofnode child;
+	struct arm_smccc_res res;
+	struct rk_mcu_sleep_tags *config;
+	struct rk_sleep_tag *slp_tag;
+	char *end;
+
+	mcu_sleep_node = ofnode_find_subnode(node, "rockchip-mcu-sleep-cfg");
+	if (ofnode_valid(mcu_sleep_node) == 0) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	child = ofnode_first_subnode(mcu_sleep_node);
+	if (ofnode_valid(child) == 0) {
+		pr_err("%s: no valid child node in rockchip-mcu-sleep-cfg\n",
+		       __func__);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/*
+	 * 4kb for sleep parameters
+	 */
+	res = sip_smc_request_share_mem(1, SHARE_PAGE_TYPE_SLEEP);
+	if (res.a0 != 0) {
+		pr_err("%s: no trust memory for mcu_sleep\n", __func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* Initialize core tag */
+	memset((void *)res.a1, 0, sizeof(struct rk_mcu_sleep_tags));
+	config = (struct rk_mcu_sleep_tags *)res.a1;
+	config->core.hdr.tag = RK_ATAG_MCU_SLP_CORE;
+	config->core.hdr.size = sizeof(struct rk_mcu_sleep_core_tag) / sizeof(u32);
+	config->core.total_size = sizeof(struct rk_mcu_sleep_tags) -
+				  sizeof(struct rk_sleep_tag);
+
+	slp_tag = &config->slp_tags;
+
+	/* End point of sleep data  */
+	end = (char *)config + PAGE_SIZE - sizeof(struct rk_sleep_tag);
+
+	ofnode_for_each_subnode(child, mcu_sleep_node) {
+		/* Is overflow? */
+		if ((char *)slp_tag->params >= end)
+			break;
+
+		ret = ofnode_read_u32_array(child, "rockchip,tag",
+					    &slp_tag->hdr.tag, 1);
+		if (ret ||
+		    slp_tag->hdr.tag <= RK_ATAG_MCU_SLP_CORE ||
+		    slp_tag->hdr.tag >= RK_ATAG_MCU_SLP_MAX) {
+			pr_err("%s: no or invalid rockchip,tag in %s\n",
+				__func__, ofnode_get_name(child));
+
+			continue;
+		}
+
+		len = ofnode_read_size(child, "rockchip,params");
+		if (len > 0) {
+			/* Is overflow? */
+			if ((char *)(slp_tag->params + len) >= end) {
+				pr_warn("%s: no more space for rockchip,tag in %s\n",
+					__func__, ofnode_get_name(child));
+				break;
+			}
+
+			ret = ofnode_read_u32_array(child, "rockchip,params",
+						    slp_tag->params,
+						    len / sizeof(u32));
+			if (ret) {
+				pr_err("%s: read rockchip,params error in %s\n",
+				       __func__, ofnode_get_name(child));
+				break;
+			}
+
+			slp_tag->hdr.size =
+				(len + sizeof(struct rk_tag_header)) / sizeof(u32);
+		} else if (len == 0) {
+			slp_tag->hdr.size = 0;
+		} else {
+			continue;
+		}
+
+		config->core.total_size += slp_tag->hdr.size * sizeof(u32);
+
+		slp_tag = sleep_tag_next(slp_tag);
+	}
+
+	/* Add none tag.
+	 * Compiler will combine the follow code as "str xzr, [x28]", but
+	 * "slp->hdr" may not be 8-byte alignment. So we use memset_io instead:
+	 * slp_tag->hdr.size = 0;
+	 * slp_tag->hdr.tag = RK_ATAG_NONE;
+	 */
+	memset_io(&slp_tag->hdr, 0, sizeof(slp_tag->hdr));
+
+	config->core.total_size += sizeof(struct rk_sleep_tag);
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+static int rockchip_pm_config_probe(struct udevice *dev)
+{
+	parse_mcu_sleep_config(dev_ofnode(dev));
+
+	return 0;
+}
+
+static const struct udevice_id rockchip_pm_config_ids[] = {
+	{ .compatible = "rockchip,pm-rk3588" },
+	{}
+};
+
+U_BOOT_DRIVER(rockchip_pm_config) = {
+	.name = "rockchip_pm_config",
+	.id = UCLASS_MISC,
+	.of_match = rockchip_pm_config_ids,
+	.probe = rockchip_pm_config_probe,
+	.ops = &rockchip_pm_config_ops,
+};
diff --git a/u-boot/drivers/mmc/dw_mmc.c b/u-boot/drivers/mmc/dw_mmc.c
index 8126ac0e48..3286105526 100644
--- a/u-boot/drivers/mmc/dw_mmc.c
+++ b/u-boot/drivers/mmc/dw_mmc.c
@@ -241,6 +241,10 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 		buf = (unsigned int *)data->src;
 
 	timeout = dwmci_get_drto(host, size);
+	/* The tuning data is 128bytes, a timeout of 1ms is sufficient.*/
+	if ((dwmci_readl(host, DWMCI_CMD) & 0x1F) == MMC_SEND_TUNING_BLOCK_HS200)
+		timeout = 1;
+
 	size /= 4;
 
 	for (;;) {
@@ -248,6 +252,11 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 		/* Error during data transfer. */
 		if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
 			debug("%s: DATA ERROR!\n", __func__);
+			/*
+			 * It is necessary to wait for several cycles before
+			 * resetting the controller while data timeout or error.
+			 */
+			udelay(1);
 			dwmci_wait_reset(host, DWMCI_RESET_ALL);
 			dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT |
 				     DWMCI_CMD_UPD_CLK | DWMCI_CMD_START);
diff --git a/u-boot/drivers/mmc/mmc-uclass.c b/u-boot/drivers/mmc/mmc-uclass.c
index eb44c3891f..2f99198aa0 100644
--- a/u-boot/drivers/mmc/mmc-uclass.c
+++ b/u-boot/drivers/mmc/mmc-uclass.c
@@ -35,7 +35,8 @@ retry:
 	    cmd->cmdidx != MMC_CMD_SEND_OP_COND &&
 	    cmd->cmdidx != MMC_SEND_TUNING_BLOCK_HS200 &&
 	    cmd->cmdidx != MMC_CMD_READ_MULTIPLE_BLOCK &&
-	    cmd->cmdidx != MMC_CMD_WRITE_MULTIPLE_BLOCK) {
+	    cmd->cmdidx != MMC_CMD_WRITE_MULTIPLE_BLOCK &&
+	    cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION ) {
 		/* execute tuning at last retry. */
 		if (retry_time == 1 &&
 		    mmc->timing == MMC_TIMING_MMC_HS200 &&
diff --git a/u-boot/drivers/mmc/mmc.c b/u-boot/drivers/mmc/mmc.c
index 590e4ba6c8..59805d33aa 100644
--- a/u-boot/drivers/mmc/mmc.c
+++ b/u-boot/drivers/mmc/mmc.c
@@ -902,9 +902,13 @@ int mmc_send_tuning(struct mmc *mmc, u32 opcode)
 	data.flags = MMC_DATA_READ;
 
 	err = mmc_send_cmd(mmc, &cmd, &data);
-	if (err)
+	if (err) {
+		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+		cmd.cmdarg = 0;
+		cmd.resp_type = MMC_RSP_R1b;
+		mmc_send_cmd(mmc, &cmd, NULL);
 		goto out;
-
+	}
 	if (memcmp(data_buf, tuning_block_pattern, size))
 		err = -EIO;
 out:
diff --git a/u-boot/drivers/mmc/rockchip_dw_mmc.c b/u-boot/drivers/mmc/rockchip_dw_mmc.c
index a78cb39c7f..9df956f346 100644
--- a/u-boot/drivers/mmc/rockchip_dw_mmc.c
+++ b/u-boot/drivers/mmc/rockchip_dw_mmc.c
@@ -123,49 +123,115 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
 }
 
 #ifndef CONFIG_MMC_SIMPLE
+#define NUM_PHASES	32
+#define TUNING_ITERATION_TO_PHASE(i, num_phases) (DIV_ROUND_UP((i) * 360, num_phases))
+
 static int rockchip_dwmmc_execute_tuning(struct dwmci_host *host, u32 opcode)
 {
-	int i = 0;
-	int ret = -1;
 	struct mmc *mmc = host->mmc;
 	struct udevice *dev = host->priv;
 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
+	int ret = 0;
+	int i, num_phases = NUM_PHASES;
+	bool v, prev_v = 0, first_v;
+	struct range_t {
+		short start;
+		short end; /* inclusive */
+	};
+	struct range_t ranges[NUM_PHASES / 2 + 1];
+	unsigned int range_count = 0;
+	int longest_range_len = -1;
+	int longest_range = -1;
+	int middle_phase, real_middle_phase;
+	ulong ts;
 
 	if (IS_ERR(&priv->sample_clk))
 		return -EIO;
+	ts = get_timer(0);
 
-	if (mmc->default_phase > 0 && mmc->default_phase < 360) {
-		ret = clk_set_phase(&priv->sample_clk, mmc->default_phase);
-		if (ret)
-			printf("set clk phase fail\n");
-		else
-			ret = mmc_send_tuning(mmc, opcode);
-		mmc->default_phase = 0;
-	}
-	/*
-	 * If use default_phase to tune successfully, return.
-	 * Otherwise, use the othe phase to tune.
-	 */
-	if (!ret)
-		return ret;
-
-	for (i = 0; i < 5; i++) {
-		/* mmc->init_retry must be 0, 1, 2, 3 */
-		if (mmc->init_retry == 4)
-			mmc->init_retry = 0;
-
-		ret = clk_set_phase(&priv->sample_clk, 90 * mmc->init_retry);
-		if (ret) {
-			printf("set clk phase fail\n");
+	/* Try each phase and extract good ranges */
+	for (i = 0; i < num_phases; ) {
+		/* Cannot guarantee any phases larger than 270 would work well */
+		if (TUNING_ITERATION_TO_PHASE(i, num_phases) > 270)
 			break;
+		clk_set_phase(&priv->sample_clk, TUNING_ITERATION_TO_PHASE(i, num_phases));
+
+		v = !mmc_send_tuning(mmc, opcode);
+		debug("3 Tuning phase is %d v = %x\n", TUNING_ITERATION_TO_PHASE(i, num_phases), v);
+		if (i == 0)
+			first_v = v;
+
+		if ((!prev_v) && v) {
+			range_count++;
+			ranges[range_count - 1].start = i;
 		}
-		ret = mmc_send_tuning(mmc, opcode);
-		debug("Tuning phase is %d, ret is %d\n", mmc->init_retry * 90, ret);
-		mmc->init_retry++;
-		if (!ret)
-			break;
+
+		if (v)
+			ranges[range_count - 1].end = i;
+		i++;
+		prev_v = v;
 	}
 
+	if (range_count == 0) {
+		dev_warn(host->dev, "All phases bad!");
+		return -EIO;
+	}
+
+	/* wrap around case, merge the end points */
+	if ((range_count > 1) && first_v && v) {
+		ranges[0].start = ranges[range_count - 1].start;
+		range_count--;
+	}
+
+	/* Find the longest range */
+	for (i = 0; i < range_count; i++) {
+		int len = (ranges[i].end - ranges[i].start + 1);
+
+		if (len < 0)
+			len += num_phases;
+
+		if (longest_range_len < len) {
+			longest_range_len = len;
+			longest_range = i;
+		}
+
+		debug("Good phase range %d-%d (%d len)\n",
+			  TUNING_ITERATION_TO_PHASE(ranges[i].start, num_phases),
+			  TUNING_ITERATION_TO_PHASE(ranges[i].end, num_phases),
+			  len);
+	}
+
+	printf("Best phase range %d-%d (%d len)\n",
+		   TUNING_ITERATION_TO_PHASE(ranges[longest_range].start, num_phases),
+		   TUNING_ITERATION_TO_PHASE(ranges[longest_range].end, num_phases),
+		   longest_range_len);
+
+	middle_phase = ranges[longest_range].start + longest_range_len / 2;
+	middle_phase %= num_phases;
+	real_middle_phase = TUNING_ITERATION_TO_PHASE(middle_phase, num_phases);
+
+	/*
+	 * Since we cut out 270 ~ 360, the original algorithm
+	 * still rolling ranges before and after 270 together
+	 * in some corner cases, we should adjust it to avoid
+	 * using any middle phase located between 270 and 360.
+	 * By calculatiion, it happends due to the bad phases
+	 * lay between 90 ~ 180. So others are all fine to chose.
+	 * Pick 270 is a better choice in those cases. In case of
+	 * bad phases exceed 180, the middle phase of rollback
+	 * would be bigger than 315, so we chose 360.
+	 */
+	if (real_middle_phase > 270) {
+		if (real_middle_phase < 315)
+			real_middle_phase = 270;
+		else
+			real_middle_phase = 0;
+	}
+
+	printf("Successfully tuned phase to %d, used %ldms\n", real_middle_phase, get_timer(0) - ts);
+
+	clk_set_phase(&priv->sample_clk, real_middle_phase);
+
 	return ret;
 }
 #else
diff --git a/u-boot/drivers/mtd/mtd_blk.c b/u-boot/drivers/mtd/mtd_blk.c
index 6472c01d1d..bbaf077f89 100644
--- a/u-boot/drivers/mtd/mtd_blk.c
+++ b/u-boot/drivers/mtd/mtd_blk.c
@@ -21,6 +21,8 @@
 #include <linux/mtd/nand.h>
 #endif
 
+// #define MTD_BLK_VERBOSE
+
 #define MTD_PART_NAND_HEAD		"mtdparts="
 #define MTD_PART_INFO_MAX_SIZE		512
 #define MTD_SINGLE_PART_INFO_MAX_SIZE	40
@@ -458,6 +460,9 @@ ulong mtd_dread(struct udevice *udev, lbaint_t start,
 #endif
 	struct mtd_info *mtd;
 	int ret = 0;
+#ifdef MTD_BLK_VERBOSE
+	ulong us = 1;
+#endif
 
 	if (!desc)
 		return ret;
@@ -469,24 +474,21 @@ ulong mtd_dread(struct udevice *udev, lbaint_t start,
 	if (blkcnt == 0)
 		return 0;
 
-	pr_debug("mtd dread %s %lx %lx\n", mtd->name, start, blkcnt);
-
+#ifdef MTD_BLK_VERBOSE
+	us = get_ticks();
+#endif
 	if (desc->devnum == BLK_MTD_NAND) {
 		ret = mtd_map_read(mtd, off, &rwsize,
 				   NULL, mtd->size,
 				   (u_char *)(dst));
 		if (!ret)
-			return blkcnt;
-		else
-			return 0;
+			ret = blkcnt;
 	} else if (desc->devnum == BLK_MTD_SPI_NAND) {
 		ret = mtd_map_read(mtd, off, &rwsize,
 				   NULL, mtd->size,
 				   (u_char *)(dst));
 		if (!ret)
-			return blkcnt;
-		else
-			return 0;
+			ret = blkcnt;
 	} else if (desc->devnum == BLK_MTD_SPI_NOR) {
 #if defined(CONFIG_SPI_FLASH_MTD) || defined(CONFIG_SPL_BUILD)
 		struct spi_nor *nor = (struct spi_nor *)mtd->priv;
@@ -495,18 +497,22 @@ ulong mtd_dread(struct udevice *udev, lbaint_t start,
 
 		if (desc->op_flag == BLK_PRE_RW)
 			spi->mode |= SPI_DMA_PREPARE;
-		mtd_read(mtd, off, rwsize, &retlen_nor, dst);
+		ret = mtd_read(mtd, off, rwsize, &retlen_nor, dst);
 		if (desc->op_flag == BLK_PRE_RW)
 			spi->mode &= ~SPI_DMA_PREPARE;
 
 		if (retlen_nor == rwsize)
-			return blkcnt;
-		else
+			ret = blkcnt;
 #endif
-			return 0;
-	} else {
-		return 0;
 	}
+#ifdef MTD_BLK_VERBOSE
+	us = (get_ticks() - us) / 24UL;
+	pr_err("mtd dread %s %lx %lx cost %ldus: %ldMB/s\n\n", mtd->name, start, blkcnt, us, (blkcnt / 2) / ((us + 999) / 1000));
+#else
+	pr_debug("mtd dread %s %lx %lx\n\n", mtd->name, start, blkcnt);
+#endif
+
+	return ret;
 }
 
 #if CONFIG_IS_ENABLED(MTD_WRITE)
diff --git a/u-boot/drivers/mtd/nand/bbt.c b/u-boot/drivers/mtd/nand/bbt.c
index 9738ef73c8..2c9ffde09f 100644
--- a/u-boot/drivers/mtd/nand/bbt.c
+++ b/u-boot/drivers/mtd/nand/bbt.c
@@ -17,18 +17,81 @@
 #ifdef CONFIG_MTD_NAND_BBT_USING_FLASH
 
 #ifdef BBT_DEBUG
-#define BBT_DBG pr_err
+#define bbt_dbg pr_err
 #else
-#define BBT_DBG(args...)
+#define bbt_dbg(args...)
 #endif
 
+#define BBT_VERSION_INVALID		(0xFFFFFFFFU)
+#define BBT_VERSION_BLOCK_ABNORMAL	(BBT_VERSION_INVALID - 1)
+#define BBT_VERSION_MAX			(BBT_VERSION_INVALID - 8)
+
 struct nanddev_bbt_info {
 	u8 pattern[4];
 	unsigned int version;
+	u32 hash;
 };
 
 static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
 
+#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
+static void bbt_dbg_hex(char *s, void *buf, u32 len)
+{
+	u32 i, j = 0;
+	u32 *p32 = (u32 *)buf;
+
+	for (i = 0; i < len / 4; i++) {
+		if (j == 0)
+			printf("%s %p + 0x%04x: ", s, buf, i * 4);
+
+		printf("0x%08x,", p32[i]);
+
+		if (++j >= (4)) {
+			j = 0;
+			printf("\n");
+		}
+	}
+	printf("\n");
+}
+#endif
+
+static u32 js_hash(u8 *buf, u32 len)
+{
+	u32 hash = 0x47C6A7E6;
+	u32 i;
+
+	for (i = 0; i < len; i++)
+		hash ^= ((hash << 5) + buf[i] + (hash >> 2));
+
+	return hash;
+}
+
+static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp)
+{
+	u32 hash;
+
+	/* compatible with no-hash version */
+	if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF)
+		return 1;
+
+	hash = js_hash(buf, len);
+	if (hash != hash_cmp)
+		return 0;
+
+	return 1;
+}
+
+static u32 bbt_nand_isbad_bypass(struct nand_device *nand, u32 block)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct nand_pos pos;
+
+	nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_STATUS_UNKNOWN);
+	nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
+
+	return nanddev_isbad(nand, &pos);
+}
+
 /**
  * nanddev_read_bbt() - Read the BBT (Bad Block Table)
  * @nand: NAND device
@@ -50,7 +113,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
 	u8 *data_buf, *oob_buf;
 	struct nanddev_bbt_info *bbt_info;
 	struct mtd_oob_ops ops;
-	int bbt_page_num;
+	u32 bbt_page_num;
 	int ret = 0;
 	unsigned int version = 0;
 
@@ -87,27 +150,69 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
 	/* Store one entry for each block */
 	ret = mtd_read_oob(mtd, block * mtd->erasesize, &ops);
 	if (ret && ret != -EUCLEAN) {
-		pr_err("%s fail %d\n", __func__, ret);
-		ret = -EIO;
+		pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update);
+		ret = 0;
+		version = BBT_VERSION_BLOCK_ABNORMAL;
 		goto out;
 	} else {
 		ret = 0;
 	}
 
-	if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4))
-		version = bbt_info->version;
+	/* bad block or good block without bbt */
+	if (memcmp(bbt_pattern, bbt_info->pattern, 4)) {
+		ret = 0;
+		goto out;
+	}
 
-	BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version);
+	/* good block with abnornal bbt */
+	if (oob_buf[0] == 0xff ||
+	    !bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) {
+		pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update);
+		ret = 0;
+		version = BBT_VERSION_BLOCK_ABNORMAL;
+		goto out;
+	}
+
+	/* good block with good bbt */
+	version = bbt_info->version;
+	bbt_dbg("read_bbt from blk=%d ver=%d update=%d\n", block, version, update);
 	if (update && version > nand->bbt.version) {
 		memcpy(nand->bbt.cache, data_buf, nbytes);
 		nand->bbt.version = version;
 	}
 
+#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
+	bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info));
+	if (version) {
+		u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL);
+		bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED;
+
+		if (!temp_buf)
+			goto out;
+
+		memcpy(temp_buf, nand->bbt.cache, nbytes);
+		memcpy(nand->bbt.cache, data_buf, nbytes);
+
+		if (!in_scan)
+			nand->bbt.option |= NANDDEV_BBT_SCANNED;
+		for (block = 0; block < nblocks; block++) {
+			ret = nanddev_bbt_get_block_status(nand, block);
+			if (ret != NAND_BBT_BLOCK_GOOD)
+				bbt_dbg("bad block[0x%x], ret=%d\n", block, ret);
+		}
+		if (!in_scan)
+			nand->bbt.option &= ~NANDDEV_BBT_SCANNED;
+		memcpy(nand->bbt.cache, temp_buf, nbytes);
+		kfree(temp_buf);
+		ret = 0;
+	}
+#endif
+
 out:
 	kfree(data_buf);
 	kfree(oob_buf);
 
-	return ret < 0 ? -EIO : version;
+	return ret < 0 ? -EIO : (int)version;
 }
 
 static int nanddev_write_bbt(struct nand_device *nand, u32 block)
@@ -120,11 +225,11 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block)
 	u8 *data_buf, *oob_buf;
 	struct nanddev_bbt_info *bbt_info;
 	struct mtd_oob_ops ops;
-	int bbt_page_num;
-	int ret = 0;
+	u32 bbt_page_num;
+	int ret = 0, version;
 	struct nand_pos pos;
 
-	BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
+	bbt_dbg("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
 	if (!nand->bbt.cache)
 		return -ENOMEM;
 
@@ -151,6 +256,7 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block)
 	memcpy(data_buf, nand->bbt.cache, nbytes);
 	memcpy(bbt_info, bbt_pattern, 4);
 	bbt_info->version = nand->bbt.version;
+	bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4);
 
 	/* Store one entry for each block */
 	nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
@@ -166,7 +272,20 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block)
 	ops.ooblen = bbt_page_num * mtd->oobsize;
 	ops.ooboffs = 0;
 	ret = mtd_write_oob(mtd, block * mtd->erasesize, &ops);
+	if (ret) {
+		nand->ops->erase(nand, &pos);
+		goto out;
+	}
 
+	version = nanddev_read_bbt(nand, block, false);
+	if (version != bbt_info->version) {
+		pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n",
+		       block, version, bbt_info->version);
+		nand->ops->erase(nand, &pos);
+		ret = -EIO;
+	} else {
+		ret = 0;
+	}
 out:
 	kfree(data_buf);
 	kfree(oob_buf);
@@ -180,14 +299,30 @@ static __maybe_unused int nanddev_bbt_format(struct nand_device *nand)
 	struct mtd_info *mtd = nanddev_to_mtd(nand);
 	struct nand_pos pos;
 	u32 start_block, block;
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
+					   BITS_PER_LONG);
 
 	start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
 
 	for (block = 0; block < nblocks; block++) {
 		nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
-		if (nanddev_isbad(nand, &pos))
+		if (nanddev_isbad(nand, &pos)) {
+			if (bbt_nand_isbad_bypass(nand, 0)) {
+				memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
+				pr_err("bbt_format fail, test good block %d fail\n", 0);
+				return -EIO;
+			}
+
+			if (!bbt_nand_isbad_bypass(nand, block)) {
+				memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
+				pr_err("bbt_format fail, test bad block %d fail\n", block);
+				return -EIO;
+			}
+
 			nanddev_bbt_set_block_status(nand, block,
 						     NAND_BBT_BLOCK_FACTORY_BAD);
+		}
 	}
 
 	for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
@@ -214,11 +349,31 @@ static int nanddev_scan_bbt(struct nand_device *nand)
 	nand->bbt.option |= NANDDEV_BBT_SCANNED;
 #ifndef CONFIG_SPL_BUILD
 	if (nand->bbt.version == 0) {
-		nanddev_bbt_format(nand);
+		ret = nanddev_bbt_format(nand);
+		if (ret) {
+			nand->bbt.option = 0;
+			pr_err("%s format fail\n", __func__);
+
+			return ret;
+		}
+
 		ret = nanddev_bbt_update(nand);
 		if (ret) {
 			nand->bbt.option = 0;
-			pr_err("%s fail\n", __func__);
+			pr_err("%s update fail\n", __func__);
+
+			return ret;
+		}
+	}
+#endif
+
+#if defined(BBT_DEBUG)
+	pr_err("scan_bbt success\n");
+	if (nand->bbt.version) {
+		for (block = 0; block < nblocks; block++) {
+			ret = nanddev_bbt_get_block_status(nand, block);
+			if (ret != NAND_BBT_BLOCK_GOOD)
+				bbt_dbg("bad block[0x%x], ret=%d\n", block, ret);
 		}
 	}
 #endif
@@ -275,32 +430,32 @@ EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
 int nanddev_bbt_update(struct nand_device *nand)
 {
 #ifdef CONFIG_MTD_NAND_BBT_USING_FLASH
+	struct nand_pos pos;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+
 	if (nand->bbt.cache &&
 	    nand->bbt.option & NANDDEV_BBT_USE_FLASH) {
 		unsigned int nblocks = nanddev_neraseblocks(nand);
 		u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS];
 		int start_block, block;
 		u32 min_version, block_des;
-		int ret, count = 0;
+		int ret, count = 0, status;
 
 		start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
 		for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
-			ret = nanddev_bbt_get_block_status(nand, start_block + block);
-			if (ret == NAND_BBT_BLOCK_FACTORY_BAD) {
-				bbt_version[block] = 0xFFFFFFFF;
-				continue;
-			}
-			ret = nanddev_read_bbt(nand, start_block + block,
-					       false);
-			if (ret < 0)
-				bbt_version[block] = 0xFFFFFFFF;
-			else if (ret == 0)
-				bbt_version[block] = 0;
+			status = nanddev_bbt_get_block_status(nand, start_block + block);
+			ret = nanddev_read_bbt(nand, start_block + block, false);
+			if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD)
+				bbt_version[block] = BBT_VERSION_INVALID;
+			else if (ret == -EIO)
+				bbt_version[block] = BBT_VERSION_INVALID;
+			else if (ret == BBT_VERSION_BLOCK_ABNORMAL)
+				bbt_version[block] = ret;
 			else
 				bbt_version[block] = ret;
 		}
 get_min_ver:
-		min_version = 0xFFFFFFFF;
+		min_version = BBT_VERSION_MAX;
 		block_des = 0;
 		for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
 			if (bbt_version[block] < min_version) {
@@ -309,25 +464,38 @@ get_min_ver:
 			}
 		}
 
+		/* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */
+		if (nand->bbt.version < min_version)
+			nand->bbt.version = min_version + 4;
+
 		if (block_des > 0) {
 			nand->bbt.version++;
 			ret = nanddev_write_bbt(nand, block_des);
-			bbt_version[block_des - start_block] = 0xFFFFFFFF;
 			if (ret) {
-				pr_err("%s blk= %d ret= %d\n", __func__,
-				       block_des, ret);
-				goto get_min_ver;
-			} else {
-				count++;
-				if (count < 2)
-					goto get_min_ver;
-				BBT_DBG("%s success\n", __func__);
-			}
-		} else {
-			pr_err("%s failed\n", __func__);
+				pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret);
 
-			return -1;
+				return -1;
+			}
+
+			bbt_version[block_des - start_block] = BBT_VERSION_INVALID;
+			count++;
+			if (count < 2)
+				goto get_min_ver;
+			bbt_dbg("bbt_update success\n");
+		} else {
+			pr_err("bbt_update failed\n");
+			ret = -1;
 		}
+
+		for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
+			if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) {
+				block_des = start_block + block;
+				nanddev_offs_to_pos(nand, block_des * mtd->erasesize, &pos);
+				nand->ops->erase(nand, &pos);
+			}
+		}
+
+		return ret;
 	}
 #endif
 	return 0;
diff --git a/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl.c b/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl.c
index 20731d1806..1a900331ad 100644
--- a/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl.c
+++ b/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl.c
@@ -351,11 +351,11 @@ static int rockchip_nandc_probe(struct udevice *dev)
 	    id[1] == 0xDA || id[1] == 0xAC ||
 	    id[1] == 0xDC || id[1] == 0xA3 ||
 	    id[1] == 0xD3 || id[1] == 0x95 ||
-	    id[1] == 0x48) {
+	    id[1] == 0x48 || id[1] == 0x63) {
 		nand_page_size = 2048;
 		nand_page_num = 64;
 		nand_block_num = 1024;
-		if (id[1] == 0xDC) {
+		if (id[1] == 0xDC || id[1] == 0xAC) {
 			if ((id[0] == 0x2C && id[3] == 0xA6) ||
 			    (id[0] == 0xC2 && id[3] == 0xA2)) {
 				nand_page_size = 4096;
@@ -380,8 +380,11 @@ static int rockchip_nandc_probe(struct udevice *dev)
 				nand_page_size = 4096;
 				nand_block_num = 4096;
 			}
+		} else if (id[1] == 0x63 && id[3] == 0x19) { /* IS34ML08G088 */
+			nand_page_size = 4096;
+			nand_page_num = 64;
+			nand_block_num = 4096;
 		}
-
 		g_rk_nand->chipnr = 1;
 		g_rk_nand->databuf = kzalloc(nand_page_size, GFP_KERNEL);
 		if (!g_rk_nand)
diff --git a/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl_v9.c b/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl_v9.c
index 0b225be338..1943a58fe5 100644
--- a/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl_v9.c
+++ b/u-boot/drivers/mtd/nand/raw/rockchip_nand_spl_v9.c
@@ -346,11 +346,12 @@ static int rockchip_nandc_probe(struct udevice *dev)
 	    id[1] == 0xDA || id[1] == 0xAC ||
 	    id[1] == 0xDC || id[1] == 0xA3 ||
 	    id[1] == 0xD3 || id[1] == 0x95 ||
-	    id[1] == 0x48 || id[1] == 0xD7) {
+	    id[1] == 0x48 || id[1] == 0xD7 ||
+	    id[1] == 0x63) {
 		nand_page_size = 2048;
 		nand_page_num = 64;
 		nand_block_num = 1024;
-		if (id[1] == 0xDC) {
+		if (id[1] == 0xDC || id[1] == 0xAC) {
 			if ((id[0] == 0x2C && id[3] == 0xA6) ||
 			    (id[0] == 0xC2 && id[3] == 0xA2)) {
 				nand_page_size = 4096;
@@ -379,6 +380,10 @@ static int rockchip_nandc_probe(struct udevice *dev)
 			nand_page_size = 8192;
 			nand_page_num = 128;
 			nand_block_num = 4096;
+		} else if (id[1] == 0x63 && id[3] == 0x19) { /* IS34ML08G088 */
+			nand_page_size = 4096;
+			nand_page_num = 64;
+			nand_block_num = 4096;
 		}
 		g_rk_nand->chipnr = 1;
 		g_rk_nand->databuf = kzalloc(nand_page_size, GFP_KERNEL);
diff --git a/u-boot/drivers/mtd/nand/spi/core.c b/u-boot/drivers/mtd/nand/spi/core.c
index 2ddd2f362d..88b49bc453 100644
--- a/u-boot/drivers/mtd/nand/spi/core.c
+++ b/u-boot/drivers/mtd/nand/spi/core.c
@@ -872,6 +872,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 #endif
 #ifdef CONFIG_SPI_NAND_UNIM
 	&unim_spinand_manufacturer,
+	&unim_zl_spinand_manufacturer,
 #endif
 #ifdef CONFIG_SPI_NAND_SKYHIGH
 	&skyhigh_spinand_manufacturer,
diff --git a/u-boot/drivers/mtd/nand/spi/skyhigh.c b/u-boot/drivers/mtd/nand/spi/skyhigh.c
index 7cf58c6ba5..c01fd747ce 100644
--- a/u-boot/drivers/mtd/nand/spi/skyhigh.c
+++ b/u-boot/drivers/mtd/nand/spi/skyhigh.c
@@ -19,7 +19,7 @@
 #define SKYHIGH_STATUS_ECC_UNCOR_ERROR	(3 << 4)
 
 static SPINAND_OP_VARIANTS(read_cache_variants,
-		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 8, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -88,7 +88,7 @@ static const struct spinand_info skyhigh_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     0,
 		     SPINAND_ECCINFO(&s35ml04g3_ooblayout, s35ml0xg3_ecc_get_status)),
 	SPINAND_INFO("S35ML02G3",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
@@ -97,7 +97,7 @@ static const struct spinand_info skyhigh_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     0,
 		     SPINAND_ECCINFO(&s35ml04g3_ooblayout, s35ml0xg3_ecc_get_status)),
 	SPINAND_INFO("S35ML04G3",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
@@ -106,7 +106,7 @@ static const struct spinand_info skyhigh_spinand_table[] = {
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     SPINAND_HAS_QE_BIT,
+		     0,
 		     SPINAND_ECCINFO(&s35ml04g3_ooblayout, s35ml0xg3_ecc_get_status)),
 };
 
diff --git a/u-boot/drivers/mtd/nand/spi/unim.c b/u-boot/drivers/mtd/nand/spi/unim.c
index b4e3e5b1aa..e6f7b1637e 100644
--- a/u-boot/drivers/mtd/nand/spi/unim.c
+++ b/u-boot/drivers/mtd/nand/spi/unim.c
@@ -12,7 +12,8 @@
 #endif
 #include <linux/mtd/spinand.h>
 
-#define SPINAND_MFR_UNIM		0xA1
+#define SPINAND_MFR_UNIM_ZL		0xA1
+#define SPINAND_MFR_UNIM		0xB0
 
 static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
@@ -27,8 +28,8 @@ static SPINAND_OP_VARIANTS(write_cache_variants,
 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
 
 static SPINAND_OP_VARIANTS(update_cache_variants,
-		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
-		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
 
 static int tx25g01_ooblayout_ecc(struct mtd_info *mtd, int section,
 				 struct mtd_oob_region *region)
@@ -59,6 +60,59 @@ static const struct mtd_ooblayout_ops tx25g01_ooblayout = {
 	.rfree = tx25g01_ooblayout_free,
 };
 
+
+static int um19a0xisw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	return -ERANGE;
+}
+
+static int um19a0xisw_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 2;
+	region->length = 62;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops um19a0xisw_ooblayout = {
+	.ecc = um19a0xisw_ooblayout_ecc,
+	.rfree = um19a0xisw_ooblayout_free,
+};
+
+static int um19a1xisw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 64;
+	region->length = 64;
+
+	return 0;
+}
+
+static int um19a1xisw_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 2;
+	region->length = 62;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops um19a1xisw_ooblayout = {
+	.ecc = um19a1xisw_ooblayout_ecc,
+	.rfree = um19a1xisw_ooblayout_free,
+};
+
 /*
  * ecc bits: 0xC0[4,6]
  * [0b000], No bit errors were detected;
@@ -82,7 +136,32 @@ static int tx25g01_ecc_get_status(struct spinand_device *spinand,
 		return -EBADMSG;
 }
 
-static const struct spinand_info unim_spinand_table[] = {
+/*
+ * ecc bits: 0xC0[4,6]
+ * [0b000], No bit errors were detected;
+ * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not
+ *	reach Flipping Bits;
+ * [0b101], Bit error count equals the bit flip
+ *	detection threshold
+ * [0b010], Multiple bit errors were detected and
+ *	not corrected.
+ * others, Reserved.
+ */
+static int um19axxisw_ecc_ecc_get_status(struct spinand_device *spinand,
+					u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	u8 eccsr = (status & GENMASK(6, 4)) >> 4;
+
+	if (eccsr <= 1 || eccsr == 3)
+		return eccsr;
+	else if (eccsr == 5)
+		return nand->eccreq.strength;
+	else
+		return -EBADMSG;
+}
+
+static const struct spinand_info unim_zl_spinand_table[] = {
 	SPINAND_INFO("TX25G01",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF1),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
@@ -94,9 +173,56 @@ static const struct spinand_info unim_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx25g01_ooblayout, tx25g01_ecc_get_status)),
 };
 
+static const struct spinand_info unim_spinand_table[] = {
+	SPINAND_INFO("UM19A1HISW",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&um19a1xisw_ooblayout, um19axxisw_ecc_ecc_get_status)),
+	SPINAND_INFO("UM19A0HCSW",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&um19a0xisw_ooblayout, um19axxisw_ecc_ecc_get_status)),
+	SPINAND_INFO("UM19A0LCSW",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&um19a0xisw_ooblayout, um19axxisw_ecc_ecc_get_status)),
+	SPINAND_INFO("UM19A1LISW",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&um19a1xisw_ooblayout, um19axxisw_ecc_ecc_get_status)),
+};
+
 static const struct spinand_manufacturer_ops unim_spinand_manuf_ops = {
 };
 
+const struct spinand_manufacturer unim_zl_spinand_manufacturer = {
+	.id = SPINAND_MFR_UNIM_ZL,
+	.name = "UNIM_ZL",
+	.chips = unim_zl_spinand_table,
+	.nchips = ARRAY_SIZE(unim_zl_spinand_table),
+	.ops = &unim_spinand_manuf_ops,
+};
+
 const struct spinand_manufacturer unim_spinand_manufacturer = {
 	.id = SPINAND_MFR_UNIM,
 	.name = "UNIM",
diff --git a/u-boot/drivers/mtd/nand/spi/winbond.c b/u-boot/drivers/mtd/nand/spi/winbond.c
index e05a0f7338..18ebeab65e 100644
--- a/u-boot/drivers/mtd/nand/spi/winbond.c
+++ b/u-boot/drivers/mtd/nand/spi/winbond.c
@@ -210,6 +210,15 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     0,
 		     SPINAND_ECCINFO(&w25n02kv_ooblayout,
 				     w25n02kv_ecc_get_status)),
+	SPINAND_INFO("W25N01JWZEIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBC),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_ECCREQ(1, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
 };
 
 static int winbond_spinand_init(struct spinand_device *spinand)
diff --git a/u-boot/drivers/mtd/nand/spi/xincun.c b/u-boot/drivers/mtd/nand/spi/xincun.c
index dc6334d5f1..e8eadf565b 100644
--- a/u-boot/drivers/mtd/nand/spi/xincun.c
+++ b/u-boot/drivers/mtd/nand/spi/xincun.c
@@ -94,6 +94,15 @@ static const struct spinand_info xincun_spinand_table[] = {
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&xcsp2aapk_ooblayout, xcsp2aapk_ecc_get_status)),
+	SPINAND_INFO("XCSP1AAPK",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xcsp2aapk_ooblayout, xcsp2aapk_ecc_get_status)),
 };
 
 static const struct spinand_manufacturer_ops xincun_spinand_manuf_ops = {
diff --git a/u-boot/drivers/mtd/nand/spi/xtx.c b/u-boot/drivers/mtd/nand/spi/xtx.c
index accae71102..f376ecc5ff 100644
--- a/u-boot/drivers/mtd/nand/spi/xtx.c
+++ b/u-boot/drivers/mtd/nand/spi/xtx.c
@@ -345,6 +345,33 @@ static const struct spinand_info xtx_spinand_table[] = {
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&xt26g01c_ooblayout, xt26g11c_ecc_get_status)),
+	SPINAND_INFO("XT26G01DWSIGA",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x31),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xt26g01b_ooblayout, xt26g11c_ecc_get_status)),
+	SPINAND_INFO("XT26G02DWSIGA",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xt26g01b_ooblayout, xt26g11c_ecc_get_status)),
+	SPINAND_INFO("XT26G04DWSIGA",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x33),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xt26g01c_ooblayout, xt26g11c_ecc_get_status)),
 };
 
 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
diff --git a/u-boot/drivers/mtd/spi/spi-nor-core.c b/u-boot/drivers/mtd/spi/spi-nor-core.c
index 9d69456579..e31c8bd420 100644
--- a/u-boot/drivers/mtd/spi/spi-nor-core.c
+++ b/u-boot/drivers/mtd/spi/spi-nor-core.c
@@ -2633,6 +2633,7 @@ int spi_nor_scan(struct spi_nor *nor)
 	nor->sector_size = mtd->erasesize;
 
 #ifndef CONFIG_SPL_BUILD
+	printf("JEDEC id bytes: %02x, %02x, %02x\n", info->id[0], info->id[1], info->id[2]);
 	printf("SF: Detected %s with page size ", nor->name);
 	print_size(nor->page_size, ", erase size ");
 	print_size(nor->erase_size, ", total ");
diff --git a/u-boot/drivers/mtd/spi/spi-nor-ids.c b/u-boot/drivers/mtd/spi/spi-nor-ids.c
index 8be74f340f..b959e922c1 100644
--- a/u-boot/drivers/mtd/spi/spi-nor-ids.c
+++ b/u-boot/drivers/mtd/spi/spi-nor-ids.c
@@ -184,7 +184,7 @@ const struct flash_info spi_nor_ids[] = {
 	{
 		INFO("gd25lq256d", 0xc86019, 0, 64 * 1024, 512,
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+			SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 	},
 	/* adding these 1.8V QSPI flash parts */
 	{INFO("gd25lb256", 0xc86719, 0, 64 * 1024, 512,	SECT_4K |
@@ -537,6 +537,7 @@ const struct flash_info spi_nor_ids[] = {
 	{ INFO("PY25Q64HA", 0x852017, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ INFO("PY25Q128HA", 0x852018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ INFO("PY25Q256HB", 0x852019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("PY25Q128LA", 0x856518, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 #endif
 #ifdef CONFIG_SPI_FLASH_FMSH
 	/* FUDAN MICRO (Shanghai) Co., Ltd. */
diff --git a/u-boot/drivers/pci/pci-uclass.c b/u-boot/drivers/pci/pci-uclass.c
index 86df141d60..50bc324383 100644
--- a/u-boot/drivers/pci/pci-uclass.c
+++ b/u-boot/drivers/pci/pci-uclass.c
@@ -947,7 +947,6 @@ static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
 static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
 {
 	struct udevice *dev;
-	int ret = 0;
 
 	/*
 	 * Scan through all the PCI controllers. On x86 there will only be one
@@ -959,9 +958,7 @@ static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
 			*devp = dev;
 			return 0;
 		}
-		ret = uclass_next_device(&bus);
-		if (ret)
-			return ret;
+		uclass_next_device(&bus);
 	} while (bus);
 
 	return 0;
@@ -971,7 +968,6 @@ int pci_find_next_device(struct udevice **devp)
 {
 	struct udevice *child = *devp;
 	struct udevice *bus = child->parent;
-	int ret;
 
 	/* First try all the siblings */
 	*devp = NULL;
@@ -984,9 +980,7 @@ int pci_find_next_device(struct udevice **devp)
 	}
 
 	/* We ran out of siblings. Try the next bus */
-	ret = uclass_next_device(&bus);
-	if (ret)
-		return ret;
+	uclass_next_device(&bus);
 
 	return bus ? skip_to_next_device(bus, devp) : 0;
 }
@@ -994,12 +988,9 @@ int pci_find_next_device(struct udevice **devp)
 int pci_find_first_device(struct udevice **devp)
 {
 	struct udevice *bus;
-	int ret;
 
 	*devp = NULL;
-	ret = uclass_first_device(UCLASS_PCI, &bus);
-	if (ret)
-		return ret;
+	uclass_first_device(UCLASS_PCI, &bus);
 
 	return skip_to_next_device(bus, devp);
 }
diff --git a/u-boot/drivers/phy/phy-rockchip-naneng-combphy.c b/u-boot/drivers/phy/phy-rockchip-naneng-combphy.c
index 5ec79aa85e..05b41b84ba 100644
--- a/u-boot/drivers/phy/phy-rockchip-naneng-combphy.c
+++ b/u-boot/drivers/phy/phy-rockchip-naneng-combphy.c
@@ -16,6 +16,7 @@
 #include <asm/arch/clock.h>
 #include <regmap.h>
 #include <reset-uclass.h>
+#include <linux/iopoll.h>
 
 #define BIT_WRITEABLE_SHIFT		16
 
@@ -63,6 +64,7 @@ struct rockchip_combphy_grfcfg {
 	struct combphy_reg pipe_xpcs_phy_ready;
 	struct combphy_reg u3otg0_port_en;
 	struct combphy_reg u3otg1_port_en;
+	struct combphy_reg u3otg0_pipe_clk_sel;
 	struct combphy_reg pipe_phy_grf_reset;
 };
 
@@ -95,6 +97,20 @@ static int param_write(struct regmap *base,
 	return regmap_write(base, reg->offset, val);
 }
 
+static u32 rockchip_combphy_is_ready(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+	u32 mask, val;
+
+	mask = GENMASK(cfg->pipe_phy_status.bitend,
+		       cfg->pipe_phy_status.bitstart);
+
+	regmap_read(priv->phy_grf, cfg->pipe_phy_status.offset, &val);
+	val = (val & mask) >> cfg->pipe_phy_status.bitstart;
+
+	return val;
+}
+
 static int rockchip_combphy_pcie_init(struct rockchip_combphy_priv *priv)
 {
 	int ret = 0;
@@ -155,6 +171,53 @@ static int rockchip_combphy_sgmii_init(struct rockchip_combphy_priv *priv)
 	return ret;
 }
 
+int rockchip_combphy_usb3_uboot_init(void)
+{
+	struct udevice *udev;
+	struct rockchip_combphy_priv *priv;
+	const struct rockchip_combphy_grfcfg *cfg;
+	u32 val;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_PHY,
+					  DM_GET_DRIVER(rockchip_naneng_combphy),
+					  &udev);
+	if (ret) {
+		pr_err("%s: get usb3-phy node failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	priv = dev_get_priv(udev);
+	priv->mode = PHY_TYPE_USB3;
+	cfg = priv->cfg->grfcfg;
+
+	rockchip_combphy_usb3_init(priv);
+	reset_deassert(&priv->phy_rst);
+
+	if (cfg->pipe_phy_grf_reset.enable)
+		param_write(priv->phy_grf, &cfg->pipe_phy_grf_reset, false);
+
+	if (priv->mode == PHY_TYPE_USB3) {
+		ret = readx_poll_timeout(rockchip_combphy_is_ready,
+					 priv, val,
+					 val == cfg->pipe_phy_status.enable,
+					 1000);
+		if (ret) {
+			dev_err(priv->dev, "wait phy status ready timeout\n");
+			param_write(priv->phy_grf, &cfg->usb_mode_set, false);
+			if (cfg->u3otg0_pipe_clk_sel.disable)
+				param_write(priv->phy_grf, &cfg->u3otg0_pipe_clk_sel, false);
+			return ret;
+		}
+	}
+
+	/* Select clk_usb3otg0_pipe for source clk */
+	if (cfg->u3otg0_pipe_clk_sel.disable)
+		param_write(priv->phy_grf, &cfg->u3otg0_pipe_clk_sel, true);
+
+	return ret;
+}
+
 static int rockchip_combphy_set_mode(struct rockchip_combphy_priv *priv)
 {
 	switch (priv->mode) {
@@ -333,6 +396,12 @@ static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv)
 		val |= 0x01;
 		writel(val, priv->mmio + 0x200);
 
+		/* Set Rx squelch input filler bandwidth */
+		val = readl(priv->mmio + 0x20c);
+		val &= ~GENMASK(2, 0);
+		val |= 0x06;
+		writel(val, priv->mmio + 0x20c);
+
 		param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
 		param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
 		param_write(priv->phy_grf, &cfg->usb_mode_set, true);
@@ -379,6 +448,7 @@ static const struct rockchip_combphy_grfcfg rk3528_combphy_grfcfgs = {
 	.con2_for_pcie		= { 0x48008, 15, 0, 0x00, 0x101 },
 	.con3_for_pcie		= { 0x4800c, 15, 0, 0x00, 0x0200 },
 	/* pipe-grf */
+	.u3otg0_pipe_clk_sel	= { 0x40044, 7, 7, 0x01, 0x00 },
 	.u3otg0_port_en		= { 0x40044, 15, 0, 0x0181, 0x1100 },
 };
 
@@ -439,6 +509,9 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv)
 		/* Set PLL KVCO to min and set PLL charge pump current to max */
 		writel(0xf0, priv->mmio + (0xa << 2));
 
+		/* Set Rx squelch input filler bandwidth */
+		writel(0x0e, priv->mmio + (0x14 << 2));
+
 		param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
 		param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
 		param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
@@ -563,8 +636,8 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
 		/* Set PLL KVCO to min and set PLL charge pump current to max */
 		writel(0xf0, priv->mmio + (0xa << 2));
 
- 		/*Set Rx squelch input filler badwidth*/
-                writel(0x0d, priv->mmio + (0x14 << 2));
+		/* Set Rx squelch input filler bandwidth */
+		writel(0x0e, priv->mmio + (0x14 << 2));
 
 		param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
 		param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
diff --git a/u-boot/drivers/phy/phy-rockchip-usbdp.c b/u-boot/drivers/phy/phy-rockchip-usbdp.c
index c4ad1de347..9aeac3261b 100644
--- a/u-boot/drivers/phy/phy-rockchip-usbdp.c
+++ b/u-boot/drivers/phy/phy-rockchip-usbdp.c
@@ -13,6 +13,7 @@
 #include <dm/of_access.h>
 #include <generic-phy.h>
 #include <linux/bitfield.h>
+#include <linux/bitops.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/otg.h>
 #include <regmap.h>
@@ -23,7 +24,62 @@
 
 #include <linux/usb/phy-rockchip-usbdp.h>
 
-#define BIT_WRITEABLE_SHIFT	16
+/* RK3588 USBDP PHY Register Definitions */
+
+#define UDPHY_PCS				0x4000
+#define UDPHY_PMA				0x8000
+
+/* VO GRF Registers */
+#define DP_SINK_HPD_CFG				BIT(11)
+#define DP_SINK_HPD_SEL				BIT(10)
+#define DP_AUX_DIN_SEL				BIT(9)
+#define DP_AUX_DOUT_SEL				BIT(8)
+#define DP_LANE_SEL_N(n)			GENMASK(2 * (n) + 1, 2 * (n))
+#define DP_LANE_SEL_ALL				GENMASK(7, 0)
+
+/* PMA CMN Registers */
+#define CMN_LANE_MUX_AND_EN_OFFSET		0x0288  /* cmn_reg00A2 */
+#define CMN_DP_LANE_MUX_N(n)			BIT((n) + 4)
+#define CMN_DP_LANE_EN_N(n)			BIT(n)
+#define CMN_DP_LANE_MUX_ALL			GENMASK(7, 4)
+#define CMN_DP_LANE_EN_ALL			GENMASK(3, 0)
+
+#define CMN_DP_LINK_OFFSET			0x28c   /*cmn_reg00A3 */
+#define CMN_DP_TX_LINK_BW			GENMASK(6, 5)
+#define CMN_DP_TX_LANE_SWAP_EN			BIT(2)
+
+#define CMN_SSC_EN_OFFSET			0x2d0   /* cmn_reg00B4 */
+#define CMN_ROPLL_SSC_EN			BIT(1)
+#define CMN_LCPLL_SSC_EN			BIT(0)
+
+#define CMN_ANA_LCPLL_DONE_OFFSET		0x0350  /* cmn_reg00D4 */
+#define CMN_ANA_LCPLL_LOCK_DONE			BIT(7)
+#define CMN_ANA_LCPLL_AFC_DONE			BIT(6)
+
+#define CMN_ANA_ROPLL_DONE_OFFSET		0x0354  /* cmn_reg00D5 */
+#define CMN_ANA_ROPLL_LOCK_DONE			BIT(1)
+#define CMN_ANA_ROPLL_AFC_DONE			BIT(0)
+
+#define CMN_DP_RSTN_OFFSET			0x038c  /* cmn_reg00E3 */
+#define CMN_DP_INIT_RSTN			BIT(3)
+#define CMN_DP_CMN_RSTN				BIT(2)
+#define CMN_CDR_WTCHDG_EN			BIT(1)
+#define CMN_CDR_WTCHDG_MSK_CDR_EN		BIT(0)
+
+#define TRSV_ANA_TX_CLK_OFFSET_N(n)		(0x854 + (n) * 0x800)   /* trsv_reg0215 */
+#define LN_ANA_TX_SER_TXCLK_INV			BIT(1)
+
+#define TRSV_LN0_MON_RX_CDR_DONE_OFFSET		0x0b84  /* trsv_reg02E1 */
+#define TRSV_LN0_MON_RX_CDR_LOCK_DONE		BIT(0)
+
+#define TRSV_LN2_MON_RX_CDR_DONE_OFFSET		0x1b84  /* trsv_reg06E1 */
+#define TRSV_LN2_MON_RX_CDR_LOCK_DONE		BIT(0)
+
+#define BIT_WRITEABLE_SHIFT			16
+#define PHY_AUX_DP_DATA_POL_NORMAL		0
+#define PHY_AUX_DP_DATA_POL_INVERT		1
+#define PHY_LANE_MUX_USB			0
+#define PHY_LANE_MUX_DP				1
 
 enum {
 	DP_BW_RBR,
@@ -77,6 +133,11 @@ struct udphy_grf_cfg {
 	struct udphy_grf_reg	rx_lfps;
 };
 
+struct udphy_vogrf_cfg {
+	/* vo-grf */
+	u32 dp_lane_reg;
+};
+
 struct dp_tx_drv_ctrl {
 	u32 trsv_reg0204;
 	u32 trsv_reg0205;
@@ -92,14 +153,8 @@ struct rockchip_udphy_cfg {
 	int num_rsts;
 
 	struct udphy_grf_cfg grfcfg;
+	struct udphy_vogrf_cfg vogrfcfg[2];
 	const struct dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4];
-	int (*combophy_init)(struct rockchip_udphy *udphy);
-	int (*dp_phy_set_rate)(struct rockchip_udphy *udphy,
-			       struct phy_configure_opts_dp *dp);
-	int (*dp_phy_set_voltages)(struct rockchip_udphy *udphy,
-				   struct phy_configure_opts_dp *dp);
-	int (*dplane_enable)(struct rockchip_udphy *udphy, int dp_lanes);
-	int (*dplane_select)(struct rockchip_udphy *udphy);
 };
 
 struct rockchip_udphy {
@@ -223,7 +278,7 @@ static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = {
 	},
 };
 
-static const struct reg_sequence rk3588_udphy_24m_refclk_cfg[] = {
+static const struct reg_sequence udphy_24m_refclk_cfg[] = {
 	{0x0090, 0x68}, {0x0094, 0x68},
 	{0x0128, 0x24}, {0x012c, 0x44},
 	{0x0130, 0x3f}, {0x0134, 0x44},
@@ -262,7 +317,7 @@ static const struct reg_sequence rk3588_udphy_24m_refclk_cfg[] = {
 	{0x1a5c, 0xe0}, {0x1a64, 0xa8}
 };
 
-static const struct reg_sequence rk3588_udphy_init_sequence[] = {
+static const struct reg_sequence udphy_init_sequence[] = {
 	{0x0104, 0x44}, {0x0234, 0xE8},
 	{0x0248, 0x44}, {0x028C, 0x18},
 	{0x081C, 0xE5}, {0x0878, 0x00},
@@ -452,9 +507,26 @@ static void udphy_usb_bvalid_enable(struct rockchip_udphy *udphy, u8 enable)
 static int udphy_dplane_select(struct rockchip_udphy *udphy)
 {
 	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
+	u32 value = 0;
 
-	if (cfg->dplane_select)
-		return cfg->dplane_select(udphy);
+	switch (udphy->mode) {
+	case UDPHY_MODE_DP:
+		value |= 2 << udphy->dp_lane_sel[2] * 2;
+		value |= 3 << udphy->dp_lane_sel[3] * 2;
+	case UDPHY_MODE_DP_USB:
+		value |= 0 << udphy->dp_lane_sel[0] * 2;
+		value |= 1 << udphy->dp_lane_sel[1] * 2;
+		break;
+	case UDPHY_MODE_USB:
+		break;
+	default:
+		break;
+	}
+
+	regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg,
+		     ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) |
+		     FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) |
+		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
 
 	return 0;
 }
@@ -482,18 +554,25 @@ static int udphy_dplane_get(struct rockchip_udphy *udphy)
 
 static int udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes)
 {
-	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
-	int ret = 0;
+	int i;
+	u32 val = 0;
 
-	if (cfg->dplane_enable)
-		ret = cfg->dplane_enable(udphy, dp_lanes);
+	for (i = 0; i < dp_lanes; i++)
+		val |= BIT(udphy->dp_lane_sel[i]);
 
-	return ret;
+	regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL,
+			   FIELD_PREP(CMN_DP_LANE_EN_ALL, val));
+
+	if (!dp_lanes)
+		regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
+				   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
+
+	return 0;
 }
 
 
 __maybe_unused
-static int upphy_set_typec_default_mapping(struct rockchip_udphy *udphy)
+static int udphy_set_typec_default_mapping(struct rockchip_udphy *udphy)
 {
 	if (udphy->flip) {
 		udphy->dp_lane_sel[0] = 0;
@@ -524,16 +603,137 @@ static int upphy_set_typec_default_mapping(struct rockchip_udphy *udphy)
 	return 0;
 }
 
-static int udphy_setup(struct rockchip_udphy *udphy)
+static int udphy_refclk_set(struct rockchip_udphy *udphy)
+{
+	int ret;
+
+	/* configure phy reference clock */
+	ret = __regmap_multi_reg_write(udphy->pma_regmap, udphy_24m_refclk_cfg,
+				       ARRAY_SIZE(udphy_24m_refclk_cfg));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int udphy_status_check(struct rockchip_udphy *udphy)
+{
+	unsigned int val;
+	int ret;
+
+	/* LCPLL check */
+	if (udphy->mode & UDPHY_MODE_USB) {
+		ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET,
+					       val, (val & CMN_ANA_LCPLL_AFC_DONE) &&
+					       (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100);
+		if (ret) {
+			dev_err(udphy->dev, "cmn ana lcpll lock timeout\n");
+			return ret;
+		}
+	}
+
+	if (udphy->mode & UDPHY_MODE_USB) {
+		if (!udphy->flip) {
+			ret = regmap_read_poll_timeout(udphy->pma_regmap,
+						       TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val,
+						       val & TRSV_LN0_MON_RX_CDR_LOCK_DONE,
+						       200, 100);
+			if (ret)
+				dev_notice(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n");
+		} else {
+			ret = regmap_read_poll_timeout(udphy->pma_regmap,
+						       TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val,
+						       val & TRSV_LN2_MON_RX_CDR_LOCK_DONE,
+						       200, 100);
+			if (ret)
+				dev_notice(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n");
+		}
+	}
+
+	return 0;
+}
+
+static int udphy_init(struct rockchip_udphy *udphy)
 {
 	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
+	int ret;
+
+	/* enable rx lfps for usb */
+	if (udphy->mode & UDPHY_MODE_USB)
+		grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true);
+
+	/* Step 1: power on pma and deassert apb rstn */
+	grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true);
+
+	udphy_reset_deassert(udphy, "pma_apb");
+	udphy_reset_deassert(udphy, "pcs_apb");
+
+	/* Step 2: set init sequence and phy refclk */
+	ret = __regmap_multi_reg_write(udphy->pma_regmap, udphy_init_sequence,
+				       ARRAY_SIZE(udphy_init_sequence));
+	if (ret) {
+		dev_err(udphy->dev, "init sequence set error %d\n", ret);
+		goto assert_apb;
+	}
+
+	ret = udphy_refclk_set(udphy);
+	if (ret) {
+		dev_err(udphy->dev, "refclk set error %d\n", ret);
+		goto assert_apb;
+	}
+
+	/* Step 3: configure lane mux */
+	regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET,
+			   CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL,
+			   FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) |
+			   FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) |
+			   FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) |
+			   FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) |
+			   FIELD_PREP(CMN_DP_LANE_EN_ALL, 0));
+
+	/* Step 4: deassert init rstn and wait for 200ns from datasheet */
+	if (udphy->mode & UDPHY_MODE_USB)
+		udphy_reset_deassert(udphy, "init");
+
+	if (udphy->mode & UDPHY_MODE_DP) {
+		regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
+				   CMN_DP_INIT_RSTN,
+				   FIELD_PREP(CMN_DP_INIT_RSTN, 0x1));
+	}
+
+	udelay(1);
+
+	/*  Step 5: deassert cmn/lane rstn */
+	if (udphy->mode & UDPHY_MODE_USB) {
+		udphy_reset_deassert(udphy, "cmn");
+		udphy_reset_deassert(udphy, "lane");
+	}
+
+	/*  Step 6: wait for lock done of pll */
+	ret = udphy_status_check(udphy);
+	if (ret)
+		goto assert_phy;
+
+	return 0;
+
+assert_phy:
+	udphy_reset_assert(udphy, "init");
+	udphy_reset_assert(udphy, "cmn");
+	udphy_reset_assert(udphy, "lane");
+
+assert_apb:
+	udphy_reset_assert(udphy, "pma_apb");
+	udphy_reset_assert(udphy, "pcs_apb");
+	return ret;
+}
+
+static int udphy_setup(struct rockchip_udphy *udphy)
+{
 	int ret = 0;
 
-	if (cfg->combophy_init) {
-		ret = cfg->combophy_init(udphy);
-		if (ret)
-			dev_err(udphy->dev, "failed to init combophy\n");
-	}
+	ret = udphy_init(udphy);
+	if (ret)
+		dev_err(udphy->dev, "failed to init combophy\n");
 
 	return ret;
 }
@@ -551,11 +751,10 @@ static int udphy_disable(struct rockchip_udphy *udphy)
 
 static int udphy_parse_lane_mux_data(struct rockchip_udphy *udphy, struct udevice *dev)
 {
-	const struct device_node *np = ofnode_to_np(dev->node);
-	struct property *prop;
+	const void *prop;
 	int ret, i, len, num_lanes;
 
-	prop = of_find_property(np, "rockchip,dp-lane-mux", &len);
+	prop = dev_read_prop(dev, "rockchip,dp-lane-mux", &len);
 	if (!prop) {
 		dev_dbg(dev, "failed to find dp lane mux, following dp alt mode\n");
 		udphy->mode = UDPHY_MODE_USB;
@@ -569,7 +768,7 @@ static int udphy_parse_lane_mux_data(struct rockchip_udphy *udphy, struct udevic
 		return -EINVAL;
 	}
 
-	ret = of_read_u32_array(np, "rockchip,dp-lane-mux", udphy->dp_lane_sel, num_lanes);
+	ret = dev_read_u32_array(dev, "rockchip,dp-lane-mux", udphy->dp_lane_sel, num_lanes);
 	if (ret) {
 		dev_err(dev, "get dp lane mux failed\n");
 		return -EINVAL;
@@ -813,20 +1012,115 @@ static int rockchip_dpphy_verify_config(struct rockchip_udphy *udphy,
 	return 0;
 }
 
+static int dp_phy_set_rate(struct rockchip_udphy *udphy,
+			   struct phy_configure_opts_dp *dp)
+{
+	u32 val;
+	int ret;
+
+	regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
+			   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
+
+	switch (dp->link_rate) {
+	case 1620:
+		udphy->bw = DP_BW_RBR;
+		break;
+	case 2700:
+		udphy->bw = DP_BW_HBR;
+		break;
+	case 5400:
+		udphy->bw = DP_BW_HBR2;
+		break;
+	case 8100:
+		udphy->bw = DP_BW_HBR3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW,
+			   FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw));
+	regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN,
+			   FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc));
+	regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN,
+			   FIELD_PREP(CMN_DP_CMN_RSTN, 0x1));
+
+	ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val,
+				       FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) &&
+				       FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val),
+				       0, 1000);
+	if (ret) {
+		printf("ROPLL is not lock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void dp_phy_set_voltage(struct rockchip_udphy *udphy, u8 bw,
+			       u32 voltage, u32 pre, u32 lane)
+{
+	u32 offset = 0x800 * lane;
+	u32 val;
+	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
+	const struct dp_tx_drv_ctrl (*dp_ctrl)[4];
+
+	dp_ctrl = cfg->dp_tx_ctrl_cfg[bw];
+	val = dp_ctrl[voltage][pre].trsv_reg0204;
+	regmap_write(udphy->pma_regmap, 0x0810 + offset, val);
+
+	val = dp_ctrl[voltage][pre].trsv_reg0205;
+	regmap_write(udphy->pma_regmap, 0x0814 + offset, val);
+
+	val = dp_ctrl[voltage][pre].trsv_reg0206;
+	regmap_write(udphy->pma_regmap, 0x0818 + offset, val);
+
+	val = dp_ctrl[voltage][pre].trsv_reg0207;
+	regmap_write(udphy->pma_regmap, 0x081c + offset, val);
+}
+
+static int dp_phy_set_voltages(struct rockchip_udphy *udphy,
+			       struct phy_configure_opts_dp *dp)
+{
+	u32 i, lane;
+
+	for (i = 0; i < dp->lanes; i++) {
+		lane = udphy->dp_lane_sel[i];
+		switch (dp->link_rate) {
+		case 1620:
+		case 2700:
+			regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane),
+					   LN_ANA_TX_SER_TXCLK_INV,
+					   FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV,
+						      udphy->lane_mux_sel[lane]));
+			break;
+		case 5400:
+		case 8100:
+			regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane),
+					   LN_ANA_TX_SER_TXCLK_INV,
+					   FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0));
+			break;
+		}
+
+		dp_phy_set_voltage(udphy, udphy->bw, dp->voltage[i], dp->pre[i], lane);
+	}
+
+	return 0;
+}
+
 static int rockchip_dpphy_configure(struct phy *phy,
 				    union phy_configure_opts *opts)
 {
 	struct udevice *parent = phy->dev->parent;
 	struct rockchip_udphy *udphy = dev_get_priv(parent);
-	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
 	int ret;
 
 	ret = rockchip_dpphy_verify_config(udphy, &opts->dp);
 	if (ret)
 		return ret;
 
-	if (opts->dp.set_rate && cfg->dp_phy_set_rate) {
-		ret = cfg->dp_phy_set_rate(udphy, &opts->dp);
+	if (opts->dp.set_rate) {
+		ret = dp_phy_set_rate(udphy, &opts->dp);
 		if (ret) {
 			printf("%s: rockchip_hdptx_phy_set_rate failed\n",
 			       udphy->dev->name);
@@ -834,8 +1128,8 @@ static int rockchip_dpphy_configure(struct phy *phy,
 		}
 	}
 
-	if (opts->dp.set_voltages && cfg->dp_phy_set_voltages) {
-		ret = cfg->dp_phy_set_voltages(udphy, &opts->dp);
+	if (opts->dp.set_voltages) {
+		ret = dp_phy_set_voltages(udphy, &opts->dp);
 		if (ret) {
 			printf("%s: rockchip_dp_phy_set_voltages failed\n",
 			       udphy->dev->name);
@@ -887,6 +1181,7 @@ int rockchip_u3phy_uboot_init(void)
 {
 	struct udevice *udev;
 	struct rockchip_udphy *udphy;
+	unsigned int val;
 	int ret;
 
 	ret = uclass_get_device_by_driver(UCLASS_PHY,
@@ -900,23 +1195,45 @@ int rockchip_u3phy_uboot_init(void)
 	/* DP only or high-speed, disable U3 port */
 	udphy = dev_get_priv(udev->parent);
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
-		udphy_u3_port_disable(udphy, true);
-		return 0;
+		pr_err("%s: udphy mode not support usb3\n", __func__);
+		goto disable_u3;
 	}
 
-	return udphy_power_on(udphy, UDPHY_MODE_USB);
+	udphy->flip = false;
+	udphy_set_typec_default_mapping(udphy);
+
+	ret =  udphy_power_on(udphy, UDPHY_MODE_USB);
+	if (ret) {
+		pr_err("%s: udphy power on failed: %d\n", __func__, ret);
+		goto disable_u3;
+	}
+
+	ret = regmap_read_poll_timeout(udphy->pma_regmap,
+				       TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val,
+				       val & TRSV_LN0_MON_RX_CDR_LOCK_DONE,
+				       200, 100);
+	if (ret) {
+		pr_err("%s: udphy rx cdr lock timeout\n", __func__);
+		goto disable_u3;
+	}
+
+	return 0;
+
+disable_u3:
+	udphy_u3_port_disable(udphy, true);
+
+	return -EOPNOTSUPP;
 }
 
 static int rockchip_udphy_probe(struct udevice *dev)
 {
-	const struct device_node *np = ofnode_to_np(dev->node);
 	struct rockchip_udphy *udphy = dev_get_priv(dev);
 	const struct rockchip_udphy_cfg *phy_cfgs;
 	int id, ret;
 
 	udphy->dev = dev;
 
-	id = of_alias_get_id(np, "usbdp");
+	id = of_alias_get_id(ofnode_to_np(dev->node), "usbdp");
 	if (id < 0)
 		id = 0;
 	udphy->id = id;
@@ -980,270 +1297,6 @@ static int rockchip_udphy_bind(struct udevice *parent)
 	return 0;
 }
 
-static int rk3588_udphy_refclk_set(struct rockchip_udphy *udphy)
-{
-	int ret;
-
-	/* configure phy reference clock */
-	ret = __regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_24m_refclk_cfg,
-				       ARRAY_SIZE(rk3588_udphy_24m_refclk_cfg));
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int rk3588_udphy_status_check(struct rockchip_udphy *udphy)
-{
-	unsigned int val;
-	int ret;
-
-	/* LCPLL check */
-	if (udphy->mode & UDPHY_MODE_USB) {
-		ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET,
-					       val, (val & CMN_ANA_LCPLL_AFC_DONE) &&
-					       (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100);
-		if (ret) {
-			dev_err(udphy->dev, "cmn ana lcpll lock timeout\n");
-			return ret;
-		}
-	}
-
-	if (udphy->mode & UDPHY_MODE_USB) {
-		if (!udphy->flip) {
-			ret = regmap_read_poll_timeout(udphy->pma_regmap,
-						       TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val,
-						       val & TRSV_LN0_MON_RX_CDR_LOCK_DONE,
-						       200, 100);
-			if (ret)
-				dev_notice(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n");
-		} else {
-			ret = regmap_read_poll_timeout(udphy->pma_regmap,
-						       TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val,
-						       val & TRSV_LN2_MON_RX_CDR_LOCK_DONE,
-						       200, 100);
-			if (ret)
-				dev_notice(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n");
-		}
-	}
-
-	return 0;
-}
-
-static int rk3588_udphy_init(struct rockchip_udphy *udphy)
-{
-	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
-	int ret;
-
-	/* enable rx lfps for usb */
-	if (udphy->mode & UDPHY_MODE_USB)
-		grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true);
-
-	/* Step 1: power on pma and deassert apb rstn */
-	grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true);
-
-	udphy_reset_deassert(udphy, "pma_apb");
-	udphy_reset_deassert(udphy, "pcs_apb");
-
-	/* Step 2: set init sequence and phy refclk */
-	ret = __regmap_multi_reg_write(udphy->pma_regmap, rk3588_udphy_init_sequence,
-				       ARRAY_SIZE(rk3588_udphy_init_sequence));
-	if (ret) {
-		dev_err(udphy->dev, "init sequence set error %d\n", ret);
-		goto assert_apb;
-	}
-
-	ret = rk3588_udphy_refclk_set(udphy);
-	if (ret) {
-		dev_err(udphy->dev, "refclk set error %d\n", ret);
-		goto assert_apb;
-	}
-
-	/* Step 3: configure lane mux */
-	regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET,
-			   CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL,
-			   FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) |
-			   FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) |
-			   FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) |
-			   FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) |
-			   FIELD_PREP(CMN_DP_LANE_EN_ALL, 0));
-
-	/* Step 4: deassert init rstn and wait for 200ns from datasheet */
-	if (udphy->mode & UDPHY_MODE_USB)
-		udphy_reset_deassert(udphy, "init");
-
-	if (udphy->mode & UDPHY_MODE_DP) {
-		regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
-				   CMN_DP_INIT_RSTN,
-				   FIELD_PREP(CMN_DP_INIT_RSTN, 0x1));
-	}
-
-	udelay(1);
-
-	/*  Step 5: deassert cmn/lane rstn */
-	if (udphy->mode & UDPHY_MODE_USB) {
-		udphy_reset_deassert(udphy, "cmn");
-		udphy_reset_deassert(udphy, "lane");
-	}
-
-	/*  Step 6: wait for lock done of pll */
-	ret = rk3588_udphy_status_check(udphy);
-	if (ret)
-		goto assert_phy;
-
-	return 0;
-
-assert_phy:
-	udphy_reset_assert(udphy, "init");
-	udphy_reset_assert(udphy, "cmn");
-	udphy_reset_assert(udphy, "lane");
-
-assert_apb:
-	udphy_reset_assert(udphy, "pma_apb");
-	udphy_reset_assert(udphy, "pcs_apb");
-	return ret;
-}
-
-static int rk3588_udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes)
-{
-	int i;
-	u32 val = 0;
-
-	for (i = 0; i < dp_lanes; i++)
-		val |= BIT(udphy->dp_lane_sel[i]);
-
-	regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL,
-			   FIELD_PREP(CMN_DP_LANE_EN_ALL, val));
-
-	if (!dp_lanes)
-		regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
-				   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
-
-	return 0;
-}
-
-static int rk3588_udphy_dplane_select(struct rockchip_udphy *udphy)
-{
-	u32 value = 0;
-
-	switch (udphy->mode) {
-	case UDPHY_MODE_DP:
-		value |= 2 << udphy->dp_lane_sel[2] * 2;
-		value |= 3 << udphy->dp_lane_sel[3] * 2;
-	case UDPHY_MODE_DP_USB:
-		value |= 0 << udphy->dp_lane_sel[0] * 2;
-		value |= 1 << udphy->dp_lane_sel[1] * 2;
-		break;
-	case UDPHY_MODE_USB:
-		break;
-	default:
-		break;
-	}
-
-	regmap_write(udphy->vogrf, udphy->id ? RK3588_GRF_VO0_CON2 : RK3588_GRF_VO0_CON0,
-		     ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) |
-		     FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) |
-		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
-
-	return 0;
-}
-
-static int rk3588_dp_phy_set_rate(struct rockchip_udphy *udphy,
-				  struct phy_configure_opts_dp *dp)
-{
-	u32 val;
-	int ret;
-
-	regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
-			   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
-
-	switch (dp->link_rate) {
-	case 1620:
-		udphy->bw = DP_BW_RBR;
-		break;
-	case 2700:
-		udphy->bw = DP_BW_HBR;
-		break;
-	case 5400:
-		udphy->bw = DP_BW_HBR2;
-		break;
-	case 8100:
-		udphy->bw = DP_BW_HBR3;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW,
-			   FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw));
-	regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN,
-			   FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc));
-	regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN,
-			   FIELD_PREP(CMN_DP_CMN_RSTN, 0x1));
-
-	ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val,
-				       FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) &&
-				       FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val),
-				       0, 1000);
-	if (ret) {
-		printf("ROPLL is not lock\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static void rk3588_dp_phy_set_voltage(struct rockchip_udphy *udphy, u8 bw,
-				      u32 voltage, u32 pre, u32 lane)
-{
-	u32 offset = 0x800 * lane;
-	u32 val;
-	const struct rockchip_udphy_cfg *cfg = udphy->cfgs;
-	const struct dp_tx_drv_ctrl (*dp_ctrl)[4];
-
-	dp_ctrl = cfg->dp_tx_ctrl_cfg[bw];
-	val = dp_ctrl[voltage][pre].trsv_reg0204;
-	regmap_write(udphy->pma_regmap, 0x0810 + offset, val);
-
-	val = dp_ctrl[voltage][pre].trsv_reg0205;
-	regmap_write(udphy->pma_regmap, 0x0814 + offset, val);
-
-	val = dp_ctrl[voltage][pre].trsv_reg0206;
-	regmap_write(udphy->pma_regmap, 0x0818 + offset, val);
-
-	val = dp_ctrl[voltage][pre].trsv_reg0207;
-	regmap_write(udphy->pma_regmap, 0x081c + offset, val);
-}
-
-static int rk3588_dp_phy_set_voltages(struct rockchip_udphy *udphy,
-				      struct phy_configure_opts_dp *dp)
-{
-	u32 i, lane;
-
-	for (i = 0; i < dp->lanes; i++) {
-		lane = udphy->dp_lane_sel[i];
-		switch (dp->link_rate) {
-		case 1620:
-		case 2700:
-			regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane),
-					   LN_ANA_TX_SER_TXCLK_INV,
-					   FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV,
-						      udphy->lane_mux_sel[lane]));
-			break;
-		case 5400:
-		case 8100:
-			regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane),
-					   LN_ANA_TX_SER_TXCLK_INV,
-					   FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0));
-			break;
-		}
-
-		rk3588_dp_phy_set_voltage(udphy, udphy->bw, dp->voltage[i], dp->pre[i], lane);
-	}
-
-	return 0;
-}
-
 static int rockchip_dpphy_probe(struct udevice *dev)
 {
 	struct rockchip_udphy *udphy = dev_get_priv(dev->parent);
@@ -1287,17 +1340,20 @@ static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = {
 		.low_pwrn		= { 0x0004, 13, 13, 0, 1 },
 		.rx_lfps		= { 0x0004, 14, 14, 0, 1 },
 	},
+	.vogrfcfg = {
+		{
+			.dp_lane_reg	= 0x0000,
+		},
+		{
+			.dp_lane_reg	= 0x0008,
+		},
+	},
 	.dp_tx_ctrl_cfg = {
 		rk3588_dp_tx_drv_ctrl_rbr_hbr,
 		rk3588_dp_tx_drv_ctrl_rbr_hbr,
 		rk3588_dp_tx_drv_ctrl_hbr2,
 		rk3588_dp_tx_drv_ctrl_hbr3,
 	},
-	.combophy_init = rk3588_udphy_init,
-	.dp_phy_set_rate = rk3588_dp_phy_set_rate,
-	.dp_phy_set_voltages = rk3588_dp_phy_set_voltages,
-	.dplane_enable = rk3588_udphy_dplane_enable,
-	.dplane_select = rk3588_udphy_dplane_select,
 };
 
 static const struct udevice_id rockchip_udphy_dt_match[] = {
diff --git a/u-boot/drivers/pinctrl/Kconfig b/u-boot/drivers/pinctrl/Kconfig
index 4899c71332..151297f3be 100644
--- a/u-boot/drivers/pinctrl/Kconfig
+++ b/u-boot/drivers/pinctrl/Kconfig
@@ -59,6 +59,22 @@ config PINCONF
 	  This option enables pin configuration through the generic pinctrl
 	  framework.
 
+config PINCONF_RECURSIVE
+	bool "Support recursive binding for pin configuration nodes"
+	depends on PINCTRL_FULL
+	default n if ARCH_STM32MP
+	default y
+	help
+	  In the Linux pinctrl binding, the pin configuration nodes need not be
+	  direct children of the pin controller device (may be grandchildren for
+	  example). It is define is each individual pin controller device.
+	  Say Y here if you want to keep this behavior with the pinconfig
+	  u-class: all sub are recursivelly bounded.
+	  If the option is disabled, this behavior is deactivated and only
+	  the direct children of pin controller will be assumed as pin
+	  configuration; you can save memory footprint when this feature is
+	  no needed.
+
 config SPL_PINCTRL
 	bool "Support pin controllers in SPL"
 	depends on SPL && SPL_DM
@@ -104,6 +120,15 @@ config SPL_PINCONF
 	  This option is an SPL-variant of the PINCONF option.
 	  See the help of PINCONF for details.
 
+config SPL_PINCONF_RECURSIVE
+	bool "Support recursive binding for pin configuration nodes in SPL"
+	depends on SPL_PINCTRL_FULL
+	default n if ARCH_STM32MP
+	default y
+	help
+	  This option is an SPL-variant of the PINCONF_RECURSIVE option.
+	  See the help of PINCONF_RECURSIVE for details.
+
 if PINCTRL || SPL_PINCTRL
 
 config PINCTRL_AR933X
diff --git a/u-boot/drivers/pinctrl/pinctrl-generic.c b/u-boot/drivers/pinctrl/pinctrl-generic.c
index a204035a9d..f3d7d5b8e3 100644
--- a/u-boot/drivers/pinctrl/pinctrl-generic.c
+++ b/u-boot/drivers/pinctrl/pinctrl-generic.c
@@ -227,6 +227,13 @@ static int pinconf_enable_setting(struct udevice *dev, bool is_group,
 }
 #endif
 
+enum pinmux_subnode_type {
+	PST_NONE = 0,
+	PST_PIN,
+	PST_GROUP,
+	PST_PINMUX,
+};
+
 /**
  * pinctrl_generic_set_state_one() - set state for a certain pin/group
  * Apply all pin multiplexing and pin configurations specified by @config
@@ -234,13 +241,15 @@ static int pinconf_enable_setting(struct udevice *dev, bool is_group,
  *
  * @dev: pin controller device
  * @config: pseudo device pointing to config node
- * @is_group: target of operation (true: pin group, false: pin)
- * @selector: pin selector or group selector, depending on @is_group
+ * @subnode_type: target of operation (pin, group, or pin specified by a pinmux
+ * group)
+ * @selector: pin selector or group selector, depending on @subnode_type
  * @return: 0 on success, or negative error code on failure
  */
 static int pinctrl_generic_set_state_one(struct udevice *dev,
 					 struct udevice *config,
-					 bool is_group, unsigned selector)
+					 enum pinmux_subnode_type subnode_type,
+					 unsigned selector)
 {
 	const char *propname;
 	const void *value;
@@ -248,17 +257,22 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 	int len, func_selector, param, ret;
 	u32 arg, default_val;
 
+	assert(subnode_type != PST_NONE);
+
 	dev_for_each_property(property, config) {
 		value = dev_read_prop_by_prop(&property, &propname, &len);
 		if (!value)
 			return -EINVAL;
 
-		if (!strcmp(propname, "function")) {
+		/* pinmux subnodes already have their muxing set */
+		if (subnode_type != PST_PINMUX &&
+		    !strcmp(propname, "function")) {
 			func_selector = pinmux_func_name_to_selector(dev,
 								     value);
 			if (func_selector < 0)
 				return func_selector;
-			ret = pinmux_enable_setting(dev, is_group,
+			ret = pinmux_enable_setting(dev,
+						    subnode_type == PST_GROUP,
 						    selector,
 						    func_selector);
 		} else {
@@ -272,7 +286,8 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 			else
 				arg = default_val;
 
-			ret = pinconf_enable_setting(dev, is_group,
+			ret = pinconf_enable_setting(dev,
+						     subnode_type == PST_GROUP,
 						     selector, param, arg);
 		}
 
@@ -283,6 +298,41 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 	return 0;
 }
 
+/**
+ * pinctrl_generic_get_subnode_type() - determine whether there is a valid
+ * pins, groups, or pinmux property in the config node
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @count: number of specifiers contained within the property
+ * @return: the type of the subnode, or PST_NONE
+ */
+static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice *dev,
+								 struct udevice *config,
+								 int *count)
+{
+	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	*count = dev_read_string_count(config, "pins");
+	if (*count >= 0)
+		return PST_PIN;
+
+	*count = dev_read_string_count(config, "groups");
+	if (*count >= 0)
+		return PST_GROUP;
+
+	if (ops->pinmux_property_set) {
+		*count = dev_read_size(config, "pinmux");
+		if (*count >= 0 && !(*count % sizeof(u32))) {
+			*count /= sizeof(u32);
+			return PST_PINMUX;
+		}
+	}
+
+	*count = 0;
+	return PST_NONE;
+}
+
 /**
  * pinctrl_generic_set_state_subnode() - apply all settings in config node
  *
@@ -293,38 +343,55 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
 static int pinctrl_generic_set_state_subnode(struct udevice *dev,
 					     struct udevice *config)
 {
-	const char *subnode_target_type = "pins";
-	bool is_group = false;
+	enum pinmux_subnode_type subnode_type;
 	const char *name;
-	int strings_count, selector, i, ret;
+	int count, selector, i, ret, scratch;
+	const u32 *pinmux_groups = NULL; /* prevent use-uninitialized warning */
 
-	strings_count = dev_read_string_count(config, subnode_target_type);
-	if (strings_count < 0) {
-		subnode_target_type = "groups";
-		is_group = true;
-		strings_count = dev_read_string_count(config,
-						      subnode_target_type);
-		if (strings_count < 0) {
+	subnode_type = pinctrl_generic_get_subnode_type(dev, config, &count);
+
+	debug("%s(%s, %s): count=%d\n", __func__, dev->name, config->name,
+	      count);
+
+	if (subnode_type == PST_PINMUX) {
+		pinmux_groups = dev_read_prop(config, "pinmux", &scratch);
+		if (!pinmux_groups)
+			return -EINVAL;
+	}
+
+	for (i = 0; i < count; i++) {
+		switch (subnode_type) {
+		case PST_PIN:
+			ret = dev_read_string_index(config, "pins", i, &name);
+			if (ret)
+				return ret;
+			selector = pinctrl_pin_name_to_selector(dev, name);
+			break;
+		case PST_GROUP:
+			ret = dev_read_string_index(config, "groups", i, &name);
+			if (ret)
+				return ret;
+			selector = pinctrl_group_name_to_selector(dev, name);
+			break;
+		case PST_PINMUX: {
+			const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+			u32 pinmux_group = fdt32_to_cpu(pinmux_groups[i]);
+
+			/* Checked for in pinctrl_generic_get_subnode_type */
+			selector = ops->pinmux_property_set(dev, pinmux_group);
+			break;
+		}
+		case PST_NONE:
+		default:
 			/* skip this node; may contain config child nodes */
 			return 0;
 		}
-	}
 
-	for (i = 0; i < strings_count; i++) {
-		ret = dev_read_string_index(config, subnode_target_type, i,
-					    &name);
-		if (ret)
-			return ret;
-
-		if (is_group)
-			selector = pinctrl_group_name_to_selector(dev, name);
-		else
-			selector = pinctrl_pin_name_to_selector(dev, name);
 		if (selector < 0)
 			return selector;
 
-		ret = pinctrl_generic_set_state_one(dev, config,
-						    is_group, selector);
+		ret = pinctrl_generic_set_state_one(dev, config, subnode_type,
+						    selector);
 		if (ret)
 			return ret;
 	}
diff --git a/u-boot/drivers/pinctrl/pinctrl-uclass.c b/u-boot/drivers/pinctrl/pinctrl-uclass.c
index 04776f7395..a4bab4c993 100644
--- a/u-boot/drivers/pinctrl/pinctrl-uclass.c
+++ b/u-boot/drivers/pinctrl/pinctrl-uclass.c
@@ -79,25 +79,31 @@ static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
 		 */
 		state = simple_strtoul(statename, &end, 10);
 		if (*end)
-			return -EINVAL;
+			return -ENOSYS;
 	}
 
 	snprintf(propname, sizeof(propname), "pinctrl-%d", state);
 	list = dev_read_prop(dev, propname, &size);
 	if (!list)
-		return -EINVAL;
+		return -ENOSYS;
 
 	size /= sizeof(*list);
 	for (i = 0; i < size; i++) {
 		phandle = fdt32_to_cpu(*list++);
 		ret = uclass_get_device_by_phandle_id(UCLASS_PINCONFIG, phandle,
 						      &config);
-		if (ret)
-			return ret;
+		if (ret) {
+			dev_warn(dev, "%s: uclass_get_device_by_phandle_id: err=%d\n",
+				__func__, ret);
+			continue;
+		}
 
 		ret = pinctrl_config_one(config);
-		if (ret)
-			return ret;
+		if (ret) {
+			dev_warn(dev, "%s: pinctrl_config_one: err=%d\n",
+				__func__, ret);
+			continue;
+		}
 	}
 
 	return 0;
@@ -117,6 +123,9 @@ static int pinconfig_post_bind(struct udevice *dev)
 	ofnode node;
 	int ret;
 
+	if (!dev_of_valid(dev))
+		return 0;
+
 	dev_for_each_subnode(node, dev) {
 		if (pre_reloc_only &&
 		    !ofnode_pre_reloc(node))
@@ -146,7 +155,9 @@ static int pinconfig_post_bind(struct udevice *dev)
 
 UCLASS_DRIVER(pinconfig) = {
 	.id = UCLASS_PINCONFIG,
+#if CONFIG_IS_ENABLED(PINCONF_RECURSIVE)
 	.post_bind = pinconfig_post_bind,
+#endif
 	.name = "pinconfig",
 };
 
@@ -156,17 +167,115 @@ U_BOOT_DRIVER(pinconfig_generic) = {
 };
 
 #else
-static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
-{
-	return -ENODEV;
-}
-
 static int pinconfig_post_bind(struct udevice *dev)
 {
 	return 0;
 }
+
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+	return 0;
+}
 #endif
 
+static int
+pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset,
+				    struct udevice **pctldev,
+				    unsigned int *pin_selector)
+{
+	struct ofnode_phandle_args args;
+	unsigned gpio_offset, pfc_base, pfc_pins;
+	int ret;
+
+	ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
+					 0, &args);
+	if (ret) {
+		dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL,
+					  args.node, pctldev);
+	if (ret) {
+		dev_dbg(dev,
+			"%s: uclass_get_device_by_of_offset failed: err=%d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	gpio_offset = args.args[0];
+	pfc_base = args.args[1];
+	pfc_pins = args.args[2];
+
+	if (offset < gpio_offset || offset > gpio_offset + pfc_pins) {
+		dev_dbg(dev,
+			"%s: GPIO can not be mapped to pincontrol pin\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	offset -= gpio_offset;
+	offset += pfc_base;
+	*pin_selector = offset;
+
+	return 0;
+}
+
+/**
+ * pinctrl_gpio_request() - request a single pin to be used as GPIO
+ *
+ * @dev: GPIO peripheral device
+ * @offset: the GPIO pin offset from the GPIO controller
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
+{
+	const struct pinctrl_ops *ops;
+	struct udevice *pctldev;
+	unsigned int pin_selector;
+	int ret;
+
+	ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset,
+						  &pctldev, &pin_selector);
+	if (ret)
+		return ret;
+
+	ops = pinctrl_get_ops(pctldev);
+	assert(ops);
+	if (!ops->gpio_request_enable)
+		return -ENOSYS;
+
+	return ops->gpio_request_enable(pctldev, pin_selector);
+}
+
+/**
+ * pinctrl_gpio_free() - free a single pin used as GPIO
+ *
+ * @dev: GPIO peripheral device
+ * @offset: the GPIO pin offset from the GPIO controller
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_gpio_free(struct udevice *dev, unsigned offset)
+{
+	const struct pinctrl_ops *ops;
+	struct udevice *pctldev;
+	unsigned int pin_selector;
+	int ret;
+
+	ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset,
+						  &pctldev, &pin_selector);
+	if (ret)
+		return ret;
+
+	ops = pinctrl_get_ops(pctldev);
+	assert(ops);
+	if (!ops->gpio_disable_free)
+		return -ENOSYS;
+
+	return ops->gpio_disable_free(pctldev, pin_selector);
+}
+
 /**
  * pinctrl_select_state_simple() - simple implementation of pinctrl_select_state
  *
@@ -202,14 +311,20 @@ static int pinctrl_select_state_simple(struct udevice *dev)
 
 int pinctrl_select_state(struct udevice *dev, const char *statename)
 {
+	/*
+	 * Some device which is logical like mmc.blk, do not have
+	 * a valid ofnode.
+	 */
+	if (!ofnode_valid(dev->node))
+		return 0;
 	/*
 	 * Try full-implemented pinctrl first.
 	 * If it fails or is not implemented, try simple one.
 	 */
-	if (pinctrl_select_state_full(dev, statename))
-		return pinctrl_select_state_simple(dev);
+	if (CONFIG_IS_ENABLED(PINCTRL_FULL))
+		return pinctrl_select_state_full(dev, statename);
 
-	return 0;
+	return pinctrl_select_state_simple(dev);
 }
 
 int pinctrl_request(struct udevice *dev, int func, int flags)
@@ -257,6 +372,30 @@ int pinctrl_get_pins_count(struct udevice *dev)
 	return ops->get_pins_count(dev);
 }
 
+int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf,
+			 int size)
+{
+	struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	if (!ops->get_pin_name)
+		return -ENOSYS;
+
+	snprintf(buf, size, ops->get_pin_name(dev, selector));
+
+	return 0;
+}
+
+int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf,
+			   int size)
+{
+	struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+	if (!ops->get_pin_muxing)
+		return -ENOSYS;
+
+	return ops->get_pin_muxing(dev, selector, buf, size);
+}
+
 /**
  * pinconfig_post_bind() - post binding for PINCTRL uclass
  * Recursively bind child nodes as pinconfig devices in case of full pinctrl.
@@ -264,7 +403,7 @@ int pinctrl_get_pins_count(struct udevice *dev)
  * @dev: pinctrl device
  * @return: 0 on success, or negative error code on failure
  */
-static int pinctrl_post_bind(struct udevice *dev)
+static int __maybe_unused pinctrl_post_bind(struct udevice *dev)
 {
 	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
 
diff --git a/u-boot/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c b/u-boot/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
index 7f1fa1a76a..79475f5854 100644
--- a/u-boot/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
+++ b/u-boot/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
@@ -9,6 +9,8 @@
 #include <regmap.h>
 #include <syscon.h>
 #include <fdtdec.h>
+#include <dm/uclass-internal.h>
+#include <asm/gpio.h>
 
 #include "pinctrl-rockchip.h"
 
@@ -353,6 +355,11 @@ static int rockchip_pinconf_set(struct rockchip_pin_bank *bank,
 				u32 pin, u32 param, u32 arg)
 {
 	int rc;
+#if CONFIG_IS_ENABLED(DM_GPIO) && \
+	(CONFIG_IS_ENABLED(SPL_GPIO_SUPPORT) || !defined(CONFIG_SPL_BUILD))
+	struct gpio_desc desc;
+	char gpio_name[16];
+#endif
 
 	switch (param) {
 	case PIN_CONFIG_BIAS_DISABLE:
@@ -377,6 +384,32 @@ static int rockchip_pinconf_set(struct rockchip_pin_bank *bank,
 			return rc;
 		break;
 
+	case PIN_CONFIG_OUTPUT:
+#if CONFIG_IS_ENABLED(DM_GPIO) && \
+	(CONFIG_IS_ENABLED(SPL_GPIO_SUPPORT) || !defined(CONFIG_SPL_BUILD))
+		desc.flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE;
+		if (!arg) desc.flags |= GPIOD_ACTIVE_LOW;
+		snprintf(gpio_name, 16, "%s%d", bank->name, pin);
+		rc = dm_gpio_lookup_name(gpio_name, &desc);
+		if (rc < 0) {
+			debug("%s: GPIO %s-%d lookup failed (ret=%d)\n", __func__,
+				bank->name, pin, rc);
+			return rc;
+		}
+
+		rc = dm_gpio_request(&desc, gpio_name);
+		if (rc < 0) {
+			debug("%s: GPIO %s-%d request failed (ret=%d)\n", __func__,
+				bank->name, pin, rc);
+			return rc;
+		}
+		dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
+		dm_gpio_set_value(&desc, arg ? 1 : 0);
+		debug("%s: GPIO %s-%d set to %d\n", __func__, bank->name, pin, arg);
+#else
+		return -ENOSYS;
+#endif
+		break;
 	default:
 		break;
 	}
@@ -393,6 +426,8 @@ static const struct pinconf_param rockchip_conf_params[] = {
 	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
 	{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
 	{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+	{ "output-high", PIN_CONFIG_OUTPUT, 1, },
+	{ "output-low", PIN_CONFIG_OUTPUT, 0, },
 };
 
 static int rockchip_pinconf_prop_name_to_param(const char *property,
diff --git a/u-boot/drivers/pinctrl/rockchip/pinctrl-rv1126.c b/u-boot/drivers/pinctrl/rockchip/pinctrl-rv1126.c
index 03bf70395a..d1ae132b64 100644
--- a/u-boot/drivers/pinctrl/rockchip/pinctrl-rv1126.c
+++ b/u-boot/drivers/pinctrl/rockchip/pinctrl-rv1126.c
@@ -292,7 +292,7 @@ static int rv1126_set_drive(struct rockchip_pin_bank *bank,
 	rv1126_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
 
 	/* enable the write to the equivalent lower bits */
-	data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+	data = ((1 << RV1126_DRV_BITS_PER_PIN) - 1) << (bit + 16);
 	data |= (strength << bit);
 
 	return regmap_write(regmap, reg, data);
diff --git a/u-boot/drivers/power/charge_animation.c b/u-boot/drivers/power/charge_animation.c
index 63c99a7829..89c5db231f 100644
--- a/u-boot/drivers/power/charge_animation.c
+++ b/u-boot/drivers/power/charge_animation.c
@@ -138,6 +138,7 @@ static int regulators_parse_assigned_mem_state(struct udevice *dev)
 	return 0;
 }
 
+#ifdef CONFIG_IRQ
 static int regulators_enable_assigned_state_mem(struct udevice *dev)
 {
 	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
@@ -187,7 +188,7 @@ static void pmics_resume(void)
 {
 	pmics_ops(false);
 }
-
+#endif
 static int charge_animation_ofdata_to_platdata(struct udevice *dev)
 {
 	struct charge_animation_pdata *pdata = dev_get_platdata(dev);
@@ -1066,8 +1067,21 @@ static const struct dm_charge_display_ops charge_animation_ops = {
 static int charge_animation_probe(struct udevice *dev)
 {
 	struct charge_animation_priv *priv = dev_get_priv(dev);
+	__maybe_unused struct udevice *rk_pm_cfg;
 	int ret, soc;
 
+#ifdef CONFIG_ROCKCHIP_PM_CONFIG
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+					  DM_GET_DRIVER(rockchip_pm_config),
+					  &rk_pm_cfg);
+	if (ret) {
+		if (ret == -ENODEV)
+			printf("Can't find rockchip_pm_config\n");
+		else
+			printf("Get rockchip_pm_config failed: %d\n", ret);
+	}
+#endif
+
 	/* Get PMIC: used for power off system  */
 	ret = uclass_get_device(UCLASS_PMIC, 0, &priv->pmic);
 	if (ret) {
diff --git a/u-boot/drivers/power/pmic/rk8xx.c b/u-boot/drivers/power/pmic/rk8xx.c
index 19877f31bf..398bc2e81e 100644
--- a/u-boot/drivers/power/pmic/rk8xx.c
+++ b/u-boot/drivers/power/pmic/rk8xx.c
@@ -37,6 +37,28 @@ static struct virq_chip rk805_irq_chip = {
 	.num_irqs		= ARRAY_SIZE(rk805_irqs),
 };
 
+/* RK806 */
+static const struct virq_reg rk806_irqs[] = {
+	[RK8XX_IRQ_PWRON_FALL] = {
+		.mask = RK806_IRQ_PWRON_FALL_MSK,
+		.reg_offset = 0,
+	},
+	[RK8XX_IRQ_PWRON_RISE] = {
+		.mask = RK806_IRQ_PWRON_RISE_MSK,
+		.reg_offset = 0,
+	},
+};
+
+static struct virq_chip rk806_irq_chip = {
+	.status_base		= RK806_INT_STS0,
+	.mask_base		= RK806_INT_MSK0,
+	.num_regs		= 1,
+	.read			= pmic_reg_read,
+	.write			= pmic_reg_write,
+	.irqs			= rk806_irqs,
+	.num_irqs		= ARRAY_SIZE(rk806_irqs),
+};
+
 /* RK808 */
 static const struct virq_reg rk808_irqs[] = {
 	[RK8XX_IRQ_PLUG_OUT] = {
@@ -167,6 +189,8 @@ static struct reg_data rk818_init_current[] = {
 static const struct pmic_child_info pmic_children_info[] = {
 	{ .prefix = "DCDC", .driver = "rk8xx_buck"},
 	{ .prefix = "LDO", .driver = "rk8xx_ldo"},
+	{ .prefix = "NLDO", .driver = "rk8xx_ldo"},
+	{ .prefix = "PLDO", .driver = "rk8xx_pldo"},
 	{ .prefix = "SWITCH", .driver = "rk8xx_switch"},
 	{ },
 };
@@ -237,9 +261,57 @@ static int rk8xx_suspend(struct udevice *dev)
 {
 	struct rk8xx_priv *priv = dev_get_priv(dev);
 	int ret = 0;
-	u8 val;
+	u8 i, val;
 
 	switch (priv->variant) {
+	case RK806_ID:
+		ret = rk8xx_read(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
+		if (ret)
+			return ret;
+		val &= RK806_PWRCTRL_FUN_MSK;
+		ret = rk8xx_write(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
+		if (ret)
+			return ret;
+
+		ret = rk8xx_read(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
+		if (ret)
+			return ret;
+
+		val &= RK806_PWRCTRL_FUN_MSK;
+		ret = rk8xx_write(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
+		if (ret)
+			return ret;
+
+		for (i = RK806_VSEL_CTR_SEL0; i <= RK806_DVS_CTR_SEL4; i++) {
+			ret = rk8xx_read(dev, i, &val, 1);
+			if (ret)
+				return ret;
+			val &= RK806_VSEL_CTRL_MSK;
+			ret = rk8xx_write(dev, i, &val, 1);
+			if (ret)
+				return ret;
+		}
+
+		ret = rk8xx_read(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
+		if (ret)
+			return ret;
+		val &= RK806_PWRCTRL_FUN_MSK;
+		val |= RK806_ENABLE_PWRCTRL;
+		ret = rk8xx_write(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
+		if (ret)
+			return ret;
+
+		for (i = RK806_VSEL_CTR_SEL0; i <= RK806_DVS_CTR_SEL4; i++) {
+			ret = rk8xx_read(dev, i, &val, 1);
+			if (ret)
+				return ret;
+			val &= RK806_VSEL_CTRL_MSK;
+			val |= RK806_VSEL_PWRCTRL1;
+			ret = rk8xx_write(dev, i, &val, 1);
+			if (ret)
+				return ret;
+		}
+		break;
 	case RK809_ID:
 	case RK817_ID:
 		/* pmic_sleep active high */
@@ -262,8 +334,34 @@ static int rk8xx_resume(struct udevice *dev)
 {
 	struct rk8xx_priv *priv = dev_get_priv(dev);
 	int ret = 0;
+	u8 i, val;
 
 	switch (priv->variant) {
+	case RK806_ID:
+		for (i = RK806_VSEL_CTR_SEL0; i <= RK806_DVS_CTR_SEL4; i++) {
+			ret = rk8xx_read(dev, i, &val, 1);
+			if (ret)
+				return ret;
+			val &= RK806_VSEL_CTRL_MSK;
+			ret = rk8xx_write(dev, i, &val, 1);
+			if (ret)
+				return ret;
+		}
+
+		ret = rk8xx_read(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
+		if (ret)
+			return ret;
+		val &= RK806_PWRCTRL_FUN_MSK;
+		ret = rk8xx_write(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
+		if (ret)
+			return ret;
+
+		ret = rk8xx_read(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
+		if (ret)
+			return ret;
+		val &= RK806_PWRCTRL_FUN_MSK;
+		ret = rk8xx_write(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
+		break;
 	case RK809_ID:
 	case RK817_ID:
 		ret = rk8xx_write(dev, RK817_PMIC_SYS_CFG3, &priv->sleep_pin, 1);
@@ -282,6 +380,10 @@ static int rk8xx_shutdown(struct udevice *dev)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK806_ID:
+		devctrl_reg = RK806_SYS_CFG3;
+		dev_off = RK806_DEV_OFF;
+		break;
 	case RK808_ID:
 		devctrl_reg = REG_DEVCTRL;
 		dev_off = BIT(3);
@@ -412,6 +514,8 @@ static int rk8xx_ofdata_to_platdata(struct udevice *dev)
 	val = dev_read_bool(dev, "vsys-off-shutdown");
 	rk8xx->sys_can_sd = val;
 
+	rk8xx->rst_fun = dev_read_u32_default(dev, "pmic-reset-func", 0);
+
 	return 0;
 }
 
@@ -423,6 +527,10 @@ static int rk8xx_irq_chip_init(struct udevice *dev)
 	int ret;
 
 	switch (priv->variant) {
+	case RK806_ID:
+		irq_chip = &rk806_irq_chip;
+		irq_plugout = 0;
+		break;
 	case RK808_ID:
 		irq_chip = &rk808_irq_chip;
 		break;
@@ -496,6 +604,9 @@ static int rk8xx_probe(struct udevice *dev)
 	    device_is_compatible(dev, "rockchip,rk809")) {
 		id_msb = RK817_ID_MSB;
 		id_lsb = RK817_ID_LSB;
+	} else if (device_is_compatible(dev, "rockchip,rk806")) {
+		id_msb = RK806_CHIP_NAME;
+		id_lsb = RK806_CHIP_VER;
 	} else {
 		id_msb = ID_MSB;
 		id_lsb = ID_LSB;
@@ -511,6 +622,35 @@ static int rk8xx_probe(struct udevice *dev)
 	priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
 	show_variant = priv->variant;
 	switch (priv->variant) {
+	case RK806_ID:
+		on_source = RK806_ON_SOURCE;
+		off_source = RK806_OFF_SOURCE;
+		ret = rk8xx_read(dev, RK806_HW_VER, &value, 1);
+		if (ret)
+			panic("RK806: read RK806_HW_VER error!\n");
+
+		if ((lsb & RK806_VERSION_MSK) == RK806_VERSION_AB) {
+			ret = rk8xx_read(dev, RK806_SYS_CFG1, &value, 1);
+			if (ret) {
+				dev_err(dev, "rk806 RK806_SYS_CFG1 read error: %d\n", ret);
+				return ret;
+			}
+			value |= RK806_ABNORDET_EN;
+			rk8xx_write(dev, RK806_SYS_CFG1, &value, 1);
+		}
+
+		if (priv->rst_fun) {
+			rk8xx_read(dev, RK806_SYS_CFG3, &value, 1);
+			value &= RK806_RESET_FUN_CLR;
+			if (priv->rst_fun == RK806_RST_MODE1) {
+				value |= (RK806_RST_MODE1 << 6);
+				rk8xx_write(dev, RK806_SYS_CFG3, &value, 1);
+			} else if (priv->rst_fun == RK806_RST_MODE2) {
+				value |= (RK806_RST_MODE2 << 6);
+				rk8xx_write(dev, RK806_SYS_CFG3, &value, 1);
+			}
+		}
+		break;
 	case RK808_ID:
 		show_variant = 0x808;	/* RK808 hardware ID is 0 */
 		pwron_key = RK8XX_DEVCTRL_REG;
@@ -666,6 +806,7 @@ static struct dm_pmic_ops rk8xx_ops = {
 
 static const struct udevice_id rk8xx_ids[] = {
 	{ .compatible = "rockchip,rk805" },
+	{ .compatible = "rockchip,rk806" },
 	{ .compatible = "rockchip,rk808" },
 	{ .compatible = "rockchip,rk809" },
 	{ .compatible = "rockchip,rk816" },
diff --git a/u-boot/drivers/power/pmic/rk8xx_spi.c b/u-boot/drivers/power/pmic/rk8xx_spi.c
index 7f775b7c32..00d3bc3a71 100644
--- a/u-boot/drivers/power/pmic/rk8xx_spi.c
+++ b/u-boot/drivers/power/pmic/rk8xx_spi.c
@@ -14,47 +14,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define RK806_CHIP_NAME			0x5A
-#define RK806_CHIP_VER			0x5B
-#define RK806_HW_VER			0x21
-#define HW_DUAL_PMIC			0x28
-#define HW_SINGLE_PMIC			0xe8
-
-#define RK806_CMD_READ			0
-#define RK806_CMD_WRITE			BIT(7)
-#define RK806_CMD_CRC_EN		BIT(6)
-#define RK806_CMD_CRC_DIS		0
-#define RK806_CMD_LEN_MSK		0x0f
-#define RK806_REG_H			0x00
-
-#define RK806_SYS_CFG1			0x5f
-#define RK806_PWRCTRL_CONFIG0		0x62
-#define RK806_PWRCTRL_CONFIG1		0x63
-#define RK806_VSEL_CTR_SEL0		0x64
-#define RK806_DVS_CTR_SEL4		0x6e
-#define RK806_SYS_CFG3			0x72
-#define RK806_PWRON_KEY			0x76
-#define RK806_INT_STS0			0x77
-#define RK806_INT_MSK0			0x78
-#define RK806_INT_STS1			0x79
-#define RK806_INT_MSK1			0x7A
-#define RK806_GPIO_INT_CONFIG		0x7B
-#define RK806_ON_SOURCE			0x74
-#define RK806_OFF_SOURCE		0x75
-
-#define RK806_IRQ_PWRON_FALL_MSK	BIT(0)
-#define RK806_IRQ_PWRON_RISE_MSK	BIT(1)
-#define RK806_DEV_OFF			BIT(0)
-#define RK806_RST_MODE1			0x01
-#define RK806_RST_MODE2			0x02
-#define RK806_PWRCTRL_FUN_MSK		0x88
-#define RK806_VSEL_CTRL_MSK		0xcc
-#define RK806_VSEL_PWRCTRL1		0x11
-#define RK806_ENABLE_PWRCTRL		0x04
-#define VERSION_AB			0x01
-
 #if CONFIG_IS_ENABLED(IRQ)
-/* RK805 */
+/* RK806 */
 static const struct virq_reg rk806_irqs[] = {
 	[RK8XX_IRQ_PWRON_FALL] = {
 		.mask = RK806_IRQ_PWRON_FALL_MSK,
@@ -78,9 +39,9 @@ static struct virq_chip rk806_irq_chip = {
 #endif
 
 static const struct pmic_child_info pmic_children_info[] = {
-	{ .prefix = "DCDC", .driver = "rk8xx_spi_buck"},
-	{ .prefix = "NLDO", .driver = "rk8xx_spi_ldo"},
-	{ .prefix = "PLDO", .driver = "rk8xx_spi_pldo"},
+	{ .prefix = "DCDC", .driver = "rk8xx_buck"},
+	{ .prefix = "NLDO", .driver = "rk8xx_ldo"},
+	{ .prefix = "PLDO", .driver = "rk8xx_pldo"},
 	{ },
 };
 
@@ -212,7 +173,7 @@ static int rk8xx_spi_ofdata_to_platdata(struct udevice *dev)
 	}
 
 	rk8xx->irq = phandle_gpio_to_irq(phandle, interrupt);
-	if (rk8xx->irq < 0)
+	if (rk8xx->irq < 0 && rk8xx->irq != -EBUSY)
 		printf("Failed to request rk8xx irq, ret=%d\n", rk8xx->irq);
 
 	return 0;
@@ -318,19 +279,19 @@ static int rk8xx_spi_probe(struct udevice *dev)
 		}
 	}
 
-	if ((lsb & 0x0f) == VERSION_AB) {
+	if ((lsb & RK806_VERSION_MSK) == RK806_VERSION_AB) {
 		ret = rk806_spi_read(dev, RK806_SYS_CFG1, &value, 1);
 		if (ret) {
 			dev_err(dev, "rk806 RK806_SYS_CFG1 read error: %d\n", ret);
 			return ret;
 		}
-		value |= 0x80;
+		value |= RK806_ABNORDET_EN;
 		rk806_spi_write(dev, RK806_SYS_CFG1, &value, 1);
 	}
 
 	if (priv->rst_fun) {
 		rk806_spi_read(dev, RK806_SYS_CFG3, &value, 1);
-		value &= 0x3f;
+		value &= RK806_RESET_FUN_CLR;
 		if (priv->rst_fun == RK806_RST_MODE1) {
 			value |= (RK806_RST_MODE1 << 6);
 			rk806_spi_write(dev, RK806_SYS_CFG3, &value, 1);
@@ -388,7 +349,7 @@ static int rk806_suspend(struct udevice *dev)
 	if (ret)
 		return ret;
 
-	for (i = RK806_VSEL_CTR_SEL0; i <= 0x6e; i++) {
+	for (i = RK806_VSEL_CTR_SEL0; i <= RK806_DVS_CTR_SEL4; i++) {
 		ret = rk806_spi_read(dev, i, &val, 1);
 		if (ret)
 			return ret;
diff --git a/u-boot/drivers/power/regulator/Kconfig b/u-boot/drivers/power/regulator/Kconfig
index 37a75ccbcd..1ec20ccebf 100644
--- a/u-boot/drivers/power/regulator/Kconfig
+++ b/u-boot/drivers/power/regulator/Kconfig
@@ -110,22 +110,13 @@ config REGULATOR_RK860X
 
 config REGULATOR_RK8XX
 	bool "Enable driver for RK8XX regulators"
-	depends on DM_REGULATOR && PMIC_RK8XX
+	depends on DM_REGULATOR && (PMIC_RK8XX || PMIC_SPI_RK8XX)
 	---help---
 	Enable support for the regulator functions of the RK8XX PMIC. The
 	driver implements get/set api for the various BUCKS and LDOs supported
 	by the PMIC device. This driver is controlled by a device tree node
 	which includes voltage limits.
 
-config REGULATOR_RK806
-        bool "Enable driver for RK8XX regulators"
-        depends on DM_REGULATOR && PMIC_SPI_RK8XX
-        ---help---
-        Enable support for the regulator functions of the RK806 PMIC. The
-        driver implements get/set api for the various BUCKS and LDOs supported
-        by the PMIC device. This driver is controlled by a device tree node
-        which includes voltage limits
-
 config REGULATOR_S5M8767
 	bool "Enable support for S5M8767 regulator"
 	depends on DM_REGULATOR && PMIC_S5M8767
diff --git a/u-boot/drivers/power/regulator/Makefile b/u-boot/drivers/power/regulator/Makefile
index 73671aa8bd..1dbd8d253c 100644
--- a/u-boot/drivers/power/regulator/Makefile
+++ b/u-boot/drivers/power/regulator/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_RK860X) += rk860x_regulator.o
 obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o
-obj-$(CONFIG_REGULATOR_RK806) += rk806.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
 obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
diff --git a/u-boot/drivers/power/regulator/rk806.c b/u-boot/drivers/power/regulator/rk806.c
deleted file mode 100644
index a219ea4233..0000000000
--- a/u-boot/drivers/power/regulator/rk806.c
+++ /dev/null
@@ -1,1017 +0,0 @@
-/*
- * Copyright (C) 2021 Rockchip Electronics Co., Ltd
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <errno.h>
-#include <power/rk8xx_pmic.h>
-#include <power/pmic.h>
-#include <power/regulator.h>
-
-#ifndef CONFIG_SPL_BUILD
-#define ENABLE_DRIVER
-#endif
-
-/* Not used or exisit register and configure */
-#define NA			-1
-
-/* rk806 buck*/
-#define RK806_BUCK_ON_VSEL(n)		(0x1a + n - 1)
-#define RK806_BUCK_SLP_VSEL(n)		(0x24 + n - 1)
-#define RK806_BUCK_CONFIG(n)		(0x10 + n - 1)
-#define RK806_BUCK_VSEL_MASK		0xff
-
-/* RK806 LDO */
-#define RK806_NLDO_ON_VSEL(n)		(0x43 + n - 1)
-#define RK806_NLDO_SLP_VSEL(n)		(0x48 + n - 1)
-#define RK806_NLDO_VSEL_MASK		0xff
-#define RK806_PLDO_ON_VSEL(n)		(0x4e + n - 1)
-#define RK806_PLDO_SLP_VSEL(n)		(0x54 + n - 1)
-#define RK806_PLDO_VSEL_MASK		0xff
-
-/* RK806 ENABLE */
-#define RK806_POWER_EN(n)		(0x00 + n)
-#define RK806_NLDO_EN(n)		(0x03 + n)
-#define RK806_PLDO_EN(n)		(0x04 + n)
-
-#define RK806_BUCK_SUSPEND_EN		0x06
-#define RK806_NLDO_SUSPEND_EN		0x07
-#define RK806_PLDO_SUSPEND_EN		0x08
-
-#define RK806_RAMP_RATE_MASK1		0xc0
-#define RK806_RAMP_RATE_REG1(n)		(0x10 + n)
-#define RK806_RAMP_RATE_REG1_8		0xeb
-#define RK806_RAMP_RATE_REG9_10		0xea
-
-#define RK806_RAMP_RATE_4LSB_PER_1CLK	0x00/* LDO 100mV/uS buck 50mV/us */
-#define RK806_RAMP_RATE_2LSB_PER_1CLK	0x01/* LDO 50mV/uS buck 25mV/us */
-#define RK806_RAMP_RATE_1LSB_PER_1CLK	0x02/* LDO 25mV/uS buck 12.5mV/us */
-#define RK806_RAMP_RATE_1LSB_PER_2CLK	0x03/* LDO 12.5mV/uS buck 6.25mV/us */
-
-#define RK806_RAMP_RATE_1LSB_PER_4CLK	0x04/* LDO 6.28/2mV/uS buck 3.125mV/us */
-#define RK806_RAMP_RATE_1LSB_PER_8CLK	0x05/* LDO 3.12mV/uS buck 1.56mV/us */
-#define RK806_RAMP_RATE_1LSB_PER_13CLK	0x06/* LDO 1.9mV/uS buck 961mV/us */
-#define RK806_RAMP_RATE_1LSB_PER_32CLK	0x07/* LDO 0.78mV/uS buck 0.39mV/us */
-
-#define RK806_PLDO0_2_MSK(pldo)		(BIT(pldo + 5))
-#define RK806_PLDO0_2_SET(pldo)		(BIT(pldo + 1) | RK806_PLDO0_2_MSK(pldo))
-#define RK806_PLDO0_2_CLR(pldo)		RK806_PLDO0_2_MSK(pldo)
-
-struct rk8xx_reg_info {
-	uint min_uv;
-	uint step_uv;
-	u8 vsel_reg;
-	u8 vsel_sleep_reg;
-	u8 config_reg;
-	u8 vsel_mask;
-	u8 min_sel;
-	/* only for buck now */
-	u8 max_sel;
-	u8 range_num;
-};
-
-static const struct rk8xx_reg_info rk806_buck[] = {
-	/* buck 1 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xa0, 0xec, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 2 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 3 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 4 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 5 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 6 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 7 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 8 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 9 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-	/* buck 10 */
-	{  500000,   6250, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
-	{  1500000, 25000, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
-	{  3400000,     0, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
-};
-
-static const struct rk8xx_reg_info rk806_nldo[] = {
-	/* nldo1 */
-	{  500000, 12500, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
-	/* nldo2 */
-	{  500000, 12500, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
-	/* nldo3 */
-	{  500000, 12500, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
-	/* nldo4 */
-	{  500000, 12500, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
-	/* nldo5 */
-	{  500000, 12500, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
-};
-
-static const struct rk8xx_reg_info rk806_pldo[] = {
-	/* pldo1 */
-	{  500000, 12500, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
-	/* pldo2 */
-	{  500000, 12500, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
-	/* pldo3 */
-	{  500000, 12500, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
-	/* pldo4 */
-	{  500000, 12500, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
-	/* pldo5 */
-	{  500000, 12500, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
-	/* pldo6 */
-	{  500000, 12500, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0x00, },
-	{  3400000,    0, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
-};
-
-static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
-						 int num, int uvolt)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-
-	switch (priv->variant) {
-	case RK806_ID:
-		switch (num) {
-		case 0 ... 9:
-			if (uvolt < 1500000)
-				return &rk806_buck[num * 3 + 0];
-			else if (uvolt < 3400000)
-				return &rk806_buck[num * 3 + 1];
-			else
-				return &rk806_buck[num * 3 + 2];
-			break;
-		}
-	default:
-		return &rk806_buck[num * 3 + 0];
-	}
-}
-
-static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
-{
-	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
-	int mask = info->vsel_mask;
-	int val;
-
-	if (info->vsel_reg == NA)
-		return -EINVAL;
-
-	if (info->step_uv == 0)	/* Fixed voltage */
-		val = info->min_sel;
-	else
-		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
-
-	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
-
-	return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
-}
-
-static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint value, en_reg;
-	int ret;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		en_reg = RK806_POWER_EN(buck / 4);
-		if (enable)
-			value = ((1 << buck % 4) | (1 << (buck % 4 + 4)));
-		else
-			value = ((0 << buck % 4) | (1 << (buck % 4 + 4)));
-
-		ret = pmic_reg_write(pmic, en_reg, value);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-#ifdef ENABLE_DRIVER
-static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
-{
-	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
-	int mask = info->vsel_mask;
-	int val;
-
-	if (info->vsel_sleep_reg == NA)
-		return -EINVAL;
-
-	if (info->step_uv == 0)
-		val = info->min_sel;
-	else
-		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
-
-	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
-
-	return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
-}
-
-static int _buck_get_enable(struct udevice *pmic, int buck)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint mask = 0;
-	int ret = 0;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		mask = 1 << buck % 4;
-		ret = pmic_reg_read(pmic, RK806_POWER_EN(buck / 4));
-		break;
-	default:
-		ret = 0;
-	}
-
-	if (ret < 0)
-		return ret;
-
-	return ret & mask ? true : false;
-}
-
-static int _buck_set_ramp_delay(struct udevice *pmic, int buck, u32 ramp_delay)
-{
-	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, 0);
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	int ramp_value = 0, reg_value;
-	int ramp_reg1, ramp_reg2;
-
-	if (info->config_reg == NA)
-		return -EINVAL;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		switch (ramp_delay) {
-		case 1 ... 390:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
-			break;
-		case 391 ... 961:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_13CLK;
-			break;
-		case 962 ... 1560:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_8CLK;
-			break;
-		case 1561 ... 3125:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_4CLK;
-			break;
-		case 3126 ... 6250:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_2CLK;
-			break;
-		case 6251 ... 12500:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_1CLK;
-			break;
-		case 12501 ... 25000:
-			ramp_value = RK806_RAMP_RATE_2LSB_PER_1CLK;
-			break;
-		case 25001 ... 50000: /* 50mV/us */
-			ramp_value = RK806_RAMP_RATE_4LSB_PER_1CLK;
-			break;
-		default:
-			ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
-			printf("buck%d ramp_delay: %d not supported\n",
-			       buck, ramp_delay);
-			break;
-		}
-		break;
-	default:
-		ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
-		return -EINVAL;
-	}
-
-	ramp_reg1 = RK806_RAMP_RATE_REG1(buck);
-	if (buck < 8)
-		ramp_reg2 = RK806_RAMP_RATE_REG1_8;
-	else
-		ramp_reg2 = RK806_RAMP_RATE_REG9_10;
-
-	reg_value = pmic_reg_read(pmic, ramp_reg1);
-	if (reg_value < 0) {
-		printf("buck%d read ramp reg(0x%x) error: %d", buck, ramp_reg1, reg_value);
-		return reg_value;
-	}
-	reg_value &= 0x3f;
-
-	pmic_reg_write(pmic,
-		       ramp_reg1,
-		       reg_value | (ramp_value & 0x03) << 0x06);
-
-	reg_value = pmic_reg_read(pmic, ramp_reg2);
-	if (reg_value < 0) {
-		printf("buck%d read ramp reg(0x%x) error: %d", buck, ramp_reg2, reg_value);
-		return reg_value;
-	}
-
-	return pmic_reg_write(pmic,
-			      ramp_reg2,
-			      reg_value | (ramp_value & 0x04) << (buck % 8));
-}
-
-static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
-{
-	uint mask;
-	int ret;
-
-	if (buck <= 7) {
-		mask = 1 << buck;
-		ret = pmic_clrsetbits(pmic, RK806_BUCK_SUSPEND_EN, mask,
-				      enable ? mask : 0);
-	} else {
-		if (buck == 8)
-			mask = 0x40;
-		else
-			mask = 0x80;
-		ret = pmic_clrsetbits(pmic, RK806_NLDO_SUSPEND_EN, mask,
-				      enable ? mask : 0);
-	}
-
-	return ret;
-}
-
-static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
-{
-	uint mask, val;
-	int ret;
-
-	if (buck <= 7) {
-		mask = 1 << buck % 7;
-		val = pmic_reg_read(pmic, RK806_BUCK_SUSPEND_EN);
-	} else {
-		mask = 1 << ((buck - 7) + 6);
-		val = pmic_reg_read(pmic, RK806_NLDO_SUSPEND_EN);
-	}
-
-	if (val < 0)
-		return val;
-	ret = val & mask ? 1 : 0;
-
-	return ret;
-}
-
-static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
-						int num, int uvolt)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-
-	switch (priv->variant) {
-	case RK806_ID:
-		if (uvolt < 3400000)
-			return &rk806_nldo[num * 2];
-		else
-			return &rk806_nldo[num * 2 + 1];
-	default:
-		return &rk806_nldo[num * 2];
-	}
-}
-
-static const struct rk8xx_reg_info *get_pldo_reg(struct udevice *pmic,
-						 int num, int uvolt)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-
-	switch (priv->variant) {
-	case RK806_ID:
-		if (uvolt < 3400000)
-			return &rk806_pldo[num * 2];
-		else
-			return &rk806_pldo[num * 2 + 1];
-	default:
-		return &rk806_pldo[num * 2];
-	}
-}
-
-static int _ldo_get_enable(struct udevice *pmic, int ldo)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint mask = 0;
-	int ret = 0;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		if (ldo < 4) {
-			mask = 1 << ldo % 4;
-			ret = pmic_reg_read(pmic, RK806_NLDO_EN(ldo / 4));
-		} else {
-			mask = 1 << 2;
-			ret = pmic_reg_read(pmic, RK806_NLDO_EN(2));
-		}
-		break;
-	default:
-		return false;
-	}
-
-	if (ret < 0)
-		return ret;
-
-	return ret & mask ? true : false;
-}
-
-static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint value, en_reg;
-	int ret = 0;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		if (ldo < 4) {
-			en_reg = RK806_NLDO_EN(0);
-			if (enable)
-				value = ((1 << ldo % 4) | (1 << (ldo % 4 + 4)));
-			else
-				value = ((0 << ldo % 4) | (1 << (ldo % 4 + 4)));
-			ret = pmic_reg_write(pmic, en_reg, value);
-		} else {
-			en_reg = RK806_NLDO_EN(2);
-			if (enable)
-				value = 0x44;
-			else
-				value = 0x40;
-			ret = pmic_reg_write(pmic, en_reg, value);
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-static int _pldo_get_enable(struct udevice *pmic, int pldo)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint mask = 0, en_reg;
-	int ret = 0;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		if ((pldo < 3) || (pldo == 5)) {
-			en_reg = RK806_PLDO_EN(0);
-			mask = RK806_PLDO0_2_SET(pldo);
-			if (pldo == 5)
-				mask = (1 << 0);
-			ret = pmic_reg_read(pmic, en_reg);
-		} else if ((pldo == 3) || (pldo == 4)) {
-			en_reg = RK806_PLDO_EN(1);
-			if (pldo == 3)
-				mask = (1 << 0);
-			else
-				mask = (1 << 1);
-			ret = pmic_reg_read(pmic, en_reg);
-		}
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if (ret < 0)
-		return ret;
-
-	return ret & mask ? true : false;
-}
-
-static int _pldo_set_enable(struct udevice *pmic, int pldo, bool enable)
-{
-	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint value, en_reg;
-	int ret = 0;
-
-	switch (priv->variant) {
-	case RK806_ID:
-		if (pldo < 3) {
-			en_reg = RK806_PLDO_EN(0);
-			if (enable)
-				value = RK806_PLDO0_2_SET(pldo);
-			else
-				value = RK806_PLDO0_2_CLR(pldo);
-			ret = pmic_reg_write(pmic, en_reg, value);
-		} else if (pldo == 3) {
-			en_reg = RK806_PLDO_EN(1);
-			if (enable)
-				value = ((1 << 0) | (1 << 4));
-			else
-				value = (1 << 4);
-			ret = pmic_reg_write(pmic, en_reg, value);
-		} else if (pldo == 4) {
-			en_reg = RK806_PLDO_EN(1);
-			if (enable)
-				value = ((1 << 1) | (1 << 5));
-			else
-				value = ((0 << 1) | (1 << 5));
-			ret = pmic_reg_write(pmic, en_reg, value);
-		} else if (pldo == 5) {
-			en_reg = RK806_PLDO_EN(0);
-			if (enable)
-				value = ((1 << 0) | (1 << 4));
-			else
-				value = ((0 << 0) | (1 << 4));
-			ret = pmic_reg_write(pmic, en_reg, value);
-		}
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
-{
-	uint mask;
-	int ret;
-
-	mask = 1 << ldo;
-	ret = pmic_clrsetbits(pmic, RK806_NLDO_SUSPEND_EN, mask,
-			      enable ? mask : 0);
-
-	return ret;
-}
-
-static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
-{
-	uint mask, val;
-	int ret;
-
-	mask = 1 << ldo;
-	val = pmic_reg_read(pmic, RK806_NLDO_SUSPEND_EN);
-
-	if (val < 0)
-		return val;
-	ret = val & mask ? 1 : 0;
-
-	return ret;
-}
-
-static int buck_get_value(struct udevice *dev)
-{
-	int buck = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
-	int mask = info->vsel_mask;
-	int i, ret, val;
-
-	if (info->vsel_reg == NA)
-		return -EINVAL;
-
-	ret = pmic_reg_read(dev->parent, info->vsel_reg);
-	if (ret < 0)
-		return ret;
-
-	val = ret & mask;
-	if (val >= info->min_sel && val <= info->max_sel)
-		goto finish;
-
-	/* unlucky to try */
-	for (i = 1; i < info->range_num; i++) {
-		info++;
-		if (val <= info->max_sel && val >= info->min_sel)
-			break;
-	}
-
-finish:
-	return info->min_uv + (val - info->min_sel) * info->step_uv;
-}
-
-static int buck_set_value(struct udevice *dev, int uvolt)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_set_value(dev->parent, buck, uvolt);
-}
-
-static int buck_get_suspend_value(struct udevice *dev)
-{
-	int buck = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
-	int mask = info->vsel_mask;
-	int i, ret, val;
-
-	if (info->vsel_sleep_reg == NA)
-		return -EINVAL;
-
-	ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
-	if (ret < 0)
-		return ret;
-
-	val = ret & mask;
-	if (val <= info->max_sel && val >= info->min_sel)
-		goto finish;
-
-	/* unlucky to try */
-	for (i = 1; i < info->range_num; i++) {
-		info++;
-		if (val <= info->max_sel && val >= info->min_sel)
-			break;
-	}
-
-finish:
-	return info->min_uv + (val - info->min_sel) * info->step_uv;
-}
-
-static int buck_set_suspend_value(struct udevice *dev, int uvolt)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_set_suspend_value(dev->parent, buck, uvolt);
-}
-
-static int buck_set_enable(struct udevice *dev, bool enable)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_set_enable(dev->parent, buck, enable);
-}
-
-static int buck_set_suspend_enable(struct udevice *dev, bool enable)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_set_suspend_enable(dev->parent, buck, enable);
-}
-
-static int buck_get_suspend_enable(struct udevice *dev)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_get_suspend_enable(dev->parent, buck);
-}
-
-static int buck_set_ramp_delay(struct udevice *dev, u32 ramp_delay)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_set_ramp_delay(dev->parent, buck, ramp_delay);
-}
-
-static int buck_get_enable(struct udevice *dev)
-{
-	int buck = dev->driver_data - 1;
-
-	return _buck_get_enable(dev->parent, buck);
-}
-
-static int ldo_get_value(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
-	int mask = info->vsel_mask;
-	int ret, val;
-
-	if (info->vsel_reg == NA)
-		return -EINVAL;
-
-	ret = pmic_reg_read(dev->parent, info->vsel_reg);
-	if (ret < 0)
-		return ret;
-	val = ret & mask;
-
-	return info->min_uv + val * info->step_uv;
-}
-
-static int ldo_set_value(struct udevice *dev, int uvolt)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
-	int mask = info->vsel_mask;
-	int val;
-
-	if (info->vsel_reg == NA)
-		return -EINVAL;
-
-	if (info->step_uv == 0)
-		val = info->min_sel;
-	else
-		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
-
-	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
-
-	return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
-}
-
-static int pldo_get_value(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, 0);
-	int mask = info->vsel_mask;
-	int ret, val;
-
-	if (info->vsel_reg == NA)
-		return -EINVAL;
-
-	ret = pmic_reg_read(dev->parent, info->vsel_reg);
-	if (ret < 0)
-		return ret;
-	val = ret & mask;
-
-	return info->min_uv + val * info->step_uv;
-}
-
-static int pldo_set_value(struct udevice *dev, int uvolt)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, uvolt);
-	int mask = info->vsel_mask;
-	int val;
-
-	if (info->vsel_reg == NA)
-		return -EINVAL;
-
-	if (info->step_uv == 0)
-		val = info->min_sel;
-	else
-		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
-
-	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
-
-	return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
-}
-
-static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
-	int mask = info->vsel_mask;
-	int val;
-
-	if (info->vsel_sleep_reg == NA)
-		return -EINVAL;
-
-	if (info->step_uv == 0)
-		val = info->min_sel;
-	else
-		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
-
-	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val);
-
-	return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
-}
-
-static int ldo_get_suspend_value(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
-	int mask = info->vsel_mask;
-	int val, ret;
-
-	if (info->vsel_sleep_reg == NA)
-		return -EINVAL;
-
-	ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
-	if (ret < 0)
-		return ret;
-
-	val = ret & mask;
-
-	return info->min_uv + val * info->step_uv;
-}
-
-static int ldo_set_enable(struct udevice *dev, bool enable)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _ldo_set_enable(dev->parent, ldo, enable);
-}
-
-static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _ldo_set_suspend_enable(dev->parent, ldo, enable);
-}
-
-static int ldo_get_suspend_enable(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _ldo_get_suspend_enable(dev->parent, ldo);
-}
-
-static int ldo_get_enable(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _ldo_get_enable(dev->parent, ldo);
-}
-
-static int pldo_set_enable(struct udevice *dev, bool enable)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _pldo_set_enable(dev->parent, ldo, enable);
-}
-
-static int pldo_get_enable(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _pldo_get_enable(dev->parent, ldo);
-}
-
-static int pldo_set_suspend_value(struct udevice *dev, int uvolt)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, uvolt);;
-	int mask = info->vsel_mask;
-	int val;
-
-	if (info->vsel_sleep_reg == NA)
-		return -EINVAL;
-
-	if (info->step_uv == 0)
-		val = info->min_sel;
-	else
-		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
-
-	return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
-}
-
-static int pldo_get_suspend_value(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, 0);
-	int mask = info->vsel_mask;
-	int val, ret;
-
-	if (info->vsel_sleep_reg == NA)
-		return -EINVAL;
-
-	ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
-	if (ret < 0)
-		return ret;
-
-	val = ret & mask;
-
-	return info->min_uv + val * info->step_uv;
-}
-
-static int _pldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
-{
-	uint mask;
-	int ret;
-
-	if (ldo < 5)
-		mask = 1 << (ldo + 1);
-	else
-		mask = 1;
-	ret = pmic_clrsetbits(pmic, RK806_PLDO_SUSPEND_EN, mask,
-			      enable ? mask : 0);
-
-	return ret;
-}
-
-static int _pldo_get_suspend_enable(struct udevice *pmic, int ldo)
-{
-	uint mask, val;
-	int ret;
-
-	if (ldo < 5)
-		mask = 1 << (ldo + 1);
-	else
-		mask = 1;
-	val = pmic_reg_read(pmic, RK806_PLDO_SUSPEND_EN);
-
-	if (val < 0)
-		return val;
-	ret = val & mask ? 1 : 0;
-
-	return ret;
-}
-
-static int pldo_set_suspend_enable(struct udevice *dev, bool enable)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _pldo_set_suspend_enable(dev->parent, ldo, enable);
-}
-
-static int pldo_get_suspend_enable(struct udevice *dev)
-{
-	int ldo = dev->driver_data - 1;
-
-	return _pldo_get_suspend_enable(dev->parent, ldo);
-}
-
-static int rk8xx_buck_probe(struct udevice *dev)
-{
-	struct dm_regulator_uclass_platdata *uc_pdata;
-
-	uc_pdata = dev_get_uclass_platdata(dev);
-	uc_pdata->type = REGULATOR_TYPE_BUCK;
-	uc_pdata->mode_count = 0;
-
-	return 0;
-}
-
-static int rk8xx_ldo_probe(struct udevice *dev)
-{
-	struct dm_regulator_uclass_platdata *uc_pdata;
-
-	uc_pdata = dev_get_uclass_platdata(dev);
-	uc_pdata->type = REGULATOR_TYPE_LDO;
-	uc_pdata->mode_count = 0;
-
-	return 0;
-}
-
-static int rk8xx_pldo_probe(struct udevice *dev)
-{
-	struct dm_regulator_uclass_platdata *uc_pdata;
-
-	uc_pdata = dev_get_uclass_platdata(dev);
-	uc_pdata->type = REGULATOR_TYPE_LDO;
-	uc_pdata->mode_count = 0;
-
-	return 0;
-}
-
-static const struct dm_regulator_ops rk8xx_buck_ops = {
-	.get_value  = buck_get_value,
-	.set_value  = buck_set_value,
-	.set_suspend_value = buck_set_suspend_value,
-	.get_suspend_value = buck_get_suspend_value,
-	.get_enable = buck_get_enable,
-	.set_enable = buck_set_enable,
-	.set_suspend_enable = buck_set_suspend_enable,
-	.get_suspend_enable = buck_get_suspend_enable,
-	.set_ramp_delay = buck_set_ramp_delay,
-};
-
-static const struct dm_regulator_ops rk8xx_ldo_ops = {
-	.get_value  = ldo_get_value,
-	.set_value  = ldo_set_value,
-	.set_suspend_value = ldo_set_suspend_value,
-	.get_suspend_value = ldo_get_suspend_value,
-	.get_enable = ldo_get_enable,
-	.set_enable = ldo_set_enable,
-	.set_suspend_enable = ldo_set_suspend_enable,
-	.get_suspend_enable = ldo_get_suspend_enable,
-};
-
-static const struct dm_regulator_ops rk8xx_pldo_ops = {
-	.get_value  = pldo_get_value,
-	.set_value  = pldo_set_value,
-	.set_suspend_value = pldo_set_suspend_value,
-	.get_suspend_value = pldo_get_suspend_value,
-	.get_enable = pldo_get_enable,
-	.set_enable = pldo_set_enable,
-	.set_suspend_enable = pldo_set_suspend_enable,
-	.get_suspend_enable = pldo_get_suspend_enable,
-};
-
-U_BOOT_DRIVER(rk8xx_spi_buck) = {
-	.name = "rk8xx_spi_buck",
-	.id = UCLASS_REGULATOR,
-	.ops = &rk8xx_buck_ops,
-	.probe = rk8xx_buck_probe,
-};
-
-U_BOOT_DRIVER(rk8xx_spi_ldo) = {
-	.name = "rk8xx_spi_ldo",
-	.id = UCLASS_REGULATOR,
-	.ops = &rk8xx_ldo_ops,
-	.probe = rk8xx_ldo_probe,
-};
-
-U_BOOT_DRIVER(rk8xx_spi_pldo) = {
-	.name = "rk8xx_spi_pldo",
-	.id = UCLASS_REGULATOR,
-	.ops = &rk8xx_pldo_ops,
-	.probe = rk8xx_pldo_probe,
-};
-#endif
diff --git a/u-boot/drivers/power/regulator/rk8xx.c b/u-boot/drivers/power/regulator/rk8xx.c
index 47f2b7c134..dbad1fe7af 100644
--- a/u-boot/drivers/power/regulator/rk8xx.c
+++ b/u-boot/drivers/power/regulator/rk8xx.c
@@ -94,6 +94,88 @@ struct rk8xx_reg_info {
 	u8 range_num;
 };
 
+static const struct rk8xx_reg_info rk806_buck[] = {
+	/* buck 1 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xa0, 0xec, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 2 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 3 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 4 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 5 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 6 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 7 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 8 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 9 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+	/* buck 10 */
+	{  500000,   6250, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0x00, 0x9f, 3},
+	{  1500000, 25000, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xa0, 0xed, 3},
+	{  3400000,     0, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xed, 0xff, 3},
+};
+
+static const struct rk8xx_reg_info rk806_nldo[] = {
+	/* nldo1 */
+	{  500000, 12500, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
+	/* nldo2 */
+	{  500000, 12500, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
+	/* nldo3 */
+	{  500000, 12500, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
+	/* nldo4 */
+	{  500000, 12500, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
+	/* nldo5 */
+	{  500000, 12500, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0xE8, },
+};
+
+static const struct rk8xx_reg_info rk806_pldo[] = {
+	/* pldo1 */
+	{  500000, 12500, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
+	/* pldo2 */
+	{  500000, 12500, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
+	/* pldo3 */
+	{  500000, 12500, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
+	/* pldo4 */
+	{  500000, 12500, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
+	/* pldo5 */
+	{  500000, 12500, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
+	/* pldo6 */
+	{  500000, 12500, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0x00, },
+	{  3400000,    0, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0xE8, },
+};
+
 static const struct rk8xx_reg_info rk808_buck[] = {
 	{ 712500,   12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f, 1},
 	{ 712500,   12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f, 1},
@@ -227,6 +309,16 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK806_ID:
+		switch (num) {
+		case 0 ... 9:
+			if (uvolt < 1500000)
+				return &rk806_buck[num * 3 + 0];
+			else if (uvolt < 3400000)
+				return &rk806_buck[num * 3 + 1];
+			else
+				return &rk806_buck[num * 3 + 2];
+		}
 	case RK805_ID:
 	case RK816_ID:
 		switch (num) {
@@ -293,7 +385,7 @@ static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
 		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
 
 	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, buck+1, info->vsel_reg, mask, val);
+	      __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
 
 	if (priv->variant == RK816_ID) {
 		pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
@@ -310,6 +402,15 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK806_ID:
+		en_reg = RK806_POWER_EN(buck / 4);
+		if (enable)
+			value = ((1 << buck % 4) | (1 << (buck % 4 + 4)));
+		else
+			value = ((0 << buck % 4) | (1 << (buck % 4 + 4)));
+
+		ret = pmic_reg_write(pmic, en_reg, value);
+		break;
 	case RK805_ID:
 	case RK816_ID:
 		if (buck >= 4) {
@@ -377,7 +478,7 @@ static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
 		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
 
 	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, buck+1, info->vsel_sleep_reg, mask, val);
+	      __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
 
 	return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
 }
@@ -389,6 +490,10 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK806_ID:
+		mask = 1 << buck % 4;
+		ret = pmic_reg_read(pmic, RK806_POWER_EN(buck / 4));
+		break;
 	case RK805_ID:
 	case RK816_ID:
 		if (buck >= 4) {
@@ -430,6 +535,7 @@ static int _buck_set_ramp_delay(struct udevice *pmic, int buck, u32 ramp_delay)
 	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, 0);
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 	u32 ramp_value, ramp_mask;
+	int reg_value, ramp_reg1, ramp_reg2;
 
 	if (info->config_reg == NA)
 		return -ENOSYS;
@@ -456,6 +562,64 @@ static int _buck_set_ramp_delay(struct udevice *pmic, int buck, u32 ramp_delay)
 			       buck, ramp_delay);
 		}
 		break;
+	case RK806_ID:
+		switch (ramp_delay) {
+		case 1 ... 390:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
+			break;
+		case 391 ... 961:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_13CLK;
+			break;
+		case 962 ... 1560:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_8CLK;
+			break;
+		case 1561 ... 3125:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_4CLK;
+			break;
+		case 3126 ... 6250:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_2CLK;
+			break;
+		case 6251 ... 12500:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_1CLK;
+			break;
+		case 12501 ... 25000:
+			ramp_value = RK806_RAMP_RATE_2LSB_PER_1CLK;
+			break;
+		case 25001 ... 50000: /* 50mV/us */
+			ramp_value = RK806_RAMP_RATE_4LSB_PER_1CLK;
+			break;
+		default:
+			ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
+			printf("buck%d ramp_delay: %d not supported\n",
+			       buck, ramp_delay);
+			return -EINVAL;
+		}
+		ramp_reg1 = RK806_RAMP_RATE_REG1(buck);
+		if (buck < 8)
+			ramp_reg2 = RK806_RAMP_RATE_REG1_8;
+		else
+			ramp_reg2 = RK806_RAMP_RATE_REG9_10;
+
+		reg_value = pmic_reg_read(pmic, ramp_reg1);
+		if (reg_value < 0) {
+			printf("buck%d read ramp reg(0x%x) error: %d", buck, ramp_reg1, reg_value);
+			return reg_value;
+		}
+		reg_value &= 0x3f;
+
+		pmic_reg_write(pmic,
+			       ramp_reg1,
+			       reg_value | (ramp_value & 0x03) << 0x06);
+
+		reg_value = pmic_reg_read(pmic, ramp_reg2);
+		if (reg_value < 0) {
+			printf("buck%d read ramp reg(0x%x) error: %d", buck, ramp_reg2, reg_value);
+			return reg_value;
+		}
+
+		return pmic_reg_write(pmic,
+				      ramp_reg2,
+				      reg_value | (ramp_value & 0x04) << (buck % 8));
 	case RK808_ID:
 	case RK816_ID:
 	case RK818_ID:
@@ -521,6 +685,20 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
 		ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
 				      enable ? mask : 0);
 		break;
+	case RK806_ID:
+		if (buck <= 7) {
+			mask = 1 << buck;
+			ret = pmic_clrsetbits(pmic, RK806_BUCK_SUSPEND_EN, mask,
+					      enable ? mask : 0);
+		} else {
+			if (buck == 8)
+				mask = 0x40;
+			else
+				mask = 0x80;
+			ret = pmic_clrsetbits(pmic, RK806_NLDO_SUSPEND_EN, mask,
+					      enable ? mask : 0);
+		}
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << buck;
@@ -554,6 +732,19 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
 	case RK816_ID:
 		mask = 1 << buck;
 		val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 1 : 0;
+		break;
+	case RK806_ID:
+		if (buck <= 7) {
+			mask = 1 << buck % 7;
+			val = pmic_reg_read(pmic, RK806_BUCK_SUSPEND_EN);
+		} else {
+			mask = 1 << ((buck - 7) + 6);
+			val = pmic_reg_read(pmic, RK806_NLDO_SUSPEND_EN);
+		}
+
 		if (val < 0)
 			return val;
 		ret = val & mask ? 1 : 0;
@@ -594,6 +785,11 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
 	case RK805_ID:
 	case RK816_ID:
 		return &rk816_ldo[num];
+	case RK806_ID:
+		if (uvolt < 3400000)
+			return &rk806_nldo[num * 2];
+		else
+			return &rk806_nldo[num * 2 + 1];
 	case RK809_ID:
 	case RK817_ID:
 		if (uvolt < 3400000)
@@ -624,6 +820,15 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 			ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1);
 		}
 		break;
+	case RK806_ID:
+		if (ldo < 4) {
+			mask = 1 << ldo % 4;
+			ret = pmic_reg_read(pmic, RK806_NLDO_EN(ldo / 4));
+		} else {
+			mask = 1 << 2;
+			ret = pmic_reg_read(pmic, RK806_NLDO_EN(2));
+		}
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
@@ -676,11 +881,28 @@ static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
 
 		ret = pmic_reg_write(pmic, en_reg, value);
 		break;
+	case RK806_ID:
+		if (ldo < 4) {
+			en_reg = RK806_NLDO_EN(0);
+			if (enable)
+				value = ((1 << ldo % 4) | (1 << (ldo % 4 + 4)));
+			else
+				value = ((0 << ldo % 4) | (1 << (ldo % 4 + 4)));
+			ret = pmic_reg_write(pmic, en_reg, value);
+		} else {
+			en_reg = RK806_NLDO_EN(2);
+			if (enable)
+				value = 0x44;
+			else
+				value = 0x40;
+			ret = pmic_reg_write(pmic, en_reg, value);
+		}
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
 		ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
-				       enable ? mask : 0);
+				      enable ? mask : 0);
 		break;
 	case RK809_ID:
 	case RK817_ID:
@@ -722,6 +944,11 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
 		ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
 				      enable ? mask : 0);
 		break;
+	case RK806_ID:
+		mask = 1 << ldo;
+		ret = pmic_clrsetbits(pmic, RK806_NLDO_SUSPEND_EN, mask,
+				      enable ? mask : 0);
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
@@ -756,6 +983,14 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
 	case RK816_ID:
 		mask = 1 << ldo;
 		val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 1 : 0;
+		break;
+	case RK806_ID:
+		mask = 1 << ldo;
+		val = pmic_reg_read(pmic, RK806_NLDO_SUSPEND_EN);
+
 		if (val < 0)
 			return val;
 		ret = val & mask ? 1 : 0;
@@ -929,7 +1164,7 @@ static int ldo_set_value(struct udevice *dev, int uvolt)
 		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
 
 	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, ldo+1, info->vsel_reg, mask, val);
+	      __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
 
 	return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
 }
@@ -950,7 +1185,7 @@ static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
 		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
 
 	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
-	      __func__, uvolt, ldo+1, info->vsel_sleep_reg, mask, val);
+	      __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val);
 
 	return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
 }
@@ -1165,6 +1400,238 @@ static int switch_set_value(struct udevice *dev, int uvolt)
 	return 0;
 }
 
+static const struct rk8xx_reg_info *get_pldo_reg(struct udevice *pmic,
+						 int num, int uvolt)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+	switch (priv->variant) {
+	case RK806_ID:
+		if (uvolt < 3400000)
+			return &rk806_pldo[num * 2];
+		else
+			return &rk806_pldo[num * 2 + 1];
+	default:
+		return &rk806_pldo[num * 2];
+	}
+}
+
+static int _pldo_get_enable(struct udevice *pmic, int pldo)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	uint mask = 0, en_reg;
+	int ret = 0;
+
+	switch (priv->variant) {
+	case RK806_ID:
+		if ((pldo < 3) || (pldo == 5)) {
+			en_reg = RK806_PLDO_EN(0);
+			mask = RK806_PLDO0_2_SET(pldo);
+			if (pldo == 5)
+				mask = (1 << 0);
+			ret = pmic_reg_read(pmic, en_reg);
+		} else if ((pldo == 3) || (pldo == 4)) {
+			en_reg = RK806_PLDO_EN(1);
+			if (pldo == 3)
+				mask = (1 << 0);
+			else
+				mask = (1 << 1);
+			ret = pmic_reg_read(pmic, en_reg);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return ret & mask ? true : false;
+}
+
+static int _pldo_set_enable(struct udevice *pmic, int pldo, bool enable)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	uint value, en_reg;
+	int ret = 0;
+
+	switch (priv->variant) {
+	case RK806_ID:
+		if (pldo < 3) {
+			en_reg = RK806_PLDO_EN(0);
+			if (enable)
+				value = RK806_PLDO0_2_SET(pldo);
+			else
+				value = RK806_PLDO0_2_CLR(pldo);
+			ret = pmic_reg_write(pmic, en_reg, value);
+		} else if (pldo == 3) {
+			en_reg = RK806_PLDO_EN(1);
+			if (enable)
+				value = ((1 << 0) | (1 << 4));
+			else
+				value = (1 << 4);
+			ret = pmic_reg_write(pmic, en_reg, value);
+		} else if (pldo == 4) {
+			en_reg = RK806_PLDO_EN(1);
+			if (enable)
+				value = ((1 << 1) | (1 << 5));
+			else
+				value = ((0 << 1) | (1 << 5));
+			ret = pmic_reg_write(pmic, en_reg, value);
+		} else if (pldo == 5) {
+			en_reg = RK806_PLDO_EN(0);
+			if (enable)
+				value = ((1 << 0) | (1 << 4));
+			else
+				value = ((0 << 0) | (1 << 4));
+			ret = pmic_reg_write(pmic, en_reg, value);
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int pldo_get_value(struct udevice *dev)
+{
+	int ldo = dev->driver_data - 1;
+	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, 0);
+	int mask = info->vsel_mask;
+	int ret, val;
+
+	if (info->vsel_reg == NA)
+		return -EINVAL;
+
+	ret = pmic_reg_read(dev->parent, info->vsel_reg);
+	if (ret < 0)
+		return ret;
+	val = ret & mask;
+
+	return info->min_uv + val * info->step_uv;
+}
+
+static int pldo_set_value(struct udevice *dev, int uvolt)
+{
+	int ldo = dev->driver_data - 1;
+	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, uvolt);
+	int mask = info->vsel_mask;
+	int val;
+
+	if (info->vsel_reg == NA)
+		return -EINVAL;
+
+	if (info->step_uv == 0)
+		val = info->min_sel;
+	else
+		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+	      __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
+
+	return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
+}
+
+static int pldo_set_enable(struct udevice *dev, bool enable)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _pldo_set_enable(dev->parent, ldo, enable);
+}
+
+static int pldo_get_enable(struct udevice *dev)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _pldo_get_enable(dev->parent, ldo);
+}
+
+static int pldo_set_suspend_value(struct udevice *dev, int uvolt)
+{
+	int ldo = dev->driver_data - 1;
+	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, uvolt);;
+	int mask = info->vsel_mask;
+	int val;
+
+	if (info->vsel_sleep_reg == NA)
+		return -EINVAL;
+
+	if (info->step_uv == 0)
+		val = info->min_sel;
+	else
+		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+	return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
+}
+
+static int pldo_get_suspend_value(struct udevice *dev)
+{
+	int ldo = dev->driver_data - 1;
+	const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, ldo, 0);
+	int mask = info->vsel_mask;
+	int val, ret;
+
+	if (info->vsel_sleep_reg == NA)
+		return -EINVAL;
+
+	ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
+	if (ret < 0)
+		return ret;
+
+	val = ret & mask;
+
+	return info->min_uv + val * info->step_uv;
+}
+
+static int _pldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
+{
+	uint mask;
+	int ret;
+
+	if (ldo < 5)
+		mask = 1 << (ldo + 1);
+	else
+		mask = 1;
+	ret = pmic_clrsetbits(pmic, RK806_PLDO_SUSPEND_EN, mask,
+			      enable ? mask : 0);
+
+	return ret;
+}
+
+static int _pldo_get_suspend_enable(struct udevice *pmic, int ldo)
+{
+	uint mask, val;
+	int ret;
+
+	if (ldo < 5)
+		mask = 1 << (ldo + 1);
+	else
+		mask = 1;
+	val = pmic_reg_read(pmic, RK806_PLDO_SUSPEND_EN);
+
+	if (val < 0)
+		return val;
+	ret = val & mask ? 1 : 0;
+
+	return ret;
+}
+static int pldo_set_suspend_enable(struct udevice *dev, bool enable)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _pldo_set_suspend_enable(dev->parent, ldo, enable);
+}
+
+static int pldo_get_suspend_enable(struct udevice *dev)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _pldo_get_suspend_enable(dev->parent, ldo);
+}
+
 static int rk8xx_buck_probe(struct udevice *dev)
 {
 	struct dm_regulator_uclass_platdata *uc_pdata;
@@ -1201,6 +1668,17 @@ static int rk8xx_switch_probe(struct udevice *dev)
 	return 0;
 }
 
+static int rk8xx_pldo_probe(struct udevice *dev)
+{
+	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+	uc_pdata->type = REGULATOR_TYPE_LDO;
+	uc_pdata->mode_count = 0;
+
+	return 0;
+}
+
 static const struct dm_regulator_ops rk8xx_buck_ops = {
 	.get_value  = buck_get_value,
 	.set_value  = buck_set_value,
@@ -1235,6 +1713,17 @@ static const struct dm_regulator_ops rk8xx_switch_ops = {
 	.get_suspend_value = switch_get_suspend_value,
 };
 
+static const struct dm_regulator_ops rk8xx_pldo_ops = {
+	.get_value  = pldo_get_value,
+	.set_value  = pldo_set_value,
+	.set_suspend_value = pldo_set_suspend_value,
+	.get_suspend_value = pldo_get_suspend_value,
+	.get_enable = pldo_get_enable,
+	.set_enable = pldo_set_enable,
+	.set_suspend_enable = pldo_set_suspend_enable,
+	.get_suspend_enable = pldo_get_suspend_enable,
+};
+
 U_BOOT_DRIVER(rk8xx_buck) = {
 	.name = "rk8xx_buck",
 	.id = UCLASS_REGULATOR,
@@ -1255,6 +1744,13 @@ U_BOOT_DRIVER(rk8xx_switch) = {
 	.ops = &rk8xx_switch_ops,
 	.probe = rk8xx_switch_probe,
 };
+
+U_BOOT_DRIVER(rk8xx_spi_pldo) = {
+	.name = "rk8xx_pldo",
+	.id = UCLASS_REGULATOR,
+	.ops = &rk8xx_pldo_ops,
+	.probe = rk8xx_pldo_probe,
+};
 #endif
 
 int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
diff --git a/u-boot/drivers/rkflash/flash.c b/u-boot/drivers/rkflash/flash.c
index c038d5bae8..aa7c831f86 100644
--- a/u-boot/drivers/rkflash/flash.c
+++ b/u-boot/drivers/rkflash/flash.c
@@ -452,7 +452,8 @@ u32 nandc_flash_init(void __iomem *nandc_addr)
 			    id_byte[0][1] != 0xAA &&
 			    id_byte[0][1] != 0xAC &&
 			    id_byte[0][1] != 0x6A &&
-			    id_byte[0][1] != 0xD7) {
+			    id_byte[0][1] != 0xD7 &&
+			    id_byte[0][1] != 0x63) {
 				pr_err("The device not support yet!\n");
 
 				return FTL_UNSUPPORTED_FLASH;
@@ -511,6 +512,11 @@ u32 nandc_flash_init(void __iomem *nandc_addr)
 		nand_para.sec_per_page = 16;
 		nand_para.page_per_blk = 128;
 		nand_para.plane_per_die = 2;
+	} else if (id_byte[0][1] == 0x63 && id_byte[0][3] == 0x19) { /* IS34ML08G088 */
+		nand_para.sec_per_page = 8;
+		nand_para.page_per_blk = 64;
+		nand_para.plane_per_die = 2;
+		nand_para.blk_per_plane = 2048;
 	}
 	flash_die_info_init();
 	flash_bch_sel(nand_para.ecc_bits);
diff --git a/u-boot/drivers/rkflash/sfc_nand.c b/u-boot/drivers/rkflash/sfc_nand.c
index ae5c999bec..4de03a6816 100644
--- a/u-boot/drivers/rkflash/sfc_nand.c
+++ b/u-boot/drivers/rkflash/sfc_nand.c
@@ -74,18 +74,22 @@ static struct nand_info spi_nand_tbl[] = {
 	{ 0xC8, 0x55, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status2 },
 	/* GD5F1GQ4UExxH */
 	{ 0xC8, 0xD9, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
-	/* GD5F1GQ5REYIG */
-	{ 0xC8, 0x41, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
+	/* GD5F1GQ5REYIG Add 3rd code to distingush with F50L2G41KA */
+	{ 0xC8, 0x41, 0xC8, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
 	/* GD5F2GQ5REYIG */
 	{ 0xC8, 0x42, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
 	/* GD5F2GM7RxG */
-	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
+	{ 0xC8, 0x82, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
 	/* GD5F2GM7UxG */
-	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
+	{ 0xC8, 0x92, 0x00, 4, 0x40, 1, 2048, 0x0C, 19, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
 	/* GD5F1GM7UxG */
-	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status2 },
+	{ 0xC8, 0x91, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
 	/* GD5F4GQ4UAYIG 1*4096 */
 	{ 0xC8, 0xF4, 0x00, 4, 0x40, 2, 2048, 0x0C, 20, 0x8, 1, { 0x04, 0x08, 0x14, 0x18 }, &sfc_nand_get_ecc_status0 },
+	/* GD5F1GM7REYIGR */
+	{ 0xC8, 0x81, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
+	/* GD5F4GM8UEYIGR */
+	{ 0xC8, 0x95, 0x00, 4, 0x40, 1, 4096, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status3 },
 
 	/* W25N01GV */
 	{ 0xEF, 0xAA, 0x21, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x14, 0x24, 0xFF }, &sfc_nand_get_ecc_status1 },
@@ -137,6 +141,10 @@ static struct nand_info spi_nand_tbl[] = {
 	{ 0xCD, 0x70, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 	/* F35UQA512M */
 	{ 0xCD, 0x60, 0x00, 4, 0x40, 1, 512, 0x4C, 17, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
+	/* F35UQA002G-WWT */
+	{ 0xCD, 0x62, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
+	/* F35UQA001G-WWT */
+	{ 0xCD, 0x61, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 
 	/* DS35Q1GA-IB */
 	{ 0xE5, 0x71, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
@@ -158,6 +166,8 @@ static struct nand_info spi_nand_tbl[] = {
 	{ 0xE5, 0xF5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
 	/* DS35M12B-IB */
 	{ 0xE5, 0xA5, 0x00, 4, 0x40, 1, 512, 0x0C, 17, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+	/* DS35Q1GD-IB */
+	{ 0xE5, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
 
 	/* EM73C044VCC-H */
 	{ 0xD5, 0x22, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x8, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
@@ -186,6 +196,18 @@ static struct nand_info spi_nand_tbl[] = {
 	{ 0x0B, 0x13, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status7 },
 	/* XT26G11C */
 	{ 0x0B, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
+	/* XT26Q02DWSIGA */
+	{ 0x0B, 0x52, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
+	/* XT26Q01DWSIGA */
+	{ 0x0B, 0x51, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
+	/* XT26Q04DWSIGA */
+	{ 0x0B, 0x53, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
+	/* XT26G01DWSIGA */
+	{ 0x0B, 0x31, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
+	/* XT26G02DWSIGA */
+	{ 0x0B, 0x32, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
+	/* XT26G04DWSIGA */
+	{ 0x0B, 0x33, 0x00, 8, 0x40, 1, 2048, 0x4C, 20, 0x8, 1, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status0 },
 
 	/* MT29F2G01ABA, XT26G02E, F50L2G41XA */
 	{ 0x2C, 0x24, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x8, 0, { 0x20, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
@@ -200,11 +222,27 @@ static struct nand_info spi_nand_tbl[] = {
 	{ 0xA1, 0xE5, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x1, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 	/* FM25LS01 */
 	{ 0xA1, 0xA5, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
+	/* FM25S01BI3 */
+	{ 0xA1, 0xD4, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+	/* FM25G02BI3 */
+	{ 0xA1, 0xD2, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
 
 	/* IS37SML01G1 */
 	{ 0xC8, 0x21, 0x00, 4, 0x40, 1, 1024, 0x00, 18, 0x1, 0, { 0x08, 0x0C, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 	/* F50L1G41LB */
 	{ 0xC8, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x1, 0, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
+	/* F50L2G41KA */
+	{ 0xC8, 0x41, 0x7F, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+
+	/* UM19A1HISW */
+	{ 0xB0, 0x24, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+	/* UM19A0HCSW */
+	{ 0xB0, 0x14, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+	/* UM19A0LCSW */
+	{ 0xB0, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+	/* UM19A1LISW */
+	{ 0xB0, 0x25, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status6 },
+
 	/* ATO25D1GA */
 	{ 0x9B, 0x12, 0x00, 4, 0x40, 1, 1024, 0x40, 18, 0x1, 1, { 0x14, 0x24, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 	/* BWJX08K-2Gb */
@@ -215,16 +253,23 @@ static struct nand_info spi_nand_tbl[] = {
 	{ 0xEA, 0xC1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 	/* TX25G01 */
 	{ 0xA1, 0xF1, 0x00, 4, 0x40, 1, 1024, 0x0C, 18, 0x4, 1, { 0x04, 0x14, 0xFF, 0xFF }, &sfc_nand_get_ecc_status8 },
-	/* ANV1GCP0CLG, HYF1GQ4UTXCAE */
+
+	/* S35ML01G3, ANV1GCP0CLG, HYF1GQ4UTXCAE, YX25G1E */
 	{ 0x01, 0x15, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status9 },
-	/* S35ML02G3, ANV1GCP0CLG */
+	/* S35ML02G3, ANV2GCP0CLG, HYF2GQ4UTXCAE, YX25G2E */
 	{ 0x01, 0x25, 0x00, 4, 0x40, 2, 1024, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
 	/* S35ML04G3 */
 	{ 0x01, 0x35, 0x00, 4, 0x40, 2, 2048, 0x4C, 20, 0x4, 0, { 0x04, 0x08, 0x0C, 0x10 }, &sfc_nand_get_ecc_status9 },
+
 	/* GSS01GSAK1 */
 	{ 0x52, 0xBA, 0x13, 4, 0x40, 1, 1024, 0x4C, 18, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
 	/* GSS02GSAK1 */
 	{ 0x52, 0xBA, 0x23, 4, 0x40, 1, 2048, 0x4C, 19, 0x4, 0, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status1 },
+
+	/* XCSP2AAPK */
+	{ 0x8C, 0xA1, 0x00, 4, 0x40, 1, 2048, 0x4C, 19, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
+	/* XCSP1AAPK */
+	{ 0x8C, 0x01, 0x00, 4, 0x40, 1, 1024, 0x4C, 18, 0x8, 1, { 0x04, 0x08, 0xFF, 0xFF }, &sfc_nand_get_ecc_status0 },
 };
 
 static struct nand_info *p_nand_info;
@@ -947,6 +992,9 @@ u32 sfc_nand_read(u32 row, u32 *p_page_buf, u32 column, u32 len)
 		sfc_nand_rw_preset();
 
 	sfc_nand_wait_busy(&status, 1000 * 1000);
+	if (sfc_nand_dev.manufacturer == 0x01 && status)
+		sfc_nand_wait_busy(&status, 1000 * 1000);
+
 	ecc_result = p_nand_info->ecc_status();
 
 	op.sfcmd.d32 = 0;
diff --git a/u-boot/drivers/rkflash/sfc_nor.c b/u-boot/drivers/rkflash/sfc_nor.c
index 6471efaf90..94867b38be 100644
--- a/u-boot/drivers/rkflash/sfc_nor.c
+++ b/u-boot/drivers/rkflash/sfc_nor.c
@@ -40,6 +40,10 @@ static struct flash_info spi_flash_tbl[] = {
 	{ 0xc8671A, 128, 8, 0x13, 0x12, 0x6C, 0x34, 0x21, 0xDC, 0x1C, 17, 0, 0 },
 	/* GD55LB01GEFIRR */
 	{ 0xc8671B, 128, 8, 0x13, 0x12, 0x6C, 0x34, 0x21, 0xDC, 0x1C, 18, 0, 0 },
+	/* GD55LT01GEFIRT */
+	{ 0xc8661B, 128, 8, 0x13, 0x12, 0x6C, 0x34, 0x21, 0xDC, 0x1C, 18, 0, 0 },
+	/* GD25LB256EYIGR */
+	{ 0xc86719, 128, 8, 0x13, 0x12, 0x6C, 0x34, 0x21, 0xDC, 0x1C, 16, 0, 0 },
 
 	/* W25Q32JV */
 	{ 0xef4016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 9, 0 },
@@ -152,6 +156,8 @@ static struct flash_info spi_flash_tbl[] = {
 	{ 0x852018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 },
 	/* PY25Q256H */
 	{ 0x852019, 128, 8, 0x13, 0x12, 0x6C, 0x34, 0x21, 0xDC, 0x1C, 16, 9, 0 },
+	/* PY25Q128LA */
+	{ 0x856518, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 },
 
 	/* ZB25VQ64 */
 	{ 0x5e4017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 },
@@ -160,7 +166,7 @@ static struct flash_info spi_flash_tbl[] = {
 	/* ZB25LQ128 */
 	{ 0x5e5018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 },
 
-	/* BH25Q128AS */
+	/* BH25Q128AS, BY25Q128AS */
 	{ 0x684018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 },
 	/* BH25Q64BS */
 	{ 0x684017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 },
@@ -195,6 +201,9 @@ static struct flash_info spi_flash_tbl[] = {
 
 	/* NM25Q128EVB */
 	{ 0x522118, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 10, 0 },
+
+	/* GT25Q40D */
+	{ 0xc44013, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 10, 9, 0 },
 };
 
 static int snor_write_en(void)
diff --git a/u-boot/drivers/serial/serial-uclass.c b/u-boot/drivers/serial/serial-uclass.c
index c9ba9e2ad8..2026d7df87 100644
--- a/u-boot/drivers/serial/serial-uclass.c
+++ b/u-boot/drivers/serial/serial-uclass.c
@@ -116,7 +116,7 @@ static void serial_find_console_or_panic(void)
 #endif
 		if (!uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) ||
 		    !uclass_get_device(UCLASS_SERIAL, INDEX, &dev) ||
-		    (!uclass_first_device(UCLASS_SERIAL, &dev) && dev)) {
+		    (!uclass_first_device_check(UCLASS_SERIAL, &dev) && dev)) {
 			gd->cur_serial_dev = dev;
 			return;
 		}
diff --git a/u-boot/drivers/spi/rockchip_sfc.c b/u-boot/drivers/spi/rockchip_sfc.c
index 13e4ab01ac..5e8c680da6 100644
--- a/u-boot/drivers/spi/rockchip_sfc.c
+++ b/u-boot/drivers/spi/rockchip_sfc.c
@@ -81,7 +81,7 @@
 #define  SFC_FSR_TX_IS_EMPTY		BIT(1)
 #define  SFC_FSR_RX_IS_EMPTY		BIT(2)
 #define  SFC_FSR_RX_IS_FULL		BIT(3)
-#define  SFC_FSR_TXLV_MASK		GENMASK(12, 8)
+#define  SFC_FSR_TXLV_MASK		GENMASK(13, 8)
 #define  SFC_FSR_TXLV_SHIFT		8
 #define  SFC_FSR_RXLV_MASK		GENMASK(20, 16)
 #define  SFC_FSR_RXLV_SHIFT		16
@@ -149,11 +149,9 @@
 /* Data */
 #define SFC_DATA			0x108
 
-/* The controller and documentation reports that it supports up to 4 CS
- * devices (0-3), however I have only been able to test a single CS (CS 0)
- * due to the configuration of my device.
- */
-#define SFC_MAX_CHIPSELECT_NUM		4
+#define SFC_CS1_REG_OFFSET		0x200
+
+#define SFC_MAX_CHIPSELECT_NUM		2
 
 /* The SFC can transfer max 16KB - 1 at one time
  * we set it to 15.5KB here for alignment.
@@ -180,14 +178,16 @@ struct rockchip_sfc {
 	struct clk hclk;
 	struct clk clk;
 	u32 max_freq;
-	u32 speed;
+	u32 cur_speed;
+	u32 cur_real_speed;
+	u32 speed[SFC_MAX_CHIPSELECT_NUM];
 	bool use_dma;
 	u32 max_iosize;
 	u16 version;
 
 	u32 last_async_size;
 	u32 async;
-	u32 dll_cells;
+	u32 dll_cells[SFC_MAX_CHIPSELECT_NUM];
 	u32 max_dll_cells;
 };
 
@@ -202,11 +202,13 @@ static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
 				 !(status & SFC_RCVR_RESET),
 				 1000000);
 	if (err)
-		printf("SFC reset never finished\n");
+		dev_err(sfc->dev, "SFC reset never finished\n");
 
 	/* Still need to clear the masked interrupt from RISR */
 	writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR);
 
+	dev_dbg(sfc->dev, "reset\n");
+
 	return err;
 }
 
@@ -217,7 +219,7 @@ static u16 rockchip_sfc_get_version(struct rockchip_sfc *sfc)
 
 static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc)
 {
-	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4)
+	if (sfc->version >= SFC_VER_4)
 		return SFC_MAX_IOSIZE_VER4;
 
 	return SFC_MAX_IOSIZE_VER3;
@@ -225,19 +227,15 @@ static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc)
 
 static u32 rockchip_sfc_get_max_dll_cells(struct rockchip_sfc *sfc)
 {
-	switch (rockchip_sfc_get_version(sfc)) {
-	case SFC_VER_8:
-	case SFC_VER_6:
-	case SFC_VER_5:
+	if (sfc->version > SFC_VER_4)
 		return SFC_DLL_CTRL0_DLL_MAX_VER5;
-	case SFC_VER_4:
+	else if (sfc->version == SFC_VER_4)
 		return SFC_DLL_CTRL0_DLL_MAX_VER4;
-	default:
+	else
 		return 0;
-	}
 }
 
-static __maybe_unused void rockchip_sfc_set_delay_lines(struct rockchip_sfc *sfc, u16 cells)
+static __maybe_unused void rockchip_sfc_set_delay_lines(struct rockchip_sfc *sfc, u16 cells, u8 cs)
 {
 	u16 cell_max = (u16)rockchip_sfc_get_max_dll_cells(sfc);
 	u32 val = 0;
@@ -248,7 +246,7 @@ static __maybe_unused void rockchip_sfc_set_delay_lines(struct rockchip_sfc *sfc
 	if (cells)
 		val = SFC_DLL_CTRL0_SCLK_SMP_DLL | cells;
 
-	writel(val, sfc->regbase + SFC_DLL_CTRL0);
+	writel(val, sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_DLL_CTRL0);
 }
 
 static int rockchip_sfc_init(struct rockchip_sfc *sfc)
@@ -302,13 +300,14 @@ static int rockchip_sfc_probe(struct udevice *bus)
 	if (ret)
 		dev_dbg(sfc->dev, "sfc Enable clock fail for %s: %d\n", bus->name, ret);
 #endif
+	/* Initial the version at the first */
+	sfc->version = rockchip_sfc_get_version(sfc);
 
 	ret = rockchip_sfc_init(sfc);
 	if (ret)
 		goto err_init;
 
 	sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc);
-	sfc->version = rockchip_sfc_get_version(sfc);
 	sfc->max_freq = SFC_MAX_SPEED;
 	sfc->dev = bus;
 
@@ -399,7 +398,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
 				   const struct spi_mem_op *op,
 				   u32 len)
 {
-	struct dm_spi_slave_platdata *plat = dev_get_platdata(sfc->dev);
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(mem->dev);
 	u32 ctrl = 0, cmd = 0;
 
 	/* set CMD */
@@ -414,7 +413,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
 			cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT;
 		} else {
 			cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT;
-			writel(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT);
+			writel(op->addr.nbytes * 8 - 1, sfc->regbase + plat->cs * SFC_CS1_REG_OFFSET + SFC_ABIT);
 		}
 
 		ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT);
@@ -454,7 +453,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
 	dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n",
 		ctrl, cmd, op->addr.val, len);
 
-	writel(ctrl, sfc->regbase + SFC_CTRL);
+	writel(ctrl, sfc->regbase + plat->cs * SFC_CS1_REG_OFFSET + SFC_CTRL);
 	writel(cmd, sfc->regbase + SFC_CMD);
 	if (op->addr.nbytes)
 		writel(op->addr.val, sfc->regbase + SFC_ADDR);
@@ -613,13 +612,127 @@ static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us)
 	return ret;
 }
 
+#if CONFIG_IS_ENABLED(CLK)
+static int rockchip_sfc_exec_op_bypass(struct rockchip_sfc *sfc,
+				       struct spi_slave *mem,
+				       const struct spi_mem_op *op)
+{
+	u32 len = min_t(u32, op->data.nbytes, sfc->max_iosize);
+	u32 ret;
+
+	rockchip_sfc_adjust_op_work((struct spi_mem_op *)op);
+	rockchip_sfc_xfer_setup(sfc, mem, op, len);
+	ret = rockchip_sfc_xfer_data_poll(sfc, op, len);
+	if (ret != len) {
+		dev_err(sfc->dev, "xfer data failed ret %d\n", ret);
+
+		return -EIO;
+	}
+
+	return rockchip_sfc_xfer_done(sfc, 100000);
+}
+
+static void rockchip_sfc_delay_lines_tuning(struct rockchip_sfc *sfc, struct spi_slave *mem)
+{
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(mem->dev);
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1),
+						SPI_MEM_OP_NO_ADDR,
+						SPI_MEM_OP_NO_DUMMY,
+						SPI_MEM_OP_DATA_IN(3, NULL, 1));
+	u8 id[3], id_temp[3];
+	u16 cell_max = (u16)rockchip_sfc_get_max_dll_cells(sfc);
+	u16 right, left = 0;
+	u16 step = SFC_DLL_TRANING_STEP;
+	bool dll_valid = false;
+	u8 cs = plat->cs;
+
+	clk_set_rate(&sfc->clk, SFC_DLL_THRESHOLD_RATE);
+	op.data.buf.in = &id;
+	rockchip_sfc_exec_op_bypass(sfc, mem, &op);
+	if ((0xFF == id[0] && 0xFF == id[1]) ||
+	    (0x00 == id[0] && 0x00 == id[1])) {
+		dev_dbg(sfc->dev, "no dev, dll by pass\n");
+		clk_set_rate(&sfc->clk, sfc->speed[cs]);
+		sfc->speed[cs] = SFC_DLL_THRESHOLD_RATE;
+
+		return;
+	}
+
+	clk_set_rate(&sfc->clk, sfc->speed[cs]);
+	op.data.buf.in = &id_temp;
+	for (right = 0; right <= cell_max; right += step) {
+		int ret;
+
+		rockchip_sfc_set_delay_lines(sfc, right, cs);
+		rockchip_sfc_exec_op_bypass(sfc, mem, &op);
+		dev_dbg(sfc->dev, "dll read flash id:%x %x %x\n",
+			id_temp[0], id_temp[1], id_temp[2]);
+
+		ret = memcmp(&id, &id_temp, 3);
+		if (dll_valid && ret) {
+			right -= step;
+
+			break;
+		}
+		if (!dll_valid && !ret)
+			left = right;
+
+		if (!ret)
+			dll_valid = true;
+
+		/* Add cell_max to loop */
+		if (right == cell_max)
+			break;
+		if (right + step > cell_max)
+			right = cell_max - step;
+	}
+
+	if (dll_valid && (right - left) >= SFC_DLL_TRANING_VALID_WINDOW) {
+		if (left == 0 && right < cell_max)
+			sfc->dll_cells[cs] = left + (right - left) * 2 / 5;
+		else
+			sfc->dll_cells[cs] = left + (right - left) / 2;
+	} else {
+		sfc->dll_cells[cs] = 0;
+	}
+
+	if (sfc->dll_cells[cs]) {
+		dev_dbg(sfc->dev, "%d %d %d dll training success in %dMHz max_cells=%u sfc_ver=%d\n",
+			left, right, sfc->dll_cells[cs], sfc->speed[cs],
+			rockchip_sfc_get_max_dll_cells(sfc), rockchip_sfc_get_version(sfc));
+		rockchip_sfc_set_delay_lines(sfc, (u16)sfc->dll_cells[cs], cs);
+	} else {
+		dev_err(sfc->dev, "%d %d dll training failed in %dMHz, reduce the speed\n",
+			left, right, sfc->speed[cs]);
+		rockchip_sfc_set_delay_lines(sfc, 0, cs);
+		clk_set_rate(&sfc->clk, SFC_DLL_THRESHOLD_RATE);
+		sfc->cur_speed = SFC_DLL_THRESHOLD_RATE;
+		sfc->cur_real_speed = clk_get_rate(&sfc->clk);
+		sfc->speed[cs] = SFC_DLL_THRESHOLD_RATE;
+	}
+}
+
+#endif
+
 static int rockchip_sfc_exec_op(struct spi_slave *mem,
 				const struct spi_mem_op *op)
 {
 	struct rockchip_sfc *sfc = dev_get_platdata(mem->dev->parent);
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(mem->dev);
 	u32 len = min_t(u32, op->data.nbytes, sfc->max_iosize);
 	int ret;
 
+	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4 &&
+	    sfc->cur_speed != sfc->speed[plat->cs]) {
+		sfc->speed[plat->cs] = sfc->cur_speed;
+#if CONFIG_IS_ENABLED(CLK)
+		if (sfc->cur_real_speed > SFC_DLL_THRESHOLD_RATE)
+			rockchip_sfc_delay_lines_tuning(sfc, mem);
+		else
+#endif
+			rockchip_sfc_set_delay_lines(sfc, 0, plat->cs);
+	}
+
 	/* Wait for last async transfer finished */
 	if (sfc->last_async_size) {
 		rockchip_sfc_wait_for_dma_finished(sfc, sfc->last_async_size);
@@ -655,103 +768,6 @@ static int rockchip_sfc_adjust_op_size(struct spi_slave *mem, struct spi_mem_op
 	return 0;
 }
 
-#if CONFIG_IS_ENABLED(CLK)
-static int rockchip_sfc_exec_op_bypass(struct rockchip_sfc *sfc,
-				       struct spi_slave *mem,
-				       const struct spi_mem_op *op)
-{
-	u32 len = min_t(u32, op->data.nbytes, sfc->max_iosize);
-	u32 ret;
-
-	rockchip_sfc_adjust_op_work((struct spi_mem_op *)op);
-	rockchip_sfc_xfer_setup(sfc, mem, op, len);
-	ret = rockchip_sfc_xfer_data_poll(sfc, op, len);
-	if (ret != len) {
-		dev_err(sfc->dev, "xfer data failed ret %d\n", ret);
-
-		return -EIO;
-	}
-
-	return rockchip_sfc_xfer_done(sfc, 100000);
-}
-
-static void rockchip_sfc_delay_lines_tuning(struct rockchip_sfc *sfc, struct spi_slave *mem)
-{
-	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1),
-						SPI_MEM_OP_NO_ADDR,
-						SPI_MEM_OP_NO_DUMMY,
-						SPI_MEM_OP_DATA_IN(3, NULL, 1));
-	u8 id[3], id_temp[3];
-	u16 cell_max = (u16)rockchip_sfc_get_max_dll_cells(sfc);
-	u16 right, left = 0;
-	u16 step = SFC_DLL_TRANING_STEP;
-	bool dll_valid = false;
-
-	clk_set_rate(&sfc->clk, SFC_DLL_THRESHOLD_RATE);
-	op.data.buf.in = &id;
-	rockchip_sfc_exec_op_bypass(sfc, mem, &op);
-	if ((0xFF == id[0] && 0xFF == id[1]) ||
-	    (0x00 == id[0] && 0x00 == id[1])) {
-		dev_dbg(sfc->dev, "no dev, dll by pass\n");
-		clk_set_rate(&sfc->clk, sfc->speed);
-
-		return;
-	}
-
-	clk_set_rate(&sfc->clk, sfc->speed);
-	op.data.buf.in = &id_temp;
-	for (right = 0; right <= cell_max; right += step) {
-		int ret;
-
-		rockchip_sfc_set_delay_lines(sfc, right);
-		rockchip_sfc_exec_op_bypass(sfc, mem, &op);
-		dev_dbg(sfc->dev, "dll read flash id:%x %x %x\n",
-			id_temp[0], id_temp[1], id_temp[2]);
-
-		ret = memcmp(&id, &id_temp, 3);
-		if (dll_valid && ret) {
-			right -= step;
-
-			break;
-		}
-		if (!dll_valid && !ret)
-			left = right;
-
-		if (!ret)
-			dll_valid = true;
-
-		/* Add cell_max to loop */
-		if (right == cell_max)
-			break;
-		if (right + step > cell_max)
-			right = cell_max - step;
-	}
-
-	if (dll_valid && (right - left) >= SFC_DLL_TRANING_VALID_WINDOW) {
-		if (left == 0 && right < cell_max)
-			sfc->dll_cells = left + (right - left) * 2 / 5;
-		else
-			sfc->dll_cells = left + (right - left) / 2;
-	} else {
-		sfc->dll_cells = 0;
-	}
-
-	if (sfc->dll_cells) {
-		dev_dbg(sfc->dev, "%d %d %d dll training success in %dMHz max_cells=%u sfc_ver=%d\n",
-			left, right, sfc->dll_cells, sfc->speed,
-			rockchip_sfc_get_max_dll_cells(sfc), rockchip_sfc_get_version(sfc));
-		rockchip_sfc_set_delay_lines(sfc, (u16)sfc->dll_cells);
-	} else {
-		dev_err(sfc->dev, "%d %d dll training failed in %dMHz, reduce the speed\n",
-			left, right, sfc->speed);
-		rockchip_sfc_set_delay_lines(sfc, 0);
-		clk_set_rate(&sfc->clk, SFC_DLL_THRESHOLD_RATE);
-		sfc->speed = clk_get_rate(&sfc->clk);
-	}
-}
-
-#endif
-
 static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
 {
 	struct rockchip_sfc *sfc = dev_get_platdata(bus);
@@ -759,7 +775,7 @@ static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
 	if (speed > sfc->max_freq)
 		speed = sfc->max_freq;
 
-	if (speed == sfc->speed)
+	if (speed == sfc->cur_speed)
 		return 0;
 
 #if CONFIG_IS_ENABLED(CLK)
@@ -770,16 +786,11 @@ static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
 			speed);
 		return ret;
 	}
-	sfc->speed = speed;
-	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) {
-		if (clk_get_rate(&sfc->clk) > SFC_DLL_THRESHOLD_RATE)
-			rockchip_sfc_delay_lines_tuning(sfc, NULL);
-		else
-			rockchip_sfc_set_delay_lines(sfc, 0);
-	}
+	sfc->cur_speed = speed;
+	sfc->cur_real_speed = clk_get_rate(&sfc->clk);
 
-	dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%ldHz\n",
-		sfc->speed, clk_get_rate(&sfc->clk));
+	dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%dHz\n",
+		sfc->cur_speed, sfc->cur_real_speed);
 #else
 	dev_dbg(sfc->dev, "sfc failed, CLK not support\n");
 #endif
diff --git a/u-boot/drivers/usb/common/common.c b/u-boot/drivers/usb/common/common.c
index 467cc01f6f..6fb1b1d049 100644
--- a/u-boot/drivers/usb/common/common.c
+++ b/u-boot/drivers/usb/common/common.c
@@ -49,6 +49,13 @@ static const char *const speed_names[] = {
 	[USB_SPEED_SUPER] = "super-speed",
 };
 
+const char *usb_speed_string(enum usb_device_speed speed)
+{
+	if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
+		speed = USB_SPEED_UNKNOWN;
+	return speed_names[speed];
+}
+
 enum usb_device_speed usb_get_maximum_speed(ofnode node)
 {
 	const char *max_speed;
diff --git a/u-boot/drivers/usb/dwc3/core.c b/u-boot/drivers/usb/dwc3/core.c
index ca14bab386..6f5e5249d0 100644
--- a/u-boot/drivers/usb/dwc3/core.c
+++ b/u-boot/drivers/usb/dwc3/core.c
@@ -30,6 +30,7 @@
 #include "io.h"
 
 #include "linux-compat.h"
+#include "rockusb.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -724,6 +725,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
 	 */
 	hird_threshold = 12;
 
+	dwc->check_linksts = true;
+	dwc->ts = get_timer(0);
 	dwc->maximum_speed = dwc3_dev->maximum_speed;
 	dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum;
 	if (dwc3_dev->lpm_nyet_threshold)
@@ -754,6 +757,9 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
 	/* default to superspeed if no maximum_speed passed */
 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
 		dwc->maximum_speed = USB_SPEED_SUPER;
+	else if (dwc->maximum_speed == USB_SPEED_SUPER &&
+		 rkusb_force_usb2_enabled())
+		dwc->maximum_speed = USB_SPEED_HIGH;
 
 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
 	dwc->tx_de_emphasis = tx_de_emphasis;
diff --git a/u-boot/drivers/usb/dwc3/core.h b/u-boot/drivers/usb/dwc3/core.h
index a67c899436..5b0255bc77 100644
--- a/u-boot/drivers/usb/dwc3/core.h
+++ b/u-boot/drivers/usb/dwc3/core.h
@@ -844,6 +844,9 @@ struct dwc3 {
 	unsigned		tx_de_emphasis:2;
 	unsigned		usb2_phyif_utmi_width:5;
 	int			index;
+	u64			ts;
+	u8			connected;
+	bool			check_linksts;
 	struct list_head        list;
 };
 
diff --git a/u-boot/drivers/usb/dwc3/ep0.c b/u-boot/drivers/usb/dwc3/ep0.c
index 8b98391ab9..ad806defbb 100644
--- a/u-boot/drivers/usb/dwc3/ep0.c
+++ b/u-boot/drivers/usb/dwc3/ep0.c
@@ -511,6 +511,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 		return -EINVAL;
 	}
 
+	dwc->connected = 1;
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
 	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
 	reg |= DWC3_DCFG_DEVADDR(addr);
diff --git a/u-boot/drivers/usb/dwc3/gadget.c b/u-boot/drivers/usb/dwc3/gadget.c
index 1f8d464935..dbbb889ece 100644
--- a/u-boot/drivers/usb/dwc3/gadget.c
+++ b/u-boot/drivers/usb/dwc3/gadget.c
@@ -730,10 +730,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 	 * for OUT endpoints, the total size of a Buffer Descriptor must be a
 	 * multiple of MaxPacketSize. So amend the TRB size to apply this rule.
 	 */
-	if (usb_endpoint_dir_out(dep->endpoint.desc)) {
+	if (usb_endpoint_dir_out(dep->endpoint.desc) &&
+	    (length % dep->endpoint.maxpacket))
 		length = dep->endpoint.maxpacket *
-			((length - 1) / dep->endpoint.maxpacket + 1);
-	}
+			 ((length - 1) / dep->endpoint.maxpacket + 1);
 
 	trb->size = DWC3_TRB_SIZE_LENGTH(length);
 	trb->bpl = lower_32_bits(dma);
@@ -1566,6 +1566,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
 	__dwc3_gadget_ep_disable(dwc->eps[1]);
 
 	dwc->gadget_driver	= NULL;
+	dwc->connected		= 0;
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -1695,6 +1696,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
 	unsigned int		count;
 	unsigned int		s_pkt = 0;
 	unsigned int		trb_status;
+	unsigned int		length;
 
 	if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
 		/*
@@ -1751,7 +1753,14 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
 	 * should receive and we simply bounce the request back to the
 	 * gadget driver for further processing.
 	 */
-	req->request.actual += req->request.length - count;
+	if (usb_endpoint_dir_out(dep->endpoint.desc) &&
+	    (req->request.length % dep->endpoint.maxpacket)) {
+		length = dep->endpoint.maxpacket *
+			 ((req->request.length - 1) / dep->endpoint.maxpacket + 1);
+		req->request.actual += length - count;
+	} else {
+		req->request.actual += req->request.length - count;
+	}
 	if (s_pkt)
 		return 1;
 	if ((event->status & DEPEVT_STATUS_LST) &&
@@ -2211,6 +2220,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 		break;
 	}
 
+	dev_info(dwc->dev, "usb device is %s\n",
+		 usb_speed_string(dwc->gadget.speed));
+
 	/* Enable USB2 LPM Capability */
 
 	if ((dwc->revision > DWC3_REVISION_194A)
@@ -2284,6 +2296,11 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK;
 	unsigned int		pwropt;
 
+	if (dwc->link_state == DWC3_LINK_STATE_POLL && dwc->check_linksts) {
+		dwc->check_linksts = false;
+		dwc->ts = get_timer(0);
+	}
+
 	/*
 	 * WORKAROUND: DWC3 < 2.50a have an issue when configured without
 	 * Hibernation mode enabled which would show up when device detects
@@ -2576,6 +2593,33 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 	return ret;
 }
 
+struct dwc3 *the_controller;
+#define WAIT_USB_CONN_TIMEOUT	(3 * CONFIG_SYS_HZ)
+
+bool dwc3_gadget_is_connected(void)
+{
+	struct dwc3 *dev = the_controller;
+
+	/*
+	 * If the speed is super-speed and wait device
+	 * connection time out, it means that usb3
+	 * enumeration failed. And in a special case,
+	 * if the usb3 host rx-termination is present,
+	 * but host doesn't send LFPS (e.g usb3 host
+	 * initialized fail), this cause dwc3 usb fail
+	 * to detect speed and the speed will be unknown.
+	 */
+	if ((dev->gadget.speed == USB_SPEED_UNKNOWN ||
+	     dev->gadget.speed == USB_SPEED_SUPER) &&
+	    !dev->connected) {
+		debug("ts %ld\n", get_timer(dev->ts));
+		if (get_timer(dev->ts) > WAIT_USB_CONN_TIMEOUT)
+			return false;
+	}
+
+	return true;
+}
+
 /**
  * dwc3_gadget_init - Initializes gadget related registers
  * @dwc: pointer to our controller context structure
@@ -2585,6 +2629,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
 	int					ret;
+	the_controller = dwc;
 
 	dwc->ctrl_req = dma_alloc_coherent(sizeof(*dwc->ctrl_req),
 					(unsigned long *)&dwc->ctrl_req_addr);
diff --git a/u-boot/drivers/usb/gadget/composite.c b/u-boot/drivers/usb/gadget/composite.c
index 89341e8832..76dbd95006 100644
--- a/u-boot/drivers/usb/gadget/composite.c
+++ b/u-boot/drivers/usb/gadget/composite.c
@@ -838,11 +838,15 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 				 * bcdUSB should be 0x0300 for superspeed,
 				 * but we change it to 0x0301 for rockusb.
 				 */
+#ifndef CONFIG_SUPPORT_USBPLUG
 				if (!strncmp(cdev->driver->name,
 					     "rkusb_ums_dnl", 13))
 					cdev->desc.bcdUSB = cpu_to_le16(0x0301);
 				else
 					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+#else
+				cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+#endif
 				cdev->desc.bMaxPacketSize0 = 9;
 			} else {
 				cdev->desc.bMaxPacketSize0 =
diff --git a/u-boot/drivers/usb/gadget/ether.c b/u-boot/drivers/usb/gadget/ether.c
index 0c6b0fca53..0d3b1241d9 100644
--- a/u-boot/drivers/usb/gadget/ether.c
+++ b/u-boot/drivers/usb/gadget/ether.c
@@ -2679,10 +2679,10 @@ int usb_ether_init(void)
 	struct udevice *usb_dev;
 	int ret;
 
-	ret = uclass_first_device(UCLASS_USB_GADGET_GENERIC, &usb_dev);
-	if (!usb_dev || ret) {
+	uclass_first_device(UCLASS_USB_GADGET_GENERIC, &usb_dev);
+	if (!usb_dev) {
 		pr_err("No USB device found\n");
-		return ret;
+		return -ENODEV;
 	}
 
 	ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev);
diff --git a/u-boot/drivers/usb/gadget/f_mass_storage.c b/u-boot/drivers/usb/gadget/f_mass_storage.c
index 8f6d055f07..9437d86586 100644
--- a/u-boot/drivers/usb/gadget/f_mass_storage.c
+++ b/u-boot/drivers/usb/gadget/f_mass_storage.c
@@ -319,6 +319,7 @@ struct fsg_common {
 	u32			tag;
 	u32			residue;
 	u32			usb_amount_left;
+	u32			usb_trb_size;	/* usb transfer size */
 
 	unsigned int		can_stall:1;
 	unsigned int		free_storage_on_release:1;
@@ -674,6 +675,12 @@ static int sleep_thread(struct fsg_common *common)
 			k = 0;
 		}
 
+#ifdef CONFIG_USB_DWC3_GADGET
+		if (rkusb_usb3_capable() && !dwc3_gadget_is_connected()
+		    && !rkusb_force_usb2_enabled())
+			return -ENODEV;
+#endif
+
 		usb_gadget_handle_interrupts(0);
 	}
 	common->thread_wakeup_needed = 0;
@@ -730,7 +737,7 @@ static int do_read(struct fsg_common *common)
 		 *	the next page.
 		 * If this means reading 0 then we were asked to read past
 		 *	the end of file. */
-		amount = min(amount_left, FSG_BUFLEN);
+		amount = min(amount_left, common->usb_trb_size);
 		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
 		if (partial_page > 0)
 			amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
@@ -870,7 +877,7 @@ static int do_write(struct fsg_common *common)
 			 * If this means getting 0, then we were asked
 			 *	to write past the end of file.
 			 * Finally, round down to a block boundary. */
-			amount = min(amount_left_to_req, FSG_BUFLEN);
+			amount = min(amount_left_to_req, common->usb_trb_size);
 			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
 			if (partial_page > 0)
 				amount = min(amount,
@@ -1042,7 +1049,7 @@ static int do_verify(struct fsg_common *common)
 		 * And don't try to read past the end of the file.
 		 * If this means reading 0 then we were asked to read
 		 * past the end of file. */
-		amount = min(amount_left, FSG_BUFLEN);
+		amount = min(amount_left, common->usb_trb_size);
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
@@ -1437,7 +1444,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
 				return rc;
 		}
 
-		nsend = min(fsg->common->usb_amount_left, FSG_BUFLEN);
+		nsend = min(fsg->common->usb_amount_left,
+			    fsg->common->usb_trb_size);
 		memset(bh->buf + nkeep, 0, nsend - nkeep);
 		bh->inreq->length = nsend;
 		bh->inreq->zero = 0;
@@ -1479,7 +1487,8 @@ static int throw_away_data(struct fsg_common *common)
 		bh = common->next_buffhd_to_fill;
 		if (bh->state == BUF_STATE_EMPTY
 		 && common->usb_amount_left > 0) {
-			amount = min(common->usb_amount_left, FSG_BUFLEN);
+			amount = min(common->usb_amount_left,
+				     common->usb_trb_size);
 
 			/* amount is always divisible by 512, hence by
 			 * the bulk-out maxpacket size */
@@ -2496,6 +2505,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 	common->gadget = gadget;
 	common->ep0 = gadget->ep0;
 	common->ep0req = cdev->req;
+	common->usb_trb_size = FSG_BUFLEN;
 
 	/* Maybe allocate device-global string IDs, and patch descriptors */
 	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
diff --git a/u-boot/drivers/usb/gadget/f_rockusb.c b/u-boot/drivers/usb/gadget/f_rockusb.c
index 7547c7ca6f..a40cd54892 100644
--- a/u-boot/drivers/usb/gadget/f_rockusb.c
+++ b/u-boot/drivers/usb/gadget/f_rockusb.c
@@ -14,6 +14,11 @@
 #include <write_keybox.h>
 #include <linux/mtd/mtd.h>
 #include <optee_include/OpteeClientInterface.h>
+#include <dm.h>
+#include <misc.h>
+#include <mmc.h>
+#include <stdlib.h>
+#include <usbplug.h>
 
 #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
 #include <asm/arch/vendor.h>
@@ -174,17 +179,39 @@ static int rkusb_do_reset(struct fsg_common *common,
 	return 0;
 }
 
+__weak bool rkusb_usb3_capable(void)
+{
+	return false;
+}
+
+static int rkusb_do_switch_to_usb3(struct fsg_common *common,
+				   struct fsg_buffhd *bh)
+{
+	g_dnl_set_serialnumber((char *)&common->cmnd[1]);
+	rkusb_switch_to_usb3_enable(true);
+	bh->state = BUF_STATE_EMPTY;
+
+	return 0;
+}
+
 static int rkusb_do_test_unit_ready(struct fsg_common *common,
 				    struct fsg_buffhd *bh)
 {
 	struct blk_desc *desc = &ums[common->lun].block_dev;
+	u32 usb_trb_size;
+	u16 residue;
 
 	if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) ||
 	    desc->if_type == IF_TYPE_SPINOR)
-		common->residue = 0x03 << 24; /* 128KB Max block xfer for SPI Nor */
+		residue = 0x03; /* 128KB Max block xfer for SPI Nor */
+	else if (common->cmnd[1] == 0xf7 && FSG_BUFLEN >= 0x400000)
+		residue = 0x0a; /* Max block xfer for USB DWC3 */
 	else
-		common->residue = 0x06 << 24; /* Max block xfer support from host */
+		residue = 0x06; /* Max block xfer support from host */
 
+	usb_trb_size = (1 << residue) * 4096;
+	common->usb_trb_size = min(usb_trb_size, FSG_BUFLEN);
+	common->residue = residue << 24;
 	common->data_dir = DATA_DIR_NONE;
 	bh->state = BUF_STATE_EMPTY;
 
@@ -475,6 +502,7 @@ static int rkusb_do_vs_write(struct fsg_common *common)
 			data  = bh->buf + sizeof(struct vendor_item);
 
 			if (!type) {
+				#ifndef CONFIG_SUPPORT_USBPLUG
 				if (vhead->id == HDCP_14_HDMI_ID ||
 				    vhead->id == HDCP_14_HDMIRX_ID ||
 				    vhead->id == HDCP_14_DP_ID) {
@@ -484,6 +512,7 @@ static int rkusb_do_vs_write(struct fsg_common *common)
 						return -EIO;
 					}
 				}
+				#endif
 
 				/* Vendor storage */
 				rc = vendor_storage_write(vhead->id,
@@ -542,6 +571,30 @@ static int rkusb_do_vs_write(struct fsg_common *common)
 						curlun->sense_data = SS_WRITE_ERROR;
 						return -EIO;
 					}
+				} else if (memcmp(data, "ENDA", 4) == 0) {
+					if (vhead->size - 8 != 16) {
+						printf("check oem encrypt data size fail!\n");
+						curlun->sense_data = SS_WRITE_ERROR;
+						return -EIO;
+					}
+					if (trusty_write_oem_encrypt_data((uint32_t *)(data + 8), 4) != 0) {
+						printf("trusty_write_oem_encrypt_data error!");
+						curlun->sense_data = SS_WRITE_ERROR;
+						return -EIO;
+					}
+				} else if (memcmp(data, "OTPK", 4) == 0) {
+					uint32_t key_len = vhead->size - 9;
+					uint8_t key_id = *((uint8_t *)data + 8);
+					if (key_len != 16 && key_len != 24 && key_len != 32) {
+						printf("check oem otp key size fail!\n");
+						curlun->sense_data = SS_WRITE_ERROR;
+						return -EIO;
+					}
+					if (trusty_write_oem_otp_key(key_id, (uint8_t *)(data + 9), key_len) != 0) {
+						printf("trusty_write_oem_huk error!");
+						curlun->sense_data = SS_WRITE_ERROR;
+						return -EIO;
+					}
 				} else {
 					printf("Unknown tag\n");
 					curlun->sense_data = SS_WRITE_ERROR;
@@ -638,6 +691,31 @@ static int rkusb_do_vs_read(struct fsg_common *common)
 			vhead->size = rc;
 #else
 			printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n");
+#endif
+		} else if (type == 3) {
+			/* efuse or otp*/
+#ifdef CONFIG_OPTEE_CLIENT
+			if (vhead->id == 120) {
+				u8 value;
+				char *written_str = "key is written!";
+				char *not_written_str = "key is not written!";
+				if (trusty_ta_encryption_key_is_written(&value) != 0) {
+					printf("trusty_ta_encryption_key_is_written error!");
+					return -EIO;
+				}
+				if (value) {
+					memcpy(data, written_str, strlen(written_str));
+					vhead->size = strlen(written_str);
+				} else {
+					memcpy(data, not_written_str, strlen(not_written_str));
+					vhead->size = strlen(not_written_str);
+				}
+			} else {
+				printf("Unknown tag\n");
+				return -EIO;
+			}
+#else
+			printf("Please enable CONFIG_OPTEE_CLIENT\n");
 #endif
 		} else {
 			return -EINVAL;
@@ -654,6 +732,66 @@ static int rkusb_do_vs_read(struct fsg_common *common)
 }
 #endif
 
+static int rkusb_do_switch_storage(struct fsg_common *common)
+{
+	enum if_type type, cur_type = ums[common->lun].block_dev.if_type;
+	int devnum, cur_devnum = ums[common->lun].block_dev.devnum;
+	struct blk_desc *block_dev;
+	u32 media = BOOT_TYPE_UNKNOWN;
+
+	media = 1 << common->cmnd[1];
+
+	switch (media) {
+#ifdef CONFIG_MMC
+	case BOOT_TYPE_EMMC:
+		type = IF_TYPE_MMC;
+		devnum = 0;
+		mmc_initialize(gd->bd);
+		break;
+#endif
+	case BOOT_TYPE_MTD_BLK_NAND:
+		type = IF_TYPE_MTD;
+		devnum = 0;
+		break;
+	case BOOT_TYPE_MTD_BLK_SPI_NAND:
+		type = IF_TYPE_MTD;
+		devnum = 1;
+		break;
+	case BOOT_TYPE_MTD_BLK_SPI_NOR:
+		type = IF_TYPE_MTD;
+		devnum = 2;
+		break;
+	default:
+		printf("Bootdev 0x%x is not support\n", media);
+		return -ENODEV;
+	}
+
+	if (cur_type == type && cur_devnum == devnum)
+		return 0;
+
+#if CONFIG_IS_ENABLED(SUPPORT_USBPLUG)
+	block_dev = usbplug_blk_get_devnum_by_type(type, devnum);
+#else
+	block_dev = blk_get_devnum_by_type(type, devnum);
+#endif
+	if (!block_dev) {
+		printf("Bootdev if_type=%d num=%d toggle fail\n", type, devnum);
+		return -ENODEV;
+	}
+
+	ums[common->lun].num_sectors = block_dev->lba;
+	ums[common->lun].block_dev = *block_dev;
+
+	printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
+	       0,
+	       ums[common->lun].block_dev.devnum,
+	       ums[common->lun].block_dev.hwpart,
+	       ums[common->lun].start_sector,
+	       ums[common->lun].num_sectors);
+
+	return 0;
+}
+
 static int rkusb_do_get_storage_info(struct fsg_common *common,
 				     struct fsg_buffhd *bh)
 {
@@ -726,7 +864,12 @@ static int rkusb_do_read_capacity(struct fsg_common *common,
 	 * bit[7]: Read SecureMode
 	 * bit[8]: New IDB feature
 	 * bit[9]: Get storage media info
-	 * bit[10:63}: Reserved.
+	 * bit[10]: LBAwrite Parity
+	 * bit[11]: Read Otp Data
+	 * bit[12]: usb3 download
+	 * bit[13]: Write OTP proof
+	 * bit[14]: Write Cipher Key
+	 * bit[15:63}: Reserved.
 	 */
 	memset((void *)&buf[0], 0, len);
 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME)
@@ -750,6 +893,17 @@ static int rkusb_do_read_capacity(struct fsg_common *common,
 	buf[1] |= BIT(1); /* Switch Storage */
 	buf[1] |= BIT(2); /* LBAwrite Parity */
 
+	if (rkusb_usb3_capable() && !rkusb_force_usb2_enabled())
+		buf[1] |= BIT(4);
+	else
+		buf[1] &= ~BIT(4);
+
+#ifdef CONFIG_ROCKCHIP_OTP
+	buf[1] |= BIT(3); /* Read Otp Data */
+	buf[1] |= BIT(5); /* Write OTP proof */
+	buf[1] |= BIT(6); /* Write Cipher Key */
+#endif
+
 	/* Set data xfer size */
 	common->residue = len;
 	common->data_size_from_cmnd = len;
@@ -757,6 +911,30 @@ static int rkusb_do_read_capacity(struct fsg_common *common,
 	return len;
 }
 
+#ifdef CONFIG_ROCKCHIP_OTP
+static int rkusb_do_read_otp(struct fsg_common *common,
+			       struct fsg_buffhd *bh)
+{
+	u32 len = common->data_size;
+	u32 type = common->cmnd[1];
+	u8 *buf = (u8 *)bh->buf;
+	struct udevice *dev;
+
+	buf[0] = 0;
+	if (type == 0) { /* soc uuid */
+		if (!uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(rockchip_otp), &dev)) {
+			if (!misc_read(dev, CFG_CPUID_OFFSET, (void *)&buf[1], len))
+				buf[0] = len;
+		}
+	}
+
+	common->residue = len;
+	common->data_size_from_cmnd = len;
+
+	return len;
+}
+#endif
+
 static void rkusb_fixup_cbwcb(struct fsg_common *common,
 			      struct fsg_buffhd *bh)
 {
@@ -857,6 +1035,10 @@ static int rkusb_cmd_process(struct fsg_common *common,
 		rc = RKUSB_RC_FINISHED;
 		break;
 #endif
+	case RKUSB_SWITCH_STORAGE:
+		*reply = rkusb_do_switch_storage(common);
+		rc = RKUSB_RC_FINISHED;
+		break;
 	case RKUSB_GET_STORAGE_MEDIA:
 		*reply = rkusb_do_get_storage_info(common, bh);
 		rc = RKUSB_RC_FINISHED;
@@ -867,11 +1049,23 @@ static int rkusb_cmd_process(struct fsg_common *common,
 		rc = RKUSB_RC_FINISHED;
 		break;
 
+	case RKUSB_SWITCH_USB3:
+		*reply = rkusb_do_switch_to_usb3(common, bh);
+		rc = RKUSB_RC_FINISHED;
+		break;
+
 	case RKUSB_RESET:
 		*reply = rkusb_do_reset(common, bh);
 		rc = RKUSB_RC_FINISHED;
 		break;
 
+#ifdef CONFIG_ROCKCHIP_OTP
+	case RKUSB_READ_OTP_DATA:
+		*reply = rkusb_do_read_otp(common, bh);
+		rc = RKUSB_RC_FINISHED;
+		break;
+#endif
+
 	case RKUSB_READ_10:
 	case RKUSB_WRITE_10:
 		printf("CMD Not support, pls use new version Tool\n");
@@ -888,7 +1082,6 @@ static int rkusb_cmd_process(struct fsg_common *common,
 	case RKUSB_SET_RESET_FLAG:
 	case RKUSB_SPI_READ_10:
 	case RKUSB_SPI_WRITE_10:
-	case RKUSB_SESSION:
 		/* Fall through */
 	default:
 		rc = RKUSB_RC_UNKNOWN_CMND;
diff --git a/u-boot/drivers/usb/gadget/storage_common.c b/u-boot/drivers/usb/gadget/storage_common.c
index c85a86cd2d..96ad7e544d 100644
--- a/u-boot/drivers/usb/gadget/storage_common.c
+++ b/u-boot/drivers/usb/gadget/storage_common.c
@@ -308,8 +308,12 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
 /* Number of buffers we will use.  2 is enough for double-buffering */
 #define FSG_NUM_BUFFERS	2
 
+#if defined(CONFIG_USB_DWC3_GADGET) && defined(ROCKUSB_FSG_BUFLEN)
+#define FSG_BUFLEN	((u32)ROCKUSB_FSG_BUFLEN)
+#else
 /* Default size of buffer length. */
 #define FSG_BUFLEN	((u32)262144)
+#endif
 
 /* Maximal number of LUNs supported in mass storage function */
 #define FSG_MAX_LUNS	8
diff --git a/u-boot/drivers/video/drm/Kconfig b/u-boot/drivers/video/drm/Kconfig
index cc27f66834..8b80d60da2 100644
--- a/u-boot/drivers/video/drm/Kconfig
+++ b/u-boot/drivers/video/drm/Kconfig
@@ -228,3 +228,6 @@ config ROCKCHIP_CUBIC_LUT_SIZE
 	default 0
 	help
 	  Used to calc cubic lut size.
+
+source "drivers/video/drm/display-serdes/Kconfig"
+
diff --git a/u-boot/drivers/video/drm/Makefile b/u-boot/drivers/video/drm/Makefile
index 4c28ee1ffa..a477dba5b3 100644
--- a/u-boot/drivers/video/drm/Makefile
+++ b/u-boot/drivers/video/drm/Makefile
@@ -9,7 +9,7 @@ obj-y += drm_modes.o
 ifndef CONFIG_SPL_BUILD
 obj-y += rockchip_display.o rockchip_display_helper.o rockchip_crtc.o rockchip_phy.o rockchip_bridge.o \
 		rockchip_vop.o rockchip_vop_reg.o rockchip_vop2.o bmp_helper.o \
-		rockchip_connector.o rockchip_post_csc.o
+		rockchip_connector.o rockchip_post_csc.o libnsbmp.o
 
 obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
 obj-$(CONFIG_DRM_DP_HELPER) += drm_dp_helper.o
@@ -31,13 +31,14 @@ obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX_HDMI) += phy-rockchip-samsung-hdptx-hdmi
 obj-$(CONFIG_DRM_ROCKCHIP_TVE) += rockchip_tve.o
 obj-$(CONFIG_DRM_ROCKCHIP_ANALOGIX_DP) += analogix_dp.o analogix_dp_reg.o
 obj-$(CONFIG_DRM_ROCKCHIP_DW_DP) += dw-dp.o
-obj-$(CONFIG_DRM_ROCKCHIP_LVDS) += rockchip_lvds.o
+obj-$(CONFIG_DRM_ROCKCHIP_LVDS) += rockchip_lvds.o drm_of.o
 obj-$(CONFIG_DRM_ROCKCHIP_RGB) += rockchip_rgb.o
 obj-$(CONFIG_DRM_ROCKCHIP_PANEL) += rockchip_panel.o
 obj-$(CONFIG_DRM_ROHM_BU18XL82) += rohm-bu18tl82.o rohm-bu18rl82.o
 obj-$(CONFIG_DRM_ROCKCHIP_RK618) += rk618.o rk618_lvds.o rk618_dsi.o
 obj-$(CONFIG_DRM_ROCKCHIP_RK1000) += rk1000.o rk1000_tve.o
 obj-$(CONFIG_DRM_ROCKCHIP_SAMSUNG_MIPI_DCPHY) += samsung_mipi_dcphy.o
+obj-$(CONFIG_SERDES_DISPLAY) += display-serdes/
 else
 obj-y += rockchip_spl_display.o rockchip_display_helper.o rockchip_crtc.o rockchip_connector.o rockchip_post_csc.o rockchip_vop2.o rockchip_phy.o rockchip-inno-hdmi-phy.o rockchip_dw_hdmi.o dw_hdmi.o
 endif
diff --git a/u-boot/drivers/video/drm/analogix_dp.c b/u-boot/drivers/video/drm/analogix_dp.c
index 70cd620fa8..9384542ad6 100644
--- a/u-boot/drivers/video/drm/analogix_dp.c
+++ b/u-boot/drivers/video/drm/analogix_dp.c
@@ -935,12 +935,29 @@ static int analogix_dp_connector_detect(struct rockchip_connector *conn,
 	return analogix_dp_detect(dp);
 }
 
+static int analogix_dp_connector_mode_valid(struct rockchip_connector *conn,
+					    struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct videomode vm;
+
+	drm_display_mode_to_videomode(&conn_state->mode, &vm);
+
+	if (!vm.hfront_porch || !vm.hback_porch || !vm.vfront_porch || !vm.vback_porch) {
+		dev_err(dp->dev, "front porch or back porch can not be 0\n");
+		return MODE_BAD;
+	}
+
+	return MODE_OK;
+}
+
 static const struct rockchip_connector_funcs analogix_dp_connector_funcs = {
 	.init = analogix_dp_connector_init,
 	.get_edid = analogix_dp_connector_get_edid,
 	.enable = analogix_dp_connector_enable,
 	.disable = analogix_dp_connector_disable,
 	.detect = analogix_dp_connector_detect,
+	.mode_valid = analogix_dp_connector_mode_valid,
 };
 
 static u32 analogix_dp_parse_link_frequencies(struct analogix_dp_device *dp)
diff --git a/u-boot/drivers/video/drm/display-serdes/Kconfig b/u-boot/drivers/video/drm/display-serdes/Kconfig
new file mode 100644
index 0000000000..17511e113a
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/Kconfig
@@ -0,0 +1,29 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Multifunction miscellaneous devices
+#
+comment "driver for different display serdes"
+
+menuconfig SERDES_DISPLAY
+	tristate "rockchip display serdes drivers support"
+	select SERDES_DISPLAY_CHIP_ROHM
+	select SERDES_DISPLAY_CHIP_MAXIM
+	select SERDES_DISPLAY_CHIP_ROCKCHIP
+	select SERDES_DISPLAY_CHIP_NOVO
+	select I2C_MUX
+	select DRM_ROCKCHIP
+	default n
+	help
+	  This driver supports different serdes devices from different vendor such as
+	  maxim, rohm, rockchip etc.
+
+if SERDES_DISPLAY
+source "drivers/video/drm/display-serdes/maxim/Kconfig"
+source "drivers/video/drm/display-serdes/rohm/Kconfig"
+source "drivers/video/drm/display-serdes/rockchip/Kconfig"
+source "drivers/video/drm/display-serdes/novo/Kconfig"
+endif
+
diff --git a/u-boot/drivers/video/drm/display-serdes/Makefile b/u-boot/drivers/video/drm/display-serdes/Makefile
new file mode 100644
index 0000000000..c0ed7a6a3d
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/Makefile
@@ -0,0 +1,15 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for multifunction miscellaneous devices that just used for display
+#
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM)		+= maxim/
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROHM)		+= rohm/
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP)	+= rockchip/
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_NOVO)		+= novo/
+
+obj-$(CONFIG_SERDES_DISPLAY) +=serdes-i2c.o serdes-core.o serdes-bridge.o serdes-bridge-split.o serdes-panel.o serdes-panel-split.o serdes-pinctrl.o serdes-gpio.o
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/core.h b/u-boot/drivers/video/drm/display-serdes/core.h
new file mode 100644
index 0000000000..74ba7467f2
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/core.h
@@ -0,0 +1,369 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * core.h -- core define for mfd display arch
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_dsc.h>
+#include <drm_modes.h>
+#include <video_bridge.h>
+#include <asm/unaligned.h>
+#include <linux/media-bus-format.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <power/regulator.h>
+#include <config.h>
+#include <backlight.h>
+#include <malloc.h>
+#include <video.h>
+
+#include <asm/gpio.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <dm/pinctrl.h>
+#include <dm/uclass-id.h>
+#include <dm/lists.h>
+
+#include <dm/device-internal.h>
+#include <dm/root.h>
+#include <fdtdec.h>
+#include <regmap.h>
+#include <asm/gpio.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "gpio.h"
+
+#include "../drivers/video/drm/rockchip_bridge.h"
+#include "../drivers/video/drm/rockchip_display.h"
+#include "../drivers/video/drm/rockchip_panel.h"
+
+#ifndef __SERDES_DISPLAY_CORE_H__
+#define __SERDES_DISPLAY_CORE_H__
+
+//#define SERDES_DEBUG_MFD
+//#define SERDES_DEBUG_I2C
+//#define SERDES_DEBUG_CHIP
+
+#ifdef SERDES_DEBUG_MFD
+#define  SERDES_DBG_MFD(x...) printf(x)
+#else
+#define  SERDES_DBG_MFD(x...)
+#endif
+
+#ifdef SERDES_DEBUG_I2C
+#define  SERDES_DBG_I2C(x...) printf(x)
+#else
+#define  SERDES_DBG_I2C(x...)
+#endif
+
+#ifdef SERDES_DEBUG_CHIP
+#define  SERDES_DBG_CHIP(x...) printf(x)
+#else
+#define  SERDES_DBG_CHIP(x...)
+#endif
+
+#define SERDES_UBOOT_DISPLAY_VERSION "serdes-uboot-displaly-v10-230920"
+#define MAX_NUM_SERDES_SPLIT 8
+struct serdes;
+
+enum ser_link_mode {
+	SER_DUAL_LINK,
+	SER_LINKA,
+	SER_LINKB,
+	SER_SPLITTER_MODE,
+};
+
+/* Convenience macro to define a single named or anonymous pin descriptor */
+#define PINCTRL_PIN(a, b) { .number = a, .name = b }
+
+/**
+ * struct pinctrl_pin_desc - boards/machines provide information on their
+ * pins, pads or other muxable units in this struct
+ * @number: unique pin number from the global pin number space
+ * @name: a name for this pin
+ * @drv_data: driver-defined per-pin data. pinctrl core does not touch this
+ */
+struct pinctrl_pin_desc {
+	unsigned int number;
+	const char *name;
+	void *drv_data;
+};
+
+/**
+ * struct group_desc - generic pin group descriptor
+ * @name: name of the pin group
+ * @pins: array of pins that belong to the group
+ * @num_pins: number of pins in the group
+ * @data: pin controller driver specific data
+ */
+struct group_desc {
+	const char *name;
+	int *pins;
+	int num_pins;
+	void *data;
+};
+
+/**
+ * struct function_desc - generic function descriptor
+ * @name: name of the function
+ * @group_names: array of pin group names
+ * @num_group_names: number of pin group names
+ * @data: pin controller driver specific data
+ */
+struct function_desc {
+	const char *name;
+	const char **group_names;
+	int num_group_names;
+	void *data;
+};
+
+struct serdes_chip_pinctrl_info {
+	struct pinctrl_pin_desc *pins;
+	unsigned int num_pins;
+	struct group_desc *groups;
+	unsigned int num_groups;
+	struct function_desc *functions;
+	unsigned int num_functions;
+};
+
+struct serdes_chip_bridge_ops {
+	/*serdes chip function for bridge*/
+	int (*power_on)(struct serdes *serdes);
+	int (*init)(struct serdes *serdes);
+	int (*attach)(struct serdes *serdes);
+	bool (*detect)(struct serdes *serdes);
+	int (*get_modes)(struct serdes *serdes);
+	int (*pre_enable)(struct serdes *serdes);
+	int (*enable)(struct serdes *serdes);
+	int (*disable)(struct serdes *serdes);
+	int (*post_disable)(struct serdes *serdes);
+};
+
+struct serdes_chip_panel_ops {
+	/*serdes chip function for bridge*/
+	int (*power_on)(struct serdes *serdes);
+	int (*init)(struct serdes *serdes);
+	int (*disable)(struct serdes *serdes);
+	int (*unprepare)(struct serdes *serdes);
+	int (*prepare)(struct serdes *serdes);
+	int (*enable)(struct serdes *serdes);
+	int (*get_modes)(struct serdes *serdes);
+	int (*mode_set)(struct serdes *serdes);
+	int (*backlight_enable)(struct serdes *serdes);
+	int (*backlight_disable)(struct serdes *serdes);
+};
+
+struct serdes_chip_pinctrl_ops {
+	int (*pinmux_set)(struct serdes *serdes, unsigned int pin_selector,
+			  unsigned int func_selector);
+	int (*pinmux_group_set)(struct serdes *serdes,
+				unsigned int group_selector,
+				unsigned int func_selector);
+	int (*pinconf_set)(struct serdes *serdes,
+			   unsigned int pin_selector,
+			   unsigned int param, unsigned int argument);
+	int (*pinconf_group_set)(struct serdes *serdes,
+				 unsigned int group_selector,
+				 unsigned int param, unsigned int argument);
+};
+
+struct serdes_chip_gpio_ops {
+	/*serdes chip gpio function*/
+	int (*direction_input)(struct serdes *serdes, int gpio);
+	int (*direction_output)(struct serdes *serdes, int gpio, int value);
+	int (*get_level)(struct serdes *serdes, int gpio);
+	int (*set_level)(struct serdes *serdes, int gpio, int value);
+	int (*set_config)(struct serdes *serdes,
+			  int gpio, unsigned long config);
+	int (*to_irq)(struct serdes *serdes, int gpio);
+};
+
+struct serdes_chip_split_ops {
+	int (*select)(struct serdes *serdes, int chan);
+	int (*deselect)(struct serdes *serdes, int chan);
+	int (*set_i2c_addr)(struct serdes *serdes, int address, int link);
+};
+struct serdes_chip_irq_ops {
+	/*serdes chip function for lock and err irq*/
+	int (*lock_handle)(struct serdes *serdes);
+	int (*err_handle)(struct serdes *serdes);
+};
+
+struct serdes_chip_data {
+	const char *name;
+	enum serdes_type serdes_type;
+	enum serdes_id serdes_id;
+	enum reg_val_type reg_val_type;
+	int sequence_init;
+	int connector_type;
+	int reg_id;
+	int id_data;
+	int int_status_reg;
+	int int_trig;
+	int num_gpio;
+	int gpio_base;
+	int same_chip_count;
+	u8 bank_num;
+
+	int (*chip_init)(struct serdes *serdes);
+	struct serdes_chip_pinctrl_info *pinctrl_info;
+	struct serdes_chip_bridge_ops *bridge_ops;
+	struct serdes_chip_panel_ops *panel_ops;
+	struct serdes_chip_pinctrl_ops *pinctrl_ops;
+	struct serdes_chip_gpio_ops *gpio_ops;
+	struct serdes_chip_split_ops *split_ops;
+	struct serdes_chip_irq_ops *irq_ops;
+};
+
+struct reg_sequence {
+	unsigned int reg;
+	unsigned int def;
+	unsigned int delay_us;
+};
+
+struct serdes_init_seq {
+	struct reg_sequence *reg_sequence;
+	unsigned int reg_seq_cnt;
+};
+
+struct serdes_gpio {
+	struct udevice *dev;
+	struct serdes_pinctrl *parent;
+};
+
+struct serdes_pinctrl {
+	struct udevice *dev;
+	struct serdes *parent;
+	struct serdes_gpio *serdes_gpio;
+	struct pinctrl_pin_desc *pdesc;
+	struct regmap *regmap;
+	struct pinctrl_desc *pinctrl_desc;
+	int pin_base;
+};
+
+struct serdes_panel {
+	struct rockchip_panel *panel;
+	const char *name;
+	u32 width_mm;
+	u32 height_mm;
+	u32 link_rate;
+	u32 lane_count;
+	bool ssc;
+	struct serdes *parent;
+	struct drm_display_mode mode;
+	struct udevice *backlight;
+	struct rockchip_panel_funcs *panel_ops;
+};
+
+struct serdes_panel_split {
+	struct rockchip_panel *panel;
+
+	const char *name;
+	u32 width_mm;
+	u32 height_mm;
+	u32 link_rate;
+	u32 lane_count;
+	bool ssc;
+	struct serdes *parent;
+	struct drm_display_mode mode;
+	struct udevice *backlight;
+	struct rockchip_panel_funcs *panel_ops;
+};
+
+struct serdes_bridge {
+	bool sel_mipi;
+	struct mipi_dsi_device *dsi;
+	struct serdes *parent;
+	struct drm_display_mode mode;
+	struct rockchip_bridge *bridge;
+	struct rockchip_bridge_funcs *bridge_ops;
+};
+
+struct serdes_bridge_split {
+	bool sel_mipi;
+	struct mipi_dsi_device *dsi;
+	struct serdes *parent;
+	struct drm_display_mode mode;
+	struct rockchip_bridge *bridge;
+	struct rockchip_bridge_funcs *bridge_ops;
+};
+
+struct serdes {
+	struct udevice *dev;
+	struct udevice *vpower_supply;
+	struct serdes_init_seq *serdes_init_seq;
+	enum serdes_type type;
+
+	/*serdes power and reset pin*/
+	struct gpio_desc reset_gpio;
+	struct gpio_desc enable_gpio;
+
+	/* serdes irq pin */
+	struct gpio_desc lock_gpio;
+	struct gpio_desc err_gpio;
+	int lock_irq;
+	int err_irq;
+	int lock_irq_trig;
+	int err_irq_trig;
+
+	bool sel_mipi;
+	struct mipi_dsi_device *dsi;
+
+	bool split_mode_enable;
+	unsigned int reg_hw;
+	unsigned int reg_use;
+	unsigned int link_use;
+	unsigned int id_serdes_bridge_split;
+	unsigned int id_serdes_panel_split;
+	struct serdes *g_serdes_bridge_split;
+
+	struct serdes_bridge *serdes_bridge;
+	struct serdes_bridge_split *serdes_bridge_split;
+	struct serdes_panel *serdes_panel;
+	struct serdes_panel_split *serdes_panel_split;
+	struct serdes_pinctrl *serdes_pinctrl;
+	struct serdes_chip_data *chip_data;
+};
+
+/* Device I/O API */
+int serdes_reg_read(struct serdes *serdes, unsigned int reg, unsigned int *val);
+int serdes_reg_write(struct serdes *serdes, unsigned int reg, unsigned int val);
+int serdes_set_bits(struct serdes *serdes, unsigned int reg,
+		    unsigned int mask, unsigned int val);
+int serdes_multi_reg_write(struct serdes *serdes,
+			   const struct reg_sequence *regs,
+			   int num_regs);
+int serdes_i2c_set_sequence(struct serdes *serdes);
+int serdes_parse_init_seq(struct udevice *dev, const u16 *data,
+			  int length, struct serdes_init_seq *seq);
+int serdes_get_init_seq(struct serdes *serdes);
+int serdes_gpio_register(struct udevice *dev, struct serdes *serdes);
+int serdes_pinctrl_register(struct udevice *dev, struct serdes *serdes);
+int serdes_bridge_register(struct udevice *dev, struct serdes *serdes);
+int serdes_bridge_split_register(struct udevice *dev, struct serdes *serdes);
+int serdes_power_init(void);
+int serdes_video_bridge_init(void);
+int serdes_video_bridge_split_init(void);
+int serdes_display_init(void);
+
+extern struct serdes_chip_data serdes_bu18tl82_data;
+extern struct serdes_chip_data serdes_bu18rl82_data;
+extern struct serdes_chip_data serdes_max96745_data;
+extern struct serdes_chip_data serdes_max96752_data;
+extern struct serdes_chip_data serdes_max96755_data;
+extern struct serdes_chip_data serdes_max96772_data;
+extern struct serdes_chip_data serdes_max96789_data;
+extern struct serdes_chip_data serdes_rkx111_data;
+extern struct serdes_chip_data serdes_rkx121_data;
+extern struct serdes_chip_data serdes_nca9539_data;
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/gpio.h b/u-boot/drivers/video/drm/display-serdes/gpio.h
new file mode 100644
index 0000000000..0538b78af8
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/gpio.h
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * gpio.h -- GPIO for different serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __SERDES_DISPLAY_GPIO_H__
+#define __SERDES_DISPLAY_GPIO_H__
+
+enum serdes_parent {
+	BU18TL82 = 0x1000,
+	BU18RL82 = 0x1001,
+	MAX96745 = 0x2000,
+	MAX96752 = 0x2001,
+	MAX96755 = 0x2003,
+	MAX96722 = 0x2004,
+	MAX96789 = 0x2005,
+	RKX111 = 0x3000,
+	RKX121 = 0x3001,
+};
+
+enum serdes_type {
+	TYPE_ID_INVALID = 0,
+	TYPE_SER,
+	TYPE_DES,
+	TYPE_OTHER,
+};
+
+enum reg_val_type {
+	REG_16BIT_VAL_8IT = 0,
+	REG_16BIT_VAL_16IT,
+	REG_8BIT_VAL_8IT,
+};
+
+enum serdes_bridge_type {
+	TYPE_BRIDGE_PANEL = 0,
+	TYPE_BRIDGE_BRIDGE,
+};
+
+enum serdes_id {
+	SERDES_ID_INVALID = 0,
+
+	ROHM_ID_BU18TL82,
+	ROHM_ID_BU18RL82,
+
+	MAXIM_ID_MAX96745,
+	MAXIM_ID_MAX96752,
+	MAXIM_ID_MAX96755,
+	MAXIM_ID_MAX96772,
+	MAXIM_ID_MAX96789,
+
+	ROCKCHIP_ID_RKX111,
+	ROCKCHIP_ID_RKX121,
+
+	NOVO_ID_NCA9539,
+
+	SERDES_NUM_ID,
+};
+
+enum bu18tl82_gpio_list {
+	ROHM_BU18TL82_GPIO0 = 0,
+	ROHM_BU18TL82_GPIO1,
+	ROHM_BU18TL82_GPIO2,
+	ROHM_BU18TL82_GPIO3,
+	ROHM_BU18TL82_GPIO4,
+	ROHM_BU18TL82_GPIO5,
+	ROHM_BU18TL82_GPIO6,
+	ROHM_BU18TL82_GPIO7,
+};
+
+enum bu18rl82_gpio_list {
+	ROHM_BU18RL82_GPIO0 = 0,
+	ROHM_BU18RL82_GPIO1,
+	ROHM_BU18RL82_GPIO2,
+	ROHM_BU18RL82_GPIO3,
+	ROHM_BU18RL82_GPIO4,
+	ROHM_BU18RL82_GPIO5,
+	ROHM_BU18RL82_GPIO6,
+	ROHM_BU18RL82_GPIO7,
+};
+
+enum max96745_gpio_list {
+	MAXIM_MAX96745_MFP0 = 0,
+	MAXIM_MAX96745_MFP1,
+	MAXIM_MAX96745_MFP2,
+	MAXIM_MAX96745_MFP3,
+	MAXIM_MAX96745_MFP4,
+	MAXIM_MAX96745_MFP5,
+	MAXIM_MAX96745_MFP6,
+	MAXIM_MAX96745_MFP7,
+	MAXIM_MAX96745_MFP8,
+	MAXIM_MAX96745_MFP9,
+	MAXIM_MAX96745_MFP10,
+	MAXIM_MAX96745_MFP11,
+	MAXIM_MAX96745_MFP12,
+	MAXIM_MAX96745_MFP13,
+	MAXIM_MAX96745_MFP14,
+	MAXIM_MAX96745_MFP15,
+	MAXIM_MAX96745_MFP16,
+	MAXIM_MAX96745_MFP17,
+	MAXIM_MAX96745_MFP18,
+	MAXIM_MAX96745_MFP19,
+	MAXIM_MAX96745_MFP20,
+	MAXIM_MAX96745_MFP21,
+	MAXIM_MAX96745_MFP22,
+	MAXIM_MAX96745_MFP23,
+	MAXIM_MAX96745_MFP24,
+	MAXIM_MAX96745_MFP25,
+};
+
+enum max96752_gpio_list {
+	MAXIM_MAX96752_GPIO0 = 0,
+	MAXIM_MAX96752_GPIO1,
+	MAXIM_MAX96752_GPIO2,
+	MAXIM_MAX96752_GPIO3,
+	MAXIM_MAX96752_GPIO4,
+	MAXIM_MAX96752_GPIO5,
+	MAXIM_MAX96752_GPIO6,
+	MAXIM_MAX96752_GPIO7,
+	MAXIM_MAX96752_GPIO8,
+	MAXIM_MAX96752_GPIO9,
+	MAXIM_MAX96752_GPIO10,
+	MAXIM_MAX96752_GPIO11,
+	MAXIM_MAX96752_GPIO12,
+	MAXIM_MAX96752_GPIO13,
+	MAXIM_MAX96752_GPIO14,
+	MAXIM_MAX96752_GPIO15,
+};
+
+enum max96755_gpio_list {
+	MAXIM_MAX96755_MFP0 = 0,
+	MAXIM_MAX96755_MFP1,
+	MAXIM_MAX96755_MFP2,
+	MAXIM_MAX96755_MFP3,
+	MAXIM_MAX96755_MFP4,
+	MAXIM_MAX96755_MFP5,
+	MAXIM_MAX96755_MFP6,
+	MAXIM_MAX96755_MFP7,
+	MAXIM_MAX96755_MFP8,
+	MAXIM_MAX96755_MFP9,
+	MAXIM_MAX96755_MFP10,
+	MAXIM_MAX96755_MFP11,
+	MAXIM_MAX96755_MFP12,
+	MAXIM_MAX96755_MFP13,
+	MAXIM_MAX96755_MFP14,
+	MAXIM_MAX96755_MFP15,
+	MAXIM_MAX96755_MFP16,
+	MAXIM_MAX96755_MFP17,
+	MAXIM_MAX96755_MFP18,
+	MAXIM_MAX96755_MFP19,
+	MAXIM_MAX96755_MFP20,
+};
+
+enum max96722_gpio_list {
+	MAXIM_MAX96772_GPIO0 = 0,
+	MAXIM_MAX96772_GPIO1,
+	MAXIM_MAX96772_GPIO2,
+	MAXIM_MAX96772_GPIO3,
+	MAXIM_MAX96772_GPIO4,
+	MAXIM_MAX96772_GPIO5,
+	MAXIM_MAX96772_GPIO6,
+	MAXIM_MAX96772_GPIO7,
+	MAXIM_MAX96772_GPIO8,
+	MAXIM_MAX96772_GPIO9,
+	MAXIM_MAX96772_GPIO10,
+	MAXIM_MAX96772_GPIO11,
+	MAXIM_MAX96772_GPIO12,
+	MAXIM_MAX96772_GPIO13,
+	MAXIM_MAX96772_GPIO14,
+	MAXIM_MAX96772_GPIO15,
+};
+
+enum max96789_gpio_list {
+	MAXIM_MAX96789_MFP0 = 0,
+	MAXIM_MAX96789_MFP1,
+	MAXIM_MAX96789_MFP2,
+	MAXIM_MAX96789_MFP3,
+	MAXIM_MAX96789_MFP4,
+	MAXIM_MAX96789_MFP5,
+	MAXIM_MAX96789_MFP6,
+	MAXIM_MAX96789_MFP7,
+	MAXIM_MAX96789_MFP8,
+	MAXIM_MAX96789_MFP9,
+	MAXIM_MAX96789_MFP10,
+	MAXIM_MAX96789_MFP11,
+	MAXIM_MAX96789_MFP12,
+	MAXIM_MAX96789_MFP13,
+	MAXIM_MAX96789_MFP14,
+	MAXIM_MAX96789_MFP15,
+	MAXIM_MAX96789_MFP16,
+	MAXIM_MAX96789_MFP17,
+	MAXIM_MAX96789_MFP18,
+	MAXIM_MAX96789_MFP19,
+	MAXIM_MAX96789_MFP20,
+};
+
+enum rkx111_gpio_list {
+	ROCKCHIP_RKX111_GPIO0 = 0,
+	ROCKCHIP_RKX111_GPIO1,
+	ROCKCHIP_RKX111_GPIO2,
+	ROCKCHIP_RKX111_GPIO3,
+	ROCKCHIP_RKX111_GPIO4,
+	ROCKCHIP_RKX111_GPIO5,
+	ROCKCHIP_RKX111_GPIO6,
+	ROCKCHIP_RKX111_GPIO7,
+};
+
+enum rkx121_gpio_list {
+	ROCKCHIP_RKX121_GPIO0 = 0,
+	ROCKCHIP_RKX121_GPIO1,
+	ROCKCHIP_RKX121_GPIO2,
+	ROCKCHIP_RKX121_GPIO3,
+	ROCKCHIP_RKX121_GPIO4,
+	ROCKCHIP_RKX121_GPIO5,
+	ROCKCHIP_RKX121_GPIO6,
+	ROCKCHIP_RKX121_GPIO7,
+};
+
+enum serdes_gpio_state {
+	SERDES_GPIO_PULL_NONE = 0,
+	SERDES_GPIO_PULL_DOWN,
+	SERDES_GPIO_PULL_UP,
+	SERDES_GPIO_DIR_IN,
+	SERDES_GPIO_DIR_OUT,
+	SERDES_GPIO_LEVEL_HIGH,
+	SERDES_GPIO_LEVEL_LOW,
+};
+
+enum nca9539_gpio_list {
+	NOVO_NCA9539_GPIO0 = 0,
+	NOVO_NCA9539_GPIO1,
+	NOVO_NCA9539_GPIO2,
+	NOVO_NCA9539_GPIO3,
+	NOVO_NCA9539_GPIO4,
+	NOVO_NCA9539_GPIO5,
+	NOVO_NCA9539_GPIO6,
+	NOVO_NCA9539_GPIO7,
+
+	NOVO_NCA9539_GPIO8,
+	NOVO_NCA9539_GPIO9,
+	NOVO_NCA9539_GPIO10,
+	NOVO_NCA9539_GPIO11,
+	NOVO_NCA9539_GPIO12,
+	NOVO_NCA9539_GPIO13,
+	NOVO_NCA9539_GPIO14,
+	NOVO_NCA9539_GPIO15,
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/Kconfig b/u-boot/drivers/video/drm/display-serdes/maxim/Kconfig
new file mode 100644
index 0000000000..3f18c92fab
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/Kconfig
@@ -0,0 +1,47 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# maxim display serdes drivers configuration
+#
+
+menuconfig SERDES_DISPLAY_CHIP_MAXIM
+	tristate "maxim serdes device support"
+	default y
+	help
+	  Enable this to be able to choose the drivers for controlling the
+	  maxim serdes.
+
+if SERDES_DISPLAY_CHIP_MAXIM
+config SERDES_DISPLAY_CHIP_MAXIM_MAX96745
+	tristate "maxim max96745 serdes"
+	default y
+	help
+	  To support maxim max96745 display serdes.
+
+config SERDES_DISPLAY_CHIP_MAXIM_MAX96752
+	tristate "maxim max96752 serdes"
+	default y
+	help
+	  To support maxim max96752 display serdes.
+
+config SERDES_DISPLAY_CHIP_MAXIM_MAX96755
+	tristate "maxim max96755 serdes"
+	default y
+	help
+	  To support maxim max96755 display serdes.
+
+config SERDES_DISPLAY_CHIP_MAXIM_MAX96772
+	tristate "maxim max96772 serdes"
+	default y
+	help
+	  To support maxim max96772 display serdes.
+
+config SERDES_DISPLAY_CHIP_MAXIM_MAX96789
+	tristate "maxim max96789 serdes"
+	default y
+	help
+	  To support maxim max96789 display serdes.
+
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/Makefile b/u-boot/drivers/video/drm/display-serdes/maxim/Makefile
new file mode 100644
index 0000000000..f6d24a7c18
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/Makefile
@@ -0,0 +1,14 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# maxim display serdes drivers configuration
+#
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745)	+= maxim-max96745.o
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752)	+= maxim-max96752.o
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)	+= maxim-max96755.o
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772)	+= maxim-max96772.o
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96789)	+= maxim-max96789.o
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96745.c b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96745.c
new file mode 100644
index 0000000000..febcc3749a
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96745.c
@@ -0,0 +1,813 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * maxim-max96745.c  --  I2C register interface access for max96745 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+#include "../core.h"
+#include "maxim-max96745.h"
+struct serdes_function_data {
+	u8 gpio_out_dis:1;
+	u8 gpio_io_rx_en:1;
+	u8 gpio_tx_en_a:1;
+	u8 gpio_tx_en_b:1;
+	u8 gpio_rx_en_a:1;
+	u8 gpio_rx_en_b:1;
+	u8 gpio_tx_id;
+	u8 gpio_rx_id;
+	u16 mdelay;
+};
+
+struct config_desc {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+struct serdes_group_data {
+	const struct config_desc *configs;
+	int num_configs;
+};
+
+static int MAX96745_MFP0_pins[] = {0};
+static int MAX96745_MFP1_pins[] = {1};
+static int MAX96745_MFP2_pins[] = {2};
+static int MAX96745_MFP3_pins[] = {3};
+static int MAX96745_MFP4_pins[] = {4};
+static int MAX96745_MFP5_pins[] = {5};
+static int MAX96745_MFP6_pins[] = {6};
+static int MAX96745_MFP7_pins[] = {7};
+
+static int MAX96745_MFP8_pins[] = {8};
+static int MAX96745_MFP9_pins[] = {9};
+static int MAX96745_MFP10_pins[] = {10};
+static int MAX96745_MFP11_pins[] = {11};
+static int MAX96745_MFP12_pins[] = {12};
+static int MAX96745_MFP13_pins[] = {13};
+static int MAX96745_MFP14_pins[] = {14};
+static int MAX96745_MFP15_pins[] = {15};
+
+static int MAX96745_MFP16_pins[] = {16};
+static int MAX96745_MFP17_pins[] = {17};
+static int MAX96745_MFP18_pins[] = {18};
+static int MAX96745_MFP19_pins[] = {19};
+static int MAX96745_MFP20_pins[] = {20};
+static int MAX96745_MFP21_pins[] = {21};
+static int MAX96745_MFP22_pins[] = {22};
+static int MAX96745_MFP23_pins[] = {23};
+
+static int MAX96745_MFP24_pins[] = {24};
+static int MAX96745_MFP25_pins[] = {25};
+static int MAX96745_I2C_pins[] = {3, 7};
+static int MAX96745_UART_pins[] = {3, 7};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+static const char *serdes_gpio_groups[] = {
+	"MAX96745_MFP0", "MAX96745_MFP1", "MAX96745_MFP2", "MAX96745_MFP3",
+	"MAX96745_MFP4", "MAX96745_MFP5", "MAX96745_MFP6", "MAX96745_MFP7",
+
+	"MAX96745_MFP8", "MAX96745_MFP9", "MAX96745_MFP10", "MAX96745_MFP11",
+	"MAX96745_MFP12", "MAX96745_MFP13", "MAX96745_MFP14", "MAX96745_MFP15",
+
+	"MAX96745_MFP16", "MAX96745_MFP17", "MAX96745_MFP18", "MAX96745_MFP19",
+	"MAX96745_MFP20", "MAX96745_MFP21", "MAX96745_MFP22", "MAX96745_MFP23",
+
+	"MAX96745_MFP24", "MAX96745_MFP25",
+};
+
+static const char *MAX96745_I2C_groups[] = { "MAX96745_I2C" };
+static const char *MAX96745_UART_groups[] = { "MAX96745_UART" };
+
+#define FUNCTION_DESC(nm) \
+{ \
+	.name = #nm, \
+	.group_names = nm##_groups, \
+	.num_group_names = ARRAY_SIZE(nm##_groups), \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_A(id) \
+{ \
+	.name = "SER_TXID"#id"_TO_DES_LINKA", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 1, .gpio_tx_en_a = 1, \
+		  .gpio_io_rx_en = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_B(id) \
+{ \
+	.name = "SER_TXID"#id"_TO_DES_LINKB", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 1, .gpio_tx_en_b = 1, \
+		  .gpio_io_rx_en = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_INPUT_A(id) \
+{ \
+	.name = "DES_RXID"#id"_TO_SER_LINKA", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en_a = 1, .gpio_rx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_INPUT_B(id) \
+{ \
+	.name = "DES_RXID"#id"_TO_SER_LINKB", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en_b = 1, .gpio_rx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO() \
+{ \
+	.name = "MAX96745_GPIO", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc max96745_pins_desc[] = {
+	PINCTRL_PIN(MAXIM_MAX96745_MFP0, "MAX96745_MFP0"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP1, "MAX96745_MFP1"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP2, "MAX96745_MFP2"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP3, "MAX96745_MFP3"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP4, "MAX96745_MFP4"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP5, "MAX96745_MFP5"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP6, "MAX96745_MFP6"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP7, "MAX96745_MFP7"),
+
+	PINCTRL_PIN(MAXIM_MAX96745_MFP8, "MAX96745_MFP8"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP9, "MAX96745_MFP9"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP10, "MAX96745_MFP10"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP11, "MAX96745_MFP11"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP12, "MAX96745_MFP12"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP13, "MAX96745_MFP13"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP14, "MAX96745_MFP14"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP15, "MAX96745_MFP15"),
+
+	PINCTRL_PIN(MAXIM_MAX96745_MFP16, "MAX96745_MFP16"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP17, "MAX96745_MFP17"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP18, "MAX96745_MFP18"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP19, "MAX96745_MFP19"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP20, "MAX96745_MFP20"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP21, "MAX96745_MFP21"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP22, "MAX96745_MFP22"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP23, "MAX96745_MFP23"),
+
+	PINCTRL_PIN(MAXIM_MAX96745_MFP24, "MAX96745_MFP24"),
+	PINCTRL_PIN(MAXIM_MAX96745_MFP25, "MAX96745_MFP25"),
+};
+
+static struct group_desc max96745_groups_desc[] = {
+	GROUP_DESC(MAX96745_MFP0),
+	GROUP_DESC(MAX96745_MFP1),
+	GROUP_DESC(MAX96745_MFP2),
+	GROUP_DESC(MAX96745_MFP3),
+	GROUP_DESC(MAX96745_MFP4),
+	GROUP_DESC(MAX96745_MFP5),
+	GROUP_DESC(MAX96745_MFP6),
+	GROUP_DESC(MAX96745_MFP7),
+
+	GROUP_DESC(MAX96745_MFP8),
+	GROUP_DESC(MAX96745_MFP9),
+	GROUP_DESC(MAX96745_MFP10),
+	GROUP_DESC(MAX96745_MFP11),
+	GROUP_DESC(MAX96745_MFP12),
+	GROUP_DESC(MAX96745_MFP13),
+	GROUP_DESC(MAX96745_MFP14),
+	GROUP_DESC(MAX96745_MFP15),
+
+	GROUP_DESC(MAX96745_MFP16),
+	GROUP_DESC(MAX96745_MFP17),
+	GROUP_DESC(MAX96745_MFP18),
+	GROUP_DESC(MAX96745_MFP19),
+	GROUP_DESC(MAX96745_MFP20),
+	GROUP_DESC(MAX96745_MFP21),
+	GROUP_DESC(MAX96745_MFP22),
+	GROUP_DESC(MAX96745_MFP23),
+
+	GROUP_DESC(MAX96745_MFP24),
+	GROUP_DESC(MAX96745_MFP25),
+
+	GROUP_DESC(MAX96745_I2C),
+	GROUP_DESC(MAX96745_UART),
+};
+
+static struct function_desc max96745_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT_A(0),
+	FUNCTION_DESC_GPIO_INPUT_A(1),
+	FUNCTION_DESC_GPIO_INPUT_A(2),
+	FUNCTION_DESC_GPIO_INPUT_A(3),
+	FUNCTION_DESC_GPIO_INPUT_A(4),
+	FUNCTION_DESC_GPIO_INPUT_A(5),
+	FUNCTION_DESC_GPIO_INPUT_A(6),
+	FUNCTION_DESC_GPIO_INPUT_A(7),
+
+	FUNCTION_DESC_GPIO_INPUT_A(8),
+	FUNCTION_DESC_GPIO_INPUT_A(9),
+	FUNCTION_DESC_GPIO_INPUT_A(10),
+	FUNCTION_DESC_GPIO_INPUT_A(11),
+	FUNCTION_DESC_GPIO_INPUT_A(12),
+	FUNCTION_DESC_GPIO_INPUT_A(13),
+	FUNCTION_DESC_GPIO_INPUT_A(14),
+	FUNCTION_DESC_GPIO_INPUT_A(15),
+
+	FUNCTION_DESC_GPIO_INPUT_A(16),
+	FUNCTION_DESC_GPIO_INPUT_A(17),
+	FUNCTION_DESC_GPIO_INPUT_A(18),
+	FUNCTION_DESC_GPIO_INPUT_A(19),
+	FUNCTION_DESC_GPIO_INPUT_A(20),
+	FUNCTION_DESC_GPIO_INPUT_A(21),
+	FUNCTION_DESC_GPIO_INPUT_A(22),
+	FUNCTION_DESC_GPIO_INPUT_A(23),
+
+	FUNCTION_DESC_GPIO_INPUT_A(24),
+	FUNCTION_DESC_GPIO_INPUT_A(25),
+
+	FUNCTION_DESC_GPIO_OUTPUT_A(0),
+	FUNCTION_DESC_GPIO_OUTPUT_A(1),
+	FUNCTION_DESC_GPIO_OUTPUT_A(2),
+	FUNCTION_DESC_GPIO_OUTPUT_A(3),
+	FUNCTION_DESC_GPIO_OUTPUT_A(4),
+	FUNCTION_DESC_GPIO_OUTPUT_A(5),
+	FUNCTION_DESC_GPIO_OUTPUT_A(6),
+	FUNCTION_DESC_GPIO_OUTPUT_A(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_A(8),
+	FUNCTION_DESC_GPIO_OUTPUT_A(9),
+	FUNCTION_DESC_GPIO_OUTPUT_A(10),
+	FUNCTION_DESC_GPIO_OUTPUT_A(11),
+	FUNCTION_DESC_GPIO_OUTPUT_A(12),
+	FUNCTION_DESC_GPIO_OUTPUT_A(13),
+	FUNCTION_DESC_GPIO_OUTPUT_A(14),
+	FUNCTION_DESC_GPIO_OUTPUT_A(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_A(16),
+	FUNCTION_DESC_GPIO_OUTPUT_A(17),
+	FUNCTION_DESC_GPIO_OUTPUT_A(18),
+	FUNCTION_DESC_GPIO_OUTPUT_A(19),
+	FUNCTION_DESC_GPIO_OUTPUT_A(20),
+	FUNCTION_DESC_GPIO_OUTPUT_A(21),
+	FUNCTION_DESC_GPIO_OUTPUT_A(22),
+	FUNCTION_DESC_GPIO_OUTPUT_A(23),
+
+	FUNCTION_DESC_GPIO_OUTPUT_A(24),
+	FUNCTION_DESC_GPIO_OUTPUT_A(25),
+
+	FUNCTION_DESC_GPIO_INPUT_B(0),
+	FUNCTION_DESC_GPIO_INPUT_B(1),
+	FUNCTION_DESC_GPIO_INPUT_B(2),
+	FUNCTION_DESC_GPIO_INPUT_B(3),
+	FUNCTION_DESC_GPIO_INPUT_B(4),
+	FUNCTION_DESC_GPIO_INPUT_B(5),
+	FUNCTION_DESC_GPIO_INPUT_B(6),
+	FUNCTION_DESC_GPIO_INPUT_B(7),
+
+	FUNCTION_DESC_GPIO_INPUT_B(8),
+	FUNCTION_DESC_GPIO_INPUT_B(9),
+	FUNCTION_DESC_GPIO_INPUT_B(10),
+	FUNCTION_DESC_GPIO_INPUT_B(11),
+	FUNCTION_DESC_GPIO_INPUT_B(12),
+	FUNCTION_DESC_GPIO_INPUT_B(13),
+	FUNCTION_DESC_GPIO_INPUT_B(14),
+	FUNCTION_DESC_GPIO_INPUT_B(15),
+
+	FUNCTION_DESC_GPIO_INPUT_B(16),
+	FUNCTION_DESC_GPIO_INPUT_B(17),
+	FUNCTION_DESC_GPIO_INPUT_B(18),
+	FUNCTION_DESC_GPIO_INPUT_B(19),
+	FUNCTION_DESC_GPIO_INPUT_B(20),
+	FUNCTION_DESC_GPIO_INPUT_B(21),
+	FUNCTION_DESC_GPIO_INPUT_B(22),
+	FUNCTION_DESC_GPIO_INPUT_B(23),
+
+	FUNCTION_DESC_GPIO_INPUT_B(24),
+	FUNCTION_DESC_GPIO_INPUT_B(25),
+
+	FUNCTION_DESC_GPIO_OUTPUT_B(0),
+	FUNCTION_DESC_GPIO_OUTPUT_B(1),
+	FUNCTION_DESC_GPIO_OUTPUT_B(2),
+	FUNCTION_DESC_GPIO_OUTPUT_B(3),
+	FUNCTION_DESC_GPIO_OUTPUT_B(4),
+	FUNCTION_DESC_GPIO_OUTPUT_B(5),
+	FUNCTION_DESC_GPIO_OUTPUT_B(6),
+	FUNCTION_DESC_GPIO_OUTPUT_B(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_B(8),
+	FUNCTION_DESC_GPIO_OUTPUT_B(9),
+	FUNCTION_DESC_GPIO_OUTPUT_B(10),
+	FUNCTION_DESC_GPIO_OUTPUT_B(11),
+	FUNCTION_DESC_GPIO_OUTPUT_B(12),
+	FUNCTION_DESC_GPIO_OUTPUT_B(13),
+	FUNCTION_DESC_GPIO_OUTPUT_B(14),
+	FUNCTION_DESC_GPIO_OUTPUT_B(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_B(16),
+	FUNCTION_DESC_GPIO_OUTPUT_B(17),
+	FUNCTION_DESC_GPIO_OUTPUT_B(18),
+	FUNCTION_DESC_GPIO_OUTPUT_B(19),
+	FUNCTION_DESC_GPIO_OUTPUT_B(20),
+	FUNCTION_DESC_GPIO_OUTPUT_B(21),
+	FUNCTION_DESC_GPIO_OUTPUT_B(22),
+	FUNCTION_DESC_GPIO_OUTPUT_B(23),
+
+	FUNCTION_DESC_GPIO_OUTPUT_B(24),
+	FUNCTION_DESC_GPIO_OUTPUT_B(25),
+
+	FUNCTION_DESC_GPIO(),
+
+	FUNCTION_DESC(MAX96745_I2C),
+	FUNCTION_DESC(MAX96745_UART),
+};
+
+static struct serdes_chip_pinctrl_info max96745_pinctrl_info = {
+	.pins = max96745_pins_desc,
+	.num_pins = ARRAY_SIZE(max96745_pins_desc),
+	.groups = max96745_groups_desc,
+	.num_groups = ARRAY_SIZE(max96745_groups_desc),
+	.functions = max96745_functions_desc,
+	.num_functions = ARRAY_SIZE(max96745_functions_desc),
+};
+
+static bool max96745_bridge_link_locked(struct serdes *serdes)
+{
+	u32 val;
+
+	if (dm_gpio_is_valid(&serdes->lock_gpio)) {
+		val = dm_gpio_get_value(&serdes->lock_gpio);
+		SERDES_DBG_CHIP("serdes %s:val=%d\n", __func__, val);
+		return val;
+	}
+
+	if (serdes_reg_read(serdes, 0x002a, &val)) {
+		SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
+		return false;
+	}
+
+	if (!FIELD_GET(LOCKED, val)) {
+		SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
+		return false;
+	}
+
+	return true;
+}
+
+static bool max96745_bridge_detect(struct serdes *serdes)
+{
+	return max96745_bridge_link_locked(serdes);
+}
+
+static int max96745_bridge_enable(struct serdes *serdes)
+{
+	struct drm_display_mode *mode =
+		 &serdes->serdes_bridge->bridge->state->conn_state.mode;
+	u8 cxtp, tx_rate;
+	int ret;
+	unsigned int value;
+
+	ret = serdes_reg_read(serdes, 0x0011, &value);
+	if (ret < 0)
+		return ret;
+
+	cxtp = FIELD_GET(CXTP_A, value);
+
+	ret = serdes_reg_read(serdes, 0x0028, &value);
+	if (ret < 0)
+		return ret;
+
+	tx_rate = FIELD_GET(TX_RATE, value);
+
+	if (!cxtp && mode->clock > 95000 && tx_rate == 1) {
+		ret = serdes_set_bits(serdes, 0x0028, TX_RATE,
+				      FIELD_PREP(TX_RATE, 2));
+		if (ret < 0)
+			return ret;
+
+		ret = serdes_set_bits(serdes, 0x0029, RESET_ONESHOT,
+				      FIELD_PREP(RESET_ONESHOT, 1));
+		if (ret < 0)
+			return ret;
+
+		if (readx_poll_timeout(max96745_bridge_link_locked, serdes, ret,
+				       ret, 200000))
+			printf("%s: GMSL link not locked\n", __func__);
+	}
+
+	return ret;
+}
+
+static int max96745_bridge_disable(struct serdes *serdes)
+{
+	u8 cxtp, tx_rate;
+	int ret;
+	unsigned int value;
+
+	ret = serdes_reg_read(serdes, 0x0011, &value);
+	if (ret < 0)
+		return ret;
+
+	cxtp = FIELD_GET(CXTP_A, value);
+
+	ret = serdes_reg_read(serdes, 0x0028, &value);
+	if (ret < 0)
+		return ret;
+
+	tx_rate = FIELD_GET(TX_RATE, value);
+
+	if (!cxtp && tx_rate == 2) {
+		ret = serdes_set_bits(serdes, 0x0028, TX_RATE,
+				      FIELD_PREP(TX_RATE, 1));
+		if (ret < 0)
+			return ret;
+
+		ret = serdes_set_bits(serdes, 0x0029, RESET_ONESHOT,
+				      FIELD_PREP(RESET_ONESHOT, 1));
+		if (ret < 0)
+			return ret;
+
+		if (readx_poll_timeout(max96745_bridge_link_locked, serdes, ret,
+				       ret, 200000))
+			printf("%s: GMSL link not locked\n", __func__);
+	}
+
+	return ret;
+}
+
+static struct serdes_chip_bridge_ops max96745_bridge_ops = {
+	.detect = max96745_bridge_detect,
+	.enable = max96745_bridge_enable,
+	.disable = max96745_bridge_disable,
+};
+
+static int max96745_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *data = func->data;
+
+		ms = data->mdelay;
+		offset = pin->number;
+		if (offset > 32)
+			dev_err(serdes->dev, "%s offset=%d > 32\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+					__func__, serdes->dev->name,
+					data->gpio_tx_id, data->gpio_rx_id, offset);
+		if (!ms) {
+			serdes_set_bits(serdes,
+					GPIO_A_REG(offset),
+					GPIO_OUT_DIS,
+					FIELD_PREP(GPIO_OUT_DIS, data->gpio_out_dis));
+			if (data->gpio_tx_en_a || data->gpio_tx_en_b)
+				serdes_set_bits(serdes,
+						GPIO_B_REG(offset),
+						GPIO_TX_ID,
+						FIELD_PREP(GPIO_TX_ID, data->gpio_tx_id));
+			if (data->gpio_rx_en_a || data->gpio_rx_en_b)
+				serdes_set_bits(serdes,
+						GPIO_C_REG(offset),
+						GPIO_RX_ID,
+						FIELD_PREP(GPIO_RX_ID, data->gpio_rx_id));
+			serdes_set_bits(serdes,
+					GPIO_D_REG(offset),
+					GPIO_TX_EN_A | GPIO_TX_EN_B | GPIO_IO_RX_EN |
+					GPIO_RX_EN_A | GPIO_RX_EN_B,
+					FIELD_PREP(GPIO_TX_EN_A, data->gpio_tx_en_a) |
+					FIELD_PREP(GPIO_TX_EN_B, data->gpio_tx_en_b) |
+					FIELD_PREP(GPIO_RX_EN_A, data->gpio_rx_en_a) |
+					FIELD_PREP(GPIO_RX_EN_B, data->gpio_rx_en_b) |
+					FIELD_PREP(GPIO_IO_RX_EN, data->gpio_io_rx_en));
+		} else {
+			mdelay(ms);
+			SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+		}
+	}
+
+	return 0;
+}
+
+static int max96745_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p, num=%d\n",
+			__func__, serdes->chip_data->name, func->name,
+			func->data, grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 32)
+				dev_err(serdes->dev, "%s offset=%d > 32\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+						__func__, serdes->dev->name,
+						fdata->gpio_tx_id,
+						fdata->gpio_rx_id, offset);
+
+			serdes_set_bits(serdes,
+					GPIO_A_REG(offset),
+					GPIO_OUT_DIS,
+					FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis));
+			if (fdata->gpio_tx_en_a || fdata->gpio_tx_en_b)
+				serdes_set_bits(serdes,
+						GPIO_B_REG(offset),
+						GPIO_TX_ID,
+						FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+			if (fdata->gpio_rx_en_a || fdata->gpio_rx_en_b)
+				serdes_set_bits(serdes,
+						GPIO_C_REG(offset),
+						GPIO_RX_ID,
+						FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+			serdes_set_bits(serdes,
+					GPIO_D_REG(offset),
+					GPIO_TX_EN_A | GPIO_TX_EN_B | GPIO_IO_RX_EN |
+					GPIO_RX_EN_A | GPIO_RX_EN_B,
+					FIELD_PREP(GPIO_TX_EN_A, fdata->gpio_tx_en_a) |
+					FIELD_PREP(GPIO_TX_EN_B, fdata->gpio_tx_en_b) |
+					FIELD_PREP(GPIO_RX_EN_A, fdata->gpio_rx_en_a) |
+					FIELD_PREP(GPIO_RX_EN_B, fdata->gpio_rx_en_b) |
+					FIELD_PREP(GPIO_IO_RX_EN, fdata->gpio_io_rx_en));
+		}
+	}
+
+	return 0;
+}
+
+static int max96745_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param,
+				       unsigned int argument)
+{
+	u8 res_cfg;
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 0));
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 1));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 2));
+		break;
+	case PIN_CONFIG_OUTPUT:
+			serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+					GPIO_OUT_DIS | GPIO_OUT,
+					FIELD_PREP(GPIO_OUT_DIS, 0) |
+					FIELD_PREP(GPIO_OUT, argument));
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops max96745_pinctrl_ops = {
+	.pinconf_set = max96745_pinctrl_config_set,
+	.pinmux_set = max96745_pinctrl_set_pin_mux,
+	.pinmux_group_set = max96745_pinctrl_set_grp_mux,
+};
+
+static int max96745_gpio_direction_input(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96745_gpio_direction_output(struct serdes *serdes, int gpio, int value)
+{
+	return 0;
+}
+
+static int max96745_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96745_gpio_set_level(struct serdes *serdes, int gpio, int value)
+{
+	return 0;
+}
+
+static int max96745_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int max96745_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops max96745_gpio_ops = {
+	.direction_input = max96745_gpio_direction_input,
+	.direction_output = max96745_gpio_direction_output,
+	.get_level = max96745_gpio_get_level,
+	.set_level = max96745_gpio_set_level,
+	.set_config = max96745_gpio_set_config,
+	.to_irq = max96745_gpio_to_irq,
+};
+
+static int max96745_select(struct serdes *serdes, int chan)
+{
+	/*0076 for linkA and 0086 for linkB*/
+	if (chan == DUAL_LINK) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		SERDES_DBG_CHIP("%s: enable %s remote i2c of linkA/linkB\n",
+				__func__,
+				serdes->chip_data->name);
+	} else if (chan == LINKA) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		SERDES_DBG_CHIP("%s: only enable %s remote i2c of linkA\n",
+				__func__,
+				serdes->chip_data->name);
+	} else if (chan == LINKB) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		SERDES_DBG_CHIP("%s: only enable %s remote i2c of linkB\n",
+				__func__,
+				serdes->chip_data->name);
+	} else if (chan == SPLITTER_MODE) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		SERDES_DBG_CHIP("%s: enable %s remote i2c of linkA/B\n",
+				__func__,
+				serdes->chip_data->name);
+	}
+
+	return 0;
+}
+
+static int max96745_deselect(struct serdes *serdes, int chan)
+{
+	if (chan == DUAL_LINK) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		SERDES_DBG_CHIP("%s: disable %s remote i2c of linkA/B\n",
+				__func__,
+				serdes->chip_data->name);
+	} else if (chan == LINKA) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		SERDES_DBG_CHIP("%s: only disable %s remote i2c of linkA\n",
+				__func__,
+				serdes->chip_data->name);
+	} else if (chan == LINKB) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 0));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		SERDES_DBG_CHIP("%s: only disable %s remote i2c of linkB\n",
+				__func__,
+				serdes->chip_data->name);
+	} else if (chan == SPLITTER_MODE) {
+		serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
+				FIELD_PREP(DIS_REM_CC, 1));
+		SERDES_DBG_CHIP("%s: disable %s remote i2c of linkA/B\n",
+				__func__,
+				serdes->chip_data->name);
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_split_ops max96745_split_ops = {
+	.select = max96745_select,
+	.deselect = max96745_deselect,
+};
+
+struct serdes_chip_data serdes_max96745_data = {
+	.name		= "max96745",
+	.serdes_type	= TYPE_SER,
+	.serdes_id	= MAXIM_ID_MAX96745,
+	.connector_type	= DRM_MODE_CONNECTOR_eDP,
+	.pinctrl_info	= &max96745_pinctrl_info,
+	.bridge_ops	= &max96745_bridge_ops,
+	.pinctrl_ops	= &max96745_pinctrl_ops,
+	.gpio_ops	= &max96745_gpio_ops,
+	.split_ops	= &max96745_split_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_max96745_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96745.h b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96745.h
new file mode 100644
index 0000000000..5d17fe50c0
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96745.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * maxim-max96745.h -- register define for max96745 chip
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_MAXIM_MAX96745_H__
+#define __MFD_SERDES_MAXIM_MAX96745_H__
+
+#include <linux/bitfield.h>
+
+#define GPIO_A_REG(gpio)	(0x0200 + ((gpio) * 8))
+#define GPIO_B_REG(gpio)	(0x0201 + ((gpio) * 8))
+#define GPIO_C_REG(gpio)	(0x0202 + ((gpio) * 8))
+#define GPIO_D_REG(gpio)	(0x0203 + ((gpio) * 8))
+
+/* 0005h */
+#define PU_LF3			BIT(3)
+#define PU_LF2			BIT(2)
+#define PU_LF1			BIT(1)
+#define PU_LF0			BIT(0)
+
+/* 0010h */
+#define RESET_ALL		BIT(7)
+#define SLEEP			BIT(3)
+
+/* 0011h */
+#define CXTP_B			BIT(2)
+#define CXTP_A			BIT(0)
+
+/* 0013h */
+#define LOCKED			BIT(3)
+#define ERROR			BIT(2)
+
+/* 0026h */
+#define LF_0			GENMASK(2, 0)
+#define LF_1			GENMASK(6, 4)
+
+/* 0027h */
+#define LF_2			GENMASK(2, 0)
+#define LF_3			GENMASK(6, 4)
+
+/* 0028h, 0032h */
+#define LINK_EN			BIT(7)
+#define TX_RATE			GENMASK(3, 2)
+
+/* 0029h, 0033h */
+#define RESET_LINK		BIT(0)
+#define RESET_ONESHOT		BIT(1)
+
+/* 002Ah, 0034h */
+#define LINK_LOCKED		BIT(0)
+
+/* 0076h, 0086h */
+#define DIS_REM_CC		BIT(7)
+
+/* 0100h */
+#define VID_LINK_SEL		GENMASK(2, 1)
+#define VID_TX_EN		BIT(0)
+
+/* 0101h */
+#define BPP			GENMASK(5, 0)
+
+/* 0102h */
+#define PCLKDET_A		BIT(7)
+#define DRIFT_ERR_A		BIT(6)
+#define OVERFLOW_A		BIT(5)
+#define FIFO_WARN_A		BIT(4)
+#define LIM_HEART		BIT(2)
+
+/* 0107h */
+#define VID_TX_ACTIVE_B		BIT(7)
+#define VID_TX_ACTIVE_A		BIT(6)
+
+/* 0108h */
+#define PCLKDET_B		BIT(7)
+#define DRIFT_ERR_B		BIT(6)
+#define OVERFLOW_B		BIT(5)
+#define FIFO_WARN_B		BIT(4)
+
+/* 0200h */
+#define RES_CFG			BIT(7)
+#define TX_COM_EN		BIT(5)
+#define GPIO_OUT		BIT(4)
+#define GPIO_IN			BIT(3)
+#define GPIO_OUT_DIS		BIT(0)
+
+/* 0201h */
+#define PULL_UPDN_SEL		GENMASK(7, 6)
+#define OUT_TYPE		BIT(5)
+#define GPIO_TX_ID		GENMASK(4, 0)
+
+/* 0202h */
+#define OVR_RES_CFG		BIT(7)
+#define IO_EDGE_RATE		GENMASK(6, 5)
+#define GPIO_RX_ID		GENMASK(4, 0)
+
+/* 0203h */
+#define GPIO_IO_RX_EN		BIT(5)
+#define GPIO_OUT_LGC		BIT(4)
+#define GPIO_RX_EN_B		BIT(3)
+#define GPIO_TX_EN_B		BIT(2)
+#define GPIO_RX_EN_A		BIT(1)
+#define GPIO_TX_EN_A		BIT(0)
+
+/* 0750h */
+#define FRCZEROPAD		GENMASK(7, 6)
+#define FRCZPEN			BIT(5)
+#define FRCSDGAIN		BIT(4)
+#define FRCSDEN			BIT(3)
+#define FRCGAIN			GENMASK(2, 1)
+#define FRCEN			BIT(0)
+
+/* 0751h */
+#define FRCDATAWIDTH		BIT(3)
+#define FRCASYNCEN		BIT(2)
+#define FRCHSPOL		BIT(1)
+#define FRCVSPOL		BIT(0)
+
+/* 0752h */
+#define FRCDCMODE		GENMASK(1, 0)
+
+/* 641Ah */
+#define DPRX_TRAIN_STATE	GENMASK(7, 4)
+
+/* 7000h */
+#define LINK_ENABLE		BIT(0)
+
+/* 7070h */
+#define MAX_LANE_COUNT		GENMASK(7, 0)
+
+/* 7074h */
+#define MAX_LINK_RATE		GENMASK(7, 0)
+
+enum link_mode {
+	DUAL_LINK,
+	LINKA,
+	LINKB,
+	SPLITTER_MODE,
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96752.c b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96752.c
new file mode 100644
index 0000000000..7d04c87ad9
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96752.c
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * maxim-max96752.c  --  I2C register interface access for max96752 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+#include "../core.h"
+#include "maxim-max96752.h"
+
+struct config_desc {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+struct serdes_group_data {
+	const struct config_desc *configs;
+	int num_configs;
+};
+
+static int MAX96752_GPIO0_pins[] = {0};
+static int MAX96752_GPIO1_pins[] = {1};
+static int MAX96752_GPIO2_pins[] = {2};
+static int MAX96752_GPIO3_pins[] = {3};
+static int MAX96752_GPIO4_pins[] = {4};
+static int MAX96752_GPIO5_pins[] = {5};
+static int MAX96752_GPIO6_pins[] = {6};
+static int MAX96752_GPIO7_pins[] = {7};
+
+static int MAX96752_GPIO8_pins[] = {8};
+static int MAX96752_GPIO9_pins[] = {9};
+static int MAX96752_GPIO10_pins[] = {10};
+static int MAX96752_GPIO11_pins[] = {11};
+static int MAX96752_GPIO12_pins[] = {12};
+static int MAX96752_GPIO13_pins[] = {13};
+static int MAX96752_GPIO14_pins[] = {14};
+static int MAX96752_GPIO15_pins[] = {15};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+struct serdes_function_data {
+	u8 gpio_out_dis:1;
+	u8 gpio_tx_en:1;
+	u8 gpio_rx_en:1;
+	u8 gpio_in_level:1;
+	u8 gpio_out_level:1;
+	u8 gpio_tx_id;
+	u8 gpio_rx_id;
+	u16 mdelay;
+};
+
+static const char *serdes_gpio_groups[] = {
+	"MAX96752_GPIO0", "MAX96752_GPIO1", "MAX96752_GPIO2", "MAX96752_GPIO3",
+	"MAX96752_GPIO4", "MAX96752_GPIO5", "MAX96752_GPIO6", "MAX96752_GPIO7",
+
+	"MAX96752_GPIO8", "MAX96752_GPIO9", "MAX96752_GPIO10", "MAX96752_GPIO11",
+	"MAX96752_GPIO12", "MAX96752_GPIO13", "MAX96752_GPIO14", "MAX96752_GPIO15",
+};
+
+#define FUNCTION_DESC_GPIO_INPUT_BYPASS(id) \
+{ \
+	.name = "SER_TO_DES_RXID"#id, \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 1, .gpio_rx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_BYPASS(id) \
+{ \
+	.name = "DES_TXID"#id"_TO_SER", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 1, .gpio_tx_en = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_LOW(id) \
+{ \
+	.name = "DES_TXID"#id"_OUTPUT_LOW", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 0, .gpio_tx_en = 0, \
+		  .gpio_rx_en = 0, .gpio_out_level = 0, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_HIGH(id) \
+{ \
+	.name = "DES_TXID"#id"_OUTPUT_HIGH", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 0, .gpio_tx_en = 0, \
+		  .gpio_rx_en = 0, .gpio_out_level = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DES_DELAY_MS(ms) \
+{ \
+	.name = "DELAY_"#ms"MS", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .mdelay = ms, } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc max96752_pins_desc[] = {
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO0, "MAX96752_GPIO0"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO1, "MAX96752_GPIO1"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO2, "MAX96752_GPIO2"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO3, "MAX96752_GPIO3"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO4, "MAX96752_GPIO4"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO5, "MAX96752_GPIO5"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO6, "MAX96752_GPIO6"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO7, "MAX96752_GPIO7"),
+
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO8, "MAX96752_GPIO8"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO9, "MAX96752_GPIO9"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO10, "MAX96752_GPIO10"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO11, "MAX96752_GPIO11"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO12, "MAX96752_GPIO12"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO13, "MAX96752_GPIO13"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO14, "MAX96752_GPIO14"),
+	PINCTRL_PIN(MAXIM_MAX96752_GPIO15, "MAX96752_GPIO15"),
+};
+
+static struct group_desc max96752_groups_desc[] = {
+	GROUP_DESC(MAX96752_GPIO0),
+	GROUP_DESC(MAX96752_GPIO1),
+	GROUP_DESC(MAX96752_GPIO2),
+	GROUP_DESC(MAX96752_GPIO3),
+	GROUP_DESC(MAX96752_GPIO4),
+	GROUP_DESC(MAX96752_GPIO5),
+	GROUP_DESC(MAX96752_GPIO6),
+	GROUP_DESC(MAX96752_GPIO7),
+
+	GROUP_DESC(MAX96752_GPIO8),
+	GROUP_DESC(MAX96752_GPIO9),
+	GROUP_DESC(MAX96752_GPIO10),
+	GROUP_DESC(MAX96752_GPIO11),
+	GROUP_DESC(MAX96752_GPIO12),
+	GROUP_DESC(MAX96752_GPIO13),
+	GROUP_DESC(MAX96752_GPIO14),
+	GROUP_DESC(MAX96752_GPIO15),
+};
+
+static struct function_desc max96752_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(0),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(1),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(2),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(3),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(4),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(5),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(6),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(7),
+
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(8),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(9),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(10),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(11),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(12),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(13),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(14),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(0),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(1),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(2),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(3),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(4),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(5),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(6),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(8),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(9),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(10),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(11),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(12),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(13),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(14),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(0),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(1),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(2),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(3),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(4),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(5),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(6),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(8),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(9),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(10),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(11),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(12),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(13),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(14),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(0),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(1),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(2),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(3),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(4),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(5),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(6),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(8),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(9),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(10),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(11),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(12),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(13),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(14),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(15),
+
+	FUNCTION_DES_DELAY_MS(10),
+	FUNCTION_DES_DELAY_MS(50),
+	FUNCTION_DES_DELAY_MS(100),
+	FUNCTION_DES_DELAY_MS(200),
+	FUNCTION_DES_DELAY_MS(500),
+};
+
+static struct serdes_chip_pinctrl_info max96752_pinctrl_info = {
+	.pins = max96752_pins_desc,
+	.num_pins = ARRAY_SIZE(max96752_pins_desc),
+	.groups = max96752_groups_desc,
+	.num_groups = ARRAY_SIZE(max96752_groups_desc),
+	.functions = max96752_functions_desc,
+	.num_functions = ARRAY_SIZE(max96752_functions_desc),
+};
+
+static int max96752_panel_prepare(struct serdes *serdes)
+{
+	return 0;
+}
+
+static int max96752_panel_unprepare(struct serdes *serdes)
+{
+	//serdes_reg_write(serdes, 0x0215, 0x80);	/* lcd_en */
+
+	return 0;
+}
+
+static int max96752_panel_enable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static int max96752_panel_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static int max96752_panel_backlight_enable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static int max96752_panel_backlight_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static struct serdes_chip_panel_ops max96752_panel_ops = {
+	.prepare	= max96752_panel_prepare,
+	.unprepare	= max96752_panel_unprepare,
+	.enable		= max96752_panel_enable,
+	.disable	= max96752_panel_disable,
+	.backlight_enable	= max96752_panel_backlight_enable,
+	.backlight_disable	= max96752_panel_backlight_disable,
+};
+
+static int max96752_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		offset = pin->number;
+		if (offset > 32)
+			dev_err(serdes->dev, "%s offset=%d > 32\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+					__func__, serdes->dev->name,
+					fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+		if (!ms) {
+			serdes_set_bits(serdes, GPIO_A_REG(offset),
+					GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN | GPIO_OUT,
+					FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+					FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+					FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en) |
+					FIELD_PREP(GPIO_OUT, fdata->gpio_out_level));
+			if (fdata->gpio_tx_en)
+				serdes_set_bits(serdes,
+						GPIO_B_REG(offset),
+						GPIO_TX_ID,
+						FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+			if (fdata->gpio_rx_en)
+				serdes_set_bits(serdes,
+						GPIO_C_REG(offset),
+						GPIO_RX_ID,
+						FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+		} else {
+			mdelay(ms);
+			SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+		}
+	}
+
+	return 0;
+}
+
+static int max96752_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p, num=%d\n",
+			__func__, serdes->chip_data->name, func->name,
+			func->data, grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 32)
+				dev_err(serdes->dev, "%s offset=%d > 32\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+						__func__, serdes->dev->name,
+						fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+			if (!ms) {
+				serdes_set_bits(serdes, GPIO_A_REG(offset),
+						GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN | GPIO_OUT,
+						FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+						FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+						FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en) |
+						FIELD_PREP(GPIO_OUT, fdata->gpio_out_level));
+				if (fdata->gpio_tx_en)
+					serdes_set_bits(serdes,
+							GPIO_B_REG(offset),
+							GPIO_TX_ID,
+							FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+				if (fdata->gpio_rx_en)
+					serdes_set_bits(serdes,
+							GPIO_C_REG(offset),
+							GPIO_RX_ID,
+							FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+			} else {
+				mdelay(ms);
+				SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+			}
+		}
+	}
+
+	if (grp->data) {
+		struct serdes_group_data *gdata = grp->data;
+
+		for (i = 0; i < gdata->num_configs; i++) {
+			const struct config_desc *config = &gdata->configs[i];
+
+			serdes_set_bits(serdes, config->reg,
+					config->mask, config->val);
+		}
+	}
+
+	return 0;
+}
+
+static int max96752_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param,
+				       unsigned int argument)
+{
+	u8 res_cfg;
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 0));
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 1));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 2));
+		break;
+	case PIN_CONFIG_OUTPUT:
+			serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+					GPIO_OUT_DIS | GPIO_OUT,
+					FIELD_PREP(GPIO_OUT_DIS, 0) |
+					FIELD_PREP(GPIO_OUT, argument));
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops max96752_pinctrl_ops = {
+	.pinconf_set = max96752_pinctrl_config_set,
+	.pinmux_set = max96752_pinctrl_set_pin_mux,
+	.pinmux_group_set = max96752_pinctrl_set_grp_mux,
+};
+
+static int max96752_gpio_direction_input(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96752_gpio_direction_output(struct serdes *serdes,
+					  int gpio, int value)
+{
+	return 0;
+}
+
+static int max96752_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96752_gpio_set_level(struct serdes *serdes, int gpio, int value)
+{
+	return 0;
+}
+
+static int max96752_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int max96752_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops max96752_gpio_ops = {
+	.direction_input = max96752_gpio_direction_input,
+	.direction_output = max96752_gpio_direction_output,
+	.get_level = max96752_gpio_get_level,
+	.set_level = max96752_gpio_set_level,
+	.set_config = max96752_gpio_set_config,
+	.to_irq = max96752_gpio_to_irq,
+};
+
+static int max96752_set_i2c_addr(struct serdes *serdes, int address, int link)
+{
+	int ret;
+
+	if (link == LINKA) {
+		/* TX_SRC_ID[1] = 0 */
+		ret = serdes_reg_write(serdes, 0x73, 0x31);
+		/* Receive packets with this stream ID = 0 */
+		ret = serdes_reg_write(serdes, 0x50, 0x00);
+		ret = serdes_reg_write(serdes, 0x00, address << 1);
+	} else if (link == LINKB) {
+		/* TX_SRC_ID[1] = 1 */
+		ret = serdes_reg_write(serdes, 0x73, 0x32);
+		/* Receive packets with this stream ID = 1 */
+		ret = serdes_reg_write(serdes, 0x50, 0x01);
+		ret = serdes_reg_write(serdes, 0x00, address << 1);
+	} else {
+		dev_info(serdes->dev, "link %d is error\n", link);
+		ret = -1;
+	}
+
+	SERDES_DBG_CHIP("%s: set serdes chip %s i2c 7bit address to 0x%x\n", __func__,
+			serdes->chip_data->name, address);
+
+	return ret;
+}
+
+static struct serdes_chip_split_ops max96752_split_ops = {
+	.set_i2c_addr = max96752_set_i2c_addr,
+};
+
+struct serdes_chip_data serdes_max96752_data = {
+	.name		= "max96752",
+	.serdes_type	= TYPE_DES,
+	.serdes_id	= MAXIM_ID_MAX96752,
+	.connector_type	= DRM_MODE_CONNECTOR_LVDS,
+	.pinctrl_info	= &max96752_pinctrl_info,
+	.panel_ops	= &max96752_panel_ops,
+	.pinctrl_ops	= &max96752_pinctrl_ops,
+	.split_ops	= &max96752_split_ops,
+	.gpio_ops	= &max96752_gpio_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_max96752_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96752.h b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96752.h
new file mode 100644
index 0000000000..5ff34f2c79
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96752.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * maxim-max96752.h -- register define for max96752 chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_MAXIM_MAX96752_H__
+#define __MFD_SERDES_MAXIM_MAX96752_H__
+
+#include <linux/bitfield.h>
+
+#define GPIO_A_REG(gpio)	(0x0200 + ((gpio) * 3))
+#define GPIO_B_REG(gpio)	(0x0201 + ((gpio) * 3))
+#define GPIO_C_REG(gpio)	(0x0202 + ((gpio) * 3))
+
+/* 0200h */
+#define RES_CFG			BIT(7)
+#define RSVD			BIT(6)
+#define TX_COMP_EN		BIT(5)
+#define GPIO_OUT		BIT(4)
+#define GPIO_IN			BIT(3)
+#define GPIO_RX_EN		BIT(2)
+#define GPIO_TX_EN		BIT(1)
+#define GPIO_OUT_DIS		BIT(0)
+
+/* 0201h */
+#define PULL_UPDN_SEL		GENMASK(7, 6)
+#define OUT_TYPE		BIT(5)
+#define GPIO_TX_ID		GENMASK(4, 0)
+
+/* 0202h */
+#define OVR_RES_CFG		BIT(7)
+#define GPIO_RX_ID		GENMASK(4, 0)
+
+enum link_mode {
+	DUAL_LINK,
+	LINKA,
+	LINKB,
+	SPLITTER_MODE,
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96755.c b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96755.c
new file mode 100644
index 0000000000..2fa63d9b3b
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96755.c
@@ -0,0 +1,709 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * maxim-max96755.c  --  I2C register interface access for max96755 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+#include "maxim-max96755.h"
+
+struct serdes_function_data {
+	u8 gpio_out_dis:1;
+	u8 gpio_tx_en:1;
+	u8 gpio_rx_en:1;
+	u8 gpio_tx_id;
+	u8 gpio_rx_id;
+	u16 mdelay;
+};
+
+struct config_desc {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+struct serdes_group_data {
+	const struct config_desc *configs;
+	int num_configs;
+};
+
+static int MAX96755_MFP0_pins[] = {0};
+static int MAX96755_MFP1_pins[] = {1};
+static int MAX96755_MFP2_pins[] = {2};
+static int MAX96755_MFP3_pins[] = {3};
+static int MAX96755_MFP4_pins[] = {4};
+static int MAX96755_MFP5_pins[] = {5};
+static int MAX96755_MFP6_pins[] = {6};
+static int MAX96755_MFP7_pins[] = {7};
+
+static int MAX96755_MFP8_pins[] = {8};
+static int MAX96755_MFP9_pins[] = {9};
+static int MAX96755_MFP10_pins[] = {10};
+static int MAX96755_MFP11_pins[] = {11};
+static int MAX96755_MFP12_pins[] = {12};
+static int MAX96755_MFP13_pins[] = {13};
+static int MAX96755_MFP14_pins[] = {14};
+static int MAX96755_MFP15_pins[] = {15};
+
+static int MAX96755_MFP16_pins[] = {16};
+static int MAX96755_MFP17_pins[] = {17};
+static int MAX96755_MFP18_pins[] = {18};
+static int MAX96755_MFP19_pins[] = {19};
+static int MAX96755_MFP20_pins[] = {20};
+static int MAX96755_I2C_pins[] = {19, 20};
+static int MAX96755_UART_pins[] = {19, 20};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+#define GROUP_DESC_CONFIG(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+	.data = (void *)(const struct serdes_group_data []) { \
+		{ \
+			.configs = nm ## _configs, \
+			.num_configs = ARRAY_SIZE(nm ## _configs), \
+		} \
+	}, \
+}
+
+static const struct config_desc MAX96755_MFP0_configs[] = {
+	{ 0x0005, LOCK_EN, 0 },
+	{ 0x0048, LOC_MS_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP1_configs[] = {
+	{ 0x0005, ERRB_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP4_configs[] = {
+	{ 0x070, SPI_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP5_configs[] = {
+	{ 0x006, RCLKEN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP7_configs[] = {
+	{ 0x0002, AUD_TX_EN_X, 0 },
+	{ 0x0002, AUD_TX_EN_Y, 0 }
+};
+
+static const struct config_desc MAX96755_MFP8_configs[] = {
+	{ 0x0002, AUD_TX_EN_X, 0 },
+	{ 0x0002, AUD_TX_EN_Y, 0 }
+};
+
+static const struct config_desc MAX96755_MFP9_configs[] = {
+	{ 0x0002, AUD_TX_EN_X, 0 },
+	{ 0x0002, AUD_TX_EN_Y, 0 }
+};
+
+static const struct config_desc MAX96755_MFP10_configs[] = {
+	{ 0x0001, IIC_2_EN, 0 },
+	{ 0x0003, UART_2_EN, 0 },
+	{ 0x0140, AUD_RX_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP11_configs[] = {
+	{ 0x0001, IIC_2_EN, 0 },
+	{ 0x0003, UART_2_EN, 0 },
+	{ 0x0140, AUD_RX_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP12_configs[] = {
+	{ 0x0140, AUD_RX_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP13_configs[] = {
+	{ 0x0005, PU_LF0, 0 },
+};
+
+static const struct config_desc MAX96755_MFP14_configs[] = {
+	{ 0x0005, PU_LF1, 0 },
+};
+
+static const struct config_desc MAX96755_MFP15_configs[] = {
+	{ 0x0005, PU_LF2, 0 },
+};
+
+static const struct config_desc MAX96755_MFP16_configs[] = {
+	{ 0x0005, PU_LF3, 0 },
+};
+
+static const struct config_desc MAX96755_MFP17_configs[] = {
+	{ 0x0001, IIC_1_EN, 0 },
+	{ 0x0003, UART_1_EN, 0 },
+};
+
+static const struct config_desc MAX96755_MFP18_configs[] = {
+	{ 0x0001, IIC_1_EN, 0 },
+	{ 0x0003, UART_1_EN, 0 },
+};
+
+static const char *serdes_gpio_groups[] = {
+	"MAX96755_MFP0", "MAX96755_MFP1", "MAX96755_MFP2", "MAX96755_MFP3",
+	"MAX96755_MFP4", "MAX96755_MFP5", "MAX96755_MFP6", "MAX96755_MFP7",
+
+	"MAX96755_MFP8", "MAX96755_MFP9", "MAX96755_MFP10", "MAX96755_MFP11",
+	"MAX96755_MFP12", "MAX96755_MFP13", "MAX96755_MFP14", "MAX96755_MFP15",
+
+	"MAX96755_MFP16", "MAX96755_MFP17", "MAX96755_MFP18", "MAX96755_MFP19",
+	"MAX96755_MFP20",
+};
+
+static const char *MAX96755_I2C_groups[] = { "MAX96755_I2C" };
+static const char *MAX96755_UART_groups[] = { "MAX96755_UART" };
+
+#define FUNCTION_DESC(nm) \
+{ \
+	.name = #nm, \
+	.group_names = nm##_groups, \
+	.num_group_names = ARRAY_SIZE(nm##_groups), \
+} \
+
+#define FUNCTION_DESC_GPIO_INPUT(id) \
+{ \
+	.name = "DES_RXID"#id"_TO_SER", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 0, .gpio_rx_en = 1, .gpio_rx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT(id) \
+{ \
+	.name = "SER_TXID"#id"_TO_DES", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 1, .gpio_tx_en = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc max96755_pins_desc[] = {
+	PINCTRL_PIN(MAXIM_MAX96755_MFP0, "MAX96755_MFP0"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP1, "MAX96755_MFP1"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP2, "MAX96755_MFP2"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP3, "MAX96755_MFP3"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP4, "MAX96755_MFP4"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP5, "MAX96755_MFP5"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP6, "MAX96755_MFP6"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP7, "MAX96755_MFP7"),
+
+	PINCTRL_PIN(MAXIM_MAX96755_MFP8, "MAX96755_MFP8"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP9, "MAX96755_MFP9"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP10, "MAX96755_MFP10"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP11, "MAX96755_MFP11"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP12, "MAX96755_MFP12"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP13, "MAX96755_MFP13"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP14, "MAX96755_MFP14"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP15, "MAX96755_MFP15"),
+
+	PINCTRL_PIN(MAXIM_MAX96755_MFP16, "MAX96755_MFP16"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP17, "MAX96755_MFP17"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP18, "MAX96755_MFP18"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP19, "MAX96755_MFP19"),
+	PINCTRL_PIN(MAXIM_MAX96755_MFP20, "MAX96755_MFP20"),
+};
+
+static struct group_desc max96755_groups_desc[] = {
+	GROUP_DESC_CONFIG(MAX96755_MFP0),
+	GROUP_DESC_CONFIG(MAX96755_MFP1),
+	GROUP_DESC(MAX96755_MFP2),
+	GROUP_DESC(MAX96755_MFP3),
+	GROUP_DESC_CONFIG(MAX96755_MFP4),
+	GROUP_DESC_CONFIG(MAX96755_MFP5),
+	GROUP_DESC(MAX96755_MFP6),
+	GROUP_DESC_CONFIG(MAX96755_MFP7),
+
+	GROUP_DESC_CONFIG(MAX96755_MFP8),
+	GROUP_DESC_CONFIG(MAX96755_MFP9),
+	GROUP_DESC_CONFIG(MAX96755_MFP10),
+	GROUP_DESC_CONFIG(MAX96755_MFP11),
+	GROUP_DESC_CONFIG(MAX96755_MFP12),
+	GROUP_DESC_CONFIG(MAX96755_MFP13),
+	GROUP_DESC_CONFIG(MAX96755_MFP14),
+	GROUP_DESC_CONFIG(MAX96755_MFP15),
+
+	GROUP_DESC_CONFIG(MAX96755_MFP16),
+	GROUP_DESC_CONFIG(MAX96755_MFP17),
+	GROUP_DESC_CONFIG(MAX96755_MFP18),
+	GROUP_DESC(MAX96755_MFP19),
+	GROUP_DESC(MAX96755_MFP20),
+	GROUP_DESC(MAX96755_I2C),
+	GROUP_DESC(MAX96755_UART),
+};
+
+static struct function_desc max96755_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT(0),
+	FUNCTION_DESC_GPIO_INPUT(1),
+	FUNCTION_DESC_GPIO_INPUT(2),
+	FUNCTION_DESC_GPIO_INPUT(3),
+	FUNCTION_DESC_GPIO_INPUT(4),
+	FUNCTION_DESC_GPIO_INPUT(5),
+	FUNCTION_DESC_GPIO_INPUT(6),
+	FUNCTION_DESC_GPIO_INPUT(7),
+
+	FUNCTION_DESC_GPIO_INPUT(8),
+	FUNCTION_DESC_GPIO_INPUT(9),
+	FUNCTION_DESC_GPIO_INPUT(10),
+	FUNCTION_DESC_GPIO_INPUT(11),
+	FUNCTION_DESC_GPIO_INPUT(12),
+	FUNCTION_DESC_GPIO_INPUT(13),
+	FUNCTION_DESC_GPIO_INPUT(14),
+	FUNCTION_DESC_GPIO_INPUT(15),
+
+	FUNCTION_DESC_GPIO_INPUT(16),
+	FUNCTION_DESC_GPIO_INPUT(17),
+	FUNCTION_DESC_GPIO_INPUT(18),
+	FUNCTION_DESC_GPIO_INPUT(19),
+	FUNCTION_DESC_GPIO_INPUT(20),
+
+	FUNCTION_DESC_GPIO_OUTPUT(0),
+	FUNCTION_DESC_GPIO_OUTPUT(1),
+	FUNCTION_DESC_GPIO_OUTPUT(2),
+	FUNCTION_DESC_GPIO_OUTPUT(3),
+	FUNCTION_DESC_GPIO_OUTPUT(4),
+	FUNCTION_DESC_GPIO_OUTPUT(5),
+	FUNCTION_DESC_GPIO_OUTPUT(6),
+	FUNCTION_DESC_GPIO_OUTPUT(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT(8),
+	FUNCTION_DESC_GPIO_OUTPUT(9),
+	FUNCTION_DESC_GPIO_OUTPUT(10),
+	FUNCTION_DESC_GPIO_OUTPUT(11),
+	FUNCTION_DESC_GPIO_OUTPUT(12),
+	FUNCTION_DESC_GPIO_OUTPUT(13),
+	FUNCTION_DESC_GPIO_OUTPUT(14),
+	FUNCTION_DESC_GPIO_OUTPUT(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT(16),
+	FUNCTION_DESC_GPIO_OUTPUT(17),
+	FUNCTION_DESC_GPIO_OUTPUT(18),
+	FUNCTION_DESC_GPIO_OUTPUT(19),
+	FUNCTION_DESC_GPIO_OUTPUT(20),
+
+	FUNCTION_DESC(MAX96755_I2C),
+	FUNCTION_DESC(MAX96755_UART),
+};
+
+static struct serdes_chip_pinctrl_info max96755_pinctrl_info = {
+	.pins = max96755_pins_desc,
+	.num_pins = ARRAY_SIZE(max96755_pins_desc),
+	.groups = max96755_groups_desc,
+	.num_groups = ARRAY_SIZE(max96755_groups_desc),
+	.functions = max96755_functions_desc,
+	.num_functions = ARRAY_SIZE(max96755_functions_desc),
+};
+
+static bool max96755_bridge_link_locked(struct serdes *serdes)
+{
+	u32 val;
+
+	if (dm_gpio_is_valid(&serdes->lock_gpio)) {
+		val = dm_gpio_get_value(&serdes->lock_gpio);
+		SERDES_DBG_CHIP("serdes %s:val=%d\n", __func__, val);
+		return val;
+	}
+
+	if (serdes_reg_read(serdes, 0x0013, &val)) {
+		SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
+		return false;
+	}
+
+	if (!FIELD_GET(LOCKED, val)) {
+		SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
+		return false;
+	}
+
+	return true;
+}
+
+static bool max96755_bridge_detect(struct serdes *serdes)
+{
+	return max96755_bridge_link_locked(serdes);
+}
+
+static int max96755_bridge_enable(struct serdes *serdes)
+{
+	int ret = 0;
+
+	SERDES_DBG_CHIP("%s: serdes chip %s ret=%d\n",
+			__func__, serdes->chip_data->name, ret);
+	return ret;
+}
+
+static int max96755_bridge_disable(struct serdes *serdes)
+{
+	int ret = 0;
+
+	ret = serdes_set_bits(serdes, 0x0002, VID_TX_EN_X,
+			      FIELD_PREP(VID_TX_EN_X, 0));
+
+	return ret;
+}
+
+static struct serdes_chip_bridge_ops max96755_bridge_ops = {
+	.detect = max96755_bridge_detect,
+	.enable = max96755_bridge_enable,
+	.disable = max96755_bridge_disable,
+};
+
+static int max96755_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		offset = pin->number;
+		if (offset > 32)
+			dev_err(serdes->dev, "%s offset=%d > 32\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+					__func__, serdes->dev->name,
+					fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+		if (!ms) {
+			serdes_set_bits(serdes, GPIO_A_REG(offset),
+					GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN,
+					FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+					FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+					FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en));
+
+			if (fdata->gpio_tx_en)
+				serdes_set_bits(serdes,
+						GPIO_B_REG(offset),
+						GPIO_TX_ID,
+						FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+			if (fdata->gpio_rx_en)
+				serdes_set_bits(serdes,
+						GPIO_C_REG(offset),
+						GPIO_RX_ID,
+						FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+		} else {
+			mdelay(ms);
+			SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+		}
+	}
+
+	return 0;
+}
+
+static int max96755_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p, num=%d\n",
+			__func__, serdes->chip_data->name, func->name,
+			func->data, grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 32)
+				dev_err(serdes->dev, "%s offset=%d > 32\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+						__func__, serdes->dev->name,
+						fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+			if (!ms) {
+				serdes_set_bits(serdes, GPIO_A_REG(offset),
+						GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN,
+						FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+						FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+						FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en));
+				if (fdata->gpio_tx_en)
+					serdes_set_bits(serdes,
+							GPIO_B_REG(offset),
+							GPIO_TX_ID,
+							FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+				if (fdata->gpio_rx_en)
+					serdes_set_bits(serdes,
+							GPIO_C_REG(offset),
+							GPIO_RX_ID,
+							FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+			} else {
+				mdelay(ms);
+				SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+			}
+		}
+	}
+
+	if (grp->data) {
+		struct serdes_group_data *gdata = grp->data;
+
+		for (i = 0; i < gdata->num_configs; i++) {
+			const struct config_desc *config = &gdata->configs[i];
+			serdes_set_bits(serdes, config->reg,
+					config->mask, config->val);
+		}
+	}
+
+	return 0;
+}
+
+static int max96755_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param, unsigned int argument)
+{
+	u8 res_cfg;
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 0));
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 1));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 2));
+		break;
+	case PIN_CONFIG_OUTPUT:
+			serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+					GPIO_OUT_DIS | GPIO_OUT,
+					FIELD_PREP(GPIO_OUT_DIS, 0) |
+					FIELD_PREP(GPIO_OUT, argument));
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops max96755_pinctrl_ops = {
+	.pinconf_set = max96755_pinctrl_config_set,
+	.pinmux_set = max96755_pinctrl_set_pin_mux,
+	.pinmux_group_set = max96755_pinctrl_set_grp_mux,
+};
+
+static int max96755_gpio_direction_input(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96755_gpio_direction_output(struct serdes *serdes,
+					  int gpio, int value)
+{
+	return 0;
+}
+
+static int max96755_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96755_gpio_set_level(struct serdes *serdes, int gpio, int value)
+{
+	return 0;
+}
+
+static int max96755_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int max96755_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops max96755_gpio_ops = {
+	.direction_input = max96755_gpio_direction_input,
+	.direction_output = max96755_gpio_direction_output,
+	.get_level = max96755_gpio_get_level,
+	.set_level = max96755_gpio_set_level,
+	.set_config = max96755_gpio_set_config,
+	.to_irq = max96755_gpio_to_irq,
+};
+
+static int max96755_select(struct serdes *serdes, int chan)
+{
+	u32 link_cfg;
+	int ret = 0;
+
+	serdes_set_bits(serdes, 0x0001, DIS_REM_CC,
+			FIELD_PREP(DIS_REM_CC, 0));
+
+	serdes_reg_read(serdes, 0x0010, &link_cfg);
+	if ((link_cfg & LINK_CFG) == SPLITTER_MODE)
+		SERDES_DBG_CHIP("%s: serdes %s is split mode cfg=0x%x\n",
+				__func__,
+				serdes->chip_data->name, link_cfg);
+
+	if (chan == 0 && (link_cfg & LINK_CFG) != DUAL_LINK) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 1) |
+				      FIELD_PREP(LINK_EN_B, 1));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, DUAL_LINK));
+		SERDES_DBG_CHIP("%s: change to use dual link\n", __func__);
+	} else if (chan == 1 && (link_cfg & LINK_CFG) != LINKA) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 1) |
+				      FIELD_PREP(LINK_EN_B, 0));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, LINKA));
+		SERDES_DBG_CHIP("%s: change to use linkA\n", __func__);
+	} else if (chan == 2 && (link_cfg & LINK_CFG) != LINKB) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 0) |
+				      FIELD_PREP(LINK_EN_B, 1));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, LINKB));
+		SERDES_DBG_CHIP("%s: change to use linkB\n", __func__);
+	} else if (chan == 3 && (link_cfg & LINK_CFG) != SPLITTER_MODE) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 1) |
+				      FIELD_PREP(LINK_EN_B, 1));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, SPLITTER_MODE));
+		SERDES_DBG_CHIP("%s: change to use split mode\n", __func__);
+	}
+
+	return ret;
+}
+
+static int max96755_deselect(struct serdes *serdes, int chan)
+{
+	//serdes_set_bits(serdes, 0x0001, DIS_REM_CC,
+	//		   FIELD_PREP(DIS_REM_CC, 1));
+
+	return 0;
+}
+
+static struct serdes_chip_split_ops max96755_split_ops = {
+	.select = max96755_select,
+	.deselect = max96755_deselect,
+};
+
+struct serdes_chip_data serdes_max96755_data = {
+	.name		= "max96755",
+	.serdes_type	= TYPE_SER,
+	.serdes_id	= MAXIM_ID_MAX96755,
+	.connector_type	= DRM_MODE_CONNECTOR_DSI,
+	.pinctrl_info	= &max96755_pinctrl_info,
+	.bridge_ops	= &max96755_bridge_ops,
+	.pinctrl_ops	= &max96755_pinctrl_ops,
+	.gpio_ops	= &max96755_gpio_ops,
+	.split_ops	= &max96755_split_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_max96755_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96755.h b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96755.h
new file mode 100644
index 0000000000..af96a81dd2
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96755.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * maxim-max96755.h -- register define for max96755 chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_MAXIM_MAX96755_H__
+#define __MFD_SERDES_MAXIM_MAX96755_H__
+
+#include <linux/bitfield.h>
+
+#define GPIO_A_REG(gpio)	(0x02be + ((gpio) * 3))
+#define GPIO_B_REG(gpio)	(0x02bf + ((gpio) * 3))
+#define GPIO_C_REG(gpio)	(0x02c0 + ((gpio) * 3))
+
+/* 0000h */
+#define DEV_ADDR		GENMASK(7, 1)
+#define CFG_BLOCK		BIT(0)
+
+/* 0001h */
+#define IIC_2_EN		BIT(7)
+#define IIC_1_EN		BIT(6)
+#define DIS_REM_CC		BIT(4)
+#define TX_RATE			GENMASK(3, 2)
+
+/* 0002h */
+#define VID_TX_EN_U		BIT(7)
+#define VID_TX_EN_Z		BIT(6)
+#define VID_TX_EN_Y		BIT(5)
+#define VID_TX_EN_X		BIT(4)
+#define AUD_TX_EN_Y		BIT(3)
+#define AUD_TX_EN_X		BIT(2)
+
+/* 0003h */
+#define UART_2_EN		BIT(5)
+#define UART_1_EN		BIT(4)
+
+/* 0004h */
+#define GMSL2_B			BIT(7)
+#define GMSL2_A			BIT(6)
+#define LINK_EN_B		BIT(5)
+#define LINK_EN_A		BIT(4)
+#define AUD_TX_SRC_Y	BIT(1)
+#define AUD_TX_SRC_X	BIT(0)
+
+/* 0005h */
+#define LOCK_EN			BIT(7)
+#define ERRB_EN			BIT(6)
+#define PU_LF3			BIT(3)
+#define PU_LF2			BIT(2)
+#define PU_LF1			BIT(1)
+#define PU_LF0			BIT(0)
+
+/* 0006h */
+#define RCLKEN			BIT(5)
+
+/* 0010h */
+#define RESET_ALL		BIT(7)
+#define RESET_LINK		BIT(6)
+#define RESET_ONESHOT		BIT(5)
+#define AUTO_LINK		BIT(4)
+#define SLEEP			BIT(3)
+#define REG_ENABLE		BIT(2)
+#define LINK_CFG		GENMASK(1, 0)
+
+/* 0013h */
+#define LINK_MODE		GENMASK(5, 4)
+#define	LOCKED			BIT(3)
+
+/* 0026h */
+#define LF_1			GENMASK(6, 4)
+#define LF_0			GENMASK(2, 0)
+
+/* 0048h */
+#define REM_MS_EN		BIT(5)
+#define LOC_MS_EN		BIT(4)
+
+/* 0053h */
+#define TX_SPLIT_MASK_B		BIT(5)
+#define TX_SPLIT_MASK_A		BIT(4)
+#define TX_STR_SEL		GENMASK(1, 0)
+
+/* 0140h */
+#define AUD_RX_EN		BIT(0)
+
+/* 0170h */
+#define SPI_EN			BIT(0)
+
+/* 01e5h */
+#define PATGEN_MODE		GENMASK(1, 0)
+
+/* 02beh */
+#define RES_CFG			BIT(7)
+#define TX_PRIO			BIT(6)
+#define TX_COMP_EN		BIT(5)
+#define GPIO_OUT		BIT(4)
+#define GPIO_IN			BIT(3)
+#define GPIO_RX_EN		BIT(2)
+#define GPIO_TX_EN		BIT(1)
+#define GPIO_OUT_DIS		BIT(0)
+
+/* 02bfh */
+#define PULL_UPDN_SEL		GENMASK(7, 6)
+#define OUT_TYPE		BIT(5)
+#define GPIO_TX_ID		GENMASK(4, 0)
+
+/* 02c0h */
+#define OVR_RES_CFG		BIT(7)
+#define GPIO_RX_ID		GENMASK(4, 0)
+
+/* 0311h */
+#define START_PORTBU		BIT(7)
+#define START_PORTBZ		BIT(6)
+#define START_PORTBY		BIT(5)
+#define START_PORTBX		BIT(4)
+#define START_PORTAU		BIT(3)
+#define START_PORTAZ		BIT(2)
+#define START_PORTAY		BIT(1)
+#define START_PORTAX		BIT(0)
+
+/* 032ah */
+#define DV_LOCK			BIT(7)
+#define DV_SWP_AB		BIT(6)
+#define LINE_ALT		BIT(5)
+#define DV_CONV			BIT(2)
+#define DV_SPL			BIT(1)
+#define DV_EN			BIT(0)
+
+/* 0330h */
+#define PHY_CONFIG		GENMASK(2, 0)
+#define MIPI_RX_RESET		BIT(3)
+
+/* 0331h */
+#define NUM_LANES		GENMASK(1, 0)
+
+/* 0385h */
+#define DPI_HSYNC_WIDTH_L	GENMASK(7, 0)
+
+/* 0386h */
+#define DPI_VYSNC_WIDTH_L	GENMASK(7, 0)
+
+/* 0387h */
+#define	DPI_HSYNC_WIDTH_H	GENMASK(3, 0)
+#define DPI_VSYNC_WIDTH_H	GENMASK(7, 4)
+
+/* 03a4h */
+#define DPI_DE_SKEW_SEL		BIT(1)
+#define DPI_DESKEW_EN		BIT(0)
+
+/* 03a5h */
+#define DPI_VFP_L		GENMASK(7, 0)
+
+/* 03a6h */
+#define DPI_VFP_H		GENMASK(3, 0)
+#define DPI_VBP_L		GENMASK(7, 4)
+
+/* 03a7h */
+#define DPI_VBP_H		GENMASK(7, 0)
+
+/* 03a8h */
+#define DPI_VACT_L		GENMASK(7, 0)
+
+/* 03a9h */
+#define DPI_VACT_H		GENMASK(3, 0)
+
+/* 03aah */
+#define DPI_HFP_L		GENMASK(7, 0)
+
+/* 03abh */
+#define DPI_HFP_H		GENMASK(3, 0)
+#define DPI_HBP_L		GENMASK(7, 4)
+
+/* 03ach */
+#define DPI_HBP_H		GENMASK(7, 0)
+
+/* 03adh */
+#define DPI_HACT_L		GENMASK(7, 0)
+
+/* 03aeh */
+#define DPI_HACT_H		GENMASK(4, 0)
+
+/* 055dh */
+#define VS_DET			BIT(5)
+#define HS_DET			BIT(4)
+
+enum link_mode {
+	DUAL_LINK,
+	LINKA,
+	LINKB,
+	SPLITTER_MODE,
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96772.c b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96772.c
new file mode 100644
index 0000000000..aa24fc5b5e
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96772.c
@@ -0,0 +1,737 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * maxim-max96772.c  --  I2C register interface access for max96772 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+#include "maxim-max96772.h"
+
+struct config_desc {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+struct serdes_group_data {
+	const struct config_desc *configs;
+	int num_configs;
+};
+
+static int MAX96772_GPIO0_pins[] = {0};
+static int MAX96772_GPIO1_pins[] = {1};
+static int MAX96772_GPIO2_pins[] = {2};
+static int MAX96772_GPIO3_pins[] = {3};
+static int MAX96772_GPIO4_pins[] = {4};
+static int MAX96772_GPIO5_pins[] = {5};
+static int MAX96772_GPIO6_pins[] = {6};
+static int MAX96772_GPIO7_pins[] = {7};
+
+static int MAX96772_GPIO8_pins[] = {8};
+static int MAX96772_GPIO9_pins[] = {9};
+static int MAX96772_GPIO10_pins[] = {10};
+static int MAX96772_GPIO11_pins[] = {11};
+static int MAX96772_GPIO12_pins[] = {12};
+static int MAX96772_GPIO13_pins[] = {13};
+static int MAX96772_GPIO14_pins[] = {14};
+static int MAX96772_GPIO15_pins[] = {15};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+struct serdes_function_data {
+	u8 gpio_out_dis:1;
+	u8 gpio_tx_en:1;
+	u8 gpio_rx_en:1;
+	u8 gpio_in_level:1;
+	u8 gpio_out_level:1;
+	u8 gpio_tx_id;
+	u8 gpio_rx_id;
+	u16 mdelay;
+};
+
+static const char *serdes_gpio_groups[] = {
+	"MAX96772_GPIO0", "MAX96772_GPIO1", "MAX96772_GPIO2", "MAX96772_GPIO3",
+	"MAX96772_GPIO4", "MAX96772_GPIO5", "MAX96772_GPIO6", "MAX96772_GPIO7",
+
+	"MAX96772_GPIO8", "MAX96772_GPIO9", "MAX96772_GPIO10", "MAX96772_GPIO11",
+	"MAX96772_GPIO12", "MAX96772_GPIO13", "MAX96772_GPIO14", "MAX96772_GPIO15",
+};
+
+#define FUNCTION_DESC_GPIO_INPUT_BYPASS(id) \
+{ \
+	.name = "SER_TO_DES_RXID"#id, \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 1, .gpio_rx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_BYPASS(id) \
+{ \
+	.name = "DES_TXID"#id"_TO_SER", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 1, .gpio_tx_en = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_LOW(id) \
+{ \
+	.name = "DES_TXID"#id"_OUTPUT_LOW", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 0, .gpio_tx_en = 0, \
+		  .gpio_rx_en = 0, .gpio_out_level = 0, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_HIGH(id) \
+{ \
+	.name = "DES_TXID"#id"_OUTPUT_HIGH", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 0, .gpio_tx_en = 0, \
+		  .gpio_rx_en = 0, .gpio_out_level = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DES_DELAY_MS(ms) \
+{ \
+	.name = "DELAY_"#ms"MS", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .mdelay = ms, } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc max96772_pins_desc[] = {
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO0, "MAX96772_GPIO0"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO1, "MAX96772_GPIO1"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO2, "MAX96772_GPIO2"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO3, "MAX96772_GPIO3"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO4, "MAX96772_GPIO4"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO5, "MAX96772_GPIO5"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO6, "MAX96772_GPIO6"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO7, "MAX96772_GPIO7"),
+
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO8, "MAX96772_GPIO8"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO9, "MAX96772_GPIO9"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO10, "MAX96772_GPIO10"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO11, "MAX96772_GPIO11"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO12, "MAX96772_GPIO12"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO13, "MAX96772_GPIO13"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO14, "MAX96772_GPIO14"),
+	PINCTRL_PIN(MAXIM_MAX96772_GPIO15, "MAX96772_GPIO15"),
+};
+
+static struct group_desc max96772_groups_desc[] = {
+	GROUP_DESC(MAX96772_GPIO0),
+	GROUP_DESC(MAX96772_GPIO1),
+	GROUP_DESC(MAX96772_GPIO2),
+	GROUP_DESC(MAX96772_GPIO3),
+	GROUP_DESC(MAX96772_GPIO4),
+	GROUP_DESC(MAX96772_GPIO5),
+	GROUP_DESC(MAX96772_GPIO6),
+	GROUP_DESC(MAX96772_GPIO7),
+
+	GROUP_DESC(MAX96772_GPIO8),
+	GROUP_DESC(MAX96772_GPIO9),
+	GROUP_DESC(MAX96772_GPIO10),
+	GROUP_DESC(MAX96772_GPIO11),
+	GROUP_DESC(MAX96772_GPIO12),
+	GROUP_DESC(MAX96772_GPIO13),
+	GROUP_DESC(MAX96772_GPIO14),
+	GROUP_DESC(MAX96772_GPIO15),
+};
+
+static struct function_desc max96772_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(0),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(1),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(2),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(3),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(4),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(5),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(6),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(7),
+
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(8),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(9),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(10),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(11),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(12),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(13),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(14),
+	FUNCTION_DESC_GPIO_INPUT_BYPASS(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(0),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(1),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(2),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(3),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(4),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(5),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(6),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(8),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(9),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(10),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(11),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(12),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(13),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(14),
+	FUNCTION_DESC_GPIO_OUTPUT_BYPASS(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(0),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(1),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(2),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(3),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(4),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(5),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(6),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(8),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(9),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(10),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(11),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(12),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(13),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(14),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(0),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(1),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(2),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(3),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(4),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(5),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(6),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(8),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(9),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(10),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(11),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(12),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(13),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(14),
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(15),
+
+	FUNCTION_DES_DELAY_MS(10),
+	FUNCTION_DES_DELAY_MS(50),
+	FUNCTION_DES_DELAY_MS(100),
+	FUNCTION_DES_DELAY_MS(200),
+	FUNCTION_DES_DELAY_MS(500),
+};
+
+static struct serdes_chip_pinctrl_info max96772_pinctrl_info = {
+	.pins = max96772_pins_desc,
+	.num_pins = ARRAY_SIZE(max96772_pins_desc),
+	.groups = max96772_groups_desc,
+	.num_groups = ARRAY_SIZE(max96772_groups_desc),
+	.functions = max96772_functions_desc,
+	.num_functions = ARRAY_SIZE(max96772_functions_desc),
+};
+
+static const struct reg_sequence max96772_clk_ref[3][14] = {
+	{
+		{ 0xe7b2, 0x50 },
+		{ 0xe7b3, 0x00 },
+		{ 0xe7b4, 0xcc },
+		{ 0xe7b5, 0x44 },
+		{ 0xe7b6, 0x81 },
+		{ 0xe7b7, 0x30 },
+		{ 0xe7b8, 0x07 },
+		{ 0xe7b9, 0x10 },
+		{ 0xe7ba, 0x01 },
+		{ 0xe7bb, 0x00 },
+		{ 0xe7bc, 0x00 },
+		{ 0xe7bd, 0x00 },
+		{ 0xe7be, 0x52 },
+		{ 0xe7bf, 0x00 },
+	}, {
+		{ 0xe7b2, 0x50 },
+		{ 0xe7b3, 0x00 },
+		{ 0xe7b4, 0x00 },
+		{ 0xe7b5, 0x40 },
+		{ 0xe7b6, 0x6c },
+		{ 0xe7b7, 0x20 },
+		{ 0xe7b8, 0x07 },
+		{ 0xe7b9, 0x00 },
+		{ 0xe7ba, 0x01 },
+		{ 0xe7bb, 0x00 },
+		{ 0xe7bc, 0x00 },
+		{ 0xe7bd, 0x00 },
+		{ 0xe7be, 0x52 },
+		{ 0xe7bf, 0x00 },
+	}, {
+		{ 0xe7b2, 0x30 },
+		{ 0xe7b3, 0x00 },
+		{ 0xe7b4, 0x00 },
+		{ 0xe7b5, 0x40 },
+		{ 0xe7b6, 0x6c },
+		{ 0xe7b7, 0x20 },
+		{ 0xe7b8, 0x14 },
+		{ 0xe7b9, 0x00 },
+		{ 0xe7ba, 0x2e },
+		{ 0xe7bb, 0x00 },
+		{ 0xe7bc, 0x00 },
+		{ 0xe7bd, 0x01 },
+		{ 0xe7be, 0x32 },
+		{ 0xe7bf, 0x00 },
+	}
+};
+
+static int max96772_aux_dpcd_read(struct serdes *serdes,
+				  unsigned int reg,
+				  unsigned int *value)
+{
+	serdes_reg_write(serdes, 0xe778, reg & 0xff);
+	serdes_reg_write(serdes, 0xe779, (reg >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe77c, (reg >> 16) & 0xff);
+	serdes_reg_write(serdes, 0xe776, 0x10);
+	serdes_reg_write(serdes, 0xe777, 0x80);
+	/* FIXME */
+	mdelay(50);
+	serdes_reg_read(serdes, 0xe77a, value);
+
+	return 0;
+}
+
+static int max96772_panel_init(struct serdes *serdes)
+{
+	return 0;
+}
+
+static int max96772_panel_prepare(struct serdes *serdes)
+{
+	const struct drm_display_mode *mode = &serdes->serdes_panel->mode;
+	u32 hfp, hsa, hbp, hact;
+	u32 vact, vsa, vfp, vbp;
+	u64 hwords, mvid;
+	bool hsync_pol, vsync_pol;
+
+	serdes_reg_write(serdes, 0xe790, serdes->serdes_panel->link_rate);
+	serdes_reg_write(serdes, 0xe792, serdes->serdes_panel->lane_count);
+
+	if (serdes->serdes_panel->ssc) {
+		serdes_reg_write(serdes, 0xe7b0, 0x01);
+		serdes_reg_write(serdes, 0xe7b1, 0x10);
+	} else {
+		serdes_reg_write(serdes, 0xe7b1, 0x00);
+	}
+
+	switch (serdes->serdes_panel->link_rate) {
+	case DP_LINK_BW_5_4:
+		serdes_multi_reg_write(serdes, max96772_clk_ref[2],
+				       ARRAY_SIZE(max96772_clk_ref[2]));
+		break;
+	case DP_LINK_BW_2_7:
+		serdes_multi_reg_write(serdes, max96772_clk_ref[1],
+				       ARRAY_SIZE(max96772_clk_ref[1]));
+		break;
+	case DP_LINK_BW_1_62:
+	default:
+		serdes_multi_reg_write(serdes, max96772_clk_ref[0],
+				       ARRAY_SIZE(max96772_clk_ref[0]));
+		break;
+	}
+
+	vact = mode->vdisplay;
+	vsa = mode->vsync_end - mode->vsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	hact = mode->hdisplay;
+	hsa = mode->hsync_end - mode->hsync_start;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+
+	serdes_reg_write(serdes, 0xe794, hact & 0xff);
+	serdes_reg_write(serdes, 0xe795, (hact >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe796, hfp & 0xff);
+	serdes_reg_write(serdes, 0xe797, (hfp >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe798, hsa & 0xff);
+	serdes_reg_write(serdes, 0xe799, (hsa >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe79a, hbp & 0xff);
+	serdes_reg_write(serdes, 0xe79b, (hbp >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe79c, vact & 0xff);
+	serdes_reg_write(serdes, 0xe79d, (vact >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe79e, vfp & 0xff);
+	serdes_reg_write(serdes, 0xe79f, (vfp >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe7a0, vsa & 0xff);
+	serdes_reg_write(serdes, 0xe7a1, (vsa >> 8) & 0xff);
+	serdes_reg_write(serdes, 0xe7a2, vbp & 0xff);
+	serdes_reg_write(serdes, 0xe7a3, (vbp >> 8) & 0xff);
+
+	hsync_pol = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+	vsync_pol = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	serdes_reg_write(serdes, 0xe7ac, hsync_pol | (vsync_pol << 1));
+
+	/* NVID should always be set to 0x8000 */
+	serdes_reg_write(serdes, 0xe7a8, 0);
+	serdes_reg_write(serdes, 0xe7a9, 0x80);
+
+	/* HWORDS = ((HRES x bits / pixel) / 16) - LANE_COUNT */
+	hwords = DIV_ROUND_UP(hact * 24, 16) - serdes->serdes_panel->lane_count;
+	serdes_reg_write(serdes, 0xe7a4, hwords);
+	serdes_reg_write(serdes, 0xe7a5, hwords >> 8);
+
+	/* MVID = (PCLK x NVID) x 10 / Link Rate */
+	mvid = DIV_ROUND_UP((u64)mode->clock * 32768,
+			    drm_dp_bw_code_to_link_rate(serdes->serdes_panel->link_rate));
+	serdes_reg_write(serdes, 0xe7a6, mvid & 0xff);
+	serdes_reg_write(serdes, 0xe7a7, (mvid >> 8) & 0xff);
+
+	serdes_reg_write(serdes, 0xe7aa, 0x40);
+	serdes_reg_write(serdes, 0xe7ab, 0x00);
+
+	return 0;
+}
+
+static int max96772_panel_unprepare(struct serdes *serdes)
+{
+	return 0;
+}
+
+static int max96772_panel_enable(struct serdes *serdes)
+{
+	u32 status[2];
+	u32 val;
+	int ret;
+	int i = 0;
+
+	/* Run link training */
+	serdes_reg_write(serdes, 0xe776, 0x02);
+	serdes_reg_write(serdes, 0xe777, 0x80);
+
+	for (i = 0; i < 100; i++) {
+		ret = serdes_reg_read(serdes, 0x07f0, &val);
+		if (val & 0x01)
+			break;
+		mdelay(5);
+	}
+
+	ret = max96772_aux_dpcd_read(serdes, DP_LANE0_1_STATUS, &status[0]);
+	if (ret)
+		return ret;
+
+	ret = max96772_aux_dpcd_read(serdes, DP_LANE2_3_STATUS, &status[1]);
+	if (ret)
+		return ret;
+
+	dev_err(serdes->dev, "Link Training failed: LANE0_1_STATUS=0x%02x, LANE2_3_STATUS=0x%02x\n",
+		status[0], status[1]);
+
+	return 0;
+}
+
+static int max96772_panel_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+int max96772_panel_backlight_enable(struct serdes *serdes)
+{
+	return 0;
+}
+
+int max96772_panel_backlight_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static struct serdes_chip_panel_ops max96772_panel_ops = {
+	.init		= max96772_panel_init,
+	.prepare	= max96772_panel_prepare,
+	.unprepare	= max96772_panel_unprepare,
+	.enable		= max96772_panel_enable,
+	.disable	= max96772_panel_disable,
+	.backlight_enable	= max96772_panel_backlight_enable,
+	.backlight_disable	= max96772_panel_backlight_disable,
+};
+
+static int max96772_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		offset = pin->number;
+		if (offset > 32)
+			dev_err(serdes->dev, "%s offset=%d > 32\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+					__func__, serdes->dev->name,
+					fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+		if (!ms) {
+			serdes_set_bits(serdes, GPIO_A_REG(offset),
+					GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN | GPIO_OUT,
+					FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+					FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+					FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en) |
+					FIELD_PREP(GPIO_OUT, fdata->gpio_out_level));
+			if (fdata->gpio_tx_en)
+				serdes_set_bits(serdes,
+						GPIO_B_REG(offset),
+						GPIO_TX_ID,
+						FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+			if (fdata->gpio_rx_en)
+				serdes_set_bits(serdes,
+						GPIO_C_REG(offset),
+						GPIO_RX_ID,
+						FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+		} else {
+			mdelay(ms);
+			SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+		}
+	}
+
+	return 0;
+}
+
+static int max96772_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p, num=%d\n",
+			__func__, serdes->chip_data->name, func->name,
+			func->data, grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 32)
+				dev_err(serdes->dev, "%s offset=%d > 32\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+						__func__, serdes->dev->name,
+						fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+			if (!ms) {
+				serdes_set_bits(serdes, GPIO_A_REG(offset),
+						GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN | GPIO_OUT,
+						FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+						FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+						FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en) |
+						FIELD_PREP(GPIO_OUT, fdata->gpio_out_level));
+				if (fdata->gpio_tx_en)
+					serdes_set_bits(serdes,
+							GPIO_B_REG(offset),
+							GPIO_TX_ID,
+							FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+				if (fdata->gpio_rx_en)
+					serdes_set_bits(serdes,
+							GPIO_C_REG(offset),
+							GPIO_RX_ID,
+							FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+			} else {
+				mdelay(ms);
+				SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+			}
+		}
+	}
+
+	if (grp->data) {
+		struct serdes_group_data *gdata = grp->data;
+
+		for (i = 0; i < gdata->num_configs; i++) {
+			const struct config_desc *config = &gdata->configs[i];
+			serdes_set_bits(serdes, config->reg,
+					config->mask, config->val);
+		}
+	}
+
+	return 0;
+}
+
+static int max96772_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param,
+				       unsigned int argument)
+{
+	u8 res_cfg;
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 0));
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 1));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 2));
+		break;
+	case PIN_CONFIG_OUTPUT:
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				GPIO_OUT_DIS | GPIO_OUT,
+				FIELD_PREP(GPIO_OUT_DIS, 0) |
+				FIELD_PREP(GPIO_OUT, argument));
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops max96772_pinctrl_ops = {
+	.pinconf_set = max96772_pinctrl_config_set,
+	.pinmux_set = max96772_pinctrl_set_pin_mux,
+	.pinmux_group_set = max96772_pinctrl_set_grp_mux,
+};
+
+static int max96772_gpio_direction_input(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96772_gpio_direction_output(struct serdes *serdes,
+					  int gpio, int value)
+{
+	return 0;
+}
+
+static int max96772_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96772_gpio_set_level(struct serdes *serdes, int gpio, int value)
+{
+	return 0;
+}
+
+static int max96772_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int max96772_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops max96772_gpio_ops = {
+	.direction_input = max96772_gpio_direction_input,
+	.direction_output = max96772_gpio_direction_output,
+	.get_level = max96772_gpio_get_level,
+	.set_level = max96772_gpio_set_level,
+	.set_config = max96772_gpio_set_config,
+	.to_irq = max96772_gpio_to_irq,
+};
+
+struct serdes_chip_data serdes_max96772_data = {
+	.name		= "max96772",
+	.serdes_type	= TYPE_DES,
+	.serdes_id	= MAXIM_ID_MAX96772,
+	.connector_type	= DRM_MODE_CONNECTOR_eDP,
+	.pinctrl_info	= &max96772_pinctrl_info,
+	.panel_ops	= &max96772_panel_ops,
+	.pinctrl_ops	= &max96772_pinctrl_ops,
+	.gpio_ops	= &max96772_gpio_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_max96772_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96772.h b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96772.h
new file mode 100644
index 0000000000..a3fa4c377d
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96772.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * include/linux/mfd/serdes/gpio.h -- GPIO for different serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_MAXIM_MAX96772_H__
+#define __MFD_SERDES_MAXIM_MAX96772_H__
+
+#define GPIO_A_REG(gpio)	(0x02b0 + ((gpio) * 3))
+#define GPIO_B_REG(gpio)	(0x02b1 + ((gpio) * 3))
+#define GPIO_C_REG(gpio)	(0x02b2 + ((gpio) * 3))
+
+/* 02b0h */
+#define RES_CFG			BIT(7)
+#define RSVD			BIT(6)
+#define TX_COMP_EN		BIT(5)
+#define GPIO_OUT		BIT(4)
+#define GPIO_IN			BIT(3)
+#define GPIO_RX_EN		BIT(2)
+#define GPIO_TX_EN		BIT(1)
+#define GPIO_OUT_DIS		BIT(0)
+
+/* 02b1h */
+#define PULL_UPDN_SEL		GENMASK(7, 6)
+#define OUT_TYPE		BIT(5)
+#define GPIO_TX_ID		GENMASK(4, 0)
+
+/* 02b2h */
+#define OVR_RES_CFG		BIT(7)
+#define GPIO_RX_ID		GENMASK(4, 0)
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96789.c b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96789.c
new file mode 100644
index 0000000000..00329e98fa
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96789.c
@@ -0,0 +1,726 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * maxim-max96789.c  --  I2C register interface access for max96789 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+#include "maxim-max96789.h"
+
+struct serdes_function_data {
+	u8 gpio_out_dis:1;
+	u8 gpio_tx_en:1;
+	u8 gpio_rx_en:1;
+	u8 gpio_tx_id;
+	u8 gpio_rx_id;
+	u16 mdelay;
+};
+
+struct config_desc {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+struct serdes_group_data {
+	const struct config_desc *configs;
+	int num_configs;
+};
+
+static int MAX96789_MFP0_pins[] = {0};
+static int MAX96789_MFP1_pins[] = {1};
+static int MAX96789_MFP2_pins[] = {2};
+static int MAX96789_MFP3_pins[] = {3};
+static int MAX96789_MFP4_pins[] = {4};
+static int MAX96789_MFP5_pins[] = {5};
+static int MAX96789_MFP6_pins[] = {6};
+static int MAX96789_MFP7_pins[] = {7};
+
+static int MAX96789_MFP8_pins[] = {8};
+static int MAX96789_MFP9_pins[] = {9};
+static int MAX96789_MFP10_pins[] = {10};
+static int MAX96789_MFP11_pins[] = {11};
+static int MAX96789_MFP12_pins[] = {12};
+static int MAX96789_MFP13_pins[] = {13};
+static int MAX96789_MFP14_pins[] = {14};
+static int MAX96789_MFP15_pins[] = {15};
+
+static int MAX96789_MFP16_pins[] = {16};
+static int MAX96789_MFP17_pins[] = {17};
+static int MAX96789_MFP18_pins[] = {18};
+static int MAX96789_MFP19_pins[] = {19};
+static int MAX96789_MFP20_pins[] = {20};
+static int MAX96789_I2C_pins[] = {19, 20};
+static int MAX96789_UART_pins[] = {19, 20};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+#define GROUP_DESC_CONFIG(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+	.data = (void *)(const struct serdes_group_data []) { \
+		{ \
+			.configs = nm ## _configs, \
+			.num_configs = ARRAY_SIZE(nm ## _configs), \
+		} \
+	}, \
+}
+
+static const struct config_desc MAX96789_MFP0_configs[] = {
+	{ 0x0005, LOCK_EN, 0 },
+	{ 0x0048, LOC_MS_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP1_configs[] = {
+	{ 0x0005, ERRB_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP4_configs[] = {
+	{ 0x070, SPI_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP5_configs[] = {
+	{ 0x006, RCLKEN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP7_configs[] = {
+	{ 0x0002, AUD_TX_EN_X, 0 },
+	{ 0x0002, AUD_TX_EN_Y, 0 }
+};
+
+static const struct config_desc MAX96789_MFP8_configs[] = {
+	{ 0x0002, AUD_TX_EN_X, 0 },
+	{ 0x0002, AUD_TX_EN_Y, 0 }
+};
+
+static const struct config_desc MAX96789_MFP9_configs[] = {
+	{ 0x0002, AUD_TX_EN_X, 0 },
+	{ 0x0002, AUD_TX_EN_Y, 0 }
+};
+
+static const struct config_desc MAX96789_MFP10_configs[] = {
+	{ 0x0001, IIC_2_EN, 0 },
+	{ 0x0003, UART_2_EN, 0 },
+	{ 0x0140, AUD_RX_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP11_configs[] = {
+	{ 0x0001, IIC_2_EN, 0 },
+	{ 0x0003, UART_2_EN, 0 },
+	{ 0x0140, AUD_RX_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP12_configs[] = {
+	{ 0x0140, AUD_RX_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP13_configs[] = {
+	{ 0x0005, PU_LF0, 0 },
+};
+
+static const struct config_desc MAX96789_MFP14_configs[] = {
+	{ 0x0005, PU_LF1, 0 },
+};
+
+static const struct config_desc MAX96789_MFP15_configs[] = {
+	{ 0x0005, PU_LF2, 0 },
+};
+
+static const struct config_desc MAX96789_MFP16_configs[] = {
+	{ 0x0005, PU_LF3, 0 },
+};
+
+static const struct config_desc MAX96789_MFP17_configs[] = {
+	{ 0x0001, IIC_1_EN, 0 },
+	{ 0x0003, UART_1_EN, 0 },
+};
+
+static const struct config_desc MAX96789_MFP18_configs[] = {
+	{ 0x0001, IIC_1_EN, 0 },
+	{ 0x0003, UART_1_EN, 0 },
+};
+
+static const char *serdes_gpio_groups[] = {
+	"MAX96789_MFP0", "MAX96789_MFP1", "MAX96789_MFP2", "MAX96789_MFP3",
+	"MAX96789_MFP4", "MAX96789_MFP5", "MAX96789_MFP6", "MAX96789_MFP7",
+
+	"MAX96789_MFP8", "MAX96789_MFP9", "MAX96789_MFP10", "MAX96789_MFP11",
+	"MAX96789_MFP12", "MAX96789_MFP13", "MAX96789_MFP14", "MAX96789_MFP15",
+
+	"MAX96789_MFP16", "MAX96789_MFP17", "MAX96789_MFP18", "MAX96789_MFP19",
+	"MAX96789_MFP20",
+};
+
+static const char *MAX96789_I2C_groups[] = { "MAX96789_I2C" };
+static const char *MAX96789_UART_groups[] = { "MAX96789_UART" };
+
+#define FUNCTION_DESC(nm) \
+{ \
+	.name = #nm, \
+	.group_names = nm##_groups, \
+	.num_group_names = ARRAY_SIZE(nm##_groups), \
+} \
+
+#define FUNCTION_DESC_GPIO_INPUT(id) \
+{ \
+	.name = "DES_RXID"#id"_TO_SER", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 0, .gpio_rx_en = 1, .gpio_rx_id = id } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT(id) \
+{ \
+	.name = "SER_TXID"#id"_TO_DES", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_out_dis = 1, .gpio_tx_en = 1, .gpio_tx_id = id } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc max96789_pins_desc[] = {
+	PINCTRL_PIN(MAXIM_MAX96789_MFP0, "MAX96789_MFP0"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP1, "MAX96789_MFP1"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP2, "MAX96789_MFP2"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP3, "MAX96789_MFP3"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP4, "MAX96789_MFP4"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP5, "MAX96789_MFP5"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP6, "MAX96789_MFP6"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP7, "MAX96789_MFP7"),
+
+	PINCTRL_PIN(MAXIM_MAX96789_MFP8, "MAX96789_MFP8"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP9, "MAX96789_MFP9"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP10, "MAX96789_MFP10"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP11, "MAX96789_MFP11"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP12, "MAX96789_MFP12"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP13, "MAX96789_MFP13"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP14, "MAX96789_MFP14"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP15, "MAX96789_MFP15"),
+
+	PINCTRL_PIN(MAXIM_MAX96789_MFP16, "MAX96789_MFP16"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP17, "MAX96789_MFP17"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP18, "MAX96789_MFP18"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP19, "MAX96789_MFP19"),
+	PINCTRL_PIN(MAXIM_MAX96789_MFP20, "MAX96789_MFP20"),
+};
+
+static struct group_desc max96789_groups_desc[] = {
+	GROUP_DESC_CONFIG(MAX96789_MFP0),
+	GROUP_DESC_CONFIG(MAX96789_MFP1),
+	GROUP_DESC(MAX96789_MFP2),
+	GROUP_DESC(MAX96789_MFP3),
+	GROUP_DESC_CONFIG(MAX96789_MFP4),
+	GROUP_DESC_CONFIG(MAX96789_MFP5),
+	GROUP_DESC(MAX96789_MFP6),
+	GROUP_DESC_CONFIG(MAX96789_MFP7),
+
+	GROUP_DESC_CONFIG(MAX96789_MFP8),
+	GROUP_DESC_CONFIG(MAX96789_MFP9),
+	GROUP_DESC_CONFIG(MAX96789_MFP10),
+	GROUP_DESC_CONFIG(MAX96789_MFP11),
+	GROUP_DESC_CONFIG(MAX96789_MFP12),
+	GROUP_DESC_CONFIG(MAX96789_MFP13),
+	GROUP_DESC_CONFIG(MAX96789_MFP14),
+	GROUP_DESC_CONFIG(MAX96789_MFP15),
+
+	GROUP_DESC_CONFIG(MAX96789_MFP16),
+	GROUP_DESC_CONFIG(MAX96789_MFP17),
+	GROUP_DESC_CONFIG(MAX96789_MFP18),
+	GROUP_DESC(MAX96789_MFP19),
+	GROUP_DESC(MAX96789_MFP20),
+	GROUP_DESC(MAX96789_I2C),
+	GROUP_DESC(MAX96789_UART),
+};
+
+static struct function_desc max96789_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT(0),
+	FUNCTION_DESC_GPIO_INPUT(1),
+	FUNCTION_DESC_GPIO_INPUT(2),
+	FUNCTION_DESC_GPIO_INPUT(3),
+	FUNCTION_DESC_GPIO_INPUT(4),
+	FUNCTION_DESC_GPIO_INPUT(5),
+	FUNCTION_DESC_GPIO_INPUT(6),
+	FUNCTION_DESC_GPIO_INPUT(7),
+
+	FUNCTION_DESC_GPIO_INPUT(8),
+	FUNCTION_DESC_GPIO_INPUT(9),
+	FUNCTION_DESC_GPIO_INPUT(10),
+	FUNCTION_DESC_GPIO_INPUT(11),
+	FUNCTION_DESC_GPIO_INPUT(12),
+	FUNCTION_DESC_GPIO_INPUT(13),
+	FUNCTION_DESC_GPIO_INPUT(14),
+	FUNCTION_DESC_GPIO_INPUT(15),
+
+	FUNCTION_DESC_GPIO_INPUT(16),
+	FUNCTION_DESC_GPIO_INPUT(17),
+	FUNCTION_DESC_GPIO_INPUT(18),
+	FUNCTION_DESC_GPIO_INPUT(19),
+	FUNCTION_DESC_GPIO_INPUT(20),
+
+	FUNCTION_DESC_GPIO_OUTPUT(0),
+	FUNCTION_DESC_GPIO_OUTPUT(1),
+	FUNCTION_DESC_GPIO_OUTPUT(2),
+	FUNCTION_DESC_GPIO_OUTPUT(3),
+	FUNCTION_DESC_GPIO_OUTPUT(4),
+	FUNCTION_DESC_GPIO_OUTPUT(5),
+	FUNCTION_DESC_GPIO_OUTPUT(6),
+	FUNCTION_DESC_GPIO_OUTPUT(7),
+
+	FUNCTION_DESC_GPIO_OUTPUT(8),
+	FUNCTION_DESC_GPIO_OUTPUT(9),
+	FUNCTION_DESC_GPIO_OUTPUT(10),
+	FUNCTION_DESC_GPIO_OUTPUT(11),
+	FUNCTION_DESC_GPIO_OUTPUT(12),
+	FUNCTION_DESC_GPIO_OUTPUT(13),
+	FUNCTION_DESC_GPIO_OUTPUT(14),
+	FUNCTION_DESC_GPIO_OUTPUT(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT(16),
+	FUNCTION_DESC_GPIO_OUTPUT(17),
+	FUNCTION_DESC_GPIO_OUTPUT(18),
+	FUNCTION_DESC_GPIO_OUTPUT(19),
+	FUNCTION_DESC_GPIO_OUTPUT(20),
+
+	FUNCTION_DESC(MAX96789_I2C),
+	FUNCTION_DESC(MAX96789_UART),
+};
+
+static struct serdes_chip_pinctrl_info max96789_pinctrl_info = {
+	.pins = max96789_pins_desc,
+	.num_pins = ARRAY_SIZE(max96789_pins_desc),
+	.groups = max96789_groups_desc,
+	.num_groups = ARRAY_SIZE(max96789_groups_desc),
+	.functions = max96789_functions_desc,
+	.num_functions = ARRAY_SIZE(max96789_functions_desc),
+};
+
+static bool max96789_bridge_link_locked(struct serdes *serdes)
+{
+	u32 val;
+
+	if (dm_gpio_is_valid(&serdes->lock_gpio)) {
+		val = dm_gpio_get_value(&serdes->lock_gpio);
+		SERDES_DBG_CHIP("serdes %s:val=%d\n", __func__, val);
+		return val;
+	}
+
+	if (serdes_reg_read(serdes, 0x0013, &val)) {
+		SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
+		return false;
+	}
+
+	if (!FIELD_GET(LOCKED, val)) {
+		SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
+		return false;
+	}
+
+	return true;
+}
+
+static bool max96789_bridge_detect(struct serdes *serdes)
+{
+	return max96789_bridge_link_locked(serdes);
+}
+
+static int max96789_bridge_enable(struct serdes *serdes)
+{
+	int ret = 0;
+
+	SERDES_DBG_CHIP("%s: serdes chip %s ret=%d\n",
+			__func__, serdes->chip_data->name, ret);
+	return ret;
+}
+
+static int max96789_bridge_disable(struct serdes *serdes)
+{
+	int ret = 0;
+
+	ret = serdes_set_bits(serdes, 0x0002, VID_TX_EN_X,
+			      FIELD_PREP(VID_TX_EN_X, 0));
+
+	return ret;
+}
+
+static struct serdes_chip_bridge_ops max96789_bridge_ops = {
+	.detect = max96789_bridge_detect,
+	.enable = max96789_bridge_enable,
+	.disable = max96789_bridge_disable,
+};
+
+static int max96789_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		offset = pin->number;
+		if (offset > 32)
+			dev_err(serdes->dev, "%s offset=%d > 32\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+					__func__, serdes->dev->name,
+					fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+		if (!ms) {
+			serdes_set_bits(serdes, GPIO_A_REG(offset),
+					GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN,
+					FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+					FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+					FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en));
+
+			if (fdata->gpio_tx_en)
+				serdes_set_bits(serdes,
+						GPIO_B_REG(offset),
+						GPIO_TX_ID,
+						FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+			if (fdata->gpio_rx_en)
+				serdes_set_bits(serdes,
+						GPIO_C_REG(offset),
+						GPIO_RX_ID,
+						FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+		} else {
+			mdelay(ms);
+			SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+		}
+	}
+
+	return 0;
+}
+
+static int max96789_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p num=%d\n",
+			__func__, serdes->chip_data->name, func->name,
+			func->data, grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		ms = fdata->mdelay;
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 32)
+				dev_err(serdes->dev, "%s offset=%d > 32\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
+						__func__, serdes->dev->name,
+						fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
+
+			if (!ms) {
+				serdes_set_bits(serdes, GPIO_A_REG(offset),
+						GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN,
+						FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
+						FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
+						FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en));
+				if (fdata->gpio_tx_en)
+					serdes_set_bits(serdes,
+							GPIO_B_REG(offset),
+							GPIO_TX_ID,
+							FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
+				if (fdata->gpio_rx_en)
+					serdes_set_bits(serdes,
+							GPIO_C_REG(offset),
+							GPIO_RX_ID,
+							FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
+			} else {
+				mdelay(ms);
+				SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+			}
+		}
+	}
+
+	if (grp->data) {
+		struct serdes_group_data *gdata = grp->data;
+
+		for (i = 0; i < gdata->num_configs; i++) {
+			const struct config_desc *config = &gdata->configs[i];
+
+			serdes_set_bits(serdes, config->reg,
+					config->mask, config->val);
+		}
+	}
+
+	return 0;
+}
+
+static int max96789_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param,
+				       unsigned int argument)
+{
+	u8 res_cfg;
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
+				OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 0));
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 1));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		switch (argument) {
+		case 40000:
+			res_cfg = 0;
+			break;
+		case 1000000:
+			res_cfg = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
+		serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
+				PULL_UPDN_SEL,
+				FIELD_PREP(PULL_UPDN_SEL, 2));
+	break;
+	case PIN_CONFIG_OUTPUT:
+		serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
+				GPIO_OUT_DIS | GPIO_OUT,
+				FIELD_PREP(GPIO_OUT_DIS, 0) |
+				FIELD_PREP(GPIO_OUT, argument));
+	break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops max96789_pinctrl_ops = {
+	.pinconf_set = max96789_pinctrl_config_set,
+	.pinmux_set = max96789_pinctrl_set_pin_mux,
+	.pinmux_group_set = max96789_pinctrl_set_grp_mux,
+};
+
+static int max96789_gpio_direction_input(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96789_gpio_direction_output(struct serdes *serdes,
+					  int gpio, int value)
+{
+	return 0;
+}
+
+static int max96789_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int max96789_gpio_set_level(struct serdes *serdes, int gpio, int value)
+{
+	return 0;
+}
+
+static int max96789_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int max96789_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops max96789_gpio_ops = {
+	.direction_input = max96789_gpio_direction_input,
+	.direction_output = max96789_gpio_direction_output,
+	.get_level = max96789_gpio_get_level,
+	.set_level = max96789_gpio_set_level,
+	.set_config = max96789_gpio_set_config,
+	.to_irq = max96789_gpio_to_irq,
+};
+
+static int max96789_select(struct serdes *serdes, int chan)
+{
+	u32 link_cfg, link_status;
+	int ret = 0;
+	int i = 0;
+
+	serdes_set_bits(serdes, 0x0001, DIS_REM_CC,
+			FIELD_PREP(DIS_REM_CC, 0));
+
+	serdes_reg_read(serdes, 0x0010, &link_cfg);
+	if ((link_cfg & LINK_CFG) == SPLITTER_MODE)
+		SERDES_DBG_CHIP("%s: serdes %s is split mode cfg=0x%x\n",
+				__func__,
+				serdes->chip_data->name, link_cfg);
+
+	if (chan == 0 && (link_cfg & LINK_CFG) != DUAL_LINK) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 1) |
+				      FIELD_PREP(LINK_EN_B, 1));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, DUAL_LINK));
+		SERDES_DBG_CHIP("%s: change to use dual link\n", __func__);
+	} else if (chan == 1 && (link_cfg & LINK_CFG) != LINKA) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 1) |
+				      FIELD_PREP(LINK_EN_B, 0));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, LINKA));
+		SERDES_DBG_CHIP("%s: change to use linkA\n", __func__);
+	} else if (chan == 2 && (link_cfg & LINK_CFG) != LINKB) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 0) |
+				      FIELD_PREP(LINK_EN_B, 1));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, LINKB));
+		SERDES_DBG_CHIP("%s: change to use linkB\n", __func__);
+	} else if (chan == 3 && (link_cfg & LINK_CFG) != SPLITTER_MODE) {
+		ret = serdes_set_bits(serdes, 0x0004,
+				      LINK_EN_B | LINK_EN_A,
+				      FIELD_PREP(LINK_EN_A, 1) |
+				      FIELD_PREP(LINK_EN_B, 1));
+		ret = serdes_set_bits(serdes, 0x0010,
+				      RESET_ONESHOT | AUTO_LINK | LINK_CFG,
+				      FIELD_PREP(RESET_ONESHOT, 1) |
+				      FIELD_PREP(AUTO_LINK, 0) |
+				      FIELD_PREP(LINK_CFG, SPLITTER_MODE));
+		SERDES_DBG_CHIP("%s: change to use split mode\n", __func__);
+	}
+
+	for (i = 0; i < 20; i++) {
+		serdes_reg_read(serdes, 0x0013, &link_status);
+		if (link_status & LOCKED)
+			break;
+		mdelay(5);
+	}
+
+	if (i > 9)
+		printf("%s: %s GMSL2 link lock timeout\n", __func__,
+		       serdes->dev->name);
+	else
+		printf("%s: %s GMSL2 link locked\n", __func__,
+		       serdes->dev->name);
+
+	return ret;
+}
+
+static int max96789_deselect(struct serdes *serdes, int chan)
+{
+	//serdes_set_bits(serdes, 0x0001, DIS_REM_CC,
+	//		   FIELD_PREP(DIS_REM_CC, 1));
+
+	return 0;
+}
+
+static struct serdes_chip_split_ops max96789_split_ops = {
+	.select = max96789_select,
+	.deselect = max96789_deselect,
+};
+
+struct serdes_chip_data serdes_max96789_data = {
+	.name		= "max96789",
+	.serdes_type	= TYPE_SER,
+	.serdes_id	= MAXIM_ID_MAX96789,
+	.connector_type	= DRM_MODE_CONNECTOR_DSI,
+	.pinctrl_info	= &max96789_pinctrl_info,
+	.bridge_ops	= &max96789_bridge_ops,
+	.pinctrl_ops	= &max96789_pinctrl_ops,
+	.gpio_ops	= &max96789_gpio_ops,
+	.split_ops	= &max96789_split_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_max96789_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96789.h b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96789.h
new file mode 100644
index 0000000000..35b9ed9118
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/maxim/maxim-max96789.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * maxim-max96789.h -- register define for max96789 chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_MAXIM_MAX96789_H__
+#define __MFD_SERDES_MAXIM_MAX96789_H__
+
+#include <linux/bitfield.h>
+
+#define GPIO_A_REG(gpio)	(0x02be + ((gpio) * 3))
+#define GPIO_B_REG(gpio)	(0x02bf + ((gpio) * 3))
+#define GPIO_C_REG(gpio)	(0x02c0 + ((gpio) * 3))
+
+/* 0000h */
+#define DEV_ADDR		GENMASK(7, 1)
+#define CFG_BLOCK		BIT(0)
+
+/* 0001h */
+#define IIC_2_EN		BIT(7)
+#define IIC_1_EN		BIT(6)
+#define DIS_REM_CC		BIT(4)
+#define TX_RATE			GENMASK(3, 2)
+
+/* 0002h */
+#define VID_TX_EN_U		BIT(7)
+#define VID_TX_EN_Z		BIT(6)
+#define VID_TX_EN_Y		BIT(5)
+#define VID_TX_EN_X		BIT(4)
+#define AUD_TX_EN_Y		BIT(3)
+#define AUD_TX_EN_X		BIT(2)
+
+/* 0003h */
+#define UART_2_EN		BIT(5)
+#define UART_1_EN		BIT(4)
+
+/* 0004h */
+#define GMSL2_B			BIT(7)
+#define GMSL2_A			BIT(6)
+#define LINK_EN_B		BIT(5)
+#define LINK_EN_A		BIT(4)
+#define AUD_TX_SRC_Y	BIT(1)
+#define AUD_TX_SRC_X	BIT(0)
+
+/* 0005h */
+#define LOCK_EN			BIT(7)
+#define ERRB_EN			BIT(6)
+#define PU_LF3			BIT(3)
+#define PU_LF2			BIT(2)
+#define PU_LF1			BIT(1)
+#define PU_LF0			BIT(0)
+
+/* 0006h */
+#define RCLKEN			BIT(5)
+
+/* 0010h */
+#define RESET_ALL		BIT(7)
+#define RESET_LINK		BIT(6)
+#define RESET_ONESHOT		BIT(5)
+#define AUTO_LINK		BIT(4)
+#define SLEEP			BIT(3)
+#define REG_ENABLE		BIT(2)
+#define LINK_CFG		GENMASK(1, 0)
+
+/* 0013h */
+#define LINK_MODE		GENMASK(5, 4)
+#define	LOCKED			BIT(3)
+
+/* 0026h */
+#define LF_1			GENMASK(6, 4)
+#define LF_0			GENMASK(2, 0)
+
+/* 0048h */
+#define REM_MS_EN		BIT(5)
+#define LOC_MS_EN		BIT(4)
+
+/* 0053h */
+#define TX_SPLIT_MASK_B		BIT(5)
+#define TX_SPLIT_MASK_A		BIT(4)
+#define TX_STR_SEL		GENMASK(1, 0)
+
+/* 0140h */
+#define AUD_RX_EN		BIT(0)
+
+/* 0170h */
+#define SPI_EN			BIT(0)
+
+/* 01e5h */
+#define PATGEN_MODE		GENMASK(1, 0)
+
+/* 02beh */
+#define RES_CFG			BIT(7)
+#define TX_PRIO			BIT(6)
+#define TX_COMP_EN		BIT(5)
+#define GPIO_OUT		BIT(4)
+#define GPIO_IN			BIT(3)
+#define GPIO_RX_EN		BIT(2)
+#define GPIO_TX_EN		BIT(1)
+#define GPIO_OUT_DIS		BIT(0)
+
+/* 02bfh */
+#define PULL_UPDN_SEL		GENMASK(7, 6)
+#define OUT_TYPE		BIT(5)
+#define GPIO_TX_ID		GENMASK(4, 0)
+
+/* 02c0h */
+#define OVR_RES_CFG		BIT(7)
+#define GPIO_RX_ID		GENMASK(4, 0)
+
+/* 0311h */
+#define START_PORTBU		BIT(7)
+#define START_PORTBZ		BIT(6)
+#define START_PORTBY		BIT(5)
+#define START_PORTBX		BIT(4)
+#define START_PORTAU		BIT(3)
+#define START_PORTAZ		BIT(2)
+#define START_PORTAY		BIT(1)
+#define START_PORTAX		BIT(0)
+
+/* 032ah */
+#define DV_LOCK			BIT(7)
+#define DV_SWP_AB		BIT(6)
+#define LINE_ALT		BIT(5)
+#define DV_CONV			BIT(2)
+#define DV_SPL			BIT(1)
+#define DV_EN			BIT(0)
+
+/* 0330h */
+#define PHY_CONFIG		GENMASK(2, 0)
+#define MIPI_RX_RESET		BIT(3)
+
+/* 0331h */
+#define NUM_LANES		GENMASK(1, 0)
+
+/* 0385h */
+#define DPI_HSYNC_WIDTH_L	GENMASK(7, 0)
+
+/* 0386h */
+#define DPI_VYSNC_WIDTH_L	GENMASK(7, 0)
+
+/* 0387h */
+#define	DPI_HSYNC_WIDTH_H	GENMASK(3, 0)
+#define DPI_VSYNC_WIDTH_H	GENMASK(7, 4)
+
+/* 03a4h */
+#define DPI_DE_SKEW_SEL		BIT(1)
+#define DPI_DESKEW_EN		BIT(0)
+
+/* 03a5h */
+#define DPI_VFP_L		GENMASK(7, 0)
+
+/* 03a6h */
+#define DPI_VFP_H		GENMASK(3, 0)
+#define DPI_VBP_L		GENMASK(7, 4)
+
+/* 03a7h */
+#define DPI_VBP_H		GENMASK(7, 0)
+
+/* 03a8h */
+#define DPI_VACT_L		GENMASK(7, 0)
+
+/* 03a9h */
+#define DPI_VACT_H		GENMASK(3, 0)
+
+/* 03aah */
+#define DPI_HFP_L		GENMASK(7, 0)
+
+/* 03abh */
+#define DPI_HFP_H		GENMASK(3, 0)
+#define DPI_HBP_L		GENMASK(7, 4)
+
+/* 03ach */
+#define DPI_HBP_H		GENMASK(7, 0)
+
+/* 03adh */
+#define DPI_HACT_L		GENMASK(7, 0)
+
+/* 03aeh */
+#define DPI_HACT_H		GENMASK(4, 0)
+
+/* 055dh */
+#define VS_DET			BIT(5)
+#define HS_DET			BIT(4)
+
+enum link_mode {
+	DUAL_LINK,
+	LINKA,
+	LINKB,
+	SPLITTER_MODE,
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/novo/Kconfig b/u-boot/drivers/video/drm/display-serdes/novo/Kconfig
new file mode 100644
index 0000000000..20578a857a
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/novo/Kconfig
@@ -0,0 +1,23 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# rohm serdes drivers configuration
+#
+
+menuconfig SERDES_DISPLAY_CHIP_NOVO
+	tristate "novo expander device support"
+	default y
+	help
+	  Enable this to be able to choose the drivers for controlling the
+	  rohm serdes.
+
+if SERDES_DISPLAY_CHIP_NOVO
+config SERDES_DISPLAY_CHIP_NOVO_NCA9539
+	tristate "novo nca9539 expander"
+	default y
+	help
+	  To support novo nca9539 expander.
+
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/novo/Makefile b/u-boot/drivers/video/drm/display-serdes/novo/Makefile
new file mode 100644
index 0000000000..a5defbfbdb
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/novo/Makefile
@@ -0,0 +1,10 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# novo display serdes drivers configuration
+#
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_NOVO)		+= novo-nca9539.o
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/novo/novo-nca9539.c b/u-boot/drivers/video/drm/display-serdes/novo/novo-nca9539.c
new file mode 100644
index 0000000000..9dab598a81
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/novo/novo-nca9539.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * maxim-nca9539.c  --  I2C register interface access for nca9539 chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+
+struct serdes_chip_data serdes_nca9539_data = {
+	.name			= "nca9539",
+	.serdes_type	= TYPE_OTHER,
+	.serdes_id		= NOVO_ID_NCA9539,
+	.reg_val_type	= REG_8BIT_VAL_8IT,
+};
+EXPORT_SYMBOL_GPL(serdes_nca9539_data);
diff --git a/u-boot/drivers/video/drm/display-serdes/rockchip/Kconfig b/u-boot/drivers/video/drm/display-serdes/rockchip/Kconfig
new file mode 100644
index 0000000000..65c8961d7b
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rockchip/Kconfig
@@ -0,0 +1,28 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# rockchip display serdes drivers configuration
+#
+
+menuconfig SERDES_DISPLAY_CHIP_ROCKCHIP
+	tristate "rockchip serdes device support"
+	default y
+	help
+	  Enable this to be able to choose the drivers for controlling the
+	  rockchip serdes.
+
+if SERDES_DISPLAY_CHIP_ROCKCHIP
+config SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111
+	tristate "rockchip rkx111 serdes"
+	default y
+	help
+	  To support rockchip rkx111 display serdes.
+
+config SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121
+	tristate "rockchip rkx121 serdes"
+	default y
+	help
+	  To support rockchip rkx121 display serdes.
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/rockchip/Makefile b/u-boot/drivers/video/drm/display-serdes/rockchip/Makefile
new file mode 100644
index 0000000000..56b2741ac5
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rockchip/Makefile
@@ -0,0 +1,11 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# rockchip display serdes drivers configuration
+#
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111)	+= rockchip-rkx111.o
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121)	+= rockchip-rkx121.o
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/rockchip/rockchip-rkx111.c b/u-boot/drivers/video/drm/display-serdes/rockchip/rockchip-rkx111.c
new file mode 100644
index 0000000000..1e70041422
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rockchip/rockchip-rkx111.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * rockchip-rkx111.c  --  I2C register interface access for rkx111 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+
+int rkx111_bridge_init(struct serdes *serdes)
+{
+	return 0;
+}
+
+int rkx111_bridge_enable(struct serdes *serdes)
+{
+	return 0;
+}
+
+int rkx111_bridge_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static struct serdes_chip_bridge_ops rkx111_bridge_ops = {
+	.init = rkx111_bridge_init,
+	.enable = rkx111_bridge_enable,
+	.disable = rkx111_bridge_disable,
+};
+
+struct serdes_chip_data serdes_rkx111_data = {
+	.name			= "rkx111",
+	.serdes_type	= TYPE_SER,
+	.serdes_id		= ROCKCHIP_ID_RKX111,
+	.bridge_ops		= &rkx111_bridge_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_rkx111_data);
diff --git a/u-boot/drivers/video/drm/display-serdes/rockchip/rockchip-rkx121.c b/u-boot/drivers/video/drm/display-serdes/rockchip/rockchip-rkx121.c
new file mode 100644
index 0000000000..9682a600f9
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rockchip/rockchip-rkx121.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * rockchip-rkx121.c  --  I2C register interface access for rkx121 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+
+int rkx121_bridge_init(struct serdes *serdes)
+{
+	return 0;
+}
+
+int rkx121_bridge_enable(struct serdes *serdes)
+{
+	return 0;
+}
+
+int rkx121_bridge_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static struct serdes_chip_panel_ops rkx121_panel_ops = {
+	.init = rkx121_bridge_init,
+	.enable = rkx121_bridge_enable,
+	.disable = rkx121_bridge_disable,
+};
+
+struct serdes_chip_data serdes_rkx121_data = {
+	.name			= "rkx121",
+	.serdes_type	= TYPE_DES,
+	.serdes_id		= ROCKCHIP_ID_RKX121,
+	.panel_ops		= &rkx121_panel_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_rkx121_data);
diff --git a/u-boot/drivers/video/drm/display-serdes/rohm/Kconfig b/u-boot/drivers/video/drm/display-serdes/rohm/Kconfig
new file mode 100644
index 0000000000..23eec7a21c
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rohm/Kconfig
@@ -0,0 +1,28 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# rohm serdes drivers configuration
+#
+
+menuconfig SERDES_DISPLAY_CHIP_ROHM
+	tristate "rohm serdes device support"
+	default y
+	help
+	  Enable this to be able to choose the drivers for controlling the
+	  rohm serdes.
+
+if SERDES_DISPLAY_CHIP_ROHM
+config SERDES_DISPLAY_CHIP_ROHM_BU18TL82
+	tristate "rohm bu18tl82 serdes"
+	default y
+	help
+	  To support rohm bu18tl82 display serdes.
+
+config SERDES_DISPLAY_CHIP_ROHM_BU18RL82
+	tristate "rohm bu18rl82 serdes"
+	default y
+	help
+	  To support rohm bu18rl82 display serdes.
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/rohm/Makefile b/u-boot/drivers/video/drm/display-serdes/rohm/Makefile
new file mode 100644
index 0000000000..54c459d2ed
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rohm/Makefile
@@ -0,0 +1,11 @@
+#
+#(C) Copyright 2023-2025 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+# rohm display serdes drivers configuration
+#
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82)		+= rohm-bu18tl82.o
+obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82)		+= rohm-bu18rl82.o
+endif
diff --git a/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18rl82.c b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18rl82.c
new file mode 100644
index 0000000000..f7bf500980
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18rl82.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * rohm-bu18rl82.c  --  I2C register interface access for bu18rl82 serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+#include "rohm-bu18rl82.h"
+
+static int BU18RL82_GPIO0_pins[] = {0};
+static int BU18RL82_GPIO1_pins[] = {1};
+static int BU18RL82_GPIO2_pins[] = {2};
+static int BU18RL82_GPIO3_pins[] = {3};
+static int BU18RL82_GPIO4_pins[] = {4};
+static int BU18RL82_GPIO5_pins[] = {5};
+static int BU18RL82_GPIO6_pins[] = {6};
+static int BU18RL82_GPIO7_pins[] = {7};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+struct serdes_function_data {
+	u8 gpio_rx_en:1;
+	u16 gpio_id;
+	u16 mdelay;
+};
+
+static const char *serdes_gpio_groups[] = {
+	"BU18RL82_GPIO0", "BU18RL82_GPIO1", "BU18RL82_GPIO2", "BU18RL82_GPIO3",
+	"BU18RL82_GPIO4", "BU18RL82_GPIO5", "BU18RL82_GPIO6", "BU18RL82_GPIO7",
+};
+
+/*des -> ser -> soc*/
+#define FUNCTION_DESC_GPIO_INPUT(id) \
+{ \
+	.name = "DES_TO_SER_GPIO"#id, \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 1, .gpio_id = id + 2 } \
+	}, \
+} \
+
+/*soc -> ser -> des*/
+#define FUNCTION_DESC_GPIO_OUTPUT(id) \
+{ \
+	.name = "SER_GPIO"#id"_TO_DES", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 0, .gpio_id = id + 2 } \
+	}, \
+} \
+
+#define FUNCTION_DES_DELAY_MS(ms) \
+{ \
+	.name = "DELAY_"#ms"MS", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .mdelay = ms, } \
+	}, \
+} \
+
+/*des -> device*/
+#define FUNCTION_DESC_GPIO_OUTPUT_HIGH() \
+{ \
+	.name = "DES_GPIO_OUTPUT_HIGH", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 0, .gpio_id = 1 } \
+	}, \
+} \
+
+#define FUNCTION_DESC_GPIO_OUTPUT_LOW() \
+{ \
+	.name = "DES_GPIO_OUTPUT_LOW", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 0, .gpio_id = 0 } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc bu18rl82_pins_desc[] = {
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO0, "BU18RL82_GPIO0"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO1, "BU18RL82_GPIO1"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO2, "BU18RL82_GPIO2"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO3, "BU18RL82_GPIO3"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO4, "BU18RL82_GPIO4"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO5, "BU18RL82_GPIO5"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO6, "BU18RL82_GPIO6"),
+	PINCTRL_PIN(ROHM_BU18RL82_GPIO7, "BU18RL82_GPIO7"),
+};
+
+static struct group_desc bu18rl82_groups_desc[] = {
+	GROUP_DESC(BU18RL82_GPIO0),
+	GROUP_DESC(BU18RL82_GPIO1),
+	GROUP_DESC(BU18RL82_GPIO2),
+	GROUP_DESC(BU18RL82_GPIO3),
+	GROUP_DESC(BU18RL82_GPIO4),
+	GROUP_DESC(BU18RL82_GPIO5),
+	GROUP_DESC(BU18RL82_GPIO6),
+	GROUP_DESC(BU18RL82_GPIO7),
+};
+
+static struct function_desc bu18rl82_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT(0),
+	FUNCTION_DESC_GPIO_INPUT(1),
+	FUNCTION_DESC_GPIO_INPUT(2),
+	FUNCTION_DESC_GPIO_INPUT(3),
+	FUNCTION_DESC_GPIO_INPUT(4),
+	FUNCTION_DESC_GPIO_INPUT(5),
+	FUNCTION_DESC_GPIO_INPUT(6),
+	FUNCTION_DESC_GPIO_INPUT(7),
+	FUNCTION_DESC_GPIO_INPUT(8),
+	FUNCTION_DESC_GPIO_INPUT(9),
+	FUNCTION_DESC_GPIO_INPUT(10),
+	FUNCTION_DESC_GPIO_INPUT(11),
+	FUNCTION_DESC_GPIO_INPUT(12),
+	FUNCTION_DESC_GPIO_INPUT(13),
+	FUNCTION_DESC_GPIO_INPUT(14),
+	FUNCTION_DESC_GPIO_INPUT(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT(0),
+	FUNCTION_DESC_GPIO_OUTPUT(1),
+	FUNCTION_DESC_GPIO_OUTPUT(2),
+	FUNCTION_DESC_GPIO_OUTPUT(3),
+	FUNCTION_DESC_GPIO_OUTPUT(4),
+	FUNCTION_DESC_GPIO_OUTPUT(5),
+	FUNCTION_DESC_GPIO_OUTPUT(6),
+	FUNCTION_DESC_GPIO_OUTPUT(7),
+	FUNCTION_DESC_GPIO_OUTPUT(8),
+	FUNCTION_DESC_GPIO_OUTPUT(9),
+	FUNCTION_DESC_GPIO_OUTPUT(10),
+	FUNCTION_DESC_GPIO_OUTPUT(11),
+	FUNCTION_DESC_GPIO_OUTPUT(12),
+	FUNCTION_DESC_GPIO_OUTPUT(13),
+	FUNCTION_DESC_GPIO_OUTPUT(14),
+	FUNCTION_DESC_GPIO_OUTPUT(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT_HIGH(),
+	FUNCTION_DESC_GPIO_OUTPUT_LOW(),
+
+	FUNCTION_DES_DELAY_MS(10),
+	FUNCTION_DES_DELAY_MS(50),
+	FUNCTION_DES_DELAY_MS(100),
+	FUNCTION_DES_DELAY_MS(200),
+	FUNCTION_DES_DELAY_MS(500),
+};
+
+static struct serdes_chip_pinctrl_info bu18rl82_pinctrl_info = {
+	.pins = bu18rl82_pins_desc,
+	.num_pins = ARRAY_SIZE(bu18rl82_pins_desc),
+	.groups = bu18rl82_groups_desc,
+	.num_groups = ARRAY_SIZE(bu18rl82_groups_desc),
+	.functions = bu18rl82_functions_desc,
+	.num_functions = ARRAY_SIZE(bu18rl82_functions_desc),
+};
+
+void bu18rl82_bridge_swrst(struct serdes *serdes)
+{
+	int ret;
+
+	ret = serdes_reg_write(serdes, BU18RL82_REG_RESET,
+			       BIT(0) | BIT(1) | BIT(7));
+	if (ret < 0)
+		printf("%s: failed to reset bu18rl82 0x11 ret=%d\n",
+		       __func__, ret);
+
+	mdelay(20);
+
+	SERDES_DBG_CHIP("%s: serdes %s ret=%d\n",
+			__func__, serdes->dev->name, ret);
+}
+
+void bu18rl82_enable_hwint(struct serdes *serdes, int enable)
+{
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(bu18rl82_reg_ien); i++) {
+		if (enable) {
+			ret = serdes_reg_write(serdes, bu18rl82_reg_ien[i].reg,
+					       bu18rl82_reg_ien[i].ien);
+			if (ret)
+				printf("reg 0x%04x write error\n",
+				       bu18rl82_reg_ien[i].reg);
+		} else {
+			ret = serdes_reg_write(serdes, bu18rl82_reg_ien[i].reg, 0);
+			if (ret)
+				printf("reg 0x%04x write error\n",
+				       bu18rl82_reg_ien[i].reg);
+		}
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s ret=%d\n",
+			__func__,
+			serdes->dev->name, enable);
+}
+
+int bu18rl82_bridge_init(struct serdes *serdes)
+{
+	if (!dm_gpio_is_valid(&serdes->reset_gpio)) {
+		bu18rl82_bridge_swrst(serdes);
+		SERDES_DBG_CHIP("%s: serdes %s\n", __func__,
+				serdes->dev->name);
+	}
+
+	return 0;
+}
+
+int bu18rl82_bridge_enable(struct serdes *serdes)
+{
+	int ret = 0;
+
+	/* 1:enable 0:dsiable*/
+	bu18rl82_enable_hwint(serdes, 0);
+
+	SERDES_DBG_CHIP("%s: serdes %s ret=%d\n", __func__,
+			serdes->dev->name, ret);
+	return ret;
+}
+
+int bu18rl82_bridge_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+static struct serdes_chip_bridge_ops bu18rl82_bridge_ops = {
+	.init = bu18rl82_bridge_init,
+	.enable = bu18rl82_bridge_enable,
+	.disable = bu18rl82_bridge_disable,
+};
+
+static int bu18rl82_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param, unsigned int argument)
+{
+	switch (param) {
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		serdes_set_bits(serdes, bu18rl82_gpio_sw[pin_selector].reg,
+				bu18rl82_gpio_sw[pin_selector].mask,
+				FIELD_PREP(BIT(2) | BIT(1), argument));
+		SERDES_DBG_CHIP("%s: serdes %s pin=%d drive arg=0x%x\n",
+				__func__,
+				serdes->dev->name, pin_selector, argument);
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		serdes_set_bits(serdes, bu18rl82_gpio_pden[pin_selector].reg,
+				bu18rl82_gpio_pden[pin_selector].mask,
+				FIELD_PREP(BIT(4), argument));
+		SERDES_DBG_CHIP("%s: serdes %s pin=%d pull-down arg=0x%x\n",
+				__func__,
+				serdes->dev->name, pin_selector, argument);
+		break;
+	case PIN_CONFIG_OUTPUT:
+		serdes_set_bits(serdes, bu18rl82_gpio_oen[pin_selector].reg,
+				bu18rl82_gpio_oen[pin_selector].mask,
+				FIELD_PREP(BIT(3), argument));
+		SERDES_DBG_CHIP("%s: serdes %s pin=%d output arg=0x%x\n",
+				__func__,
+				serdes->dev->name, pin_selector, argument);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int bu18rl82_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+	u16 ms;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+		ms = fdata->mdelay;
+
+		offset = pin->number;
+		if (offset > 7)
+			dev_err(serdes->dev, "%s offset=%d > 7\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s id=0x%x off=%d\n",
+					__func__, serdes->dev->name,
+					fdata->gpio_id, offset);
+		if (!ms) {
+			serdes_set_bits(serdes, bu18rl82_gpio_oen[offset].reg,
+					bu18rl82_gpio_oen[offset].mask,
+					FIELD_PREP(BIT(3), fdata->gpio_rx_en));
+			serdes_set_bits(serdes, bu18rl82_gpio_id_low[offset].reg,
+					bu18rl82_gpio_id_low[offset].mask,
+					FIELD_PREP(GENMASK(7, 0),
+					(fdata->gpio_id & 0xff)));
+			serdes_set_bits(serdes, bu18rl82_gpio_id_high[offset].reg,
+					bu18rl82_gpio_id_high[offset].mask,
+					FIELD_PREP(GENMASK(2, 0),
+					((fdata->gpio_id >> 8) & 0x7)));
+			serdes_set_bits(serdes, bu18rl82_gpio_pden[offset].reg,
+					bu18rl82_gpio_pden[offset].mask,
+					FIELD_PREP(BIT(4), 0));
+		} else {
+			mdelay(ms);
+			SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
+		}
+	}
+
+	return 0;
+}
+
+static int bu18rl82_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p, num=%d\n",
+			__func__, serdes->chip_data->name, func->name,
+			func->data, grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 7)
+				dev_err(serdes->dev, "%s offset=%d > 7\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s: serdes %s id=0x%x, offset=%d\n",
+						__func__,
+						serdes->dev->name, fdata->gpio_id, offset);
+			serdes_set_bits(serdes, bu18rl82_gpio_oen[offset].reg,
+					bu18rl82_gpio_oen[offset].mask,
+					FIELD_PREP(BIT(3), fdata->gpio_rx_en));
+			serdes_set_bits(serdes, bu18rl82_gpio_id_low[offset].reg,
+					bu18rl82_gpio_id_low[offset].mask,
+					FIELD_PREP(GENMASK(7, 0),
+					(fdata->gpio_id & 0xff)));
+			serdes_set_bits(serdes, bu18rl82_gpio_id_high[offset].reg,
+					bu18rl82_gpio_id_high[offset].mask,
+					FIELD_PREP(GENMASK(2, 0),
+					((fdata->gpio_id >> 8) & 0x7)));
+			serdes_set_bits(serdes, bu18rl82_gpio_pden[offset].reg,
+					bu18rl82_gpio_pden[offset].mask,
+					FIELD_PREP(BIT(4), 0));
+		}
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops bu18rl82_pinctrl_ops = {
+	.pinconf_set = bu18rl82_pinctrl_config_set,
+	.pinmux_set = bu18rl82_pinctrl_set_pin_mux,
+	.pinmux_group_set = bu18rl82_pinctrl_set_grp_mux,
+};
+
+static int bu18rl82_gpio_direction_input(struct serdes *serdes,
+					 int gpio)
+{
+	return 0;
+}
+
+static int bu18rl82_gpio_direction_output(struct serdes *serdes,
+					  int gpio, int value)
+{
+	return 0;
+}
+
+static int bu18rl82_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+int bu18rl82_gpio_set_level(struct serdes *serdes,
+			    int gpio, int value)
+{
+	return 0;
+}
+
+static int bu18rl82_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int bu18rl82_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops bu18rl82_gpio_ops = {
+	.direction_input = bu18rl82_gpio_direction_input,
+	.direction_output = bu18rl82_gpio_direction_output,
+	.get_level = bu18rl82_gpio_get_level,
+	.set_level = bu18rl82_gpio_set_level,
+	.set_config = bu18rl82_gpio_set_config,
+	.to_irq = bu18rl82_gpio_to_irq,
+};
+
+struct serdes_chip_data serdes_bu18rl82_data = {
+	.name		= "bu18rl82",
+	.serdes_type	= TYPE_DES,
+	.serdes_id	= ROHM_ID_BU18RL82,
+	.pinctrl_info	= &bu18rl82_pinctrl_info,
+	.pinctrl_ops	= &bu18rl82_pinctrl_ops,
+	.gpio_ops	= &bu18rl82_gpio_ops,
+	.bridge_ops	= &bu18rl82_bridge_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_bu18rl82_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18rl82.h b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18rl82.h
new file mode 100644
index 0000000000..77a8d045e8
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18rl82.h
@@ -0,0 +1,395 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * include/linux/mfd/serdes/gpio.h -- GPIO for different serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_ROHM_BU18RL82_H__
+#define __MFD_SERDES_ROHM_BU18RL82_H__
+#define BU18RL82_REG_RESET 0X000E
+
+#define BU18RL82_BLOCK_EN_CLLRX0 0x0011	//h [0] 1’b1
+#define BU18RL82_BLOCK_EN_LVDSTX0 0x0011	//h [1] 1’b0
+#define BU18RL82_BLOCK_EN_VPLL0 0x0011	//h [3] 1’b0
+#define BU18RL82_BLOCK_EN_SSCG0 0x0011	//h [4] 1’b0
+#define BU18RL82_BLOCK_EN_CLLRX1 0x0012	//h [0] 1’b1
+#define BU18RL82_BLOCK_EN_LVDSTX1 0x0012	//h [1] 1’b0
+#define BU18RL82_BLOCK_EN_VPLL1 0x0012	//h [3] 1’b0
+#define BU18RL82_BLOCK_EN_SSCG1 0x0012	//h [4] 1’b0
+#define BU18RL82_BLOCK_EN_CLLTX 0x0013	//h [0] 1’b0
+#define BU18RL82_BLOCK_EN_FSAFETY 0x0013	//h [1] 1’b0
+
+#define BU18RL82_IO_SW_GPIO0 0x0057		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO0 0x0057	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO0 0x0057	//h [4] 1’b1
+#define BU18RL82_IO_SW_GPIO1 0x005A		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO1 0x005A	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO1 0x005A	//h [4] 1’b1
+#define BU18RL82_IO_SW_GPIO2 0x005D		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO2 0x005D	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO2 0x005D	//h [4] 1’b1
+#define BU18RL82_IO_SW_GPIO3 0x0060		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO3 0x0060	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO3 0x0060	//h [4] 1’b1
+#define BU18RL82_IO_SW_GPIO4 0x0063		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO4 0x0063	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO4 0x0063	//h [4] 1’b1
+#define BU18RL82_IO_SW_GPIO5 0x0066		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO5 0x0066	//h [2:1] 2’b00
+#define BU18RL82_IO_PDEN_GPIO5 0x0066	//h [3] 1’b1
+#define BU18RL82_IO_SW_GPIO6 0x0069		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO6 0x0069	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO6 0x0069	//h [4] 1’b1
+#define BU18RL82_IO_SW_GPIO7 0x006C		//h [2:1] 2’b00
+#define BU18RL82_IO_OEN_GPIO7 0x006C	//h [3] 1’b1
+#define BU18RL82_IO_PDEN_GPIO7 0x006C	//h [4] 1’b1
+
+/*
+ * gpio register for define connection with des gpiox,
+ * 11bits such as 0x002c:002b=[b2..b0 b7...b0]
+ * default value:
+ * ser gpio0-->des gpio0
+ * ser gpio1-->des gpio1
+ * ser gpio2-->des gpio2
+ * ser gpio3-->des gpio3
+ */
+#define BU18RL82_GPIO_SEL0_HIGH 0x0059	//h [2:0],
+#define BU18RL82_GPIO_SEL0_LOW 0x0058	//h [7:0]} 11’h002
+#define BU18RL82_GPIO_SEL1_HIGH 0x005C	//h [2:0],
+#define BU18RL82_GPIO_SEL1_LOW 0x005B	//h [7:0]} 11’h003
+#define BU18RL82_GPIO_SEL2_HIGH 0x005F	//h [2:0],
+#define BU18RL82_GPIO_SEL2_LOW 0x005E	//h [7:0]} 11’h012
+#define BU18RL82_GPIO_SEL3_HIGH 0x0062	//h [2:0],
+#define BU18RL82_GPIO_SEL3_LOW 0x0061	//h [7:0]} 11’h013
+#define BU18RL82_GPIO_SEL4_HIGH 0x0065	//h [2:0],
+#define BU18RL82_GPIO_SEL4_LOW 0x0064	//h [7:0]} 11’h006
+#define BU18RL82_GPIO_SEL5_HIGH 0x0068	//h [2:0],
+#define BU18RL82_GPIO_SEL5_LOW 0x0067	//h [7:0]} 11’h007
+#define BU18RL82_GPIO_SEL6_HIGH 0x006B	//h [2:0],
+#define BU18RL82_GPIO_SEL6_LOW 0x006A	//h [7:0]} 11’h008
+#define BU18RL82_GPIO_SEL7_HIGH 0x006E	//h [2:0],
+#define BU18RL82_GPIO_SEL7_LOW 0x006D	//h [7:0]} 11’h009
+
+/*gpio register for define bu18rl82 gpio pin, and gpio0 to gpio0 default*/
+#define BU18RL82_BCCTX0__SEL_GPI0 0x042B	//h [5:0] 6’h02
+#define BU18RL82_BCCTX0__SEL_GPI1 0x042C	//h [5:0] 6’h03
+#define BU18RL82_BCCTX0__SEL_GPI2 0x042D	//h [5:0] 6’h04
+#define BU18RL82_BCCTX0__SEL_GPI3 0x042E	//h [5:0] 6’h05
+#define BU18RL82_BCCTX0__SEL_GPI4 0x042F	//h [5:0] 6’h06
+#define BU18RL82_BCCTX0__SEL_GPI5 0x0430	//h [5:0] 6’h07
+#define BU18RL82_BCCTX0__SEL_GPI6 0x0431	//h [5:0] 6’h08
+#define BU18RL82_BCCTX0__SEL_GPI7 0x0432	//h [5:0] 6’h09
+#define BU18RL82_BCCTX1__SEL_GPI0 0x052B	//h [5:0] 6’h02
+#define BU18RL82_BCCTX1__SEL_GPI1 0x052C	//h [5:0] 6’h03
+#define BU18RL82_BCCTX1__SEL_GPI2 0x052D	//h [5:0] 6’h04
+#define BU18RL82_BCCTX1__SEL_GPI3 0x052E	//h [5:0] 6’h05
+#define BU18RL82_BCCTX1__SEL_GPI4 0x052F	//h [5:0] 6’h06
+#define BU18RL82_BCCTX1__SEL_GPI5 0x0530	//h [5:0] 6’h07
+#define BU18RL82_BCCTX1__SEL_GPI6 0x0531	//h [5:0] 6’h08
+#define BU18RL82_BCCTX1__SEL_GPI7 0x0532	//h [5:0] 6’h09
+
+#define BU18RL82_IEN_CLLRX0_LINK_UNLOCK 0x0109	//h [1] 1’b0
+#define BU18RL82_IEN_CLLRX0_BIT_ERR 0x0109		//h [3] 1’b0
+#define BU18RL82_IEN_CLLRX0_ERR_CNT_OVF 0x0109	//h [4] 1’b0
+#define BU18RL82_IEN_CLLRX1_LINK_UNLOCK 0x010B	//h [1] 1’b0
+#define BU18RL82_IEN_CLLRX1_BIT_ERR 0x010B		//h [3] 1’b0
+#define BU18RL82_IEN_CLLRX1_ERR_CNT_OVF 0x010B	//h [4] 1’b0
+#define BU18RL82_IEN_FCCRX0_CRCERR 0x010D		//h [0] 1’b0
+#define BU18RL82_IEN_FCCRX1_CRCERR 0x010E		//h [0] 1’b0
+#define BU18RL82_IEN_BCCDES0_ERR_CRC 0x010F		//h [3] 1’b0
+#define BU18RL82_IEN_CLLRX0_CRCERR_R  0x0110	//h [0] 1’b0
+#define BU18RL82_IEN_CLLRX0_CRCERR_G 0x0110		//h [1] 1’b0
+#define BU18RL82_IEN_CLLRX0_CRCERR_B 0x0110		//h [2] 1’b0
+#define BU18RL82_IEN_CLLRX1_CRCERR_R 0x0111		//h [0] 1’b0
+#define BU18RL82_IEN_CLLRX1_CRCERR_G 0x0111		//h [1] 1’b0
+#define BU18RL82_IEN_CLLRX1_CRCERR_B 0x0111		//h [2] 1’b0
+#define BU18RL82_IEN_FS_IMG_STATUS0 0x0112		//h [0] 1’b0
+#define BU18RL82_IEN_FS_IMG_STATUS1 0x0112		//h [1] 1’b0
+#define BU18RL82_IEN_FS_IMG_STATUS2 0x0112		//h [2] 1’b0
+#define BU18RL82_IEN_FS_IMG_STATUS3 0x0112		//h [3] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION0 0x0113	//h [0] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION1 0x0113	//h [1] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION2 0x0113	//h [2] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION3 0x0113	//h [3] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION4 0x0113	//h [4] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION5 0x0113	//h [5] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION6 0x0113	//h [6] 1’b0
+#define BU18RL82_IEN_FS_IMG_ERR_REGION7 0x0113	//h [7] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO0 0x0114		//h [0] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO1 0x0114		//h [1] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO2 0x0114		//h [2] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO3 0x0114		//h [3] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO4 0x0114		//h [4] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO5 0x0114		//h [5] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO6 0x0114		//h [6] 1’b0
+#define BU18RL82_IEN_IO_STUCK_GPIO7 0x0114		//h [7] 1’b0
+#define BU18RL82_IEN_IO_STUCK_IRQ 0x0115		//h [1] 1’b0
+#define BU18RL82_IEN_IDS_UNSTABLE 0x0115		//h [7] 1’b0
+#define BU18RL82_IEN_I2C_A_TIMEOUT 0x0116		//h [0] 1’b0
+#define BU18RL82_IEN_I2C_A_XMIT_ERR 0x0116		//h [1] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE0 0x0117	//h [0] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE1 0x0117	//h [1] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE2 0x0117	//h [2] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE3 0x0117	//h [3] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE4 0x0117	//h [4] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE5 0x0117	//h [5] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE6 0x0117	//h [6] 1’b0
+#define BU18RL82_IEN_REGCRC_ERR_PAGE7 0x0117	//h [7] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLKIN_STOP 0x0118			//h [0] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLKIN_UNLOCK 0x0118			//h [1] 1’b0
+#define BU18RL82_IEN_CLKDETECT_OSC_STOP 0x0118				//h [4] 1’b0
+#define BU18RL82_IEN_CLKDETECT_OSC_UNLOCK 0x0118			//h [5] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_STOP 0x0119		//h [0] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_UNLOCK 0x0119	//h [1] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX0_CLK_STOP 0x0119		//h [4] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX0_CLK_UNLOCK 0x0119	//h [5] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_STOP 0x011A		//h [0] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_UNLOCK 0x011A	//h [1] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX1_CLK_STOP 0x011A		//h [4] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX1_CLK_UNLOCK 0x011A	//h [5] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP 0x011B		//h [0] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x011B	//h [1] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLTX0_PLLREF_STOP 0x011B	//h [4] 1’b0
+#define BU18RL82_IEN_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x011B	//h [5] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_STOP 0x011C	//h [0] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_UNLOCK0x011C	//h [1] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX1_PLLREF_STOP 0x011C	//h [4] 1’b0
+#define BU18RL82_IEN_CLKDETECT_LVDSTX1_PLLREF_UNLOCK 0x011C	//h [5] 1’b0
+
+#define BU18RL82_ISR_CLEAR_ALL 0x0105			//h [0] 1’b0
+#define BU18RL82_ISR_CLLRX0_LINK_UNLOCK 0x0129	//h [1] 1’b0
+#define BU18RL82_ISR_CLLRX0_BIT_ERR 0x0129		//h [3] 1’b0
+#define BU18RL82_ISR_CLLRX0_ERR_CNT_OVF 0x0129	//h [4] 1’b0
+#define BU18RL82_ISR_CLLRX1_ERR_CNT_OVF 0x012B	//h [4] 1’b0
+#define BU18RL82_ISR_CLLRX1_LINK_UNLOCK 0x012B	//h [1] 1’b0
+#define BU18RL82_ISR_CLLRX1_BIT_ERR 0x012B		//h [3] 1’b0
+#define BU18RL82_ISR_FCCRX0_CRCERR 0x012D		//h [0] 1’b0
+#define BU18RL82_ISR_FCCRX1_CRCERR 0x012E		//h [0] 1’b0
+#define BU18RL82_ISR_BCCDES0_ERR_CRC 0x012F		//h [3] 1’b0
+#define BU18RL82_ISR_CLLRX0_CRCERR_R  0x0130	//h [0] 1’b0
+#define BU18RL82_ISR_CLLRX0_CRCERR_G 0x0130		//h [1] 1’b0
+#define BU18RL82_ISR_CLLRX0_CRCERR_B 0x0130		//h [2] 1’b0
+#define BU18RL82_ISR_CLLRX1_CRCERR_R 0x0131		//h [0] 1’b0
+#define BU18RL82_ISR_CLLRX1_CRCERR_G 0x0131		//h [1] 1’b0
+#define BU18RL82_ISR_CLLRX1_CRCERR_B 0x0131		//h [2] 1’b0
+#define BU18RL82_ISR_FS_IMG_STATUS0 0x0132		//h [0] 1’b0
+#define BU18RL82_ISR_FS_IMG_STATUS1 0x0132		//h [1] 1’b0
+#define BU18RL82_ISR_FS_IMG_STATUS2 0x0132		//h [2] 1’b0
+#define BU18RL82_ISR_FS_IMG_STATUS3 0x0132		//h [3] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION0 0x0133	//h [0] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION1 0x0133	//h [1] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION2 0x0133	//h [2] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION3 0x0133	//h [3] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION4 0x0133	//h [4] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION5 0x0133	//h [5] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION6 0x0133	//h [6] 1’b0
+#define BU18RL82_ISR_FS_IMG_ERR_REGION7 0x0133	//h [7] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO0 0x0134	//h [0] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO1 0x0134	//h [1] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO2 0x0134	//h [2] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO3 0x0134	//h [3] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO4 0x0134	//h [4] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO5 0x0134	//h [5] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO6 0x0134	//h [6] 1’b0
+#define BU18RL82_ISR_IO_STUCK_GPIO7 0x0134	//h [7] 1’b0
+#define BU18RL82_ISR_IO_STUCK_IRQ 0x0135	//h [1] 1’b0
+#define BU18RL82_ISR_IDS_UNSTABLE 0x0135	//h [7] 1’b0
+#define BU18RL82_ISR_I2C_A_TIMEOUT 0x0136	//h [0] 1’b0
+#define BU18RL82_ISR_I2C_A_XMIT_ERR 0x0136	//h [1] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE0 0x0137	//h [0] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE1 0x0137	//h [1] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE2 0x0137	//h [2] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE3 0x0137	//h [3] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE4 0x0137	//h [4] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE5 0x0137	//h [5] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE6 0x0137	//h [6] 1’b0
+#define BU18RL82_ISR_REGCRC_ERR_PAGE7 0x0137	//h [7] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLKIN_STOP 0x0138			//h [0] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLKIN_UNLOCK 0x0138			//h [1] 1’b0
+#define BU18RL82_ISR_CLKDETECT_OSC_STOP 0x0138				//h [4] 1’b0
+#define BU18RL82_ISR_CLKDETECT_OSC_UNLOCK 0x0138			//h [5] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_STOP 0x0139		//h [0] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_UNLOCK 0x0139	//h [1] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX0_CLK_STOP 0x0139		//h [4] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX0_CLK_UNLOCK 0x0139	//h [5] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_STOP 0x013A		//h [0] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_UNLOCK 0x013A	//h [1] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX1_CLK_STOP 0x013A		//h [4] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX1_CLK_UNLOCK 0x013A	//h [5] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP 0x013B		//h [0] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x013B	//h [1] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLTX0_PLLREF_STOP 0x013B	//h [4] 1’b0
+#define BU18RL82_ISR_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x013B	//h [5] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_STOP 0x013C	//h [0] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_UNLOCK0x013C	//h [1] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX1_PLLREF_STOP 0x013C	//h [4] 1’b0
+#define BU18RL82_ISR_CLKDETECT_LVDSTX1_PLLREF_UNLOCK 0x013C	//h [5] 1’b0
+
+struct bu18rl82_gpio_sw_reg {
+	unsigned int reg;
+	unsigned int mask;	//2/4/6/8ma
+};
+
+struct bu18rl82_gpio_oen_reg {
+	unsigned int reg;
+	unsigned int mask;	//0:output 1:input
+};
+
+struct bu18rl82_gpio_pden_reg {
+	unsigned int reg;
+	unsigned int mask;	//0:no pulldown 1:connect pulldown
+};
+
+struct bu18rl82_gpio_id_low_reg {
+	unsigned int reg;
+	unsigned int mask;	//b2b1b0
+};
+
+struct bu18rl82_gpio_id_high_reg {
+	unsigned int reg;
+	unsigned int mask;	//b11b10b9b8b7b6b5b4b3
+};
+
+static const struct bu18rl82_gpio_sw_reg bu18rl82_gpio_sw[8] = {
+	{BU18RL82_IO_SW_GPIO0, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO1, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO2, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO3, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO4, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO5, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO6, BIT(2) | BIT(1)},
+	{BU18RL82_IO_SW_GPIO7, BIT(2) | BIT(1)},
+};
+
+static const struct bu18rl82_gpio_oen_reg bu18rl82_gpio_oen[8] = {
+	{BU18RL82_IO_OEN_GPIO0, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO1, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO2, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO3, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO4, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO5, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO6, BIT(3)},
+	{BU18RL82_IO_OEN_GPIO7, BIT(3)},
+};
+
+static const struct bu18rl82_gpio_pden_reg bu18rl82_gpio_pden[8] = {
+	{BU18RL82_IO_PDEN_GPIO0, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO1, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO2, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO3, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO4, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO5, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO6, BIT(4)},
+	{BU18RL82_IO_PDEN_GPIO7, BIT(4)},
+};
+
+static const struct bu18rl82_gpio_id_low_reg bu18rl82_gpio_id_low[8] = {
+	{BU18RL82_GPIO_SEL0_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL1_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL2_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL3_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL4_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL5_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL6_LOW, GENMASK(7, 0)},
+	{BU18RL82_GPIO_SEL7_LOW, GENMASK(7, 0)},
+};
+
+static const struct bu18rl82_gpio_id_high_reg bu18rl82_gpio_id_high[8] = {
+	{BU18RL82_GPIO_SEL0_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL1_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL2_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL3_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL4_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL5_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL6_HIGH, GENMASK(2, 0)},
+	{BU18RL82_GPIO_SEL7_HIGH, GENMASK(2, 0)},
+};
+
+struct bu18rl82_ien_reg {
+	unsigned int reg;
+	unsigned int ien;
+};
+
+struct bu18rl82_isr_reg {
+	unsigned int reg;
+	unsigned int isr;
+};
+
+struct bu18rl82_gpio_reg {
+	unsigned int reg;
+	unsigned int val;
+};
+
+static const struct bu18rl82_ien_reg bu18rl82_reg_ien[18] = {
+	{BU18RL82_IEN_CLLRX0_LINK_UNLOCK,
+	 BIT(1) | BIT(3) | BIT(4)},
+	{BU18RL82_IEN_CLLRX1_LINK_UNLOCK,
+	 BIT(1) | BIT(3) | BIT(4)},
+	{BU18RL82_IEN_FCCRX0_CRCERR, BIT(0)},
+	{BU18RL82_IEN_FCCRX1_CRCERR, BIT(0)},
+
+	{BU18RL82_IEN_BCCDES0_ERR_CRC, BIT(3)},
+	{BU18RL82_IEN_CLLRX0_CRCERR_R,
+	 BIT(0) | BIT(1) | BIT(2)},
+	{BU18RL82_IEN_CLLRX1_CRCERR_R,
+	 BIT(0) | BIT(1) | BIT(2)},
+
+	{BU18RL82_IEN_FS_IMG_STATUS0,
+	 BIT(0) | BIT(1) | BIT(2) | BIT(3)},
+	{BU18RL82_IEN_FS_IMG_ERR_REGION0, 0xff},
+	{BU18RL82_IEN_IO_STUCK_GPIO0, 0xff},
+	{BU18RL82_IEN_IO_STUCK_IRQ, BIT(1) | BIT(7)},
+	{BU18RL82_IEN_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
+
+	{BU18RL82_IEN_REGCRC_ERR_PAGE0, 0xff},
+	{BU18RL82_IEN_CLKDETECT_CLKIN_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+};
+
+static const struct bu18rl82_isr_reg bu18rl82_reg_isr[18] = {
+	{BU18RL82_ISR_CLLRX0_LINK_UNLOCK,
+	 BIT(1) | BIT(3) | BIT(4)},
+	{BU18RL82_ISR_CLLRX1_LINK_UNLOCK,
+	 BIT(1) | BIT(3) | BIT(4)},
+	{BU18RL82_ISR_FCCRX0_CRCERR, BIT(0)},
+	{BU18RL82_ISR_FCCRX1_CRCERR, BIT(0)},
+
+	{BU18RL82_ISR_BCCDES0_ERR_CRC, BIT(3)},
+	{BU18RL82_ISR_CLLRX0_CRCERR_R,
+	 BIT(0) | BIT(1) | BIT(2)},
+	{BU18RL82_ISR_CLLRX1_CRCERR_R,
+	 BIT(0) | BIT(1) | BIT(2)},
+
+	{BU18RL82_ISR_FS_IMG_STATUS0,
+	 BIT(0) | BIT(1) | BIT(2) | BIT(3)},
+	{BU18RL82_ISR_FS_IMG_ERR_REGION0, 0xff},
+	{BU18RL82_ISR_IO_STUCK_GPIO0, 0xff},
+	{BU18RL82_ISR_IO_STUCK_IRQ, BIT(1) | BIT(7)},
+	{BU18RL82_ISR_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
+
+	{BU18RL82_ISR_REGCRC_ERR_PAGE0, 0xff},
+	{BU18RL82_ISR_CLKDETECT_CLKIN_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18tl82.c b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18tl82.c
new file mode 100644
index 0000000000..36f63b92d2
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18tl82.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * rohm-bu18tl82.c  --  I2C register interface access for bu18tl82 serdes chip
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "../core.h"
+#include "rohm-bu18tl82.h"
+
+#define PINCTRL_GROUP(a, b, c) { .name = a, .pins = b, .num_pins = c}
+
+static int BU18TL82_GPIO0_pins[] = {0};
+static int BU18TL82_GPIO1_pins[] = {1};
+static int BU18TL82_GPIO2_pins[] = {2};
+static int BU18TL82_GPIO3_pins[] = {3};
+static int BU18TL82_GPIO4_pins[] = {4};
+static int BU18TL82_GPIO5_pins[] = {5};
+static int BU18TL82_GPIO6_pins[] = {6};
+static int BU18TL82_GPIO7_pins[] = {7};
+
+#define GROUP_DESC(nm) \
+{ \
+	.name = #nm, \
+	.pins = nm ## _pins, \
+	.num_pins = ARRAY_SIZE(nm ## _pins), \
+}
+
+struct serdes_function_data {
+	u8 gpio_rx_en:1;
+	u16 gpio_id;
+};
+
+static const char *serdes_gpio_groups[] = {
+	"BU18TL82_GPIO0", "BU18TL82_GPIO1", "BU18TL82_GPIO2", "BU18TL82_GPIO3",
+	"BU18TL82_GPIO4", "BU18TL82_GPIO5", "BU18TL82_GPIO6", "BU18TL82_GPIO7",
+};
+
+/*des -> ser -> soc*/
+#define FUNCTION_DESC_GPIO_INPUT(id) \
+{ \
+	.name = "DES_GPIO"#id"_TO_SER", \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 0, .gpio_id = (id < 8) ? (id + 2) : (id + 3) } \
+	}, \
+} \
+
+/*soc -> ser -> des*/
+#define FUNCTION_DESC_GPIO_OUTPUT(id) \
+{ \
+	.name = "SER_TO_DES_GPIO"#id, \
+	.group_names = serdes_gpio_groups, \
+	.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
+	.data = (void *)(const struct serdes_function_data []) { \
+		{ .gpio_rx_en = 1, .gpio_id = (id < 8) ? (id + 2) : (id + 3) } \
+	}, \
+} \
+
+static struct pinctrl_pin_desc bu18tl82_pins_desc[] = {
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO0, "BU18TL82_GPIO0"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO1, "BU18TL82_GPIO1"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO2, "BU18TL82_GPIO2"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO3, "BU18TL82_GPIO3"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO4, "BU18TL82_GPIO4"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO5, "BU18TL82_GPIO5"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO6, "BU18TL82_GPIO6"),
+	PINCTRL_PIN(ROHM_BU18TL82_GPIO7, "BU18TL82_GPIO7"),
+};
+
+static struct group_desc bu18tl82_groups_desc[] = {
+	GROUP_DESC(BU18TL82_GPIO0),
+	GROUP_DESC(BU18TL82_GPIO1),
+	GROUP_DESC(BU18TL82_GPIO2),
+	GROUP_DESC(BU18TL82_GPIO3),
+	GROUP_DESC(BU18TL82_GPIO4),
+	GROUP_DESC(BU18TL82_GPIO5),
+	GROUP_DESC(BU18TL82_GPIO6),
+	GROUP_DESC(BU18TL82_GPIO7),
+};
+
+static struct function_desc bu18tl82_functions_desc[] = {
+	FUNCTION_DESC_GPIO_INPUT(0),
+	FUNCTION_DESC_GPIO_INPUT(1),
+	FUNCTION_DESC_GPIO_INPUT(2),
+	FUNCTION_DESC_GPIO_INPUT(3),
+	FUNCTION_DESC_GPIO_INPUT(4),
+	FUNCTION_DESC_GPIO_INPUT(5),
+	FUNCTION_DESC_GPIO_INPUT(6),
+	FUNCTION_DESC_GPIO_INPUT(7),
+	FUNCTION_DESC_GPIO_INPUT(8),
+	FUNCTION_DESC_GPIO_INPUT(9),
+	FUNCTION_DESC_GPIO_INPUT(10),
+	FUNCTION_DESC_GPIO_INPUT(11),
+	FUNCTION_DESC_GPIO_INPUT(12),
+	FUNCTION_DESC_GPIO_INPUT(13),
+	FUNCTION_DESC_GPIO_INPUT(14),
+	FUNCTION_DESC_GPIO_INPUT(15),
+
+	FUNCTION_DESC_GPIO_OUTPUT(0),
+	FUNCTION_DESC_GPIO_OUTPUT(1),
+	FUNCTION_DESC_GPIO_OUTPUT(2),
+	FUNCTION_DESC_GPIO_OUTPUT(3),
+	FUNCTION_DESC_GPIO_OUTPUT(4),
+	FUNCTION_DESC_GPIO_OUTPUT(5),
+	FUNCTION_DESC_GPIO_OUTPUT(6),
+	FUNCTION_DESC_GPIO_OUTPUT(7),
+	FUNCTION_DESC_GPIO_OUTPUT(8),
+	FUNCTION_DESC_GPIO_OUTPUT(9),
+	FUNCTION_DESC_GPIO_OUTPUT(10),
+	FUNCTION_DESC_GPIO_OUTPUT(11),
+	FUNCTION_DESC_GPIO_OUTPUT(12),
+	FUNCTION_DESC_GPIO_OUTPUT(13),
+	FUNCTION_DESC_GPIO_OUTPUT(14),
+	FUNCTION_DESC_GPIO_OUTPUT(15),
+};
+
+static struct serdes_chip_pinctrl_info bu18tl82_pinctrl_info = {
+	.pins = bu18tl82_pins_desc,
+	.num_pins = ARRAY_SIZE(bu18tl82_pins_desc),
+	.groups = bu18tl82_groups_desc,
+	.num_groups = ARRAY_SIZE(bu18tl82_groups_desc),
+	.functions = bu18tl82_functions_desc,
+	.num_functions = ARRAY_SIZE(bu18tl82_functions_desc),
+};
+
+void bu18tl82_bridge_swrst(struct serdes *serdes)
+{
+	int ret;
+
+	ret = serdes_reg_write(serdes, BU18TL82_REG_SWRST_INTERNAL, 0x00ef);
+	if (ret < 0)
+		dev_err(serdes->dev,
+			"%s: failed to reset serdes 0x11 ret=%d\n",
+			__func__, ret);
+
+	ret = serdes_reg_write(serdes, BU18TL82_REG_SWRST_MIPIRX, 0x0003);
+	if (ret < 0)
+		dev_err(serdes->dev,
+			"%s: failed to reset serdes 0x12 ret=%d\n",
+			__func__, ret);
+
+	mdelay(20);
+
+	SERDES_DBG_CHIP("%s: %s ret=%d\n",
+			__func__, serdes->dev->name, ret);
+}
+
+void bu18tl82_enable_hwint(struct serdes *serdes, int enable)
+{
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(bu18tl82_reg_ien); i++) {
+		if (enable) {
+			ret = serdes_reg_write(serdes, bu18tl82_reg_ien[i].reg,
+					       bu18tl82_reg_ien[i].ien);
+			if (ret)
+				printf("%s %s reg 0x%04x write error\n",
+				       __func__,
+				       serdes->dev->name, bu18tl82_reg_ien[i].reg);
+		} else {
+			ret = serdes_reg_write(serdes, bu18tl82_reg_ien[i].reg, 0);
+			if (ret)
+				printf("%s %s reg 0x%04x write error\n",
+				       __func__,
+				       serdes->dev->name, bu18tl82_reg_ien[i].reg);
+		}
+	}
+
+	SERDES_DBG_CHIP("%s: %s enable=%d\n", __func__,
+			serdes->dev->name, enable);
+}
+
+int bu18tl82_bridge_init(struct serdes *serdes)
+{
+	if (!dm_gpio_is_valid(&serdes->reset_gpio))
+		bu18tl82_bridge_swrst(serdes);
+
+	SERDES_DBG_CHIP("%s: %s\n", __func__,
+			serdes->dev->name);
+
+	return 0;
+}
+
+int bu18tl82_bridge_enable(struct serdes *serdes)
+{
+	return 0;
+}
+
+int bu18tl82_bridge_disable(struct serdes *serdes)
+{
+	return 0;
+}
+
+int bu18tl82_bridge_get_modes(struct serdes *serdes)
+{
+	return 0;
+}
+
+int bu18tl82_bridge_pre_enable(struct serdes *serdes)
+{
+	int ret = 0;
+
+	/* 1:enable 0:dsiable*/
+	bu18tl82_enable_hwint(serdes, 0);
+
+	mdelay(160);
+
+	SERDES_DBG_CHIP("%s: %s ret=%d\n", __func__,
+			serdes->dev->name, ret);
+
+	return ret;
+}
+
+bool bu18tl82_bridge_detect(struct serdes *serdes)
+{
+	return true;
+}
+
+static struct serdes_chip_bridge_ops bu18tl82_bridge_ops = {
+	.init = bu18tl82_bridge_init,
+	.get_modes = bu18tl82_bridge_get_modes,
+	.pre_enable = bu18tl82_bridge_pre_enable,
+	.enable = bu18tl82_bridge_enable,
+	.disable = bu18tl82_bridge_disable,
+	.detect = bu18tl82_bridge_detect,
+};
+
+static int bu18tl82_pinctrl_config_set(struct serdes *serdes,
+				       unsigned int pin_selector,
+				       unsigned int param, unsigned int argument)
+{
+	switch (param) {
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		serdes_set_bits(serdes, bu18tl82_gpio_sw[pin_selector].reg,
+				bu18tl82_gpio_sw[pin_selector].mask,
+				FIELD_PREP(BIT(2) | BIT(1), argument));
+		SERDES_DBG_CHIP("%s: serdes %s pin=%d drv arg=0x%x\n",
+				 __func__,
+				 serdes->dev->name, pin_selector, argument);
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		serdes_set_bits(serdes, bu18tl82_gpio_pden[pin_selector].reg,
+				bu18tl82_gpio_pden[pin_selector].mask,
+				FIELD_PREP(BIT(4), argument));
+		SERDES_DBG_CHIP("%s: serdes %s pin=%d pull-down arg=0x%x\n",
+				 __func__,
+				 serdes->dev->name, pin_selector, argument);
+		break;
+
+	case PIN_CONFIG_OUTPUT:
+		serdes_set_bits(serdes, bu18tl82_gpio_oen[pin_selector].reg,
+				bu18tl82_gpio_oen[pin_selector].mask,
+				FIELD_PREP(BIT(3), argument));
+		SERDES_DBG_CHIP("%s: serdes %s pin=%d output arg=0x%x\n",
+				 __func__,
+				 serdes->dev->name, pin_selector, argument);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int bu18tl82_pinctrl_set_pin_mux(struct serdes *serdes,
+					unsigned int pin_selector,
+					unsigned int func_selector)
+{
+	struct function_desc *func;
+	struct pinctrl_pin_desc *pin;
+	int offset;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
+	if (!pin) {
+		printf("%s: pin is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			pin->name, pin->number);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		offset = pin->number;
+		if (offset > 7)
+			dev_err(serdes->dev, "%s gpio offset=%d > 7\n",
+				serdes->dev->name, offset);
+		else
+			SERDES_DBG_CHIP("%s: serdes %s gpio=0x%x, off=%d\n",
+					__func__, serdes->dev->name,
+					fdata->gpio_id, offset);
+		serdes_set_bits(serdes, bu18tl82_gpio_oen[offset].reg,
+				bu18tl82_gpio_oen[offset].mask,
+				FIELD_PREP(BIT(3), fdata->gpio_rx_en));
+		serdes_set_bits(serdes, bu18tl82_gpio_id_low[offset].reg,
+				bu18tl82_gpio_id_low[offset].mask,
+				FIELD_PREP(GENMASK(7, 0),
+				(fdata->gpio_id & 0xff)));
+		serdes_set_bits(serdes, bu18tl82_gpio_id_high[offset].reg,
+				bu18tl82_gpio_id_high[offset].mask,
+				FIELD_PREP(GENMASK(2, 0),
+				((fdata->gpio_id >> 8) & 0x7)));
+		serdes_set_bits(serdes, bu18tl82_gpio_pden[offset].reg,
+				bu18tl82_gpio_pden[offset].mask,
+				FIELD_PREP(BIT(4), 0));
+	}
+
+	return 0;
+}
+
+static int bu18tl82_pinctrl_set_grp_mux(struct serdes *serdes,
+					unsigned int group_selector,
+					unsigned int func_selector)
+{
+	struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
+	struct function_desc *func;
+	struct group_desc *grp;
+	int i, offset;
+
+	func = &serdes->chip_data->pinctrl_info->functions[func_selector];
+	if (!func) {
+		printf("%s: func is null\n", __func__);
+		return -EINVAL;
+	}
+
+	grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
+	if (!grp) {
+		printf("%s: grp is null\n", __func__);
+		return -EINVAL;
+	}
+
+	SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p, num=%d\n",
+			__func__, serdes->dev->name,
+			func->name, func->data,
+			grp->name, grp->data, grp->num_pins);
+
+	if (func->data) {
+		struct serdes_function_data *fdata = func->data;
+
+		for (i = 0; i < grp->num_pins; i++) {
+			offset = grp->pins[i] - pinctrl->pin_base;
+			if (offset > 7)
+				dev_err(serdes->dev, "%s gpio offset=%d > 7\n",
+					serdes->dev->name, offset);
+			else
+				SERDES_DBG_CHIP("%s serdes %s io=0x%x off=%d\n",
+						__func__, serdes->dev->name,
+						fdata->gpio_id, offset);
+			serdes_set_bits(serdes, bu18tl82_gpio_oen[offset].reg,
+					bu18tl82_gpio_oen[offset].mask,
+					FIELD_PREP(BIT(3), fdata->gpio_rx_en));
+			serdes_set_bits(serdes, bu18tl82_gpio_id_low[offset].reg,
+					bu18tl82_gpio_id_low[offset].mask,
+					FIELD_PREP(GENMASK(7, 0),
+					(fdata->gpio_id & 0xff)));
+			serdes_set_bits(serdes, bu18tl82_gpio_id_high[offset].reg,
+					bu18tl82_gpio_id_high[offset].mask,
+					FIELD_PREP(GENMASK(2, 0),
+					((fdata->gpio_id >> 8) & 0x7)));
+			serdes_set_bits(serdes, bu18tl82_gpio_pden[offset].reg,
+					bu18tl82_gpio_pden[offset].mask,
+					FIELD_PREP(BIT(4), 0));
+		}
+	}
+
+	return 0;
+}
+
+static struct serdes_chip_pinctrl_ops bu18tl82_pinctrl_ops = {
+	.pinconf_set = bu18tl82_pinctrl_config_set,
+	.pinmux_set = bu18tl82_pinctrl_set_pin_mux,
+	.pinmux_group_set = bu18tl82_pinctrl_set_grp_mux,
+};
+
+static int bu18tl82_gpio_direction_input(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int bu18tl82_gpio_direction_output(struct serdes *serdes,
+					  int gpio, int value)
+{
+	return 0;
+}
+
+static int bu18tl82_gpio_get_level(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static int bu18tl82_gpio_set_level(struct serdes *serdes,
+				   int gpio, int value)
+{
+	return 0;
+}
+
+static int bu18tl82_gpio_set_config(struct serdes *serdes,
+				    int gpio, unsigned long config)
+{
+	return 0;
+}
+
+static int bu18tl82_gpio_to_irq(struct serdes *serdes, int gpio)
+{
+	return 0;
+}
+
+static struct serdes_chip_gpio_ops bu18tl82_gpio_ops = {
+	.direction_input = bu18tl82_gpio_direction_input,
+	.direction_output = bu18tl82_gpio_direction_output,
+	.get_level = bu18tl82_gpio_get_level,
+	.set_level = bu18tl82_gpio_set_level,
+	.set_config = bu18tl82_gpio_set_config,
+	.to_irq = bu18tl82_gpio_to_irq,
+};
+
+struct serdes_chip_data serdes_bu18tl82_data = {
+	.name		= "bu18tl82",
+	.serdes_type	= TYPE_SER,
+	.serdes_id	= ROHM_ID_BU18TL82,
+	.pinctrl_info	= &bu18tl82_pinctrl_info,
+	.bridge_ops	= &bu18tl82_bridge_ops,
+	.pinctrl_ops	= &bu18tl82_pinctrl_ops,
+	.gpio_ops	= &bu18tl82_gpio_ops,
+};
+EXPORT_SYMBOL_GPL(serdes_bu18tl82_data);
+
+MODULE_LICENSE("GPL");
diff --git a/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18tl82.h b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18tl82.h
new file mode 100644
index 0000000000..6e991cef43
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/rohm/rohm-bu18tl82.h
@@ -0,0 +1,452 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * include/linux/mfd/serdes/gpio.h -- GPIO for different serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#ifndef __MFD_SERDES_ROHM_BU18TL82_H__
+#define __MFD_SERDES_ROHM_BU18TL82_H__
+
+#define BU18TL82_REG_SWRST_INTERNAL 0x0011
+#define BU18TL82_REG_SWRST_MIPIRX 0x0012
+
+#define BU18TL82_REG_SWRST_INTERNAL 0x0011
+#define BU18TL82_REG_SWRST_MIPIRX 0x0012
+
+#define BU18TL82_BLOCK_EN_MIPIRX0 0x0013	//h [0] 1’b0
+#define BU18TL82_BLOCK_EN_LVDSRX0 0x0013	//h [1] 1’b0
+#define BU18TL82_BLOCK_EN_CLLTX0 0x0013	//h [3] 1’b0
+#define BU18TL82_BLOCK_EN_VPLL0 0x0013	//h [4] 1’b0
+#define BU18TL82_BLOCK_EN_SSCG0 0x0013	//h [5] 1’b0
+#define BU18TL82_BLOCK_EN_MIPIRX1 0x0014	//h [0] 1’b0
+#define BU18TL82_BLOCK_EN_LVDSRX1 0x0014	//h [1] 1’b0
+#define BU18TL82_BLOCK_EN_CLLTX1 0x0014	//h [3] 1’b0
+#define BU18TL82_BLOCK_EN_VPLL1 0x0014	//h [4] 1’b0
+#define BU18TL82_BLOCK_EN_SSCG1 0x0014	//h [5] 1’b0
+
+/*gpio register for driver/direction/pull-down*/
+#define BU18TL82_IO_SW_GPIO0 0x002A	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO0 0x002A	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO0 0x002A	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO1 0x002D	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO1 0x002D	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO1 0x002D	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO2 0x0030	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO2 0x0030	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO2 0x0030	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO3 0x0033	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO3 0x0033	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO3 0x0033	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO4 0x0036	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO4 0x0036	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO4 0x0036	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO5 0x0039	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO5 0x0039	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO5 0x0039	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO6 0x003C	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO6 0x003C	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO6 0x003C	//h [4] 1’b1
+#define BU18TL82_IO_SW_GPIO7 0x003F	//h [2:1] 2’b00
+#define BU18TL82_IO_OEN_GPIO7 0x003F	//h [3] 1’b1
+#define BU18TL82_IO_PDEN_GPIO7 0x003F	//h [4] 1’b1
+
+/*
+ * gpio register for define connection with des gpiox,
+ * 11bits such as 0x002c:002b=[b2..b0 b7...b0]
+ * default value:
+ * ser gpio0-->des gpio0
+ * ser gpio1-->des gpio1
+ * ser gpio2-->des gpio2
+ * ser gpio3-->des gpio3
+ */
+#define BU18TL82_GPIO_SEL0_HIGH 0x002C	//h [2:0],
+#define BU18TL82_GPIO_SEL0_LOW 0x002B	//h [7:0] 11’h002
+#define BU18TL82_GPIO_SEL1_HIGH 0x002F	//h [2:0],
+#define BU18TL82_GPIO_SEL1_LOW 0x002E	//h [7:0] 11’h003
+#define BU18TL82_GPIO_SEL2_HIGH 0x0032	//h [2:0],
+#define BU18TL82_GPIO_SEL2_LOW 0x0031	//h [7:0] 11’h004
+#define BU18TL82_GPIO_SEL3_HIGH 0x0035	//h [2:0],
+#define BU18TL82_GPIO_SEL3_LOW 0x0034	//h [7:0] 11’h005
+#define BU18TL82_GPIO_SEL4_HIGH 0x0038	//h [2:0],
+#define BU18TL82_GPIO_SEL4_LOW 0x0037	//h [7:0] 11’h006
+#define BU18TL82_GPIO_SEL5_HIGH 0x003B	//h [2:0],
+#define BU18TL82_GPIO_SEL5_LOW 0x003A	//h [7:0] 11’h007
+/*datasheet about gpio6/7 need modify*/
+#define BU18TL82_GPIO_SEL6_LOW 0x003E	//h [2:0],
+#define BU18TL82_GPIO_SEL6_HIGH 0x003D	//h [7:0] 11’h008
+#define BU18TL82_GPIO_SEL7_LOW 0x0041	//h [2:0],
+#define BU18TL82_GPIO_SEL7_HIGH 0x0040	//h [7:0] 11’h009
+
+/*gpio register for define bu18tl82 gpio pin, and gpio0 to gpio0 default*/
+#define BU18TL82_FCCTX0_SEL_GPI0 0x02A7	//h [4:0] 5’h02
+#define BU18TL82_FCCTX0_SEL_GPI1 0x02A8	//h [4:0] 5’h03
+#define BU18TL82_FCCTX0_SEL_GPI2 0x02A9	//h [4:0] 5’h04
+#define BU18TL82_FCCTX0_SEL_GPI3 0x02AA	//h [4:0] 5’h05
+#define BU18TL82_FCCTX0_SEL_GPI4 0x02AB	//h [4:0] 5’h06
+#define BU18TL82_FCCTX0_SEL_GPI5 0x02AC	//h [4:0] 5’h07
+#define BU18TL82_FCCTX0_SEL_GPI6 0x02AD	//h [4:0] 5’h08
+#define BU18TL82_FCCTX0_SEL_GPI7 0x02AE	//h [4:0] 5’h09
+#define BU18TL82_CLLTX0_SEL_GPI0 0x02AF	//h [4:0] 5’h04
+#define BU18TL82_CLLTX0_SEL_GPI1 0x02B0	//h [4:0] 5’h05
+
+#define BU18TL82_FCCTX1_SEL_GPI0 0x03A7	//h [4:0] 5’h02
+#define BU18TL82_FCCTX1_SEL_GPI1 0x03A8	//h [4:0] 5’h03
+#define BU18TL82_FCCTX1_SEL_GPI2 0x03A9	//h [4:0] 5’h04
+#define BU18TL82_FCCTX1_SEL_GPI3 0x03AA	//h [4:0] 5’h05
+#define BU18TL82_FCCTX1_SEL_GPI4 0x03AB	//h [4:0] 5’h06
+#define BU18TL82_FCCTX1_SEL_GPI5 0x03AC	//h [4:0] 5’h07
+#define BU18TL82_FCCTX1_SEL_GPI6 0x03AD	//h [4:0] 5’h08
+#define BU18TL82_FCCTX1_SEL_GPI7 0x03AE	//h [4:0] 5’h09
+#define BU18TL82_CLLTX1_SEL_GPI0 0x03AF	//h [4:0] 5’h04
+#define BU18TL82_CLLTX1_SEL_GPI1 0x03B0	//h [4:0] 5’h05
+
+/*write 1'b0 to this register to clear all isr register value8*/
+#define BU18TL82_ISR_CLEAR_ALL 0x0105	//h[0]
+
+#define BU18TL82_ISR_BCCDES0_ERR_CRC 0x0131			//h [3] 1’b0
+#define BU18TL82_ISR_BCCRX0_STATUS_NEAR_LOST 0x0131	//h[7]
+#define BU18TL82_ISR_BCCDES1_ERR_CRC 0x0132			//h [3] 1’b0
+#define BU18TL82_ISR_BCCRX1_STATUS_NEAR_LOST 0x0132	//h[7]
+#define BU18TL82_ISR_MIPIRX0_SOT_ERR 0x0133			//h[0]
+#define BU18TL82_ISR_MIPIRX0_SOT_SYNC_ERR 0x0133	//h[1]
+#define BU18TL82_ISR_MIPIRX0_EOT_SYNC_ERR 0x0133	//h[2]
+#define BU18TL82_ISR_MIPIRX0_ECC1BIT_ERR 0x0134		//h[0]
+#define BU18TL82_ISR_MIPIRX0_ECCMULT_ERR 0x0134		//h[1]
+#define BU18TL82_ISR_MIPIRX0_CRC_ERR 0x0134			//h[2]
+#define BU18TL82_ISR_MIPIRX1_SOT_ERR 0x0135			//h[0]
+#define BU18TL82_ISR_MIPIRX1_SOT_SYNC_ERR 0x0135	//h[1]
+#define BU18TL82_ISR_MIPIRX1_EOT_SYNC_ERR 0x0135	//h[2]
+#define BU18TL82_ISR_MIPIRX1_ECC1BIT_ERR 0x0136		//h[0]
+#define BU18TL82_ISR_MIPIRX1_ECCMULT_ERR 0x0136		//h[1]
+#define BU18TL82_ISR_MIPIRX1_CRC_ERR 0x0136			//h[2]
+#define BU18TL82_ISR_LVDSRX0_V_TOTAL_MAX_ERR 0x0137		//h[0]
+#define BU18TL82_ISR_LVDSRX0_V_TOTAL_MIN_ERR 0x0137		//h[1]
+#define BU18TL82_ISR_LVDSRX0_V_ACTIVE_MAX_ERR 0x0137	//h[2]
+#define BU18TL82_ISR_LVDSRX0_V_ACTIVE_MIN_ERR 0x0137	//h[3]
+#define BU18TL82_ISR_LVDSRX0_H_TOTAL_MAX_ERR 0x0137		//h[4]
+#define BU18TL82_ISR_LVDSRX0_H_TOTAL_MIN_ERR 0x0137		//h[5]
+#define BU18TL82_ISR_LVDSRX0_H_ACTIVE_MAX_ERR 0x0137	//h[6]
+#define BU18TL82_ISR_LVDSRX0_H_ACTIVE_MIN_ERR 0x0137	//h[7]
+#define BU18TL82_ISR_LVDSRX1_V_TOTAL_MAX_ERR 0x0138		//h[0]
+#define BU18TL82_ISR_LVDSRX1_V_TOTAL_MIN_ERR 0x0138		//h[1]
+#define BU18TL82_ISR_LVDSRX1_V_ACTIVE_MAX_ERR 0x0138	//h[2]
+#define BU18TL82_ISR_LVDSRX1_V_ACTIVE_MIN_ERR 0x0138	//h[3]
+#define BU18TL82_ISR_LVDSRX1_H_TOTAL_MAX_ERR 0x0138		//h[4]
+#define BU18TL82_ISR_LVDSRX1_H_TOTAL_MIN_ERR 0x0138		//h[5]
+#define BU18TL82_ISR_LVDSRX1_H_ACTIVE_MAX_ERR 0x0138	//h[6]
+#define BU18TL82_ISR_LVDSRX1_H_ACTIVE_MIN_ERR 0x0138	//h[7]
+#define BU18TL82_ISR_IO_STUCK_GPIO0 0x0139	//h[0]
+#define BU18TL82_ISR_IO_STUCK_GPIO1 0x0139	//h[1]
+#define BU18TL82_ISR_IO_STUCK_GPIO2 0x0139	//h[2]
+#define BU18TL82_ISR_IO_STUCK_GPIO3 0x0139	//h[3]
+#define BU18TL82_ISR_IO_STUCK_GPIO4 0x0139	//h[4]
+#define BU18TL82_ISR_IO_STUCK_GPIO5 0x0139	//h[5]
+#define BU18TL82_ISR_IO_STUCK_GPIO6 0x0139	//h[6]
+#define BU18TL82_ISR_IO_STUCK_GPIO7 0x0139	//h[7]
+#define BU18TL82_ISR_IO_STUCK_IRQ 0x013a	//h[1]
+#define BU18TL82_ISR_IDS_UNSTABLE 0x013a	//h [7] 1’b0
+#define BU18TL82_ISR_I2C_A_TIMEOUT 0x013b	//h [0] 1’b0
+#define BU18TL82_ISR_I2C_A_XMIT_ERR 0x013b	//h [1] 1’b0
+#define BU18TL82_ISR_I2C_B_TIMEOUT 0x013c	//h [0] 1’b0
+#define BU18TL82_ISR_I2C_B_XMIT_ERR 0x013c	//h [1] 1’b0
+#define BU18TL82_ISR_REGCRC_ERR_PAGE0 0x013d	//h[0]
+#define BU18TL82_ISR_REGCRC_ERR_PAGE1 0x013d	//h[1]
+#define BU18TL82_ISR_REGCRC_ERR_PAGE2 0x013d	//h[2]
+#define BU18TL82_ISR_REGCRC_ERR_PAGE3 0x013d	//h[3]
+#define BU18TL82_ISR_REGCRC_ERR_PAGE4 0x013d	//h[4]
+#define BU18TL82_ISR_REGCRC_ERR_PAGE5 0x013d	//h[5]
+#define BU18TL82_ISR_CLKDETECT_CLKIN0_STOP 0x013e	//h [0] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLKIN0_UNLOCK 0x013e	//h [1] 1’b0
+#define BU18TL82_ISR_CLKDETECT_OSC_STOP 0x013e		//h [4] 1’b0
+#define BU18TL82_ISR_CLKDETECT_OSC_UNLOCK 0x013e	//h [5] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLKIN1_STOP 0x013f	//h [0] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLKIN1_UNLOCK 0x013f	//h [1] 1’b0
+#define BU18TL82_ISR_CLKDETECT_LVDSRX0_STOP 0x0140		//h [0] 1’b0
+#define BU18TL82_ISR_CLKDETECT_LVDSRX0_UNLOCK 0x0140	//h [1] 1’b0
+#define BU18TL82_ISR_CLKDETECT_MIPIRX0_STOP 0x0140		//h [4] 1’b0
+#define BU18TL82_ISR_CLKDETECT_MIPIRX0_UNLOCK 0x0140	//h [5] 1’b0
+#define BU18TL82_ISR_CLKDETECT_LVDSRX1_STOP 0x0141		//h [0] 1’b0
+#define BU18TL82_ISR_CLKDETECT_LVDSRX1_UNLOCK 0x0141	//h [1] 1’b0
+#define BU18TL82_ISR_CLKDETECT_MIPIRX1_STOP 0x0141		//h [4] 1’b0
+#define BU18TL82_ISR_CLKDETECT_MIPIRX1_UNLOCK 0x0141	//h [5] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP 0x0142		//h [0] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x0142	//h [1] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX0_PLLREF_STOP 0x0142	//h [4] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x0142	//h [5] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_STOP 0x0143		//h [0] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_UNLOCK 0x0143	//h [1] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX1_PLLREF_STOP 0x0143	//h [4] 1’b0
+#define BU18TL82_ISR_CLKDETECT_CLLTX1_PLLREF_UNLOCK 0x0143	//h [5] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR00 0x0149	//h [0] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR01 0x0149	//h [1] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR02 0x0149	//h [2] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR03 0x0149	//h [3] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR04 0x0149	//h [4] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR05 0x0149	//h [5] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR06 0x0149	//h [6] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR07 0x0149	//h [7] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR08 0x014a	//h [0] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR09 0x014a	//h [1] 1’b0
+#define BU18TL82_ISR_STATUS_RX0_ISR10 0x014a	//h [2] 1’b0
+
+#define BU18TL82_IEN_BCCDES0_ERR_CRC 0x0109			//h [3] 1’b0
+#define BU18TL82_IEN_BCCRX0_STATUS_NEAR_LOST 0x0109	//h[7]
+#define BU18TL82_IEN_BCCDES1_ERR_CRC 0x010A			//h [3] 1’b0
+#define BU18TL82_IEN_BCCRX1_STATUS_NEAR_LOST 0x010A	//h[7]
+#define BU18TL82_IEN_MIPIRX0_SOT_ERR 0x010B			//h[0]
+#define BU18TL82_IEN_MIPIRX0_SOT_SYNC_ERR 0x010B	//h[1]
+#define BU18TL82_IEN_MIPIRX0_EOT_SYNC_ERR 0x010B	//h[2]
+#define BU18TL82_IEN_MIPIRX0_ECC1BIT_ERR 0x010C		//h[0]
+#define BU18TL82_IEN_MIPIRX0_ECCMULT_ERR 0x010C		//h[1]
+#define BU18TL82_IEN_MIPIRX0_CRC_ERR 0x010C			//h[2]
+#define BU18TL82_IEN_MIPIRX1_SOT_ERR 0x010D			//h[0]
+#define BU18TL82_IEN_MIPIRX1_SOT_SYNC_ERR 0x010D	//h[1]
+#define BU18TL82_IEN_MIPIRX1_EOT_SYNC_ERR 0x010D	//h[2]
+#define BU18TL82_IEN_MIPIRX1_ECC1BIT_ERR 0x010E		//h[0]
+#define BU18TL82_IEN_MIPIRX1_ECCMULT_ERR 0x010E		//h[1]
+#define BU18TL82_IEN_MIPIRX1_CRC_ERR 0x010E			//h[2]
+#define BU18TL82_IEN_LVDSRX0_V_TOTAL_MAX_ERR 0x010F		//h[0]
+#define BU18TL82_IEN_LVDSRX0_V_TOTAL_MIN_ERR 0x010F		//h[1]
+#define BU18TL82_IEN_LVDSRX0_V_ACTIVE_MAX_ERR 0x010F	//h[2]
+#define BU18TL82_IEN_LVDSRX0_V_ACTIVE_MIN_ERR 0x010F	//h[3]
+#define BU18TL82_IEN_LVDSRX0_H_TOTAL_MAX_ERR 0x010F		//h[4]
+#define BU18TL82_IEN_LVDSRX0_H_TOTAL_MIN_ERR 0x010F		//h[5]
+#define BU18TL82_IEN_LVDSRX0_H_ACTIVE_MAX_ERR 0x010F	//h[6]
+#define BU18TL82_IEN_LVDSRX0_H_ACTIVE_MIN_ERR 0x010F	//h[7]
+#define BU18TL82_IEN_LVDSRX1_V_TOTAL_MAX_ERR 0x0110		//h[0]
+#define BU18TL82_IEN_LVDSRX1_V_TOTAL_MIN_ERR 0x0110		//h[1]
+#define BU18TL82_IEN_LVDSRX1_V_ACTIVE_MAX_ERR 0x0110	//h[2]
+#define BU18TL82_IEN_LVDSRX1_V_ACTIVE_MIN_ERR 0x0110	//h[3]
+#define BU18TL82_IEN_LVDSRX1_H_TOTAL_MAX_ERR 0x0110		//h[4]
+#define BU18TL82_IEN_LVDSRX1_H_TOTAL_MIN_ERR 0x0110		//h[5]
+#define BU18TL82_IEN_LVDSRX1_H_ACTIVE_MAX_ERR 0x0110	//h[6]
+#define BU18TL82_IEN_LVDSRX1_H_ACTIVE_MIN_ERR 0x0110	//h[7]
+#define BU18TL82_IEN_IO_STUCK_GPIO0 0x0111	//h[0]
+#define BU18TL82_IEN_IO_STUCK_GPIO1 0x0111	//h[1]
+#define BU18TL82_IEN_IO_STUCK_GPIO2 0x0111	//h[2]
+#define BU18TL82_IEN_IO_STUCK_GPIO3 0x0111	//h[3]
+#define BU18TL82_IEN_IO_STUCK_GPIO4 0x0111	//h[4]
+#define BU18TL82_IEN_IO_STUCK_GPIO5 0x0111	//h[5]
+#define BU18TL82_IEN_IO_STUCK_GPIO6 0x0111	//h[6]
+#define BU18TL82_IEN_IO_STUCK_GPIO7 0x0111	//h[7]
+#define BU18TL82_IEN_IO_STUCK_IRQ 0x0112	//h[1]
+#define BU18TL82_IEN_IDS_UNSTABLE 0x0112	//h [7] 1’b0
+#define BU18TL82_IEN_I2C_A_TIMEOUT 0x0113	//h [0] 1’b0
+#define BU18TL82_IEN_I2C_A_XMIT_ERR 0x0113	//h [1] 1’b0
+#define BU18TL82_IEN_I2C_B_TIMEOUT 0x0114	//h [0] 1’b0
+#define BU18TL82_IEN_I2C_B_XMIT_ERR 0x0114	//h [1] 1’b0
+#define BU18TL82_IEN_REGCRC_ERR_PAGE0 0x0115	//h[0]
+#define BU18TL82_IEN_REGCRC_ERR_PAGE1 0x0115	//h[1]
+#define BU18TL82_IEN_REGCRC_ERR_PAGE2 0x0115	//h[2]
+#define BU18TL82_IEN_REGCRC_ERR_PAGE3 0x0115	//h[3]
+#define BU18TL82_IEN_REGCRC_ERR_PAGE4 0x0115	//h[4]
+#define BU18TL82_IEN_REGCRC_ERR_PAGE5 0x0115	//h[5]
+#define BU18TL82_IEN_CLKDETECT_CLKIN0_STOP 0x0116	//h [0] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLKIN0_UNLOCK 0x0116	//h [1] 1’b0
+#define BU18TL82_IEN_CLKDETECT_OSC_STOP 0x0116		//h [4] 1’b0
+#define BU18TL82_IEN_CLKDETECT_OSC_UNLOCK 0x0116	//h [5] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLKIN1_STOP 0x0117	//h [0] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLKIN1_UNLOCK 0x0117	//h [1] 1’b0
+#define BU18TL82_IEN_CLKDETECT_LVDSRX0_STOP 0x0118		//h [0] 1’b0
+#define BU18TL82_IEN_CLKDETECT_LVDSRX0_UNLOCK 0x0118	//h [1] 1’b0
+#define BU18TL82_IEN_CLKDETECT_MIPIRX0_STOP 0x0118		//h [4] 1’b0
+#define BU18TL82_IEN_CLKDETECT_MIPIRX0_UNLOCK 0x0118	//h [5] 1’b0
+#define BU18TL82_IEN_CLKDETECT_LVDSRX1_STOP 0x0119		//h [0] 1’b0
+#define BU18TL82_IEN_CLKDETECT_LVDSRX1_UNLOCK 0x0119	//h [1] 1’b0
+#define BU18TL82_IEN_CLKDETECT_MIPIRX1_STOP 0x0119		//h [4] 1’b0
+#define BU18TL82_IEN_CLKDETECT_MIPIRX1_UNLOCK 0x0119	//h [5] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP 0x011A		//h [0] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x011A	//h [1] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX0_PLLREF_STOP 0x011A	//h [4] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x011A	//h [5] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_STOP 0x011B		//h [0] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_UNLOCK 0x011B	//h [1] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX1_PLLREF_STOP 0x011B	//h [4] 1’b0
+#define BU18TL82_IEN_CLKDETECT_CLLTX1_PLLREF_UNLOCK 0x011B	//h [5] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR00 0x0121	//h [0] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR01 0x0121	//h [1] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR02 0x0121	//h [2] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR03 0x0121	//h [3] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR04 0x0121	//h [4] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR05 0x0121	//h [5] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR06 0x0121	//h [6] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR07 0x0121	//h [7] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR08 0x0122	//h [0] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR09 0x0122	//h [1] 1’b0
+#define BU18TL82_IEN_STATUS_RX0_ISR10 0x0122	//h [2] 1’b0
+
+struct bu18tl82_gpio_sw_reg {
+	unsigned int reg;
+	unsigned int mask;	//2/4/6/8ma
+};
+
+struct bu18tl82_gpio_oen_reg {
+	unsigned int reg;
+	unsigned int mask;	//0:output 1:input
+};
+
+struct bu18tl82_gpio_pden_reg {
+	unsigned int reg;
+	unsigned int mask;	//0:no pulldown 1:connect pulldown
+};
+
+struct bu18tl82_gpio_id_low_reg {
+	unsigned int reg;
+	unsigned int mask;	//b2b1b0
+};
+
+struct bu18tl82_gpio_id_high_reg {
+	unsigned int reg;
+	unsigned int mask;	//b11b10b9b8b7b6b5b4b3
+};
+
+static const struct bu18tl82_gpio_sw_reg bu18tl82_gpio_sw[8] = {
+	{BU18TL82_IO_SW_GPIO0, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO1, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO2, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO3, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO4, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO5, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO6, BIT(2) | BIT(1)},
+	{BU18TL82_IO_SW_GPIO7, BIT(2) | BIT(1)},
+};
+
+static const struct bu18tl82_gpio_oen_reg bu18tl82_gpio_oen[8] = {
+	{BU18TL82_IO_OEN_GPIO0, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO1, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO2, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO3, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO4, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO5, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO6, BIT(3)},
+	{BU18TL82_IO_OEN_GPIO7, BIT(3)},
+};
+
+static const struct bu18tl82_gpio_pden_reg bu18tl82_gpio_pden[8] = {
+	{BU18TL82_IO_PDEN_GPIO0, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO1, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO2, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO3, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO4, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO5, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO6, BIT(4)},
+	{BU18TL82_IO_PDEN_GPIO7, BIT(4)},
+};
+
+static const struct bu18tl82_gpio_id_low_reg bu18tl82_gpio_id_low[8] = {
+	{BU18TL82_GPIO_SEL0_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL1_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL2_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL3_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL4_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL5_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL6_LOW, GENMASK(7, 0)},
+	{BU18TL82_GPIO_SEL7_LOW, GENMASK(7, 0)},
+};
+
+static const struct bu18tl82_gpio_id_high_reg bu18tl82_gpio_id_high[8] = {
+	{BU18TL82_GPIO_SEL0_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL1_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL2_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL3_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL4_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL5_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL6_HIGH, GENMASK(2, 0)},
+	{BU18TL82_GPIO_SEL7_HIGH, GENMASK(2, 0)},
+};
+
+struct bu18tl82_ien_reg {
+	unsigned int reg;
+	unsigned int ien;
+};
+
+struct bu18tl82_isr_reg {
+	unsigned int reg;
+	unsigned int isr;
+};
+
+static const struct bu18tl82_ien_reg bu18tl82_reg_ien[21] = {
+	{BU18TL82_IEN_BCCRX0_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
+	{BU18TL82_IEN_BCCRX1_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
+
+	{BU18TL82_IEN_MIPIRX0_SOT_ERR,
+	 BIT(0) | BIT(0) | BIT(2)},
+	{BU18TL82_IEN_MIPIRX0_ECC1BIT_ERR,
+	 BIT(0) | BIT(0) | BIT(2)},
+
+	{BU18TL82_IEN_MIPIRX1_SOT_ERR,
+	 BIT(0) | BIT(0) | BIT(2)},
+	{BU18TL82_IEN_MIPIRX1_ECC1BIT_ERR,
+	 BIT(0) | BIT(0) | BIT(2)},
+
+	{BU18TL82_IEN_LVDSRX0_V_TOTAL_MAX_ERR, 0XFF},
+	{BU18TL82_IEN_LVDSRX1_V_TOTAL_MAX_ERR, 0XFF},
+
+	{BU18TL82_IEN_IO_STUCK_GPIO0, 0XFF},
+	{BU18TL82_IEN_IO_STUCK_IRQ, BIT(1) | BIT(7)},
+	{BU18TL82_IEN_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
+	{BU18TL82_IEN_I2C_B_TIMEOUT, BIT(0) | BIT(1)},
+
+	{BU18TL82_IEN_REGCRC_ERR_PAGE0, 0x3F},
+
+	{BU18TL82_IEN_CLKDETECT_CLKIN0_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_IEN_CLKDETECT_CLKIN1_STOP,
+	 BIT(0) | BIT(1)},
+
+	{BU18TL82_IEN_CLKDETECT_LVDSRX0_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_IEN_CLKDETECT_LVDSRX1_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+
+	{BU18TL82_IEN_STATUS_RX0_ISR00, 0xff},
+	{BU18TL82_IEN_STATUS_RX0_ISR08, BIT(0) | BIT(1) | BIT(2)},
+};
+
+static const struct bu18tl82_isr_reg bu18tl82_reg_isr[21] = {
+	{BU18TL82_ISR_BCCRX0_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
+	{BU18TL82_ISR_BCCRX1_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
+
+	{BU18TL82_ISR_MIPIRX0_SOT_ERR, BIT(0) | BIT(0) | BIT(2)},
+	{BU18TL82_ISR_MIPIRX0_ECC1BIT_ERR, BIT(0) | BIT(0) | BIT(2)},
+
+	{BU18TL82_ISR_MIPIRX1_SOT_ERR, BIT(0) | BIT(0) | BIT(2)},
+	{BU18TL82_ISR_MIPIRX1_ECC1BIT_ERR, BIT(0) | BIT(0) | BIT(2)},
+
+	{BU18TL82_ISR_LVDSRX0_V_TOTAL_MAX_ERR, 0XFF},
+	{BU18TL82_ISR_LVDSRX1_V_TOTAL_MAX_ERR, 0XFF},
+
+	{BU18TL82_ISR_IO_STUCK_GPIO0, 0XFF},
+	{BU18TL82_ISR_IO_STUCK_IRQ, BIT(1) | BIT(7)},
+	{BU18TL82_ISR_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
+	{BU18TL82_ISR_I2C_B_TIMEOUT, BIT(0) | BIT(1)},
+
+	{BU18TL82_ISR_REGCRC_ERR_PAGE0, 0x3F},
+
+	{BU18TL82_ISR_CLKDETECT_CLKIN0_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_ISR_CLKDETECT_CLKIN1_STOP,
+	 BIT(0) | BIT(1)},
+
+	{BU18TL82_ISR_CLKDETECT_LVDSRX0_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_ISR_CLKDETECT_LVDSRX1_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+	{BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_STOP,
+	 BIT(0) | BIT(1) | BIT(4) | BIT(5)},
+
+	{BU18TL82_ISR_STATUS_RX0_ISR00, 0xff},
+	{BU18TL82_ISR_STATUS_RX0_ISR08, BIT(0) | BIT(1) | BIT(2)},
+};
+
+#endif
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-bridge-split.c b/u-boot/drivers/video/drm/display-serdes/serdes-bridge-split.c
new file mode 100644
index 0000000000..707aa8a9be
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-bridge-split.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-bridge_split.c  --  display bridge_split for different serdes chips
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static void serdes_bridge_split_init(struct serdes *serdes)
+{
+	if (serdes->vpower_supply)
+		regulator_set_enable(serdes->vpower_supply, true);
+
+	if (dm_gpio_is_valid(&serdes->enable_gpio))
+		dm_gpio_set_value(&serdes->enable_gpio, 1);
+
+	mdelay(5);
+
+	//video_bridge_set_active(serdes->dev, true);
+
+	if (serdes->chip_data->bridge_ops->init)
+		serdes->chip_data->bridge_ops->init(serdes);
+
+	serdes_i2c_set_sequence(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_split_pre_enable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	//serdes_bridge_split_split_init(serdes);
+
+	if (serdes->chip_data->bridge_ops->pre_enable)
+		serdes->chip_data->bridge_ops->pre_enable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_split_post_disable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->bridge_ops->post_disable)
+		serdes->chip_data->bridge_ops->post_disable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_split_enable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->serdes_type == TYPE_DES)
+		serdes_bridge_split_init(serdes);
+
+	if (serdes->chip_data->bridge_ops->enable)
+		serdes->chip_data->bridge_ops->enable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_split_disable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->bridge_ops->disable)
+		serdes->chip_data->bridge_ops->disable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_split_mode_set(struct rockchip_bridge *bridge,
+					 const struct drm_display_mode *mode)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	memcpy(&serdes->serdes_bridge_split->mode, mode,
+	       sizeof(struct drm_display_mode));
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static bool serdes_bridge_split_detect(struct rockchip_bridge *bridge)
+{
+	bool ret = true;
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->bridge_ops->detect)
+		ret = serdes->chip_data->bridge_ops->detect(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name, ret ? "detected" : "no detected");
+
+	return ret;
+}
+
+struct rockchip_bridge_funcs serdes_bridge_split_ops = {
+	.pre_enable = serdes_bridge_split_pre_enable,
+	.post_disable = serdes_bridge_split_post_disable,
+	.enable = serdes_bridge_split_enable,
+	.disable = serdes_bridge_split_disable,
+	.mode_set = serdes_bridge_split_mode_set,
+	.detect = serdes_bridge_split_detect,
+};
+
+static int serdes_bridge_split_probe(struct udevice *dev)
+{
+	struct rockchip_bridge *bridge;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	struct mipi_dsi_device *device = dev_get_platdata(dev);
+
+	serdes->sel_mipi = dev_read_bool(dev->parent, "sel-mipi");
+	if (serdes->sel_mipi) {
+		device->dev = dev;
+		device->lanes = dev_read_u32_default(dev->parent, "dsi,lanes", 4);
+		device->format = dev_read_u32_default(dev->parent, "dsi,format",
+						      MIPI_DSI_FMT_RGB888);
+		device->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+		device->channel = dev_read_u32_default(dev->parent, "reg", 0);
+	}
+
+	bridge = calloc(1, sizeof(*bridge));
+	if (!bridge)
+		return -ENOMEM;
+
+	dev->driver_data = (ulong)bridge;
+	bridge->dev = dev;
+	bridge->funcs = &serdes_bridge_split_ops;
+
+	serdes->serdes_bridge_split->bridge = bridge;
+
+	SERDES_DBG_MFD("%s: %s %s bridge=%p name=%s device=%p\n",
+		       __func__, serdes->dev->name,
+		       serdes->chip_data->name,
+		       bridge, bridge->dev->name, device);
+
+	return 0;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745)
+	{ .compatible = "maxim,max96745-bridge-split", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)
+	{ .compatible = "maxim,max96755-bridge-split", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96789)
+	{ .compatible = "maxim,max96789-bridge-split", },
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_bridge_split) = {
+	.name = "serdes-bridge-split",
+	.id = UCLASS_VIDEO_BRIDGE,
+	.of_match = serdes_of_match,
+	.probe = serdes_bridge_split_probe,
+	.priv_auto_alloc_size = sizeof(struct serdes_bridge_split),
+	.platdata_auto_alloc_size = sizeof(struct mipi_dsi_device),
+};
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-bridge.c b/u-boot/drivers/video/drm/display-serdes/serdes-bridge.c
new file mode 100644
index 0000000000..ebac665dd7
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-bridge.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-bridge.c  --  display bridge for different serdes chips
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static void serdes_bridge_init(struct serdes *serdes)
+{
+	if (serdes->vpower_supply)
+		regulator_set_enable(serdes->vpower_supply, true);
+
+	if (dm_gpio_is_valid(&serdes->enable_gpio))
+		dm_gpio_set_value(&serdes->enable_gpio, 1);
+
+	mdelay(5);
+
+	//video_bridge_set_active(serdes->dev, true);
+
+	if (serdes->chip_data->bridge_ops->init)
+		serdes->chip_data->bridge_ops->init(serdes);
+
+	serdes_i2c_set_sequence(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_pre_enable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	//serdes_bridge_init(serdes);
+
+	if (serdes->chip_data->bridge_ops->pre_enable)
+		serdes->chip_data->bridge_ops->pre_enable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_post_disable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->bridge_ops->post_disable)
+		serdes->chip_data->bridge_ops->post_disable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_enable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->serdes_type == TYPE_DES)
+		serdes_bridge_init(serdes);
+
+	if (serdes->chip_data->bridge_ops->enable)
+		serdes->chip_data->bridge_ops->enable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_disable(struct rockchip_bridge *bridge)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->bridge_ops->disable)
+		serdes->chip_data->bridge_ops->disable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_bridge_mode_set(struct rockchip_bridge *bridge,
+				   const struct drm_display_mode *mode)
+{
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	memcpy(&serdes->serdes_bridge->mode, mode,
+	       sizeof(struct drm_display_mode));
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static bool serdes_bridge_detect(struct rockchip_bridge *bridge)
+{
+	bool ret = true;
+	struct udevice *dev = bridge->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->bridge_ops->detect)
+		ret = serdes->chip_data->bridge_ops->detect(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name, (ret == true) ? "detected" : "no detected");
+
+	return ret;
+}
+
+struct rockchip_bridge_funcs serdes_bridge_ops = {
+	.pre_enable = serdes_bridge_pre_enable,
+	.post_disable = serdes_bridge_post_disable,
+	.enable = serdes_bridge_enable,
+	.disable = serdes_bridge_disable,
+	.mode_set = serdes_bridge_mode_set,
+	.detect = serdes_bridge_detect,
+};
+
+static int serdes_bridge_probe(struct udevice *dev)
+{
+	struct rockchip_bridge *bridge;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	struct mipi_dsi_device *device = dev_get_platdata(dev);
+
+	if (!serdes->chip_data->bridge_ops) {
+		SERDES_DBG_MFD("%s %s no bridge ops\n",
+			       __func__, serdes->chip_data->name);
+		return 0;
+	}
+
+	serdes->sel_mipi = dev_read_bool(dev->parent, "sel-mipi");
+	if (serdes->sel_mipi) {
+		device->dev = dev;
+		device->lanes = dev_read_u32_default(dev->parent, "dsi,lanes", 4);
+		device->format = dev_read_u32_default(dev->parent, "dsi,format",
+						      MIPI_DSI_FMT_RGB888);
+		device->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+		device->channel = dev_read_u32_default(dev->parent, "reg", 0);
+	}
+
+	bridge = calloc(1, sizeof(*bridge));
+	if (!bridge)
+		return -ENOMEM;
+
+	dev->driver_data = (ulong)bridge;
+	bridge->dev = dev;
+	bridge->funcs = &serdes_bridge_ops;
+
+	serdes->serdes_bridge->bridge = bridge;
+
+	SERDES_DBG_MFD("%s: %s %s bridge=%p name=%s device=%p\n",
+		       __func__, serdes->dev->name,
+		       serdes->chip_data->name,
+		       bridge, bridge->dev->name, device);
+
+	return 0;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82)
+	{ .compatible = "rohm,bu18tl82-bridge",  },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82)
+	{ .compatible = "rohm,bu18rl82-bridge", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745)
+	{ .compatible = "maxim,max96745-bridge", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)
+	{ .compatible = "maxim,max96755-bridge", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)
+	{ .compatible = "maxim,max96789-bridge", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111)
+	{ .compatible = "rockchip,rkx111-bridge", },
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_bridge) = {
+	.name = "serdes-bridge",
+	.id = UCLASS_VIDEO_BRIDGE,
+	.of_match = serdes_of_match,
+	.probe = serdes_bridge_probe,
+	.priv_auto_alloc_size = sizeof(struct serdes_bridge),
+	.platdata_auto_alloc_size = sizeof(struct mipi_dsi_device),
+};
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-core.c b/u-boot/drivers/video/drm/display-serdes/serdes-core.c
new file mode 100644
index 0000000000..075220ae77
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-core.c
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-i2c.c  --  display i2c for different serdes chips
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static int dm_i2c_reg_write_u8(struct udevice *dev, u8 reg, u8 val)
+{
+	int ret;
+	u8 buf[2];
+	struct i2c_msg msg;
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+
+	buf[0] = reg;
+	buf[1] = val;
+	msg.addr = chip->chip_addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = buf;
+
+	ret = dm_i2c_xfer(dev, &msg, 1);
+	if (ret) {
+		printf("dm i2c write failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static uint8_t dm_i2c_reg_read_u8(struct udevice *dev, u8 reg)
+{
+	int ret;
+	u8 data;
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+	struct i2c_msg msg[] = {
+		{
+			.addr = chip->chip_addr,
+			.flags = 0,
+			.buf = (u8 *)&reg,
+			.len = 1,
+		}, {
+			.addr = chip->chip_addr,
+			.flags = I2C_M_RD,
+			.buf = (u8 *)&data,
+			.len = 1,
+		}
+	};
+
+	ret = dm_i2c_xfer(dev, msg, 2);
+	if (ret) {
+		printf("dm i2c read failed: %d\n", ret);
+		return ret;
+	}
+
+	return data;
+}
+
+static int dm_i2c_reg_clrset_u8(struct udevice *dev,
+				u8 offset,
+				u8 clr, u8 set)
+{
+	u8 val;
+
+	val = dm_i2c_reg_read_u8(dev, offset);
+	if (val < 0)
+		return val;
+
+	val &= ~clr;
+	val |= set;
+
+	return dm_i2c_reg_write_u8(dev, offset, val);
+}
+
+/**
+ * serdes_reg_read: Read a single serdes register.
+ *
+ * @serdes: Device to read from.
+ * @reg: Register to read.
+ * @val: Date read from register.
+ */
+int serdes_reg_read(struct serdes *serdes,
+		    unsigned int reg, unsigned int *val)
+{
+	unsigned int value;
+
+	if (serdes->chip_data->reg_val_type == REG_8BIT_VAL_8IT)
+		value = dm_i2c_reg_read_u8(serdes->dev, reg);
+	else
+		value = dm_i2c_reg_read(serdes->dev, reg);
+
+	*val = value;
+	SERDES_DBG_I2C("%s %s %s Read Reg%04x %04x\n",
+		       __func__, serdes->dev->name,
+		       serdes->dev->name, reg, *val);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(serdes_reg_read);
+
+/**
+ * serdes_reg_write: Write a single serdes register.
+ *
+ * @serdes: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+int serdes_reg_write(struct serdes *serdes, unsigned int reg,
+		     unsigned int val)
+{
+	int ret = 0;
+
+	SERDES_DBG_I2C("%s %s Write Reg%04x %04x) type=%d\n",
+		       __func__, serdes->dev->name,
+		       reg, val, serdes->chip_data->reg_val_type);
+	if (serdes->chip_data->reg_val_type == REG_8BIT_VAL_8IT) {
+		ret = dm_i2c_reg_write_u8(serdes->dev, reg, val);
+		if (ret != 0)
+			return ret;
+	} else {
+		ret = dm_i2c_reg_write(serdes->dev, reg, val);
+		if (ret != 0)
+			return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_reg_write);
+
+/**
+ * serdes_multi_reg_write: Write many serdes register.
+ *
+ * @serdes: Device to write to.
+ * @regs: Registers to write to.
+ * @num_regs: Number of registers to write.
+ */
+int serdes_multi_reg_write(struct serdes *serdes,
+			   const struct reg_sequence *regs,
+			   int num_regs)
+{
+	int i, ret = 0;
+
+	SERDES_DBG_I2C("%s %s %s num=%d\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name, num_regs);
+
+	for (i = 0; i < num_regs; i++) {
+		ret = serdes_reg_write(serdes, regs[i].reg, regs[i].def);
+		SERDES_DBG_I2C("serdes %s Write Reg%04x %04x ret=%d\n",
+			       serdes->chip_data->name,
+			       regs[i].reg, regs[i].def, ret);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_multi_reg_write);
+
+/**
+ * serdes_set_bits: Set the value of a bitfield in a serdes register
+ *
+ * @serdes: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ */
+int serdes_set_bits(struct serdes *serdes, unsigned int reg,
+		    unsigned int mask, unsigned int val)
+{
+	int ret = 0;
+
+	SERDES_DBG_I2C("%s %s %s Write Reg%04x %04x) mask=%04x\n",
+		       __func__,
+		       serdes->dev->name,
+		       serdes->dev->name, reg, val, mask);
+
+	if (serdes->chip_data->reg_val_type == REG_8BIT_VAL_8IT)
+		ret = dm_i2c_reg_clrset_u8(serdes->dev, reg, mask, val);
+	else
+		ret = dm_i2c_reg_clrset(serdes->dev, reg, mask, val);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_set_bits);
+
+int serdes_i2c_set_sequence(struct serdes *serdes)
+{
+	int i, ret = 0;
+	unsigned int def = 0;
+
+	for (i = 0; i < serdes->serdes_init_seq->reg_seq_cnt; i++) {
+		if (serdes->serdes_init_seq->reg_sequence[i].reg == 0xffff) {
+			SERDES_DBG_MFD("%s: delay 0x%04x us\n", __func__,
+				       serdes->serdes_init_seq->reg_sequence[i].def);
+			udelay(serdes->serdes_init_seq->reg_sequence[i].def);
+			continue;
+		}
+
+		ret = serdes_reg_write(serdes,
+				       serdes->serdes_init_seq->reg_sequence[i].reg,
+				       serdes->serdes_init_seq->reg_sequence[i].def);
+
+		if (ret < 0) {
+			SERDES_DBG_MFD("failed to write reg %04x, ret %d\n",
+				       serdes->serdes_init_seq->reg_sequence[i].reg, ret);
+			ret = serdes_reg_write(serdes,
+					       serdes->serdes_init_seq->reg_sequence[i].reg,
+					       serdes->serdes_init_seq->reg_sequence[i].def);
+		}
+		serdes_reg_read(serdes, serdes->serdes_init_seq->reg_sequence[i].reg, &def);
+		if ((def != serdes->serdes_init_seq->reg_sequence[i].def) || (ret < 0)) {
+			/*if read value != write value then write again*/
+			printf("%s read %04x %04x != %04x\n", serdes->dev->name,
+			       serdes->serdes_init_seq->reg_sequence[i].reg,
+			       def, serdes->serdes_init_seq->reg_sequence[i].def);
+			ret = serdes_reg_write(serdes,
+					       serdes->serdes_init_seq->reg_sequence[i].reg,
+					       serdes->serdes_init_seq->reg_sequence[i].def);
+		}
+	}
+
+	SERDES_DBG_MFD("serdes %s sequence_init\n", serdes->dev->name);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_i2c_set_sequence);
+
+int serdes_parse_init_seq(struct udevice *dev, const u16 *data,
+			  int length, struct serdes_init_seq *seq)
+{
+	struct reg_sequence *reg_sequence;
+	u16 *buf, *d;
+	unsigned int i, cnt;
+	int ret;
+
+	if (!seq)
+		return -EINVAL;
+
+	buf = calloc(1, length);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy(buf, data, length);
+
+	d = buf;
+	cnt = length / 4;
+	seq->reg_seq_cnt = cnt;
+
+	seq->reg_sequence = calloc(cnt, sizeof(struct reg_sequence));
+	if (!seq->reg_sequence) {
+		ret = -ENOMEM;
+		goto free_buf;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		reg_sequence = &seq->reg_sequence[i];
+		reg_sequence->reg = get_unaligned_be16(&d[0]);
+		reg_sequence->def = get_unaligned_be16(&d[1]);
+		d += 2;
+	}
+
+	return 0;
+
+free_buf:
+	free(buf);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_parse_init_seq);
+
+int serdes_get_init_seq(struct serdes *serdes)
+{
+	const void *data = NULL;
+	int len, err;
+
+	data = dev_read_prop(serdes->dev, "serdes-init-sequence", &len);
+	if (!data) {
+		printf("failed to get serdes-init-sequence\n");
+		return -EINVAL;
+	}
+
+	serdes->serdes_init_seq = calloc(1, sizeof(*serdes->serdes_init_seq));
+	if (!serdes->serdes_init_seq)
+		return -ENOMEM;
+
+	err = serdes_parse_init_seq(serdes->dev,
+				    data, len, serdes->serdes_init_seq);
+	if (err) {
+		printf("failed to parse serdes-init-sequence\n");
+		goto free_init_seq;
+	}
+
+	return 0;
+
+free_init_seq:
+	free(serdes->serdes_init_seq);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(serdes_get_init_seq);
+
+int serdes_gpio_register(struct udevice *dev,
+			 struct serdes *serdes)
+{
+	bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+	struct uclass_driver *drv;
+	int ret = -ENODEV;
+	const char *name;
+	ofnode subnode;
+	struct udevice *subdev;
+	struct udevice *gpio_dev;
+
+	SERDES_DBG_MFD("%s node=%s\n",
+		       __func__, ofnode_get_name(dev->node));
+
+	/* Lookup GPIO driver */
+	drv = lists_uclass_lookup(UCLASS_GPIO);
+	if (!drv) {
+		printf("Cannot find GPIO driver\n");
+		return -ENOENT;
+	}
+
+	dev_for_each_subnode(subnode, dev) {
+		if (pre_reloc_only &&
+		    !ofnode_pre_reloc(subnode))
+			continue;
+
+		name = ofnode_get_name(subnode);
+		if (!name)
+			continue;
+
+		if (strstr(name, "gpio")) {
+			ret = device_bind_driver_to_node(dev,
+							 "serdes-gpio", name,
+							 subnode, &subdev);
+			if (ret)
+				return ret;
+
+			ret = uclass_get_device_by_ofnode(UCLASS_GPIO,
+							  subnode,
+							  &gpio_dev);
+			if (ret) {
+				printf("%s failed to get gpio dev\n", __func__);
+				return ret;
+			}
+
+			SERDES_DBG_MFD("%s select %s gpio_dev=%s\n",
+				       __func__, name, gpio_dev->name);
+			return 0;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_gpio_register);
+
+int serdes_pinctrl_register(struct udevice *dev,
+			    struct serdes *serdes)
+{
+	bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+	struct uclass_driver *drv;
+	int ret = -ENODEV;
+	const char *name;
+	ofnode subnode;
+	struct udevice *subdev;
+	struct udevice *pinctrl_dev;
+
+	SERDES_DBG_MFD("%s node=%s\n",
+		       __func__, ofnode_get_name(dev->node));
+
+	/* Lookup PINCTRL driver */
+	drv = lists_uclass_lookup(UCLASS_PINCTRL);
+	if (!drv) {
+		printf("Cannot find PINCTRL driver\n");
+		return -ENOENT;
+	}
+
+	dev_for_each_subnode(subnode, dev) {
+		if (pre_reloc_only &&
+		    !ofnode_pre_reloc(subnode))
+			continue;
+
+		name = ofnode_get_name(subnode);
+		if (!name)
+			continue;
+
+		if (strstr(name, "pinctrl")) {
+			ret = device_bind_driver_to_node(dev,
+							 "serdes-pinctrl", name,
+							 subnode, &subdev);
+			if (ret)
+				return ret;
+
+			ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL,
+							  subnode,
+							  &pinctrl_dev);
+			if (ret) {
+				printf("%s failed to get pinctrl\n", __func__);
+				return ret;
+			}
+
+			SERDES_DBG_MFD("%s select %s pinctrl_dev=%s\n",
+				       __func__, name, pinctrl_dev->name);
+			return 0;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(serdes_pinctrl_register);
+
+static int serdes_i2c_init(struct serdes *serdes)
+{
+	int ret = 0;
+	int i = 0;
+
+	if (serdes->vpower_supply)
+		regulator_set_enable(serdes->vpower_supply, true);
+
+	if (dm_gpio_is_valid(&serdes->enable_gpio))
+		dm_gpio_set_value(&serdes->enable_gpio, 1);
+
+	mdelay(5);
+
+	for (i = 0; i < 3; i++) {
+		ret = serdes_i2c_set_sequence(serdes);
+		if (!ret)
+			break;
+		mdelay(20);
+	}
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+
+	return ret;
+}
+
+static int serdes_i2c_probe(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev);
+	int ret;
+
+	ret = i2c_set_chip_offset_len(dev, 2);
+	if (ret)
+		return ret;
+
+	serdes->dev = dev;
+	serdes->chip_data = (struct serdes_chip_data *)dev_get_driver_data(dev);
+	serdes->type = serdes->chip_data->serdes_type;
+
+	SERDES_DBG_MFD("serdes %s %s probe start\n",
+		       serdes->dev->name, serdes->chip_data->name);
+
+	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					   "vpower-supply",
+					   &serdes->vpower_supply);
+	if (ret && ret != -ENOENT)
+		SERDES_DBG_MFD("%s: Cannot get power supply: %d\n",
+			       __func__, ret);
+
+	ret = gpio_request_by_name(dev, "enable-gpios", 0,
+				   &serdes->enable_gpio, GPIOD_IS_OUT);
+	if (ret)
+		SERDES_DBG_MFD("%s: failed to get enable gpio: %d\n",
+			       __func__, ret);
+
+	ret = gpio_request_by_name(dev, "lock-gpios", 0,
+				   &serdes->lock_gpio,
+				   GPIOD_IS_IN);
+	if (ret)
+		SERDES_DBG_MFD("%s: failed to get lock gpio: %d\n",
+			       __func__, ret);
+
+	ret = gpio_request_by_name(dev, "err-gpios", 0,
+				   &serdes->err_gpio,
+				   GPIOD_IS_IN);
+	if (ret)
+		SERDES_DBG_MFD("%s: failed to err gpio: %d\n",
+			       __func__, ret);
+
+	ret = serdes_get_init_seq(serdes);
+	if (ret)
+		return ret;
+
+	serdes_i2c_init(serdes);
+
+	printf("%s %s successful, version %s\n",
+	       __func__,
+	       serdes->dev->name,
+	       SERDES_UBOOT_DISPLAY_VERSION);
+
+	return 0;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_NOVO_NCA9539)
+	{ .compatible = "novo,nca9539", .data = (ulong)&serdes_nca9539_data },
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_misc) = {
+	.name = "serdes-misc",
+	.id = UCLASS_MISC,
+	.of_match = serdes_of_match,
+	.probe = serdes_i2c_probe,
+	.priv_auto_alloc_size = sizeof(struct serdes),
+};
+
+int serdes_power_init(void)
+{
+	struct udevice *dev;
+	int ret = 0;
+
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+					  DM_GET_DRIVER(serdes_misc),
+					  &dev);
+	if (ret)
+		printf("%s failed to get misc device ret=%d\n", __func__, ret);
+
+	return ret;
+}
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-gpio.c b/u-boot/drivers/video/drm/display-serdes/serdes-gpio.c
new file mode 100644
index 0000000000..f35454561d
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-gpio.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * gpiolib support for different serdes chip
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ *
+ */
+
+#include "core.h"
+
+static int serdes_gpio_get(struct udevice *dev, unsigned int offset)
+{
+	struct serdes_pinctrl *serdes_pinctrl = dev_get_priv(dev->parent);
+	struct serdes *serdes = serdes_pinctrl->parent;
+	int ret = 0;
+
+	if (serdes->chip_data->gpio_ops->get_level)
+		ret = serdes->chip_data->gpio_ops->get_level(serdes, offset);
+
+	SERDES_DBG_MFD("%s: %s %s gpio=%d\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name, offset);
+	return ret;
+}
+
+static int serdes_gpio_set(struct udevice *dev,
+			   unsigned int offset, int value)
+{
+	struct serdes_pinctrl *serdes_pinctrl = dev_get_priv(dev->parent);
+	struct serdes *serdes = serdes_pinctrl->parent;
+	int ret = 0;
+
+	if (serdes->chip_data->gpio_ops->set_level)
+		ret = serdes->chip_data->gpio_ops->set_level(serdes, offset, value);
+
+	SERDES_DBG_MFD("%s: %s %s gpio=%d,val=%d\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name, offset, value);
+	return ret;
+}
+
+static int serdes_gpio_direction_input(struct udevice *dev,
+				       unsigned int offset)
+{
+	struct serdes_pinctrl *serdes_pinctrl = dev_get_priv(dev->parent);
+	struct serdes *serdes = serdes_pinctrl->parent;
+	int ret = 0;
+
+	if (serdes->chip_data->gpio_ops->direction_input)
+		ret = serdes->chip_data->gpio_ops->direction_input(serdes, offset);
+
+	SERDES_DBG_MFD("%s: %s %s gpio=%d\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name, offset);
+	return ret;
+}
+
+static int serdes_gpio_direction_output(struct udevice *dev,
+					unsigned int offset, int value)
+{
+	struct serdes_pinctrl *serdes_pinctrl = dev_get_priv(dev->parent);
+	struct serdes *serdes = serdes_pinctrl->parent;
+	int ret = 0;
+
+	if (serdes->chip_data->gpio_ops->direction_output)
+		ret = serdes->chip_data->gpio_ops->direction_output(serdes, offset, value);
+
+	SERDES_DBG_MFD("%s: %s %s gpio=%d,val=%d\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name, offset, value);
+	return ret;
+}
+
+static int serdes_gpio_probe(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent->parent);
+	struct serdes_pinctrl *serdes_pinctrl = serdes->serdes_pinctrl;
+	struct serdes_gpio *serdes_gpio;
+
+	serdes_gpio = calloc(1, sizeof(*serdes_gpio));
+	if (!serdes_gpio)
+		return -ENOMEM;
+
+	serdes_pinctrl->serdes_gpio = serdes_gpio;
+
+	serdes_gpio->parent = serdes_pinctrl;
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       dev->name, serdes->chip_data->name);
+	return 0;
+}
+
+static struct dm_gpio_ops serdes_gpio_ops = {
+	.set_value = serdes_gpio_set,
+	.get_value = serdes_gpio_get,
+	.direction_input = serdes_gpio_direction_input,
+	.direction_output = serdes_gpio_direction_output,
+};
+
+U_BOOT_DRIVER(serdes_gpio) = {
+	.name = "serdes-gpio",
+	.id = UCLASS_GPIO,
+	.probe = serdes_gpio_probe,
+	.ops = &serdes_gpio_ops,
+	.priv_auto_alloc_size = sizeof(struct serdes_gpio),
+};
+
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-i2c.c b/u-boot/drivers/video/drm/display-serdes/serdes-i2c.c
new file mode 100644
index 0000000000..933bca96f0
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-i2c.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-bridge.c  --  display bridge for different serdes chips
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static struct serdes *g_serdes_ser_split[MAX_NUM_SERDES_SPLIT];
+
+static void serdes_i2c_init(struct serdes *serdes)
+{
+	if (serdes->vpower_supply)
+		regulator_set_enable(serdes->vpower_supply, true);
+
+	if (dm_gpio_is_valid(&serdes->enable_gpio))
+		dm_gpio_set_value(&serdes->enable_gpio, 1);
+
+	//mdelay(5);
+
+	//video_bridge_set_active(serdes->dev, true);
+
+	if (serdes->chip_data->bridge_ops->init)
+		serdes->chip_data->bridge_ops->init(serdes);
+
+	serdes_i2c_set_sequence(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__,
+		       serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static int serdes_set_i2c_address(struct serdes *serdes,
+				  u32 reg_hw, u32 reg_use, int link)
+{
+	int ret = 0;
+	struct dm_i2c_chip *chip_split;
+	struct serdes *serdes_split = serdes->g_serdes_bridge_split;
+
+	if (!serdes_split) {
+		pr_info("%s: serdes_split is null\n", __func__);
+		return -1;
+	}
+
+	chip_split = dev_get_parent_platdata(serdes->dev);
+	SERDES_DBG_MFD("%s: %s addr=0x%x reg_hw=0x%x, reg_use=0x%x split=0x%p\n",
+		       __func__, serdes_split->dev->name,
+		       chip_split->chip_addr, serdes->reg_hw,
+		       serdes->reg_use, serdes_split);
+
+	chip_split->chip_addr = serdes->reg_hw;
+
+	if (serdes_split && serdes_split->chip_data->split_ops &&
+	    serdes_split->chip_data->split_ops->select)
+		ret = serdes_split->chip_data->split_ops->select(serdes_split, link);
+
+	if (serdes->chip_data->split_ops &&
+	    serdes->chip_data->split_ops->set_i2c_addr)
+		serdes->chip_data->split_ops->set_i2c_addr(serdes,
+							   reg_use, link);
+
+	if (serdes_split && serdes_split->chip_data->split_ops &&
+	    serdes_split->chip_data->split_ops->select)
+		ret = serdes_split->chip_data->split_ops->select(serdes_split,
+								 SER_SPLITTER_MODE);
+
+	chip_split->chip_addr = serdes->reg_use;
+
+	serdes_i2c_set_sequence(serdes);
+
+	return ret;
+}
+
+static int serdes_i2c_probe(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev);
+	struct serdes_bridge *serdes_bridge = NULL;
+	struct serdes_bridge_split *serdes_bridge_split = NULL;
+	struct serdes_pinctrl *serdes_pinctrl = NULL;
+	int ret;
+
+	ret = i2c_set_chip_offset_len(dev, 2);
+	if (ret)
+		return ret;
+
+	serdes->dev = dev;
+	serdes->chip_data = (struct serdes_chip_data *)dev_get_driver_data(dev);
+	serdes->type = serdes->chip_data->serdes_type;
+
+	SERDES_DBG_MFD("serdes %s %s probe start serdes=%p\n",
+		       serdes->dev->name, serdes->chip_data->name, serdes);
+
+	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					   "vpower-supply",
+					   &serdes->vpower_supply);
+	if (ret && ret != -ENOENT)
+		SERDES_DBG_MFD("%s: Cannot get power supply: %d\n",
+			       __func__, ret);
+
+	ret = gpio_request_by_name(dev, "enable-gpios", 0,
+				   &serdes->enable_gpio, GPIOD_IS_OUT);
+	if (ret)
+		SERDES_DBG_MFD("%s: failed to get enable gpio: %d\n",
+			       __func__, ret);
+
+	ret = gpio_request_by_name(dev, "lock-gpios", 0, &serdes->lock_gpio,
+				   GPIOD_IS_IN);
+	if (ret)
+		SERDES_DBG_MFD("%s: failed to get lock gpio: %d\n",
+			       __func__, ret);
+
+	ret = gpio_request_by_name(dev, "err-gpios", 0, &serdes->err_gpio,
+				   GPIOD_IS_IN);
+	if (ret)
+		SERDES_DBG_MFD("%s: failed to err gpio: %d\n",
+			       __func__, ret);
+
+	if (serdes->chip_data->serdes_type == TYPE_OTHER) {
+		SERDES_DBG_MFD("TYPE_OTHER just need only init i2c\n");
+		serdes_i2c_init(serdes);
+		return 0;
+	}
+
+	ret = serdes_get_init_seq(serdes);
+	if (ret)
+		return ret;
+
+	if (serdes->chip_data->serdes_type == TYPE_SER)
+		serdes_i2c_init(serdes);
+
+	if (serdes->chip_data->bridge_ops) {
+		serdes_bridge = calloc(1, sizeof(*serdes_bridge));
+		if (!serdes_bridge)
+			return -ENOMEM;
+		serdes->serdes_bridge = serdes_bridge;
+
+		serdes_bridge_split = calloc(1, sizeof(*serdes_bridge_split));
+		if (!serdes_bridge_split)
+			return -ENOMEM;
+		serdes->serdes_bridge_split = serdes_bridge_split;
+	}
+
+	serdes_pinctrl = calloc(1, sizeof(*serdes_pinctrl));
+	if (!serdes_pinctrl)
+		return -ENOMEM;
+
+	serdes->serdes_pinctrl = serdes_pinctrl;
+	ret = serdes_pinctrl_register(dev, serdes);
+	if (ret)
+		return ret;
+
+	serdes->id_serdes_bridge_split = dev_read_u32_default(dev, "id-serdes-bridge-split", 0);
+	if ((serdes->id_serdes_bridge_split < MAX_NUM_SERDES_SPLIT) && (serdes->type == TYPE_SER)) {
+		g_serdes_ser_split[serdes->id_serdes_bridge_split] = serdes;
+		SERDES_DBG_MFD("%s: %s-%s g_serdes_split[%d]=0x%p\n", __func__,
+			       serdes->dev->name, serdes->chip_data->name,
+			       serdes->id_serdes_bridge_split, serdes);
+	}
+
+	serdes->reg_hw = dev_read_u32_default(dev, "reg-hw", 0);
+	serdes->reg_use = dev_read_u32_default(dev, "reg", 0);
+	serdes->link_use = dev_read_u32_default(dev, "link", 0);
+	serdes->id_serdes_panel_split = dev_read_u32_default(dev, "id-serdes-panel-split", 0);
+
+	if ((serdes->id_serdes_panel_split) && (serdes->type == TYPE_DES)) {
+		serdes->g_serdes_bridge_split = g_serdes_ser_split[serdes->id_serdes_panel_split];
+		SERDES_DBG_MFD("%s: id=%d p=0x%p\n", __func__,
+			       serdes->id_serdes_panel_split,
+			       serdes->g_serdes_bridge_split);
+	}
+
+	if (serdes->reg_hw) {
+		SERDES_DBG_MFD("%s: %s change i2c addr from 0x%x to 0x%x\n",
+			       __func__, dev->name,
+			       serdes->reg_hw, serdes->reg_use);
+		serdes_set_i2c_address(serdes, serdes->reg_hw,
+				       serdes->reg_use, serdes->link_use);
+	}
+
+	printf("%s %s %s successful\n",
+	       __func__,
+	       serdes->dev->name,
+	       serdes->chip_data->name);
+
+	return 0;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82)
+	{ .compatible = "rohm,bu18tl82",
+		.data = (ulong)&serdes_bu18tl82_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82)
+	{ .compatible = "rohm,bu18rl82",
+		.data = (ulong)&serdes_bu18rl82_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745)
+	{ .compatible = "maxim,max96745",
+		.data = (ulong)&serdes_max96745_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)
+	{ .compatible = "maxim,max96755",
+		.data = (ulong)&serdes_max96755_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96789)
+	{ .compatible = "maxim,max96789",
+		.data = (ulong)&serdes_max96789_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111)
+	{ .compatible = "rockchip,rkx111",
+		.data = (ulong)&serdes_rkx111_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752)
+	{ .compatible = "maxim,max96752",
+		.data = (ulong)&serdes_max96752_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772)
+	{ .compatible = "maxim,max96772",
+		.data = (ulong)&serdes_max96772_data },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121)
+	{ .compatible = "rockchip,rkx121",
+		.data = (ulong)&serdes_rkx121_data },
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_i2c) = {
+	.name = "serdes-i2c",
+	.id = UCLASS_MISC,
+	.of_match = serdes_of_match,
+	.probe = serdes_i2c_probe,
+	.bind = dm_scan_fdt_dev,
+	.priv_auto_alloc_size = sizeof(struct serdes),
+};
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-panel-split.c b/u-boot/drivers/video/drm/display-serdes/serdes-panel-split.c
new file mode 100644
index 0000000000..34891c0b58
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-panel-split.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-panel.c  --  display panel for different serdes chips
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static void serdes_panel_split_init(struct serdes *serdes)
+{
+	if (serdes->vpower_supply)
+		regulator_set_enable(serdes->vpower_supply, true);
+
+	if (dm_gpio_is_valid(&serdes->enable_gpio))
+		dm_gpio_set_value(&serdes->enable_gpio, 1);
+
+	mdelay(5);
+
+	if (serdes->chip_data->panel_ops->init)
+		serdes->chip_data->panel_ops->init(serdes);
+
+	if (serdes->chip_data->serdes_type == TYPE_DES)
+		serdes_i2c_set_sequence(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_split_prepare(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->prepare)
+		serdes->chip_data->panel_ops->prepare(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_split_unprepare(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->unprepare)
+		serdes->chip_data->panel_ops->unprepare(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_split_enable(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->enable)
+		serdes->chip_data->panel_ops->enable(serdes);
+
+	serdes_panel_split_init(serdes);
+
+	if (serdes->serdes_panel_split->backlight)
+		backlight_enable(serdes->serdes_panel_split->backlight);
+
+	if (serdes->chip_data->panel_ops->backlight_enable)
+		serdes->chip_data->panel_ops->backlight_enable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_split_disable(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->backlight_disable)
+		serdes->chip_data->panel_ops->backlight_disable(serdes);
+
+	if (serdes->serdes_panel_split->backlight)
+		backlight_disable(serdes->serdes_panel_split->backlight);
+
+	if (serdes->chip_data->panel_ops->disable)
+		serdes->chip_data->panel_ops->disable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static struct rockchip_panel_funcs serdes_panel_split_ops = {
+	.prepare = serdes_panel_split_prepare,
+	.unprepare = serdes_panel_split_unprepare,
+	.enable = serdes_panel_split_enable,
+	.disable = serdes_panel_split_disable,
+};
+
+static int serdes_panel_split_probe(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	struct serdes_panel_split *serdes_panel_split = NULL;
+	struct rockchip_panel *panel;
+	int ret;
+
+	SERDES_DBG_MFD("%s: %s %s start\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+
+	if (!serdes->chip_data->panel_ops) {
+		printf("%s %s no panel ops\n",
+		       __func__, serdes->chip_data->name);
+		return -1;
+	}
+
+	if (serdes->chip_data->serdes_type != TYPE_DES)
+		printf("%s warning: this chip is not des type\n", __func__);
+
+	serdes_panel_split = calloc(1, sizeof(*serdes_panel_split));
+	if (!serdes_panel_split)
+		return -ENOMEM;
+
+	serdes->serdes_panel_split = serdes_panel_split;
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight",
+					   &serdes->serdes_panel_split->backlight);
+	if (ret && ret != -ENOENT)
+		printf("%s: Cannot get backlight: %d\n", __func__, ret);
+
+	panel = calloc(1, sizeof(*panel));
+	if (!panel)
+		return -ENOMEM;
+
+	ret = serdes_get_init_seq(serdes);
+	if (ret)
+		goto free_panel;
+
+	dev->driver_data = (ulong)panel;
+	panel->dev = dev;
+	panel->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	panel->funcs = &serdes_panel_split_ops;
+
+	serdes->serdes_panel_split->panel = panel;
+
+	printf("%s %s successful, version %s\n",
+	       __func__,
+	       serdes->dev->name,
+	       SERDES_UBOOT_DISPLAY_VERSION);
+
+	return 0;
+
+free_panel:
+	free(panel);
+
+	return ret;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752)
+	{ .compatible = "maxim,max96752-panel-split",},
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772)
+	{ .compatible = "maxim,max96772-panel-split",},
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121)
+	{ .compatible = "rockchip,rkx121-panel-split",},
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_panel_split) = {
+	.name = "serdes-panel-split",
+	.id = UCLASS_PANEL,
+	.of_match = serdes_of_match,
+	.probe = serdes_panel_split_probe,
+	.priv_auto_alloc_size = sizeof(struct serdes_panel_split),
+};
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-panel.c b/u-boot/drivers/video/drm/display-serdes/serdes-panel.c
new file mode 100644
index 0000000000..4fea21bb48
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-panel.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-panel.c  --  display panel for different serdes chips
+ *
+ * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static void serdes_panel_init(struct serdes *serdes)
+{
+	if (serdes->vpower_supply)
+		regulator_set_enable(serdes->vpower_supply, true);
+
+	if (dm_gpio_is_valid(&serdes->enable_gpio))
+		dm_gpio_set_value(&serdes->enable_gpio, 1);
+
+	mdelay(5);
+
+	if (serdes->chip_data->panel_ops->init)
+		serdes->chip_data->panel_ops->init(serdes);
+
+	if (serdes->chip_data->serdes_type == TYPE_DES)
+		serdes_i2c_set_sequence(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_prepare(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->prepare)
+		serdes->chip_data->panel_ops->prepare(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_unprepare(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->unprepare)
+		serdes->chip_data->panel_ops->unprepare(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_enable(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->enable)
+		serdes->chip_data->panel_ops->enable(serdes);
+
+	serdes_panel_init(serdes);
+
+	if (serdes->serdes_panel->backlight)
+		backlight_enable(serdes->serdes_panel->backlight);
+
+	if (serdes->chip_data->panel_ops->backlight_enable)
+		serdes->chip_data->panel_ops->backlight_enable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static void serdes_panel_disable(struct rockchip_panel *panel)
+{
+	struct udevice *dev = panel->dev;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->panel_ops->backlight_disable)
+		serdes->chip_data->panel_ops->backlight_disable(serdes);
+
+	if (serdes->serdes_panel->backlight)
+		backlight_disable(serdes->serdes_panel->backlight);
+
+	if (serdes->chip_data->panel_ops->disable)
+		serdes->chip_data->panel_ops->disable(serdes);
+
+	SERDES_DBG_MFD("%s: %s %s\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+}
+
+static struct rockchip_panel_funcs serdes_panel_ops = {
+	.prepare = serdes_panel_prepare,
+	.unprepare = serdes_panel_unprepare,
+	.enable = serdes_panel_enable,
+	.disable = serdes_panel_disable,
+};
+
+static int serdes_panel_probe(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	struct serdes_panel *serdes_panel = NULL;
+	struct rockchip_panel *panel;
+	int ret;
+
+	SERDES_DBG_MFD("%s: %s %s start\n", __func__, serdes->dev->name,
+		       serdes->chip_data->name);
+
+	if (!serdes->chip_data->panel_ops) {
+		printf("%s %s no panel ops\n",
+		       __func__, serdes->chip_data->name);
+		return -1;
+	}
+
+	if (serdes->chip_data->serdes_type != TYPE_DES)
+		printf("warning: this chip is not des type\n");
+
+	serdes_panel = calloc(1, sizeof(*serdes_panel));
+	if (!serdes_panel)
+		return -ENOMEM;
+
+	serdes->serdes_panel = serdes_panel;
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight",
+					   &serdes->serdes_panel->backlight);
+	if (ret && ret != -ENOENT)
+		printf("%s: Cannot get backlight: %d\n", __func__, ret);
+
+	panel = calloc(1, sizeof(*panel));
+	if (!panel)
+		return -ENOMEM;
+
+	ret = serdes_get_init_seq(serdes);
+	if (ret)
+		goto free_panel;
+
+	dev->driver_data = (ulong)panel;
+	panel->dev = dev;
+	panel->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	panel->funcs = &serdes_panel_ops;
+
+	serdes->serdes_panel->panel = panel;
+
+	printf("%s %s successful, version %s\n",
+	       __func__,
+	       serdes->dev->name,
+	       SERDES_UBOOT_DISPLAY_VERSION);
+
+	return 0;
+
+free_panel:
+	free(panel);
+
+	return ret;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752)
+	{ .compatible = "maxim,max96752-panel",},
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772)
+	{ .compatible = "maxim,max96772-panel",},
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121)
+	{ .compatible = "rockchip,rkx121-panel",},
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_panel) = {
+	.name = "serdes-panel",
+	.id = UCLASS_PANEL,
+	.of_match = serdes_of_match,
+	.probe = serdes_panel_probe,
+	.priv_auto_alloc_size = sizeof(struct serdes_panel),
+};
diff --git a/u-boot/drivers/video/drm/display-serdes/serdes-pinctrl.c b/u-boot/drivers/video/drm/display-serdes/serdes-pinctrl.c
new file mode 100644
index 0000000000..5fe1537029
--- /dev/null
+++ b/u-boot/drivers/video/drm/display-serdes/serdes-pinctrl.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * serdes-pinctrl.c  -- serdes pin control driver.
+ *
+ * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
+ *
+ * Author: luowei <lw@rock-chips.com>
+ */
+
+#include "core.h"
+
+static const struct pinconf_param serdes_conf_params[] = {
+	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+	{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+	{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+	{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+	{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+	{ "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+};
+
+static int serdes_pinctrl_get_pins_count(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_info->num_pins)
+		return serdes->chip_data->pinctrl_info->num_pins;
+	else
+		return 0;
+}
+
+static const char *serdes_pinctrl_get_pin_name(struct udevice *dev,
+					       unsigned int selector)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_info->pins[selector].name)
+		return serdes->chip_data->pinctrl_info->pins[selector].name;
+	else
+		return "unknow-pin";
+}
+
+static int serdes_pinctrl_get_groups_count(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_info->num_groups)
+		return serdes->chip_data->pinctrl_info->num_groups;
+	else
+		return 0;
+}
+
+static const char *serdes_pinctrl_get_group_name(struct udevice *dev,
+						 unsigned int selector)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_info->groups[selector].name)
+		return serdes->chip_data->pinctrl_info->groups[selector].name;
+	else
+		return "unknow-group";
+}
+
+static int serdes_pinctrl_get_functions_count(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_info->num_functions)
+		return serdes->chip_data->pinctrl_info->num_functions;
+	else
+		return 0;
+}
+
+static const char *serdes_pinctrl_get_function_name(struct udevice *dev,
+						    unsigned int selector)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_info->functions[selector].name)
+		return serdes->chip_data->pinctrl_info->functions[selector].name;
+	else
+		return "unknow-function";
+}
+
+static int serdes_pinmux_set_mux(struct udevice *dev,
+				 unsigned int pin_selector,
+				 unsigned int func_selector)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	int ret = 0;
+
+	if (serdes->chip_data->pinctrl_ops->pinmux_set)
+		ret = serdes->chip_data->pinctrl_ops->pinmux_set(serdes,
+								 pin_selector, func_selector);
+
+	SERDES_DBG_MFD("%s: %s pin=%d,func=%d\n", __func__,
+		       serdes->chip_data->name, pin_selector, func_selector);
+	return ret;
+}
+
+static int serdes_pinmux_group_set_mux(struct udevice *dev,
+				       unsigned int group_selector,
+				       unsigned int func_selector)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	int ret = 0;
+
+	if (serdes->chip_data->pinctrl_ops->pinmux_group_set)
+		ret = serdes->chip_data->pinctrl_ops->pinmux_group_set(serdes,
+								       group_selector, func_selector);
+
+	SERDES_DBG_MFD("%s: %s function=%d,group=%d\n", __func__,
+		       serdes->chip_data->name, func_selector, group_selector);
+	return ret;
+}
+
+static int serdes_pinconf_set(struct udevice *dev, unsigned int pin_selector,
+			      unsigned int param, unsigned int argument)
+{
+	int ret = 0;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_ops->pinconf_set)
+		ret = serdes->chip_data->pinctrl_ops->pinconf_set(serdes,
+								  pin_selector, param, argument);
+
+	SERDES_DBG_MFD("serdes: pin = %d (%s), param = %d, arg = %d\n",
+		       pin_selector,
+		       serdes_pinctrl_get_pin_name(dev, pin_selector),
+		       param, argument);
+
+	return ret;
+}
+
+static int serdes_pinconf_group_set(struct udevice *dev,
+				    unsigned int group_selector,
+				    unsigned int param, unsigned int argument)
+{
+	int ret = 0;
+	struct serdes *serdes = dev_get_priv(dev->parent);
+
+	if (serdes->chip_data->pinctrl_ops->pinconf_group_set)
+		ret = serdes->chip_data->pinctrl_ops->pinconf_group_set(serdes,
+									group_selector, param, argument);
+
+	SERDES_DBG_MFD("serdes: group = %d (%s), param = %d, arg = %d\n",
+		       group_selector,
+		       serdes_pinctrl_get_group_name(dev, group_selector),
+		       param, argument);
+	return ret;
+}
+
+static struct pinctrl_ops serdes_pinctrl_ops = {
+	.get_pins_count = serdes_pinctrl_get_pins_count,
+	.get_pin_name = serdes_pinctrl_get_pin_name,
+	.get_groups_count = serdes_pinctrl_get_groups_count,
+	.get_group_name = serdes_pinctrl_get_group_name,
+	.get_functions_count = serdes_pinctrl_get_functions_count,
+	.get_function_name = serdes_pinctrl_get_function_name,
+	.set_state = pinctrl_generic_set_state,
+	.pinmux_set = serdes_pinmux_set_mux,
+	.pinmux_group_set = serdes_pinmux_group_set_mux,
+	.pinconf_num_params = ARRAY_SIZE(serdes_conf_params),
+	.pinconf_params = serdes_conf_params,
+	.pinconf_set = serdes_pinconf_set,
+	.pinconf_group_set = serdes_pinconf_group_set,
+};
+
+int serdes_pinctrl_probe(struct udevice *dev)
+{
+	struct serdes *serdes = dev_get_priv(dev->parent);
+	struct serdes_pinctrl *serdes_pinctrl = serdes->serdes_pinctrl;
+	int ret = 0;
+
+	SERDES_DBG_MFD("%s: %s %s start\n", __func__, dev->name,
+		       serdes->chip_data->name);
+
+	serdes_pinctrl->parent = serdes;
+
+	ret = serdes_gpio_register(dev, serdes);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct udevice_id serdes_of_match[] = {
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82)
+	{ .compatible = "rohm,bu18tl82-pinctrl" },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82)
+	{ .compatible = "rohm,bu18rl82-pinctrl" },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745)
+	{ .compatible = "maxim,max96745-pinctrl", },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)
+	{ .compatible = "maxim,max96755-pinctrl" },
+#endif
+#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111)
+	{ .compatible = "rockchip,rkx111-pinctrl" },
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(serdes_pinctrl) = {
+	.name = "serdes-pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = serdes_of_match,
+	.probe = serdes_pinctrl_probe,
+	.ops	= &serdes_pinctrl_ops,
+	.priv_auto_alloc_size = sizeof(struct serdes_pinctrl),
+};
diff --git a/u-boot/drivers/video/drm/drm_of.c b/u-boot/drivers/video/drm/drm_of.c
new file mode 100644
index 0000000000..d79f6da271
--- /dev/null
+++ b/u-boot/drivers/video/drm/drm_of.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2023 Rockchip Electronics Co., Ltd
+ *
+ */
+#include <dm/device.h>
+#include <dm/read.h>
+
+#include "drm_of.h"
+
+enum drm_of_lvds_pixels {
+	DRM_OF_LVDS_EVEN = BIT(0),
+	DRM_OF_LVDS_ODD = BIT(1),
+	DRM_OF_LVDS_LEFT = BIT(2),
+	DRM_OF_LVDS_RIGHT = BIT(3),
+};
+
+static int
+drm_of_lvds_get_port_pixels_type(const struct device_node *port_node)
+{
+	ofnode node = np_to_ofnode(port_node);
+
+	bool even_pixels =
+		ofnode_read_bool(node, "dual-lvds-even-pixels");
+	bool odd_pixels =
+		ofnode_read_bool(node, "dual-lvds-odd-pixels");
+	bool left_pixels =
+		ofnode_read_bool(node, "dual-lvds-left-pixels");
+	bool right_pixels =
+		ofnode_read_bool(node, "dual-lvds-right-pixels");
+
+	return (even_pixels ? DRM_OF_LVDS_EVEN : 0) |
+		   (odd_pixels ? DRM_OF_LVDS_ODD : 0) |
+		   (left_pixels ? DRM_OF_LVDS_LEFT : 0) |
+		   (right_pixels ? DRM_OF_LVDS_RIGHT : 0);
+}
+
+static int
+drm_of_lvds_get_remote_pixels_type(const struct device_node *port_node)
+{
+	ofnode node = np_to_ofnode(port_node);
+	ofnode endpoint;
+	uint phandle;
+	int pixels_type = -EPIPE;
+
+	ofnode_for_each_subnode(endpoint, node) {
+		int current_pt;
+		const char *name;
+
+		if (!ofnode_is_available(endpoint))
+			continue;
+
+		name = ofnode_get_name(endpoint);
+		if (strncmp(name, "endpoint", 8) != 0)
+			continue;
+
+		if (ofnode_read_u32(endpoint, "remote-endpoint", &phandle))
+			continue;
+
+		endpoint = ofnode_get_by_phandle(phandle);
+		if (!ofnode_valid(endpoint) || !ofnode_is_available(endpoint))
+			continue;
+
+		endpoint = ofnode_get_parent(endpoint);
+		if (!ofnode_valid(endpoint))
+			continue;
+
+		current_pt =
+			drm_of_lvds_get_port_pixels_type(ofnode_to_np(endpoint
+				));
+		if (pixels_type < 0)
+			pixels_type = current_pt;
+
+		/*
+		 * Sanity check, ensure that all remote endpoints have the same
+		 * pixel type. We may lift this restriction later if we need to
+		 * support multiple sinks with different dual-link
+		 * configurations by passing the endpoints explicitly to
+		 * drm_of_lvds_get_dual_link_pixel_order().
+		 */
+		if (!current_pt || pixels_type != current_pt)
+			return -EINVAL;
+	}
+
+	return pixels_type;
+}
+
+/**
+ * drm_of_lvds_get_dual_link_pixel_order - Get LVDS dual-link pixel order
+ * @port1: First DT port node of the Dual-link LVDS source
+ * @port2: Second DT port node of the Dual-link LVDS source
+ *
+ * An LVDS dual-link connection is made of two links, the two link can transmit
+ * odd pixels and even pixels independently, or the two link can also transmit
+ * left pixels and right pixels independently. This function returns for two
+ * ports of an LVDS dual-link source, based on the requirements of the connected
+ * sink.
+ *
+ * The pixel order is determined from the dual-lvds-even-pixels +
+ * dual-lvds-odd-pixels or dual-lvds-left-pixels + dual-lvds-right-pixels
+ * properties in the sink's DT port nodes. If those
+ * properties are not present, or if their usage is not valid, this function
+ * returns -EINVAL.
+ *
+ * If either port is not connected, this function returns -EPIPE.
+ *
+ * @port1 and @port2 are typically DT sibling nodes, but may have different
+ * parents when, for instance, two separate LVDS encoders carry the even and
+ * odd pixels.
+ *
+ * Return:
+ * * DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS - @port1 carries even pixels and @port2
+ *   carries odd pixels
+ * * DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS - @port1 carries odd pixels and @port2
+ *   carries even pixels
+ * * DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS - @port1 carries left pixels and
+ *   @port2 carries right pixels
+ * * DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS - @port1 carries right pixels and
+ *   @port2 carries left pixels
+
+ * * -EINVAL - @port1 and @port2 are not connected to a dual-link LVDS sink, or
+ *   the sink configuration is invalid
+ * * -EPIPE - when @port1 or @port2 are not connected
+ */
+int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1,
+					  const struct device_node *port2)
+{
+	int remote_p1_pt, remote_p2_pt;
+
+	if (!port1 || !port2)
+		return -EINVAL;
+
+	remote_p1_pt = drm_of_lvds_get_remote_pixels_type(port1);
+	if (remote_p1_pt < 0)
+		return remote_p1_pt;
+
+	remote_p2_pt = drm_of_lvds_get_remote_pixels_type(port2);
+	if (remote_p2_pt < 0)
+		return remote_p2_pt;
+
+	/*
+	 * A valid dual-lVDS bus is found when one remote port is marked with
+	 * "dual-lvds-even-pixels" or "dual-lvds-left-pixels", and the other
+	 * remote port is marked with "dual-lvds-odd-pixels"or
+	 * "dual-lvds-right-pixels", bail out if the markers are not right.
+	 */
+	if ((remote_p1_pt + remote_p2_pt !=
+		DRM_OF_LVDS_EVEN + DRM_OF_LVDS_ODD) &&
+		(remote_p1_pt + remote_p2_pt !=
+		DRM_OF_LVDS_LEFT + DRM_OF_LVDS_RIGHT))
+		return -EINVAL;
+
+	if (remote_p1_pt == DRM_OF_LVDS_EVEN)
+		return DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
+	else if (remote_p1_pt == DRM_OF_LVDS_ODD)
+		return DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
+	else if (remote_p1_pt == DRM_OF_LVDS_LEFT)
+		return DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS;
+	else
+		return DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS;
+}
diff --git a/u-boot/drivers/video/drm/drm_of.h b/u-boot/drivers/video/drm/drm_of.h
new file mode 100644
index 0000000000..f0cb3460ca
--- /dev/null
+++ b/u-boot/drivers/video/drm/drm_of.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2023 Rockchip Electronics Co., Ltd
+ *
+ */
+#ifndef __DRM_OF_H__
+#define __DRM_OF_H__
+
+#include <dm/ofnode.h>
+#include <dm/of_access.h>
+
+/**
+ * enum drm_lvds_dual_link_pixels - Pixel order of an LVDS dual-link connection
+ * @DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: Even pixels are expected to be
+ *    generated from the first port, odd pixels from the second port
+ * @DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: Odd pixels are expected to be
+ *    generated from the first port, even pixels from the second port
+ * @DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS: Left pixels are expected to be
+ *    generated from the first port, right pixels from the second port
+ * @DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS: Right pixels are expected to be
+ *    generated from the first port, left pixels from the second port
+ */
+enum drm_lvds_dual_link_pixels {
+	DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 0,
+	DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 1,
+	DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS = 2,
+	DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS = 3,
+};
+
+int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1,
+					  const struct device_node *port2);
+
+#endif
diff --git a/u-boot/drivers/video/drm/dw_hdmi.c b/u-boot/drivers/video/drm/dw_hdmi.c
index a30e4d526c..882bae2d6e 100644
--- a/u-boot/drivers/video/drm/dw_hdmi.c
+++ b/u-boot/drivers/video/drm/dw_hdmi.c
@@ -181,6 +181,7 @@ struct dw_hdmi {
 	bool cable_plugin;
 	bool sink_is_hdmi;
 	bool sink_has_audio;
+	bool force_output;
 	void *regs;
 	void *grf;
 	void *gpio_base;
@@ -878,7 +879,7 @@ static int rockchip_dw_hdmi_scrambling_enable(struct dw_hdmi *hdmi,
 
 	drm_scdc_readb(&hdmi->adap, SCDC_TMDS_CONFIG, &stat);
 
-	if (stat < 0) {
+	if (stat < 0 && !hdmi->force_output) {
 		debug("Failed to read tmds config\n");
 		return false;
 	}
@@ -1168,7 +1169,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	}
 
 	/* Scrambling Control */
-	if (hdmi_info->scdc.supported) {
+	if (hdmi_info->scdc.supported || hdmi->force_output) {
 		if (vmode->mtmdsclock > 340000000 ||
 		    (hdmi_info->scdc.scrambling.low_rates &&
 		     hdmi->scramble_low_rates)) {
@@ -2519,6 +2520,20 @@ int rockchip_dw_hdmi_disable(struct rockchip_connector *conn, struct display_sta
 	return 0;
 }
 
+static void rockchip_dw_hdmi_mode_valid(struct dw_hdmi *hdmi)
+{
+	struct hdmi_edid_data *edid_data = &hdmi->edid_data;
+	int i;
+
+	for (i = 0; i < edid_data->modes; i++) {
+		if (edid_data->mode_buf[i].invalid)
+			continue;
+
+		if (edid_data->mode_buf[i].clock > 600000)
+			edid_data->mode_buf[i].invalid = true;
+	}
+}
+
 int rockchip_dw_hdmi_get_timing(struct rockchip_connector *conn, struct display_state *state)
 {
 	int ret, i, vic;
@@ -2555,6 +2570,7 @@ int rockchip_dw_hdmi_get_timing(struct rockchip_connector *conn, struct display_
 	conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
 #endif
 	drm_rk_filter_whitelist(&hdmi->edid_data);
+	rockchip_dw_hdmi_mode_valid(hdmi);
 	if (hdmi->phy.ops->mode_valid)
 		hdmi->phy.ops->mode_valid(conn, hdmi, state);
 	drm_mode_max_resolution_filter(&hdmi->edid_data,
@@ -2586,8 +2602,12 @@ int rockchip_dw_hdmi_get_timing(struct rockchip_connector *conn, struct display_
 	*mode = *hdmi->edid_data.preferred_mode;
 	hdmi->vic = drm_match_cea_mode(mode);
 
-	if (state->force_output)
+	if (state->force_output) {
+		hdmi->force_output = state->force_output;
+		hdmi->sink_is_hdmi = true;
+		hdmi->sink_has_audio = true;
 		bus_format = state->force_bus_format;
+	}
 	conn_state->bus_format = bus_format;
 	hdmi->hdmi_data.enc_in_bus_format = bus_format;
 	hdmi->hdmi_data.enc_out_bus_format = bus_format;
diff --git a/u-boot/drivers/video/drm/dw_hdmi_qp.c b/u-boot/drivers/video/drm/dw_hdmi_qp.c
index 70ea921bc0..c25c5b96db 100644
--- a/u-boot/drivers/video/drm/dw_hdmi_qp.c
+++ b/u-boot/drivers/video/drm/dw_hdmi_qp.c
@@ -18,6 +18,7 @@
 #include <linux/media-bus-format.h>
 #include <linux/dw_hdmi.h>
 #include <asm/io.h>
+#include "rockchip_bridge.h"
 #include "rockchip_display.h"
 #include "rockchip_crtc.h"
 #include "rockchip_connector.h"
@@ -1111,9 +1112,15 @@ int dw_hdmi_detect_hotplug(struct dw_hdmi_qp *hdmi,
 			   struct display_state *state)
 {
 	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_connector *conn = conn_state->connector;
 	int ret;
 
 	ret = hdmi->phy.ops->read_hpd(hdmi->rk_hdmi);
+	if (!ret) {
+		if (conn->bridge)
+			ret = rockchip_bridge_detect(conn->bridge);
+	}
+
 	if (ret || state->force_output) {
 		if (!hdmi->id)
 			conn_state->output_if |= VOP_OUTPUT_IF_HDMI0;
@@ -1209,8 +1216,80 @@ void rockchip_dw_hdmi_qp_deinit(struct rockchip_connector *conn, struct display_
 		free(hdmi);
 }
 
+static void rockchip_dw_hdmi_qp_config_output(struct rockchip_connector *conn,
+					      struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct drm_display_mode *mode = &conn_state->mode;
+	struct dw_hdmi_qp *hdmi = conn->data;
+	unsigned int bus_format;
+	unsigned long enc_out_encoding;
+	struct overscan *overscan = &conn_state->overscan;
+
+	dw_hdmi_qp_selete_output(&hdmi->edid_data, conn, &bus_format,
+				 overscan, hdmi->dev_type,
+				 hdmi->output_bus_format_rgb, hdmi->rk_hdmi,
+				 state);
+
+	*mode = *hdmi->edid_data.preferred_mode;
+	hdmi->vic = drm_match_cea_mode(mode);
+
+	printf("mode:%dx%d bus_format:0x%x\n", mode->hdisplay, mode->vdisplay, bus_format);
+	conn_state->bus_format = bus_format;
+	hdmi->hdmi_data.enc_in_bus_format = bus_format;
+	hdmi->hdmi_data.enc_out_bus_format = bus_format;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_YUYV10_1X20:
+		conn_state->bus_format = MEDIA_BUS_FMT_YUYV10_1X20;
+		hdmi->hdmi_data.enc_in_bus_format =
+			MEDIA_BUS_FMT_YUYV10_1X20;
+		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
+		break;
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+		conn_state->bus_format = MEDIA_BUS_FMT_YUYV8_1X16;
+		hdmi->hdmi_data.enc_in_bus_format =
+			MEDIA_BUS_FMT_YUYV8_1X16;
+		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
+		break;
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420;
+		break;
+	}
+
+	if (hdmi->vic == 6 || hdmi->vic == 7 || hdmi->vic == 21 ||
+	    hdmi->vic == 22 || hdmi->vic == 2 || hdmi->vic == 3 ||
+	    hdmi->vic == 17 || hdmi->vic == 18)
+		enc_out_encoding = V4L2_YCBCR_ENC_601;
+	else
+		enc_out_encoding = V4L2_YCBCR_ENC_709;
+
+	if (enc_out_encoding == V4L2_YCBCR_ENC_BT2020)
+		conn_state->color_space = V4L2_COLORSPACE_BT2020;
+	else if (bus_format == MEDIA_BUS_FMT_RGB888_1X24 ||
+		 bus_format == MEDIA_BUS_FMT_RGB101010_1X30)
+		conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
+	else if (enc_out_encoding == V4L2_YCBCR_ENC_709)
+		conn_state->color_space = V4L2_COLORSPACE_REC709;
+	else
+		conn_state->color_space = V4L2_COLORSPACE_SMPTE170M;
+}
+
 int rockchip_dw_hdmi_qp_prepare(struct rockchip_connector *conn, struct display_state *state)
 {
+	struct connector_state *conn_state = &state->conn_state;
+	struct drm_display_mode *mode = &conn_state->mode;
+	struct dw_hdmi_qp *hdmi = conn->data;
+
+	if (!hdmi->edid_data.preferred_mode && conn->bridge) {
+		drm_add_hdmi_modes(&hdmi->edid_data, mode);
+		drm_mode_sort(&hdmi->edid_data);
+		hdmi->sink_is_hdmi = true;
+		hdmi->sink_has_audio = true;
+		rockchip_dw_hdmi_qp_config_output(conn, state);
+	}
+
 	return 0;
 }
 
@@ -1284,12 +1363,8 @@ static int _rockchip_dw_hdmi_qp_get_timing(struct rockchip_connector *conn,
 {
 	int i;
 	struct connector_state *conn_state = &state->conn_state;
-	struct drm_display_mode *mode = &conn_state->mode;
 	struct dw_hdmi_qp *hdmi = conn->data;
 	struct edid *edid = (struct edid *)conn_state->edid;
-	unsigned int bus_format;
-	unsigned long enc_out_encoding;
-	struct overscan *overscan = &conn_state->overscan;
 	const u8 def_modes_vic[6] = {4, 16, 2, 17, 31, 19};
 
 	if (!hdmi)
@@ -1323,54 +1398,8 @@ static int _rockchip_dw_hdmi_qp_get_timing(struct rockchip_connector *conn,
 			drm_mode_vrefresh(&hdmi->edid_data.mode_buf[i]);
 
 	drm_mode_sort(&hdmi->edid_data);
-	dw_hdmi_qp_selete_output(&hdmi->edid_data, conn, &bus_format,
-				 overscan, hdmi->dev_type,
-				 hdmi->output_bus_format_rgb, hdmi->rk_hdmi,
-				 state);
 
-	*mode = *hdmi->edid_data.preferred_mode;
-	hdmi->vic = drm_match_cea_mode(mode);
-
-	printf("mode:%dx%d bus_format:0x%x\n", mode->hdisplay, mode->vdisplay, bus_format);
-	conn_state->bus_format = bus_format;
-	hdmi->hdmi_data.enc_in_bus_format = bus_format;
-	hdmi->hdmi_data.enc_out_bus_format = bus_format;
-
-	switch (bus_format) {
-	case MEDIA_BUS_FMT_YUYV10_1X20:
-		conn_state->bus_format = MEDIA_BUS_FMT_YUYV10_1X20;
-		hdmi->hdmi_data.enc_in_bus_format =
-			MEDIA_BUS_FMT_YUYV10_1X20;
-		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
-		break;
-	case MEDIA_BUS_FMT_YUYV8_1X16:
-		conn_state->bus_format = MEDIA_BUS_FMT_YUYV8_1X16;
-		hdmi->hdmi_data.enc_in_bus_format =
-			MEDIA_BUS_FMT_YUYV8_1X16;
-		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
-		break;
-	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
-	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
-		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420;
-		break;
-	}
-
-	if (hdmi->vic == 6 || hdmi->vic == 7 || hdmi->vic == 21 ||
-	    hdmi->vic == 22 || hdmi->vic == 2 || hdmi->vic == 3 ||
-	    hdmi->vic == 17 || hdmi->vic == 18)
-		enc_out_encoding = V4L2_YCBCR_ENC_601;
-	else
-		enc_out_encoding = V4L2_YCBCR_ENC_709;
-
-	if (enc_out_encoding == V4L2_YCBCR_ENC_BT2020)
-		conn_state->color_space = V4L2_COLORSPACE_BT2020;
-	else if (bus_format == MEDIA_BUS_FMT_RGB888_1X24 ||
-		 bus_format == MEDIA_BUS_FMT_RGB101010_1X30)
-		conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
-	else if (enc_out_encoding == V4L2_YCBCR_ENC_709)
-		conn_state->color_space = V4L2_COLORSPACE_REC709;
-	else
-		conn_state->color_space = V4L2_COLORSPACE_SMPTE170M;
+	rockchip_dw_hdmi_qp_config_output(conn, state);
 
 	return 0;
 }
diff --git a/u-boot/drivers/video/drm/dw_mipi_dsi2.c b/u-boot/drivers/video/drm/dw_mipi_dsi2.c
index fcd7cbe0ee..5882026c3c 100644
--- a/u-boot/drivers/video/drm/dw_mipi_dsi2.c
+++ b/u-boot/drivers/video/drm/dw_mipi_dsi2.c
@@ -272,6 +272,7 @@ struct dw_mipi_dsi2 {
 	struct dw_mipi_dsi2 *slave;
 	bool prepared;
 
+	bool auto_calc_mode;
 	bool c_option;
 	bool dsc_enable;
 	bool scrambling_en;
@@ -285,6 +286,7 @@ struct dw_mipi_dsi2 {
 	u32 lanes;
 	u32 format;
 	u32 mode_flags;
+	u64 mipi_pixel_rate;
 	struct mipi_dcphy dcphy;
 	struct drm_display_mode mode;
 	bool data_swap;
@@ -551,6 +553,9 @@ static void dw_mipi_dsi2_ipi_set(struct dw_mipi_dsi2 *dsi2)
 
 	dw_mipi_dsi2_ipi_color_coding_cfg(dsi2);
 
+	if (dsi2->auto_calc_mode)
+		return;
+
 	/*
 	 * if the controller is intended to operate in data stream mode,
 	 * no more steps are required.
@@ -655,15 +660,27 @@ static void dw_mipi_dsi2_set_cmd_mode(struct dw_mipi_dsi2 *dsi2)
 
 static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2)
 {
+	u32 mode;
+	int ret;
+
 	dw_mipi_dsi2_ipi_set(dsi2);
 
+	if (dsi2->auto_calc_mode) {
+		dsi_write(dsi2, DSI2_MODE_CTRL, AUTOCALC_MODE);
+		ret = readl_poll_timeout(dsi2->base + DSI2_MODE_STATUS,
+					 mode, mode == IDLE_MODE,
+					 MODE_STATUS_TIMEOUT_US);
+		if (ret < 0)
+			printf("auto calculation training failed\n");
+	}
+
 	if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)
 		dw_mipi_dsi2_set_vid_mode(dsi2);
 	else
 		dw_mipi_dsi2_set_data_stream_mode(dsi2);
 
 	if (dsi2->slave)
-		dw_mipi_dsi2_enable(dsi2->slave);
+	    dw_mipi_dsi2_enable(dsi2->slave);
 }
 
 static void dw_mipi_dsi2_disable(struct dw_mipi_dsi2 *dsi2)
@@ -822,6 +839,8 @@ static int dw_mipi_dsi2_connector_init(struct rockchip_connector *conn, struct d
 
 		dsi2->slave->master = dsi2;
 		dsi2->lanes /= 2;
+
+		dsi2->slave->auto_calc_mode = dsi2->auto_calc_mode;
 		dsi2->slave->lanes = dsi2->lanes;
 		dsi2->slave->format = dsi2->format;
 		dsi2->slave->mode_flags = dsi2->mode_flags;
@@ -981,8 +1000,7 @@ static void dw_mipi_dsi2_phy_clk_mode_cfg(struct dw_mipi_dsi2 *dsi2)
 
 static void dw_mipi_dsi2_phy_ratio_cfg(struct dw_mipi_dsi2 *dsi2)
 {
-	struct drm_display_mode *mode = &dsi2->mode;
-	u64 pixel_clk, ipi_clk, phy_hsclk, tmp;
+	u64 ipi_clk, phy_hsclk, tmp;
 
 	/*
 	 * in DPHY mode, the phy_hstx_clk is exactly 1/16 the Lane high-speed
@@ -996,8 +1014,7 @@ static void dw_mipi_dsi2_phy_ratio_cfg(struct dw_mipi_dsi2 *dsi2)
 		phy_hsclk = DIV_ROUND_CLOSEST(dsi2->lane_hs_rate * MSEC_PER_SEC, 16);
 
 	/* IPI_RATIO_MAN_CFG = PHY_HSTX_CLK / IPI_CLK */
-	pixel_clk = mode->crtc_clock * MSEC_PER_SEC;
-	ipi_clk = pixel_clk / 4;
+	ipi_clk = dsi2->mipi_pixel_rate;
 
 	tmp = DIV_ROUND_CLOSEST(phy_hsclk << 16, ipi_clk);
 	dsi_write(dsi2, DSI2_PHY_IPI_RATIO_MAN_CFG, PHY_IPI_RATIO(tmp));
@@ -1033,6 +1050,10 @@ static void dw_mipi_dsi2_phy_init(struct dw_mipi_dsi2 *dsi2)
 {
 	dw_mipi_dsi2_phy_mode_cfg(dsi2);
 	dw_mipi_dsi2_phy_clk_mode_cfg(dsi2);
+
+	if (dsi2->auto_calc_mode)
+		return;
+
 	dw_mipi_dsi2_phy_ratio_cfg(dsi2);
 	dw_mipi_dsi2_lp2hs_or_hs2lp_cfg(dsi2);
 
@@ -1092,7 +1113,7 @@ static void dw_mipi_dsi2_pre_enable(struct dw_mipi_dsi2 *dsi2)
 	dw_mipi_dsi2_host_softrst(dsi2);
 	dsi_write(dsi2, DSI2_PWR_UP, RESET);
 
-	dw_mipi_dsi2_work_mode(dsi2, MANUAL_MODE_EN);
+	dw_mipi_dsi2_work_mode(dsi2, dsi2->auto_calc_mode ? 0 : MANUAL_MODE_EN);
 	dw_mipi_dsi2_phy_init(dsi2);
 	dw_mipi_dsi2_tx_option_set(dsi2);
 	dw_mipi_dsi2_irq_enable(dsi2, 0);
@@ -1106,11 +1127,37 @@ static void dw_mipi_dsi2_pre_enable(struct dw_mipi_dsi2 *dsi2)
 		dw_mipi_dsi2_pre_enable(dsi2->slave);
 }
 
+static void dw_mipi_dsi2_get_mipi_pixel_clk(struct dw_mipi_dsi2 *dsi2,
+					    struct crtc_state *s)
+{
+	struct drm_display_mode *mode = &dsi2->mode;
+	u8 k = dsi2->slave ? 2 : 1;
+
+	/* 1.When MIPI works in uncompressed mode:
+	 * (Video Timing Pixel Rate)/(4)=(MIPI Pixel ClockxK)=(dclk_out×K)=dclk_core
+	 * 2.When MIPI works in compressed mode:
+	 * MIPI Pixel Clock = cds_clk / 2
+	 * MIPI is configured as double channel display mode, K=2, otherwise K=1.
+	 */
+	if (dsi2->dsc_enable) {
+		dsi2->mipi_pixel_rate = s->dsc_cds_clk_rate / 2;
+		if (dsi2->slave)
+			dsi2->slave->mipi_pixel_rate = dsi2->mipi_pixel_rate;
+
+		return;
+	}
+
+	dsi2->mipi_pixel_rate = (mode->crtc_clock * MSEC_PER_SEC) / (4 * k);
+	if (dsi2->slave)
+		dsi2->slave->mipi_pixel_rate = dsi2->mipi_pixel_rate;
+}
+
 static int dw_mipi_dsi2_connector_prepare(struct rockchip_connector *conn,
 					  struct display_state *state)
 {
 	struct dw_mipi_dsi2 *dsi2 = dev_get_priv(conn->dev);
 	struct connector_state *conn_state = &state->conn_state;
+	struct crtc_state *cstate = &state->crtc_state;
 	unsigned long lane_rate;
 
 	memcpy(&dsi2->mode, &conn_state->mode, sizeof(struct drm_display_mode));
@@ -1118,6 +1165,8 @@ static int dw_mipi_dsi2_connector_prepare(struct rockchip_connector *conn,
 		memcpy(&dsi2->slave->mode, &dsi2->mode,
 		       sizeof(struct drm_display_mode));
 
+	dw_mipi_dsi2_get_mipi_pixel_clk(dsi2, cstate);
+
 	lane_rate = dw_mipi_dsi2_get_lane_rate(dsi2);
 	if (dsi2->dcphy.phy)
 		dw_mipi_dsi2_set_hs_clk(dsi2, lane_rate);
@@ -1192,7 +1241,9 @@ static int dw_mipi_dsi2_connector_mode_valid(struct rockchip_connector *conn,
 	if (vm.hactive < min_pixels)
 		vm.hactive = min_pixels;
 
+	memset(&conn_state->mode, 0, sizeof(struct drm_display_mode));
 	drm_display_mode_from_videomode(&vm, &conn_state->mode);
+	conn_state->mode.vrefresh = drm_mode_vrefresh(&conn_state->mode);
 
 	return MODE_OK;
 }
@@ -1240,6 +1291,7 @@ static int dw_mipi_dsi2_probe(struct udevice *dev)
 	dsi2->pdata = pdata;
 	dsi2->id = id;
 	dsi2->data_swap = dev_read_bool(dsi2->dev, "rockchip,data-swap");
+	dsi2->auto_calc_mode = dev_read_bool(dsi2->dev, "auto-calculation-mode");
 
 	rockchip_connector_bind(&dsi2->connector, dev, id, &dw_mipi_dsi2_connector_funcs, NULL,
 				DRM_MODE_CONNECTOR_DSI);
diff --git a/u-boot/drivers/video/drm/inno_mipi_phy.c b/u-boot/drivers/video/drm/inno_mipi_phy.c
index 447aaec5e7..8a3741ec3e 100644
--- a/u-boot/drivers/video/drm/inno_mipi_phy.c
+++ b/u-boot/drivers/video/drm/inno_mipi_phy.c
@@ -93,6 +93,7 @@
 #define T_HS_TRAIL_OFFSET	0x0020
 #define T_HS_EXIT_OFFSET	0x0024
 #define T_CLK_POST_OFFSET	0x0028
+#define T_CLK_POST_OFFSET_H	0x0040
 #define T_WAKUP_H_OFFSET	0x0030
 #define T_WAKUP_L_OFFSET	0x0034
 #define T_CLK_PRE_OFFSET	0x0038
@@ -112,6 +113,8 @@
 #define T_HS_EXIT(x)		UPDATE(x, 4, 0)
 #define T_CLK_POST_MASK		GENMASK(3, 0)
 #define T_CLK_POST(x)		UPDATE(x, 3, 0)
+#define T_CLK_POST_HI_MASK	GENMASK(7, 6)
+#define T_CLK_POST_HI(x)	UPDATE(x, 7, 6)
 #define T_WAKUP_H_MASK		GENMASK(1, 0)
 #define T_WAKUP_H(x)		UPDATE(x, 1, 0)
 #define T_WAKUP_L_MASK		GENMASK(7, 0)
@@ -328,7 +331,9 @@ static void inno_mipi_dphy_timing_update(struct inno_mipi_dphy *inno,
 		m = T_CLK_POST_MASK;
 		v = T_CLK_POST(t->clk_post);
 		inno_update_bits(inno, base + T_CLK_POST_OFFSET, m, v);
-
+		m = T_CLK_POST_HI_MASK;
+		v = T_CLK_POST_HI(t->clk_post >> 4);
+		inno_update_bits(inno, base + T_CLK_POST_OFFSET_H, m, v);
 		m = T_CLK_PRE_MASK;
 		v = T_CLK_PRE(t->clk_pre);
 		inno_update_bits(inno, base + T_CLK_PRE_OFFSET, m, v);
diff --git a/u-boot/drivers/video/drm/libnsbmp.c b/u-boot/drivers/video/drm/libnsbmp.c
new file mode 100644
index 0000000000..bbefb6707b
--- /dev/null
+++ b/u-boot/drivers/video/drm/libnsbmp.c
@@ -0,0 +1,1369 @@
+/*
+ * Copyright 2006 Richard Wilson <richard.wilson@netsurf-browser.org>
+ * Copyright 2008 Sean Fox <dyntryx@gmail.com>
+ *
+ * This file is part of NetSurf's libnsbmp, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * BMP decoding implementation
+ *
+ * This library decode windows bitmaps and icons from their disc images.
+ *
+ * The image format is described in several documents:
+ *  https://msdn.microsoft.com/en-us/library/dd183391(v=vs.85).aspx
+ *  http://www.fileformat.info/format/bmp/egff.htm
+ *  https://en.wikipedia.org/wiki/BMP_file_format
+ *
+ * Despite the format being clearly defined many bitmaps found on the web are
+ *  not compliant and this implementation attempts to cope with as many issues
+ *  as possible rather than simply failing.
+ */
+
+#include "libnsbmp.h"
+
+/* squashes unused variable compiler warnings */
+#define UNUSED(x) ((x)=(x))
+
+/* BMP entry sizes */
+#define BMP_FILE_HEADER_SIZE 14
+#define ICO_FILE_HEADER_SIZE 6
+#define ICO_DIR_ENTRY_SIZE 16
+
+/* the bitmap information header types (encoded as lengths) */
+#define BITMAPCOREHEADER 12
+
+#ifdef WE_NEED_INT8_READING_NOW
+static inline int8_t read_int8(uint8_t *data, unsigned int o) {
+        return (int8_t) data[o];
+}
+#endif
+
+static inline uint8_t read_uint8(uint8_t *data, unsigned int o) {
+        return (uint8_t) data[o];
+}
+
+static inline int16_t read_int16(uint8_t *data, unsigned int o) {
+        return (int16_t) (data[o] | (data[o+1] << 8));
+}
+
+static inline uint16_t read_uint16(uint8_t *data, unsigned int o) {
+        return (uint16_t) (data[o] | (data[o+1] << 8));
+}
+
+static inline int32_t read_int32(uint8_t *data, unsigned int o) {
+        return (int32_t) ((unsigned)data[o] |
+			  ((unsigned)data[o+1] << 8) |
+			  ((unsigned)data[o+2] << 16) |
+			  ((unsigned)data[o+3] << 24));
+}
+
+static inline uint32_t read_uint32(uint8_t *data, unsigned int o) {
+        return (uint32_t) ((unsigned)data[o] |
+                           ((unsigned)data[o+1] << 8) |
+                           ((unsigned)data[o+2] << 16) |
+                           ((unsigned)data[o+3] << 24));
+}
+
+
+/**
+ * Parse the bitmap info header
+ */
+static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data)
+{
+        uint32_t header_size;
+        uint32_t i;
+        uint8_t j;
+        int32_t width, height;
+        uint8_t palette_size;
+        unsigned int flags = 0;
+
+        /* must be at least enough data for a core header */
+        if (bmp->buffer_size < (BMP_FILE_HEADER_SIZE + BITMAPCOREHEADER)) {
+                return BMP_INSUFFICIENT_DATA;
+        }
+
+        header_size = read_uint32(data, 0);
+
+        /* ensure there is enough data for the declared header size*/
+        if ((bmp->buffer_size - BMP_FILE_HEADER_SIZE) < header_size) {
+                return BMP_INSUFFICIENT_DATA;
+        }
+
+        /* a variety of different bitmap headers can follow, depending
+         * on the BMP variant. The header length field determines the type.
+         */
+        if (header_size == BITMAPCOREHEADER) {
+                /* the following header is for os/2 and windows 2.x and consists of:
+                 *
+                 *	+0	UINT32	size of this header (in bytes)
+                 *	+4	INT16	image width (in pixels)
+                 *	+6	INT16	image height (in pixels)
+                 *	+8	UINT16	number of colour planes (always 1)
+                 *	+10	UINT16	number of bits per pixel
+                 */
+                width = read_int16(data, 4);
+                height = read_int16(data, 6);
+                if ((width <= 0) || (height == 0))
+                        return BMP_DATA_ERROR;
+                if (height < 0) {
+                        bmp->reversed = true;
+                        height = -height;
+                }
+                /* ICOs only support 256*256 resolutions
+                 * In the case of the ICO header, the height is actually the added
+                 * height of XOR-Bitmap and AND-Bitmap (double the visible height)
+                 * Technically we could remove this check and ICOs with bitmaps
+                 * of any size could be processed; this is to conform to the spec.
+                 */
+                if (bmp->ico) {
+                        if ((width > 256) || (height > 512)) {
+                                return BMP_DATA_ERROR;
+                        } else {
+                                bmp->width = width;
+                                bmp->height = height / 2;
+                        }
+                } else {
+                        bmp->width = width;
+                        bmp->height = height;
+                }
+                if (read_uint16(data, 8) != 1)
+                        return BMP_DATA_ERROR;
+                bmp->bpp = read_uint16(data, 10);
+                /**
+                 * The bpp value should be in the range 1-32, but the only
+                 * values considered legal are:
+                 * RGB ENCODING: 1, 4, 8, 16, 24 and 32
+                 */
+                if ((bmp->bpp != 1) && (bmp->bpp != 4) &&
+                    (bmp->bpp != 8) &&
+                    (bmp->bpp != 16) &&
+                    (bmp->bpp != 24) &&
+                    (bmp->bpp != 32))
+                        return BMP_DATA_ERROR;
+                if (bmp->bpp < 16)
+                        bmp->colours = (1 << bmp->bpp);
+                palette_size = 3;
+        } else if (header_size < 40) {
+                return BMP_DATA_ERROR;
+        } else {
+                /* the following header is for windows 3.x and onwards. it is a
+                 * minimum of 40 bytes and (as of Windows 95) a maximum of 108 bytes.
+                 *
+                 *	+0	UINT32	size of this header (in bytes)
+                 *	+4	INT32	image width (in pixels)
+                 *	+8	INT32	image height (in pixels)
+                 *	+12	UINT16	number of colour planes (always 1)
+                 *	+14	UINT16	number of bits per pixel
+                 *	+16	UINT32	compression methods used
+                 *	+20	UINT32	size of bitmap (in bytes)
+                 *	+24	UINT32	horizontal resolution (in pixels per meter)
+                 *	+28	UINT32	vertical resolution (in pixels per meter)
+                 *	+32	UINT32	number of colours in the image
+                 *	+36	UINT32	number of important colours
+                 *	+40	UINT32	mask identifying bits of red component
+                 *	+44	UINT32	mask identifying bits of green component
+                 *	+48	UINT32	mask identifying bits of blue component
+                 *	+52	UINT32	mask identifying bits of alpha component
+                 *	+56	UINT32	color space type
+                 *	+60	UINT32	x coordinate of red endpoint
+                 *	+64	UINT32	y coordinate of red endpoint
+                 *	+68	UINT32	z coordinate of red endpoint
+                 *	+72	UINT32	x coordinate of green endpoint
+                 *	+76	UINT32	y coordinate of green endpoint
+                 *	+80	UINT32	z coordinate of green endpoint
+                 *	+84	UINT32	x coordinate of blue endpoint
+                 *	+88	UINT32	y coordinate of blue endpoint
+                 *	+92	UINT32	z coordinate of blue endpoint
+                 *	+96	UINT32	gamma red coordinate scale value
+                 *	+100	UINT32	gamma green coordinate scale value
+                 *	+104	UINT32	gamma blue coordinate scale value
+                 */
+                width = read_int32(data, 4);
+                height = read_int32(data, 8);
+                if ((width <= 0) || (height == 0))
+                        return BMP_DATA_ERROR;
+                if (height < 0) {
+                        bmp->reversed = true;
+                        if (height <= -INT32_MAX) {
+                                height = INT32_MAX;
+                        } else {
+                                height = -height;
+                        }
+                }
+                /* ICOs only support 256*256 resolutions
+                 * In the case of the ICO header, the height is actually the added
+                 * height of XOR-Bitmap and AND-Bitmap (double the visible height)
+                 * Technically we could remove this check and ICOs with bitmaps
+                 * of any size could be processed; this is to conform to the spec.
+                 */
+                if (bmp->ico) {
+                        if ((width > 256) || (height > 512)) {
+                                return BMP_DATA_ERROR;
+                        } else {
+                                bmp->width = width;
+                                bmp->height = height / 2;
+                        }
+                } else {
+                        bmp->width = width;
+                        bmp->height = height;
+                }
+                if (read_uint16(data, 12) != 1)
+                        return BMP_DATA_ERROR;
+                bmp->bpp = read_uint16(data, 14);
+                if (bmp->bpp == 0)
+                        bmp->bpp = 8;
+                bmp->encoding = read_uint32(data, 16);
+                /**
+                 * The bpp value should be in the range 1-32, but the only
+                 * values considered legal are:
+                 * RGB ENCODING: 1, 4, 8, 16, 24 and 32
+                 * RLE4 ENCODING: 4
+                 * RLE8 ENCODING: 8
+                 * BITFIELD ENCODING: 16 and 32
+                 */
+                switch (bmp->encoding) {
+                case BMP_ENCODING_RGB:
+                        if ((bmp->bpp != 1) && (bmp->bpp != 4) &&
+                            (bmp->bpp != 8) &&
+                            (bmp->bpp != 16) &&
+                            (bmp->bpp != 24) &&
+                            (bmp->bpp != 32))
+                                return BMP_DATA_ERROR;
+                        break;
+                case BMP_ENCODING_RLE8:
+                        if (bmp->bpp != 8)
+                                return BMP_DATA_ERROR;
+                        break;
+                case BMP_ENCODING_RLE4:
+                        if (bmp->bpp != 4)
+                                return BMP_DATA_ERROR;
+                        break;
+                case BMP_ENCODING_BITFIELDS:
+                        if ((bmp->bpp != 16) && (bmp->bpp != 32))
+                                return BMP_DATA_ERROR;
+                        break;
+                        /* invalid encoding */
+                default:
+                        return BMP_DATA_ERROR;
+                        break;
+                }
+                /* Bitfield encoding means we have red, green, blue, and alpha masks.
+                 * Here we acquire the masks and determine the required bit shift to
+                 * align them in our 24-bit color 8-bit alpha format.
+                 */
+                if (bmp->encoding == BMP_ENCODING_BITFIELDS) {
+                        if (header_size == 40) {
+                                header_size += 12;
+                                if (bmp->buffer_size < (14 + header_size))
+                                        return BMP_INSUFFICIENT_DATA;
+                                for (i = 0; i < 3; i++)
+                                        bmp->mask[i] = read_uint32(data, 40 + (i << 2));
+                        } else {
+                                if (header_size < 56)
+                                        return BMP_INSUFFICIENT_DATA;
+                                for (i = 0; i < 4; i++)
+                                        bmp->mask[i] = read_uint32(data, 40 + (i << 2));
+                        }
+                        for (i = 0; i < 4; i++) {
+                                if (bmp->mask[i] == 0)
+                                        break;
+                                for (j = 31; j > 0; j--)
+                                        if (bmp->mask[i] & ((unsigned)1 << j)) {
+                                                if ((j - 7) > 0)
+                                                        bmp->mask[i] &= (unsigned)0xff << (j - 7);
+                                                else
+                                                        bmp->mask[i] &= 0xff >> (-(j - 7));
+                                                bmp->shift[i] = (i << 3) - (j - 7);
+                                                break;
+                                        }
+                        }
+                }
+                bmp->colours = read_uint32(data, 32);
+                if (bmp->colours == 0 && bmp->bpp < 16)
+                        bmp->colours = (1 << bmp->bpp);
+                palette_size = 4;
+        }
+        data += header_size;
+
+        /* if there's no alpha mask, flag the bmp opaque */
+        if ((!bmp->ico) && (bmp->mask[3] == 0)) {
+                flags |= BMP_OPAQUE;
+                bmp->opaque = true;
+        }
+
+        /* we only have a palette for <16bpp */
+        if (bmp->bpp < 16) {
+                /* we now have a series of palette entries of the format:
+                 *
+                 *	+0	BYTE	blue
+                 *	+1	BYTE	green
+                 *	+2	BYTE	red
+                 *
+                 * if the palette is from an OS/2 or Win2.x file then the entries
+                 * are padded with an extra byte.
+                 */
+
+                /* boundary checking */
+                if (bmp->buffer_size < (14 + header_size + ((uint64_t)4 * bmp->colours)))
+                        return BMP_INSUFFICIENT_DATA;
+
+                /* create the colour table */
+                bmp->colour_table = (uint32_t *)malloc(bmp->colours * 4);
+                if (!bmp->colour_table)
+                        return BMP_INSUFFICIENT_MEMORY;
+                for (i = 0; i < bmp->colours; i++) {
+                        uint32_t colour = data[2] | (data[1] << 8) | (data[0] << 16);
+                        if (bmp->opaque)
+                                colour |= ((uint32_t)0xff << 24);
+                        data += palette_size;
+                        bmp->colour_table[i] = read_uint32((uint8_t *)&colour,0);
+                }
+
+                /* some bitmaps have a bad offset if there is a pallete, work
+                 * round this by fixing up the data offset to after the palette
+                 * but only if there is data following the palette as some
+                 * bitmaps encode data in the palette!
+                 */
+                if ((bmp->bitmap_offset < (uint32_t)(data - bmp->bmp_data)) &&
+                    ((bmp->buffer_size - (data - bmp->bmp_data)) > 0)) {
+                        bmp->bitmap_offset = data - bmp->bmp_data;
+                }
+        }
+
+        /* create our bitmap */
+        flags |= BMP_NEW | BMP_CLEAR_MEMORY;
+        bmp->bitmap = bmp->bitmap_callbacks.bitmap_create(bmp->width, bmp->height, flags);
+        if (!bmp->bitmap) {
+                if (bmp->colour_table)
+                        free(bmp->colour_table);
+                bmp->colour_table = NULL;
+                return BMP_INSUFFICIENT_MEMORY;
+        }
+        /* BMPs within ICOs don't have BMP file headers, so the image data should
+         * always be right after the colour table.
+         */
+        if (bmp->ico)
+                bmp->bitmap_offset = (uintptr_t)data - (uintptr_t)bmp->bmp_data;
+        return BMP_OK;
+}
+
+
+/**
+ * Parse the bitmap file header
+ *
+ * \param bmp The bitmap.
+ * \param data The data for the file header
+ * \return BMP_OK on success or error code on faliure
+ */
+static bmp_result bmp_file_header_parse(bmp_image *bmp, uint8_t *data)
+{
+        /* standard 14-byte BMP file header is:
+         *
+         *   +0    UINT16   File Type ('BM')
+         *   +2    UINT32   Size of File (in bytes)
+         *   +6    INT16    Reserved Field (1)
+         *   +8    INT16    Reserved Field (2)
+         *   +10   UINT32   Starting Position of Image Data (offset in bytes)
+         */
+        if (bmp->buffer_size < BMP_FILE_HEADER_SIZE)
+                return BMP_INSUFFICIENT_DATA;
+
+        if ((data[0] != (uint8_t)'B') || (data[1] != (uint8_t)'M'))
+                return BMP_DATA_ERROR;
+
+        bmp->bitmap_offset = read_uint32(data, 10);
+
+        /* check the offset to data lies within the file */
+        if (bmp->bitmap_offset >= bmp->buffer_size) {
+                return BMP_INSUFFICIENT_DATA;
+        }
+
+        return BMP_OK;
+}
+
+
+/**
+ * Allocates memory for the next BMP in an ICO collection
+ *
+ * Sets proper structure values
+ *
+ * \param ico the ICO collection to add the image to
+ * \param image a pointer to the ICO image to be initialised
+ */
+static bmp_result next_ico_image(ico_collection *ico, ico_image *image) {
+        bmp_create(&image->bmp, &ico->bitmap_callbacks);
+        image->next = ico->first;
+        ico->first = image;
+        return BMP_OK;
+}
+
+
+/**
+ * Parse the icon file header
+ *
+ * \param ico The icon collection.
+ * \param data The header data to parse.
+ * \return BMP_OK on successful parse else error code
+ */
+static bmp_result ico_header_parse(ico_collection *ico, uint8_t *data)
+{
+        uint16_t count, i;
+        bmp_result result;
+        int area, max_area = 0;
+
+        /* 6-byte ICO file header is:
+         *
+         *	+0	INT16	Reserved (should be 0)
+         *	+2	UINT16	Type (1 for ICO, 2 for CUR)
+         *	+4	UINT16	Number of BMPs to follow
+         */
+        if (ico->buffer_size < ICO_FILE_HEADER_SIZE)
+                return BMP_INSUFFICIENT_DATA;
+        //      if (read_int16(data, 2) != 0x0000)
+        //              return BMP_DATA_ERROR;
+        if (read_uint16(data, 2) != 0x0001)
+                return BMP_DATA_ERROR;
+        count = read_uint16(data, 4);
+        if (count == 0)
+                return BMP_DATA_ERROR;
+        data += ICO_FILE_HEADER_SIZE;
+
+        /* check if we have enough data for the directory */
+        if (ico->buffer_size < (uint32_t)(ICO_FILE_HEADER_SIZE + (ICO_DIR_ENTRY_SIZE * count)))
+                return BMP_INSUFFICIENT_DATA;
+
+        /* Decode the BMP files.
+         *
+         * 16-byte ICO directory entry is:
+         *
+         *	+0	UINT8	Width (0 for 256 pixels)
+         *	+1	UINT8	Height (0 for 256 pixels)
+         *	+2	UINT8	Colour count (0 if more than 256 colours)
+         *	+3	INT8	Reserved (should be 0, but may not be)
+         *	+4	UINT16	Colour Planes (should be 0 or 1)
+         *	+6	UINT16	Bits Per Pixel
+         *	+8	UINT32	Size of BMP info header + bitmap data in bytes
+         *	+12	UINT32	Offset (points to the BMP info header, not the bitmap data)
+         */
+        for (i = 0; i < count; i++) {
+                ico_image *image;
+                image = calloc(1, sizeof(ico_image));
+                if (!image)
+                        return BMP_INSUFFICIENT_MEMORY;
+                result = next_ico_image(ico, image);
+                if (result != BMP_OK)
+                        return result;
+                image->bmp.width = read_uint8(data, 0);
+                if (image->bmp.width == 0)
+                        image->bmp.width = 256;
+                image->bmp.height = read_uint8(data, 1);
+                if (image->bmp.height == 0)
+                        image->bmp.height = 256;
+                image->bmp.buffer_size = read_uint32(data, 8);
+                image->bmp.bmp_data = ico->ico_data + read_uint32(data, 12);
+                if (image->bmp.bmp_data + image->bmp.buffer_size >
+                    ico->ico_data + ico->buffer_size)
+                        return BMP_INSUFFICIENT_DATA;
+                image->bmp.ico = true;
+                data += ICO_DIR_ENTRY_SIZE;
+
+                /* Ensure that the bitmap data resides in the buffer */
+                if (image->bmp.bmp_data - ico->ico_data >= 0 &&
+                    (uint32_t)(image->bmp.bmp_data -
+                               ico->ico_data) >= ico->buffer_size)
+                        return BMP_DATA_ERROR;
+
+                /* Ensure that we have sufficient data to read the bitmap */
+                if (image->bmp.buffer_size - ICO_DIR_ENTRY_SIZE >=
+                    ico->buffer_size - (ico->ico_data - data))
+                        return BMP_INSUFFICIENT_DATA;
+
+                result = bmp_info_header_parse(&image->bmp,
+                                               image->bmp.bmp_data);
+                if (result != BMP_OK)
+                        return result;
+
+                /* adjust the size based on the images available */
+                area = image->bmp.width * image->bmp.height;
+                if (area > max_area) {
+                        ico->width = image->bmp.width;
+                        ico->height = image->bmp.height;
+                        max_area = area;
+                }
+        }
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored in 32bpp colour.
+ *
+ * \param bmp	the BMP image to decode
+ * \param start	the data to decode, updated to last byte read on success
+ * \param bytes	the number of bytes of data available
+ * \return	BMP_OK on success
+ *		BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *			in this case, the image may be partially viewable
+ */
+static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes)
+{
+        uint8_t *top, *bottom, *end, *data;
+        uint32_t *scanline;
+        uint32_t x, y;
+        uint32_t swidth;
+        uint8_t i;
+        uint32_t word;
+
+        data = *start;
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        bmp->decoded = true;
+
+        /* Determine transparent index */
+        if (bmp->limited_trans) {
+                if ((data + 4) > end)
+                        return BMP_INSUFFICIENT_DATA;
+                if (bmp->encoding == BMP_ENCODING_BITFIELDS)
+                        bmp->transparent_index = read_uint32(data, 0);
+                else
+                        bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16);
+        }
+
+        for (y = 0; y < bmp->height; y++) {
+                if ((data + (4 * bmp->width)) > end)
+                        return BMP_INSUFFICIENT_DATA;
+                if (bmp->reversed)
+                        scanline = (void *)(top + (y * swidth));
+                else
+                        scanline = (void *)(bottom - (y * swidth));
+                if (bmp->encoding == BMP_ENCODING_BITFIELDS) {
+                        for (x = 0; x < bmp->width; x++) {
+                                word = read_uint32(data, 0);
+                                for (i = 0; i < 4; i++)
+                                        if (bmp->shift[i] > 0)
+                                                scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]);
+                                        else
+                                                scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i]));
+                                /* 32-bit BMPs have alpha masks, but sometimes they're not utilized */
+                                if (bmp->opaque)
+                                        scanline[x] |= ((unsigned)0xff << 24);
+                                data += 4;
+                                scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+                        }
+                } else {
+                        for (x = 0; x < bmp->width; x++) {
+                                scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16);
+                                if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) {
+                                        scanline[x] = bmp->trans_colour;
+                                }
+                                if (bmp->opaque) {
+                                        scanline[x] |= ((unsigned)0xff << 24);
+                                } else {
+                                        scanline[x] |= (unsigned)data[3] << 24;
+                                }
+                                data += 4;
+                                scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+                        }
+                }
+        }
+        *start = data;
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored in 24bpp colour.
+ *
+ * \param bmp	the BMP image to decode
+ * \param start	the data to decode, updated to last byte read on success
+ * \param bytes	the number of bytes of data available
+ * \return	BMP_OK on success
+ *		BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *			in this case, the image may be partially viewable
+ */
+static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes)
+{
+        uint8_t *top, *bottom, *end, *data;
+        uint32_t *scanline;
+        uint32_t x, y;
+        uint32_t swidth;
+        uintptr_t addr;
+
+        data = *start;
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top) {
+                return BMP_INSUFFICIENT_MEMORY;
+        }
+
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        addr = ((uintptr_t)data) & 3;
+        bmp->decoded = true;
+
+        /* Determine transparent index */
+        if (bmp->limited_trans) {
+                if ((data + 3) > end) {
+                        return BMP_INSUFFICIENT_DATA;
+                }
+
+                bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16);
+        }
+
+        for (y = 0; y < bmp->height; y++) {
+                if ((data + (3 * bmp->width)) > end) {
+                        return BMP_INSUFFICIENT_DATA;
+                }
+
+                if (bmp->reversed) {
+                        scanline = (void *)(top + (y * swidth));
+                } else {
+                        scanline = (void *)(bottom - (y * swidth));
+                }
+
+                for (x = 0; x < bmp->width; x++) {
+                        scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16);
+                        if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) {
+                                scanline[x] = bmp->trans_colour;
+                        } else {
+                                scanline[x] |= ((uint32_t)0xff << 24);
+                        }
+                        data += 3;
+                        scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+                }
+
+                while (addr != (((uintptr_t)data) & 3)) {
+                        data++;
+                }
+        }
+        *start = data;
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored in 16bpp colour.
+ *
+ * \param bmp	the BMP image to decode
+ * \param start	the data to decode, updated to last byte read on success
+ * \param bytes	the number of bytes of data available
+ * \return	BMP_OK on success
+ *		BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *			in this case, the image may be partially viewable
+ */
+static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes)
+{
+        uint8_t *top, *bottom, *end, *data;
+        uint32_t *scanline;
+        uint32_t x, y, swidth;
+        uintptr_t addr;
+        uint8_t i;
+        uint16_t word;
+
+        data = *start;
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        addr = ((uintptr_t)data) & 3;
+        bmp->decoded = true;
+
+        /* Determine transparent index */
+        if (bmp->limited_trans) {
+                if ((data + 2) > end)
+                        return BMP_INSUFFICIENT_DATA;
+                bmp->transparent_index = read_uint16(data, 0);
+        }
+
+        for (y = 0; y < bmp->height; y++) {
+                if ((data + (2 * bmp->width)) > end)
+                        return BMP_INSUFFICIENT_DATA;
+                if (bmp->reversed)
+                        scanline = (void *)(top + (y * swidth));
+                else
+                        scanline = (void *)(bottom - (y * swidth));
+                if (bmp->encoding == BMP_ENCODING_BITFIELDS) {
+                        for (x = 0; x < bmp->width; x++) {
+                                word = read_uint16(data, 0);
+                                if ((bmp->limited_trans) && (word == bmp->transparent_index))
+                                        scanline[x] = bmp->trans_colour;
+                                else {
+                                        scanline[x] = 0;
+                                        for (i = 0; i < 4; i++)
+                                                if (bmp->shift[i] > 0)
+                                                        scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]);
+                                                else
+                                                        scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i]));
+                                        if (bmp->opaque)
+                                                scanline[x] |= ((unsigned)0xff << 24);
+                                }
+                                data += 2;
+                                scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+                        }
+                } else {
+                        for (x = 0; x < bmp->width; x++) {
+                                word = read_uint16(data, 0);
+                                if ((bmp->limited_trans) && (word == bmp->transparent_index))
+                                        scanline[x] = bmp->trans_colour;
+                                else {
+                                        /* 16-bit RGB defaults to RGB555 */
+                                        scanline[x] = ((word & (31 << 0)) << 19) |
+                                                      ((word & (31 << 5)) << 6) |
+                                                      ((word & (31 << 10)) >> 7);
+                                }
+                                if (bmp->opaque)
+                                        scanline[x] |= ((unsigned)0xff << 24);
+                                data += 2;
+                                scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
+                        }
+                }
+                while (addr != (((uintptr_t)data) & 3))
+                        data += 2;
+        }
+        *start = data;
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored with a palette and in 8bpp colour or less.
+ *
+ * \param bmp	the BMP image to decode
+ * \param start	the data to decode, updated to last byte read on success
+ * \param bytes	the number of bytes of data available
+ * \return	BMP_OK on success
+ *		BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *			in this case, the image may be partially viewable
+ */
+static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes)
+{
+        uint8_t *top, *bottom, *end, *data;
+        uint32_t *scanline;
+        uintptr_t addr;
+        uint32_t x, y, swidth;
+        uint8_t bit_shifts[8];
+        uint8_t ppb = 8 / bmp->bpp;
+        uint8_t bit_mask = (1 << bmp->bpp) - 1;
+        uint8_t cur_byte = 0, bit, i;
+
+        for (i = 0; i < ppb; i++)
+                bit_shifts[i] = 8 - ((i + 1) * bmp->bpp);
+
+        data = *start;
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        addr = ((uintptr_t)data) & 3;
+        bmp->decoded = true;
+
+        /* Determine transparent index */
+        if (bmp->limited_trans) {
+                uint32_t idx = (*data >> bit_shifts[0]) & bit_mask;
+                if (idx >= bmp->colours)
+                        return BMP_DATA_ERROR;
+                bmp->transparent_index = bmp->colour_table[idx];
+        }
+
+        for (y = 0; y < bmp->height; y++) {
+                bit = 8;
+                if ((data + ((bmp->width + ppb - 1) / ppb)) > end)
+                        return BMP_INSUFFICIENT_DATA;
+                if (bmp->reversed)
+                        scanline = (void *)(top + (y * swidth));
+                else
+                        scanline = (void *)(bottom - (y * swidth));
+                for (x = 0; x < bmp->width; x++) {
+                        uint32_t idx;
+                        if (bit >= ppb) {
+                                bit = 0;
+                                cur_byte = *data++;
+                        }
+                        idx = (cur_byte >> bit_shifts[bit++]) & bit_mask;
+                        if (idx < bmp->colours) {
+                                /* ensure colour table index is in bounds */
+                                scanline[x] = bmp->colour_table[idx];
+                                if ((bmp->limited_trans) &&
+                                    (scanline[x] == bmp->transparent_index)) {
+                                        scanline[x] = bmp->trans_colour;
+                                }
+                        }
+                }
+                while (addr != (((uintptr_t)data) & 3))
+                        data++;
+        }
+        *start = data;
+        return BMP_OK;
+}
+
+
+/**
+ * Decode a 1bpp mask for an ICO
+ *
+ * \param bmp	the BMP image to decode
+ * \param data	the data to decode
+ * \param bytes	the number of bytes of data available
+ * \return BMP_OK on success
+ */
+static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes)
+{
+        uint8_t *top, *bottom, *end;
+        uint32_t *scanline;
+        uintptr_t addr;
+        uint32_t x, y, swidth;
+        uint32_t cur_byte = 0;
+
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+
+        addr = ((uintptr_t)data) & 3;
+
+        for (y = 0; y < bmp->height; y++) {
+                if ((data + (bmp->width >> 3)) > end)
+                        return BMP_INSUFFICIENT_DATA;
+                scanline = (void *)(bottom - (y * swidth));
+                for (x = 0; x < bmp->width; x++) {
+                        if ((x & 7) == 0)
+                                cur_byte = *data++;
+                        scanline[x] = read_uint32((uint8_t *)&scanline[x], 0);
+                        if ((cur_byte & 128) == 0) {
+                                scanline[x] |= ((unsigned)0xff << 24);
+                        } else {
+                                scanline[x] &= 0xffffff;
+                        }
+                        scanline[x] = read_uint32((uint8_t *)&scanline[x], 0);
+                        cur_byte = cur_byte << 1;
+                }
+                while (addr != (((uintptr_t)data) & 3))
+                        data++;
+        }
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored encoded in RLE8.
+ *
+ * \param bmp	the BMP image to decode
+ * \param data	the data to decode
+ * \param bytes	the number of bytes of data available
+ * \return	BMP_OK on success
+ *		BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *			in this case, the image may be partially viewable
+ */
+static bmp_result
+bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes)
+{
+        uint8_t *top, *bottom, *end;
+        uint32_t *scanline;
+        uint32_t swidth;
+        uint32_t i, length, pixels_left;
+        uint32_t x = 0, y = 0, last_y = 0;
+        uint32_t pixel = 0;
+
+        if (bmp->ico)
+                return BMP_DATA_ERROR;
+
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        bmp->decoded = true;
+
+        do {
+                if (data + 2 > end)
+                        return BMP_INSUFFICIENT_DATA;
+                length = *data++;
+                if (length == 0) {
+                        length = *data++;
+                        switch (length) {
+                        case 0:
+                                /* 00 - 00 means end of scanline */
+                                x = 0;
+                                if (last_y == y) {
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                }
+                                last_y = y;
+                                break;
+
+                        case 1:
+                                /* 00 - 01 means end of RLE data */
+                                return BMP_OK;
+
+                        case 2:
+                                /* 00 - 02 - XX - YY means move cursor */
+                                if (data + 2 > end)
+                                        return BMP_INSUFFICIENT_DATA;
+                                x += *data++;
+                                if (x >= bmp->width)
+                                        return BMP_DATA_ERROR;
+                                y += *data++;
+                                if (y >= bmp->height)
+                                        return BMP_DATA_ERROR;
+                                break;
+
+                        default:
+                                /* 00 - NN means escape NN pixels */
+                                if (bmp->reversed) {
+                                        pixels_left = (bmp->height - y) * bmp->width - x;
+                                        scanline = (void *)(top + (y * swidth));
+                                } else {
+                                        pixels_left = (y + 1) * bmp->width - x;
+                                        scanline = (void *)(bottom - (y * swidth));
+                                }
+                                if (length > pixels_left)
+                                        length = pixels_left;
+                                if (data + length > end)
+                                        return BMP_INSUFFICIENT_DATA;
+
+                                /* the following code could be easily optimised
+                                 * by simply checking the bounds on entry and
+                                 * using some simple copying routines if so
+                                 */
+                                for (i = 0; i < length; i++) {
+                                        uint32_t idx = (uint32_t) *data++;
+                                        if (x >= bmp->width) {
+                                                x = 0;
+                                                y++;
+                                                if (y >= bmp->height)
+                                                        return BMP_DATA_ERROR;
+                                                if (bmp->reversed) {
+                                                        scanline += bmp->width;
+                                                } else {
+                                                        scanline -= bmp->width;
+                                                }
+                                        }
+                                        if (idx >= bmp->colours)
+                                                return BMP_DATA_ERROR;
+                                        scanline[x++] = bmp->colour_table[idx];
+                                }
+
+                                if ((length & 1) && (*data++ != 0x00))
+                                        return BMP_DATA_ERROR;
+
+                                break;
+                        }
+                } else {
+                        uint32_t idx;
+
+                        /* NN means perform RLE for NN pixels */
+                        if (bmp->reversed) {
+                                pixels_left = (bmp->height - y) * bmp->width - x;
+                                scanline = (void *)(top + (y * swidth));
+                        } else {
+                                pixels_left = (y + 1) * bmp->width - x;
+                                scanline = (void *)(bottom - (y * swidth));
+                        }
+                        if (length > pixels_left)
+                                length = pixels_left;
+
+                        /* boundary checking */
+                        if (data + 1 > end)
+                                return BMP_INSUFFICIENT_DATA;
+
+                        /* the following code could be easily optimised by
+                         * simply checking the bounds on entry and using some
+                         * simply copying routines if so
+                         */
+                        idx = (uint32_t) *data++;
+                        if (idx >= bmp->colours)
+                                return BMP_DATA_ERROR;
+
+                        pixel = bmp->colour_table[idx];
+                        for (i = 0; i < length; i++) {
+                                if (x >= bmp->width) {
+                                        x = 0;
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                        if (bmp->reversed) {
+                                                scanline += bmp->width;
+                                        } else {
+                                                scanline -= bmp->width;
+                                        }
+                                }
+                                scanline[x++] = pixel;
+                        }
+                }
+        } while (data < end);
+
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored encoded in RLE4.
+ *
+ * \param bmp	the BMP image to decode
+ * \param data	the data to decode
+ * \param bytes	the number of bytes of data available
+ * \return	BMP_OK on success
+ *		BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *			in this case, the image may be partially viewable
+ */
+static bmp_result
+bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes)
+{
+        uint8_t *top, *bottom, *end;
+        uint32_t *scanline;
+        uint32_t swidth;
+        uint32_t i, length, pixels_left;
+        uint32_t x = 0, y = 0, last_y = 0;
+        uint32_t pixel = 0, pixel2;
+
+        if (bmp->ico)
+                return BMP_DATA_ERROR;
+
+        swidth = sizeof(uint32_t) * bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        bmp->decoded = true;
+
+        do {
+                if (data + 2 > end)
+                        return BMP_INSUFFICIENT_DATA;
+                length = *data++;
+                if (length == 0) {
+                        length = *data++;
+                        switch (length) {
+                        case 0:
+                                /* 00 - 00 means end of scanline */
+                                x = 0;
+                                if (last_y == y) {
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                }
+                                last_y = y;
+                                break;
+
+                        case 1:
+                                /* 00 - 01 means end of RLE data */
+                                return BMP_OK;
+
+                        case 2:
+                                /* 00 - 02 - XX - YY means move cursor */
+                                if (data + 2 > end)
+                                        return BMP_INSUFFICIENT_DATA;
+                                x += *data++;
+                                if (x >= bmp->width)
+                                        return BMP_DATA_ERROR;
+                                y += *data++;
+                                if (y >= bmp->height)
+                                        return BMP_DATA_ERROR;
+                                break;
+
+                        default:
+                                /* 00 - NN means escape NN pixels */
+                                if (bmp->reversed) {
+                                        pixels_left = (bmp->height - y) * bmp->width - x;
+                                        scanline = (void *)(top + (y * swidth));
+                                } else {
+                                        pixels_left = (y + 1) * bmp->width - x;
+                                        scanline = (void *)(bottom - (y * swidth));
+                                }
+                                if (length > pixels_left)
+                                        length = pixels_left;
+                                if (data + ((length + 1) / 2) > end)
+                                        return BMP_INSUFFICIENT_DATA;
+
+                                /* the following code could be easily optimised
+                                 * by simply checking the bounds on entry and
+                                 * using some simple copying routines
+                                 */
+
+                                for (i = 0; i < length; i++) {
+                                        if (x >= bmp->width) {
+                                                x = 0;
+                                                y++;
+                                                if (y >= bmp->height)
+                                                        return BMP_DATA_ERROR;
+                                                if (bmp->reversed) {
+                                                        scanline += bmp->width;
+                                                } else {
+                                                        scanline -= bmp->width;
+                                                }
+
+                                        }
+                                        if ((i & 1) == 0) {
+                                                pixel = *data++;
+                                                if ((pixel >> 4) >= bmp->colours)
+                                                        return BMP_DATA_ERROR;
+                                                scanline[x++] = bmp->colour_table
+                                                                [pixel >> 4];
+                                        } else {
+                                                if ((pixel & 0xf) >= bmp->colours)
+                                                        return BMP_DATA_ERROR;
+                                                scanline[x++] = bmp->colour_table
+                                                                [pixel & 0xf];
+                                        }
+                                }
+                                length = (length + 1) >> 1;
+
+                                if ((length & 1) && (*data++ != 0x00))
+                                        return BMP_DATA_ERROR;
+
+                                break;
+                        }
+                } else {
+                        /* NN means perform RLE for NN pixels */
+                        if (bmp->reversed) {
+                                pixels_left = (bmp->height - y) * bmp->width - x;
+                                scanline = (void *)(top + (y * swidth));
+                        } else {
+                                pixels_left = (y + 1) * bmp->width - x;
+                                scanline = (void *)(bottom - (y * swidth));
+                        }
+                        if (length > pixels_left)
+                                length = pixels_left;
+
+                        /* boundary checking */
+                        if (data + 1 > end)
+                                return BMP_INSUFFICIENT_DATA;
+
+                        /* the following code could be easily optimised by
+                         * simply checking the bounds on entry and using some
+                         * simple copying routines
+                         */
+
+                        pixel2 = *data++;
+                        if ((pixel2 >> 4) >= bmp->colours ||
+                            (pixel2 & 0xf) >= bmp->colours)
+                                return BMP_DATA_ERROR;
+                        pixel = bmp->colour_table[pixel2 >> 4];
+                        pixel2 = bmp->colour_table[pixel2 & 0xf];
+                        for (i = 0; i < length; i++) {
+                                if (x >= bmp->width) {
+                                        x = 0;
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                        if (bmp->reversed) {
+                                                scanline += bmp->width;
+                                        } else {
+                                                scanline -= bmp->width;
+                                        }
+                                }
+                                if ((i & 1) == 0)
+                                        scanline[x++] = pixel;
+                                else
+                                        scanline[x++] = pixel2;
+                        }
+
+                }
+        } while (data < end);
+
+        return BMP_OK;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_result
+bmp_create(bmp_image *bmp,
+           bmp_bitmap_callback_vt *bitmap_callbacks)
+{
+        memset(bmp, 0, sizeof(bmp_image));
+        bmp->bitmap_callbacks = *bitmap_callbacks;
+
+        return BMP_OK;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_result
+ico_collection_create(ico_collection *ico,
+                      bmp_bitmap_callback_vt *bitmap_callbacks)
+{
+
+        memset(ico, 0, sizeof(ico_collection));
+        ico->bitmap_callbacks = *bitmap_callbacks;
+
+        return BMP_OK;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_result bmp_analyse(bmp_image *bmp, size_t size, uint8_t *data)
+{
+        bmp_result res;
+
+        /* ensure we aren't already initialised */
+        if (bmp->bitmap) {
+                return BMP_OK;
+        }
+
+        /* initialize source data values */
+        bmp->buffer_size = size;
+        bmp->bmp_data = data;
+
+        res = bmp_file_header_parse(bmp, data);
+        if (res == BMP_OK) {
+                res = bmp_info_header_parse(bmp, data + BMP_FILE_HEADER_SIZE);
+        }
+        return res;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_result ico_analyse(ico_collection *ico, size_t size, uint8_t *data)
+{
+        /* ensure we aren't already initialised */
+        if (ico->first)
+                return BMP_OK;
+
+        /* initialize values */
+        ico->buffer_size = size;
+        ico->ico_data = data;
+
+        return ico_header_parse(ico, data);
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_result bmp_decode(bmp_image *bmp)
+{
+        uint8_t *data;
+        uint32_t bytes;
+        bmp_result result = BMP_OK;
+
+        data = bmp->bmp_data + bmp->bitmap_offset;
+        bytes = bmp->buffer_size - bmp->bitmap_offset;
+
+        switch (bmp->encoding) {
+        case BMP_ENCODING_RGB:
+                switch (bmp->bpp) {
+                case 32:
+                        result = bmp_decode_rgb32(bmp, &data, bytes);
+                        break;
+
+                case 24:
+                        result = bmp_decode_rgb24(bmp, &data, bytes);
+                        break;
+
+                case 16:
+                        result = bmp_decode_rgb16(bmp, &data, bytes);
+                        break;
+
+                default:
+                        result = bmp_decode_rgb(bmp, &data, bytes);
+                        break;
+                }
+                break;
+
+        case BMP_ENCODING_RLE8:
+                result = bmp_decode_rle8(bmp, data, bytes);
+                break;
+
+        case BMP_ENCODING_RLE4:
+                result = bmp_decode_rle4(bmp, data, bytes);
+                break;
+
+        case BMP_ENCODING_BITFIELDS:
+                switch (bmp->bpp) {
+                case 32:
+                        result = bmp_decode_rgb32(bmp, &data, bytes);
+                        break;
+
+                case 16:
+                        result = bmp_decode_rgb16(bmp, &data, bytes);
+                        break;
+
+                default:
+                        result = BMP_DATA_ERROR;
+                        break;
+                }
+                break;
+        }
+
+        /* icons with less than 32bpp have a 1bpp alpha mask */
+        if ((result == BMP_OK) && (bmp->ico) && (bmp->bpp != 32)) {
+                bytes = (uintptr_t)bmp->bmp_data + bmp->buffer_size - (uintptr_t)data;
+                result = bmp_decode_mask(bmp, data, bytes);
+        }
+        return result;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_result bmp_decode_trans(bmp_image *bmp, uint32_t colour)
+{
+        bmp->limited_trans = true;
+        bmp->trans_colour = colour;
+        return bmp_decode(bmp);
+}
+
+
+/* exported interface documented in libnsbmp.h */
+bmp_image *ico_find(ico_collection *ico, uint16_t width, uint16_t height)
+{
+        bmp_image *bmp = NULL;
+        ico_image *image;
+        int x, y, cur, distance = (1 << 24);
+
+        if (width == 0)
+                width = ico->width;
+        if (height == 0)
+                height = ico->height;
+        for (image = ico->first; image; image = image->next) {
+                if ((image->bmp.width == width) && (image->bmp.height == height))
+                        return &image->bmp;
+                x = image->bmp.width - width;
+                y = image->bmp.height - height;
+                cur = (x * x) + (y * y);
+                if (cur < distance) {
+                        distance = cur;
+                        bmp = &image->bmp;
+                }
+        }
+        return bmp;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+void bmp_finalise(bmp_image *bmp)
+{
+        if (bmp->bitmap)
+                bmp->bitmap_callbacks.bitmap_destroy(bmp->bitmap);
+        bmp->bitmap = NULL;
+        if (bmp->colour_table)
+                free(bmp->colour_table);
+        bmp->colour_table = NULL;
+}
+
+
+/* exported interface documented in libnsbmp.h */
+void ico_finalise(ico_collection *ico)
+{
+        ico_image *image;
+
+        for (image = ico->first; image; image = image->next)
+                bmp_finalise(&image->bmp);
+        while (ico->first) {
+                image = ico->first;
+                ico->first = image->next;
+                free(image);
+        }
+}
diff --git a/u-boot/drivers/video/drm/libnsbmp.h b/u-boot/drivers/video/drm/libnsbmp.h
new file mode 100644
index 0000000000..4f750c472c
--- /dev/null
+++ b/u-boot/drivers/video/drm/libnsbmp.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2006 Richard Wilson <richard.wilson@netsurf-browser.org>
+ * Copyright 2008 Sean Fox <dyntryx@gmail.com>
+ *
+ * This file is part of NetSurf's libnsbmp, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * Bitmap file decoding interface.
+ */
+
+#ifndef _LIBNSBMP_H_
+#define _LIBNSBMP_H_
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/types.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX               (2147483647)
+#endif
+
+/* bmp flags */
+#define BMP_NEW			0
+/** image is opaque (as opposed to having an alpha mask) */
+#define BMP_OPAQUE		(1 << 0)
+/** memory should be wiped */
+#define BMP_CLEAR_MEMORY	(1 << 1)
+
+/**
+ * error return values
+ */
+typedef enum {
+        BMP_OK = 0,
+        BMP_INSUFFICIENT_MEMORY = 1,
+        BMP_INSUFFICIENT_DATA = 2,
+        BMP_DATA_ERROR = 3
+} bmp_result;
+
+/**
+ * encoding types
+ */
+typedef enum {
+        BMP_ENCODING_RGB = 0,
+        BMP_ENCODING_RLE8 = 1,
+        BMP_ENCODING_RLE4 = 2,
+        BMP_ENCODING_BITFIELDS = 3
+} bmp_encoding;
+
+/* API for Bitmap callbacks */
+typedef void* (*bmp_bitmap_cb_create)(int width, int height, unsigned int state);
+typedef void (*bmp_bitmap_cb_destroy)(void *bitmap);
+typedef unsigned char* (*bmp_bitmap_cb_get_buffer)(void *bitmap);
+typedef size_t (*bmp_bitmap_cb_get_bpp)(void *bitmap);
+
+/**
+ * The Bitmap callbacks function table
+ */
+typedef struct bmp_bitmap_callback_vt_s {
+        /** Callback to allocate bitmap storage. */
+        bmp_bitmap_cb_create bitmap_create;
+        /** Called to free bitmap storage. */
+        bmp_bitmap_cb_destroy bitmap_destroy;
+        /** Return a pointer to the pixel data in a bitmap. */
+        bmp_bitmap_cb_get_buffer bitmap_get_buffer;
+} bmp_bitmap_callback_vt;
+
+/**
+ * bitmap image
+ */
+typedef struct bmp_img {
+        /** callbacks for bitmap functions */
+        bmp_bitmap_callback_vt bitmap_callbacks;
+        /** pointer to BMP data */
+        uint8_t *bmp_data;
+        /** width of BMP (valid after _analyse) */
+        uint32_t width;
+        /** heigth of BMP (valid after _analyse) */
+        uint32_t height;
+        /** whether the image has been decoded */
+        bool decoded;
+        /** decoded image */
+        void *bitmap;
+
+        /* Internal members are listed below */
+        /** total number of bytes of BMP data available */
+        uint32_t buffer_size;
+        /** pixel encoding type */
+        bmp_encoding encoding;
+        /** offset of bitmap data */
+        uint32_t bitmap_offset;
+        /** bits per pixel */
+        uint16_t bpp;
+        /** number of colours */
+        uint32_t colours;
+        /** colour table */
+        uint32_t *colour_table;
+        /** whether to use bmp's limited transparency */
+        bool limited_trans;
+        /** colour to display for "transparent" pixels when using limited
+         * transparency
+         */
+        uint32_t trans_colour;
+        /** scanlines are top to bottom */
+        bool reversed;
+        /** image is part of an ICO, mask follows */
+        bool ico;
+        /** true if the bitmap does not contain an alpha channel */
+        bool opaque;
+        /** four bitwise mask */
+        uint32_t mask[4];
+        /** four bitwise shifts */
+        int32_t shift[4];
+        /** colour representing "transparency" in the bitmap */
+        uint32_t transparent_index;
+} bmp_image;
+
+typedef struct ico_image {
+        bmp_image bmp;
+        struct ico_image *next;
+} ico_image;
+
+/**
+ * icon image collection
+ */
+typedef struct ico_collection {
+        /** callbacks for bitmap functions */
+        bmp_bitmap_callback_vt bitmap_callbacks;
+        /** width of largest BMP */
+        uint16_t width;
+        /** heigth of largest BMP */
+        uint16_t height;
+
+        /* Internal members are listed below */
+        /** pointer to ICO data */
+        uint8_t *ico_data;
+        /** total number of bytes of ICO data available */
+        uint32_t buffer_size;
+        /** root of linked list of images */
+        ico_image *first;
+} ico_collection;
+
+/**
+ * Initialises bitmap ready for analysing the bitmap.
+ *
+ * \param bmp The Bitmap to initialise
+ * \param callbacks The callbacks the library will call on operations.
+ * \return BMP_OK on success or appropriate error code.
+ */
+bmp_result bmp_create(bmp_image *bmp, bmp_bitmap_callback_vt *callbacks);
+
+/**
+ * Initialises icon ready for analysing the icon
+ *
+ * \param bmp The Bitmap to initialise
+ * \param callbacks The callbacks the library will call on operations.
+ * \return BMP_OK on success or appropriate error code.
+ */
+bmp_result ico_collection_create(ico_collection *ico,
+                                 bmp_bitmap_callback_vt *callbacks);
+
+/**
+ * Analyse a BMP prior to decoding.
+ *
+ * This will scan the data provided and perform checks to ensure the data is a
+ * valid BMP and prepare the bitmap image structure ready for decode.
+ *
+ * This function must be called and resturn BMP_OK before bmp_decode() as it
+ * prepares the bmp internal state for the decode process.
+ *
+ * \param bmp the BMP image to analyse.
+ * \param size The size of data in cdata.
+ * \param data The bitmap source data.
+ * \return BMP_OK on success or error code on faliure.
+ */
+bmp_result bmp_analyse(bmp_image *bmp, size_t size, uint8_t *data);
+
+/**
+ * Analyse an ICO prior to decoding.
+ *
+ * This function will scan the data provided and perform checks to ensure the
+ * data is a valid ICO.
+ *
+ * This function must be called before ico_find().
+ *
+ * \param ico the ICO image to analyse
+ * \param size The size of data in cdata.
+ * \param data The bitmap source data.
+ * \return BMP_OK on success
+ */
+bmp_result ico_analyse(ico_collection *ico, size_t size, uint8_t *data);
+
+/**
+ * Decode a BMP
+ *
+ * This function decodes the BMP data such that bmp->bitmap is a valid
+ * image. The state of bmp->decoded is set to TRUE on exit such that it
+ * can easily be identified which BMPs are in a fully decoded state.
+ *
+ * \param bmp the BMP image to decode
+ * \return BMP_OK on success
+ */
+bmp_result bmp_decode(bmp_image *bmp);
+
+/**
+ * Decode a BMP using "limited transparency"
+ *
+ * Bitmaps do not have native transparency support.  However, there is a
+ * "trick" that is used in some instances in which the first pixel of the
+ * bitmap becomes the "transparency index".  The decoding application can
+ * replace this index with whatever background colour it chooses to
+ * create the illusion of transparency.
+ *
+ * When to use transparency is at the discretion of the decoding
+ * application.
+ *
+ * \param bmp the BMP image to decode
+ * \param colour the colour to use as "transparent"
+ * \return BMP_OK on success
+ */
+bmp_result bmp_decode_trans(bmp_image *bmp, uint32_t transparent_colour);
+
+/**
+ * Finds the closest BMP within an ICO collection
+ *
+ * This function finds the BMP with dimensions as close to a specified set
+ * as possible from the images in the collection.
+ *
+ * \param ico the ICO collection to examine
+ * \param width the preferred width (0 to use ICO header width)
+ * \param height the preferred height (0 to use ICO header height)
+ */
+bmp_image *ico_find(ico_collection *ico, uint16_t width, uint16_t height);
+
+/**
+ * Finalise a BMP prior to destruction.
+ *
+ * \param bmp the BMP image to finalise.
+ */
+void bmp_finalise(bmp_image *bmp);
+
+/**
+ * Finalise an ICO prior to destruction.
+ *
+ * \param ico the ICO image to finalise,
+ */
+void ico_finalise(ico_collection *ico);
+
+#endif
diff --git a/u-boot/drivers/video/drm/phy-rockchip-samsung-hdptx-hdmi.c b/u-boot/drivers/video/drm/phy-rockchip-samsung-hdptx-hdmi.c
index f964ddb905..43b1327153 100644
--- a/u-boot/drivers/video/drm/phy-rockchip-samsung-hdptx-hdmi.c
+++ b/u-boot/drivers/video/drm/phy-rockchip-samsung-hdptx-hdmi.c
@@ -2012,15 +2012,16 @@ static int rockchip_hdptx_phy_hdmi_bind(struct udevice *parent)
 
 	subnode = ofnode_find_subnode(parent->node, "clk-port");
 	if (!ofnode_valid(subnode)) {
-		free(str);
-		printf("%s: no subnode for %s\n", __func__, parent->name);
-		return -ENXIO;
+		ret = device_bind_driver_to_node(parent, "clk_hdptx", str,
+						 dev_ofnode(parent), NULL);
+	} else {
+		ret = device_bind_driver_to_node(parent, "clk_hdptx", str,
+						 subnode, &child);
 	}
 
-	ret = device_bind_driver_to_node(parent, "clk_hdptx", str, subnode, &child);
 	if (ret) {
 		free(str);
-		printf("%s: clk-port cannot bind its driver\n", __func__);
+		printf("%s: clk_hdptx cannot bind its driver\n", __func__);
 		return ret;
 	}
 
diff --git a/u-boot/drivers/video/drm/rockchip_display.c b/u-boot/drivers/video/drm/rockchip_display.c
index 2eb9112019..989c063679 100644
--- a/u-boot/drivers/video/drm/rockchip_display.c
+++ b/u-boot/drivers/video/drm/rockchip_display.c
@@ -23,8 +23,10 @@
 #include <dm/device.h>
 #include <dm/uclass-internal.h>
 #include <asm/arch-rockchip/resource_img.h>
+#include <asm/arch-rockchip/cpu.h>
 
 #include "bmp_helper.h"
+#include "libnsbmp.h"
 #include "rockchip_display.h"
 #include "rockchip_crtc.h"
 #include "rockchip_connector.h"
@@ -48,6 +50,8 @@
 
 #define RK_BLK_SIZE 512
 #define BMP_PROCESSED_FLAG 8399
+#define BYTES_PER_PIXEL sizeof(uint32_t)
+#define MAX_IMAGE_BYTES (8 * 1024 * 1024)
 
 DECLARE_GLOBAL_DATA_PTR;
 static LIST_HEAD(rockchip_display_list);
@@ -76,6 +80,61 @@ struct public_phy_data {
 	bool phy_init;
 };
 
+char* rockchip_get_output_if_name(u32 output_if, char *name)
+{
+	if (output_if & VOP_OUTPUT_IF_RGB)
+		strcat(name, " RGB");
+	if (output_if & VOP_OUTPUT_IF_BT1120)
+		strcat(name, " BT1120");
+	if (output_if & VOP_OUTPUT_IF_BT656)
+		strcat(name, " BT656");
+	if (output_if & VOP_OUTPUT_IF_LVDS0)
+		strcat(name, " LVDS0");
+	if (output_if & VOP_OUTPUT_IF_LVDS1)
+		strcat(name, " LVDS1");
+	if (output_if & VOP_OUTPUT_IF_MIPI0)
+		strcat(name, " MIPI0");
+	if (output_if & VOP_OUTPUT_IF_MIPI1)
+		strcat(name, " MIPI1");
+	if (output_if & VOP_OUTPUT_IF_eDP0)
+		strcat(name, " eDP0");
+	if (output_if & VOP_OUTPUT_IF_eDP1)
+		strcat(name, " eDP1");
+	if (output_if & VOP_OUTPUT_IF_DP0)
+		strcat(name, " DP0");
+	if (output_if & VOP_OUTPUT_IF_DP1)
+		strcat(name, " DP1");
+	if (output_if & VOP_OUTPUT_IF_HDMI0)
+		strcat(name, " HDMI0");
+	if (output_if & VOP_OUTPUT_IF_HDMI1)
+		strcat(name, " HDMI1");
+
+	return name;
+}
+
+u32 rockchip_drm_get_cycles_per_pixel(u32 bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+		return 1;
+	case MEDIA_BUS_FMT_RGB565_2X8_LE:
+	case MEDIA_BUS_FMT_BGR565_2X8_LE:
+		return 2;
+	case MEDIA_BUS_FMT_RGB666_3X6:
+	case MEDIA_BUS_FMT_RGB888_3X8:
+	case MEDIA_BUS_FMT_BGR888_3X8:
+		return 3;
+	case MEDIA_BUS_FMT_RGB888_DUMMY_4X8:
+	case MEDIA_BUS_FMT_BGR888_DUMMY_4X8:
+		return 4;
+	default:
+		return 1;
+	}
+}
+
 int rockchip_get_baseparameter(void)
 {
 	struct blk_desc *dev_desc;
@@ -1082,12 +1141,13 @@ static int get_crtc_mcu_mode(struct crtc_state *crtc_state, struct device_node *
 	return 0;
 }
 
-struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp)
+struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp, int rotate)
 {
 	struct rockchip_logo_cache *tmp, *logo_cache = NULL;
 
 	list_for_each_entry(tmp, &logo_cache_list, head) {
-		if (!strcmp(tmp->name, bmp)) {
+		if ((!strcmp(tmp->name, bmp) && rotate == tmp->logo_rotate) ||
+		    (soc_is_rk3566() && tmp->logo_rotate)) {
 			logo_cache = tmp;
 			break;
 		}
@@ -1143,7 +1203,8 @@ static int load_kernel_bmp_logo(struct logo_info *logo, const char *bmp_name)
 	return 0;
 }
 
-static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
+#ifdef BMP_DECODEER_LEGACY
+static int load_bmp_logo_legacy(struct logo_info *logo, const char *bmp_name)
 {
 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
 	struct rockchip_logo_cache *logo_cache;
@@ -1156,7 +1217,7 @@ static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
 
 	if (!logo || !bmp_name)
 		return -EINVAL;
-	logo_cache = find_or_alloc_logo_cache(bmp_name);
+	logo_cache = find_or_alloc_logo_cache(bmp_name, logo->rotate);
 	if (!logo_cache)
 		return -ENOMEM;
 
@@ -1244,6 +1305,227 @@ free_header:
 	return -EINVAL;
 #endif
 }
+#endif
+
+static void *bitmap_create(int width, int height, unsigned int state)
+{
+	/* Ensure a stupidly large bitmap is not created */
+	if (width > 4096 || height > 4096)
+		return NULL;
+
+	return calloc(width * height, BYTES_PER_PIXEL);
+}
+
+static unsigned char *bitmap_get_buffer(void *bitmap)
+{
+	return bitmap;
+}
+
+static void bitmap_destroy(void *bitmap)
+{
+	free(bitmap);
+}
+
+static void bmp_copy(void *dst, bmp_image *bmp)
+{
+	u16 row, col;
+	u8 *image;
+	u8 *pdst = (u8 *)dst;
+
+	image = (u8 *)bmp->bitmap;
+	for (row = 0; row != bmp->height; row++) {
+		for (col = 0; col != bmp->width; col++) {
+			size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
+
+			*pdst++ = image[z + 2];
+			*pdst++ = image[z + 1];
+			*pdst++ = image[z + 0];
+			*pdst++ = image[z + 3];
+		}
+	}
+}
+
+static void *rockchip_logo_rotate(struct logo_info *logo, void *src)
+{
+	void *dst_rotate;
+	int width = logo->width;
+	int height = logo->height;
+	int width_rotate = logo->height & 0x3 ? (logo->height & ~0x3) + 4 : logo->height;
+	int height_rotate = logo->width;
+	int dst_size = width * height * logo->bpp >> 3;
+	int dst_size_rotate = width_rotate * height_rotate * logo->bpp >> 3;
+	int bytes_per_pixel = logo->bpp >> 3;
+	int padded_width;
+	int i, j;
+	char *img_data;
+
+	if (!(logo->rotate == 90 || logo->rotate == 180 || logo->rotate == 270)) {
+		printf("Unsupported rotation angle\n");
+		return NULL;
+	}
+
+	img_data = (char *)malloc(dst_size);
+	if (!img_data) {
+		printf("failed to alloc memory for image data\n");
+		return NULL;
+	}
+	memcpy(img_data, src, dst_size);
+
+	dst_rotate = get_display_buffer(dst_size_rotate);
+	if (!dst_rotate)
+		return NULL;
+	memset(dst_rotate, 0, dst_size_rotate);
+
+	switch (logo->rotate) {
+	case 90:
+		logo->width = width_rotate;
+		logo->height = height_rotate;
+		padded_width = height & 0x3 ? (height & ~0x3) + 4 : height;
+		for (i = 0; i < height; i++) {
+			for (j = 0; j < width; j++) {
+				memcpy(dst_rotate + (j * padded_width * bytes_per_pixel) +
+				       (height - i - 1) * bytes_per_pixel,
+				       img_data + i * width * bytes_per_pixel + j * bytes_per_pixel,
+				       bytes_per_pixel);
+			}
+		}
+		break;
+	case 180:
+		for (i = 0; i < height; i++) {
+			for (j = 0; j < width; j++) {
+				memcpy(dst_rotate + (height - i - 1) * width * bytes_per_pixel +
+				       (width - j - 1) * bytes_per_pixel,
+				       img_data + i * width * bytes_per_pixel + j * bytes_per_pixel,
+				       bytes_per_pixel);
+			}
+		}
+		break;
+	case 270:
+		logo->width = width_rotate;
+		logo->height = height_rotate;
+		padded_width = height & 0x3 ? (height & ~0x3) + 4 : height;
+		for (i = 0; i < height; i++) {
+			for (j = 0; j < width; j++) {
+				memcpy(dst_rotate + (width - j - 1) * padded_width * bytes_per_pixel +
+				       i * bytes_per_pixel,
+				       img_data + i * width * bytes_per_pixel + j * bytes_per_pixel,
+				       bytes_per_pixel);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	free(img_data);
+
+	return dst_rotate;
+}
+
+static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
+{
+#ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
+	struct rockchip_logo_cache *logo_cache;
+	bmp_bitmap_callback_vt bitmap_callbacks = {
+		bitmap_create,
+		bitmap_destroy,
+		bitmap_get_buffer,
+	};
+	bmp_result code;
+	bmp_image bmp;
+	void *bmp_data;
+	void *dst = NULL;
+	void *dst_rotate = NULL;
+	int len, dst_size;
+	int ret = 0;
+
+	if (!logo || !bmp_name)
+		return -EINVAL;
+
+	logo_cache = find_or_alloc_logo_cache(bmp_name, logo->rotate);
+	if (!logo_cache)
+		return -ENOMEM;
+
+	if (logo_cache->logo.mem) {
+		memcpy(logo, &logo_cache->logo, sizeof(*logo));
+		return 0;
+	}
+
+	bmp_data = malloc(MAX_IMAGE_BYTES);
+	if (!bmp_data)
+		return -ENOMEM;
+
+	bmp_create(&bmp, &bitmap_callbacks);
+
+	len = rockchip_read_resource_file(bmp_data, bmp_name, 0, MAX_IMAGE_BYTES);
+	if (len < 0) {
+		ret = -EINVAL;
+		goto free_bmp_data;
+	}
+
+	/* analyse the BMP */
+	code = bmp_analyse(&bmp, len, bmp_data);
+	if (code != BMP_OK) {
+		printf("failed to parse bmp:%s header\n", bmp_name);
+		ret = -EINVAL;
+		goto free_bmp_data;
+	}
+	/* fix bpp to 32 */
+	logo->bpp = 32;
+	logo->offset = 0;
+	logo->ymirror = 0;
+	logo->width = get_unaligned_le32(&bmp.width);
+	logo->height = get_unaligned_le32(&bmp.height);
+	dst_size = logo->width * logo->height * logo->bpp >> 3;
+	/* decode the image to RGBA8888 format */
+	code = bmp_decode(&bmp);
+	if (code != BMP_OK) {
+		/* allow partially decoded images */
+		if (code != BMP_INSUFFICIENT_DATA && code != BMP_DATA_ERROR) {
+			printf("failed to allocate the buffer of bmp:%s\n", bmp_name);
+			ret = -EINVAL;
+			goto free_bmp_data;
+		}
+
+		/* skip if the partially decoded image would be ridiculously large */
+		if ((bmp.width * bmp.height) > 200000) {
+			printf("partially decoded bmp:%s can not be too large\n", bmp_name);
+			ret = -EINVAL;
+			goto free_bmp_data;
+		}
+	}
+
+	dst = get_display_buffer(dst_size);
+	if (!dst) {
+		ret = -ENOMEM;
+		goto free_bmp_data;
+	}
+	bmp_copy(dst, &bmp);
+
+	if (logo->rotate) {
+		dst_rotate = rockchip_logo_rotate(logo, dst);
+		if (dst_rotate) {
+			dst = dst_rotate;
+			dst_size = logo->width * logo->height * logo->bpp >> 3;
+		}
+		printf("logo ratate %d\n", logo->rotate);
+	}
+	logo->mem = dst;
+
+	memcpy(&logo_cache->logo, logo, sizeof(*logo));
+	logo_cache->logo_rotate = logo->rotate;
+
+	flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
+free_bmp_data:
+	/* clean up */
+	bmp_finalise(&bmp);
+	free(bmp_data);
+
+	return ret;
+#else
+	return -EINVAL;
+#endif
+}
 
 void rockchip_show_fbbase(ulong fbbase)
 {
@@ -1291,6 +1573,7 @@ int rockchip_show_logo(void)
 
 	list_for_each_entry(s, &rockchip_display_list, head) {
 		s->logo.mode = s->logo_mode;
+		s->logo.rotate = s->logo_rotate;
 		if (load_bmp_logo(&s->logo, s->ulogo_name)) {
 			printf("failed to display uboot logo\n");
 		} else {
@@ -1354,7 +1637,7 @@ enum {
 	PORT_DIR_OUT,
 };
 
-static const struct device_node *rockchip_of_graph_get_port_by_id(ofnode node, int id)
+const struct device_node *rockchip_of_graph_get_port_by_id(ofnode node, int id)
 {
 	ofnode ports, port;
 	u32 reg;
@@ -1611,6 +1894,7 @@ static struct rockchip_connector *rockchip_get_split_connector(struct rockchip_c
 	int ret;
 
 	split_mode = ofnode_read_bool(conn->dev->node, "split-mode");
+	split_mode |= ofnode_read_bool(conn->dev->node, "dual-channel");
 	if (!split_mode)
 		return NULL;
 
@@ -1624,6 +1908,9 @@ static struct rockchip_connector *rockchip_get_split_connector(struct rockchip_c
 	case DRM_MODE_CONNECTOR_HDMIA:
 		conn_name = "hdmi";
 		break;
+	case DRM_MODE_CONNECTOR_LVDS:
+		conn_name = "lvds";
+		break;
 	default:
 		return NULL;
 	}
@@ -1850,6 +2137,8 @@ static int rockchip_display_probe(struct udevice *dev)
 		else
 			s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER;
 
+		s->logo_rotate = ofnode_read_u32_default(node, "logo,rotate", 0);
+
 		s->force_output = ofnode_read_bool(node, "force-output");
 
 		if (s->force_output) {
@@ -2035,7 +2324,8 @@ void rockchip_display_fixup(void *blob)
 			continue;
 		}
 
-		if (s->conn_state.secondary) {
+		if (s->conn_state.secondary &&
+		    s->conn_state.secondary->type != DRM_MODE_CONNECTOR_LVDS) {
 			s->conn_state.mode.clock *= 2;
 			s->conn_state.mode.hdisplay *= 2;
 		}
diff --git a/u-boot/drivers/video/drm/rockchip_display.h b/u-boot/drivers/video/drm/rockchip_display.h
index 8447871c68..82789ca1df 100644
--- a/u-boot/drivers/video/drm/rockchip_display.h
+++ b/u-boot/drivers/video/drm/rockchip_display.h
@@ -253,6 +253,7 @@ struct connector_state {
 
 struct logo_info {
 	int mode;
+	int rotate;
 	char *mem;
 	bool ymirror;
 	u32 offset;
@@ -265,6 +266,7 @@ struct rockchip_logo_cache {
 	struct list_head head;
 	char name[20];
 	struct logo_info logo;
+	int logo_rotate;
 };
 
 struct display_state {
@@ -283,6 +285,7 @@ struct display_state {
 	struct logo_info logo;
 	int logo_mode;
 	int charge_logo_mode;
+	int logo_rotate;
 	void *mem_base;
 	int mem_size;
 
@@ -317,6 +320,10 @@ int display_rect_calc_vscale(struct display_rect *src, struct display_rect *dst,
 			     int min_vscale, int max_vscale);
 const struct device_node *
 rockchip_of_graph_get_endpoint_by_regs(ofnode node, int port, int endpoint);
+const struct device_node *
+rockchip_of_graph_get_port_by_id(ofnode node, int id);
+uint32_t rockchip_drm_get_cycles_per_pixel(uint32_t bus_format);
+char* rockchip_get_output_if_name(u32 output_if, char *name);
 
 #ifdef CONFIG_SPL_BUILD
 int rockchip_spl_vop_probe(struct crtc_state *crtc_state);
diff --git a/u-boot/drivers/video/drm/rockchip_dw_hdmi_qp.c b/u-boot/drivers/video/drm/rockchip_dw_hdmi_qp.c
index 76971600f7..f5d3cfdfa2 100644
--- a/u-boot/drivers/video/drm/rockchip_dw_hdmi_qp.c
+++ b/u-boot/drivers/video/drm/rockchip_dw_hdmi_qp.c
@@ -1063,7 +1063,8 @@ null_basep:
 	hdmi_select_link_config(hdmi, edid_data->preferred_mode, tmdsclk);
 	dw_hdmi_qp_dsc_configure(hdmi, edid_data->preferred_mode);
 	if (hdmi->link_cfg.frl_mode) {
-		dm_gpio_set_value(&hdmi->enable_gpio, 0);
+		if (dm_gpio_is_valid(&hdmi->enable_gpio))
+			dm_gpio_set_value(&hdmi->enable_gpio, 0);
 		/* in the current version, support max 40G frl */
 		if (hdmi->link_cfg.rate_per_lane >= 10) {
 			hdmi->link_cfg.frl_lanes = 4;
@@ -1078,7 +1079,8 @@ null_basep:
 		else
 			hdmi->bus_width |= HDMI_FRL_MODE;
 	} else {
-		dm_gpio_set_value(&hdmi->enable_gpio, 1);
+		if (dm_gpio_is_valid(&hdmi->enable_gpio))
+			dm_gpio_set_value(&hdmi->enable_gpio, 1);
 		hdmi->bus_width =
 			hdmi_get_tmdsclock(hdmi, pixel_clk * 10);
 		if (hdmi_bus_fmt_is_yuv420(*bus_format))
diff --git a/u-boot/drivers/video/drm/rockchip_lvds.c b/u-boot/drivers/video/drm/rockchip_lvds.c
index d7acbe48ce..d930de7009 100644
--- a/u-boot/drivers/video/drm/rockchip_lvds.c
+++ b/u-boot/drivers/video/drm/rockchip_lvds.c
@@ -21,6 +21,7 @@
 #include "rockchip_connector.h"
 #include "rockchip_phy.h"
 #include "rockchip_panel.h"
+#include "drm_of.h"
 
 #define HIWORD_UPDATE(v, h, l)		(((v) << (l)) | (GENMASK(h, l) << 16))
 
@@ -90,6 +91,7 @@ enum lvds_format {
 struct rockchip_lvds;
 
 struct rockchip_lvds_funcs {
+	int (*probe)(struct rockchip_lvds *lvds);
 	void (*enable)(struct rockchip_lvds *lvds, int pipe);
 	void (*disable)(struct rockchip_lvds *lvds);
 };
@@ -105,12 +107,14 @@ struct rockchip_lvds {
 	enum lvds_format format;
 	bool data_swap;
 	bool dual_channel;
+	enum drm_lvds_dual_link_pixels pixel_order;
 };
 
 static int rockchip_lvds_connector_init(struct rockchip_connector *conn,
 					struct display_state *state)
 {
 	struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
+	struct rockchip_lvds *primary_lvds = NULL;
 	struct connector_state *conn_state = &state->conn_state;
 	struct rockchip_panel *panel = conn->panel;
 
@@ -118,6 +122,9 @@ static int rockchip_lvds_connector_init(struct rockchip_connector *conn,
 	lvds->phy = conn->phy;
 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type, lvds->id);
 
+	if (conn_state->secondary)
+		primary_lvds = dev_get_priv(conn_state->connector->dev);
+
 	switch (panel->bus_format) {
 	case MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA:	/* jeida-18 */
 		lvds->format = LVDS_6BIT_MODE;
@@ -139,6 +146,7 @@ static int rockchip_lvds_connector_init(struct rockchip_connector *conn,
 		break;
 	}
 
+	conn_state->bus_format = panel->bus_format;
 	conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
 
 	if ((lvds->format == LVDS_10BIT_MODE_FORMAT_1) ||
@@ -146,7 +154,46 @@ static int rockchip_lvds_connector_init(struct rockchip_connector *conn,
 		conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
 
 	conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
-	conn_state->output_if = VOP_OUTPUT_IF_LVDS0;
+	if (primary_lvds) {
+		conn_state->output_flags = 0;
+		conn_state->output_if = 0;
+
+		switch (primary_lvds->pixel_order) {
+		case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
+			conn_state->output_flags |=
+				ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE;
+			conn_state->output_if |=
+				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
+			break;
+		case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
+			conn_state->output_flags |=
+				ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE;
+			conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
+			conn_state->output_if |=
+				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
+			break;
+		case DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS:
+			conn_state->output_flags |=
+				ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
+			conn_state->output_if |=
+				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
+			break;
+		case DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS:
+			conn_state->output_flags |=
+				ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
+			conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
+			conn_state->output_if |=
+				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (lvds->id)
+		conn_state->output_if |= VOP_OUTPUT_IF_LVDS1;
+	else
+		conn_state->output_if |= VOP_OUTPUT_IF_LVDS0;
 
 	return 0;
 }
@@ -205,6 +252,10 @@ static int rockchip_lvds_probe(struct udevice *dev)
 	if (lvds->id < 0)
 		lvds->id = 0;
 
+	lvds->pixel_order = -1;
+	if (lvds->funcs->probe)
+		lvds->funcs->probe(lvds);
+
 	rockchip_connector_bind(&lvds->connector, dev, lvds->id, &rockchip_lvds_connector_funcs,
 				NULL, DRM_MODE_CONNECTOR_LVDS);
 
@@ -329,21 +380,61 @@ static const struct rockchip_lvds_funcs rk3562_lvds_funcs = {
 	.disable = rk3562_lvds_disable,
 };
 
+static int rk3568_lvds_probe(struct rockchip_lvds *lvds)
+{
+	if (lvds->dual_channel) {
+		const struct device_node *port0, *port1;
+		int pixel_order;
+
+		port1 = of_alias_get_dev("lvds", 1);
+		if (!port1 || !of_device_is_available(port1)) {
+			lvds->pixel_order = 0;
+			return 0;
+		}
+
+		port0 = rockchip_of_graph_get_port_by_id(lvds->dev->node, 1);
+		port1 = rockchip_of_graph_get_port_by_id(np_to_ofnode(port1),
+							 1);
+		pixel_order =
+			drm_of_lvds_get_dual_link_pixel_order(port0, port1);
+
+		lvds->pixel_order = pixel_order >= 0 ? pixel_order : 0;
+	}
+
+	return 0;
+}
+
 static void rk3568_lvds_enable(struct rockchip_lvds *lvds, int pipe)
 {
-	regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
-		     RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) |
-		     RK3568_LVDS0_DCLK_INV_SEL(1));
-	regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
-		     RK3568_LVDS0_SELECT(lvds->format) | RK3568_LVDS0_MSBSEL(1));
+	if (lvds->id) {
+		regmap_write(lvds->grf, RK3568_GRF_VO_CON3,
+			     RK3568_LVDS1_MODE_EN(1) | RK3568_LVDS1_P2S_EN(1) |
+				     RK3568_LVDS1_DCLK_INV_SEL(1));
+		regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
+			     RK3568_LVDS1_SELECT(lvds->format) |
+				     RK3568_LVDS1_MSBSEL(1));
+	} else {
+		regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
+			     RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) |
+				     RK3568_LVDS0_DCLK_INV_SEL(1));
+		regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
+			     RK3568_LVDS0_SELECT(lvds->format) |
+				     RK3568_LVDS0_MSBSEL(1));
+	}
 }
 
 static void rk3568_lvds_disable(struct rockchip_lvds *lvds)
 {
-	regmap_write(lvds->grf, RK3568_GRF_VO_CON2, RK3568_LVDS0_MODE_EN(0));
+	if (lvds->id)
+		regmap_write(lvds->grf, RK3568_GRF_VO_CON3,
+			     RK3568_LVDS1_MODE_EN(0));
+	else
+		regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
+			     RK3568_LVDS0_MODE_EN(0));
 }
 
 static const struct rockchip_lvds_funcs rk3568_lvds_funcs = {
+	.probe = rk3568_lvds_probe,
 	.enable = rk3568_lvds_enable,
 	.disable = rk3568_lvds_disable,
 };
diff --git a/u-boot/drivers/video/drm/rockchip_rgb.c b/u-boot/drivers/video/drm/rockchip_rgb.c
index 35c9cf8ba1..116ac246d6 100644
--- a/u-boot/drivers/video/drm/rockchip_rgb.c
+++ b/u-boot/drivers/video/drm/rockchip_rgb.c
@@ -659,6 +659,9 @@ static const struct udevice_id rockchip_rgb_ids[] = {
 		.compatible = "rockchip,rk3568-rgb",
 		.data = (ulong)&rk3568_rgb_funcs,
 	},
+	{
+		.compatible = "rockchip,rk3588-rgb",
+	},
 	{
 		.compatible = "rockchip,rv1106-rgb",
 		.data = (ulong)&rv1106_rgb_funcs,
diff --git a/u-boot/drivers/video/drm/rockchip_vop.c b/u-boot/drivers/video/drm/rockchip_vop.c
index 11bbae5dd1..6d29298225 100644
--- a/u-boot/drivers/video/drm/rockchip_vop.c
+++ b/u-boot/drivers/video/drm/rockchip_vop.c
@@ -255,6 +255,7 @@ static int rockchip_vop_init(struct display_state *state)
 	bool yuv_overlay = false, post_r2y_en = false, post_y2r_en = false;
 	u16 post_csc_mode;
 	bool dclk_inv;
+	char output_type_name[30] = {0};
 
 	vop = malloc(sizeof(*vop));
 	if (!vop)
@@ -278,6 +279,12 @@ static int rockchip_vop_init(struct display_state *state)
 	vop->win_csc = vop_data->win_csc;
 	vop->version = vop_data->version;
 
+	printf("VOP:0x%8p update mode to: %dx%d%s%d, type:%s\n",
+	       vop->regs, mode->crtc_hdisplay, mode->vdisplay,
+	       mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
+	       mode->vrefresh,
+	       rockchip_get_output_if_name(conn_state->output_if, output_type_name));
+
 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
 	ret = clk_set_defaults(crtc_state->dev);
 	if (ret)
@@ -285,11 +292,12 @@ static int rockchip_vop_init(struct display_state *state)
 
 	ret = clk_get_by_name(crtc_state->dev, "dclk_vop", &dclk);
 	if (!ret)
-		ret = clk_set_rate(&dclk, mode->clock * 1000);
+		ret = clk_set_rate(&dclk, mode->crtc_clock * 1000);
 	if (IS_ERR_VALUE(ret)) {
 		printf("%s: Failed to set dclk: ret=%d\n", __func__, ret);
 		return ret;
 	}
+	printf("VOP:0x%8p set crtc_clock to %dKHz\n", vop->regs, mode->crtc_clock);
 
 	memcpy(vop->regsbak, vop->regs, vop_data->reg_len);
 
@@ -904,11 +912,16 @@ static int rockchip_vop_plane_check(struct display_state *state)
 
 static int rockchip_vop_mode_fixup(struct display_state *state)
 {
+	struct crtc_state *crtc_state = &state->crtc_state;
 	struct connector_state *conn_state = &state->conn_state;
 	struct drm_display_mode *mode = &conn_state->mode;
 
 	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
 
+	mode->crtc_clock *= rockchip_drm_get_cycles_per_pixel(conn_state->bus_format);
+	if (crtc_state->mcu_timing.mcu_pix_total)
+		mode->crtc_clock *= crtc_state->mcu_timing.mcu_pix_total + 1;
+
 	return 0;
 }
 
diff --git a/u-boot/drivers/video/drm/rockchip_vop2.c b/u-boot/drivers/video/drm/rockchip_vop2.c
index 33de5eae18..eb11f1ab38 100644
--- a/u-boot/drivers/video/drm/rockchip_vop2.c
+++ b/u-boot/drivers/video/drm/rockchip_vop2.c
@@ -86,10 +86,14 @@
 
 #define RK3568_DSP_IF_CTRL			0x02c
 #define LVDS_DUAL_EN_SHIFT			0
+#define RK3588_BT656_UV_SWAP_SHIFT		0
 #define LVDS_DUAL_LEFT_RIGHT_EN_SHIFT		1
+#define RK3588_BT656_YC_SWAP_SHIFT		1
 #define LVDS_DUAL_SWAP_EN_SHIFT			2
 #define BT656_UV_SWAP				4
+#define RK3588_BT1120_UV_SWAP_SHIFT		4
 #define BT656_YC_SWAP				5
+#define RK3588_BT1120_YC_SWAP_SHIFT		5
 #define BT656_DCLK_POL				6
 #define RK3588_HDMI_DUAL_EN_SHIFT		8
 #define RK3588_EDP_DUAL_EN_SHIFT		8
@@ -879,6 +883,9 @@
 #define GRF_BT1120_CLK_INV_SHIFT		2
 #define GRF_RGB_DCLK_INV_SHIFT			3
 
+#define RK3588_GRF_SOC_CON1			0x0304
+#define RK3588_GRF_VOP_DCLK_INV_SEL_SHIFT	14
+
 #define RK3588_GRF_VOP_CON2			0x0008
 #define RK3588_GRF_EDP0_ENABLE_SHIFT		0
 #define RK3588_GRF_HDMITX0_ENABLE_SHIFT		1
@@ -1415,38 +1422,6 @@ static inline u32 vop2_grf_readl(struct vop2 *vop, void *grf_base, u32 offset,
 	return (readl(grf_base + offset) >> shift) & mask;
 }
 
-static char* get_output_if_name(u32 output_if, char *name)
-{
-	if (output_if & VOP_OUTPUT_IF_RGB)
-		strcat(name, " RGB");
-	if (output_if & VOP_OUTPUT_IF_BT1120)
-		strcat(name, " BT1120");
-	if (output_if & VOP_OUTPUT_IF_BT656)
-		strcat(name, " BT656");
-	if (output_if & VOP_OUTPUT_IF_LVDS0)
-		strcat(name, " LVDS0");
-	if (output_if & VOP_OUTPUT_IF_LVDS1)
-		strcat(name, " LVDS1");
-	if (output_if & VOP_OUTPUT_IF_MIPI0)
-		strcat(name, " MIPI0");
-	if (output_if & VOP_OUTPUT_IF_MIPI1)
-		strcat(name, " MIPI1");
-	if (output_if & VOP_OUTPUT_IF_eDP0)
-		strcat(name, " eDP0");
-	if (output_if & VOP_OUTPUT_IF_eDP1)
-		strcat(name, " eDP1");
-	if (output_if & VOP_OUTPUT_IF_DP0)
-		strcat(name, " DP0");
-	if (output_if & VOP_OUTPUT_IF_DP1)
-		strcat(name, " DP1");
-	if (output_if & VOP_OUTPUT_IF_HDMI0)
-		strcat(name, " HDMI0");
-	if (output_if & VOP_OUTPUT_IF_HDMI1)
-		strcat(name, " HDMI1");
-
-	return name;
-}
-
 static char *get_plane_name(int plane_id, char *name)
 {
 	switch (plane_id) {
@@ -1584,6 +1559,19 @@ static bool is_rb_swap(u32 bus_format, u32 output_mode)
 		return false;
 }
 
+static bool is_yc_swap(u32 bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+	case MEDIA_BUS_FMT_YVYU8_1X16:
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static inline bool is_hot_plug_devices(int output_type)
 {
 	switch (output_type) {
@@ -2540,6 +2528,7 @@ static int rockchip_vop2_preinit(struct display_state *state)
 {
 	struct crtc_state *cstate = &state->crtc_state;
 	const struct vop2_data *vop2_data = cstate->crtc->data;
+	struct regmap *map;
 
 	if (!rockchip_vop2) {
 		rockchip_vop2 = calloc(1, sizeof(struct vop2));
@@ -2552,23 +2541,24 @@ static int rockchip_vop2_preinit(struct display_state *state)
 		rockchip_vop2->regs = (void *)RK3528_VOP_BASE;
 #else
 		rockchip_vop2->regs = dev_read_addr_ptr(cstate->dev);
-		rockchip_vop2->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+		map = syscon_regmap_lookup_by_phandle(cstate->dev, "rockchip,grf");
+		rockchip_vop2->grf = regmap_get_range(map, 0);
 		if (rockchip_vop2->grf <= 0)
 			printf("%s: Get syscon grf failed (ret=%p)\n", __func__, rockchip_vop2->grf);
 #endif
 		rockchip_vop2->version = vop2_data->version;
 		rockchip_vop2->data = vop2_data;
 		if (rockchip_vop2->version == VOP_VERSION_RK3588) {
-			struct regmap *map;
-
-			rockchip_vop2->vop_grf = syscon_get_first_range(ROCKCHIP_SYSCON_VOP_GRF);
+			map = syscon_regmap_lookup_by_phandle(cstate->dev, "rockchip,vop-grf");
+			rockchip_vop2->vop_grf = regmap_get_range(map, 0);
 			if (rockchip_vop2->vop_grf <= 0)
 				printf("%s: Get syscon vop_grf failed (ret=%p)\n", __func__, rockchip_vop2->vop_grf);
 			map = syscon_regmap_lookup_by_phandle(cstate->dev, "rockchip,vo1-grf");
 			rockchip_vop2->vo1_grf = regmap_get_range(map, 0);
 			if (rockchip_vop2->vo1_grf <= 0)
 				printf("%s: Get syscon vo1_grf failed (ret=%p)\n", __func__, rockchip_vop2->vo1_grf);
-			rockchip_vop2->sys_pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
+			map = syscon_regmap_lookup_by_phandle(cstate->dev, "rockchip,pmu");
+			rockchip_vop2->sys_pmu = regmap_get_range(map, 0);
 			if (rockchip_vop2->sys_pmu <= 0)
 				printf("%s: Get syscon sys_pmu failed (ret=%p)\n", __func__, rockchip_vop2->sys_pmu);
 		}
@@ -2770,8 +2760,10 @@ static unsigned long rk3588_vop2_if_cfg(struct display_state *state)
 	int if_pixclk_div = 0;
 	int if_dclk_div = 0;
 	unsigned long dclk_rate;
+	bool dclk_inv, yc_swap = false;
 	u32 val;
 
+	dclk_inv = (conn_state->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) ? 1 : 0;
 	if (output_if & (VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1)) {
 		val = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? BIT(HSYNC_POSITIVE) : 0;
 		val |= (mode->flags & DRM_MODE_FLAG_NVSYNC) ? BIT(VSYNC_POSITIVE) : 0;
@@ -2806,16 +2798,28 @@ static unsigned long rk3588_vop2_if_cfg(struct display_state *state)
 	if (output_if & VOP_OUTPUT_IF_RGB) {
 		vop2_mask_write(vop2, RK3568_DSP_IF_EN, 0x7, RK3588_RGB_EN_SHIFT,
 				4, false);
+		vop2_grf_writel(vop2, vop2->grf, RK3588_GRF_SOC_CON1, EN_MASK,
+				RK3588_GRF_VOP_DCLK_INV_SEL_SHIFT, !dclk_inv);
 	}
 
 	if (output_if & VOP_OUTPUT_IF_BT1120) {
 		vop2_mask_write(vop2, RK3568_DSP_IF_EN, 0x7, RK3588_RGB_EN_SHIFT,
 				3, false);
+		vop2_grf_writel(vop2, vop2->grf, RK3588_GRF_SOC_CON1, EN_MASK,
+				RK3588_GRF_VOP_DCLK_INV_SEL_SHIFT, !dclk_inv);
+		yc_swap = is_yc_swap(conn_state->bus_format);
+		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK, RK3588_BT1120_YC_SWAP_SHIFT,
+				yc_swap, false);
 	}
 
 	if (output_if & VOP_OUTPUT_IF_BT656) {
 		vop2_mask_write(vop2, RK3568_DSP_IF_EN, 0x7, RK3588_RGB_EN_SHIFT,
 				2, false);
+		vop2_grf_writel(vop2, vop2->grf, RK3588_GRF_SOC_CON1, EN_MASK,
+				RK3588_GRF_VOP_DCLK_INV_SEL_SHIFT, !dclk_inv);
+		yc_swap = is_yc_swap(conn_state->bus_format);
+		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK, RK3588_BT656_YC_SWAP_SHIFT,
+				yc_swap, false);
 	}
 
 	if (output_if & VOP_OUTPUT_IF_MIPI0) {
@@ -2989,13 +2993,47 @@ static unsigned long rk3588_vop2_if_cfg(struct display_state *state)
 	return dclk_rate;
 }
 
+static void rk3568_vop2_setup_dual_channel_if(struct display_state *state)
+{
+	struct crtc_state *cstate = &state->crtc_state;
+	struct connector_state *conn_state = &state->conn_state;
+	struct vop2 *vop2 = cstate->private;
+	u32 vp_offset = (cstate->crtc_id * 0x100);
+
+	if (conn_state->output_flags &
+	    ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE) {
+		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
+				LVDS_DUAL_EN_SHIFT, 1, false);
+		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
+				LVDS_DUAL_LEFT_RIGHT_EN_SHIFT, 0, false);
+		if (conn_state->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP)
+			vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
+					LVDS_DUAL_SWAP_EN_SHIFT, 1, false);
+
+		return;
+	}
+
+	vop2_mask_write(vop2, RK3568_VP0_MIPI_CTRL + vp_offset, EN_MASK,
+			MIPI_DUAL_EN_SHIFT, 1, false);
+	if (conn_state->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP) {
+		vop2_mask_write(vop2, RK3568_VP0_MIPI_CTRL + vp_offset, EN_MASK,
+				MIPI_DUAL_SWAP_EN_SHIFT, 1, false);
+	}
+
+	if (conn_state->output_if & VOP_OUTPUT_IF_LVDS1) {
+		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
+				LVDS_DUAL_EN_SHIFT, 1, false);
+		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
+				LVDS_DUAL_LEFT_RIGHT_EN_SHIFT, 1, false);
+	}
+}
+
 static unsigned long rk3568_vop2_if_cfg(struct display_state *state)
 {
 	struct crtc_state *cstate = &state->crtc_state;
 	struct connector_state *conn_state = &state->conn_state;
 	struct drm_display_mode *mode = &conn_state->mode;
 	struct vop2 *vop2 = cstate->private;
-	u32 vp_offset = (cstate->crtc_id * 0x100);
 	bool dclk_inv;
 	u32 val;
 
@@ -3056,20 +3094,6 @@ static unsigned long rk3568_vop2_if_cfg(struct display_state *state)
 				IF_CTRL_RGB_LVDS_DCLK_POL_SHIFT, dclk_inv, false);
 	}
 
-	if (conn_state->output_flags &
-	    (ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE |
-	     ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE)) {
-		vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
-				LVDS_DUAL_EN_SHIFT, 1, false);
-		if (conn_state->output_flags &
-		    ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE)
-			vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
-					LVDS_DUAL_LEFT_RIGHT_EN_SHIFT, 1,
-					false);
-		if (conn_state->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP)
-			vop2_mask_write(vop2, RK3568_DSP_IF_CTRL, EN_MASK,
-					LVDS_DUAL_SWAP_EN_SHIFT, 1, false);
-	}
 
 	if (conn_state->output_if & VOP_OUTPUT_IF_MIPI0) {
 		vop2_mask_write(vop2, RK3568_DSP_IF_EN, EN_MASK, MIPI0_EN_SHIFT,
@@ -3090,14 +3114,10 @@ static unsigned long rk3568_vop2_if_cfg(struct display_state *state)
 	}
 
 	if (conn_state->output_flags &
-	    ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) {
-		vop2_mask_write(vop2, RK3568_VP0_MIPI_CTRL + vp_offset, EN_MASK,
-				MIPI_DUAL_EN_SHIFT, 1, false);
-		if (conn_state->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP)
-			vop2_mask_write(vop2, RK3568_VP0_MIPI_CTRL + vp_offset,
-					EN_MASK, MIPI_DUAL_SWAP_EN_SHIFT, 1,
-					false);
-	}
+		    ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE ||
+	    conn_state->output_flags &
+		    ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE)
+		rk3568_vop2_setup_dual_channel_if(state);
 
 	if (conn_state->output_if & VOP_OUTPUT_IF_eDP0) {
 		vop2_mask_write(vop2, RK3568_DSP_IF_EN, EN_MASK, EDP0_EN_SHIFT,
@@ -3122,7 +3142,7 @@ static unsigned long rk3568_vop2_if_cfg(struct display_state *state)
 				IF_CRTL_HDMI_PIN_POL_SHIT, val, false);
 	}
 
-	return mode->clock;
+	return mode->crtc_clock;
 }
 
 static unsigned long rk3528_vop2_if_cfg(struct display_state *state)
@@ -3636,18 +3656,6 @@ static int rockchip_vop2_send_mcu_cmd(struct display_state *state, u32 type, u32
 	return 0;
 }
 
-static int vop2_get_vrefresh(struct display_state *state)
-{
-	struct crtc_state *cstate = &state->crtc_state;
-	struct connector_state *conn_state = &state->conn_state;
-	struct drm_display_mode *mode = &conn_state->mode;
-
-	if (cstate->mcu_timing.mcu_pix_total)
-		return mode->vrefresh / cstate->mcu_timing.mcu_pix_total;
-	else
-		return mode->vrefresh;
-}
-
 static void vop2_dither_setup(struct vop2 *vop2, int bus_format, int crtc_id)
 {
 	u32 vp_offset = crtc_id * 0x100;
@@ -3739,8 +3747,8 @@ static int rockchip_vop2_init(struct display_state *state)
 	printf("VOP update mode to: %dx%d%s%d, type:%s for VP%d\n",
 	       mode->crtc_hdisplay, mode->vdisplay,
 	       mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
-	       vop2_get_vrefresh(state),
-	       get_output_if_name(conn_state->output_if, output_type_name),
+	       mode->vrefresh,
+	       rockchip_get_output_if_name(conn_state->output_if, output_type_name),
 	       cstate->crtc_id);
 
 	if (mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) {
@@ -3771,8 +3779,9 @@ static int rockchip_vop2_init(struct display_state *state)
 	else if (vop2->version == VOP_VERSION_RK3562)
 		dclk_rate = rk3562_vop2_if_cfg(state);
 
-	if (conn_state->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
-	    !(cstate->feature & VOP_FEATURE_OUTPUT_10BIT))
+	if ((conn_state->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
+	     !(cstate->feature & VOP_FEATURE_OUTPUT_10BIT)) ||
+	    conn_state->output_if & VOP_OUTPUT_IF_BT656)
 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
 
 	vop2_post_color_swap(state);
@@ -3962,12 +3971,12 @@ static int rockchip_vop2_init(struct display_state *state)
 		       __func__, cstate->crtc_id, dclk_rate, ret);
 		return ret;
 	} else {
-		dclk_div_factor = mode->clock / dclk_rate;
-		if (vop2->version == VOP_VERSION_RK3528 &&
-		    conn_state->output_if & VOP_OUTPUT_IF_BT656)
-			mode->crtc_clock = ret / 4 / 1000;
-		else
-			mode->crtc_clock = ret * dclk_div_factor / 1000;
+		if (cstate->mcu_timing.mcu_pix_total) {
+			mode->crtc_clock = roundup(ret, 1000) / 1000;
+		} else {
+			dclk_div_factor = mode->crtc_clock / dclk_rate;
+			mode->crtc_clock = roundup(ret, 1000) * dclk_div_factor / 1000;
+		}
 		printf("VP%d set crtc_clock to %dKHz\n", cstate->crtc_id, mode->crtc_clock);
 	}
 
@@ -4005,12 +4014,30 @@ static void vop2_setup_scale(struct vop2 *vop2, struct vop2_win_data *win,
 		}
 	}
 
-	if (src_h >= (4 * dst_h)) {
-		ygt4 = 1;
-		src_h >>= 2;
-	} else if (src_h >= (2 * dst_h)) {
-		ygt2 = 1;
-		src_h >>= 1;
+	/**
+	 * The rk3528 is processed as 2 pixel/cycle,
+	 * so ygt2/ygt4 needs to be triggered in advance to improve performance
+	 * when src_w is bigger than 1920.
+	 * dst_h / src_h is at [1, 0.65)     ygt2=0; ygt4=0;
+	 * dst_h / src_h is at [0.65, 0.35)  ygt2=1; ygt4=0;
+	 * dst_h / src_h is at [0.35, 0)     ygt2=0; ygt4=1;
+	 */
+	if (vop2->version == VOP_VERSION_RK3528 && src_w > 1920) {
+		if (src_h >= (100 * dst_h / 35)) {
+			ygt4 = 1;
+			src_h >>= 2;
+		} else if ((src_h >= 100 * dst_h / 65) && (src_h < 100 * dst_h / 35)) {
+			ygt2 = 1;
+			src_h >>= 1;
+		}
+	} else {
+		if (src_h >= (4 * dst_h)) {
+			ygt4 = 1;
+			src_h >>= 2;
+		} else if (src_h >= (2 * dst_h)) {
+			ygt2 = 1;
+			src_h >>= 1;
+		}
 	}
 
 	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
@@ -4702,22 +4729,12 @@ static int rockchip_vop2_mode_fixup(struct display_state *state)
 	if (vop2->version == VOP_VERSION_RK3528 && conn_state->output_if & VOP_OUTPUT_IF_BT656)
 		mode->crtc_clock *= 4;
 
-	if (cstate->mcu_timing.mcu_pix_total) {
-		if (conn_state->output_mode == ROCKCHIP_OUT_MODE_S888)
-			/*
-			 * For serial output_mode rgb3x8, one pixel need 3 cycles.
-			 * So dclk should be three times mode clock.
-			 */
-			mode->crtc_clock *= 3;
-		else if (conn_state->output_mode == ROCKCHIP_OUT_MODE_S888_DUMMY)
-			/*
-			 * For serial output_mode argb4x8, one pixel need 4 cycles.
-			 * So dclk should be four times mode clock.
-			 */
-			mode->crtc_clock *= 4;
-	}
+	mode->crtc_clock *= rockchip_drm_get_cycles_per_pixel(conn_state->bus_format);
+	if (cstate->mcu_timing.mcu_pix_total)
+		mode->crtc_clock *= cstate->mcu_timing.mcu_pix_total + 1;
 
-	if (conn_state->secondary) {
+	if (conn_state->secondary &&
+	    conn_state->secondary->type != DRM_MODE_CONNECTOR_LVDS) {
 		mode->crtc_clock *= 2;
 		mode->crtc_hdisplay *= 2;
 		mode->crtc_hsync_start *= 2;
diff --git a/u-boot/drivers/video/drm/samsung_mipi_dcphy.c b/u-boot/drivers/video/drm/samsung_mipi_dcphy.c
index f4cae1f1c7..1310553947 100644
--- a/u-boot/drivers/video/drm/samsung_mipi_dcphy.c
+++ b/u-boot/drivers/video/drm/samsung_mipi_dcphy.c
@@ -1540,6 +1540,9 @@ static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung)
 	samsung_mipi_dphy_lane_enable(samsung);
 
 	reset_deassert(&samsung->m_phy_rst);
+
+	/* The Tskewcal maximum is 100 usec at initial calibration. */
+	udelay(100);
 }
 
 static void samsung_mipi_cphy_power_on(struct samsung_mipi_dcphy *samsung)
diff --git a/u-boot/env/envf.c b/u-boot/env/envf.c
index fc55afd0d4..a29351f37c 100644
--- a/u-boot/env/envf.c
+++ b/u-boot/env/envf.c
@@ -24,6 +24,12 @@ DECLARE_GLOBAL_DATA_PTR;
 #define BLK_CNT(desc, sz)	((sz) / (desc)->blksz)
 #define ENVF_MAX		64
 
+/*
+ * env_dev maybe: boot-device, sdcard.
+ *
+ * env_size/offset/offset_redund should be updated when env_dev changed.
+ */
+static u32 env_dev;
 static ulong env_size, env_offset, env_offset_redund;
 
 #if CONFIG_IS_ENABLED(ENV_PARTITION)
@@ -75,6 +81,9 @@ static int can_find_pmbr(struct blk_desc *dev_desc)
 
 static void envf_init_location(struct blk_desc *desc)
 {
+	if (env_dev == ((desc->if_type << 8) | desc->devnum))
+		return;
+
 	/* eMMC (default) */
 	env_size = CONFIG_ENV_SIZE;
 	env_offset = CONFIG_ENV_OFFSET;
@@ -99,6 +108,8 @@ static void envf_init_location(struct blk_desc *desc)
 #endif
 	if (env_offset == env_offset_redund)
 		env_offset_redund = 0;
+
+	env_dev = (desc->if_type << 8) | desc->devnum;
 }
 
 static int env_read(struct blk_desc *desc, u32 offset, u32 size, env_t **envp)
@@ -293,6 +304,8 @@ static int envf_save(void)
 		return -EINVAL;
 	}
 
+	envf_init_location(desc);
+
 	res = (char *)env->data;
 	len = hexport_r(&env_htab, '\0', H_MATCH_KEY | H_MATCH_IDENT,
 			&res, env_size - ENV_HEADER_SIZE,
diff --git a/u-boot/include/abuf.h b/u-boot/include/abuf.h
new file mode 100644
index 0000000000..d230f72806
--- /dev/null
+++ b/u-boot/include/abuf.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Handles a buffer that can be allocated and freed
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __ABUF_H
+#define __ABUF_H
+
+#include <linux/types.h>
+
+/**
+ * struct abuf - buffer that can be allocated and freed
+ *
+ * This is useful for a block of data which may be allocated with malloc(), or
+ * not, so that it needs to be freed correctly when finished with.
+ *
+ * For now it has a very simple purpose.
+ *
+ * Using memset() to zero all fields is guaranteed to be equivalent to
+ * abuf_init().
+ *
+ * @data: Pointer to data
+ * @size: Size of data in bytes
+ * @alloced: true if allocated with malloc(), so must be freed after use
+ */
+struct abuf {
+	void *data;
+	size_t size;
+	bool alloced;
+};
+
+static inline void *abuf_data(const struct abuf *abuf)
+{
+	return abuf->data;
+}
+
+static inline size_t abuf_size(const struct abuf *abuf)
+{
+	return abuf->size;
+}
+
+/**
+ * abuf_set() - set the (unallocated) data in a buffer
+ *
+ * This simply makes the abuf point to the supplied data, which must be live
+ * for the lifetime of the abuf. It is not alloced.
+ *
+ * Any existing data in the abuf is freed and the alloced member is set to
+ * false.
+ *
+ * @abuf: abuf to adjust
+ * @data: New contents of abuf
+ * @size: New size of abuf
+ */
+void abuf_set(struct abuf *abuf, void *data, size_t size);
+
+/**
+ * abuf_map_sysmem() - calls map_sysmem() to set up an abuf
+ *
+ * This is equivalent to abuf_set(abuf, map_sysmem(addr, size), size)
+ *
+ * Any existing data in the abuf is freed and the alloced member is set to
+ * false.
+ *
+ * @abuf: abuf to adjust
+ * @addr: Address to set the abuf to
+ * @size: New size of abuf
+ */
+void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size);
+
+/**
+ * abuf_realloc() - Change the size of a buffer
+ *
+ * This uses realloc() to change the size of the buffer, with the same semantics
+ * as that function. If the abuf is not currently alloced, then it will alloc
+ * it if the size needs to increase (i.e. set the alloced member to true)
+ *
+ * @abuf: abuf to adjust
+ * @new_size: new size in bytes.
+ *	if 0, the abuf is freed
+ *	if greater than the current size, the abuf is extended and the new
+ *	   space is not inited. The alloced member is set to true
+ *	if less than the current size, the abuf is contracted and the data at
+ *	   the end is lost. If @new_size is 0, this sets the alloced member to
+ *	   false
+ * @return true if OK, false if out of memory
+ */
+bool abuf_realloc(struct abuf *abuf, size_t new_size);
+
+/**
+ * abuf_uninit_move() - Return the allocated contents and uninit the abuf
+ *
+ * This returns the abuf data to the caller, allocating it if necessary, so that
+ * the caller receives data that it can be sure will hang around. The caller is
+ * responsible for freeing the data.
+ *
+ * If the abuf has allocated data, it is returned. If the abuf has data but it
+ * is not allocated, then it is first allocated, then returned.
+ *
+ * If the abuf size is 0, this returns NULL
+ *
+ * The abuf is uninited as part of this, except if the allocation fails, in
+ * which NULL is returned and the abuf remains untouched.
+ *
+ * The abuf must be inited before this can be called.
+ *
+ * @abuf: abuf to uninit
+ * @sizep: if non-NULL, returns the size of the returned data
+ * @return data contents, allocated with malloc(), or NULL if the data could not
+ *	be allocated, or the data size is 0
+ */
+void *abuf_uninit_move(struct abuf *abuf, size_t *sizep);
+
+/**
+ * abuf_init_move() - Make abuf take over the management of an allocated region
+ *
+ * After this, @data must not be used. All access must be via the abuf.
+ *
+ * @abuf: abuf to init
+ * @data: Existing allocated buffer to place in the abuf
+ * @size: Size of allocated buffer
+ */
+void abuf_init_move(struct abuf *abuf, void *data, size_t size);
+
+/**
+ * abuf_init_set() - Set up a new abuf
+ *
+ * Inits a new abuf and sets up its (unallocated) data
+ *
+ * @abuf: abuf to set up
+ * @data: New contents of abuf
+ * @size: New size of abuf
+ */
+void abuf_init_set(struct abuf *abuf, void *data, size_t size);
+
+/**
+ * abuf_uninit() - Free any memory used by an abuf
+ *
+ * The buffer must be inited before this can be called.
+ *
+ * @abuf: abuf to uninit
+ */
+void abuf_uninit(struct abuf *abuf);
+
+/**
+ * abuf_init() - Set up a new abuf
+ *
+ * This initially has no data and alloced is set to false. This is equivalent to
+ * setting all fields to 0, e.g. with memset(), so callers can do that instead
+ * if desired.
+ *
+ * @abuf: abuf to set up
+ */
+void abuf_init(struct abuf *abuf);
+
+#endif
diff --git a/u-boot/include/attestation_key.h b/u-boot/include/attestation_key.h
index 87b3abb89c..4a4e56f423 100644
--- a/u-boot/include/attestation_key.h
+++ b/u-boot/include/attestation_key.h
@@ -21,6 +21,7 @@ typedef enum {
 	ATAP_RESULT_ERROR_INVALID_DEVICE_ID,
 	ATAP_RESULT_ERROR_BUF_COPY,
 	ATAP_RESULT_ERROR_STORAGE,
+	ATAP_RESULT_ERROR_ALREADY_EXSIT,
 } atap_result;
 
 /* load attestation key from misc partition. */
diff --git a/u-boot/include/configs/rk3528_common.h b/u-boot/include/configs/rk3528_common.h
index ad81095a1a..78548bd36f 100644
--- a/u-boot/include/configs/rk3528_common.h
+++ b/u-boot/include/configs/rk3528_common.h
@@ -7,6 +7,8 @@
 #ifndef __CONFIG_RK3528_COMMON_H
 #define __CONFIG_RK3528_COMMON_H
 
+#define CFG_CPUID_OFFSET		0xa
+
 #include "rockchip-common.h"
 
 #define CONFIG_SPL_FRAMEWORK
@@ -71,6 +73,7 @@
 /* usb mass storage */
 #define CONFIG_USB_FUNCTION_MASS_STORAGE
 #define CONFIG_ROCKUSB_G_DNL_PID	0x350c
+#define ROCKUSB_FSG_BUFLEN		0x400000
 
 #ifdef CONFIG_ARM64
 #define ENV_MEM_LAYOUT_SETTINGS \
diff --git a/u-boot/include/configs/rk3562_common.h b/u-boot/include/configs/rk3562_common.h
index b076f90d6b..6d618db25e 100644
--- a/u-boot/include/configs/rk3562_common.h
+++ b/u-boot/include/configs/rk3562_common.h
@@ -7,6 +7,8 @@
 #ifndef __CONFIG_RK3562_COMMON_H
 #define __CONFIG_RK3562_COMMON_H
 
+#define CFG_CPUID_OFFSET		0xa
+
 #include "rockchip-common.h"
 
 #define CONFIG_SPL_FRAMEWORK
diff --git a/u-boot/include/configs/rk3568_common.h b/u-boot/include/configs/rk3568_common.h
index 7a9d53bc9c..d963e3ac77 100644
--- a/u-boot/include/configs/rk3568_common.h
+++ b/u-boot/include/configs/rk3568_common.h
@@ -7,6 +7,8 @@
 #ifndef __CONFIG_RK3568_COMMON_H
 #define __CONFIG_RK3568_COMMON_H
 
+#define CFG_CPUID_OFFSET		0xa
+
 #include "rockchip-common.h"
 
 #define CONFIG_SPL_FRAMEWORK
@@ -58,6 +60,7 @@
 					 CONFIG_SYS_SCSI_MAX_LUN)
 #endif
 /* Nand */
+#define CONFIG_SYS_NAND_BASE		0xFE330000
 #define CONFIG_SYS_MAX_NAND_DEVICE	1
 #define CONFIG_SYS_NAND_ONFI_DETECTION
 #define CONFIG_SYS_NAND_PAGE_SIZE	2048
diff --git a/u-boot/include/configs/rk3588_common.h b/u-boot/include/configs/rk3588_common.h
index 1399468985..67a816a33f 100644
--- a/u-boot/include/configs/rk3588_common.h
+++ b/u-boot/include/configs/rk3588_common.h
@@ -23,7 +23,12 @@
 #define CONFIG_SYS_MALLOC_LEN		(32 << 20)
 #define CONFIG_SYS_CBSIZE		1024
 #define CONFIG_SKIP_LOWLEVEL_INIT
+
+#ifdef CONFIG_SUPPORT_USBPLUG
+#define CONFIG_SYS_TEXT_BASE		0x00000000
+#else
 #define CONFIG_SYS_TEXT_BASE		0x00200000
+#endif
 
 #define CONFIG_SYS_INIT_SP_ADDR		0x00600000
 #define CONFIG_SYS_LOAD_ADDR		0x00600800
@@ -54,6 +59,7 @@
 /* usb mass storage */
 #define CONFIG_USB_FUNCTION_MASS_STORAGE
 #define CONFIG_ROCKUSB_G_DNL_PID	0x350b
+#define ROCKUSB_FSG_BUFLEN		0x400000
 
 /*
  * decompressed kernel:  4M ~ 84M
diff --git a/u-boot/include/configs/rockchip-common.h b/u-boot/include/configs/rockchip-common.h
index 002dcd60c2..f12af5d6b0 100644
--- a/u-boot/include/configs/rockchip-common.h
+++ b/u-boot/include/configs/rockchip-common.h
@@ -8,6 +8,10 @@
 #define _ROCKCHIP_COMMON_H_
 #include <linux/sizes.h>
 
+#ifndef CFG_CPUID_OFFSET
+#define CFG_CPUID_OFFSET		0x7
+#endif
+
 #define COUNTER_FREQUENCY               24000000
 
 #if CONFIG_IS_ENABLED(TINY_FRAMEWORK) && !defined(CONFIG_ARM64)
diff --git a/u-boot/include/configs/rv1106_common.h b/u-boot/include/configs/rv1106_common.h
index 0b4f77f749..dc927a8f36 100644
--- a/u-boot/include/configs/rv1106_common.h
+++ b/u-boot/include/configs/rv1106_common.h
@@ -7,6 +7,8 @@
 #ifndef __CONFIG_RV1106_COMMON_H
 #define __CONFIG_RV1106_COMMON_H
 
+#define CFG_CPUID_OFFSET		0xa
+
 #include "rockchip-common.h"
 
 #define COUNTER_FREQUENCY		24000000
@@ -14,7 +16,11 @@
 #define CONFIG_SYS_CBSIZE		1024
 #define CONFIG_SYS_NS16550_MEM32
 
+#ifdef CONFIG_SUPPORT_USBPLUG
+#define CONFIG_SYS_TEXT_BASE		0x00000000
+#else
 #define CONFIG_SYS_TEXT_BASE		0x00200000
+#endif
 #define CONFIG_SYS_INIT_SP_ADDR		0x00400000
 #define CONFIG_SYS_LOAD_ADDR		0x00e00800
 #define CONFIG_SYS_BOOTM_LEN		(64 << 20)
@@ -29,7 +35,7 @@
 /* SPL */
 #define CONFIG_SPL_FRAMEWORK
 #define CONFIG_SPL_TEXT_BASE		0x00000000
-#define CONFIG_SPL_MAX_SIZE		0x30000
+#define CONFIG_SPL_MAX_SIZE		0x28000
 #define CONFIG_SPL_BSS_START_ADDR	0x001fe000
 #define CONFIG_SPL_BSS_MAX_SIZE		0x20000
 #define CONFIG_SPL_STACK		0x001fe000
diff --git a/u-boot/include/dm/pinctrl.h b/u-boot/include/dm/pinctrl.h
index 0bcf30d6e6..05e0fce3b3 100644
--- a/u-boot/include/dm/pinctrl.h
+++ b/u-boot/include/dm/pinctrl.h
@@ -7,6 +7,9 @@
 #ifndef __PINCTRL_H
 #define __PINCTRL_H
 
+#define PINNAME_SIZE	10
+#define PINMUX_SIZE	40
+
 /**
  * struct pinconf_param - pin config parameters
  *
@@ -32,29 +35,33 @@ struct pinconf_param {
  * depending on your necessity.
  *
  * @get_pins_count: return number of selectable named pins available
- *	in this driver.  (necessary to parse "pins" property in DTS)
+ *	in this driver. (necessary to parse "pins" property in DTS)
  * @get_pin_name: return the pin name of the pin selector,
  *	called by the core to figure out which pin it shall do
- *	operations to.  (necessary to parse "pins" property in DTS)
+ *	operations to. (necessary to parse "pins" property in DTS)
  * @get_groups_count: return number of selectable named groups available
- *	in this driver.  (necessary to parse "groups" property in DTS)
+ *	in this driver. (necessary to parse "groups" property in DTS)
  * @get_group_name: return the group name of the group selector,
  *	called by the core to figure out which pin group it shall do
- *	operations to.  (necessary to parse "groups" property in DTS)
+ *	operations to. (necessary to parse "groups" property in DTS)
  * @get_functions_count: return number of selectable named functions available
- *	in this driver.  (necessary for pin-muxing)
+ *	in this driver. (necessary for pin-muxing)
  * @get_function_name: return the function name of the muxing selector,
  *	called by the core to figure out which mux setting it shall map a
- *	certain device to.  (necessary for pin-muxing)
+ *	certain device to. (necessary for pin-muxing)
  * @pinmux_set: enable a certain muxing function with a certain pin.
  *	The @func_selector selects a certain function whereas @pin_selector
  *	selects a certain pin to be used. On simple controllers one of them
- *	may be ignored.  (necessary for pin-muxing against a single pin)
+ *	may be ignored. (necessary for pin-muxing against a single pin)
  * @pinmux_group_set: enable a certain muxing function with a certain pin
- *	group.  The @func_selector selects a certain function whereas
+ *	group. The @func_selector selects a certain function whereas
  *	@group_selector selects a certain set of pins to be used. On simple
  *	controllers one of them may be ignored.
  *	(necessary for pin-muxing against a pin group)
+ * @pinmux_property_set: enable a pinmux group. @pinmux_group should specify the
+ *      pin identifier and mux settings. The exact format of a pinmux group is
+ *      left up to the driver. The pin selector for the mux-ed pin should be
+ *      returned on success. (necessary to parse the "pinmux" property in DTS)
  * @pinconf_num_params: number of driver-specific parameters to be parsed
  *	from device trees  (necessary for pin-configuration)
  * @pinconf_params: list of driver_specific parameters to be parsed from
@@ -67,6 +74,14 @@ struct pinconf_param {
  *	pointing a config node. (necessary for pinctrl_full)
  * @set_state_simple: do needed pinctrl operations for a peripherl @periph.
  *	(necessary for pinctrl_simple)
+ * @get_pin_muxing: display the muxing of a given pin.
+ * @gpio_request_enable: requests and enables GPIO on a certain pin.
+ *	Implement this only if you can mux every pin individually as GPIO. The
+ *	affected GPIO range is passed along with an offset(pin number) into that
+ *	specific GPIO range - function selectors and pin groups are orthogonal
+ *	to this, the core will however make sure the pins do not collide.
+ * @gpio_disable_free: free up GPIO muxing on a certain pin, the reverse of
+ *	@gpio_request_enable
  */
 struct pinctrl_ops {
 	int (*get_pins_count)(struct udevice *dev);
@@ -80,6 +95,7 @@ struct pinctrl_ops {
 			  unsigned func_selector);
 	int (*pinmux_group_set)(struct udevice *dev, unsigned group_selector,
 				unsigned func_selector);
+	int (*pinmux_property_set)(struct udevice *dev, u32 pinmux_group);
 	unsigned int pinconf_num_params;
 	const struct pinconf_param *pinconf_params;
 	int (*pinconf_set)(struct udevice *dev, unsigned pin_selector,
@@ -130,6 +146,42 @@ struct pinctrl_ops {
 	* @return mux value (SoC-specific, e.g. 0 for input, 1 for output)
 	 */
 	int (*get_gpio_mux)(struct udevice *dev, int banknum, int index);
+
+	/**
+	 * get_pin_muxing() - show pin muxing
+	 *
+	 * This allows to display the muxing of a given pin. It's useful for
+	 * debug purpose to know if a pin is configured as GPIO or as an
+	 * alternate function and which one.
+	 * Typically it is used by a PINCTRL driver with knowledge of the SoC
+	 * pinctrl setup.
+	 *
+	 * @dev:	Pinctrl device to use
+	 * @selector:	Pin selector
+	 * @buf		Pin's muxing description
+	 * @size	Pin's muxing description length
+	 * return 0 if OK, -ve on error
+	 */
+	 int (*get_pin_muxing)(struct udevice *dev, unsigned int selector,
+			       char *buf, int size);
+
+	/**
+	 * gpio_request_enable: requests and enables GPIO on a certain pin.
+	 *
+	 * @dev:	Pinctrl device to use
+	 * @selector:	Pin selector
+	 * return 0 if OK, -ve on error
+	 */
+	int (*gpio_request_enable)(struct udevice *dev, unsigned int selector);
+
+	/**
+	 * gpio_disable_free: free up GPIO muxing on a certain pin.
+	 *
+	 * @dev:	Pinctrl device to use
+	 * @selector:	Pin selector
+	 * return 0 if OK, -ve on error
+	 */
+	int (*gpio_disable_free)(struct udevice *dev, unsigned int selector);
 };
 
 #define pinctrl_get_ops(dev)	((struct pinctrl_ops *)(dev)->driver->ops)
@@ -331,6 +383,53 @@ int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index);
  * @return pins count
 */
 int pinctrl_get_pins_count(struct udevice *dev);
+
+/**
+ * pinctrl_get_pin_name() - Returns the pin's name
+ *
+ * This allows to display the pin's name for debug purpose
+ *
+ * @dev:	Pinctrl device to use
+ * @selector	Pin index within pin-controller
+ * @buf		Pin's name
+ * @return 0 if OK, -ve on error
+ */
+int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf,
+			 int size);
+
+/**
+ * pinctrl_get_pin_muxing() - Returns the muxing description
+ *
+ * This allows to display the muxing description of the given pin for
+ * debug purpose
+ *
+ * @dev:	Pinctrl device to use
+ * @selector	Pin index within pin-controller
+ * @buf		Pin's muxing description
+ * @size	Pin's muxing description length
+ * @return 0 if OK, -ve on error
+ */
+int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf,
+			   int size);
+
+/**
+ * pinctrl_gpio_request() - request a single pin to be used as GPIO
+ *
+ * @dev: GPIO peripheral device
+ * @offset: the GPIO pin offset from the GPIO controller
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_gpio_request(struct udevice *dev, unsigned offset);
+
+/**
+ * pinctrl_gpio_free() - free a single pin used as GPIO
+ *
+ * @dev: GPIO peripheral device
+ * @offset: the GPIO pin offset from the GPIO controller
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_gpio_free(struct udevice *dev, unsigned offset);
+
 #else
 static inline int pinctrl_select_state(struct udevice *dev,
 				       const char *statename)
@@ -367,6 +466,29 @@ static inline int pinctrl_get_pins_count(struct udevice *dev)
 {
 	return -EINVAL;
 }
+
+static inline int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf,
+			 int size)
+{
+	return -EINVAL;
+}
+
+static inline int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf,
+			   int size)
+{
+	return -EINVAL;
+}
+
+static inline int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
+{
+	return -EINVAL;
+}
+
+static inline int pinctrl_gpio_free(struct udevice *dev, unsigned offset)
+{
+	return -EINVAL;
+}
+
 #endif
 
 #endif /* __PINCTRL_H */
diff --git a/u-boot/include/dm/test.h b/u-boot/include/dm/test.h
index cecee26f33..6ad83d1489 100644
--- a/u-boot/include/dm/test.h
+++ b/u-boot/include/dm/test.h
@@ -57,6 +57,8 @@ enum {
 enum {
 	DM_TEST_TYPE_FIRST = 0,
 	DM_TEST_TYPE_SECOND,
+
+	DM_TEST_TYPE_COUNT,
 };
 
 /* The number added to the ping total on each probe */
diff --git a/u-boot/include/dm/uclass.h b/u-boot/include/dm/uclass.h
index aafeb80c2c..6f86106790 100644
--- a/u-boot/include/dm/uclass.h
+++ b/u-boot/include/dm/uclass.h
@@ -267,17 +267,31 @@ int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
  * uclass_first_device() - Get the first device in a uclass
  *
  * The device returned is probed if necessary, and ready for use
+ * Devices that fail to probe are skipped
  *
  * This function is useful to start iterating through a list of devices which
  * are functioning correctly and can be probed.
  *
  * @id: Uclass ID to look up
  * @devp: Returns pointer to the first device in that uclass if no error
- * occurred, or NULL if there is no first device, or an error occurred with
- * that device.
- * @return 0 if OK (found or not found), other -ve on error
+ * occurred, or NULL if there is no usable device
  */
-int uclass_first_device(enum uclass_id id, struct udevice **devp);
+void uclass_first_device(enum uclass_id id, struct udevice **devp);
+
+/**
+ * uclass_next_device() - Get the next device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use
+ * Devices that fail to probe are skipped
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly and can be probed.
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the uclass if no error occurred, or NULL if there is
+ * no next device
+ */
+void uclass_next_device(struct udevice **devp);
 
 /**
  * uclass_first_device_err() - Get the first device in a uclass
@@ -286,27 +300,24 @@ int uclass_first_device(enum uclass_id id, struct udevice **devp);
  *
  * @id: Uclass ID to look up
  * @devp: Returns pointer to the first device in that uclass, or NULL if none
- * @return 0 if found, -ENODEV if not found, other -ve on error
+ * Return: 0 if found, -ENODEV if not found, other -ve on error
  */
 int uclass_first_device_err(enum uclass_id id, struct udevice **devp);
 
 /**
- * uclass_next_device() - Get the next device in a uclass
+ * uclass_next_device_err() - Get the next device in a uclass
  *
  * The device returned is probed if necessary, and ready for use
  *
- * This function is useful to start iterating through a list of devices which
- * are functioning correctly and can be probed.
- *
  * @devp: On entry, pointer to device to lookup. On exit, returns pointer
- * to the next device in the uclass if no error occurred, or NULL if there is
- * no next device, or an error occurred with that next device.
- * @return 0 if OK (found or not found), other -ve on error
+ * to the next device in the uclass if no error occurred, or -ENODEV if
+ * there is no next device.
+ * @return 0 if found, -ENODEV if not found, other -ve on error
  */
-int uclass_next_device(struct udevice **devp);
+int uclass_next_device_err(struct udevice **devp);
 
 /**
- * uclass_first_device() - Get the first device in a uclass
+ * uclass_first_device_check() - Get the first device in a uclass
  *
  * The device returned is probed if necessary, and ready for use
  *
@@ -322,7 +333,7 @@ int uclass_next_device(struct udevice **devp);
 int uclass_first_device_check(enum uclass_id id, struct udevice **devp);
 
 /**
- * uclass_next_device() - Get the next device in a uclass
+ * uclass_next_device_check() - Get the next device in a uclass
  *
  * The device returned is probed if necessary, and ready for use
  *
@@ -336,6 +347,20 @@ int uclass_first_device_check(enum uclass_id id, struct udevice **devp);
  */
 int uclass_next_device_check(struct udevice **devp);
 
+/**
+ * uclass_first_device_drvdata() - Find the first device with given driver data
+ *
+ * This searches through the devices for a particular uclass looking for one
+ * that has the given driver data.
+ *
+ * @id: Uclass ID to check
+ * @driver_data: Driver data to search for
+ * @devp: Returns pointer to the first matching device in that uclass, if found
+ * @return 0 if found, -ENODEV if not found, other -ve on error
+ */
+int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
+				struct udevice **devp);
+
 /**
  * uclass_resolve_seq() - Resolve a device's sequence number
  *
@@ -351,6 +376,23 @@ int uclass_next_device_check(struct udevice **devp);
  */
 int uclass_resolve_seq(struct udevice *dev);
 
+/**
+ * uclass_id_foreach_dev() - Helper function to iteration through devices
+ *
+ * This creates a for() loop which works through the available devices in
+ * a uclass ID in order from start to end.
+ *
+ * If for some reason the uclass cannot be found, this does nothing.
+ *
+ * @id: enum uclass_id ID to use
+ * @pos: struct udevice * to hold the current device. Set to NULL when there
+ * are no more devices.
+ * @uc: temporary uclass variable (struct udevice *)
+ */
+#define uclass_id_foreach_dev(id, pos, uc) \
+	if (!uclass_get(id, &uc)) \
+		list_for_each_entry(pos, &uc->dev_head, uclass_node)
+
 /**
  * uclass_foreach_dev() - Helper function to iteration through devices
  *
@@ -379,4 +421,20 @@ int uclass_resolve_seq(struct udevice *dev);
 #define uclass_foreach_dev_safe(pos, next, uc)	\
 	list_for_each_entry_safe(pos, next, &uc->dev_head, uclass_node)
 
+/**
+ * uclass_foreach_dev_probe() - Helper function to iteration through devices
+ * of given uclass
+ *
+ * This creates a for() loop which works through the available devices in
+ * a uclass in order from start to end. Devices are probed if necessary,
+ * and ready for use.
+ *
+ * @id: Uclass ID
+ * @dev: struct udevice * to hold the current device. Set to NULL when there
+ * are no more devices.
+ */
+#define uclass_foreach_dev_probe(id, dev)	\
+	for (int _ret = uclass_first_device_err(id, &dev); !_ret && dev; \
+	     _ret = uclass_next_device_err(&dev))
+
 #endif
diff --git a/u-boot/include/drm_modes.h b/u-boot/include/drm_modes.h
index a79dfdfada..00fb3169c2 100644
--- a/u-boot/include/drm_modes.h
+++ b/u-boot/include/drm_modes.h
@@ -78,6 +78,53 @@
 #define  DRM_MODE_FLAG_PIC_AR_256_135 \
 			(DRM_MODE_PICTURE_ASPECT_256_135 << 19)
 
+/*
+ * DRM_MODE_ROTATE_<degrees>
+ *
+ * Signals that a drm plane is been rotated <degrees> degrees in counter
+ * clockwise direction.
+ *
+ * This define is provided as a convenience, looking up the property id
+ * using the name->prop id lookup is the preferred method.
+ */
+#define DRM_MODE_ROTATE_0       (1<<0)
+#define DRM_MODE_ROTATE_90      (1<<1)
+#define DRM_MODE_ROTATE_180     (1<<2)
+#define DRM_MODE_ROTATE_270     (1<<3)
+
+/*
+ * DRM_MODE_ROTATE_MASK
+ *
+ * Bitmask used to look for drm plane rotations.
+ */
+#define DRM_MODE_ROTATE_MASK (\
+		DRM_MODE_ROTATE_0  | \
+		DRM_MODE_ROTATE_90  | \
+		DRM_MODE_ROTATE_180 | \
+		DRM_MODE_ROTATE_270)
+
+/*
+ * DRM_MODE_REFLECT_<axis>
+ *
+ * Signals that the contents of a drm plane is reflected along the <axis> axis,
+ * in the same way as mirroring.
+ * See kerneldoc chapter "Plane Composition Properties" for more details.
+ *
+ * This define is provided as a convenience, looking up the property id
+ * using the name->prop id lookup is the preferred method.
+ */
+#define DRM_MODE_REFLECT_X      (1<<4)
+#define DRM_MODE_REFLECT_Y      (1<<5)
+
+/*
+ * DRM_MODE_REFLECT_MASK
+ *
+ * Bitmask used to look for drm plane reflections.
+ */
+#define DRM_MODE_REFLECT_MASK (\
+		DRM_MODE_REFLECT_X | \
+		DRM_MODE_REFLECT_Y)
+
 #define DRM_MODE_CONNECTOR_Unknown	0
 #define DRM_MODE_CONNECTOR_VGA		1
 #define DRM_MODE_CONNECTOR_DVII		2
diff --git a/u-boot/include/dt-bindings/clock/rk3308-cru.h b/u-boot/include/dt-bindings/clock/rk3308-cru.h
index 5f4a34bc0c..ad8c7b9157 100644
--- a/u-boot/include/dt-bindings/clock/rk3308-cru.h
+++ b/u-boot/include/dt-bindings/clock/rk3308-cru.h
@@ -36,7 +36,7 @@
 #define SCLK_I2C1		23
 #define SCLK_I2C2		24
 #define SCLK_I2C3		25
-#define SCLK_PWM		26
+#define SCLK_PWM0		26
 #define SCLK_SPI0		27
 #define SCLK_SPI1		28
 #define SCLK_SPI2		29
@@ -130,6 +130,8 @@
 #define SCLK_I2S3_8CH_RX_SRC	117
 #define SCLK_I2S0_2CH_SRC	118
 #define SCLK_I2S1_2CH_SRC	119
+#define SCLK_PWM1		120
+#define SCLK_PWM2		121
 
 /* dclk */
 #define DCLK_VOP		125
diff --git a/u-boot/include/edid.h b/u-boot/include/edid.h
index 0967912b54..b10a6765db 100644
--- a/u-boot/include/edid.h
+++ b/u-boot/include/edid.h
@@ -1018,6 +1018,8 @@ int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
 int edid_get_drm_mode(u8 *buf, int buf_size, struct drm_display_mode *mode,
 		      int *panel_bits_per_colourp);
 int drm_add_edid_modes(struct hdmi_edid_data *data, u8 *edid);
+void drm_add_hdmi_modes(struct hdmi_edid_data *data,
+			const struct drm_display_mode *mode);
 bool drm_detect_hdmi_monitor(struct edid *edid);
 bool drm_detect_monitor_audio(struct edid *edid);
 int do_cea_modes(struct hdmi_edid_data *data, const u8 *db, u8 len);
diff --git a/u-boot/include/elf.h b/u-boot/include/elf.h
index fe2128f378..1ce323bbdc 100644
--- a/u-boot/include/elf.h
+++ b/u-boot/include/elf.h
@@ -1,35 +1,27 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
 /*
  * Copyright (c) 1995, 1996, 2001, 2002
  * Erik Theisen.  All rights reserved.
- *
- * SPDX-License-Identifier:	BSD-3-Clause
  */
 
-/*
- * This is the ELF ABI header file
- * formerly known as "elf_abi.h".
- */
+/* This is the ELF ABI header file formerly known as "elf_abi.h" */
 
 #ifndef _ELF_H
 #define _ELF_H
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 #include "compiler.h"
 
-/*
- *  This version doesn't work for 64-bit ABIs - Erik.
- */
+/* This version doesn't work for 64-bit ABIs - Erik */
 
-/*
- * These typedefs need to be handled better.
- */
+/* These typedefs need to be handled better */
 typedef uint32_t	Elf32_Addr;	/* Unsigned program address */
 typedef uint32_t	Elf32_Off;	/* Unsigned file offset */
 typedef int32_t		Elf32_Sword;	/* Signed large integer */
 typedef uint32_t	Elf32_Word;	/* Unsigned large integer */
 typedef uint16_t	Elf32_Half;	/* Unsigned medium integer */
 
-/* 64-bit ELF base types. */
+/* 64-bit ELF base types */
 typedef uint64_t	Elf64_Addr;
 typedef uint16_t	Elf64_Half;
 typedef int16_t		Elf64_SHalf;
@@ -96,7 +88,7 @@ typedef int64_t		Elf64_Sxword;
 		      (ehdr).e_ident[EI_MAG3] == ELFMAG3)
 
 /* ELF Header */
-typedef struct elfhdr{
+typedef struct {
 	unsigned char	e_ident[EI_NIDENT]; /* ELF Identification */
 	Elf32_Half	e_type;		/* object file type */
 	Elf32_Half	e_machine;	/* machine */
@@ -114,6 +106,24 @@ typedef struct elfhdr{
 					   header string table" entry offset */
 } Elf32_Ehdr;
 
+typedef struct {
+	unsigned char	e_ident[EI_NIDENT]; /* ELF Identification */
+	Elf64_Half	e_type;		/* object file type */
+	Elf64_Half	e_machine;	/* machine */
+	Elf64_Word	e_version;	/* object file version */
+	Elf64_Addr	e_entry;	/* virtual entry point */
+	Elf64_Off	e_phoff;	/* program header table offset */
+	Elf64_Off	e_shoff;	/* section header table offset */
+	Elf64_Word	e_flags;	/* processor-specific flags */
+	Elf64_Half	e_ehsize;	/* ELF header size */
+	Elf64_Half	e_phentsize;	/* program header entry size */
+	Elf64_Half	e_phnum;	/* number of program header entries */
+	Elf64_Half	e_shentsize;	/* section header entry size */
+	Elf64_Half	e_shnum;	/* number of section header entries */
+	Elf64_Half	e_shstrndx;	/* section header table's "section
+					   header string table" entry offset */
+} Elf64_Ehdr;
+
 /* e_type */
 #define ET_NONE		0		/* No file type */
 #define ET_REL		1		/* relocatable file */
@@ -122,9 +132,9 @@ typedef struct elfhdr{
 #define ET_CORE		4		/* core file */
 #define ET_NUM		5		/* number of types */
 #define ET_LOOS		0xfe00		/* reserved range for operating */
-#define ET_HIOS		0xfeff		/*  system specific e_type */
+#define ET_HIOS		0xfeff		/* system specific e_type */
 #define ET_LOPROC	0xff00		/* reserved range for processor */
-#define ET_HIPROC	0xffff		/*  specific e_type */
+#define ET_HIPROC	0xffff		/* specific e_type */
 
 /* e_machine */
 #define EM_NONE		0		/* No Machine */
@@ -178,14 +188,14 @@ typedef struct elfhdr{
 #define EM_NDR1		57		/* Denso NDR1 microprocessor */
 #define EM_STARCORE	58		/* Motorola Start*Core processor */
 #define EM_ME16		59		/* Toyota ME16 processor */
-#define EM_ST100	60		/* STMicroelectronic ST100 processor */
+#define EM_ST100	60		/* STMicroelectronics ST100 processor */
 #define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
 #define EM_X86_64	62		/* AMD x86-64 */
 #define EM_PDSP		63		/* Sony DSP Processor */
 /* RESERVED 64,65 for future use */
 #define EM_FX66		66		/* Siemens FX66 microcontroller */
 #define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
-#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
+#define EM_ST7		68		/* STMicroelectronics ST7 8 bit mc */
 #define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
 #define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
 #define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
@@ -231,13 +241,27 @@ typedef struct {
 	Elf32_Word	sh_entsize;	/* section entry size */
 } Elf32_Shdr;
 
+typedef struct {
+	Elf64_Word	sh_name;	/* name - index into section header
+					   string table section */
+	Elf64_Word	sh_type;	/* type */
+	Elf64_Xword	sh_flags;	/* flags */
+	Elf64_Addr	sh_addr;	/* address */
+	Elf64_Off	sh_offset;	/* file offset */
+	Elf64_Xword	sh_size;	/* section size */
+	Elf64_Word	sh_link;	/* section header table index link */
+	Elf64_Word	sh_info;	/* extra information */
+	Elf64_Xword	sh_addralign;	/* address alignment */
+	Elf64_Xword	sh_entsize;	/* section entry size */
+} Elf64_Shdr;
+
 /* Special Section Indexes */
 #define SHN_UNDEF	0		/* undefined */
 #define SHN_LORESERVE	0xff00		/* lower bounds of reserved indexes */
 #define SHN_LOPROC	0xff00		/* reserved range for processor */
-#define SHN_HIPROC	0xff1f		/*   specific section indexes */
+#define SHN_HIPROC	0xff1f		/* specific section indexes */
 #define SHN_LOOS	0xff20		/* reserved range for operating */
-#define SHN_HIOS	0xff3f		/*   specific semantics */
+#define SHN_HIOS	0xff3f		/* specific semantics */
 #define SHN_ABS		0xfff1		/* absolute value */
 #define SHN_COMMON	0xfff2		/* common symbol */
 #define SHN_XINDEX	0xffff		/* Index is an extra table */
@@ -265,46 +289,46 @@ typedef struct {
 #define SHT_LOOS	0x60000000	/* Start OS-specific */
 #define SHT_HIOS	0x6fffffff	/* End OS-specific */
 #define SHT_LOPROC	0x70000000	/* reserved range for processor */
-#define SHT_HIPROC	0x7fffffff	/*  specific section header types */
+#define SHT_HIPROC	0x7fffffff	/* specific section header types */
 #define SHT_LOUSER	0x80000000	/* reserved range for application */
-#define SHT_HIUSER	0xffffffff	/*  specific indexes */
+#define SHT_HIUSER	0xffffffff	/* specific indexes */
 
 /* Section names */
-#define ELF_BSS         ".bss"		/* uninitialized data */
+#define ELF_BSS		".bss"		/* uninitialized data */
 #define ELF_COMMENT	".comment"	/* version control information */
-#define ELF_DATA        ".data"		/* initialized data */
-#define ELF_DATA1       ".data1"	/* initialized data */
-#define ELF_DEBUG       ".debug"	/* debug */
-#define ELF_DYNAMIC     ".dynamic"	/* dynamic linking information */
-#define ELF_DYNSTR      ".dynstr"	/* dynamic string table */
-#define ELF_DYNSYM      ".dynsym"	/* dynamic symbol table */
-#define ELF_FINI        ".fini"		/* termination code */
+#define ELF_DATA	".data"		/* initialized data */
+#define ELF_DATA1	".data1"	/* initialized data */
+#define ELF_DEBUG	".debug"	/* debug */
+#define ELF_DYNAMIC	".dynamic"	/* dynamic linking information */
+#define ELF_DYNSTR	".dynstr"	/* dynamic string table */
+#define ELF_DYNSYM	".dynsym"	/* dynamic symbol table */
+#define ELF_FINI	".fini"		/* termination code */
 #define ELF_FINI_ARRAY	".fini_array"	/* Array of destructors */
-#define ELF_GOT         ".got"		/* global offset table */
-#define ELF_HASH        ".hash"		/* symbol hash table */
-#define ELF_INIT        ".init"		/* initialization code */
+#define ELF_GOT		".got"		/* global offset table */
+#define ELF_HASH	".hash"		/* symbol hash table */
+#define ELF_INIT	".init"		/* initialization code */
 #define ELF_INIT_ARRAY	".init_array"	/* Array of constuctors */
 #define ELF_INTERP	".interp"	/* Pathname of program interpreter */
 #define ELF_LINE	".line"		/* Symbolic line numnber information */
 #define ELF_NOTE	".note"		/* Contains note section */
 #define ELF_PLT		".plt"		/* Procedure linkage table */
 #define ELF_PREINIT_ARRAY ".preinit_array" /* Array of pre-constructors */
-#define ELF_REL_DATA    ".rel.data"	/* relocation data */
-#define ELF_REL_FINI    ".rel.fini"	/* relocation termination code */
-#define ELF_REL_INIT    ".rel.init"	/* relocation initialization code */
-#define ELF_REL_DYN     ".rel.dyn"	/* relocaltion dynamic link info */
-#define ELF_REL_RODATA  ".rel.rodata"	/* relocation read-only data */
-#define ELF_REL_TEXT    ".rel.text"	/* relocation code */
-#define ELF_RODATA      ".rodata"	/* read-only data */
-#define ELF_RODATA1     ".rodata1"	/* read-only data */
-#define ELF_SHSTRTAB    ".shstrtab"	/* section header string table */
-#define ELF_STRTAB      ".strtab"	/* string table */
-#define ELF_SYMTAB      ".symtab"	/* symbol table */
+#define ELF_REL_DATA	".rel.data"	/* relocation data */
+#define ELF_REL_FINI	".rel.fini"	/* relocation termination code */
+#define ELF_REL_INIT	".rel.init"	/* relocation initialization code */
+#define ELF_REL_DYN	".rel.dyn"	/* relocaltion dynamic link info */
+#define ELF_REL_RODATA	".rel.rodata"	/* relocation read-only data */
+#define ELF_REL_TEXT	".rel.text"	/* relocation code */
+#define ELF_RODATA	".rodata"	/* read-only data */
+#define ELF_RODATA1	".rodata1"	/* read-only data */
+#define ELF_SHSTRTAB	".shstrtab"	/* section header string table */
+#define ELF_STRTAB	".strtab"	/* string table */
+#define ELF_SYMTAB	".symtab"	/* symbol table */
 #define ELF_SYMTAB_SHNDX ".symtab_shndx"/* symbol table section index */
 #define ELF_TBSS	".tbss"		/* thread local uninit data */
 #define ELF_TDATA	".tdata"	/* thread local init data */
 #define ELF_TDATA1	".tdata1"	/* thread local init data */
-#define ELF_TEXT        ".text"		/* code */
+#define ELF_TEXT	".text"		/* code */
 
 /* Section Attribute Flags - sh_flags */
 #define SHF_WRITE	0x1		/* Writable */
@@ -319,7 +343,7 @@ typedef struct {
 #define SHF_TLS		0x400		/* Thread local storage */
 #define SHF_MASKOS	0x0ff00000	/* OS specific */
 #define SHF_MASKPROC	0xf0000000	/* reserved bits for processor */
-					/*  specific section attributes */
+					/* specific section attributes */
 
 /* Section Group Flags */
 #define GRP_COMDAT	0x1		/* COMDAT group */
@@ -327,7 +351,7 @@ typedef struct {
 #define GRP_MASKPROC	0xf0000000	/* Mask processor specific flags */
 
 /* Symbol Table Entry */
-typedef struct elf32_sym {
+typedef struct {
 	Elf32_Word	st_name;	/* name - index into string table */
 	Elf32_Addr	st_value;	/* symbol value */
 	Elf32_Word	st_size;	/* symbol size */
@@ -351,9 +375,9 @@ typedef struct elf32_sym {
 #define STB_WEAK	2		/* like global - lower precedence */
 #define STB_NUM		3		/* number of symbol bindings */
 #define STB_LOOS	10		/* reserved range for operating */
-#define STB_HIOS	12		/*   system specific symbol bindings */
+#define STB_HIOS	12		/* system specific symbol bindings */
 #define STB_LOPROC	13		/* reserved range for processor */
-#define STB_HIPROC	15		/*  specific symbol bindings */
+#define STB_HIPROC	15		/* specific symbol bindings */
 
 /* Symbol type - ELF32_ST_TYPE - st_info */
 #define STT_NOTYPE	0		/* not specified */
@@ -364,9 +388,9 @@ typedef struct elf32_sym {
 #define STT_NUM		5		/* number of symbol types */
 #define STT_TLS		6		/* Thread local storage symbol */
 #define STT_LOOS	10		/* reserved range for operating */
-#define STT_HIOS	12		/*  system specific symbol types */
+#define STT_HIOS	12		/* system specific symbol types */
 #define STT_LOPROC	13		/* reserved range for processor */
-#define STT_HIPROC	15		/*  specific symbol types */
+#define STT_HIPROC	15		/* specific symbol types */
 
 /* Symbol visibility - ELF32_ST_VISIBILITY - st_other */
 #define STV_DEFAULT	0		/* Normal visibility rules */
@@ -374,17 +398,14 @@ typedef struct elf32_sym {
 #define STV_HIDDEN	2		/* Symbol unavailable in other mods */
 #define STV_PROTECTED	3		/* Not preemptible, not exported */
 
-
 /* Relocation entry with implicit addend */
-typedef struct
-{
+typedef struct {
 	Elf32_Addr	r_offset;	/* offset of relocation */
 	Elf32_Word	r_info;		/* symbol table index and type */
 } Elf32_Rel;
 
 /* Relocation entry with explicit addend */
-typedef struct
-{
+typedef struct {
 	Elf32_Addr	r_offset;	/* offset of relocation */
 	Elf32_Word	r_info;		/* symbol table index and type */
 	Elf32_Sword	r_addend;
@@ -396,9 +417,9 @@ typedef struct {
 } Elf64_Rel;
 
 typedef struct {
-	Elf64_Addr r_offset;    /* Location at which to apply the action */
-	Elf64_Xword r_info;     /* index and type of relocation */
-	Elf64_Sxword r_addend;  /* Constant addend used to compute value */
+	Elf64_Addr r_offset;	/* Location at which to apply the action */
+	Elf64_Xword r_info;	/* index and type of relocation */
+	Elf64_Sxword r_addend;	/* Constant addend used to compute value */
 } Elf64_Rela;
 
 /* Extract relocation info - r_info */
@@ -411,13 +432,24 @@ typedef struct {
 	Elf32_Word	p_type;		/* segment type */
 	Elf32_Off	p_offset;	/* segment offset */
 	Elf32_Addr	p_vaddr;	/* virtual address of segment */
-	Elf32_Addr	p_paddr;	/* physical address - ignored? */
-	Elf32_Word	p_filesz;	/* number of bytes in file for seg. */
-	Elf32_Word	p_memsz;	/* number of bytes in mem. for seg. */
+	Elf32_Addr	p_paddr;	/* physical address of segment */
+	Elf32_Word	p_filesz;	/* number of bytes in file for seg */
+	Elf32_Word	p_memsz;	/* number of bytes in mem. for seg */
 	Elf32_Word	p_flags;	/* flags */
 	Elf32_Word	p_align;	/* memory alignment */
 } Elf32_Phdr;
 
+typedef struct {
+	Elf64_Word	p_type;		/* segment type */
+	Elf64_Word	p_flags;	/* flags */
+	Elf64_Off	p_offset;	/* segment offset */
+	Elf64_Addr	p_vaddr;	/* virtual address of segment */
+	Elf64_Addr	p_paddr;	/* physical address of segment */
+	Elf64_Xword	p_filesz;	/* number of bytes in file for seg */
+	Elf64_Xword	p_memsz;	/* number of bytes in mem. for seg */
+	Elf64_Xword	p_align;	/* memory alignment */
+} Elf64_Phdr;
+
 /* Segment types - p_type */
 #define PT_NULL		0		/* unused */
 #define PT_LOAD		1		/* loadable segment */
@@ -429,9 +461,9 @@ typedef struct {
 #define PT_TLS		7		/* Thread local storage template */
 #define PT_NUM		8		/* Number of segment types */
 #define PT_LOOS		0x60000000	/* reserved range for operating */
-#define PT_HIOS		0x6fffffff	/*   system specific segment types */
+#define PT_HIOS		0x6fffffff	/* system specific segment types */
 #define PT_LOPROC	0x70000000	/* reserved range for processor */
-#define PT_HIPROC	0x7fffffff	/*  specific segment types */
+#define PT_HIPROC	0x7fffffff	/* specific segment types */
 
 /* Segment flags - p_flags */
 #define PF_X		0x1		/* Executable */
@@ -439,13 +471,11 @@ typedef struct {
 #define PF_R		0x4		/* Readable */
 #define PF_MASKOS	0x0ff00000	/* OS specific segment flags */
 #define PF_MASKPROC	0xf0000000	/* reserved bits for processor */
-					/*  specific segment flags */
+					/* specific segment flags */
 /* Dynamic structure */
-typedef struct
-{
+typedef struct {
 	Elf32_Sword	d_tag;		/* controls meaning of d_val */
-	union
-	{
+	union {
 		Elf32_Word	d_val;	/* Multiple meanings - see d_tag */
 		Elf32_Addr	d_ptr;	/* program virtual address */
 	} d_un;
@@ -477,12 +507,12 @@ typedef struct {
 #define DT_RELAENT	9		/* size of relocation entry */
 #define DT_STRSZ	10		/* size of string table */
 #define DT_SYMENT	11		/* size of symbol table entry */
-#define DT_INIT		12		/* address of initialization func. */
+#define DT_INIT		12		/* address of initialization func */
 #define DT_FINI		13		/* address of termination function */
 #define DT_SONAME	14		/* string table offset of shared obj */
 #define DT_RPATH	15		/* string table offset of library
 					   search path */
-#define DT_SYMBOLIC	16		/* start sym search in shared obj. */
+#define DT_SYMBOLIC	16		/* start sym search in shared obj */
 #define DT_REL		17		/* address of rel. tbl. w addends */
 #define DT_RELSZ	18		/* size of DT_REL relocation table */
 #define DT_RELENT	19		/* size of DT_REL relocation entry */
@@ -500,11 +530,11 @@ typedef struct {
 #define DT_ENCODING	32		/* Start of encoded range */
 #define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
 #define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
-#define DT_NUM		34		/* Number used. */
+#define DT_NUM		34		/* Number used */
 #define DT_LOOS		0x60000000	/* reserved range for OS */
-#define DT_HIOS		0x6fffffff	/*   specific dynamic array tags */
+#define DT_HIOS		0x6fffffff	/* specific dynamic array tags */
 #define DT_LOPROC	0x70000000	/* reserved range for processor */
-#define DT_HIPROC	0x7fffffff	/*  specific dynamic array tags */
+#define DT_HIPROC	0x7fffffff	/* specific dynamic array tags */
 
 /* Dynamic Tag Flags - d_un.d_val */
 #define DF_ORIGIN	0x01		/* Object may use DF_ORIGIN */
@@ -520,106 +550,150 @@ unsigned long elf_hash(const unsigned char *name);
 
 #endif /* __ASSEMBLER */
 
+/* ELF register definitions */
+#define R_386_NONE	0
+#define R_386_32	1
+#define R_386_PC32	2
+#define R_386_GOT32	3
+#define R_386_PLT32	4
+#define R_386_COPY	5
+#define R_386_GLOB_DAT	6
+#define R_386_JMP_SLOT	7
+#define R_386_RELATIVE	8
+#define R_386_GOTOFF	9
+#define R_386_GOTPC	10
+#define R_386_NUM	11
+
+/* x86-64 relocation types */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+/* 32 bit signed pc relative offset to GOT */
+#define R_X86_64_GOTPCREL	9
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM		16
+
 /*
  * XXX - PowerPC defines really don't belong in here,
  * but we'll put them in for simplicity.
  */
 
-/* Values for Elf32/64_Ehdr.e_flags.  */
-#define EF_PPC_EMB              0x80000000      /* PowerPC embedded flag */
+/* Values for Elf32/64_Ehdr.e_flags */
+#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
+
+#define EF_PPC64_ELFV1_ABI	0x00000001
+#define EF_PPC64_ELFV2_ABI	0x00000002
 
 /* Cygnus local bits below */
-#define EF_PPC_RELOCATABLE      0x00010000      /* PowerPC -mrelocatable flag*/
-#define EF_PPC_RELOCATABLE_LIB  0x00008000      /* PowerPC -mrelocatable-lib
+#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
 						   flag */
 
 /* PowerPC relocations defined by the ABIs */
-#define R_PPC_NONE              0
-#define R_PPC_ADDR32            1       /* 32bit absolute address */
-#define R_PPC_ADDR24            2       /* 26bit address, 2 bits ignored.  */
-#define R_PPC_ADDR16            3       /* 16bit absolute address */
-#define R_PPC_ADDR16_LO         4       /* lower 16bit of absolute address */
-#define R_PPC_ADDR16_HI         5       /* high 16bit of absolute address */
-#define R_PPC_ADDR16_HA         6       /* adjusted high 16bit */
-#define R_PPC_ADDR14            7       /* 16bit address, 2 bits ignored */
-#define R_PPC_ADDR14_BRTAKEN    8
-#define R_PPC_ADDR14_BRNTAKEN   9
-#define R_PPC_REL24             10      /* PC relative 26 bit */
-#define R_PPC_REL14             11      /* PC relative 16 bit */
-#define R_PPC_REL14_BRTAKEN     12
-#define R_PPC_REL14_BRNTAKEN    13
-#define R_PPC_GOT16             14
-#define R_PPC_GOT16_LO          15
-#define R_PPC_GOT16_HI          16
-#define R_PPC_GOT16_HA          17
-#define R_PPC_PLTREL24          18
-#define R_PPC_COPY              19
-#define R_PPC_GLOB_DAT          20
-#define R_PPC_JMP_SLOT          21
-#define R_PPC_RELATIVE          22
-#define R_PPC_LOCAL24PC         23
-#define R_PPC_UADDR32           24
-#define R_PPC_UADDR16           25
-#define R_PPC_REL32             26
-#define R_PPC_PLT32             27
-#define R_PPC_PLTREL32          28
-#define R_PPC_PLT16_LO          29
-#define R_PPC_PLT16_HI          30
-#define R_PPC_PLT16_HA          31
-#define R_PPC_SDAREL16          32
-#define R_PPC_SECTOFF           33
-#define R_PPC_SECTOFF_LO        34
-#define R_PPC_SECTOFF_HI        35
-#define R_PPC_SECTOFF_HA        36
-/* Keep this the last entry.  */
-#define R_PPC_NUM               37
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+/* Keep this the last entry */
+#define R_PPC_NUM		37
 
-/* The remaining relocs are from the Embedded ELF ABI, and are not
-   in the SVR4 ELF ABI.  */
-#define R_PPC_EMB_NADDR32       101
-#define R_PPC_EMB_NADDR16       102
-#define R_PPC_EMB_NADDR16_LO    103
-#define R_PPC_EMB_NADDR16_HI    104
-#define R_PPC_EMB_NADDR16_HA    105
-#define R_PPC_EMB_SDAI16        106
-#define R_PPC_EMB_SDA2I16       107
-#define R_PPC_EMB_SDA2REL       108
-#define R_PPC_EMB_SDA21         109     /* 16 bit offset in SDA */
-#define R_PPC_EMB_MRKREF        110
-#define R_PPC_EMB_RELSEC16      111
-#define R_PPC_EMB_RELST_LO      112
-#define R_PPC_EMB_RELST_HI      113
-#define R_PPC_EMB_RELST_HA      114
-#define R_PPC_EMB_BIT_FLD       115
-#define R_PPC_EMB_RELSDA        116     /* 16 bit relative offset in SDA */
+/*
+ * The remaining relocs are from the Embedded ELF ABI, and are not
+ * in the SVR4 ELF ABI.
+ */
+#define R_PPC_EMB_NADDR32	101
+#define R_PPC_EMB_NADDR16	102
+#define R_PPC_EMB_NADDR16_LO	103
+#define R_PPC_EMB_NADDR16_HI	104
+#define R_PPC_EMB_NADDR16_HA	105
+#define R_PPC_EMB_SDAI16	106
+#define R_PPC_EMB_SDA2I16	107
+#define R_PPC_EMB_SDA2REL	108
+#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF	110
+#define R_PPC_EMB_RELSEC16	111
+#define R_PPC_EMB_RELST_LO	112
+#define R_PPC_EMB_RELST_HI	113
+#define R_PPC_EMB_RELST_HA	114
+#define R_PPC_EMB_BIT_FLD	115
+#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
 
-/* Diab tool relocations.  */
-#define R_PPC_DIAB_SDA21_LO     180     /* like EMB_SDA21, but lower 16 bit */
-#define R_PPC_DIAB_SDA21_HI     181     /* like EMB_SDA21, but high 16 bit */
-#define R_PPC_DIAB_SDA21_HA     182     /* like EMB_SDA21, adjusted high 16 */
-#define R_PPC_DIAB_RELSDA_LO    183     /* like EMB_RELSDA, but lower 16 bit */
-#define R_PPC_DIAB_RELSDA_HI    184     /* like EMB_RELSDA, but high 16 bit */
-#define R_PPC_DIAB_RELSDA_HA    185     /* like EMB_RELSDA, adjusted high 16 */
+/* Diab tool relocations */
+#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
 
-/* This is a phony reloc to handle any old fashioned TOC16 references
-   that may still be in object files.  */
-#define R_PPC_TOC16             255
+/*
+ * This is a phony reloc to handle any old fashioned TOC16 references
+ * that may still be in object files.
+ */
+#define R_PPC_TOC16		255
 
  /* ARM relocs */
 #define R_ARM_NONE		0	/* No reloc */
 #define R_ARM_RELATIVE		23	/* Adjust by program base */
 
 /* AArch64 relocs */
-#define R_AARCH64_NONE		0	/* No relocation.  */
-#define R_AARCH64_RELATIVE	1027	/* Adjust by program base.  */
+#define R_AARCH64_NONE		0	/* No relocation */
+#define R_AARCH64_RELATIVE	1027	/* Adjust by program base */
 
 /* RISC-V relocations */
 #define R_RISCV_32		1
 #define R_RISCV_64		2
 #define R_RISCV_RELATIVE	3
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 int valid_elf_image(unsigned long addr);
+unsigned long load_elf64_image_phdr(unsigned long addr);
+unsigned long load_elf64_image_shdr(unsigned long addr);
 #endif
 
 #endif /* _ELF_H */
diff --git a/u-boot/include/fdt_support.h b/u-boot/include/fdt_support.h
index 0f4ceda2a3..15ec7eaa05 100644
--- a/u-boot/include/fdt_support.h
+++ b/u-boot/include/fdt_support.h
@@ -11,6 +11,7 @@
 #ifdef CONFIG_OF_LIBFDT
 
 #include <linux/libfdt.h>
+#include <abuf.h>
 
 u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell,
 				const char *prop, const u32 dflt);
@@ -183,6 +184,18 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
  */
 int ft_board_setup(void *blob, bd_t *bd);
 
+/**
+ * board_rng_seed() - Provide a seed to be passed via /chosen/rng-seed
+ *
+ * This function is called if CONFIG_BOARD_RNG_SEED is set, and must
+ * be provided by the board. It should return, via @buf, some suitable
+ * seed value to pass to the kernel.
+ *
+ * @param buf         A struct abuf for returning the seed and its size.
+ * @return            0 if ok, negative on error.
+ */
+int board_rng_seed(struct abuf *buf);
+
 /**
  * board_fdt_chosen_bootargs() - Arbitrarily amend fdt kernel command line
  *
diff --git a/u-boot/include/id_attestation.h b/u-boot/include/id_attestation.h
new file mode 100644
index 0000000000..83559d1c96
--- /dev/null
+++ b/u-boot/include/id_attestation.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023, Rockchip Electronics Co., Ltd
+ * callen.cai, <callen.cai@rock-chips.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef ID_ATTESTATION_H_
+#define ID_ATTESTATION_H_
+
+#include <common.h>
+#include "attestation_key.h"
+#define   IDAT_DEBUG     0
+#if IDAT_DEBUG
+    #define MSG(...) printf(__VA_ARGS__)
+#else
+    #define MSG(...) do {} while (0)
+#endif
+
+#define PROP_LEN   32
+
+typedef struct AttestationIds_ {
+	u8 brand[PROP_LEN];
+	u8 device[PROP_LEN];
+	u8 product[PROP_LEN];
+	u8 serial[PROP_LEN];
+	u8 imei[PROP_LEN];
+	u8 second_imei[PROP_LEN];
+	u8 meid[PROP_LEN];
+	u8 manufacturer[PROP_LEN];
+	u8 model[PROP_LEN];
+} AttestationIds;
+
+void printAttestationIds(const AttestationIds *ids);
+
+/*
+ * write id attestation to secure storage.
+ * @received_data: received data from usb
+ * @len: the size of received_data
+ * @return ATAP_RESULT_OK if ok, or ATAP_RESULT_ERROR_* on error
+ */
+atap_result write_id_attestation_to_secure_storage(u8 *received_data, uint32_t len);
+#endif	//ID_ATTESTATION_H_
diff --git a/u-boot/include/linux/mtd/spinand.h b/u-boot/include/linux/mtd/spinand.h
index 76c00df4e6..2ff2038bbb 100644
--- a/u-boot/include/linux/mtd/spinand.h
+++ b/u-boot/include/linux/mtd/spinand.h
@@ -263,6 +263,7 @@ extern const struct spinand_manufacturer etron_spinand_manufacturer;
 extern const struct spinand_manufacturer jsc_spinand_manufacturer;
 extern const struct spinand_manufacturer silicongo_spinand_manufacturer;
 extern const struct spinand_manufacturer unim_spinand_manufacturer;
+extern const struct spinand_manufacturer unim_zl_spinand_manufacturer;
 extern const struct spinand_manufacturer skyhigh_spinand_manufacturer;
 extern const struct spinand_manufacturer gsto_spinand_manufacturer;
 
diff --git a/u-boot/include/linux/string.h b/u-boot/include/linux/string.h
index 3606620739..a2427c24f5 100644
--- a/u-boot/include/linux/string.h
+++ b/u-boot/include/linux/string.h
@@ -120,6 +120,19 @@ extern void * memchr(const void *,int,__kernel_size_t);
 void *memchr_inv(const void *, int, size_t);
 #endif
 
+/**
+ * memdup() - allocate a buffer and copy in the contents
+ *
+ * Note that this returns a valid pointer even if @len is 0
+ *
+ * @src: data to copy in
+ * @len: number of bytes to copy
+ * @return allocated buffer with the copied contents, or NULL if not enough
+ *	memory is available
+ *
+ */
+char *memdup(const void *src, size_t len);
+
 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base);
 unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base);
 
diff --git a/u-boot/include/linux/usb/ch9.h b/u-boot/include/linux/usb/ch9.h
index 264c9712a3..79a4c7c17c 100644
--- a/u-boot/include/linux/usb/ch9.h
+++ b/u-boot/include/linux/usb/ch9.h
@@ -955,8 +955,6 @@ enum usb_device_speed {
 	USB_SPEED_SUPER,			/* usb 3.0 */
 };
 
-#ifdef __KERNEL__
-
 /**
  * usb_speed_string() - Returns human readable-name of the speed.
  * @speed: The speed to return human-readable name for.  If it's not
@@ -965,8 +963,6 @@ enum usb_device_speed {
  */
 extern const char *usb_speed_string(enum usb_device_speed speed);
 
-#endif
-
 enum usb_device_state {
 	/* NOTATTACHED isn't in the USB spec, and this state acts
 	 * the same as ATTACHED ... but it's clearer this way.
diff --git a/u-boot/include/linux/usb/phy-rockchip-naneng-combphy.h b/u-boot/include/linux/usb/phy-rockchip-naneng-combphy.h
new file mode 100644
index 0000000000..5996f4b051
--- /dev/null
+++ b/u-boot/include/linux/usb/phy-rockchip-naneng-combphy.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier:     GPL-2.0 */
+/*
+ * Copyright (C) 2023 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef _PHY_ROCKCHIP_NANENG_COMBPHY_H
+#define _PHY_ROCKCHIP_NANENG_COMBPHY_H
+
+#if CONFIG_IS_ENABLED(PHY_ROCKCHIP_NANENG_COMBOPHY)
+int rockchip_combphy_usb3_uboot_init(void);
+#else
+static inline int rockchip_combphy_usb3_uboot_init(void)
+{
+	return -ENOTSUPP;
+}
+#endif
+
+#endif /* _PHY_ROCKCHIP_NANENG_COMBPHY_H */
diff --git a/u-boot/include/linux/usb/phy-rockchip-usbdp.h b/u-boot/include/linux/usb/phy-rockchip-usbdp.h
index 8acfa6ddf5..12117c2e90 100644
--- a/u-boot/include/linux/usb/phy-rockchip-usbdp.h
+++ b/u-boot/include/linux/usb/phy-rockchip-usbdp.h
@@ -8,63 +8,13 @@
 #ifndef __PHY_ROCKCHIP_USBDP_H_
 #define __PHY_ROCKCHIP_USBDP_H_
 
-#include <linux/bitops.h>
-
-/* RK3588 USBDP PHY Register Definitions */
-
-#define UDPHY_PCS				0x4000
-#define UDPHY_PMA				0x8000
-
-/* VO0 GRF Registers */
-#define RK3588_GRF_VO0_CON0			0x0000
-#define RK3588_GRF_VO0_CON2			0x0008
-#define DP_SINK_HPD_CFG				BIT(11)
-#define DP_SINK_HPD_SEL				BIT(10)
-#define DP_AUX_DIN_SEL				BIT(9)
-#define DP_AUX_DOUT_SEL				BIT(8)
-#define DP_LANE_SEL_N(n)			GENMASK(2 * (n) + 1, 2 * (n))
-#define DP_LANE_SEL_ALL				GENMASK(7, 0)
-#define PHY_AUX_DP_DATA_POL_NORMAL		0
-#define PHY_AUX_DP_DATA_POL_INVERT		1
-
-/* PMA CMN Registers */
-#define CMN_LANE_MUX_AND_EN_OFFSET		0x0288	/* cmn_reg00A2 */
-#define CMN_DP_LANE_MUX_N(n)			BIT((n) + 4)
-#define CMN_DP_LANE_EN_N(n)			BIT(n)
-#define CMN_DP_LANE_MUX_ALL			GENMASK(7, 4)
-#define CMN_DP_LANE_EN_ALL			GENMASK(3, 0)
-#define PHY_LANE_MUX_USB			0
-#define PHY_LANE_MUX_DP				1
-
-#define CMN_DP_LINK_OFFSET			0x28c	/*cmn_reg00A3 */
-#define CMN_DP_TX_LINK_BW			GENMASK(6, 5)
-#define CMN_DP_TX_LANE_SWAP_EN			BIT(2)
-
-#define CMN_SSC_EN_OFFSET			0x2d0	/* cmn_reg00B4 */
-#define CMN_ROPLL_SSC_EN			BIT(1)
-#define CMN_LCPLL_SSC_EN			BIT(0)
-
-#define CMN_ANA_LCPLL_DONE_OFFSET		0x0350	/* cmn_reg00D4 */
-#define CMN_ANA_LCPLL_LOCK_DONE			BIT(7)
-#define CMN_ANA_LCPLL_AFC_DONE			BIT(6)
-
-#define CMN_ANA_ROPLL_DONE_OFFSET		0x0354	/* cmn_reg00D5 */
-#define CMN_ANA_ROPLL_LOCK_DONE			BIT(1)
-#define CMN_ANA_ROPLL_AFC_DONE			BIT(0)
-
-#define CMN_DP_RSTN_OFFSET			0x038c	/* cmn_reg00E3 */
-#define CMN_DP_INIT_RSTN			BIT(3)
-#define CMN_DP_CMN_RSTN				BIT(2)
-#define CMN_CDR_WTCHDG_EN			BIT(1)
-#define CMN_CDR_WTCHDG_MSK_CDR_EN		BIT(0)
-
-#define TRSV_ANA_TX_CLK_OFFSET_N(n)		(0x854 + (n) * 0x800)	/* trsv_reg0215 */
-#define LN_ANA_TX_SER_TXCLK_INV			BIT(1)
-
-#define TRSV_LN0_MON_RX_CDR_DONE_OFFSET		0x0b84	/* trsv_reg02E1 */
-#define TRSV_LN0_MON_RX_CDR_LOCK_DONE		BIT(0)
-
-#define TRSV_LN2_MON_RX_CDR_DONE_OFFSET		0x1b84	/* trsv_reg06E1 */
-#define TRSV_LN2_MON_RX_CDR_LOCK_DONE		BIT(0)
+#if CONFIG_IS_ENABLED(PHY_ROCKCHIP_USBDP)
+int rockchip_u3phy_uboot_init(void);
+#else
+static inline int rockchip_u3phy_uboot_init(void)
+{
+	return -ENOTSUPP;
+}
+#endif
 
 #endif
diff --git a/u-boot/include/optee_include/OpteeClientInterface.h b/u-boot/include/optee_include/OpteeClientInterface.h
index ce8f547737..eb7ce2619d 100644
--- a/u-boot/include/optee_include/OpteeClientInterface.h
+++ b/u-boot/include/optee_include/OpteeClientInterface.h
@@ -18,6 +18,12 @@ enum RK_OEM_OTP_KEYID {
 	RK_OEM_OTP_KEYMAX
 };
 
+enum RK_HDCP_KEYID {
+	RK_HDCP_KEY0 = 0,
+	RK_HDCP_KEY1 = 1,
+	RK_HDCP_KEYMAX
+};
+
 /* Crypto mode */
 enum RK_CIPIHER_MODE {
 	RK_CIPHER_MODE_ECB = 0,
@@ -87,6 +93,9 @@ uint32_t trusty_read_vbootkey_hash(uint32_t *buf, uint32_t length);
 uint32_t trusty_write_vbootkey_hash(uint32_t *buf, uint32_t length);
 uint32_t trusty_read_vbootkey_enable_flag(uint8_t *flag);
 uint32_t trusty_write_ta_encryption_key(uint32_t *buf, uint32_t length);
+uint32_t trusty_ta_encryption_key_is_written(uint8_t *value);
+uint32_t trusty_write_oem_encrypt_data(uint32_t *buf, uint32_t length);
+uint32_t trusty_oem_encrypt_data_is_written(uint8_t *value);
 uint32_t trusty_check_security_level_flag(uint8_t flag);
 uint32_t trusty_write_oem_huk(uint32_t *buf, uint32_t length);
 uint32_t trusty_read_permanent_attributes_flag(uint8_t *attributes);
@@ -100,6 +109,12 @@ uint32_t trusty_set_oem_hr_otp_read_lock(enum RK_OEM_OTP_KEYID key_id);
 uint32_t trusty_oem_otp_key_cipher(enum RK_OEM_OTP_KEYID key_id, rk_cipher_config *config,
 				   uint32_t src_phys_addr, uint32_t dst_phys_addr,
 				   uint32_t len);
+uint32_t trusty_oem_user_ta_transfer(void);
+uint32_t trusty_oem_user_ta_storage(void);
+uint32_t trusty_write_oem_hdcp_key(enum RK_HDCP_KEYID key_id,
+				  uint8_t *byte_buf, uint32_t byte_len);
+uint32_t trusty_oem_hdcp_key_is_written(enum RK_HDCP_KEYID key_id, uint8_t *value);
+uint32_t trusty_set_oem_hdcp_key_mask(enum RK_HDCP_KEYID key_id);
 uint32_t trusty_attest_dh(uint8_t *dh, uint32_t *dh_size);
 uint32_t trusty_attest_uuid(uint8_t *uuid, uint32_t *uuid_size);
 uint32_t trusty_attest_get_ca
diff --git a/u-boot/include/optee_include/OpteeClientLoadTa.h b/u-boot/include/optee_include/OpteeClientLoadTa.h
new file mode 100644
index 0000000000..f68d7887fe
--- /dev/null
+++ b/u-boot/include/optee_include/OpteeClientLoadTa.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023, Rockchip Electronics Co., Ltd
+ * hisping lin, <hisping.lin@rock-chips.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef _OPTEE_CLIENT_LOAD_TA_H_
+#define _OPTEE_CLIENT_LOAD_TA_H_
+
+#include <optee_include/tee_base_types.h>
+#include <optee_include/tee_client_api.h>
+
+#define TA_BINARY_FOUND 0
+#define TA_BINARY_NOT_FOUND -2
+
+struct userta_header {
+	uint32_t magic;
+	uint32_t img_ver;
+	uint32_t ta_num;
+    uint32_t reserve;
+};
+
+struct userta_item {
+	uint8_t ta_uuid[16];
+	uint32_t ta_offset;
+	uint32_t ta_len;
+	uint32_t ta_ver;
+    uint32_t reserve;
+};
+
+int search_ta(void *uuid_octets, void *ta, size_t *ta_size);
+
+#endif /*_OPTEE_CLIENT_LOAD_TA_H_*/
diff --git a/u-boot/include/power/rk8xx_pmic.h b/u-boot/include/power/rk8xx_pmic.h
index 84d1104dab..d5ec548140 100644
--- a/u-boot/include/power/rk8xx_pmic.h
+++ b/u-boot/include/power/rk8xx_pmic.h
@@ -245,6 +245,91 @@ enum {
 #define RK805_IRQ_PWRON_FALL_MSK	BIT(7)
 #define RK805_IRQ_PWRON_RISE_MSK	BIT(0)
 
+#define RK806_CHIP_NAME			0x5A
+#define RK806_CHIP_VER			0x5B
+#define RK806_HW_VER			0x21
+#define HW_DUAL_PMIC			0x28
+#define HW_SINGLE_PMIC			0xe8
+
+#define RK806_CMD_READ			0
+#define RK806_CMD_WRITE			BIT(7)
+#define RK806_CMD_CRC_EN		BIT(6)
+#define RK806_CMD_CRC_DIS		0
+#define RK806_CMD_LEN_MSK		0x0f
+#define RK806_REG_H			0x00
+
+#define RK806_SYS_CFG1			0x5f
+#define RK806_PWRCTRL_CONFIG0		0x62
+#define RK806_PWRCTRL_CONFIG1		0x63
+#define RK806_VSEL_CTR_SEL0		0x64
+#define RK806_DVS_CTR_SEL4		0x6e
+#define RK806_SYS_CFG3			0x72
+#define RK806_PWRON_KEY			0x76
+#define RK806_INT_STS0			0x77
+#define RK806_INT_MSK0			0x78
+#define RK806_INT_STS1			0x79
+#define RK806_INT_MSK1			0x7A
+#define RK806_GPIO_INT_CONFIG		0x7B
+#define RK806_ON_SOURCE			0x74
+#define RK806_OFF_SOURCE		0x75
+
+#define RK806_IRQ_PWRON_FALL_MSK	BIT(0)
+#define RK806_IRQ_PWRON_RISE_MSK	BIT(1)
+#define RK806_DEV_OFF			BIT(0)
+#define RK806_RST_MODE1			0x01
+#define RK806_RST_MODE2			0x02
+#define RK806_PWRCTRL_FUN_MSK		0x88
+#define RK806_VSEL_CTRL_MSK		0xcc
+#define RK806_VSEL_PWRCTRL1		0x11
+#define RK806_ENABLE_PWRCTRL		0x04
+#define RK806_VERSION_AB		0x01
+
+#define RK806_ABNORDET_EN		0x80
+#define RK806_VERSION_MSK		0x0f
+#define RK806_RESET_FUN_CLR		0x3f
+
+/* RK806 buck*/
+#define RK806_BUCK_ON_VSEL(n)		(0x1a + n - 1)
+#define RK806_BUCK_SLP_VSEL(n)		(0x24 + n - 1)
+#define RK806_BUCK_CONFIG(n)		(0x10 + n - 1)
+#define RK806_BUCK_VSEL_MASK		0xff
+
+/* RK806 LDO */
+#define RK806_NLDO_ON_VSEL(n)		(0x43 + n - 1)
+#define RK806_NLDO_SLP_VSEL(n)		(0x48 + n - 1)
+#define RK806_NLDO_VSEL_MASK		0xff
+#define RK806_PLDO_ON_VSEL(n)		(0x4e + n - 1)
+#define RK806_PLDO_SLP_VSEL(n)		(0x54 + n - 1)
+#define RK806_PLDO_VSEL_MASK		0xff
+
+/* RK806 ENABLE */
+#define RK806_POWER_EN(n)		(0x00 + n)
+#define RK806_NLDO_EN(n)		(0x03 + n)
+#define RK806_PLDO_EN(n)		(0x04 + n)
+
+#define RK806_BUCK_SUSPEND_EN		0x06
+#define RK806_NLDO_SUSPEND_EN		0x07
+#define RK806_PLDO_SUSPEND_EN		0x08
+
+#define RK806_RAMP_RATE_MASK1		0xc0
+#define RK806_RAMP_RATE_REG1(n)		(0x10 + n)
+#define RK806_RAMP_RATE_REG1_8		0xeb
+#define RK806_RAMP_RATE_REG9_10		0xea
+
+#define RK806_RAMP_RATE_4LSB_PER_1CLK	0x00/* LDO 100mV/uS buck 50mV/us */
+#define RK806_RAMP_RATE_2LSB_PER_1CLK	0x01/* LDO 50mV/uS buck 25mV/us */
+#define RK806_RAMP_RATE_1LSB_PER_1CLK	0x02/* LDO 25mV/uS buck 12.5mV/us */
+#define RK806_RAMP_RATE_1LSB_PER_2CLK	0x03/* LDO 12.5mV/uS buck 6.25mV/us */
+
+#define RK806_RAMP_RATE_1LSB_PER_4CLK	0x04/* LDO 6.28/2mV/uS buck 3.125mV/us */
+#define RK806_RAMP_RATE_1LSB_PER_8CLK	0x05/* LDO 3.12mV/uS buck 1.56mV/us */
+#define RK806_RAMP_RATE_1LSB_PER_13CLK	0x06/* LDO 1.9mV/uS buck 961mV/us */
+#define RK806_RAMP_RATE_1LSB_PER_32CLK	0x07/* LDO 0.78mV/uS buck 0.39mV/us */
+
+#define RK806_PLDO0_2_MSK(pldo)		(BIT(pldo + 5))
+#define RK806_PLDO0_2_SET(pldo)		(BIT(pldo + 1) | RK806_PLDO0_2_MSK(pldo))
+#define RK806_PLDO0_2_CLR(pldo)		RK806_PLDO0_2_MSK(pldo)
+
 #define RK816_INT_STS_REG1		0x49
 #define RK816_INT_MSK_REG1		0x4a
 #define RK816_INT_STS_REG3		0x4e
diff --git a/u-boot/include/rk_mini_dump.h b/u-boot/include/rk_mini_dump.h
new file mode 100644
index 0000000000..2980c773fb
--- /dev/null
+++ b/u-boot/include/rk_mini_dump.h
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2020 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef RK_MINIDUMP_H
+#define RK_MINIDUMP_H
+
+#include <elf.h>
+
+#define MD_MAX_NAME_LENGTH		16
+/* md_region -  Minidump table entry
+ * @name:	Entry name, Minidump will dump binary with this name.
+ * @id:		Entry ID, used only for SDI dumps.
+ * @virt_addr:  Address of the entry.
+ * @phys_addr:	Physical address of the entry to dump.
+ * @size:	Number of byte to dump from @address location
+ *		it should be 4 byte aligned.
+ */
+struct md_region {
+	char	name[MD_MAX_NAME_LENGTH];
+	u32	id;
+	u64	virt_addr;
+	u64	phys_addr;
+	u64	size;
+};
+
+void rk_minidump_init(void);
+
+#ifdef CONFIG_ARM64
+void rk_minidump_get_el64(void **ram_image_addr, Elf64_Xword *ram_image_size);
+#else
+void rk_minidump_get_el32(void **ram_image_addr, Elf32_Word *ram_image_size);
+#endif
+
+struct md_region *md_get_region(char *name);
+u32 md_no_fault_handler(struct pt_regs *pt_regs, unsigned int esr);
+#endif
diff --git a/u-boot/include/rockusb.h b/u-boot/include/rockusb.h
index 81daabfaa6..d742faeec8 100644
--- a/u-boot/include/rockusb.h
+++ b/u-boot/include/rockusb.h
@@ -39,9 +39,11 @@ enum rkusb_cmd {
 	RKUSB_LBA_ERASE		= 0x25,
 	RKUSB_VS_WRITE		= 0x26,
 	RKUSB_VS_READ		= 0x27,
+	RKUSB_SWITCH_STORAGE	= 0x2A,
 	RKUSB_GET_STORAGE_MEDIA = 0x2B,
-	RKUSB_SESSION		= 0x30,
+	RKUSB_READ_OTP_DATA	= 0x2C,
 	RKUSB_READ_CAPACITY	= 0xAA,
+	RKUSB_SWITCH_USB3	= 0xBB,
 	RKUSB_RESET		= 0xFF,
 };
 
@@ -58,6 +60,12 @@ struct fsg_common;
 #define IS_RKUSB_UMS_DNL(name)	(!strncmp((name), "rkusb_ums_dnl", 13))
 
 int rkusb_do_check_parity(struct fsg_common *common);
+void rkusb_force_to_usb2(bool enable);
+bool rkusb_force_usb2_enabled(void);
+void rkusb_switch_to_usb3_enable(bool enable);
+bool rkusb_switch_usb3_enabled(void);
+bool rkusb_usb3_capable(void);
+
 #else
 #define IS_RKUSB_UMS_DNL(name)	0
 
@@ -79,6 +87,33 @@ static inline int rkusb_do_check_parity(struct fsg_common *common)
 {
 	return -EOPNOTSUPP;
 }
+
+static inline void rkusb_force_to_usb2(bool enable)
+{
+}
+
+static inline bool rkusb_force_usb2_enabled(void)
+{
+	return false;
+}
+
+static inline void rkusb_switch_to_usb3_enable(bool enable)
+{
+}
+
+static inline bool rkusb_switch_usb3_enabled(void)
+{
+	return false;
+}
+
+static inline bool rkusb_usb3_capable(void)
+{
+	return false;
+}
+#endif
+
+#ifdef CONFIG_USB_DWC3_GADGET
+bool dwc3_gadget_is_connected(void);
 #endif
 
 /* Wait at maximum 60 seconds for cable connection */
@@ -90,6 +125,8 @@ static inline int rkusb_do_check_parity(struct fsg_common *common)
 struct rockusb {
 	struct ums *ums;
 	int ums_cnt;
+	bool force_usb2;
+	bool switch_usb3;
 };
 
 #endif /* __ROCKUSB_H__ */
diff --git a/u-boot/include/usbplug.h b/u-boot/include/usbplug.h
new file mode 100644
index 0000000000..3af2a99853
--- /dev/null
+++ b/u-boot/include/usbplug.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * (C) Copyright 2023 Rockchip Electronics Co., Ltd
+ *
+ */
+
+#ifndef __USBPLUG_H
+#define __USBPLUG_H
+
+struct blk_desc *usbplug_blk_get_devnum_by_type(enum if_type if_type, int devnum);
+
+#endif
\ No newline at end of file
diff --git a/u-boot/lib/Makefile b/u-boot/lib/Makefile
index 0b7a01a034..b0b0e78904 100644
--- a/u-boot/lib/Makefile
+++ b/u-boot/lib/Makefile
@@ -76,6 +76,7 @@ ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o
 obj-$(CONFIG_SPL_NET_SUPPORT) += net_utils.o
 endif
+obj-y += abuf.o
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
 obj-y += hashtable.o
 obj-y += errno.o
diff --git a/u-boot/lib/abuf.c b/u-boot/lib/abuf.c
new file mode 100644
index 0000000000..aa7c429652
--- /dev/null
+++ b/u-boot/lib/abuf.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Handles a buffer that can be allocated and freed
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <abuf.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <linux/string.h>
+
+void abuf_set(struct abuf *abuf, void *data, size_t size)
+{
+	abuf_uninit(abuf);
+	abuf->data = data;
+	abuf->size = size;
+}
+
+void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size)
+{
+	abuf_set(abuf, map_sysmem(addr, size), size);
+}
+
+bool abuf_realloc(struct abuf *abuf, size_t new_size)
+{
+	void *ptr;
+
+	if (!new_size) {
+		/* easy case, just need to uninit, freeing any allocation */
+		abuf_uninit(abuf);
+		return true;
+	} else if (abuf->alloced) {
+		/* currently allocated, so need to reallocate */
+		ptr = realloc(abuf->data, new_size);
+		if (!ptr)
+			return false;
+		abuf->data = ptr;
+		abuf->size = new_size;
+		return true;
+	} else if (new_size <= abuf->size) {
+		/*
+		 * not currently alloced and new size is no larger. Just update
+		 * it. Data is lost off the end if new_size < abuf->size
+		 */
+		abuf->size = new_size;
+		return true;
+	} else {
+		/* not currently allocated and new size is larger. Alloc and
+		 * copy in data. The new space is not inited.
+		 */
+		ptr = memdup(abuf->data, new_size);
+		if (!ptr)
+			return false;
+		abuf->data = ptr;
+		abuf->size = new_size;
+		abuf->alloced = true;
+		return true;
+	}
+}
+
+void *abuf_uninit_move(struct abuf *abuf, size_t *sizep)
+{
+	void *ptr;
+
+	if (sizep)
+		*sizep = abuf->size;
+	if (!abuf->size)
+		return NULL;
+	if (abuf->alloced) {
+		ptr = abuf->data;
+	} else {
+		ptr = memdup(abuf->data, abuf->size);
+		if (!ptr)
+			return NULL;
+	}
+	/* Clear everything out so there is no record of the data */
+	abuf_init(abuf);
+
+	return ptr;
+}
+
+void abuf_init_set(struct abuf *abuf, void *data, size_t size)
+{
+	abuf_init(abuf);
+	abuf_set(abuf, data, size);
+}
+
+void abuf_init_move(struct abuf *abuf, void *data, size_t size)
+{
+	abuf_init_set(abuf, data, size);
+	abuf->alloced = true;
+}
+
+void abuf_uninit(struct abuf *abuf)
+{
+	if (abuf->alloced)
+		free(abuf->data);
+	abuf_init(abuf);
+}
+
+void abuf_init(struct abuf *abuf)
+{
+	abuf->data = NULL;
+	abuf->size = 0;
+	abuf->alloced = false;
+}
diff --git a/u-boot/lib/display_options.c b/u-boot/lib/display_options.c
index 4ea27ca99d..467c7b8da0 100644
--- a/u-boot/lib/display_options.c
+++ b/u-boot/lib/display_options.c
@@ -21,7 +21,7 @@ char *display_options_get_banner_priv(bool newlines, const char *build_tag,
 	len = snprintf(buf, size, "%s%s", newlines ? "\n\n" : "",
 		       version_string);
 	if (build_tag && len < size)
-		len += snprintf(buf + len, size - len, ", Build: %s",
+		len += snprintf(buf + len, size - len, ", fwver: %s",
 				build_tag);
 	if (len > size - 3)
 		len = size - 3;
diff --git a/u-boot/lib/efi_loader/efi_gop.c b/u-boot/lib/efi_loader/efi_gop.c
index 411a8c9226..66b7093b76 100644
--- a/u-boot/lib/efi_loader/efi_gop.c
+++ b/u-boot/lib/efi_loader/efi_gop.c
@@ -137,7 +137,8 @@ int efi_gop_register(void)
 	struct udevice *vdev;
 
 	/* We only support a single video output device for now */
-	if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev)
+	uclass_first_device(UCLASS_VIDEO, &vdev);
+	if (!vdev)
 		return -1;
 
 	struct video_priv *priv = dev_get_uclass_priv(vdev);
diff --git a/u-boot/lib/optee_clientApi/Makefile b/u-boot/lib/optee_clientApi/Makefile
index 4ee69ec055..cbede317b7 100644
--- a/u-boot/lib/optee_clientApi/Makefile
+++ b/u-boot/lib/optee_clientApi/Makefile
@@ -8,6 +8,7 @@ obj-y += OpteeClientApiLib.o
 obj-y += OpteeClientInterface.o
 obj-y += OpteeClientSMC.o
 obj-y += OpteeClientRPC.o
+obj-y += OpteeClientLoadTa.o
 obj-y += tee_smc-arm64.o
 obj-y += OpteeClientRkFs_common.o
 
diff --git a/u-boot/lib/optee_clientApi/OpteeClientInterface.c b/u-boot/lib/optee_clientApi/OpteeClientInterface.c
index 43546e714d..3a63f356d0 100644
--- a/u-boot/lib/optee_clientApi/OpteeClientInterface.c
+++ b/u-boot/lib/optee_clientApi/OpteeClientInterface.c
@@ -29,6 +29,12 @@
 #define STORAGE_CMD_WRITE_OEM_OTP_KEY		14
 #define STORAGE_CMD_SET_OEM_HR_OTP_READ_LOCK	15
 #define STORAGE_CMD_OEM_OTP_KEY_IS_WRITTEN	16
+#define STORAGE_CMD_TA_ENCRYPTION_KEY_IS_WRITTEN	20
+#define STORAGE_CMD_WRITE_OEM_HDCP_KEY	21
+#define STORAGE_CMD_OEM_HDCP_KEY_IS_WRITTEN	22
+#define STORAGE_CMD_SET_OEM_HDCP_KEY_MASK	23
+#define STORAGE_CMD_WRITE_OEM_ENCRYPT_DATA	24
+#define STORAGE_CMD_OEM_ENCRYPT_DATA_IS_WRITTEN	25
 
 #define CRYPTO_SERVICE_CMD_OEM_OTP_KEY_PHYS_CIPHER	0x00000002
 
@@ -647,6 +653,112 @@ uint32_t trusty_write_ta_encryption_key(uint32_t *buf, uint32_t length)
 						  true, buf, length);
 }
 
+uint32_t trusty_ta_encryption_key_is_written(uint8_t *value)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+
+	*value = 0;
+
+	TEEC_UUID tempuuid = { 0x2d26d8a8, 0x5134, 0x4dd8,
+			{ 0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71 } };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				NULL,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT,
+						    TEEC_NONE,
+						    TEEC_NONE,
+						    TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					STORAGE_CMD_TA_ENCRYPTION_KEY_IS_WRITTEN,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult == TEEC_SUCCESS)
+		*value = TeecOperation.params[0].value.a;
+
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
+uint32_t trusty_write_oem_encrypt_data(uint32_t *buf, uint32_t length)
+{
+	return trusty_base_efuse_or_otp_operation(STORAGE_CMD_WRITE_OEM_ENCRYPT_DATA,
+						  true, buf, length);
+}
+
+uint32_t trusty_oem_encrypt_data_is_written(uint8_t *value)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+
+	*value = 0;
+
+	TEEC_UUID tempuuid = { 0x2d26d8a8, 0x5134, 0x4dd8,
+			{ 0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71 } };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				NULL,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT,
+						    TEEC_NONE,
+						    TEEC_NONE,
+						    TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					STORAGE_CMD_OEM_ENCRYPT_DATA_IS_WRITTEN,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult == TEEC_SUCCESS)
+		*value = TeecOperation.params[0].value.a;
+
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
 uint32_t trusty_check_security_level_flag(uint8_t flag)
 {
 	uint32_t levelflag;
@@ -1092,6 +1204,322 @@ exit:
 	return TeecResult;
 }
 
+uint32_t trusty_write_oem_hdcp_key(enum RK_HDCP_KEYID key_id,
+				  uint8_t *byte_buf, uint32_t byte_len)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+
+	TEEC_UUID tempuuid = { 0x2d26d8a8, 0x5134, 0x4dd8,
+			{ 0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71 } };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				NULL,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.params[0].value.a = key_id;
+
+	TEEC_SharedMemory SharedMem = {0};
+
+	SharedMem.size = byte_len;
+	SharedMem.flags = 0;
+
+	TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+	TeecOperation.params[1].tmpref.buffer = SharedMem.buffer;
+	TeecOperation.params[1].tmpref.size = SharedMem.size;
+
+	memcpy(SharedMem.buffer, byte_buf, SharedMem.size);
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+						    TEEC_MEMREF_TEMP_INPUT,
+						    TEEC_NONE,
+						    TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					STORAGE_CMD_WRITE_OEM_HDCP_KEY,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+exit:
+	TEEC_ReleaseSharedMemory(&SharedMem);
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
+uint32_t trusty_oem_hdcp_key_is_written(enum RK_HDCP_KEYID key_id, uint8_t *value)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+
+	*value = 0xFF;
+
+	TEEC_UUID tempuuid = { 0x2d26d8a8, 0x5134, 0x4dd8,
+			{ 0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71 } };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				NULL,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.params[0].value.a = key_id;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT,
+						    TEEC_NONE,
+						    TEEC_NONE,
+						    TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					STORAGE_CMD_OEM_HDCP_KEY_IS_WRITTEN,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult == TEEC_SUCCESS)
+		*value = TeecOperation.params[0].value.b;
+
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
+uint32_t trusty_set_oem_hdcp_key_mask(enum RK_HDCP_KEYID key_id)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+
+	TEEC_UUID tempuuid = { 0x2d26d8a8, 0x5134, 0x4dd8,
+			{ 0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71 } };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				NULL,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.params[0].value.a = key_id;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+						    TEEC_NONE,
+						    TEEC_NONE,
+						    TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					STORAGE_CMD_SET_OEM_HDCP_KEY_MASK,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+exit:
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
+uint32_t trusty_oem_user_ta_transfer(void)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+	TEEC_UUID tempuuid = { 0x1db57234, 0xdacd, 0x462d,
+		{ 0x9b, 0xb1, 0xae, 0x79, 0xde, 0x44, 0xe2, 0xa5} };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+	const uint8_t transfer_inout[] = "Transfer data test.";
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE,
+						TEEC_NONE,
+						TEEC_NONE,
+						TEEC_NONE);
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				&TeecOperation,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TEEC_SharedMemory SharedMem0 = {0};
+
+	SharedMem0.size = sizeof(transfer_inout);
+	SharedMem0.flags = 0;
+
+	TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem0);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+	memcpy(SharedMem0.buffer, transfer_inout, SharedMem0.size);
+
+	TEEC_SharedMemory SharedMem1 = {0};
+
+	SharedMem1.size = sizeof(transfer_inout);
+	SharedMem1.flags = 0;
+
+	TeecResult = TEEC_AllocateSharedMemory(&TeecContext, &SharedMem1);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+	TeecOperation.params[0].value.a = 66;
+	TeecOperation.params[1].tmpref.buffer = SharedMem0.buffer;
+	TeecOperation.params[1].tmpref.size = SharedMem0.size;
+	TeecOperation.params[2].tmpref.buffer = SharedMem1.buffer;
+	TeecOperation.params[2].tmpref.size = SharedMem1.size;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT,
+						TEEC_MEMREF_TEMP_INPUT,
+						TEEC_MEMREF_TEMP_OUTPUT,
+						TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					102,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+	//Check the result
+	if (TeecOperation.params[0].value.a == 66 + 1 &&
+	    TeecOperation.params[0].value.b == TeecOperation.params[0].value.a)
+		printf("test value : Pass!\n");
+	else
+		printf("test value : Fail! (mismatch values)\n");
+
+	if (memcmp(SharedMem1.buffer, transfer_inout, sizeof(transfer_inout)) == 0)
+		printf("test buffer : Pass!\n");
+	else
+		printf("test buffer : Fail! (mismatch buffer)\n");
+
+exit:
+	TEEC_ReleaseSharedMemory(&SharedMem0);
+	TEEC_ReleaseSharedMemory(&SharedMem1);
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
+uint32_t trusty_oem_user_ta_storage(void)
+{
+	TEEC_Result TeecResult;
+	TEEC_Context TeecContext;
+	TEEC_Session TeecSession;
+	uint32_t ErrorOrigin;
+	TEEC_UUID tempuuid = { 0x1db57234, 0xdacd, 0x462d,
+		{ 0x9b, 0xb1, 0xae, 0x79, 0xde, 0x44, 0xe2, 0xa5} };
+	TEEC_UUID *TeecUuid = &tempuuid;
+	TEEC_Operation TeecOperation = {0};
+
+	TeecResult = OpteeClientApiLibInitialize();
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecResult = TEEC_InitializeContext(NULL, &TeecContext);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE,
+						TEEC_NONE,
+						TEEC_NONE,
+						TEEC_NONE);
+
+	TeecResult = TEEC_OpenSession(&TeecContext,
+				&TeecSession,
+				TeecUuid,
+				TEEC_LOGIN_PUBLIC,
+				NULL,
+				&TeecOperation,
+				&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		return TeecResult;
+
+	TeecOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE,
+						TEEC_NONE,
+						TEEC_NONE,
+						TEEC_NONE);
+
+	TeecResult = TEEC_InvokeCommand(&TeecSession,
+					103,
+					&TeecOperation,
+					&ErrorOrigin);
+	if (TeecResult != TEEC_SUCCESS)
+		goto exit;
+
+exit:
+	TEEC_CloseSession(&TeecSession);
+	TEEC_FinalizeContext(&TeecContext);
+
+	return TeecResult;
+}
+
 uint32_t trusty_attest_dh(uint8_t *dh, uint32_t *dh_size)
 {
 	TEEC_Result TeecResult;
diff --git a/u-boot/lib/optee_clientApi/OpteeClientLoadTa.c b/u-boot/lib/optee_clientApi/OpteeClientLoadTa.c
new file mode 100644
index 0000000000..ccbd6e290c
--- /dev/null
+++ b/u-boot/lib/optee_clientApi/OpteeClientLoadTa.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2023, Rockchip Electronics Co., Ltd
+ * hisping lin, <hisping.lin@rock-chips.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <stdlib.h>
+#include <boot_rkimg.h>
+#include <command.h>
+#include <common.h>
+#include <mmc.h>
+#include <optee_include/OpteeClientLoadTa.h>
+
+int is_uuid_equal(TEEC_UUID uuid1, TEEC_UUID uuid2)
+{
+	bool a, b, c;
+
+	a = (uuid1.timeLow == uuid2.timeLow);
+	b = (uuid1.timeMid == uuid2.timeMid);
+	c = (uuid1.timeHiAndVersion == uuid2.timeHiAndVersion);
+	if ((a & b & c) == 0) {
+		return 0;
+	} else {
+		if (memcmp(uuid1.clockSeqAndNode,
+			   uuid2.clockSeqAndNode, 8) == 0) {
+			return 1;
+		} else {
+			return 0;
+		}
+	}
+}
+
+void tee_uuid_from_octets(TEEC_UUID *d, const uint8_t *s)
+{
+	d->timeLow = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+	d->timeMid = (s[4] << 8) | s[5];
+	d->timeHiAndVersion = (s[6] << 8) | s[7];
+	memcpy(d->clockSeqAndNode, s + 8, sizeof(d->clockSeqAndNode));
+}
+
+static struct blk_desc *dev_desc;
+static disk_partition_t part_info;
+int search_ta(void *uuid_octets, void *ta, size_t *ta_size)
+{
+	char fname[255];
+	char *format;
+	unsigned long ret = 0;
+	TEEC_UUID uuid;
+	TEEC_UUID ta_uuid;
+	uint8_t *userta;
+	struct userta_header *header;
+	struct userta_item *item;
+	int ta_ver;
+	int res;
+
+	if (!uuid_octets || !ta_size) {
+		printf("TEEC: wrong parameter to search_ta\n");
+		return -1;
+	}
+
+	if (!dev_desc) {
+		dev_desc = rockchip_get_bootdev();
+		if (!dev_desc) {
+			printf("TEEC: %s: Could not find device\n", __func__);
+			return -1;
+		}
+
+		if (part_get_info_by_name(dev_desc,
+					  "userta", &part_info) < 0) {
+			dev_desc = NULL;
+			printf("TEEC: Could not find userta partition\n");
+			return -1;
+		}
+	}
+
+#ifdef CONFIG_OPTEE_V1
+	memcpy(&uuid, uuid_octets, sizeof(TEEC_UUID));
+	ta_ver = 1;
+	format = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x.ta";
+#endif
+
+#ifdef CONFIG_OPTEE_V2
+	tee_uuid_from_octets(&uuid, uuid_octets);
+	ta_ver = 2;
+	format = "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.ta";
+#endif
+
+	snprintf(fname, 255,
+			format,
+			uuid.timeLow,
+			uuid.timeMid,
+			uuid.timeHiAndVersion,
+			uuid.clockSeqAndNode[0],
+			uuid.clockSeqAndNode[1],
+			uuid.clockSeqAndNode[2],
+			uuid.clockSeqAndNode[3],
+			uuid.clockSeqAndNode[4],
+			uuid.clockSeqAndNode[5],
+			uuid.clockSeqAndNode[6],
+			uuid.clockSeqAndNode[7]);
+
+	printf("Attempt to load %s \n", fname);
+
+    userta = (uint8_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, part_info.size * part_info.blksz);
+	if (!userta) {
+		printf("TEEC: Malloc failed!\n");
+		res = -1;
+		goto exit;
+	}
+
+	ret = blk_dread(dev_desc, part_info.start, part_info.size, userta);
+	if (ret != part_info.size) {
+		printf("TEEC: blk_dread fail\n");
+		res = -1;
+		goto exit;
+	}
+
+	header = (struct userta_header *)userta;
+	if (header->magic != 0x524B5441 || header->img_ver != 1) {
+		printf("TEEC: userta_header format error! \n");
+		res = -1;
+		goto exit;
+	}
+
+	item = (struct userta_item *)(header + 1);
+
+	for (int i = 0; i < header->ta_num; i++) {
+		tee_uuid_from_octets(&ta_uuid, item->ta_uuid);
+			snprintf(fname, 255,
+			format,
+			ta_uuid.timeLow,
+			ta_uuid.timeMid,
+			ta_uuid.timeHiAndVersion,
+			ta_uuid.clockSeqAndNode[0],
+			ta_uuid.clockSeqAndNode[1],
+			ta_uuid.clockSeqAndNode[2],
+			ta_uuid.clockSeqAndNode[3],
+			ta_uuid.clockSeqAndNode[4],
+			ta_uuid.clockSeqAndNode[5],
+			ta_uuid.clockSeqAndNode[6],
+			ta_uuid.clockSeqAndNode[7]);
+		debug("search TA %s \n", fname);
+		debug("item->ta_offset=0x%x item->ta_len=0x%x *ta_size=%zu\n",
+				item->ta_offset, item->ta_len, *ta_size);
+
+		if (is_uuid_equal(ta_uuid, uuid) && item->ta_ver == ta_ver) {
+			if (item->ta_len <= *ta_size && ta)
+				memcpy(ta, userta + item->ta_offset, item->ta_len);
+			*ta_size = item->ta_len;
+			res = TA_BINARY_FOUND;
+			goto exit;
+		} else {
+			item++;
+		}
+	}
+	res = TA_BINARY_NOT_FOUND;
+
+exit:
+	if (userta)
+		free(userta);
+	return res;
+}
diff --git a/u-boot/lib/optee_clientApi/OpteeClientRPC.c b/u-boot/lib/optee_clientApi/OpteeClientRPC.c
index 8085b66997..d9dd5d9cec 100644
--- a/u-boot/lib/optee_clientApi/OpteeClientRPC.c
+++ b/u-boot/lib/optee_clientApi/OpteeClientRPC.c
@@ -8,6 +8,7 @@
 #include <stdlib.h>
 #include <command.h>
 #include <mmc.h>
+#include <optee_include/OpteeClientLoadTa.h>
 #include <optee_include/OpteeClientMem.h>
 #include <optee_include/OpteeClientRPC.h>
 #include <optee_include/teesmc.h>
@@ -54,107 +55,12 @@ TEEC_Result OpteeRpcFree(uint32_t Address)
 	return TEEC_SUCCESS;
 }
 
-int is_uuid_equal(TEE_UUID uuid1, TEEC_UUID uuid2)
-{
-	bool a, b, c;
-
-	a = (uuid1.timeLow == uuid2.timeLow);
-	b = (uuid1.timeMid == uuid2.timeMid);
-	c = (uuid1.timeHiAndVersion == uuid2.timeHiAndVersion);
-	if ((a & b & c) == 0) {
-		return 0;
-	} else {
-		if (memcmp(uuid1.clockSeqAndNode,
-			   uuid2.clockSeqAndNode, 8) == 0) {
-			return 1;
-		} else {
-			return 0;
-		}
-	}
-}
-
-/*
- * Load a TA from storage into memory and provide it back to OpTEE.
- * Param[0] = IN: struct tee_rpc_load_ta_cmd
- * Param[1] = IN: all-zero OUT: TA Image allocated
- */
-TEEC_Result OpteeRpcCmdLoadTa(t_teesmc32_arg *TeeSmc32Arg)
-{
-	TEEC_Result TeecResult = TEEC_SUCCESS;
-	t_teesmc32_param *TeeSmc32Param = NULL;
-	struct tee_rpc_load_ta_cmd *TeeLoadTaCmd = NULL;
-	uint32_t TeeLoadTaCmdSize = 0;
-
-	if (TeeSmc32Arg->num_params != 2) {
-		TeecResult = TEEC_ERROR_BAD_PARAMETERS;
-		goto Exit;
-	}
-
-	TEEC_UUID TA_RK_KEYMASTER_UUID = {0x258be795, 0xf9ca, 0x40e6,
-			{0xa8, 0x69, 0x9c, 0xe6, 0x88, 0x6c, 0x5d, 0x5d} };
-	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
-	TeeLoadTaCmd = (struct tee_rpc_load_ta_cmd *)
-					(size_t)TeeSmc32Param[0].u.memref.buf_ptr;
-	TeeLoadTaCmdSize = TeeSmc32Param[0].u.memref.size;
-
-	if ((TeeLoadTaCmd == NULL) ||
-		(TeeLoadTaCmdSize != sizeof(*TeeLoadTaCmd))) {
-		TeecResult = TEEC_ERROR_BAD_PARAMETERS;
-		goto Exit;
-	}
-
-	TEEC_Result Status = 0;
-	void *ImageData = NULL;
-	uint32_t ImageSize = 0;
-	size_t AllocAddress = 0;
-
-	if (is_uuid_equal(TeeLoadTaCmd->uuid, TA_RK_KEYMASTER_UUID)) {
-		ImageData = (void *)0;
-		ImageSize = 0;
-	} else {
-		ImageData = (void *)0;
-		ImageSize = 0;
-	}
-
-	if (Status != 0) {
-		TeecResult = TEEC_ERROR_ITEM_NOT_FOUND;
-		goto Exit;
-	}
-
-	AllocAddress = (size_t) OpteeClientMemAlloc(ImageSize);
-
-	if (AllocAddress == 0) {
-		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
-		goto Exit;
-	}
-
-	memcpy((void *)AllocAddress, ImageData, ImageSize);
-
-	debug("TEEC: ...TA loaded at 0x%zu of size 0x%X bytes\n",
-		AllocAddress, ImageSize);
-	debug("TEEC: ...AllocAddress[0] 0x%X ; AllocAddress[1] 0x%X bytes\n",
-		*(char *)AllocAddress, *(char *)(AllocAddress+1));
-
-	TeeLoadTaCmd->va = AllocAddress;
-
-	TeeSmc32Param[1].u.memref.buf_ptr = AllocAddress;
-	TeeSmc32Param[1].u.memref.size = ImageSize;
-
-Exit:
-	TeeSmc32Arg->ret = TeecResult;
-	TeeSmc32Arg->ret_origin = TEEC_ORIGIN_API;
-
-	debug("TEEC: OpteeRpcCmdLoadTa Exit : TeecResult=0x%X\n", TeecResult);
-
-	return TeecResult;
-}
-
 TEEC_Result OpteeRpcCmdLoadV2Ta(t_teesmc32_arg *TeeSmc32Arg)
 {
 	TEEC_Result TeecResult = TEEC_SUCCESS;
 	t_teesmc32_param *TeeSmc32Param = NULL;
-	uint8_t uuid[16];
-	int i;
+	int ta_found = 0;
+	size_t size = 0;
 
 	if (TeeSmc32Arg->num_params != 2) {
 		TeecResult = TEEC_ERROR_BAD_PARAMETERS;
@@ -163,70 +69,22 @@ TEEC_Result OpteeRpcCmdLoadV2Ta(t_teesmc32_arg *TeeSmc32Arg)
 
 	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
 
-	memcpy(uuid, (void *)&TeeSmc32Param[0].u.value, 16);
-	for (i = 0; i < 16; i++)
-		debug("TEEC: uuid 0x%x", uuid[i]);
-
-	if (TeeSmc32Param[1].u.memref.buf_ptr == 0) {
-		debug("TEEC: return size of TA, keymaster_size = 0\n");
-		TeeSmc32Param[1].u.memref.size = 0;
+	size = TeeSmc32Param[1].u.memref.size;
+	ta_found = search_ta((void *)(size_t)&TeeSmc32Param[0].u.value,
+				(void *)(size_t)TeeSmc32Param[1].u.memref.buf_ptr, &size);
+	if (ta_found == TA_BINARY_FOUND) {
+		TeeSmc32Param[1].u.memref.size = size;
+		TeecResult = TEEC_SUCCESS;
 	} else {
-		/*memcpy((void *)(size_t)TeeSmc32Param[1].u.memref.buf_ptr,
-			(void *)keymaster_data, TeeSmc32Param[1].u.memref.size);*/
-		debug("TEEC: memref.buf_ptr = 0x%llx; memref.size = 0x%llx\n",
-			(uint64_t)TeeSmc32Param[1].u.memref.buf_ptr,
-			(uint64_t)TeeSmc32Param[1].u.memref.size);
+		printf("  TA not found \n");
+		TeecResult = TEEC_ERROR_ITEM_NOT_FOUND;
 	}
 
 Exit:
 	TeeSmc32Arg->ret = TeecResult;
 	TeeSmc32Arg->ret_origin = TEEC_ORIGIN_API;
 
-	debug("TEEC: OpteeRpcCmdLoadTa Exit : TeecResult=0x%X\n", TeecResult);
-
-	return TeecResult;
-}
-
-/*
- * Free a previously loaded TA and release the memory
- * Param[0] = IN: TA Image to free
- *
- * Um, why is OpTEE holding on to this memory? The OS code suggests that OpTEE
- * is using the binary in place out of shared memory but I don't understand how
- * runtime modifications of the binary are being prevented if that's the case?
- */
-TEEC_Result OpteeRpcCmdFreeTa(t_teesmc32_arg *TeeSmc32Arg)
-{
-	TEEC_Result TeecResult = TEEC_SUCCESS;
-	t_teesmc32_param *TeeSmc32Param = NULL;
-	uint32_t ImageSize = 0;
-	size_t AllocAddress = 0;
-
-	if (TeeSmc32Arg->num_params != 1) {
-		TeecResult = TEEC_ERROR_BAD_PARAMETERS;
-		goto Exit;
-	}
-
-	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
-
-	AllocAddress = TeeSmc32Param[0].u.memref.buf_ptr;
-	ImageSize = TeeSmc32Param[0].u.memref.size;
-
-	debug("TEEC: OpteeRpcCmdFreeTa Enter: AllocAddress=0x%X, ImageSize=0x%X\n",
-			(uint32_t) AllocAddress, (uint32_t) ImageSize);
-
-	if (AllocAddress == 0) {
-		TeecResult = TEEC_ERROR_BAD_PARAMETERS;
-		goto Exit;
-	}
-
-	OpteeClientMemFree((void *)AllocAddress);
-
-Exit:
-	TeeSmc32Arg->ret = TeecResult;
-	TeeSmc32Arg->ret_origin = TEEC_ORIGIN_API;
-
-	debug("TEEC: OpteeRpcCmdFreeTa Exit : TeecResult=0x%X\n", TeecResult);
+	debug("TEEC: OpteeRpcCmdLoadV2Ta Exit : TeecResult=0x%X\n", TeecResult);
 
 	return TeecResult;
 }
diff --git a/u-boot/lib/optee_clientApi/tabinary_to_img.py b/u-boot/lib/optee_clientApi/tabinary_to_img.py
new file mode 100644
index 0000000000..ed7ecedb9b
--- /dev/null
+++ b/u-boot/lib/optee_clientApi/tabinary_to_img.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+#
+# Copyright 2023, Rockchip Electronics Co., Ltd
+# hisping lin, <hisping.lin@rock-chips.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+def get_args():
+	import argparse
+
+	parser = argparse.ArgumentParser()
+
+	parser.add_argument('--out', required=True, \
+		help='Name of image for the TA')
+
+	parser.add_argument('--tadir', required=True, help='Path of TA director')
+
+	return parser.parse_args()
+
+def main():
+	import os
+	import array
+	import glob
+	import struct
+	import uuid
+	try:
+		from Cryptodome.Hash import SHA256
+	except ImportError:
+		from Crypto.Hash import SHA256
+
+	args = get_args();
+
+	path = args.tadir + "/*.ta"
+	files = glob.glob(path)
+	for f in files:
+		print(f)
+
+	fimg = open(args.out, 'wb')
+	magic = 0x524B5441 #RKTA
+	img_ver = 0x00000001
+	ta_num = len(files)
+	reserve = 0
+	header = struct.pack('<IIII', magic, img_ver, ta_num, reserve)
+	fimg.write(header)
+
+	g_offset = len(header) + (ta_num * 32)
+	for f in files:
+		fta = open(f, 'rb')
+		tadata = fta.read()
+		fta.close
+		ta_name = os.path.basename(f)
+		ta_name_without_extension = os.path.splitext(ta_name)[0]
+		ta_uuid = uuid.UUID(ta_name_without_extension)
+		ta_uuid_hex = bytes.fromhex(ta_uuid.hex)
+		fimg.write(ta_uuid_hex)
+		ta_offset = struct.pack('<I', g_offset)
+		fimg.write(ta_offset)
+		ta_len = struct.pack('<I', len(tadata))
+		fimg.write(ta_len)
+		ta_ver_num = len(ta_name_without_extension) - 34;
+		ta_ver = struct.pack('<I', ta_ver_num)
+		fimg.write(ta_ver)
+		ta_reserve = struct.pack('<I', reserve)
+		fimg.write(ta_reserve)
+		g_offset += len(tadata)
+
+	for f in files:
+		fta = open(f, 'rb')
+		tadata = fta.read()
+		fta.close
+		fimg.write(tadata)
+	fimg.close
+
+	fimg = open(args.out, 'rb+')
+	userta = fimg.read()
+	h = SHA256.new()
+	h.update(userta)
+	img_digest = h.digest()
+	fimg.write(img_digest)
+	fimg.close
+
+	print("pack ta binary success!")
+
+if __name__ == "__main__":
+	main()
diff --git a/u-boot/lib/optee_clientApi/userta/1db57234-dacd-462d-9bb1-ae79de44e2a5.ta b/u-boot/lib/optee_clientApi/userta/1db57234-dacd-462d-9bb1-ae79de44e2a5.ta
new file mode 100644
index 0000000000..9678a370df
--- /dev/null
+++ b/u-boot/lib/optee_clientApi/userta/1db57234-dacd-462d-9bb1-ae79de44e2a5.ta
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:42551e519199464c494f200a45ff0b79ad240b33cd204e1e2bd6205071f73df2
+size 80196
diff --git a/u-boot/lib/optee_clientApi/userta/1db57234-dacd-462d-9bb1ae79de44e2a5.ta b/u-boot/lib/optee_clientApi/userta/1db57234-dacd-462d-9bb1ae79de44e2a5.ta
new file mode 100644
index 0000000000..e37e2f50d1
--- /dev/null
+++ b/u-boot/lib/optee_clientApi/userta/1db57234-dacd-462d-9bb1ae79de44e2a5.ta
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f93f48f2b4a4f26f921edd5c1413807cde9fb9bf91c7f4ce8eb4519d68bc05f2
+size 178000
diff --git a/u-boot/lib/rsa/rsa-verify.c b/u-boot/lib/rsa/rsa-verify.c
index fe15293dca..3c656edfce 100644
--- a/u-boot/lib/rsa/rsa-verify.c
+++ b/u-boot/lib/rsa/rsa-verify.c
@@ -609,20 +609,10 @@ int rsa_burn_key_hash(struct image_sign_info *info)
 	const void *blob = info->fdt_blob;
 	uint8_t digest[FIT_MAX_HASH_LEN];
 	uint8_t digest_read[FIT_MAX_HASH_LEN];
-	int sig_node, node, digest_len, i, ret = 0;
-
-	dev = misc_otp_get_device(OTP_S);
-	if (!dev)
-		return -ENODEV;
-
-	ret = misc_otp_read(dev, OTP_SECURE_BOOT_ENABLE_ADDR,
-			    &secure_flags, OTP_SECURE_BOOT_ENABLE_SIZE);
-	if (ret)
-		return ret;
-
-	if (secure_flags == 0xff)
-		return 0;
+	int sig_node, node, digest_len, i;
+	int ret = 0, written_size = 0;
 
+	/* Check burn-key-hash flag in itb first */
 	sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
 	if (sig_node < 0) {
 		debug("%s: No signature node found\n", __func__);
@@ -636,7 +626,20 @@ int rsa_burn_key_hash(struct image_sign_info *info)
 		return -1;
 
 	if (!(prop.burn_key))
-		return -EPERM;
+		return 0;
+
+	/* Handle burn_key_hash process from now on */
+	dev = misc_otp_get_device(OTP_S);
+	if (!dev)
+		return -ENODEV;
+
+	ret = misc_otp_read(dev, OTP_SECURE_BOOT_ENABLE_ADDR,
+			    &secure_flags, OTP_SECURE_BOOT_ENABLE_SIZE);
+	if (ret)
+		return ret;
+
+	if (secure_flags == 0xff)
+		return 0;
 
 	if (!prop.hash || !prop.modulus || !prop.public_exponent_BN)
 		return -ENOENT;
@@ -686,14 +689,24 @@ int rsa_burn_key_hash(struct image_sign_info *info)
 		goto error;
 
 	for (i = 0; i < OTP_RSA_HASH_SIZE; i++) {
-		if (digest_read[i]) {
+		if (digest_read[i] == digest[i]) {
+			written_size++;
+		} else if (digest_read[i] == 0) {
+			break;
+		} else {
 			printf("RSA: The secure region has been written.\n");
 			ret = -EIO;
 			goto error;
 		}
 	}
 
-	ret = misc_otp_write(dev, OTP_RSA_HASH_ADDR, digest, OTP_RSA_HASH_SIZE);
+	if (OTP_RSA_HASH_SIZE - written_size) {
+		ret = misc_otp_write(dev, OTP_RSA_HASH_ADDR + written_size, digest + written_size,
+				     OTP_RSA_HASH_SIZE - written_size);
+		if (ret)
+			goto error;
+	}
+
 	if (ret)
 		goto error;
 
@@ -703,6 +716,7 @@ int rsa_burn_key_hash(struct image_sign_info *info)
 		goto error;
 
 	if (memcmp(digest, digest_read, digest_len) != 0) {
+		ret = -EAGAIN;
 		printf("RSA: Write public key hash fail.\n");
 		goto error;
 	}
@@ -713,7 +727,10 @@ int rsa_burn_key_hash(struct image_sign_info *info)
 	if (ret)
 		goto error;
 
-	printf("RSA: Write key hash successfully\n");
+	if (written_size)
+		printf("RSA: Repair RSA key hash successfully.\n");
+	else
+		printf("RSA: Write RSA key hash successfully.\n");
 
 error:
 	free(rsa_key);
diff --git a/u-boot/lib/string.c b/u-boot/lib/string.c
index c4ca944bb4..9634d1d6e9 100644
--- a/u-boot/lib/string.c
+++ b/u-boot/lib/string.c
@@ -599,6 +599,19 @@ void * memscan(void * addr, int c, size_t size)
 }
 #endif
 
+char *memdup(const void *src, size_t len)
+{
+	char *p;
+
+	p = malloc(len);
+	if (!p)
+		return NULL;
+
+	memcpy(p, src, len);
+
+	return p;
+}
+
 #ifndef __HAVE_ARCH_STRSTR
 /**
  * strstr - Find the first substring in a %NUL terminated string
diff --git a/u-boot/make.sh b/u-boot/make.sh
index f1d3b5e1da..6051559124 100755
--- a/u-boot/make.sh
+++ b/u-boot/make.sh
@@ -192,6 +192,14 @@ function process_args()
 				ARG_SPL_BIN="spl/u-boot-spl.bin"
 				shift 1
 				;;
+			--spl-fwver)
+				ARG_SPL_FWVER="SPL_FWVER=$2"
+				shift 2
+				;;
+			--fwver)
+				ARG_FWVER="FWVER=$2"
+				shift 2
+				;;
 			--uboot|--fdt|--optee|--mcu|--bl31) # uboot.img components
 				mkdir -p ${REP_DIR}
 				if [ ! -f $2 ]; then
@@ -616,9 +624,13 @@ function pack_uboot_itb_image()
 	done
 
 	# COMPRESSION
-	COMPRESSION=`awk -F"," '/COMPRESSION=/  { printf $1 }' ${INI} | tr -d ' ' | cut -c 13-`
-	if [ ! -z "${COMPRESSION}" -a "${COMPRESSION}" != "none" ]; then
-		COMPRESSION_ARG="-c ${COMPRESSION}"
+	if grep -q '^CONFIG_IMAGE_GZIP=y' .config ; then
+		COMPRESSION_ARG="-c gzip"
+	else
+		COMPRESSION=`awk -F"," '/COMPRESSION=/  { printf $1 }' ${INI} | tr -d ' ' | cut -c 13-`
+		if [ ! -z "${COMPRESSION}" -a "${COMPRESSION}" != "none" ]; then
+			COMPRESSION_ARG="-c ${COMPRESSION}"
+		fi
 	fi
 
 	if [ -d ${REP_DIR} ]; then
@@ -789,7 +801,7 @@ select_ini_file
 handle_args_late
 sub_commands
 clean_files
-make PYTHON=python2 CROSS_COMPILE=${TOOLCHAIN} all --jobs=${JOB}
+make PYTHON=python2 ${ARG_SPL_FWVER} ${ARG_FWVER} CROSS_COMPILE=${TOOLCHAIN} all --jobs=${JOB}
 pack_images
 finish
 echo ${TOOLCHAIN}
diff --git a/u-boot/net/eth-uclass.c b/u-boot/net/eth-uclass.c
index bd153ac13a..b7a0358e4c 100644
--- a/u-boot/net/eth-uclass.c
+++ b/u-boot/net/eth-uclass.c
@@ -70,8 +70,8 @@ struct udevice *eth_get_dev(void)
 
 	uc_priv = eth_get_uclass_priv();
 	if (!uc_priv->current)
-		eth_errno = uclass_first_device(UCLASS_ETH,
-				    &uc_priv->current);
+		uclass_first_device(UCLASS_ETH,
+			    &uc_priv->current);
 	return uc_priv->current;
 }
 
diff --git a/u-boot/scripts/fit.sh b/u-boot/scripts/fit.sh
index bbdbf160cf..8999841e3c 100755
--- a/u-boot/scripts/fit.sh
+++ b/u-boot/scripts/fit.sh
@@ -22,13 +22,24 @@ else
 		fit_gen_boot_itb
 		fit_gen_boot_img
 	fi
-	fit_gen_uboot_itb
-	fit_gen_uboot_img
-	fit_gen_loader
+
+	if [ ! -z "${ARG_INI_TRUST}" ]; then
+		fit_gen_uboot_itb
+		fit_gen_uboot_img
+	fi
+
+	if [ ! -z "${ARG_INI_LOADER}" ]; then
+		fit_gen_loader
+	fi
 
 	echo
-	fit_msg_uboot
+
+	if [ ! -z "${ARG_INI_TRUST}" ]; then
+		fit_msg_uboot
+	fi
 	fit_msg_recovery
 	fit_msg_boot
-	fit_msg_loader
+	if [ ! -z "${ARG_INI_LOADER}" ]; then
+		fit_msg_loader
+	fi
 fi
diff --git a/u-boot/test/dm/core.c b/u-boot/test/dm/core.c
index 052bf8fffb..7e447f728e 100644
--- a/u-boot/test/dm/core.c
+++ b/u-boot/test/dm/core.c
@@ -479,7 +479,6 @@ static int dm_test_leak(struct unit_test_state *uts)
 
 	for (i = 0; i < 2; i++) {
 		struct udevice *dev;
-		int ret;
 		int id;
 
 		dm_leak_check_start(uts);
@@ -489,11 +488,9 @@ static int dm_test_leak(struct unit_test_state *uts)
 
 		/* Scanning the uclass is enough to probe all the devices */
 		for (id = UCLASS_ROOT; id < UCLASS_COUNT; id++) {
-			for (ret = uclass_first_device(UCLASS_TEST, &dev);
-			     dev;
-			     ret = uclass_next_device(&dev))
+			for (uclass_first_device(UCLASS_TEST, &dev); dev;
+			     uclass_next_device(&dev))
 				;
-			ut_assertok(ret);
 		}
 
 		ut_assertok(dm_leak_check_end(uts));
@@ -564,7 +561,6 @@ static int dm_test_children(struct unit_test_state *uts)
 	struct udevice *grandchild[NODE_COUNT];
 	struct udevice *dev;
 	int total;
-	int ret;
 	int i;
 
 	/* We don't care about the numbering for this test */
@@ -606,11 +602,9 @@ static int dm_test_children(struct unit_test_state *uts)
 	ut_asserteq(2 + NODE_COUNT, dm_testdrv_op_count[DM_TEST_OP_PROBE]);
 
 	/* Probe everything */
-	for (ret = uclass_first_device(UCLASS_TEST, &dev);
-	     dev;
-	     ret = uclass_next_device(&dev))
+	for (uclass_first_device(UCLASS_TEST, &dev); dev;
+	     uclass_next_device(&dev))
 		;
-	ut_assertok(ret);
 
 	ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_PROBE]);
 
@@ -796,11 +790,10 @@ static int dm_test_uclass_devices_get(struct unit_test_state *uts)
 	struct udevice *dev;
 	int ret;
 
-	for (ret = uclass_first_device(UCLASS_TEST, &dev);
+	for (ret = uclass_first_device_check(UCLASS_TEST, &dev);
 	     dev;
-	     ret = uclass_next_device(&dev)) {
+	     ret = uclass_next_device_check(&dev)) {
 		ut_assert(!ret);
-		ut_assert(dev);
 		ut_assert(device_active(dev));
 	}
 
@@ -830,11 +823,10 @@ static int dm_test_uclass_devices_get_by_name(struct unit_test_state *uts)
 	 * this will fail on checking condition: testdev == finddev, since the
 	 * uclass_get_device_by_name(), returns the first device by given name.
 	*/
-	for (ret = uclass_first_device(UCLASS_TEST_FDT, &testdev);
+	for (ret = uclass_first_device_check(UCLASS_TEST_FDT, &testdev);
 	     testdev;
-	     ret = uclass_next_device(&testdev)) {
+	     ret = uclass_next_device_check(&testdev)) {
 		ut_assertok(ret);
-		ut_assert(testdev);
 		ut_assert(device_active(testdev));
 
 		findret = uclass_get_device_by_name(UCLASS_TEST_FDT,
diff --git a/u-boot/test/dm/test-fdt.c b/u-boot/test/dm/test-fdt.c
index dcc2ef8b65..aaedc399bd 100644
--- a/u-boot/test/dm/test-fdt.c
+++ b/u-boot/test/dm/test-fdt.c
@@ -311,13 +311,12 @@ static int dm_test_first_next_device(struct unit_test_state *uts)
 	int ret;
 
 	/* There should be 4 devices */
-	for (ret = uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
+	for (uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
 	     dev;
-	     ret = uclass_next_device(&dev)) {
+	     uclass_next_device(&dev)) {
 		count++;
 		parent = dev_get_parent(dev);
 		}
-	ut_assertok(ret);
 	ut_asserteq(4, count);
 
 	/* Remove them and try again, with an error on the second one */
@@ -325,21 +324,56 @@ static int dm_test_first_next_device(struct unit_test_state *uts)
 	pdata = dev_get_platdata(dev);
 	pdata->probe_err = -ENOMEM;
 	device_remove(parent, DM_REMOVE_NORMAL);
-	ut_assertok(uclass_first_device(UCLASS_TEST_PROBE, &dev));
-	ut_asserteq(-ENOMEM, uclass_next_device(&dev));
-	ut_asserteq_ptr(dev, NULL);
+	for (ret = uclass_first_device_check(UCLASS_TEST_PROBE, &dev),
+		count = 0;
+	     dev;
+	     ret = uclass_next_device_check(&dev)) {
+		if (!ret)
+			count++;
+		else
+			ut_asserteq(-ENOMEM, ret);
+		parent = dev_get_parent(dev);
+		}
+	ut_asserteq(3, count);
 
 	/* Now an error on the first one */
 	ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 0, &dev));
 	pdata = dev_get_platdata(dev);
 	pdata->probe_err = -ENOENT;
 	device_remove(parent, DM_REMOVE_NORMAL);
-	ut_asserteq(-ENOENT, uclass_first_device(UCLASS_TEST_PROBE, &dev));
+	for (uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
+	     dev;
+	     uclass_next_device(&dev)) {
+		count++;
+		parent = dev_get_parent(dev);
+		}
+	ut_asserteq(2, count);
 
 	return 0;
 }
 DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+/* Test iteration through devices in a uclass */
+static int dm_test_uclass_foreach(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int count;
+
+	count = 0;
+	uclass_id_foreach_dev(UCLASS_TEST_FDT, dev, uc)
+		count++;
+	ut_asserteq(8, count);
+
+	count = 0;
+	uclass_foreach_dev(dev, uc)
+		count++;
+	ut_asserteq(8, count);
+
+	return 0;
+}
+DM_TEST(dm_test_uclass_foreach, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /**
  * check_devices() - Check return values and pointers
  *
@@ -419,3 +453,24 @@ static int dm_test_first_next_ok_device(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_first_next_ok_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test iteration through devices by drvdata */
+static int dm_test_uclass_drvdata(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_first_device_drvdata(UCLASS_TEST_FDT,
+						DM_TEST_TYPE_FIRST, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_assertok(uclass_first_device_drvdata(UCLASS_TEST_FDT,
+						DM_TEST_TYPE_SECOND, &dev));
+	ut_asserteq_str("d-test", dev->name);
+
+	ut_asserteq(-ENODEV, uclass_first_device_drvdata(UCLASS_TEST_FDT,
+							 DM_TEST_TYPE_COUNT,
+							 &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_uclass_drvdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/u-boot/test/dm/test-main.c b/u-boot/test/dm/test-main.c
index 4478e6b8fc..bc610e2001 100644
--- a/u-boot/test/dm/test-main.c
+++ b/u-boot/test/dm/test-main.c
@@ -45,15 +45,13 @@ static int dm_test_init(struct unit_test_state *uts, bool of_live)
 static int do_autoprobe(struct unit_test_state *uts)
 {
 	struct udevice *dev;
-	int ret;
 
 	/* Scanning the uclass is enough to probe all the devices */
-	for (ret = uclass_first_device(UCLASS_TEST, &dev);
-	     dev;
-	     ret = uclass_next_device(&dev))
+	for (uclass_first_device(UCLASS_TEST, &dev); dev;
+	     uclass_next_device(&dev))
 		;
 
-	return ret;
+	return 0;
 }
 
 static int dm_test_destroy(struct unit_test_state *uts)