diff --git a/vendor/rkh/patches/third_party/u-boot-2010.01/u-boot-2020.01.patch b/vendor/rkh/patches/third_party/u-boot-2010.01/u-boot-2020.01.patch
new file mode 100644
index 0000000000000000000000000000000000000000..aa7d615912c679a83718601ead638b75f99b2aa8
--- /dev/null
+++ b/vendor/rkh/patches/third_party/u-boot-2010.01/u-boot-2020.01.patch
@@ -0,0 +1,402993 @@
+diff --git a/Kconfig b/Kconfig
+index 92fc4fc..4a5d2c3 100644
+--- a/Kconfig
++++ b/Kconfig
+@@ -309,8 +309,8 @@ config ANDROID_BOOT_IMAGE
+
+ config FIT
+ bool "Support Flattened Image Tree"
+- select MD5
+- select SHA1
++ select MD5 if !VENDOR_MC
++ select SHA1 if !VENDOR_MC
+ help
+ This option allows you to boot the new uImage structure,
+ Flattened Image Tree. FIT is formally a FDT, which can include
+@@ -347,11 +347,21 @@ config FIT_ENABLE_SHA256_SUPPORT
+ SHA256 variant is supported: SHA512 and others are not currently
+ supported in U-Boot.
+
++config FIT_FULL_CHECK
++ bool "Do a full check of the FIT before using it"
++ default y
++ help
++ Enable this do a full check of the FIT to make sure it is valid. This
++ helps to protect against carefully crafted FITs which take advantage
++ of bugs or omissions in the code. This includes a bad structure,
++ multiple root nodes and the like.
++
+ config FIT_SIGNATURE
+ bool "Enable signature verification of FIT uImages"
+ depends on DM
+ select HASH
+ select RSA
++ select FIT_FULL_CHECK
+ help
+ This option enables signature verification of FIT uImages,
+ using a hash signed and verified using RSA. If
+@@ -383,6 +393,14 @@ config FIT_ENABLE_RSASSA_PSS_SUPPORT
+ Enable this to support the pss padding algorithm as described
+ in the rfc8017 (https://tools.ietf.org/html/rfc8017).
+
++config FIT_CIPHER
++ bool "Enable ciphering data in a FIT uImages"
++ depends on DM
++ select AES
++ help
++ Enable the feature of data ciphering/unciphering in the tool mkimage
++ and in the u-boot support of the FIT image.
++
+ config FIT_VERBOSE
+ bool "Show verbose messages when FIT images fail"
+ help
+@@ -427,11 +445,20 @@ config SPL_FIT_PRINT
+ help
+ Support printing the content of the fitImage in a verbose manner in SPL.
+
++config SPL_FIT_FULL_CHECK
++ bool "Do a full check of the FIT before using it"
++ help
++ Enable this do a full check of the FIT to make sure it is valid. This
++ helps to protect against carefully crafted FITs which take advantage
++ of bugs or omissions in the code. This includes a bad structure,
++ multiple root nodes and the like.
++
+ config SPL_FIT_SIGNATURE
+ bool "Enable signature verification of FIT firmware within SPL"
+ depends on SPL_DM
+ select SPL_FIT
+ select SPL_RSA
++ select SPL_FIT_FULL_CHECK
+
+ config SPL_LOAD_FIT
+ bool "Enable SPL loading U-Boot as a FIT (basic fitImage features)"
+@@ -595,3 +622,5 @@ source "fs/Kconfig"
+ source "lib/Kconfig"
+
+ source "test/Kconfig"
++
++source "product/Kconfig"
+diff --git a/Makefile b/Makefile
+index 1766f5a..e1f1215 100644
+--- a/Makefile
++++ b/Makefile
+@@ -16,7 +16,7 @@ NAME =
+ # (this increases performance and avoids hard-to-debug behaviour);
+ # o Look for make include files relative to root of kernel src
+ MAKEFLAGS += -rR --include-dir=$(CURDIR)
+-
++-include include/autoconf.mk
+ # Determine host architecture
+ include include/host_arch.h
+ MK_ARCH="${shell uname -m}"
+@@ -34,7 +34,7 @@ else ifeq ("riscv32", $(MK_ARCH))
+ else ifeq ("riscv64", $(MK_ARCH))
+ export HOST_ARCH=$(HOST_ARCH_RISCV64)
+ endif
+-undefine MK_ARCH
++#undefine MK_ARCH #change open souce code warning
+
+ # Avoid funny character set dependencies
+ unexport LC_ALL
+@@ -311,7 +311,7 @@ os_x_before = $(shell if [ $(DARWIN_MAJOR_VERSION) -le $(1) -a \
+ $(DARWIN_MINOR_VERSION) -le $(2) ] ; then echo "$(3)"; else echo "$(4)"; fi ;)
+
+ os_x_after = $(shell if [ $(DARWIN_MAJOR_VERSION) -ge $(1) -a \
+- $(DARWIN_MINOR_VERSION) -ge $(2) ] ; then echo "$(3)"; else echo "$(4)"; fi ;)
++ $(DARWIN_MINOR_VERSION) -ge $(2) ] ; then echo "$(3)"; else echo "$(4)"; fi ;)
+
+ # Snow Leopards build environment has no longer restrictions as described above
+ HOSTCC = $(call os_x_before, 10, 5, "cc", "gcc")
+@@ -323,7 +323,7 @@ HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress")
+ # tools
+ HOSTLDFLAGS += $(call os_x_before, 10, 7, "", "-Xlinker -no_pie")
+
+-# macOS Mojave (10.14.X)
++# macOS Mojave (10.14.X)
+ # Undefined symbols for architecture x86_64: "_PyArg_ParseTuple"
+ HOSTLDFLAGS += $(call os_x_after, 10, 14, "-lpython -dynamclib", "")
+ endif
+@@ -407,6 +407,7 @@ PYTHON3 = python3
+ DTC ?= $(objtree)/scripts/dtc/dtc
+ CHECK = sparse
+
++HW_DIR = hw_compressed
+ CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
+ -Wbitwise -Wno-return-void -D__CHECK_ENDIAN__ $(CF)
+
+@@ -415,7 +416,8 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__
+ KBUILD_CFLAGS := -Wall -Wstrict-prototypes \
+ -Wno-format-security \
+ -fno-builtin -ffreestanding $(CSTD_FLAG)
+-KBUILD_CFLAGS += -fshort-wchar -fno-strict-aliasing
++# del -fshort-wchar Compiling Options change warning
++KBUILD_CFLAGS += -fno-strict-aliasing
+ KBUILD_AFLAGS := -D__ASSEMBLY__
+
+ # Don't generate position independent code
+@@ -724,15 +726,15 @@ HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makef
+ libs-y += lib/
+ libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
+ libs-$(CONFIG_OF_EMBED) += dts/
+-libs-y += fs/
+-libs-y += net/
+-libs-y += disk/
++libs-$(CONFIG_PARTITIONS) += fs/
++libs-$(CONFIG_NET) += net/
++libs-$(CONFIG_PARTITIONS) += disk/
+ libs-y += drivers/
+ libs-y += drivers/dma/
+ libs-y += drivers/gpio/
+ libs-y += drivers/i2c/
+-libs-y += drivers/net/
+-libs-y += drivers/net/phy/
++libs-$(CONFIG_NET) += drivers/net/
++libs-$(CONFIG_NET) += drivers/net/phy/
+ libs-y += drivers/power/ \
+ drivers/power/domain/ \
+ drivers/power/fuel_gauge/ \
+@@ -746,18 +748,19 @@ libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
+ libs-$(CONFIG_SYS_FSL_MMDC) += drivers/ddr/fsl/
+ libs-$(CONFIG_$(SPL_)ALTERA_SDRAM) += drivers/ddr/altera/
+ libs-y += drivers/serial/
+-libs-y += drivers/usb/cdns3/
+-libs-y += drivers/usb/dwc3/
+-libs-y += drivers/usb/common/
+-libs-y += drivers/usb/emul/
+-libs-y += drivers/usb/eth/
++libs-$(CONFIG_USB) += drivers/usb/cdns3/
++libs-$(CONFIG_USB) += drivers/usb/dwc3/
++libs-$(CONFIG_USB) += drivers/usb/common/
++libs-$(CONFIG_USB) += drivers/usb/emul/
++libs-$(CONFIG_USB) += drivers/usb/eth/
+ libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/
+ libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/udc/
+-libs-y += drivers/usb/host/
+-libs-y += drivers/usb/musb/
+-libs-y += drivers/usb/musb-new/
+-libs-y += drivers/usb/phy/
+-libs-y += drivers/usb/ulpi/
++libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/udc3/
++libs-$(CONFIG_USB_HOST) += drivers/usb/host/
++libs-$(CONFIG_USB) += drivers/usb/musb/
++libs-$(CONFIG_USB) += drivers/usb/musb-new/
++libs-$(CONFIG_USB) += drivers/usb/phy/
++libs-$(CONFIG_USB) += drivers/usb/ulpi/
+ libs-y += cmd/
+ libs-y += common/
+ libs-y += env/
+@@ -767,6 +770,26 @@ libs-$(CONFIG_UNIT_TEST) += test/ test/dm/
+ libs-$(CONFIG_UT_ENV) += test/env/
+ libs-$(CONFIG_UT_OPTEE) += test/optee/
+ libs-$(CONFIG_UT_OVERLAY) += test/overlay/
++# for ot_osd
++sinclude Makefile-otproduct
++
++export CONFIG_PRODUCTNAME
++
++ifdef CONFIG_CIPHER_ENABLE
++libs-$(CONFIG_CIPHER_ENABLE) += product/security_subsys/cipher/
++endif
++ifdef CONFIG_KLAD_ENABLE
++libs-$(CONFIG_KLAD_ENABLE) += product/security_subsys/klad/src/
++endif
++ifdef CONFIG_OTP_ENABLE
++libs-$(CONFIG_OTP_ENABLE) += product/security_subsys/otp/src/
++endif
++
++libs-$(CONFIG_I2C_BSP) += product/i2c/
++
++libs-$(CONFIG_AUTO_UPDATE) += product/update/
++
++libs-y += securec/src/
+
+ libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
+
+@@ -1148,7 +1171,16 @@ endif
+ ifeq ($(CONFIG_MULTI_DTB_FIT),y)
+ IMX_DEPS = u-boot-fit-dtb.bin
+ endif
++.PHONY: u-boot-z.bin
++u-boot-z.bin: $(CURDIR)/u-boot.bin
++ make -C $(CURDIR)/arch/$(ARCH)/cpu/$(CPU)/$(SOC)/$(HW_DIR)/ \
++ CROSS_COMPILE=$(CROSS_COMPILE) \
++ BINIMAGE=$(CURDIR)/u-boot.bin TOPDIR=$(CURDIR)
+
++.PHONY: u-boot-z.clean
++u-boot-z.clean:
++ make -C $(CURDIR)/arch/$(ARCH)/cpu/$(CPU)/$(SOC)/$(HW_DIR) \
++ CROSS_COMPILE=$(CROSS_COMPILE) clean
+ %.imx: $(IMX_DEPS) %.bin
+ $(Q)$(MAKE) $(build)=arch/arm/mach-imx $@
+ $(BOARD_SIZE_CHECK)
+@@ -1755,7 +1787,12 @@ prepare0: archprepare FORCE
+ $(Q)$(MAKE) $(build)=.
+
+ # All the preparing..
++ifdef CONFIG_DDR_TRAINING_V2
++prepare: ddr_training_prepare
++ddr_training_prepare: prepare0
++else
+ prepare: prepare0
++endif
+
+ # Generate some files
+ # ---------------------------------------------------------------------------
+@@ -1950,7 +1987,7 @@ PHONY += $(clean-dirs) clean archclean
+ $(clean-dirs):
+ $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
+
+-clean: $(clean-dirs)
++clean: $(clean-dirs) ddr_training_clean
+ $(call cmd,rmdirs)
+ $(call cmd,rmfiles)
+ @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+@@ -2163,6 +2200,26 @@ endif
+
+ endif # skip-makefile
+
++ifneq ($(filter $(CONFIG_PRODUCTNAME), "ss928v100" "ss927v100"),)
++DDRT_DEFAULT := default_v2
++else
++DDRT_DEFAULT := default
++endif
++
++DDR_SSRC := ddr_training_custom.h ddr_training_custom.c
++
++ddr_training_prepare:$(DDR_SSRC)
++ make -C $(srctree)/drivers/ddr/vendor/$(DDRT_DEFAULT)/cmd_bin all
++
++ddr_training_clean:
++ make -C $(srctree)/drivers/ddr/vendor/$(DDRT_DEFAULT)/cmd_bin clean
++ @for file in $(DDR_SSRC); \
++ do \
++ rm -f $(srctree)/drivers/ddr/vendor/$(DDRT_DEFAULT)/$$file; \
++ done
++ @if [ -f $(srctree)/ddr_cmd.bin ]; then rm $(srctree)/ddr_cmd.bin; fi;
++$(DDR_SSRC):
++ ln -sf ../$(SOC)/$@ $(CURDIR)/drivers/ddr/vendor/$(DDRT_DEFAULT)/$@
+ PHONY += FORCE
+ FORCE:
+
+diff --git a/Makefile-otproduct b/Makefile-otproduct
+new file mode 100644
+index 0000000..048d959
+--- /dev/null
++++ b/Makefile-otproduct
+@@ -0,0 +1,100 @@
++# FOR AUDIO
++ifeq ($(CONFIG_AUDIO_ENABLE), y)
++ifeq ($(CONFIG_PRODUCTNAME),"ss101v200")
++libs-y += product/audio/acodec/v750/
++libs-y += product/audio/ao/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v500")
++libs-y += product/audio/acodec/v750/
++libs-y += product/audio/ao/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v300")
++libs-y += product/audio/acodec/v750/
++libs-y += product/audio/ao/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v600")
++libs-y += product/audio/acodec/v750/
++libs-y += product/audio/ao/ss101v200/
++endif
++endif
++
++ifeq ($(CONFIG_OSD_ENABLE),y)
++# FOR DEC of all chip
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v200")
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v500")
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v300")
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v600")
++libs-y += ./product/ot_osd/dec/
++endif
++endif
++endif
++endif
++
++# FOR VO,HDMI,MIPI_Tx of ss919v100
++ifeq ($(CONFIG_PRODUCTNAME),"ss919v100")
++libs-y += ./product/ot_osd/vo/ss919v100/
++libs-y += ./product/ot_osd/mipi_tx/ss919v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss918v100")
++libs-y += ./product/ot_osd/vo/ss918v100/
++libs-y += ./product/ot_osd/mipi_tx/ss918v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss013v100")
++libs-y += ./product/ot_osd/vo/ss918v100/
++libs-y += ./product/ot_osd/mipi_tx/ss918v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss812v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss813v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss815v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v500")
++libs-y += ./product/ot_osd/vo/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v200")
++libs-y += ./product/ot_osd/vo/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v300")
++libs-y += ./product/ot_osd/vo/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v600")
++libs-y += ./product/ot_osd/vo/ss101v200/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss312v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss313v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss011v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss012v100")
++libs-y += ./product/ot_osd/vo/ss812v100/
++libs-y += ./product/ot_osd/mipi_tx/ss812v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++libs-y += ./product/ot_osd/rgb/ss812v100/
++else ifeq ($(CONFIG_PRODUCTNAME),"ss015v100")
++libs-y += ./product/ot_osd/vo/ss919v100/
++libs-y += ./product/ot_osd/mipi_tx/ss919v100/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++else ifeq ($(CONFIG_PRODUCTNAME),$(filter $(CONFIG_PRODUCTNAME), "ss528v100" "ss625v100" "ss524v100" "ss522v101" "ss522v100" "ss615v100"))
++libs-y += ./product/ot_osd/vo/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++else ifeq ($(CONFIG_PRODUCTNAME),$(filter $(CONFIG_PRODUCTNAME), "ss928v100" "ss927v100"))
++libs-y += ./product/ot_osd/vo/
++libs-y += ./product/ot_osd/hdmi/hdmi_2_0/drv/
++libs-y += ./product/ot_osd/mipi_tx/ss928v100/
++else
++$(warning "warning: "$(CONFIG_PRODUCTNAME)" is invalid")
++endif
++
++endif # end of ifeq ($(CONFIG_OSD_ENABLE),y)
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 36c9c2f..d4a7fae 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1229,6 +1229,25 @@ config TARGET_HIKEY
+ Support for HiKey 96boards platform. It features a HI6220
+ SoC, with 8xA53 CPU, mali450 gpu, and 1GB RAM.
+
++config TARGET_SS928V100
++ bool "Support SS928V100"
++ select ARM64
++ select DM
++ help
++ Support for SS928V100 platform.
++
++config TARGET_SS927V100
++ bool "Support SS927V100"
++ select ARM64
++ select DM
++ help
++ Support for SS927V100 platform.
++
++config ARCH_VENDOR
++ bool "VENDOR SoCs"
++ select DM
++
++
+ config TARGET_HIKEY960
+ bool "Support HiKey960 96boards Consumer Edition Platform"
+ select ARM64
+@@ -1690,6 +1709,8 @@ source "arch/arm/mach-exynos/Kconfig"
+
+ source "arch/arm/mach-highbank/Kconfig"
+
++source "arch/arm/mach-vendor/Kconfig"
++
+ source "arch/arm/mach-integrator/Kconfig"
+
+ source "arch/arm/mach-k3/Kconfig"
+@@ -1816,6 +1837,8 @@ source "board/freescale/s32v234evb/Kconfig"
+ source "board/grinn/chiliboard/Kconfig"
+ source "board/gumstix/pepper/Kconfig"
+ source "board/hisilicon/hikey/Kconfig"
++source "board/vendor/ss928v100/Kconfig"
++source "board/vendor/ss927v100/Kconfig"
+ source "board/hisilicon/hikey960/Kconfig"
+ source "board/hisilicon/poplar/Kconfig"
+ source "board/isee/igep003x/Kconfig"
+@@ -1846,6 +1869,6 @@ endmenu
+ config SPL_LDSCRIPT
+ default "arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds" if (ARCH_MX23 || ARCH_MX28) && !SPL_FRAMEWORK
+ default "arch/arm/cpu/arm1136/u-boot-spl.lds" if CPU_ARM1136
+- default "arch/arm/cpu/armv8/u-boot-spl.lds" if ARM64
++ default "arch/arm/cpu/armv8/u-boot-spl.lds" if ARM64 && !TARGET_SS928V100 && !TARGET_SS927V100
+
+
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 856f2d8..5990fe6 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -59,6 +59,7 @@ machine-$(CONFIG_ARCH_DAVINCI) += davinci
+ machine-$(CONFIG_ARCH_EXYNOS) += exynos
+ machine-$(CONFIG_ARCH_HIGHBANK) += highbank
+ machine-$(CONFIG_ARCH_K3) += k3
++machine-$(CONFIG_ARCH_VENDOR) += vendor
+ machine-$(CONFIG_ARCH_KEYSTONE) += keystone
+ # TODO: rename CONFIG_KIRKWOOD -> CONFIG_ARCH_KIRKWOOD
+ machine-$(CONFIG_KIRKWOOD) += kirkwood
+diff --git a/arch/arm/config.mk b/arch/arm/config.mk
+index f256031..ea657e9 100644
+--- a/arch/arm/config.mk
++++ b/arch/arm/config.mk
+@@ -132,11 +132,11 @@ endif
+
+ # limit ourselves to the sections we want in the .bin.
+ ifdef CONFIG_ARM64
+-OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \
++OBJCOPYFLAGS += -j .text -j .image -j .secure_text -j .secure_data -j .rodata -j .data \
+ -j .u_boot_list -j .rela.dyn -j .got -j .got.plt \
+ -j .binman_sym_table -j .text_rest
+ else
+-OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
++OBJCOPYFLAGS += -j .text -j .secure_text -j .image -j .secure_data -j .rodata -j .hash \
+ -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \
+ -j .binman_sym_table -j .text_rest
+ endif
+diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig
+index 73d57a2..61782d9 100644
+--- a/arch/arm/cpu/armv7/Kconfig
++++ b/arch/arm/cpu/armv7/Kconfig
+@@ -11,7 +11,7 @@ config ARCH_SUPPORT_PSCI
+
+ config ARMV7_NONSEC
+ bool "Enable support for booting in non-secure mode" if EXPERT
+- depends on CPU_V7_HAS_NONSEC
++ depends on CPU_V7_HAS_NONSEC
+ default y
+ ---help---
+ Say Y here to enable support for booting in non-secure / SVC mode.
+diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
+index 99eb7db..b70a6da 100644
+--- a/arch/arm/cpu/armv7/cache_v7.c
++++ b/arch/arm/cpu/armv7/cache_v7.c
+@@ -117,9 +117,32 @@ void flush_dcache_all(void)
+ */
+ void invalidate_dcache_range(unsigned long start, unsigned long stop)
+ {
+- check_cache_range(start, stop);
++ unsigned int align = 0;
+
+- v7_dcache_maint_range(start, stop, ARMV7_DCACHE_INVAL_RANGE);
++ if (!IS_ALIGNED(start, CONFIG_SYS_CACHELINE_SIZE)){
++ align = 1;
++ }
++
++ if (!IS_ALIGNED(stop, CONFIG_SYS_CACHELINE_SIZE)){
++ align = 1;
++ }
++
++ if (!align){
++ v7_dcache_maint_range(start, stop, ARMV7_DCACHE_INVAL_RANGE);
++ }
++ else{
++ u32 line_len, ccsidr;
++
++ ccsidr = get_ccsidr();
++ line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
++ CCSIDR_LINE_SIZE_OFFSET) + 2;
++ /* Converting from words to bytes */
++ line_len += 2;
++ /* converting from log2(linelen) to linelen */
++ line_len = 1 << line_len;
++
++ v7_dcache_clean_inval_range(start, stop, line_len);
++ }
+
+ v7_outer_cache_inval_range(start, stop);
+ }
+@@ -131,8 +154,6 @@ void invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+ void flush_dcache_range(unsigned long start, unsigned long stop)
+ {
+- check_cache_range(start, stop);
+-
+ v7_dcache_maint_range(start, stop, ARMV7_DCACHE_CLEAN_INVAL_RANGE);
+
+ v7_outer_cache_flush_range(start, stop);
+diff --git a/arch/arm/cpu/armv7/config.mk b/arch/arm/cpu/armv7/config.mk
+index 68036d6..e85da3d 100644
+--- a/arch/arm/cpu/armv7/config.mk
++++ b/arch/arm/cpu/armv7/config.mk
+@@ -8,4 +8,5 @@
+ # the default so we must pass in -mno-unaligned-access so that it is aware
+ # of our decision.
+ PF_NO_UNALIGNED := $(call cc-option, -mno-unaligned-access,)
++PF_NO_UNALIGNED += $(call cc-option, -fno-store-merging,)
+ PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
+diff --git a/arch/arm/cpu/armv7/cpu.c b/arch/arm/cpu/armv7/cpu.c
+index 68807d2..24a7383 100644
+--- a/arch/arm/cpu/armv7/cpu.c
++++ b/arch/arm/cpu/armv7/cpu.c
+@@ -55,8 +55,9 @@ int cleanup_before_linux_select(int flags)
+ * any static data) So just invalidate the entire d-cache again
+ * to avoid coherency problems for kernel
+ */
++#ifndef CONFIG_SYS_LEVEL2_CACHE_SHARE
+ invalidate_dcache_all();
+-
++#endif
+ icache_disable();
+ invalidate_icache_all();
+ } else {
+diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
+old mode 100644
+new mode 100755
+index dcb4195..e02cb55
+--- a/arch/arm/cpu/armv7/start.S
++++ b/arch/arm/cpu/armv7/start.S
+@@ -88,7 +88,6 @@ switch_to_hypervisor_ret:
+ bl cpu_init_crit
+ #endif
+ #endif
+-
+ bl _main
+
+ /*------------------------------------------------------------------------------*/
+@@ -120,7 +119,6 @@ ENTRY(save_boot_params)
+ b save_boot_params_ret @ back to my caller
+ ENDPROC(save_boot_params)
+ .weak save_boot_params
+-
+ #ifdef CONFIG_ARMV7_LPAE
+ ENTRY(switch_to_hypervisor)
+ b switch_to_hypervisor_ret
+diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
+index 16c83e8..24e6542 100644
+--- a/arch/arm/cpu/armv8/Kconfig
++++ b/arch/arm/cpu/armv8/Kconfig
+@@ -110,7 +110,8 @@ config PSCI_RESET
+ !TARGET_LS1046AFRWY && \
+ !TARGET_LS2081ARDB && !TARGET_LX2160ARDB && \
+ !TARGET_LX2160AQDS && \
+- !ARCH_UNIPHIER && !TARGET_S32V234EVB
++ !ARCH_UNIPHIER && !TARGET_S32V234EVB && \
++ !TARGET_SS928V100 && !TARGET_SS927V100
+ help
+ Most armv8 systems have PSCI support enabled in EL3, either through
+ ARM Trusted Firmware or other firmware.
+diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c
+index 46e6329..d673548 100644
+--- a/arch/arm/cpu/armv8/generic_timer.c
++++ b/arch/arm/cpu/armv8/generic_timer.c
+@@ -14,7 +14,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ /*
+ * Generic timer implementation of get_tbclk()
+ */
+-unsigned long get_tbclk(void)
++__weak unsigned long get_tbclk(void)
+ {
+ unsigned long cntfrq;
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq));
+@@ -32,7 +32,7 @@ unsigned long get_tbclk(void)
+ * was the same in both reads.
+ * Assumes that the CPU runs in much higher frequency than the timer.
+ */
+-unsigned long timer_read_counter(void)
++__weak unsigned long timer_read_counter(void)
+ {
+ unsigned long cntpct;
+ unsigned long temp;
+@@ -86,13 +86,19 @@ unsigned long timer_read_counter(void)
+ }
+ #endif
+
+-uint64_t get_ticks(void)
++__weak uint64_t get_ticks(void)
+ {
+ unsigned long ticks = timer_read_counter();
+
+ gd->arch.tbl = ticks;
+
+- return ticks;
++ /* increment tbu if tbl has rolled over */
++ if (ticks < gd->timebase_l) {
++ gd->timebase_h++;
++ }
++
++ gd->timebase_l = ticks;
++ return ((uint64_t)gd->timebase_h << 32) | gd->timebase_l;
+ }
+
+ unsigned long usec2ticks(unsigned long usec)
+diff --git a/arch/arm/cpu/armv8/ss927v100/hw_compressed/Makefile b/arch/arm/cpu/armv8/ss927v100/hw_compressed/Makefile
+new file mode 100644
+index 0000000..e5184b0
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/hw_compressed/Makefile
+@@ -0,0 +1,154 @@
++################################################################################
++
++PWD = $(shell pwd)
++CROSS_COMPILE =: aarch64-c01v01-linux-gnu-
++TOPDIR =
++
++################################################################################
++CC := $(CROSS_COMPILE)gcc
++AR := $(CROSS_COMPILE)ar
++LD := $(CROSS_COMPILE)ld
++OBJCOPY := $(CROSS_COMPILE)objcopy
++OBJDUMP := $(CROSS_COMPILE)objdump
++
++
++################################################################################
++BOOT := u-boot-$(SOC)
++TEXTBASE := 0x48700000
++CFLAGS :=-Os -fno-builtin -ffreestanding \
++ -D__KERNEL__ -DTEXT_BASE=$(TEXTBASE) \
++ -I$(TOPDIR)/include \
++ -I$(TOPDIR)/include/linux \
++ -I$(TOPDIR)/drivers/ddr/vendor/default_v2 \
++ -I$(TOPDIR)/drivers/ddr/vendor/$(SOC) \
++ -I$(TOPDIR)/arch/arm/include \
++ -fno-pic -mstrict-align -ffunction-sections \
++ -fdata-sections -fno-common -ffixed-r9 \
++ -fno-common -ffixed-x18 -pipe -march=armv8-a \
++ -Wall -Wstrict-prototypes -fno-stack-protector \
++ -D__LINUX_ARM_ARCH__=8 -D__ARM__ \
++ -DCONFIG_SS927V100 -DCONFIG_MMC -DDDR_TRAINING_MEM_FUNC \
++ $(MKFLAGS) -fno-strict-aliasing -mcmodel=tiny
++
++################################################################################
++
++START := start.o
++COBJS := lowlevel_init_v300.o \
++ init_registers.o \
++ sdhci_boot.o \
++ uart.o \
++ ddr_training_impl.o \
++ ddr_ac_training.o \
++ ddr_dcc_training.o \
++ ddr_ddrt_training.o \
++ ddr_gate_training.o \
++ ddr_lpca_training.o \
++ ddr_mpr_training.o \
++ ddr_pcode_training.o \
++ ddr_wl_training.o \
++ ddr_training_ctl.o \
++ ddr_training_boot.o \
++ ddr_training_custom.o \
++ ddr_training_console.o \
++ startup.o \
++ image_data.o \
++ div0.o \
++ reset.o
++
++SSRC := arch/arm/cpu/armv8/$(SOC)/start.S \
++ arch/arm/cpu/armv8/$(SOC)/reset.S \
++ arch/arm/cpu/armv8/$(SOC)/sdhci_boot.c \
++ arch/arm/cpu/armv8/$(SOC)/uart.S \
++ arch/arm/cpu/armv8/$(SOC)/init_registers.c \
++ arch/arm/cpu/armv8/$(SOC)/lowlevel_init_v300.c \
++ drivers/ddr/vendor/default_v2/ddr_training_impl.c \
++ drivers/ddr/vendor/default_v2/ddr_ac_training.c \
++ drivers/ddr/vendor/default_v2/ddr_dcc_training.c \
++ drivers/ddr/vendor/default_v2/ddr_ddrt_training.c \
++ drivers/ddr/vendor/default_v2/ddr_gate_training.c \
++ drivers/ddr/vendor/default_v2/ddr_lpca_training.c \
++ drivers/ddr/vendor/default_v2/ddr_mpr_training.c \
++ drivers/ddr/vendor/default_v2/ddr_pcode_training.c \
++ drivers/ddr/vendor/default_v2/ddr_wl_training.c \
++ drivers/ddr/vendor/default_v2/ddr_training_ctl.c \
++ drivers/ddr/vendor/default_v2/ddr_training_boot.c \
++ drivers/ddr/vendor/default_v2/ddr_training_console.c \
++ drivers/ddr/vendor/$(SOC)/ddr_training_custom.c \
++ arch/arm/lib/div0.c \
++ lib/hw_dec/hw_decompress.c \
++ lib/hw_dec/hw_decompress_$(SOC).c \
++ lib/hw_dec/hw_decompress_v2.c \
++ lib/hw_dec/hw_decompress_v2.h
++
++REG := $(wildcard $(TOPDIR)/*.reg $(TOPDIR)/.reg)
++SRC := $(notdir $(SSRC))
++
++################################################################################
++.PHONY: $(BOOT).bin
++$(BOOT).bin: $(BOOT).tmp regfile
++ @dd if=./$(BOOT).tmp of=./tmp1 bs=1 count=64 2>/dev/null
++ @dd if=$(REG) of=./tmp2 bs=11008 conv=sync 2>/dev/null
++ @dd if=./$(BOOT).tmp of=./tmp3 bs=1 skip=11072 2>/dev/null
++ @cat tmp1 tmp2 tmp3 > $(BOOT).bin
++ @rm -f tmp1 tmp2 tmp3
++ @chmod 754 $(BOOT).bin
++ @cp -fv $@ $(TOPDIR)
++ @echo $(BOOT).bin is Ready.
++
++$(BOOT).tmp: $(BOOT).elf
++ $(OBJCOPY) -O srec $< $(BOOT).srec
++ $(OBJCOPY) -j .text -O binary $< $(BOOT).text
++ $(OBJCOPY) --gap-fill=0xff -O binary $< $@
++
++$(BOOT).elf: image_data.gzip $(SRC) $(START) $(COBJS)
++ $(LD) -Bstatic -T u-boot.lds -Ttext $(TEXTBASE) $(START) \
++ $(COBJS) -Map $(BOOT).map -o $@
++ $(OBJDUMP) -d $@ > $@.asm
++
++.PHONY: regfile
++regfile:
++ @if [ "$(words $(REG))" = "0" ]; then ( \
++ echo '***' Need '.reg' or '*.reg' file in directory $(TOPDIR); \
++ exit 1; \
++ ) fi
++ @if [ "$(words $(REG))" != "1" ]; then ( \
++ echo '***' Found multi '.reg' or '*.reg' file in directory $(TOPDIR); \
++ echo '***' Files: $(notdir $(REG)); \
++ exit 1; \
++ ) fi
++
++################################################################################
++start.o: start.S
++ $(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c
++
++# -1 : --fast -9 : --best
++image_data.gzip: $(BINIMAGE)
++ gzip -fNqc -7 $< > $@
++
++%.o: %.c
++ $(CC) $(CFLAGS) -Wall -Wstrict-prototypes \
++ -fno-stack-protector -o $@ $< -c
++
++%.o: %.S
++ $(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c
++
++image_data.o: image_data.S image_data.gzip
++ $(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c
++
++#############################################################################
++
++$(SRC):
++ ln -sf ../../../../../../$(filter %/$@,$(SSRC)) $@
++################################################################################
++TMPS := $(COBJS) start.o $(SRC) \
++ $(BOOT).map $(BOOT).elf $(BOOT).srec $(BOOT).bin $(BOOT).text $(BOOT).tmp \
++ image_data.gzip
++
++distclean: clean
++
++clean:
++ -rm -f $(TMPS)
++
++################################################################################
++.PHONY: clean
++################################################################################
+diff --git a/arch/arm/cpu/armv8/ss927v100/hw_compressed/image_data.S b/arch/arm/cpu/armv8/ss927v100/hw_compressed/image_data.S
+new file mode 100644
+index 0000000..f8d2d36
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/hw_compressed/image_data.S
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++ .section .image,"a"
++ .globl input_data
++ /*gzip source addr must be 16 bytes aligned*/
++ .balign 16
++input_data:
++ .incbin "image_data.gzip"
++ .globl input_data_end
++input_data_end:
+diff --git a/arch/arm/cpu/armv8/ss927v100/hw_compressed/startup.c b/arch/arm/cpu/armv8/ss927v100/hw_compressed/startup.c
+new file mode 100644
+index 0000000..4d1785c
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/hw_compressed/startup.c
+@@ -0,0 +1,191 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++#include
++#include
++
++const uintptr_t image_entry = (CONFIG_SYS_TEXT_BASE);
++
++#define error(_s) uart_early_puts(_s)
++#define putstr(_s) uart_early_puts(_s)
++#define EXCEPTION_LEVEL1 1
++#define EXCEPTION_LEVEL2 2
++#include "hw_decompress.c"
++#define GZIP_SIZE_OFFSET 0x4
++
++void icache_enable(void);
++void invalidate_icache_all(void);
++void __asm_invalidate_icache_all(void);
++
++void start_armboot(void)
++{
++ unsigned char *pdst_h32 = NULL;
++ unsigned char *pdst_l32 = NULL;
++ unsigned char *input_data_h32 = NULL;
++ unsigned int image_data_len;
++ int pdst_len;
++ int ret;
++ uart_early_init();
++ uart_early_puts("\r\nUncompress ");
++
++ /* enable I-Cache */
++ icache_enable();
++
++ /* use direct address mode */
++ hw_dec_type = 0;
++ /* init hw decompress IP */
++ hw_dec_init();
++
++ /* start decompress */
++ pdst_l32 = (unsigned char *)(uintptr_t)image_entry;
++ image_data_len = input_data_end - input_data;
++ for (int i = 0; i < sizeof(pdst_len); i++)
++ *((char *)(&pdst_len) + i) = *((char *)(input_data_end -
++ GZIP_SIZE_OFFSET) + i);
++
++ ret = hw_dec_decompress(pdst_h32, pdst_l32, &pdst_len, input_data_h32,
++ input_data, image_data_len, NULL);
++ if (!ret) {
++ uart_early_puts("Ok!");
++ } else {
++ uart_early_puts("Fail!");
++ while (1);
++ }
++
++ /* uinit hw decompress IP */
++ hw_dec_uinit();
++ void (*uboot)(void);
++ uboot = (void (*))CONFIG_SYS_TEXT_BASE;
++ invalidate_icache_all();
++ uboot();
++}
++
++void hang(void)
++{
++ uart_early_puts("### ERROR ### Please RESET the board ###\n");
++ for (; ;);
++}
++
++void invalidate_icache_all(void)
++{
++ __asm_invalidate_icache_all();
++}
++
++static inline unsigned int current_el(void)
++{
++ unsigned int el;
++ asm volatile("mrs %0, CurrentEL" : "=r"(el) : : "cc");
++ return el >> 2; /* Move Left 2bit */
++}
++
++static void set_sctlr(unsigned int val)
++{
++ unsigned int el;
++
++ el = current_el();
++ if (el == EXCEPTION_LEVEL1)
++ asm volatile("msr sctlr_el1, %0" : : "r"(val) : "cc");
++ else if (el == EXCEPTION_LEVEL2)
++ asm volatile("msr sctlr_el2, %0" : : "r"(val) : "cc");
++ else
++ asm volatile("msr sctlr_el3, %0" : : "r"(val) : "cc");
++
++ asm volatile("isb");
++}
++
++static unsigned int get_sctlr(void)
++{
++ unsigned int el, val;
++
++ el = current_el();
++ if (el == EXCEPTION_LEVEL1)
++ asm volatile("mrs %0, sctlr_el1" : "=r"(val) : : "cc");
++ else if (el == EXCEPTION_LEVEL2)
++ asm volatile("mrs %0, sctlr_el2" : "=r"(val) : : "cc");
++ else
++ asm volatile("mrs %0, sctlr_el3" : "=r"(val) : : "cc");
++
++ return val;
++}
++
++void icache_enable(void)
++{
++ invalidate_icache_all();
++#define CR_I (1 << 12) /* Icache enable */
++ set_sctlr(get_sctlr() | CR_I);
++}
++
++void do_bad_sync(void)
++{
++ uart_early_puts("bad sync abort\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_sync(void)
++{
++ uart_early_puts("sync abort\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_bad_error(void)
++{
++ uart_early_puts("bad error\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_error(void)
++{
++ uart_early_puts("error\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_bad_fiq(void)
++{
++ uart_early_puts("bad fast interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_bad_irq(void)
++{
++ uart_early_puts("bad interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_fiq(void)
++{
++ uart_early_puts("fast interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_irq(void)
++{
++ uart_early_puts("interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
+diff --git a/arch/arm/cpu/armv8/ss927v100/hw_compressed/u-boot.lds b/arch/arm/cpu/armv8/ss927v100/hw_compressed/u-boot.lds
+new file mode 100644
+index 0000000..e0f0fdc
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/hw_compressed/u-boot.lds
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
++OUTPUT_ARCH(aarch64)
++ENTRY(_start)
++SECTIONS
++{
++ . = 0x48700000;
++ __image_copy_start =.;
++ . = ALIGN(8);
++ .text :
++ {
++ __text_start = .;
++ start.o (.text*)
++ init_registers.o (.text*)
++ lowlevel_init_v300.o (.text*)
++ ddr_training_impl.o (.text*)
++ ddr_ac_training.o (.text*)
++ ddr_dcc_training.o (.text*)
++ ddr_ddrt_training.o (.text*)
++ ddr_gate_training.o (.text*)
++ ddr_lpca_training.o (.text*)
++ ddr_mpr_training.o (.text*)
++ ddr_pcode_training.o (.text*)
++ ddr_wl_training.o (.text*)
++ ddr_training_console.o (.text*)
++ ddr_training_ctl.o (.text*)
++ ddr_training_boot.o (.text*)
++ ddr_training_custom.o (.text*)
++ uart.o (.text*)
++ div0.o (.text*)
++ sdhci_boot.o (.text*)
++ image_data.o (.text*)
++ startup.o(.text*)
++ reset.o(.text*)
++ __init_end = .;
++ ASSERT(((__init_end - __text_start) < 0x8000), "init sections too big!");
++ *(.text*)
++ }
++
++ . = ALIGN(8);
++ .image : { *(.image) }
++
++ . = ALIGN(8);
++ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
++
++ . = ALIGN(8);
++ .data : {
++ *(.data*)
++ }
++
++ . = ALIGN(8);
++
++ .got : { *(.got) }
++
++ . = ALIGN(8);
++ __image_copy_end =.;
++ __bss_start = .;
++ .bss :
++ {
++ *(.bss)
++ }
++ __bss_end = .;
++
++
++ _end = .;
++}
+diff --git a/arch/arm/cpu/armv8/ss927v100/init_registers.c b/arch/arm/cpu/armv8/ss927v100/init_registers.c
+new file mode 100644
+index 0000000..08cc9b6
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/init_registers.c
+@@ -0,0 +1,179 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#define W_WHETHER_WRITE (1 << 0)
++#define W_WHETHER_PM (1 << 1)
++#define W_WHETHER_BOOT_NORMAL (1 << 2)
++#define W_BIT_OFFSET 3
++#define W_BIT_MASK (0x1f << W_BIT_OFFSET)
++#define W_REG_BIT_OFFSET 11
++#define W_REG_BIT_MASK (0x1f << W_REG_BIT_OFFSET)
++
++#define R_WHETHER_READ (W_WHETHER_WRITE << 16)
++#define R_WHETHER_PM (W_WHETHER_PM << 16)
++#define R_WHETHER_BOOT_NORMAL (W_WHETHER_BOOT_NORMAL << 16)
++#define R_BIT_OFFSET (W_BIT_OFFSET + 16)
++#define R_BIT_MASK (W_BIT_MASK << 16)
++#define R_REG_BIT_OFFSET (W_REG_BIT_OFFSET + 16)
++#define R_REG_BIT_MASK (W_REG_BIT_MASK << 16)
++
++#define RW_BIT_NUM 32
++
++struct regentry {
++ unsigned int reg_addr;
++ unsigned int value;
++ unsigned int delay;
++ unsigned int attr;
++};
++
++static void dwb(void) /* drain write buffer */
++{
++}
++
++static void writel(unsigned val, unsigned addr)
++{
++ dwb();
++ (*(volatile unsigned *)(uintptr_t)(addr)) = (val);
++ dwb();
++}
++
++static void delay(void)
++{
++ __asm__ __volatile__("nop");
++}
++
++static void reg_read(struct regentry* const reg, unsigned int* const ret)
++{
++ unsigned int reg_val_r;
++ unsigned int bit_start_r;
++ unsigned int bit_num_r;
++
++ bit_start_r = ((reg->attr & R_REG_BIT_MASK) >> R_REG_BIT_OFFSET);
++ bit_num_r = ((reg->attr & R_BIT_MASK) >> R_BIT_OFFSET) + 1;
++ reg_val_r = (*(volatile unsigned *)(long)(reg->reg_addr));
++
++ if (bit_num_r != RW_BIT_NUM) {
++ reg_val_r >>= bit_start_r;
++ reg_val_r &= ((1 << bit_num_r) - 1);
++ }
++
++ *ret = ((reg_val_r == reg->value) ? 0 : 1);
++}
++
++static void reg_write(struct regentry *reg)
++{
++ unsigned int reg_val_w;
++ unsigned int delay_2;
++ unsigned int bit_start_w;
++ unsigned int bit_num_w;
++
++ delay_2 = reg->delay;
++ bit_start_w = ((reg->attr & W_REG_BIT_MASK) >> W_REG_BIT_OFFSET);
++ bit_num_w = ((reg->attr & W_BIT_MASK) >> W_BIT_OFFSET) + 1;
++ reg_val_w = (*(volatile unsigned *)(long)(reg->reg_addr));
++
++ if (bit_num_w == RW_BIT_NUM) {
++ reg_val_w = reg->value;
++ } else {
++ reg_val_w &= (~(((1 << bit_num_w) - 1) << bit_start_w));
++ reg_val_w |= (reg->value) << bit_start_w;
++ }
++ writel(reg_val_w, reg->reg_addr);
++
++ do {
++ delay();
++ } while (delay_2--);
++}
++
++static void read_write(struct regentry *reg, unsigned int pm)
++{
++ unsigned int ret;
++ unsigned int delay_1;
++
++ ret = 0;
++ delay_1 = reg->delay;
++
++ if (pm) {
++ if (reg->attr & W_WHETHER_PM) {
++ reg_write(reg);
++ } else if (reg->attr & R_WHETHER_PM) {
++ do {
++ reg_read(reg, &ret);
++ delay();
++ } while (ret);
++
++ do {
++ delay();
++ } while (delay_1--);
++ } else {
++ do {
++ delay();
++ } while (delay_1--);
++ }
++ } else {
++ if (reg->attr & W_WHETHER_BOOT_NORMAL) {
++ reg_write(reg);
++ } else if (reg->attr & R_WHETHER_BOOT_NORMAL) {
++ do {
++ reg_read(reg, &ret);
++ delay();
++ } while (ret);
++
++ do {
++ delay();
++ } while (delay_1--);
++ } else {
++ do {
++ delay();
++ } while (delay_1--);
++ }
++ }
++}
++
++static void part_read_write(struct regentry *reg_table, unsigned int pm)
++{
++ unsigned int i;
++
++ for (i = 0; ; i++) {
++ if ((!reg_table[i].reg_addr) && (!reg_table[i].value) &&
++ (!reg_table[i].delay) && (!reg_table[i].attr))
++ goto main_end;
++
++ read_write(®_table[i], pm);
++ }
++
++main_end:
++ delay();
++}
++
++/*
++ * base - reg base address
++ * pm - is suspend
++ * 0 normal
++ * 1 pm
++ */
++void init_registers(unsigned long base, unsigned long pm)
++{
++ struct regentry *reg_table = (struct regentry *)(uintptr_t)base;
++
++ part_read_write(reg_table, pm);
++}
++
+diff --git a/arch/arm/cpu/armv8/ss927v100/lowlevel_init_v300.c b/arch/arm/cpu/armv8/ss927v100/lowlevel_init_v300.c
+new file mode 100644
+index 0000000..4c048a1
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/lowlevel_init_v300.c
+@@ -0,0 +1,516 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include "ddr_interface.h"
++
++#define SYS_CTL_REG SYS_CTRL_REG_BASE
++
++#define OK 0
++#define ERROR (-1)
++#define CH0_DMC_CFG_DDRMODE 0x11148050
++#define CH0_DMC_CFG_RNKVOL_0 0x11148060
++#define CH0_DMC_CFG_RNKVOL_1 0x11148064
++
++#define CH1_DMC_CFG_DDRMODE 0x11149050
++#define CH1_DMC_CFG_RNKVOL_0 0x11149060
++#define CH1_DMC_CFG_RNKVOL_1 0x11149064
++
++#define CH2_DMC_CFG_DDRMODE 0x1114a050
++#define CH2_DMC_CFG_RNKVOL_0 0x1114a060
++#define CH2_DMC_CFG_RNKVOL_1 0x1114a064
++
++#define CH3_DMC_CFG_DDRMODE 0x1114b050
++#define CH3_DMC_CFG_RNKVOL_0 0x1114b060
++#define CH3_DMC_CFG_RNKVOL_1 0x1114b064
++
++#define CH0_QOS_CFG_DDRMODE 0x11144630
++#define CH0_QOS_CFG_RNKVOL_0 0x11144634
++#define CH0_QOS_CFG_RNKVOL_1 0x11144638
++
++#define CH1_QOS_CFG_DDRMODE 0x11144640
++#define CH1_QOS_CFG_RNKVOL_0 0x11144644
++#define CH1_QOS_CFG_RNKVOL_1 0x11144648
++
++#define CH2_QOS_CFG_DDRMODE 0x11144650
++#define CH2_QOS_CFG_RNKVOL_0 0x11144654
++#define CH2_QOS_CFG_RNKVOL_1 0x11144658
++
++#define CH3_QOS_CFG_DDRMODE 0x11144660
++#define CH3_QOS_CFG_RNKVOL_0 0x11144664
++#define CH3_QOS_CFG_RNKVOL_1 0x11144668
++
++static inline void delay(unsigned int num)
++{
++ volatile unsigned int i;
++
++ for (i = 0; i < (100 * num); i++) /* 100: Cycle */
++ __asm__ __volatile__("nop");
++}
++
++static inline void dwb(void) /* drain write buffer */
++{
++}
++
++static inline unsigned int readl(unsigned addr)
++{
++ unsigned int val;
++
++ val = (*(volatile unsigned int *)(long)(addr));
++ return val;
++}
++
++static inline void writel(unsigned val, unsigned addr)
++{
++ dwb();
++ (*(volatile unsigned *)(long)(addr)) = (val);
++ dwb();
++}
++
++#define REG_BASE_MISC 0x11020000
++#define DDRCA_REE_RANDOM_L 0x4040
++#define DDRCA_REE_RANDOM_H 0x4044
++#define DDRCA_TEE_RANDOM_L 0x4048
++#define DDRCA_TEE_RANDOM_H 0x404C
++#define DDRCA_EN 0x4050
++#define DDRCA_REE_UPDATE 0x4054
++#define DDRCA_TEE_UPDATE 0x4058
++#define DDR_CA_LOCK 0x405c
++#define RANDOM_SIZE 4
++
++#define REG_TSENSOR_CTRL 0x1102e000
++#define TSENSOR_CTRL0 0x0
++#define TSENSOR_CTRL0_CFG 0xc0300000
++#define TSENSOR_CTRL1 0x4
++#define TSENSOR_CTRL1_CFG 0x8
++
++#define SYSCTRL_REG 0x11020000
++#define HPM_CORE_VOL_REG (SYSCTRL_REG + 0x9004)
++#define HPM_MDA_VOL_REG (SYSCTRL_REG + 0x9104)
++#define HPM_NPU_VOL_REG (SYSCTRL_REG + 0x9204)
++#define HPM_MONITOR_CFG 0x60200001
++#define HPM_CORE_OFFSET 0xb030
++#define HPM_MDA_OFFSET 0xb020
++#define HPM_NPU_OFFSET 0xb010
++#define CYCLE_NUM 8
++#define HPM_NPU_REG0 0xb018
++#define HPM_NPU_REG1 0xb01c
++#define HPM_MDA_REG0 0xb028
++#define HPM_MDA_REG1 0xb02c
++#define HPM_CORE_REG0 0xb038
++#define HPM_CORE_REG1 0xb03c
++
++#define HPM_CLK_REG 0x11014a80
++#define HPM_CLK_CFG 0x30
++
++#define CPU_ISO_REG 0x1d821104
++
++#define TSENSOR_CTRL 0x70
++#define TSENSOR_STATUS0 0x8
++
++#define OTP_CPU_IF_REG 0x10120000
++#define OTP_HPM_CORE_OFFSET 0x1504
++#define OTP_HPM_MDA_OFFSET 0x1534
++#define OTP_HPM_NPU_OFFSET 0x1530
++#define OTP_SHPM_MDA_OFFSET 0x153c
++
++#define SYSCTRL_BASE_REG 0x11020000
++#define HPM_CORE_STORAGE_REG 0x340
++#define HPM_MDA_STORAGE_REG 0x344
++#define HPM_NPU_STORAGE_REG 0x348
++#define TEMPERATURE_STORAGE_REG 0x34c
++#define DELTA_V_STORAGE_REG 0x350
++#define CORE_DUTY_STORAGE_REG 0x354
++#define MDA_DUTY_STORAGE_REG 0x358
++#define NPU_DUTY_STORAGE_REG 0x35c
++
++/* physical max/min */
++#define CORE_VOLT_MAX 920
++#define CORE_VOLT_MIN 599
++
++#define MDA_VOLT_MAX 1049
++#define MDA_VOLT_MIN 600
++
++#define NPU_VOLT_MAX 1049
++#define NPU_VOLT_MIN 600
++
++/* curve max/min; voltage curve: v = (b - a * hpm) / 10 */
++#define CORE_CURVE_VLOT_MAX 850
++#define CORE_CURVE_VLOT_MIN 760
++#define CORE_CURVE_B 16200
++#define CORE_CURVE_A 20
++
++#define MEDIA_CURVE_VLOT_MAX 770
++#define MEDIA_CURVE_VLOT_MIN 690
++#define MEDIA_CURVE_B 11150
++#define MEDIA_CURVE_A 10
++
++
++#define NPU_CURVE_VLOT_MAX 810
++#define NPU_CURVE_VLOT_MIN 730
++#define NPU_CURVE_B 127500
++#define NPU_CURVE_A 125
++
++#define SVB_VER_REG 0x11020168
++#define SVB_VER 0x30303030
++#define temperature_formula(val) (((((val) - 116) * 165) / 806) - 40)
++#define duty_formula(max, min, val) ((((max) - (val)) * 416 + ((max) - (min) + 1) / 2) / ((max) - (min)) - 1)
++#define volt_regval_formula(val) (((val) << 16) + ((416 - 1) << 4) + 0x5)
++
++static unsigned hpm_value_avg(unsigned int *val, unsigned int num)
++{
++ unsigned int i;
++ unsigned tmp = 0;
++
++ for (i = 0; i < num; i++) /* 4: Cycle */
++ tmp += val[i];
++
++ return (tmp / CYCLE_NUM) >> 2;
++}
++
++static void get_hpm_value(unsigned int *hpm_core, unsigned int *hpm_npu,
++ unsigned int *hpm_mda)
++{
++ int i;
++ unsigned int temp;
++ unsigned int core_value[4] = {0, 0, 0, 0};
++ unsigned int mda_value[4] = {0, 0, 0, 0};
++ unsigned int npu_value[4] = {0, 0, 0, 0};
++
++ for (i = 0; i < CYCLE_NUM; i++) {
++ /* (at least 16us*4) */
++ delay(5); /* delay 5 s */
++ /* npu */
++ temp = readl(SYSCTRL_REG + HPM_NPU_REG0);
++ npu_value[1] += (temp >> 16) & 0x3ff;
++ npu_value[0] += temp & 0x3ff;
++ temp = readl(SYSCTRL_REG + HPM_NPU_REG1);
++ npu_value[3] += (temp >> 16) & 0x3ff;
++ npu_value[2] += temp & 0x3ff;
++
++ /* mda */
++ temp = readl(SYSCTRL_REG + HPM_MDA_REG0);
++ mda_value[1] += (temp >> 16) & 0x3ff;
++ mda_value[0] += temp & 0x3ff;
++ temp = readl(SYSCTRL_REG + HPM_MDA_REG1);
++ mda_value[3] += (temp >> 16) & 0x3ff;
++ mda_value[2] += temp & 0x3ff;
++
++ /* core */
++ temp = readl(SYSCTRL_REG + HPM_CORE_REG0);
++ core_value[1] += (temp >> 16) & 0x3ff;
++ core_value[0] += temp & 0x3ff;
++ temp = readl(SYSCTRL_REG + HPM_CORE_REG1);
++ core_value[3] += (temp >> 16) & 0x3ff;
++ core_value[2] += temp & 0x3ff;
++ }
++
++ *hpm_core = hpm_value_avg(core_value, 4); /* 4 : Array size */
++ *hpm_mda = hpm_value_avg(mda_value, 4); /* 4 : Array size */
++ *hpm_npu = hpm_value_avg(npu_value, 4); /* 4 : Array size */
++}
++
++static void start_hpm(unsigned int *hpm_core, unsigned int *hpm_npu,
++ unsigned int *hpm_mda)
++{
++ get_hpm_value(hpm_core, hpm_npu, hpm_mda);
++}
++
++static void adjust_hpm(unsigned int *hpm_core, unsigned int *hpm_mda,
++ unsigned int *hpm_npu, int temperature)
++{
++ unsigned int otp_hpm_core = readl(SYSCTRL_BASE_REG + OTP_HPM_CORE_OFFSET);
++ unsigned int otp_hpm_npu = readl(SYSCTRL_BASE_REG + OTP_HPM_NPU_OFFSET);
++ unsigned int otp_hpm_mda = readl(SYSCTRL_BASE_REG + OTP_HPM_MDA_OFFSET);
++
++ if (temperature <= 0) {
++ *hpm_npu -= 2; /* 2 : Adjustment Value */
++ *hpm_mda -= 3; /* 3 : Adjustment Value */
++ *hpm_core -= 4; /* 4 : Adjustment Value */
++ } else if (temperature > 100) { /* 100: temperature value */
++ *hpm_npu += 5; /* 5 : Adjustment Value */
++ *hpm_mda += 5; /* 5 : Adjustment Value */
++ *hpm_core += 8; /* 8 : Adjustment Value */
++ }else if(temperature > 70) { /* 70: temperature value */
++ *hpm_npu += 3; /* 2 : Adjustment Value */
++ *hpm_mda += 3; /* 2 : Adjustment Value */
++ *hpm_core += 4; /* 3 : Adjustment Value */
++ }
++
++
++ if (otp_hpm_core) {
++ if (*hpm_core > (otp_hpm_core + 59)) /* 10: Increment */
++ *hpm_core = otp_hpm_core + 59; /* 5: Increment */
++ }
++
++ if (otp_hpm_npu) {
++ if (*hpm_npu > (otp_hpm_npu + 62)) /* 15: Increment */
++ *hpm_npu = otp_hpm_npu + 62;
++ }
++
++ if (otp_hpm_mda) {
++ if (*hpm_mda > (otp_hpm_mda + 61)) /* 15: Increment */
++ *hpm_mda = otp_hpm_mda + 61;
++ }
++}
++
++static void save_hpm(unsigned int hpm_core, unsigned int hpm_npu,
++ unsigned int hpm_mda)
++{
++ writel(hpm_mda, SYSCTRL_BASE_REG + HPM_MDA_STORAGE_REG);
++ writel(hpm_npu, SYSCTRL_BASE_REG + HPM_NPU_STORAGE_REG);
++ writel(hpm_core, SYSCTRL_BASE_REG + HPM_CORE_STORAGE_REG);
++}
++
++static unsigned int calc_volt_regval(unsigned int volt_val, unsigned int volt_max,
++ unsigned int volt_min)
++{
++ unsigned int duty;
++
++ if (volt_val >= volt_max)
++ volt_val = volt_max - 1;
++ if (volt_val <= volt_min)
++ volt_val = volt_min + 1;
++ duty = duty_formula(volt_max, volt_min, volt_val);
++
++ return duty;
++}
++
++static void set_hpm_core_volt(unsigned int hpm_core_value, int delta_v)
++{
++ unsigned int volt_val;
++ unsigned int reg_val;
++
++ volt_val = (CORE_CURVE_B - CORE_CURVE_A * hpm_core_value) / 10;
++
++ if (volt_val > CORE_CURVE_VLOT_MAX)
++ volt_val = CORE_CURVE_VLOT_MAX;
++ else if (volt_val < CORE_CURVE_VLOT_MIN)
++ volt_val = CORE_CURVE_VLOT_MIN;
++
++ volt_val += delta_v;
++ reg_val = calc_volt_regval(volt_val, CORE_VOLT_MAX, CORE_VOLT_MIN);
++ writel(reg_val, SYSCTRL_BASE_REG + CORE_DUTY_STORAGE_REG);
++ writel(reg_val, HPM_CORE_VOL_REG);
++}
++
++static void set_hpm_mda_volt(unsigned int hpm_mda_value, int delta_v)
++{
++ unsigned int volt_val;
++ unsigned int reg_val;
++
++ volt_val = (MEDIA_CURVE_B - MEDIA_CURVE_A * hpm_mda_value) / 10;
++ if (volt_val > MEDIA_CURVE_VLOT_MAX)
++ volt_val = MEDIA_CURVE_VLOT_MAX;
++ else if (volt_val < MEDIA_CURVE_VLOT_MIN)
++ volt_val = MEDIA_CURVE_VLOT_MIN;
++
++ volt_val += delta_v;
++ reg_val = calc_volt_regval(volt_val, MDA_VOLT_MAX, MDA_VOLT_MIN);
++ writel(reg_val, SYSCTRL_BASE_REG + MDA_DUTY_STORAGE_REG);
++
++ writel(reg_val, HPM_MDA_VOL_REG);
++}
++
++static void set_hpm_npu_volt(unsigned int hpm_npu_value, int delta_v)
++{
++ unsigned int volt_val;
++ unsigned int reg_val;
++
++ volt_val = (NPU_CURVE_B - NPU_CURVE_A * hpm_npu_value) / 100;
++ if (volt_val > NPU_CURVE_VLOT_MAX)
++ volt_val = NPU_CURVE_VLOT_MAX;
++ else if (volt_val < NPU_CURVE_VLOT_MIN)
++ volt_val = NPU_CURVE_VLOT_MIN;
++
++ volt_val += delta_v;
++ reg_val = calc_volt_regval(volt_val, NPU_VOLT_MAX, NPU_VOLT_MIN);
++ writel(reg_val, SYSCTRL_BASE_REG + NPU_DUTY_STORAGE_REG);
++
++ writel(reg_val, HPM_NPU_VOL_REG);
++}
++
++static void get_delta_v(int *core_delta_v, int *npu_delta_v, int *mda_delta_v)
++{
++ unsigned int value = readl(SYSCTRL_REG + OTP_SHPM_MDA_OFFSET);
++ writel(value, SYSCTRL_BASE_REG + DELTA_V_STORAGE_REG);
++ /* core:bit 11-8,
++ * bit11 equal to 1 means negative, equal to 0 means positive,
++ * bit 8-10 is the absolute delta_v
++ */
++ int flag = (value & 0x800) ? -1 : 1;
++ *core_delta_v = flag * (int)((value >> 8) & 0x7) * 10;
++
++ /* mda:bit 7-4,
++ * bit7 equal to 1 means negative, equal to 0 means positive,
++ * bit 4-6 is the absolute delta_v
++ */
++ flag = (value & 0x80) ? -1 : 1;
++ *mda_delta_v = flag * (int)((value >> 4) & 0x7) * 10;
++
++ /* npu:bit 3-0,
++ * bit3 equal to 1 means negative, equal to 0 means positive,
++ * bit 0-2 is the absolute delta_v
++ */
++ flag = (value & 0x8) ? -1 : 1;
++ *npu_delta_v = flag * (int)(value & 0x7) * 10;
++}
++
++
++static void set_volt(unsigned int hpm_core, unsigned int hpm_npu,
++ unsigned int hpm_mda)
++{
++ int core_delta_v = 0;
++ int npu_delta_v = 0;
++ int mda_delta_v = 0;
++ get_delta_v(&core_delta_v, &npu_delta_v, &mda_delta_v);
++
++ set_hpm_core_volt(hpm_core, core_delta_v);
++ set_hpm_mda_volt(hpm_mda, mda_delta_v);
++ set_hpm_npu_volt(hpm_npu, npu_delta_v);
++
++ /* delay 300 Cycle */
++ delay(300);
++}
++
++static void get_temperature(int *temperature)
++{
++ int value = 0;
++ int tsensor_chn;
++ float m = 0.5;
++ float temperature_temp[3] = {0};
++ for(tsensor_chn = 0; tsensor_chn < 3; tsensor_chn++) {
++ value = (int)(readl(REG_TSENSOR_CTRL + TSENSOR_STATUS0 +
++ 0x100 * tsensor_chn) & 0x3ff);
++
++ m = ((float)value - 146) / 718 * 165 - 40;
++
++ if(m > 0)
++ temperature_temp[tsensor_chn] = m + 0.5;
++ else
++ temperature_temp[tsensor_chn] = m - 0.5;
++ }
++
++ *temperature = (temperature_temp[0]+temperature_temp[1]+temperature_temp[2])/3;
++ writel(*temperature, SYSCTRL_BASE_REG + TEMPERATURE_STORAGE_REG);
++}
++
++void init_temperature(void)
++{
++ int tsensor_chn;
++
++ for(tsensor_chn = 0; tsensor_chn < 3; tsensor_chn++) {
++ writel(TSENSOR_CTRL0_CFG, REG_TSENSOR_CTRL + TSENSOR_CTRL0 +
++ 0x100 * tsensor_chn);
++ writel(TSENSOR_CTRL1_CFG, REG_TSENSOR_CTRL + TSENSOR_CTRL1 +
++ 0x100 * tsensor_chn);
++ }
++
++}
++
++void init_hpm(void)
++{
++ /* open hmp clock */
++ writel(HPM_CLK_CFG, HPM_CLK_REG);
++
++ /* npu */
++ writel(HPM_MONITOR_CFG, SYSCTRL_REG + HPM_NPU_OFFSET);
++ /* mda */
++ writel(HPM_MONITOR_CFG, SYSCTRL_REG + HPM_MDA_OFFSET);
++ /* core */
++ writel(HPM_MONITOR_CFG, SYSCTRL_REG + HPM_CORE_OFFSET);
++
++}
++static void start_svb(void)
++{
++ unsigned int hpm_core;
++ unsigned int hpm_npu;
++ unsigned int hpm_mda;
++ int temperature;
++
++ /* init temperature and hpm*/
++ init_temperature();
++ init_hpm();
++ delay(1000);
++ start_hpm(&hpm_core, &hpm_npu, &hpm_mda);
++
++ /*get temperature */
++ get_temperature(&temperature);
++
++ adjust_hpm(&hpm_core, &hpm_mda, &hpm_npu, temperature);
++ set_volt(hpm_core, hpm_npu, hpm_mda);
++ save_hpm(hpm_core, hpm_npu, hpm_mda);
++
++ /* add SVB VER*/
++ writel(SVB_VER, SVB_VER_REG);
++}
++
++static void set_qosbuf_cfg(void)
++{
++ unsigned int val;
++
++ val = readl(CH0_DMC_CFG_DDRMODE);
++ writel(val, CH0_QOS_CFG_DDRMODE);
++ val = readl(CH0_DMC_CFG_RNKVOL_0);
++ writel(val, CH0_QOS_CFG_RNKVOL_0);
++ val = readl(CH0_DMC_CFG_RNKVOL_1);
++ writel(val, CH0_QOS_CFG_RNKVOL_1);
++
++ val = readl(CH1_DMC_CFG_DDRMODE);
++ writel(val, CH1_QOS_CFG_DDRMODE);
++ val = readl(CH1_DMC_CFG_RNKVOL_0);
++ writel(val, CH1_QOS_CFG_RNKVOL_0);
++ val = readl(CH1_DMC_CFG_RNKVOL_1);
++ writel(val, CH1_QOS_CFG_RNKVOL_1);
++
++ val = readl(CH2_DMC_CFG_DDRMODE);
++ writel(val, CH2_QOS_CFG_DDRMODE);
++ val = readl(CH2_DMC_CFG_RNKVOL_0);
++ writel(val, CH2_QOS_CFG_RNKVOL_0);
++ val = readl(CH2_DMC_CFG_RNKVOL_1);
++ writel(val, CH2_QOS_CFG_RNKVOL_1);
++
++ val = readl(CH3_DMC_CFG_DDRMODE);
++ writel(val, CH3_QOS_CFG_DDRMODE);
++ val = readl(CH3_DMC_CFG_RNKVOL_0);
++ writel(val, CH3_QOS_CFG_RNKVOL_0);
++ val = readl(CH3_DMC_CFG_RNKVOL_1);
++ writel(val, CH3_QOS_CFG_RNKVOL_1);
++}
++
++void start_ddr_training(unsigned int base)
++{
++ start_svb();
++
++ set_qosbuf_cfg();
++
++ ddr_set_rdqbdl_def_val();
++
++ /* ddr hw training */
++ ddr_hw_training_init();
++
++ /* ddr sw training */
++ ddr_sw_training_if();
++
++ ddr_retrain_anti_aging_enable();
++
++ /* ddr DMC auto power down config */
++ ddr_dmc_auto_power_down_cfg();
++}
+diff --git a/arch/arm/cpu/armv8/ss927v100/reset.S b/arch/arm/cpu/armv8/ss927v100/reset.S
+new file mode 100644
+index 0000000..ad86198
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/reset.S
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++
++.global reset_cpu
++reset_cpu:
++ ldr x1, rstctl /* get addr for global reset */
++ /* reg */
++ mov w3, #0x2 /* full reset pll + mpu */
++ str w3, [x1] /* force reset */
++ mov x0, x0
++
++_loop_forever:
++ b _loop_forever
++.align 3
++rstctl:
++ .quad SYS_CTRL_REG_BASE + REG_SC_SYSRES
+diff --git a/arch/arm/cpu/armv8/ss927v100/sdhci_boot.c b/arch/arm/cpu/armv8/ss927v100/sdhci_boot.c
+new file mode 100644
+index 0000000..c0036d6
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/sdhci_boot.c
+@@ -0,0 +1,391 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++
++#define DELAY_US 1000
++
++#define MMC_BLK_SZ 512
++#define CP_STEP1_SIZE 0x7800
++
++/*
++ * Controller registers
++ */
++#define SDHCI_DMA_ADDRESS 0x00
++#define SDHCI_BLOCK_SIZE 0x04
++#define SDHCI_BLOCK_COUNT 0x06
++#define SDHCI_ARGUMENT 0x08
++
++#define SDHCI_TRANSFER_MODE 0x0C
++#define SDHCI_TRNS_DMA 0x0001
++#define SDHCI_TRNS_BLK_CNT_EN 0x0002
++#define SDHCI_TRNS_READ 0x0010
++#define SDHCI_TRNS_MULTI 0x0020
++
++#define SDHCI_COMMAND 0x0E
++#define SDHCI_CMD_RESP_NONE 0x0000
++#define SDHCI_CMD_RESP_LONG 0x0001
++#define SDHCI_CMD_RESP_SHORT 0x0002
++#define SDHCI_CMD_CRC 0x0008
++#define SDHCI_CMD_DATA 0x0020
++
++#define SDHCI_RESPONSE 0x10
++#define SDHCI_BUFFER 0x20
++
++#define SDHCI_PRESENT_STATE 0x24
++#define SDHCI_PSTATE_DAT_0 0x00100000
++
++#define SDHCI_HOST_CONTROL 0x28
++#define SDHCI_CTRL_4BITBUS 0x02
++#define SDHCI_CTRL_8BITBUS 0x20
++
++#define SDHCI_POWER_CONTROL 0x29
++#define SDHCI_POWER_ON 0x01
++#define SDHCI_POWER_180 0x0A
++#define SDHCI_POWER_300 0x0C
++#define SDHCI_POWER_330 0x0E
++
++#define SDHCI_CLOCK_CONTROL 0x2C
++#define SDHCI_CLOCK_INT_EN 0x0001
++#define SDHCI_CLOCK_INT_STABLE 0x0002
++#define SDHCI_CLOCK_CARD_EN 0x0004
++
++#define SDHCI_TIMEOUT_CONTROL 0x2E
++
++#define SDHCI_SOFTWARE_RESET 0x2F
++#define SDHCI_RESET_ALL 0x01
++#define SDHCI_RESET_CMD 0x02
++#define SDHCI_RESET_DATA 0x04
++
++#define SDHCI_INT_STATUS 0x30
++#define SDHCI_INT_RESPONSE 0x00000001
++#define SDHCI_INT_DATA_END 0x00000002
++#define SDHCI_INT_DMA 0x00000008
++#define SDHCI_INT_DATA_AVAIL 0x00000020
++#define SDHCI_INT_NORMAL_MASK 0x00007FFF
++#define SDHCI_INT_ERROR_MASK 0xFFFF8000
++
++#define SDHCI_INT_ENABLE 0x34
++
++#define SDHCI_EMMC_CTRL 0x52C
++#define SDHCI_CARD_IS_EMMC 0x0001
++
++#define SDHCI_BOOT_CTRL 0x52E
++#define MAN_BOOT_EN 0x0001
++#define VALIDATE_BOOT 0x0080
++
++#define SDHCI_EMMC_HW_RESET 0x534
++
++#define sdhci_make_cmd(idx, param) ((((idx) & 0xFF) << 8) | ((param) & 0xFF))
++#define sdhci_make_blksz(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
++
++#define MMC_CMD_GO_IDLE_STATE 0
++#define MMC_CMD_SEND_OP_COND 1
++#define MMC_CMD_ALL_SEND_CID 2
++#define MMC_CMD_SET_RELATIVE_ADDR 3
++#define MMC_CMD_SWITCH 6
++#define MMC_CMD_SELECT_CARD 7
++#define MMC_CMD_SEND_CSD 9
++#define MMC_CMD_STOP_TRANSMISSION 12
++#define MMC_CMD_SET_BLOCKLEN 16
++#define MMC_CMD_READ_SINGLE_BLOCK 17
++#define MMC_CMD_READ_MULTIPLE_BLOCK 18
++#define MMC_CMD_SET_BLOCK_COUNT 23
++
++#define MMC_SWITCH_MODE_WRITE_BYTE 0x3
++#define MMC_SWITCH_ACCESS_SHIFT 24
++#define MMC_SWITCH_INDEX_SHIFT 16
++#define MMC_SWITCH_VALUE_SHIFT 8
++
++/* SDMA Configuration */
++#define BOUNDARY_SIZE (512 * 1024) /* 512K */
++#define BOUNDARY_ARG (0x7 << 12) /* 512K */
++#define MMC_SDMA_ENABLE 1
++
++#define OCR_BUSY 0x80000000
++#define OCR_HCS 0x40000000
++
++#define debug_printf(fmt, args...);
++#define reg_get(addr) (*(volatile unsigned int *)((uintptr_t)(addr)))
++
++static unsigned int is_bootmode(void)
++{
++ return !(reg_get(REG_BASE_SCTL + REG_PERI_EMMC_STAT) & EMMC_NORMAL_MODE);
++}
++
++static unsigned int get_hcs(void)
++{
++ return reg_get(REG_SAVE_HCS) & OCR_HCS;
++}
++
++static inline void delay(unsigned int cnt)
++{
++ while (cnt--)
++ __asm__ __volatile__("nop");
++}
++
++static inline unsigned int sdhci_readb(unsigned addr)
++{
++ return *((volatile unsigned char *) (uintptr_t)(EMMC_BASE_REG + addr));
++}
++
++static inline void sdhci_writeb(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned char *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
++}
++
++static inline unsigned int sdhci_readw(unsigned addr)
++{
++ return *((volatile unsigned short *) (uintptr_t)(EMMC_BASE_REG + addr));
++}
++
++static inline void sdhci_writew(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned short *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
++}
++
++static inline unsigned int sdhci_readl(unsigned addr)
++{
++ return *((volatile unsigned int *) (uintptr_t)(EMMC_BASE_REG + addr));
++}
++
++static inline void sdhci_writel(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned int *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
++}
++
++static int sdhci_read_block_pio(void *data_addr, unsigned int block)
++{
++ const unsigned int offset = sizeof(unsigned int);
++ unsigned int size;
++ unsigned char *buf;
++
++ size = MMC_BLK_SZ;
++ buf = (unsigned char *)data_addr + MMC_BLK_SZ * block;
++ while (size) {
++ *(unsigned int *)buf = sdhci_readl(SDHCI_BUFFER);
++ buf += offset;
++ size -= offset;
++ }
++
++ return 0;
++}
++
++static int sdhci_check_int_status(unsigned int mask, unsigned int timeout)
++{
++ unsigned int reg;
++
++ timeout *= 1000; /* ms is converted to us multiplied by 1000 */
++ for (;;) {
++ reg = sdhci_readl(SDHCI_INT_STATUS);
++ if (reg & mask)
++ break;
++ if (!(--timeout)) {
++ debug_printf("wait int status time out, reg = 0x%x, mask = 0x%x\n",
++ reg, mask);
++ return -1;
++ }
++ if (reg & SDHCI_INT_ERROR_MASK) {
++ debug_printf("int err: reg = 0x%x\n", reg);
++ return -1;
++ }
++
++ delay(DELAY_US);
++ }
++
++ return 0;
++}
++
++static int sdhci_boot_read(void *data_addr, unsigned int read_block)
++{
++ const unsigned int timeout = 2000; /* 2s timeout: 2000000 * 1us */
++ int ret;
++ unsigned int blocks = 0;
++
++ while (1) {
++ ret = sdhci_check_int_status(SDHCI_INT_DATA_AVAIL, timeout);
++ if (ret) {
++ debug_printf("wait data available int time out\n");
++ return ret;
++ }
++
++ sdhci_writel(SDHCI_INT_DATA_AVAIL, SDHCI_INT_STATUS);
++ sdhci_read_block_pio(data_addr, blocks);
++
++ blocks++;
++ if (blocks == read_block)
++ break;
++ }
++
++ return 0;
++}
++
++static int mmc_send_cmd(unsigned int cmd, unsigned int arg)
++{
++ const unsigned int timeout = 3000; /* 3s timeout: 3000000 * 1us */
++
++ sdhci_writel(0xFFFFFFFF, SDHCI_INT_STATUS);
++ sdhci_writel(arg, SDHCI_ARGUMENT);
++ sdhci_writew(cmd, SDHCI_COMMAND);
++
++ if (sdhci_check_int_status(SDHCI_INT_RESPONSE, timeout)) {
++ debug_printf("send cmd error\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static void mmc_read_cmd(unsigned long int start_addr, unsigned int src,
++ unsigned int size, unsigned int dma)
++{
++ unsigned int cmd, hcs;
++ unsigned short mode;
++
++ /* Send CMD16 to set blocksize */
++ cmd = sdhci_make_cmd(MMC_CMD_SET_BLOCKLEN, SDHCI_CMD_CRC |
++ SDHCI_CMD_RESP_SHORT);
++ mmc_send_cmd(cmd, MMC_BLK_SZ);
++
++ /* set data timeout */
++ sdhci_writeb(0xE, SDHCI_TIMEOUT_CONTROL);
++
++ /* set host count */
++ sdhci_writew(size, SDHCI_BLOCK_COUNT);
++
++ /* Send CMD23 to set blockcount */
++ cmd = sdhci_make_cmd(MMC_CMD_SET_BLOCK_COUNT,
++ SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT);
++ mmc_send_cmd(cmd, size);
++
++ /* set transfer mode */
++ mode = SDHCI_TRNS_READ | SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN;
++ if (dma)
++ mode |= SDHCI_TRNS_DMA;
++
++ sdhci_writew(mode, SDHCI_TRANSFER_MODE);
++
++ /* set SDMA address */
++ if (dma)
++ sdhci_writel(start_addr, SDHCI_DMA_ADDRESS);
++
++ /* Send CMD18 for multiple block read */
++ hcs = get_hcs();
++ if (hcs) {
++ cmd = sdhci_make_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,
++ SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_DATA);
++ mmc_send_cmd(cmd, src / MMC_BLK_SZ);
++ } else {
++ cmd = sdhci_make_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,
++ SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_DATA);
++ mmc_send_cmd(cmd, src);
++ }
++}
++
++static int sdhci_normal_read_sdma(void *dst, unsigned int src, unsigned int size)
++{
++ unsigned int stat;
++ unsigned int timeout;
++ unsigned long int start_addr;
++
++ start_addr = (uintptr_t)dst;
++
++ /* set host block size 512 */
++ sdhci_writew(MMC_BLK_SZ | BOUNDARY_ARG, SDHCI_BLOCK_SIZE);
++
++ mmc_read_cmd(start_addr, src, size, MMC_SDMA_ENABLE);
++
++ sdhci_writel(SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
++
++ timeout = 300000; /* 3s timeout: 300000 * 10us */
++ do {
++ stat = sdhci_readl(SDHCI_INT_STATUS);
++ if (stat & SDHCI_INT_ERROR_MASK) {
++ debug_printf("interrupt error\n");
++ return -1;
++ }
++
++ if (stat & SDHCI_INT_DMA) {
++ sdhci_writel(SDHCI_INT_DMA, SDHCI_INT_STATUS);
++ start_addr &= ~(BOUNDARY_SIZE - 1);
++ start_addr += BOUNDARY_SIZE;
++ sdhci_writel(start_addr, SDHCI_DMA_ADDRESS);
++ }
++
++ if (timeout > 0) {
++ delay(10 * DELAY_US); /* delay 10us */
++ timeout -= 1;
++ } else {
++ debug_printf("read timeout!\n");
++ return -1;
++ }
++ } while (!(stat & SDHCI_INT_DATA_END));
++
++ sdhci_writel(SDHCI_INT_DATA_END, SDHCI_INT_STATUS);
++
++ return 0;
++}
++
++static void copy_step1_to_ddr(unsigned int *dst, unsigned int *src, unsigned int size)
++{
++ unsigned int cycle = size / sizeof(unsigned int);
++ unsigned int i;
++
++ for (i = 0; i < cycle; i++)
++ *dst++ = *src++;
++}
++
++static int emmc_read_boot_data(void *data_addr, unsigned int data_size)
++{
++ unsigned int read_block;
++ int bootmode;
++
++ if (data_size <= CP_STEP1_SIZE) {
++ copy_step1_to_ddr((void *)data_addr, (void *)CP_STEP1_ADDR, data_size);
++ return 0;
++ } else {
++ copy_step1_to_ddr((void *)data_addr, (void *)CP_STEP1_ADDR, CP_STEP1_SIZE);
++ data_addr += CP_STEP1_SIZE;
++ data_size -= CP_STEP1_SIZE;
++ }
++
++ if (data_size % MMC_BLK_SZ) {
++ debug_printf("sdhci_read_boot_data error\n");
++ debug_printf("data_size:%d not round by block size\n", data_size);
++ read_block = data_size / MMC_BLK_SZ + 1;
++ } else {
++ read_block = data_size / MMC_BLK_SZ;
++ }
++
++ bootmode = is_bootmode();
++ if (bootmode)
++ return sdhci_boot_read(data_addr, read_block);
++
++ return sdhci_normal_read_sdma(data_addr, CP_STEP1_SIZE, read_block);
++}
++
++int emmc_boot_read(void *ptr, unsigned int size)
++{
++ int ret;
++
++ ret = emmc_read_boot_data(ptr, size);
++ return ret;
++}
+diff --git a/arch/arm/cpu/armv8/ss927v100/start.S b/arch/arm/cpu/armv8/ss927v100/start.S
+new file mode 100644
+index 0000000..b2cadac
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/start.S
+@@ -0,0 +1,371 @@
++/*
++ * (C) Copyright 2013
++ * David Feng
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++#include
++#include
++#include
++#include
++
++/*************************************************************************
++ *
++ * Startup Code (reset vector)
++ *
++ *************************************************************************/
++/*
++ * Branch according to exception level
++ */
++.macro switch_el, xreg, el3_label, el2_label, el1_label
++ mrs \xreg, CurrentEL
++ cmp \xreg, 0xc
++ b.eq \el3_label
++ cmp \xreg, 0x8
++ b.eq \el2_label
++ cmp \xreg, 0x4
++ b.eq \el1_label
++.endm
++
++/*
++ * Enter Exception.
++ * This will save the processor state that is ELR/X0~X30
++ * to the stack frame.
++ */
++.macro exception_entry
++ stp x29, x30, [sp, #-16]!
++ stp x27, x28, [sp, #-16]!
++ stp x25, x26, [sp, #-16]!
++ stp x23, x24, [sp, #-16]!
++ stp x21, x22, [sp, #-16]!
++ stp x19, x20, [sp, #-16]!
++ stp x17, x18, [sp, #-16]!
++ stp x15, x16, [sp, #-16]!
++ stp x13, x14, [sp, #-16]!
++ stp x11, x12, [sp, #-16]!
++ stp x9, x10, [sp, #-16]!
++ stp x7, x8, [sp, #-16]!
++ stp x5, x6, [sp, #-16]!
++ stp x3, x4, [sp, #-16]!
++ stp x1, x2, [sp, #-16]!
++
++ /* Could be running at EL3/EL2/EL1 */
++ switch_el x11, 3f, 2f, 1f
++3: mrs x1, esr_el3
++ mrs x2, elr_el3
++ b 0f
++2: mrs x1, esr_el2
++ mrs x2, elr_el2
++ b 0f
++1: mrs x1, esr_el1
++ mrs x2, elr_el1
++0:
++ stp x2, x0, [sp, #-16]!
++ mov x0, sp
++.endm
++
++.globl _start
++_start:
++ b reset
++
++.balignl 64,0xdeadbeef
++__blank_zone_start:
++.fill 11008,1,0
++__blank_zone_end:
++
++.globl _blank_zone_start
++_blank_zone_start:
++.quad __blank_zone_start
++
++.globl _blank_zone_end
++_blank_zone_end:
++.quad __blank_zone_end
++.balignl 16,0xdeadbeef
++
++.align 3
++
++.globl _TEXT_BASE
++_TEXT_BASE:
++ .quad TEXT_BASE
++
++/*
++ * These are defined in the linker script.
++ */
++.globl _end_ofs
++_end_ofs:
++ .quad _end - _start
++
++.globl _bss_start_ofs
++_bss_start_ofs:
++ .quad __bss_start - _start
++
++.globl _bss_end_ofs
++_bss_end_ofs:
++ .quad __bss_end - _start
++
++reset:
++ /*
++ * Could be EL3/EL2/EL1, Initial State:
++ * Little Endian, MMU Disabled, i/dCache Disabled
++ */
++ adr x0, vectors
++ switch_el x1, 3f, 2f, 1f
++3: msr vbar_el3, x0
++ mrs x0, scr_el3
++ orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */
++ msr scr_el3, x0
++ msr cptr_el3, xzr /* Enable FP/SIMD */
++#ifdef COUNTER_FREQUENCY
++ ldr x0, =COUNTER_FREQUENCY
++ msr cntfrq_el0, x0 /* Initialize CNTFRQ */
++#endif
++ b 0f
++2: msr vbar_el2, x0
++ mov x0, #0x33ff
++ msr cptr_el2, x0 /* Enable FP/SIMD */
++ b 0f
++1: msr vbar_el1, x0
++ mov x0, #3 << 20
++ msr cpacr_el1, x0 /* Enable FP/SIMD */
++0:
++
++ /*
++ * Cache/BPB/TLB Invalidate
++ * i-cache is invalidated before enabled in icache_enable()
++ * tlb is invalidated before mmu is enabled in dcache_enable()
++ * d-cache is invalidated before enabled in dcache_enable()
++ */
++
++#ifndef CONFIG_BSP_DISABLE_DOWNLOAD
++ /*
++ * read system register REG_SC_GEN2
++ * check if ziju flag
++ */
++ ldr x0, =SYS_CTRL_REG_BASE
++ ldr w1, [x0, #REG_SC_GEN2]
++ ldr w2, =0x7a696a75 /* magic for "ziju" */
++ cmp w1, w2
++ bne normal_start_flow
++ mov x1, sp /* save sp */
++ str w1, [x0, #REG_SC_GEN2] /* clear ziju flag */
++
++ziju_flow:
++ ldr x2, =(STACK_TRAINING)
++ bic sp, x2, #0xf /* 16-byte alignment for ABI compliance */
++ ldr x0, _blank_zone_start
++ ldr x1, _TEXT_BASE
++ sub x0, x0, x1
++ adr x1, _start
++ add x0, x0, x1
++ mov x1, #0x0 /* flags: 0->normal 1->pm */
++ bl init_registers /* init PLL/DDRC/... */
++ bl start_ddr_training /* DDR training */
++
++ ldr x0, =SYS_CTRL_REG_BASE
++ ldr w1, [x0, #REG_SC_GEN2]
++ mov sp, x1 /* restore sp */
++ ldr w1, [x0, #REG_SC_GEN3]
++ mov x30, x1
++ ret /* return to bootrom */
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ b . /* bug here */
++
++
++normal_start_flow:
++#endif
++ /* set stack for C code */
++ ldr x0, =(CONFIG_SYS_INIT_SP_ADDR)
++ bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
++
++ bl uart_early_init
++ adr x0, Str_SystemSartup
++ bl uart_early_puts
++
++running_addr_check:
++ adr x0,running_addr_check
++ lsr x0, x0, #28
++ cmp x0, #4
++ bge not_ddr_init
++
++ /* read init table and config registers */
++ ldr x0, _blank_zone_start
++ ldr x1, _TEXT_BASE
++ sub x0, x0, x1
++ adr x1, _start
++ add x0, x0, x1
++ mov x1, #0 /* flags: 0->normal 1->pm */
++ bl init_registers
++ bl start_ddr_training
++check_boot_mode:
++ ldr x0, =SYS_CTRL_REG_BASE
++ ldr w0, [x0, #REG_SYSSTAT]
++ lsr w6, w0, #2
++ and w6, w6, #0x3
++ cmp w6, #BOOT_FROM_EMMC
++ bne not_ddr_init
++
++#ifdef CONFIG_SDHCI
++emmc_boot:
++ ldr x0, _TEXT_BASE
++ ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */
++ ldr x2, =__bss_start /* x2 <- SRC &__bss_start */
++ sub x1, x2, x1
++ bl emmc_boot_read
++ b no_copy
++#endif
++
++not_ddr_init:
++master_cpu:
++relocate:
++ adr x0, _start /*runing addr start*/
++ ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */
++ cmp x0, x1
++ b.eq no_copy /* skip relocation */
++ ldr x2, =__bss_start /* x2 <- SRC &__bss_start*/
++
++copy_loop:
++ ldp x10, x11, [x0], #16 /* copy from source address [x0] */
++ stp x10, x11, [x1], #16 /* copy to target address [x1] */
++ cmp x1, x2 /* until source end address [x2] */
++ b.lo copy_loop
++no_copy:
++clear_remap:
++ ldr x1, =SYS_CTRL_REG_BASE
++ ldr w0, [x1]
++ mov w2, #0x5
++ bic w0, w0, #0xf
++ orr w0, w0, w2
++ str w0, [x1]
++set_scs_finish:
++ ldr x1, =REG_SCS_CTRL
++ ldr w0, [x1]
++ mov w2, #0x5
++ bic w0, w0, #0xf
++ orr w0, w0, w2
++ str w0, [x1]
++jump_to_ddr:
++ adr x0, _start_armboot
++ ldr x30,[x0]
++ ret
++.align 3
++_start_armboot: .quad start_armboot
++
++/*-----------------------------------------------------------------------*/
++
++/*
++ * Exception vectors.
++ */
++ .align 3
++ .globl vectors
++vectors:
++ .align 3
++ b _do_bad_sync /* Current EL Synchronous Thread */
++
++ .align 3
++ b _do_bad_irq /* Current EL IRQ Thread */
++
++ .align 3
++ b _do_bad_fiq /* Current EL FIQ Thread */
++
++ .align 3
++ b _do_bad_error /* Current EL Error Thread */
++
++ .align 3
++ b _do_sync /* Current EL Synchronous Handler */
++
++ .align 3
++ b _do_irq /* Current EL IRQ Handler */
++
++ .align 3
++ b _do_fiq /* Current EL FIQ Handler */
++
++ .align 3
++ b _do_error /* Current EL Error Handler */
++
++
++_do_bad_sync:
++ exception_entry
++ bl do_bad_sync
++ b exception_exit
++
++_do_bad_irq:
++ exception_entry
++ bl do_bad_irq
++ b exception_exit
++
++_do_bad_fiq:
++ exception_entry
++ bl do_bad_fiq
++ b exception_exit
++
++_do_bad_error:
++ exception_entry
++ bl do_bad_error
++ b exception_exit
++
++_do_sync:
++ exception_entry
++ bl do_sync
++ b exception_exit
++
++_do_irq:
++ exception_entry
++ bl do_irq
++ b exception_exit
++
++_do_fiq:
++ exception_entry
++ bl do_fiq
++ b exception_exit
++
++_do_error:
++ exception_entry
++ bl do_error
++ b exception_exit
++
++exception_exit:
++ ldp x2, x0, [sp],#16
++ switch_el x11, 3f, 2f, 1f
++3: msr elr_el3, x2
++ b 0f
++2: msr elr_el2, x2
++ b 0f
++1: msr elr_el1, x2
++0:
++ ldp x1, x2, [sp],#16
++ ldp x3, x4, [sp],#16
++ ldp x5, x6, [sp],#16
++ ldp x7, x8, [sp],#16
++ ldp x9, x10, [sp],#16
++ ldp x11, x12, [sp],#16
++ ldp x13, x14, [sp],#16
++ ldp x15, x16, [sp],#16
++ ldp x17, x18, [sp],#16
++ ldp x19, x20, [sp],#16
++ ldp x21, x22, [sp],#16
++ ldp x23, x24, [sp],#16
++ ldp x25, x26, [sp],#16
++ ldp x27, x28, [sp],#16
++ ldp x29, x30, [sp],#16
++ eret
++
++/*
++ * void __asm_invalidate_icache_all(void)
++ *
++ * invalidate all tlb entries.
++ */
++ENTRY(__asm_invalidate_icache_all)
++ ic ialluis
++ isb sy
++ ret
++ENDPROC(__asm_invalidate_icache_all)
++
++.align 3
++Str_SystemSartup:
++.ascii "\r\n\r\nSystem startup\r\n\0"
+diff --git a/arch/arm/cpu/armv8/ss927v100/uart.S b/arch/arm/cpu/armv8/ss927v100/uart.S
+new file mode 100644
+index 0000000..e2d4b82
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss927v100/uart.S
+@@ -0,0 +1,116 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++
++#include
++
++//******************************************************************************
++//
++// void uart_early_init(void);
++//
++.text
++.align 4
++.global uart_early_init
++.type uart_early_init, %function
++uart_early_init:
++#ifndef CONFIG_BSP_DISABLE_CONSOLE
++ ldr x4, io_base_addr_L0
++ ldr w3, =0x1101
++ str w3, [x4, #0X124]
++ ldr w3, =0x1011
++ str w3, [x4, #0X128]
++
++ ldr x4, uart_base_addr_L0
++ mov w3, #0
++ /* Disable UART */
++ str w3, [x4, #48]
++ /* Set baud rate to 115200, uart clock:24M */
++ add w3, w3, #13
++ str w3, [x4, #36]
++ mov w3, #1
++ str w3, [x4, #40]
++ /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled. */
++ ldr w3, =112
++ str w3, [x4, #44]
++ /* Enable UART */
++ ldr w3, =769
++ str w3, [x4, #48]
++#endif
++ ret
++.align 4
++uart_base_addr_L0:
++ .quad CONFIG_CUR_UART_BASE
++io_base_addr_L0:
++ .quad 0x102f0000
++
++//******************************************************************************
++//
++// void uart_early_puts(const char *ss);
++//
++.align 4
++.global uart_early_puts
++.type uart_early_puts, %function
++uart_early_puts:
++#ifndef CONFIG_BSP_DISABLE_CONSOLE
++#if !defined(CONFIG_SUPPORT_CA_RELEASE)
++ ldr x2, uart_base_addr_L1
++ b next_char
++output:
++ ldr w4, [x2, #24]
++ tst w4, #32
++ bne output
++ str w3, [x2, #0]
++ add x0, x0, #1
++next_char:
++ ldrb w3, [x0]
++ cmp w3, #0
++ bne output
++#endif /* CONFIG_SUPPORT_CA_RELEASE */
++#endif /* CONFIG_BSP_DISABLE_CONSOLE */
++ ret
++.align 4
++uart_base_addr_L1:
++ .quad CONFIG_CUR_UART_BASE
++
++//******************************************************************************
++//
++// void uart_early_putc(int chr);
++//
++// call example:
++// mov w0, #'A'
++// bl uart_early_putc
++//
++.align 4
++.global uart_early_putc
++.type uart_early_putc, %function
++uart_early_putc:
++#ifndef CONFIG_BSP_DISABLE_CONSOLE
++#if !defined(CONFIG_SUPPORT_CA_RELEASE)
++ ldr x2, uart_base_addr_L3
++wait3:
++ ldr w4, [x2, #24]
++ tst w4, #32
++ bne wait3
++ str w0, [x2, #0]
++
++#endif /* CONFIG_SUPPORT_CA_RELEASE */
++#endif /* CONFIG_BSP_DISABLE_CONSOLE */
++ ret
++.align 4
++uart_base_addr_L3:
++ .quad CONFIG_CUR_UART_BASE
+diff --git a/arch/arm/cpu/armv8/ss928v100/hw_compressed/Makefile b/arch/arm/cpu/armv8/ss928v100/hw_compressed/Makefile
+new file mode 100644
+index 0000000..9a57e6c
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/hw_compressed/Makefile
+@@ -0,0 +1,154 @@
++################################################################################
++
++PWD = $(shell pwd)
++CROSS_COMPILE =: aarch64-c01v01-linux-gnu-
++TOPDIR =
++
++################################################################################
++CC := $(CROSS_COMPILE)gcc
++AR := $(CROSS_COMPILE)ar
++LD := $(CROSS_COMPILE)ld
++OBJCOPY := $(CROSS_COMPILE)objcopy
++OBJDUMP := $(CROSS_COMPILE)objdump
++
++
++################################################################################
++BOOT := u-boot-$(SOC)
++TEXTBASE := 0x48700000
++CFLAGS :=-Os -fno-builtin -ffreestanding \
++ -D__KERNEL__ -DTEXT_BASE=$(TEXTBASE) \
++ -I$(TOPDIR)/include \
++ -I$(TOPDIR)/include/linux \
++ -I$(TOPDIR)/drivers/ddr/vendor/default_v2 \
++ -I$(TOPDIR)/drivers/ddr/vendor/$(SOC) \
++ -I$(TOPDIR)/arch/arm/include \
++ -fno-pic -mstrict-align -ffunction-sections \
++ -fdata-sections -fno-common -ffixed-r9 \
++ -fno-common -ffixed-x18 -pipe -march=armv8-a \
++ -Wall -Wstrict-prototypes -fno-stack-protector \
++ -D__LINUX_ARM_ARCH__=8 -D__ARM__ \
++ -DCONFIG_SS928V100 -DCONFIG_MMC -DDDR_TRAINING_MEM_FUNC \
++ $(MKFLAGS) -fno-strict-aliasing -mcmodel=tiny
++
++################################################################################
++
++START := start.o
++COBJS := lowlevel_init_v300.o \
++ init_registers.o \
++ sdhci_boot.o \
++ uart.o \
++ ddr_training_impl.o \
++ ddr_ac_training.o \
++ ddr_dcc_training.o \
++ ddr_ddrt_training.o \
++ ddr_gate_training.o \
++ ddr_lpca_training.o \
++ ddr_mpr_training.o \
++ ddr_pcode_training.o \
++ ddr_wl_training.o \
++ ddr_training_ctl.o \
++ ddr_training_boot.o \
++ ddr_training_custom.o \
++ ddr_training_console.o \
++ startup.o \
++ image_data.o \
++ div0.o \
++ reset.o
++
++SSRC := arch/arm/cpu/armv8/$(SOC)/start.S \
++ arch/arm/cpu/armv8/$(SOC)/reset.S \
++ arch/arm/cpu/armv8/$(SOC)/sdhci_boot.c \
++ arch/arm/cpu/armv8/$(SOC)/uart.S \
++ arch/arm/cpu/armv8/$(SOC)/init_registers.c \
++ arch/arm/cpu/armv8/$(SOC)/lowlevel_init_v300.c \
++ drivers/ddr/vendor/default_v2/ddr_training_impl.c \
++ drivers/ddr/vendor/default_v2/ddr_ac_training.c \
++ drivers/ddr/vendor/default_v2/ddr_dcc_training.c \
++ drivers/ddr/vendor/default_v2/ddr_ddrt_training.c \
++ drivers/ddr/vendor/default_v2/ddr_gate_training.c \
++ drivers/ddr/vendor/default_v2/ddr_lpca_training.c \
++ drivers/ddr/vendor/default_v2/ddr_mpr_training.c \
++ drivers/ddr/vendor/default_v2/ddr_pcode_training.c \
++ drivers/ddr/vendor/default_v2/ddr_wl_training.c \
++ drivers/ddr/vendor/default_v2/ddr_training_ctl.c \
++ drivers/ddr/vendor/default_v2/ddr_training_boot.c \
++ drivers/ddr/vendor/default_v2/ddr_training_console.c \
++ drivers/ddr/vendor/$(SOC)/ddr_training_custom.c \
++ arch/arm/lib/div0.c \
++ lib/hw_dec/hw_decompress.c \
++ lib/hw_dec/hw_decompress_$(SOC).c \
++ lib/hw_dec/hw_decompress_v2.c \
++ lib/hw_dec/hw_decompress_v2.h
++
++REG := $(wildcard $(TOPDIR)/*.reg $(TOPDIR)/.reg)
++SRC := $(notdir $(SSRC))
++
++################################################################################
++.PHONY: $(BOOT).bin
++$(BOOT).bin: $(BOOT).tmp regfile
++ @dd if=./$(BOOT).tmp of=./tmp1 bs=1 count=64 2>/dev/null
++ @dd if=$(REG) of=./tmp2 bs=11008 conv=sync 2>/dev/null
++ @dd if=./$(BOOT).tmp of=./tmp3 bs=1 skip=11072 2>/dev/null
++ @cat tmp1 tmp2 tmp3 > $(BOOT).bin
++ @rm -f tmp1 tmp2 tmp3
++ @chmod 754 $(BOOT).bin
++ @cp -fv $@ $(TOPDIR)
++ @echo $(BOOT).bin is Ready.
++
++$(BOOT).tmp: $(BOOT).elf
++ $(OBJCOPY) -O srec $< $(BOOT).srec
++ $(OBJCOPY) -j .text -O binary $< $(BOOT).text
++ $(OBJCOPY) --gap-fill=0xff -O binary $< $@
++
++$(BOOT).elf: image_data.gzip $(SRC) $(START) $(COBJS)
++ $(LD) -Bstatic -T u-boot.lds -Ttext $(TEXTBASE) $(START) \
++ $(COBJS) -Map $(BOOT).map -o $@
++ $(OBJDUMP) -d $@ > $@.asm
++
++.PHONY: regfile
++regfile:
++ @if [ "$(words $(REG))" = "0" ]; then ( \
++ echo '***' Need '.reg' or '*.reg' file in directory $(TOPDIR); \
++ exit 1; \
++ ) fi
++ @if [ "$(words $(REG))" != "1" ]; then ( \
++ echo '***' Found multi '.reg' or '*.reg' file in directory $(TOPDIR); \
++ echo '***' Files: $(notdir $(REG)); \
++ exit 1; \
++ ) fi
++
++################################################################################
++start.o: start.S
++ $(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c
++
++# -1 : --fast -9 : --best
++image_data.gzip: $(BINIMAGE)
++ gzip -fNqc -7 $< > $@
++
++%.o: %.c
++ $(CC) $(CFLAGS) -Wall -Wstrict-prototypes \
++ -fno-stack-protector -o $@ $< -c
++
++%.o: %.S
++ $(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c
++
++image_data.o: image_data.S image_data.gzip
++ $(CC) -D__ASSEMBLY__ $(CFLAGS) -o $@ $< -c
++
++#############################################################################
++
++$(SRC):
++ ln -sf ../../../../../../$(filter %/$@,$(SSRC)) $@
++################################################################################
++TMPS := $(COBJS) start.o $(SRC) \
++ $(BOOT).map $(BOOT).elf $(BOOT).srec $(BOOT).bin $(BOOT).text $(BOOT).tmp \
++ image_data.gzip
++
++distclean: clean
++
++clean:
++ -rm -f $(TMPS)
++
++################################################################################
++.PHONY: clean
++################################################################################
+diff --git a/arch/arm/cpu/armv8/ss928v100/hw_compressed/image_data.S b/arch/arm/cpu/armv8/ss928v100/hw_compressed/image_data.S
+new file mode 100644
+index 0000000..f8d2d36
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/hw_compressed/image_data.S
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++ .section .image,"a"
++ .globl input_data
++ /*gzip source addr must be 16 bytes aligned*/
++ .balign 16
++input_data:
++ .incbin "image_data.gzip"
++ .globl input_data_end
++input_data_end:
+diff --git a/arch/arm/cpu/armv8/ss928v100/hw_compressed/startup.c b/arch/arm/cpu/armv8/ss928v100/hw_compressed/startup.c
+new file mode 100644
+index 0000000..4d1785c
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/hw_compressed/startup.c
+@@ -0,0 +1,191 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++#include
++#include
++
++const uintptr_t image_entry = (CONFIG_SYS_TEXT_BASE);
++
++#define error(_s) uart_early_puts(_s)
++#define putstr(_s) uart_early_puts(_s)
++#define EXCEPTION_LEVEL1 1
++#define EXCEPTION_LEVEL2 2
++#include "hw_decompress.c"
++#define GZIP_SIZE_OFFSET 0x4
++
++void icache_enable(void);
++void invalidate_icache_all(void);
++void __asm_invalidate_icache_all(void);
++
++void start_armboot(void)
++{
++ unsigned char *pdst_h32 = NULL;
++ unsigned char *pdst_l32 = NULL;
++ unsigned char *input_data_h32 = NULL;
++ unsigned int image_data_len;
++ int pdst_len;
++ int ret;
++ uart_early_init();
++ uart_early_puts("\r\nUncompress ");
++
++ /* enable I-Cache */
++ icache_enable();
++
++ /* use direct address mode */
++ hw_dec_type = 0;
++ /* init hw decompress IP */
++ hw_dec_init();
++
++ /* start decompress */
++ pdst_l32 = (unsigned char *)(uintptr_t)image_entry;
++ image_data_len = input_data_end - input_data;
++ for (int i = 0; i < sizeof(pdst_len); i++)
++ *((char *)(&pdst_len) + i) = *((char *)(input_data_end -
++ GZIP_SIZE_OFFSET) + i);
++
++ ret = hw_dec_decompress(pdst_h32, pdst_l32, &pdst_len, input_data_h32,
++ input_data, image_data_len, NULL);
++ if (!ret) {
++ uart_early_puts("Ok!");
++ } else {
++ uart_early_puts("Fail!");
++ while (1);
++ }
++
++ /* uinit hw decompress IP */
++ hw_dec_uinit();
++ void (*uboot)(void);
++ uboot = (void (*))CONFIG_SYS_TEXT_BASE;
++ invalidate_icache_all();
++ uboot();
++}
++
++void hang(void)
++{
++ uart_early_puts("### ERROR ### Please RESET the board ###\n");
++ for (; ;);
++}
++
++void invalidate_icache_all(void)
++{
++ __asm_invalidate_icache_all();
++}
++
++static inline unsigned int current_el(void)
++{
++ unsigned int el;
++ asm volatile("mrs %0, CurrentEL" : "=r"(el) : : "cc");
++ return el >> 2; /* Move Left 2bit */
++}
++
++static void set_sctlr(unsigned int val)
++{
++ unsigned int el;
++
++ el = current_el();
++ if (el == EXCEPTION_LEVEL1)
++ asm volatile("msr sctlr_el1, %0" : : "r"(val) : "cc");
++ else if (el == EXCEPTION_LEVEL2)
++ asm volatile("msr sctlr_el2, %0" : : "r"(val) : "cc");
++ else
++ asm volatile("msr sctlr_el3, %0" : : "r"(val) : "cc");
++
++ asm volatile("isb");
++}
++
++static unsigned int get_sctlr(void)
++{
++ unsigned int el, val;
++
++ el = current_el();
++ if (el == EXCEPTION_LEVEL1)
++ asm volatile("mrs %0, sctlr_el1" : "=r"(val) : : "cc");
++ else if (el == EXCEPTION_LEVEL2)
++ asm volatile("mrs %0, sctlr_el2" : "=r"(val) : : "cc");
++ else
++ asm volatile("mrs %0, sctlr_el3" : "=r"(val) : : "cc");
++
++ return val;
++}
++
++void icache_enable(void)
++{
++ invalidate_icache_all();
++#define CR_I (1 << 12) /* Icache enable */
++ set_sctlr(get_sctlr() | CR_I);
++}
++
++void do_bad_sync(void)
++{
++ uart_early_puts("bad sync abort\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_sync(void)
++{
++ uart_early_puts("sync abort\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_bad_error(void)
++{
++ uart_early_puts("bad error\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_error(void)
++{
++ uart_early_puts("error\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_bad_fiq(void)
++{
++ uart_early_puts("bad fast interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_bad_irq(void)
++{
++ uart_early_puts("bad interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_fiq(void)
++{
++ uart_early_puts("fast interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
++
++void do_irq(void)
++{
++ uart_early_puts("interrupt request\r\n");
++ uart_early_puts("Resetting CPU ...\r\n");
++ reset_cpu(0);
++}
+diff --git a/arch/arm/cpu/armv8/ss928v100/hw_compressed/u-boot.lds b/arch/arm/cpu/armv8/ss928v100/hw_compressed/u-boot.lds
+new file mode 100644
+index 0000000..e0f0fdc
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/hw_compressed/u-boot.lds
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
++OUTPUT_ARCH(aarch64)
++ENTRY(_start)
++SECTIONS
++{
++ . = 0x48700000;
++ __image_copy_start =.;
++ . = ALIGN(8);
++ .text :
++ {
++ __text_start = .;
++ start.o (.text*)
++ init_registers.o (.text*)
++ lowlevel_init_v300.o (.text*)
++ ddr_training_impl.o (.text*)
++ ddr_ac_training.o (.text*)
++ ddr_dcc_training.o (.text*)
++ ddr_ddrt_training.o (.text*)
++ ddr_gate_training.o (.text*)
++ ddr_lpca_training.o (.text*)
++ ddr_mpr_training.o (.text*)
++ ddr_pcode_training.o (.text*)
++ ddr_wl_training.o (.text*)
++ ddr_training_console.o (.text*)
++ ddr_training_ctl.o (.text*)
++ ddr_training_boot.o (.text*)
++ ddr_training_custom.o (.text*)
++ uart.o (.text*)
++ div0.o (.text*)
++ sdhci_boot.o (.text*)
++ image_data.o (.text*)
++ startup.o(.text*)
++ reset.o(.text*)
++ __init_end = .;
++ ASSERT(((__init_end - __text_start) < 0x8000), "init sections too big!");
++ *(.text*)
++ }
++
++ . = ALIGN(8);
++ .image : { *(.image) }
++
++ . = ALIGN(8);
++ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
++
++ . = ALIGN(8);
++ .data : {
++ *(.data*)
++ }
++
++ . = ALIGN(8);
++
++ .got : { *(.got) }
++
++ . = ALIGN(8);
++ __image_copy_end =.;
++ __bss_start = .;
++ .bss :
++ {
++ *(.bss)
++ }
++ __bss_end = .;
++
++
++ _end = .;
++}
+diff --git a/arch/arm/cpu/armv8/ss928v100/init_registers.c b/arch/arm/cpu/armv8/ss928v100/init_registers.c
+new file mode 100644
+index 0000000..08cc9b6
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/init_registers.c
+@@ -0,0 +1,179 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#define W_WHETHER_WRITE (1 << 0)
++#define W_WHETHER_PM (1 << 1)
++#define W_WHETHER_BOOT_NORMAL (1 << 2)
++#define W_BIT_OFFSET 3
++#define W_BIT_MASK (0x1f << W_BIT_OFFSET)
++#define W_REG_BIT_OFFSET 11
++#define W_REG_BIT_MASK (0x1f << W_REG_BIT_OFFSET)
++
++#define R_WHETHER_READ (W_WHETHER_WRITE << 16)
++#define R_WHETHER_PM (W_WHETHER_PM << 16)
++#define R_WHETHER_BOOT_NORMAL (W_WHETHER_BOOT_NORMAL << 16)
++#define R_BIT_OFFSET (W_BIT_OFFSET + 16)
++#define R_BIT_MASK (W_BIT_MASK << 16)
++#define R_REG_BIT_OFFSET (W_REG_BIT_OFFSET + 16)
++#define R_REG_BIT_MASK (W_REG_BIT_MASK << 16)
++
++#define RW_BIT_NUM 32
++
++struct regentry {
++ unsigned int reg_addr;
++ unsigned int value;
++ unsigned int delay;
++ unsigned int attr;
++};
++
++static void dwb(void) /* drain write buffer */
++{
++}
++
++static void writel(unsigned val, unsigned addr)
++{
++ dwb();
++ (*(volatile unsigned *)(uintptr_t)(addr)) = (val);
++ dwb();
++}
++
++static void delay(void)
++{
++ __asm__ __volatile__("nop");
++}
++
++static void reg_read(struct regentry* const reg, unsigned int* const ret)
++{
++ unsigned int reg_val_r;
++ unsigned int bit_start_r;
++ unsigned int bit_num_r;
++
++ bit_start_r = ((reg->attr & R_REG_BIT_MASK) >> R_REG_BIT_OFFSET);
++ bit_num_r = ((reg->attr & R_BIT_MASK) >> R_BIT_OFFSET) + 1;
++ reg_val_r = (*(volatile unsigned *)(long)(reg->reg_addr));
++
++ if (bit_num_r != RW_BIT_NUM) {
++ reg_val_r >>= bit_start_r;
++ reg_val_r &= ((1 << bit_num_r) - 1);
++ }
++
++ *ret = ((reg_val_r == reg->value) ? 0 : 1);
++}
++
++static void reg_write(struct regentry *reg)
++{
++ unsigned int reg_val_w;
++ unsigned int delay_2;
++ unsigned int bit_start_w;
++ unsigned int bit_num_w;
++
++ delay_2 = reg->delay;
++ bit_start_w = ((reg->attr & W_REG_BIT_MASK) >> W_REG_BIT_OFFSET);
++ bit_num_w = ((reg->attr & W_BIT_MASK) >> W_BIT_OFFSET) + 1;
++ reg_val_w = (*(volatile unsigned *)(long)(reg->reg_addr));
++
++ if (bit_num_w == RW_BIT_NUM) {
++ reg_val_w = reg->value;
++ } else {
++ reg_val_w &= (~(((1 << bit_num_w) - 1) << bit_start_w));
++ reg_val_w |= (reg->value) << bit_start_w;
++ }
++ writel(reg_val_w, reg->reg_addr);
++
++ do {
++ delay();
++ } while (delay_2--);
++}
++
++static void read_write(struct regentry *reg, unsigned int pm)
++{
++ unsigned int ret;
++ unsigned int delay_1;
++
++ ret = 0;
++ delay_1 = reg->delay;
++
++ if (pm) {
++ if (reg->attr & W_WHETHER_PM) {
++ reg_write(reg);
++ } else if (reg->attr & R_WHETHER_PM) {
++ do {
++ reg_read(reg, &ret);
++ delay();
++ } while (ret);
++
++ do {
++ delay();
++ } while (delay_1--);
++ } else {
++ do {
++ delay();
++ } while (delay_1--);
++ }
++ } else {
++ if (reg->attr & W_WHETHER_BOOT_NORMAL) {
++ reg_write(reg);
++ } else if (reg->attr & R_WHETHER_BOOT_NORMAL) {
++ do {
++ reg_read(reg, &ret);
++ delay();
++ } while (ret);
++
++ do {
++ delay();
++ } while (delay_1--);
++ } else {
++ do {
++ delay();
++ } while (delay_1--);
++ }
++ }
++}
++
++static void part_read_write(struct regentry *reg_table, unsigned int pm)
++{
++ unsigned int i;
++
++ for (i = 0; ; i++) {
++ if ((!reg_table[i].reg_addr) && (!reg_table[i].value) &&
++ (!reg_table[i].delay) && (!reg_table[i].attr))
++ goto main_end;
++
++ read_write(®_table[i], pm);
++ }
++
++main_end:
++ delay();
++}
++
++/*
++ * base - reg base address
++ * pm - is suspend
++ * 0 normal
++ * 1 pm
++ */
++void init_registers(unsigned long base, unsigned long pm)
++{
++ struct regentry *reg_table = (struct regentry *)(uintptr_t)base;
++
++ part_read_write(reg_table, pm);
++}
++
+diff --git a/arch/arm/cpu/armv8/ss928v100/lowlevel_init_v300.c b/arch/arm/cpu/armv8/ss928v100/lowlevel_init_v300.c
+new file mode 100644
+index 0000000..4c048a1
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/lowlevel_init_v300.c
+@@ -0,0 +1,516 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include "ddr_interface.h"
++
++#define SYS_CTL_REG SYS_CTRL_REG_BASE
++
++#define OK 0
++#define ERROR (-1)
++#define CH0_DMC_CFG_DDRMODE 0x11148050
++#define CH0_DMC_CFG_RNKVOL_0 0x11148060
++#define CH0_DMC_CFG_RNKVOL_1 0x11148064
++
++#define CH1_DMC_CFG_DDRMODE 0x11149050
++#define CH1_DMC_CFG_RNKVOL_0 0x11149060
++#define CH1_DMC_CFG_RNKVOL_1 0x11149064
++
++#define CH2_DMC_CFG_DDRMODE 0x1114a050
++#define CH2_DMC_CFG_RNKVOL_0 0x1114a060
++#define CH2_DMC_CFG_RNKVOL_1 0x1114a064
++
++#define CH3_DMC_CFG_DDRMODE 0x1114b050
++#define CH3_DMC_CFG_RNKVOL_0 0x1114b060
++#define CH3_DMC_CFG_RNKVOL_1 0x1114b064
++
++#define CH0_QOS_CFG_DDRMODE 0x11144630
++#define CH0_QOS_CFG_RNKVOL_0 0x11144634
++#define CH0_QOS_CFG_RNKVOL_1 0x11144638
++
++#define CH1_QOS_CFG_DDRMODE 0x11144640
++#define CH1_QOS_CFG_RNKVOL_0 0x11144644
++#define CH1_QOS_CFG_RNKVOL_1 0x11144648
++
++#define CH2_QOS_CFG_DDRMODE 0x11144650
++#define CH2_QOS_CFG_RNKVOL_0 0x11144654
++#define CH2_QOS_CFG_RNKVOL_1 0x11144658
++
++#define CH3_QOS_CFG_DDRMODE 0x11144660
++#define CH3_QOS_CFG_RNKVOL_0 0x11144664
++#define CH3_QOS_CFG_RNKVOL_1 0x11144668
++
++static inline void delay(unsigned int num)
++{
++ volatile unsigned int i;
++
++ for (i = 0; i < (100 * num); i++) /* 100: Cycle */
++ __asm__ __volatile__("nop");
++}
++
++static inline void dwb(void) /* drain write buffer */
++{
++}
++
++static inline unsigned int readl(unsigned addr)
++{
++ unsigned int val;
++
++ val = (*(volatile unsigned int *)(long)(addr));
++ return val;
++}
++
++static inline void writel(unsigned val, unsigned addr)
++{
++ dwb();
++ (*(volatile unsigned *)(long)(addr)) = (val);
++ dwb();
++}
++
++#define REG_BASE_MISC 0x11020000
++#define DDRCA_REE_RANDOM_L 0x4040
++#define DDRCA_REE_RANDOM_H 0x4044
++#define DDRCA_TEE_RANDOM_L 0x4048
++#define DDRCA_TEE_RANDOM_H 0x404C
++#define DDRCA_EN 0x4050
++#define DDRCA_REE_UPDATE 0x4054
++#define DDRCA_TEE_UPDATE 0x4058
++#define DDR_CA_LOCK 0x405c
++#define RANDOM_SIZE 4
++
++#define REG_TSENSOR_CTRL 0x1102e000
++#define TSENSOR_CTRL0 0x0
++#define TSENSOR_CTRL0_CFG 0xc0300000
++#define TSENSOR_CTRL1 0x4
++#define TSENSOR_CTRL1_CFG 0x8
++
++#define SYSCTRL_REG 0x11020000
++#define HPM_CORE_VOL_REG (SYSCTRL_REG + 0x9004)
++#define HPM_MDA_VOL_REG (SYSCTRL_REG + 0x9104)
++#define HPM_NPU_VOL_REG (SYSCTRL_REG + 0x9204)
++#define HPM_MONITOR_CFG 0x60200001
++#define HPM_CORE_OFFSET 0xb030
++#define HPM_MDA_OFFSET 0xb020
++#define HPM_NPU_OFFSET 0xb010
++#define CYCLE_NUM 8
++#define HPM_NPU_REG0 0xb018
++#define HPM_NPU_REG1 0xb01c
++#define HPM_MDA_REG0 0xb028
++#define HPM_MDA_REG1 0xb02c
++#define HPM_CORE_REG0 0xb038
++#define HPM_CORE_REG1 0xb03c
++
++#define HPM_CLK_REG 0x11014a80
++#define HPM_CLK_CFG 0x30
++
++#define CPU_ISO_REG 0x1d821104
++
++#define TSENSOR_CTRL 0x70
++#define TSENSOR_STATUS0 0x8
++
++#define OTP_CPU_IF_REG 0x10120000
++#define OTP_HPM_CORE_OFFSET 0x1504
++#define OTP_HPM_MDA_OFFSET 0x1534
++#define OTP_HPM_NPU_OFFSET 0x1530
++#define OTP_SHPM_MDA_OFFSET 0x153c
++
++#define SYSCTRL_BASE_REG 0x11020000
++#define HPM_CORE_STORAGE_REG 0x340
++#define HPM_MDA_STORAGE_REG 0x344
++#define HPM_NPU_STORAGE_REG 0x348
++#define TEMPERATURE_STORAGE_REG 0x34c
++#define DELTA_V_STORAGE_REG 0x350
++#define CORE_DUTY_STORAGE_REG 0x354
++#define MDA_DUTY_STORAGE_REG 0x358
++#define NPU_DUTY_STORAGE_REG 0x35c
++
++/* physical max/min */
++#define CORE_VOLT_MAX 920
++#define CORE_VOLT_MIN 599
++
++#define MDA_VOLT_MAX 1049
++#define MDA_VOLT_MIN 600
++
++#define NPU_VOLT_MAX 1049
++#define NPU_VOLT_MIN 600
++
++/* curve max/min; voltage curve: v = (b - a * hpm) / 10 */
++#define CORE_CURVE_VLOT_MAX 850
++#define CORE_CURVE_VLOT_MIN 760
++#define CORE_CURVE_B 16200
++#define CORE_CURVE_A 20
++
++#define MEDIA_CURVE_VLOT_MAX 770
++#define MEDIA_CURVE_VLOT_MIN 690
++#define MEDIA_CURVE_B 11150
++#define MEDIA_CURVE_A 10
++
++
++#define NPU_CURVE_VLOT_MAX 810
++#define NPU_CURVE_VLOT_MIN 730
++#define NPU_CURVE_B 127500
++#define NPU_CURVE_A 125
++
++#define SVB_VER_REG 0x11020168
++#define SVB_VER 0x30303030
++#define temperature_formula(val) (((((val) - 116) * 165) / 806) - 40)
++#define duty_formula(max, min, val) ((((max) - (val)) * 416 + ((max) - (min) + 1) / 2) / ((max) - (min)) - 1)
++#define volt_regval_formula(val) (((val) << 16) + ((416 - 1) << 4) + 0x5)
++
++static unsigned hpm_value_avg(unsigned int *val, unsigned int num)
++{
++ unsigned int i;
++ unsigned tmp = 0;
++
++ for (i = 0; i < num; i++) /* 4: Cycle */
++ tmp += val[i];
++
++ return (tmp / CYCLE_NUM) >> 2;
++}
++
++static void get_hpm_value(unsigned int *hpm_core, unsigned int *hpm_npu,
++ unsigned int *hpm_mda)
++{
++ int i;
++ unsigned int temp;
++ unsigned int core_value[4] = {0, 0, 0, 0};
++ unsigned int mda_value[4] = {0, 0, 0, 0};
++ unsigned int npu_value[4] = {0, 0, 0, 0};
++
++ for (i = 0; i < CYCLE_NUM; i++) {
++ /* (at least 16us*4) */
++ delay(5); /* delay 5 s */
++ /* npu */
++ temp = readl(SYSCTRL_REG + HPM_NPU_REG0);
++ npu_value[1] += (temp >> 16) & 0x3ff;
++ npu_value[0] += temp & 0x3ff;
++ temp = readl(SYSCTRL_REG + HPM_NPU_REG1);
++ npu_value[3] += (temp >> 16) & 0x3ff;
++ npu_value[2] += temp & 0x3ff;
++
++ /* mda */
++ temp = readl(SYSCTRL_REG + HPM_MDA_REG0);
++ mda_value[1] += (temp >> 16) & 0x3ff;
++ mda_value[0] += temp & 0x3ff;
++ temp = readl(SYSCTRL_REG + HPM_MDA_REG1);
++ mda_value[3] += (temp >> 16) & 0x3ff;
++ mda_value[2] += temp & 0x3ff;
++
++ /* core */
++ temp = readl(SYSCTRL_REG + HPM_CORE_REG0);
++ core_value[1] += (temp >> 16) & 0x3ff;
++ core_value[0] += temp & 0x3ff;
++ temp = readl(SYSCTRL_REG + HPM_CORE_REG1);
++ core_value[3] += (temp >> 16) & 0x3ff;
++ core_value[2] += temp & 0x3ff;
++ }
++
++ *hpm_core = hpm_value_avg(core_value, 4); /* 4 : Array size */
++ *hpm_mda = hpm_value_avg(mda_value, 4); /* 4 : Array size */
++ *hpm_npu = hpm_value_avg(npu_value, 4); /* 4 : Array size */
++}
++
++static void start_hpm(unsigned int *hpm_core, unsigned int *hpm_npu,
++ unsigned int *hpm_mda)
++{
++ get_hpm_value(hpm_core, hpm_npu, hpm_mda);
++}
++
++static void adjust_hpm(unsigned int *hpm_core, unsigned int *hpm_mda,
++ unsigned int *hpm_npu, int temperature)
++{
++ unsigned int otp_hpm_core = readl(SYSCTRL_BASE_REG + OTP_HPM_CORE_OFFSET);
++ unsigned int otp_hpm_npu = readl(SYSCTRL_BASE_REG + OTP_HPM_NPU_OFFSET);
++ unsigned int otp_hpm_mda = readl(SYSCTRL_BASE_REG + OTP_HPM_MDA_OFFSET);
++
++ if (temperature <= 0) {
++ *hpm_npu -= 2; /* 2 : Adjustment Value */
++ *hpm_mda -= 3; /* 3 : Adjustment Value */
++ *hpm_core -= 4; /* 4 : Adjustment Value */
++ } else if (temperature > 100) { /* 100: temperature value */
++ *hpm_npu += 5; /* 5 : Adjustment Value */
++ *hpm_mda += 5; /* 5 : Adjustment Value */
++ *hpm_core += 8; /* 8 : Adjustment Value */
++ }else if(temperature > 70) { /* 70: temperature value */
++ *hpm_npu += 3; /* 2 : Adjustment Value */
++ *hpm_mda += 3; /* 2 : Adjustment Value */
++ *hpm_core += 4; /* 3 : Adjustment Value */
++ }
++
++
++ if (otp_hpm_core) {
++ if (*hpm_core > (otp_hpm_core + 59)) /* 10: Increment */
++ *hpm_core = otp_hpm_core + 59; /* 5: Increment */
++ }
++
++ if (otp_hpm_npu) {
++ if (*hpm_npu > (otp_hpm_npu + 62)) /* 15: Increment */
++ *hpm_npu = otp_hpm_npu + 62;
++ }
++
++ if (otp_hpm_mda) {
++ if (*hpm_mda > (otp_hpm_mda + 61)) /* 15: Increment */
++ *hpm_mda = otp_hpm_mda + 61;
++ }
++}
++
++static void save_hpm(unsigned int hpm_core, unsigned int hpm_npu,
++ unsigned int hpm_mda)
++{
++ writel(hpm_mda, SYSCTRL_BASE_REG + HPM_MDA_STORAGE_REG);
++ writel(hpm_npu, SYSCTRL_BASE_REG + HPM_NPU_STORAGE_REG);
++ writel(hpm_core, SYSCTRL_BASE_REG + HPM_CORE_STORAGE_REG);
++}
++
++static unsigned int calc_volt_regval(unsigned int volt_val, unsigned int volt_max,
++ unsigned int volt_min)
++{
++ unsigned int duty;
++
++ if (volt_val >= volt_max)
++ volt_val = volt_max - 1;
++ if (volt_val <= volt_min)
++ volt_val = volt_min + 1;
++ duty = duty_formula(volt_max, volt_min, volt_val);
++
++ return duty;
++}
++
++static void set_hpm_core_volt(unsigned int hpm_core_value, int delta_v)
++{
++ unsigned int volt_val;
++ unsigned int reg_val;
++
++ volt_val = (CORE_CURVE_B - CORE_CURVE_A * hpm_core_value) / 10;
++
++ if (volt_val > CORE_CURVE_VLOT_MAX)
++ volt_val = CORE_CURVE_VLOT_MAX;
++ else if (volt_val < CORE_CURVE_VLOT_MIN)
++ volt_val = CORE_CURVE_VLOT_MIN;
++
++ volt_val += delta_v;
++ reg_val = calc_volt_regval(volt_val, CORE_VOLT_MAX, CORE_VOLT_MIN);
++ writel(reg_val, SYSCTRL_BASE_REG + CORE_DUTY_STORAGE_REG);
++ writel(reg_val, HPM_CORE_VOL_REG);
++}
++
++static void set_hpm_mda_volt(unsigned int hpm_mda_value, int delta_v)
++{
++ unsigned int volt_val;
++ unsigned int reg_val;
++
++ volt_val = (MEDIA_CURVE_B - MEDIA_CURVE_A * hpm_mda_value) / 10;
++ if (volt_val > MEDIA_CURVE_VLOT_MAX)
++ volt_val = MEDIA_CURVE_VLOT_MAX;
++ else if (volt_val < MEDIA_CURVE_VLOT_MIN)
++ volt_val = MEDIA_CURVE_VLOT_MIN;
++
++ volt_val += delta_v;
++ reg_val = calc_volt_regval(volt_val, MDA_VOLT_MAX, MDA_VOLT_MIN);
++ writel(reg_val, SYSCTRL_BASE_REG + MDA_DUTY_STORAGE_REG);
++
++ writel(reg_val, HPM_MDA_VOL_REG);
++}
++
++static void set_hpm_npu_volt(unsigned int hpm_npu_value, int delta_v)
++{
++ unsigned int volt_val;
++ unsigned int reg_val;
++
++ volt_val = (NPU_CURVE_B - NPU_CURVE_A * hpm_npu_value) / 100;
++ if (volt_val > NPU_CURVE_VLOT_MAX)
++ volt_val = NPU_CURVE_VLOT_MAX;
++ else if (volt_val < NPU_CURVE_VLOT_MIN)
++ volt_val = NPU_CURVE_VLOT_MIN;
++
++ volt_val += delta_v;
++ reg_val = calc_volt_regval(volt_val, NPU_VOLT_MAX, NPU_VOLT_MIN);
++ writel(reg_val, SYSCTRL_BASE_REG + NPU_DUTY_STORAGE_REG);
++
++ writel(reg_val, HPM_NPU_VOL_REG);
++}
++
++static void get_delta_v(int *core_delta_v, int *npu_delta_v, int *mda_delta_v)
++{
++ unsigned int value = readl(SYSCTRL_REG + OTP_SHPM_MDA_OFFSET);
++ writel(value, SYSCTRL_BASE_REG + DELTA_V_STORAGE_REG);
++ /* core:bit 11-8,
++ * bit11 equal to 1 means negative, equal to 0 means positive,
++ * bit 8-10 is the absolute delta_v
++ */
++ int flag = (value & 0x800) ? -1 : 1;
++ *core_delta_v = flag * (int)((value >> 8) & 0x7) * 10;
++
++ /* mda:bit 7-4,
++ * bit7 equal to 1 means negative, equal to 0 means positive,
++ * bit 4-6 is the absolute delta_v
++ */
++ flag = (value & 0x80) ? -1 : 1;
++ *mda_delta_v = flag * (int)((value >> 4) & 0x7) * 10;
++
++ /* npu:bit 3-0,
++ * bit3 equal to 1 means negative, equal to 0 means positive,
++ * bit 0-2 is the absolute delta_v
++ */
++ flag = (value & 0x8) ? -1 : 1;
++ *npu_delta_v = flag * (int)(value & 0x7) * 10;
++}
++
++
++static void set_volt(unsigned int hpm_core, unsigned int hpm_npu,
++ unsigned int hpm_mda)
++{
++ int core_delta_v = 0;
++ int npu_delta_v = 0;
++ int mda_delta_v = 0;
++ get_delta_v(&core_delta_v, &npu_delta_v, &mda_delta_v);
++
++ set_hpm_core_volt(hpm_core, core_delta_v);
++ set_hpm_mda_volt(hpm_mda, mda_delta_v);
++ set_hpm_npu_volt(hpm_npu, npu_delta_v);
++
++ /* delay 300 Cycle */
++ delay(300);
++}
++
++static void get_temperature(int *temperature)
++{
++ int value = 0;
++ int tsensor_chn;
++ float m = 0.5;
++ float temperature_temp[3] = {0};
++ for(tsensor_chn = 0; tsensor_chn < 3; tsensor_chn++) {
++ value = (int)(readl(REG_TSENSOR_CTRL + TSENSOR_STATUS0 +
++ 0x100 * tsensor_chn) & 0x3ff);
++
++ m = ((float)value - 146) / 718 * 165 - 40;
++
++ if(m > 0)
++ temperature_temp[tsensor_chn] = m + 0.5;
++ else
++ temperature_temp[tsensor_chn] = m - 0.5;
++ }
++
++ *temperature = (temperature_temp[0]+temperature_temp[1]+temperature_temp[2])/3;
++ writel(*temperature, SYSCTRL_BASE_REG + TEMPERATURE_STORAGE_REG);
++}
++
++void init_temperature(void)
++{
++ int tsensor_chn;
++
++ for(tsensor_chn = 0; tsensor_chn < 3; tsensor_chn++) {
++ writel(TSENSOR_CTRL0_CFG, REG_TSENSOR_CTRL + TSENSOR_CTRL0 +
++ 0x100 * tsensor_chn);
++ writel(TSENSOR_CTRL1_CFG, REG_TSENSOR_CTRL + TSENSOR_CTRL1 +
++ 0x100 * tsensor_chn);
++ }
++
++}
++
++void init_hpm(void)
++{
++ /* open hmp clock */
++ writel(HPM_CLK_CFG, HPM_CLK_REG);
++
++ /* npu */
++ writel(HPM_MONITOR_CFG, SYSCTRL_REG + HPM_NPU_OFFSET);
++ /* mda */
++ writel(HPM_MONITOR_CFG, SYSCTRL_REG + HPM_MDA_OFFSET);
++ /* core */
++ writel(HPM_MONITOR_CFG, SYSCTRL_REG + HPM_CORE_OFFSET);
++
++}
++static void start_svb(void)
++{
++ unsigned int hpm_core;
++ unsigned int hpm_npu;
++ unsigned int hpm_mda;
++ int temperature;
++
++ /* init temperature and hpm*/
++ init_temperature();
++ init_hpm();
++ delay(1000);
++ start_hpm(&hpm_core, &hpm_npu, &hpm_mda);
++
++ /*get temperature */
++ get_temperature(&temperature);
++
++ adjust_hpm(&hpm_core, &hpm_mda, &hpm_npu, temperature);
++ set_volt(hpm_core, hpm_npu, hpm_mda);
++ save_hpm(hpm_core, hpm_npu, hpm_mda);
++
++ /* add SVB VER*/
++ writel(SVB_VER, SVB_VER_REG);
++}
++
++static void set_qosbuf_cfg(void)
++{
++ unsigned int val;
++
++ val = readl(CH0_DMC_CFG_DDRMODE);
++ writel(val, CH0_QOS_CFG_DDRMODE);
++ val = readl(CH0_DMC_CFG_RNKVOL_0);
++ writel(val, CH0_QOS_CFG_RNKVOL_0);
++ val = readl(CH0_DMC_CFG_RNKVOL_1);
++ writel(val, CH0_QOS_CFG_RNKVOL_1);
++
++ val = readl(CH1_DMC_CFG_DDRMODE);
++ writel(val, CH1_QOS_CFG_DDRMODE);
++ val = readl(CH1_DMC_CFG_RNKVOL_0);
++ writel(val, CH1_QOS_CFG_RNKVOL_0);
++ val = readl(CH1_DMC_CFG_RNKVOL_1);
++ writel(val, CH1_QOS_CFG_RNKVOL_1);
++
++ val = readl(CH2_DMC_CFG_DDRMODE);
++ writel(val, CH2_QOS_CFG_DDRMODE);
++ val = readl(CH2_DMC_CFG_RNKVOL_0);
++ writel(val, CH2_QOS_CFG_RNKVOL_0);
++ val = readl(CH2_DMC_CFG_RNKVOL_1);
++ writel(val, CH2_QOS_CFG_RNKVOL_1);
++
++ val = readl(CH3_DMC_CFG_DDRMODE);
++ writel(val, CH3_QOS_CFG_DDRMODE);
++ val = readl(CH3_DMC_CFG_RNKVOL_0);
++ writel(val, CH3_QOS_CFG_RNKVOL_0);
++ val = readl(CH3_DMC_CFG_RNKVOL_1);
++ writel(val, CH3_QOS_CFG_RNKVOL_1);
++}
++
++void start_ddr_training(unsigned int base)
++{
++ start_svb();
++
++ set_qosbuf_cfg();
++
++ ddr_set_rdqbdl_def_val();
++
++ /* ddr hw training */
++ ddr_hw_training_init();
++
++ /* ddr sw training */
++ ddr_sw_training_if();
++
++ ddr_retrain_anti_aging_enable();
++
++ /* ddr DMC auto power down config */
++ ddr_dmc_auto_power_down_cfg();
++}
+diff --git a/arch/arm/cpu/armv8/ss928v100/reset.S b/arch/arm/cpu/armv8/ss928v100/reset.S
+new file mode 100644
+index 0000000..ad86198
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/reset.S
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++
++.global reset_cpu
++reset_cpu:
++ ldr x1, rstctl /* get addr for global reset */
++ /* reg */
++ mov w3, #0x2 /* full reset pll + mpu */
++ str w3, [x1] /* force reset */
++ mov x0, x0
++
++_loop_forever:
++ b _loop_forever
++.align 3
++rstctl:
++ .quad SYS_CTRL_REG_BASE + REG_SC_SYSRES
+diff --git a/arch/arm/cpu/armv8/ss928v100/sdhci_boot.c b/arch/arm/cpu/armv8/ss928v100/sdhci_boot.c
+new file mode 100644
+index 0000000..c0036d6
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/sdhci_boot.c
+@@ -0,0 +1,391 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++
++#define DELAY_US 1000
++
++#define MMC_BLK_SZ 512
++#define CP_STEP1_SIZE 0x7800
++
++/*
++ * Controller registers
++ */
++#define SDHCI_DMA_ADDRESS 0x00
++#define SDHCI_BLOCK_SIZE 0x04
++#define SDHCI_BLOCK_COUNT 0x06
++#define SDHCI_ARGUMENT 0x08
++
++#define SDHCI_TRANSFER_MODE 0x0C
++#define SDHCI_TRNS_DMA 0x0001
++#define SDHCI_TRNS_BLK_CNT_EN 0x0002
++#define SDHCI_TRNS_READ 0x0010
++#define SDHCI_TRNS_MULTI 0x0020
++
++#define SDHCI_COMMAND 0x0E
++#define SDHCI_CMD_RESP_NONE 0x0000
++#define SDHCI_CMD_RESP_LONG 0x0001
++#define SDHCI_CMD_RESP_SHORT 0x0002
++#define SDHCI_CMD_CRC 0x0008
++#define SDHCI_CMD_DATA 0x0020
++
++#define SDHCI_RESPONSE 0x10
++#define SDHCI_BUFFER 0x20
++
++#define SDHCI_PRESENT_STATE 0x24
++#define SDHCI_PSTATE_DAT_0 0x00100000
++
++#define SDHCI_HOST_CONTROL 0x28
++#define SDHCI_CTRL_4BITBUS 0x02
++#define SDHCI_CTRL_8BITBUS 0x20
++
++#define SDHCI_POWER_CONTROL 0x29
++#define SDHCI_POWER_ON 0x01
++#define SDHCI_POWER_180 0x0A
++#define SDHCI_POWER_300 0x0C
++#define SDHCI_POWER_330 0x0E
++
++#define SDHCI_CLOCK_CONTROL 0x2C
++#define SDHCI_CLOCK_INT_EN 0x0001
++#define SDHCI_CLOCK_INT_STABLE 0x0002
++#define SDHCI_CLOCK_CARD_EN 0x0004
++
++#define SDHCI_TIMEOUT_CONTROL 0x2E
++
++#define SDHCI_SOFTWARE_RESET 0x2F
++#define SDHCI_RESET_ALL 0x01
++#define SDHCI_RESET_CMD 0x02
++#define SDHCI_RESET_DATA 0x04
++
++#define SDHCI_INT_STATUS 0x30
++#define SDHCI_INT_RESPONSE 0x00000001
++#define SDHCI_INT_DATA_END 0x00000002
++#define SDHCI_INT_DMA 0x00000008
++#define SDHCI_INT_DATA_AVAIL 0x00000020
++#define SDHCI_INT_NORMAL_MASK 0x00007FFF
++#define SDHCI_INT_ERROR_MASK 0xFFFF8000
++
++#define SDHCI_INT_ENABLE 0x34
++
++#define SDHCI_EMMC_CTRL 0x52C
++#define SDHCI_CARD_IS_EMMC 0x0001
++
++#define SDHCI_BOOT_CTRL 0x52E
++#define MAN_BOOT_EN 0x0001
++#define VALIDATE_BOOT 0x0080
++
++#define SDHCI_EMMC_HW_RESET 0x534
++
++#define sdhci_make_cmd(idx, param) ((((idx) & 0xFF) << 8) | ((param) & 0xFF))
++#define sdhci_make_blksz(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
++
++#define MMC_CMD_GO_IDLE_STATE 0
++#define MMC_CMD_SEND_OP_COND 1
++#define MMC_CMD_ALL_SEND_CID 2
++#define MMC_CMD_SET_RELATIVE_ADDR 3
++#define MMC_CMD_SWITCH 6
++#define MMC_CMD_SELECT_CARD 7
++#define MMC_CMD_SEND_CSD 9
++#define MMC_CMD_STOP_TRANSMISSION 12
++#define MMC_CMD_SET_BLOCKLEN 16
++#define MMC_CMD_READ_SINGLE_BLOCK 17
++#define MMC_CMD_READ_MULTIPLE_BLOCK 18
++#define MMC_CMD_SET_BLOCK_COUNT 23
++
++#define MMC_SWITCH_MODE_WRITE_BYTE 0x3
++#define MMC_SWITCH_ACCESS_SHIFT 24
++#define MMC_SWITCH_INDEX_SHIFT 16
++#define MMC_SWITCH_VALUE_SHIFT 8
++
++/* SDMA Configuration */
++#define BOUNDARY_SIZE (512 * 1024) /* 512K */
++#define BOUNDARY_ARG (0x7 << 12) /* 512K */
++#define MMC_SDMA_ENABLE 1
++
++#define OCR_BUSY 0x80000000
++#define OCR_HCS 0x40000000
++
++#define debug_printf(fmt, args...);
++#define reg_get(addr) (*(volatile unsigned int *)((uintptr_t)(addr)))
++
++static unsigned int is_bootmode(void)
++{
++ return !(reg_get(REG_BASE_SCTL + REG_PERI_EMMC_STAT) & EMMC_NORMAL_MODE);
++}
++
++static unsigned int get_hcs(void)
++{
++ return reg_get(REG_SAVE_HCS) & OCR_HCS;
++}
++
++static inline void delay(unsigned int cnt)
++{
++ while (cnt--)
++ __asm__ __volatile__("nop");
++}
++
++static inline unsigned int sdhci_readb(unsigned addr)
++{
++ return *((volatile unsigned char *) (uintptr_t)(EMMC_BASE_REG + addr));
++}
++
++static inline void sdhci_writeb(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned char *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
++}
++
++static inline unsigned int sdhci_readw(unsigned addr)
++{
++ return *((volatile unsigned short *) (uintptr_t)(EMMC_BASE_REG + addr));
++}
++
++static inline void sdhci_writew(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned short *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
++}
++
++static inline unsigned int sdhci_readl(unsigned addr)
++{
++ return *((volatile unsigned int *) (uintptr_t)(EMMC_BASE_REG + addr));
++}
++
++static inline void sdhci_writel(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned int *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
++}
++
++static int sdhci_read_block_pio(void *data_addr, unsigned int block)
++{
++ const unsigned int offset = sizeof(unsigned int);
++ unsigned int size;
++ unsigned char *buf;
++
++ size = MMC_BLK_SZ;
++ buf = (unsigned char *)data_addr + MMC_BLK_SZ * block;
++ while (size) {
++ *(unsigned int *)buf = sdhci_readl(SDHCI_BUFFER);
++ buf += offset;
++ size -= offset;
++ }
++
++ return 0;
++}
++
++static int sdhci_check_int_status(unsigned int mask, unsigned int timeout)
++{
++ unsigned int reg;
++
++ timeout *= 1000; /* ms is converted to us multiplied by 1000 */
++ for (;;) {
++ reg = sdhci_readl(SDHCI_INT_STATUS);
++ if (reg & mask)
++ break;
++ if (!(--timeout)) {
++ debug_printf("wait int status time out, reg = 0x%x, mask = 0x%x\n",
++ reg, mask);
++ return -1;
++ }
++ if (reg & SDHCI_INT_ERROR_MASK) {
++ debug_printf("int err: reg = 0x%x\n", reg);
++ return -1;
++ }
++
++ delay(DELAY_US);
++ }
++
++ return 0;
++}
++
++static int sdhci_boot_read(void *data_addr, unsigned int read_block)
++{
++ const unsigned int timeout = 2000; /* 2s timeout: 2000000 * 1us */
++ int ret;
++ unsigned int blocks = 0;
++
++ while (1) {
++ ret = sdhci_check_int_status(SDHCI_INT_DATA_AVAIL, timeout);
++ if (ret) {
++ debug_printf("wait data available int time out\n");
++ return ret;
++ }
++
++ sdhci_writel(SDHCI_INT_DATA_AVAIL, SDHCI_INT_STATUS);
++ sdhci_read_block_pio(data_addr, blocks);
++
++ blocks++;
++ if (blocks == read_block)
++ break;
++ }
++
++ return 0;
++}
++
++static int mmc_send_cmd(unsigned int cmd, unsigned int arg)
++{
++ const unsigned int timeout = 3000; /* 3s timeout: 3000000 * 1us */
++
++ sdhci_writel(0xFFFFFFFF, SDHCI_INT_STATUS);
++ sdhci_writel(arg, SDHCI_ARGUMENT);
++ sdhci_writew(cmd, SDHCI_COMMAND);
++
++ if (sdhci_check_int_status(SDHCI_INT_RESPONSE, timeout)) {
++ debug_printf("send cmd error\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static void mmc_read_cmd(unsigned long int start_addr, unsigned int src,
++ unsigned int size, unsigned int dma)
++{
++ unsigned int cmd, hcs;
++ unsigned short mode;
++
++ /* Send CMD16 to set blocksize */
++ cmd = sdhci_make_cmd(MMC_CMD_SET_BLOCKLEN, SDHCI_CMD_CRC |
++ SDHCI_CMD_RESP_SHORT);
++ mmc_send_cmd(cmd, MMC_BLK_SZ);
++
++ /* set data timeout */
++ sdhci_writeb(0xE, SDHCI_TIMEOUT_CONTROL);
++
++ /* set host count */
++ sdhci_writew(size, SDHCI_BLOCK_COUNT);
++
++ /* Send CMD23 to set blockcount */
++ cmd = sdhci_make_cmd(MMC_CMD_SET_BLOCK_COUNT,
++ SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT);
++ mmc_send_cmd(cmd, size);
++
++ /* set transfer mode */
++ mode = SDHCI_TRNS_READ | SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN;
++ if (dma)
++ mode |= SDHCI_TRNS_DMA;
++
++ sdhci_writew(mode, SDHCI_TRANSFER_MODE);
++
++ /* set SDMA address */
++ if (dma)
++ sdhci_writel(start_addr, SDHCI_DMA_ADDRESS);
++
++ /* Send CMD18 for multiple block read */
++ hcs = get_hcs();
++ if (hcs) {
++ cmd = sdhci_make_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,
++ SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_DATA);
++ mmc_send_cmd(cmd, src / MMC_BLK_SZ);
++ } else {
++ cmd = sdhci_make_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,
++ SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_DATA);
++ mmc_send_cmd(cmd, src);
++ }
++}
++
++static int sdhci_normal_read_sdma(void *dst, unsigned int src, unsigned int size)
++{
++ unsigned int stat;
++ unsigned int timeout;
++ unsigned long int start_addr;
++
++ start_addr = (uintptr_t)dst;
++
++ /* set host block size 512 */
++ sdhci_writew(MMC_BLK_SZ | BOUNDARY_ARG, SDHCI_BLOCK_SIZE);
++
++ mmc_read_cmd(start_addr, src, size, MMC_SDMA_ENABLE);
++
++ sdhci_writel(SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
++
++ timeout = 300000; /* 3s timeout: 300000 * 10us */
++ do {
++ stat = sdhci_readl(SDHCI_INT_STATUS);
++ if (stat & SDHCI_INT_ERROR_MASK) {
++ debug_printf("interrupt error\n");
++ return -1;
++ }
++
++ if (stat & SDHCI_INT_DMA) {
++ sdhci_writel(SDHCI_INT_DMA, SDHCI_INT_STATUS);
++ start_addr &= ~(BOUNDARY_SIZE - 1);
++ start_addr += BOUNDARY_SIZE;
++ sdhci_writel(start_addr, SDHCI_DMA_ADDRESS);
++ }
++
++ if (timeout > 0) {
++ delay(10 * DELAY_US); /* delay 10us */
++ timeout -= 1;
++ } else {
++ debug_printf("read timeout!\n");
++ return -1;
++ }
++ } while (!(stat & SDHCI_INT_DATA_END));
++
++ sdhci_writel(SDHCI_INT_DATA_END, SDHCI_INT_STATUS);
++
++ return 0;
++}
++
++static void copy_step1_to_ddr(unsigned int *dst, unsigned int *src, unsigned int size)
++{
++ unsigned int cycle = size / sizeof(unsigned int);
++ unsigned int i;
++
++ for (i = 0; i < cycle; i++)
++ *dst++ = *src++;
++}
++
++static int emmc_read_boot_data(void *data_addr, unsigned int data_size)
++{
++ unsigned int read_block;
++ int bootmode;
++
++ if (data_size <= CP_STEP1_SIZE) {
++ copy_step1_to_ddr((void *)data_addr, (void *)CP_STEP1_ADDR, data_size);
++ return 0;
++ } else {
++ copy_step1_to_ddr((void *)data_addr, (void *)CP_STEP1_ADDR, CP_STEP1_SIZE);
++ data_addr += CP_STEP1_SIZE;
++ data_size -= CP_STEP1_SIZE;
++ }
++
++ if (data_size % MMC_BLK_SZ) {
++ debug_printf("sdhci_read_boot_data error\n");
++ debug_printf("data_size:%d not round by block size\n", data_size);
++ read_block = data_size / MMC_BLK_SZ + 1;
++ } else {
++ read_block = data_size / MMC_BLK_SZ;
++ }
++
++ bootmode = is_bootmode();
++ if (bootmode)
++ return sdhci_boot_read(data_addr, read_block);
++
++ return sdhci_normal_read_sdma(data_addr, CP_STEP1_SIZE, read_block);
++}
++
++int emmc_boot_read(void *ptr, unsigned int size)
++{
++ int ret;
++
++ ret = emmc_read_boot_data(ptr, size);
++ return ret;
++}
+diff --git a/arch/arm/cpu/armv8/ss928v100/start.S b/arch/arm/cpu/armv8/ss928v100/start.S
+new file mode 100644
+index 0000000..b2cadac
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/start.S
+@@ -0,0 +1,371 @@
++/*
++ * (C) Copyright 2013
++ * David Feng
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++#include
++#include
++#include
++#include
++
++/*************************************************************************
++ *
++ * Startup Code (reset vector)
++ *
++ *************************************************************************/
++/*
++ * Branch according to exception level
++ */
++.macro switch_el, xreg, el3_label, el2_label, el1_label
++ mrs \xreg, CurrentEL
++ cmp \xreg, 0xc
++ b.eq \el3_label
++ cmp \xreg, 0x8
++ b.eq \el2_label
++ cmp \xreg, 0x4
++ b.eq \el1_label
++.endm
++
++/*
++ * Enter Exception.
++ * This will save the processor state that is ELR/X0~X30
++ * to the stack frame.
++ */
++.macro exception_entry
++ stp x29, x30, [sp, #-16]!
++ stp x27, x28, [sp, #-16]!
++ stp x25, x26, [sp, #-16]!
++ stp x23, x24, [sp, #-16]!
++ stp x21, x22, [sp, #-16]!
++ stp x19, x20, [sp, #-16]!
++ stp x17, x18, [sp, #-16]!
++ stp x15, x16, [sp, #-16]!
++ stp x13, x14, [sp, #-16]!
++ stp x11, x12, [sp, #-16]!
++ stp x9, x10, [sp, #-16]!
++ stp x7, x8, [sp, #-16]!
++ stp x5, x6, [sp, #-16]!
++ stp x3, x4, [sp, #-16]!
++ stp x1, x2, [sp, #-16]!
++
++ /* Could be running at EL3/EL2/EL1 */
++ switch_el x11, 3f, 2f, 1f
++3: mrs x1, esr_el3
++ mrs x2, elr_el3
++ b 0f
++2: mrs x1, esr_el2
++ mrs x2, elr_el2
++ b 0f
++1: mrs x1, esr_el1
++ mrs x2, elr_el1
++0:
++ stp x2, x0, [sp, #-16]!
++ mov x0, sp
++.endm
++
++.globl _start
++_start:
++ b reset
++
++.balignl 64,0xdeadbeef
++__blank_zone_start:
++.fill 11008,1,0
++__blank_zone_end:
++
++.globl _blank_zone_start
++_blank_zone_start:
++.quad __blank_zone_start
++
++.globl _blank_zone_end
++_blank_zone_end:
++.quad __blank_zone_end
++.balignl 16,0xdeadbeef
++
++.align 3
++
++.globl _TEXT_BASE
++_TEXT_BASE:
++ .quad TEXT_BASE
++
++/*
++ * These are defined in the linker script.
++ */
++.globl _end_ofs
++_end_ofs:
++ .quad _end - _start
++
++.globl _bss_start_ofs
++_bss_start_ofs:
++ .quad __bss_start - _start
++
++.globl _bss_end_ofs
++_bss_end_ofs:
++ .quad __bss_end - _start
++
++reset:
++ /*
++ * Could be EL3/EL2/EL1, Initial State:
++ * Little Endian, MMU Disabled, i/dCache Disabled
++ */
++ adr x0, vectors
++ switch_el x1, 3f, 2f, 1f
++3: msr vbar_el3, x0
++ mrs x0, scr_el3
++ orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */
++ msr scr_el3, x0
++ msr cptr_el3, xzr /* Enable FP/SIMD */
++#ifdef COUNTER_FREQUENCY
++ ldr x0, =COUNTER_FREQUENCY
++ msr cntfrq_el0, x0 /* Initialize CNTFRQ */
++#endif
++ b 0f
++2: msr vbar_el2, x0
++ mov x0, #0x33ff
++ msr cptr_el2, x0 /* Enable FP/SIMD */
++ b 0f
++1: msr vbar_el1, x0
++ mov x0, #3 << 20
++ msr cpacr_el1, x0 /* Enable FP/SIMD */
++0:
++
++ /*
++ * Cache/BPB/TLB Invalidate
++ * i-cache is invalidated before enabled in icache_enable()
++ * tlb is invalidated before mmu is enabled in dcache_enable()
++ * d-cache is invalidated before enabled in dcache_enable()
++ */
++
++#ifndef CONFIG_BSP_DISABLE_DOWNLOAD
++ /*
++ * read system register REG_SC_GEN2
++ * check if ziju flag
++ */
++ ldr x0, =SYS_CTRL_REG_BASE
++ ldr w1, [x0, #REG_SC_GEN2]
++ ldr w2, =0x7a696a75 /* magic for "ziju" */
++ cmp w1, w2
++ bne normal_start_flow
++ mov x1, sp /* save sp */
++ str w1, [x0, #REG_SC_GEN2] /* clear ziju flag */
++
++ziju_flow:
++ ldr x2, =(STACK_TRAINING)
++ bic sp, x2, #0xf /* 16-byte alignment for ABI compliance */
++ ldr x0, _blank_zone_start
++ ldr x1, _TEXT_BASE
++ sub x0, x0, x1
++ adr x1, _start
++ add x0, x0, x1
++ mov x1, #0x0 /* flags: 0->normal 1->pm */
++ bl init_registers /* init PLL/DDRC/... */
++ bl start_ddr_training /* DDR training */
++
++ ldr x0, =SYS_CTRL_REG_BASE
++ ldr w1, [x0, #REG_SC_GEN2]
++ mov sp, x1 /* restore sp */
++ ldr w1, [x0, #REG_SC_GEN3]
++ mov x30, x1
++ ret /* return to bootrom */
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ b . /* bug here */
++
++
++normal_start_flow:
++#endif
++ /* set stack for C code */
++ ldr x0, =(CONFIG_SYS_INIT_SP_ADDR)
++ bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
++
++ bl uart_early_init
++ adr x0, Str_SystemSartup
++ bl uart_early_puts
++
++running_addr_check:
++ adr x0,running_addr_check
++ lsr x0, x0, #28
++ cmp x0, #4
++ bge not_ddr_init
++
++ /* read init table and config registers */
++ ldr x0, _blank_zone_start
++ ldr x1, _TEXT_BASE
++ sub x0, x0, x1
++ adr x1, _start
++ add x0, x0, x1
++ mov x1, #0 /* flags: 0->normal 1->pm */
++ bl init_registers
++ bl start_ddr_training
++check_boot_mode:
++ ldr x0, =SYS_CTRL_REG_BASE
++ ldr w0, [x0, #REG_SYSSTAT]
++ lsr w6, w0, #2
++ and w6, w6, #0x3
++ cmp w6, #BOOT_FROM_EMMC
++ bne not_ddr_init
++
++#ifdef CONFIG_SDHCI
++emmc_boot:
++ ldr x0, _TEXT_BASE
++ ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */
++ ldr x2, =__bss_start /* x2 <- SRC &__bss_start */
++ sub x1, x2, x1
++ bl emmc_boot_read
++ b no_copy
++#endif
++
++not_ddr_init:
++master_cpu:
++relocate:
++ adr x0, _start /*runing addr start*/
++ ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */
++ cmp x0, x1
++ b.eq no_copy /* skip relocation */
++ ldr x2, =__bss_start /* x2 <- SRC &__bss_start*/
++
++copy_loop:
++ ldp x10, x11, [x0], #16 /* copy from source address [x0] */
++ stp x10, x11, [x1], #16 /* copy to target address [x1] */
++ cmp x1, x2 /* until source end address [x2] */
++ b.lo copy_loop
++no_copy:
++clear_remap:
++ ldr x1, =SYS_CTRL_REG_BASE
++ ldr w0, [x1]
++ mov w2, #0x5
++ bic w0, w0, #0xf
++ orr w0, w0, w2
++ str w0, [x1]
++set_scs_finish:
++ ldr x1, =REG_SCS_CTRL
++ ldr w0, [x1]
++ mov w2, #0x5
++ bic w0, w0, #0xf
++ orr w0, w0, w2
++ str w0, [x1]
++jump_to_ddr:
++ adr x0, _start_armboot
++ ldr x30,[x0]
++ ret
++.align 3
++_start_armboot: .quad start_armboot
++
++/*-----------------------------------------------------------------------*/
++
++/*
++ * Exception vectors.
++ */
++ .align 3
++ .globl vectors
++vectors:
++ .align 3
++ b _do_bad_sync /* Current EL Synchronous Thread */
++
++ .align 3
++ b _do_bad_irq /* Current EL IRQ Thread */
++
++ .align 3
++ b _do_bad_fiq /* Current EL FIQ Thread */
++
++ .align 3
++ b _do_bad_error /* Current EL Error Thread */
++
++ .align 3
++ b _do_sync /* Current EL Synchronous Handler */
++
++ .align 3
++ b _do_irq /* Current EL IRQ Handler */
++
++ .align 3
++ b _do_fiq /* Current EL FIQ Handler */
++
++ .align 3
++ b _do_error /* Current EL Error Handler */
++
++
++_do_bad_sync:
++ exception_entry
++ bl do_bad_sync
++ b exception_exit
++
++_do_bad_irq:
++ exception_entry
++ bl do_bad_irq
++ b exception_exit
++
++_do_bad_fiq:
++ exception_entry
++ bl do_bad_fiq
++ b exception_exit
++
++_do_bad_error:
++ exception_entry
++ bl do_bad_error
++ b exception_exit
++
++_do_sync:
++ exception_entry
++ bl do_sync
++ b exception_exit
++
++_do_irq:
++ exception_entry
++ bl do_irq
++ b exception_exit
++
++_do_fiq:
++ exception_entry
++ bl do_fiq
++ b exception_exit
++
++_do_error:
++ exception_entry
++ bl do_error
++ b exception_exit
++
++exception_exit:
++ ldp x2, x0, [sp],#16
++ switch_el x11, 3f, 2f, 1f
++3: msr elr_el3, x2
++ b 0f
++2: msr elr_el2, x2
++ b 0f
++1: msr elr_el1, x2
++0:
++ ldp x1, x2, [sp],#16
++ ldp x3, x4, [sp],#16
++ ldp x5, x6, [sp],#16
++ ldp x7, x8, [sp],#16
++ ldp x9, x10, [sp],#16
++ ldp x11, x12, [sp],#16
++ ldp x13, x14, [sp],#16
++ ldp x15, x16, [sp],#16
++ ldp x17, x18, [sp],#16
++ ldp x19, x20, [sp],#16
++ ldp x21, x22, [sp],#16
++ ldp x23, x24, [sp],#16
++ ldp x25, x26, [sp],#16
++ ldp x27, x28, [sp],#16
++ ldp x29, x30, [sp],#16
++ eret
++
++/*
++ * void __asm_invalidate_icache_all(void)
++ *
++ * invalidate all tlb entries.
++ */
++ENTRY(__asm_invalidate_icache_all)
++ ic ialluis
++ isb sy
++ ret
++ENDPROC(__asm_invalidate_icache_all)
++
++.align 3
++Str_SystemSartup:
++.ascii "\r\n\r\nSystem startup\r\n\0"
+diff --git a/arch/arm/cpu/armv8/ss928v100/uart.S b/arch/arm/cpu/armv8/ss928v100/uart.S
+new file mode 100644
+index 0000000..e2d4b82
+--- /dev/null
++++ b/arch/arm/cpu/armv8/ss928v100/uart.S
+@@ -0,0 +1,116 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++
++#include
++
++//******************************************************************************
++//
++// void uart_early_init(void);
++//
++.text
++.align 4
++.global uart_early_init
++.type uart_early_init, %function
++uart_early_init:
++#ifndef CONFIG_BSP_DISABLE_CONSOLE
++ ldr x4, io_base_addr_L0
++ ldr w3, =0x1101
++ str w3, [x4, #0X124]
++ ldr w3, =0x1011
++ str w3, [x4, #0X128]
++
++ ldr x4, uart_base_addr_L0
++ mov w3, #0
++ /* Disable UART */
++ str w3, [x4, #48]
++ /* Set baud rate to 115200, uart clock:24M */
++ add w3, w3, #13
++ str w3, [x4, #36]
++ mov w3, #1
++ str w3, [x4, #40]
++ /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled. */
++ ldr w3, =112
++ str w3, [x4, #44]
++ /* Enable UART */
++ ldr w3, =769
++ str w3, [x4, #48]
++#endif
++ ret
++.align 4
++uart_base_addr_L0:
++ .quad CONFIG_CUR_UART_BASE
++io_base_addr_L0:
++ .quad 0x102f0000
++
++//******************************************************************************
++//
++// void uart_early_puts(const char *ss);
++//
++.align 4
++.global uart_early_puts
++.type uart_early_puts, %function
++uart_early_puts:
++#ifndef CONFIG_BSP_DISABLE_CONSOLE
++#if !defined(CONFIG_SUPPORT_CA_RELEASE)
++ ldr x2, uart_base_addr_L1
++ b next_char
++output:
++ ldr w4, [x2, #24]
++ tst w4, #32
++ bne output
++ str w3, [x2, #0]
++ add x0, x0, #1
++next_char:
++ ldrb w3, [x0]
++ cmp w3, #0
++ bne output
++#endif /* CONFIG_SUPPORT_CA_RELEASE */
++#endif /* CONFIG_BSP_DISABLE_CONSOLE */
++ ret
++.align 4
++uart_base_addr_L1:
++ .quad CONFIG_CUR_UART_BASE
++
++//******************************************************************************
++//
++// void uart_early_putc(int chr);
++//
++// call example:
++// mov w0, #'A'
++// bl uart_early_putc
++//
++.align 4
++.global uart_early_putc
++.type uart_early_putc, %function
++uart_early_putc:
++#ifndef CONFIG_BSP_DISABLE_CONSOLE
++#if !defined(CONFIG_SUPPORT_CA_RELEASE)
++ ldr x2, uart_base_addr_L3
++wait3:
++ ldr w4, [x2, #24]
++ tst w4, #32
++ bne wait3
++ str w0, [x2, #0]
++
++#endif /* CONFIG_SUPPORT_CA_RELEASE */
++#endif /* CONFIG_BSP_DISABLE_CONSOLE */
++ ret
++.align 4
++uart_base_addr_L3:
++ .quad CONFIG_CUR_UART_BASE
+diff --git a/arch/arm/include/asm/arch-ss927v100/mmu.h b/arch/arm/include/asm/arch-ss927v100/mmu.h
+new file mode 100644
+index 0000000..54debdf
+--- /dev/null
++++ b/arch/arm/include/asm/arch-ss927v100/mmu.h
+@@ -0,0 +1,214 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#ifndef __ARM_ARCH_MMU_H
++#define __ARM_ARCH_MMU_H
++
++#include
++#ifdef CONFIG_ARCH_MMU
++/*
++ * Translation Table Base Bit Masks
++ */
++#define ARM_TRANSLATION_TABLE_MASK 0xFFFFC000
++
++/*
++ * Domain Access Control Bit Masks
++ */
++#define arm_access_type_no_access(domain_num) (0x0 << (domain_num)*2)
++#define arm_access_type_client(domain_num) (0x1 << (domain_num)*2)
++#define arm_access_type_manager(domain_num) (0x3 << (domain_num)*2)
++
++
++#define ARM_MMU_FIRST_LEVEL_FAULT_ID 0x0
++
++struct arm_mmu_first_level_fault {
++ unsigned int id: 2;
++ unsigned int sbz: 30;
++};
++
++#define ARM_MMU_FIRST_LEVEL_PAGE_TABLE_ID 0x1
++
++struct arm_mmu_first_level_page_table {
++ unsigned int id: 2;
++ unsigned int sbz0: 1;
++ unsigned int ns: 1;
++ unsigned int sbz1: 1;
++ unsigned int domain: 4;
++ unsigned int imp: 1;
++ unsigned int base_address: 22;
++};
++
++#define ARM_MMU_FIRST_LEVEL_SECTION_ID 0x2
++
++struct arm_mmu_first_level_section {
++ unsigned int id: 2;
++ unsigned int b: 1;
++ unsigned int c: 1;
++ unsigned int xn: 1;
++ unsigned int domain: 4;
++ unsigned int imp: 1;
++ unsigned int ap0: 2;
++ unsigned int tex: 3;
++ unsigned int ap1: 1;
++ unsigned int s: 1;
++ unsigned int ng: 1;
++ unsigned int reserved: 1;
++ unsigned int ns: 1;
++ unsigned int base_address: 12;
++};
++
++struct arm_mmu_first_level_reserved {
++ unsigned int id: 2;
++ unsigned int sbz: 30;
++};
++
++#define ARM_MMU_SECOND_LEVEL_FAULT_ID 0x0
++
++struct arm_mmu_second_level_fault {
++ unsigned int id: 2;
++ unsigned int sbz: 30;
++};
++
++#define ARM_MMU_SECOND_LEVEL_SMALL_ID 0x2
++
++struct arm_mmu_second_level_small {
++ unsigned int id: 2;
++ unsigned int b: 1;
++ unsigned int c: 1;
++ unsigned int ap0: 2;
++ unsigned int tex: 3;
++ unsigned int ap1: 1;
++ unsigned int s: 1;
++ unsigned int ng: 1;
++ unsigned int base_address: 20;
++};
++
++#define ARM_MMU_FIRST_LEVEL_RESERVED_ID 0x3
++
++#define arm_mmu_first_level_descriptor_address(ttb_base, table_index) \
++ (unsigned long *)((unsigned long)(ttb_base) + ((table_index) << 2))
++
++#define ARM_FIRST_LEVEL_PAGE_TABLE_SIZE 0x4000
++
++union arm_mmu_first_level_descriptor {
++ unsigned long word;
++ struct arm_mmu_first_level_fault fault;
++ struct arm_mmu_first_level_page_table page_table;
++ struct arm_mmu_first_level_section section;
++ struct arm_mmu_first_level_reserved reserved;
++};
++
++union arm_mmu_second_level_descriptor {
++ unsigned long word;
++ struct arm_mmu_second_level_fault fault;
++ struct arm_mmu_second_level_small small;
++};
++
++static inline void arm_mmu_section(int ttb_base, int actual_base,
++ int virtual_base, unsigned int tex, unsigned int cacheable,
++ unsigned int bufferable, unsigned int perm,
++ unsigned int shareable)
++{
++ register union arm_mmu_first_level_descriptor desc;
++
++ desc.word = 0;
++ desc.section.id = ARM_MMU_FIRST_LEVEL_SECTION_ID;
++ desc.section.c = cacheable;
++ desc.section.b = bufferable;
++ desc.section.xn = 0;
++ desc.section.domain = 0;
++ desc.section.ap0 = perm;
++ desc.section.tex = tex;
++ desc.section.ap1 = 0;
++ desc.section.s = shareable;
++ desc.section.base_address = actual_base;
++ *arm_mmu_first_level_descriptor_address(ttb_base, (virtual_base))
++ = desc.word;
++}
++
++static inline void x_arm_mmu_section(int abase, int vbase, int size,
++ unsigned int tex, unsigned int cache, unsigned int buff,
++ unsigned int access, unsigned int shareable)
++{
++ int i;
++ int j = abase;
++ int k = vbase;
++ unsigned long ttb_base = CONFIG_TTB_ADDR;
++
++ for (i = size; i > 0 ; i--, j++, k++)
++ arm_mmu_section(ttb_base, j, k, tex, cache,
++ buff, access, shareable);
++}
++
++#define ARM_UNCACHEABLE 0
++#define ARM_CACHEABLE 1
++#define ARM_UNBUFFERABLE 0
++#define ARM_BUFFERABLE 1
++
++#define ARM_ACCESS_PERM_NONE_NONE 0
++#define ARM_ACCESS_PERM_RW_NONE 1
++#define ARM_ACCESS_PERM_RW_RO 2
++#define ARM_ACCESS_PERM_RW_RW 3
++
++#define ARM_NOSHAREABLE 0
++#define ARM_SHAREABLE 1
++
++#define ARM_MEMTYPE_STRONGORDER 0
++#define ARM_MEMTYPE_DEVICE 1
++#define ARM_MEMTYPE_NORMAL 2
++#define ARM_MEMTYPE_RESERVED 3
++
++
++#define ARM_CACHETYPE_NOCACHE 0
++#define ARM_CACHETYPE_WRITEBACK 1
++#define ARM_CACHETYPE_WRITETHROUGH 2
++#define ARM_CACHETYPE_WRITEBACK_ONLY 3
++
++
++/*
++ * Initialization for the Domain Access Control Register
++ */
++#define ARM_ACCESS_DACR_DEFAULT ( \
++ arm_access_type_manager(0) | \
++ arm_access_type_no_access(1) | \
++ arm_access_type_no_access(2) | \
++ arm_access_type_no_access(3) | \
++ arm_access_type_no_access(4) | \
++ arm_access_type_no_access(5) | \
++ arm_access_type_no_access(6) | \
++ arm_access_type_no_access(7) | \
++ arm_access_type_no_access(8) | \
++ arm_access_type_no_access(9) | \
++ arm_access_type_no_access(10) | \
++ arm_access_type_no_access(11) | \
++ arm_access_type_no_access(12) | \
++ arm_access_type_no_access(13) | \
++ arm_access_type_no_access(14) | \
++ arm_access_type_no_access(15))
++
++#endif
++#endif
+diff --git a/arch/arm/include/asm/arch-ss927v100/platform.h b/arch/arm/include/asm/arch-ss927v100/platform.h
+new file mode 100644
+index 0000000..aa0dad1
+--- /dev/null
++++ b/arch/arm/include/asm/arch-ss927v100/platform.h
+@@ -0,0 +1,447 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#ifndef __CHIP_REGS_H__
++#define __CHIP_REGS_H__
++
++/* -------------------------------------------------------------------- */
++/* Communication Register and flag used by bootrom */
++/* -------------------------------------------------------------------- */
++#define REG_START_FLAG (SYS_CTRL_REG_BASE + REG_SC_GEN1)
++#define START_MAGIC (0x444f574e)
++#define SELF_BOOT_TYPE_USBDEV 0x2
++#define CP_STEP1_ADDR 0x04010a00
++#define PCIE_SLAVE_BOOT_CTL_REG 0x0134
++#define DDR_INIT_DOWNLOAD_OK_FLAG 0xDCDFF001 /* step1:Ddrinit Code Download Finished Flag: DCDFF001 */
++#define DDR_INIT_EXCUTE_OK_FLAG 0xDCEFF002 /* step2:Ddrinit Code Excute Finished Flag: DCEFF002 */
++#define UBOOT_DOWNLOAD_OK_FLAG 0xBCDFF003 /* step3:Boot Code Download Finished Flag: BCDFF003 */
++
++/* -------------------------------------------------------------------- */
++/* System Control */
++/* -------------------------------------------------------------------- */
++#define SYS_CTRL_REG_BASE 0x11020000
++#define REG_BASE_SCTL SYS_CTRL_REG_BASE
++#define REG_SC_CTRL 0x0000
++#define REG_SC_SYSRES 0x0004
++#define REG_PERISTAT 0x0030
++#define REG_SYSSTAT 0x0018
++#define REG_DATA_CHANNEL_TYPE 0x31c
++#define EMMC_BOOT_8BIT (0x1 << 11)
++#define REG_PERI_EMMC_STAT 0x0404
++#define mmc_boot_clk_sel(val) ((val) & 0x3)
++#define MMC_BOOT_CLK_50M 0x2
++#define EMMC_NORMAL_MODE (0x1 << 3)
++#define get_spi_nor_addr_mode(_reg) (((_reg) >> 11) & 0x1)
++#define get_spi_device_type(_reg) (((_reg) >> 2) & 0x1)
++#define get_sys_boot_mode(_reg) (((_reg) >> 2) & 0x3)
++#define BOOT_FROM_SPI 0
++#define BOOT_FROM_SPI_NAND 1
++#define BOOT_FROM_NAND 2
++#define BOOT_FROM_EMMC 3
++
++#define SEC_UBOOT_DATA_ADDR 0x41000000
++#define OTP_USER_LOCKABLE14 0x10122090
++#define get_sec_boot_mode(x) ((((x) & 0xf) == 0x5) ? 0 : 1)
++
++#define REG_SC_GEN1 0x013c
++#define REG_SC_GEN2 0x0140
++#define REG_SC_GEN3 0x0144
++#define REG_SC_GEN4 0x0148
++#define REG_SC_GEN9 0x0154
++#define REG_SC_GEN20 0x0090
++
++/* -------------------------------------------------------------------- */
++/* CPU SUBSYS */
++/* -------------------------------------------------------------------- */
++#define REG_CRG_CLUSTER0_CLK_RST 0x0190 /* CPU SUBSYS clock and reset control*/
++#define CLUSTER0_GLB_SRST_REQ (0x1 << 17)
++
++#define REG_PERI_CPU_RVBARADDR_SOC 0x12030020
++
++#define REG_CRG_CLUSTER1_CLK_RST 0x0194
++#define CLUSTER1_GLB_SRST_REQ (0x1 << 9)
++#define CLUSTER1_GLB_CKEN (0x1 << 8)
++
++/* -------------------------------------------------------------------- */
++/* CRG */
++/* -------------------------------------------------------------------- */
++#define CRG_REG_BASE 0x11010000
++
++/* -------------------------------------------------------------------- */
++/* Peripheral Control REG */
++/* -------------------------------------------------------------------- */
++#define MISC_REG_BASE 0x11024000
++
++/* -------------------------------------------------------------------- */
++/* IO configuration REG:mux and driver */
++/* -------------------------------------------------------------------- */
++#define AHB_IO_CONFIG_REG_BASE 0x11180000
++
++/* -------------------------------------------------------------------- */
++/* TIMER */
++/* -------------------------------------------------------------------- */
++#define TIMER0_REG_BASE 0x11000000
++#define REG_TIMER_RELOAD 0x0
++#define REG_TIMER_VALUE 0x4
++#define REG_TIMER_CONTROL 0x8
++#define CFG_TIMER_CLK (3000000)
++#define CFG_TIMERBASE TIMER0_REG_BASE
++/* enable timer.32bit, periodic,mask irq, 1 divider.*/
++#define CFG_TIMER_CTRL 0xC2
++
++/* -------------------------------------------------------------------- */
++/* UART */
++/* -------------------------------------------------------------------- */
++#define UART0_REG_BASE 0x11040000
++#define UART1_REG_BASE 0x11041000
++#define UART2_REG_BASE 0x11042000
++#define UART3_REG_BASE 0x11043000
++
++/* -------------------------------------------------------------------- */
++/* DDRC */
++/* -------------------------------------------------------------------- */
++#define STACK_TRAINING 0x0402a000
++#define DDRC0_REG_BASE 0x11140000
++#define DDR_MEM_BASE 0x40000000
++
++/* -------------------------------------------------------------------- */
++/* FMC */
++/* -------------------------------------------------------------------- */
++#define FMC_REG_BASE 0x10000000
++#define FMC_MEM_BASE 0x0f000000
++
++/* FMC CRG register offset */
++#define FMC_CLK_REG 0x3F40
++#define REG_FMC_CRG FMC_CLK_REG
++
++#define fmc_clk_sel(_clk) (((_clk) & 0x7) << 12)
++#define FMC_CLK_SEL_MASK (0x7 << 12)
++#define get_fmc_clk_type(_reg) (((_reg) >> 12) & 0x7)
++
++/* SDR/DDR clock */
++#define FMC_CLK_24M 0
++#define FMC_CLK_100M 1
++#define FMC_CLK_150M 2
++#define FMC_CLK_200M 3
++/* Only DDR clock */
++#define FMC_CLK_250M 4
++#define FMC_CLK_300M 5
++#define FMC_CLK_400M 6
++
++#define FMC_CLK_ENABLE BIT(4)
++#define FMC_SOFT_RST_REQ BIT(0)
++
++/*--------------------------------------------------------------------- */
++/* EMMC / SD */
++/* -------------------------------------------------------------------- */
++
++/* eMMC CRG register offset */
++#define REG_EMMC_CRG (CRG_REG_BASE + 0x34c0)
++#define mmc_clk_sel(_clk) (((_clk) & 0x7) << 24)
++#define MMC_CLK_SEL_MASK (0x7 << 24)
++#define REG_SAVE_HCS 0x11020300
++
++/* EMMC REG*/
++#define EMMC_BASE_REG 0x10020000
++#define NO_EMMC_PHY 1
++
++#define NF_BOOTBW_MASK (1 << 11)
++#define REG_BASE_PERI_CTRL REG_BASE_SCTL
++#define REG_BASE_IO_CONFIG IO_CONFIG_REG_BASE
++
++/* SDIO0 REG */
++#define REG_SDIO0_CRG (CRG_REG_BASE + 0x35c0)
++#define SDIO0_BASE_REG 0x10030000
++
++/*--------------------------------------------------------------------- */
++/* GMAC */
++/* -------------------------------------------------------------------- */
++#define GMAC0_IOBASE 0x10290000
++#define GMAC1_IOBASE 0x102A0000
++
++/* Ethernet MAC0 MAC_IF CRG register offset */
++#define REG_ETH0_MACIF_CRG 0x37c0
++/* Ethernet MAC0 MAC_If CRG register bit map*/
++#define BIT_MACIF0_RST BIT(0)
++#define BIT_GMACIF0_CLK_EN BIT(4)
++#define BIT_RMII0_CLKSEL_PAD BIT(12)
++
++/* Ethernet MAC0 GSF CRG register offset */
++#define REG_ETH0_GSF_CRG 0x37c4
++/* Ethernet MAC0 GSF CRG register bit map*/
++#define BIT_GMAC0_RST BIT(0)
++#define BIT_GMAC0_CLK_EN BIT(4)
++
++/* Ethernet MAC0 PHY CRG register offset */
++#define REG_ETH0_PHY_CRG 0x37cc
++/* Ethernet MAC0 PHY CRG register bit map*/
++#define BIT_EXT_PHY0_RST BIT(0)
++#define BIT_EXT_PHY0_CLK_SELECT BIT(12)
++
++
++/* Ethernet MAC1 MAC_IF CRG register offset */
++#define REG_ETH1_MACIF_CRG 0x3800
++/* Ethernet MAC1 MAC_If CRG register bit map*/
++#define BIT_MACIF1_RST BIT(0)
++#define BIT_GMACIF1_CLK_EN BIT(4)
++#define BIT_RMII1_CLKSEL_PAD BIT(12)
++
++/* Ethernet MAC1 GSF CRG register offset */
++#define REG_ETH1_GSF_CRG 0x3804
++/* Ethernet MAC1 GSF CRG register bit map*/
++#define BIT_GMAC1_RST BIT(0)
++#define BIT_GMAC1_CLK_EN BIT(4)
++
++/* Ethernet MAC1 PHY CRG register offset */
++#define REG_ETH1_PHY_CRG 0x380c
++/* Ethernet MAC1 PHY CRG register bit map*/
++#define BIT_EXT_PHY1_RST BIT(0)
++#define BIT_EXT_PHY1_CLK_SELECT BIT(12)
++
++#define PHY0_CLK_25M 0
++#define PHY0_CLK_50M BIT_EXT_PHY0_CLK_SELECT
++#define PHY1_CLK_25M 0
++#define PHY1_CLK_50M BIT_EXT_PHY1_CLK_SELECT
++
++#define GMAC_MACIF0_CTRL (GMAC0_IOBASE + 0x300c)
++#define GMAC_MACIF1_CTRL (GMAC1_IOBASE + 0x300c)
++#define GMAC_DUAL_MAC_CRF_ACK_TH (GMAC0_IOBASE + 0x3004)
++
++/* Configure gmac pinctrl parameters in software */
++#define CFG_NET_PINCTRL
++
++/* MDIO0 pinctrl phyical addr */
++#define PHY_ADDR_MDCK0 0x0102F0038
++#define PHY_ADDR_MDIO0 0x0102F003C
++/* MDIO1 pinctrl phyical addr */
++#define PHY_ADDR_MDCK1 0x0102F0068
++#define PHY_ADDR_MDIO1 0x0102F006C
++
++/* PHY0 pinctrl phyical addr */
++#define PHY_ADDR_EPHY0_CLK 0x0102F0030
++#define PHY_ADDR_EPHY0_RSTN 0x0102F0034
++/* PHY1 pinctrl phyical addr */
++#define PHY_ADDR_EPHY1_CLK 0x0102F005C
++#define PHY_ADDR_EPHY1_RSTN 0x0102F0064
++
++/* RGMII0 pinctrl phyical addr */
++#define PHY_ADDR_RGMII0_TXCKOUT 0x0102F002C
++#define PHY_ADDR_RGMII0_TXD0 0x0102F0024
++#define PHY_ADDR_RGMII0_TXD1 0x0102F0020
++#define PHY_ADDR_RGMII0_TXD2 0x0102F001C
++#define PHY_ADDR_RGMII0_TXD3 0x0102F0018
++#define PHY_ADDR_RGMII0_TXEN 0x0102F0028
++#define PHY_ADDR_RGMII0_RXCK 0x0102F0014
++#define PHY_ADDR_RGMII0_RXD0 0x0102F000C
++#define PHY_ADDR_RGMII0_RXD1 0x0102F0008
++#define PHY_ADDR_RGMII0_RXD2 0x0102F0004
++#define PHY_ADDR_RGMII0_RXD3 0x0102F0000
++#define PHY_ADDR_RGMII0_RXDV 0x0102F0010
++/* RGMII1 pinctrl phyical addr */
++#define PHY_ADDR_RGMII1_TXCKOUT 0x0102F0050
++#define PHY_ADDR_RGMII1_TXD0 0x0102F0040
++#define PHY_ADDR_RGMII1_TXD1 0x0102F0044
++#define PHY_ADDR_RGMII1_TXD2 0x0102F0054
++#define PHY_ADDR_RGMII1_TXD3 0x0102F004C
++#define PHY_ADDR_RGMII1_TXEN 0x0102F0058
++#define PHY_ADDR_RGMII1_RXCK 0x0102F0074
++#define PHY_ADDR_RGMII1_RXD0 0x0102F0070
++#define PHY_ADDR_RGMII1_RXD1 0x0102F0078
++#define PHY_ADDR_RGMII1_RXD2 0x0102F007C
++#define PHY_ADDR_RGMII1_RXD3 0x0102F0060
++#define PHY_ADDR_RGMII1_RXDV 0x0102F0048
++
++/* RMII0 pinctrl phyical addr */
++#define PHY_ADDR_RMII0_CLK 0x0102F002C
++#define PHY_ADDR_RMII0_TXD0 0x0102F0024
++#define PHY_ADDR_RMII0_TXD1 0x0102F0020
++#define PHY_ADDR_RMII0_TXEN 0x0102F0028
++#define PHY_ADDR_RMII0_RXD0 0x0102F000C
++#define PHY_ADDR_RMII0_RXD1 0x0102F0008
++#define PHY_ADDR_RMII0_RXDV 0x0102F0010
++
++/* RMII1 pinctrl phyical addr */
++#define PHY_ADDR_RMII1_CLK 0x0102F0050
++#define PHY_ADDR_RMII1_TXD0 0x0102F0040
++#define PHY_ADDR_RMII1_TXD1 0x0102F0044
++#define PHY_ADDR_RMII1_TXEN 0x0102F0058
++#define PHY_ADDR_RMII1_RXD0 0x0102F0070
++#define PHY_ADDR_RMII1_RXD1 0x0102F0078
++#define PHY_ADDR_RMII1_RXDV 0x0102F0048
++
++/* MDIO0 config value */
++#define VALUE_MDCK0 0x1231
++#define VALUE_MDIO0 0x1221
++/* MDIO1 config value */
++#define VALUE_MDCK1 0x0032
++#define VALUE_MDIO1 0x0032
++
++/* PHY0 config value */
++#define VALUE_EPHY0_CLK 0x1261
++#define VALUE_EPHY0_RSTN 0x1201
++/* PHY1 config value */
++#define VALUE_EPHY1_CLK 0x0062
++#define VALUE_EPHY1_RSTN 0x00F2
++
++/* RGMII0 config value */
++#define VALUE_RGMII0_TXCKOUT 0x1261
++#define VALUE_RGMII0_TXD0 0x1251
++#define VALUE_RGMII0_TXD1 0x1251
++#define VALUE_RGMII0_TXD2 0x1251
++#define VALUE_RGMII0_TXD3 0x1261
++#define VALUE_RGMII0_TXEN 0x1251
++#define VALUE_RGMII0_RXCK 0x1271
++#define VALUE_RGMII0_RXD0 0x1271
++#define VALUE_RGMII0_RXD1 0x1271
++#define VALUE_RGMII0_RXD2 0x1271
++#define VALUE_RGMII0_RXD3 0x1271
++#define VALUE_RGMII0_RXDV 0x1271
++/* RGMII1 config value */
++#define VALUE_RGMII1_TXCKOUT 0x00A2
++#define VALUE_RGMII1_TXD0 0x0062
++#define VALUE_RGMII1_TXD1 0x0062
++#define VALUE_RGMII1_TXD2 0x0062
++#define VALUE_RGMII1_TXD3 0x0062
++#define VALUE_RGMII1_TXEN 0x0062
++#define VALUE_RGMII1_RXCK 0x0072
++#define VALUE_RGMII1_RXD0 0x0072
++#define VALUE_RGMII1_RXD1 0x0072
++#define VALUE_RGMII1_RXD2 0x0072
++#define VALUE_RGMII1_RXD3 0x0072
++#define VALUE_RGMII1_RXDV 0x0072
++
++/* RMII0 config value */
++#define VALUE_RMII0_CLK 0x1262
++#define VALUE_RMII0_TXD0 0x1251
++#define VALUE_RMII0_TXD1 0x1251
++#define VALUE_RMII0_TXEN 0x1251
++#define VALUE_RMII0_RXD0 0x1271
++#define VALUE_RMII0_RXD1 0x1271
++#define VALUE_RMII0_RXDV 0x1271
++/* RMII1 config value */
++#define VALUE_RMII1_CLK 0x1063
++#define VALUE_RMII1_TXD0 0x1242
++#define VALUE_RMII1_TXD1 0x1242
++#define VALUE_RMII1_TXEN 0x1242
++#define VALUE_RMII1_RXD0 0x12F2
++#define VALUE_RMII1_RXD1 0x12F2
++#define VALUE_RMII1_RXDV 0x12F2
++
++/* -------------------------------------------------------------------- */
++/* USB */
++/* -------------------------------------------------------------------- */
++#define USB3_CTRL_REG_BASE 0x10320000
++#define USB3_CTRL_REG_BASE_1 0x10300000
++
++/* USB CRG register offset and config */
++#define USB3_CTRL_CRG (CRG_REG_BASE + 0x3960)
++#define USB3_CTRL_CRG_1 (CRG_REG_BASE + 0x3940)
++#define USB2_PHY_CRG (CRG_REG_BASE + 0x38e0)
++#define USB2_PHY_CRG_1 (CRG_REG_BASE + 0x38c0)
++#define USB3_PHY_CRG (CRG_REG_BASE + 0x3964)
++#define USB3_PHY_CRG_1 (CRG_REG_BASE + 0x3944)
++
++#define USB3_CTRL_CRG_DEFAULT_VALUE 0x30001
++#define USB2_PHY_CRG_DEFAULT_VALUE 0x57
++#define USB3_PHY_CRG_DEFAULT_VALUE 0x13
++
++#define USB3_CRG_PCLK_OCC_SEL (0x1 << 18)
++#define USB3_CRG_PIPE_CKEN (0x1 << 12)
++#define USB3_CRG_UTMI_CKEN (0x1 << 8)
++#define USB3_CRG_SUSPEND_CKEN (0x1 << 6)
++#define USB3_CRG_REF_CKEN (0x1 << 5)
++#define USB3_CRG_BUS_CKEN (0x1 << 4)
++#define USB3_CRG_SRST_REQ (0x1 << 0)
++
++#define USB2_PHY_CRG_APB_SREQ (0x1 << 2)
++#define USB2_PHY_CRG_TREQ (0x1 << 1)
++#define USB2_PHY_CRG_REQ (0x1 << 0)
++
++#define USB3_PHY_CRG_TREQ (0x1 << 1)
++#define USB3_PHY_CRG_REQ (0x1 << 0)
++
++#define COMBPHY_REF_CKEN (0x1<<24)
++#define COMBPHY_SRST_REQ (0x1<<16)
++
++#define USB3_VCC_SRST_REQ (0x1<<0)
++#define USB3_UTMI_CKSEL (0x1<<13)
++#define USB3_PCLK_OCC_SEL (0x1<<14)
++
++/* USB CTRL register offset and config */
++#define GTXTHRCFG 0xc108
++#define GRXTHRCFG 0xc10c
++#define REG_GCTL 0xc110
++
++#define USB_TXPKT_CNT_SEL (0x1 << 29)
++#define USB_TXPKT_CNT (0x11 << 24)
++#define USB_MAXTX_BURST_SIZE (0x1 << 20)
++#define CLEAN_USB3_GTXTHRCFG 0x0
++
++#define REG_GUSB3PIPECTL0 0xc2c0
++#define PCS_SSP_SOFT_RESET (0x1 << 31)
++#define SUSPEND_ENABLE (0x1 <<17)
++
++#define PORT_CAP_DIR_MASK (0x3 << 12)
++#define PORT_CAP_DIR_HOST (0X1 << 12)
++
++/* USB PHY register EYE diagram para offset and config */
++#define USB2_PHY_BASE 0x10330000
++#define USB2_PHY_BASE_1 0x10310000
++
++/* -------------------------------------------------------------------- */
++/* PCIE */
++/* -------------------------------------------------------------------- */
++#define SYS_SATA 0x8c
++#define PCIE_MODE 12
++
++#define PERI_CRG98 0x188
++#define PHY0_SRS_REQ 0
++#define PHY0_SRS_REQ_SEL 1
++#define PHY1_SRS_REQ 16
++#define PHY1_SRS_REQ_SEL 17
++
++#define MISC_CTRL5 0x14
++#define NUM_0 0
++#define NUM_1 1
++#define NUM_2 2
++#define NUM_3 3
++#define NUM_4 4
++#define NUM_5 5
++#define NUM_6 6
++#define NUM_7 7
++#define NUM_8 8
++#define NUM_9 9
++#define NUM_10 10
++
++/*-----------------------------------------------------------------------------------
++ * boot sel type
++ *-----------------------------------------------------------------------------------*/
++#define BOOT_SEL_PCIE 0x965a4b87
++#define BOOT_SEL_UART 0x69a5b478
++#define BOOT_SEL_USB 0x965ab487
++#define BOOT_SEL_SDIO 0x69a54b87
++#define BOOT_SEL_FLASH 0x96a54b78
++#define BOOT_SEL_EMMC 0x695ab487
++#define BOOT_SEL_UNKNOW 0x965a4b78
++
++/* -------------------------------------------------------------------- */
++/* GZIP */
++/* -------------------------------------------------------------------- */
++#define HW_DEC_INTR 97
++#endif /* End of __CHIP_REGS_H__ */
+diff --git a/arch/arm/include/asm/arch-ss928v100/mmu.h b/arch/arm/include/asm/arch-ss928v100/mmu.h
+new file mode 100644
+index 0000000..54debdf
+--- /dev/null
++++ b/arch/arm/include/asm/arch-ss928v100/mmu.h
+@@ -0,0 +1,214 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#ifndef __ARM_ARCH_MMU_H
++#define __ARM_ARCH_MMU_H
++
++#include
++#ifdef CONFIG_ARCH_MMU
++/*
++ * Translation Table Base Bit Masks
++ */
++#define ARM_TRANSLATION_TABLE_MASK 0xFFFFC000
++
++/*
++ * Domain Access Control Bit Masks
++ */
++#define arm_access_type_no_access(domain_num) (0x0 << (domain_num)*2)
++#define arm_access_type_client(domain_num) (0x1 << (domain_num)*2)
++#define arm_access_type_manager(domain_num) (0x3 << (domain_num)*2)
++
++
++#define ARM_MMU_FIRST_LEVEL_FAULT_ID 0x0
++
++struct arm_mmu_first_level_fault {
++ unsigned int id: 2;
++ unsigned int sbz: 30;
++};
++
++#define ARM_MMU_FIRST_LEVEL_PAGE_TABLE_ID 0x1
++
++struct arm_mmu_first_level_page_table {
++ unsigned int id: 2;
++ unsigned int sbz0: 1;
++ unsigned int ns: 1;
++ unsigned int sbz1: 1;
++ unsigned int domain: 4;
++ unsigned int imp: 1;
++ unsigned int base_address: 22;
++};
++
++#define ARM_MMU_FIRST_LEVEL_SECTION_ID 0x2
++
++struct arm_mmu_first_level_section {
++ unsigned int id: 2;
++ unsigned int b: 1;
++ unsigned int c: 1;
++ unsigned int xn: 1;
++ unsigned int domain: 4;
++ unsigned int imp: 1;
++ unsigned int ap0: 2;
++ unsigned int tex: 3;
++ unsigned int ap1: 1;
++ unsigned int s: 1;
++ unsigned int ng: 1;
++ unsigned int reserved: 1;
++ unsigned int ns: 1;
++ unsigned int base_address: 12;
++};
++
++struct arm_mmu_first_level_reserved {
++ unsigned int id: 2;
++ unsigned int sbz: 30;
++};
++
++#define ARM_MMU_SECOND_LEVEL_FAULT_ID 0x0
++
++struct arm_mmu_second_level_fault {
++ unsigned int id: 2;
++ unsigned int sbz: 30;
++};
++
++#define ARM_MMU_SECOND_LEVEL_SMALL_ID 0x2
++
++struct arm_mmu_second_level_small {
++ unsigned int id: 2;
++ unsigned int b: 1;
++ unsigned int c: 1;
++ unsigned int ap0: 2;
++ unsigned int tex: 3;
++ unsigned int ap1: 1;
++ unsigned int s: 1;
++ unsigned int ng: 1;
++ unsigned int base_address: 20;
++};
++
++#define ARM_MMU_FIRST_LEVEL_RESERVED_ID 0x3
++
++#define arm_mmu_first_level_descriptor_address(ttb_base, table_index) \
++ (unsigned long *)((unsigned long)(ttb_base) + ((table_index) << 2))
++
++#define ARM_FIRST_LEVEL_PAGE_TABLE_SIZE 0x4000
++
++union arm_mmu_first_level_descriptor {
++ unsigned long word;
++ struct arm_mmu_first_level_fault fault;
++ struct arm_mmu_first_level_page_table page_table;
++ struct arm_mmu_first_level_section section;
++ struct arm_mmu_first_level_reserved reserved;
++};
++
++union arm_mmu_second_level_descriptor {
++ unsigned long word;
++ struct arm_mmu_second_level_fault fault;
++ struct arm_mmu_second_level_small small;
++};
++
++static inline void arm_mmu_section(int ttb_base, int actual_base,
++ int virtual_base, unsigned int tex, unsigned int cacheable,
++ unsigned int bufferable, unsigned int perm,
++ unsigned int shareable)
++{
++ register union arm_mmu_first_level_descriptor desc;
++
++ desc.word = 0;
++ desc.section.id = ARM_MMU_FIRST_LEVEL_SECTION_ID;
++ desc.section.c = cacheable;
++ desc.section.b = bufferable;
++ desc.section.xn = 0;
++ desc.section.domain = 0;
++ desc.section.ap0 = perm;
++ desc.section.tex = tex;
++ desc.section.ap1 = 0;
++ desc.section.s = shareable;
++ desc.section.base_address = actual_base;
++ *arm_mmu_first_level_descriptor_address(ttb_base, (virtual_base))
++ = desc.word;
++}
++
++static inline void x_arm_mmu_section(int abase, int vbase, int size,
++ unsigned int tex, unsigned int cache, unsigned int buff,
++ unsigned int access, unsigned int shareable)
++{
++ int i;
++ int j = abase;
++ int k = vbase;
++ unsigned long ttb_base = CONFIG_TTB_ADDR;
++
++ for (i = size; i > 0 ; i--, j++, k++)
++ arm_mmu_section(ttb_base, j, k, tex, cache,
++ buff, access, shareable);
++}
++
++#define ARM_UNCACHEABLE 0
++#define ARM_CACHEABLE 1
++#define ARM_UNBUFFERABLE 0
++#define ARM_BUFFERABLE 1
++
++#define ARM_ACCESS_PERM_NONE_NONE 0
++#define ARM_ACCESS_PERM_RW_NONE 1
++#define ARM_ACCESS_PERM_RW_RO 2
++#define ARM_ACCESS_PERM_RW_RW 3
++
++#define ARM_NOSHAREABLE 0
++#define ARM_SHAREABLE 1
++
++#define ARM_MEMTYPE_STRONGORDER 0
++#define ARM_MEMTYPE_DEVICE 1
++#define ARM_MEMTYPE_NORMAL 2
++#define ARM_MEMTYPE_RESERVED 3
++
++
++#define ARM_CACHETYPE_NOCACHE 0
++#define ARM_CACHETYPE_WRITEBACK 1
++#define ARM_CACHETYPE_WRITETHROUGH 2
++#define ARM_CACHETYPE_WRITEBACK_ONLY 3
++
++
++/*
++ * Initialization for the Domain Access Control Register
++ */
++#define ARM_ACCESS_DACR_DEFAULT ( \
++ arm_access_type_manager(0) | \
++ arm_access_type_no_access(1) | \
++ arm_access_type_no_access(2) | \
++ arm_access_type_no_access(3) | \
++ arm_access_type_no_access(4) | \
++ arm_access_type_no_access(5) | \
++ arm_access_type_no_access(6) | \
++ arm_access_type_no_access(7) | \
++ arm_access_type_no_access(8) | \
++ arm_access_type_no_access(9) | \
++ arm_access_type_no_access(10) | \
++ arm_access_type_no_access(11) | \
++ arm_access_type_no_access(12) | \
++ arm_access_type_no_access(13) | \
++ arm_access_type_no_access(14) | \
++ arm_access_type_no_access(15))
++
++#endif
++#endif
+diff --git a/arch/arm/include/asm/arch-ss928v100/platform.h b/arch/arm/include/asm/arch-ss928v100/platform.h
+new file mode 100644
+index 0000000..1a49022
+--- /dev/null
++++ b/arch/arm/include/asm/arch-ss928v100/platform.h
+@@ -0,0 +1,452 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#ifndef __CHIP_REGS_H__
++#define __CHIP_REGS_H__
++
++/* -------------------------------------------------------------------- */
++/* Communication Register and flag used by bootrom */
++/* -------------------------------------------------------------------- */
++#define REG_START_FLAG (SYS_CTRL_REG_BASE + REG_SC_GEN1)
++#define START_MAGIC (0x444f574e)
++#define SELF_BOOT_TYPE_USBDEV 0x2
++#define CP_STEP1_ADDR 0x04010a00
++#define PCIE_SLAVE_BOOT_CTL_REG 0x0134
++#define DDR_INIT_DOWNLOAD_OK_FLAG 0xDCDFF001 /* step1:Ddrinit Code Download Finished Flag: DCDFF001 */
++#define DDR_INIT_EXCUTE_OK_FLAG 0xDCEFF002 /* step2:Ddrinit Code Excute Finished Flag: DCEFF002 */
++#define UBOOT_DOWNLOAD_OK_FLAG 0xBCDFF003 /* step3:Boot Code Download Finished Flag: BCDFF003 */
++
++/* -------------------------------------------------------------------- */
++/* System Control */
++/* -------------------------------------------------------------------- */
++#define SYS_CTRL_REG_BASE 0x11020000
++#define REG_BASE_SCTL SYS_CTRL_REG_BASE
++#define REG_SC_CTRL 0x0000
++#define REG_SC_SYSRES 0x0004
++#define REG_PERISTAT 0x0030
++#define REG_SYSSTAT 0x0018
++#define REG_DATA_CHANNEL_TYPE 0x31c
++#define EMMC_BOOT_8BIT (0x1 << 11)
++#define REG_PERI_EMMC_STAT 0x0404
++#define mmc_boot_clk_sel(val) ((val) & 0x3)
++#define MMC_BOOT_CLK_50M 0x2
++#define EMMC_NORMAL_MODE (0x1 << 3)
++#define get_spi_nor_addr_mode(_reg) (((_reg) >> 11) & 0x1)
++#define get_spi_device_type(_reg) (((_reg) >> 2) & 0x1)
++#define get_sys_boot_mode(_reg) (((_reg) >> 2) & 0x3)
++#define BOOT_FROM_SPI 0
++#define BOOT_FROM_SPI_NAND 1
++#define BOOT_FROM_NAND 2
++#define BOOT_FROM_EMMC 3
++
++#define SEC_UBOOT_DATA_ADDR 0x41000000
++#define OTP_USER_LOCKABLE14 0x10122090
++#define get_sec_boot_mode(x) ((((x) & 0xf) == 0x5) ? 0 : 1)
++
++#define REG_SC_GEN1 0x013c
++#define REG_SC_GEN2 0x0140
++#define REG_SC_GEN3 0x0144
++#define REG_SC_GEN4 0x0148
++#define REG_SC_GEN9 0x0154
++#define REG_SC_GEN20 0x0090
++
++/* -------------------------------------------------------------------- */
++/* CPU SUBSYS */
++/* -------------------------------------------------------------------- */
++#define REG_CRG_CLUSTER0_CLK_RST 0x0190 /* CPU SUBSYS clock and reset control*/
++#define CLUSTER0_GLB_SRST_REQ (0x1 << 17)
++
++#define REG_PERI_CPU_RVBARADDR_SOC 0x12030020
++
++#define REG_CRG_CLUSTER1_CLK_RST 0x0194
++#define CLUSTER1_GLB_SRST_REQ (0x1 << 9)
++#define CLUSTER1_GLB_CKEN (0x1 << 8)
++
++/* -------------------------------------------------------------------- */
++/* CRG */
++/* -------------------------------------------------------------------- */
++#define CRG_REG_BASE 0x11010000
++
++/* -------------------------------------------------------------------- */
++/* Peripheral Control REG */
++/* -------------------------------------------------------------------- */
++#define MISC_REG_BASE 0x11024000
++
++/* -------------------------------------------------------------------- */
++/* IO configuration REG:mux and driver */
++/* -------------------------------------------------------------------- */
++#define AHB_IO_CONFIG_REG_BASE 0x11180000
++
++/* -------------------------------------------------------------------- */
++/* TIMER */
++/* -------------------------------------------------------------------- */
++#define TIMER0_REG_BASE 0x11000000
++#define REG_TIMER_RELOAD 0x0
++#define REG_TIMER_VALUE 0x4
++#define REG_TIMER_CONTROL 0x8
++#define CFG_TIMER_CLK (3000000)
++#define CFG_TIMERBASE TIMER0_REG_BASE
++/* enable timer.32bit, periodic,mask irq, 1 divider.*/
++#define CFG_TIMER_CTRL 0xC2
++
++/* -------------------------------------------------------------------- */
++/* UART */
++/* -------------------------------------------------------------------- */
++#define UART0_REG_BASE 0x11040000
++#define UART1_REG_BASE 0x11041000
++#define UART2_REG_BASE 0x11042000
++#define UART3_REG_BASE 0x11043000
++
++/* -------------------------------------------------------------------- */
++/* DDRC */
++/* -------------------------------------------------------------------- */
++#define STACK_TRAINING 0x0402a000
++#define DDRC0_REG_BASE 0x11140000
++#define DDR_MEM_BASE 0x40000000
++
++/* -------------------------------------------------------------------- */
++/* FMC */
++/* -------------------------------------------------------------------- */
++#define FMC_REG_BASE 0x10000000
++#define FMC_MEM_BASE 0x0f000000
++
++/* FMC CRG register offset */
++#define FMC_CLK_REG 0x3F40
++#define REG_FMC_CRG FMC_CLK_REG
++
++#define fmc_clk_sel(_clk) (((_clk) & 0x7) << 12)
++#define FMC_CLK_SEL_MASK (0x7 << 12)
++#define get_fmc_clk_type(_reg) (((_reg) >> 12) & 0x7)
++
++/* SDR/DDR clock */
++#define FMC_CLK_24M 0
++#define FMC_CLK_100M 1
++#define FMC_CLK_150M 2
++#define FMC_CLK_200M 3
++/* Only DDR clock */
++#define FMC_CLK_250M 4
++#define FMC_CLK_300M 5
++#define FMC_CLK_400M 6
++
++#define FMC_CLK_ENABLE BIT(4)
++#define FMC_SOFT_RST_REQ BIT(0)
++
++/*--------------------------------------------------------------------- */
++/* EMMC / SD */
++/* -------------------------------------------------------------------- */
++
++/* eMMC CRG register offset */
++#define REG_EMMC_CRG (CRG_REG_BASE + 0x34c0)
++#define mmc_clk_sel(_clk) (((_clk) & 0x7) << 24)
++#define MMC_CLK_SEL_MASK (0x7 << 24)
++#define REG_SAVE_HCS 0x11020300
++
++/* EMMC REG*/
++#define EMMC_BASE_REG 0x10020000
++#define NO_EMMC_PHY 1
++
++#define NF_BOOTBW_MASK (1 << 11)
++#define REG_BASE_PERI_CTRL REG_BASE_SCTL
++#define REG_BASE_IO_CONFIG IO_CONFIG_REG_BASE
++
++/* SDIO0 REG */
++#define REG_SDIO0_CRG (CRG_REG_BASE + 0x35c0)
++#define SDIO0_BASE_REG 0x10030000
++
++/*--------------------------------------------------------------------- */
++/* GMAC */
++/* -------------------------------------------------------------------- */
++#define GMAC0_IOBASE 0x10290000
++#define GMAC1_IOBASE 0x102A0000
++
++/* Ethernet MAC0 MAC_IF CRG register offset */
++#define REG_ETH0_MACIF_CRG 0x37c0
++/* Ethernet MAC0 MAC_If CRG register bit map*/
++#define BIT_MACIF0_RST BIT(0)
++#define BIT_GMACIF0_CLK_EN BIT(4)
++#define BIT_RMII0_CLKSEL_PAD BIT(12)
++
++/* Ethernet MAC0 GSF CRG register offset */
++#define REG_ETH0_GSF_CRG 0x37c4
++/* Ethernet MAC0 GSF CRG register bit map*/
++#define BIT_GMAC0_RST BIT(0)
++#define BIT_GMAC0_CLK_EN BIT(4)
++
++/* Ethernet MAC0 PHY CRG register offset */
++#define REG_ETH0_PHY_CRG 0x37cc
++/* Ethernet MAC0 PHY CRG register bit map*/
++#define BIT_EXT_PHY0_RST BIT(0)
++#define BIT_EXT_PHY0_CLK_SELECT BIT(12)
++
++
++/* Ethernet MAC1 MAC_IF CRG register offset */
++#define REG_ETH1_MACIF_CRG 0x3800
++/* Ethernet MAC1 MAC_If CRG register bit map*/
++#define BIT_MACIF1_RST BIT(0)
++#define BIT_GMACIF1_CLK_EN BIT(4)
++#define BIT_RMII1_CLKSEL_PAD BIT(12)
++
++/* Ethernet MAC1 GSF CRG register offset */
++#define REG_ETH1_GSF_CRG 0x3804
++/* Ethernet MAC1 GSF CRG register bit map*/
++#define BIT_GMAC1_RST BIT(0)
++#define BIT_GMAC1_CLK_EN BIT(4)
++
++/* Ethernet MAC1 PHY CRG register offset */
++#define REG_ETH1_PHY_CRG 0x380c
++/* Ethernet MAC1 PHY CRG register bit map*/
++#define BIT_EXT_PHY1_RST BIT(0)
++#define BIT_EXT_PHY1_CLK_SELECT BIT(12)
++
++#define PHY0_CLK_25M 0
++#define PHY0_CLK_50M BIT_EXT_PHY0_CLK_SELECT
++#define PHY1_CLK_25M 0
++#define PHY1_CLK_50M BIT_EXT_PHY1_CLK_SELECT
++
++#define GMAC_MACIF0_CTRL (GMAC0_IOBASE + 0x300c)
++#define GMAC_MACIF1_CTRL (GMAC1_IOBASE + 0x300c)
++#define GMAC_DUAL_MAC_CRF_ACK_TH (GMAC0_IOBASE + 0x3004)
++
++/* Configure gmac pinctrl parameters in software */
++#define CFG_NET_PINCTRL
++
++/* MDIO0 pinctrl phyical addr */
++#define PHY_ADDR_MDCK0 0x0102F0038
++#define PHY_ADDR_MDIO0 0x0102F003C
++/* MDIO1 pinctrl phyical addr */
++#define PHY_ADDR_MDCK1 0x0102F0068
++#define PHY_ADDR_MDIO1 0x0102F006C
++
++/* PHY0 pinctrl phyical addr */
++#define PHY_ADDR_EPHY0_CLK 0x0102F0030
++#define PHY_ADDR_EPHY0_RSTN 0x0102F0034
++/* PHY1 pinctrl phyical addr */
++#define PHY_ADDR_EPHY1_CLK 0x0102F005C
++#define PHY_ADDR_EPHY1_RSTN 0x0102F0064
++
++/* RGMII0 pinctrl phyical addr */
++#define PHY_ADDR_RGMII0_TXCKOUT 0x0102F002C
++#define PHY_ADDR_RGMII0_TXD0 0x0102F0024
++#define PHY_ADDR_RGMII0_TXD1 0x0102F0020
++#define PHY_ADDR_RGMII0_TXD2 0x0102F001C
++#define PHY_ADDR_RGMII0_TXD3 0x0102F0018
++#define PHY_ADDR_RGMII0_TXEN 0x0102F0028
++#define PHY_ADDR_RGMII0_RXCK 0x0102F0014
++#define PHY_ADDR_RGMII0_RXD0 0x0102F000C
++#define PHY_ADDR_RGMII0_RXD1 0x0102F0008
++#define PHY_ADDR_RGMII0_RXD2 0x0102F0004
++#define PHY_ADDR_RGMII0_RXD3 0x0102F0000
++#define PHY_ADDR_RGMII0_RXDV 0x0102F0010
++/* RGMII1 pinctrl phyical addr */
++#define PHY_ADDR_RGMII1_TXCKOUT 0x0102F0050
++#define PHY_ADDR_RGMII1_TXD0 0x0102F0040
++#define PHY_ADDR_RGMII1_TXD1 0x0102F0044
++#define PHY_ADDR_RGMII1_TXD2 0x0102F0054
++#define PHY_ADDR_RGMII1_TXD3 0x0102F004C
++#define PHY_ADDR_RGMII1_TXEN 0x0102F0058
++#define PHY_ADDR_RGMII1_RXCK 0x0102F0074
++#define PHY_ADDR_RGMII1_RXD0 0x0102F0070
++#define PHY_ADDR_RGMII1_RXD1 0x0102F0078
++#define PHY_ADDR_RGMII1_RXD2 0x0102F007C
++#define PHY_ADDR_RGMII1_RXD3 0x0102F0060
++#define PHY_ADDR_RGMII1_RXDV 0x0102F0048
++
++/* RMII0 pinctrl phyical addr */
++#define PHY_ADDR_RMII0_CLK 0x0102F002C
++#define PHY_ADDR_RMII0_TXD0 0x0102F0024
++#define PHY_ADDR_RMII0_TXD1 0x0102F0020
++#define PHY_ADDR_RMII0_TXEN 0x0102F0028
++#define PHY_ADDR_RMII0_RXD0 0x0102F000C
++#define PHY_ADDR_RMII0_RXD1 0x0102F0008
++#define PHY_ADDR_RMII0_RXDV 0x0102F0010
++
++/* RMII1 pinctrl phyical addr */
++#define PHY_ADDR_RMII1_CLK 0x0102F0050
++#define PHY_ADDR_RMII1_TXD0 0x0102F0040
++#define PHY_ADDR_RMII1_TXD1 0x0102F0044
++#define PHY_ADDR_RMII1_TXEN 0x0102F0058
++#define PHY_ADDR_RMII1_RXD0 0x0102F0070
++#define PHY_ADDR_RMII1_RXD1 0x0102F0078
++#define PHY_ADDR_RMII1_RXDV 0x0102F0048
++
++/* MDIO0 config value */
++#define VALUE_MDCK0 0x1231
++#define VALUE_MDIO0 0x1221
++/* MDIO1 config value */
++#define VALUE_MDCK1 0x0032
++#define VALUE_MDIO1 0x0032
++
++/* PHY0 config value */
++#define VALUE_EPHY0_CLK 0x1261
++#define VALUE_EPHY0_RSTN 0x1201
++/* PHY1 config value */
++#define VALUE_EPHY1_CLK 0x0062
++#define VALUE_EPHY1_RSTN 0x00F2
++
++/* RGMII0 config value */
++#define VALUE_RGMII0_TXCKOUT 0x1261
++#define VALUE_RGMII0_TXD0 0x1251
++#define VALUE_RGMII0_TXD1 0x1251
++#define VALUE_RGMII0_TXD2 0x1251
++#define VALUE_RGMII0_TXD3 0x1261
++#define VALUE_RGMII0_TXEN 0x1251
++#define VALUE_RGMII0_RXCK 0x1271
++#define VALUE_RGMII0_RXD0 0x1271
++#define VALUE_RGMII0_RXD1 0x1271
++#define VALUE_RGMII0_RXD2 0x1271
++#define VALUE_RGMII0_RXD3 0x1271
++#define VALUE_RGMII0_RXDV 0x1271
++/* RGMII1 config value */
++#define VALUE_RGMII1_TXCKOUT 0x00A2
++#define VALUE_RGMII1_TXD0 0x0062
++#define VALUE_RGMII1_TXD1 0x0062
++#define VALUE_RGMII1_TXD2 0x0062
++#define VALUE_RGMII1_TXD3 0x0062
++#define VALUE_RGMII1_TXEN 0x0062
++#define VALUE_RGMII1_RXCK 0x0072
++#define VALUE_RGMII1_RXD0 0x0072
++#define VALUE_RGMII1_RXD1 0x0072
++#define VALUE_RGMII1_RXD2 0x0072
++#define VALUE_RGMII1_RXD3 0x0072
++#define VALUE_RGMII1_RXDV 0x0072
++
++/* RMII0 config value */
++#define VALUE_RMII0_CLK 0x1262
++#define VALUE_RMII0_TXD0 0x1251
++#define VALUE_RMII0_TXD1 0x1251
++#define VALUE_RMII0_TXEN 0x1251
++#define VALUE_RMII0_RXD0 0x1271
++#define VALUE_RMII0_RXD1 0x1271
++#define VALUE_RMII0_RXDV 0x1271
++/* RMII1 config value */
++#define VALUE_RMII1_CLK 0x1063
++#define VALUE_RMII1_TXD0 0x1242
++#define VALUE_RMII1_TXD1 0x1242
++#define VALUE_RMII1_TXEN 0x1242
++#define VALUE_RMII1_RXD0 0x12F2
++#define VALUE_RMII1_RXD1 0x12F2
++#define VALUE_RMII1_RXDV 0x12F2
++
++/* -------------------------------------------------------------------- */
++/* USB */
++/* -------------------------------------------------------------------- */
++#define USB3_CTRL_REG_BASE 0x10320000
++#define USB3_CTRL_REG_BASE_1 0x10300000
++
++#define MISC_USB3_CTRL_REG 0x10220024
++#define MISC_USB3_CTRL_REG_1 0x1022003c
++#define USB3_DISABLE_U3_SPEED (0x1 << 9)
++#define USB3_DISABLE_U3_SPEED_1 (0x1 << 12)
++
++/* USB CRG register offset and config */
++#define USB3_CTRL_CRG (CRG_REG_BASE + 0x3960)
++#define USB3_CTRL_CRG_1 (CRG_REG_BASE + 0x3940)
++#define USB2_PHY_CRG (CRG_REG_BASE + 0x38e0)
++#define USB2_PHY_CRG_1 (CRG_REG_BASE + 0x38c0)
++#define USB3_PHY_CRG (CRG_REG_BASE + 0x3964)
++#define USB3_PHY_CRG_1 (CRG_REG_BASE + 0x3944)
++
++#define USB3_CTRL_CRG_DEFAULT_VALUE 0x30001
++#define USB2_PHY_CRG_DEFAULT_VALUE 0x57
++#define USB3_PHY_CRG_DEFAULT_VALUE 0x13
++
++#define USB3_CRG_PCLK_OCC_SEL (0x1 << 18)
++#define USB3_CRG_PIPE_CKEN (0x1 << 12)
++#define USB3_CRG_UTMI_CKEN (0x1 << 8)
++#define USB3_CRG_SUSPEND_CKEN (0x1 << 6)
++#define USB3_CRG_REF_CKEN (0x1 << 5)
++#define USB3_CRG_BUS_CKEN (0x1 << 4)
++#define USB3_CRG_SRST_REQ (0x1 << 0)
++
++#define USB2_PHY_CRG_APB_SREQ (0x1 << 2)
++#define USB2_PHY_CRG_TREQ (0x1 << 1)
++#define USB2_PHY_CRG_REQ (0x1 << 0)
++
++#define USB3_PHY_CRG_TREQ (0x1 << 1)
++#define USB3_PHY_CRG_REQ (0x1 << 0)
++
++#define COMBPHY_REF_CKEN (0x1<<24)
++#define COMBPHY_SRST_REQ (0x1<<16)
++
++#define USB3_VCC_SRST_REQ (0x1<<0)
++#define USB3_UTMI_CKSEL (0x1<<13)
++#define USB3_PCLK_OCC_SEL (0x1<<14)
++
++/* USB CTRL register offset and config */
++#define GTXTHRCFG 0xc108
++#define GRXTHRCFG 0xc10c
++#define REG_GCTL 0xc110
++
++#define USB_TXPKT_CNT_SEL (0x1 << 29)
++#define USB_TXPKT_CNT (0x11 << 24)
++#define USB_MAXTX_BURST_SIZE (0x1 << 20)
++#define CLEAN_USB3_GTXTHRCFG 0x0
++
++#define REG_GUSB3PIPECTL0 0xc2c0
++#define PCS_SSP_SOFT_RESET (0x1 << 31)
++#define SUSPEND_ENABLE (0x1 <<17)
++
++#define PORT_CAP_DIR_MASK (0x3 << 12)
++#define PORT_CAP_DIR_HOST (0X1 << 12)
++
++/* USB PHY register EYE diagram para offset and config */
++#define USB2_PHY_BASE 0x10330000
++#define USB2_PHY_BASE_1 0x10310000
++
++/* -------------------------------------------------------------------- */
++/* PCIE */
++/* -------------------------------------------------------------------- */
++#define SYS_SATA 0x8c
++#define PCIE_MODE 12
++
++#define PERI_CRG98 0x188
++#define PHY0_SRS_REQ 0
++#define PHY0_SRS_REQ_SEL 1
++#define PHY1_SRS_REQ 16
++#define PHY1_SRS_REQ_SEL 17
++
++#define MISC_CTRL5 0x14
++#define NUM_0 0
++#define NUM_1 1
++#define NUM_2 2
++#define NUM_3 3
++#define NUM_4 4
++#define NUM_5 5
++#define NUM_6 6
++#define NUM_7 7
++#define NUM_8 8
++#define NUM_9 9
++#define NUM_10 10
++
++/*-----------------------------------------------------------------------------------
++ * boot sel type
++ *-----------------------------------------------------------------------------------*/
++#define BOOT_SEL_PCIE 0x965a4b87
++#define BOOT_SEL_UART 0x69a5b478
++#define BOOT_SEL_USB 0x965ab487
++#define BOOT_SEL_SDIO 0x69a54b87
++#define BOOT_SEL_FLASH 0x96a54b78
++#define BOOT_SEL_EMMC 0x695ab487
++#define BOOT_SEL_UNKNOW 0x965a4b78
++
++/* -------------------------------------------------------------------- */
++/* GZIP */
++/* -------------------------------------------------------------------- */
++#define HW_DEC_INTR 97
++#endif /* End of __CHIP_REGS_H__ */
+diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h
+old mode 100644
+new mode 100755
+index bf692ce..d192ba8
+--- a/arch/arm/include/asm/config.h
++++ b/arch/arm/include/asm/config.h
+@@ -5,6 +5,7 @@
+
+ #ifndef _ASM_CONFIG_H_
+ #define _ASM_CONFIG_H_
++#include
+
+ #define CONFIG_LMB
+ #define CONFIG_SYS_BOOT_RAMDISK_HIGH
+diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
+index 1774014..ba47c64 100644
+--- a/arch/arm/include/asm/global_data.h
++++ b/arch/arm/include/asm/global_data.h
+@@ -71,6 +71,9 @@ struct arch_global_data {
+ u32 omap_boot_mode;
+ u8 omap_ch_flags;
+ #endif
++#ifdef CONFIG_VENDOR
++ u32 boot_media;
++#endif
+ #if defined(CONFIG_FSL_LSCH3) && defined(CONFIG_SYS_FSL_HAS_DP_DDR)
+ unsigned long mem2_clk;
+ #endif
+diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
+index 32532b3..f4918db 100644
+--- a/arch/arm/include/asm/mach-types.h
++++ b/arch/arm/include/asm/mach-types.h
+@@ -5051,4 +5051,6 @@
+ #define MACH_TYPE_NASM25 5112
+ #define MACH_TYPE_TOMATO 5113
+ #define MACH_TYPE_OMAP3_MRC3D 5114
++#define MACH_TYPE_SS928V100 8000
++
+ #endif
+diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
+index bb33b4b..a58ba2b 100644
+--- a/arch/arm/include/asm/macro.h
++++ b/arch/arm/include/asm/macro.h
+@@ -62,7 +62,8 @@
+ /*
+ * Register aliases.
+ */
+-lr .req x30
++/*fix warning:gcc 6.3.0 not support*/
++/* lr .req x30 */
+
+ /*
+ * Branch according to exception level
+diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
+index 9de9a9a..929adfd 100644
+--- a/arch/arm/lib/Makefile
++++ b/arch/arm/lib/Makefile
+@@ -60,6 +60,8 @@ ifndef CONFIG_SYSRESET
+ obj-y += reset.o
+ endif
+
++obj-y += process.o
++
+ obj-y += cache.o
+ obj-$(CONFIG_SYS_ARM_CACHE_CP15) += cache-cp15.o
+
+diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
+old mode 100644
+new mode 100755
+index 75b70d9..24a485a
+--- a/arch/arm/lib/interrupts.c
++++ b/arch/arm/lib/interrupts.c
+@@ -51,6 +51,7 @@ void bad_mode (void)
+ reset_cpu (0);
+ }
+
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ static void show_efi_loaded_images(struct pt_regs *regs)
+ {
+ efi_print_image_infos((void *)instruction_pointer(regs));
+@@ -79,9 +80,11 @@ static void dump_instr(struct pt_regs *regs)
+ }
+ printf("\n");
+ }
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+
+ void show_regs (struct pt_regs *regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ unsigned long __maybe_unused flags;
+ const char __maybe_unused *processor_modes[] = {
+ "USER_26", "FIQ_26", "IRQ_26", "SVC_26",
+@@ -121,81 +124,98 @@ void show_regs (struct pt_regs *regs)
+ processor_modes[processor_mode (regs)],
+ thumb_mode (regs) ? " (T)" : "");
+ dump_instr(regs);
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ /* fixup PC to point to the instruction leading to the exception */
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ static inline void fixup_pc(struct pt_regs *regs, int offset)
+ {
+ uint32_t pc = instruction_pointer(regs) + offset;
+ regs->ARM_pc = pc | (regs->ARM_pc & PCMASK);
+ }
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+
+ void do_undefined_instruction (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("undefined instruction\n");
+ fixup_pc(pt_regs, -4);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ void do_software_interrupt (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("software interrupt\n");
+ fixup_pc(pt_regs, -4);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ void do_prefetch_abort (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("prefetch abort\n");
+ fixup_pc(pt_regs, -8);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ void do_data_abort (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("data abort\n");
+ fixup_pc(pt_regs, -8);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ void do_not_used (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("not used\n");
+ fixup_pc(pt_regs, -8);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ void do_fiq (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("fast interrupt request\n");
+ fixup_pc(pt_regs, -8);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+
+ void do_irq (struct pt_regs *pt_regs)
+ {
++#ifndef CONFIG_DISABLE_INTERRUPTS
+ efi_restore_gd();
+ printf ("interrupt request\n");
+ fixup_pc(pt_regs, -8);
+ show_regs (pt_regs);
+ show_efi_loaded_images(pt_regs);
+ bad_mode ();
++#endif /* CONFIG_DISABLE_INTERRUPTS */
+ }
+diff --git a/arch/arm/lib/process.c b/arch/arm/lib/process.c
+new file mode 100644
+index 0000000..f41fbaf
+--- /dev/null
++++ b/arch/arm/lib/process.c
+@@ -0,0 +1,45 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++
++#define CFG_MAX_SHUTDOWN 10
++
++static struct shutdown_ctrl {
++ int count;
++ void (*shutdown[CFG_MAX_SHUTDOWN])(void);
++} shutdown_ctrl = {0, {0}, };
++
++void add_shutdown(void (*shutdown)(void))
++{
++ if (shutdown_ctrl.count >= CFG_MAX_SHUTDOWN) {
++ printf("Can't add shutdown function,"
++ "Please increase CFG_MAX_SHUTDOWN count\n");
++ return;
++ }
++ shutdown_ctrl.shutdown[shutdown_ctrl.count++]
++ = shutdown;
++}
++
++void do_shutdown(void)
++{
++ int ix;
++ for (ix = 0; ix < shutdown_ctrl.count; ix++)
++ shutdown_ctrl.shutdown[ix]();
++}
+diff --git a/arch/arm/lib/relocate.S b/arch/arm/lib/relocate.S
+index e5f7267..2827d77 100644
+--- a/arch/arm/lib/relocate.S
++++ b/arch/arm/lib/relocate.S
+@@ -94,6 +94,8 @@ copy_loop:
+ */
+ ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
+ ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
++ cmp r2, r3
++ beq relocate_done
+ fixloop:
+ ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
+ and r1, r1, #0xff
+diff --git a/arch/arm/lib/reset.c b/arch/arm/lib/reset.c
+index 3c4512d..ee4ecff 100644
+--- a/arch/arm/lib/reset.c
++++ b/arch/arm/lib/reset.c
+@@ -33,6 +33,8 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+
+ udelay (50000); /* wait 50 ms */
+
++ do_shutdown();
++
+ disable_interrupts();
+
+ reset_misc();
+diff --git a/arch/arm/mach-vendor/Kconfig b/arch/arm/mach-vendor/Kconfig
+new file mode 100644
+index 0000000..0f82a80
+--- /dev/null
++++ b/arch/arm/mach-vendor/Kconfig
+@@ -0,0 +1,43 @@
++if ARCH_VENDOR
++
++config VENDOR_COMMON
++ bool "VENDOR common options"
++ select DM
++
++config SYS_VENDOR
++ default "vendor"
++
++endif
++
++config DISABLE_INTERRUPTS
++ bool "disable interrupts"
++ default n
++
++config LOW_DELAY_INITIALIZATION
++ bool "low delay initialization"
++ default n
++
++config INIT_TIMER_EARLY
++ bool "init timer early"
++ default n
++
++config CMD_TIMESTAMP
++ bool "timestamp - record timestamp"
++ default n
++ help
++ Enable the 'timestamp' command which record timestamp in DDR since
++ Chip started running.
++
++config CMD_TIMESTAMP_TEST
++ bool "timestamp_unit_test - record timestamp"
++ default n
++ depends on CMD_TIMESTAMP
++ help
++ Enable the 'timestamp_unit_test' command which record timestamp in DDR
++ since Chip started running.
++
++config TIME_ADDR_OFFSET
++ hex "record timestamp addr offset"
++ default 0xC800
++ help
++ record the timestamp addr,base addr is fdt, TIME_ADDR_OFFSET is offset
+diff --git a/arch/arm/mach-vendor/Makefile b/arch/arm/mach-vendor/Makefile
+new file mode 100644
+index 0000000..75c15fb
+--- /dev/null
++++ b/arch/arm/mach-vendor/Makefile
+@@ -0,0 +1,21 @@
++# Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License
++# as published by the Free Software Foundation; either version 2
++# of the License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, see
++# .
++#
++
++extra-$(CONFIG_VENDOR_COMMON) += init_regs.o uart.o soc.o util.o
++obj-y += dummy.o
++
++
+diff --git a/arch/arm/mach-vendor/boot0_hook.S b/arch/arm/mach-vendor/boot0_hook.S
+new file mode 100644
+index 0000000..e3c089f
+--- /dev/null
++++ b/arch/arm/mach-vendor/boot0_hook.S
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++
++VENDOR_BOOT0_HOOK
++
++ .globl _blank_zone_start
++_blank_zone_start: .word __blank_zone_start
++ENTRY(get_blank_start)
++ ldr r0, _blank_zone_start
++ ldr r1, =__image_copy_start
++ sub r0, r0, r1
++ adrl r1, _start
++ add r0, r0, r1
++ mov pc, lr
++ENDPROC(get_blank_start)
++
++ENTRY(get_code_start)
++ adrl r0, _start
++ mov pc, lr
++ENDPROC(get_code_start)
+diff --git a/arch/arm/mach-vendor/dummy.c b/arch/arm/mach-vendor/dummy.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/arch/arm/mach-vendor/init_regs.c b/arch/arm/mach-vendor/init_regs.c
+new file mode 100644
+index 0000000..2a4cad5
+--- /dev/null
++++ b/arch/arm/mach-vendor/init_regs.c
+@@ -0,0 +1,184 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++#include
++
++#define W_WHETHER_WRITE (1<<0)
++#define W_WHETHER_PM (1<<1)
++#define W_WHETHER_BOOT_NORMAL (1<<2)
++#define W_BIT_OFFSET 3
++#define W_BIT_MASK (0x1f<attr & R_REG_BIT_MASK) >> R_REG_BIT_OFFSET);
++ bit_num_r = ((reg->attr & R_BIT_MASK) >> R_BIT_OFFSET) + 1;
++ reg_val_r = (*(volatile unsigned *)(long)(reg->reg_addr));
++
++ if (bit_num_r != RW_BIT_NUM) {
++ reg_val_r >>= bit_start_r;
++ reg_val_r &= ((1 << bit_num_r) - 1);
++ }
++
++ *ret = ((reg_val_r == reg->value) ? 0 : 1);
++}
++
++static void reg_write(const struct regentry *reg)
++{
++ unsigned int reg_val_w;
++ unsigned int delay_2;
++ unsigned int bit_start_w;
++ unsigned int bit_num_w;
++
++ delay_2 = reg->delay;
++ bit_start_w = ((reg->attr & W_REG_BIT_MASK) >> W_REG_BIT_OFFSET);
++ bit_num_w = ((reg->attr & W_BIT_MASK) >> W_BIT_OFFSET) + 1;
++ reg_val_w = (*(volatile unsigned *)(long)(reg->reg_addr));
++
++ if (bit_num_w == RW_BIT_NUM) {
++ reg_val_w = reg->value;
++ } else {
++ reg_val_w &= (~(((1 << bit_num_w) - 1) << bit_start_w));
++ reg_val_w |= (reg->value) << bit_start_w;
++ }
++ writel(reg_val_w, reg->reg_addr);
++
++ do {
++ delay();
++ } while (delay_2--);
++}
++
++static void read_write(const struct regentry *reg, unsigned int pm)
++{
++ unsigned int ret;
++ unsigned int delay_1;
++
++ ret = 0;
++ delay_1 = reg->delay;
++
++ if (pm) {
++ if (reg->attr & W_WHETHER_PM) {
++ reg_write(reg);
++ } else if (reg->attr & R_WHETHER_PM) {
++ do {
++ reg_read(reg, &ret);
++ delay();
++ } while (ret);
++
++ do {
++ delay();
++ } while (delay_1--);
++ } else {
++ do {
++ delay();
++ } while (delay_1--);
++ }
++ } else {
++ if (reg->attr & W_WHETHER_BOOT_NORMAL) {
++ reg_write(reg);
++ } else if (reg->attr & R_WHETHER_BOOT_NORMAL) {
++ do {
++ reg_read(reg, &ret);
++ delay();
++ } while (ret);
++
++ do {
++ delay();
++ } while (delay_1--);
++ } else {
++ do {
++ delay();
++ } while (delay_1--);
++ }
++ }
++}
++
++static void part_read_write(const struct regentry *reg_table, unsigned int pm)
++{
++ unsigned int i;
++
++ for (i = 0; ; i++) {
++ if ((!reg_table[i].reg_addr) && (!reg_table[i].value) &&
++ (!reg_table[i].delay) && (!reg_table[i].attr))
++ goto main_end;
++
++ read_write(®_table[i], pm);
++ }
++
++main_end:
++ delay();
++}
++
++/*
++ * base - reg base address
++ * pm - is suspend
++ * 0 normal
++ * 1 pm
++ */
++void init_registers(unsigned long base, unsigned long pm)
++{
++ struct regentry *reg_table = (struct regentry *)(uintptr_t)base;
++
++ part_read_write(reg_table, pm);
++}
+diff --git a/arch/arm/mach-vendor/mci_boot.c b/arch/arm/mach-vendor/mci_boot.c
+new file mode 100644
+index 0000000..8f993e8
+--- /dev/null
++++ b/arch/arm/mach-vendor/mci_boot.c
+@@ -0,0 +1,131 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++#include "soc.h"
++#include
++
++#define DELAY_US 1000
++#define CP_STEP1_SIZE 0x6000
++
++static inline unsigned int mci_readl(unsigned addr)
++{
++ return *((volatile unsigned *)(uintptr_t)(addr));
++}
++
++static inline void mci_writel(unsigned val, unsigned addr)
++{
++ (*(volatile unsigned *)(uintptr_t)(addr)) = (val);
++}
++
++static inline void delay(unsigned int cnt)
++{
++ while (cnt--)
++ __asm__ __volatile__("nop");
++}
++
++static void emmc_deinit(void)
++{
++ unsigned int mmc_base = EMMC_REG_BASE;
++ unsigned int val;
++
++ val = mci_readl(mmc_base + MCI_CTRL);
++ val |= (CTRL_RESET | FIFO_RESET | DMA_RESET);
++ mci_writel(val, mmc_base + MCI_CTRL);
++
++ /* clear MMC host intr */
++ mci_writel(ALL_INT_CLR, mmc_base + MCI_RINTSTS);
++}
++
++static void emmc_boot_mode_read(void *ptr, unsigned int size)
++{
++ unsigned int count, val;
++ unsigned int tmp_reg;
++ unsigned int *buf = NULL;
++ unsigned int data;
++
++ if (size <= CP_STEP1_SIZE) {
++ memcpy_32(ptr, (void *)RAM_START_ADRS, size);
++ return;
++ }
++ memcpy_32(ptr, (void *)RAM_START_ADRS, CP_STEP1_SIZE);
++ buf = (unsigned int *)(ptr + CP_STEP1_SIZE);
++ size = (size - CP_STEP1_SIZE) >> NUM_2;
++
++ while (size > 0) {
++ tmp_reg = mci_readl(EMMC_REG_BASE + MCI_STATUS);
++ count = (tmp_reg >> FIFO_COUNT) & FIFO_COUNT_MASK;
++
++ if (count > size)
++ count = size;
++
++ /* start to read data */
++ while (1) {
++ val = (DCRC_INT_STATUS | FRUN_INT_STATUS | HLE_INT_STATUS |
++ SBE_INT_STATUS | EBE_INT_STATUS);
++ tmp_reg = mci_readl(EMMC_REG_BASE + MCI_RINTSTS);
++ if (tmp_reg & val)
++ return;
++
++ if (tmp_reg & RXDR_INT_STATUS)
++ break;
++ }
++
++ mci_writel(ALL_INT_CLR, EMMC_REG_BASE + MCI_RINTSTS);
++
++ for (; count != 0; --count) {
++ data = mci_readl(EMMC_REG_BASE + MCI_FIFO_START);
++
++ *buf = data;
++ buf++;
++ --size;
++ }
++ }
++
++ mci_writel(START_CMD | DISABLE_BOOT | STOP_ABORT_CMD, EMMC_REG_BASE + MCI_CMD);
++ count = 1000; /* 1000: Cycle */
++ do {
++ delay(DELAY_US);
++ count--;
++ tmp_reg = mci_readl(EMMC_REG_BASE + MCI_CMD);
++ } while ((tmp_reg & START_CMD) && count);
++
++ count = 1000; /* 1000: Cycle */
++ do {
++ delay(DELAY_US);
++ count--;
++ tmp_reg = mci_readl(EMMC_REG_BASE + MCI_RINTSTS);
++ } while (!(tmp_reg & DTO_INT_STATUS) && count);
++}
++
++static void emmc_boot_mode_deinit(void)
++{
++ unsigned int mmc_base = EMMC_REG_BASE;
++
++ mci_writel(START_CMD | DISABLE_BOOT | STOP_ABORT_CMD, mmc_base + MCI_CMD);
++}
++
++void emmc_boot_read(void *ptr, unsigned int size)
++{
++ emmc_boot_mode_read(ptr, size);
++ emmc_boot_mode_deinit();
++ emmc_deinit();
++}
+diff --git a/arch/arm/mach-vendor/soc.c b/arch/arm/mach-vendor/soc.c
+new file mode 100644
+index 0000000..b5640e6
+--- /dev/null
++++ b/arch/arm/mach-vendor/soc.c
+@@ -0,0 +1,63 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include "soc.h"
++#include
++#include
++#include
++#include
++#include
++
++void s_init(void)
++{
++ unsigned int blank_zone_start;
++
++ blank_zone_start = get_blank_start();
++ init_registers(blank_zone_start, 0);
++
++#ifdef CONFIG_DDR_TRAINING_V2
++ start_ddr_training(REG_BASE_SCTL);
++#endif
++}
++
++void load_image(void)
++{
++ unsigned int len = (unsigned int)&__bss_start -
++ (unsigned int)__image_copy_start;
++
++ switch (get_boot_media()) {
++#ifdef CONFIG_SUPPORT_EMMC_BOOT
++ case BOOT_MEDIA_EMMC:
++ emmc_boot_read(__image_copy_start, len);
++ break;
++#endif
++ case BOOT_MEDIA_NAND:
++ case BOOT_MEDIA_SPIFLASH:
++ memcpy_32((void *)__image_copy_start, (void *)FMC_MEM_BASE, len);
++ break;
++ default:
++ break;
++ }
++}
++
++void enable_syscounter(int hz)
++{
++ writel(hz, REG_BASE_SYSCNT + CNTFID0);
++ writel(1, REG_BASE_SYSCNT + CNTCR);
++}
+diff --git a/arch/arm/mach-vendor/soc.h b/arch/arm/mach-vendor/soc.h
+new file mode 100644
+index 0000000..144906e
+--- /dev/null
++++ b/arch/arm/mach-vendor/soc.h
+@@ -0,0 +1,33 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#ifndef __BSP_SOC_H__
++#define __BSP_SOC_H__
++
++extern unsigned int blank_zone_start;
++extern unsigned int get_blank_start(void);
++extern void init_registers(unsigned int base, unsigned int pm);
++extern void emmc_boot_read(void *ptr, unsigned int size);
++extern void memcpy_32(void *dst, void *src, unsigned int size);
++
++#ifdef CONFIG_DDR_TRAINING_V2
++ extern void start_ddr_training(unsigned int base);
++#endif /* CONFIG_DDR_TRAINING_V2 */
++
++#endif
+diff --git a/arch/arm/mach-vendor/uart.S b/arch/arm/mach-vendor/uart.S
+new file mode 100644
+index 0000000..8a9bc88
+--- /dev/null
++++ b/arch/arm/mach-vendor/uart.S
+@@ -0,0 +1,129 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++
++
++#include
++
++@******************************************************************************
++@
++@ void uart_early_init(void);
++@
++.text
++.align 2
++.global uart_early_init
++.type uart_early_init, %function
++uart_early_init:
++ ldr a4, uart_base_addr_L0
++ mov a3, #0
++ /* Disable UART */
++ str a3, [a4, #48]
++ /* Set baud rate to 115200, uart clock:24M */
++ add a3, a3, #13
++ str a3, [a4, #36]
++ mov a3, #1
++ str a3, [a4, #40]
++ /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled. */
++ ldr a3, =112
++ str a3, [a4, #44]
++ /* Enable UART */
++ ldr a3, =769
++ str a3, [a4, #48]
++ bx lr
++uart_base_addr_L0:
++ .word CONFIG_CUR_UART_BASE
++
++@******************************************************************************
++@
++@ void uart_early_puts(const char *ss);
++@
++.align 2
++.global uart_early_puts
++.type uart_early_puts, %function
++uart_early_puts:
++ ldr a2, uart_base_addr_L1
++ b next_char
++output:
++ ldr a4, [a2, #24]
++ tst a4, #32
++ bne output
++ str a3, [a2, #0]
++ add a1, a1, #1
++next_char:
++ ldrb a3, [a1]
++ cmp a3, #0
++ bne output
++ bx lr
++uart_base_addr_L1:
++ .word CONFIG_CUR_UART_BASE
++
++@******************************************************************************
++@
++@ void uart_early_put_hex(int hex);
++@
++@ call example:
++@ mov r0, sp
++@ bl uart_early_put_hex
++@
++.align 2
++.global uart_early_put_hex
++.type uart_early_put_hex, %function
++uart_early_put_hex:
++ ldr a2, uart_base_addr_L2
++ mov a3, #28
++wait2:
++ ldr a4, [a2, #24]
++ tst a4, #32
++ bne wait2
++
++ mov a4, #0xF
++ and a4, a4, a1, lsr a3
++ cmp a4, #9
++ addle a4, a4, #0x30 @ a4 = a4 + '0'
++ addgt a4, a4, #55 @ a4 = a4 - 10 + 'A'
++ str a4, [a2, #0]
++ cmp a3, #0
++ beq exit2
++ sub a3, a3, #4
++ b wait2
++exit2:
++ bx lr
++uart_base_addr_L2:
++ .word CONFIG_CUR_UART_BASE
++
++@******************************************************************************
++@
++@ void uart_early_putc(int chr);
++@
++@ call example:
++@ mov r0, #'A'
++@ bl uart_early_putc
++@
++.align 2
++.global uart_early_putc
++.type uart_early_putc, %function
++uart_early_putc:
++ ldr a2, uart_base_addr_L3
++wait3:
++ ldr a4, [a2, #24]
++ tst a4, #32
++ bne wait3
++ str a1, [a2, #0]
++ bx lr
++uart_base_addr_L3:
++ .word CONFIG_CUR_UART_BASE
+diff --git a/arch/arm/mach-vendor/util.S b/arch/arm/mach-vendor/util.S
+new file mode 100644
+index 0000000..1bc1daa
+--- /dev/null
++++ b/arch/arm/mach-vendor/util.S
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++
++ENTRY(memcpy_32)
++memcpy:
++ push {r3 - r10}
++ cmp r0, r1
++ beq copy_done
++ add r2, r0, r2
++memcpy_loop:
++ ldmia r1!, {r3 - r10}
++ stmia r0!, {r3 - r10}
++ cmp r0, r2
++ ble memcpy_loop
++copy_done:
++ pop {r3 - r10}
++ mov pc, lr
++ENDPROC(memcpy_32)
+diff --git a/board/vendor/ss927v100/Kconfig b/board/vendor/ss927v100/Kconfig
+new file mode 100644
+index 0000000..ca04827
+--- /dev/null
++++ b/board/vendor/ss927v100/Kconfig
+@@ -0,0 +1,15 @@
++if TARGET_SS927V100
++
++config SYS_BOARD
++ default "ss927v100"
++
++config SYS_VENDOR
++ default "vendor"
++
++config SYS_SOC
++ default "ss927v100"
++
++config SYS_CONFIG_NAME
++ default "ss927v100"
++
++endif
+diff --git a/board/vendor/ss927v100/Makefile b/board/vendor/ss927v100/Makefile
+new file mode 100644
+index 0000000..7b02198
+--- /dev/null
++++ b/board/vendor/ss927v100/Makefile
+@@ -0,0 +1,8 @@
++#
++# (C) Copyright 2000-2004
++# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
++#
++# SPDX-License-Identifier: GPL-2.0+
++#
++
++obj-y := ss927v100.o
+diff --git a/board/vendor/ss927v100/ss927v100.c b/board/vendor/ss927v100/ss927v100.c
+new file mode 100644
+index 0000000..e88f8b0
+--- /dev/null
++++ b/board/vendor/ss927v100/ss927v100.c
+@@ -0,0 +1,792 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++static struct mm_region ss928v100_mem_map[] = {
++ {
++ .virt = 0x0UL,
++ .phys = 0x0UL,
++ .size = 0x05000000UL,
++ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
++ PTE_BLOCK_NON_SHARE
++ },
++ {
++ .virt = 0x05000000UL,
++ .phys = 0x05000000UL,
++ .size = 0x40000000UL - 0x05000000UL,
++ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
++ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN
++ },
++ {
++ .virt = 0x40000000UL,
++ .phys = 0x40000000UL,
++ .size = 0x200000000UL, /* PHYS_SDRAM_1_SIZE */
++ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
++ PTE_BLOCK_INNER_SHARE
++ },
++ {
++ /* List terminator */
++ 0,
++ }
++};
++
++struct mm_region *mem_map = ss928v100_mem_map;
++static int boot_media = BOOT_MEDIA_UNKNOWN;
++
++#if defined(CONFIG_SHOW_BOOT_PROGRESS)
++void show_boot_progress(int progress)
++{
++ printf("Boot reached stage %d\n", progress);
++}
++#endif
++
++#define COMP_MODE_ENABLE ((unsigned int)0x0000EAEF)
++
++static inline void delay(unsigned long loops)
++{
++ __asm__ volatile ("1:\n"
++ "subs %0, %1, #1\n"
++ "bne 1b" : "=r" (loops) : "0" (loops));
++}
++
++int is_tee_enable_otp(void)
++{
++ if ((NUM_FF & readl(OTP_USER_LOCKABLE0)) == OTP_SOC_TEE_DISABLE_FLAG)
++ return OTP_TEE_DISABLE; /* tee is disable */
++ else
++ return OTP_TEE_ENABLE; /* tee is enable */
++}
++
++int check_otp_cmd_mode(void)
++{
++ unsigned int el;
++ if (is_tee_enable_otp() == OTP_TEE_ENABLE) { /* tee is enable */
++ asm volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc");
++ el >>= 2; /* Move Left 2 bit */
++ if (el == EXCEPTION_LEVEL1)
++ return OTP_REE_CMD_MODE;
++ else if (el == EXCEPTION_LEVEL3)
++ return OTP_TEE_CMD_MODE;
++ }
++
++ return OTP_TEE_CMD_MODE; /* TEE mode */
++}
++
++/* get uboot start media. */
++int get_boot_media(void)
++{
++ return boot_media;
++}
++
++int get_text_base(void)
++{
++ return CONFIG_SYS_TEXT_BASE;
++}
++
++static void boot_flag_init(void)
++{
++ unsigned int regval, boot_mode;
++
++ /* get boot mode */
++ regval = __raw_readl(SYS_CTRL_REG_BASE + REG_SYSSTAT);
++ boot_mode = get_sys_boot_mode(regval);
++
++ switch (boot_mode) {
++ /* [3:2] 00b - boot from Spi Nor device */
++ case BOOT_FROM_SPI:
++ boot_media = BOOT_MEDIA_SPIFLASH;
++ break;
++ /* [3:2] 01b - boot from Spi Nand device */
++ case BOOT_FROM_SPI_NAND:
++ boot_media = BOOT_MEDIA_NAND;
++ break;
++ /* [3:2] 10b - boot from Nand device */
++ case BOOT_FROM_NAND:
++ boot_media = BOOT_MEDIA_NAND;
++ break;
++ /* [3:2] 11b - boot from emmc */
++ case BOOT_FROM_EMMC:
++ boot_media = BOOT_MEDIA_EMMC;
++ break;
++ default:
++ boot_media = BOOT_MEDIA_UNKNOWN;
++ break;
++ }
++}
++
++int board_early_init_f(void)
++{
++ return 0;
++}
++
++#define UBOOT_DATA_ADDR 0x41000000UL
++#define UBOOT_DATA_SIZE 0x80000UL
++int data_to_spiflash(void)
++{
++ static struct spi_flash *flash = NULL;
++ void *buf = NULL;
++ int spi_flash_erase_ret;
++ ssize_t val;
++
++ /* 0:bus 0:cs 1000000:max_hz 0x3:spi_mode */
++ flash = spi_flash_probe(0, 0, 1000000, 0x3);
++ if (!flash) {
++ printf("Failed to initialize SPI flash\n");
++ return -1;
++ }
++
++ /* erase the address range. */
++ printf("Spi flash erase...\n");
++ spi_flash_erase_ret = spi_flash_erase(flash, NUM_0, UBOOT_DATA_SIZE);
++ if (spi_flash_erase_ret) {
++ printf("SPI flash sector erase failed\n");
++ return 1;
++ }
++
++ buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
++ UBOOT_DATA_SIZE, MAP_WRBACK);
++ if (!buf) {
++ puts("Failed to map physical memory\n");
++ return 1;
++ }
++
++ /* copy the data from RAM to FLASH */
++ printf("Spi flash write...\n");
++ val = flash->write(flash, NUM_0, UBOOT_DATA_SIZE, buf);
++ if (val) {
++ printf("SPI flash write failed, return %zd\n", val);
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 1;
++ }
++
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 0; /* 0:success */
++}
++
++int data_to_nandflash(void)
++{
++ struct mtd_info *nand_flash = NULL;
++ void *buf = NULL;
++ size_t length = UBOOT_DATA_SIZE;
++ int val;
++
++ nand_flash = nand_info[0];
++
++ printf("Nand flash erase...\n");
++ val = nand_erase(nand_flash, 0, UBOOT_DATA_SIZE);
++ if (val) {
++ printf("Nand flash erase failed\n");
++ return 1;
++ }
++
++ buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
++ UBOOT_DATA_SIZE, MAP_WRBACK);
++ if (!buf) {
++ puts("Failed to map physical memory\n");
++ return 1;
++ }
++
++ printf("Nand flash write...\n");
++ val = nand_write(nand_flash, 0, &length, buf);
++ if (val) {
++ printf("Nand flash write failed, return %d\n", val);
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 1;
++ }
++
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 0;
++}
++
++int data_to_emmc(void)
++{
++ struct mmc *mmc = find_mmc_device(0);
++ void *buf = NULL;
++
++ if (!mmc)
++ return 1;
++
++ (void)mmc_init(mmc);
++
++ buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
++ UBOOT_DATA_SIZE, MAP_WRBACK);
++ if (!buf) {
++ puts("Failed to map physical memory\n");
++ return 1;
++ }
++
++ printf("MMC write...\n");
++ blk_dwrite(mmc_get_blk_desc(mmc), 0, (UBOOT_DATA_SIZE >> NUM_9), buf);
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 0;
++}
++
++int save_bootdata_to_flash(void)
++{
++ unsigned int sd_update_flag;
++ int ret;
++ sd_update_flag = readl(REG_BASE_SCTL + REG_SC_GEN4);
++ if (sd_update_flag == START_MAGIC) {
++#if defined(CONFIG_FMC)
++ if (boot_media == BOOT_MEDIA_SPIFLASH) {
++ ret = data_to_spiflash();
++ if (ret != 0)
++ return ret;
++ }
++ if (boot_media == BOOT_MEDIA_NAND) {
++ ret = data_to_nandflash();
++ if (ret != 0)
++ return ret;
++ }
++#endif
++#if defined(CONFIG_MMC)
++ if (boot_media == BOOT_MEDIA_EMMC) {
++ ret = data_to_emmc();
++ if (ret != 0)
++ return ret;
++ }
++#endif
++
++ printf("update success!\n");
++ }
++
++ return 0;
++}
++
++int auto_update_flag = 0;
++int bare_chip_program = 0;
++
++#define REG_BASE_GPIO0 0x11090000
++#define GPIO0_0_DATA_OFST 0x4
++#define GPIO_DIR_OFST 0x400
++#define PROC_TIME_OUT 100
++#define PROC_LOOP 5
++#define DOWNLOAD_FLAG 0x1f
++#define ACK 0xAA
++
++int is_bare_program(void)
++{
++ return 1;
++}
++
++/* Connect to TOOLS */
++int uart_self_boot_check(void)
++{
++ uint32_t count, i;
++ uint32_t timer_count;
++ unsigned char cr;
++
++ for (count = 0; count < PROC_LOOP; ++count) {
++ for (i = 0; i < PROC_LOOP; i++)
++ serial_putc((unsigned char) DOWNLOAD_FLAG);
++
++ timer_count = 0;
++ while (timer_count < PROC_TIME_OUT) {
++ if (serial_tstc()) {
++ cr = (unsigned char)serial_getc();
++ if (cr == ACK)
++ return 1;
++ }
++ timer_count++;
++ udelay(100); /* delay 100 us */
++ }
++ }
++ serial_putc((unsigned char) '\n');
++
++ return 0;
++}
++
++/* return the flag for usb/sd update */
++int check_usb_sd_update_flag(void)
++{
++ u32 flag;
++
++ writel(0x0, REG_BASE_GPIO0 + GPIO_DIR_OFST);
++
++ flag = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ if (!flag) {
++ mdelay(10); /* delay 10 ms */
++ flag = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ if (!flag) {
++ mdelay(10); /* delay 10 ms */
++ flag = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ }
++ }
++
++ return (!flag);
++}
++
++void set_bootloader_download_process_flag(void)
++{
++ uint32_t channel_type;
++
++ if (readl(REG_START_FLAG) == START_MAGIC)
++ return;
++
++ channel_type = readl(REG_BASE_SCTL + REG_DATA_CHANNEL_TYPE);
++ switch (channel_type) {
++ case BOOT_SEL_PCIE:
++ return;
++ default:
++ break;
++ }
++
++ /* set download flag */
++ if (uart_self_boot_check()) {
++ writel(START_MAGIC, REG_START_FLAG);
++ return;
++ }
++
++ if (check_usb_sd_update_flag()) {
++ writel(START_MAGIC, REG_START_FLAG);
++ writel(SELF_BOOT_TYPE_USBDEV, SYS_CTRL_REG_BASE + REG_SC_GEN9);
++ return;
++ }
++}
++
++int is_auto_update(void)
++{
++#if (CONFIG_AUTO_SD_UPDATE == 1) || (CONFIG_AUTO_USB_UPDATE == 1)
++ /* to add some judgement if neccessary */
++ unsigned int val[NUM_3];
++
++ writel(0, REG_BASE_GPIO0 + GPIO_DIR_OFST);
++
++ val[NUM_0] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ if (val[NUM_0])
++ return 0;
++
++ udelay(10000); /* delay 10000 us */
++ val[NUM_1] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ udelay(10000); /* delay 10000 us */
++ val[NUM_2] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ udelay(10000); /* delay 10000 us */
++
++ if (val[NUM_0] == val[NUM_1] && val[NUM_1] == val[NUM_2] && val[NUM_0] == NUM_0)
++ return 1; /* update enable */
++ else
++ return 0;
++
++#else
++ return 0;
++#endif
++}
++
++void set_pcie_para_ss928v100(void)
++{
++ unsigned int val;
++ val = readl(SYS_CTRL_REG_BASE + SYS_SATA);
++ if ((val & (0x3 << PCIE_MODE)) == 0) {
++ /* X2 release phy reset */
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val &= ((~(0x1 << PHY1_SRS_REQ)) & (~(0x1 << PHY0_SRS_REQ)));
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++
++ /*X2 select phy reset from crg*/
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val |= (0x1 << PHY1_SRS_REQ_SEL) | (0x1 << PHY0_SRS_REQ_SEL);
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X2 seperate_rate=1
++ */
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x94f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x92f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x96f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x92f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X2 split_cp_dis
++ */
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd51, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd31, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd71, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd31, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++ } else {
++ /*X1 release phy reset*/
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val &= ~(0x1 << PHY0_SRS_REQ);
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++
++ /*X1 select phy reset from crg*/
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val |= (0x1 << PHY0_SRS_REQ_SEL);
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X1 seperate_rate=1
++ */
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x94f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X1 split_cp_dis
++ */
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd51, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++ };
++}
++
++int misc_init_r(void)
++{
++#ifdef CONFIG_RANDOM_ETHADDR
++ random_init_r();
++#endif
++ env_set("verify", "n");
++
++#if (CONFIG_AUTO_UPDATE == 1)
++ /* auto update flag */
++ if (is_auto_update())
++ auto_update_flag = 1;
++ else
++ auto_update_flag = 0;
++
++ /* bare chip program flag */
++ if (is_bare_program())
++ bare_chip_program = 1;
++ else
++ bare_chip_program = 0;
++
++#ifdef CFG_MMU_HANDLEOK
++ dcache_stop();
++#endif
++
++#ifdef CFG_MMU_HANDLEOK
++ dcache_start();
++#endif
++
++#endif /*CONFIG_AUTO_UPDATE*/
++
++#if (CONFIG_AUTO_UPDATE == 1)
++ if (auto_update_flag)
++ do_auto_update();
++ if (bare_chip_program && !auto_update_flag)
++ save_bootdata_to_flash();
++#endif
++ set_bootloader_download_process_flag();
++ return 0;
++}
++
++int board_init(void)
++{
++ DECLARE_GLOBAL_DATA_PTR;
++
++ gd->bd->bi_arch_number = MACH_TYPE_SS928V100;
++ gd->bd->bi_boot_params = CFG_BOOT_PARAMS;
++
++ boot_flag_init();
++
++ return 0;
++}
++
++int dram_init(void)
++{
++ DECLARE_GLOBAL_DATA_PTR;
++
++ gd->ram_size = PHYS_SDRAM_1_SIZE;
++ return 0;
++}
++
++void reset_cpu(ulong addr)
++{
++ writel(0x12345678, REG_BASE_SCTL + REG_SC_SYSRES);
++ while (1);
++}
++
++int timer_init(void)
++{
++ /*
++ * *Under uboot, 0xffffffff is set to load register,
++ * * timer_clk = BUSCLK/2/256.
++ * * e.g. BUSCLK = 50M, it will roll back after 0xffffffff/timer_clk
++ * * = 43980s = 12hours
++ * */
++ __raw_writel(0, CFG_TIMERBASE + REG_TIMER_CONTROL);
++ __raw_writel(~0, CFG_TIMERBASE + REG_TIMER_RELOAD);
++
++ /*32 bit, periodic*/
++ __raw_writel(CFG_TIMER_CTRL, CFG_TIMERBASE + REG_TIMER_CONTROL);
++
++ return 0;
++}
++
++int board_eth_init(bd_t *bis)
++{
++ int rc = 0;
++
++#ifdef CONFIG_GMACV300_ETH
++ rc = gmac_initialize(bis);
++#endif
++ return rc;
++}
++
++#ifdef CONFIG_GENERIC_MMC
++int board_mmc_init(bd_t *bis)
++{
++ int ret = 0;
++
++#ifdef CONFIG_MMC_SDHCI
++
++#if!defined(CONFIG_FMC) || defined(CONFIG_AUTO_SD_UPDATE)
++ int dev_num = 0;
++#endif
++
++#ifndef CONFIG_FMC
++ ret = sdhci_add_port(0, EMMC_BASE_REG, MMC_TYPE_MMC);
++ if (!ret) {
++ ret = bsp_mmc_init(dev_num);
++ if (ret)
++ printf("No EMMC device found !\n");
++ }
++ dev_num++;
++#endif
++
++#ifdef CONFIG_AUTO_SD_UPDATE
++ if (is_auto_update()) {
++ ret = sdhci_add_port(1, SDIO0_BASE_REG, MMC_TYPE_SD);
++ if (ret)
++ return ret;
++
++ ret = bsp_mmc_init(dev_num);
++ if (ret)
++ printf("No SD device found !\n");
++ }
++#endif
++#endif
++
++ return ret;
++}
++#endif
++
++#define QOS_PRI_BASE 0x11140000
++#define REG_STEP 0x10
++
++#define AXI_QOS_WRPRI0 0x0204
++#define AXI_QOS_WRPRI12 0x02c4
++
++#define AXI_QOS_RDPRI0 0x0208
++#define AXI_QOS_RDPRI12 0x02c8
++
++#define AXI_QOS_MAP0 0x0200
++#define AXI_QOS_MAP12 0x02c0
++
++#define REG_VALUE 0x01234567
++#define AXI_QOS_MAP_VALUE 0x00110000
++
++int config_qos_registers(void)
++{
++ unsigned int i, len;
++
++ /* AXI_QOS_WRPRI0 - AXI_QOS_WRPRI12 */
++ len = (AXI_QOS_WRPRI12 - AXI_QOS_WRPRI0) / REG_STEP;
++ for (i = 0; i <= len; i++)
++ writel(REG_VALUE, (uintptr_t)(QOS_PRI_BASE + AXI_QOS_WRPRI0 + i * REG_STEP));
++
++ /* AXI_QOS_RDPRI0 - AXI_QOS_RDPRI12 */
++ len = (AXI_QOS_RDPRI12 - AXI_QOS_RDPRI0) / REG_STEP;
++ for (i = 0; i <= len; i++)
++ writel(REG_VALUE, (uintptr_t)(QOS_PRI_BASE + AXI_QOS_RDPRI0 + i * REG_STEP));
++
++ /* AXI_QOS_MAP0 - AXI_QOS_MAP12 */
++ len = (AXI_QOS_MAP12 - AXI_QOS_MAP0) / REG_STEP;
++ for (i = 0; i <= len; i++)
++ writel(AXI_QOS_MAP_VALUE, (uintptr_t)(QOS_PRI_BASE + AXI_QOS_MAP0 +
++ i * REG_STEP));
++
++ return 0;
++}
++
++static unsigned int npu_get_stable_power_cpm(void)
++{
++ unsigned int power_cpm = 0;
++ unsigned int val;
++ unsigned int mask = 1;
++
++ do {
++ power_cpm += mask;
++
++ if (power_cpm > NPU_CPM_POWER_MAX_VAL)
++ return 0;
++
++ if (power_cpm == (mask << NPU_CPM_POWER_STEP) - 1)
++ mask <<= NPU_CPM_POWER_STEP;
++
++ writel(power_cpm, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_POWER_CPM_OFFSET));
++ udelay(1); /* delay 1 us */
++
++ val = (readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_MA_VAL_OFFSET)) & NPU_CPM_MA_MASK);
++ } while (val < NPU_CPM_MA_MIN_VAL || val > NPU_CPM_MA_MIN_MAX);
++
++ return power_cpm;
++}
++
++int config_pi_defense_registers(void)
++{
++ unsigned int index;
++ unsigned int times = 0;
++ unsigned int val = 0;
++ unsigned int reg_val = 0;
++
++ reg_val = readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++ reg_val += NPU_VOL_OFFSET_VAL;
++ writel(reg_val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++ udelay(NPU_DELAY_TIME_US);
++
++ /* 1. FFS clk */
++ writel(NPU_FFS_RESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CLK_OFFSET)); /* FFS reset */
++ writel(NPU_CLK_CTRL_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CLK_CTRL_OFFSET));
++ writel(NPU_DROP_FLAG_VAL, (uintptr_t)(SOC_NPU_TOP_BASE_ADDR + NPU_TOP_DROP_FLAG_OFFSET));
++
++ /* 2. static config */
++ writel(NPU_FFS_DEF_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CONFIG_OFFSET)); /* FFS */
++ writel(NPU_CPM_RESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CPM_CLK_OFFSET)); /* CPM reset */
++ writel(NPU_CPM_DEF_VAL, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_CONFIG_OFFSET));
++
++ /* 3. detect ma */
++ writel(NPU_CPM_UNRESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CPM_CLK_OFFSET)); /* CPM unreset */
++ reg_val = npu_get_stable_power_cpm();
++ if (reg_val == 0)
++ goto npu_clk_disable;
++ writel(reg_val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_POWER_CPM_OFFSET));
++
++ /* 4. Threshold */
++ for (index = 0; index < NPU_GET_MA_TIMES; index++) {
++ reg_val = (readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_MA_VAL_OFFSET)) & NPU_CPM_MA_MASK);
++ if (reg_val < NPU_CPM_MA_MIN_VAL || reg_val > NPU_CPM_MA_MIN_MAX)
++ continue;
++ val += reg_val;
++ times++;
++ }
++
++ if (times == 0)
++ goto npu_clk_disable;
++
++ val /= times;
++ val = (val - NPU_CPM_THRESHOLD_DIFF) << NPU_CPM_THRESHOLD_BIT;
++ val += readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_CONFIG_OFFSET));
++ writel(val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_CONFIG_OFFSET));
++
++ /* 5. freq enable */
++ writel(NPU_FFS_UNRESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CLK_OFFSET)); /* FFS unreset */
++ udelay(NPU_CRG_DELAY_TIME);
++
++ val = readl((uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_STATE_OFFSET));
++ if ((val & NPU_FFS_STATE_MASK_VAL) == 0)
++ writel(NPU_FFS_RESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CLK_OFFSET)); /* FFS reset */
++
++ writel(NPU_FFS_CLK_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CONFIG_OFFSET));
++
++npu_clk_disable:
++ /* 6. npu clk disable */
++ writel(NPU_CLK_DISABLE_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CLK_CTRL_OFFSET));
++
++ reg_val = readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++ reg_val -= NPU_VOL_OFFSET_VAL;
++ writel(reg_val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++
++ return 0;
++}
++
++int start_riscv(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++ unsigned long addr;
++
++ if (argc < 2)
++ return CMD_RET_USAGE;
++ addr = simple_strtoul(argv[1], NULL, 16); /* 16 Hexadecimal */
++
++ /* start up riscv */
++ {
++ printf ("## Starting RISCV UP at 0x%016lX ...\n", addr);
++ __asm_flush_dcache_all();
++ writel(addr, 0x110D2004);//set start addr
++
++ writel(0x10, 0x11024000);//jtag to mcu
++ writel(0x1, 0x110D2000);//core wait
++ writel(0x3, 0x11016400);//rst
++
++ writel(0x0, 0x110D2000);//unwait
++ writel(0x4030, 0x11016400);//unrst
++ }
++ return 0;
++}
++
++static int do_watch_dog_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++ unsigned int reg_val = 0;
++
++ printf("watch dog reset ...\n");
++ mdelay(10); /* delay 10 ms */
++ reg_val = readl((uintptr_t)REG_MISC_CTRL3);
++ reg_val |= WATCH_DOG_MODE;
++ writel(reg_val, REG_MISC_CTRL3);
++ writel(WATCH_DOG_LOAD_VAL, REG_BASE_WATCH_DOG);
++ reg_val = readl((uintptr_t)WATCH_DOG_CONTROL);
++ reg_val |= WATCH_DOG_ENABLE;
++ writel(reg_val, WATCH_DOG_CONTROL);
++
++ return 0;
++}
++
++U_BOOT_CMD(
++ go_riscv, CONFIG_SYS_MAXARGS, 1, start_riscv,
++ "start riscv at address 'addr'",
++ "addr [arg ...]\n - start riscv application at address 'addr'\n"
++ " passing 'arg' as arguments"
++);
++
++U_BOOT_CMD(
++ dog_reset, CONFIG_SYS_MAXARGS, 0, do_watch_dog_reset,
++ "watchdog reset system",
++ "watchdog reset \n"
++);
+diff --git a/board/vendor/ss928v100/Kconfig b/board/vendor/ss928v100/Kconfig
+new file mode 100644
+index 0000000..9b5cf23
+--- /dev/null
++++ b/board/vendor/ss928v100/Kconfig
+@@ -0,0 +1,15 @@
++if TARGET_SS928V100
++
++config SYS_BOARD
++ default "ss928v100"
++
++config SYS_VENDOR
++ default "vendor"
++
++config SYS_SOC
++ default "ss928v100"
++
++config SYS_CONFIG_NAME
++ default "ss928v100"
++
++endif
+diff --git a/board/vendor/ss928v100/Makefile b/board/vendor/ss928v100/Makefile
+new file mode 100644
+index 0000000..cdd7b20
+--- /dev/null
++++ b/board/vendor/ss928v100/Makefile
+@@ -0,0 +1,8 @@
++#
++# (C) Copyright 2000-2004
++# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
++#
++# SPDX-License-Identifier: GPL-2.0+
++#
++
++obj-y := ss928v100.o
+diff --git a/board/vendor/ss928v100/ss928v100.c b/board/vendor/ss928v100/ss928v100.c
+new file mode 100644
+index 0000000..0e7f18b
+--- /dev/null
++++ b/board/vendor/ss928v100/ss928v100.c
+@@ -0,0 +1,792 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++static struct mm_region ss928v100_mem_map[] = {
++ {
++ .virt = 0x0UL,
++ .phys = 0x0UL,
++ .size = 0x05000000UL,
++ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
++ PTE_BLOCK_NON_SHARE
++ },
++ {
++ .virt = 0x05000000UL,
++ .phys = 0x05000000UL,
++ .size = 0x40000000UL - 0x05000000UL,
++ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
++ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN
++ },
++ {
++ .virt = 0x40000000UL,
++ .phys = 0x40000000UL,
++ .size = 0x200000000UL, /* PHYS_SDRAM_1_SIZE */
++ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
++ PTE_BLOCK_INNER_SHARE
++ },
++ {
++ /* List terminator */
++ 0,
++ }
++};
++
++struct mm_region *mem_map = ss928v100_mem_map;
++static int boot_media = BOOT_MEDIA_UNKNOWN;
++
++#if defined(CONFIG_SHOW_BOOT_PROGRESS)
++void show_boot_progress(int progress)
++{
++ printf("Boot reached stage %d\n", progress);
++}
++#endif
++
++#define COMP_MODE_ENABLE ((unsigned int)0x0000EAEF)
++
++static inline void delay(unsigned long loops)
++{
++ __asm__ volatile ("1:\n"
++ "subs %0, %1, #1\n"
++ "bne 1b" : "=r" (loops) : "0" (loops));
++}
++
++int is_tee_enable_otp(void)
++{
++ if ((NUM_FF & readl(OTP_USER_LOCKABLE0)) == OTP_SOC_TEE_DISABLE_FLAG)
++ return OTP_TEE_DISABLE; /* tee is disable */
++ else
++ return OTP_TEE_ENABLE; /* tee is enable */
++}
++
++int check_otp_cmd_mode(void)
++{
++ unsigned int el;
++ if (is_tee_enable_otp() == OTP_TEE_ENABLE) { /* tee is enable */
++ asm volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc");
++ el >>= 2; /* Move Left 2 bit */
++ if (el == EXCEPTION_LEVEL1)
++ return OTP_REE_CMD_MODE;
++ else if (el == EXCEPTION_LEVEL3)
++ return OTP_TEE_CMD_MODE;
++ }
++
++ return OTP_TEE_CMD_MODE; /* TEE mode */
++}
++
++/* get uboot start media. */
++int get_boot_media(void)
++{
++ return boot_media;
++}
++
++int get_text_base(void)
++{
++ return CONFIG_SYS_TEXT_BASE;
++}
++
++static void boot_flag_init(void)
++{
++ unsigned int regval, boot_mode;
++
++ /* get boot mode */
++ regval = __raw_readl(SYS_CTRL_REG_BASE + REG_SYSSTAT);
++ boot_mode = get_sys_boot_mode(regval);
++
++ switch (boot_mode) {
++ /* [3:2] 00b - boot from Spi Nor device */
++ case BOOT_FROM_SPI:
++ boot_media = BOOT_MEDIA_SPIFLASH;
++ break;
++ /* [3:2] 01b - boot from Spi Nand device */
++ case BOOT_FROM_SPI_NAND:
++ boot_media = BOOT_MEDIA_NAND;
++ break;
++ /* [3:2] 10b - boot from Nand device */
++ case BOOT_FROM_NAND:
++ boot_media = BOOT_MEDIA_NAND;
++ break;
++ /* [3:2] 11b - boot from emmc */
++ case BOOT_FROM_EMMC:
++ boot_media = BOOT_MEDIA_EMMC;
++ break;
++ default:
++ boot_media = BOOT_MEDIA_UNKNOWN;
++ break;
++ }
++}
++
++int board_early_init_f(void)
++{
++ return 0;
++}
++
++#define UBOOT_DATA_ADDR 0x41000000UL
++#define UBOOT_DATA_SIZE 0x80000UL
++int data_to_spiflash(void)
++{
++ static struct spi_flash *flash = NULL;
++ void *buf = NULL;
++ int spi_flash_erase_ret;
++ ssize_t val;
++
++ /* 0:bus 0:cs 1000000:max_hz 0x3:spi_mode */
++ flash = spi_flash_probe(0, 0, 1000000, 0x3);
++ if (!flash) {
++ printf("Failed to initialize SPI flash\n");
++ return -1;
++ }
++
++ /* erase the address range. */
++ printf("Spi flash erase...\n");
++ spi_flash_erase_ret = spi_flash_erase(flash, NUM_0, UBOOT_DATA_SIZE);
++ if (spi_flash_erase_ret) {
++ printf("SPI flash sector erase failed\n");
++ return 1;
++ }
++
++ buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
++ UBOOT_DATA_SIZE, MAP_WRBACK);
++ if (!buf) {
++ puts("Failed to map physical memory\n");
++ return 1;
++ }
++
++ /* copy the data from RAM to FLASH */
++ printf("Spi flash write...\n");
++ val = flash->write(flash, NUM_0, UBOOT_DATA_SIZE, buf);
++ if (val) {
++ printf("SPI flash write failed, return %zd\n", val);
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 1;
++ }
++
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 0; /* 0:success */
++}
++
++int data_to_nandflash(void)
++{
++ struct mtd_info *nand_flash = NULL;
++ void *buf = NULL;
++ size_t length = UBOOT_DATA_SIZE;
++ int val;
++
++ nand_flash = nand_info[0];
++
++ printf("Nand flash erase...\n");
++ val = nand_erase(nand_flash, 0, UBOOT_DATA_SIZE);
++ if (val) {
++ printf("Nand flash erase failed\n");
++ return 1;
++ }
++
++ buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
++ UBOOT_DATA_SIZE, MAP_WRBACK);
++ if (!buf) {
++ puts("Failed to map physical memory\n");
++ return 1;
++ }
++
++ printf("Nand flash write...\n");
++ val = nand_write(nand_flash, 0, &length, buf);
++ if (val) {
++ printf("Nand flash write failed, return %d\n", val);
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 1;
++ }
++
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 0;
++}
++
++int data_to_emmc(void)
++{
++ struct mmc *mmc = find_mmc_device(0);
++ void *buf = NULL;
++
++ if (!mmc)
++ return 1;
++
++ (void)mmc_init(mmc);
++
++ buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
++ UBOOT_DATA_SIZE, MAP_WRBACK);
++ if (!buf) {
++ puts("Failed to map physical memory\n");
++ return 1;
++ }
++
++ printf("MMC write...\n");
++ blk_dwrite(mmc_get_blk_desc(mmc), 0, (UBOOT_DATA_SIZE >> NUM_9), buf);
++ unmap_physmem(buf, UBOOT_DATA_SIZE);
++ return 0;
++}
++
++int save_bootdata_to_flash(void)
++{
++ unsigned int sd_update_flag;
++ int ret;
++ sd_update_flag = readl(REG_BASE_SCTL + REG_SC_GEN4);
++ if (sd_update_flag == START_MAGIC) {
++#if defined(CONFIG_FMC)
++ if (boot_media == BOOT_MEDIA_SPIFLASH) {
++ ret = data_to_spiflash();
++ if (ret != 0)
++ return ret;
++ }
++ if (boot_media == BOOT_MEDIA_NAND) {
++ ret = data_to_nandflash();
++ if (ret != 0)
++ return ret;
++ }
++#endif
++#if defined(CONFIG_MMC)
++ if (boot_media == BOOT_MEDIA_EMMC) {
++ ret = data_to_emmc();
++ if (ret != 0)
++ return ret;
++ }
++#endif
++
++ printf("update success!\n");
++ }
++
++ return 0;
++}
++
++int auto_update_flag = 0;
++int bare_chip_program = 0;
++
++#define REG_BASE_GPIO0 0x11090000
++#define GPIO0_0_DATA_OFST 0x4
++#define GPIO_DIR_OFST 0x400
++#define PROC_TIME_OUT 100
++#define PROC_LOOP 5
++#define DOWNLOAD_FLAG 0x1f
++#define ACK 0xAA
++
++int is_bare_program(void)
++{
++ return 1;
++}
++
++/* Connect to TOOLS */
++int uart_self_boot_check(void)
++{
++ uint32_t count, i;
++ uint32_t timer_count;
++ unsigned char cr;
++
++ for (count = 0; count < PROC_LOOP; ++count) {
++ for (i = 0; i < PROC_LOOP; i++)
++ serial_putc((unsigned char) DOWNLOAD_FLAG);
++
++ timer_count = 0;
++ while (timer_count < PROC_TIME_OUT) {
++ if (serial_tstc()) {
++ cr = (unsigned char)serial_getc();
++ if (cr == ACK)
++ return 1;
++ }
++ timer_count++;
++ udelay(100); /* delay 100 us */
++ }
++ }
++ serial_putc((unsigned char) '\n');
++
++ return 0;
++}
++
++/* return the flag for usb/sd update */
++int check_usb_sd_update_flag(void)
++{
++ u32 flag;
++
++ writel(0x0, REG_BASE_GPIO0 + GPIO_DIR_OFST);
++
++ flag = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ if (!flag) {
++ mdelay(10); /* delay 10 ms */
++ flag = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ if (!flag) {
++ mdelay(10); /* delay 10 ms */
++ flag = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ }
++ }
++
++ return (!flag);
++}
++
++void set_bootloader_download_process_flag(void)
++{
++ uint32_t channel_type;
++
++ if (readl(REG_START_FLAG) == START_MAGIC)
++ return;
++
++ channel_type = readl(REG_BASE_SCTL + REG_DATA_CHANNEL_TYPE);
++ switch (channel_type) {
++ case BOOT_SEL_PCIE:
++ return;
++ default:
++ break;
++ }
++
++ /* set download flag */
++ if (uart_self_boot_check()) {
++ writel(START_MAGIC, REG_START_FLAG);
++ return;
++ }
++
++ if (check_usb_sd_update_flag()) {
++ writel(START_MAGIC, REG_START_FLAG);
++ writel(SELF_BOOT_TYPE_USBDEV, SYS_CTRL_REG_BASE + REG_SC_GEN9);
++ return;
++ }
++}
++
++int is_auto_update(void)
++{
++#if (CONFIG_AUTO_SD_UPDATE == 1) || (CONFIG_AUTO_USB_UPDATE == 1)
++ /* to add some judgement if neccessary */
++ unsigned int val[NUM_3];
++
++ writel(0, REG_BASE_GPIO0 + GPIO_DIR_OFST);
++
++ val[NUM_0] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ if (val[NUM_0])
++ return 0;
++
++ udelay(10000); /* delay 10000 us */
++ val[NUM_1] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ udelay(10000); /* delay 10000 us */
++ val[NUM_2] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
++ udelay(10000); /* delay 10000 us */
++
++ if (val[NUM_0] == val[NUM_1] && val[NUM_1] == val[NUM_2] && val[NUM_0] == NUM_0)
++ return 1; /* update enable */
++ else
++ return 0;
++
++#else
++ return 0;
++#endif
++}
++
++void set_pcie_para_ss928v100(void)
++{
++ unsigned int val;
++ val = readl(SYS_CTRL_REG_BASE + SYS_SATA);
++ if ((val & (0x3 << PCIE_MODE)) == 0) {
++ /* X2 release phy reset */
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val &= ((~(0x1 << PHY1_SRS_REQ)) & (~(0x1 << PHY0_SRS_REQ)));
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++
++ /*X2 select phy reset from crg*/
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val |= (0x1 << PHY1_SRS_REQ_SEL) | (0x1 << PHY0_SRS_REQ_SEL);
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X2 seperate_rate=1
++ */
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x94f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x92f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x96f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x92f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X2 split_cp_dis
++ */
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd51, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd31, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd71, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd31, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++ } else {
++ /*X1 release phy reset*/
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val &= ~(0x1 << PHY0_SRS_REQ);
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++
++ /*X1 select phy reset from crg*/
++ val = readl(CRG_REG_BASE + PERI_CRG98);
++ val |= (0x1 << PHY0_SRS_REQ_SEL);
++ writel(val, CRG_REG_BASE + PERI_CRG98);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X1 seperate_rate=1
++ */
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x94f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x90f, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++
++ /*
++ * X1 split_cp_dis
++ */
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd51, MISC_REG_BASE + MISC_CTRL5);
++ writel(0xd11, MISC_REG_BASE + MISC_CTRL5);
++ writel(0x0, MISC_REG_BASE + MISC_CTRL5);
++ mdelay(10); /* delay 10 ms */
++ };
++}
++
++int misc_init_r(void)
++{
++#ifdef CONFIG_RANDOM_ETHADDR
++ random_init_r();
++#endif
++ env_set("verify", "n");
++
++#if (CONFIG_AUTO_UPDATE == 1)
++ /* auto update flag */
++ if (is_auto_update())
++ auto_update_flag = 1;
++ else
++ auto_update_flag = 0;
++
++ /* bare chip program flag */
++ if (is_bare_program())
++ bare_chip_program = 1;
++ else
++ bare_chip_program = 0;
++
++#ifdef CFG_MMU_HANDLEOK
++ dcache_stop();
++#endif
++
++#ifdef CFG_MMU_HANDLEOK
++ dcache_start();
++#endif
++
++#endif /*CONFIG_AUTO_UPDATE*/
++
++#if (CONFIG_AUTO_UPDATE == 1)
++ if (auto_update_flag)
++ do_auto_update();
++ if (bare_chip_program && !auto_update_flag)
++ save_bootdata_to_flash();
++#endif
++ set_bootloader_download_process_flag();
++ return 0;
++}
++
++int board_init(void)
++{
++ DECLARE_GLOBAL_DATA_PTR;
++
++ gd->bd->bi_arch_number = MACH_TYPE_SS928V100;
++ gd->bd->bi_boot_params = CFG_BOOT_PARAMS;
++
++ boot_flag_init();
++
++ return 0;
++}
++
++int dram_init(void)
++{
++ DECLARE_GLOBAL_DATA_PTR;
++
++ gd->ram_size = PHYS_SDRAM_1_SIZE;
++ return 0;
++}
++
++void reset_cpu(ulong addr)
++{
++ writel(0x12345678, REG_BASE_SCTL + REG_SC_SYSRES);
++ while (1);
++}
++
++int timer_init(void)
++{
++ /*
++ * *Under uboot, 0xffffffff is set to load register,
++ * * timer_clk = BUSCLK/2/256.
++ * * e.g. BUSCLK = 50M, it will roll back after 0xffffffff/timer_clk
++ * * = 43980s = 12hours
++ * */
++ __raw_writel(0, CFG_TIMERBASE + REG_TIMER_CONTROL);
++ __raw_writel(~0, CFG_TIMERBASE + REG_TIMER_RELOAD);
++
++ /*32 bit, periodic*/
++ __raw_writel(CFG_TIMER_CTRL, CFG_TIMERBASE + REG_TIMER_CONTROL);
++
++ return 0;
++}
++
++int board_eth_init(bd_t *bis)
++{
++ int rc = 0;
++
++#ifdef CONFIG_GMACV300_ETH
++ rc = gmac_initialize(bis);
++#endif
++ return rc;
++}
++
++#ifdef CONFIG_GENERIC_MMC
++int board_mmc_init(bd_t *bis)
++{
++ int ret = 0;
++
++#ifdef CONFIG_MMC_SDHCI
++
++#if!defined(CONFIG_FMC) || defined(CONFIG_AUTO_SD_UPDATE)
++ int dev_num = 0;
++#endif
++
++#ifndef CONFIG_FMC
++ ret = sdhci_add_port(0, EMMC_BASE_REG, MMC_TYPE_MMC);
++ if (!ret) {
++ ret = bsp_mmc_init(dev_num);
++ if (ret)
++ printf("No EMMC device found !\n");
++ }
++ dev_num++;
++#endif
++
++#ifdef CONFIG_AUTO_SD_UPDATE
++ if (is_auto_update()) {
++ ret = sdhci_add_port(1, SDIO0_BASE_REG, MMC_TYPE_SD);
++ if (ret)
++ return ret;
++
++ ret = bsp_mmc_init(dev_num);
++ if (ret)
++ printf("No SD device found !\n");
++ }
++#endif
++#endif
++
++ return ret;
++}
++#endif
++
++#define QOS_PRI_BASE 0x11140000
++#define REG_STEP 0x10
++
++#define AXI_QOS_WRPRI0 0x0204
++#define AXI_QOS_WRPRI12 0x02c4
++
++#define AXI_QOS_RDPRI0 0x0208
++#define AXI_QOS_RDPRI12 0x02c8
++
++#define AXI_QOS_MAP0 0x0200
++#define AXI_QOS_MAP12 0x02c0
++
++#define REG_VALUE 0x01234567
++#define AXI_QOS_MAP_VALUE 0x00110000
++
++int config_qos_registers(void)
++{
++ unsigned int i, len;
++
++ /* AXI_QOS_WRPRI0 - AXI_QOS_WRPRI12 */
++ len = (AXI_QOS_WRPRI12 - AXI_QOS_WRPRI0) / REG_STEP;
++ for (i = 0; i <= len; i++)
++ writel(REG_VALUE, (uintptr_t)(QOS_PRI_BASE + AXI_QOS_WRPRI0 + i * REG_STEP));
++
++ /* AXI_QOS_RDPRI0 - AXI_QOS_RDPRI12 */
++ len = (AXI_QOS_RDPRI12 - AXI_QOS_RDPRI0) / REG_STEP;
++ for (i = 0; i <= len; i++)
++ writel(REG_VALUE, (uintptr_t)(QOS_PRI_BASE + AXI_QOS_RDPRI0 + i * REG_STEP));
++
++ /* AXI_QOS_MAP0 - AXI_QOS_MAP12 */
++ len = (AXI_QOS_MAP12 - AXI_QOS_MAP0) / REG_STEP;
++ for (i = 0; i <= len; i++)
++ writel(AXI_QOS_MAP_VALUE, (uintptr_t)(QOS_PRI_BASE + AXI_QOS_MAP0 +
++ i * REG_STEP));
++
++ return 0;
++}
++
++static unsigned int npu_get_stable_power_cpm(void)
++{
++ unsigned int power_cpm = 0;
++ unsigned int val;
++ unsigned int mask = 1;
++
++ do {
++ power_cpm += mask;
++
++ if (power_cpm > NPU_CPM_POWER_MAX_VAL)
++ return 0;
++
++ if (power_cpm == (mask << NPU_CPM_POWER_STEP) - 1)
++ mask <<= NPU_CPM_POWER_STEP;
++
++ writel(power_cpm, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_POWER_CPM_OFFSET));
++ udelay(1); /* delay 1 us */
++
++ val = (readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_MA_VAL_OFFSET)) & NPU_CPM_MA_MASK);
++ } while (val < NPU_CPM_MA_MIN_VAL || val > NPU_CPM_MA_MIN_MAX);
++
++ return power_cpm;
++}
++
++int config_pi_defense_registers(void)
++{
++ unsigned int index;
++ unsigned int times = 0;
++ unsigned int val = 0;
++ unsigned int reg_val = 0;
++
++ reg_val = readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++ reg_val += NPU_VOL_OFFSET_VAL;
++ writel(reg_val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++ udelay(NPU_DELAY_TIME_US);
++
++ /* 1. FFS clk */
++ writel(NPU_FFS_RESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CLK_OFFSET)); /* FFS reset */
++ writel(NPU_CLK_CTRL_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CLK_CTRL_OFFSET));
++ writel(NPU_DROP_FLAG_VAL, (uintptr_t)(SOC_NPU_TOP_BASE_ADDR + NPU_TOP_DROP_FLAG_OFFSET));
++
++ /* 2. static config */
++ writel(NPU_FFS_DEF_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CONFIG_OFFSET)); /* FFS */
++ writel(NPU_CPM_RESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CPM_CLK_OFFSET)); /* CPM reset */
++ writel(NPU_CPM_DEF_VAL, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_CONFIG_OFFSET));
++
++ /* 3. detect ma */
++ writel(NPU_CPM_UNRESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CPM_CLK_OFFSET)); /* CPM unreset */
++ reg_val = npu_get_stable_power_cpm();
++ if (reg_val == 0)
++ goto npu_clk_disable;
++ writel(reg_val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_POWER_CPM_OFFSET));
++
++ /* 4. Threshold */
++ for (index = 0; index < NPU_GET_MA_TIMES; index++) {
++ reg_val = (readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_MA_VAL_OFFSET)) & NPU_CPM_MA_MASK);
++ if (reg_val < NPU_CPM_MA_MIN_VAL || reg_val > NPU_CPM_MA_MIN_MAX)
++ continue;
++ val += reg_val;
++ times++;
++ }
++
++ if (times == 0)
++ goto npu_clk_disable;
++
++ val /= times;
++ val = (val - NPU_CPM_THRESHOLD_DIFF) << NPU_CPM_THRESHOLD_BIT;
++ val += readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_CONFIG_OFFSET));
++ writel(val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_CPM_CONFIG_OFFSET));
++
++ /* 5. freq enable */
++ writel(NPU_FFS_UNRESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CLK_OFFSET)); /* FFS unreset */
++ udelay(NPU_CRG_DELAY_TIME);
++
++ val = readl((uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_STATE_OFFSET));
++ if ((val & NPU_FFS_STATE_MASK_VAL) == 0)
++ writel(NPU_FFS_RESET_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CLK_OFFSET)); /* FFS reset */
++
++ writel(NPU_FFS_CLK_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_FFS_CONFIG_OFFSET));
++
++npu_clk_disable:
++ /* 6. npu clk disable */
++ writel(NPU_CLK_DISABLE_VAL, (uintptr_t)(SOC_CRG_BASE_ADDR + CRG_NPU_CLK_CTRL_OFFSET));
++
++ reg_val = readl((uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++ reg_val -= NPU_VOL_OFFSET_VAL;
++ writel(reg_val, (uintptr_t)(SOC_SYS_BASE_ADDR + SYS_NPU_VOL_OFFSET));
++
++ return 0;
++}
++
++int start_riscv(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++ unsigned long addr;
++
++ if (argc < 2)
++ return CMD_RET_USAGE;
++ addr = simple_strtoul(argv[1], NULL, 16); /* 16 Hexadecimal */
++
++ /* start up riscv */
++ {
++ printf ("## Starting RISCV UP at 0x%016lX ...\n", addr);
++ __asm_flush_dcache_all();
++ writel(addr, 0x110D2004);//set start addr
++
++ writel(0x10, 0x11024000);//jtag to mcu
++ writel(0x1, 0x110D2000);//core wait
++ writel(0x3, 0x11016400);//rst
++
++ writel(0x0, 0x110D2000);//unwait
++ writel(0x4030, 0x11016400);//unrst
++ }
++ return 0;
++}
++
++static int do_watch_dog_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++ unsigned int reg_val = 0;
++
++ printf("watch dog reset ...\n");
++ mdelay(10); /* delay 10 ms */
++ reg_val = readl((uintptr_t)REG_MISC_CTRL3);
++ reg_val |= WATCH_DOG_MODE;
++ writel(reg_val, REG_MISC_CTRL3);
++ writel(WATCH_DOG_LOAD_VAL, REG_BASE_WATCH_DOG);
++ reg_val = readl((uintptr_t)WATCH_DOG_CONTROL);
++ reg_val |= WATCH_DOG_ENABLE;
++ writel(reg_val, WATCH_DOG_CONTROL);
++
++ return 0;
++}
++
++U_BOOT_CMD(
++ go_riscv, CONFIG_SYS_MAXARGS, 1, start_riscv,
++ "start riscv at address 'addr'",
++ "addr [arg ...]\n - start riscv application at address 'addr'\n"
++ " passing 'arg' as arguments"
++);
++
++U_BOOT_CMD(
++ dog_reset, CONFIG_SYS_MAXARGS, 0, do_watch_dog_reset,
++ "watchdog reset system",
++ "watchdog reset \n"
++);
+diff --git a/cmd/Kconfig b/cmd/Kconfig
+index 1e4cf14..380764e 100644
+--- a/cmd/Kconfig
++++ b/cmd/Kconfig
+@@ -553,6 +553,12 @@ config CMD_NVEDIT_INFO
+ [-p] : evaluate whether environment can be persisted
+ The result of multiple evaluations will be combined with AND.
+
++config CMD_COPYENV
++ bool "copy env"
++ default n
++ help
++ copy specified env to dst memory. such as: envcopy bootargs 0x80000020
++
+ endmenu
+
+ menu "Memory commands"
+@@ -723,6 +729,12 @@ config CMD_STRINGS
+ within the range are displayed. The minimum number of characters
+ for a sequence to be considered a string can be provided.
+
++config CMD_DDR_TRAINING
++ bool "ddr training"
++ default y
++ help
++ ddr training function
++
+ endmenu
+
+ menu "Compression commands"
+@@ -746,6 +758,17 @@ config CMD_ZIP
+ help
+ Compress a memory region with zlib deflate method.
+
++config CMD_CREAD
++ bool "Enable cycle read function"
++ help
++ Enable the function for cycle read.
++
++config CMD_UGZIP
++ bool "ugzip"
++ select HWDEC
++ help
++ UnCompress a gzip file with hardware umcompress ip of chip.
++
+ endmenu
+
+ menu "Device access commands"
+@@ -1048,7 +1071,7 @@ config CMD_MTD
+ config CMD_NAND
+ bool "nand"
+ default y if NAND_SUNXI
+- depends on MTD_RAW_NAND
++ depends on MTD_RAW_NAND || FMC_SPI_NAND || FMC_NAND
+ help
+ NAND support.
+
+@@ -1172,7 +1195,7 @@ config CMD_SDRAM
+
+ config CMD_SF
+ bool "sf"
+- depends on DM_SPI_FLASH || SPI_FLASH
++ depends on DM_SPI_FLASH || SPI_FLASH || FMC_SPI_NOR
+ default y if DM_SPI_FLASH
+ help
+ SPI Flash support
+@@ -1227,6 +1250,7 @@ config CMD_UNIVERSE
+ config CMD_USB
+ bool "usb"
+ select HAVE_BLOCK_DEVICE
++ depends on USB_GADGET
+ help
+ USB support.
+
+diff --git a/cmd/Makefile b/cmd/Makefile
+index 3ac7104..654b76d 100644
+--- a/cmd/Makefile
++++ b/cmd/Makefile
+@@ -184,6 +184,8 @@ endif # !CONFIG_SPL_BUILD
+
+ # core command
+ obj-y += nvedit.o
++obj-y += vendor/getinfo.o
++obj-$(CONFIG_CMD_USB) += usbtftp.o
+
+ obj-$(CONFIG_TI_COMMON_CMD_OPTIONS) += ti/
+
+@@ -224,3 +226,11 @@ $(obj)/license_data_size.h: $(srctree)/Licenses/gpl-2.0.txt FORCE
+ $(call filechk,data_size)
+
+ CFLAGS_ethsw.o := -Wno-enum-conversion
++
++# osd command
++sinclude $(srctree)/cmd/Makefile-otproduct
++
++obj-$(CONFIG_CMD_CREAD) += cmd_cycle.o
++obj-$(CONFIG_CMD_UGZIP) += cmd_ugzip.o
++obj-$(CONFIG_CMD_COPYENV) += nvcopy.o
++obj-$(CONFIG_CMD_TIMESTAMP) += cmd_timestamp.o
+diff --git a/cmd/Makefile-otproduct b/cmd/Makefile-otproduct
+new file mode 100644
+index 0000000..3f81448
+--- /dev/null
++++ b/cmd/Makefile-otproduct
+@@ -0,0 +1,105 @@
++# for audio
++ifeq ($(CONFIG_AUDIO_ENABLE),y)
++ifeq ($(CONFIG_PRODUCTNAME),$(filter $(CONFIG_PRODUCTNAME), "ss101v500" "ss101v200" "ss101v300" "ss101v600"))
++AO_ARCH_NAME = ss101v200
++ACODEC_NAME = v750
++endif
++cflags-y += -I$(srctree)/product/audio/ao/$(AO_ARCH_NAME)
++cflags-y += -I$(srctree)/product/audio/acodec/$(ACODEC_NAME)
++ccflags-y += $(cflags-y)
++obj-y += cmd_ao.o
++endif
++
++# Osd command
++ifeq ($(CONFIG_OSD_ENABLE),y)
++# for dec
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v500")
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v200")
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v300")
++ifneq ($(CONFIG_PRODUCTNAME),"ss101v600")
++obj-y += cmd_dec.o
++endif
++endif
++endif
++endif
++ifeq ($(CONFIG_PRODUCTNAME),"ss919v100")
++EXTRA_CFLAGS += -DRGB_OUTPUT_ENABLE
++endif
++ifeq ($(CONFIG_PRODUCTNAME),"ss015v100")
++EXTRA_CFLAGS += -DRGB_OUTPUT_ENABLE
++endif
++# for vo
++ifeq ($(CONFIG_PRODUCTNAME),"ss919v100")
++ccflags-y += -DCONFIG_OT_HDMI_SUPPORT
++obj-y += cmd_vo_ss919v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss015v100")
++ccflags-y += -DCONFIG_OT_HDMI_SUPPORT
++obj-y += cmd_vo_ss015v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss918v100")
++obj-y += cmd_vo_ss918v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss013v100")
++obj-y += cmd_vo_ss918v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss813v100")
++obj-y += cmd_vo_ss812v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss815v100")
++obj-y += cmd_vo_ss812v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v200")
++obj-y += cmd_vo_ss101v200.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v500")
++obj-y += cmd_vo_ss101v200.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v300")
++obj-y += cmd_vo_ss101v200.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss101v600")
++obj-y += cmd_vo_ss101v200.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss313v100")
++obj-y += cmd_vo_ss812v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss011v100")
++obj-y += cmd_vo_ss812v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss012v100")
++obj-y += cmd_vo_ss812v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),"ss312v100")
++obj-y += cmd_vo_ss812v100.o
++else ifeq ($(CONFIG_PRODUCTNAME),$(filter $(CONFIG_PRODUCTNAME), "ss528v100" "ss625v100" "ss524v100" "ss522v101" "ss522v100" "ss615v100" "ss928v100" "ss927v100"))
++
++ifeq ($(CONFIG_PRODUCTNAME),$(filter $(CONFIG_PRODUCTNAME), "ss524v100" "ss522v101" "ss522v100"))
++VO_ARCH_NAME = ss524v100
++else
++VO_ARCH_NAME = $(CONFIG_PRODUCTNAME)
++endif
++
++VO_SUB_ARCH_NAME = $(CONFIG_PRODUCTNAME)
++cflags-y += -I$(srctree)/product/ot_osd/vo/include
++cflags-y += -I$(srctree)/product/ot_osd/include
++cflags-y += -I$(srctree)/product/ot_osd/hdmi/hdmi_2_0
++cflags-y += -I$(srctree)/product/ot_osd/vo/arch/$(VO_ARCH_NAME)/include
++cflags-y += -I$(srctree)/product/ot_osd/vo/arch/$(VO_ARCH_NAME)/include/$(VO_SUB_ARCH_NAME)
++ccflags-y += -DCONFIG_OT_HDMI_SUPPORT
++ccflags-y += $(cflags-y)
++obj-y += cmd_vo.o
++endif
++
++ifeq ($(CONFIG_PRODUCTNAME), "ss528v100")
++ccflags-y += -DCHIP_SS528V100
++else ifeq ($(CONFIG_PRODUCTNAME), "ss625v100")
++ccflags-y += -DCHIP_SS625V100
++else ifeq ($(CONFIG_PRODUCTNAME), "ss524v100")
++ccflags-y += -DCHIP_SS524V100
++else ifeq ($(CONFIG_PRODUCTNAME), "ss615v100")
++ccflags-y += -DCHIP_SS615V100
++else ifeq ($(CONFIG_PRODUCTNAME), "ss522v100")
++ccflags-y += -DCHIP_SS524V100
++else ifeq ($(CONFIG_PRODUCTNAME), "ss522v101")
++ccflags-y += -DCHIP_SS522V101
++else ifeq ($(CONFIG_PRODUCTNAME), "ss928v100")
++ccflags-y += -DCHIP_SS928V100
++ccflags-y += -DCONFIG_OT_MIPI_TX_SUPPORT
++cflags-y += -I$(srctree)/product/ot_osd/mipi_tx/ss928v100
++ccflags-y += $(cflags-y)
++else ifeq ($(CONFIG_PRODUCTNAME), "ss927v100")
++ccflags-y += -DCHIP_SS927V100
++ccflags-y += -DCONFIG_OT_MIPI_TX_SUPPORT
++cflags-y += -I$(srctree)/product/ot_osd/mipi_tx/ss928v100
++ccflags-y += $(cflags-y)
++endif
++
++endif
+diff --git a/cmd/boot.c b/cmd/boot.c
+index 9150fce..5d43df5 100644
+--- a/cmd/boot.c
++++ b/cmd/boot.c
+@@ -12,6 +12,9 @@
+ #include
+
+ #ifdef CONFIG_CMD_GO
++#if defined(CONFIG_CMD_USB)
++#include
++#endif
+
+ /* Allow ports to override the default behavior */
+ __attribute__((weak))
+@@ -29,10 +32,24 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
++#if defined(CONFIG_CMD_USB)
++ /*
++ * turn off USB to prevent the host controller from writing to the
++ * SDRAM while Linux is booting. This could happen (at least for OHCI
++ * controller), because the HCCA (Host Controller Communication Area)
++ * lies within the SDRAM and the host controller writes continously to
++ * this area (as busmaster!). The HccaFrameNumber is for example
++ * updated every 1 ms within the HCCA structure in SDRAM! For more
++ * details see the OpenHCI specification.
++ */
++ usb_stop();
++#endif
++
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ printf ("## Starting application at 0x%08lX ...\n", addr);
+
++ cleanup_before_linux();
+ /*
+ * pass address parameter as argv[0] (aka command name),
+ * and all remaining args
+diff --git a/cmd/bootm.c b/cmd/bootm.c
+index 62ee7c4..bc9b778 100644
+--- a/cmd/bootm.c
++++ b/cmd/bootm.c
+@@ -20,9 +20,12 @@
+ #include
+ #include
+ #include
++#if CONFIG_IS_ENABLED(CMD_TIMESTAMP)
++#include "cmd_timestamp.h"
++#endif
+
+ DECLARE_GLOBAL_DATA_PTR;
+-
++#define TEE_ENABLE "tee_enable"
+ #if defined(CONFIG_CMD_IMI)
+ static int image_info(unsigned long addr);
+ #endif
+@@ -37,6 +40,10 @@ extern flash_info_t flash_info[]; /* info for FLASH chips */
+ static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+ #endif
+
++#ifdef CONFIG_CMD_USB
++#include
++#endif
++
+ /* we overload the cmd field with our state machine info instead of a
+ * function pointer */
+ static cmd_tbl_t cmd_bootm_sub[] = {
+@@ -85,12 +92,66 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
+ return ret;
+ }
+
++#if defined(CONFIG_TARGET_SS928V100) || defined(CONFIG_TARGET_SS927V100)
++extern int is_tee_enable_otp(void);
++int tee_start_flow_enable(void)
++{
++ char *bootargs = NULL;
++
++ bootargs = env_get("bootargs");
++ if (((bootargs == NULL)) || (strstr(bootargs ,TEE_ENABLE) == NULL))
++ return 0;
++
++ if (!is_tee_enable_otp()) {
++ printf("tee distable int otp\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++#endif
++
+ /*******************************************************************/
+ /* bootm - boot application image from image in memory */
+ /*******************************************************************/
+
+ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ {
++#ifdef CONFIG_CMD_USB
++ usb_stop();
++#endif
++
++#if CONFIG_IS_ENABLED(CMD_TIMESTAMP)
++ timestamp_mark("load_kernel_start", __LINE__);
++#endif
++
++#if defined(CONFIG_TARGET_SS928V100) || defined(CONFIG_TARGET_SS927V100)
++ extern int load_fip_secure_os(char *common_os, char *secure_os);
++ extern long long kernel_load_addr;
++ if (0 != tee_start_flow_enable()) {
++ char *common_os = (char *)(uintptr_t)simple_strtoul(argv[1], NULL, 16);
++ char *secure_os = (char *)(uintptr_t)simple_strtoul(argv[2], NULL, 16);
++ kernel_load_addr = CONFIG_KERNEL_LOAD_ADDR;
++ return load_fip_secure_os(common_os, secure_os);
++ }
++#endif
++
++#ifdef CONFIG_ARM64_SUPPORT_LOAD_FIP
++ extern int is_fip(const char *buf);
++ extern int load_fip(char *buf);
++ extern int load_fip_amp(char *buf);
++ extern long long kernel_load_addr;
++ if (argc == 2) {
++ char *buf = (char *)(uintptr_t)simple_strtoul(argv[1], NULL, 16);
++ /* Modify this configuration according to the system framework */
++ kernel_load_addr = CONFIG_KERNEL_LOAD_ADDR;
++ if (is_fip(buf)) {
++ return load_fip(buf);
++ }
++ }
++#endif
++
+ #ifdef CONFIG_NEEDS_MANUAL_RELOC
+ static int relocated = 0;
+
+@@ -123,6 +184,10 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ return do_bootm_subcommand(cmdtp, flag, argc, argv);
+ }
+
++#if CONFIG_IS_ENABLED(CMD_TIMESTAMP)
++ timestamp_mark("load_kernel_end", __LINE__);
++#endif
++
+ return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
+ BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
+ BOOTM_STATE_LOADOS |
+diff --git a/cmd/cmd_ao.c b/cmd/cmd_ao.c
+new file mode 100644
+index 0000000..3ebb150
+--- /dev/null
++++ b/cmd/cmd_ao.c
+@@ -0,0 +1,145 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++#include
++#include
++
++#include "audio_ao.h"
++#include "acodec.h"
++#include "amp.h"
++#include "ao.h"
++
++#define CMD_AO_ARGS_BASE10 10
++#define CMD_AO_ARGS_BASE16 16
++
++audio_sample_rate g_sample_rate_list[] = {
++ AUDIO_SAMPLE_RATE_8000,
++ AUDIO_SAMPLE_RATE_11025,
++ AUDIO_SAMPLE_RATE_12000,
++ AUDIO_SAMPLE_RATE_16000,
++ AUDIO_SAMPLE_RATE_22050,
++ AUDIO_SAMPLE_RATE_24000,
++ AUDIO_SAMPLE_RATE_32000,
++ AUDIO_SAMPLE_RATE_44100,
++ AUDIO_SAMPLE_RATE_48000
++};
++
++int ao_check_param(unsigned int addr, unsigned int size, audio_sample_rate sample_rate, unsigned int chn_cnt,
++ int vol)
++{
++ unsigned int rate_flag = 0;
++ unsigned int i;
++
++ if (addr % 32) { /* 32: align */
++ printf("[Error] Invalid addr parameter:0x%0x, address should be aligned by 32Byte!\n", addr);
++ return -1;
++ }
++
++ if (size % 32) { /* 32: align */
++ printf("[Warning] Invalid size parameter:0x%0x, size should be aligned by 32Byte!\n", size);
++ return -1;
++ }
++
++ if (size == 0) {
++ printf("[Warning] Invalid size parameter:0x%0x, size should be greater than 0!\n", size);
++ return -1;
++ }
++
++ for (i = 0; i < sizeof(g_sample_rate_list) / sizeof(g_sample_rate_list[0]); i++) {
++ if (sample_rate == g_sample_rate_list[i]) {
++ rate_flag = 1;
++ break;
++ }
++ }
++
++ if (rate_flag == 0) {
++ printf("[Warning] Invalid samplerate parameter.\n");
++ return -1;
++ }
++
++ if (vol > 6 || vol < 0) { /* 6: max vol */
++ printf("[Warning] Invalid volume parameter, range:[0, 6]dB!\n");
++ return -1;
++ }
++
++ if ((chn_cnt == 0) || (chn_cnt > 2)) { /* 2: max chn */
++ printf("[Warning] Invalid channelnum parameter, range:[1, 2].\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++int do_startao(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++ unsigned int addr, size;
++ int vol;
++
++ audio_sample_rate sample_rate;
++ unsigned int chn_cnt;
++
++ if (argc < 6) { /* 6: param num */
++ printf("Insufficient parameter!\n");
++ printf("Usage:\n%s\n", cmdtp->usage);
++ return -1;
++ }
++
++ addr = (unsigned int)simple_strtoul(argv[1], NULL, CMD_AO_ARGS_BASE16);
++ size = (unsigned int)simple_strtoul(argv[2], NULL, CMD_AO_ARGS_BASE16); /* 2th arg */
++ sample_rate = (unsigned int)simple_strtoul(argv[3], NULL, CMD_AO_ARGS_BASE10); /* 3th arg */
++ chn_cnt = (unsigned int)simple_strtoul(argv[4], NULL, CMD_AO_ARGS_BASE10); /* 4th arg */
++ vol = (int)simple_strtol(argv[5], NULL, CMD_AO_ARGS_BASE10); /* 5th arg */
++ if (ao_check_param(addr, size, sample_rate, chn_cnt, vol) != 0) {
++ return -1;
++ }
++
++ acodec_device_init();
++ acodec_i2s_set(sample_rate);
++ udelay(100 * 1000); /* 100 * 1000 us */
++ start_ao(addr, size, sample_rate, chn_cnt, vol);
++ amp_unmute();
++
++ printf("ao dev start ok!\n");
++ return 0;
++}
++
++int do_stopao(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++ amp_mute();
++ stop_ao();
++
++ printf("ao dev closed!\n");
++ return 0;
++}
++
++U_BOOT_CMD(
++ startao, 10, 1, do_startao,
++ "startao - open interface of ao device.\n"
++ "\t- startao [addr size samplerate channelnum volume]",
++ "\nargs: [addr size samplerate channelnum volume]\n"
++ "\t- : address of raw audio data,align by 32Byte\n"
++ "\t-: size of raw audio data,align by 32Byte\n"
++ "\t-: sample rate of raw audio data\n"
++ "\t-: channel number of raw audio data\n"
++ "\t-: audio output volume default:0dB, range:0 ~ 6dB\n");
++
++U_BOOT_CMD(
++ stopao, 1, 0, do_stopao,
++ "stopao - close interface of ao device.\n",
++ "");
+diff --git a/cmd/cmd_cycle.c b/cmd/cmd_cycle.c
+new file mode 100644
+index 0000000..7dcd3ce
+--- /dev/null
++++ b/cmd/cmd_cycle.c
+@@ -0,0 +1,251 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2025 HiSilicon (Shanghai) Technologies Co., Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see
++ * .
++ */
++
++/*
++ * Command for compress.
++ */
++
++#include
++#include
++#include
++#include
++
++#define CYCLE_MAGIC_HEAD 0x6379636c
++
++#define CYCLE_MAGIC_ITEM_START 0x63796373
++
++#define CYCLE_MAGIC_ITEM_END 0x63796365
++
++/** Cycle Head Infomation */
++typedef struct cycle_head_s {
++ unsigned int u32magichead;
++ unsigned int u32cycleflashsize; /* "fmt, __FUNCTION__, __LINE__, ##args)
++#define cycle_dbg(fmt, args...) printf("DBG: <%s:%d> "fmt, __FUNCTION__, __LINE__, ##args)
++
++static int cycle_get_initdata(unsigned long ulsrc, unsigned int u32srclen,
++ cycle_item_start_s **ppstItem,
++ unsigned int *pu32compress)
++{
++ cycle_head_s *psthead = NULL;
++ cycle_item_start_s *pstitem = NULL;
++ unsigned int u32itemmagicend;
++ unsigned long ulbuffer = ulsrc;
++
++ /* Cycle Head */
++ psthead = (cycle_head_s *)ulsrc;
++
++ if ((psthead->u32magichead != CYCLE_MAGIC_HEAD) ||
++ (psthead->u32cycleflashsize > u32srclen) ||
++ (psthead->u32alignsize == 0)) {
++ cycle_err("psthead->u32magichead: %#x\n", psthead->u32magichead);
++ cycle_err("SrcLen[%u] CycleFlashSize[%u]\n", u32srclen,
++ psthead->u32cycleflashsize);
++ return -1;
++ }
++
++ /* Compress Type */
++ *pu32compress = psthead->u32compress;
++ cycle_dbg("Compress[%u]\n", *pu32compress);
++
++ /* First Item */
++ ulbuffer += sizeof(cycle_head_s);
++ ulbuffer = (ulbuffer + psthead->u32alignsize - 1) &
++ ~(psthead->u32alignsize - 1);
++
++ pstitem = (cycle_item_start_s *)ulbuffer;
++ if ((pstitem->u32itemlen == 0) ||
++ ((pstitem->u32itemlen % BYTE_ALIGN) != 0)) {
++ cycle_err("pstitem->u32itemlen: %#x\n", pstitem->u32itemlen);
++ return -1;
++ }
++
++ u32itemmagicend = *(unsigned int *)(uintptr_t)(ulbuffer +
++ (pstitem->u32itemlen + sizeof(cycle_item_start_s)));
++ if ((pstitem->u32magicitemstart != CYCLE_MAGIC_ITEM_START) ||
++ (pstitem->u32itemalllen >= (psthead->u32cycleflashsize / DIVIDE)) ||
++ (u32itemmagicend != CYCLE_MAGIC_ITEM_END)) {
++ cycle_err("Item MagicStart[%#x] Len[%u] MagicEnd[%#x] CycleFlashSize[%u]\n",
++ pstitem->u32magicitemstart, pstitem->u32itemlen, u32itemmagicend,
++ psthead->u32cycleflashsize);
++ return -1;
++ }
++
++ while (1) {
++ /* update item to last valid one */
++ *ppstItem = (cycle_item_start_s *)ulbuffer;
++
++ /* check next item valid or not */
++ ulbuffer += pstitem->u32itemalllen;
++
++ pstitem = (cycle_item_start_s *)ulbuffer;
++
++ /* = psthead->u32cycleflashsize)
++ return 0;
++
++ if (pstitem->u32magicitemstart != CYCLE_MAGIC_ITEM_START) {
++ /* u32magicitemstart == 0xffffffff) {
++ return 0;
++ } else {
++ cycle_err(
++ "pstitem->u32magicitemstart(0x%x) wrong!\n",
++ pstitem->u32magicitemstart);
++ return -1;
++ }
++ }
++
++ u32itemmagicend = *(unsigned int *)(uintptr_t)(ulbuffer +
++ (pstitem->u32itemlen + sizeof(cycle_item_start_s)));
++ /* - u32itemlen >= (psthead->u32cycleflashsize / DIVIDE)) ||
++ (u32itemmagicend != CYCLE_MAGIC_ITEM_END)) {
++ cycle_err("\n");
++ return -1;
++ }
++ }
++
++ return -1;
++}
++
++static int cycle_get_data(unsigned long ulsrc, unsigned int u32srclen, unsigned long uldst)
++{
++ int s32ret;
++
++ cycle_item_start_s *pstitem = NULL;
++ unsigned long ulitemdata = 0;
++ unsigned int ncompressed = 0;
++
++ s32ret = cycle_get_initdata(ulsrc, u32srclen, &pstitem, &ncompressed);
++ if ((s32ret == 0) && pstitem) {
++ ulitemdata += (uintptr_t)pstitem + sizeof(cycle_item_start_s);
++
++ if (ncompressed) {
++ hw_dec_type = 0; /**