Update the initial BPI-F3 codes from Vendor
authorJaehoon Chung <jh80.chung@samsung.com>
Thu, 18 Jul 2024 09:12:39 +0000 (18:12 +0900)
committerJaehoon Chung <jh80.chung@samsung.com>
Tue, 23 Jul 2024 08:53:38 +0000 (17:53 +0900)
Update the initial BPI-F3 codes from vendor.
- URL  https://github.com/BPI-SINOVOIP/pi-u-boot -b v2022.10-k1

Change-Id: I8e65d6c181c93fd2d7ca076bb6c853d2c8759ce6
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
327 files changed:
Makefile
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/cpu/start.S
arch/riscv/cpu/u-boot-spl.lds
arch/riscv/cpu/x60/Kconfig [new file with mode: 0644]
arch/riscv/cpu/x60/Makefile [new file with mode: 0644]
arch/riscv/cpu/x60/cache.c [new file with mode: 0644]
arch/riscv/cpu/x60/cpu.c [new file with mode: 0644]
arch/riscv/cpu/x60/dram.c [new file with mode: 0644]
arch/riscv/dts/Makefile
arch/riscv/dts/k1-x.dtsi [new file with mode: 0644]
arch/riscv/dts/k1-x_MINI-PC.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_MUSE-N1.dts [new file with mode: 0755]
arch/riscv/dts/k1-x_MUSE-Pi.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_deb1.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_deb2.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_evb.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_hs450.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_kx312.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_mingo.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_pinctrl.dtsi [new file with mode: 0644]
arch/riscv/dts/k1-x_pm853.dtsi [new file with mode: 0644]
arch/riscv/dts/k1-x_spl.dts [new file with mode: 0644]
arch/riscv/dts/k1-x_spm8821.dtsi [new file with mode: 0644]
arch/riscv/include/asm/arch-x60/ddr.h [new file with mode: 0644]
arch/riscv/include/asm/arch-x60/gpio.h [new file with mode: 0644]
arch/riscv/include/asm/atomic.h [new file with mode: 0644]
arch/riscv/include/asm/bitops.h
arch/riscv/include/asm/cache.h
arch/riscv/include/asm/system.h
arch/riscv/lib/bootm.c
arch/riscv/lib/cache.c
arch/riscv/lib/fdt_fixup.c
arch/riscv/lib/interrupts.c
arch/riscv/lib/reset.c
board/spacemit/k1-x/Kconfig [new file with mode: 0644]
board/spacemit/k1-x/Makefile [new file with mode: 0644]
board/spacemit/k1-x/config.mk [new file with mode: 0644]
board/spacemit/k1-x/configs/bootinfo_emmc.json [new file with mode: 0755]
board/spacemit/k1-x/configs/bootinfo_sd.json [new file with mode: 0755]
board/spacemit/k1-x/configs/bootinfo_spinand.json [new file with mode: 0755]
board/spacemit/k1-x/configs/bootinfo_spinor.json [new file with mode: 0755]
board/spacemit/k1-x/configs/fsbl.json [new file with mode: 0755]
board/spacemit/k1-x/configs/uboot_fdt.its [new file with mode: 0644]
board/spacemit/k1-x/k1-x.env [new file with mode: 0644]
board/spacemit/k1-x/k1x-i2c-eeprom.c [new file with mode: 0644]
board/spacemit/k1-x/k1x.c [new file with mode: 0644]
board/spacemit/k1-x/spl.c [new file with mode: 0644]
board/spacemit/k1-x/splash.c [new file with mode: 0644]
boot/Kconfig
cmd/Kconfig
cmd/Makefile
cmd/bootmenu.c
cmd/jffs2.c
cmd/mtd.c
cmd/nvedit.c
cmd/spacemit_flash.c [new file with mode: 0644]
common/Kconfig
common/Makefile
common/board_f.c
common/board_r.c
common/cli.c
common/cli_readline.c
common/command.c
common/console.c
common/dlmalloc.c
common/fdt_support.c
common/hash.c
common/menu.c
common/spl/Kconfig
common/spl/Makefile
common/spl/spl.c
common/spl/spl_fastboot.c [new file with mode: 0644]
common/spl/spl_fit.c
common/spl/spl_mmc.c
common/spl/spl_mtd.c [new file with mode: 0644]
common/spl/spl_opensbi.c
common/spl/spl_ram.c
common/splash.c
common/splash_source.c
common/usb.c
configs/k1-x_fpga_1x4_defconfig [new file with mode: 0644]
configs/k1-x_fpga_2x2_defconfig [new file with mode: 0644]
configs/k1-x_fpga_defconfig [new file with mode: 0644]
configs/k1_defconfig [new file with mode: 0644]
debian/.gitignore [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/env_k1-x.txt [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/source/format [new file with mode: 0644]
debian/u-boot-spacemit.install [new file with mode: 0644]
debian/u-boot-spacemit.postinst [new file with mode: 0755]
disk/Kconfig
disk/part.c
disk/part_dos.c
disk/part_efi.c
drivers/Makefile
drivers/block/blk-uclass.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-uclass.c
drivers/clk/spacemit/Kconfig [new file with mode: 0644]
drivers/clk/spacemit/Makefile [new file with mode: 0644]
drivers/clk/spacemit/ccu-k1x.c [new file with mode: 0644]
drivers/clk/spacemit/ccu-k1x.h [new file with mode: 0644]
drivers/clk/spacemit/ccu_ddn.c [new file with mode: 0644]
drivers/clk/spacemit/ccu_ddn.h [new file with mode: 0644]
drivers/clk/spacemit/ccu_mix.c [new file with mode: 0644]
drivers/clk/spacemit/ccu_mix.h [new file with mode: 0644]
drivers/clk/spacemit/ccu_pll.c [new file with mode: 0644]
drivers/clk/spacemit/ccu_pll.h [new file with mode: 0644]
drivers/core/Makefile
drivers/ddr/Kconfig
drivers/ddr/spacemit/k1x/Makefile [new file with mode: 0644]
drivers/ddr/spacemit/k1x/ddr_freq.c [new file with mode: 0644]
drivers/ddr/spacemit/k1x/ddr_freq.h [new file with mode: 0644]
drivers/ddr/spacemit/k1x/ddr_init.c [new file with mode: 0644]
drivers/ddr/spacemit/k1x/ddr_init_asic.h [new file with mode: 0644]
drivers/ddr/spacemit/k1x/ddr_init_fpga.h [new file with mode: 0644]
drivers/ddr/spacemit/k1x/lpddr4_silicon_init.c [new file with mode: 0644]
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/axi-dma.c [new file with mode: 0644]
drivers/dma/axi-dma.h [new file with mode: 0644]
drivers/fastboot/Kconfig
drivers/fastboot/Makefile
drivers/fastboot/fb_blk.c [new file with mode: 0644]
drivers/fastboot/fb_command.c
drivers/fastboot/fb_common.c
drivers/fastboot/fb_getvar.c
drivers/fastboot/fb_mmc.c
drivers/fastboot/fb_mtd.c [new file with mode: 0644]
drivers/fastboot/fb_nand.c
drivers/fastboot/fb_spacemit.c [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/k1x_gpio.c [new file with mode: 0644]
drivers/gpio/k1x_gpio.h [new file with mode: 0644]
drivers/i2c/Kconfig
drivers/i2c/Makefile
drivers/i2c/designware_i2c.c
drivers/i2c/designware_i2c_pci.c
drivers/i2c/i2c_core.c
drivers/i2c/spacemit_i2c.c [new file with mode: 0644]
drivers/i2c/spacemit_i2c.h [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/mcp4725.c [new file with mode: 0644]
drivers/misc/spacemit-onboard-hub.c [new file with mode: 0644]
drivers/misc/spacemit_k1x_efuse.c [new file with mode: 0644]
drivers/mmc/Kconfig
drivers/mmc/Makefile
drivers/mmc/k1x_sdhci.c [new file with mode: 0644]
drivers/mmc/mmc-uclass.c
drivers/mmc/mmc.c
drivers/mmc/sdhci.c
drivers/mmc/spacemit_sdhci.c [new file with mode: 0644]
drivers/mtd/Makefile
drivers/mtd/cfi_flash.c
drivers/mtd/mtd_uboot.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Makefile
drivers/mtd/nand/spi/Makefile
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/other.c [new file with mode: 0644]
drivers/mtd/spi/Kconfig
drivers/mtd/spi/Makefile
drivers/mtd/spi/sf_mtd.c
drivers/mtd/spi/sf_probe.c
drivers/mtd/spi/spi-nor-blk.c [new file with mode: 0644]
drivers/mtd/spi/spi-nor-ids.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/designware.c
drivers/net/designware.h
drivers/net/dwc_eth_qos.c
drivers/net/dwc_eth_qos.h
drivers/net/dwc_eth_qos_spacemit.c [new file with mode: 0644]
drivers/net/spacemit/Kconfig [new file with mode: 0644]
drivers/net/spacemit/Makefile [new file with mode: 0644]
drivers/net/spacemit/k1x_emac.c [new file with mode: 0644]
drivers/net/spacemit/k1x_emac.h [new file with mode: 0644]
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/pcie_dw_k1x.c [new file with mode: 0644]
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/spacemit/Kconfig [new file with mode: 0644]
drivers/phy/spacemit/Makefile [new file with mode: 0644]
drivers/phy/spacemit/k1x-combphy.c [new file with mode: 0644]
drivers/phy/spacemit/k1x-usb2-ci-phy.c [new file with mode: 0644]
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/spacemit/Kconfig [new file with mode: 0644]
drivers/pinctrl/spacemit/Makefile [new file with mode: 0644]
drivers/pinctrl/spacemit/pinctrl-spacemit.c [new file with mode: 0644]
drivers/pinctrl/spacemit/pinctrl-spacemit.h [new file with mode: 0644]
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/domain/Kconfig
drivers/power/domain/Makefile
drivers/power/domain/k1x-power-domain.c [new file with mode: 0644]
drivers/power/pmic/Kconfig
drivers/power/pmic/Makefile
drivers/power/pmic/spacemit_pmic.c [new file with mode: 0644]
drivers/power/power_spm8xx.c [new file with mode: 0644]
drivers/power/regulator/Kconfig
drivers/power/regulator/Makefile
drivers/power/regulator/regulator-uclass.c
drivers/power/regulator/spacemit-hub-regulator.c [new file with mode: 0644]
drivers/power/regulator/spacemit_regulator.c [new file with mode: 0644]
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/reset-spacemit-k1x.c [new file with mode: 0644]
drivers/serial/Kconfig
drivers/serial/ns16550.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/designware_spi.c
drivers/spi/k1x_qspi.c [new file with mode: 0644]
drivers/sysreset/Kconfig
drivers/sysreset/Makefile
drivers/sysreset/sysreset_spacemit.c [new file with mode: 0644]
drivers/timer/sifive_clint_timer.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-generic.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/dwc2_udc_otg.c
drivers/usb/gadget/dwc2_udc_otg_phy.c
drivers/usb/gadget/f_fastboot.c
drivers/usb/gadget/f_sdp.c
drivers/usb/gadget/g_dnl.c
drivers/usb/gadget/k1x_usb2_ci.c [new file with mode: 0644]
drivers/usb/gadget/k1x_usb2_ci.h [new file with mode: 0644]
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/dwc2.c
drivers/usb/host/dwc2.h
drivers/usb/host/ehci-k1x-ci.c [new file with mode: 0644]
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/console_truetype.c
drivers/video/dw_hdmi.c
drivers/video/spacemit/Kconfig [new file with mode: 0644]
drivers/video/spacemit/Makefile [new file with mode: 0644]
drivers/video/spacemit/dsi/Makefile [new file with mode: 0644]
drivers/video/spacemit/dsi/drv/spacemit_dphy.c [new file with mode: 0644]
drivers/video/spacemit/dsi/drv/spacemit_dphy.h [new file with mode: 0644]
drivers/video/spacemit/dsi/drv/spacemit_dsi_common.c [new file with mode: 0644]
drivers/video/spacemit/dsi/drv/spacemit_dsi_drv.c [new file with mode: 0644]
drivers/video/spacemit/dsi/drv/spacemit_dsi_drv.h [new file with mode: 0644]
drivers/video/spacemit/dsi/drv/spacemit_dsi_hw.h [new file with mode: 0644]
drivers/video/spacemit/dsi/include/spacemit_dsi_common.h [new file with mode: 0644]
drivers/video/spacemit/dsi/include/spacemit_video_tx.h [new file with mode: 0644]
drivers/video/spacemit/dsi/video/lcd/lcd_gx09inx101.c [new file with mode: 0644]
drivers/video/spacemit/dsi/video/lcd/lcd_icnl9911c.c [new file with mode: 0644]
drivers/video/spacemit/dsi/video/spacemit_mipi_port.c [new file with mode: 0644]
drivers/video/spacemit/dsi/video/spacemit_video_tx.c [new file with mode: 0644]
drivers/video/spacemit/spacemit_dpu.c [new file with mode: 0644]
drivers/video/spacemit/spacemit_dpu.h [new file with mode: 0644]
drivers/video/spacemit/spacemit_hdmi.c [new file with mode: 0644]
drivers/video/spacemit/spacemit_hdmi.h [new file with mode: 0644]
drivers/video/spacemit/spacemit_mipi.c [new file with mode: 0644]
drivers/video/spacemit/spacemit_mipi.h [new file with mode: 0644]
drivers/video/u_boot_logo.bmp
drivers/video/vidconsole-uclass.c
drivers/video/video-uclass.c
env/Kconfig
env/Makefile
env/attr.c
env/common.c
env/env.c
env/flags.c
env/mmc.c
env/mtd.c [new file with mode: 0644]
env/sf.c
fs/jffs2/Kconfig
fs/jffs2/jffs2_1pass.c
fs/jffs2/jffs2_private.h
fs/jffs2/stat.h [new file with mode: 0644]
include/asm-generic/global_data.h
include/blk.h
include/cJSON.h [new file with mode: 0644]
include/clk.h
include/command.h
include/configs/k1-x.h [new file with mode: 0644]
include/cpu_func.h
include/dt-bindings/clock/spacemit-k1x-clock.h [new file with mode: 0644]
include/dt-bindings/pinctrl/k1-x-pinctrl.h [new file with mode: 0644]
include/dt-bindings/power-domain/k1x-pmu.h [new file with mode: 0644]
include/dt-bindings/reset/reset-spacemit-k1x.h [new file with mode: 0644]
include/dt-bindings/soc/spacemit-k1x.h [new file with mode: 0644]
include/efi_api.h
include/env_default.h
include/env_internal.h
include/fastboot.h
include/fb_blk.h [new file with mode: 0644]
include/fb_mmc.h
include/fb_mtd.h [new file with mode: 0644]
include/fb_spacemit.h [new file with mode: 0644]
include/image-sparse.h
include/linux/mtd/spinand.h
include/linux/printk.h
include/log.h
include/part.h
include/power/spacemit/pm853.h [new file with mode: 0644]
include/power/spacemit/spacemit_pmic.h [new file with mode: 0644]
include/power/spacemit/spm8821.h [new file with mode: 0644]
include/power/spacemit/sy8810l.h [new file with mode: 0644]
include/splash.h
lib/Kconfig
lib/Makefile
lib/cJSON.c [new file with mode: 0644]
lib/efi_loader/efi_device_path.c
lib/image-sparse.c
lib/zstd/zstd.c
scripts/Makefile.lib
test/dm/clk.c
tools/common_decorator.py [new file with mode: 0755]
tools/logos/bianbu.bmp [new file with mode: 0644]
tools/logos/k1-x.bmp [new file with mode: 0644]

index 50077027ba72b9aebfd5fe1f4212c59af3c416ff..bad77c2be7e9f4585ae72e1601ec1ec2f9a1f274 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -798,6 +798,10 @@ include scripts/Makefile.extrawarn
 KBUILD_CPPFLAGS += $(KCPPFLAGS)
 KBUILD_AFLAGS += $(KAFLAGS)
 KBUILD_CFLAGS += $(KCFLAGS)
+KBUILD_CFLAGS += $(call cc-option, -Werror)
+
+KBUILD_LDFLAGS  += -z noexecstack
+KBUILD_LDFLAGS  += $(call ld-option,--no-warn-rwx-segments)
 
 KBUILD_HOSTCFLAGS += $(if $(CONFIG_TOOLS_DEBUG),-g)
 
index 78e964db129a251aa9acb0ced000b74bb1ce93a8..58d3e3075f3221cf6ae73056d5327ac47315965a 100644 (file)
@@ -31,8 +31,24 @@ config TARGET_SIPEED_MAIX
 config TARGET_OPENPITON_RISCV64
        bool "Support RISC-V cores on OpenPiton SoC"
 
+config TARGET_SPACEMIT_K1PRO
+       bool "Support Spacemit K1-Pro SoC"
+       select SYS_CACHE_SHIFT_6
+
+config TARGET_SPACEMIT_K1X
+       bool "Support Spacemit K1-X SoC"
+       select SYS_CACHE_SHIFT_6
+
 endchoice
 
+config NOT_RELOC_TEXT_SECTION
+       bool "Don't relocate text section for u-boot debug!!!"
+       depends on TARGET_SPACEMIT_K1PRO || TARGET_SPACEMIT_K1X
+       default n
+       help
+         Attention: this feture is just used for u-boot debug,
+         it will make fatal error when boot kernel.
+
 config SYS_ICACHE_OFF
        bool "Do not enable icache"
        help
@@ -45,6 +61,30 @@ config SPL_SYS_ICACHE_OFF
        help
          Do not enable instruction cache in SPL.
 
+config SYS_BRANCH_PREDICT_OFF
+       bool "Do not enable branch predict"
+       help
+         Do not enable instruction branch predict in U-Boot.
+
+config SPL_SYS_BRANCH_PREDICT_OFF
+       bool "Do not enable branch predict in SPL"
+       depends on SPL
+       default SYS_BRANCH_PREDICT_OFF
+       help
+         Do not enable instruction branch predict in SPL.
+
+config SYS_PREFETCH_OFF
+       bool "Do not enable prefetch"
+       help
+         Do not enable instruction prefetch in U-Boot.
+
+config SPL_SYS_PREFETCH_OFF
+       bool "Do not enable prefetch in SPL"
+       depends on SPL
+       default SYS_PREFETCH_OFF
+       help
+         Do not enable instruction prefetch in SPL.
+
 config SYS_DCACHE_OFF
        bool "Do not enable dcache"
        help
@@ -65,12 +105,14 @@ source "board/sifive/unleashed/Kconfig"
 source "board/sifive/unmatched/Kconfig"
 source "board/openpiton/riscv64/Kconfig"
 source "board/sipeed/maix/Kconfig"
+source "board/spacemit/k1-x/Kconfig"
 
 # platform-specific options below
 source "arch/riscv/cpu/ax25/Kconfig"
 source "arch/riscv/cpu/fu540/Kconfig"
 source "arch/riscv/cpu/fu740/Kconfig"
 source "arch/riscv/cpu/generic/Kconfig"
+source "arch/riscv/cpu/x60/Kconfig"
 
 # architecture-specific options below
 
@@ -155,6 +197,30 @@ config RISCV_ISA_C
 config RISCV_ISA_A
        def_bool y
 
+config RISCV_ISA_DOUBLE_FLOAT
+       bool "double-precision floating-point instruction"
+       default y
+       help
+         Choose this option to turn on double-precision floating-point support.
+
+config RISCV_ISA_ZICBOM
+       bool "Zicbom extension support for non-coherent DMA operation"
+       default y
+       help
+          Adds support to dynamically detect the presence of the ZICBOM
+          extension (Cache Block Management Operations) and enable its
+          usage.
+
+          The Zicbom extension can be used to handle for example
+          non-coherent DMA support on devices that need it.
+
+          If you don't know what to do here, say Y.
+
+config RISCV_CBOM_BLOCK_SIZE
+       int
+       depends on RISCV_ISA_ZICBOM
+       default SYS_CACHELINE_SIZE
+
 config 32BIT
        bool
 
index 0b80eb8d864582fb67babd325dc793fe164eed68..40783cc2de762240708796d112fb5106c64da4bc 100644 (file)
@@ -17,6 +17,12 @@ endif
 ifeq ($(CONFIG_RISCV_ISA_C),y)
        ARCH_C = c
 endif
+ifeq ($(CONFIG_RISCV_ISA_DOUBLE_FLOAT),y)
+       ARCH_F = fd
+endif
+ifeq ($(CONFIG_RISCV_ISA_ZICBOM),y)
+       ARCH_EXTENTION = _zicbom
+endif
 ifeq ($(CONFIG_CMODEL_MEDLOW),y)
        CMODEL = medlow
 endif
@@ -24,8 +30,12 @@ ifeq ($(CONFIG_CMODEL_MEDANY),y)
        CMODEL = medany
 endif
 
-ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_C) -mabi=$(ABI) \
-            -mcmodel=$(CMODEL)
+ifeq ($(CONFIG_SPACEMIT_X60),y)
+       SPACEMIT_X60_EXTENTION = _zba_zbb_zbc_zbs_zicsr_zifencei
+endif
+
+ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_C)$(ARCH_EXTENTION)$(SPACEMIT_X60_EXTENTION) -mabi=$(ABI) \
+               -mcmodel=$(CMODEL)
 
 PLATFORM_CPPFLAGS      += $(ARCH_FLAGS)
 CFLAGS_EFI             += $(ARCH_FLAGS)
index b7f21ab63e00cbd117def75ca5a122a2e67fccd2..dd1cf7d5170a8e4f052f045a7e8228ebd7f73f48 100644 (file)
@@ -41,6 +41,12 @@ secondary_harts_relocation_error:
 .globl _start
 _start:
 #if CONFIG_IS_ENABLED(RISCV_MMODE)
+#ifdef CONFIG_RISCV_ISA_DOUBLE_FLOAT
+       csrr    a0, CSR_MSTATUS
+       li              t0, 3<<13
+       xor             a0, a0, t0
+       csrw    CSR_MSTATUS, a0
+#endif
        csrr    a0, CSR_MHARTID
 #endif
 
@@ -189,6 +195,10 @@ wait_for_gd_init:
        jal     icache_enable
        jal     dcache_enable
 
+       /* Enable prefetch and branch predict*/
+       jal branch_predict_enable
+       jal prefetch_enable
+
 #ifdef CONFIG_DEBUG_UART
        jal     debug_uart_init
 #endif
index 993536302a2756d7f221a5f2278a59a09e4fdbfa..6f5a3b62ba981b6c4ed9cf9d633f6e3bd6cd906b 100644 (file)
@@ -28,7 +28,9 @@ SECTIONS
 
        . = ALIGN(4);
        .data : {
+               __data_start = .;
                *(.data*)
+               __data_end = .;
        } > .spl_mem
        . = ALIGN(4);
 
diff --git a/arch/riscv/cpu/x60/Kconfig b/arch/riscv/cpu/x60/Kconfig
new file mode 100644 (file)
index 0000000..f900cc2
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2023 Spacemit, Inc
+
+config SPACEMIT_X60
+       bool
+       select SUPPORT_SPL
+       select RAM
+       select SPL_RAM if SPL
+       select ARCH_EARLY_INIT_R
+       imply CPU
+       imply CPU_RISCV
+       imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
+       imply SIFIVE_CLINT if RISCV_MMODE
+       imply SPL_SIFIVE_CLINT if SPL_RISCV_MMODE
+       imply CMD_CPU
+       imply SPL_CPU
+       imply SPL_OPENSBI
+       imply SPL_LOAD_FIT
diff --git a/arch/riscv/cpu/x60/Makefile b/arch/riscv/cpu/x60/Makefile
new file mode 100644 (file)
index 0000000..c3959a2
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2023 Spacemit, Inc
+
+obj-y += cpu.o
+obj-y += cache.o
+obj-y += dram.o
diff --git a/arch/riscv/cpu/x60/cache.c b/arch/riscv/cpu/x60/cache.c
new file mode 100644 (file)
index 0000000..c6836ed
--- /dev/null
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <asm/cache.h>
+#include <cache.h>
+#include <asm/csr.h>
+
+void icache_enable(void)
+{
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       asm volatile("csrsi 0x7c0, 0x2 \n\t");
+#endif
+#endif
+}
+
+void icache_disable(void)
+{
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       asm volatile("csrci 0x7c0, 0x2 \n\t");
+#endif
+#endif
+}
+
+int icache_status(void)
+{
+       int ret = 0;
+
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
+       /* 
+         if the I$ is enabled by configuration, 
+         set icache is enabled as default, it will be
+         updated with csr:0x7c0 if it can be accessed
+       */
+       ret = 1;
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       asm volatile (
+               "csrr t1, 0x7c0\n\t"
+               "andi   %0, t1, 0x02\n\t"
+               : "=r" (ret)
+               :
+               : "memory"
+       );
+#endif
+#endif
+
+       return ret;
+}
+
+void dcache_enable(void)
+{
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       asm volatile("csrsi 0x7c0, 0x1 \n\t");
+#endif
+#endif
+}
+
+void dcache_disable(void)
+{
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       asm volatile("csrci 0x7c0, 0x1 \n\t");
+#endif
+#endif
+}
+
+int dcache_status(void)
+{
+       int ret = 0;
+
+#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
+       /* 
+         if the I$ is enabled by configuration, 
+         set icache is enabled as default, it will be
+         updated with csr:0x7c0 if it can be accessed
+       */
+       ret = 1;
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       asm volatile (
+               "csrr t1, 0x7c0\n\t"
+               "andi   %0, t1, 0x01\n\t"
+               : "=r" (ret)
+               :
+               : "memory"
+       );
+#endif
+#endif
+
+       return ret;
+}
+
+
+void branch_predict_enable(void)
+{
+
+#if !CONFIG_IS_ENABLED(SYS_BRANCH_PREDICT_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       csr_set(0x7c0, 0x10);
+#endif
+#endif
+}
+
+void branch_predict_disable(void)
+{
+#if !CONFIG_IS_ENABLED(SYS_BRANCH_PREDICT_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       csr_clear(0x7c0, 0x10);
+#endif
+#endif
+}
+
+void prefetch_enable(void)
+{
+
+#if !CONFIG_IS_ENABLED(SYS_PREFETCH_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       csr_set(0x7c0, 0x20);
+#endif
+#endif
+}
+
+void prefetch_disable(void)
+{
+#if !CONFIG_IS_ENABLED(SYS_PREFETCH_OFF)
+#if CONFIG_SPL_BUILD && CONFIG_SPL_RISCV_MMODE
+       /* csr:0x7c0 can be accessed in MMODE only */
+       csr_clear(0x7c0, 0x20);
+#endif
+#endif
+}
+
+
+
+int check_cache_range(unsigned long start, unsigned long end)
+{
+       int ok = 1;
+
+       if (start & (CONFIG_RISCV_CBOM_BLOCK_SIZE - 1))
+               ok = 0;
+
+       if (end & (CONFIG_RISCV_CBOM_BLOCK_SIZE - 1))
+               ok = 0;
+
+       if (!ok) {
+               warn_non_spl("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
+                       start, end);
+       }
+
+       return ok;
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+       if (!check_cache_range(start, end))
+               return;
+
+       while (start < end) {
+               cbo_invalid(start);
+               start += CONFIG_RISCV_CBOM_BLOCK_SIZE;
+       }
+}
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+       if (!check_cache_range(start, end))
+               return;
+
+       while (start < end) {
+               cbo_flush(start);
+               start += CONFIG_RISCV_CBOM_BLOCK_SIZE;
+       }
+}
+
+void clean_dcache_range(unsigned long start, unsigned long end)
+{
+       if (!check_cache_range(start, end))
+               return;
+
+       while (start < end) {
+               cbo_clean(start);
+               start += CONFIG_RISCV_CBOM_BLOCK_SIZE;
+       }
+}
diff --git a/arch/riscv/cpu/x60/cpu.c b/arch/riscv/cpu/x60/cpu.c
new file mode 100644 (file)
index 0000000..d432517
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <irq_func.h>
+#include <asm/cache.h>
+
+
+/*
+ * cleanup_before_linux() is called just before we call linux
+ * it prepares the processor for linux
+ *
+ * we disable interrupt and caches.
+ */
+int cleanup_before_linux(void)
+{
+       disable_interrupts();
+
+       cache_flush();
+
+       return 0;
+}
+
diff --git a/arch/riscv/cpu/x60/dram.c b/arch/riscv/cpu/x60/dram.c
new file mode 100644 (file)
index 0000000..c8a5db2
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__weak int dram_init(void)
+{
+       return fdtdec_setup_mem_size_base();
+}
+
+__weak int dram_init_banksize(void)
+{
+       return fdtdec_setup_memory_banksize();
+}
+
index 5c15a0f303a1407217f05c529b3ebd0ee8566902..19926479c44ae64621c54fb580bb3223104f58ea 100644 (file)
@@ -7,6 +7,9 @@ dtb-$(CONFIG_TARGET_OPENPITON_RISCV64) += openpiton-riscv64.dtb
 dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb
 dtb-$(CONFIG_TARGET_SIFIVE_UNMATCHED) += hifive-unmatched-a00.dtb
 dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb
+dtb-$(CONFIG_TARGET_SPACEMIT_K1PRO) += k1-pro_qemu.dtb k1-pro_sim.dtb k1-pro_fpga.dtb
+dtb-$(CONFIG_TARGET_SPACEMIT_K1X) += k1-x_evb.dtb k1-x_deb2.dtb k1-x_deb1.dtb k1-x_hs450.dtb \
+                                    k1-x_kx312.dtb k1-x_MINI-PC.dtb k1-x_mingo.dtb k1-x_MUSE-N1.dtb k1-x_MUSE-Pi.dtb k1-x_spl.dtb
 
 include $(srctree)/scripts/Makefile.dts
 
diff --git a/arch/riscv/dts/k1-x.dtsi b/arch/riscv/dts/k1-x.dtsi
new file mode 100644 (file)
index 0000000..87f4d82
--- /dev/null
@@ -0,0 +1,875 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+#include <dt-bindings/reset/reset-spacemit-k1x.h>
+#include <dt-bindings/clock/spacemit-k1x-clock.h>
+#include <dt-bindings/power-domain/k1x-pmu.h>
+#include <dt-bindings/phy/phy.h>
+
+/ {
+       compatible = "spacemit,k1x", "riscv";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               serial0 = &uart0;
+               mmc0 = &sdhci0;
+               mmc1 = &sdhci1;
+               mmc2 = &sdhci2;
+       };
+
+       cpus: cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               timebase-frequency = <10000000>;
+               cpu_0: cpu@0 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <0>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu0_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_1: cpu@1 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <1>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu1_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_2: cpu@2 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <2>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu2_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_3: cpu@3 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <3>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu3_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_4: cpu@4 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <4>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu4_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_5: cpu@5 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <5>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu5_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_6: cpu@6 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <6>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu6_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+               cpu_7: cpu@7 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       reg = <7>;
+                       status = "okay";
+                       riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
+                       mmu-type = "riscv,sv39";
+
+                       cpu7_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+       };
+
+       clocks: clocks {
+               #address-cells = <0x2>;
+               #size-cells = <0x2>;
+               ranges;
+
+               vctcxo_24: vctcxo_24 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <24000000>;
+                       clock-output-names = "vctcxo_24";
+               };
+               vctcxo_3: vctcxo_3 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <3000000>;
+                       clock-output-names = "vctcxo_3";
+               };
+               vctcxo_1: vctcxo_1 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <1000000>;
+                       clock-output-names = "vctcxo_1";
+               };
+               pll1_vco: pll1_vco {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <24576000>;
+                       clock-output-names = "pll1_vco";
+               };
+               clk_32k: clk_32k {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <32000>;
+                       clock-output-names = "clk_32k";
+               };
+               clk_dummy: clk_dummy {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <0>;
+                       clock-output-names = "clk_dummy";
+               };
+       };
+
+       soc:soc {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               clint0: clint@e4000000 {
+                       compatible = "riscv,clint0";
+                       interrupts-extended = <
+                               &cpu0_intc  3 &cpu0_intc  7
+                               &cpu1_intc  3 &cpu1_intc  7
+                               &cpu2_intc  3 &cpu2_intc  7
+                               &cpu3_intc  3 &cpu3_intc  7
+                               &cpu4_intc  3 &cpu4_intc  7
+                               &cpu5_intc  3 &cpu5_intc  7
+                               &cpu6_intc  3 &cpu6_intc  7
+                               &cpu7_intc  3 &cpu7_intc  7
+                       >;
+                       reg = <0x0 0xE4000000 0x0 0x00010000>;
+               };
+
+               ccu: clock-controller@d4050000 {
+                       compatible = "spacemit,k1x-ccu";
+                       reg = <0x0 0xd4050000 0x0 0x209c>,
+                               <0x0 0xd4282800 0x0 0x400>,
+                               <0x0 0xd4015000 0x0 0x1000>,
+                               <0x0 0xd4090000 0x0 0x1000>,
+                               <0x0 0xd4282c00 0x0 0x400>,
+                               <0x0 0xd8440000 0x0 0x98>,
+                               <0x0 0xc0000000 0x0 0x4280>,
+                               <0x0 0xf0610000 0x0 0x20>;
+                       reg-names = "mpmu", "apmu", "apbc", "apbs", "ciu", "dciu", "ddrc", "apbc2";
+                       clocks = <&vctcxo_24>, <&vctcxo_3>, <&vctcxo_1>, <&pll1_vco>,
+                               <&clk_32k>, <&clk_dummy>;
+                       clock-names = "vctcxo_24", "vctcxo_3", "vctcxo_1", "pll1_vco",
+                               "clk_32k", "clk_dummy";
+                       #clock-cells = <1>;
+                       status = "okay";
+               };
+
+               reset: reset-controller@d4050000 {
+                       compatible = "spacemit,k1x-reset";
+                       reg = <0x0 0xd4050000 0x0 0x209c>,
+                               <0x0 0xd4282800 0x0 0x400>,
+                               <0x0 0xd4015000 0x0 0x1000>,
+                               <0x0 0xd4090000 0x0 0x1000>,
+                               <0x0 0xd4282c00 0x0 0x400>,
+                               <0x0 0xd8440000 0x0 0x98>,
+                               <0x0 0xc0000000 0x0 0x4280>,
+                               <0x0 0xf0610000 0x0 0x20>;
+                       reg-names = "mpmu", "apmu", "apbc", "apbs", "ciu", "dciu", "ddrc", "apbc2";
+                       #reset-cells = <1>;
+                       status = "okay";
+               };
+
+               intc: interrupt-controller@e0000000 {
+                       #interrupt-cells = <1>;
+                       compatible = "riscv,plic0";
+                       interrupt-controller;
+                       interrupts-extended = <
+                               &cpu0_intc 11 &cpu0_intc 9
+                               &cpu1_intc 11 &cpu1_intc 9
+                               &cpu2_intc 11 &cpu2_intc 9
+                               &cpu3_intc 11 &cpu3_intc 9
+                               &cpu4_intc 11 &cpu4_intc 9
+                               &cpu5_intc 11 &cpu5_intc 9
+                               &cpu6_intc 11 &cpu6_intc 9
+                               &cpu7_intc 11 &cpu7_intc 9
+                       >;
+                       reg = <0x0 0xE0000000 0x0 0x04000000>;
+                       reg-names = "control";
+                       riscv,max-priority = <7>;
+                       riscv,ndev = <159>;
+               };
+
+               gpio: gpio@d4019000 {
+                       compatible = "spacemit,k1x-gpio";
+                       reg = <0x0 0xd4019000 0x0 0x800>;
+                       gpio-controller;
+                       gpio-count = <128>;
+                       #gpio-cells = <2>;
+                       interrupts = <58>;
+                       clocks = <&ccu CLK_GPIO>;
+                       interrupt-names = "gpio_mux";
+                       interrupt-parent = <&intc>;
+               };
+
+               pinctrl: pinctrl@d401e000 {
+                       compatible = "pinctrl-single";
+                       reg = <0x0 0xd401e000 0x0 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       #pinctrl-cells = <2>;
+                       #gpio-range-cells = <3>;
+
+                       pinctrl-single,register-width = <32>;
+                       pinctrl-single,function-mask = <0xff77>;
+
+                       range: gpio-range {
+                               #pinctrl-single,gpio-range-cells = <3>;
+                       };
+               };
+
+                pmu: power-management@0 {
+                       compatible = "spacemit,k1x-pm-domain";
+                       reg = <0x0 0xd4050000 0x0 0x3004>, <0x0 0xd4282800 0x0 0x400>;
+                       #power-domain-cells = <1>;
+                };
+
+               uart0: uart@d4017000 {
+                       compatible = "ns16550";
+                       reg = <0x00000000 0xD4017000 0x00000000 0x00000100>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clock-frequency = <14000000>;
+               };
+
+               dramc: ddr@c0000000 {
+                       compatible = "spacemit,ddr-ctl";
+                       reg = <0x00000000 0xC0000000 0x00000000 0x00400000>;
+               };
+
+               eth0: ethernet@cac80000 {
+                       compatible = "spacemit,k1x-emac";
+                       reg = <0x00000000 0xCAC80000 0x00000000 0x00000420>;
+                       ctrl-reg = <0x3e4>;
+                       dline-reg = <0x3e8>;
+                       clocks = <&ccu CLK_EMAC0_BUS>;
+                       clock-names = "emac-clk";
+                       resets = <&reset RESET_EMAC0>;
+                       reset-names = "emac-reset";
+                       status = "disabled";
+               };
+
+               udc: udc@c0900100 {
+                       compatible = "spacemit,mv-udc";
+                       reg = <0x0 0xc0900100 0x0 0x4000>;
+                       interrupts = <105>;
+                       interrupt-parent = <&intc>;
+                       status = "disabled";
+               };
+
+               usbphy1: usbphy1@c09c0000 {
+                       compatible = "spacemit,usb2-phy";
+                       reg = <0x0 0xc09c0000 0x0 0x200>;
+                       spacemit,phy-name = "mv-usb-phy";
+                       spacemit,pll-lock-bypass;
+                       clocks = <&ccu CLK_USB_P1>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               ehci1: ehci1@c0980100 {
+                       compatible = "spacemit,mv-ehci";
+                       reg = <0x0 0xc0980100 0x0 0x4000>;
+                       interrupts = <118>;
+                       interrupt-parent = <&intc>;
+                       spacemit,ehci-name = "mv-ehci";
+                       spacemit,otg-force-a-bus-req;
+                       resets = <&reset RESET_USBP1_AXI>;
+                       clocks = <&ccu CLK_USB_P1>;
+                       phys = <&usbphy1>;
+                       status = "disabled";
+               };
+
+               combphy: phy@c0b10000{
+                       compatible = "spacemit,k1x-combphy";
+                       reg = <0x0 0xc0b10000 0x0 0x800>,
+                                 <0x0 0xd4282910 0x0 0x400>;
+                       reg-names = "puphy", "phy_sel";
+                       resets = <&reset RESET_PCIE0>;
+                       reset-names = "phy_rst";
+                       #phy-cells = <1>;
+                       status = "disabled";
+               };
+
+               usb2phy: usb2phy@0xc0a30000 {
+                       compatible = "spacemit,usb2-phy";
+                       reg = <0x0 0xc0a30000  0x0 0x200>;
+                       spacemit,phy-name = "mv-usb-phy";
+                       spacemit,pll-lock-bypass;
+                       clocks = <&ccu CLK_USB30>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               usbdrd3: usb3@0 {
+                       compatible = "spacemit,k1-x-dwc3";
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       resets = <&reset RESET_USB3_0>;
+                       reset-names = "ctl_rst";
+                       clocks = <&ccu CLK_USB30>;
+                       clock-names = "usbdrd30";
+                       interrupt-parent = <&intc>;
+                       interrupts = <149>;
+                       ranges;
+                       status = "disabled";
+
+                       dwc3@c0a00000 {
+                               compatible = "snps,dwc3";
+                               reg = <0x0 0xc0a00000 0x0 0x10000>;
+                               interrupt-parent = <&intc>;
+                               interrupts = <125>;
+                               phys = <&combphy PHY_TYPE_USB3>, <&usb2phy>;
+                               phy-names = "usb3-phy", "usb2-phy";
+                       };
+               };
+
+               sdhci0: sdh@d4280000 {
+                       compatible = "spacemit,k1-x-sdhci";
+                       reg = <0x0 0xd4280000 0x0 0x200>;
+                       interrupt-parent = <&intc>;
+                       interrupts = <99>;
+                       resets = <&reset RESET_SDH_AXI>,
+                                        <&reset RESET_SDH0>;
+                       reset-names = "sdh_axi", "sdh0";
+                       clocks = <&ccu CLK_SDH0>,
+                                        <&ccu CLK_SDH_AXI>;
+                       clock-names = "sdh-io", "sdh-core";
+                       status = "disabled";
+               };
+
+               sdhci1: sdh@d4280800 {
+                       compatible = "spacemit,k1-x-sdhci";
+                       reg = <0x0 0xd4280800 0x0 0x200>;
+                       interrupt-parent = <&intc>;
+                       interrupts = <100>;
+                       resets = <&reset RESET_SDH_AXI>,
+                                        <&reset RESET_SDH1>;
+                       reset-names = "sdh_axi", "sdh1";
+                       clocks = <&ccu CLK_SDH1>,
+                                        <&ccu CLK_SDH_AXI>;
+                       clock-names = "sdh-io", "sdh-core";
+                       status = "disabled";
+               };
+
+               sdhci2: sdh@d4281000 {
+                       compatible = "spacemit,k1-x-sdhci";
+                       reg = <0x0 0xd4281000 0x0 0x200>;
+                       interrupt-parent = <&intc>;
+                       interrupts = <101>;
+                       resets = <&reset RESET_SDH_AXI>,
+                                        <&reset RESET_SDH2>;
+                       reset-names = "sdh_axi", "sdh2";
+                       clocks = <&ccu CLK_SDH2>,
+                                        <&ccu CLK_SDH_AXI>;
+                       clock-names = "sdh-io", "sdh-core";
+                       status = "disabled";
+               };
+
+                i2c0: twsi0@d4010800 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd4010800 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI0>;
+                       resets = <&reset RESET_TWSI0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c1: twsi1@d4011000 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd4011000 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI1>;
+                       resets = <&reset RESET_TWSI1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c2: twsi2@d4012000 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd4012000 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI2>;
+                       resets = <&reset RESET_TWSI2>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c3: twsi3@f0614000 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xf0614000 0x0 0x38>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c4: twsi4@d4012800 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd4012800 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI4>;
+                       resets = <&reset RESET_TWSI4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c5: twsi5@d4013800 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd4013800 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI5>;
+                       resets = <&reset RESET_TWSI5>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c6: twsi6@d4018800 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd4018800 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI6>;
+                       resets = <&reset RESET_TWSI6>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c7: twsi7@d401d000 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd401d000 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI7>;
+                       resets = <&reset RESET_TWSI7>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+                i2c8: twsi8@d401d800 {
+                       compatible = "spacemit,i2c";
+                       reg = <0x0 0xd401d800 0x0 0x38>;
+                       clocks = <&ccu CLK_TWSI8>;
+                       resets = <&reset RESET_TWSI8>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+                };
+
+               pcie0_rc: pcie@ca000000 {
+                       compatible = "k1x,dwc-pcie";
+                       reg = <0x0 0xca000000 0x0 0x00001000>, /* dbi */
+                             <0x0 0xca300000 0x0 0x0001ff24>, /* atu registers */
+                             <0x0 0x80000000 0x0 0x00100000>, /* config space */
+                             <0x0 0xd4282bcc 0x0 0x00000008>, /* k1x soc config addr */
+                             <0x0 0xc0b20000 0x0 0x00001000>, /* phy ahb */
+                             <0x0 0xc0b10000 0x0 0x00001000>, /* phy addr */
+                             <0x0 0xd4282bcc 0x0 0x00000008>, /* conf0 addr */
+                             <0x0 0xc0b10000 0x0 0x00001000>; /* phy0 addr */
+                       reg-names = "dbi", "atu", "config", "k1x_conf", "phy_ahb", "phy_addr", "conf0_addr", "phy0_addr";
+
+                       k1x,pcie-port = <0>;
+                       clocks = <&ccu CLK_PCIE0>;
+                       clock-names = "pcie-clk";
+                       resets = <&reset RESET_PCIE0>;
+                       reset-names = "pcie-reset";
+
+                       bus-range = <0x00 0xff>;
+                       max-link-speed = <2>;
+                       num-lanes = <1>;
+                       num-viewport = <8>;
+                       device_type = "pci";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges = <0x81000000 0x0 0x80100000 0 0x80100000 0x0 0x100000>,
+                                <0x82000000 0x0 0x80200000 0 0x80200000 0x0 0x0fe00000>;
+
+                       interrupts = <141>, <145>;
+                       interrupt-parent = <&intc>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0000 0 0 1 &pcie0_intc 1>, /* int_a */
+                                       <0000 0 0 2 &pcie0_intc 2>, /* int_b */
+                                       <0000 0 0 3 &pcie0_intc 3>, /* int_c */
+                                       <0000 0 0 4 &pcie0_intc 4>; /* int_d */
+                       linux,pci-domain = <0>;
+                       status = "disabled";
+                       pcie0_intc: interrupt-controller@0 {
+                               interrupt-controller;
+                               reg = <0 0 0 0 0>;
+                               #address-cells = <0>;
+                               #interrupt-cells = <1>;
+                       };
+               };
+
+               pcie1_rc: pcie@ca400000 {
+                       compatible = "k1x,dwc-pcie";
+                       reg = <0x0 0xca400000 0x0 0x00001000>, /* dbi */
+                             <0x0 0xca700000 0x0 0x0001ff24>, /* atu registers */
+                             <0x0 0x90000000 0x0 0x00100000>, /* config space */
+                             <0x0 0xd4282bd4 0x0 0x00000008>, /* k1x soc config addr */
+                             <0x0 0xc0c20000 0x0 0x00001000>, /* phy ahb */
+                             <0x0 0xc0c10000 0x0 0x00001000>, /* phy addr */
+                             <0x0 0xd4282bcc 0x0 0x00000008>, /* conf0 addr */
+                             <0x0 0xc0b10000 0x0 0x00001000>; /* phy0 addr */
+                       reg-names = "dbi", "atu", "config", "k1x_conf", "phy_ahb", "phy_addr", "conf0_addr", "phy0_addr";
+
+                       k1x,pcie-port = <1>;
+                       clocks = <&ccu CLK_PCIE1>;
+                       clock-names = "pcie-clk";
+                       resets = <&reset RESET_PCIE1>;
+                       reset-names = "pcie-reset";
+
+                       bus-range = <0x00 0xff>;
+                       max-link-speed = <2>;
+                       num-lanes = <2>;
+                       num-viewport = <8>;
+                       device_type = "pci";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges = <0x01000000 0x0 0x90100000 0 0x90100000 0x0 0x100000>,
+                                <0x02000000 0x0 0x90200000 0 0x90200000 0x0 0x0fe00000>;
+
+                       interrupts = <142>, <146>;
+                       interrupt-parent = <&intc>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0000 0 0 1 &pcie1_intc 1>, /* int_a */
+                                       <0000 0 0 2 &pcie1_intc 2>, /* int_b */
+                                       <0000 0 0 3 &pcie1_intc 3>, /* int_c */
+                                       <0000 0 0 4 &pcie1_intc 4>; /* int_d */
+                       linux,pci-domain = <1>;
+                       status = "disabled";
+                       pcie1_intc: interrupt-controller@0 {
+                               interrupt-controller;
+                               reg = <0 0 0 0 0>;
+                               #address-cells = <0>;
+                               #interrupt-cells = <1>;
+                       };
+               };
+
+               pcie2_rc: pcie@ca800000 {
+                       compatible = "k1x,dwc-pcie";
+                       reg = <0x0 0xca800000 0x0 0x00001000>, /* dbi */
+                             <0x0 0xcab00000 0x0 0x0001ff24>, /* atu registers */
+                             <0x0 0xa0000000 0x0 0x00100000>, /* config space */
+                             <0x0 0xd4282bdc 0x0 0x00000008>, /* k1x soc config addr */
+                             <0x0 0xc0d20000 0x0 0x00001000>, /* phy ahb */
+                             <0x0 0xc0d10000 0x0 0x00001000>, /* phy addr */
+                             <0x0 0xd4282bcc 0x0 0x00000008>, /* conf0 addr */
+                             <0x0 0xc0b10000 0x0 0x00001000>; /* phy0 addr */
+                       reg-names = "dbi", "atu", "config", "k1x_conf", "phy_ahb", "phy_addr", "conf0_addr", "phy0_addr";
+
+                       k1x,pcie-port = <2>;
+                       clocks = <&ccu CLK_PCIE2>;
+                       clock-names = "pcie-clk";
+                       resets = <&reset RESET_PCIE2>;
+                       reset-names = "pcie-reset";
+
+                       bus-range = <0x00 0xff>;
+                       max-link-speed = <2>;
+                       num-lanes = <2>;
+                       num-viewport = <8>;
+                       device_type = "pci";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges = <0x01000000 0x0 0xa0100000 0 0xa0100000 0x0 0x100000>,
+                                <0x02000000 0x0 0xa0200000 0 0xa0200000 0x0 0x16000000>;
+
+                       interrupts = <143>, <147>;
+                       interrupt-parent = <&intc>;
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0000 0 0 1 &pcie2_intc 1>, /* int_a */
+                                       <0000 0 0 2 &pcie2_intc 2>, /* int_b */
+                                       <0000 0 0 3 &pcie2_intc 3>, /* int_c */
+                                       <0000 0 0 4 &pcie2_intc 4>; /* int_d */
+                       linux,pci-domain = <2>;
+                       status = "disabled";
+                       pcie2_intc: interrupt-controller@0 {
+                               interrupt-controller;
+                               reg = <0 0 0 0 0>;
+                               #address-cells = <0>;
+                               #interrupt-cells = <1>;
+                       };
+               };
+
+               qspi: spi@d420c000 {
+                       compatible = "spacemit,k1x-qspi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0xd420c000 0x0 0x1000>,
+                             <0x0 0xb8000000 0x0 0xd00000>;
+                       reg-names = "qspi-base", "qspi-mmap";
+                       qspi-sfa1ad = <0xa00000>;
+                       qspi-sfa2ad = <0xb00000>;
+                       qspi-sfb1ad = <0xc00000>;
+                       qspi-sfb2ad = <0xd00000>;
+                       clocks = <&ccu CLK_QSPI>,
+                               <&ccu CLK_QSPI_BUS>;
+                       clock-names = "qspi_clk", "qspi_bus_clk";
+                       resets = <&reset RESET_QSPI>,
+                               <&reset RESET_QSPI_BUS>;
+                       reset-names = "qspi_reset", "qspi_bus_reset";
+                       qspi-pmuap-reg = <0xd4282860>;
+                       spi-max-frequency = <26500000>;
+                       qspi-id = <4>;
+                       status = "disabled";
+               };
+
+               efuse: fuse@f0702800 {
+                       compatible = "spacemit,k1x-efuse";
+                       reg = <0x0 0xf0702800 0x0 0x400>;
+                       resets = <&reset RESET_AES>;
+                       reset-names = "aes_reset";
+                       clocks = <&ccu CLK_AES>;
+                       clock-names = "aes_core";
+                       status = "disabled";
+               };
+
+               dpu: dpu@c0340000 {
+                       compatible = "spacemit,dpu";
+                       reg = <0x0 0xC0340000 0x0 0x2A000>,
+                                 <0x0 0xC0440000 0x0 0x2A000>;
+                       reg-names = "dsi", "hdmi";
+                       status = "disabled";
+
+                       dpu_out: port {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               dpu_out_mipi: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&mipi_in_dpu>;
+                               };
+
+                               dpu_out_hdmi: endpoint@1 {
+                                       reg = <1>;
+                                       remote-endpoint = <&hdmi_in_dpu>;
+                               };
+                       };
+               };
+
+               mipi_dsi: mipi@d421a800 {
+                       compatible = "spacemit,mipi-dsi";
+                       reg = <0x0 0xD421A800 0 0x200>;
+                       reg-names = "dsi";
+
+                       clocks = <&ccu CLK_DPU_PXCLK>,
+                               <&ccu CLK_DPU_MCLK>,
+                               <&ccu CLK_DPU_HCLK>,
+                               <&ccu CLK_DPU_ESC>,
+                               <&ccu CLK_DPU_BIT>;
+                       clock-names = "pxclk", "mclk", "hclk", "escclk", "bitclk";
+                       resets = <&reset RESET_MIPI>,
+                               <&reset RESET_LCD_MCLK>,
+                               <&reset RESET_DSI_ESC>,
+                               <&reset RESET_LCD>;
+                       reset-names= "dsi_reset", "mclk_reset", "esc_reset", "lcd_reset";
+                       power-domains = <&pmu K1X_PMU_LCD_PWR_DOMAIN>;
+
+                       status = "disabled";
+
+                       ports {
+                               mipi_in: port {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       mipi_in_dpu: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&dpu_out_mipi>;
+                                       };
+                               };
+                       };
+               };
+
+               panel: panel {
+                         compatible = "spacemit,panel";
+                         status = "disabled";
+               };
+
+               hdmi: hdmi@c0400500 {
+                       compatible = "spacemit,hdmi";
+                       reg = <0x0 0xC0400500 0x0 0x200>;
+                       reg-names = "hdmi";
+                       clocks = <&ccu CLK_HDMI>;
+                       clock-names = "hmclk";
+                       resets = <&reset RESET_HDMI>;
+                       reset-names= "hdmi_reset";
+                       power-domains = <&pmu K1X_PMU_HDMI_PWR_DOMAIN>;
+                       status = "disabled";
+
+                       ports {
+                               hdmi_in: port {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       hdmi_in_dpu: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&dpu_out_hdmi>;
+                                       };
+                               };
+                       };
+               };
+
+       };
+
+       binman: binman {
+               multiple-images;
+               itb {
+                       filename = "u-boot.itb";
+
+                       fit {
+                               description = "Configuration to load U-Boot";
+                               #address-cells = <2>;
+                               fit,fdt-list = "of-list";
+
+                               images {
+                                       uboot {
+                                               description = "U-Boot";
+                                               type = "standalone";
+                                               os = "U-Boot";
+                                               arch = "riscv";
+                                               compression = "none";
+                                               load = <CONFIG_SYS_TEXT_BASE>;
+
+                                               uboot_blob: blob-ext {
+                                                       filename = "u-boot-nodtb.bin";
+                                               };
+                                       };
+
+                                       @fdt-SEQ {
+                                               description = "NAME";
+                                               type = "flat_dt";
+                                               compression = "none";
+                                       };
+                               };
+
+                               configurations {
+                                       default = "conf-1";
+
+                                       @conf-SEQ {
+                                               description = "U-boot FIT config";
+                                               loadables = "uboot";
+                                               fdt = "fdt-SEQ";
+                                       };
+                               };
+                       };
+               };
+       };
+
+       pmu {
+               compatible = "riscv,pmu";
+
+               riscv,event-to-mhpmevent =
+                       /* BRANCH_INSTRUCTIONS */
+                       <0x00005 0x0 0x01>,
+                       /* BRANCH_MISSES */
+                       <0x00006 0x0 0x02>,
+                       /* STALLED_CYCLES_FRONTEND */
+                       <0x00008 0x0 0x03>,
+                       /* STALLED_CYCLES_BACKEND */
+                       <0x00009 0x0 0x04>,
+                       /* L1D_READ_ACCESS */
+                       <0x10000 0x0 0x06>,
+                       /* L1D_READ_MISS */
+                       <0x10001 0x0 0x05>,
+                       /* L1D_WRITE_ACCESS */
+                       <0x10002 0x0 0x0a>,
+                       /* L1D_WRITE_MISS */
+                       <0x10003 0x0 0x09>,
+                       /* L1I_READ_ACCESS */
+                       <0x10008 0x0 0x0c>,
+                       /* L1I_READ_MISS */
+                       <0x10009 0x0 0x0b>,
+                       /* L1I_PREFETCH_ACCESS */
+                       <0x1000c 0x0 0x0e>,
+                       /* L1I_PREFETCH_MISS */
+                       <0x1000d 0x0 0x0d>,
+                       /* DTLB_READ_MISS */
+                       <0x10019 0x0 0x15>,
+                       /* DTLB_WRITE_MISS */
+                       <0x1001b 0x0 0x19>,
+                       /* ITLB_READ_MISS */
+                       <0x10021 0x0 0x1b>;
+
+               /* 16 valid counters: mhpmcounter3 ~ mhpmcounter18 */
+               riscv,event-to-mhpmcounters =
+                       <0x00005 0x00006 0x0007fff8>,
+                       <0x00008 0x00009 0x0007fff8>,
+                       <0x10000 0x10003 0x0007fff8>,
+                       <0x10008 0x10009 0x0007fff8>,
+                       <0x1000c 0x1000d 0x0007fff8>,
+                       <0x10019 0x10019 0x0007fff8>,
+                       <0x1001b 0x1001b 0x0007fff8>,
+                       <0x10021 0x10021 0x0007fff8>;
+
+               riscv,raw-event-to-mhpmcounters =
+                       /*
+                        * For convenience, we treat 0x1~0xff as valid indexes,
+                        * but actually in hardware the valid indexes are 0x1~0xbd.
+                        */
+                       <0x0 0x0 0xffffffff 0xffffff00 0x0007fff8>;
+       };
+};
diff --git a/arch/riscv/dts/k1-x_MINI-PC.dts b/arch/riscv/dts/k1-x_MINI-PC.dts
new file mode 100644 (file)
index 0000000..4d06b50
--- /dev/null
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+
+/ {
+       model = "spacemit k1-x MINI-PC board";
+
+       aliases {
+               efuse_power = &ldo_31;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+
+       usb3hub:usb3hub {
+               compatible = "spacemit,usb-hub";
+               hub-gpios = <
+                       &gpio 123 0     /* usb3 hub en */
+                       &gpio 124 0>;   /* usb3 hub rst*/
+               vbus-gpios = <&gpio 97 0>;      /* gpio_97 for usb3 hub output vbus */
+               regulator-force-boot-off;
+               status = "okay";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "disabled";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2_0>;
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               vin-supply-names = "eeprom_1v8";
+               status = "okay";
+       };
+};
+
+&i2c3 {
+       status = "disabled";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&i2c5 {
+       status = "disabled";
+};
+
+&i2c6 {
+       status = "disabled";
+};
+
+&i2c7 {
+       status = "disabled";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDI  2 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range PRI_TCK  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDO  1 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     2 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_124 1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       usbp1_vbus: usbp1_vbus {
+               pinctrl-single,pins =<
+                       K1X_PADCONF(GPIO_66, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* drive_vbus1_iso */
+               >;
+       };
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+               &pinctrl 70 PRI_TDI 4
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 3
+               &pinctrl 123 GPIO_123 5
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+&usbdrd3 {
+       status = "okay";
+       vbus-supply = <&usb3hub>;
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <110>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
+&mipi_dsi {
+       status = "disabled";
+};
+
+&panel {
+       dcp-gpios = <&gpio 82 0>;
+       dcn-gpios = <&gpio 83 0>;
+       bl-gpios = <&gpio 44 0>;
+       reset-gpios = <&gpio 81 0>;
+       status = "disabled";
+};
diff --git a/arch/riscv/dts/k1-x_MUSE-N1.dts b/arch/riscv/dts/k1-x_MUSE-N1.dts
new file mode 100755 (executable)
index 0000000..e1df0ff
--- /dev/null
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+
+/ {
+       model = "spacemit k1-x MUSE-N1 board";
+
+       aliases {
+               efuse_power = &ldo_31;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+
+       usb3hub:usb3hub {
+               compatible = "spacemit,usb-hub";
+               vbus-gpios = <&gpio 127 0>;     /* gpio_97 for usb3 hub output vbus */
+               regulator-force-boot-off;
+               status = "okay";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2_0>;
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               vin-supply-names = "eeprom_1v8";
+               status = "okay";
+       };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_75  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_125 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+                &range GPIO_127 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+                &pinctrl 75 GPIO_75 1
+                &pinctrl 79 GPIO_79 1
+               &pinctrl 90 GPIO_90 1
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 115 GPIO_115 2
+               &pinctrl 125 GPIO_125 1
+                &pinctrl 127 GPIO_127 1
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+&usbdrd3 {
+       status = "okay";
+       vbus-supply = <&usb3hub>;
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       clk-src-freq = <204800000>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       clk-src-freq = <375000000>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <110>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+&pcie2_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie2_4>;
+       status = "okay";
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};
+
+&efuse {
+       status = "okay";
+};
diff --git a/arch/riscv/dts/k1-x_MUSE-Pi.dts b/arch/riscv/dts/k1-x_MUSE-Pi.dts
new file mode 100644 (file)
index 0000000..213f129
--- /dev/null
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+
+/ {
+       model = "spacemit k1-x MUSE-Pi board";
+
+       aliases {
+               efuse_power = &ldo_31;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+
+       usb2hub: usb2hub {
+               compatible = "spacemit,usb-hub";
+               vbus-gpios = <&gpio 123 0>;     /* for usb2 hub output vbus */
+               status = "okay";
+       };
+
+       usb3hub: usb3hub {
+               compatible = "spacemit,usb-hub";
+               vbus-gpios = <&gpio 79 0>;      /* gpio_79 for usb3 pwren */
+               status = "okay";
+       };
+
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "disabled";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2_0>;
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               vin-supply-names = "eeprom_1v8";
+               status = "okay";
+       };
+};
+
+&i2c3 {
+       status = "disabled";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&i2c5 {
+       status = "disabled";
+};
+
+&i2c6 {
+       status = "disabled";
+};
+
+&i2c7 {
+       status = "disabled";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_64  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDI  2 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range PRI_TCK  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDO  1 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_79  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     2 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_124 1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       usbp1_vbus: usbp1_vbus {
+               pinctrl-single,pins =<
+                       K1X_PADCONF(GPIO_66, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* drive_vbus1_iso */
+               >;
+       };
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 1
+               &pinctrl 65 GPIO_65 3
+               &pinctrl 70 PRI_TDI 4
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 79 GPIO_79 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 3
+               &pinctrl 123 GPIO_123 5
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usbphy1 {
+       status = "okay";
+};
+
+&ehci1 {
+       vbus-supply = <&usb2hub>;
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+
+&usbdrd3 {
+       status = "okay";
+       vbus-supply = <&usb3hub>;
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       clk-src-freq = <204800000>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       clk-src-freq = <375000000>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <110>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie0_rc {
+       status = "disabled";
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+/*&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};*/
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
+&mipi_dsi {
+       status = "disabled";
+};
+
+&panel {
+       dcp-gpios = <&gpio 82 0>;
+       dcn-gpios = <&gpio 83 0>;
+       bl-gpios = <&gpio 44 0>;
+       reset-gpios = <&gpio 81 0>;
+       status = "disabled";
+};
diff --git a/arch/riscv/dts/k1-x_deb1.dts b/arch/riscv/dts/k1-x_deb1.dts
new file mode 100644 (file)
index 0000000..b5774b4
--- /dev/null
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+
+/ {
+       model = "spacemit k1-x deb1 board";
+
+       aliases {
+               efuse_power = &ldo_31;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+
+       usb3hub:usb3hub {
+               compatible = "spacemit,usb-hub";
+               hub-gpios = <
+                       &gpio 123 0     /* usb3 hub en */
+                       &gpio 124 0>;   /* usb3 hub rst*/
+               vbus-gpios = <&gpio 97 0>;      /* gpio_97 for usb3 hub output vbus */
+               regulator-force-boot-off;
+               vbus_delay_ms = <250>;
+               status = "okay";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "disabled";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2_0>;
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               vin-supply-names = "eeprom_1v8";
+               status = "okay";
+       };
+};
+
+&i2c3 {
+       status = "disabled";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&i2c5 {
+       status = "disabled";
+};
+
+&i2c6 {
+       status = "disabled";
+};
+
+&i2c7 {
+       status = "disabled";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDI  2 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range PRI_TCK  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDO  1 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range DVL1     1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS0)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS0)
+               &range GPIO_124 1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       usbp1_vbus: usbp1_vbus {
+               pinctrl-single,pins =<
+                       K1X_PADCONF(GPIO_66, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* drive_vbus1_iso */
+               >;
+       };
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+               &pinctrl 70 PRI_TDI 4
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 3
+               &pinctrl 123 GPIO_123 5
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+&usbdrd3 {
+       status = "okay";
+       vbus-supply = <&usb3hub>;
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       clk-src-freq = <204800000>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       clk-src-freq = <375000000>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <110>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie0_rc {
+       status = "disabled";
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
+&mipi_dsi {
+       status = "disabled";
+};
+
+&panel {
+       dcp-gpios = <&gpio 82 0>;
+       dcn-gpios = <&gpio 83 0>;
+       bl-gpios = <&gpio 44 0>;
+       reset-gpios = <&gpio 81 0>;
+       status = "disabled";
+};
diff --git a/arch/riscv/dts/k1-x_deb2.dts b/arch/riscv/dts/k1-x_deb2.dts
new file mode 100644 (file)
index 0000000..8f5fa45
--- /dev/null
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_pm853.dtsi"
+
+/ {
+       model = "spacemit k1-x deb2 board";
+
+       aliases {
+               efuse_power = &ldo_15;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+
+       usb3hub:usb3hub {
+               compatible = "spacemit,usb-hub";
+               hub-gpios = <
+                       &gpio 123 0     /* usb3 hub en */
+                       &gpio 124 0>;   /* usb3 hub rst*/
+               vbus-gpios = <&gpio 97 0>;      /* gpio_97 for usb3 hub output vbus */
+               regulator-force-boot-off;
+               status = "okay";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "disabled";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+        #size-cells = <0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_i2c2_0>;
+        status = "okay";
+
+        eeprom@50{
+                compatible = "atmel,24c02";
+                reg = <0x50>;
+                status = "okay";
+        };
+};
+
+&i2c3 {
+       status = "disabled";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&i2c5 {
+       status = "disabled";
+};
+
+&i2c6 {
+        status = "disabled";
+};
+
+&i2c7 {
+       status = "disabled";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDI  2 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range PRI_TCK  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDO  1 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     2 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_124 1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       usbp1_vbus: usbp1_vbus {
+               pinctrl-single,pins =<
+                       K1X_PADCONF(GPIO_66, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* drive_vbus1_iso */
+               >;
+       };
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+               &pinctrl 70 PRI_TDI 4
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 3
+               &pinctrl 123 GPIO_123 5
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+&usbdrd3 {
+       status = "okay";
+       vbus-supply = <&usb3hub>;
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       clk-src-freq = <204800000>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       clk-src-freq = <375000000>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <110>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie0_rc {
+       status = "disabled";
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+&qspi {
+        status = "okay";
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_qspi>;
+
+        flash@0 {
+                compatible = "jedec,spi-nor";
+                reg = <0>;
+                spi-max-frequency = <26500000>;
+                m25p,fast-read;
+                broken-flash-reset;
+                status = "okay";
+        };
+};
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
+&mipi_dsi {
+       status = "disabled";
+};
+
+&panel {
+       dcp-gpios = <&gpio 82 0>;
+       dcn-gpios = <&gpio 83 0>;
+       bl-gpios = <&gpio 44 0>;
+       reset-gpios = <&gpio 81 0>;
+       status = "disabled";
+};
diff --git a/arch/riscv/dts/k1-x_evb.dts b/arch/riscv/dts/k1-x_evb.dts
new file mode 100644 (file)
index 0000000..183b01b
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_pm853.dtsi"
+
+/ {
+       model = "spacemit k1-x evb board";
+
+       aliases {
+               efuse_power = &ldo_15;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "disabled";
+};
+
+&i2c2 {
+       status = "disabled";
+};
+
+&i2c3 {
+       status = "disabled";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&i2c5 {
+       status = "disabled";
+};
+
+&i2c6 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               bus = <6>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               status = "okay";
+       };
+};
+
+&i2c7 {
+       status = "disabled";
+};
+
+&pinctrl {
+       usbp1_vbus: usbp1_vbus {
+               pinctrl-single,pins =<
+                       K1X_PADCONF(GPIO_66, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* drive_vbus1_iso */
+               >;
+       };
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&udc {
+       status = "okay";
+};
+
+&usbphy1 {
+       status = "disabled";
+};
+
+&ehci1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usbp1_vbus>;
+       status = "disabled";
+};
+
+&usbdrd3 {
+       status = "disabled";
+       dwc3@c0a00000 {
+               maximum-speed = "high-speed";
+               dr_mode = "peripheral";
+               phy_type = "utmi_wide";
+               snps,dis_enblslpm_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       clk-src-freq = <204800000>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       clk-src-freq = <375000000>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <44>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie0_rc {
+       status = "disabled";
+};
+
+&pcie1_rc {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_0>;
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
+&ldo_13 {
+       regulator-init-microvolt = <2800000>;
+       regulator-boot-on;
+       regulator-state-mem {
+                       regulator-off-in-suspend;
+       };
+};
+
+&ldo_15 {
+       regulator-init-microvolt = <1800000>;
+       regulator-boot-on;
+       regulator-state-mem {
+                       regulator-off-in-suspend;
+       };
+};
+
+&ldo_17 {
+       regulator-init-microvolt = <1200000>;
+       regulator-boot-on;
+       regulator-state-mem {
+                       regulator-off-in-suspend;
+       };
+};
+
+&mipi_dsi {
+       status = "disabled";
+};
+
+&panel {
+       dcp-gpios = <&gpio 21 0>;
+       dcn-gpios = <&gpio 22 0>;
+       bl-gpios = <&gpio 23 0>;
+       reset-gpios = <&gpio 24 0>;
+       status = "disabled";
+};
diff --git a/arch/riscv/dts/k1-x_hs450.dts b/arch/riscv/dts/k1-x_hs450.dts
new file mode 100644 (file)
index 0000000..67a595f
--- /dev/null
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_pm853.dtsi"
+
+/ {
+       model = "spacemit k1-x hs450 board";
+
+       aliases {
+               efuse_power = &ldo_15;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+        #size-cells = <0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_i2c2_0>;
+        status = "okay";
+
+        eeprom@50{
+                compatible = "atmel,24c02";
+                reg = <0x50>;
+                status = "okay";
+        };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     2 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 4
+               &pinctrl 123 GPIO_123 1
+               &pinctrl 125 GPIO_125 3
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+&usbdrd3 {
+       status = "okay";
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       clk-src-freq = <204800000>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       clk-src-freq = <375000000>;
+       status = "okay";
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+&qspi {
+        status = "okay";
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_qspi>;
+
+        flash@0 {
+                compatible = "jedec,spi-nor";
+                reg = <0>;
+                spi-max-frequency = <26500000>;
+                m25p,fast-read;
+                broken-flash-reset;
+                status = "okay";
+        };
+};
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
diff --git a/arch/riscv/dts/k1-x_kx312.dts b/arch/riscv/dts/k1-x_kx312.dts
new file mode 100644 (file)
index 0000000..6104728
--- /dev/null
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+
+/ {
+       model = "spacemit k1-x kx312 board";
+
+       aliases {
+               efuse_power = &ldo_31;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&ccu {
+       pll2-freq = <2800000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2_0>;
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               vin-supply-names = "eeprom_1v8";
+               status = "okay";
+       };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDI  2 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range PRI_TCK  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDO  1 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     2 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_124 1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+               &pinctrl 70 PRI_TDI 4
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 3
+               &pinctrl 123 GPIO_123 5
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       status = "okay";
+};
+
+&pcie2_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie2_4>;
+       status = "okay";
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};
+
+&efuse {
+       status = "okay";
+};
+
+&dpu {
+       status = "okay";
+};
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hdmi_0>;
+       status = "okay";
+};
+
diff --git a/arch/riscv/dts/k1-x_mingo.dts b/arch/riscv/dts/k1-x_mingo.dts
new file mode 100644 (file)
index 0000000..256de4b
--- /dev/null
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+
+/ {
+       model = "spacemit k1-x mingo board";
+
+       aliases {
+               efuse_power = &ldo_31;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "earlycon=sbi console=ttyS0,115200 debug loglevel=8,initcall_debug=1 rdinit=/init.tmp";
+               stdout-path = "serial0:115200n8";
+       };
+
+       usb3hub:usb3hub {
+               compatible = "spacemit,usb-hub";
+               hub-gpios = <
+                       &gpio 123 0     /* usb3 hub en */
+                       &gpio 124 0>;   /* usb3 hub rst*/
+               vbus-gpios = <&gpio 97 0>;      /* gpio_97 for usb3 hub output vbus */
+               regulator-force-boot-off;
+               status = "okay";
+       };
+};
+
+&cpu_0 {
+       /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster0 = <1228000>;
+       /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+       boot_freq_cluster1 = <1228000>;
+};
+
+&dramc {
+       /* dram data rate, should be 1200, 1600, or 2400 */
+       datarate = <2400>;
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2_0>;
+       status = "okay";
+
+       eeprom@50{
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               vin-supply-names = "eeprom_1v8";
+               status = "okay";
+       };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       status = "okay";
+};
+
+&pinctrl {
+       pinctrl-single,gpio-range = <
+               &range GPIO_49  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_58  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_63  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_65  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_66  2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDI  2 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range PRI_TCK  1 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range PRI_TDO  1 (MUX_MODE1 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_74  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_80  1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_3V_DS4)
+               &range GPIO_81  3 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_90  1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_91  2 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range DVL0     2 (MUX_MODE1 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_110 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_114 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_115 2 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_123 1 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+               &range GPIO_124 1 (MUX_MODE0 | EDGE_NONE | PULL_UP   | PAD_1V8_DS2)
+               &range GPIO_125 3 (MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)
+       >;
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
+&gpio{
+       gpio-ranges = <
+               &pinctrl 49 GPIO_49 2
+               &pinctrl 58 GPIO_58 1
+               &pinctrl 63 GPIO_63 5
+               &pinctrl 70 PRI_TDI 4
+               &pinctrl 74 GPIO_74 1
+               &pinctrl 80 GPIO_80 4
+               &pinctrl 90 GPIO_90 3
+               &pinctrl 96 DVL0 2
+               &pinctrl 110 GPIO_110 1
+               &pinctrl 114 GPIO_114 3
+               &pinctrl 123 GPIO_123 5
+       >;
+};
+
+&udc {
+       status = "okay";
+};
+
+&usb2phy {
+       status = "okay";
+};
+
+&combphy {
+       status = "okay";
+};
+
+&usbdrd3 {
+       status = "okay";
+       vbus-supply = <&usb3hub>;
+       dwc3@c0a00000 {
+               dr_mode = "host";
+               phy_type = "utmi";
+               snps,dis_enblslpm_quirk;
+               snps,dis-u2-freeclk-exists-quirk;
+               snps,dis-del-phy-power-chg-quirk;
+               snps,dis_u2_susphy_quirk;
+               snps,dis_u3_susphy_quirk;
+       };
+};
+
+&sdhci0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+       bus-width = <4>;
+       cd-gpios = <&gpio 80 0>;
+       cd-inverted;
+       cap-sd-highspeed;
+       sdh-phy-module = <0>;
+       status = "okay";
+};
+
+/* eMMC */
+&sdhci2 {
+       bus-width = <8>;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       sdh-phy-module = <1>;
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gmac0>;
+
+       phy-reset-pin = <110>;
+
+       clk_tuning_enable;
+       clk-tuning-by-delayline;
+       tx-phase = <90>;
+       rx-phase = <73>;
+
+       phy-mode = "rgmii";
+       phy-addr = <1>;
+       phy-handle = <&rgmii>;
+
+       ref-clock-from-phy;
+
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               rgmii: phy@0 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       device_type = "ethernet-phy";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&pcie1_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1_3>;
+       status = "okay";
+};
+
+&qspi {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <26500000>;
+               m25p,fast-read;
+               broken-flash-reset;
+               status = "okay";
+       };
+};
+
+&efuse {
+       status = "okay";
+};
+
diff --git a/arch/riscv/dts/k1-x_pinctrl.dtsi b/arch/riscv/dts/k1-x_pinctrl.dtsi
new file mode 100644 (file)
index 0000000..996be62
--- /dev/null
@@ -0,0 +1,1151 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2022 Spacemit, Inc */
+
+#include <dt-bindings/pinctrl/k1-x-pinctrl.h>
+/* Pin Configuration Node: */
+/* Format: <pin_id  muxsel  edge/st/ds/pull> */
+&pinctrl {
+    pinctrl_uart0_0: uart0_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT3, MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* uart0_txd */
+            K1X_PADCONF(MMC1_DAT2, MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* uart0_rxd */
+        >;
+    };
+
+    pinctrl_uart0_1: uart0_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_CMD, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* uart0_txd */
+            K1X_PADCONF(GPIO_80,  MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))       /* uart0_rxd */
+        >;
+    };
+
+    pinctrl_uart0_2: uart0_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_68,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))     /* uart0_txd */
+            K1X_PADCONF(GPIO_69,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))       /* uart0_rxd */
+        >;
+    };
+
+    pinctrl_uart2: uart2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_21,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart2_txd */
+            K1X_PADCONF(GPIO_22,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart2_rxd */
+            K1X_PADCONF(GPIO_23,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart2_cts_n */
+            K1X_PADCONF(GPIO_24,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart2_rts_n */
+        >;
+    };
+
+    pinctrl_uart3_0: uart3_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_81,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_txd */
+            K1X_PADCONF(GPIO_82,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_rxd */
+            K1X_PADCONF(GPIO_83,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_cts_n */
+            K1X_PADCONF(GPIO_84,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_rts_n */
+        >;
+    };
+
+    pinctrl_uart3_1: uart3_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_18,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* uart3_txd */
+            K1X_PADCONF(GPIO_19,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* uart3_rxd */
+            K1X_PADCONF(GPIO_20,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* uart3_cts_n */
+            K1X_PADCONF(GPIO_21,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart3_rts_n */
+        >;
+    };
+
+    pinctrl_uart3_2: uart3_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_53,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* uart3_txd */
+            K1X_PADCONF(GPIO_54,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_rxd */
+            K1X_PADCONF(GPIO_55,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_cts_n */
+            K1X_PADCONF(GPIO_56,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart3_rts_n */
+        >;
+    };
+
+    pinctrl_uart4_0: uart4_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(QSPI_DAT1, MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))         /* uart4_txd */
+            K1X_PADCONF(QSPI_DAT0, MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))         /* uart4_rxd */
+        >;
+    };
+
+    pinctrl_uart4_1: uart4_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_81,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* uart4_cts_n */
+            K1X_PADCONF(GPIO_82,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* uart4_rts_n */
+            K1X_PADCONF(GPIO_83,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* uart4_txd */
+            K1X_PADCONF(GPIO_84,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* uart4_rxd */
+        >;
+    };
+
+    pinctrl_uart4_2: uart4_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_23, MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* uart4_txd */
+            K1X_PADCONF(GPIO_24, MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* uart4_rxd */
+        >;
+    };
+
+    pinctrl_uart4_3: uart4_3_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_33,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_txd */
+            K1X_PADCONF(GPIO_34,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_rxd */
+            K1X_PADCONF(GPIO_35,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_cts_n */
+            K1X_PADCONF(GPIO_36,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_rts_n */
+        >;
+    };
+
+    pinctrl_uart4_4: uart4_4_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_111,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_txd */
+            K1X_PADCONF(GPIO_112,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_rxd */
+            K1X_PADCONF(GPIO_113,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_cts_n */
+            K1X_PADCONF(GPIO_114,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart4_rts_n */
+        >;
+    };
+
+    pinctrl_uart5_0: uart5_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(QSPI_CLK, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))         /* uart5_txd */
+            K1X_PADCONF(QSPI_CSI, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))         /* uart5_rxd */
+        >;
+    };
+
+    pinctrl_uart5_1: uart5_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_25,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_txd */
+            K1X_PADCONF(GPIO_26,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_rxd */
+            K1X_PADCONF(GPIO_27,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_cts_n */
+            K1X_PADCONF(GPIO_28,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_rts_n */
+        >;
+    };
+
+    pinctrl_uart5_2: uart5_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_42,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_txd */
+            K1X_PADCONF(GPIO_43,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_rxd */
+            K1X_PADCONF(GPIO_44,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_cts_n */
+            K1X_PADCONF(GPIO_45,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_rts_n */
+        >;
+    };
+
+    pinctrl_uart5_3: uart5_3_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(PRI_TDI,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* uart5_txd */
+            K1X_PADCONF(PRI_TMS,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* uart5_rxd */
+            K1X_PADCONF(PRI_TCK,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* uart5_cts_n */
+            K1X_PADCONF(PRI_TDO,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* uart5_rts_n */
+        >;
+    };
+
+    pinctrl_uart6_0: uart6_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_85,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart6_cts_n */
+            K1X_PADCONF(GPIO_86,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart6_txd */
+            K1X_PADCONF(GPIO_87,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* uart6_rxd */
+            K1X_PADCONF(GPIO_90,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* uart6_rts_n */
+        >;
+    };
+
+    pinctrl_uart6_1: uart6_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_00,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart6_txd */
+            K1X_PADCONF(GPIO_01,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart6_rxd */
+            K1X_PADCONF(GPIO_02,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart6_cts_n */
+            K1X_PADCONF(GPIO_03,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart6_rts_n */
+        >;
+    };
+
+    pinctrl_uart6_2: uart6_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_56,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* uart6_txd */
+            K1X_PADCONF(GPIO_57,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* uart6_rxd */
+        >;
+    };
+
+    pinctrl_uart7_0: uart7_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_88,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* uart7_txd */
+            K1X_PADCONF(GPIO_89,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* uart7_rxd */
+        >;
+    };
+
+    pinctrl_uart7_1: uart7_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_04,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart7_txd */
+            K1X_PADCONF(GPIO_05,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart7_rxd */
+            K1X_PADCONF(GPIO_06,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart7_cts_n */
+            K1X_PADCONF(GPIO_07,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart7_rts_n */
+        >;
+    };
+
+    pinctrl_uart8_0: uart8_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_82,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* uart8_txd */
+            K1X_PADCONF(GPIO_83,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* uart8_rxd */
+        >;
+    };
+
+    pinctrl_uart8_1: uart8_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_08,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart8_txd */
+            K1X_PADCONF(GPIO_09,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart8_rxd */
+            K1X_PADCONF(GPIO_10,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart8_cts_n */
+            K1X_PADCONF(GPIO_11,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart8_rts_n */
+        >;
+    };
+
+    pinctrl_uart8_2: uart8_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_75,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_3V_DS4))  /* uart8_txd */
+            K1X_PADCONF(GPIO_76,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_3V_DS4))  /* uart8_rxd */
+            K1X_PADCONF(GPIO_77,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_3V_DS4))  /* uart8_cts_n */
+            K1X_PADCONF(GPIO_78,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_3V_DS4))  /* uart8_rts_n */
+        >;
+    };
+
+    pinctrl_uart9_0: uart9_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_12,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_txd */
+            K1X_PADCONF(GPIO_13,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_rxd */
+        >;
+    };
+
+    pinctrl_uart9_1: uart9_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_110,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_cts_n */
+            K1X_PADCONF(GPIO_115,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_rts_n */
+            K1X_PADCONF(GPIO_116,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_txd */
+            K1X_PADCONF(GPIO_117,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_rxd */
+        >;
+    };
+
+    pinctrl_uart9_2: uart9_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(PRI_TCK,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* uart9_txd */
+            K1X_PADCONF(PRI_TDO,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* uart9_rxd */
+        >;
+    };
+
+    pinctrl_i2c0: i2c0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_54,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c0_scl */
+            K1X_PADCONF(GPIO_55,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c0_sda */
+        >;
+    };
+
+    pinctrl_i2c1: i2c1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_56,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c1_scl */
+            K1X_PADCONF(GPIO_57,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c1_sda */
+        >;
+    };
+
+    pinctrl_i2c2_0: i2c2_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_84,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))   /* i2c2_scl */
+            K1X_PADCONF(GPIO_85,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))   /* i2c2_sda */
+        >;
+    };
+
+    pinctrl_i2c2_1: i2c2_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(PRI_TDI,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c2_scl */
+            K1X_PADCONF(PRI_TMS,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c2_sda */
+        >;
+    };
+
+    pinctrl_i2c2_2: i2c2_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_68,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c2_scl */
+            K1X_PADCONF(GPIO_69,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c2_sda */
+        >;
+    };
+
+    pinctrl_i2c3_0: i2c3_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_38,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c3_scl */
+            K1X_PADCONF(GPIO_39,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c3_sda */
+        >;
+    };
+
+    pinctrl_i2c3_1: i2c3_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_47,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c3_scl */
+            K1X_PADCONF(GPIO_48,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c3_sda */
+        >;
+    };
+
+    pinctrl_i2c3_2: i2c3_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_77,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c3_scl */
+            K1X_PADCONF(GPIO_78,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c3_sda */
+        >;
+    };
+
+    pinctrl_i2c4_0: i2c4_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_40,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))   /* i2c4_scl */
+            K1X_PADCONF(GPIO_41,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))   /* i2c4_sda */
+        >;
+    };
+
+    pinctrl_i2c4_1: i2c4_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_75,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS0))   /* i2c4_scl */
+            K1X_PADCONF(GPIO_76,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS0))   /* i2c4_sda */
+        >;
+    };
+
+    pinctrl_i2c4_2: i2c4_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_51,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_3V_DS0))   /* i2c4_scl */
+            K1X_PADCONF(GPIO_52,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_3V_DS0))   /* i2c4_sda */
+        >;
+    };
+
+    pinctrl_i2c5_0: i2c5_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_81,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* i2c5_scl */
+            K1X_PADCONF(GPIO_82,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* i2c5_sda */
+        >;
+    };
+
+    pinctrl_i2c5_1: i2c5_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_54,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* i2c5_scl */
+            K1X_PADCONF(GPIO_55,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* i2c5_sda */
+        >;
+    };
+
+    pinctrl_i2c6_0: i2c6_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_83,    MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* i2c6_scl */
+            K1X_PADCONF(GPIO_90,    MUX_MODE5, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS0))   /* i2c6_sda */
+        >;
+    };
+
+    pinctrl_i2c6_1: i2c6_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_118,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c6_scl */
+            K1X_PADCONF(GPIO_119,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c6_sda */
+        >;
+    };
+
+    pinctrl_i2c6_2: i2c6_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_56,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c6_scl */
+            K1X_PADCONF(GPIO_57,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))    /* i2c6_sda */
+        >;
+    };
+
+    pinctrl_i2c7: i2c7_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_118,   MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* i2c6_scl */
+            K1X_PADCONF(GPIO_119,   MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS0))   /* i2c6_sda */
+        >;
+    };
+
+    pinctrl_i2c8: i2c8_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(PWR_SCL,    MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* pwr_scl */
+            K1X_PADCONF(PWR_SDA,    MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS0))     /* pwr_sda */
+        >;
+    };
+
+    pinctrl_one_wire_0: one_wire_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_110,   MUX_MODE5, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* one_wire */
+        >;
+    };
+
+    pinctrl_one_wire_1: one_wire_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_47,   MUX_MODE5, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))   /* one_wire */
+        >;
+    };
+
+    pinctrl_ir_rx_0: ir_rx_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(DVL1,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))        /* ir_rx */
+        >;
+    };
+
+    pinctrl_ir_rx_1: ir_rx_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_79,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))   /* ir_rx */
+        >;
+    };
+
+    pinctrl_ir_rx_2: ir_rx_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_58,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))     /* ir_rx */
+        >;
+    };
+
+    pinctrl_pwm0_0: pwm0_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT3, MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* pwm0 */
+        >;
+    };
+
+    pinctrl_pwm0_1: pwm0_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_14,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm0 */
+        >;
+    };
+
+    pinctrl_pwm0_2: pwm0_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_22, MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* pwm0 */
+        >;
+    };
+
+    pinctrl_pwm1_0: pwm1_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT2, MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* pwm1 */
+        >;
+    };
+
+    pinctrl_pwm1_1: pwm1_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_29, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))        /* pwm1 */
+        >;
+    };
+
+    pinctrl_pwm1_2: pwm1_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_23, MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))        /* pwm1 */
+        >;
+    };
+
+    pinctrl_pwm2_0: pwm2_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT1, MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* pwm2 */
+        >;
+    };
+
+    pinctrl_pwm2_1: pwm2_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_22, MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* pwm2 */
+        >;
+    };
+
+    pinctrl_pwm2_2: pwm2_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_30, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))        /* pwm2 */
+        >;
+    };
+
+    pinctrl_pwm2_3: pwm2_3_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_24, MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))        /* pwm2 */
+        >;
+    };
+
+    pinctrl_pwm3_0: pwm3_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT0, MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* pwm3 */
+        >;
+    };
+
+    pinctrl_pwm3_1: pwm3_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_33, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* pwm3 */
+        >;
+    };
+
+    pinctrl_pwm3_2: pwm3_2_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_25, MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))        /* pwm3 */
+        >;
+    };
+
+    pinctrl_pwm4_0: pwm4_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_CMD, MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS4))          /* pwm4 */
+        >;
+    };
+
+    pinctrl_pwm4_1: pwm4_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_34, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* pwm4 */
+        >;
+    };
+
+    pinctrl_pwm5_0: pwm5_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_CLK, MUX_MODE5, (EDGE_NONE | PULL_UP | PAD_3V_DS4))          /* pwm5 */
+        >;
+    };
+
+    pinctrl_pwm5_1: pwm5_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_35, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* pwm5 */
+        >;
+    };
+
+    pinctrl_pwm6_0: pwm6_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_88,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm6 */
+        >;
+    };
+
+    pinctrl_pwm6_1: pwm6_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_36, MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))         /* pwm6 */
+        >;
+    };
+
+    pinctrl_pwm7_0: pwm7_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_92,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* pwm7 */
+        >;
+    };
+
+    pinctrl_pwm7_1: pwm7_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_37,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm7 */
+        >;
+    };
+
+    pinctrl_pwm8_0: pwm8_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_00,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm8 */
+        >;
+    };
+
+    pinctrl_pwm8_1: pwm8_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_38,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* pwm8 */
+        >;
+    };
+
+    pinctrl_pwm9_0: pwm9_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_01,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm9 */
+        >;
+    };
+
+    pinctrl_pwm9_1: pwm9_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_39,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* pwm9 */
+        >;
+    };
+
+    pinctrl_pwm9_2: pwm9_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_74,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* pwm9 */
+        >;
+    };
+
+    pinctrl_pwm10_0: pwm10_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_02,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm10 */
+        >;
+    };
+
+    pinctrl_pwm10_1: pwm10_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_40,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* pwm10 */
+        >;
+    };
+
+    pinctrl_pwm11_0: pwm11_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_03,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm11 */
+        >;
+    };
+
+    pinctrl_pwm11_1: pwm11_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_41,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* pwm11 */
+        >;
+    };
+
+    pinctrl_pwm12_0: pwm12_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_04,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm12 */
+        >;
+    };
+
+    pinctrl_pwm12_1: pwm12_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_42,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm12 */
+        >;
+    };
+
+    pinctrl_pwm13_0: pwm13_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_05,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm13 */
+        >;
+    };
+
+    pinctrl_pwm13_1: pwm13_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_43,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm13 */
+        >;
+    };
+
+    pinctrl_pwm14_0: pwm14_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_06,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm14 */
+        >;
+    };
+
+    pinctrl_pwm14_1: pwm14_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_44,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm14 */
+        >;
+    };
+
+    pinctrl_pwm15_0: pwm15_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_07,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm15 */
+        >;
+    };
+
+    pinctrl_pwm15_1: pwm15_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_45,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm15 */
+        >;
+    };
+
+    pinctrl_pwm16_0: pwm16_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_09,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm16 */
+        >;
+    };
+
+    pinctrl_pwm16_1: pwm16_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_46,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm16 */
+        >;
+    };
+
+    pinctrl_pwm17_0: pwm17_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_10,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm17 */
+        >;
+    };
+
+    pinctrl_pwm17_1: pwm17_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_53,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm17 */
+        >;
+    };
+
+    pinctrl_pwm18_0: pwm18_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_11,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm18 */
+        >;
+    };
+
+    pinctrl_pwm18_1: pwm18_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_57,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* pwm18 */
+        >;
+    };
+
+    pinctrl_pwm19_0: pwm19_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_13,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* pwm19 */
+        >;
+    };
+
+    pinctrl_pwm19_1: pwm19_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_63,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* pwm19 */
+        >;
+    };
+
+    pinctrl_sspa0_0: sspa0_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_118,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* sspa0_clk */
+            K1X_PADCONF(GPIO_119,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* sspa0_frm */
+            K1X_PADCONF(GPIO_120,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa0_txd */
+            K1X_PADCONF(GPIO_121,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa0_rxd */
+            K1X_PADCONF(GPIO_122,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa0_sysclk */
+        >;
+    };
+
+    pinctrl_sspa0_1: sspa0_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_58,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* sspa0_sysclk */
+            K1X_PADCONF(GPIO_111,   MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* sspa0_clk */
+            K1X_PADCONF(GPIO_112,   MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* sspa0_frm */
+            K1X_PADCONF(GPIO_113,   MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* sspa0_txd */
+            K1X_PADCONF(GPIO_114,   MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* sspa0_rxd */
+        >;
+    };
+
+    pinctrl_sspa1: sspa1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_24,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa1_sysclk */
+            K1X_PADCONF(GPIO_25,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa1_sclk */
+            K1X_PADCONF(GPIO_26,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa1_frm */
+            K1X_PADCONF(GPIO_27,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa1_txd */
+            K1X_PADCONF(GPIO_28,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* sspa1_rxd */
+        >;
+    };
+
+    pinctrl_ssp2_0: ssp2_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_75,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_sclk */
+            K1X_PADCONF(GPIO_76,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_frm */
+            K1X_PADCONF(GPIO_77,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_txd */
+            K1X_PADCONF(GPIO_78,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_rxd */
+        >;
+    };
+
+    pinctrl_ssp2_1: ssp2_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_64,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_sclk */
+            K1X_PADCONF(GPIO_65,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_frm */
+            K1X_PADCONF(GPIO_66,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_txd */
+            K1X_PADCONF(GPIO_67,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp2_rxd */
+        >;
+    };
+
+    pinctrl_ssp3_0: ssp3_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_75,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp3_sclk */
+            K1X_PADCONF(GPIO_76,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp3_frm */
+            K1X_PADCONF(GPIO_77,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp3_txd */
+            K1X_PADCONF(GPIO_78,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* ssp3_rxd */
+        >;
+    };
+
+    pinctrl_ssp3_1: ssp3_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_59,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* ssp3_sclk */
+            K1X_PADCONF(GPIO_60,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* ssp3_frm */
+            K1X_PADCONF(GPIO_61,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* ssp3_txd */
+            K1X_PADCONF(GPIO_62,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* ssp3_rxd */
+        >;
+    };
+
+    pinctrl_qspi: qspi_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(QSPI_DAT3, MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))        /* qspi_d3 */
+            K1X_PADCONF(QSPI_DAT2, MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))        /* qspi_d2 */
+            K1X_PADCONF(QSPI_DAT1, MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))        /* qspi_d1 */
+            K1X_PADCONF(QSPI_DAT0, MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))        /* qspi_d1 */
+            K1X_PADCONF(QSPI_CLK,  MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))        /* qspi_clk */
+            K1X_PADCONF(QSPI_CSI,  MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_3V_DS4))          /* qspi_csi */
+        >;
+    };
+
+    pinctrl_mmc1: mmc1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT3, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* mmc1_d3 */
+            K1X_PADCONF(MMC1_DAT2, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* mmc1_d2 */
+            K1X_PADCONF(MMC1_DAT1, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* mmc1_d1 */
+            K1X_PADCONF(MMC1_DAT0, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* mmc1_d0 */
+            K1X_PADCONF(MMC1_CMD,  MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_3V_DS4))         /* mmc1_cmd */
+            K1X_PADCONF(MMC1_CLK,  MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_3V_DS4))       /* mmc1_clk */
+        >;
+    };
+
+    pinctrl_mmc1_fast: mmc1_fast_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(MMC1_DAT3, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS3))         /* mmc1_d3 */
+            K1X_PADCONF(MMC1_DAT2, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS3))         /* mmc1_d2 */
+            K1X_PADCONF(MMC1_DAT1, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS3))         /* mmc1_d1 */
+            K1X_PADCONF(MMC1_DAT0, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS3))         /* mmc1_d0 */
+            K1X_PADCONF(MMC1_CMD,  MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS3))         /* mmc1_cmd */
+            K1X_PADCONF(MMC1_CLK,  MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS3))       /* mmc1_clk */
+        >;
+    };
+
+    pinctrl_mmc2: mmc2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_15,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mmc2_data3 */
+            K1X_PADCONF(GPIO_16,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mmc2_data2 */
+            K1X_PADCONF(GPIO_17,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mmc2_data1 */
+            K1X_PADCONF(GPIO_18,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mmc2_data0 */
+            K1X_PADCONF(GPIO_19,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mmc2_cmd */
+            K1X_PADCONF(GPIO_20,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mmc2_clk */
+        >;
+    };
+
+    pinctrl_usb0_0: usb0_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_125,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* vbus_on0 */
+            K1X_PADCONF(GPIO_126,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* usb_id0 */
+            K1X_PADCONF(GPIO_127,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* drive_vbus0_iso */
+        >;
+    };
+
+    pinctrl_usb0_1: usb0_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_64,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* vbus_on0 */
+            K1X_PADCONF(GPIO_65,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* usb_id0 */
+            K1X_PADCONF(GPIO_63,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* drive_vbus0_iso */
+        >;
+    };
+
+    pinctrl_usb1_0: usb1_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_124,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* drive_vbus1_iso */
+        >;
+    };
+
+    pinctrl_usb1_1: usb1_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_66,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* drive_vbus1_iso */
+        >;
+    };
+
+    pinctrl_usb2_0: usb2_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_121,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* vbus_on2 */
+            K1X_PADCONF(GPIO_122,    MUX_MODE2, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* usb_id2 */
+            K1X_PADCONF(GPIO_123,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* drive_vbus2_iso */
+        >;
+    };
+
+    pinctrl_usb2_1: usb2_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_68,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* vbus_on2 */
+            K1X_PADCONF(GPIO_69,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* usb_id2 */
+            K1X_PADCONF(GPIO_67,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* drive_vbus2_iso */
+        >;
+    };
+
+    pinctrl_pcie0_0: pcie0_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_15,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* PCIe0_perstn */
+            K1X_PADCONF(GPIO_16,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* PCIe0_waken */
+            K1X_PADCONF(GPIO_17,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* PCIe0_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie0_1: pcie0_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_29,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_perstn */
+            K1X_PADCONF(GPIO_30,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_waken */
+            K1X_PADCONF(GPIO_31,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie0_2: pcie0_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_110,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_perstn */
+            K1X_PADCONF(GPIO_115,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_waken */
+            K1X_PADCONF(GPIO_116,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie0_3: pcie0_3_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_53,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe0_perstn */
+            K1X_PADCONF(GPIO_54,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe0_waken */
+            K1X_PADCONF(GPIO_55,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe0_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie1_0: pcie1_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_15,    MUX_MODE4, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))  /* PCIe1_perstn */
+            K1X_PADCONF(GPIO_16,    MUX_MODE4, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))  /* PCIe1_waken */
+            K1X_PADCONF(GPIO_17,    MUX_MODE4, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))  /* PCIe1_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie1_1: pcie1_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_32,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe1_perstn */
+            K1X_PADCONF(GPIO_33,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe1_waken */
+            K1X_PADCONF(GPIO_34,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe1_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie1_2: pcie1_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_56,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe1_perstn */
+            K1X_PADCONF(GPIO_57,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe1_waken */
+            K1X_PADCONF(GPIO_58,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe1_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie1_3: pcie1_3_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_59,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe1_perstn */
+            K1X_PADCONF(GPIO_60,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe1_waken */
+            K1X_PADCONF(GPIO_61,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe1_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie2_0: pcie2_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_18,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* PCIe2_perstn */
+            K1X_PADCONF(GPIO_19,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* PCIe2_waken */
+            K1X_PADCONF(GPIO_20,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))  /* PCIe2_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie2_1: pcie2_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_35,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_perstn */
+            K1X_PADCONF(GPIO_36,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_waken */
+            K1X_PADCONF(GPIO_37,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie2_2: pcie2_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_62,     MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe2_perstn */
+            K1X_PADCONF(GPIO_74,     MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe2_waken */
+            K1X_PADCONF(GPIO_117,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie2_3: pcie2_3_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_111,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_perstn */
+            K1X_PADCONF(GPIO_112,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_waken */
+            K1X_PADCONF(GPIO_113,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_clkreqn */
+        >;
+    };
+
+    pinctrl_pcie2_4: pcie2_4_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_62,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe2_perstn */
+            K1X_PADCONF(GPIO_112,   MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* PCIe2_waken */
+            K1X_PADCONF(GPIO_117,   MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* PCIe2_clkreqn */
+        >;
+    };
+
+    pinctrl_gmac0: gmac0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_00,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_rxdv */
+            K1X_PADCONF(GPIO_01,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_rx_d0 */
+            K1X_PADCONF(GPIO_02,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_rx_d1 */
+            K1X_PADCONF(GPIO_03,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_rx_clk */
+            K1X_PADCONF(GPIO_04,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_rx_d2 */
+            K1X_PADCONF(GPIO_05,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_rx_d3 */
+            K1X_PADCONF(GPIO_06,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_tx_d0 */
+            K1X_PADCONF(GPIO_07,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_tx_d1 */
+            K1X_PADCONF(GPIO_08,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_tx */
+            K1X_PADCONF(GPIO_09,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_tx_d2 */
+            K1X_PADCONF(GPIO_10,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_tx_d3 */
+            K1X_PADCONF(GPIO_11,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_tx_en */
+            K1X_PADCONF(GPIO_12,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_mdc */
+            K1X_PADCONF(GPIO_13,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_mdio */
+            K1X_PADCONF(GPIO_14,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_int_n */
+            K1X_PADCONF(GPIO_45,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac0_clk_ref */
+        >;
+    };
+
+    pinctrl_gmac1: gmac1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_29,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_rxdv */
+            K1X_PADCONF(GPIO_30,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_rx_d0 */
+            K1X_PADCONF(GPIO_31,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_rx_d1 */
+            K1X_PADCONF(GPIO_32,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_rx_clk */
+            K1X_PADCONF(GPIO_33,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_rx_d2 */
+            K1X_PADCONF(GPIO_34,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_rx_d3 */
+            K1X_PADCONF(GPIO_35,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_tx_d0 */
+            K1X_PADCONF(GPIO_36,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_tx_d1 */
+            K1X_PADCONF(GPIO_37,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_tx */
+            K1X_PADCONF(GPIO_38,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_tx_d2 */
+            K1X_PADCONF(GPIO_39,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_tx_d3 */
+            K1X_PADCONF(GPIO_40,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_tx_en */
+            K1X_PADCONF(GPIO_41,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_mdc */
+            K1X_PADCONF(GPIO_42,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_mdio */
+            K1X_PADCONF(GPIO_43,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_int_n */
+            K1X_PADCONF(GPIO_46,    MUX_MODE1, (EDGE_NONE | PULL_DIS | PAD_1V8_DS2))   /* gmac1_clk_ref */
+        >;
+    };
+
+    pinctrl_can_0: can_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_75,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* can_tx0 */
+            K1X_PADCONF(GPIO_76,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_3V_DS4))    /* can_rx0 */
+        >;
+    };
+
+    pinctrl_can_1: can_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_54,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* can_tx0 */
+            K1X_PADCONF(GPIO_55,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* can_rx0 */
+        >;
+    };
+
+    pinctrl_hdmi_0: hdmi_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_86, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* hdmi_tx_hscl */
+            K1X_PADCONF(GPIO_87, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* hdmi_tx_hsda */
+            K1X_PADCONF(GPIO_88, MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))       /* hdmi_tx_hcec */
+            K1X_PADCONF(GPIO_89, MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))       /* hdmi_tx_pdp */
+        >;
+    };
+
+    pinctrl_hdmi_1: hdmi_1_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_59, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* hdmi_tx_hscl */
+            K1X_PADCONF(GPIO_60, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* hdmi_tx_hsda */
+            K1X_PADCONF(GPIO_61, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* hdmi_tx_hcec */
+            K1X_PADCONF(GPIO_62, MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* hdmi_tx_pdp */
+        >;
+    };
+
+    pinctrl_spi_lcd_0: spi_lcd_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_86,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* dclk */
+            K1X_PADCONF(GPIO_87,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* dcx */
+            K1X_PADCONF(GPIO_88,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)) /* din */
+            K1X_PADCONF(GPIO_89,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)) /* dout0 */
+            K1X_PADCONF(GPIO_90,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2)) /* dout1 */
+            K1X_PADCONF(GPIO_91,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* dsi_te */
+            K1X_PADCONF(GPIO_92,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* smpn_rstb */
+        >;
+    };
+
+    pinctrl_spi_lcd_1: spi_lcd_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(PRI_TDI,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* dclk */
+            K1X_PADCONF(PRI_TMS,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* dcx */
+            K1X_PADCONF(PRI_TCK,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* din */
+            K1X_PADCONF(PRI_TDO,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* dout0 */
+            K1X_PADCONF(GPIO_74,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* dout1 */
+            K1X_PADCONF(GPIO_114,   MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* dsi_te */
+            K1X_PADCONF(GPIO_63,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* smpn_rstb */
+        >;
+    };
+
+    pinctrl_camera0: camera0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_53,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* cam_mclk0 */
+        >;
+    };
+
+    pinctrl_camera1: camera1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_58,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* cam_mclk1 */
+        >;
+    };
+
+    pinctrl_camera2: camera2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_120,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* cam_mclk2 */
+        >;
+    };
+
+    pinctrl_pmic: pmic_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(VCXO_EN, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))         /* vcxo_en */
+            K1X_PADCONF(DVL0,    MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))       /* dvl0 */
+            K1X_PADCONF(DVL1,    MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))       /* dvl1 */
+        >;
+    };
+
+    pinctrl_mn_clk_0: mn_clk_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_92,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))     /* mn_clk */
+        >;
+    };
+
+    pinctrl_mn_clk_1: mn_clk_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_81,    MUX_MODE4, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* mn_clk */
+        >;
+    };
+
+    pinctrl_mn_clk_2: mn_clk_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_44,    MUX_MODE1, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* mn_clk */
+        >;
+    };
+
+    pinctrl_mn_clk_3: mn_clk_3_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_20,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* mn_clk */
+        >;
+    };
+
+    pinctrl_mn_clk_4: mn_clk_4_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_23,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* mn_clk */
+        >;
+    };
+
+    pinctrl_mn_clk_5: mn_clk_5_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_32,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* mn_clk */
+        >;
+    };
+
+    pinctrl_mn_clk2_0: mn_clk2_0_grp {
+        pinctrl-single,pins = <
+            K1X_PADCONF(GPIO_91,    MUX_MODE1, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))      /* mn_clk2 */
+        >;
+    };
+
+    pinctrl_mn_clk2_1: mn_clk2_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_85,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))   /* mn_clk2 */
+        >;
+    };
+
+    pinctrl_vcxo_0: vcxo_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(DVL0,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* vcxo_req */
+            K1X_PADCONF(DVL1,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))    /* vcxo_out */
+        >;
+    };
+
+    pinctrl_vcxo_1: vcxo_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_16,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* vcxo_req */
+            K1X_PADCONF(GPIO_17,    MUX_MODE3, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* vcxo_out */
+        >;
+    };
+
+    pinctrl_vcxo_2: vcxo_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_89,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* vcxo_req */
+            K1X_PADCONF(GPIO_90,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* vcxo_out */
+        >;
+    };
+
+    pinctrl_vcxo_out_0: vcxo_out_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_91,    MUX_MODE2, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* vcxo_out_0 */
+        >;
+    };
+
+    pinctrl_vcxo_out_1: vcxo_out_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_12,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* vcxo_out */
+        >;
+    };
+
+    pinctrl_32k_out_0: 32k_out_0_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_21,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* 32k_out */
+        >;
+    };
+
+    pinctrl_32k_out_1: 32k_out_1_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_31,    MUX_MODE3, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* 32k_out */
+        >;
+    };
+
+    pinctrl_32k_out_2: 32k_out_2_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(GPIO_28,    MUX_MODE4, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))   /* 32k_out */
+        >;
+    };
+
+    pinctrl_pri: pri_grp {
+        pinctrl-single,pins =<
+            K1X_PADCONF(PRI_TDI,    MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* pri_tdi */
+            K1X_PADCONF(PRI_TMS,    MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* pri_tms */
+            K1X_PADCONF(PRI_TCK,    MUX_MODE0, (EDGE_NONE | PULL_DOWN | PAD_1V8_DS2))  /* pri_tck */
+            K1X_PADCONF(PRI_TDO,    MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* pri_tck */
+        >;
+    };
+};
+
diff --git a/arch/riscv/dts/k1-x_pm853.dtsi b/arch/riscv/dts/k1-x_pm853.dtsi
new file mode 100644 (file)
index 0000000..2785986
--- /dev/null
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+&i2c8 {
+       clock-frequency = <100000>;
+       u-boot,dm-spl;
+       status = "okay";
+
+       pm853: pmic@31 {
+               compatible = "spacemit,pm853";
+               reg = <0x31>;
+               bus = <8>;
+               u-boot,dm-spl;
+
+               regulators {
+                       /* buck */
+                       dcdc_1: DCDC_REG1 {
+                               regulator-name = "dcdc1";
+                               regulator-min-microvolt = <480000>;
+                               regulator-max-microvolt = <3160000>;
+                               regulator-init-microvolt = <950000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       dcdc_2: DCDC_REG2 {
+                               regulator-name = "dcdc2";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
+                       dcdc_3: DCDC_REG3 {
+                               regulator-name = "dcdc3";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
+                       /**
+                        * the order of powering on
+                        * 1. dcdc5
+                        * 2. ldo19
+                        * 3. dcdc4
+                        * 4. ldo4
+                        * 5. ldo9
+                        */
+                       dcdc_5: DCDC_REG5 {
+                               regulator-name = "dcdc5";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <3950000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       ldo_19: LDO_REG19 {
+                               regulator-name = "ldo19";
+                               regulator-min-microvolt = <100000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       dcdc_4: DCDC_REG4 {
+                               regulator-name = "dcdc4";
+                               regulator-min-microvolt = <480000>;
+                               regulator-max-microvolt = <3160000>;
+                               regulator-init-microvolt = <650000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       ldo_4: LDO_REG4 {
+                               regulator-name = "ldo4";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-init-microvolt = <3300000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       ldo_9: LDO_REG9 {
+                               regulator-name = "ldo9";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-init-microvolt = <3300000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       /* ldo */
+                       ldo_1: LDO_REG1 {
+                               regulator-name = "ldo1";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_2: LDO_REG2 {
+                               regulator-name = "ldo2";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_3: LDO_REG3 {
+                               regulator-name = "ldo3";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_5: LDO_REG5 {
+                               regulator-name = "ldo5";
+                               regulator-min-microvolt = <1600000>;
+                               regulator-max-microvolt = <1900000>;
+                       };
+
+                       ldo_6: LDO_REG6 {
+                               regulator-name = "ldo6";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_7: LDO_REG7 {
+                               regulator-name = "ldo7";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1950000>;
+                       };
+
+                       ldo_8: LDO_REG8 {
+                               regulator-name = "ldo8";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_10: LDO_REG10 {
+                               regulator-name = "ldo10";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_11: LDO_REG11 {
+                               regulator-name = "ldo11";
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1950000>;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       ldo_12: LDO_REG12 {
+                               regulator-name = "ldo12";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_13: LDO_REG13 {
+                               regulator-name = "ldo13";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_14: LDO_REG14 {
+                               regulator-name = "ldo14";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_15: LDO_REG15 {
+                               regulator-name = "ldo15";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1950000>;
+                       };
+
+                       ldo_16: LDO_REG16 {
+                               regulator-name = "ldo16";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo_17: LDO_REG17 {
+                               regulator-name = "ldo17";
+                               regulator-min-microvolt = <100000>;
+                               regulator-max-microvolt = <1350000>;
+                       };
+
+                       ldo_18: LDO_REG18 {
+                               regulator-name = "ldo18";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1950000>;
+                       };
+
+                       ldo_20: LDO_REG20 {
+                               regulator-name = "ldo20";
+                               regulator-min-microvolt = <100000>;
+                               regulator-max-microvolt = <1350000>;
+                       };
+
+                       ldo_21: LDO_REG21 {
+                               regulator-name = "ldo21";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1950000>;
+                       };
+
+                       ldo_22: LDO_REG22 {
+                               regulator-name = "ldo22";
+                               regulator-min-microvolt = <100000>;
+                               regulator-max-microvolt = <1350000>;
+                       };
+
+                       sw_1: SWITCH_REG1 {
+                               regulator-name = "switch1";
+                       };
+               };
+       };
+
+       sy8810l: sy8810l@70 {
+               compatible = "spacemit,sy8810l";
+               reg = <0x70>;
+               bus = <8>;
+               u-boot,dm-spl;
+
+               regulators {
+                       u-boot,dm-spl;
+
+                       edcdc_1: EDCDC_REG1 {
+                               regulator-name = "edcdc1";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-init-microvolt = <950000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+};
diff --git a/arch/riscv/dts/k1-x_spl.dts b/arch/riscv/dts/k1-x_spl.dts
new file mode 100644 (file)
index 0000000..fe5d999
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+/dts-v1/;
+
+#include "k1-x.dtsi"
+#include "k1-x_pinctrl.dtsi"
+#include "k1-x_spm8821.dtsi"
+#include "k1-x_pm853.dtsi"
+
+/ {
+       model = "spacemit k1-x spl";
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+               u-boot,dm-spl;
+       };
+};
+
+&cpus {
+       timebase-frequency = <24000000>;
+       u-boot,dm-spl;
+
+       cpu@0 {
+               /* boot frequency for cluster-0, should be 1600000, 1228000, 819000, or 614000 */
+               boot_freq_cluster0 = <1228000>;
+               /* boot frequency for cluster-1, should be 1600000, 1228000, 819000, or 614000 */
+               boot_freq_cluster1 = <1228000>;
+               u-boot,dm-spl;
+       };
+};
+
+&clocks {
+       u-boot,dm-spl;
+
+       vctcxo_24 {
+               u-boot,dm-spl;
+       };
+
+       vctcxo_3 {
+               u-boot,dm-spl;
+       };
+
+       vctcxo_1 {
+               u-boot,dm-spl;
+       };
+
+       pll1_vco {
+               u-boot,dm-spl;
+       };
+
+       clk_32k {
+               u-boot,dm-spl;
+       };
+
+       clk_dummy {
+               u-boot,dm-spl;
+       };
+};
+
+&soc {
+       u-boot,dm-spl;
+
+       clock-controller@d4050000 {
+               status = "okay";
+               u-boot,dm-spl;
+       };
+
+       reset-controller@d4050000 {
+               status = "okay";
+               u-boot,dm-spl;
+       };
+
+       uart@d4017000 {
+               status = "okay";
+               u-boot,dm-spl;
+       };
+
+       ddr@c0000000 {
+               /* dram data rate, should be 1200, 1600, or 2400 */
+               datarate = <2400>;
+               cs-num = <2>;
+               u-boot,dm-spl;
+       };
+
+       sdh@d4280000 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
+               bus-width = <4>;
+               cap-sd-highspeed;
+               sdh-phy-module = <0>;
+               status = "okay";
+               u-boot,dm-spl;
+       };
+
+       /* eMMC */
+       sdh@d4281000 {
+               bus-width = <8>;
+               non-removable;
+               mmc-hs400-1_8v;
+               mmc-hs400-enhanced-strobe;
+               sdh-phy-module = <1>;
+               status = "okay";
+               u-boot,dm-spl;
+       };
+
+       spi@d420c000 {
+               status = "okay";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_qspi>;
+               u-boot,dm-spl;
+
+               spi-max-frequency = <15140000>;
+               flash@0 {
+                       compatible = "jedec,spi-nor";
+                       reg = <0>;
+                       spi-max-frequency = <26500000>;
+
+                       m25p,fast-read;
+                       broken-flash-reset;
+                       u-boot,dm-spl;
+                       status = "okay";
+               };
+       };
+
+       fuse@f0702800 {
+               status = "okay";
+               u-boot,dm-spl;
+       };
+};
+
+&pinctrl {
+       usbp1_vbus: usbp1_vbus {
+               pinctrl-single,pins =<
+                       K1X_PADCONF(GPIO_66, MUX_MODE0, (EDGE_NONE | PULL_UP | PAD_1V8_DS2))    /* drive_vbus1_iso */
+               >;
+       };
+
+       gpio80_pmx_func0: gpio80_pmx_func0 {
+               pinctrl-single,pins = <
+                       K1X_PADCONF(GPIO_80, MUX_MODE0, (EDGE_BOTH | PULL_UP | PAD_3V_DS4))  /* mmc cd */
+               >;
+       };
+};
+
diff --git a/arch/riscv/dts/k1-x_spm8821.dtsi b/arch/riscv/dts/k1-x_spm8821.dtsi
new file mode 100644 (file)
index 0000000..8bf14a0
--- /dev/null
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright (c) 2023 Spacemit, Inc */
+
+&i2c8 {
+       clock-frequency = <100000>;
+       u-boot,dm-spl;
+       status = "okay";
+
+       spm8821: pmic@41 {
+               compatible = "spacemit,spm8821";
+               reg = <0x41>;
+               bus = <8>;
+               u-boot,dm-spl;
+
+               regulators {
+                       /* buck */
+                       dcdc_6: DCDC_REG1 {
+                               regulator-name = "dcdc1";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3450000>;
+                               regulator-init-microvolt = <950000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       dcdc_7: DCDC_REG2 {
+                               regulator-name = "dcdc2";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3450000>;
+                       };
+
+                       dcdc_8: DCDC_REG3 {
+                               regulator-name = "dcdc3";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3450000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                       };
+
+                       dcdc_9: DCDC_REG4 {
+                               regulator-name = "dcdc4";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3450000>;
+                       };
+
+                       dcdc_10: DCDC_REG5 {
+                               regulator-name = "dcdc5";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3450000>;
+                       };
+
+                       dcdc_11: DCDC_REG6 {
+                               regulator-name = "dcdc6";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3450000>;
+                       };
+
+                       /* aldo */
+                       ldo_23: LDO_REG1 {
+                               regulator-name = "ldo1";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                               regulator-init-microvolt = <3300000>;
+                               regulator-boot-on;
+                               u-boot,dm-spl;
+                       };
+
+                       ldo_24: LDO_REG2 {
+                               regulator-name = "ldo2";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_25: LDO_REG3 {
+                               regulator-name = "ldo3";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_26: LDO_REG4 {
+                               regulator-name = "ldo4";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       /* dldo */
+                       ldo_27: LDO_REG5 {
+                               regulator-name = "ldo5";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_28: LDO_REG6 {
+                               regulator-name = "ldo6";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_29: LDO_REG7 {
+                               regulator-name = "ldo7";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_30: LDO_REG8 {
+                               regulator-name = "ldo8";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_31: LDO_REG9 {
+                               regulator-name = "ldo9";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_32: LDO_REG10 {
+                               regulator-name = "ldo10";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       ldo_33: LDO_REG11 {
+                               regulator-name = "ldo11";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3400000>;
+                       };
+
+                       sw_2: SWITCH_REG1 {
+                               regulator-name = "switch1";
+                       };
+               };
+       };
+};
+
diff --git a/arch/riscv/include/asm/arch-x60/ddr.h b/arch/riscv/include/asm/arch-x60/ddr.h
new file mode 100644 (file)
index 0000000..9db4697
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 spacemit, Inc.
+ */
+
+#ifndef _DDR_SPACEMIT_H
+#define _DDR_SPACEMIT_H
+
+int ddr_freq_max(void);
+u32 ddr_get_density(void);
+
+#endif /* _DDR_SPACEMIT_H */
diff --git a/arch/riscv/include/asm/arch-x60/gpio.h b/arch/riscv/include/asm/arch-x60/gpio.h
new file mode 100644 (file)
index 0000000..1d93145
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 spacemit, Inc.
+ */
+
+#ifndef _GPIO_SPACEMIT_H
+#define _GPIO_SPACEMIT_H
+
+/* It is only used for compiling */
+
+#endif /* _GPIO_SPACEMIT_H */
diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h
new file mode 100644 (file)
index 0000000..f541fb4
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2023 SiFive, Inc.
+ */
+
+#ifndef __RISCV_ATOMIC_H
+#define __RISCV_ATOMIC_H
+
+/* use the generic asm/atomic.h until we define a better one */
+
+#include <asm/system.h>
+#include <asm-generic/atomic.h>
+
+#endif
index 536629bbecb3571322fc679d8ef7972d6013db34..cb5f1b84a3159376caf00c4e90536e5c5ab4302b 100644 (file)
@@ -149,6 +149,43 @@ static inline unsigned long ffz(unsigned long word)
  * #define ffs(x) generic_ffs(x)
  */
 
+static inline int find_next_zero_bit(void *addr, int size, int offset)
+{
+       unsigned long *p = ((unsigned long *)addr) + (offset / BITS_PER_LONG);
+       unsigned long result = offset & ~(BITS_PER_LONG - 1);
+       unsigned long tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= (BITS_PER_LONG - 1);
+       if (offset) {
+               tmp = *(p++);
+               tmp |= ~0UL >> (BITS_PER_LONG - offset);
+               if (size < BITS_PER_LONG)
+                       goto found_first;
+               if (~tmp)
+                       goto found_middle;
+               size -= BITS_PER_LONG;
+               result += BITS_PER_LONG;
+       }
+       while (size & ~(BITS_PER_LONG - 1)) {
+               tmp = *(p++);
+               if (~tmp)
+                       goto found_middle;
+               result += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+
+found_first:
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
 /*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
@@ -158,6 +195,9 @@ static inline unsigned long ffz(unsigned long word)
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
+#define test_and_set_bit               __test_and_set_bit
+#define test_and_clear_bit             __test_and_clear_bit
+
 #define ext2_set_bit                   test_and_set_bit
 #define ext2_clear_bit                 test_and_clear_bit
 #define ext2_test_bit                  test_bit
index 874963d731169d38c91400d22aab401376940b26..b19c5d4b2e00acf3a9823cd6d51e338fd10fde30 100644 (file)
@@ -7,6 +7,38 @@
 #ifndef _ASM_RISCV_CACHE_H
 #define _ASM_RISCV_CACHE_H
 
+#ifndef __ASSEMBLY__
+#define cbo_clean(start)                       \
+       ({                                                              \
+               unsigned long __v = (unsigned long)(start); \
+               __asm__ __volatile__("cbo.clean"        \
+                                                        " 0(%0)"               \
+                                                        :                              \
+                                                        : "rK"(__v)    \
+                                                        : "memory");   \
+       })
+
+#define cbo_invalid(start)                     \
+       ({                                                              \
+               unsigned long __v = (unsigned long)(start); \
+               __asm__ __volatile__("cbo.inval"        \
+                                                        " 0(%0)"               \
+                                                        :                              \
+                                                        : "rK"(__v)    \
+                                                        : "memory");   \
+       })
+
+#define cbo_flush(start)                       \
+       ({                                                              \
+               unsigned long __v = (unsigned long)(start); \
+               __asm__ __volatile__("cbo.flush"        \
+                                                        " 0(%0)"               \
+                                                        :                              \
+                                                        : "rK"(__v)    \
+                                                        : "memory");   \
+       })
+#endif /* __ASSEMBLY__ */
+
 /* cache */
 void cache_flush(void);
 
index 9d8e43e394269883bec2883bb1e0e94334473419..ffa7649f3f9e16125d408b99c0b2afb6eb25454f 100644 (file)
@@ -7,15 +7,24 @@
 #ifndef __ASM_RISCV_SYSTEM_H
 #define __ASM_RISCV_SYSTEM_H
 
+#include <asm/csr.h>
+
 struct event;
 
 /*
- * Interrupt configuring macros.
- *
- * TODO
- *
+ * Interupt configuration macros
  */
 
+#define local_irq_save(__flags)                                 \
+    do {                                                        \
+        __flags = csr_read_clear(CSR_SSTATUS, SR_SIE) & SR_SIE; \
+    } while (0)
+
+#define local_irq_restore(__flags)              \
+    do {                                        \
+        csr_set(CSR_SSTATUS, __flags & SR_SIE); \
+    } while (0)
+
 /* Hook to set up the CPU (called from SPL too) */
 int riscv_cpu_setup(void *ctx, struct event *event);
 
index 670d9c9ebcfb665b5cf2e791f342695d711d631f..db59196da72c710021156997afbc554318fb3fc3 100644 (file)
@@ -67,11 +67,11 @@ static void boot_prep_linux(bootm_headers_t *images)
        if (CONFIG_IS_ENABLED(OF_LIBFDT) && CONFIG_IS_ENABLED(LMB) && images->ft_len) {
                debug("using: FDT\n");
                if (image_setup_linux(images)) {
-                       printf("FDT creation failed! hanging...");
+                       pr_info("FDT creation failed! hanging...");
                        hang();
                }
        } else {
-               printf("Device tree not found or missing FDT support\n");
+               pr_info("Device tree not found or missing FDT support\n");
                hang();
        }
 }
index 686e699efbcde2d9ad90a2bf814263118a38592e..60f9c622203ab833efaa05f8766390cbdd975bdd 100644 (file)
@@ -74,3 +74,20 @@ __weak int dcache_status(void)
 __weak void enable_caches(void)
 {
 }
+
+
+__weak void branch_predict_enable(void)
+{
+}
+
+__weak void branch_predict_disable(void)
+{
+}
+
+__weak void prefetch_enable(void)
+{
+}
+
+__weak void prefetch_disable(void)
+{
+}
index 36c16e9be2ae402754344ef17e0de6048362a584..28eb3daff3058ac322fc17e2775ac71bc415b1e6 100644 (file)
@@ -51,7 +51,7 @@ int riscv_fdt_copy_resv_mem_node(const void *src, void *dst)
         */
        err = fdt_open_into(dst, dst, fdt_totalsize(dst) + 1024);
        if (err < 0) {
-               printf("Device Tree can't be expanded to accommodate new node");
+               pr_info("Device Tree can't be expanded to accommodate new node");
                return err;
        }
 
@@ -133,6 +133,41 @@ int board_fix_fdt(void *fdt)
 }
 #endif
 
+#ifdef CONFIG_FDT_ADD_MEMORY_NODE
+#if CONFIG_NR_DRAM_BANKS > 4
+#define _MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS
+#else
+#define _MEMORY_BANKS_MAX 4
+#endif
+/*
+ * fdt_pack_reg - pack address and size array into the "reg"-suitable stream
+ */
+static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size,
+                       int n)
+{
+       int i;
+       int address_cells = fdt_address_cells(fdt, 0);
+       int size_cells = fdt_size_cells(fdt, 0);
+       char *p = buf;
+
+       for (i = 0; i < n; i++) {
+               if (address_cells == 2)
+                       *(fdt64_t *)p = cpu_to_fdt64(address[i]);
+               else
+                       *(fdt32_t *)p = cpu_to_fdt32(address[i]);
+               p += 4 * address_cells;
+
+               if (size_cells == 2)
+                       *(fdt64_t *)p = cpu_to_fdt64(size[i]);
+               else
+                       *(fdt32_t *)p = cpu_to_fdt32(size[i]);
+               p += 4 * size_cells;
+       }
+
+       return p - (char *)buf;
+}
+#endif
+
 int arch_fixup_fdt(void *blob)
 {
        int err;
@@ -161,6 +196,53 @@ int arch_fixup_fdt(void *blob)
                return log_msg_ret("could not set boot-hartid", err);
 #endif
 
+
+#ifdef CONFIG_FDT_ADD_MEMORY_NODE
+       u8 tmp[_MEMORY_BANKS_MAX * 16];
+       u64 ram_base[1];
+       u64 ram_size[1];
+       char memstart[32];
+       int nodeoffset, len;
+
+       /* delete memory node before add new memory node. */
+       do {
+               nodeoffset = fdt_subnode_offset(blob, 0, "memory");
+               if (nodeoffset >= 0) {
+                       fdt_del_node(blob, nodeoffset);
+               }
+       } while(nodeoffset >= 0);
+
+       for (int bank_index = CONFIG_NR_DRAM_BANKS - 1; bank_index >= 0; bank_index--){
+               if (0 == gd->bd->bi_dram[bank_index].size)
+                       continue;
+
+               memset(memstart, 0, 32);
+               sprintf(memstart, "memory@%llx", gd->bd->bi_dram[bank_index].start);
+
+               ram_base[0] = gd->bd->bi_dram[bank_index].start;
+               ram_size[0] = gd->bd->bi_dram[bank_index].size;
+
+               nodeoffset = fdt_add_subnode(blob, 0, memstart);
+
+               err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
+                               sizeof("memory"));
+               if (err < 0) {
+                       pr_info("WARNING: could not set %s %s.\n", "device_type",
+                                       fdt_strerror(err));
+                       return err;
+               }
+
+               len = fdt_pack_reg(blob, tmp, ram_base, ram_size, 1);
+
+               err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
+               if (err < 0) {
+                       pr_info("WARNING: could not set %s %s.\n",
+                                       "reg", fdt_strerror(err));
+                       return err;
+               }
+       }
+#endif
+
        /* Copy the reserved-memory node to the DT used by OS */
        err = riscv_fdt_copy_resv_mem_node(gd->fdt_blob, blob);
        if (err < 0)
index 100be2e9662e480c11e5c68c8d21851feb251edb..8e01327a7e2d5edbaeb225b0362cad29b647217a 100644 (file)
@@ -28,25 +28,25 @@ static void show_efi_loaded_images(uintptr_t epc)
 static void show_regs(struct pt_regs *regs)
 {
 #ifdef CONFIG_SHOW_REGS
-       printf("\nSP:  " REG_FMT " GP:  " REG_FMT " TP:  " REG_FMT "\n",
+       pr_crit("\nSP:  " REG_FMT " GP:  " REG_FMT " TP:  " REG_FMT "\n",
               regs->sp, regs->gp, regs->tp);
-       printf("T0:  " REG_FMT " T1:  " REG_FMT " T2:  " REG_FMT "\n",
+       pr_crit("T0:  " REG_FMT " T1:  " REG_FMT " T2:  " REG_FMT "\n",
               regs->t0, regs->t1, regs->t2);
-       printf("S0:  " REG_FMT " S1:  " REG_FMT " A0:  " REG_FMT "\n",
+       pr_crit("S0:  " REG_FMT " S1:  " REG_FMT " A0:  " REG_FMT "\n",
               regs->s0, regs->s1, regs->a0);
-       printf("A1:  " REG_FMT " A2:  " REG_FMT " A3:  " REG_FMT "\n",
+       pr_crit("A1:  " REG_FMT " A2:  " REG_FMT " A3:  " REG_FMT "\n",
               regs->a1, regs->a2, regs->a3);
-       printf("A4:  " REG_FMT " A5:  " REG_FMT " A6:  " REG_FMT "\n",
+       pr_crit("A4:  " REG_FMT " A5:  " REG_FMT " A6:  " REG_FMT "\n",
               regs->a4, regs->a5, regs->a6);
-       printf("A7:  " REG_FMT " S2:  " REG_FMT " S3:  " REG_FMT "\n",
+       pr_crit("A7:  " REG_FMT " S2:  " REG_FMT " S3:  " REG_FMT "\n",
               regs->a7, regs->s2, regs->s3);
-       printf("S4:  " REG_FMT " S5:  " REG_FMT " S6:  " REG_FMT "\n",
+       pr_crit("S4:  " REG_FMT " S5:  " REG_FMT " S6:  " REG_FMT "\n",
               regs->s4, regs->s5, regs->s6);
-       printf("S7:  " REG_FMT " S8:  " REG_FMT " S9:  " REG_FMT "\n",
+       pr_crit("S7:  " REG_FMT " S8:  " REG_FMT " S9:  " REG_FMT "\n",
               regs->s7, regs->s8, regs->s9);
-       printf("S10: " REG_FMT " S11: " REG_FMT " T3:  " REG_FMT "\n",
+       pr_crit("S10: " REG_FMT " S11: " REG_FMT " T3:  " REG_FMT "\n",
               regs->s10, regs->s11, regs->t3);
-       printf("T4:  " REG_FMT " T5:  " REG_FMT " T6:  " REG_FMT "\n",
+       pr_crit("T4:  " REG_FMT " T5:  " REG_FMT " T6:  " REG_FMT "\n",
               regs->t4, regs->t5, regs->t6);
 #endif
 }
@@ -75,12 +75,14 @@ static void show_code(ulong epc)
        u16 *pos = (u16 *)(epc & ~1UL);
        int i, len = instr_len(*pos);
 
-       printf("\nCode: ");
-       for (i = -8; i; ++i)
-               printf("%04x ", pos[i]);
-       printf("(");
-       for (i = 0; i < len; ++i)
-               printf("%04x%s", pos[i], i + 1 == len ? ")\n" : " ");
+       pr_crit("\nCode: ");
+       for (i = -8; i; ++i){
+               pr_crit("%04x ", pos[i]);
+       }
+       pr_crit("(");
+       for (i = 0; i < len; ++i){
+               pr_crit("%04x%s", pos[i], i + 1 == len ? ")\n" : " ");
+       }
 }
 
 static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
@@ -104,17 +106,20 @@ static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
                "Store/AMO page fault",
        };
 
-       if (code < ARRAY_SIZE(exception_code))
-               printf("Unhandled exception: %s\n", exception_code[code]);
-       else
-               printf("Unhandled exception code: %ld\n", code);
+       if (code < ARRAY_SIZE(exception_code)){
+               pr_crit("Unhandled exception: %s\n", exception_code[code]);
+       }
+       else{
+               pr_crit("Unhandled exception code: %ld\n", code);
+       }
 
-       printf("EPC: " REG_FMT " RA: " REG_FMT " TVAL: " REG_FMT "\n",
+       pr_crit("EPC: " REG_FMT " RA: " REG_FMT " TVAL: " REG_FMT "\n",
               epc, regs->ra, tval);
        /* Print relocation adjustments, but only if gd is initialized */
-       if (gd && gd->flags & GD_FLG_RELOC)
-               printf("EPC: " REG_FMT " RA: " REG_FMT " reloc adjusted\n",
+       if (gd && gd->flags & GD_FLG_RELOC){
+               pr_crit("EPC: " REG_FMT " RA: " REG_FMT " reloc adjusted\n",
                       epc - gd->reloc_off, regs->ra - gd->reloc_off);
+       }
 
        show_regs(regs);
        show_code(epc);
index 8779c619cc5abd1ab4f388bac9054b6786281ecc..2c97f38ebf2cb19520aa2f9f067123f6f9abcf9e 100644 (file)
@@ -9,9 +9,9 @@
 
 int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-       printf("resetting ...\n");
+       pr_info("resetting ...\n");
 
-       printf("reset not supported yet\n");
+       pr_info("reset not supported yet\n");
        hang();
 
        return 0;
diff --git a/board/spacemit/k1-x/Kconfig b/board/spacemit/k1-x/Kconfig
new file mode 100644 (file)
index 0000000..6ec53bc
--- /dev/null
@@ -0,0 +1,100 @@
+if TARGET_SPACEMIT_K1X
+
+config SYS_BOARD
+       default "k1-x"
+
+config SYS_VENDOR
+       default "spacemit"
+
+config SYS_CPU
+       default "x60"
+
+config SYS_CONFIG_NAME
+       default "k1-x"
+
+config SYS_TEXT_BASE
+       default 0x81200000 if SPL
+       default 0x80000000 if !RISCV_SMODE
+       default 0x80200000 if RISCV_SMODE && ARCH_RV64I
+       default 0x80400000 if RISCV_SMODE && ARCH_RV32I
+
+config SPL_TEXT_BASE
+       default 0x20100000
+
+config SPL_OPENSBI_LOAD_ADDR
+       hex
+       default 0x21000000
+
+config FDT_ADD_MEMORY_NODE
+       bool "enable to add memory node to fdt before boot kernel"
+       default n
+
+config SPACEMIT_BUILD_BIN
+       bool "build fsbl.bin for spacemit image"
+       default n
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+       def_bool y
+       select SPACEMIT_X60
+       select FDT_ADD_MEMORY_NODE
+       imply AHCI
+       imply SMP
+       imply BOARD_LATE_INIT
+       imply PCI_INIT_R
+       imply SPL_RAM_SUPPORT
+       imply SPL_RAM_DEVICE
+       imply CMD_PCI
+       imply CMD_POWEROFF
+       imply CMD_SBI
+       imply CMD_SCSI
+       imply CMD_PING
+       imply CMD_EXT2
+       imply CMD_EXT4
+       imply CMD_FAT
+       imply CMD_FS_GENERIC
+       imply DOS_PARTITION
+       imply ISO_PARTITION
+       imply EFI_PARTITION
+       imply SCSI_AHCI
+       imply AHCI_PCI
+       imply E1000
+       imply NVME
+       imply PCI
+       imply PCIE_ECAM_GENERIC
+       imply SCSI
+       imply DM_SCSI
+       imply SYS_NS16550
+       imply SIFIVE_SERIAL
+       imply HTIF_CONSOLE if 64BIT
+       imply SYSRESET
+       imply SYSRESET_CMD_POWEROFF
+       imply SYSRESET_SYSCON
+       imply VIRTIO_MMIO
+       imply VIRTIO_PCI
+       imply VIRTIO_NET
+       imply VIRTIO_BLK
+       imply MTD_NOR_FLASH
+       imply CFI_FLASH
+       imply OF_HAS_PRIOR_STAGE
+
+choice
+       prompt "product board"
+       default K1_X_BOARD_FPGA
+
+config K1_X_BOARD_FPGA
+       bool "k1-x board fpga"
+       help
+         k1-x board is fpga.
+
+config K1_X_BOARD_ASIC
+       bool "k1-x board asic"
+       help
+         k1-x board is asic.
+
+config K1_X_BOARD_SIMULATION
+       bool "k1-x board simulation"
+       help
+         k1-x board is simulation.
+endchoice
+
+endif
diff --git a/board/spacemit/k1-x/Makefile b/board/spacemit/k1-x/Makefile
new file mode 100644 (file)
index 0000000..a55f7b1
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2022-2023 Spacemit, Inc
+
+obj-y  += k1x.o
+obj-$(CONFIG_SPL_BUILD)        += spl.o k1x-i2c-eeprom.o
+obj-$(CONFIG_SPLASH_SOURCE) +=splash.o
diff --git a/board/spacemit/k1-x/config.mk b/board/spacemit/k1-x/config.mk
new file mode 100644 (file)
index 0000000..459dc3f
--- /dev/null
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2022-2024 Spacemit, Inc
+
+quiet_cmd_build_itb = BUILD   $2
+cmd_build_itb = \
+       mkdir -p $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/dtb && \
+       cp $(srctree)/arch/$(ARCH)/dts/*.dtb $(srctree)/ &&\
+       cp $(srctree)/arch/$(ARCH)/dts/*.dtb \
+               $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/dtb/ && \
+       cp $(srctree)/u-boot-nodtb.bin \
+               $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/ && \
+       $(srctree)/tools/mkimage -f \
+               $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/configs/uboot_fdt.its \
+               -r $(srctree)/$2;\
+       rm -rf $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/dtb && \
+       rm -f $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/u-boot-nodtb.bin
+
+quiet_cmd_build_default_env = BUILD   $2
+cmd_build_default_env = \
+       $(srctree)/scripts/get_default_envs.sh $(srctree) > $(srctree)/u-boot-env-default.txt && \
+       $(srctree)/tools/mkenvimage -s $(CONFIG_ENV_SIZE) -o $(srctree)/u-boot-env-default.bin \
+               $(srctree)/u-boot-env-default.txt
+
+MRPROPER_FILES += $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/u-boot-nodtb.bin
+MRPROPER_FILES += $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/u-boot-spl.bin
+MRPROPER_FILES += u-boot.itb FSBL.bin u-boot-env-default.*
+MRPROPER_FILES += bootinfo_spinor.bin bootinfo_spinand.bin bootinfo_emmc.bin bootinfo_sd.bin
+MRPROPER_FILES += k1-x_evb.dtb k1-x_deb2.dtb k1-x_deb1.dtb k1-x_spl.dtb
+MRPROPER_DIRS += $(srctree)/board/$(CONFIG_SYS_VENDOR)/$(CONFIG_SYS_BOARD)/dtb
+
+u-boot.itb: u-boot-nodtb.bin u-boot-dtb.bin u-boot.dtb FORCE
+       $(call if_changed,build_itb,$@)
+
+ifneq ($(CONFIG_SPL_BUILD),)
+INPUTS-y += FSBL.bin
+
+FSBL.bin: spl/u-boot-spl.bin FORCE
+else
+INPUTS-y += u-boot-env-default.bin
+u-boot-env-default.bin: u-boot-nodtb.bin FORCE
+       $(call if_changed,build_default_env,$@)
+endif
diff --git a/board/spacemit/k1-x/configs/bootinfo_emmc.json b/board/spacemit/k1-x/configs/bootinfo_emmc.json
new file mode 100755 (executable)
index 0000000..7d14ded
--- /dev/null
@@ -0,0 +1,50 @@
+{
+  "_comment": {
+    "info": "bootinfo build configuration script",
+    "key word": {
+      "image": "image definition",
+      "module": "image module definition",
+      "data": "image item data config"
+    }
+  },
+  "info": {
+    "arch": "RISCV64",
+    "description": "spacemit k1x eMMC bootinfo image"
+  },
+  "image": [
+    {
+      "module": "bootinfo",
+      "data": [
+        {
+          "structure": [
+            "name, header, 0",
+            "magic, 0xB00714F0, 4",
+            "version, 0x00010001, 4",
+            "flash_type, eMMC, 4",
+            "mid, 0, 1",
+            "reserved, 0, 1",
+            "did, 0, 2",
+            "page_size, 512, 4",
+            "block_size, 0x10000, 4",
+            "total_size, 0x10000000, 4",
+            "multi_plane, 0, 1",
+            "reserved, 0, 3",
+            "spl0_offset, 0x200, 4",
+            "spl1_offset, 0x00000, 4",
+            "spl_size_limit, 0x36000, 4",
+            "partitiontable0_offset, 0, 4",
+            "partitiontable1_offset, 0, 4",
+            "reserved, 0, 12"
+          ]
+        },
+        {
+          "structure": [
+            "name, crc32_sum, 0",
+            "crc, crc32(header), 4",
+            "pad, 0, 12"
+          ]
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/board/spacemit/k1-x/configs/bootinfo_sd.json b/board/spacemit/k1-x/configs/bootinfo_sd.json
new file mode 100755 (executable)
index 0000000..a582d86
--- /dev/null
@@ -0,0 +1,50 @@
+{
+  "_comment": {
+    "info": "bootinfo build configuration script",
+    "key word": {
+      "image": "image definition",
+      "module": "image module definition",
+      "data": "image item data config"
+    }
+  },
+  "info": {
+    "arch": "RISCV64",
+    "description": "spacemit k1x sdcard bootinfo image"
+  },
+  "image": [
+    {
+      "module": "bootinfo",
+      "data": [
+        {
+          "structure": [
+            "name, header, 0",
+            "magic, 0xB00714F0, 4",
+            "version, 0x00010001, 4",
+            "flash_type, SDC, 4",
+            "mid, 0, 1",
+            "reserved, 0, 1",
+            "did, 0, 2",
+            "page_size, 512, 4",
+            "block_size, 0x10000, 4",
+            "total_size, 0x10000000, 4",
+            "multi_plane, 0, 1",
+            "reserved, 0, 3",
+            "spl0_offset, 0x20000, 4",
+            "spl1_offset, 0x80000, 4",
+            "spl_size_limit, 0x36000, 4",
+            "partitiontable0_offset, 0, 4",
+            "partitiontable1_offset, 0, 4",
+            "reserved, 0, 12"
+          ]
+        },
+        {
+          "structure": [
+            "name, crc32_sum, 0",
+            "crc, crc32(header), 4",
+            "pad, 0, 12"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/board/spacemit/k1-x/configs/bootinfo_spinand.json b/board/spacemit/k1-x/configs/bootinfo_spinand.json
new file mode 100755 (executable)
index 0000000..4b7b199
--- /dev/null
@@ -0,0 +1,50 @@
+{
+  "_comment": {
+    "info": "bootinfo build configuration script",
+    "key word": {
+      "image": "image definition",
+      "module": "image module definition",
+      "data": "image item data config"
+    }
+  },
+  "info": {
+    "arch": "RISCV64",
+    "description": "spacemit k1x spinand bootinfo image"
+  },
+  "image": [
+    {
+      "module": "bootinfo",
+      "data": [
+        {
+          "structure": [
+            "name, header, 0",
+            "magic, 0xB00714F0, 4",
+            "version, 0x00010001, 4",
+            "flash_type, NAND, 4",
+            "mid, 0, 1",
+            "reserved, 0, 1",
+            "did, 0, 2",
+            "page_size, 2048, 4",
+            "block_size, 0x20000, 4",
+            "total_size, 0x10000000, 4",
+            "multi_plane, 0, 1",
+            "reserved, 0, 3",
+            "spl0_offset, 0x20000, 4",
+            "spl1_offset, 0x80000, 4",
+            "spl_size_limit, 0x36000, 4",
+            "partitiontable0_offset, 0, 4",
+            "partitiontable1_offset, 0, 4",
+            "reserved, 0, 12"
+          ]
+        },
+        {
+          "structure": [
+            "name, crc32_sum, 0",
+            "crc, crc32(header), 4",
+            "pad, 0, 12"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/board/spacemit/k1-x/configs/bootinfo_spinor.json b/board/spacemit/k1-x/configs/bootinfo_spinor.json
new file mode 100755 (executable)
index 0000000..cb7228f
--- /dev/null
@@ -0,0 +1,50 @@
+{
+  "_comment": {
+    "info": "bootinfo build configuration script",
+    "key word": {
+      "image": "image definition",
+      "module": "image module definition",
+      "data": "image item data config"
+    }
+  },
+  "info": {
+    "arch": "RISCV64",
+    "description": "spacemit k1x spinor bootinfo image"
+  },
+  "image": [
+    {
+      "module": "bootinfo",
+      "data": [
+        {
+          "structure": [
+            "name, header, 0",
+            "magic, 0xB00714F0, 4",
+            "version, 0x00010001, 4",
+            "flash_type, NORF, 4",
+            "mid, 0, 1",
+            "reserved, 0, 1",
+            "did, 0, 2",
+            "page_size, 256, 4",
+            "block_size, 0x10000, 4",
+            "total_size, 0x100000, 4",
+            "multi_plane, 0, 1",
+            "reserved, 0, 3",
+            "spl0_offset, 0x20000, 4",
+            "spl1_offset, 0x70000, 4",
+            "spl_size_limit, 0x36000, 4",
+            "partitiontable0_offset, 0, 4",
+            "partitiontable1_offset, 0, 4",
+            "reserved, 0, 12"
+          ]
+        },
+        {
+          "structure": [
+            "name, crc32_sum, 0",
+            "crc, crc32(header), 4",
+            "pad, 0, 12"
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/board/spacemit/k1-x/configs/fsbl.json b/board/spacemit/k1-x/configs/fsbl.json
new file mode 100755 (executable)
index 0000000..8261e3b
--- /dev/null
@@ -0,0 +1,196 @@
+{
+  "_comment": {
+    "info": "bootinfo build configuration script",
+    "key word": {
+      "image": "image definition",
+      "module": "image module definition",
+      "data": "image item data config"
+    }
+  },
+  "info": {
+    "arch": "RISCV64",
+    "description": "spacemit k1x fsbl image"
+  },
+  "image": [
+    {
+      "module": "ROTPK",
+      "data": [
+        {
+          "pubkey": {
+            "name": "rsakeypair0",
+            "algorithm": "RSA2048",
+            "source": "key/rsakeypair0_prv.key",
+            "align": 256
+          }
+        }
+      ]
+    },
+    {
+      "module": "image_header",
+      "data": [
+        {
+          "structure": [
+            "name, header0, 0",
+            "magic, AIHD, 4",
+            "version, 1, 1",
+            "secure, 0, 1",
+            "reserved, 0, 2",
+            "imgsize, 0x1000, 8",
+            "load_addr, 0, 8",
+            "pad, 0xA5, 8"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "image_config",
+      "data": [
+        {
+          "structure": [
+            "name, keydata, 0",
+            "key_default, 0, 4",
+            "table_num, 4, 4",
+            {
+              "structure": [
+                "name, keytable0, 0",
+                "key_name, spl, 16",
+                "key_id, 0, 4"
+              ]
+            },
+            {
+              "structure": [
+                "name, keytable1, 0",
+                "key_name, uboot, 16",
+                "key_id, 1, 4"
+              ]
+            },
+            {
+              "structure": [
+                "name, keytable2, 0",
+                "key_name, kernel, 16",
+                "key_id, 2, 4"
+              ]
+            },
+            {
+              "structure": [
+                "name, keytable3, 0",
+                "key_name, rootfs, 16",
+                "key_id, 3, 4"
+              ]
+            },
+            "reserved, 0, 320",
+            {
+              "hash": {
+                "name": "rotpk_hash",
+                "algorithm": "SHA256",
+                "source": "rsakeypair0",
+                "align": 32
+              }
+            },
+            "pad, 0, 40"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "oem_pubkey",
+      "data": [
+        {
+          "structure": [
+            "name, oem_key, 0",
+            {
+              "pubkey": {
+                "name": "spl_pubkey",
+                "algorithm": "RSA2048",
+                "source": "key/spl_pubkey_prv.key",
+                "align": 256
+              }
+            },
+            {
+              "pubkey": {
+                "name": "uboot_pubkey",
+                "algorithm": "RSA2048",
+                "source": "key/uboot_pubkey_pub.key",
+                "align": 256
+              }
+            },
+            {
+              "pubkey": {
+                "name": "kernel_pubkey",
+                "algorithm": "RSA2048",
+                "source": "key/kernel_pubkey_pub.key",
+                "align": 256
+              }
+            },
+            {
+              "pubkey": {
+                "name": "rootfs_pubkey",
+                "algorithm": "RSA2048",
+                "source": "key/rootfs_pubkey_pub.key",
+                "align": 256
+              }
+            },
+            "reserved, 0, 1024"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "cert0",
+      "data": [
+        {
+          "signature": {
+            "name": "signature0",
+            "algorithm": "SHA256+RSA2048",
+            "key": "rsakeypair0",
+            "source": "header0 + keydata + oem_key",
+            "align": 256
+          }
+        }
+      ]
+    },
+    {
+      "module": "padding",
+      "data": [
+        {
+          "structure": [
+            "pad, 0, 992"
+          ]
+        }
+      ]
+    },
+    {
+      "module": "spl",
+      "data": [
+        {
+          "structure": [
+            "name, header1, 0",
+            "magic, AIHD, 4",
+            "version, 1, 1",
+            "secure, 0, 1",
+            "reserved, 0, 2",
+            "imgsize, sizeof(fsbl), 8",
+            "load_addr, 0, 8",
+            "pad, 0xA5, 8"
+          ]
+        },
+        {
+          "file": {
+            "name": "fsbl",
+            "source": "../u-boot-spl.bin",
+            "align": 32
+          }
+        },
+        {
+          "signature": {
+            "name": "signature1",
+            "algorithm": "SHA256+RSA2048",
+            "key": "spl_pubkey",
+            "source": "header1 + fsbl",
+            "align": 256
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/board/spacemit/k1-x/configs/uboot_fdt.its b/board/spacemit/k1-x/configs/uboot_fdt.its
new file mode 100644 (file)
index 0000000..1797fa4
--- /dev/null
@@ -0,0 +1,153 @@
+/dts-v1/;
+
+/ {
+       description = "U-boot FIT image for k1x";
+       #address-cells = <2>;
+       fit,fdt-list = "of-list";
+
+       images {
+               uboot {
+                       description = "U-Boot";
+                       type = "standalone";
+                       os = "U-Boot";
+                       arch = "riscv";
+                       compression = "none";
+                       load = <0x0 0x00200000>;
+                       data = /incbin/("../u-boot-nodtb.bin");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+
+               fdt_1 {
+                       description = "k1-x_evb";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_evb.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_2 {
+                       description = "k1-x_deb1";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_deb1.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_3 {
+                       description = "k1-x_deb2";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_deb2.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_4 {
+                       description = "k1-x_hs450";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_hs450.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_5 {
+                       description = "k1-x_kx312";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_kx312.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_6 {
+                       description = "k1-x_MINI-PC";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_MINI-PC.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_7 {
+                       description = "k1-x_mingo";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_mingo.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_8 {
+                       description = "k1-x_MUSE-N1";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_MUSE-N1.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+               fdt_9 {
+                       description = "k1-x_MUSE-Pi";
+                       type = "flat_dt";
+                       compression = "none";
+                       data = /incbin/("../dtb/k1-x_MUSE-Pi.dtb");
+                       hash-1 {
+                               algo = "crc32";
+                       };
+               };
+       };
+
+       configurations {
+               default = "conf_1";
+               conf_1 {
+                       description = "k1-x_evb";
+                       loadables = "uboot";
+                       fdt = "fdt_1";
+               };
+               conf_2 {
+                       description = "k1-x_deb1";
+                       loadables = "uboot";
+                       fdt = "fdt_2";
+               };
+               conf_3 {
+                       description = "k1-x_deb2";
+                       loadables = "uboot";
+                       fdt = "fdt_3";
+               };
+               conf_4 {
+                       description = "k1-x_hs450";
+                       loadables = "uboot";
+                       fdt = "fdt_4";
+               };
+               conf_5 {
+                       description = "k1-x_kx312";
+                       loadables = "uboot";
+                       fdt = "fdt_5";
+               };
+               conf_6 {
+                       description = "k1-x_MINI-PC";
+                       loadables = "uboot";
+                       fdt = "fdt_6";
+               };
+               conf_7 {
+                       description = "k1-x_mingo";
+                       loadables = "uboot";
+                       fdt = "fdt_7";
+               };
+               conf_8 {
+                       description = "k1-x_MUSE-N1";
+                       loadables = "uboot";
+                       fdt = "fdt_8";
+               };
+               conf_9 {
+                       description = "k1-x_MUSE-Pi";
+                       loadables = "uboot";
+                       fdt = "fdt_9";
+               };
+       };
+};
diff --git a/board/spacemit/k1-x/k1-x.env b/board/spacemit/k1-x/k1-x.env
new file mode 100644 (file)
index 0000000..3b30e07
--- /dev/null
@@ -0,0 +1,165 @@
+// Common parameter
+earlycon=sbi
+console=ttyS0,115200
+init=/init
+bootdelay=0
+baudrate=115200
+loglevel=8
+stderr=serial
+stdin=serial,usbkbd
+stdout=serial
+
+//partitions/mtdparts/mtdids would set while flashing env.bin
+
+// Nor flash rootfs device
+nor_root=/dev/mtdblock6
+nor_rootfstype=squashfs
+
+// eMMC/SDCard rootfs device
+mmc_rootfstype=ext4
+
+// Get "rootfs" partition number in decimal, and set var "mmc_root"
+// Variable "boot_devnum" is set during board_lat_init()
+set_mmc_root=part number mmc ${boot_devnum} rootfs rootfs_part; \
+             setexpr rootfs_part ${rootfs_part} + 0; \
+             setenv mmc_root "/dev/mmcblk${boot_devnum}p${rootfs_part}";
+
+set_nvme_root=part number nvme ${boot_devnum} rootfs rootfs_part; \
+             setexpr rootfs_part ${rootfs_part} + 0; \
+             setenv nvme_root "/dev/nvme${boot_devnum}n1p${rootfs_part}";
+
+//override here, otherwise gen random addr and save to eeprom by uboot
+//ethaddr=fe:fe:fe:22:22:01
+//eth1addr=fe:fe:fe:22:22:02
+
+ipaddr=10.0.92.100
+netmask=255.255.255.0
+serverip=10.0.92.134
+gatewayip=10.0.92.1
+net_data_path=net_flash_file/net_flash_file/
+
+preboot=
+kernel_addr_r=0x10000000
+ramdisk_addr=0x20000000
+ramdisk_size=-
+ramdisk_combo=-
+knl_name=Image.itb
+ramdisk_name=initramfs-generic.img
+dtb_dir=
+dtb_name=k1-x_evb.dtb
+dtb_addr=0x1F000000
+splashfile=bianbu.bmp
+mdio_intf=
+phyaddr0=1
+phy_link_time=10000
+netdev=eth0
+
+// Common boot args
+commonargs=setenv bootargs earlycon=${earlycon} earlyprintk console=tty1 console=${console} loglevel=${loglevel} clk_ignore_unused swiotlb=65536 rdinit=${init}
+
+//detect product_name from env and select dtb file to load
+dtb_env=if test -n "${product_name}"; then \
+                if test "${product_name}" = k1_evb; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_evb.dtb; \
+                elif test "${product_name}" = k1_deb1; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_deb1.dtb; \
+                elif test "${product_name}" = k1_deb2; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_deb2.dtb; \
+                elif test "${product_name}" = k1_hs450; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_hs450.dtb; \
+                elif test "${product_name}" = k1_kx312; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_kx312.dtb; \
+                elif test "${product_name}" = k1_mingo; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_mingo.dtb; \
+                elif test "${product_name}" = k1_MINI-PC; then \
+                    setenv dtb_name ${dtb_dir}/k1-x_MINI-PC.dtb; \
+                else \
+                    echo "falling to default dtb: ${dtb_dir}/${product_name}.dtb"; \
+                    setenv dtb_name  ${dtb_dir}/${product_name}.dtb; \
+                fi; \
+            fi;
+
+detect_dtb=echo "product_name: ${product_name}"; run dtb_env; echo "select ${dtb_name} to load";
+
+loadknl=echo "Loading kernel..."; \
+            load ${bootfs_devname} ${boot_devnum}:${bootfs_part} ${kernel_addr_r} ${knl_name};
+
+loadramdisk=echo "Loading ramdisk ..."; \
+            if load ${bootfs_devname} ${boot_devnum}:${bootfs_part} ${ramdisk_addr} ${ramdisk_name}; then \
+                size ${bootfs_devname} ${boot_devnum}:${bootfs_part} ${ramdisk_name}; \
+                setenv ramdisk_size ${filesize}; \
+                setenv ramdisk_combo ${ramdisk_addr}:${ramdisk_size}; \
+            else \
+                echo "load ramdisk from bootfs fail, use built-in ramdisk"; \
+                setenv ramdisk_addr -; \
+            fi;
+
+loaddtb=echo "Loading dtb..."; \
+            if load ${bootfs_devname} ${boot_devnum}:${bootfs_part} ${dtb_addr} ${dtb_name}; then \
+            else \
+                echo "load dtb from bootfs fail, use built-in dtb"; \
+                setenv dtb_addr ""; \
+            fi;
+
+// Nor+ssd boot combo
+set_nor_args=setenv bootargs ${bootargs} mtdparts=${mtdparts} root=${nvme_root} rootfstype=ext4
+nor_boot=echo "Try to boot from NVMe ..."; \
+         run commonargs; \
+         run set_nvme_root; \
+         run set_nor_args; \
+         run detect_dtb; \
+         run loadknl; \
+         run loaddtb; \
+         run loadramdisk; \
+         bootm ${kernel_addr_r} ${ramdisk_combo} ${dtb_addr}; \
+         echo "########### boot kernel failed by default config, check your boot config #############"
+
+//##############################################################################
+// eMMC/SDCard boot
+//##############################################################################
+set_mmc_args=setenv bootargs "${bootargs}" root=${mmc_root} rootwait rootfstype=${mmc_rootfstype};
+
+mmc_boot=echo "Try to boot from MMC${boot_devnum} ..."; \
+         run commonargs; \
+         run set_mmc_root; \
+         run set_mmc_args; \
+         run detect_dtb; \
+         run loadknl; \
+         run loaddtb; \
+         run loadramdisk; \
+         bootm ${kernel_addr_r} ${ramdisk_combo} ${dtb_addr}; \
+         echo "########### boot kernel failed by default config, check your boot config #############"
+
+// Variable "boot_device" is set during board_late_init()
+autoboot=if test ${boot_device} = nand; then \
+                run nand_boot; \
+        elif test ${boot_device} = nor; then \
+                run nor_boot; \
+        elif test ${boot_device} = mmc; then \
+                run mmc_boot; \
+        fi;
+
+bootcmd=run autoboot; echo "run autoboot"
+
+// Boot menu definitions
+boot_default=echo "Current Boot Device: ${boot_device}"
+flash_default=echo "Returning to Boot Menu..."
+flash_from_usb=echo "recovery from usb...... "; \
+                                         flash_image usb;
+flash_from_mmc=echo "recovery from mmc...... " \
+                                         flash_image mmc;
+flash_from_net=echo "recovery from net...... " \
+                                         flash_image net;
+
+bootmenu_delay=5
+bootmenu_0="-------- Boot Options --------"=run boot_default
+bootmenu_1="Boot from Nor"=run nor_boot
+bootmenu_2="Boot from Nand"=run nand_boot
+bootmenu_3="Boot from MMC"=run mmc_boot
+bootmenu_4="Autoboot"=run autoboot
+bootmenu_5="Show current Boot Device"=run boot_default
+bootmenu_6="-------- Flash Options --------"=run flash_default
+bootmenu_7="recovery from usb"=run flash_from_usb
+bootmenu_8="recovery from mmc"=run flash_from_mmc
+bootmenu_9="recovery from net"=run flash_from_net
+
diff --git a/board/spacemit/k1-x/k1x-i2c-eeprom.c b/board/spacemit/k1-x/k1x-i2c-eeprom.c
new file mode 100644 (file)
index 0000000..d8a8c87
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <env.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <common.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MUX_MODE0      0                                       /* func 0 */
+#define MUX_MODE1      BIT(0)                          /* func 1 */
+#define MUX_MODE2      BIT(1)                          /* func 2 */
+#define MUX_MODE3      BIT(0) | BIT(1)         /* func 3 */
+#define MUX_MODE4      BIT(2)                          /* func 4 */
+#define MUX_MODE5      BIT(0) | BIT(2)         /* func 5 */
+#define EDGE_NONE      BIT(6)                          /* edge-detection is unabled */
+#define PAD_1V8_DS2    BIT(12)                         /* voltage:1.8v, driver strength: 2 */
+#define PULL_UP                BIT(14) | BIT(15)       /* pull-up */
+
+#define I2C_PIN_CONFIG(x)      ((x) | EDGE_NONE | PULL_UP | PAD_1V8_DS2)
+
+char *spacemit_i2c_eeprom[] = {
+       "atmel,24c02",
+};
+
+struct tlv_eeprom {
+       uint8_t type;
+       uint8_t length;
+};
+
+struct eeprom_config {
+       uint8_t bus;
+       uint16_t addr;
+       uint8_t pin_function;
+       uint32_t scl_pin_reg;
+       uint32_t sda_pin_reg;
+};
+
+const struct eeprom_config eeprom_info[] = {
+       // eeprom @deb1 & deb2: I2C2, pin group(GPIO_84, GPIO_85)
+       {2, 0x50, MUX_MODE4, 0xd401e154, 0xd401e158},
+       // eeprom @evb: I2C6, pin group(GPIO_118, GPIO_119)
+       {6, 0x50, MUX_MODE2, 0xd401e228, 0xd401e22c},
+};
+
+int spacemit_eeprom_read(uint8_t chip, uint8_t *buffer, uint8_t id)
+{
+       struct tlv_eeprom tlv;
+       int ret;
+       uint8_t buf[1] = {0};
+       uint8_t len[1] = {0};
+       uint16_t i = 0;
+       uint8_t j;
+
+       tlv.type = 0;
+       tlv.length = 0;
+
+       for (i = 11; i <= 256; i = i + tlv.length + 2) {
+               ret = i2c_read(chip, i, 1, buf, 1);
+               tlv.type = *buf;
+
+               ret = i2c_read(chip, i + 1, 1, len, 1);
+               tlv.length = *len;
+
+               if (tlv.length == 0) {
+                       pr_err("Error: wrong tlv length\n");
+                       return -1;
+               }
+
+               if (tlv.type == id) {
+                       for(j = 0; j < tlv.length; j++) {
+                               ret = i2c_read(chip, i + 2 + j, 1, (char *)buffer, 1);
+                               buffer++;
+                       }
+                       return 0;
+               }
+       }
+
+       pr_info("No 0x%x tlv type in eeprom\n", id);
+       return -2;
+}
+
+static void i2c_set_pinctrl(uint32_t value, uint32_t reg_addr)
+{
+       writel(value, (void __iomem *)(size_t)reg_addr);
+}
+
+static uint32_t i2c_get_pinctrl(uint32_t reg_addr)
+{
+       return readl((void __iomem *)(size_t)reg_addr);
+}
+
+int k1x_eeprom_init(void)
+{
+       static int saddr = -1, i;
+       uint8_t bus;
+       uint32_t scl_pin_backup, sda_pin_backup;
+
+       if (saddr >= 0)
+               return saddr;
+
+       for (i = 0; i < ARRAY_SIZE(eeprom_info); i++) {
+               bus = eeprom_info[i].bus;
+               saddr = eeprom_info[i].addr;
+
+               scl_pin_backup = i2c_get_pinctrl(eeprom_info[i].scl_pin_reg);;
+               sda_pin_backup = i2c_get_pinctrl(eeprom_info[i].sda_pin_reg);;
+               i2c_set_pinctrl(I2C_PIN_CONFIG(eeprom_info[i].pin_function), eeprom_info[i].scl_pin_reg);
+               i2c_set_pinctrl(I2C_PIN_CONFIG(eeprom_info[i].pin_function), eeprom_info[i].sda_pin_reg);
+
+               if ((i2c_set_bus_num(bus) < 0) || (i2c_probe(saddr) < 0)) {
+                       pr_err("%s: probe i2c(%d) @eeprom %d failed\n", __func__, bus, saddr);
+                       i2c_set_pinctrl(scl_pin_backup, eeprom_info[i].scl_pin_reg);
+                       i2c_set_pinctrl(sda_pin_backup, eeprom_info[i].sda_pin_reg);
+               }
+               else {
+                       pr_info("find eeprom in bus %d, address %d\n", bus, saddr);
+                       return saddr;
+               }
+       }
+
+       return -EINVAL;
+}
diff --git a/board/spacemit/k1-x/k1x.c b/board/spacemit/k1-x/k1x.c
new file mode 100644 (file)
index 0000000..0d3ebf6
--- /dev/null
@@ -0,0 +1,989 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <dm/lists.h>
+#include <env.h>
+#include <fdtdec.h>
+#include <image.h>
+#include <log.h>
+#include <mapmem.h>
+#include <spl.h>
+#include <init.h>
+#include <virtio_types.h>
+#include <virtio.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <stdlib.h>
+#include <linux/io.h>
+#include <asm/global_data.h>
+#include <part.h>
+#include <env_internal.h>
+#include <asm/arch/ddr.h>
+#include <power/regulator.h>
+#include <fb_spacemit.h>
+#include <net.h>
+#include <i2c.h>
+#include <linux/delay.h>
+#include <tlv_eeprom.h>
+#include <u-boot/crc.h>
+#include <fb_mtd.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+static char found_partition[64] = {0};
+extern u32 ddr_cs_num;
+#ifdef CONFIG_DISPLAY_SPACEMIT_HDMI
+extern int is_hdmi_connected;
+#endif
+void refresh_config_info(u8 *eeprom_data);
+int mac_read_from_buffer(u8 *eeprom_data);
+
+void set_boot_mode(enum board_boot_mode boot_mode)
+{
+       writel(boot_mode, (void *)BOOT_DEV_FLAG_REG);
+}
+
+enum board_boot_mode get_boot_pin_select(void)
+{
+       /*if not set boot mode, try to return boot pin select*/
+       u32 boot_select = readl((void *)BOOT_PIN_SELECT) & BOOT_STRAP_BIT_STORAGE_MASK;
+       boot_select = boot_select >> BOOT_STRAP_BIT_OFFSET;
+       pr_debug("boot_select:%x\n", boot_select);
+
+       /*select spl boot device:
+                b'(bit1)(bit0)
+       emmc:b'00, //BOOT_STRAP_BIT_EMMC
+       nor :b'10, //BOOT_STRAP_BIT_NOR
+       nand:b'01, //BOOT_STRAP_BIT_NAND
+       sd  :b'11, //BOOT_STRAP_BIT_SD
+*/
+       switch (boot_select) {
+       case BOOT_STRAP_BIT_EMMC:
+               return BOOT_MODE_EMMC;
+       case BOOT_STRAP_BIT_NAND:
+               return BOOT_MODE_NAND;
+       case BOOT_STRAP_BIT_NOR:
+               return BOOT_MODE_NOR;
+       case BOOT_STRAP_BIT_SD:
+       default:
+               return BOOT_MODE_SD;
+       }
+}
+
+enum board_boot_mode get_boot_mode(void)
+{
+       /*if usb boot or has set boot mode, return boot mode*/
+       u32 boot_mode = readl((void *)BOOT_DEV_FLAG_REG);
+       pr_debug("%s, boot_mode:%x\n", __func__, boot_mode);
+
+       switch (boot_mode) {
+       case BOOT_MODE_USB:
+               return BOOT_MODE_USB;
+       case BOOT_MODE_EMMC:
+               return BOOT_MODE_EMMC;
+       case BOOT_MODE_NAND:
+               return BOOT_MODE_NAND;
+       case BOOT_MODE_NOR:
+               return BOOT_MODE_NOR;
+       case BOOT_MODE_SD:
+               return BOOT_MODE_SD;
+       case BOOT_MODE_SHELL:
+               return BOOT_MODE_SHELL;
+       }
+
+       /*else return boot pin select*/
+       return get_boot_pin_select();
+}
+
+enum board_boot_mode get_boot_storage(void)
+{
+       enum board_boot_mode boot_storage = get_boot_mode();
+
+       // save to card only when boot from card
+       if (BOOT_MODE_SD != boot_storage)
+               boot_storage =  get_boot_pin_select();
+
+       return boot_storage;
+}
+
+int mmc_get_env_dev(void)
+{
+       u32 boot_mode = 0;
+       boot_mode = get_boot_mode();
+       pr_debug("%s, uboot boot_mode:%x\n", __func__, boot_mode);
+
+       if (boot_mode == BOOT_MODE_EMMC)
+               return MMC_DEV_EMMC;
+       else
+               return MMC_DEV_SD;
+}
+
+static bool write_boot_storage_emmc(ulong byte_addr, ulong byte_size, void *buff)
+{
+       struct blk_desc *dev_desc = blk_get_dev("mmc", MMC_DEV_EMMC);
+
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid mmc device\n");
+               return false;
+       }
+
+       blk_dselect_hwpart(dev_desc, 0);
+       pr_info("write %ldbyte to emmc address %ld\n", byte_size, byte_addr);
+       blk_dwrite(dev_desc,
+               byte_addr / dev_desc->blksz,
+               byte_size / dev_desc->blksz, buff);
+       return true;
+}
+
+static bool write_boot_storage_sdcard(ulong byte_addr, ulong byte_size, void *buff)
+{
+       struct blk_desc *dev_desc = blk_get_dev("mmc", MMC_DEV_SD);
+
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid sd device\n");
+               return false;
+       }
+
+       pr_info("write %ldbyte to sdcard address %ld\n", byte_size, byte_addr);
+       blk_dwrite(dev_desc,
+               byte_addr / dev_desc->blksz,
+               byte_size / dev_desc->blksz, buff);
+       return true;
+}
+
+static bool write_boot_storage_spinor(ulong byte_addr, ulong byte_size, void *buff)
+{
+       struct mtd_info *mtd;
+       const char* part = "private";
+
+       mtd_probe_devices();
+       mtd = get_mtd_device_nm(part);
+       if ((NULL != mtd) && (0 == _fb_mtd_erase(mtd, byte_size))
+               && (0 == _fb_mtd_write(mtd, buff, byte_addr, byte_size, NULL))) {
+               pr_info("write %ldbyte to spinor partition %s @offset %ld\n", byte_size, part, byte_addr);
+               return true;
+       }
+       else
+               return false;
+}
+
+static const struct boot_storage_op storage_write[] = {
+       {BOOT_MODE_EMMC, 0x10000, NULL, write_boot_storage_emmc},
+       {BOOT_MODE_SD, 0x10000, NULL, write_boot_storage_sdcard},
+       {BOOT_MODE_NOR, 0, NULL, write_boot_storage_spinor},
+};
+
+static bool write_training_info(void *buff, ulong byte_size)
+{
+       int i;
+       // save data to boot storage
+       enum board_boot_mode boot_storage = get_boot_storage();
+
+       for (i = 0; i < ARRAY_SIZE(storage_write); i++) {
+               if (boot_storage == storage_write[i].boot_storage)
+                       return storage_write[i].write(storage_write[i].address, byte_size, buff);
+       }
+
+       return false;
+}
+
+void save_ddr_training_info(void)
+{
+       struct ddr_training_info_t *info;
+       info = (struct ddr_training_info_t*)map_sysmem(DDR_TRAINING_INFO_BUFF, 0);
+
+       if ((DDR_TRAINING_INFO_MAGIC == info->magic) &&
+               (info->crc32 == crc32(0, (const uchar *)&info->chipid, sizeof(*info) - 8))) {
+               // save DDR training info to boot storage
+               write_training_info(info, sizeof(*info));
+       }
+}
+
+void get_ddr_config_info(void)
+{
+       struct ddr_training_info_t *info;
+       info = (struct ddr_training_info_t*)map_sysmem(DDR_TRAINING_INFO_BUFF, 0);
+
+       if ((DDR_TRAINING_INFO_MAGIC == info->magic) &&
+               (info->crc32 == crc32(0, (const uchar *)&info->chipid, sizeof(*info) - 8))) {
+               // get DDR cs number that is update in spl stage
+               ddr_cs_num = info->cs_num;
+       }
+       else
+               ddr_cs_num = DDR_CS_NUM;
+}
+
+void run_fastboot_command(void)
+{
+       u32 boot_mode = get_boot_mode();
+
+       /*if define BOOT_MODE_USB flag in BOOT_CIU_DEBUG_REG0, it would excute fastboot*/
+       u32 cui_flasg = readl((void *)BOOT_CIU_DEBUG_REG0);
+       if (boot_mode == BOOT_MODE_USB || cui_flasg == BOOT_MODE_USB){
+               /* show flash log*/
+               env_set("stdout", env_get("stdout_flash"));
+               /*would reset debug_reg0*/
+               writel(0, (void *)BOOT_CIU_DEBUG_REG0);
+
+               char *cmd_para = "fastboot 0";
+               run_command(cmd_para, 0);
+
+               /*read from eeprom and update info to env*/
+               refresh_config_info(NULL);
+       }
+}
+
+int run_uboot_shell(void)
+{
+       u32 boot_mode = get_boot_mode();
+
+       /*if define BOOT_MODE_SHELL flag in BOOT_CIU_DEBUG_REG0, it would into uboot shell*/
+       u32 flag = readl((void *)BOOT_CIU_DEBUG_REG0);
+       if (boot_mode == BOOT_MODE_SHELL || flag == BOOT_MODE_SHELL){
+               /*would reset debug_reg0*/
+               writel(0, (void *)BOOT_CIU_DEBUG_REG0);
+               return 0;
+       }
+       return 1;
+}
+
+void _load_env_from_blk(struct blk_desc *dev_desc, const char *dev_name, int dev)
+{
+       /*
+       TODO:
+               load env from bootfs, if bootfs is fat/ext4 at blk dev, use fatload/ext4load.
+       */
+       int err;
+       u32 part;
+       char cmd[128];
+       struct disk_partition info;
+
+       printf("BPI: :%s\n", "_load_env_from_blk");
+       for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+               err = part_get_info(dev_desc, part, &info);
+               if (err)
+                       continue;
+               if (!strcmp(BOOTFS_NAME, info.name)){
+                       pr_debug("match info.name:%s\n", info.name);
+                       break;
+               }
+       }
+       if (part > MAX_SEARCH_PARTITIONS) {
+#ifdef BPI
+               return;
+#else
+               part = 1;
+#endif
+       }
+
+       env_set("bootfs_part", simple_itoa(part));
+       env_set("bootfs_devname", dev_name);
+
+       /*load env.txt and import to uboot*/
+       memset((void *)CONFIG_SPL_LOAD_FIT_ADDRESS, 0, CONFIG_ENV_SIZE);
+       sprintf(cmd, "load %s %d:%d 0x%x env_%s.txt", dev_name,
+                       dev, part, CONFIG_SPL_LOAD_FIT_ADDRESS, CONFIG_SYS_CONFIG_NAME);
+       pr_debug("cmd:%s\n", cmd);
+       printf("BPI: cmd:%s\n", cmd);
+       if (run_command(cmd, 0))
+               return;
+
+       memset(cmd, '\0', 128);
+       sprintf(cmd, "env import -t 0x%x", CONFIG_SPL_LOAD_FIT_ADDRESS);
+       pr_debug("cmd:%s\n", cmd);
+       printf("BPI: cmd:%s\n", cmd);
+       if (!run_command(cmd, 0)){
+               pr_info("load env_%s.txt from bootfs successful\n", CONFIG_SYS_CONFIG_NAME);
+       }
+}
+
+char* parse_mtdparts_and_find_bootfs(void) {
+       const char *mtdparts = env_get("mtdparts");
+       char cmd_buf[256];
+
+       if (!mtdparts) {
+               pr_debug("mtdparts not set\n");
+               return NULL;
+       }
+
+       /* Find the last partition */
+       const char *last_part_start = strrchr(mtdparts, '(');
+       if (last_part_start) {
+               last_part_start++; /* Skip the left parenthesis */
+               const char *end = strchr(last_part_start, ')');
+               if (end && (end - last_part_start < sizeof(found_partition))) {
+                       int len = end - last_part_start;
+                       strncpy(found_partition, last_part_start, len);
+                       found_partition[len] = '\0';
+
+                       snprintf(cmd_buf, sizeof(cmd_buf), "ubi part %s", found_partition);
+                       if (run_command(cmd_buf, 0) == 0) {
+                               /* Check if the bootfs volume exists */
+                               snprintf(cmd_buf, sizeof(cmd_buf), "ubi check %s", BOOTFS_NAME);
+                               if (run_command(cmd_buf, 0) == 0) {
+                                       pr_info("Found bootfs in partition: %s\n", found_partition);
+                                       return found_partition;
+                               }
+                       }
+               }
+       }
+
+       pr_debug("bootfs not found in any partition\n");
+       return NULL;
+}
+
+void import_env_from_bootfs(void)
+{
+       u32 boot_mode = get_boot_mode();
+       switch (boot_mode) {
+       case BOOT_MODE_NAND:
+#if CONFIG_IS_ENABLED(ENV_IS_IN_MTD)
+               /*load env from nand bootfs*/
+               const char *bootfs_name = BOOTFS_NAME ;
+               char cmd[128];
+
+               if (!bootfs_name) {
+                       pr_err("bootfs not set\n");
+                       return;
+               }
+
+               /* Parse mtdparts to find the partition containing the BOOTFS_NAME volume */
+               char *mtd_partition   = parse_mtdparts_and_find_bootfs();
+               if (!mtd_partition  ) {
+                       pr_err("Bootfs not found in any partition\n");
+                       return;
+               }
+
+               sprintf(cmd, "ubifsmount ubi0:%s", bootfs_name);
+               if (run_command(cmd, 0)) {
+                       pr_err("Cannot mount ubifs partition '%s'\n", bootfs_name);
+                       return;
+               }
+
+               memset((void *)CONFIG_SPL_LOAD_FIT_ADDRESS, 0, CONFIG_ENV_SIZE);
+               sprintf(cmd, "ubifsload 0x%x env_%s.txt", CONFIG_SPL_LOAD_FIT_ADDRESS, CONFIG_SYS_CONFIG_NAME);
+               if (run_command(cmd, 0)) {
+                       pr_err("Failed to load env_%s.txt from bootfs\n", CONFIG_SYS_CONFIG_NAME);
+                       return;
+               }
+
+               memset(cmd, '\0', 128);
+               sprintf(cmd, "env import -t 0x%x", CONFIG_SPL_LOAD_FIT_ADDRESS);
+               if (!run_command(cmd, 0)) {
+                       pr_err("Imported environment from 'env_k1-x.txt'\n");
+               }
+#endif
+               break;
+       case BOOT_MODE_NOR:
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+               struct blk_desc *dev_desc;
+
+               /*nvme need scan at first*/
+               if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)
+                                               && run_command("nvme scan", 0)){
+                       pr_err("can not find any nvme devices!\n");
+                       return;
+               }
+
+               if (strlen(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME) > 0){
+                       /* First try partition names on the default device */
+                       dev_desc = blk_get_dev(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME,
+                                                               CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX);
+                       if (dev_desc) {
+                               _load_env_from_blk(dev_desc, CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME,
+                                                       CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX);
+                       }
+       }
+#endif
+               break;
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+#ifdef CONFIG_MMC
+               int dev;
+               struct mmc *mmc;
+
+               dev = mmc_get_env_dev();
+               mmc = find_mmc_device(dev);
+               if (!mmc) {
+                       pr_err("Cannot find mmc device\n");
+                       return;
+               }
+               if (mmc_init(mmc)){
+                       return;
+               }
+
+               _load_env_from_blk(mmc_get_blk_desc(mmc), "mmc", dev);
+               break;
+#endif
+       default:
+               break;
+       }
+       return;
+}
+
+void run_cardfirmware_flash_command(void)
+{
+       struct mmc *mmc;
+       struct disk_partition info;
+       int part_dev, err;
+       char cmd[128] = {"\0"};
+
+#ifdef CONFIG_MMC
+       mmc = find_mmc_device(MMC_DEV_SD);
+       if (!mmc)
+               return;
+       if (mmc_init(mmc))
+               return;
+
+       for (part_dev = 1; part_dev <= MAX_SEARCH_PARTITIONS; part_dev++) {
+               err = part_get_info(mmc_get_blk_desc(mmc), part_dev, &info);
+               if (err)
+                       continue;
+               if (!strcmp(BOOTFS_NAME, info.name))
+                       break;
+
+       }
+
+       if (part_dev > MAX_SEARCH_PARTITIONS)
+               return;
+
+       /*check if flash config file is in sd card*/
+       sprintf(cmd, "fatsize mmc %d:%d %s", MMC_DEV_SD, part_dev, FLASH_CONFIG_FILE_NAME);
+       pr_debug("cmd:%s\n", cmd);
+       if (!run_command(cmd, 0)){
+               /* show flash log*/
+               env_set("stdout", env_get("stdout_flash"));
+               run_command("flash_image mmc", 0);
+       }
+#endif
+       return;
+}
+
+void setenv_boot_mode(void)
+{
+       u32 boot_mode = get_boot_mode();
+       switch (boot_mode) {
+       case BOOT_MODE_NAND:
+               env_set("boot_device", "nand");
+               break;
+       case BOOT_MODE_NOR:
+               env_set("boot_device", "nor");
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+               env_set("boot_devnum", simple_itoa(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX));
+#endif
+               break;
+       case BOOT_MODE_EMMC:
+               env_set("boot_device", "mmc");
+               env_set("boot_devnum", simple_itoa(MMC_DEV_EMMC));
+               break;
+       case BOOT_MODE_SD:
+               env_set("boot_device", "mmc");
+               env_set("boot_devnum", simple_itoa(MMC_DEV_SD));
+               break;
+       case BOOT_MODE_USB:
+               // for fastboot image download and run test
+               env_set("bootcmd", CONFIG_BOOTCOMMAND);
+               break;
+       default:
+               env_set("boot_device", "");
+               break;
+       }
+}
+
+void read_from_eeprom(struct tlvinfo_tlv **tlv_data, u8 tcode)
+{
+       static u8 eeprom_data[256];
+       struct tlvinfo_header *tlv_hdr = NULL;
+       struct tlvinfo_tlv *tlv_entry;
+       unsigned int tlv_offset, tlv_len;
+       int ret = 0;
+
+       ret = read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr, &tlv_entry, 0);
+       if (ret < 0) {
+               pr_err("read tlvinfo from eeprom failed!\n");
+               return;
+       }
+
+       tlv_offset = sizeof(struct tlvinfo_header);
+       tlv_len = sizeof(struct tlvinfo_header) + be16_to_cpu(tlv_hdr->totallen);
+       while (tlv_offset < tlv_len) {
+               tlv_entry = (struct tlvinfo_tlv *)&eeprom_data[tlv_offset];
+               if (tlv_entry->type == tcode) {
+                       *tlv_data = tlv_entry;
+                       return;
+               }
+
+               tlv_offset += sizeof(struct tlvinfo_tlv) + tlv_entry->length;
+       }
+
+       *tlv_data = NULL;
+       return;
+}
+
+struct tlvinfo_tlv *find_tlv_in_buffer(u8 *eeprom_data, u8 tcode)
+{
+       struct tlvinfo_header *hdr = (struct tlvinfo_header *)eeprom_data;
+       int total_length = be16_to_cpu(hdr->totallen);
+       u8 *tlv_end = eeprom_data + sizeof(struct tlvinfo_header) + total_length;
+       u8 *ptr = eeprom_data + sizeof(struct tlvinfo_header);
+
+       while (ptr < tlv_end) {
+               struct tlvinfo_tlv *tlv = (struct tlvinfo_tlv *)ptr;
+
+               if (tlv->type == tcode) {
+                       return tlv;
+               }
+
+               ptr += sizeof(struct tlvinfo_tlv) + tlv->length;
+       }
+
+       return NULL;
+}
+
+int mac_read_from_buffer(u8 *eeprom_data) {
+       unsigned int i;
+       struct tlvinfo_tlv *mac_size_tlv;
+       struct tlvinfo_tlv *mac_base_tlv;
+       int maccount;
+       u8 macbase[6];
+       struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom_data;
+
+       pr_info("EEPROM: ");
+
+       mac_size_tlv = find_tlv_in_buffer(eeprom_data, TLV_CODE_MAC_SIZE);
+       maccount = 1;
+       if (mac_size_tlv) {
+               maccount = (mac_size_tlv->value[0] << 8) | mac_size_tlv->value[1];
+       }
+
+       mac_base_tlv = find_tlv_in_buffer(eeprom_data, TLV_CODE_MAC_BASE);
+       if (mac_base_tlv) {
+               memcpy(macbase, mac_base_tlv->value, 6);
+       } else {
+               memset(macbase, 0, sizeof(macbase));
+       }
+
+       for (i = 0; i < maccount; i++) {
+               if (is_valid_ethaddr(macbase)) {
+                       char ethaddr[18];
+                       char enetvar[11];
+
+                       sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
+                               macbase[0], macbase[1], macbase[2],
+                               macbase[3], macbase[4], macbase[5]);
+                       sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
+                       /* Only initialize environment variables that are blank
+                        * (i.e. have not yet been set)
+                        */
+                       if (!env_get(enetvar))
+                               env_set(enetvar, ethaddr);
+
+                       macbase[5]++;
+                       if (macbase[5] == 0) {
+                               macbase[4]++;
+                               if (macbase[4] == 0) {
+                                       macbase[3]++;
+                                       if (macbase[3] == 0) {
+                                               macbase[0] = 0;
+                                               macbase[1] = 0;
+                                               macbase[2] = 0;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       printf("%s v%u len=%u\n", eeprom_hdr->signature, eeprom_hdr->version,
+              be16_to_cpu(eeprom_hdr->totallen));
+
+       return 0;
+}
+
+void set_env_ethaddr(u8 *eeprom_data) {
+       int ethaddr_valid = 0, eth1addr_valid = 0;
+       uint8_t mac_addr[6], mac1_addr[6];
+       char cmd_str[128] = {0};
+
+       /* Determine source of MAC address and attempt to read it */
+       if (eeprom_data != NULL) {
+               // Attempt to read MAC address from buffer
+
+               if (mac_read_from_buffer(eeprom_data) < 0) {
+                       pr_err("Failed to set MAC addresses from EEPROM buffer.\n");
+                       return;
+               }
+       } else {
+               // Attempt to read MAC address from EEPROM
+               if (mac_read_from_eeprom() < 0) {
+                       pr_err("Read MAC address from EEPROM failed!\n");
+                       return;
+               }
+       }
+
+       /* check ethaddr valid */
+       ethaddr_valid = eth_env_get_enetaddr("ethaddr", mac_addr);
+       eth1addr_valid = eth_env_get_enetaddr("eth1addr", mac1_addr);
+       if (ethaddr_valid && eth1addr_valid) {
+               pr_info("valid ethaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       mac_addr[0], mac_addr[1], mac_addr[2],
+                       mac_addr[3], mac_addr[4], mac_addr[5]);
+               return ;
+       }
+
+       /*create random ethaddr*/
+       net_random_ethaddr(mac_addr);
+       mac_addr[0] = 0xfe;
+       mac_addr[1] = 0xfe;
+       mac_addr[2] = 0xfe;
+
+       memcpy(mac1_addr, mac_addr, sizeof(mac1_addr));
+       mac1_addr[5] = mac_addr[5] + 1;
+
+       /* write to env ethaddr and eth1addr */
+       eth_env_set_enetaddr("ethaddr", mac_addr);
+       eth_env_set_enetaddr("eth1addr", mac1_addr);
+
+       /* save mac address to eeprom */
+       snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom set 0x24 %02x:%02x:%02x:%02x:%02x:%02x", \
+                       mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+       run_command(cmd_str, 0);
+
+       memset(cmd_str, 0, sizeof(cmd_str));
+       snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom set 0x2A 2");
+       run_command(cmd_str, 0);
+
+       memset(cmd_str, 0, sizeof(cmd_str));
+       snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom write");
+       run_command(cmd_str, 0);
+}
+
+void set_dev_serial_no(uint8_t *eeprom_data)
+{
+       u8 sn[6] = {0};
+       char cmd_str[128] = {0};
+       struct tlvinfo_tlv *tlv_entry = NULL;
+       int i = 0;
+       unsigned int seed = 0;
+
+       // Decide where to read the serial number from
+       if (eeprom_data != NULL) {
+               tlv_entry = find_tlv_in_buffer(eeprom_data, TLV_CODE_SERIAL_NUMBER);
+       } else {
+               read_from_eeprom(&tlv_entry, TLV_CODE_SERIAL_NUMBER);
+       }
+       if (tlv_entry && tlv_entry->length == 12) {
+               for (i = 0; i < 12; i++) {
+                       if (tlv_entry->value[i] != 0) {
+                               pr_err("Serial number is valid.\n");
+                               return;
+                       }
+               }
+       }
+
+       pr_info("Generate rand serial number:\n");
+       /* Generate rand serial number */
+       seed = get_ticks();
+       for (i = 0; i < 6; i++) {
+               sn[i] = rand_r(&seed);
+               pr_info("%02x", sn[i]);
+       }
+       pr_info("\n");
+
+       /* save serial number to eeprom */
+       snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom set 0x23 %02x%02x%02x%02x%02x%02x", \
+                       sn[0], sn[1], sn[2], sn[3], sn[4], sn[5]);
+       run_command(cmd_str, 0);
+
+       memset(cmd_str, 0, sizeof(cmd_str));
+       snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom write");
+       run_command(cmd_str, 0);
+}
+
+struct code_desc_info {
+       u8      m_code;
+       char    *m_name;
+};
+
+void refresh_config_info(u8 *eeprom_data)
+{
+       struct tlvinfo_tlv *tlv_info = NULL;
+       char *strval;
+       int i;
+       char tmp_name[64];
+
+       const struct code_desc_info {
+               u8    m_code;
+               u8    is_data;
+               char *m_name;
+       } info[] = {
+               { TLV_CODE_PRODUCT_NAME,   false, "product_name"},
+               { TLV_CODE_SERIAL_NUMBER,  false, "serial#"},
+               { TLV_CODE_MANUF_DATE,     false, "manufacture_date"},
+               { TLV_CODE_MANUF_NAME,     false, "manufacturer"},
+               { TLV_CODE_DEVICE_VERSION, true,  "device_version"},
+               { TLV_CODE_SDK_VERSION,    true,  "sdk_version"},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(info); i++) {
+               if (eeprom_data != NULL) {
+                       tlv_info = find_tlv_in_buffer(eeprom_data, info[i].m_code);
+               } else {
+                       read_from_eeprom(&tlv_info, info[i].m_code);
+               }
+
+               if (tlv_info != NULL) {
+                       if (info[i].is_data) {
+                               // Convert the numeric value to string
+                               strval = malloc(64);
+                               int num = 0;
+                               for (int j = 0; j < tlv_info->length && j < sizeof(num); j++) {
+                                       num = (num << 8) | tlv_info->value[j];
+                               }
+                               sprintf(strval, "%d", num);
+                       } else {
+                               // Copy the value directly as string
+                               strval = malloc(tlv_info->length + 1);
+                               memcpy(strval, tlv_info->value, tlv_info->length);
+                               strval[tlv_info->length] = '\0';
+
+                               /*
+                                       be compatible to previous format name,
+                                       such as: k1_deb1 -> k1-x_deb1
+                               */
+                               if (info[i].m_code == TLV_CODE_PRODUCT_NAME && strncmp(strval, CONFIG_SYS_BOARD, 4)){
+                                       sprintf(tmp_name, "%s_%s", CONFIG_SYS_BOARD, &strval[3]);
+                                       strcpy(strval, tmp_name);
+                               }
+                       }
+                       env_set(info[i].m_name, strval);
+                       free(strval);
+               } else {
+                       pr_err("Cannot find TLV data: %s\n", info[i].m_name);
+               }
+       }
+}
+
+int board_init(void)
+{
+#ifdef CONFIG_DM_REGULATOR_SPM8XX
+       int ret;
+
+       ret = regulators_enable_boot_on(true);
+       if (ret)
+               pr_debug("%s: Cannot enable boot on regulator\n", __func__);
+#endif
+       return 0;
+}
+
+int board_late_init(void)
+{
+       ulong kernel_start;
+       ofnode chosen_node;
+       char ram_size_str[16] = {"\0"};
+       int ret;
+       u8 *eeprom_data;
+       struct tlvinfo_header *tlv_hdr = NULL;
+       struct tlvinfo_tlv *first_entry = NULL;
+
+       // save_ddr_training_info();
+       if (IS_ENABLED(CONFIG_SYSRESET_SPACEMIT))
+               device_bind_driver(gd->dm_root, "spacemit_sysreset",
+                                       "spacemit_sysreset", NULL);
+
+       // it MAY be NULL when did NOT load build-in env and eeprom is empty
+       if (NULL == env_get("product_name"))
+               env_set("product_name", DEFAULT_PRODUCT_NAME);
+
+       eeprom_data = memalign(ARCH_DMA_MINALIGN, TLV_INFO_MAX_LEN);
+       if (!eeprom_data) {
+               pr_err("Failed to allocate memory for EEPROM data\n");
+               return -ENOMEM;
+       }
+       if (read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr, &first_entry, 0) < 0) {
+               pr_err("Failed to read all EEPROM data\n");
+       }
+       if (tlv_hdr != NULL && first_entry != NULL && is_valid_tlvinfo_header(tlv_hdr)) {
+               set_env_ethaddr(eeprom_data);
+               set_dev_serial_no(eeprom_data);
+               refresh_config_info(eeprom_data);
+       } else {
+               set_env_ethaddr(NULL);
+               set_dev_serial_no(NULL);
+               refresh_config_info(NULL);
+       }
+
+       run_fastboot_command();
+
+       run_cardfirmware_flash_command();
+
+       ret = run_uboot_shell();
+       if (!ret) {
+               pr_info("reboot into uboot shell\n");
+               return 0;
+       }
+
+       /*import env.txt from bootfs*/
+       import_env_from_bootfs();
+
+#ifdef CONFIG_DISPLAY_SPACEMIT_HDMI
+       if (is_hdmi_connected < 0) {
+               env_set("stdout", "serial");
+       }
+#endif
+
+       setenv_boot_mode();
+
+       /*save ram size to env, transfer to MB*/
+       sprintf(ram_size_str, "mem=%dMB", (int)(gd->ram_size / SZ_1MB));
+       env_set("ram_size", ram_size_str);
+
+       chosen_node = ofnode_path("/chosen");
+       if (!ofnode_valid(chosen_node)) {
+               pr_debug("No chosen node found, can't get kernel start address\n");
+               return 0;
+       }
+
+       ret = ofnode_read_u64(chosen_node, "riscv,kernel-start",
+                                 (u64 *)&kernel_start);
+       if (ret) {
+               pr_debug("Can't find kernel start address in device tree\n");
+               return 0;
+       }
+
+       env_set_hex("kernel_start", kernel_start);
+
+       return 0;
+}
+
+void *board_fdt_blob_setup(int *err)
+{
+       *err = 0;
+
+       /* Stored the DTB address there during our init */
+       if (IS_ENABLED(CONFIG_OF_SEPARATE) || IS_ENABLED(CONFIG_OF_BOARD)) {
+               if (gd->arch.firmware_fdt_addr){
+                       if (!fdt_check_header((void *)(ulong)gd->arch.firmware_fdt_addr)){
+                               return (void *)(ulong)gd->arch.firmware_fdt_addr;
+                       }
+               }
+       }
+       return (ulong *)&_end;
+}
+
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+       if (prio >= 1)
+               return ENVL_UNKNOWN;
+
+       u32 boot_mode = get_boot_mode();
+       switch (boot_mode) {
+#ifdef CONFIG_ENV_IS_IN_MTD
+       case BOOT_MODE_NAND:
+               return ENVL_MTD;
+#endif
+#ifdef CONFIG_ENV_IS_IN_NAND
+       case BOOT_MODE_NAND:
+               return ENVL_NAND;
+#endif
+#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
+       case BOOT_MODE_NOR:
+               return ENVL_SPI_FLASH;
+#endif
+#ifdef CONFIG_ENV_IS_IN_MMC
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+               return ENVL_MMC;
+#endif
+       default:
+#ifdef CONFIG_ENV_IS_NOWHERE
+               return ENVL_NOWHERE;
+#else
+               return ENVL_UNKNOWN;
+#endif
+       }
+}
+
+int misc_init_r(void)
+{
+#ifdef CONFIG_DYNAMIC_DDR_CLK_FREQ
+       int ret;
+       char cmd[32];
+
+       ret = ddr_freq_max();
+       if(ret < 0) {
+               pr_debug("%s: Try to adjust ddr freq failed!\n", __func__);
+               return ret;
+       }
+
+       // change DDR data rate to 2400MT/s and set
+       sprintf(cmd, "ddrfreq %d", 6);
+       pr_debug("cmd:%s\n", cmd);
+       if (run_command(cmd, 0)) {
+                       pr_err("DDR frequency change fail\n");
+                       return -1;
+       }
+#endif
+
+       return 0;
+}
+
+int dram_init(void)
+{
+       get_ddr_config_info();
+       u64 dram_size = (u64)ddr_get_density() * SZ_1MB;
+
+       gd->ram_base = CONFIG_SYS_SDRAM_BASE;
+       gd->ram_size = dram_size;
+
+       return 0;
+}
+
+int dram_init_banksize(void)
+{
+       u64 dram_size = (u64)ddr_get_density() * SZ_1MB;
+
+       memset(gd->bd->bi_dram, 0, sizeof(gd->bd->bi_dram));
+       gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+       if(dram_size > SZ_2GB) {
+               gd->bd->bi_dram[0].size = SZ_2G;
+               if (CONFIG_NR_DRAM_BANKS > 1) {
+                       gd->bd->bi_dram[1].start = 0x100000000;
+                       gd->bd->bi_dram[1].size = dram_size - SZ_2G;
+               }
+       } else {
+               gd->bd->bi_dram[0].size = dram_size;
+       }
+
+       return 0;
+}
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+       u64 dram_size = (u64)ddr_get_density() * SZ_1MB;
+
+               /* Some devices (like the EMAC) have a 32-bit DMA limit. */
+       if(dram_size > SZ_2GB) {
+               return 0x80000000;
+       } else {
+               return dram_size;
+       }
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+int board_fit_config_name_match(const char *name)
+{
+       char *product_name = env_get("product_name");
+
+       if ((NULL != product_name) && (0 == strcmp(product_name, name))) {
+               log_emerg("Boot from fit configuration %s\n", name);
+               return 0;
+       }
+       else
+               return -1;
+}
+#endif
diff --git a/board/spacemit/k1-x/spl.c b/board/spacemit/k1-x/spl.c
new file mode 100644 (file)
index 0000000..fc35fb9
--- /dev/null
@@ -0,0 +1,726 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <init.h>
+#include <spl.h>
+#include <misc.h>
+#include <log.h>
+#include <i2c.h>
+#include <cpu.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <env.h>
+#include <env_internal.h>
+#include <mapmem.h>
+#include <asm/global_data.h>
+#include <fb_spacemit.h>
+#include <tlv_eeprom.h>
+#include <stdlib.h>
+#include <u-boot/crc.h>
+#include <cpu_func.h>
+#include <dt-bindings/soc/spacemit-k1x.h>
+#include <display_options.h>
+
+#define GEN_CNT                        (0xD5001000)
+#define STORAGE_API_P_ADDR     (0xC0838498)
+#define SDCARD_API_ENTRY       (0xFFE0A548)
+
+/* pin mux */
+#define MUX_MODE0       0
+#define MUX_MODE1       1
+#define MUX_MODE2       2
+#define MUX_MODE3       3
+#define MUX_MODE4       4
+#define MUX_MODE5       5
+#define MUX_MODE6       6
+#define MUX_MODE7       7
+
+/* edge detect */
+#define EDGE_NONE       (1 << 6)
+#define EDGE_RISE       (1 << 4)
+#define EDGE_FALL       (1 << 5)
+#define EDGE_BOTH       (3 << 4)
+
+/* driver strength*/
+#define PAD_1V8_DS0     (0 << 11)
+#define PAD_1V8_DS1     (1 << 11)
+#define PAD_1V8_DS2     (2 << 11)
+#define PAD_1V8_DS3     (3 << 11)
+
+/*
+ * notice: !!!
+ * ds2 ---> bit10, ds1 ----> bit12, ds0 ----> bit11
+*/
+#define PAD_3V_DS0      (0 << 10)     /* bit[12:10] 000 */
+#define PAD_3V_DS1      (2 << 10)     /* bit[12:10] 010 */
+#define PAD_3V_DS2      (4 << 10)     /* bit[12:10] 100 */
+#define PAD_3V_DS3      (6 << 10)     /* bit[12:10] 110 */
+#define PAD_3V_DS4      (1 << 10)     /* bit[12:10] 001 */
+#define PAD_3V_DS5      (3 << 10)     /* bit[12:10] 011 */
+#define PAD_3V_DS6      (5 << 10)     /* bit[12:10] 101 */
+#define PAD_3V_DS7      (7 << 10)     /* bit[12:10] 111 */
+
+/* pull up/down */
+#define PULL_DIS        (0 << 13)     /* bit[15:13] 000 */
+#define PULL_UP         (6 << 13)     /* bit[15:13] 110 */
+#define PULL_DOWN       (5 << 13)     /* bit[15:13] 101 */
+
+#define MFPR_MMC1_BASE     0xD401E1B8
+#define MMC1_DATA3_OFFSET  0x00
+#define MMC1_DATA2_OFFSET  0x04
+#define MMC1_DATA1_OFFSET  0x08
+#define MMC1_DATA0_OFFSET  0x0C
+#define MMC1_CMD_OFFSET    0x10
+#define MMC1_CLK_OFFSET    0x14
+
+extern int __data_start[], __data_end[];
+extern int k1x_eeprom_init(void);
+extern int spacemit_eeprom_read(uint8_t chip, uint8_t *buffer, uint8_t id);
+extern bool get_mac_address(uint64_t *mac_addr);
+extern bool get_ddr_cs_number(uint32_t *cs_num);
+extern enum board_boot_mode get_boot_storage(void);
+extern int spl_mtd_read(struct mtd_info *mtd, ulong sector, ulong count, void *buf);
+char *product_name;
+extern u32 ddr_cs_num;
+
+int timer_init(void)
+{
+       /* enable generic cnt */
+       u32 read_data;
+       void __iomem *reg;
+
+       reg = ioremap(GEN_CNT, 0x20);
+       read_data = readl(reg);
+       read_data |= BIT(0);
+       writel(read_data, reg);
+
+       return 0;
+}
+
+enum board_boot_mode __get_boot_storage(void)
+{
+       size_t *api = (size_t*)STORAGE_API_P_ADDR;
+       size_t address = *api;
+       // Did NOT select sdcard boot, but sdcard always has first boot priority
+       if (SDCARD_API_ENTRY == address)
+               return BOOT_MODE_SD;
+       else
+               return get_boot_pin_select();
+}
+
+void fix_boot_mode(void)
+{
+       if (0 == readl((void *)BOOT_DEV_FLAG_REG))
+               set_boot_mode(__get_boot_storage());
+}
+
+void board_pinctrl_setup(void)
+{
+       //sdcard pinctrl setup
+       writel(MUX_MODE0 | EDGE_NONE | PULL_UP | PAD_3V_DS4, (void __iomem *)MFPR_MMC1_BASE + MMC1_DATA3_OFFSET);
+       writel(MUX_MODE0 | EDGE_NONE | PULL_UP | PAD_3V_DS4, (void __iomem *)MFPR_MMC1_BASE + MMC1_DATA2_OFFSET);
+       writel(MUX_MODE0 | EDGE_NONE | PULL_UP | PAD_3V_DS4, (void __iomem *)MFPR_MMC1_BASE + MMC1_DATA1_OFFSET);
+       writel(MUX_MODE0 | EDGE_NONE | PULL_UP | PAD_3V_DS4, (void __iomem *)MFPR_MMC1_BASE + MMC1_DATA0_OFFSET);
+       writel(MUX_MODE0 | EDGE_NONE | PULL_UP | PAD_3V_DS4, (void __iomem *)MFPR_MMC1_BASE + MMC1_CMD_OFFSET);
+       writel(MUX_MODE0 | EDGE_NONE | PULL_DOWN | PAD_3V_DS4, (void __iomem *)MFPR_MMC1_BASE + MMC1_CLK_OFFSET);
+}
+
+static uint32_t adjust_cpu_freq(uint64_t cluster, uint32_t freq)
+{
+       uint32_t freq_act=freq, val;
+
+       /* switch cpu clock source */
+       val = readl((void __iomem *)(K1X_APMU_BASE + 0x38c + cluster*4));
+       val &= ~(0x07 | BIT(13));
+       switch(freq) {
+       case 1600000:
+               val |= 0x07;
+               break;
+
+       case 1228000:
+               val |= 0x04;
+               break;
+
+       case 819000:
+               val |= 0x01;
+               break;
+
+       case 614000:
+       default:
+               freq_act = 614000;
+               val |= 0x00;
+               break;
+       }
+       writel(val, (void __iomem *)(K1X_APMU_BASE + 0x38c + cluster*4));
+
+       /* set cluster frequency change request, and wait done */
+       val = readl((void __iomem *)(K1X_APMU_BASE + 0x38c + cluster*4));
+       val |= BIT(12);
+       writel(val, (void __iomem *)(K1X_APMU_BASE + 0x38c + cluster*4));
+       while(readl((void __iomem *)(K1X_APMU_BASE + 0x38c + cluster*4)) & BIT(12));
+
+       return freq_act;
+}
+
+void raise_cpu_frequency(void)
+{
+       uint32_t val, cpu_freq;
+       struct udevice *cpu;
+
+       writel(0x2dffff, (void __iomem *)0xd4051024);
+
+       /* enable CLK_1228M */
+       val = readl((void __iomem *)(K1X_MPMU_BASE + 0x1024));
+       val |= BIT(16) | BIT(15) | BIT(14) | BIT(13);
+       writel(val, (void __iomem *)(K1X_MPMU_BASE + 0x1024));
+
+       /* enable PLL3(3200Mhz) */
+       val = readl((void __iomem *)(K1X_APB_SPARE_BASE + 0x12C));
+       val |= BIT(31);
+       writel(val, (void __iomem *)(K1X_APB_SPARE_BASE + 0x12C));
+       /* enable PLL3_DIV2 */
+       val = readl((void __iomem *)(K1X_APB_SPARE_BASE + 0x128));
+       val |= BIT(1);
+       writel(val, (void __iomem *)(K1X_APB_SPARE_BASE + 0x128));
+
+       cpu = cpu_get_current_dev();
+       if(dev_read_u32u(cpu, "boot_freq_cluster0", &cpu_freq)) {
+               pr_info("boot_freq_cluster0 not configured, use 1228000 as default!\n");
+               cpu_freq = 1228000;
+       }
+       cpu_freq = adjust_cpu_freq(0, cpu_freq);
+       pr_info("adjust cluster-0 frequency to %u ...   [done]\n", cpu_freq);
+
+       if(dev_read_u32u(cpu, "boot_freq_cluster1", &cpu_freq)) {
+               pr_info("boot_freq_cluster1 not configured, use 1228000 as default!\n");
+               cpu_freq = 614000;
+       }
+       cpu_freq = adjust_cpu_freq(1, cpu_freq);
+       pr_info("adjust cluster-1 frequency to %u ...   [done]\n", cpu_freq);
+}
+
+#if CONFIG_IS_ENABLED(SPACEMIT_K1X_EFUSE)
+int load_board_config_from_efuse(int *eeprom_i2c_index,
+                                int *eeprom_pin_group, int *pmic_type)
+{
+       struct udevice *dev;
+       uint8_t fuses[2];
+       int ret;
+
+       /* retrieve the device */
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                       DM_DRIVER_GET(spacemit_k1x_efuse), &dev);
+       if (ret) {
+               return ret;
+       }
+
+       // read from efuse, each bank has 32byte efuse data
+       ret = misc_read(dev, 9 * 32 + 0, fuses, sizeof(fuses));
+       if ((0 == ret) && (0 != fuses[0])) {
+               // byte0 bit0~3 is eeprom i2c controller index
+               *eeprom_i2c_index = fuses[0] & 0x0F;
+               // byte0 bit4~5 is eeprom pin group index
+               *eeprom_pin_group = (fuses[0] >> 4) & 0x03;
+               // byte1 bit0~3 is pmic type
+               *pmic_type = fuses[1] & 0x0F;
+       }
+
+       return ret;
+}
+
+int load_chipid_from_efuse(uint64_t *chipid)
+{
+       struct udevice *dev;
+       uint8_t fuses[32];
+       int ret;
+
+       /* retrieve the device */
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                       DM_DRIVER_GET(spacemit_k1x_efuse), &dev);
+       if (ret) {
+               return ret;
+       }
+
+       // read from efuse, each bank has 32byte efuse data
+       ret = misc_read(dev, 7 * 32 + 0, fuses, sizeof(fuses));
+       if (0 == ret) {
+               // bit191~251 is chipid
+               // 1. get bit 192~251
+               // 2. left shift 1bit, and merge with efuse_bank[7].bit191
+               *chipid = 0;
+               memcpy(chipid, &fuses[24], 8);
+               *chipid <<= 4;
+               *chipid >>= 3;
+               *chipid |= (fuses[23] & 0x80) >> 7;
+               pr_debug("Get chipid %llx\n", *chipid);
+       }
+
+       return ret;
+}
+#endif
+
+static void load_default_board_config(int *eeprom_i2c_index,
+               int *eeprom_pin_group, int *pmic_type)
+{
+       char *temp;
+
+       temp = env_get("eeprom_i2c_index");
+       if (NULL != temp)
+               *eeprom_i2c_index = dectoul(temp, NULL);
+       else
+               *eeprom_i2c_index = K1_DEFALT_EEPROM_I2C_INDEX;
+
+       temp = env_get("eeprom_pin_group");
+       if (NULL != temp)
+               *eeprom_pin_group = dectoul(temp, NULL);
+       else
+               *eeprom_pin_group = K1_DEFALT_EEPROM_PIN_GROUP;
+
+       temp = env_get("pmic_type");
+       if (NULL != temp)
+               *pmic_type = dectoul(temp, NULL);
+       else
+               *pmic_type = K1_DEFALT_PMIC_TYPE;
+}
+
+#if CONFIG_IS_ENABLED(SPACEMIT_POWER)
+extern int board_pmic_init(void);
+#endif
+
+void load_board_config(int *eeprom_i2c_index, int *eeprom_pin_group, int *pmic_type)
+{
+       load_default_board_config(eeprom_i2c_index, eeprom_pin_group, pmic_type);
+
+#if CONFIG_IS_ENABLED(SPACEMIT_K1X_EFUSE)
+       /* update env from efuse data */
+       load_board_config_from_efuse(eeprom_i2c_index, eeprom_pin_group, pmic_type);
+#endif
+
+       pr_debug("eeprom_i2c_index :%d\n", *eeprom_i2c_index);
+       pr_debug("eeprom_pin_group :%d\n", *eeprom_pin_group);
+       pr_debug("pmic_type :%d\n", *pmic_type);
+}
+
+static ulong read_boot_storage_emmc(ulong byte_addr, ulong byte_size, void *buff)
+{
+       ulong ret;
+       //select mmc device(MUST be align with spl.dts): 0:sd, 1:emmc
+       struct blk_desc *dev_desc = blk_get_dev("mmc", 1);
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid mmc device\n");
+               return 0;
+       }
+
+       blk_dselect_hwpart(dev_desc, 0);
+       ret = blk_dread(dev_desc,
+               byte_addr / dev_desc->blksz,
+               byte_size / dev_desc->blksz, buff);
+       return dev_desc->blksz * ret;
+}
+
+static ulong read_boot_storage_sdcard(ulong byte_addr, ulong byte_size, void *buff)
+{
+       ulong ret;
+       //select sdcard device(MUST be align with spl.dts): 0:sd, 1:emmc
+       struct blk_desc *dev_desc = blk_get_dev("mmc", 0);
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid sdcard device\n");
+               return 0;
+       }
+
+       ret = blk_dread(dev_desc,
+               byte_addr / dev_desc->blksz,
+               byte_size / dev_desc->blksz, buff);
+       return dev_desc->blksz * ret;
+}
+
+static ulong read_boot_storage_spinor(ulong byte_addr, ulong byte_size, void *buff)
+{
+       struct mtd_info *mtd;
+       const char* part = "private";
+
+       mtd_probe_devices();
+       mtd = get_mtd_device_nm(part);
+       if ((NULL != mtd) && (0 == spl_mtd_read(mtd, byte_addr, byte_size, buff))) {
+               // print_buffer(0, buff, 1, byte_size, 16);
+               return byte_size;
+       }
+       else
+               return 0;
+}
+
+static const struct boot_storage_op storage_read[] = {
+       {BOOT_MODE_EMMC, 0x10000, read_boot_storage_emmc, NULL},
+       {BOOT_MODE_SD, 0x10000, read_boot_storage_sdcard, NULL},
+       {BOOT_MODE_NOR, 0, read_boot_storage_spinor, NULL},
+};
+
+static ulong read_training_info(void *buff, ulong byte_size)
+{
+       int i;
+       // read data from boot storage
+       enum board_boot_mode boot_storage = get_boot_storage();
+
+       for (i = 0; i < ARRAY_SIZE(storage_read); i++) {
+               if (boot_storage == storage_read[i].boot_storage)
+                       return storage_read[i].read(storage_read[i].address, byte_size, buff);
+       }
+
+       return 0;
+}
+
+bool restore_ddr_training_info(uint64_t chipid, uint64_t mac_addr)
+{
+       bool success = true;
+       struct ddr_training_info_t *info;
+       ulong flush_start, flush_lenth;
+
+       pr_debug("chipid %llx\n", chipid);
+       pr_debug("mac_addr %llx\n", mac_addr);
+
+       info = (struct ddr_training_info_t*)map_sysmem(DDR_TRAINING_INFO_BUFF, 0);
+       // Force to do DDR software training while in USB download mode or info is invalid
+       if ((BOOT_MODE_USB == get_boot_mode()) ||
+               (sizeof(*info) != read_training_info(info, sizeof(*info))) ||
+               (DDR_TRAINING_INFO_MAGIC != info->magic) ||
+               (chipid != info->chipid) ||
+               (mac_addr != info->mac_addr) ||
+               (DDR_TRAINING_INFO_VER != info->version) ||
+               (info->crc32 != crc32(0, (const uchar *)&info->chipid, sizeof(*info) - 8))) {
+               // clear magic, set invalid
+               memset(info, 0, sizeof(*info));
+               success = false;
+       }
+
+       flush_start = round_down((size_t)info, CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       flush_lenth = round_up(sizeof(*info), CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       flush_dcache_range(flush_start, flush_start + flush_lenth);
+       return success;
+}
+
+void update_ddr_training_info(uint64_t chipid, uint64_t mac_addr)
+{
+       struct ddr_training_info_t *info;
+       // ulong flush_start, flush_lenth;
+
+       info = (struct ddr_training_info_t*)map_sysmem(DDR_TRAINING_INFO_BUFF, 0);
+       if ((DDR_TRAINING_INFO_MAGIC == info->magic) &&
+               (info->crc32 == crc32(0, (const uchar *)&info->chipid, sizeof(*info) - 8))) {
+               // NO need to save ddr trainig info
+               info->magic = 0;
+               }
+       else {
+               // first time to do ddr training or ddr training info is update
+               info->magic = DDR_TRAINING_INFO_MAGIC;
+               info->chipid = chipid;
+               info->mac_addr = mac_addr;
+               info->version = DDR_TRAINING_INFO_VER;
+               info->crc32 = crc32(0, (const uchar *)&info->chipid, sizeof(*info) - 8);
+       }
+
+       // flush_start = round_down((size_t)info, CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       // flush_lenth = round_up(sizeof(*info), CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       // flush_dcache_range(flush_start, flush_start + flush_lenth);
+}
+
+void update_ddr_config_info(uint32_t cs_num)
+{
+       struct ddr_training_info_t *info;
+
+       info = (struct ddr_training_info_t*)map_sysmem(DDR_TRAINING_INFO_BUFF, 0);
+
+       info->magic = DDR_TRAINING_INFO_MAGIC;
+       info->version = DDR_TRAINING_INFO_VER;
+       info->cs_num = cs_num;
+       info->crc32 = crc32(0, (const uchar *)&info->chipid, sizeof(*info) - 8);
+}
+
+int spl_board_init_f(void)
+{
+       int ret;
+       struct udevice *dev;
+       bool flag;
+       // uint64_t chipid = 0, mac_addr = 0;
+
+#if CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
+       /* init i2c */
+       i2c_init_board();
+#endif
+
+#if CONFIG_IS_ENABLED(SPACEMIT_POWER)
+       board_pmic_init();
+#endif
+
+       raise_cpu_frequency();
+#if CONFIG_IS_ENABLED(SPACEMIT_K1X_EFUSE)
+       // load_chipid_from_efuse(&chipid);
+#endif
+       // get_mac_address(&mac_addr);
+
+       // if fail to get ddr cs number from eeprom, update it from dts node
+       if (!get_ddr_cs_number(&ddr_cs_num))
+               ddr_cs_num = 0;
+
+       // restore prevous saved ddr training info data
+       // flag = restore_ddr_training_info(chipid, mac_addr);
+       flag = true;
+       if (!flag) {
+               // flush data and stack
+               flush_dcache_range(CONFIG_SPL_BSS_START_ADDR, CONFIG_SPL_STACK);
+               flush_dcache_range(round_down((size_t)__data_start, CONFIG_RISCV_CBOM_BLOCK_SIZE),
+                       round_up((size_t)__data_end, CONFIG_RISCV_CBOM_BLOCK_SIZE));
+               icache_disable();
+               dcache_disable();
+               invalidate_dcache_range(CONFIG_SPL_BSS_START_ADDR, CONFIG_SPL_STACK);
+       }
+
+       /* DDR init */
+       ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+       if (ret) {
+               pr_err("DRAM init failed: %d\n", ret);
+               return ret;
+       }
+
+       if (!flag) {
+               icache_enable();
+               dcache_enable();
+       }
+
+       // update_ddr_training_info(chipid, mac_addr);
+       update_ddr_config_info(ddr_cs_num);
+       timer_init();
+
+       return 0;
+}
+
+void board_init_f(ulong dummy)
+{
+       int ret;
+
+       // fix boot mode after boot rom
+       fix_boot_mode();
+
+       // setup pinctrl
+       board_pinctrl_setup();
+
+       ret = spl_early_init();
+       if (ret)
+               panic("spl_early_init() failed: %d\n", ret);
+
+       riscv_cpu_setup(NULL, NULL);
+
+       preloader_console_init();
+       pr_debug("boot_mode: %x\n", get_boot_mode());
+
+       ret = spl_board_init_f();
+       if (ret)
+               panic("spl_board_init_f() failed: %d\n", ret);
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+       char *buildin_name;
+
+       buildin_name = product_name;
+       if (NULL == buildin_name)
+               buildin_name = DEFAULT_PRODUCT_NAME;
+
+       if ((NULL != buildin_name) && (0 == strcmp(buildin_name, name))) {
+               log_emerg("Boot from fit configuration %s\n", name);
+               return 0;
+       }
+       else
+               return -1;
+}
+#endif
+
+static struct env_driver *_spl_env_driver_lookup(enum env_location loc)
+{
+       struct env_driver *drv;
+       const int n_ents = ll_entry_count(struct env_driver, env_driver);
+       struct env_driver *entry;
+
+       drv = ll_entry_start(struct env_driver, env_driver);
+       for (entry = drv; entry != drv + n_ents; entry++) {
+               if (loc == entry->location)
+                       return entry;
+       }
+
+       /* Not found */
+       return NULL;
+}
+
+static struct env_driver *spl_env_driver_lookup(enum env_operation op, enum env_location loc)
+{
+       struct env_driver *drv;
+
+       if (loc == ENVL_UNKNOWN)
+               return NULL;
+
+       drv = _spl_env_driver_lookup(loc);
+       if (!drv) {
+               pr_debug("%s: No environment driver for location %d\n", __func__, loc);
+               return NULL;
+       }
+
+       return drv;
+}
+
+static void spl_load_env(void)
+{
+       struct env_driver *drv;
+       int ret = -1;
+       u32 boot_mode = get_boot_mode();
+
+       /*if boot from usb, spl should not find env*/
+       if (boot_mode == BOOT_MODE_USB){
+               return;
+       }
+
+       /*
+       only load env from mtd dev, because only mtd dev need
+       env mtdparts info to load image.
+       */
+       enum env_location loc = ENVL_UNKNOWN;
+       switch (boot_mode) {
+#ifdef CONFIG_ENV_IS_IN_NAND
+       case BOOT_MODE_NAND:
+               loc = ENVL_NAND;
+               break;
+#endif
+#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
+       case BOOT_MODE_NOR:
+               loc = ENVL_SPI_FLASH;
+               break;
+#endif
+#ifdef CONFIG_ENV_IS_IN_MTD
+       case BOOT_MODE_NAND:
+       case BOOT_MODE_NOR:
+               loc = ENVL_MTD;
+               break;
+#endif
+       default:
+               return;
+       }
+
+       drv = spl_env_driver_lookup(ENVOP_INIT, loc);
+       if (!drv){
+               pr_err("%s, can not load env from storage\n", __func__);
+               return;
+       }
+
+       ret = drv->load();
+       if (!ret){
+               pr_info("has init env successful\n");
+       }else{
+               pr_err("load env from storage fail, would use default env\n");
+               /*if load env from storage fail, it should not write bootmode to reg*/
+               boot_mode = BOOT_MODE_NONE;
+       }
+}
+
+bool get_mac_address(uint64_t *mac_addr)
+{
+       int eeprom_addr;
+
+       eeprom_addr = k1x_eeprom_init();
+       if ((eeprom_addr >= 0) && (NULL != mac_addr) && (0 == spacemit_eeprom_read(
+               eeprom_addr, (uint8_t*)mac_addr, TLV_CODE_MAC_BASE))) {
+               pr_info("Get mac address %llx from eeprom\n", *mac_addr);
+               return true;
+       }
+
+       return false;
+}
+
+char *get_product_name(void)
+{
+       char *name = NULL;
+       int eeprom_addr;
+       char tmp_name[64];
+
+       eeprom_addr = k1x_eeprom_init();
+       name = calloc(1, 64);
+       if ((eeprom_addr >= 0) && (NULL != name) && (0 == spacemit_eeprom_read(
+               eeprom_addr, name, TLV_CODE_PRODUCT_NAME))) {
+               pr_info("Get product name from eeprom %s\n", name);
+
+               /*
+                       be compatible to previous format name,
+                       such as: k1_deb1 -> k1-x_deb1
+               */
+               if (strncmp(name, CONFIG_SYS_BOARD, 4)){
+                       sprintf(tmp_name, "%s_%s", CONFIG_SYS_BOARD, &name[3]);
+                       strcpy(name, tmp_name);
+               }
+               return name;
+       }
+
+       if (NULL != name)
+               free(name);
+
+       pr_debug("Use default product name %s\n", DEFAULT_PRODUCT_NAME);
+       return NULL;
+}
+
+bool get_ddr_cs_number(uint32_t *cs_num)
+{
+       int eeprom_addr;
+
+       eeprom_addr = k1x_eeprom_init();
+       if ((eeprom_addr >= 0) && (NULL != cs_num) && (0 == spacemit_eeprom_read(
+               eeprom_addr, (uint8_t*)cs_num, TLV_CODE_DDR_CSNUM))) {
+               pr_info("Get ddr cs num %d from eeprom\n", *cs_num);
+               return true;
+       }
+
+       return false;
+}
+
+void spl_board_init(void)
+{
+       /*load env*/
+       spl_load_env();
+       product_name = get_product_name();
+}
+
+struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+       return map_sysmem(CONFIG_SPL_LOAD_FIT_ADDRESS, 0);
+}
+
+void board_boot_order(u32 *spl_boot_list)
+{
+       u32 boot_mode = get_boot_mode();
+       pr_debug("boot_mode:%x\n", boot_mode);
+       if (boot_mode == BOOT_MODE_USB){
+               spl_boot_list[0] = BOOT_DEVICE_BOARD;
+       }else{
+               switch (boot_mode) {
+               case BOOT_MODE_EMMC:
+                       spl_boot_list[0] = BOOT_DEVICE_MMC2;
+                       break;
+               case BOOT_MODE_NAND:
+                       spl_boot_list[0] = BOOT_DEVICE_NAND;
+                       break;
+               case BOOT_MODE_NOR:
+                       spl_boot_list[0] = BOOT_DEVICE_NOR;
+                       break;
+               case BOOT_MODE_SD:
+                       spl_boot_list[0] = BOOT_DEVICE_MMC1;
+                       break;
+               default:
+                       spl_boot_list[0] = BOOT_DEVICE_RAM;
+                       break;
+               }
+
+               //reserve for debug/test to load/run uboot from ram.
+               spl_boot_list[1] = BOOT_DEVICE_RAM;
+       }
+}
diff --git a/board/spacemit/k1-x/splash.c b/board/spacemit/k1-x/splash.c
new file mode 100644 (file)
index 0000000..bde77aa
--- /dev/null
@@ -0,0 +1,172 @@
+#include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <image.h>
+#include <splash.h>
+#include <mmc.h>
+#include <fb_spacemit.h>
+
+
+#if defined(CONFIG_SPLASH_SCREEN) && defined(CONFIG_CMD_BMP)
+
+int set_emmc_splash_location(struct splash_location *locations) {
+       int dev_index = mmc_get_env_dev();
+       int part_index;
+       char devpart_str[16];
+       int err;
+
+       err = get_partition_index_by_name(BOOTFS_NAME, &part_index);
+       if (err) {
+               pr_err("Failed to get partition index for %s\n", BOOTFS_NAME);
+               return -1;
+       }
+
+       snprintf(devpart_str, sizeof(devpart_str), "%d:%d", dev_index, part_index);
+
+       locations[0].name = "emmc_fs";
+       locations[0].storage = SPLASH_STORAGE_MMC;
+       locations[0].flags = SPLASH_STORAGE_FS;
+       locations[0].devpart = strdup(devpart_str);
+       return 0;
+}
+
+int set_mmc_splash_location(struct splash_location *locations) {
+       int dev_index = mmc_get_env_dev();
+       int part_index;
+       char devpart_str[16];
+       int err;
+
+       err = get_partition_index_by_name(BOOTFS_NAME, &part_index);
+       if (err) {
+               pr_err("Failed to get partition index for %s\n", BOOTFS_NAME);
+               return -1;
+       }
+
+       snprintf(devpart_str, sizeof(devpart_str), "%d:%d", dev_index, part_index);
+
+       locations[0].name = "mmc_fs";
+       locations[0].storage = SPLASH_STORAGE_MMC;
+       locations[0].flags = SPLASH_STORAGE_FS;
+       locations[0].devpart = strdup(devpart_str);
+       return 0;
+}
+
+int set_nor_splash_location(struct splash_location *locations) {
+       struct blk_desc *dev_desc;
+       struct disk_partition info;
+       int err;
+       u32 part;
+       char devpart_str[16];
+
+       if (run_command("nvme scan", 0)) {
+               pr_err("Cannot scan NVMe devices!\n");
+               return -1;
+       }
+
+       dev_desc = blk_get_dev("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX);
+       if (!dev_desc) {
+               pr_err("Cannot find NVMe device\n");
+               return -1;
+       }
+
+       for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+               err = part_get_info(dev_desc, part, &info);
+               if (err) {
+                       continue;
+               }
+
+               if (!strcmp(BOOTFS_NAME, info.name)) {
+                       break;
+               }
+       }
+
+       if (part > MAX_SEARCH_PARTITIONS) {
+               pr_err("Failed to find bootfs on NOR\n");
+               return -1;
+       }
+
+       snprintf(devpart_str, sizeof(devpart_str), "%d:%d", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX, part);
+
+       locations[0].name = "nvme_fs";
+       locations[0].storage = SPLASH_STORAGE_NVME;
+       locations[0].flags = SPLASH_STORAGE_FS;
+       locations[0].devpart = strdup(devpart_str);
+       return 0;
+}
+
+int set_nand_splash_location(struct splash_location *locations)
+{
+       char *nand_part = parse_mtdparts_and_find_bootfs();
+       if (nand_part) {
+               locations[0].name = "nand_fs";
+               locations[0].storage = SPLASH_STORAGE_NAND;
+               locations[0].flags = SPLASH_STORAGE_FS;
+               locations[0].mtdpart = strdup(nand_part);
+               locations[0].ubivol = strdup(BOOTFS_NAME);
+               return 0;
+       } else {
+               pr_err("Failed to find bootfs on NAND\n");
+               return -1;
+       }
+}
+
+int load_splash_screen(void) {
+       int ret;
+       enum board_boot_mode boot_mode = get_boot_mode();
+       struct splash_location splash_locations[1];
+
+       memset(splash_locations, 0, sizeof(splash_locations));
+
+       switch (boot_mode) {
+               case BOOT_MODE_EMMC:
+                       ret = set_emmc_splash_location(splash_locations);
+                       break;
+               case BOOT_MODE_SD:
+                       ret = set_mmc_splash_location(splash_locations);
+                       break;
+               case BOOT_MODE_NAND:
+                       ret = set_nand_splash_location(splash_locations);
+                       break;
+               case BOOT_MODE_NOR:
+                       ret = set_nor_splash_location(splash_locations);
+                       break;
+               default:
+                       pr_err("Unsupported boot mode for splash screen\n");
+                       break;
+       }
+       if(ret)
+               return -1;
+
+       if (CONFIG_IS_ENABLED(SPLASH_SOURCE))
+               return splash_source_load(splash_locations, ARRAY_SIZE(splash_locations));
+
+       return splash_video_logo_load();
+}
+
+int splash_screen_prepare(void)
+{
+       enum board_boot_mode boot_mode = get_boot_mode();
+       switch (boot_mode) {
+       case BOOT_MODE_EMMC:
+               env_set("splashsource", "emmc_fs");
+               break;
+       case BOOT_MODE_SD:
+               env_set("splashsource", "mmc_fs");
+               break;
+       case BOOT_MODE_NAND:
+               env_set("splashsource", "nand_fs");
+               break;
+       case BOOT_MODE_NOR:
+               env_set("splashsource", "nvme_fs");
+               break;
+       case BOOT_MODE_SHELL:
+       case BOOT_MODE_USB:
+       default:
+               pr_err("Cannot support showing bootlogo in this boot mode!\n");
+               break;
+       }
+
+       return load_splash_screen();
+}
+
+#endif
index 6b3b8f072cb918546f4ccc5c62ed502e409ec32d..e29e5e15d9badd726fcb9f3f8993f7d652139d32 100644 (file)
@@ -1190,6 +1190,13 @@ config AUTOBOOT_MENU_SHOW
          environmnent variable (if enabled) and before handling the boot delay.
          See README.bootmenu for more details.
 
+config BOOTMENU_KEY_ESC
+       bool "Use ESC key to enter the boot menu"
+       depends on AUTOBOOT_MENU_SHOW
+       help
+         If this option is enabled, holding down the ESC key during boot will
+         trigger the boot menu.
+
 config BOOTMENU_DISABLE_UBOOT_CONSOLE
        bool "Disallow bootmenu to enter the U-Boot console"
        depends on AUTOBOOT_MENU_SHOW
index 0e0be94f41f1e6d4763e925d58ff961f7109638b..88e5cd5e38f7389300cfd71d2938168550bef7ed 100644 (file)
@@ -2405,16 +2405,23 @@ config JFFS2_DEV
        help
          The default device to use with the jffs2 command.
 
+config JFFS2_MTDPARTS
+    bool "Enable JFFS2 MTD partition options"
+    depends on CMD_JFFS2
+    help
+      Enable specifying default offset and size for JFFS2 partition
+      through configuration.
+
 config JFFS2_PART_OFFSET
        hex "Default offset within flash to locate the JFFS2 image"
-       depends on CMD_JFFS2
+       depends on JFFS2_MTDPARTS
        default 0x0
        help
          The default offset within flash to locate the JFFS2 image.
 
 config JFFS2_PART_SIZE
        hex "Default size of JFFS2 partition"
-       depends on CMD_JFFS2
+       depends on JFFS2_MTDPARTS
        default 0xFFFFFFFF
        help
          The default size of the JFFS2 partition
@@ -2625,4 +2632,21 @@ config MMC_SPEED_MODE_SET
          and is indicated using the index from enum bus_mode in
          include/mmc.h. A speed mode can be set only if it has already
          been enabled in the device tree.
+
+menu "spacemit commands"
+
+config SPACEMIT_FLASH
+       bool "enable spacemit flash behavior"
+       default n
+       help
+         enable spacemit flash behavior, use for flashing function.
+
+config SPL_FASTBOOT
+       bool "Enable SPL Fastboot Mode"
+       default n
+       help
+         Enable this option to enable fastboot in spl
+
+endmenu
+
 endmenu
index 6e87522b62e819429de731fc7be8cefbc345c931..e81ff13b96e996b3fc6a00670fa1e6b76a625aa0 100644 (file)
@@ -194,6 +194,8 @@ obj-$(CONFIG_CMD_ETHSW) += ethsw.o
 obj-$(CONFIG_CMD_AXI) += axi.o
 obj-$(CONFIG_CMD_PVBLOCK) += pvblock.o
 
+obj-$(CONFIG_SPACEMIT_FLASH) += spacemit_flash.o
+
 # Power
 obj-$(CONFIG_CMD_PMIC) += pmic.o
 obj-$(CONFIG_CMD_REGULATOR) += regulator.o
index 704d36debe0faf670beac8a4fae7ecd3e08c7520..3f3e7f84cc2e7d32740b8df31bc3596f7a4e9b69 100644 (file)
@@ -424,7 +424,7 @@ static void menu_display_statusline(struct menu *m)
        printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
        puts(ANSI_CLEAR_LINE);
        printf(ANSI_CURSOR_POSITION, menu->count + 6, 3);
-       puts("Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
+       puts("Press UP/DOWN to move, ENTER to select, CTRL+C to quit");
        puts(ANSI_CLEAR_LINE_TO_END);
        printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
        puts(ANSI_CLEAR_LINE);
@@ -581,6 +581,26 @@ cleanup:
 int menu_show(int bootdelay)
 {
        int ret;
+#ifdef CONFIG_BOOTMENU_KEY_ESC
+       ret = run_command("usb start", 0);
+       if (ret != 0) {
+               printf("Error: Failed to execute 'usb start'\n");
+       }
+
+       if (tstc()) {
+               int key = fgetc(stdin);
+               /* 0x1B is the ASCII code for 'Esc' */
+               if (key == 0x1B){
+                       printf("Enter boot menu\n");
+               }else{
+                       return 0;
+               }
+       }
+       else
+               return 0;
+#endif
+
+       env_set("stdout","serial,vidconsole");
 
        while (1) {
                ret = bootmenu_show(bootdelay);
index e00fcc2022665024c7399d97224da15861566bc8..b726ddab2d1670b34b6bf3cc9fcbb75de7fd654f 100644 (file)
@@ -83,6 +83,7 @@
 #include <linux/list.h>
 #include <linux/ctype.h>
 #include <cramfs/cramfs_fs.h>
+#include <linux/mtd/mtd.h>
 
 #if defined(CONFIG_CMD_NAND)
 #include <linux/mtd/rawnand.h>
 #define MTD_WRITEABLE_CMD              1
 
 /* current active device and partition number */
-#ifdef CONFIG_CMD_MTDPARTS
+#ifdef CONFIG_JFFS2_MTDPARTS
+/* Use local ones */
+static struct mtd_device *current_mtd_dev = NULL;
+static u8 current_mtd_partnum = 0;
+struct mtd_info *get_spi_flash(void);
+#else
 /* Use the ones declared in cmd_mtdparts.c */
 extern struct mtd_device *current_mtd_dev;
 extern u8 current_mtd_partnum;
-#else
-/* Use local ones */
-struct mtd_device *current_mtd_dev = NULL;
-u8 current_mtd_partnum = 0;
 #endif
 
 #if defined(CONFIG_CMD_CRAMFS)
@@ -146,7 +148,7 @@ extern int cramfs_info (struct part_info *info);
 #define cramfs_info(x)         (0)
 #endif
 
-#ifndef CONFIG_CMD_MTDPARTS
+#ifdef CONFIG_JFFS2_MTDPARTS
 /**
  * Check device number to be within valid range for given device type.
  *
@@ -235,7 +237,7 @@ static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *d
 }
 
 /*
- * 'Static' version of command line mtdparts_init() routine. Single partition on
+ * 'Static' version of command line jffs2_mtdparts_init() routine. Single partition on
  * a single device configuration.
  */
 
@@ -258,39 +260,17 @@ static inline u32 get_part_sector_size_nand(struct mtdids *id)
 #endif
 }
 
-static inline u32 get_part_sector_size_nor(struct mtdids *id, struct part_info *part)
+static u32 get_part_sector_size_nor(struct part_info *part)
 {
-#if defined(CONFIG_CMD_FLASH)
-       u32 end_phys, start_phys, sector_size = 0, size = 0;
-       int i;
-       flash_info_t *flash;
-
-       flash = &flash_info[id->num];
-
-       start_phys = flash->start[0] + part->offset;
-       end_phys = start_phys + part->size - 1;
-
-       for (i = 0; i < flash->sector_count; i++) {
-               if (flash->start[i] >= end_phys)
-                       break;
-
-               if (flash->start[i] >= start_phys) {
-                       if (i == flash->sector_count - 1) {
-                               size = flash->start[0] + flash->size - flash->start[i];
-                       } else {
-                               size = flash->start[i+1] - flash->start[i];
-                       }
+       struct mtd_info *mtd;
 
-                       if (sector_size < size)
-                               sector_size = size;
-               }
+       mtd = get_spi_flash();
+       if (!mtd) {
+               pr_err("Failed to get MTD device for SPI NOR\n");
+               return 0;
        }
-
-       return sector_size;
-#else
-       BUG();
-       return 0;
-#endif
+       part->sector_size = mtd->erasesize;
+       return mtd->erasesize;
 }
 
 static inline u32 get_part_sector_size_onenand(void)
@@ -312,7 +292,7 @@ static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part
        if (id->type == MTD_DEV_TYPE_NAND)
                return get_part_sector_size_nand(id);
        else if (id->type == MTD_DEV_TYPE_NOR)
-               return get_part_sector_size_nor(id, part);
+               return get_part_sector_size_nor(part);
        else if (id->type == MTD_DEV_TYPE_ONENAND)
                return get_part_sector_size_onenand();
        else
@@ -325,18 +305,18 @@ static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part
  * Parse and initialize global mtdids mapping and create global
  * device/partition list.
  *
- * 'Static' version of command line mtdparts_init() routine. Single partition on
+ * 'Static' version of command line jffs2_mtdparts_init() routine. Single partition on
  * a single device configuration.
  *
  * Return: 0 on success, 1 otherwise
  */
-int mtdparts_init(void)
+int jffs2_mtdparts_init(void)
 {
        static int initialized = 0;
        u32 size;
        char *dev_name;
 
-       DEBUGF("\n---mtdparts_init---\n");
+       DEBUGF("\n---jffs2_mtdparts_init---\n");
        if (!initialized) {
                struct mtdids *id;
                struct part_info *part;
@@ -370,11 +350,11 @@ int mtdparts_init(void)
                id->size = size;
                INIT_LIST_HEAD(&id->link);
 
-               DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
+               DEBUGF("dev id: type = %d, num = %d, size = 0x%08llx, mtd_id = %s\n",
                                id->type, id->num, id->size, id->mtd_id);
 
                /* partition */
-               part->name = "static";
+               part->name = "jffs2";
                part->auto_name = 0;
 
                part->size = CONFIG_JFFS2_PART_SIZE;
@@ -390,7 +370,7 @@ int mtdparts_init(void)
 
                part->sector_size = get_part_sector_size(id, part);
 
-               DEBUGF("part  : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
+               DEBUGF("part  : name = %s, size = 0x%08llx, offset = 0x%08llx\n",
                                part->name, part->size, part->offset);
 
                /* device */
@@ -403,7 +383,7 @@ int mtdparts_init(void)
 
        return 0;
 }
-#endif /* #ifndef CONFIG_CMD_MTDPARTS */
+#endif /* #ifdef CONFIG_JFFS2_MTDPARTS */
 
 /**
  * Return pointer to the partition of a requested number from a requested
@@ -483,9 +463,15 @@ int do_jffs2_fsload(struct cmd_tbl *cmdtp, int flag, int argc,
                filename = argv[2];
        }
 
+#ifdef CONFIG_JFFS2_MTDPARTS
+       /* make sure we are in sync with env variables */
+       if (jffs2_mtdparts_init() !=0)
+               return 1;
+#else
        /* make sure we are in sync with env variables */
        if (mtdparts_init() !=0)
                return 1;
+#endif
 
        if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
 
@@ -532,9 +518,15 @@ int do_jffs2_ls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
        if (argc == 2)
                filename = argv[1];
 
+#ifdef CONFIG_JFFS2_MTDPARTS
+       /* make sure we are in sync with env variables */
+       if (jffs2_mtdparts_init() !=0)
+               return 1;
+#else
        /* make sure we are in sync with env variables */
        if (mtdparts_init() !=0)
                return 1;
+#endif
 
        if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
 
@@ -568,9 +560,15 @@ int do_jffs2_fsinfo(struct cmd_tbl *cmdtp, int flag, int argc,
        char *fsname;
        int ret;
 
+#ifdef CONFIG_JFFS2_MTDPARTS
+       /* make sure we are in sync with env variables */
+       if (jffs2_mtdparts_init() !=0)
+               return 1;
+#else
        /* make sure we are in sync with env variables */
        if (mtdparts_init() !=0)
                return 1;
+#endif
 
        if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
 
index ad5cc9827d5540d495dd3dd827c94b33f5f707b0..8cb7478cab5636b3ebefbe6c765cf2761b283e23 100644 (file)
--- a/cmd/mtd.c
+++ b/cmd/mtd.c
@@ -253,7 +253,8 @@ static int do_mtd_io(struct cmd_tbl *cmdtp, int flag, int argc,
        bool dump, read, raw, woob, write_empty_pages, has_pages = false;
        u64 start_off, off, len, remaining, default_len;
        struct mtd_oob_ops io_op = {};
-       uint user_addr = 0, npages;
+       uint npages;
+       u64 user_addr = 0;
        const char *cmd = argv[0];
        struct mtd_info *mtd;
        u32 oob_len;
index 53e6b57b60eada06ad974915c1ea418bb56dfd4b..4d580d818aef8636dbebc400cc5ad252db91bb5b 100644 (file)
@@ -118,7 +118,7 @@ static int env_print(char *name, int flag)
        }
 
        /* should never happen */
-       printf("## Error: cannot export environment\n");
+       pr_err("## Error: cannot export environment\n");
        return 0;
 }
 
@@ -145,7 +145,7 @@ static int do_env_print(struct cmd_tbl *cmdtp, int flag, int argc,
                rcode = env_print(NULL, env_flag);
                if (!rcode)
                        return 1;
-               printf("\nEnvironment size: %d/%ld bytes\n",
+               pr_debug("\nEnvironment size: %d/%ld bytes\n",
                        rcode, (ulong)ENV_SIZE);
                return 0;
        }
@@ -155,7 +155,7 @@ static int do_env_print(struct cmd_tbl *cmdtp, int flag, int argc,
        for (i = 1; i < argc; ++i) {
                int rc = env_print(argv[i], env_flag);
                if (!rc) {
-                       printf("## Error: \"%s\" not defined\n", argv[i]);
+                       pr_err("## Error: \"%s\" not defined\n", argv[i]);
                        ++rcode;
                }
        }
@@ -255,7 +255,7 @@ static int _do_env_set(int flag, int argc, char *const argv[], int env_flag)
        name = argv[1];
 
        if (strchr(name, '=')) {
-               printf("## Error: illegal character '='"
+               pr_err("## Error: illegal character '='"
                       "in variable name \"%s\"\n", name);
                return 1;
        }
@@ -278,7 +278,7 @@ static int _do_env_set(int flag, int argc, char *const argv[], int env_flag)
 
        value = malloc(len);
        if (value == NULL) {
-               printf("## Can't malloc %d bytes\n", len);
+               pr_err("## Can't malloc %d bytes\n", len);
                return 1;
        }
        for (i = 2, s = value; i < argc; ++i) {
@@ -296,7 +296,7 @@ static int _do_env_set(int flag, int argc, char *const argv[], int env_flag)
        hsearch_r(e, ENV_ENTER, &ep, &env_htab, env_flag);
        free(value);
        if (!ep) {
-               printf("## Error inserting \"%s\" variable, errno=%d\n",
+               pr_err("## Error inserting \"%s\" variable, errno=%d\n",
                        name, errno);
                return 1;
        }
@@ -411,7 +411,7 @@ int do_env_ask(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 static int print_static_binding(const char *var_name, const char *callback_name,
                                void *priv)
 {
-       printf("\t%-20s %-20s\n", var_name, callback_name);
+       pr_debug("\t%-20s %-20s\n", var_name, callback_name);
 
        return 0;
 }
@@ -440,9 +440,9 @@ static int print_active_callback(struct env_entry *entry)
 
        if (i == num_callbacks)
                /* this should probably never happen, but just in case... */
-               printf("\t%-20s %p\n", entry->key, entry->callback);
+               pr_debug("\t%-20s %p\n", entry->key, entry->callback);
        else
-               printf("\t%-20s %-20s\n", entry->key, clbkp->name);
+               pr_debug("\t%-20s %-20s\n", entry->key, clbkp->name);
 
        return 0;
 }
@@ -465,20 +465,20 @@ int do_env_callback(struct cmd_tbl *cmdtp, int flag, int argc,
        for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
             i < num_callbacks;
             i++, clbkp++)
-               printf("\t%s\n", clbkp->name);
+               pr_debug("\t%s\n", clbkp->name);
        puts("\n");
 
        /* Print the static bindings that may exist */
        puts("Static callback bindings:\n");
-       printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
-       printf("\t%-20s %-20s\n", "-------------", "-------------");
+       pr_debug("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+       pr_debug("\t%-20s %-20s\n", "-------------", "-------------");
        env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding, NULL);
        puts("\n");
 
        /* walk through each variable and print the callback if it has one */
        puts("Active callback bindings:\n");
-       printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
-       printf("\t%-20s %-20s\n", "-------------", "-------------");
+       pr_debug("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+       pr_debug("\t%-20s %-20s\n", "-------------", "-------------");
        hwalk_r(&env_htab, print_active_callback);
        return 0;
 }
@@ -491,7 +491,7 @@ static int print_static_flags(const char *var_name, const char *flags,
        enum env_flags_vartype type = env_flags_parse_vartype(flags);
        enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
 
-       printf("\t%-20s %-20s %-20s\n", var_name,
+       pr_debug("\t%-20s %-20s %-20s\n", var_name,
                env_flags_get_vartype_name(type),
                env_flags_get_varaccess_name(access));
 
@@ -509,7 +509,7 @@ static int print_active_flags(struct env_entry *entry)
        type = (enum env_flags_vartype)
                (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
        access = env_flags_parse_varaccess_from_binflags(entry->flags);
-       printf("\t%-20s %-20s %-20s\n", entry->key,
+       pr_debug("\t%-20s %-20s %-20s\n", entry->key,
                env_flags_get_vartype_name(type),
                env_flags_get_varaccess_name(access));
 
@@ -522,7 +522,7 @@ static int print_active_flags(struct env_entry *entry)
 int do_env_flags(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
        /* Print the available variable types */
-       printf("Available variable type flags (position %d):\n",
+       pr_debug("Available variable type flags (position %d):\n",
                ENV_FLAGS_VARTYPE_LOC);
        puts("\tFlag\tVariable Type Name\n");
        puts("\t----\t------------------\n");
@@ -530,7 +530,7 @@ int do_env_flags(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
        puts("\n");
 
        /* Print the available variable access types */
-       printf("Available variable access flags (position %d):\n",
+       pr_debug("Available variable access flags (position %d):\n",
                ENV_FLAGS_VARACCESS_LOC);
        puts("\tFlag\tVariable Access Name\n");
        puts("\t----\t--------------------\n");
@@ -539,18 +539,18 @@ int do_env_flags(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 
        /* Print the static flags that may exist */
        puts("Static flags:\n");
-       printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+       pr_debug("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
                "Variable Access");
-       printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+       pr_debug("\t%-20s %-20s %-20s\n", "-------------", "-------------",
                "---------------");
        env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags, NULL);
        puts("\n");
 
        /* walk through each variable and print the flags if non-default */
        puts("Active flags:\n");
-       printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+       pr_debug("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
                "Variable Access");
-       printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+       pr_debug("\t%-20s %-20s %-20s\n", "-------------", "-------------",
                "---------------");
        hwalk_r(&env_htab, print_active_flags);
        return 0;
@@ -865,7 +865,7 @@ NXTARG:             ;
        return 0;
 
 sep_err:
-       printf("## Error: %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
+       pr_err("## Error: %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
               cmd);
        return 1;
 }
@@ -946,8 +946,9 @@ static int do_env_import(struct cmd_tbl *cmdtp, int flag,
        if (argc < 1)
                return CMD_RET_USAGE;
 
-       if (!fmt)
-               printf("## Warning: defaulting to text format\n");
+       if (!fmt){
+               pr_info("## Warning: defaulting to text format\n");
+       }
 
        if (sep != '\n' && crlf_is_lf )
                crlf_is_lf = 0;
@@ -972,11 +973,11 @@ static int do_env_import(struct cmd_tbl *cmdtp, int flag,
                        ++size;
                }
                if (size == MAX_ENV_SIZE) {
-                       printf("## Warning: Input data exceeds %d bytes"
+                       pr_info("## Warning: Input data exceeds %d bytes"
                                " - truncated\n", MAX_ENV_SIZE);
                }
                size += 2;
-               printf("## Info: input data size = %zu = 0x%zX\n", size, size);
+               pr_info("## Info: input data size = %zu = 0x%zX\n", size, size);
        }
 
        if (argc > 2)
@@ -987,7 +988,7 @@ static int do_env_import(struct cmd_tbl *cmdtp, int flag,
                env_t *ep = (env_t *)ptr;
 
                if (size <= offsetof(env_t, data)) {
-                       printf("## Error: Invalid size 0x%zX\n", size);
+                       pr_err("## Error: Invalid size 0x%zX\n", size);
                        return 1;
                }
 
@@ -1012,7 +1013,7 @@ static int do_env_import(struct cmd_tbl *cmdtp, int flag,
        return 0;
 
 sep_err:
-       printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
+       pr_err("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
                cmd);
        return 1;
 }
@@ -1036,7 +1037,7 @@ static int do_env_indirect(struct cmd_tbl *cmdtp, int flag,
        }
 
        if (env_get(from) == NULL && default_value == NULL) {
-               printf("## env indirect: Environment variable for <from> (%s) does not exist.\n", from);
+               pr_err("## env indirect: Environment variable for <from> (%s) does not exist.\n", from);
 
                return CMD_RET_FAILURE;
        }
@@ -1080,15 +1081,15 @@ static int print_env_info(void)
                value = "unknown";
                break;
        }
-       printf("env_valid = %s\n", value);
+       pr_debug("env_valid = %s\n", value);
 
        /* print environment ready flag */
        value = gd->flags & GD_FLG_ENV_READY ? "true" : "false";
-       printf("env_ready = %s\n", value);
+       pr_debug("env_ready = %s\n", value);
 
        /* print environment using default flag */
        value = gd->flags & GD_FLG_ENV_DEFAULT ? "true" : "false";
-       printf("env_use_default = %s\n", value);
+       pr_debug("env_use_default = %s\n", value);
 
        return CMD_RET_SUCCESS;
 }
@@ -1142,11 +1143,11 @@ static int do_env_info(struct cmd_tbl *cmdtp, int flag,
        if (eval_flags & ENV_INFO_IS_DEFAULT) {
                if (gd->flags & GD_FLG_ENV_DEFAULT) {
                        if (!quiet)
-                               printf("Default environment is used\n");
+                               pr_debug("Default environment is used\n");
                        eval_results |= ENV_INFO_IS_DEFAULT;
                } else {
                        if (!quiet)
-                               printf("Environment was loaded from persistent storage\n");
+                               pr_debug("Environment was loaded from persistent storage\n");
                }
        }
 
@@ -1156,15 +1157,15 @@ static int do_env_info(struct cmd_tbl *cmdtp, int flag,
                loc = env_get_location(ENVOP_SAVE, gd->env_load_prio);
                if (ENVL_NOWHERE != loc && ENVL_UNKNOWN != loc) {
                        if (!quiet)
-                               printf("Environment can be persisted\n");
+                               pr_debug("Environment can be persisted\n");
                        eval_results |= ENV_INFO_IS_PERSISTED;
                } else {
                        if (!quiet)
-                               printf("Environment cannot be persisted\n");
+                               pr_debug("Environment cannot be persisted\n");
                }
 #else
                if (!quiet)
-                       printf("Environment cannot be persisted\n");
+                       pr_debug("Environment cannot be persisted\n");
 #endif
        }
 
diff --git a/cmd/spacemit_flash.c b/cmd/spacemit_flash.c
new file mode 100644 (file)
index 0000000..811f1b5
--- /dev/null
@@ -0,0 +1,1193 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <blk.h>
+#include <bootstage.h>
+#include <command.h>
+#include <common.h>
+#include <console.h>
+#include <div64.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <fs.h>
+#include <image.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <memalign.h>
+#include <mmc.h>
+#include <part.h>
+#include <u-boot/crc.h>
+#include <usb.h>
+#include <fb_spacemit.h>
+#include <cJSON.h>
+#include <env.h>
+#include <mtd.h>
+#include <fb_mtd.h>
+#include <nvme.h>
+
+static int dev_emmc_num = -1;
+static int dev_sdio_num = -1;
+static u32 bootfs_part_index = 0;
+
+void recovery_show_result(struct flash_dev *fdev, int ret);
+
+static void free_flash_dev(struct flash_dev *fdev)
+{
+       for (int i = 0; i < MAX_PARTITION_NUM; i++){
+               if (fdev->parts_info[i].part_name != NULL){
+                       free(fdev->parts_info[i].part_name);
+                       free(fdev->parts_info[i].file_name);
+                       free(fdev->parts_info[i].size);
+               }else{
+                       break;
+               }
+       }
+       free(fdev->gptinfo.gpt_table);
+       free(fdev->mtd_table);
+       free(fdev);
+}
+
+
+static int _write_gpt_partition(struct flash_dev *fdev)
+{
+       __maybe_unused char write_part_command[300] = {"\0"};
+       char *gpt_table_str = NULL;
+
+       u32 boot_mode = get_boot_pin_select();
+
+       if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 0){
+               gpt_table_str = malloc(strlen(fdev->gptinfo.gpt_table) + 32);
+               if (gpt_table_str == NULL){
+                       return -1;
+               }
+               sprintf(gpt_table_str, "env set -f partitions '%s'", fdev->gptinfo.gpt_table);
+               run_command(gpt_table_str, 0);
+               free(gpt_table_str);
+       }
+
+       switch(boot_mode){
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+               sprintf(write_part_command, "gpt write mmc %x '%s'",
+                       CONFIG_FASTBOOT_FLASH_MMC_DEV, fdev->gptinfo.gpt_table);
+               if (run_command(write_part_command, 0)){
+                       printf("write gpt fail\n");
+                       return -1;
+               }
+               break;
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_SUPPORT_BLOCK_DEV)
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               printf("write gpt to dev:%s\n", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME);
+
+               /*nvme need scan at first*/
+               if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)
+                                               && nvme_scan_namespace()){
+                       printf("can not can nvme devices!\n");
+                       return -1;
+               }
+
+               sprintf(write_part_command, "gpt write %s %x '%s'",
+                       CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX,
+                       fdev->gptinfo.gpt_table);
+               if (run_command(write_part_command, 0)){
+                       printf("write gpt fail\n");
+                       return -1;
+               }
+               break;
+#endif
+       default:
+               break;
+       }
+       return 0;
+}
+
+
+static int _write_mtd_partition(char mtd_table[128])
+{
+#ifdef CONFIG_MTD
+       struct mtd_info *mtd;
+       char mtd_ids[36] = {"\0"};
+       char mtd_parts[128] = {"\0"};
+
+       mtd_probe_devices();
+
+       /*
+       try to find the first mtd device, it there have mutil mtd device such as nand and nor,
+       it only use the first one.
+       */
+       mtd_for_each_device(mtd) {
+               if (!mtd_is_partition(mtd))
+                       break;
+       }
+
+       if (mtd == NULL){
+               printf("can not get mtd device\n");
+               return -1;
+       }
+
+       /*to mtd device, it should write mtd table to env.*/
+       sprintf(mtd_ids, "%s=spi-dev", mtd->name);
+       sprintf(mtd_parts, "spi-dev:%s", mtd_table);
+
+       env_set("mtdids", mtd_ids);
+       env_set("mtdparts", mtd_parts);
+#endif
+       return 0;
+}
+
+/* Initialize the mmc device given its number */
+static int init_mmc_device(int dev_num)
+{
+       struct mmc *mmc = find_mmc_device(dev_num);
+
+       if (!mmc) {
+               debug("Cannot find mmc device %d\n", dev_num);
+               return RESULT_FAIL;
+       }
+
+       if (mmc_init(mmc)) {
+               debug("mmc init failed for device %d\n", dev_num);
+               return RESULT_FAIL;
+       }
+       return RESULT_OK;
+}
+
+/* Detect and classify mmc device */
+static void detect_and_classify_mmc(int dev_num)
+{
+       int current_dev_num, err;
+       struct disk_partition info;
+
+       struct mmc *mmc = find_mmc_device(dev_num);
+       if (!mmc)
+               return;
+
+       current_dev_num = mmc_get_blk_desc(mmc)->devnum;
+       if (IS_SD(mmc)) {
+               dev_sdio_num = current_dev_num;
+               for (u32 p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+                       err = part_get_info(mmc_get_blk_desc(mmc), p, &info);
+                       if (err)
+                               continue;
+                       if (!strcmp(FLASH_IMG_PARTNAME, info.name)){
+                               debug("match info.name:%s\n", info.name);
+                               bootfs_part_index = p;
+                               break;
+                       }
+               }
+               debug("SDIO detected with number: %d\n", dev_sdio_num);
+       } else {
+               dev_emmc_num = current_dev_num;
+               debug("eMMC initialized with number: %d\n", dev_emmc_num);
+       }
+}
+
+
+int check_mmc_exist_and_initialize(void)
+{
+       int mmc_dev_num = get_mmc_num();
+
+       for (int i = 0; i < mmc_dev_num; i++) {
+               if (init_mmc_device(i) == RESULT_OK) {
+                       detect_and_classify_mmc(i);
+               }
+       }
+
+       if (dev_sdio_num == -1) {
+               printf("SDIO not detected.\n");
+               return RESULT_FAIL;
+       }
+       return RESULT_OK;
+}
+
+int download_file_via_tftp(char *file_name, char *load_addr) {
+       char full_path[128];
+       char cmd_buffer[256];
+       char *tftp_server_ip;
+       char *tftp_path_prefix;
+
+       tftp_server_ip = env_get("serverip");
+       if (!tftp_server_ip) {
+               printf("Error: TFTP server IP not set\n");
+               return -1;
+       }
+
+       tftp_path_prefix = env_get("net_data_path");
+       if (!tftp_path_prefix) {
+               printf("Error: TFTP relative path not set\n");
+               return -1;
+       }
+
+       sprintf(full_path, "%s%s", tftp_path_prefix, file_name);
+       sprintf(cmd_buffer, "tftpboot %s %s:%s", load_addr, tftp_server_ip, full_path);
+
+       if (run_command(cmd_buffer, 0)) {
+               printf("Error: TFTP download failed\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int _find_partition_file(struct flash_dev *fdev, char *tmp_file, char *temp_fname, u32 temp_fname_size)
+{
+       if (strlen(FLASH_IMG_FOLDER) > 0){
+               strcpy(temp_fname, FLASH_IMG_FOLDER);
+               strcat(temp_fname, "/");
+               strcat(temp_fname, tmp_file);
+       }else{
+               strcpy(temp_fname, tmp_file);
+       }
+       if (!run_commandf("fatsize %s %d:%d %s", fdev->device_name, fdev->dev_index,
+                                                                               bootfs_part_index, temp_fname)){
+               /*has find partition file name*/
+               return 0;
+       }else{
+               memset(tmp_file, '\0', 30);
+               memset(temp_fname, '\0', temp_fname_size);
+       }
+       return -1;
+}
+
+static int find_mtd_partition_file(struct flash_dev *fdev, char *temp_fname, u32 temp_fname_size)
+{
+       char tmp_file[30] = {"\0"};
+       u32 mtd_size = fdev->mtdinfo.size;
+       bool nand_flag = false;
+       memset(temp_fname, '\0', temp_fname_size);
+
+       switch (fdev->mtdinfo.size_type) {
+       case MTD_SIZE_G:
+               while (mtd_size/2){
+                       mtd_size /= 2;
+                       sprintf(tmp_file, "partition_%dG.json", mtd_size);
+                       if (!_find_partition_file(fdev, tmp_file, temp_fname, temp_fname_size))
+                               return 0;
+               }
+
+               /*retry to find until 64M*/
+               mtd_size = 1024;
+
+               /*if can not find at type G, try to find type M, should not break*/
+               /*break;*/
+       case MTD_SIZE_M:
+               if (mtd_size >= 64)
+                       nand_flag = true;
+
+               while (mtd_size/2){
+                       mtd_size /= 2;
+                       if (nand_flag && mtd_size < 64){
+                               pr_err("can not find suitable nand partition file\n");
+                               return -1;
+                       }
+                       sprintf(tmp_file, "partition_%dM.json", mtd_size);
+                       if (!_find_partition_file(fdev, tmp_file, temp_fname, temp_fname_size))
+                               return 0;
+               }
+
+               /*retry to find type K patition file*/
+               mtd_size = 1024;
+               /*break;*/
+       case MTD_SIZE_K:
+               while (mtd_size/2){
+                       mtd_size /= 2;
+                       sprintf(tmp_file, "partition_%dK.json", mtd_size);
+                       if (!_find_partition_file(fdev, tmp_file, temp_fname, temp_fname_size))
+                               return 0;
+               }
+
+       default:
+               pr_err("undefine mtd size type, return fail\n");
+               return -1;
+       }
+}
+
+
+static int load_from_device(struct cmd_tbl *cmdtp, char *load_str,
+                       int device_type, struct flash_dev *fdev)
+{
+       int retval = RESULT_OK;
+       char blk_dev_str[10] = {"\0"};
+
+       switch (device_type) {
+#ifdef CONFIG_MMC
+       case DEVICE_MMC:
+               if (check_mmc_exist_and_initialize() != RESULT_OK) {
+                       retval = RESULT_FAIL;
+                       break;
+               }
+               fdev->dev_index = dev_sdio_num;
+               fdev->device_name = strdup("mmc");
+               break;
+#endif //CONFIG_MMC
+
+#ifdef CONFIG_USB_STORAGE
+       case DEVICE_USB:
+               static bool usb_init_flag = false;
+               if (!usb_init_flag){
+                       usb_init();
+                       int device_number = usb_stor_scan(1);
+                       if (device_number < 0){
+                               printf("No USB storage devices found.\n");
+                               retval = RESULT_FAIL;
+                               break;
+                       }
+                       fdev->dev_index = device_number;
+                       fdev->device_name = strdup("usb");
+                       usb_init_flag = true;
+
+                       char cmd[128];
+                       for (u32 p = 1; p <= MAX_SEARCH_PARTITIONS; p++){
+                               sprintf(cmd, "fatls usb %d:%d", device_number, p);
+                               if (!run_command(cmd, 0))
+                               {
+                                       bootfs_part_index = p;
+                                       break;
+                               }
+                       }
+
+                       if (bootfs_part_index == 0){
+                               printf("No valid filesystem found in any partition on USB.\n");
+                               retval = RESULT_FAIL;
+                               break;
+                       }
+               }
+               break;
+#else
+               printf("USB storage support is not enabled.\n");
+               retval = RESULT_FAIL;
+               break;
+#endif //CONFIG_USB_STORAGE
+
+#ifdef CONFIG_CMD_TFTPBOOT
+       case DEVICE_NET:
+               if (run_command("dhcp", 0)) {
+                       printf("Error: DHCP request failed\n");
+                       retval = RESULT_FAIL;
+                       break;
+               }
+
+               fdev->device_name = strdup("net");
+               break;
+#endif //CONFIG_CMD_TFTPBOOT
+
+       default:
+               printf("Unknown device type!\n");
+               retval = RESULT_FAIL;
+               break;
+       }
+
+       /* If the above operation fails, return early */
+       if (retval != RESULT_OK) {
+               return retval;
+       }
+
+       debug("device_name: %s\n", fdev->device_name);
+       debug("dev_index: %d\n", fdev->dev_index);
+
+       u32 temp_fname_size = strlen(fdev->partition_file_name) + strlen(FLASH_IMG_FOLDER) + 2;
+       char *temp_fname = malloc(temp_fname_size);
+       if (!temp_fname){
+               printf("malloc file_name fail\n");
+               return RESULT_FAIL;
+       }
+       memset(temp_fname, '\0', temp_fname_size);
+       if (strlen(FLASH_IMG_FOLDER) > 0){
+               strcpy(temp_fname, FLASH_IMG_FOLDER);
+               strcat(temp_fname, "/");
+               strcat(temp_fname, fdev->partition_file_name);
+       }else{
+               strcpy(temp_fname, fdev->partition_file_name);
+       }
+
+       if (strcmp(fdev->device_name, "mmc") == 0 || strcmp(fdev->device_name, "usb") == 0) {
+
+               /*would try to detect mtd partition file exists or not*/
+               if (strcmp(FLASH_CONFIG_FILE_NAME, fdev->partition_file_name) &&
+                       run_commandf("fatsize %s %d:%d %s", fdev->device_name, fdev->dev_index,
+                                                bootfs_part_index, temp_fname)) {
+                       /*can not find mtd partition file, would try to find suitable file*/
+                       if (find_mtd_partition_file(fdev, temp_fname, temp_fname_size)){
+                               pr_err("can not find suitable partition file\n");
+                               recovery_show_result(fdev, RESULT_FAIL);
+                       }
+                       printf("find temp_fname:%s\n", temp_fname);
+               }
+
+               sprintf(blk_dev_str, "%d:%d", fdev->dev_index, bootfs_part_index);
+               char *fat_argv[] = {"fatload", fdev->device_name, blk_dev_str, load_str, temp_fname};
+
+               if (do_load(cmdtp, 0, 5, fat_argv, FS_TYPE_FAT)) {
+                       printf("do_load flash_config from %s failed\n", fdev->device_name);
+                       retval = RESULT_FAIL;
+               } else {
+                       printf("do_load flash_config %s success\n", fdev->device_name);
+               }
+       } else if (strcmp(fdev->device_name, "net") == 0) {
+
+               if (download_file_via_tftp(temp_fname, load_str) < 0) {
+                       printf("Failed to download file via TFTP\n");
+                       retval = RESULT_FAIL;
+               } else {
+                       printf("Downloaded file via TFTP successfully\n");
+               }
+       }
+
+       free(temp_fname);
+       return retval;
+}
+
+void recovery_show_result(struct flash_dev *fdev, int ret)
+{
+       if (ret) {
+               printf("!!!!!!!!!!!!!!!!!!! recovery flash false !!!!!!!!!!!!!!!!!!!\n");
+       } else {
+               printf("################### recovery flash success ###################\n");
+       }
+
+       /*free the malloc paramenter*/
+       free_flash_dev(fdev);
+
+       while(1){
+               /* do not retrun while flashing over! */
+       }
+
+}
+
+int get_part_info(struct blk_desc *dev_desc, const char *name,
+               struct disk_partition *info)
+{
+       int ret;
+
+       if (dev_desc) {
+               ret = part_get_info_by_name(dev_desc, name, info);
+               if (ret >= 0)
+                       return ret;
+       }
+
+       printf("%s, can not find part info\n", __func__);
+       return -1;
+}
+
+
+/**
+ * mmc_blk_write() - Write/erase MMC in chunks of MAX_BLK_WRITE
+ *
+ * @block_dev: Pointer to block device
+ * @start: First block to write/erase
+ * @blkcnt: Count of blocks
+ * @buffer: Pointer to data buffer for write or NULL for erase
+ */
+static __maybe_unused lbaint_t mmc_blk_write(struct blk_desc *block_dev, lbaint_t start,
+                       lbaint_t blkcnt, const void *buffer)
+{
+       lbaint_t blk = start;
+       lbaint_t blks_written;
+       lbaint_t cur_blkcnt;
+       lbaint_t blks = 0;
+       int i;
+
+       for (i = 0; i < blkcnt; i += MAX_BLK_WRITE) {
+               cur_blkcnt = min((int)blkcnt - i, MAX_BLK_WRITE);
+               if (buffer) {
+                       blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
+                                       buffer + (i * block_dev->blksz));
+               } else {
+                       blks_written = blk_derase(block_dev, blk, cur_blkcnt);
+               }
+               blk += blks_written;
+               blks += blks_written;
+       }
+       return blks;
+}
+
+
+int blk_write_raw_image(struct blk_desc *dev_desc,
+               struct disk_partition *info, const char *part_name,
+               void *buffer, u32 download_bytes)
+{
+#ifdef CONFIG_MMC
+       lbaint_t blkcnt;
+       lbaint_t blks;
+
+       /* determine number of blocks to write */
+       blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1));
+       blkcnt = lldiv(blkcnt, info->blksz);
+
+       if (blkcnt > info->size) {
+               printf("too large for partition: '%s'\n", part_name);
+               return RESULT_FAIL;
+       }
+
+       puts("Flashing Raw Image\n");
+
+       blks = mmc_blk_write(dev_desc, info->start, blkcnt, buffer);
+
+       if (blks != blkcnt) {
+               printf("failed writing to device %d\n", dev_desc->devnum);
+               return RESULT_FAIL;
+       }
+
+       printf("........ wrote " LBAFU " bytes to '%s'\n", \
+               blkcnt * info->blksz,part_name);
+       return RESULT_OK;
+#else
+       printf("not mmc dev found\n");
+       return RESULT_FAIL;
+#endif
+}
+
+int mtd_write_raw_image(struct mtd_info *mtd, const char *part_name, void *buffer, u32 download_bytes)
+{
+       int ret;
+
+       printf("Erasing MTD partition %s\n", part_name);
+       ret = _fb_mtd_erase(mtd, download_bytes);
+       if (ret) {
+               printf("failed erasing from device %s\n", mtd->name);
+               return RESULT_FAIL;
+       }
+
+       ret = _fb_mtd_write(mtd, buffer, 0, download_bytes, NULL);
+       if (ret < 0) {
+               printf("Failed to write mtd part:%s\n", part_name);
+               return RESULT_FAIL;
+       }
+
+       return 0;
+}
+
+void specific_flash_mmc_opt(struct cmd_tbl *cmdtp, struct flash_dev *fdev)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       char blk_dev_str[20] = {"\0"};
+       char file_name[50] = {"\0"};
+       u32 image_size = 0;
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+       sprintf(blk_dev_str, "%d:%d", fdev->dev_index, bootfs_part_index);
+
+       /*flash emmc info to boot0*/
+       fastboot_oem_flash_bootinfo(NULL, load_addr, image_size, NULL, fdev);
+
+       /*load fsbl.bin to load_addr*/
+       if (strlen(FLASH_IMG_FACTORY_FOLDER) > 0){
+               strcpy(file_name, FLASH_IMG_FACTORY_FOLDER);
+               strcat(file_name, "/");
+               strcat(file_name, "FSBL.bin");
+       }else{
+               strcpy(file_name, "FSBL.bin");
+       }
+
+       struct blk_desc *dev_desc = blk_get_dev("mmc",
+                                          CONFIG_FASTBOOT_FLASH_MMC_DEV);
+
+       if (strcmp(fdev->device_name, "net") == 0) {
+               if (download_file_via_tftp(file_name, simple_xtoa((ulong)load_addr)) < 0) {
+                       printf("Failed to download file via TFTP\n");
+                       return;
+               }
+               image_size = env_get_hex("filesize", 0);
+       } else {
+               char *const argv_image[] = {"fatload", fdev->device_name, blk_dev_str, simple_xtoa((ulong)load_addr), file_name};
+
+               if (do_load(cmdtp, 0, 5, argv_image, FS_TYPE_FAT)) {
+                       printf("Cannot load file %s\n", file_name);
+                       return;
+               }
+               image_size = env_get_hex("filesize", 0);
+       }
+
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid mmc device\n");
+               return;
+       }
+
+       /*flash fsbl.bin to boot0*/
+       if (flash_mmc_boot_op(dev_desc, load_addr, 1, image_size, BOOT_INFO_EMMC_SPL0_OFFSET)){
+               printf("flash fsbl fail\n");
+               return;
+       }
+
+       /*flash fsbl.bin to boot1*/
+       if (flash_mmc_boot_op(dev_desc, load_addr, 2, image_size, BOOT_INFO_EMMC_SPL1_OFFSET)){
+               printf("flash fsbl fail\n");
+               return;
+       }
+#endif
+}
+
+int load_and_flash_file(struct cmd_tbl *cmdtp, struct flash_dev *fdev, char *file_name, char *partition, uint64_t *partition_offset)
+{
+       char load_str[20];
+       char addr_str[20];
+       char offset_str[20];
+       char blk_dev_str[16];
+       struct disk_partition info = {0};
+       struct mtd_info *mtd = NULL;
+       struct part_info *mtd_part_info = NULL;
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+       lbaint_t part_start_addr;
+       uint64_t image_size = 0;
+       uint64_t byte_remain = 0;
+       uint64_t download_offset, download_bytes, bytes_read;
+       u64 compare_value = 0;
+       int div_times, data_source;
+
+       memset(load_str, 0, sizeof(load_str));
+       memset(offset_str, 0, sizeof(offset_str));
+       strcpy(load_str, simple_xtoa((ulong)load_addr));
+       sprintf(blk_dev_str, "%d:%d", fdev->dev_index, bootfs_part_index);
+
+       if (strcmp(fdev->device_name, "mmc") == 0 || strcmp(fdev->device_name, "usb") == 0) {
+               // load data from fat disk
+               data_source = 0;
+               char *const argv_image_size[] = {"fatsize", fdev->device_name, blk_dev_str, file_name};
+               if (do_size(cmdtp, 0, 4, argv_image_size, FS_TYPE_FAT)) {
+                       printf("can not find file :%s, \n", file_name);
+                       return RESULT_FAIL;
+               }
+
+               image_size = env_get_hex("filesize", 0);
+               byte_remain = image_size;
+               div_times = (image_size + RECOVERY_LOAD_IMG_SIZE - 1) / RECOVERY_LOAD_IMG_SIZE;
+               pr_info("\n\ndev_times:%d\n", div_times);
+       } else if (strcmp(fdev->device_name, "net") == 0) {
+               // load data from net with tftp
+               data_source = 1;
+               /* Temporarily, the logic for network fragment download has not been added,
+               so set the number of downloads to 1 and directly download the entire file. */
+               div_times = 1;
+       } else {
+               printf("NOT support data source %s\n", fdev->device_name);
+               return RESULT_FAIL;
+       }
+
+       if (fdev->blk_write != NULL && get_part_info(fdev->dev_desc, partition, &info) < 0) {
+               printf("can not get part %s in gpt tabel\n", partition);
+               return RESULT_FAIL;
+       }
+       if(fdev->mtd_write != NULL){
+               /*init mtd info*/
+               if(fb_mtd_lookup(partition, &mtd, &mtd_part_info)){
+                       printf("invalid mtd device \n");
+                       return RESULT_FAIL;
+               }
+               /*update info to mtd dev*/
+               info.start = 0;
+               info.blksz = 1;
+       }
+
+       download_offset = 0;
+       compare_value = 0;
+       info.start += *partition_offset;
+
+       /* save the partition start cnt */
+       part_start_addr = info.start;
+       for (int j = 0; j < div_times; j++) {
+               debug("\nflash data count %d\n", j);
+               if (0 == data_source) {
+                       download_bytes = byte_remain > RECOVERY_LOAD_IMG_SIZE ? RECOVERY_LOAD_IMG_SIZE : byte_remain;
+                       strcpy(addr_str, simple_xtoa((ulong)download_bytes));
+                       strcpy(offset_str, simple_xtoa((ulong)download_offset));
+
+                       char *const argv_image[] = {"fatload", fdev->device_name, blk_dev_str,
+                                                                               load_str, file_name, addr_str, offset_str};
+                       printf("load from %llx, bytes:%llx\n", download_offset, download_bytes);
+                       if (do_load(cmdtp, 0, 7, argv_image, FS_TYPE_FAT))
+                               return RESULT_FAIL;
+
+                       bytes_read = env_get_hex("filesize", 0);
+                       printf("read data size %lld\n", bytes_read);
+                       if (bytes_read != download_bytes) {
+                               printf("download file size is not equal require\n");
+                               return RESULT_FAIL;
+                       }
+               } else {
+                       if (download_file_via_tftp(file_name, load_str) < 0) {
+                               printf("Failed to download file via TFTP\n");
+                               return RESULT_FAIL;
+                       }
+                       image_size = download_bytes = env_get_hex("filesize", 0);
+               }
+
+               // compare_value = crc32_wd(compare_value, (const uchar *)load_addr, download_bytes, CHUNKSZ_CRC32);
+               compare_value += checksum64(load_addr, download_bytes);
+               info.size = (download_bytes + (info.blksz - 1)) / info.blksz;
+               printf("write storage at block: 0x%lx, size: %lx\n", info.start, info.size);
+
+               if (fdev->blk_write != NULL){
+                       if (fdev->blk_write(fdev->dev_desc, &info, partition, load_addr, download_bytes)){
+                               return RESULT_FAIL;
+                       }
+               }else{
+                       /*write to mtd dev*/
+                       if (fdev->mtd_write(mtd, partition, load_addr, download_bytes))
+                               return RESULT_FAIL;
+               }
+
+               info.start += info.size;
+               *partition_offset += info.size;
+               download_offset += download_bytes;
+               byte_remain -= download_bytes;
+       }
+
+       /* read from device and check crc */
+       debug("check crc, read %lx, imagesize:%lld\n", part_start_addr, image_size);
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+
+       if (fdev->blk_write){
+               if (compare_blk_image_val(fdev->dev_desc, compare_value, part_start_addr, info.blksz, image_size)) {
+                       printf("check image crc32 fail, \n");
+                       return RESULT_FAIL;
+               }
+       }else{
+               if (compare_mtd_image_val(mtd, compare_value, image_size)) {
+                       printf("check image crc32 fail, \n");
+                       return RESULT_FAIL;
+               }
+       }
+#endif
+       return RESULT_OK;
+}
+
+int flash_volume_from_file(struct cmd_tbl *cmdtp, struct flash_dev *fdev, const char *volume_name, const char *file_name, const char *partition, uint64_t *partition_offset) {
+       char blk_dev_str[32];
+       uint64_t image_size = 0;
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+    char cmd_buf[256];
+
+       sprintf(blk_dev_str, "%d:%d", fdev->dev_index, bootfs_part_index);
+
+       sprintf(cmd_buf, "fatload %s %s %lx %s", fdev->device_name, blk_dev_str, (ulong)load_addr, file_name);
+       if (run_command(cmd_buf, 0) != 0) {
+               printf("Failed to load file %s\n", file_name);
+               return RESULT_FAIL;
+       }
+
+       image_size = env_get_hex("filesize", 0);
+       printf("Loaded %s, size: %llu bytes\n", file_name, image_size);
+
+       printf("Creating and writing to UBI volume: %s\n", volume_name);
+
+       sprintf(cmd_buf, "ubi part %s", partition);
+       if (run_command(cmd_buf, 0) != 0) {
+               printf("Failed to select MTD partition %s\n", partition);
+               return RESULT_FAIL;
+       }
+
+       sprintf(cmd_buf, "ubi check %s", volume_name);
+       if (run_command(cmd_buf, 0) != 0) {
+               sprintf(cmd_buf, "ubi create %s %llx dynamic", volume_name, image_size);
+               if (run_command(cmd_buf, 0) != 0) {
+                       printf("Failed to create UBI volume %s\n", volume_name);
+                       return RESULT_FAIL;
+               }
+       }
+
+       sprintf(cmd_buf, "ubi write %lx %s %llx", (ulong)load_addr, volume_name, image_size);
+       if (run_command(cmd_buf, 0) != 0) {
+               printf("Failed to write to UBI volume %s\n", volume_name);
+               return RESULT_FAIL;
+       }
+
+       return RESULT_OK;
+}
+
+static int flash_image(struct cmd_tbl *cmdtp, struct flash_dev *fdev)
+{
+       int ret = RESULT_OK, i, j;
+       uint64_t time_start_flash, partition_offset;
+       char *part_name, *file_name;
+       char blk_dev_str[16], *split_file_name, *name, *extension;
+
+       for (i = 0; i < MAX_PARTITION_NUM; i++) {
+               part_name = fdev->parts_info[i].part_name;
+               file_name = fdev->parts_info[i].file_name;
+               time_start_flash = get_timer(0);
+
+               if (part_name == NULL || strlen(part_name) == 0) {
+                       printf("no more partition to flash\n");
+                       break;
+               }
+
+               if ((file_name == NULL || strlen(file_name) == 0) && (fdev->parts_info[i].volume_images_count == 0)) {
+                       /* if not file not exists, it mean not to flash */
+                       printf("file name is null, not to flashing, continue\n");
+                       continue;
+               }
+
+               if (fdev->parts_info[i].volume_images_count == 0) {
+                       partition_offset = 0;
+                       printf("\n\nFlashing part: %s, file:%s\n", part_name, file_name);
+                       // big rootfs image(larger than 4GB) will split to multi files except flash to nand.
+                       sprintf(blk_dev_str, "%d:%d", fdev->dev_index, bootfs_part_index);
+                       if ((0 == strcmp(part_name, BIG_IMG_PARTNAME))
+                               && (strcmp(fdev->device_name, "mmc") == 0 || strcmp(fdev->device_name, "usb") == 0)
+                               && !file_exists(fdev->device_name, blk_dev_str, file_name, FS_TYPE_FAT)) {
+                                       split_file_name = malloc(strlen(file_name) + 8);
+                                       extension = file_name;
+                                       // MUST has only 1 "." inside file name
+                                       name = strsep(&extension, ".");
+                                       j = 1;
+                                       while (1) {
+                                               sprintf(split_file_name, "%s_%d.%s", name, j, extension);
+                                               if (file_exists(fdev->device_name, blk_dev_str, split_file_name, FS_TYPE_FAT)) {
+                                                       printf("write %s to device %s\n", split_file_name, fdev->device_name);
+                                                       ret = load_and_flash_file(cmdtp, fdev, split_file_name, part_name, &partition_offset);
+                                                       if (RESULT_OK != ret)
+                                                               break;
+                                                       j++;
+                                               }
+                                               else
+                                                       break;
+                                       }
+
+                                       free(split_file_name);
+                               }
+                       else{
+                               ret = load_and_flash_file(cmdtp, fdev, file_name, part_name, &partition_offset);
+                       }
+
+                       if (RESULT_OK != ret) {
+                               printf("Write %s to partition %s fail(%d)\n", file_name, part_name, ret);
+                               break;
+                       }
+                       time_start_flash = get_timer(time_start_flash);
+                       printf("finish image %s flash, consume %lld ms\n", file_name, time_start_flash);
+               } else if (fdev->parts_info[i].volume_images_count > 0) {
+                       for (j = 0; j < fdev->parts_info[i].volume_images_count; ++j) {
+                               const char *volume_name = fdev->parts_info[i].volume_images[j].name;
+                               char *volume_file_name = fdev->parts_info[i].volume_images[j].file_name;
+
+                               printf("\n\nFlashing volume %s with file %s\n", volume_name, volume_file_name);
+                               ret = flash_volume_from_file(cmdtp, fdev, volume_name, volume_file_name, part_name, &partition_offset);
+                               if (ret != RESULT_OK) {
+                                       printf("Failed to flash volume %s from file %s\n", volume_name, volume_file_name);
+                                       break;
+                               }
+
+                               time_start_flash = get_timer(time_start_flash);
+                               printf("finish image %s flash, consume %lld ms\n", file_name, time_start_flash);
+                       }
+               }
+
+       }
+
+       return ret;
+}
+
+
+static int parse_flash_config(struct flash_dev *fdev)
+{
+       int ret = 0;
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+
+       ret = _parse_flash_config(fdev, load_addr);
+       if (ret){
+               if (ret == -1)
+                       printf("parsing config fail\n");
+               if (ret == -5)
+                       printf("offset must larger then previous size and offset\n");
+               return ret;
+       }
+
+       if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 1 && fdev->gptinfo.fastboot_flash_gpt){
+               _write_gpt_partition(fdev);
+       }
+
+       if (fdev->mtd_table != NULL && strlen(fdev->mtd_table) > 1){
+               _write_mtd_partition(fdev->mtd_table);
+       }
+
+       /*set partition to env*/
+       if (_clear_env_part(load_addr, 0, fdev)){
+               printf("update part info to env fail\n");
+               return -1;
+       }
+       return 0;
+}
+
+/*Attempt to load recovery files from all possible sources*/
+static int load_recovery_file(struct cmd_tbl *cmdtp, struct flash_dev *fdev,
+                       int argc, char *const argv[])
+{
+       char load_str[13] = {"\0"};
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+       strcpy(load_str, simple_xtoa((ulong)load_addr));
+       int device_type, result;
+
+       if (argc < 2) {
+               printf("Error: Missing source argument. Expected 'mmc', 'usb', or 'net'.\n");
+               return CMD_RET_USAGE;
+       }
+       if (strcmp(argv[1], "mmc") == 0) {
+               device_type = DEVICE_MMC;
+       } else if (strcmp(argv[1], "usb") == 0) {
+               device_type = DEVICE_USB;
+       } else if (strcmp(argv[1], "net") == 0) {
+               device_type = DEVICE_NET;
+       } else {
+               printf("Error: Invalid source '%s'. Expected 'mmc', 'usb', or 'net'.\n", argv[1]);
+               return CMD_RET_USAGE;
+       }
+
+       result = load_from_device(cmdtp, load_str, device_type, fdev);
+
+       return result;
+}
+
+static int perform_flash_operations(struct cmd_tbl *cmdtp, struct flash_dev *fdev)
+{
+       u32 boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+       case BOOT_MODE_NOR:
+               /*nvme devices need scan at first*/
+               if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)){
+                       run_command("nvme scan", 0);
+               }
+
+               fdev->dev_desc = blk_get_dev(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME,
+                                                        CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX);
+               if (!fdev->dev_desc || fdev->dev_desc->type == DEV_TYPE_UNKNOWN) {
+                       printf("get blk faild\n");
+                       return -1;
+               }
+
+               if (flash_image(cmdtp, fdev)) {
+                       return RESULT_FAIL;
+               }
+
+               break;
+#endif //CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+
+       case BOOT_MODE_NAND:
+               if (flash_image(cmdtp, fdev)) {
+                       return RESULT_FAIL;
+               }
+
+               break;
+
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+               fdev->dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+               if (!fdev->dev_desc || fdev->dev_desc->type == DEV_TYPE_UNKNOWN) {
+                       printf("get emmc_device faild\n");
+                       return -1;
+               }
+
+               if (flash_image(cmdtp, fdev)) {
+                       return RESULT_FAIL;
+               }
+               /*if flash to emmc,it should write bootinfo to boot0/boot1*/
+               specific_flash_mmc_opt(cmdtp, fdev);
+               break;
+#endif //CONFIG_FASTBOOT_FLASH_MMC_DEV
+
+       default:
+               return -1;
+       }
+
+       /* all flash operations successed */
+       return RESULT_OK;
+}
+
+void get_mtd_partition_file(struct flash_dev *fdev)
+{
+       char tmp_file[30] = {"\0"};
+
+       u32 boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MTD) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MTD)
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               /*if select nor/nand, it would check if mtd dev exists or not*/
+               struct mtd_info *mtd;
+               mtd_probe_devices();
+               mtd_for_each_device(mtd) {
+                       if (!mtd_is_partition(mtd)) {
+                               if (mtd->size / 0x40000000){
+                                       sprintf(tmp_file, "partition_%lldG.json", mtd->size / 0x40000000);
+                                       fdev->mtdinfo.size_type = MTD_SIZE_G;
+                                       fdev->mtdinfo.size = mtd->size / 0x40000000;
+                               } else if (mtd->size / 0x100000){
+                                       sprintf(tmp_file, "partition_%lldM.json", mtd->size / 0x100000);
+                                       fdev->mtdinfo.size_type = MTD_SIZE_M;
+                                       fdev->mtdinfo.size = mtd->size / 0x100000;
+                               } else if (mtd->size / 0x400){
+                                       sprintf(tmp_file, "partition_%lldK.json", mtd->size / 0x400);
+                                       fdev->mtdinfo.size_type = MTD_SIZE_K;
+                                       fdev->mtdinfo.size = mtd->size / 0x400;
+                               }
+                       }
+               }
+               pr_info("get mtd partition file name:%s, \n", tmp_file);
+               strcpy(fdev->partition_file_name, tmp_file);
+               return;
+#endif
+       default:
+               return;
+       }
+}
+
+void get_blk_partition_file(char *file_name)
+{
+       struct blk_desc *dev_desc = NULL;
+       const char *blk_name;
+       int blk_index;
+
+       u32 boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+       case BOOT_MODE_NOR:
+               blk_name = CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME;
+               blk_index = CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX;
+
+               /*nvme devices need scan at first*/
+               if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)){
+                       run_command("nvme scan", 0);
+               }
+
+               dev_desc = blk_get_devnum_by_typename(blk_name, blk_index);
+               if (dev_desc != NULL)
+                       strcpy(file_name, FLASH_CONFIG_FILE_NAME);
+               return;
+#endif //CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+       case BOOT_MODE_NAND:
+               return;
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+               blk_name = "mmc";
+               blk_index = CONFIG_FASTBOOT_FLASH_MMC_DEV;
+               dev_desc = blk_get_devnum_by_typename(blk_name, blk_index);
+               if (dev_desc != NULL)
+                       strcpy(file_name, FLASH_CONFIG_FILE_NAME);
+               return;
+#endif //CONFIG_FASTBOOT_FLASH_MMC_DEV
+
+       default:
+               return;
+       }
+}
+
+static int do_flash_image(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+       printf("RECOVERY_LOAD_IMG_ADDR:%lx, RECOVERY_LOAD_IMG_SIZE:%llx\n", RECOVERY_LOAD_IMG_ADDR, RECOVERY_LOAD_IMG_SIZE);
+       struct flash_dev *fdev;
+
+       /*fdev would free after finish revocery at func recovery_show_result*/
+       fdev = malloc(sizeof(struct flash_dev));
+       if (!fdev) {
+               printf("Memory allocation failed!\n");
+               return RESULT_FAIL;
+       }
+       /*would realloc the size*/
+       fdev->gptinfo.gpt_table = malloc(1);
+       if (!fdev->gptinfo.gpt_table)
+               printf("can not malloc fdev->gptinfo.gpt_table\n");
+
+       fdev->mtd_table = malloc(1);
+       if (!fdev->mtd_table)
+               printf("can not malloc fdev->mtd_table\n");
+
+       memset(fdev, 0, sizeof(struct flash_dev));
+       memset(fdev->partition_file_name, '\0', sizeof(fdev->partition_file_name));
+
+       /*start flash*/
+       unsigned long time_start_flash = get_timer(0);
+
+       get_mtd_partition_file(fdev);
+       if (strlen(fdev->partition_file_name) > 0){
+               /*flash image to mtd dev*/
+               printf("partition file:%s\n", fdev->partition_file_name);
+
+               /*only one write method.*/
+               fdev->mtd_write = mtd_write_raw_image;
+               fdev->blk_write = NULL;
+
+               /*Load partitino.json file*/
+               int result = load_recovery_file(cmdtp, fdev, argc, argv);
+               if (result != RESULT_OK) {
+                       recovery_show_result(fdev, RESULT_FAIL);
+                       return RESULT_FAIL;
+               }
+
+               /*Parse json file and fill in relevant data structures*/
+               if (parse_flash_config(fdev)) {
+                       printf("Failed to parse flash config.\n");
+                       recovery_show_result(fdev, RESULT_FAIL);
+                       return RESULT_FAIL;
+               }
+
+               /*Perform programming operation based on the provided information*/
+               if (perform_flash_operations(cmdtp, fdev)) {
+                       printf("Failed to flash the device.\n");
+                       recovery_show_result(fdev, RESULT_FAIL);
+                       return RESULT_FAIL;
+               }
+       }
+
+       memset(fdev->partition_file_name, '\0', sizeof(fdev->partition_file_name));
+       get_blk_partition_file(fdev->partition_file_name);
+       if (strlen(fdev->partition_file_name) > 0){
+               /*flash image to blk dev*/
+               printf("partition file:%s\n", fdev->partition_file_name);
+
+               /*clear parts infomation*/
+               for (int i = 0; i < MAX_PARTITION_NUM; i++){
+                       if (fdev->parts_info[i].part_name != NULL){
+                               free(fdev->parts_info[i].part_name);
+                               free(fdev->parts_info[i].file_name);
+                               free(fdev->parts_info[i].size);
+                       }else{
+                               break;
+                       }
+               }
+
+               /*only one write method.*/
+               fdev->mtd_write = NULL;
+               fdev->blk_write = blk_write_raw_image;
+
+               /*Load partition.json file*/
+               int result = load_recovery_file(cmdtp, fdev, argc, argv);
+               if (result != RESULT_OK) {
+                       recovery_show_result(fdev, RESULT_FAIL);
+                       return RESULT_FAIL;
+               }
+
+               /*Parse json file and fill in relevant data structures*/
+               if (parse_flash_config(fdev)) {
+                       printf("Failed to parse flash config.\n");
+                       recovery_show_result(fdev, RESULT_FAIL);
+                       return RESULT_FAIL;
+               }
+
+               /*Perform programming operation based on the provided information*/
+               if (perform_flash_operations(cmdtp, fdev)) {
+                       printf("Failed to flash the device.\n");
+                       recovery_show_result(fdev, RESULT_FAIL);
+                       return RESULT_FAIL;
+               }
+       }
+
+       ulong time_enc_flash = get_timer(0);
+       printf("flashing over, use time:%lu ms\n", time_enc_flash - time_start_flash);
+       recovery_show_result(fdev, RESULT_OK);
+       return 0;
+}
+
+U_BOOT_CMD(
+       flash_image, 2, 1, do_flash_image,
+       "flash image from specified source",
+       "<source>\n"
+       "    - <source>: mmc | usb | net\n"
+       "      flash image from the specified source (e.g., mmc, usb, or net) to emmc/nand/nor.");
index ebee856e5676e5c964ad4e74ce463a465ea43133..c35937798f028a8cf5bc1704c5048947e747a8b6 100644 (file)
@@ -82,9 +82,10 @@ config LOGLEVEL
            9 - debug hardware I/O
 
 config SPL_LOGLEVEL
-       int
+       int "loglevel for spl"
        depends on SPL
        default LOGLEVEL
+       range 0 10
 
 config TPL_LOGLEVEL
        int
index 2ed8672c3ac1bd3a34c8c7ddfe78b5f1fd40c088..8f07b45896b5b9b4c59c9be7aa3c60ef77e39627 100644 (file)
@@ -10,6 +10,7 @@ obj-y += main.o
 obj-y += exports.o
 obj-$(CONFIG_HUSH_PARSER) += cli_hush.o
 obj-$(CONFIG_AUTOBOOT) += autoboot.o
+obj-$(CONFIG_SPL_FASTBOOT) += cli.o
 
 # # boards
 obj-y += board_f.o
@@ -59,6 +60,7 @@ obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o
 obj-$(CONFIG_SPL_USB_HOST) += usb.o usb_hub.o
 obj-$(CONFIG_SPL_USB_STORAGE) += usb_storage.o
 obj-$(CONFIG_SPL_MUSB_NEW) += usb.o
+obj-$(CONFIG_SPL_FASTBOOT) += usb.o
 endif # CONFIG_SPL_BUILD
 
 #others
index 18e2246733b09a63b03468a066edc4eaa61699e4..5d09cbbbef5c9b76ef79e1d13a12e9107be591eb 100644 (file)
@@ -742,6 +742,10 @@ static int jump_to_copy(void)
        arch_setup_gd(gd->new_gd);
        board_init_f_r_trampoline(gd->start_addr_sp);
 #else
+       #ifdef CONFIG_NOT_RELOC_TEXT_SECTION
+       gd->relocaddr = CONFIG_SYS_TEXT_BASE;
+       #endif
+
        relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
 #endif
 
index 00926dcb1e10c62fc9c9ab00a03def04f141f7c7..913c68905920beda07b98a3f6cb7a086754ec222 100644 (file)
@@ -65,6 +65,7 @@
 #include <asm-generic/gpio.h>
 #include <efi_loader.h>
 #include <relocate.h>
+#include <command.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -582,6 +583,34 @@ static int run_main_loop(void)
        return 0;
 }
 
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+int initialize_console_log_buffer(void)
+{
+       printf("initialize_console_log_buffer\n");
+
+       if (!gd->console_log.buffer) {
+               gd->console_log.buffer = (char *)malloc(LOG_BUFFER_SIZE);
+               if (gd->console_log.buffer) {
+                       memset(gd->console_log.buffer, 0, LOG_BUFFER_SIZE);
+                       gd->console_log.write_ptr = gd->console_log.buffer;
+                       gd->console_log.read_ptr = gd->console_log.buffer;
+                       printf("Have allocated memory for console log buffer\n");
+               } else {
+                       printf("Error: Unable to allocate memory for console log buffer\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+void free_console_log_buffer(void)
+{
+       if (gd->console_log.buffer) {
+               free(gd->console_log.buffer);
+       }
+}
+#endif
+
 /*
  * We hope to remove most of the driver-related init and do it if/when
  * the driver is later used.
@@ -724,6 +753,9 @@ static init_fnc_t init_sequence_r[] = {
 #endif
        stdio_add_devices,
        jumptable_init,
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+       initialize_console_log_buffer,
+#endif
 #ifdef CONFIG_API
        api_init,
 #endif
index a47d6a3f2b4226a100ecbfc35915faf28f436eff..4ba31f95610cfe5f95808bc90b185eee66f740f1 100644 (file)
@@ -75,7 +75,7 @@ int run_command_repeatable(const char *cmd, int flag)
 #else
 __weak int board_run_command(const char *cmdline)
 {
-       printf("## Commands are disabled. Please enable CONFIG_CMDLINE.\n");
+       pr_debug("## Commands are disabled. Please enable CONFIG_CMDLINE.\n");
 
        return 1;
 }
@@ -156,7 +156,7 @@ int do_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 
                arg = env_get(argv[i]);
                if (arg == NULL) {
-                       printf("## Error: \"%s\" not defined\n", argv[i]);
+                       pr_err("## Error: \"%s\" not defined\n", argv[i]);
                        return 1;
                }
 
@@ -203,7 +203,7 @@ void cli_secure_boot_cmd(const char *cmd)
        int rc;
 
        if (!cmd) {
-               printf("## Error: Secure boot command not specified\n");
+               pr_err("## Error: Secure boot command not specified\n");
                goto err;
        }
 
@@ -214,7 +214,7 @@ void cli_secure_boot_cmd(const char *cmd)
 #ifdef CONFIG_CMDLINE
        cmdtp = find_cmd(cmd);
        if (!cmdtp) {
-               printf("## Error: \"%s\" not defined\n", cmd);
+               pr_err("## Error: \"%s\" not defined\n", cmd);
                goto err;
        }
 
@@ -226,7 +226,7 @@ void cli_secure_boot_cmd(const char *cmd)
 #endif
 
        /* Shouldn't ever return from boot command. */
-       printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
+       pr_err("## Error: \"%s\" returned (code %d)\n", cmd, rc);
 
 err:
        /*
@@ -247,7 +247,7 @@ void cli_loop(void)
 #elif defined(CONFIG_CMDLINE)
        cli_simple_loop();
 #else
-       printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
+       pr_debug("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
 #endif /*CONFIG_HUSH_PARSER*/
 }
 
index e86ee73faf7afd841b331947fedff9ffaf340f7a..20cea3abdfa2fa9ceb414f57ef554a20d36e8d77 100644 (file)
@@ -243,7 +243,7 @@ static void cread_add_str(char *str, int strsize, int insert,
                str++;
        }
 }
-
+int is_direction_key = 0;
 static int cread_line(const char *const prompt, char *buf, unsigned int *len,
                int timeout)
 {
@@ -297,6 +297,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len,
                        } else if (esc_len == 2) {
                                switch (ichar) {
                                case 'D':       /* <- key */
+                                       is_direction_key = 1;
                                        ichar = CTL_CH('b');
                                        act = ESC_CONVERTED;
                                        break;  /* pass off to ^B handler */
index 41c91c6d8c876802caf9d00a95d2dbeef6daa39a..2ccab67cb8626d45240cb4ee8ba99f6e0dc279d3 100644 (file)
@@ -79,7 +79,7 @@ int _do_help(struct cmd_tbl *cmd_start, int cmd_items, struct cmd_tbl *cmdtp,
                if (cmdtp != NULL) {
                        rcode |= cmd_usage(cmdtp);
                } else {
-                       printf("Unknown command '%s' - try 'help' without arguments for list of all known commands\n\n",
+                       pr_debug("Unknown command '%s' - try 'help' without arguments for list of all known commands\n\n",
                               argv[i]);
                        rcode = 1;
                }
@@ -132,10 +132,10 @@ struct cmd_tbl *find_cmd(const char *cmd)
 
 int cmd_usage(const struct cmd_tbl *cmdtp)
 {
-       printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
+       pr_info("%s - %s\n\n", cmdtp->name, cmdtp->usage);
 
 #ifdef CONFIG_SYS_LONGHELP
-       printf("Usage:\n%s ", cmdtp->name);
+       pr_info("Usage:\n%s ", cmdtp->name);
 
        if (!cmdtp->help) {
                puts ("- No additional help available.\n");
@@ -508,7 +508,7 @@ void fixup_cmdtable(struct cmd_tbl *cmdtp, int size)
 
                addr = (ulong)(cmdtp->cmd) + gd->reloc_off;
 #ifdef DEBUG_COMMANDS
-               printf("Command \"%s\": 0x%08lx => 0x%08lx\n",
+               pr_debug("Command \"%s\": 0x%08lx => 0x%08lx\n",
                       cmdtp->name, (ulong)(cmdtp->cmd), addr);
 #endif
                cmdtp->cmd = (int (*)(struct cmd_tbl *, int, int,
@@ -606,7 +606,7 @@ enum command_ret_t cmd_process(int flag, int argc, char *const argv[],
        /* Look up command in command table */
        cmdtp = find_cmd(argv[0]);
        if (cmdtp == NULL) {
-               printf("Unknown command '%s' - try 'help'\n", argv[0]);
+               pr_debug("Unknown command '%s' - try 'help'\n", argv[0]);
                return 1;
        }
 
@@ -648,7 +648,7 @@ int cmd_process_error(struct cmd_tbl *cmdtp, int err)
                return CMD_RET_USAGE;
 
        if (err) {
-               printf("Command '%s' failed: Error %d\n", cmdtp->name, err);
+               pr_err("Command '%s' failed: Error %d\n", cmdtp->name, err);
                return CMD_RET_FAILURE;
        }
 
index e783f309bf0699a5e8e8bf09a8374bfb6b65a1c0..206a0f7cb43868d545f2a79631ca225a2e6d09fb 100644 (file)
@@ -22,6 +22,7 @@
 #include <watchdog.h>
 #include <asm/global_data.h>
 #include <linux/delay.h>
+#include <command.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -59,7 +60,7 @@ static int on_console(const char *name, const char *value, enum env_op op,
 
        case env_op_delete:
                if ((flags & H_FORCE) == 0)
-                       printf("Can't delete \"%s\"\n", name);
+                       pr_err("Can't delete \"%s\"\n", name);
                return 1;
 
        default:
@@ -655,13 +656,42 @@ static inline void pre_console_puts(const char *s) {}
 static inline void print_pre_console_buffer(int flushpoint) {}
 #endif
 
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+void handle_console_log(const char *s) {
+       if (!gd || !gd->console_log.buffer) {
+               return;
+       }
+
+       while (*s) {
+               /* To ensure that the write pointer does not overlap with the read pointer,
+               the log buffer maintains at least 1 byte free. */
+               if (gd->console_log.write_ptr == gd->console_log.read_ptr - 1 ||
+                       (gd->console_log.write_ptr == gd->console_log.buffer + LOG_BUFFER_SIZE - 1 &&
+                        gd->console_log.read_ptr == gd->console_log.buffer)) {
+                       break;
+               }
+
+               *gd->console_log.write_ptr++ = *s;
+
+               if (gd->console_log.write_ptr >= gd->console_log.buffer + LOG_BUFFER_SIZE) {
+                       gd->console_log.write_ptr = gd->console_log.buffer;
+               }
+
+               s++;
+       }
+}
+#endif
+
 void putc(const char c)
 {
        if (!gd)
                return;
 
        console_record_putc(c);
-
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+       char str[2] = {c, '\0'};
+       handle_console_log(str);
+#endif
        /* sandbox can send characters to stdout before it has a console */
        if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
                os_putc(c);
@@ -703,6 +733,9 @@ void puts(const char *s)
 
        console_record_puts(s);
 
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+       handle_console_log(s);
+#endif
        /* sandbox can send characters to stdout before it has a console */
        if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
                os_puts(s);
index f48cd2a333db31738e51c86cff1b5228ee3c5994..456ad397b16fbcda61d484f5f2ffe3997eb83194 100644 (file)
@@ -2392,14 +2392,14 @@ static void malloc_update_mallinfo()
 void malloc_stats()
 {
   malloc_update_mallinfo();
-  printf("max system bytes = %10u\n",
+  pr_debug("max system bytes = %10u\n",
          (unsigned int)(max_total_mem));
-  printf("system bytes     = %10u\n",
+  pr_debug("system bytes     = %10u\n",
          (unsigned int)(sbrked_mem + mmapped_mem));
-  printf("in use bytes     = %10u\n",
+  pr_debug("in use bytes     = %10u\n",
          (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
 #if HAVE_MMAP
-  printf("max mmap regions = %10u\n",
+  pr_debug("max mmap regions = %10u\n",
          (unsigned int)max_n_mmaps);
 #endif
 }
index baf7fb70659ded7e05d361deb6aa87035858ed4f..235bc9c448bf32fd5409811099e37a5dbbc82f72 100644 (file)
@@ -121,8 +121,9 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name)
        if (offset == -FDT_ERR_NOTFOUND)
                offset = fdt_add_subnode(fdt, parentoffset, name);
 
-       if (offset < 0)
-               printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
+       if (offset < 0){
+               pr_debug("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
+       }
 
        return offset;
 }
@@ -155,14 +156,15 @@ static int fdt_fixup_stdout(void *fdt, int chosenoff)
        memcpy(tmp, path, len);
 
        err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len);
-       if (err < 0)
-               printf("WARNING: could not set linux,stdout-path %s.\n",
+       if (err < 0){
+               pr_debug("WARNING: could not set linux,stdout-path %s.\n",
                       fdt_strerror(err));
+       }
 
        return err;
 
 noalias:
-       printf("WARNING: %s: could not read %s alias: %s\n",
+       pr_debug("WARNING: %s: could not read %s alias: %s\n",
               __func__, sername, fdt_strerror(err));
 
        return 0;
@@ -190,7 +192,7 @@ int fdt_root(void *fdt)
 
        err = fdt_check_header(fdt);
        if (err < 0) {
-               printf("fdt_root: %s\n", fdt_strerror(err));
+               pr_debug("fdt_root: %s\n", fdt_strerror(err));
                return err;
        }
 
@@ -200,7 +202,7 @@ int fdt_root(void *fdt)
                                  strlen(serial) + 1);
 
                if (err < 0) {
-                       printf("WARNING: could not set serial-number %s.\n",
+                       pr_debug("WARNING: could not set serial-number %s.\n",
                               fdt_strerror(err));
                        return err;
                }
@@ -241,7 +243,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
 
        err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start);
        if (err < 0) {
-               printf("fdt_initrd: %s\n", fdt_strerror(err));
+               pr_debug("fdt_initrd: %s\n", fdt_strerror(err));
                return err;
        }
 
@@ -251,7 +253,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
                              (uint64_t)initrd_start, is_u64);
 
        if (err < 0) {
-               printf("WARNING: could not set linux,initrd-start %s.\n",
+               pr_debug("WARNING: could not set linux,initrd-start %s.\n",
                       fdt_strerror(err));
                return err;
        }
@@ -260,7 +262,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
                              (uint64_t)initrd_end, is_u64);
 
        if (err < 0) {
-               printf("WARNING: could not set linux,initrd-end %s.\n",
+               pr_debug("WARNING: could not set linux,initrd-end %s.\n",
                       fdt_strerror(err));
 
                return err;
@@ -287,7 +289,7 @@ int fdt_chosen(void *fdt)
 
        err = fdt_check_header(fdt);
        if (err < 0) {
-               printf("fdt_chosen: %s\n", fdt_strerror(err));
+               pr_debug("fdt_chosen: %s\n", fdt_strerror(err));
                return err;
        }
 
@@ -301,7 +303,7 @@ int fdt_chosen(void *fdt)
                                  abuf_data(&buf), abuf_size(&buf));
                abuf_uninit(&buf);
                if (err < 0) {
-                       printf("WARNING: could not set rng-seed %s.\n",
+                       pr_debug("WARNING: could not set rng-seed %s.\n",
                               fdt_strerror(err));
                        return err;
                }
@@ -313,7 +315,7 @@ int fdt_chosen(void *fdt)
                err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
                                  strlen(str) + 1);
                if (err < 0) {
-                       printf("WARNING: could not set bootargs %s.\n",
+                       pr_debug("WARNING: could not set bootargs %s.\n",
                               fdt_strerror(err));
                        return err;
                }
@@ -323,7 +325,7 @@ int fdt_chosen(void *fdt)
        err = fdt_setprop(fdt, nodeoffset, "u-boot,version", PLAIN_VERSION,
                          strlen(PLAIN_VERSION) + 1);
        if (err < 0) {
-               printf("WARNING: could not set u-boot,version %s.\n",
+               pr_debug("WARNING: could not set u-boot,version %s.\n",
                       fdt_strerror(err));
                return err;
        }
@@ -342,9 +344,10 @@ void do_fixup_by_path(void *fdt, const char *path, const char *prop,
        debug("\n");
 #endif
        int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
-       if (rc)
-               printf("Unable to update property %s:%s, err=%s\n",
+       if (rc){
+               pr_debug("Unable to update property %s:%s, err=%s\n",
                        path, prop, fdt_strerror(rc));
+       }
 }
 
 void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
@@ -465,7 +468,7 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
        u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */
 
        if (banks > MEMORY_BANKS_MAX) {
-               printf("%s: num banks %d exceeds hardcoded limit %d."
+               pr_debug("%s: num banks %d exceeds hardcoded limit %d."
                       " Recompile with higher MEMORY_BANKS_MAX?\n",
                       __FUNCTION__, banks, MEMORY_BANKS_MAX);
                return -1;
@@ -473,7 +476,7 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
 
        err = fdt_check_header(blob);
        if (err < 0) {
-               printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
+               pr_debug("%s: %s\n", __FUNCTION__, fdt_strerror(err));
                return err;
        }
 
@@ -485,7 +488,7 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
        err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
                        sizeof("memory"));
        if (err < 0) {
-               printf("WARNING: could not set %s %s.\n", "device_type",
+               pr_debug("WARNING: could not set %s %s.\n", "device_type",
                                fdt_strerror(err));
                return err;
        }
@@ -504,7 +507,7 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
 
        err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
        if (err < 0) {
-               printf("WARNING: could not set %s %s.\n",
+               pr_debug("WARNING: could not set %s %s.\n",
                                "reg", fdt_strerror(err));
                return err;
        }
@@ -518,14 +521,14 @@ int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas)
        u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */
 
        if (areas > 8) {
-               printf("%s: num areas %d exceeds hardcoded limit %d\n",
+               pr_debug("%s: num areas %d exceeds hardcoded limit %d\n",
                       __func__, areas, 8);
                return -1;
        }
 
        err = fdt_check_header(blob);
        if (err < 0) {
-               printf("%s: %s\n", __func__, fdt_strerror(err));
+               pr_debug("%s: %s\n", __func__, fdt_strerror(err));
                return err;
        }
 
@@ -538,7 +541,7 @@ int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas)
 
        err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len);
        if (err < 0) {
-               printf("WARNING: could not set %s %s.\n",
+               pr_debug("WARNING: could not set %s %s.\n",
                       "reg", fdt_strerror(err));
                return err;
        }
@@ -638,7 +641,7 @@ int fdt_record_loadable(void *blob, u32 index, const char *name,
 
        err = fdt_check_header(blob);
        if (err < 0) {
-               printf("%s: %s\n", __func__, fdt_strerror(err));
+               pr_debug("%s: %s\n", __func__, fdt_strerror(err));
                return err;
        }
 
@@ -837,7 +840,7 @@ static int fdt_del_subnodes(const void *blob, int parent_offset)
                                fdt_get_name(blob, off, 0), off);
                        ret = fdt_del_node((void *)blob, off);
                        if (ret < 0) {
-                               printf("Can't delete node: %s\n",
+                               pr_debug("Can't delete node: %s\n",
                                        fdt_strerror(ret));
                                return ret;
                        } else {
@@ -868,7 +871,7 @@ static int fdt_del_partitions(void *blob, int parent_offset)
                } else {
                        ret = fdt_del_subnodes(blob, parent_offset);
                        if (ret < 0) {
-                               printf("Can't remove subnodes: %s\n",
+                               pr_debug("Can't remove subnodes: %s\n",
                                        fdt_strerror(ret));
                                return ret;
                        }
@@ -926,7 +929,7 @@ add_sub:
                        else
                                goto err_size;
                } else if (ret < 0) {
-                       printf("Can't add partition node: %s\n",
+                       pr_debug("Can't add partition node: %s\n",
                                fdt_strerror(ret));
                        return ret;
                }
@@ -985,10 +988,10 @@ add_label:
        }
        return 0;
 err_size:
-       printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+       pr_err("Can't increase blob size: %s\n", fdt_strerror(ret));
        return ret;
 err_prop:
-       printf("Can't add property: %s\n", fdt_strerror(ret));
+       pr_err("Can't add property: %s\n", fdt_strerror(ret));
        return ret;
 }
 
@@ -1073,10 +1076,11 @@ void fdt_del_node_and_alias(void *blob, const char *alias)
 #ifdef DEBUG
 static void of_dump_addr(const char *s, const fdt32_t *addr, int na)
 {
-       printf("%s", s);
-       while(na--)
-               printf(" %08x", *(addr++));
-       printf("\n");
+       pr_debug("%s", s);
+       while(na--){
+               pr_debug(" %08x", *(addr++));
+       }
+       pr_debug("\n");
 }
 #else
 static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { }
@@ -1348,7 +1352,7 @@ static u64 __of_translate_address(const void *blob, int node_offset,
        /* Cound address cells & copy address locally */
        bus->count_cells(blob, parent, &na, &ns);
        if (!OF_CHECK_COUNTS(na, ns)) {
-               printf("%s: Bad cell count for %s\n", __FUNCTION__,
+               pr_debug("%s: Bad cell count for %s\n", __FUNCTION__,
                       fdt_get_name(blob, node_offset, NULL));
                goto bail;
        }
@@ -1375,7 +1379,7 @@ static u64 __of_translate_address(const void *blob, int node_offset,
                pbus = of_match_bus(blob, parent);
                pbus->count_cells(blob, parent, &pna, &pns);
                if (!OF_CHECK_COUNTS(pna, pns)) {
-                       printf("%s: Bad cell count for %s\n", __FUNCTION__,
+                       pr_debug("%s: Bad cell count for %s\n", __FUNCTION__,
                                fdt_get_name(blob, node_offset, NULL));
                        break;
                }
@@ -1454,7 +1458,7 @@ int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
        node = parent;
        parent = fdt_parent_offset(blob, node);
        if (parent < 0) {
-               printf("Found dma-ranges in root node, shouldn't happen\n");
+               pr_debug("Found dma-ranges in root node, shouldn't happen\n");
                ret = -EINVAL;
                goto out;
        }
@@ -1463,7 +1467,7 @@ int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
        bus_node = of_match_bus(blob, node);
        bus_node->count_cells(blob, node, &na, &ns);
        if (!OF_CHECK_COUNTS(na, ns)) {
-               printf("%s: Bad cell count for %s\n", __FUNCTION__,
+               pr_debug("%s: Bad cell count for %s\n", __FUNCTION__,
                       fdt_get_name(blob, node, NULL));
                return -EINVAL;
                goto out;
@@ -1472,7 +1476,7 @@ int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
        bus_node = of_match_bus(blob, parent);
        bus_node->count_cells(blob, parent, &pna, &pns);
        if (!OF_CHECK_COUNTS(pna, pns)) {
-               printf("%s: Bad cell count for %s\n", __FUNCTION__,
+               pr_debug("%s: Bad cell count for %s\n", __FUNCTION__,
                       fdt_get_name(blob, parent, NULL));
                return -EINVAL;
                goto out;
@@ -1557,11 +1561,11 @@ int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle)
                char buf[64];
 
                fdt_get_path(fdt, nodeoffset, buf, sizeof(buf));
-               printf("Trying to update node %s with phandle %u ",
+               pr_debug("Trying to update node %s with phandle %u ",
                       buf, phandle);
 
                fdt_get_path(fdt, off, buf, sizeof(buf));
-               printf("that already exists in node %s.\n", buf);
+               pr_debug("that already exists in node %s.\n", buf);
                return -FDT_ERR_BADPHANDLE;
        }
 #endif
@@ -1588,14 +1592,14 @@ unsigned int fdt_create_phandle(void *fdt, int nodeoffset)
 
                ret = fdt_generate_phandle(fdt, &phandle);
                if (ret < 0) {
-                       printf("Can't generate phandle: %s\n",
+                       pr_debug("Can't generate phandle: %s\n",
                               fdt_strerror(ret));
                        return 0;
                }
 
                ret = fdt_set_phandle(fdt, nodeoffset, phandle);
                if (ret < 0) {
-                       printf("Can't set phandle %u: %s\n", phandle,
+                       pr_debug("Can't set phandle %u: %s\n", phandle,
                               fdt_strerror(ret));
                        return 0;
                }
@@ -1616,7 +1620,7 @@ unsigned int fdt_create_phandle_by_compatible(void *fdt, const char *compat)
        int offset = fdt_node_offset_by_compatible(fdt, -1, compat);
 
        if (offset < 0) {
-               printf("Can't find node with compatible \"%s\": %s\n", compat,
+               pr_debug("Can't find node with compatible \"%s\": %s\n", compat,
                       fdt_strerror(offset));
                return 0;
        }
@@ -1641,7 +1645,7 @@ unsigned int fdt_create_phandle_by_pathf(void *fdt, const char *fmt, ...)
        va_end(ap);
 
        if (offset < 0) {
-               printf("Can't find node by given path: %s\n",
+               pr_debug("Can't find node by given path: %s\n",
                       fdt_strerror(offset));
                return 0;
        }
@@ -1674,7 +1678,7 @@ int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status)
                ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail");
                break;
        default:
-               printf("Invalid fdt status: %x\n", status);
+               pr_debug("Invalid fdt status: %x\n", status);
                ret = -1;
                break;
        }
@@ -1758,13 +1762,13 @@ add_edid:
                        else
                                goto err_size;
                } else if (ret < 0) {
-                       printf("Can't add property: %s\n", fdt_strerror(ret));
+                       pr_debug("Can't add property: %s\n", fdt_strerror(ret));
                        return ret;
                }
        }
        return 0;
 err_size:
-       printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+       pr_err("Can't increase blob size: %s\n", fdt_strerror(ret));
        return ret;
 }
 #endif
@@ -1793,21 +1797,21 @@ int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr)
 
        node = fdt_path_offset(fdt, path);
        if (node < 0) {
-               printf("Warning: device tree alias '%s' points to invalid "
+               pr_debug("Warning: device tree alias '%s' points to invalid "
                       "node %s.\n", alias, path);
                return 0;
        }
 
        reg = fdt_getprop(fdt, node, "reg", &len);
        if (!reg) {
-               printf("Warning: device tree node '%s' has no address.\n",
+               pr_debug("Warning: device tree node '%s' has no address.\n",
                       path);
                return 0;
        }
 
        dt_addr = fdt_translate_address(fdt, node, reg);
        if (addr != dt_addr) {
-               printf("Warning: U-Boot configured device %s at address %llu,\n"
+               pr_debug("Warning: U-Boot configured device %s at address %llu,\n"
                       "but the device tree has it address %llx.\n",
                       alias, addr, dt_addr);
                return 0;
@@ -2048,11 +2052,11 @@ int fdt_overlay_apply_verbose(void *fdt, void *fdto)
 
        err = fdt_overlay_apply(fdt, fdto);
        if (err < 0) {
-               printf("failed on fdt_overlay_apply(): %s\n",
+               pr_err("failed on fdt_overlay_apply(): %s\n",
                                fdt_strerror(err));
                if (!has_symbols) {
-                       printf("base fdt does did not have a /__symbols__ node\n");
-                       printf("make sure you've compiled with -@\n");
+                       pr_debug("base fdt does did not have a /__symbols__ node\n");
+                       pr_debug("make sure you've compiled with -@\n");
                }
        }
        return err;
@@ -2071,7 +2075,7 @@ int fdt_valid(struct fdt_header **blobp)
        int err;
 
        if (!blob) {
-               printf("The address of the fdt is invalid (NULL).\n");
+               pr_debug("The address of the fdt is invalid (NULL).\n");
                return 0;
        }
 
@@ -2080,25 +2084,25 @@ int fdt_valid(struct fdt_header **blobp)
                return 1;       /* valid */
 
        if (err < 0) {
-               printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
+               pr_debug("libfdt fdt_check_header(): %s", fdt_strerror(err));
                /*
                 * Be more informative on bad version.
                 */
                if (err == -FDT_ERR_BADVERSION) {
                        if (fdt_version(blob) <
                            FDT_FIRST_SUPPORTED_VERSION) {
-                               printf(" - too old, fdt %d < %d",
+                               pr_debug(" - too old, fdt %d < %d",
                                       fdt_version(blob),
                                       FDT_FIRST_SUPPORTED_VERSION);
                        }
                        if (fdt_last_comp_version(blob) >
                            FDT_LAST_SUPPORTED_VERSION) {
-                               printf(" - too new, fdt %d > %d",
+                               pr_debug(" - too new, fdt %d > %d",
                                       fdt_version(blob),
                                       FDT_LAST_SUPPORTED_VERSION);
                        }
                }
-               printf("\n");
+               pr_debug("\n");
                *blobp = NULL;
                return 0;
        }
index 9e53545dbde7e346988f6c8bb465ef061aa5c154..95ab17467cdb65660f09d2296ac2a172fef4f393 100644 (file)
@@ -536,7 +536,7 @@ static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
                else {
                        vsum_str = env_get(verify_str);
                        if (vsum_str == NULL || strlen(vsum_str) != digits) {
-                               printf("Expected %d hex digits in env var\n",
+                               pr_debug("Expected %d hex digits in env var\n",
                                       digits);
                                return 1;
                        }
@@ -551,9 +551,10 @@ static void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *ou
 {
        int i;
 
-       printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
-       for (i = 0; i < algo->digest_size; i++)
-               printf("%02x", output[i]);
+       pr_debug("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
+       for (i = 0; i < algo->digest_size; i++){
+               pr_debug("%02x", output[i]);
+       }
 }
 
 int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
@@ -574,7 +575,7 @@ int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
                void *buf;
 
                if (hash_lookup_algo(algo_name, &algo)) {
-                       printf("Unknown hash algorithm '%s'\n", algo_name);
+                       pr_debug("Unknown hash algorithm '%s'\n", algo_name);
                        return CMD_RET_USAGE;
                }
                argc -= 2;
@@ -600,7 +601,7 @@ int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
 #endif
                        if (parse_verify_sum(algo, *argv, vsum,
                                        flags & HASH_FLAG_ENV)) {
-                               printf("ERROR: %s does not contain a valid "
+                               pr_err("ERROR: %s does not contain a valid "
                                        "%s sum\n", *argv, algo->name);
                                return 1;
                        }
@@ -608,15 +609,15 @@ int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
                                int i;
 
                                hash_show(algo, addr, len, output);
-                               printf(" != ");
+                               pr_debug(" != ");
                                for (i = 0; i < algo->digest_size; i++)
-                                       printf("%02x", vsum[i]);
+                                       pr_debug("%02x", vsum[i]);
                                puts(" ** ERROR **\n");
                                return 1;
                        }
                } else {
                        hash_show(algo, addr, len, output);
-                       printf("\n");
+                       pr_debug("\n");
 
                        if (argc) {
                                store_result(algo, output, *argv,
@@ -633,7 +634,7 @@ int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
 
                crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
 
-               printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
+               pr_debug("CRC32 for %08lx ... %08lx ==> %08lx\n",
                                addr, addr + len - 1, crc);
 
                if (argc >= 3) {
index 3e876b55b34a49c83f2f379d3c9f612bdd7c1fdd..7d74d50f49f58c77236f64326288b70c3846ca88 100644 (file)
@@ -513,7 +513,7 @@ void bootmenu_loop(struct bootmenu_data *menu,
                        *key = KEY_NONE;
                } else {
                /* Alone ESC key was pressed */
-                       *key = KEY_QUIT;
+                       *key = KEY_NONE;
                        *esc = (c == '\e') ? 1 : 0;
                }
                break;
index 70d97815f0a1f6bb05cfb5d01d4d542139a229cd..6320f16750ef167cb5fc5a609ff9ea43a5c8c327 100644 (file)
@@ -690,6 +690,20 @@ config SPL_FS_LOAD_PAYLOAD_NAME
        help
          Filename to read to load U-Boot when reading from filesystem.
 
+config SPL_FS_LOAD_OTHERS_FILES
+       bool "Support onother file to load"
+       depends on SPL_FS_EXT4 || SPL_FS_FAT || SPL_FS_SQUASHFS
+       help
+         it support that load onother file from the filessystem
+         independent.
+
+config SPL_FS_LOAD_OTHERS_FILES_NAME
+       string "another File to load for U-Boot from the filesystem"
+       depends on SPL_FS_LOAD_OTHERS_FILES
+       default "u-boot.itb"
+       help
+         if it has onother file should load independent from filesystem.
+
 config SPL_FS_LOAD_KERNEL_NAME
        string "File to load for the OS kernel from the filesystem"
        depends on (SPL_FS_EXT4 || SPL_FS_FAT || SPL_FS_SQUASHFS) && SPL_OS_BOOT
@@ -1297,8 +1311,39 @@ config SPL_SPI_LOAD
          Enable support for loading next stage, U-Boot or otherwise, from
          SPI NOR in U-Boot SPL.
 
+config SPL_MTD_LOAD
+       bool "Support loading from mtd device"
+       help
+         Enable support for loading next stage, U-Boot or otherwise, from
+         SPI NOR in U-Boot SPL. it would dynamic to get the current mtd dev.
+
 endif # SPL_SPI_FLASH_SUPPORT
 
+config SYS_LOAD_IMAGE_PARTITION_NAME
+       string "Partition name to use to load U-Boot from"
+       depends on SPL_MTD_LOAD || SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+       help
+         Partition name on the storage to load U-Boot from.
+
+config SYS_LOAD_IMAGE_SEC_PARTITION
+       bool "Second partition to use to load U-Boot from"
+       depends on SPL_MTD_LOAD || SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+       help
+         Second Partition if need on the storage to load U-Boot from.
+
+config SYS_LOAD_IMAGE_SEC_PARTITION_INDEX
+       int "Second partition index to use to load U-Boot from"
+       depends on SYS_LOAD_IMAGE_SEC_PARTITION
+       default 2
+       help
+         Second partition name on the storage to load U-Boot from.
+
+config SYS_LOAD_IMAGE_SEC_PARTITION_NAME
+       string "Second partition name to use to load U-Boot from"
+       depends on SYS_LOAD_IMAGE_SEC_PARTITION
+       help
+         Second partition name on the storage to load U-Boot from.
+
 config SYS_SPI_U_BOOT_OFFS
        hex "address of u-boot payload in SPI flash"
        default 0x8000 if ARCH_SUNXI
@@ -1376,6 +1421,12 @@ config SPL_DFU
          This feature is useful to flash the binaries to factory or bare-metal
          boards using USB interface.
 
+config SPL_FASTBOOT_LOAD
+       bool "Support fastboot in spl to load image"
+       help
+         This feature enables fastboot in spl, and it could download image to
+         ram and run it.
+
 choice
        bool "DFU device selection"
        depends on SPL_DFU
index 13db3df993380ae15e2ae22cbaa9853b7102b4ba..472f7a96ff31a5ddcf237ae0591d4775f0308dbd 100644 (file)
@@ -33,4 +33,6 @@ obj-$(CONFIG_$(SPL_TPL_)DFU) += spl_dfu.o
 obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
 obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o
 obj-$(CONFIG_$(SPL_TPL_)USB_SDP_SUPPORT) += spl_sdp.o
+obj-$(CONFIG_$(SPL_TPL_)FASTBOOT_LOAD) += spl_fastboot.o
+obj-$(CONFIG_$(SPL_TPL_)MTD_LOAD) += spl_mtd.o
 endif
index 29e0898f03de15b1dd01c675fd24c3fad00ed0eb..8a094dd3686f23e8c442c952090e2101e942c159 100644 (file)
@@ -133,20 +133,20 @@ void spl_fixup_fdt(void *fdt_blob)
 
        err = fdt_check_header(fdt_blob);
        if (err < 0) {
-               printf("fdt_root: %s\n", fdt_strerror(err));
+               pr_debug("fdt_root: %s\n", fdt_strerror(err));
                return;
        }
 
        /* fixup the memory dt node */
        err = fdt_shrink_to_minimum(fdt_blob, 0);
        if (err == 0) {
-               printf(SPL_TPL_PROMPT "fdt_shrink_to_minimum err - %d\n", err);
+               pr_debug(SPL_TPL_PROMPT "fdt_shrink_to_minimum err - %d\n", err);
                return;
        }
 
        err = arch_fixup_fdt(fdt_blob);
        if (err) {
-               printf(SPL_TPL_PROMPT "arch_fixup_fdt err - %d\n", err);
+               pr_debug(SPL_TPL_PROMPT "arch_fixup_fdt err - %d\n", err);
                return;
        }
 #endif
@@ -272,8 +272,8 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
                             IH_ARCH_DEFAULT, IH_TYPE_STANDALONE, -1,
                             FIT_LOAD_OPTIONAL, &fw_data, &fw_len);
        if (ret >= 0) {
-               printf("DEPRECATED: 'standalone = ' property.");
-               printf("Please use either 'firmware =' or 'kernel ='\n");
+               pr_debug("DEPRECATED: 'standalone = ' property.");
+               pr_debug("Please use either 'firmware =' or 'kernel ='\n");
        } else {
                ret = fit_image_load(&images, (ulong)header, NULL,
                                     &fit_uname_config, IH_ARCH_DEFAULT,
@@ -298,7 +298,7 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
                spl_image->os = IH_OS_INVALID;
        spl_image->name = genimg_get_os_name(spl_image->os);
 
-       debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n",
+       pr_debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n",
              spl_image->name, spl_image->load_addr, spl_image->size);
 
 #ifdef CONFIG_SPL_FIT_SIGNATURE
@@ -314,7 +314,7 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
                        /* HACK: U-boot expects FDT at a specific address */
                        fdt_hack = spl_image->load_addr + spl_image->size;
                        fdt_hack = (fdt_hack + 3) & ~3;
-                       debug("Relocating FDT to %p\n", spl_image->fdt_addr);
+                       pr_debug("Relocating FDT to %p\n", spl_image->fdt_addr);
                        memcpy((void *)fdt_hack, spl_image->fdt_addr, dt_len);
                }
        }
@@ -357,7 +357,7 @@ __weak int spl_parse_legacy_header(struct spl_image_info *spl_image,
                                   const struct image_header *header)
 {
        /* LEGACY image not supported */
-       debug("Legacy boot image support not enabled, proceeding to other boot methods\n");
+       pr_debug("Legacy boot image support not enabled, proceeding to other boot methods\n");
        return -EINVAL;
 }
 
@@ -399,7 +399,7 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
                        spl_image->load_addr = CONFIG_SYS_LOAD_ADDR;
                        spl_image->entry_point = CONFIG_SYS_LOAD_ADDR;
                        spl_image->size = end - start;
-                       debug(SPL_TPL_PROMPT
+                       pr_debug(SPL_TPL_PROMPT
                              "payload zImage, load addr: 0x%lx size: %d\n",
                              spl_image->load_addr, spl_image->size);
                        return 0;
@@ -411,12 +411,12 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
 
 #ifdef CONFIG_SPL_RAW_IMAGE_SUPPORT
                /* Signature not found - assume u-boot.bin */
-               debug("mkimage signature not found - ih_magic = %x\n",
+               pr_debug("mkimage signature not found - ih_magic = %x\n",
                        header->ih_magic);
                spl_set_header_raw_uboot(spl_image);
 #else
                /* RAW image not supported, proceed to other boot methods. */
-               debug("Raw boot image support not enabled, proceeding to other boot methods\n");
+               pr_debug("Raw boot image support not enabled, proceeding to other boot methods\n");
                return -EINVAL;
 #endif
        }
@@ -431,7 +431,7 @@ __weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
        image_entry_noargs_t image_entry =
                (image_entry_noargs_t)spl_image->entry_point;
 
-       debug("image entry point: 0x%lx\n", spl_image->entry_point);
+       pr_debug("image entry point: 0x%lx\n", spl_image->entry_point);
        image_entry();
 }
 
@@ -469,7 +469,7 @@ static int write_spl_handoff(void)
        ret = handoff_arch_save(ho);
        if (ret)
                return ret;
-       debug(SPL_TPL_PROMPT "Wrote SPL handoff\n");
+       pr_debug(SPL_TPL_PROMPT "Wrote SPL handoff\n");
 
        return 0;
 }
@@ -512,7 +512,7 @@ static int spl_common_init(bool setup_malloc)
 #endif
        ret = bootstage_init(u_boot_first_phase());
        if (ret) {
-               debug("%s: Failed to set up bootstage: ret=%d\n", __func__,
+               pr_debug("%s: Failed to set up bootstage: ret=%d\n", __func__,
                      ret);
                return ret;
        }
@@ -523,7 +523,7 @@ static int spl_common_init(bool setup_malloc)
 
                ret = bootstage_unstash(stash, CONFIG_BOOTSTAGE_STASH_SIZE);
                if (ret)
-                       debug("%s: Failed to unstash bootstage: ret=%d\n",
+                       pr_debug("%s: Failed to unstash bootstage: ret=%d\n",
                              __func__, ret);
        }
 #endif /* CONFIG_BOOTSTAGE_STASH */
@@ -532,14 +532,14 @@ static int spl_common_init(bool setup_malloc)
 #if CONFIG_IS_ENABLED(LOG)
        ret = log_init();
        if (ret) {
-               debug("%s: Failed to set up logging\n", __func__);
+               pr_debug("%s: Failed to set up logging\n", __func__);
                return ret;
        }
 #endif
        if (CONFIG_IS_ENABLED(OF_REAL)) {
                ret = fdtdec_setup();
                if (ret) {
-                       debug("fdtdec_setup() returned error %d\n", ret);
+                       pr_debug("fdtdec_setup() returned error %d\n", ret);
                        return ret;
                }
        }
@@ -550,7 +550,7 @@ static int spl_common_init(bool setup_malloc)
                ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA));
                bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_SPL);
                if (ret) {
-                       debug("dm_init_and_scan() returned error %d\n", ret);
+                       pr_debug("dm_init_and_scan() returned error %d\n", ret);
                        return ret;
                }
        }
@@ -572,7 +572,7 @@ int spl_early_init(void)
 {
        int ret;
 
-       debug("%s\n", __func__);
+       pr_debug("%s\n", __func__);
 
        ret = spl_common_init(true);
        if (ret)
@@ -588,7 +588,7 @@ int spl_init(void)
        bool setup_malloc = !(IS_ENABLED(CONFIG_SPL_STACK_R) &&
                        IS_ENABLED(CONFIG_SPL_SYS_MALLOC_SIMPLE));
 
-       debug("%s\n", __func__);
+       pr_debug("%s\n", __func__);
 
        if (!(gd->flags & GD_FLG_SPL_EARLY_INIT)) {
                ret = spl_common_init(setup_malloc);
@@ -686,10 +686,17 @@ static int boot_from_devices(struct spl_image_info *spl_image,
                    CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT) &&
                    !IS_ENABLED(CONFIG_SILENT_CONSOLE)) {
                        if (loader)
-                               printf("Trying to boot from %s\n",
+                       {
+                               pr_debug("Trying to boot from %s\n",
                                       spl_loader_name(loader));
+#if IS_ENABLED(CONFIG_TARGET_SPACEMIT_K1X)
+                               if (!strncmp("RAM", spl_loader_name(loader), 3)){
+                                       asm("ebreak");
+                               }
+#endif
+                       }
                        else if (CONFIG_IS_ENABLED(SHOW_ERRORS))
-                               printf(SPL_TPL_PROMPT
+                               pr_debug(SPL_TPL_PROMPT
                                       "Unsupported Boot Device %d\n", bootdev);
                        else
                                puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n");
@@ -711,7 +718,7 @@ void board_init_f(ulong dummy)
 
                ret = spl_early_init();
                if (ret) {
-                       debug("spl_early_init() failed: %d\n", ret);
+                       pr_debug("spl_early_init() failed: %d\n", ret);
                        hang();
                }
        }
@@ -732,7 +739,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
        struct spl_image_info spl_image;
        int ret;
 
-       debug(">>" SPL_TPL_PROMPT "board_init_r()\n");
+       pr_debug(">>" SPL_TPL_PROMPT "board_init_r()\n");
 
        spl_set_bd();
 
@@ -754,7 +761,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
        if (CONFIG_IS_ENABLED(BLOBLIST)) {
                ret = bloblist_init();
                if (ret) {
-                       debug("%s: Failed to set up bloblist: ret=%d\n",
+                       pr_debug("%s: Failed to set up bloblist: ret=%d\n",
                              __func__, ret);
                        puts(SPL_TPL_PROMPT "Cannot set up bloblist\n");
                        hang();
@@ -799,6 +806,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
 #ifdef CONFIG_SYS_SPL_ARGS_ADDR
        spl_image.arg = (void *)CONFIG_SYS_SPL_ARGS_ADDR;
 #endif
+
        spl_image.boot_device = BOOT_DEVICE_NONE;
        board_boot_order(spl_boot_list);
 
@@ -807,7 +815,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
        if (ret) {
                if (CONFIG_IS_ENABLED(SHOW_ERRORS) &&
                    CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT))
-                       printf(SPL_TPL_PROMPT "failed to boot from all boot devices (err=%d)\n",
+                       pr_err(SPL_TPL_PROMPT "failed to boot from all boot devices (err=%d)\n",
                               ret);
                else
                        puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n");
@@ -817,44 +825,46 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
        spl_perform_fixups(&spl_image);
        if (CONFIG_IS_ENABLED(HANDOFF)) {
                ret = write_spl_handoff();
-               if (ret)
-                       printf(SPL_TPL_PROMPT
+               if (ret){
+                       pr_err(SPL_TPL_PROMPT
                               "SPL hand-off write failed (err=%d)\n", ret);
+               }
        }
        if (CONFIG_IS_ENABLED(BLOBLIST)) {
                ret = bloblist_finish();
-               if (ret)
-                       printf("Warning: Failed to finish bloblist (ret=%d)\n",
+               if (ret){
+                       pr_err("Warning: Failed to finish bloblist (ret=%d)\n",
                               ret);
+               }
        }
 
        switch (spl_image.os) {
        case IH_OS_U_BOOT:
-               debug("Jumping to %s...\n", spl_phase_name(spl_next_phase()));
+               pr_debug("Jumping to %s...\n", spl_phase_name(spl_next_phase()));
                break;
 #if CONFIG_IS_ENABLED(ATF)
        case IH_OS_ARM_TRUSTED_FIRMWARE:
-               debug("Jumping to U-Boot via ARM Trusted Firmware\n");
+               pr_debug("Jumping to U-Boot via ARM Trusted Firmware\n");
                spl_fixup_fdt(spl_image.fdt_addr);
                spl_invoke_atf(&spl_image);
                break;
 #endif
 #if CONFIG_IS_ENABLED(OPTEE_IMAGE)
        case IH_OS_TEE:
-               debug("Jumping to U-Boot via OP-TEE\n");
+               pr_debug("Jumping to U-Boot via OP-TEE\n");
                spl_board_prepare_for_optee(spl_image.fdt_addr);
                jump_to_image_optee(&spl_image);
                break;
 #endif
 #if CONFIG_IS_ENABLED(OPENSBI)
        case IH_OS_OPENSBI:
-               debug("Jumping to U-Boot via RISC-V OpenSBI\n");
+               pr_debug("Jumping to U-Boot via RISC-V OpenSBI\n");
                spl_invoke_opensbi(&spl_image);
                break;
 #endif
 #if CONFIG_IS_ENABLED(OS_BOOT)
        case IH_OS_LINUX:
-               debug("Jumping to Linux\n");
+               pr_debug("Jumping to Linux\n");
 #if defined(CONFIG_SYS_SPL_ARGS_ADDR)
                spl_fixup_fdt((void *)CONFIG_SYS_SPL_ARGS_ADDR);
 #endif
@@ -862,18 +872,19 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
                jump_to_image_linux(&spl_image);
 #endif
        default:
-               debug("Unsupported OS image.. Jumping nevertheless..\n");
+               pr_debug("Unsupported OS image.. Jumping nevertheless..\n");
        }
 #if CONFIG_VAL(SYS_MALLOC_F_LEN) && !defined(CONFIG_SYS_SPL_MALLOC_SIZE)
-       debug("SPL malloc() used 0x%lx bytes (%ld KB)\n", gd->malloc_ptr,
+       pr_debug("SPL malloc() used 0x%lx bytes (%ld KB)\n", gd->malloc_ptr,
              gd->malloc_ptr / 1024);
 #endif
        bootstage_mark_name(get_bootstage_id(false), "end phase");
 #ifdef CONFIG_BOOTSTAGE_STASH
        ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
                              CONFIG_BOOTSTAGE_STASH_SIZE);
-       if (ret)
-               debug("Failed to stash bootstage: err=%d\n", ret);
+       if (ret){
+               pr_debug("Failed to stash bootstage: err=%d\n", ret);
+       }
 #endif
 
        spl_board_prepare_for_boot();
@@ -920,7 +931,7 @@ __weak void spl_relocate_stack_check(void)
                        break;
                ptr++;
        }
-       printf("SPL initial stack usage: %lu bytes\n",
+       pr_debug("SPL initial stack usage: %lu bytes\n",
               CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK) - i);
 #endif
 }
@@ -954,7 +965,7 @@ ulong spl_relocate_stack_gd(void)
 
 #if defined(CONFIG_SPL_SYS_MALLOC_SIMPLE) && CONFIG_VAL(SYS_MALLOC_F_LEN)
        if (CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN) {
-               debug("SPL malloc() before relocation used 0x%lx bytes (%ld KB)\n",
+               pr_debug("SPL malloc() before relocation used 0x%lx bytes (%ld KB)\n",
                      gd->malloc_ptr, gd->malloc_ptr / 1024);
                ptr -= CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN;
                gd->malloc_base = ptr;
diff --git a/common/spl/spl_fastboot.c b/common/spl/spl_fastboot.c
new file mode 100644 (file)
index 0000000..1d49609
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <mtd.h>
+#include <linux/err.h>
+#include <env.h>
+
+#include <g_dnl.h>
+#include <fastboot.h>
+#include <net.h>
+#include <usb.h>
+#include <watchdog.h>
+#include <linux/stringify.h>
+#include <vsprintf.h>
+
+static ulong spl_fastboot_load_read(struct spl_load_info *load, ulong sector,
+                              ulong count, void *buf)
+{
+       ulong addr;
+
+       pr_debug("%s: sector %lx, count %lx, buf %lx\n",
+             __func__, sector, count, (ulong)buf);
+
+       addr = (ulong)CONFIG_SPL_LOAD_FIT_ADDRESS + sector;
+       if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD))
+               addr += image_load_offset;
+
+       memcpy(buf, (void *)addr, count);
+
+       return count;
+}
+
+
+
+static int run_fastboot_usb(void)
+{
+       int controller_index = 0;
+       int ret;
+
+       fastboot_init((void *)CONFIG_SPL_LOAD_FIT_ADDRESS, CONFIG_FASTBOOT_BUF_SIZE);
+       ret = usb_gadget_initialize(controller_index);
+       if (ret) {
+               pr_err("USB init failed: %d\n", ret);
+               return -1;
+       }
+
+       g_dnl_clear_detach();
+       ret = g_dnl_register("usb_dnl_fastboot");
+       if (ret)
+               return ret;
+
+       if (!g_dnl_board_usb_cable_connected()) {
+               puts("\rUSB cable not detected.\n" \
+                    "Command exit.\n");
+               ret = -1;
+               goto exit;
+       }
+
+       while (1) {
+               if (g_dnl_detach())
+                       break;
+               if (ctrlc())
+                       break;
+               WATCHDOG_RESET();
+               usb_gadget_handle_interrupts(controller_index);
+       }
+
+       ret = 0;
+
+exit:
+       g_dnl_unregister();
+       g_dnl_clear_detach();
+       usb_gadget_release(controller_index);
+
+       return ret;
+}
+
+
+static int spl_fastboot_load_image(struct spl_image_info *spl_image,
+                             struct spl_boot_device *bootdev)
+{
+       struct image_header *header;
+
+       if (run_fastboot_usb()){
+               pr_err("run fastboot fail\n");
+               return -1;
+       }
+
+       header = (struct image_header *)CONFIG_SPL_LOAD_FIT_ADDRESS;
+       if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+           image_get_magic(header) == FDT_MAGIC) {
+               struct spl_load_info load;
+
+               pr_debug("Found FIT\n");
+               load.bl_len = 1;
+               load.read = spl_fastboot_load_read;
+               spl_load_simple_fit(spl_image, &load, 0, header);
+       }else{
+               pr_debug("not support legacy image\n");
+               return -1;
+       }
+       return 0;
+}
+
+SPL_LOAD_IMAGE_METHOD("FASTBOOT", 0, BOOT_DEVICE_BOARD, spl_fastboot_load_image);
index a35be52965679e683c56b8e935a40e177c18d080..cc7072649ef3a3fa6d026fc3cb6aa18393358383 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/cache.h>
 #include <asm/global_data.h>
 #include <linux/libfdt.h>
+#include <cpu_func.h>
+#include <linux/kernel.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -91,7 +93,7 @@ static int spl_fit_get_image_name(const struct spl_fit_info *ctx,
 
        name = fdt_getprop(ctx->fit, ctx->conf_node, type, &len);
        if (!name) {
-               debug("cannot find property '%s': %d\n", type, len);
+               pr_debug("cannot find property '%s': %d\n", type, len);
                return -EINVAL;
        }
 
@@ -138,7 +140,7 @@ static int spl_fit_get_image_name(const struct spl_fit_info *ctx,
        }
 
        if (!found) {
-               debug("no string for index %d\n", index);
+               pr_debug("no string for index %d\n", index);
                return -E2BIG;
        }
 
@@ -169,7 +171,7 @@ static int spl_fit_get_image_node(const struct spl_fit_info *ctx,
        if (err)
                return err;
 
-       debug("%s: '%s'\n", type, str);
+       pr_debug("%s: '%s'\n", type, str);
 
        node = fdt_subnode_offset(ctx->fit, ctx->images_node, str);
        if (node < 0) {
@@ -249,23 +251,25 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
        const void *data;
        const void *fit = ctx->fit;
        bool external_data = false;
+       ulong flush_dcache_addr;
+       ulong flush_lenth;
 
        if (IS_ENABLED(CONFIG_SPL_FPGA) ||
            (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP))) {
                if (fit_image_get_type(fit, node, &type))
                        puts("Cannot get image type.\n");
                else
-                       debug("%s ", genimg_get_type_name(type));
+                       pr_debug("%s ", genimg_get_type_name(type));
        }
 
        if (IS_ENABLED(CONFIG_SPL_GZIP)) {
                fit_image_get_comp(fit, node, &image_comp);
-               debug("%s ", genimg_get_comp_name(image_comp));
+               pr_debug("%s ", genimg_get_comp_name(image_comp));
        }
 
        if (fit_image_get_load(fit, node, &load_addr)) {
                if (!image_info->load_addr) {
-                       printf("Can't load %s: No load address and no buffer\n",
+                       pr_debug("Can't load %s: No load address and no buffer\n",
                               fit_get_name(fit, node, NULL));
                        return -ENOBUFS;
                }
@@ -304,7 +308,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
                               nr_sectors, src_ptr) != nr_sectors)
                        return -EIO;
 
-               debug("External data: dst=%p, offset=%x, size=%lx\n",
+               pr_debug("External data: dst=%p, offset=%x, size=%lx\n",
                      src_ptr, offset, (unsigned long)length);
                src = src_ptr + overhead;
        } else {
@@ -313,7 +317,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
                        puts("Cannot get image data/size\n");
                        return -ENOENT;
                }
-               debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
+               pr_debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
                      (unsigned long)length);
                src = (void *)data;     /* cast away const */
        }
@@ -342,6 +346,10 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
                memcpy(load_ptr, src, length);
        }
 
+       flush_dcache_addr = round_down((ulong)load_ptr,CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       flush_lenth = round_up(length, CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       flush_dcache_range(flush_dcache_addr, flush_dcache_addr + flush_lenth);
+
        if (image_info) {
                ulong entry_point;
 
@@ -385,7 +393,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
        /* Figure out which device tree the board wants to use */
        node = spl_fit_get_image_node(ctx, FIT_FDT_PROP, index++);
        if (node < 0) {
-               debug("%s: cannot find FDT node\n", __func__);
+               pr_debug("%s: cannot find FDT node\n", __func__);
 
                /*
                 * U-Boot did not find a device tree inside the FIT image. Use
@@ -414,10 +422,10 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
                for (; ; index++) {
                        node = spl_fit_get_image_node(ctx, FIT_FDT_PROP, index);
                        if (node == -E2BIG) {
-                               debug("%s: No additional FDT node\n", __func__);
+                               pr_debug("%s: No additional FDT node\n", __func__);
                                break;
                        } else if (node < 0) {
-                               debug("%s: unable to find FDT node %d\n",
+                               pr_debug("%s: unable to find FDT node %d\n",
                                      __func__, index);
                                continue;
                        }
@@ -431,7 +439,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
                                 */
                                tmpbuffer = malloc(CONFIG_SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ);
                                if (!tmpbuffer)
-                                       debug("%s: unable to allocate space for overlays\n",
+                                       pr_debug("%s: unable to allocate space for overlays\n",
                                              __func__);
                        }
                        image_info.load_addr = (ulong)tmpbuffer;
@@ -454,7 +462,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
                                break;
                        }
 
-                       debug("%s: DT overlay %s applied\n", __func__,
+                       pr_debug("%s: DT overlay %s applied\n", __func__,
                              fit_get_name(ctx->fit, node, NULL));
                }
                free(tmpbuffer);
@@ -537,7 +545,7 @@ static void *spl_get_fit_load_buffer(size_t size)
 {
        void *buf;
 
-       buf = malloc(size);
+       buf = memalign(ARCH_DMA_MINALIGN, size);
        if (!buf) {
                pr_err("Could not get FIT buffer of %lu bytes\n", (ulong)size);
                pr_err("\tcheck CONFIG_SYS_SPL_MALLOC_SIZE\n");
@@ -572,8 +580,8 @@ __weak void *spl_load_simple_fit_fix_load(const void *fit)
 
 static void warn_deprecated(const char *msg)
 {
-       printf("DEPRECATED: %s\n", msg);
-       printf("\tSee doc/uImage.FIT/source_file_format.txt\n");
+       pr_debug("DEPRECATED: %s\n", msg);
+       pr_debug("\tSee doc/uImage.FIT/source_file_format.txt\n");
 }
 
 static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
@@ -584,7 +592,7 @@ static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
        int devnum = 0;
        int flags = 0;
 
-       debug("FPGA bitstream at: %x, size: %x\n",
+       pr_debug("FPGA bitstream at: %x, size: %x\n",
              (u32)fpga_image->load_addr, fpga_image->size);
 
        compatible = fdt_getprop(ctx->fit, node, "compatible", NULL);
@@ -594,14 +602,14 @@ static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
                if (CONFIG_IS_ENABLED(FPGA_LOAD_SECURE))
                        flags = fpga_compatible2flag(devnum, compatible);
                if (strcmp(compatible, "u-boot,fpga-legacy"))
-                       debug("Ignoring compatible = %s property\n",
+                       pr_debug("Ignoring compatible = %s property\n",
                              compatible);
        }
 
        ret = fpga_load(devnum, (void *)fpga_image->load_addr,
                        fpga_image->size, BIT_FULL, flags);
        if (ret) {
-               printf("%s: Cannot load the image to the FPGA\n", __func__);
+               pr_debug("%s: Cannot load the image to the FPGA\n", __func__);
                return ret;
        }
 
@@ -628,7 +636,7 @@ static int spl_fit_load_fpga(struct spl_fit_info *ctx,
        /* Load the image and set up the fpga_image structure */
        ret = spl_load_fit_image(info, sector, ctx, node, &fpga_image);
        if (ret) {
-               printf("%s: Cannot load the FPGA: %i\n", __func__, ret);
+               pr_debug("%s: Cannot load the FPGA: %i\n", __func__, ret);
                return ret;
        }
 
@@ -664,7 +672,7 @@ static int spl_simple_fit_read(struct spl_fit_info *ctx,
 
        count = info->read(info, sector, sectors, buf);
        ctx->fit = buf;
-       debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu, size=0x%lx\n",
+       pr_debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu, size=0x%lx\n",
              sector, sectors, buf, count, size);
 
        return (count == 0) ? -EIO : 0;
@@ -688,7 +696,7 @@ static int spl_simple_fit_parse(struct spl_fit_info *ctx)
        /* find the node holding the images information */
        ctx->images_node = fdt_path_offset(ctx->fit, FIT_IMAGES_PATH);
        if (ctx->images_node < 0) {
-               debug("%s: Cannot find /images node: %d\n", __func__,
+               pr_debug("%s: Cannot find /images node: %d\n", __func__,
                      ctx->images_node);
                return -EINVAL;
        }
@@ -736,7 +744,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
                node = spl_fit_get_image_node(&ctx, FIT_KERNEL_PROP, 0);
 
        if (node < 0) {
-               debug("could not find firmware image, trying loadables...\n");
+               pr_debug("could not find firmware image, trying loadables...\n");
                node = spl_fit_get_image_node(&ctx, "loadables", 0);
                /*
                 * If we pick the U-Boot image from "loadables", start at
@@ -745,7 +753,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
                index = 1;
        }
        if (node < 0) {
-               debug("%s: Cannot find u-boot image node: %d\n",
+               pr_debug("%s: Cannot find u-boot image node: %d\n",
                      __func__, node);
                return -1;
        }
@@ -760,7 +768,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
         * as a U-Boot image, if no OS-type has been declared.
         */
        if (!spl_fit_image_get_os(ctx.fit, node, &spl_image->os))
-               debug("Image OS is %s\n", genimg_get_os_name(spl_image->os));
+               pr_debug("Image OS is %s\n", genimg_get_os_name(spl_image->os));
        else if (!IS_ENABLED(CONFIG_SPL_OS_BOOT))
                spl_image->os = IH_OS_U_BOOT;
 
@@ -794,7 +802,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
                image_info.load_addr = 0;
                ret = spl_load_fit_image(info, sector, &ctx, node, &image_info);
                if (ret < 0) {
-                       printf("%s: can't load image loadables index %d (ret = %d)\n",
+                       pr_debug("%s: can't load image loadables index %d (ret = %d)\n",
                               __func__, index, ret);
                        return ret;
                }
@@ -803,7 +811,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
                        spl_fit_upload_fpga(&ctx, node, &image_info);
 
                if (!spl_fit_image_get_os(ctx.fit, node, &os_type))
-                       debug("Loadable is %s\n", genimg_get_os_name(os_type));
+                       pr_debug("Loadable is %s\n", genimg_get_os_name(os_type));
 
                if (os_takes_devicetree(os_type)) {
                        spl_fit_append_fdt(&image_info, info, sector, &ctx);
index 23a395e63d4ef74d4a92655090a673c4a7150f4d..581958bb1e1a8c2b6ff47090e14aa4f76ecb51b3 100644 (file)
@@ -91,6 +91,7 @@ int mmc_load_image_raw_sector(struct spl_image_info *spl_image,
 
        /* read image header to find the image size & load address */
        count = blk_dread(bd, sector, 1, header);
+       printf("BPI:hdr read sector %lx, count=%lu\n", sector, count);
        debug("hdr read sector %lx, count=%lu\n", sector, count);
        if (count == 0) {
                ret = -EIO;
@@ -144,7 +145,7 @@ static int spl_mmc_get_device_index(u32 boot_device)
        }
 
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
-       printf("spl: unsupported mmc boot device.\n");
+       pr_debug("spl: unsupported mmc boot device.\n");
 #endif
 
        return -ENODEV;
@@ -165,7 +166,7 @@ static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device)
 #endif /* DM_MMC */
        if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
-               printf("spl: could not initialize mmc. error: %d\n", err);
+               pr_err("spl: could not initialize mmc. error: %d\n", err);
 #endif
                return err;
        }
@@ -173,7 +174,7 @@ static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device)
        err = *mmcp ? 0 : -ENODEV;
        if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
-               printf("spl: could not find mmc device %d. error: %d\n",
+               pr_err("spl: could not find mmc device %d. error: %d\n",
                       mmc_dev, err);
 #endif
                return err;
@@ -190,6 +191,7 @@ static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
 {
        struct disk_partition info;
        int err;
+       const char *part_name;
 
 #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE
        int type_part;
@@ -206,6 +208,49 @@ static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
        }
 #endif
 
+#ifdef CONFIG_SYS_LOAD_IMAGE_PARTITION_NAME
+       if (partition == CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION){
+               if (strlen(CONFIG_SYS_LOAD_IMAGE_PARTITION_NAME) > 0){
+                       part_name = CONFIG_SYS_LOAD_IMAGE_PARTITION_NAME;
+               }
+       }
+#endif
+
+#ifdef CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME
+       if (partition == CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_INDEX){
+               if (strlen(CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME) > 0){
+                       part_name = CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME;
+               }
+       }
+#endif
+       printf("BPI: partition=%d part_name[%s]\n",partition ,part_name);
+
+       for (int p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+               err = part_get_info(mmc_get_blk_desc(mmc), p, &info);
+               if (err) {
+#ifdef BPI
+#else
+                       if (!strcmp(part_name, "opensbi")){
+                               info.start = 0x500;
+                               strcpy(info.name,"opensbi");
+                       }
+                       else 
+                       if (!strcmp(part_name, "uboot")){
+                               info.start = 0x800;
+                               strcpy(info.name,"uboot");
+                       }
+                       else
+#endif
+                               continue;
+               }
+               printf("BPI: p=%d info.name=[%s] info.start[%lx]\n",p ,info.name,info.start);
+               if (!strcmp(part_name, info.name)){
+                       if (mmc_load_image_raw_sector(spl_image, bootdev, mmc, info.start) == 0)
+                               return 0;
+                       break;
+               }
+       }
+
        err = part_get_info(mmc_get_blk_desc(mmc), partition, &info);
        if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
@@ -217,6 +262,7 @@ static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
 #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
        return mmc_load_image_raw_sector(spl_image, bootdev, mmc, info.start + sector);
 #else
+       printf("BPI2: info.name=[%s] info.start[%lx]\n" ,info.name,info.start);
        return mmc_load_image_raw_sector(spl_image, bootdev, mmc, info.start);
 #endif
 }
@@ -297,7 +343,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image,
                                break;
                        }
                }
-               printf("Using first bootable partition: %d\n", partition);
+               pr_debug("Using first bootable partition: %d\n", partition);
                if (partition == CONFIG_SYS_MMCSD_FS_BOOT_PARTITION) {
                        return -ENOSYS;
                }
@@ -418,6 +464,7 @@ int spl_mmc_load(struct spl_image_info *spl_image,
        static struct mmc *mmc;
        u32 boot_mode;
        int err = 0;
+       __maybe_unused int load_others_res = -1;
        __maybe_unused int part = 0;
        int mmc_dev;
 
@@ -432,7 +479,7 @@ int spl_mmc_load(struct spl_image_info *spl_image,
                if (err) {
                        mmc = NULL;
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
-                       printf("spl: mmc init failed with error: %d\n", err);
+                       pr_err("spl: mmc init failed with error: %d\n", err);
 #endif
                        return err;
                }
@@ -468,11 +515,19 @@ int spl_mmc_load(struct spl_image_info *spl_image,
                raw_sect = spl_mmc_get_uboot_raw_sector(mmc, raw_sect);
 
 #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
+
+#ifdef CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION
+               /*load second */
+               load_others_res = mmc_load_image_raw_partition(spl_image, bootdev,
+                                                  mmc, CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_INDEX,
+                                                  raw_sect);
+
+#endif
                err = mmc_load_image_raw_partition(spl_image, bootdev,
                                                   mmc, raw_part,
                                                   raw_sect);
-               if (!err)
-                       return err;
+               if (!err || !load_others_res)
+                       return 0;
 #endif
 #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
                err = mmc_load_image_raw_sector(spl_image, bootdev, mmc,
@@ -484,9 +539,22 @@ int spl_mmc_load(struct spl_image_info *spl_image,
        case MMCSD_MODE_FS:
                debug("spl: mmc boot mode: fs\n");
 
+#ifdef CONFIG_SPL_FS_LOAD_OTHERS_FILES_NAME
+               pr_debug("load other itb file\n");
+               const char *other_filename = CONFIG_SPL_FS_LOAD_OTHERS_FILES_NAME;
+
+               /* if load other file file, it should not return fail directory, and
+                       try to load the normal bootfile.
+               */
+               load_others_res = spl_mmc_do_fs_boot(spl_image, bootdev, mmc, other_filename);
+               if (load_others_res){
+                       pr_debug("load other file fail, try to load the normal boot file\n");
+               }
+
+#endif
                err = spl_mmc_do_fs_boot(spl_image, bootdev, mmc, filename);
-               if (!err)
-                       return err;
+               if (!err || !load_others_res)
+                       return 0;
 
                break;
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
diff --git a/common/spl/spl_mtd.c b/common/spl/spl_mtd.c
new file mode 100644 (file)
index 0000000..07b8f50
--- /dev/null
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <mtd.h>
+#include <linux/err.h>
+#include <env.h>
+#include <mapmem.h>
+
+static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
+{
+       do_div(len, mtd->writesize);
+
+       return len;
+}
+
+static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
+{
+       return !do_div(size, mtd->writesize);
+}
+
+static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
+{
+       return !do_div(size, mtd->erasesize);
+}
+
+int spl_mtd_read(struct mtd_info *mtd, ulong sector, ulong count, void *buf)
+{
+       bool read, raw, woob, has_pages = false;
+       u64 start_off, off, len, remaining;
+       struct mtd_oob_ops io_op = {};
+       uint npages;
+       int ret = -1;
+
+       u8 *buffer = map_sysmem((u64)buf, 0);
+       if (!buffer)
+               return -1;
+
+       debug("sector:%lx, count:%lx, buffer:%lx\n", sector, count, (ulong)buffer);
+       start_off = sector;
+       if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
+               pr_debug("Offset not aligned with a page (0x%x)\n",
+                      mtd->writesize);
+               return ret;
+       }
+
+       len = count;
+       if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
+               len = round_up(len, mtd->writesize);
+               debug("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
+                      mtd->writesize, len);
+       }
+       if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
+               has_pages = true;
+
+       remaining = len;
+       npages = mtd_len_to_pages(mtd, len);
+
+       io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
+       io_op.len = has_pages ? mtd->writesize : len;
+       io_op.ooblen = woob ? mtd->oobsize : 0;
+       io_op.datbuf = buffer;
+       io_op.oobbuf = woob ? &buffer[len] : NULL;
+
+       /* Search for the first good block after the given offset */
+       off = start_off;
+       while (mtd_block_isbad(mtd, off))
+               off += mtd->erasesize;
+
+       /* Loop over the pages to do the actual read/write */
+       while (remaining) {
+               /* Skip the block if it is bad */
+               if (mtd_is_aligned_with_block_size(mtd, off) &&
+                   mtd_block_isbad(mtd, off)) {
+                       off += mtd->erasesize;
+                       continue;
+               }
+
+               ret = mtd_read_oob(mtd, off, &io_op);
+               if (ret) {
+                       pr_debug("Failure while %s at offset 0x%llx\n",
+                              read ? "reading" : "writing", off);
+                       break;
+               }
+
+               off += io_op.retlen;
+               remaining -= io_op.retlen;
+               io_op.datbuf += io_op.retlen;
+               io_op.oobbuf += io_op.oobretlen;
+       }
+       return ret;
+}
+
+
+static ulong spl_spi_load_read(struct spl_load_info *load, ulong sector,
+                              ulong count, void *buf)
+{
+       int ret;
+
+       debug("%s: sector %lx, count %lx, buf %lx\n",
+             __func__, sector, count, (ulong)buf);
+
+       struct mtd_info *mtd = load->dev;
+       debug("%s, get mtd:%p\n", __func__, mtd);
+       ret = spl_mtd_read(mtd, sector, count, buf);
+       if (!ret)
+               return count;
+       else
+               return 0;
+}
+
+
+static int mtd_load_image(struct spl_image_info *spl_image,
+                             struct spl_boot_device *bootdev, struct mtd_info *mtd)
+{
+       struct image_header *header;
+       ulong len;
+       int err = 0;
+       len = sizeof(*header);
+       if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
+               len = round_up(len, mtd->writesize);
+               pr_debug("Size not on a page boundary (0x%x), rounding to 0x%lx\n",
+                      mtd->writesize, len);
+       }
+
+       header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
+       err = spl_mtd_read(mtd, 0, len, (void *)header);
+       if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+           image_get_magic(header) == FDT_MAGIC) {
+               struct spl_load_info load;
+
+               debug("Found FIT\n");
+               load.dev = mtd;
+               load.priv = NULL;
+               load.filename = NULL;
+               load.bl_len = 1;
+               load.read = spl_spi_load_read;
+               err = spl_load_simple_fit(spl_image, &load, 0, header);
+       } else {
+               debug("unsupport Legacy image\n");
+               return -1;
+       }
+
+       return err;
+}
+
+
+static int spl_spi_load_image(struct spl_image_info *spl_image,
+                             struct spl_boot_device *bootdev)
+{
+       struct mtd_info *mtd;
+       int err = 0;
+       __maybe_unused int load_others_res = -1;
+
+       mtd_probe_devices();
+
+#ifdef CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME
+       mtd = get_mtd_device_nm(CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME);
+       if (IS_ERR_OR_NULL(mtd)){
+               debug("MTD device %s not found\n", CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME);
+               return -1;
+       }
+       load_others_res = mtd_load_image(spl_image, bootdev, mtd);
+#endif
+
+       mtd = get_mtd_device_nm(CONFIG_SYS_LOAD_IMAGE_PARTITION_NAME);
+       if (IS_ERR_OR_NULL(mtd)){
+               debug("MTD device %s not found\n", CONFIG_SYS_LOAD_IMAGE_PARTITION_NAME);
+               return -1;
+       }
+       err = mtd_load_image(spl_image, bootdev, mtd);
+
+       if (!err || !load_others_res)
+               return 0;
+       else
+               return -1;
+}
+
+/* Use priorty 1 so that boards can override this */
+SPL_LOAD_IMAGE_METHOD("MTD-NOR", 0, BOOT_DEVICE_NOR, spl_spi_load_image);
+SPL_LOAD_IMAGE_METHOD("MTD-NAND", 0, BOOT_DEVICE_NAND, spl_spi_load_image);
index b0f40076c34533bdfa18bc2ae95cc9aead7ce6b4..a6040eb8e9a9bafcf9eaa1b4614ef62530752271 100644 (file)
@@ -57,8 +57,12 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image)
        /* Find U-Boot image in /fit-images */
        ret = spl_opensbi_find_uboot_node(spl_image->fdt_addr, &uboot_node);
        if (ret) {
-               pr_err("Can't find U-Boot node, %d\n", ret);
+               debug("Can't find U-Boot node, %d\n", ret);
+#ifdef CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION
+               debug("had defined another file to load, maybe the uboot node set in it\n");
+#else
                hang();
+#endif
        }
 
        /* Get U-Boot entry point */
@@ -66,6 +70,10 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image)
        if (ret)
                ret = fit_image_get_load(spl_image->fdt_addr, uboot_node, &uboot_entry);
 
+#ifdef CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION
+       /*if load other image, uboot_entry maybe not true, set to TEXT_BASE directory*/
+       uboot_entry = CONFIG_SYS_TEXT_BASE;
+#endif
        /* Prepare opensbi_info object */
        opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
        opensbi_info.version = FW_DYNAMIC_INFO_VERSION;
index d64710878cf25620f7c6350673e0e56c70dc8c5d..c046c617c3592b8e0ae2a88768adb50b3acbcf13 100644 (file)
@@ -94,6 +94,7 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
 
        return 0;
 }
+
 #if CONFIG_IS_ENABLED(RAM_DEVICE)
 SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
 #endif
index 0e520cc1030df205baf7af50d19c1e2e6fcef43c..d91779519ee30cb624d2fdfc3a029ffe5b4c4cf7 100644 (file)
@@ -57,7 +57,7 @@ static struct splash_location default_splash_locations[] = {
 
 #include <bmp_logo_data.h>
 
-static int splash_video_logo_load(void)
+int splash_video_logo_load(void)
 {
        char *splashimage;
        ulong bmp_load_addr;
@@ -78,7 +78,7 @@ static int splash_video_logo_load(void)
        return 0;
 }
 #else
-static inline int splash_video_logo_load(void) { return -ENOSYS; }
+inline int splash_video_logo_load(void) { return -ENOSYS; }
 #endif
 
 __weak int splash_screen_prepare(void)
index 2c03cbdf928b30ba35f806a0f17239394542d029..95fc2ed87191bb9449ec03ea25bf5dc9d29a4a19 100644 (file)
@@ -22,6 +22,7 @@
 #include <usb.h>
 #include <virtio.h>
 #include <asm/global_data.h>
+#include <stdint.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -127,6 +128,9 @@ static int splash_select_fs_dev(struct splash_location *location)
        case SPLASH_STORAGE_SATA:
                res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
                break;
+       case SPLASH_STORAGE_NVME:
+               res = fs_set_blk_dev("nvme", location->devpart, FS_TYPE_ANY);
+               break;
        case SPLASH_STORAGE_NAND:
                if (location->ubivol != NULL)
                        res = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
@@ -201,7 +205,7 @@ static int splash_mount_ubifs(struct splash_location *location)
        if (res)
                return res;
 
-       sprintf(cmd, "ubifsmount %s", location->ubivol);
+       sprintf(cmd, "ubifsmount ubi0:%s", location->ubivol);
        res = run_command(cmd, 0);
 
        return res;
@@ -263,6 +267,10 @@ static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr)
                goto out;
        }
 
+       res = splash_select_fs_dev(location);
+       if (res)
+               goto out;
+
        if (bmp_load_addr + bmp_size >= gd->start_addr_sp) {
                printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
                res = -EFAULT;
@@ -337,7 +345,7 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
        if (res < 0)
                return res;
 
-       img_header = (struct image_header *)bmp_load_addr;
+       img_header = (struct image_header *)(uintptr_t)bmp_load_addr;
        if (image_get_magic(img_header) != FDT_MAGIC) {
                printf("Could not find FDT magic\n");
                return -EINVAL;
@@ -347,7 +355,7 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
 
        /* Read in entire FIT */
        fit_header = (const u32 *)(bmp_load_addr + header_size);
-       res = splash_storage_read_raw(location, (u32)fit_header, fit_size);
+       res = splash_storage_read_raw(location, (uintptr_t)fit_header, fit_size);
        if (res < 0)
                return res;
 
@@ -372,7 +380,7 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
        /* Extract the splash data from FIT */
        /* 1. Test if splash is in FIT internal data. */
        if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, &internal_splash_size))
-               memmove((void *)bmp_load_addr, internal_splash_data, internal_splash_size);
+               memmove((void *)(uintptr_t)bmp_load_addr, internal_splash_data, internal_splash_size);
        /* 2. Test if splash is in FIT external data with fixed position. */
        else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr))
                is_splash_external = true;
index 6fcf1e8428e95524979331d58d7ad3c718cea27a..2bb0f8db8a025feae21142ee357fdbaa9c57c054 100644 (file)
@@ -73,7 +73,7 @@ int usb_init(void)
        /* init low_level USB */
        for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
                /* init low_level USB */
-               printf("USB%d:   ", i);
+               pr_debug("USB%d:   ", i);
                ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl);
                if (ret == -ENODEV) {   /* No such device. */
                        puts("Port not available.\n");
@@ -91,7 +91,7 @@ int usb_init(void)
                 */
                controllers_initialized++;
                start_index = dev_index;
-               printf("scanning bus %d for devices... ", i);
+               pr_debug("scanning bus %d for devices... ", i);
                ret = usb_alloc_new_device(ctrl, &dev);
                if (ret)
                        break;
@@ -108,7 +108,7 @@ int usb_init(void)
                        puts("No USB Device found\n");
                        continue;
                } else {
-                       printf("%d USB Device(s) found\n",
+                       pr_debug("%d USB Device(s) found\n",
                                dev_index - start_index);
                }
 
@@ -136,8 +136,9 @@ int usb_stop(void)
                usb_hub_reset();
 
                for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
-                       if (usb_lowlevel_stop(i))
-                               printf("failed to stop USB controller %d\n", i);
+                       if (usb_lowlevel_stop(i)){
+                               pr_err("failed to stop USB controller %d\n", i);
+                       }
                }
        }
 
@@ -390,12 +391,12 @@ static int usb_parse_config(struct usb_device *dev,
        dev->configno = cfgno;
        head = (struct usb_descriptor_header *) &buffer[0];
        if (head->bDescriptorType != USB_DT_CONFIG) {
-               printf(" ERROR: NOT USB_CONFIG_DESC %x\n",
+               pr_err(" ERROR: NOT USB_CONFIG_DESC %x\n",
                        head->bDescriptorType);
                return -EINVAL;
        }
        if (head->bLength != USB_DT_CONFIG_SIZE) {
-               printf("ERROR: Invalid USB CFG length (%d)\n", head->bLength);
+               pr_err("ERROR: Invalid USB CFG length (%d)\n", head->bLength);
                return -EINVAL;
        }
        memcpy(&dev->config, head, USB_DT_CONFIG_SIZE);
@@ -409,7 +410,7 @@ static int usb_parse_config(struct usb_device *dev,
                switch (head->bDescriptorType) {
                case USB_DT_INTERFACE:
                        if (head->bLength != USB_DT_INTERFACE_SIZE) {
-                               printf("ERROR: Invalid USB IF length (%d)\n",
+                               pr_err("ERROR: Invalid USB IF length (%d)\n",
                                        head->bLength);
                                break;
                        }
@@ -446,7 +447,7 @@ static int usb_parse_config(struct usb_device *dev,
                case USB_DT_ENDPOINT:
                        if (head->bLength != USB_DT_ENDPOINT_SIZE &&
                            head->bLength != USB_DT_ENDPOINT_AUDIO_SIZE) {
-                               printf("ERROR: Invalid USB EP length (%d)\n",
+                               pr_err("ERROR: Invalid USB EP length (%d)\n",
                                        head->bLength);
                                break;
                        }
@@ -462,7 +463,7 @@ static int usb_parse_config(struct usb_device *dev,
                        epno = dev->config.if_desc[ifno].no_of_ep;
                        if_desc = &dev->config.if_desc[ifno];
                        if (epno >= USB_MAXENDPOINTS) {
-                               printf("Interface %d has too many endpoints!\n",
+                               pr_debug("Interface %d has too many endpoints!\n",
                                        if_desc->desc.bInterfaceNumber);
                                return -EINVAL;
                        }
@@ -483,7 +484,7 @@ static int usb_parse_config(struct usb_device *dev,
                        break;
                case USB_DT_SS_ENDPOINT_COMP:
                        if (head->bLength != USB_DT_SS_EP_COMP_SIZE) {
-                               printf("ERROR: Invalid USB EPC length (%d)\n",
+                               pr_err("ERROR: Invalid USB EPC length (%d)\n",
                                        head->bLength);
                                break;
                        }
@@ -580,12 +581,13 @@ int usb_get_configuration_len(struct usb_device *dev, int cfgno)
        config = (struct usb_config_descriptor *)&buffer[0];
        result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9);
        if (result < 9) {
-               if (result < 0)
-                       printf("unable to get descriptor, error %lX\n",
+               if (result < 0){
+                       pr_err("unable to get descriptor, error %lX\n",
                                dev->status);
-               else
-                       printf("config descriptor too short " \
+               }else{
+                       pr_debug("config descriptor too short " \
                                "(expected %i, got %i)\n", 9, result);
+               }
                return -EIO;
        }
        return le16_to_cpu(config->wTotalLength);
@@ -636,7 +638,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
                }
        }
        if (!if_face) {
-               printf("selecting invalid interface %d", interface);
+               pr_err("selecting invalid interface %d", interface);
                return -EINVAL;
        }
        /*
@@ -875,7 +877,7 @@ int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp)
        int i;
        debug("New Device %d\n", dev_index);
        if (dev_index == USB_MAX_DEVICE) {
-               printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
+               pr_err("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
                return -ENOSPC;
        }
        /* default Address is 0, real addresses start with 1 */
@@ -935,11 +937,11 @@ static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
        err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, len);
        if (err < expect_len) {
                if (err < 0) {
-                       printf("unable to get device descriptor (error=%d)\n",
+                       pr_err("unable to get device descriptor (error=%d)\n",
                                err);
                        return err;
                } else {
-                       printf("USB device descriptor short read (expected %i, got %i)\n",
+                       pr_debug("USB device descriptor short read (expected %i, got %i)\n",
                                expect_len, err);
                        return -EIO;
                }
@@ -1017,7 +1019,7 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
                dev->maxpacketsize = PACKET_SIZE_64;
                break;
        default:
-               printf("%s: invalid max packet size\n", __func__);
+               pr_err("%s: invalid max packet size\n", __func__);
                return -EIO;
        }
 
@@ -1037,7 +1039,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
         */
        err = usb_alloc_device(dev);
        if (err) {
-               printf("Cannot allocate device context to get SLOT_ID\n");
+               pr_err("Cannot allocate device context to get SLOT_ID\n");
                return err;
        }
        err = usb_setup_descriptor(dev, do_read);
@@ -1052,7 +1054,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
        err = usb_set_address(dev); /* set address */
 
        if (err < 0) {
-               printf("\n      USB device not accepting new address " \
+               pr_err("\n      USB device not accepting new address " \
                        "(error=%lX)\n", dev->status);
                return err;
        }
@@ -1106,7 +1108,7 @@ int usb_select_config(struct usb_device *dev)
                        err = usb_get_configuration_no(dev, 0, tmpbuf, err);
        }
        if (err < 0) {
-               printf("usb_new_device: Cannot read configuration, " \
+               pr_err("usb_new_device: Cannot read configuration, " \
                       "skipping device %04x:%04x\n",
                       dev->descriptor.idVendor, dev->descriptor.idProduct);
                free(tmpbuf);
@@ -1122,7 +1124,7 @@ int usb_select_config(struct usb_device *dev)
         */
        err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue);
        if (err < 0) {
-               printf("failed to set default configuration " \
+               pr_err("failed to set default configuration " \
                        "len %d, status %lX\n", dev->act_len, dev->status);
                return err;
        }
@@ -1252,7 +1254,7 @@ void usb_find_usb2_hub_address_port(struct usb_device *udev,
                struct udevice *dev = parent;
 
                if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
-                       printf("Error: Cannot find high speed parent of usb-1 device\n");
+                       pr_err("Error: Cannot find high speed parent of usb-1 device\n");
                        *hub_address = 0;
                        *hub_port = 0;
                        return;
@@ -1279,7 +1281,7 @@ void usb_find_usb2_hub_address_port(struct usb_device *udev,
                        return;
                }
 
-       printf("Error: Cannot find high speed parent of usb-1 device\n");
+       pr_err("Error: Cannot find high speed parent of usb-1 device\n");
        *hub_address = 0;
        *hub_port = 0;
 }
diff --git a/configs/k1-x_fpga_1x4_defconfig b/configs/k1-x_fpga_1x4_defconfig
new file mode 100644 (file)
index 0000000..02b9b90
--- /dev/null
@@ -0,0 +1,134 @@
+CONFIG_RISCV=y
+CONFIG_SYS_TEXT_BASE=0x00200000
+CONFIG_SYS_MALLOC_LEN=0x800000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x80000
+CONFIG_DEFAULT_DEVICE_TREE="k1-x_fpga_1x4"
+CONFIG_SPL_TEXT_BASE=0xC0801000
+CONFIG_SPL_MMC=y
+CONFIG_SPL_SIZE_LIMIT=0x30000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x200000
+# CONFIG_AHCI is not set
+CONFIG_TARGET_SPACEMIT_K1X=y
+CONFIG_SPL_OPENSBI_LOAD_ADDR=0x0
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+CONFIG_LOCALVERSION="spacemit"
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x1000000
+CONFIG_STACK_SIZE=0x100000
+CONFIG_FIT=y
+# CONFIG_FIT_FULL_CHECK is not set
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x40000000
+# CONFIG_BOOTSTD is not set
+# CONFIG_LEGACY_IMAGE_FORMAT is not set
+CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_BOOTDELAY=0
+CONFIG_AUTOBOOT_KEYED=y
+CONFIG_AUTOBOOT_STOP_STR="s"
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="bootm 0x50000000"
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_SPL_MAX_SIZE=0x30000
+CONFIG_SPL_PAD_TO=0x0
+CONFIG_SPL_BSS_START_ADDR=0xC0830000
+CONFIG_SPL_BSS_MAX_SIZE=0x8000
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_STACK=0xc0840000
+CONFIG_SYS_SPL_MALLOC=y
+CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y
+CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x4000000
+CONFIG_SYS_SPL_MALLOC_SIZE=0x2000000
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_NAME="opensbi"
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION_INDEX=0x2
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION_NAME="uboot"
+CONFIG_SPL_ENV_SUPPORT=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_FASTBOOT_LOAD=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_CBSIZE=256
+CONFIG_SYS_PBSIZE=276
+# CONFIG_CMD_CPU is not set
+CONFIG_SYS_BOOTM_LEN=0xa000000
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_BKOPS_ENABLE=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_PART=y
+# CONFIG_CMD_SCSI is not set
+CONFIG_CMD_DHCP=y
+CONFIG_SYS_DISABLE_AUTOLOAD=y
+CONFIG_CMD_PXE=y
+CONFIG_CMD_SYSBOOT=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_MTDPARTS_SPREAD=y
+CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi-nor"
+CONFIG_MTDPARTS_DEFAULT="spi-nor:448K(reserve),2M(uboot)"
+CONFIG_SPACEMIT_FLASH=y
+CONFIG_SPL_FASTBOOT=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_IS_NOWHERE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_MMC_ENV_DEV=1
+# CONFIG_SPL_ENV_IS_NOWHERE is not set
+CONFIG_PROT_UDP=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_IP_DEFRAG=y
+CONFIG_KEEP_SERVERADDR=y
+CONFIG_BOOTP_SERVERIP=y
+CONFIG_DEVRES=y
+# CONFIG_SCSI_AHCI is not set
+# CONFIG_CLK is not set
+CONFIG_DMA=y
+CONFIG_DMA_CHANNELS=y
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x40000000
+CONFIG_FASTBOOT_BUF_SIZE=0x10000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=1
+CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
+CONFIG_FASTBOOT_MMC_BOOT1_NAME="fsbl"
+CONFIG_FASTBOOT_MMC_BOOT2_NAME="fsbl_1"
+# CONFIG_GPIO is not set
+# CONFIG_I2C is not set
+# CONFIG_INPUT is not set
+CONFIG_MISC=y
+CONFIG_MMC=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ADMA=y
+CONFIG_MMC_SDHCI_K1X=y
+CONFIG_DM_MTD=y
+# CONFIG_MTD_NOR_FLASH is not set
+CONFIG_SPACEMIT_K1X_EMAC=y
+CONFIG_NVME_PCI=y
+CONFIG_PCIE_DW_K1X=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_RESET_SPACEMIT_K1X=y
+# CONFIG_SCSI is not set
+# CONFIG_DM_SCSI is not set
+CONFIG_SYS_NS16550_IER=0x40
+# CONFIG_HTIF_CONSOLE is not set
+# CONFIG_SIFIVE_SERIAL is not set
+CONFIG_TIMER_EARLY=y
+CONFIG_USB=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VENDOR_NUM=0x361C
+CONFIG_USB_GADGET_PRODUCT_NUM=0x1001
+CONFIG_USB2_K1X_CI=y
+# CONFIG_BINMAN_FDT is not set
+# CONFIG_SPL_USE_TINY_PRINTF is not set
diff --git a/configs/k1-x_fpga_2x2_defconfig b/configs/k1-x_fpga_2x2_defconfig
new file mode 100644 (file)
index 0000000..7d6e258
--- /dev/null
@@ -0,0 +1,134 @@
+CONFIG_RISCV=y
+CONFIG_SYS_TEXT_BASE=0x00200000
+CONFIG_SYS_MALLOC_LEN=0x800000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x80000
+CONFIG_DEFAULT_DEVICE_TREE="k1-x_fpga_2x2"
+CONFIG_SPL_TEXT_BASE=0xC0801000
+CONFIG_SPL_MMC=y
+CONFIG_SPL_SIZE_LIMIT=0x30000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x200000
+# CONFIG_AHCI is not set
+CONFIG_TARGET_SPACEMIT_K1X=y
+CONFIG_SPL_OPENSBI_LOAD_ADDR=0x0
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+CONFIG_LOCALVERSION="spacemit"
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x1000000
+CONFIG_STACK_SIZE=0x100000
+CONFIG_FIT=y
+# CONFIG_FIT_FULL_CHECK is not set
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x40000000
+# CONFIG_BOOTSTD is not set
+# CONFIG_LEGACY_IMAGE_FORMAT is not set
+CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_BOOTDELAY=0
+CONFIG_AUTOBOOT_KEYED=y
+CONFIG_AUTOBOOT_STOP_STR="s"
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="bootm 0x50000000"
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_SPL_MAX_SIZE=0x30000
+CONFIG_SPL_PAD_TO=0x0
+CONFIG_SPL_BSS_START_ADDR=0xC0830000
+CONFIG_SPL_BSS_MAX_SIZE=0x8000
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_STACK=0xc0840000
+CONFIG_SYS_SPL_MALLOC=y
+CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y
+CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x4000000
+CONFIG_SYS_SPL_MALLOC_SIZE=0x2000000
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_NAME="opensbi"
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION_INDEX=0x2
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION_NAME="uboot"
+CONFIG_SPL_ENV_SUPPORT=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_FASTBOOT_LOAD=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_CBSIZE=256
+CONFIG_SYS_PBSIZE=276
+# CONFIG_CMD_CPU is not set
+CONFIG_SYS_BOOTM_LEN=0xa000000
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_BKOPS_ENABLE=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_PART=y
+# CONFIG_CMD_SCSI is not set
+CONFIG_CMD_DHCP=y
+CONFIG_SYS_DISABLE_AUTOLOAD=y
+CONFIG_CMD_PXE=y
+CONFIG_CMD_SYSBOOT=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_MTDPARTS_SPREAD=y
+CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi-nor"
+CONFIG_MTDPARTS_DEFAULT="spi-nor:448K(reserve),2M(uboot)"
+CONFIG_SPACEMIT_FLASH=y
+CONFIG_SPL_FASTBOOT=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_IS_NOWHERE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_MMC_ENV_DEV=1
+# CONFIG_SPL_ENV_IS_NOWHERE is not set
+CONFIG_PROT_UDP=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_IP_DEFRAG=y
+CONFIG_KEEP_SERVERADDR=y
+CONFIG_BOOTP_SERVERIP=y
+CONFIG_DEVRES=y
+# CONFIG_SCSI_AHCI is not set
+# CONFIG_CLK is not set
+CONFIG_DMA=y
+CONFIG_DMA_CHANNELS=y
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x40000000
+CONFIG_FASTBOOT_BUF_SIZE=0x10000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=1
+CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
+CONFIG_FASTBOOT_MMC_BOOT1_NAME="fsbl"
+CONFIG_FASTBOOT_MMC_BOOT2_NAME="fsbl_1"
+# CONFIG_GPIO is not set
+# CONFIG_I2C is not set
+# CONFIG_INPUT is not set
+CONFIG_MISC=y
+CONFIG_MMC=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ADMA=y
+CONFIG_MMC_SDHCI_K1X=y
+CONFIG_DM_MTD=y
+# CONFIG_MTD_NOR_FLASH is not set
+CONFIG_SPACEMIT_K1X_EMAC=y
+CONFIG_NVME_PCI=y
+CONFIG_PCIE_DW_K1X=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_RESET_SPACEMIT_K1X=y
+# CONFIG_SCSI is not set
+# CONFIG_DM_SCSI is not set
+CONFIG_SYS_NS16550_IER=0x40
+# CONFIG_HTIF_CONSOLE is not set
+# CONFIG_SIFIVE_SERIAL is not set
+CONFIG_TIMER_EARLY=y
+CONFIG_USB=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VENDOR_NUM=0x361C
+CONFIG_USB_GADGET_PRODUCT_NUM=0x1001
+CONFIG_USB2_K1X_CI=y
+# CONFIG_BINMAN_FDT is not set
+# CONFIG_SPL_USE_TINY_PRINTF is not set
diff --git a/configs/k1-x_fpga_defconfig b/configs/k1-x_fpga_defconfig
new file mode 100644 (file)
index 0000000..7d6a11e
--- /dev/null
@@ -0,0 +1,137 @@
+CONFIG_RISCV=y
+CONFIG_SYS_TEXT_BASE=0x00200000
+CONFIG_SYS_MALLOC_LEN=0x800000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x80000
+CONFIG_DEFAULT_DEVICE_TREE="k1-x_fpga"
+CONFIG_SPL_TEXT_BASE=0xC0801000
+CONFIG_SPL_MMC=y
+CONFIG_SPL_SIZE_LIMIT=0x30000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x200000
+# CONFIG_AHCI is not set
+CONFIG_TARGET_SPACEMIT_K1X=y
+CONFIG_SPL_OPENSBI_LOAD_ADDR=0x0
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+CONFIG_LOCALVERSION="spacemit"
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x1000000
+CONFIG_STACK_SIZE=0x100000
+CONFIG_FIT=y
+# CONFIG_FIT_FULL_CHECK is not set
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x40000000
+# CONFIG_BOOTSTD is not set
+# CONFIG_LEGACY_IMAGE_FORMAT is not set
+CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_BOOTDELAY=0
+CONFIG_AUTOBOOT_KEYED=y
+CONFIG_AUTOBOOT_STOP_STR="s"
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="bootm 0x50000000"
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_SPL_MAX_SIZE=0x30000
+CONFIG_SPL_PAD_TO=0x0
+CONFIG_SPL_BSS_START_ADDR=0xC0830000
+CONFIG_SPL_BSS_MAX_SIZE=0x8000
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_STACK=0xc0840000
+CONFIG_SYS_SPL_MALLOC=y
+CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y
+CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x4000000
+CONFIG_SYS_SPL_MALLOC_SIZE=0x2000000
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_NAME="opensbi"
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION_INDEX=0x2
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SEC_PARTITION_NAME="uboot"
+CONFIG_SPL_ENV_SUPPORT=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_FASTBOOT_LOAD=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_CBSIZE=256
+CONFIG_SYS_PBSIZE=276
+# CONFIG_CMD_CPU is not set
+CONFIG_SYS_BOOTM_LEN=0xa000000
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_BKOPS_ENABLE=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_PART=y
+# CONFIG_CMD_SCSI is not set
+CONFIG_CMD_DHCP=y
+CONFIG_SYS_DISABLE_AUTOLOAD=y
+CONFIG_CMD_PXE=y
+CONFIG_CMD_SYSBOOT=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_MTDPARTS_SPREAD=y
+CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi-nor"
+CONFIG_MTDPARTS_DEFAULT="spi-nor:448K(reserve),2M(uboot)"
+CONFIG_SPACEMIT_FLASH=y
+CONFIG_SPL_FASTBOOT=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_IS_NOWHERE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_MMC_ENV_DEV=1
+# CONFIG_SPL_ENV_IS_NOWHERE is not set
+CONFIG_PROT_UDP=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_IP_DEFRAG=y
+CONFIG_KEEP_SERVERADDR=y
+CONFIG_BOOTP_SERVERIP=y
+CONFIG_DEVRES=y
+# CONFIG_SCSI_AHCI is not set
+CONFIG_SPACEMIT_K1X_CCU=y
+CONFIG_DMA=y
+CONFIG_DMA_CHANNELS=y
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x40000000
+CONFIG_FASTBOOT_BUF_SIZE=0x10000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=1
+CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
+CONFIG_FASTBOOT_MMC_BOOT1_NAME="fsbl"
+CONFIG_FASTBOOT_MMC_BOOT2_NAME="fsbl_1"
+# CONFIG_GPIO is not set
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_SPACEMIT=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+# CONFIG_INPUT is not set
+CONFIG_MISC=y
+CONFIG_MMC=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ADMA=y
+CONFIG_MMC_SDHCI_K1X=y
+CONFIG_DM_MTD=y
+# CONFIG_MTD_NOR_FLASH is not set
+CONFIG_SPACEMIT_K1X_EMAC=y
+CONFIG_NVME_PCI=y
+CONFIG_PCIE_DW_K1X=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_RESET_SPACEMIT_K1X=y
+# CONFIG_SCSI is not set
+# CONFIG_DM_SCSI is not set
+CONFIG_SYS_NS16550_IER=0x40
+# CONFIG_HTIF_CONSOLE is not set
+# CONFIG_SIFIVE_SERIAL is not set
+CONFIG_TIMER_EARLY=y
+CONFIG_USB=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VENDOR_NUM=0x361C
+CONFIG_USB_GADGET_PRODUCT_NUM=0x1001
+CONFIG_USB2_K1X_CI=y
+# CONFIG_BINMAN_FDT is not set
+# CONFIG_SPL_USE_TINY_PRINTF is not set
diff --git a/configs/k1_defconfig b/configs/k1_defconfig
new file mode 100644 (file)
index 0000000..67b5b58
--- /dev/null
@@ -0,0 +1,257 @@
+CONFIG_RISCV=y
+CONFIG_SYS_TEXT_BASE=0x00200000
+CONFIG_SYS_MALLOC_LEN=0x1000000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x60000
+CONFIG_DM_GPIO=y
+CONFIG_SPL_DM_SPI=y
+CONFIG_DEFAULT_DEVICE_TREE="k1-x_spl"
+CONFIG_SPL_TEXT_BASE=0xC0801000
+CONFIG_SPL_MMC=y
+CONFIG_SPL_DRIVERS_MISC=y
+CONFIG_SPL_SIZE_LIMIT=0x31000
+CONFIG_SPL=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI=y
+CONFIG_SYS_LOAD_ADDR=0x200000
+# CONFIG_AHCI is not set
+CONFIG_TARGET_SPACEMIT_K1X=y
+CONFIG_SPL_OPENSBI_LOAD_ADDR=0x0
+CONFIG_K1_X_BOARD_ASIC=y
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+# CONFIG_SPL_SMP is not set
+CONFIG_LOCALVERSION="spacemit"
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x1000000
+CONFIG_STACK_SIZE=0x100000
+CONFIG_FIT=y
+CONFIG_SPL_FIT_SIGNATURE=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x20000000
+# CONFIG_BOOTSTD is not set
+CONFIG_LEGACY_IMAGE_FORMAT=y
+CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_BOOTDELAY=1
+CONFIG_AUTOBOOT_KEYED=y
+CONFIG_AUTOBOOT_PROMPT="Autoboot in %d seconds, press <Space> to stop\n"
+CONFIG_AUTOBOOT_DELAY_STR=""
+CONFIG_AUTOBOOT_STOP_STR=" "
+CONFIG_AUTOBOOT_KEYED_CTRLC=y
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="bootm 0x20000000"
+CONFIG_LOGLEVEL=7
+CONFIG_SPL_LOGLEVEL=1
+# CONFIG_SYS_DEVICE_NULLDEV is not set
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_MISC_INIT_R=y
+CONFIG_SPL_MAX_SIZE=0x33000
+CONFIG_SPL_PAD_TO=0x0
+CONFIG_SPL_BSS_START_ADDR=0xC0837000
+CONFIG_SPL_BSS_MAX_SIZE=0x2000
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_STACK=0xC0840000
+CONFIG_SYS_SPL_MALLOC=y
+CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y
+CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x4000000
+CONFIG_SYS_SPL_MALLOC_SIZE=0x2000000
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
+CONFIG_SPL_ENV_SUPPORT=y
+CONFIG_SPL_I2C=y
+CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_DM_SPI_FLASH=y
+CONFIG_SPL_DM_RESET=y
+CONFIG_SPL_POWER=y
+# CONFIG_SPL_RAM_SUPPORT is not set
+# CONFIG_SPL_SPI_FLASH_TINY is not set
+CONFIG_SPL_SPI_FLASH_MTD=y
+CONFIG_SPL_MTD_LOAD=y
+CONFIG_SYS_LOAD_IMAGE_PARTITION_NAME="opensbi"
+CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION=y
+CONFIG_SYS_LOAD_IMAGE_SEC_PARTITION_NAME="uboot"
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_FASTBOOT_LOAD=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_CBSIZE=256
+CONFIG_SYS_PBSIZE=276
+# CONFIG_CMD_CPU is not set
+CONFIG_CMD_TLV_EEPROM=y
+CONFIG_SYS_BOOTM_LEN=0xa000000
+CONFIG_CMD_EEPROM=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPIO_READ=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_BKOPS_ENABLE=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_PART=y
+# CONFIG_CMD_SCSI is not set
+CONFIG_CMD_USB=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_TFTPSRV=y
+CONFIG_SYS_DISABLE_AUTOLOAD=y
+CONFIG_CMD_PXE=y
+CONFIG_CMD_BMP=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_GETTIME=y
+CONFIG_CMD_TIMER=y
+CONFIG_CMD_SYSBOOT=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_SQUASHFS=y
+CONFIG_CMD_JFFS2=y
+CONFIG_JFFS2_MTDPARTS=y
+CONFIG_JFFS2_PART_OFFSET=0x700000
+CONFIG_JFFS2_PART_SIZE=0x100000
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_MTDPARTS_SPREAD=y
+CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi-nor"
+CONFIG_MTDPARTS_DEFAULT="spi-nor:64K@0(bootinfo),64K@64K(private),256K@128K(fsbl),64K@384K(env),192K@448K(opensbi),-@640K(uboot)"
+CONFIG_CMD_UBI=y
+CONFIG_SPACEMIT_FLASH=y
+CONFIG_SPL_FASTBOOT=y
+CONFIG_ENABLE_SET_NUM_PART_SEARCH=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_MULTI_DTB_FIT=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_NOWHERE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_SYS_MMC_ENV_DEV=1
+# CONFIG_SPL_ENV_IS_NOWHERE is not set
+CONFIG_PROT_UDP=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_IP_DEFRAG=y
+CONFIG_KEEP_SERVERADDR=y
+CONFIG_BOOTP_SERVERIP=y
+CONFIG_REGMAP=y
+CONFIG_DEVRES=y
+# CONFIG_SCSI_AHCI is not set
+CONFIG_SPL_CLK=y
+CONFIG_SPL_CLK_CCF=y
+CONFIG_SPACEMIT_K1X_CCU=y
+CONFIG_DYNAMIC_DDR_CLK_FREQ=y
+CONFIG_DMA=y
+CONFIG_DMA_CHANNELS=y
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x20000000
+CONFIG_FASTBOOT_BUF_SIZE=0x8000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_MULTI_FLASH_OPTION=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=2
+CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
+CONFIG_FASTBOOT_MMC_BOOT1_NAME="fsbl"
+CONFIG_FASTBOOT_MMC_BOOT2_NAME="fsbl_1"
+CONFIG_FASTBOOT_CMD_OEM_READ=y
+CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV=y
+CONFIG_FASTBOOT_CMD_OEM_CONFIG_ACCESS=y
+CONFIG_FASTBOOT_CMD_OEM_ENV_ACCESS=y
+CONFIG_SPL_FASTBOOT_CMD_OEM_ENV_ACCESS=y
+CONFIG_K1X_GPIO=y
+CONFIG_DM_I2C=y
+# CONFIG_SPL_DM_I2C is not set
+CONFIG_SPL_SYS_I2C_LEGACY=y
+CONFIG_SYS_I2C_SPACEMIT=y
+CONFIG_SPL_SYS_I2C_SPACEMIT=y
+CONFIG_I2C_MUX=y
+# CONFIG_INPUT is not set
+CONFIG_MISC=y
+CONFIG_I2C_EEPROM=y
+CONFIG_SPACEMIT_K1X_EFUSE=y
+CONFIG_SPL_SPACEMIT_K1X_EFUSE=y
+CONFIG_MMC=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_HS400_ES_SUPPORT=y
+CONFIG_SPL_MMC_HS400_ES_SUPPORT=y
+CONFIG_MMC_HS400_SUPPORT=y
+CONFIG_SPL_MMC_HS400_SUPPORT=y
+# CONFIG_MMC_VERBOSE is not set
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ADMA=y
+CONFIG_SPL_MMC_SDHCI_ADMA=y
+CONFIG_MMC_SDHCI_K1X=y
+CONFIG_DM_MTD=y
+# CONFIG_MTD_NOR_FLASH is not set
+CONFIG_MTD_SPI_NAND=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_FM=y
+CONFIG_SPINOR_BLOCK_SUPPORT=y
+# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_REALTEK=y
+CONFIG_SPACEMIT_K1X_EMAC=y
+CONFIG_NVME_PCI=y
+CONFIG_PCIE_DW_K1X=y
+CONFIG_PHY=y
+CONFIG_PHY_SPACEMIT_K1X_USB2=y
+CONFIG_PHY_SPACEMIT_K1X_COMBPHY=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_K1X_POWER_DOMAIN=y
+CONFIG_DM_PMIC=y
+# CONFIG_SPL_DM_PMIC is not set
+CONFIG_PMIC_SPM8XX=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_SPM8XX=y
+CONFIG_SPL_SPACEMIT_POWER=y
+CONFIG_RESET_SPACEMIT_K1X=y
+# CONFIG_SCSI is not set
+# CONFIG_DM_SCSI is not set
+CONFIG_SYS_NS16550_IER=0x40
+# CONFIG_HTIF_CONSOLE is not set
+# CONFIG_SIFIVE_SERIAL is not set
+CONFIG_SPI=y
+CONFIG_K1X_QSPI=y
+# CONFIG_SYSRESET_SBI is not set
+# CONFIG_SYSRESET_SYSCON is not set
+CONFIG_SYSRESET_SPACEMIT=y
+CONFIG_TIMER_EARLY=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+# CONFIG_USB_DWC3_GADGET is not set
+CONFIG_USB_DWC3_GENERIC=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VENDOR_NUM=0x361C
+CONFIG_USB_GADGET_PRODUCT_NUM=0x1001
+CONFIG_USB2_K1X_CI=y
+CONFIG_DM_VIDEO=y
+CONFIG_VIDEO_PCI_DEFAULT_FB_SIZE=0x8000000
+CONFIG_VIDEO_COPY=y
+CONFIG_SYS_WHITE_ON_BLACK=y
+CONFIG_DISPLAY=y
+CONFIG_SPLASH_SCREEN=y
+CONFIG_SPLASH_SCREEN_ALIGN=y
+CONFIG_SPLASH_SOURCE=y
+CONFIG_VIDEO_BMP_RLE8=y
+CONFIG_BMP_16BPP=y
+CONFIG_BMP_24BPP=y
+CONFIG_BMP_32BPP=y
+CONFIG_VIDEO_SPACEMIT=y
+CONFIG_DISPLAY_SPACEMIT_HDMI=y
+CONFIG_DISPLAY_SPACEMIT_MIPI=y
+CONFIG_JFFS2_NOR=y
+CONFIG_JFFS2_USE_MTD_READ=y
+CONFIG_UBIFS_SILENCE_MSG=y
+CONFIG_IMAGE_SPARSE_TRANSFER_BLK_NUM=0x3000
+# CONFIG_SPL_USE_TINY_PRINTF is not set
+# CONFIG_RSA is not set
+# CONFIG_SPL_SHA1 is not set
+# CONFIG_SPL_SHA256 is not set
+CONFIG_ZSTD=y
diff --git a/debian/.gitignore b/debian/.gitignore
new file mode 100644 (file)
index 0000000..6d10dce
--- /dev/null
@@ -0,0 +1 @@
+changelog
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..1d83df7
--- /dev/null
@@ -0,0 +1,39 @@
+Source: u-boot-spacemit
+Section: admin
+Priority: optional
+Maintainer: 李伟智  <weizhi.li@spacemit.com>
+Build-Depends: bc,
+ bison,
+ debhelper-compat (= 13),
+ flex,
+ libpython3-dev:native [linux-any],
+ libssl-dev,
+ python3:any [linux-any],
+ python3-pyelftools [linux-any],
+ python3-setuptools [linux-any],
+ swig [linux-any],
+ device-tree-compiler,
+ hart-payload-generator [riscv64],
+ libgnutls28-dev,
+ libncurses-dev,
+ libncurses-dev:native,
+ libssl-dev:native,
+ opensbi (>= 1.0-2~) [riscv64],
+ uuid-dev,
+Rules-Requires-Root: no
+Standards-Version: 4.6.2
+Homepage: https://www.denx.de/wiki/U-Boot/
+Vcs-Browser: https://salsa.debian.org/debian/u-boot
+Vcs-Git: https://salsa.debian.org/debian/u-boot.git
+
+Package: u-boot-spacemit
+Architecture: all
+Multi-Arch: foreign
+Depends: ${misc:Depends}
+Built-Using: ${u-boot-spacemit:Built-Using}
+Description: A boot loader for SpacemiT systems
+ Das U-Boot is a cross-platform bootloader for embedded systems,
+ used as the default boot loader by several board vendors.  It is
+ intended to be easy to port and to debug, and runs on many
+ supported architectures, including PPC, ARM, MIPS, x86, m68k,
+ NIOS, and Microblaze.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..426e439
--- /dev/null
@@ -0,0 +1,369 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Das U-Boot
+Source: https://www.denx.de/wiki/U-Boot
+Files-Excluded:
+  drivers/dma/MCD_tasks.c
+
+Files: *
+Copyright: 2000-2013 Wolfgang Denk <wd@denx.de>
+ 1995-2002 Russell King
+ 1996-1998 Russell King
+ 1996-1999 Russell King
+ 1996-2000 Russell King
+ 1996 Russell King
+ 1997-1999 Russell King
+ 1999-2002 Vojtech Pavlik
+ 1999 Linus Torvalds / 2000-2002 Transmeta Corporation
+ 1999 Russell King
+ 2000-2002 Russell King
+ 2000-2010 David Woodhouse <dwmw2@infradead.org>
+ 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ 2001, 2002, 2003 / 2004 Gary Jennejohn garyj@denx.de
+ 2002-2007 Aleph One Ltd
+ 2002-2011 Aleph One Ltd
+ 2002 Thomas Gleixner (tglx@linutronix.de)
+ 2003 Kai-Uwe Bloem / 2000-2002 Transmeta Corporation / 1999 Linus Torvalds
+ 2004 by David Brownell
+ 2004 Nokia Corporation
+ 2004 Thomas Gleixner (tglx@linutronix.de)
+ 2005-2006 by Texas Instruments
+ 2005-2006 by Texas Instruments / 2005 Mentor Graphics Corporation / 2006-2007 Nokia Corporation
+ 2005-2007 Samsung Electronics
+ 2005-2007 Samsung Electronics / Samsung Electronics, 2009 / Nokia Corporation, 2007
+ 2005-2008 Samsung Electronics
+ 2005 Mentor Graphics Corporation / 2005-2006 by Texas Instruments / 2006-2007 Nokia Corporation
+ 2005 Mentor Graphics Corporation / 2005-2006 by Texas Instruments / 2008-2009 MontaVista Software, Inc. <source@mvista.com> / 2006-2007 Nokia Corporation
+ 2005, Seagate Technology LLC / 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ 2006-2007 Nokia Corporation / 2005-2006 by Texas Instruments / 2005 Mentor Graphics Corporation
+ 2006-2007 Nokia Corporation / 2005 Mentor Graphics Corporation / 2005-2006 by Texas Instruments
+ 2006-2007 Nokia Corporation / 2005 Mentor Graphics Corporation / 2005-2006 by Texas Instruments / 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+ 2006, 2007 University of Szeged, Hungary / 2006-2008 Nokia Corporation
+ 2006-2008 Nokia Corporation
+ 2006,2009 Freescale Semiconductor, Inc
+ 2006-2009 Solarflare Communications Inc
+ 2006 Freescale Semiconductor, Inc
+ 2006 Nokia Corporation / 2005-2007 by Texas Instruments
+ 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> / 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> / 2009 Ilya Yanok, <yanok@emcraft.com>
+ 2006 Thomas Gleixner <tglx@linutronix.de>
+ 2007-2011 Freescale Semiconductor, Inc
+ 2007 Freescale Semiconductor, Inc
+ 2008-2009 / 2006-2008 Nokia Corporation
+ 2008-2009 Freescale Semiconductor, Inc
+ 2008-2009, MontaVista Software, Inc. <source@mvista.com> / 2010, by Texas Instruments
+ 2008,2009 STMicroelectronics / 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com> / 2009 Alessandro Rubini <rubini@unipv.it>
+ 2008-2010 / 2006-2008 Nokia Corporation
+ 2008-2011 Freescale Semiconductor, Inc
+ 2008, 2011 Freescale Semiconductor, Inc
+ 2008,2011 Freescale Semiconductor, Inc
+ 2008-2012 Freescale Semiconductor, Inc
+ 2008 Altera Corporation / 2010 Thomas Chou <thomas@wytron.com.tw>
+ 2008 Atmel Corporation / 2013 Jagannadha Sutradharudu Teki, Xilinx Inc
+ 2008 by Texas Instruments / 2008 Mentor Graphics Corporation
+ 2008 Dave S.r.l. <www.dave.eu>
+ 2008 Extreme Engineering Solutions, Inc
+ 2008 Freescale Semiconductor, Inc
+ 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> / 2004-2007 ARM Limited
+ 2008 Kim B. Heino / 2009
+ 2008 Qstreams Networks, Inc
+ 2008 Samsung Electronics / 2008-2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ 2008 STMicroelectronics / 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com> / 2009 Alessandro Rubini <rubini@unipv.it>
+ 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ 2009-2010 eXMeritus, A Boeing Company / 2008-2009 Freescale Semiconductor, Inc
+ 2009-2010 Freescale Semiconductor, Inc
+ 2009-2010 Texas Instruments, Inc
+ 2009-2011 Freescale Semiconductor, Inc
+ 2009 coresystems GmbH
+ 2009 Freescale Semiconductor, Inc
+ 2009 Micrel Inc / 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it>
+ 2009 MontaVista Software, Inc. <source@mvista.com> / 2006-2007 Nokia Corporation / 2005-2006 by Texas Instruments / 2005 Mentor Graphics Corporation
+ 2010-2011 Freescale Semiconductor, Inc
+ 2010-2011 NVIDIA Corporation
+ 2010-2012 NVIDIA Corporation
+ 2010-2013 NVIDIA Corporation
+ 2010 Broadcom / 2012 Oleksandr Tymoshenko / 2012 Stephen Warren
+ 2010 NISHIMOTO Hiroki / 2010 Renesas Solutions Corp
+ 2010 Thomas Chou <thomas@wytron.com.tw>
+ 2010, Thomas Chou <thomas@wytron.com.tw>
+ 2010 Thomas Chou <thomas@wytron.com.tw> / 2008-2009 Avionic Design GmbH / 2007-2008 Avionic Design Development GmbH
+ 2010 Thomas Chou <thomas@wytron.com.tw> / 2008 Altera Corporation
+ 2011-2012 Renesas Solutions Corp
+ 2011 - 2012 Samsung Electronics / 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
+ 2011 Analog Devices Inc
+ 2011 Freescale Semiconductor, Inc
+ 2011 Infineon Technologies
+ 2011 Ivan Djelic <ivan.djelic@parrot.com>
+ 2011 Macpaul Lin (macpaul@andestech.com) / 2011 Andes Technology Corporation / 1995-2002 Russell King / 2010 Shawn Lin (nobuhiro@andestech.com)
+ 2011 Macpaul Lin (macpaul@andestech.com) / 2011 Andes Technology Corporation / 1996-1998 Russell King / 2010 Shawn Lin (nobuhiro@andestech.com)
+ 2011 Macpaul Lin (macpaul@andestech.com) / 2011 Andes Technology Corporation / 2010 Shawn Lin (nobuhiro@andestech.com)
+ 2011 Maxim Integrated Products
+ 2011 Parrot S.A
+ 2011 Renesas Solutions Corp
+ 2011 Renesas Solutions Corp / 2011 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ 2011 The ChromiumOS Authors. All rights reserved
+ 2012-2013 Stephen Warren
+ 2012, by Texas Instruments
+ 2012, Google Inc
+ 2012 Renesas Solutions Corp
+ 2012 Samsung Electronics Co., Ltd
+ 2012 Stephen Warren
+ 2012 Texas Instruments Incorporated - http://www.ti.com/
+ 2013 Synopsys, Inc. (www.synopsys.com)
+License: GPL-2
+
+Files: 
+ drivers/tpm/tpm_atmel_twi.c
+ drivers/gpio/tca642x.c
+ include/splash.h
+ include/linux/libfdt.h
+ include/configs/mxs.h
+ include/tca642x.h
+ board/gdsys/common/dp501.h
+ common/splash.c
+ fs/jffs2/compr_lzo.c
+ arch/arm/include/asm/arch-am33xx/hardware_ti816x.h
+ arch/arm/mach-exynos/dmc_init_exynos4.c
+ arch/arm/mach-exynos/lowlevel_init.c
+ arch/arm/mach-exynos/clock_init_exynos4.c
+ arch/arm/mach-exynos/common_setup.h
+ arch/arm/mach-omap2/am33xx/clock_ti816x.c
+Copyright: 
+  2013 Texas Instruments, Inc
+  2013, Boundary Devices <info@boundarydevices.com>
+  2006 David Gibson, IBM Corporation 
+  2012 Kim Phillips, Freescale Semiconductor
+  2010-2013 Freescale Semiconductor, Inc
+  2013 Marek Vasut <marex@denx.de>
+  2010-2011 Freescale Semiconductor, Inc
+  2004 Patrik Kluba
+  1996-2002 Markus Franz Xaver Johannes Oberhumer
+  2013 NVIDIA Corporation
+  2011 The Chromium OS Authors
+  2013 Samsung Electronics
+  2013, Adeneo Embedded <www.adeneo-embedded.com> 
+  2009, Texas Instruments, Incorporated
+License: GPL-2+
+
+Files: debian/*
+Copyright: Clint Adams <clint@debian.org>
+ Joey Hess <joeyh@debian.org>
+ Marc Singer <elf@debian.org>
+ Per Andersson <avtobiff@gmail.com>
+ Vagrant Cascadian <vagrant@debian.org>
+ Loïc Minier <lool@debian.org>
+ Adam Borowski <kilobyte@angband.pl>
+License: GPL-2+
+
+Files: fs/yaffs2/yaffs_allocator.h
+ fs/yaffs2/yaffs_verify.h
+ fs/yaffs2/yaffs_packedtags1.h
+ fs/yaffs2/yaffs_yaffs1.h
+ fs/yaffs2/ydirectenv.h
+ fs/yaffs2/yaffs_yaffs2.h
+ fs/yaffs2/yaffsfs.h
+ fs/yaffs2/yaffs_osglue.h
+ fs/yaffs2/yaffs_flashif.h
+ fs/yaffs2/yaffs_nand.h
+ fs/yaffs2/yportenv.h
+ fs/yaffs2/yaffs_packedtags2.h
+ fs/yaffs2/yaffs_attribs.h
+ fs/yaffs2/yaffs_ecc.h
+ fs/yaffs2/yaffs_trace.h
+ fs/yaffs2/yaffs_guts.h
+ fs/yaffs2/yaffs_getblockinfo.h
+ fs/yaffs2/yaffs_bitmap.h
+ fs/yaffs2/yaffs_nameval.h
+ fs/yaffs2/yaffscfg.h
+ fs/yaffs2/yaffs_nandemul2k.h
+ fs/yaffs2/yaffs_mtdif2.h
+ fs/yaffs2/yaffs_flashif2.h
+ fs/yaffs2/yaffs_checkptrw.h
+ fs/yaffs2/yaffs_tagscompat.h
+ fs/yaffs2/yaffs_nandif.h
+ fs/yaffs2/yaffs_summary.h
+ fs/yaffs2/yaffs_mtdif.h
+Copyright: Copyright (C) 2002-2011 Aleph One Ltd.
+License: LGPL-2.1
+
+Files: lib/sha1.c
+Copyright: Copyright (C) 2003-2006  Christophe Devine
+License: LGPL-2.1
+
+Files: include/bzlib.h
+ lib/bzip2/*
+Copyright: Copyright (C) 1996-2002 Julian R Seward.  All rights reserved.
+License: bzlib-BSD-3
+
+Files: drivers/usb/musb-new/musb_host.h
+ drivers/usb/musb-new/musb_core.h
+ drivers/usb/musb-new/musb_core.c
+ drivers/usb/musb-new/musb_gadget.c
+ drivers/usb/musb-new/musb_gadget.h
+ drivers/usb/musb-new/musb_dma.h
+ drivers/usb/musb-new/musb_regs.h
+ drivers/usb/musb-new/musb_debug.h
+ drivers/usb/musb-new/musb_host.c
+ drivers/usb/musb-new/musb_gadget_ep0.c
+ drivers/usb/musb-new/musb_io.h
+Copyright: Copyright 2005 Mentor Graphics Corporation
+ Copyright (C) 2005-2006 by Texas Instruments
+ Copyright (C) 2006-2007 Nokia Corporation
+ Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+License: GPL-2
+
+Files: net/dns.c
+ include/slre.h
+ lib/slre.c
+Copyright: 2008 Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl>
+ 2004-2005 Sergey Lyubka <valenok@gmail.com>
+ 2009 Robin Getz <rgetz@blackfin.uclinux.org>]
+License: Beerware
+
+Files: scripts/dtc/libfdt/*
+Copyright: 2006 David Gibson, IBM Corporation
+ 2012 Kim Phillips, Freescale Semiconductor
+License: libfdt-BSD-GPL
+
+License: libfdt-BSD-GPL
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: Beerware
+ "THE BEER-WARE LICENSE" (Revision 42):
+ Sergey Lyubka wrote this file.  As long as you retain this notice you
+ can do whatever you want with this stuff. If we meet some day, and you think
+ this stuff is worth it, you can buy me a beer in return.
+
+License: GPL-2
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+ .
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
+
+License: bzlib-BSD-3
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  .
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  .
+  2. The origin of this software must not be misrepresented; you must
+     not claim that you wrote the original software.  If you use this
+     software in a product, an acknowledgment in the product
+     documentation would be appreciated but is not required.
+  .
+  3. Altered source versions must be plainly marked as such, and must
+     not be misrepresented as being the original software.
+  .
+  4. The name of the author may not be used to endorse or promote
+     products derived from this software without specific prior written
+     permission.
+  .
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: GPL-2+
+ 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 package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
+
+License: LGPL-2.1
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1 as
+ published by the Free Software Foundation.
+ .
+ This library 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
+ Lesser General Public License for more details.
+ . 
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA  02110-1301  USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/LGPL-2.1'.
diff --git a/debian/env_k1-x.txt b/debian/env_k1-x.txt
new file mode 100644 (file)
index 0000000..7106697
--- /dev/null
@@ -0,0 +1,10 @@
+# Common parameter
+console=ttyS0,115200
+init=/init
+bootdelay=0
+baudrate=115200
+loglevel=8
+
+knl_name=vmlinuz-6.1.15
+ramdisk_name=initrd.img-6.1.15
+dtb_dir=spacemit
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..8f795dc
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# Always set CROSS_COMPILE, which also works for native builds.
+export CROSS_COMPILE=riscv64-unknown-linux-gnu-
+export ARCH=riscv
+%:
+       dh $@
+
+override_dh_auto_build:
+       make k1_defconfig
+       make -j$(nproc)
+       cp -f u-boot-env-default.bin env.bin
+
+override_dh_auto_test-indep:
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/u-boot-spacemit.install b/debian/u-boot-spacemit.install
new file mode 100644 (file)
index 0000000..5c74aa8
--- /dev/null
@@ -0,0 +1,6 @@
+u-boot.itb usr/lib/u-boot/spacemit
+FSBL.bin usr/lib/u-boot/spacemit
+bootinfo*.bin usr/lib/u-boot/spacemit
+env.bin usr/lib/u-boot/spacemit
+debian/env_k1-x.txt boot
+tools/logos/bianbu.bmp boot
diff --git a/debian/u-boot-spacemit.postinst b/debian/u-boot-spacemit.postinst
new file mode 100755 (executable)
index 0000000..4e5aa07
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/sh
+set -e
+
+case "$1" in
+configure)
+    target=""
+    if grep -q '^spacemit' /sys/firmware/devicetree/base/model; then
+        target="spacemit"
+    else
+        exit 0
+    fi
+
+    for x in $(cat /proc/cmdline); do
+        case $x in
+        root=*)
+            ROOT=${x#root=}
+            ;;
+        esac
+    done
+
+    if [ -n $ROOT ]; then
+        case $ROOT in
+        "/dev/mmcblk0"*)
+            BOOTINFO_FILE=bootinfo_sd.bin
+            BOOTINFO=/dev/mmcblk0
+            FSBL=/dev/mmcblk0p1
+            FSBL_SEEK=0
+            ENV=/dev/mmcblk0p2
+            UBOOT=/dev/mmcblk0p4
+            ;;
+        "/dev/mmcblk2"*)
+            BOOTINFO_FILE=bootinfo_emmc.bin
+            BOOTINFO=/dev/mmcblk2boot0
+            FSBL=/dev/mmcblk2boot0
+            FSBL_SEEK=512
+            ENV=/dev/mmcblk2p2
+            UBOOT=/dev/mmcblk2p4
+            if [ -e $BOOTINFO ]; then
+                echo 0 | tee /sys/block/mmcblk2boot0/force_ro
+            else
+                exit 0
+            fi
+            ;;
+        *)
+            echo "Unsupported root=$ROOT"
+            exit 0
+            ;;
+        esac
+    else
+        echo "Missing root= in cmdline"
+        exit 0
+    fi
+
+    BIN_DIR="/usr/lib/u-boot/$target"
+    # 待检查文件/分区列表
+    files="${BIN_DIR}/${BOOTINFO_FILE} ${BIN_DIR}/FSBL.bin ${BIN_DIR}/env.bin ${BIN_DIR}/u-boot.itb $BOOTINFO $FSBL $ENV $UBOOT"
+    for file in $files; do
+        if [ ! -e "$file" ]; then
+            # 任意不存在则退出
+            echo "Missing $file"
+            exit 0
+        fi
+    done
+
+    # 此前已经做了所有检查
+    dd if=/usr/lib/u-boot/$target/$BOOTINFO_FILE of=$BOOTINFO && sync
+    dd if=/usr/lib/u-boot/$target/FSBL.bin of=$FSBL seek=$FSBL_SEEK bs=1 && sync
+    dd if=/usr/lib/u-boot/$target/env.bin of=$ENV bs=1 && sync
+    dd if=/usr/lib/u-boot/$target/u-boot.itb of=$UBOOT bs=1M && sync
+
+    ;;
+esac
+
+exit 0
index 81d8867ed7fcad395c7ccef34a1ae4be5a83bb1b..07476087dee05214ddb382f8d2345564e1146f75 100644 (file)
@@ -89,6 +89,27 @@ config SPL_AMIGA_PARTITION
        default y if AMIGA_PARTITION
        select SPL_PARTITIONS
 
+config ENABLE_SET_NUM_PART_SEARCH
+       bool "Enable custom maximum partition search limit"
+       default n
+       help
+         Enable this to specify a custom maximum number of partitions
+         that U-Boot will search on a block device. Disabling this
+         will use the default maximum search limit.
+
+config MAX_SEARCH_PARTITIONS
+       int "Maximum number of partitions to search"
+       depends on ENABLE_SET_NUM_PART_SEARCH
+       default 16
+       help
+         Specifies the maximum number of partitions that U-Boot will
+         search on a block device when ENABLE_MAX_PART_SEARCH is enabled.
+         Reducing this number can speed up the boot process by limiting
+         the number of partitions that U-Boot scans during boot. The
+         maximum supported value is 128.
+
+         If unsure, leave at the default value of 16.
+
 config EFI_PARTITION
        bool "Enable EFI GPT partition table"
        default y if DISTRO_DEFAULTS
index de1b917e842b381eca9449ce4d1bcc025269c267..a1d4b37e24fcf8983fe08a62c64f7bdec1bcc7e5 100644 (file)
@@ -125,13 +125,13 @@ void dev_print (struct blk_desc *dev_desc)
        lba512_t lba512; /* number of blocks if 512bytes block size */
 
        if (dev_desc->type == DEV_TYPE_UNKNOWN) {
-               puts ("not available\n");
+               pr_crit ("not available\n");
                return;
        }
 
        switch (dev_desc->if_type) {
        case IF_TYPE_SCSI:
-               printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
+               pr_crit ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
                        dev_desc->target,dev_desc->lun,
                        dev_desc->vendor,
                        dev_desc->product,
@@ -140,7 +140,7 @@ void dev_print (struct blk_desc *dev_desc)
        case IF_TYPE_ATAPI:
        case IF_TYPE_IDE:
        case IF_TYPE_SATA:
-               printf ("Model: %s Firm: %s Ser#: %s\n",
+               pr_crit ("Model: %s Firm: %s Ser#: %s\n",
                        dev_desc->vendor,
                        dev_desc->revision,
                        dev_desc->product);
@@ -151,45 +151,45 @@ void dev_print (struct blk_desc *dev_desc)
        case IF_TYPE_NVME:
        case IF_TYPE_PVBLOCK:
        case IF_TYPE_HOST:
-               printf ("Vendor: %s Rev: %s Prod: %s\n",
+               pr_crit ("Vendor: %s Rev: %s Prod: %s\n",
                        dev_desc->vendor,
                        dev_desc->revision,
                        dev_desc->product);
                break;
        case IF_TYPE_VIRTIO:
-               printf("%s VirtIO Block Device\n", dev_desc->vendor);
+               pr_crit("%s VirtIO Block Device\n", dev_desc->vendor);
                break;
        case IF_TYPE_DOC:
-               puts("device type DOC\n");
+               pr_crit("device type DOC\n");
                return;
        case IF_TYPE_UNKNOWN:
-               puts("device type unknown\n");
+               pr_crit("device type unknown\n");
                return;
        default:
-               printf("Unhandled device type: %i\n", dev_desc->if_type);
+               pr_crit("Unhandled device type: %i\n", dev_desc->if_type);
                return;
        }
-       puts ("            Type: ");
+       pr_crit ("            Type: ");
        if (dev_desc->removable)
-               puts ("Removable ");
+               pr_crit ("Removable ");
        switch (dev_desc->type & 0x1F) {
        case DEV_TYPE_HARDDISK:
-               puts ("Hard Disk");
+               pr_crit ("Hard Disk");
                break;
        case DEV_TYPE_CDROM:
-               puts ("CD ROM");
+               pr_crit ("CD ROM");
                break;
        case DEV_TYPE_OPDISK:
-               puts ("Optical Device");
+               pr_crit ("Optical Device");
                break;
        case DEV_TYPE_TAPE:
-               puts ("Tape");
+               pr_crit ("Tape");
                break;
        default:
-               printf ("# %02X #", dev_desc->type & 0x1F);
+               pr_crit ("# %02X #", dev_desc->type & 0x1F);
                break;
        }
-       puts ("\n");
+       pr_crit ("\n");
        if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
                ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
                lbaint_t lba;
@@ -208,24 +208,25 @@ void dev_print (struct blk_desc *dev_desc)
                gb_quot = gb / 10;
                gb_rem  = gb - (10 * gb_quot);
 #ifdef CONFIG_LBA48
-               if (dev_desc->lba48)
-                       printf ("            Supports 48-bit addressing\n");
+               if (dev_desc->lba48){
+                       pr_crit ("            Supports 48-bit addressing\n");
+               }
 #endif
 #if defined(CONFIG_SYS_64BIT_LBA)
-               printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
+               pr_crit ("            Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
                        mb_quot, mb_rem,
                        gb_quot, gb_rem,
                        lba,
                        dev_desc->blksz);
 #else
-               printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
+               pr_crit ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
                        mb_quot, mb_rem,
                        gb_quot, gb_rem,
                        (ulong)lba,
                        dev_desc->blksz);
 #endif
        } else {
-               puts ("            Capacity: not available\n");
+               pr_crit ("            Capacity: not available\n");
        }
 }
 #endif
@@ -261,49 +262,49 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
        CONFIG_IS_ENABLED(ISO_PARTITION) || \
        CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
        CONFIG_IS_ENABLED(EFI_PARTITION)
-       puts ("\nPartition Map for ");
+       pr_crit ("\nPartition Map for ");
        switch (dev_desc->if_type) {
        case IF_TYPE_IDE:
-               puts ("IDE");
+               pr_crit ("IDE");
                break;
        case IF_TYPE_SATA:
-               puts ("SATA");
+               pr_crit ("SATA");
                break;
        case IF_TYPE_SCSI:
-               puts ("SCSI");
+               pr_crit ("SCSI");
                break;
        case IF_TYPE_ATAPI:
-               puts ("ATAPI");
+               pr_crit ("ATAPI");
                break;
        case IF_TYPE_USB:
-               puts ("USB");
+               pr_crit ("USB");
                break;
        case IF_TYPE_DOC:
-               puts ("DOC");
+               pr_crit ("DOC");
                break;
        case IF_TYPE_MMC:
-               puts ("MMC");
+               pr_crit ("MMC");
                break;
        case IF_TYPE_HOST:
-               puts ("HOST");
+               pr_crit ("HOST");
                break;
        case IF_TYPE_NVME:
-               puts ("NVMe");
+               pr_crit ("NVMe");
                break;
        case IF_TYPE_PVBLOCK:
-               puts("PV BLOCK");
+               pr_crit("PV BLOCK");
                break;
        case IF_TYPE_VIRTIO:
-               puts("VirtIO");
+               pr_crit("VirtIO");
                break;
        case IF_TYPE_EFI_MEDIA:
-               puts("EFI");
+               pr_crit("EFI");
                break;
        default:
-               puts("UNKNOWN");
+               pr_crit("UNKNOWN");
                break;
        }
-       printf (" device %d  --   Partition Type: %s\n\n",
+       pr_crit (" device %d  --   Partition Type: %s\n\n",
                        dev_desc->devnum, type);
 #endif /* any CONFIG_..._PARTITION */
 }
@@ -314,7 +315,7 @@ void part_print(struct blk_desc *dev_desc)
 
        drv = part_driver_lookup_type(dev_desc);
        if (!drv) {
-               printf("## Unknown partition table type %x\n",
+               pr_crit("## Unknown partition table type %x\n",
                       dev_desc->part_type);
                return;
        }
@@ -401,7 +402,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
 
        dev = hextoul(dev_str, &ep);
        if (*ep) {
-               printf("** Bad device specification %s %s **\n",
+               PRINTF("** Bad device specification %s %s **\n",
                       ifname, dev_str);
                dev = -EINVAL;
                goto cleanup;
@@ -410,7 +411,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
        if (hwpart_str) {
                hwpart = hextoul(hwpart_str, &ep);
                if (*ep) {
-                       printf("** Bad HW partition specification %s %s **\n",
+                       pr_err("** Bad HW partition specification %s %s **\n",
                            ifname, hwpart_str);
                        dev = -EINVAL;
                        goto cleanup;
@@ -486,7 +487,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
         */
        if (0 == strcmp(ifname, "ubi")) {
                if (!ubifs_is_mounted()) {
-                       printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
+                       pr_err("UBIFS not mounted, use ubifsmount to mount volume first!\n");
                        return -EINVAL;
                }
 
@@ -508,7 +509,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 
        /* If still no dev_part_str, it's an error */
        if (!dev_part_str) {
-               printf("** No device specified **\n");
+               pr_err("** No device specified **\n");
                ret = -ENODEV;
                goto cleanup;
        }
@@ -527,7 +528,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
        /* Look up the device */
        dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
        if (dev < 0) {
-               printf("** Bad device specification %s %s **\n",
+               PRINTF("** Bad device specification %s %s **\n",
                       ifname, dev_str);
                ret = dev;
                goto cleanup;
@@ -546,7 +547,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
                 * or request for whole device, but caller requires partition.
                 */
                if (*ep || (part == 0 && !allow_whole_dev)) {
-                       printf("** Bad partition specification %s %s **\n",
+                       pr_err("** Bad partition specification %s %s **\n",
                            ifname, dev_part_str);
                        ret = -ENOENT;
                        goto cleanup;
@@ -560,7 +561,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
        if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
            (part == 0)) {
                if (!(*dev_desc)->lba) {
-                       printf("** Bad device size - %s %s **\n", ifname,
+                       pr_err("** Bad device size - %s %s **\n", ifname,
                               dev_str);
                        ret = -EINVAL;
                        goto cleanup;
@@ -572,7 +573,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
                 * it's an error.
                 */
                if ((part > 0) || (!allow_whole_dev)) {
-                       printf("** No partition table - %s %s **\n", ifname,
+                       pr_err("** No partition table - %s %s **\n", ifname,
                               dev_str);
                        ret = -EPROTONOSUPPORT;
                        goto cleanup;
@@ -600,7 +601,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
        if (part != PART_AUTO) {
                ret = part_get_info(*dev_desc, part, info);
                if (ret) {
-                       printf("** Invalid partition %d **\n", part);
+                       pr_err("** Invalid partition %d **\n", part);
                        goto cleanup;
                }
        } else {
@@ -642,12 +643,12 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
                        if (p == MAX_SEARCH_PARTITIONS + 1)
                                *info = tmpinfo;
                } else {
-                       printf("** No valid partitions found **\n");
+                       pr_err("** No valid partitions found **\n");
                        goto cleanup;
                }
        }
        if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
-               printf("** Invalid partition type \"%.32s\""
+               pr_err("** Invalid partition type \"%.32s\""
                        " (expect \"" BOOT_PART_TYPE "\")\n",
                        info->type);
                ret  = -EINVAL;
@@ -746,8 +747,9 @@ static int part_get_info_by_dev_and_name(const char *dev_iface,
                goto cleanup;
 
        ret = part_get_info_by_name(*dev_desc, part_str, part_info);
-       if (ret < 0)
-               printf("Could not find \"%s\" partition\n", part_str);
+       if (ret < 0){
+               pr_crit("Could not find \"%s\" partition\n", part_str);
+       }
 
 cleanup:
        free(dup_str);
@@ -773,9 +775,10 @@ int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
         */
        ret = blk_get_device_part_str(dev_iface, dev_part_str,
                                      dev_desc, part_info, allow_whole_dev);
-       if (ret < 0)
-               printf("Couldn't find partition %s %s\n",
+       if (ret < 0){
+               pr_err("Couldn't find partition %s %s\n",
                       dev_iface, dev_part_str);
+       }
        return ret;
 }
 
index 94fae7166d7b169731edd7d41c5d7f0eb37237e5..8f146a4b62fcaa0be3ebb2e451d700009a8869d9 100644 (file)
@@ -55,7 +55,7 @@ static void print_one_part(dos_partition_t *p, lbaint_t ext_part_sector,
        lbaint_t lba_start = ext_part_sector + get_unaligned_le32(p->start4);
        lbaint_t lba_size  = get_unaligned_le32(p->size4);
 
-       printf("%3d\t%-10" LBAFlength "u\t%-10" LBAFlength
+       pr_info("%3d\t%-10" LBAFlength "u\t%-10" LBAFlength
                "u\t%08x-%02x\t%02x%s%s\n",
                part_num, lba_start, lba_size, disksig, part_num, p->sys_ind,
                (is_extended(p->sys_ind) ? " Extd" : ""),
@@ -144,18 +144,18 @@ static void print_partition_extended(struct blk_desc *dev_desc,
        /* set a maximum recursion level */
        if (part_num > MAX_EXT_PARTS)
        {
-               printf("** Nested DOS partitions detected, stopping **\n");
+               pr_err("** Nested DOS partitions detected, stopping **\n");
                return;
     }
 
        if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) {
-               printf ("** Can't read partition table on %d:" LBAFU " **\n",
+               pr_err ("** Can't read partition table on %d:" LBAFU " **\n",
                        dev_desc->devnum, ext_part_sector);
                return;
        }
        i=test_block_type(buffer);
        if (i != DOS_MBR) {
-               printf ("bad MBR sector signature 0x%02x%02x\n",
+               pr_err ("bad MBR sector signature 0x%02x%02x\n",
                        buffer[DOS_PART_MAGIC_OFFSET],
                        buffer[DOS_PART_MAGIC_OFFSET + 1]);
                return;
@@ -216,18 +216,18 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
        /* set a maximum recursion level */
        if (part_num > MAX_EXT_PARTS)
        {
-               printf("** Nested DOS partitions detected, stopping **\n");
+               pr_err("** Nested DOS partitions detected, stopping **\n");
                return -1;
     }
 
        if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) {
-               printf ("** Can't read partition table on %d:" LBAFU " **\n",
+               pr_err ("** Can't read partition table on %d:" LBAFU " **\n",
                        dev_desc->devnum, ext_part_sector);
                return -1;
        }
        if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
                buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
-               printf ("bad MBR sector signature 0x%02x%02x\n",
+               pr_err ("bad MBR sector signature 0x%02x%02x\n",
                        buffer[DOS_PART_MAGIC_OFFSET],
                        buffer[DOS_PART_MAGIC_OFFSET + 1]);
                return -1;
@@ -305,7 +305,7 @@ static int part_get_info_extended(struct blk_desc *dev_desc,
 
 static void __maybe_unused part_print_dos(struct blk_desc *dev_desc)
 {
-       printf("Part\tStart Sector\tNum Sectors\tUUID\t\tType\n");
+       pr_info("Part\tStart Sector\tNum Sectors\tUUID\t\tType\n");
        print_partition_extended(dev_desc, 0, 0, 1, 0);
 }
 
@@ -381,14 +381,14 @@ int write_mbr_partitions(struct blk_desc *dev,
        }
 
        if (i < count && !ext_part_start) {
-               printf("%s: extended partition is needed for more than 4 partitions\n",
+               pr_err("%s: extended partition is needed for more than 4 partitions\n",
                        __func__);
                return -1;
        }
 
        /* write MBR */
        if (blk_dwrite(dev, 0, 1, buffer) != 1) {
-               printf("%s: failed writing 'MBR' (1 blks at 0x0)\n",
+               pr_err("%s: failed writing 'MBR' (1 blks at 0x0)\n",
                       __func__);
                return -1;
        }
@@ -416,7 +416,7 @@ int write_mbr_partitions(struct blk_desc *dev,
 
                /* write EBR */
                if (blk_dwrite(dev, ext_part_sect, 1, buffer) != 1) {
-                       printf("%s: failed writing 'EBR' (1 blks at 0x%lx)\n",
+                       pr_err("%s: failed writing 'EBR' (1 blks at 0x%lx)\n",
                               __func__, ext_part_sect);
                        return -1;
                }
@@ -499,7 +499,7 @@ int write_mbr_sector(struct blk_desc *dev_desc, void *buf)
 
        /* write MBR */
        if (blk_dwrite(dev_desc, 0, 1, buf) != 1) {
-               printf("%s: failed writing '%s' (1 blks at 0x0)\n",
+               pr_err("%s: failed writing '%s' (1 blks at 0x0)\n",
                       __func__, "MBR");
                return 1;
        }
index 5090efd1192f7c6e8a50e4fe46ce73e539750cea..23e607088b5ea6e79d8a335d154d23067735a7aa 100644 (file)
@@ -96,7 +96,7 @@ static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
 
        /* Check the GPT header signature */
        if (le64_to_cpu(gpt_h->signature) != GPT_HEADER_SIGNATURE_UBOOT) {
-               printf("%s signature is wrong: 0x%llX != 0x%llX\n",
+               pr_err("%s signature is wrong: 0x%llX != 0x%llX\n",
                       "GUID Partition Table Header",
                       le64_to_cpu(gpt_h->signature),
                       GPT_HEADER_SIGNATURE_UBOOT);
@@ -113,7 +113,7 @@ static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
        memcpy(&gpt_h->header_crc32, &crc32_backup, sizeof(crc32_backup));
 
        if (calc_crc32 != le32_to_cpu(crc32_backup)) {
-               printf("%s CRC is wrong: 0x%x != 0x%x\n",
+               pr_err("%s CRC is wrong: 0x%x != 0x%x\n",
                       "GUID Partition Table Header",
                       le32_to_cpu(crc32_backup), calc_crc32);
                return -1;
@@ -123,7 +123,7 @@ static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
         * Check that the my_lba entry points to the LBA that contains the GPT
         */
        if (le64_to_cpu(gpt_h->my_lba) != lba) {
-               printf("GPT: my_lba incorrect: %llX != " LBAF "\n",
+               pr_err("GPT: my_lba incorrect: %llX != " LBAF "\n",
                       le64_to_cpu(gpt_h->my_lba),
                       lba);
                return -1;
@@ -134,12 +134,12 @@ static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
         * within the disk.
         */
        if (le64_to_cpu(gpt_h->first_usable_lba) > lastlba) {
-               printf("GPT: first_usable_lba incorrect: %llX > " LBAF "\n",
+               pr_err("GPT: first_usable_lba incorrect: %llX > " LBAF "\n",
                       le64_to_cpu(gpt_h->first_usable_lba), lastlba);
                return -1;
        }
        if (le64_to_cpu(gpt_h->last_usable_lba) > lastlba) {
-               printf("GPT: last_usable_lba incorrect: %llX > " LBAF "\n",
+               pr_err("GPT: last_usable_lba incorrect: %llX > " LBAF "\n",
                       le64_to_cpu(gpt_h->last_usable_lba), lastlba);
                return -1;
        }
@@ -161,7 +161,7 @@ static int validate_gpt_entries(gpt_header *gpt_h, gpt_entry *gpt_e)
                le32_to_cpu(gpt_h->sizeof_partition_entry));
 
        if (calc_crc32 != le32_to_cpu(gpt_h->partition_entry_array_crc32)) {
-               printf("%s: 0x%x != 0x%x\n",
+               pr_err("%s: 0x%x != 0x%x\n",
                       "GUID Partition Table Entry Array CRC is wrong",
                       le32_to_cpu(gpt_h->partition_entry_array_crc32),
                       calc_crc32);
@@ -229,28 +229,28 @@ void part_print_efi(struct blk_desc *dev_desc)
 
        debug("%s: gpt-entry at %p\n", __func__, gpt_pte);
 
-       printf("Part\tStart LBA\tEnd LBA\t\tName\n");
-       printf("\tAttributes\n");
-       printf("\tType GUID\n");
-       printf("\tPartition GUID\n");
+       pr_info("Part\tStart LBA\tEnd LBA\t\tName\n");
+       pr_info("\tAttributes\n");
+       pr_info("\tType GUID\n");
+       pr_info("\tPartition GUID\n");
 
        for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
                /* Skip invalid PTE */
                if (!is_pte_valid(&gpt_pte[i]))
                        continue;
 
-               printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
+               pr_info("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
                        le64_to_cpu(gpt_pte[i].starting_lba),
                        le64_to_cpu(gpt_pte[i].ending_lba),
                        print_efiname(&gpt_pte[i]));
-               printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);
+               pr_info("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);
                uuid = (unsigned char *)gpt_pte[i].partition_type_guid.b;
                if (CONFIG_IS_ENABLED(PARTITION_TYPE_GUID))
-                       printf("\ttype:\t%pUl\n\t\t(%pUs)\n", uuid, uuid);
+                       pr_info("\ttype:\t%pUl\n\t\t(%pUs)\n", uuid, uuid);
                else
-                       printf("\ttype:\t%pUl\n", uuid);
+                       pr_info("\ttype:\t%pUl\n", uuid);
                uuid = (unsigned char *)gpt_pte[i].unique_partition_guid.b;
-               printf("\tguid:\t%pUl\n", uuid);
+               pr_info("\tguid:\t%pUl\n", uuid);
        }
 
        /* Remember to free pte */
@@ -266,7 +266,7 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part,
 
        /* "part" argument must be at least 1 */
        if (part < 1) {
-               printf("%s: Invalid Argument(s)\n", __func__);
+               pr_err("%s: Invalid Argument(s)\n", __func__);
                return -1;
        }
 
@@ -333,7 +333,7 @@ static int set_protective_mbr(struct blk_desc *dev_desc)
        /* Setup the Protective MBR */
        ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, p_mbr, 1, dev_desc->blksz);
        if (p_mbr == NULL) {
-               printf("%s: calloc failed!\n", __func__);
+               pr_err("%s: calloc failed!\n", __func__);
                return -1;
        }
 
@@ -355,7 +355,7 @@ static int set_protective_mbr(struct blk_desc *dev_desc)
 
        /* Write MBR sector to the MMC device */
        if (blk_dwrite(dev_desc, 0, 1, p_mbr) != 1) {
-               printf("** Can't write to device %d **\n",
+               pr_err("** Can't write to device %d **\n",
                        dev_desc->devnum);
                return -1;
        }
@@ -407,7 +407,7 @@ int write_gpt_table(struct blk_desc *dev_desc,
        return 0;
 
  err:
-       printf("** Can't write to device %d **\n", dev_desc->devnum);
+       pr_err("** Can't write to device %d **\n", dev_desc->devnum);
        return -1;
 }
 
@@ -454,14 +454,14 @@ int gpt_fill_pte(struct blk_desc *dev_desc,
                 */
                if (((start < hdr_end && hdr_start < (start + size)) ||
                     (start < pte_end && pte_start < (start + size)))) {
-                       printf("Partition overlap\n");
+                       pr_err("Partition overlap\n");
                        return -1;
                }
 
                gpt_e[i].starting_lba = cpu_to_le64(start);
 
                if (offset > (last_usable_lba + 1)) {
-                       printf("Partitions layout exceds disk size\n");
+                       pr_err("Partitions layout exceds disk size\n");
                        return -1;
                }
                /* partition ending lba */
@@ -477,7 +477,7 @@ int gpt_fill_pte(struct blk_desc *dev_desc,
                if (strlen(str_type_guid)) {
                        if (uuid_str_to_bin(str_type_guid, bin_type_guid,
                                            UUID_STR_FORMAT_GUID)) {
-                               printf("Partition no. %d: invalid type guid: %s\n",
+                               pr_err("Partition no. %d: invalid type guid: %s\n",
                                       i, str_type_guid);
                                return -1;
                        }
@@ -497,7 +497,7 @@ int gpt_fill_pte(struct blk_desc *dev_desc,
                bin_uuid = gpt_e[i].unique_partition_guid.b;
 
                if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_GUID)) {
-                       printf("Partition no. %d: invalid guid: %s\n",
+                       pr_err("Partition no. %d: invalid guid: %s\n",
                                i, str_uuid);
                        return -1;
                }
@@ -611,7 +611,7 @@ int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
        size = PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc);
        gpt_h = malloc_cache_aligned(size);
        if (gpt_h == NULL) {
-               printf("%s: calloc failed!\n", __func__);
+               pr_err("%s: calloc failed!\n", __func__);
                return -1;
        }
        memset(gpt_h, 0, size);
@@ -620,7 +620,7 @@ int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
                                dev_desc);
        gpt_e = malloc_cache_aligned(size);
        if (gpt_e == NULL) {
-               printf("%s: calloc failed!\n", __func__);
+               pr_err("%s: calloc failed!\n", __func__);
                free(gpt_h);
                return -1;
        }
@@ -678,7 +678,7 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
        if (is_gpt_valid(dev_desc,
                         GPT_PRIMARY_PARTITION_TABLE_LBA,
                         gpt_head, gpt_pte) != 1) {
-               printf("%s: *** ERROR: Invalid GPT ***\n",
+               pr_err("%s: *** ERROR: Invalid GPT ***\n",
                       __func__);
                return -1;
        }
@@ -690,14 +690,14 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
         * Check that the alternate_lba entry points to the last LBA
         */
        if (le64_to_cpu(gpt_head->alternate_lba) != (dev_desc->lba - 1)) {
-               printf("%s: *** ERROR: Misplaced Backup GPT ***\n",
+               pr_err("%s: *** ERROR: Misplaced Backup GPT ***\n",
                       __func__);
                return -1;
        }
 
        if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
                         gpt_head, gpt_pte) != 1) {
-               printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+               pr_err("%s: *** ERROR: Invalid Backup GPT ***\n",
                       __func__);
                return -1;
        }
@@ -916,7 +916,7 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
        lba = 0;        /* MBR is always at 0 */
        cnt = 1;        /* MBR (1 block) */
        if (blk_dwrite(dev_desc, lba, cnt, buf) != cnt) {
-               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+               pr_err("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
                       __func__, "MBR", cnt, lba);
                return 1;
        }
@@ -925,7 +925,7 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
        lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
        cnt = 1;        /* GPT Header (1 block) */
        if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
-               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+               pr_err("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
                       __func__, "Primary GPT Header", cnt, lba);
                return 1;
        }
@@ -933,7 +933,7 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
        lba = le64_to_cpu(gpt_h->partition_entry_lba);
        cnt = gpt_e_blk_cnt;
        if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
-               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+               pr_err("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
                       __func__, "Primary GPT Entries", cnt, lba);
                return 1;
        }
@@ -944,7 +944,7 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
        lba = le64_to_cpu(gpt_h->partition_entry_lba);
        cnt = gpt_e_blk_cnt;
        if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
-               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+               pr_err("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
                       __func__, "Backup GPT Entries", cnt, lba);
                return 1;
        }
@@ -952,7 +952,7 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
        lba = le64_to_cpu(gpt_h->my_lba);
        cnt = 1;        /* GPT Header (1 block) */
        if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
-               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+               pr_err("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
                       __func__, "Backup GPT Header", cnt, lba);
                return 1;
        }
@@ -1020,7 +1020,7 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
 {
        /* Confirm valid arguments prior to allocation. */
        if (!dev_desc || !pgpt_head) {
-               printf("%s: Invalid Argument(s)\n", __func__);
+               pr_err("%s: Invalid Argument(s)\n", __func__);
                return 0;
        }
 
@@ -1028,13 +1028,13 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
 
        /* Read MBR Header from device */
        if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) {
-               printf("*** ERROR: Can't read MBR header ***\n");
+               pr_err("*** ERROR: Can't read MBR header ***\n");
                return 0;
        }
 
        /* Read GPT Header from device */
        if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) {
-               printf("*** ERROR: Can't read GPT header ***\n");
+               pr_err("*** ERROR: Can't read GPT header ***\n");
                return 0;
        }
 
@@ -1091,18 +1091,20 @@ static int find_valid_gpt(struct blk_desc *dev_desc, gpt_header *gpt_head,
                         pgpt_pte);
 
        if (r != 1) {
-               if (r != 2)
-                       printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+               if (r != 2){
+                       pr_err("%s: *** ERROR: Invalid GPT ***\n", __func__);
+               }
 
                if (is_gpt_valid(dev_desc, (dev_desc->lba - 1), gpt_head,
                                 pgpt_pte) != 1) {
-                       printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+                       pr_err("%s: *** ERROR: Invalid Backup GPT ***\n",
                               __func__);
                        return 0;
                }
-               if (r != 2)
-                       printf("%s: ***        Using Backup GPT ***\n",
+               if (r != 2){
+                       pr_err("%s: ***        Using Backup GPT ***\n",
                               __func__);
+               }
        }
        return 1;
 }
@@ -1124,7 +1126,7 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
        gpt_entry *pte = NULL;
 
        if (!dev_desc || !pgpt_head) {
-               printf("%s: Invalid Argument(s)\n", __func__);
+               pr_err("%s: Invalid Argument(s)\n", __func__);
                return NULL;
        }
 
@@ -1143,7 +1145,7 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
        }
 
        if (count == 0 || pte == NULL) {
-               printf("%s: ERROR: Can't allocate %#lX bytes for GPT Entries\n",
+               pr_err("%s: ERROR: Can't allocate %#lX bytes for GPT Entries\n",
                       __func__, (ulong)count);
                return NULL;
        }
@@ -1152,7 +1154,7 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
        blk = le64_to_cpu(pgpt_head->partition_entry_lba);
        blk_cnt = BLOCK_CNT(count, dev_desc);
        if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
-               printf("*** ERROR: Can't read GPT Entries ***\n");
+               pr_err("*** ERROR: Can't read GPT Entries ***\n");
                free(pte);
                return NULL;
        }
@@ -1170,7 +1172,7 @@ static int is_pte_valid(gpt_entry * pte)
        efi_guid_t unused_guid;
 
        if (!pte) {
-               printf("%s: Invalid Argument(s)\n", __func__);
+               pr_err("%s: Invalid Argument(s)\n", __func__);
                return 0;
        }
 
index eba9940231f9c925ca39d9999fcc2b5bcbe6e6dc..4492d473658a4212c7f15ee3bbf4aa51c6fc1657 100644 (file)
@@ -61,6 +61,8 @@ obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/
 obj-$(CONFIG_SPL_SATA) += ata/ scsi/
 obj-$(CONFIG_HAVE_BLOCK_DEVICE) += block/
 obj-$(CONFIG_SPL_THERMAL) += thermal/
+obj-$(CONFIG_SPL_FASTBOOT) += fastboot/
+obj-$(CONFIG_SPL_FASTBOOT) += core/
 
 endif
 endif
@@ -121,4 +123,5 @@ obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/
 obj-$(CONFIG_DM_RNG) += rng/
 endif
 
+obj-$(CONFIG_TARGET_SPACEMIT_K1X) += ddr/spacemit/k1x/
 obj-y += soc/
index 21c5209bb63e647192b794f48249ba42cda1a1e5..728ee973757ca162cbe1dc9b4bf9b819dfbe4466 100644 (file)
@@ -32,6 +32,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
        [IF_TYPE_EFI_LOADER]    = "efiloader",
        [IF_TYPE_VIRTIO]        = "virtio",
        [IF_TYPE_PVBLOCK]       = "pvblock",
+       [IF_TYPE_NOR]           = "nor",
 };
 
 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
@@ -49,6 +50,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
        [IF_TYPE_EFI_LOADER]    = UCLASS_EFI_LOADER,
        [IF_TYPE_VIRTIO]        = UCLASS_VIRTIO,
        [IF_TYPE_PVBLOCK]       = UCLASS_PVBLOCK,
+       [IF_TYPE_NOR]           = UCLASS_SPI,
 };
 
 static enum if_type if_typename_to_iftype(const char *if_typename)
index fd9e1a80c6aa0c2f4c24e22a15444577ac7f6acc..7b3ca65633ced9ec503b4e9193b693120211dedd 100644 (file)
@@ -114,6 +114,13 @@ config CLK_ICS8N3QV01
          Crystal Oscillator). The output frequency can be programmed via an
          I2C interface.
 
+config CLK_IMX
+       bool "Enable clock driver for imx"
+       depends on CLK
+       default n
+       help
+         This provides very basic support for clocks on imx SoCs.
+
 config CLK_INTEL
        bool "Enable clock driver for Intel x86"
        depends on CLK && X86
@@ -239,5 +246,6 @@ source "drivers/clk/stm32/Kconfig"
 source "drivers/clk/tegra/Kconfig"
 source "drivers/clk/ti/Kconfig"
 source "drivers/clk/uniphier/Kconfig"
+source "drivers/clk/spacemit/Kconfig"
 
 endmenu
index c274cda77c6abf2ca0946cb5f6d6f8d2688f0d39..c5a7237a3d173c64aaca0e4944b10cbbffeb41fc 100644 (file)
@@ -12,7 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o
 obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o
 
 obj-y += analogbits/
-obj-y += imx/
+obj-$(CONFIG_CLK_IMX) += imx/
 obj-y += tegra/
 obj-y += ti/
 obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/
@@ -53,3 +53,4 @@ obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
 obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
+obj-y += spacemit/
index b89c77bf79468e342b2dd1dfb4ab5f6bf5f893d9..d533f62c002cc80a23e7d6119c8c6373a94b512e 100644 (file)
@@ -54,10 +54,10 @@ int clk_get_by_phandle(struct udevice *dev, const struct phandle_1_arg *cells,
 static int clk_of_xlate_default(struct clk *clk,
                                struct ofnode_phandle_args *args)
 {
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
 
        if (args->args_count > 1) {
-               debug("Invalid args_count: %d\n", args->args_count);
+               pr_debug("Invalid args_count: %d\n", args->args_count);
                return -EINVAL;
        }
 
@@ -86,7 +86,7 @@ static int clk_get_by_index_tail(int ret, ofnode node,
 
        ret = uclass_get_device_by_ofnode(UCLASS_CLK, args->node, &dev_clk);
        if (ret) {
-               debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
+               pr_debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
                      __func__, ret);
                return log_msg_ret("get", ret);
        }
@@ -100,13 +100,13 @@ static int clk_get_by_index_tail(int ret, ofnode node,
        else
                ret = clk_of_xlate_default(clk, args);
        if (ret) {
-               debug("of_xlate() failed: %d\n", ret);
+               pr_debug("of_xlate() failed: %d\n", ret);
                return log_msg_ret("xlate", ret);
        }
 
        return clk_request(dev_clk, clk);
 err:
-       debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n",
+       pr_debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n",
              __func__, ofnode_get_name(node), list_name, index, ret);
 
        return log_msg_ret("prop", ret);
@@ -118,7 +118,7 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
        int ret;
        struct ofnode_phandle_args args;
 
-       debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
+       pr_debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
 
        assert(clk);
        clk->dev = NULL;
@@ -126,7 +126,7 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
        ret = dev_read_phandle_with_args(dev, prop_name, "#clock-cells", 0,
                                         index, &args);
        if (ret) {
-               debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
+               pr_debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
                      __func__, ret);
                return log_ret(ret);
        }
@@ -180,7 +180,7 @@ int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
 bulk_get_err:
        err = clk_release_all(bulk->clks, bulk->count);
        if (err)
-               debug("%s: could release all clocks for %p\n",
+               pr_debug("%s: could release all clocks for %p\n",
                      __func__, dev);
 
        return ret;
@@ -194,7 +194,7 @@ static struct clk *clk_set_default_get_by_id(struct clk *clk)
                int ret = clk_get_by_id(clk->id, &c);
 
                if (ret) {
-                       debug("%s(): could not get parent clock pointer, id %lu\n",
+                       pr_debug("%s(): could not get parent clock pointer, id %lu\n",
                              __func__, clk->id);
                        ERR_PTR(ret);
                }
@@ -214,7 +214,7 @@ static int clk_set_default_parents(struct udevice *dev,
        num_parents = dev_count_phandle_with_args(dev, "assigned-clock-parents",
                                                  "#clock-cells", 0);
        if (num_parents < 0) {
-               debug("%s: could not read assigned-clock-parents for %p\n",
+               pr_debug("%s: could not read assigned-clock-parents for %p\n",
                      __func__, dev);
                return 0;
        }
@@ -227,7 +227,7 @@ static int clk_set_default_parents(struct udevice *dev,
                        continue;
 
                if (ret) {
-                       debug("%s: could not get parent clock %d for %s\n",
+                       pr_debug("%s: could not get parent clock %d for %s\n",
                              __func__, index, dev_read_name(dev));
                        return ret;
                }
@@ -248,7 +248,7 @@ static int clk_set_default_parents(struct udevice *dev,
                }
 
                if (ret) {
-                       debug("%s: could not get assigned clock %d for %s\n",
+                       pr_debug("%s: could not get assigned clock %d for %s\n",
                              __func__, index, dev_read_name(dev));
                        return ret;
                }
@@ -277,7 +277,7 @@ static int clk_set_default_parents(struct udevice *dev,
                        continue;
 
                if (ret < 0) {
-                       debug("%s: failed to reparent clock %d for %s\n",
+                       pr_debug("%s: failed to reparent clock %d for %s\n",
                              __func__, index, dev_read_name(dev));
                        return ret;
                }
@@ -378,7 +378,7 @@ int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage)
                if (stage != CLK_DEFAULTS_POST_FORCE)
                        return 0;
 
-       debug("%s(%s)\n", __func__, dev_read_name(dev));
+       pr_debug("%s(%s)\n", __func__, dev_read_name(dev));
 
        ret = clk_set_default_parents(dev, stage);
        if (ret)
@@ -399,16 +399,18 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
 
 int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
 {
-       int index;
+       int index = 0;
 
-       debug("%s(node=%p, name=%s, clk=%p)\n", __func__,
+       pr_debug("%s(node=%p, name=%s, clk=%p)\n", __func__,
                ofnode_get_name(node), name, clk);
        clk->dev = NULL;
 
-       index = ofnode_stringlist_search(node, "clock-names", name);
-       if (index < 0) {
-               debug("fdt_stringlist_search() failed: %d\n", index);
-               return index;
+       if (name) {
+               index = ofnode_stringlist_search(node, "clock-names", name);
+               if (index < 0) {
+                       pr_debug("fdt_stringlist_search() failed: %d\n", index);
+                       return index;
+               }
        }
 
        return clk_get_by_index_nodev(node, index, clk);
@@ -419,7 +421,7 @@ int clk_release_all(struct clk *clk, int count)
        int i, ret;
 
        for (i = 0; i < count; i++) {
-               debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]);
+               pr_debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]);
 
                /* check if clock has been previously requested */
                if (!clk[i].dev)
@@ -439,7 +441,7 @@ int clk_request(struct udevice *dev, struct clk *clk)
 {
        const struct clk_ops *ops;
 
-       debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
+       pr_debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
        if (!clk)
                return 0;
        ops = clk_dev_ops(dev);
@@ -456,7 +458,7 @@ void clk_free(struct clk *clk)
 {
        const struct clk_ops *ops;
 
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
        if (!clk_valid(clk))
                return;
        ops = clk_dev_ops(clk->dev);
@@ -469,9 +471,8 @@ void clk_free(struct clk *clk)
 ulong clk_get_rate(struct clk *clk)
 {
        const struct clk_ops *ops;
-       int ret;
 
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
        if (!clk_valid(clk))
                return 0;
        ops = clk_dev_ops(clk->dev);
@@ -479,11 +480,7 @@ ulong clk_get_rate(struct clk *clk)
        if (!ops->get_rate)
                return -ENOSYS;
 
-       ret = ops->get_rate(clk);
-       if (ret)
-               return log_ret(ret);
-
-       return 0;
+       return ops->get_rate(clk);
 }
 
 struct clk *clk_get_parent(struct clk *clk)
@@ -491,7 +488,7 @@ struct clk *clk_get_parent(struct clk *clk)
        struct udevice *pdev;
        struct clk *pclk;
 
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
        if (!clk_valid(clk))
                return NULL;
 
@@ -505,12 +502,12 @@ struct clk *clk_get_parent(struct clk *clk)
        return pclk;
 }
 
-long long clk_get_parent_rate(struct clk *clk)
+ulong clk_get_parent_rate(struct clk *clk)
 {
        const struct clk_ops *ops;
        struct clk *pclk;
 
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
        if (!clk_valid(clk))
                return 0;
 
@@ -533,7 +530,7 @@ ulong clk_round_rate(struct clk *clk, ulong rate)
 {
        const struct clk_ops *ops;
 
-       debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
+       pr_debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
        if (!clk_valid(clk))
                return 0;
 
@@ -544,6 +541,19 @@ ulong clk_round_rate(struct clk *clk, ulong rate)
        return ops->round_rate(clk, rate);
 }
 
+static void clk_get_priv(struct clk *clk, struct clk **clkp)
+{
+       *clkp = clk;
+
+       /* get private clock struct associated to the provided clock */
+       if (CONFIG_IS_ENABLED(CLK_CCF)) {
+               /* Take id 0 as a non-valid clk, such as dummy */
+               if (clk->id)
+                       clk_get_by_id(clk->id, clkp);
+       }
+}
+
+/* clean cache, called with private clock struct */
 static void clk_clean_rate_cache(struct clk *clk)
 {
        struct udevice *child_dev;
@@ -563,8 +573,9 @@ static void clk_clean_rate_cache(struct clk *clk)
 ulong clk_set_rate(struct clk *clk, ulong rate)
 {
        const struct clk_ops *ops;
+       struct clk *clkp;
 
-       debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
+       pr_debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
        if (!clk_valid(clk))
                return 0;
        ops = clk_dev_ops(clk->dev);
@@ -572,8 +583,10 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
        if (!ops->set_rate)
                return -ENOSYS;
 
+       /* get private clock struct used for cache */
+       clk_get_priv(clk, &clkp);
        /* Clean up cached rates for us and all child clocks */
-       clk_clean_rate_cache(clk);
+       clk_clean_rate_cache(clkp);
 
        return ops->set_rate(clk, rate);
 }
@@ -581,9 +594,12 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
        const struct clk_ops *ops;
+       struct clk *clkp;
+       struct clk *parentp;
+       struct clk *cur_parent;
        int ret;
 
-       debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
+       pr_debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
        if (!clk_valid(clk))
                return 0;
        ops = clk_dev_ops(clk->dev);
@@ -595,8 +611,31 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        if (ret)
                return ret;
 
+       /* get private clock struct used for cache */
+       clk_get_priv(clk, &clkp);
+       clk_get_priv(parent, &parentp);
+       if (CONFIG_IS_ENABLED(CLK_CCF)) {
+               if (clkp->enable_count)
+                       clk_enable(parent);
+               if (clkp->dev->parent) {
+                       cur_parent = dev_get_clk_ptr(clkp->dev->parent);
+                       if (clkp->enable_count && cur_parent->enable_count) {
+                               if (device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
+                                       ret = clk_disable(cur_parent);
+                                       if (ret) {
+                                               pr_debug("Disable %s failed\n", clkp->dev->parent->name);
+                                               return ret;
+                                       }
+                               }
+                       }
+
+               }
+       }
        if (CONFIG_IS_ENABLED(CLK_CCF))
-               ret = device_reparent(clk->dev, parent->dev);
+               ret = device_reparent(clkp->dev, parentp->dev);
+
+       /* Clean up cached rates for us and all child clocks */
+       clk_clean_rate_cache(clkp);
 
        return ret;
 }
@@ -607,7 +646,7 @@ int clk_enable(struct clk *clk)
        struct clk *clkp = NULL;
        int ret;
 
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
        if (!clk_valid(clk))
                return 0;
        ops = clk_dev_ops(clk->dev);
@@ -623,7 +662,7 @@ int clk_enable(struct clk *clk)
                            device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
                                ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent));
                                if (ret) {
-                                       printf("Enable %s failed\n",
+                                       pr_debug("Enable %s failed\n",
                                               clkp->dev->parent->name);
                                        return ret;
                                }
@@ -633,7 +672,7 @@ int clk_enable(struct clk *clk)
                if (ops->enable) {
                        ret = ops->enable(clk);
                        if (ret) {
-                               printf("Enable %s failed\n", clk->dev->name);
+                               pr_debug("Enable %s failed\n", clk->dev->name);
                                return ret;
                        }
                }
@@ -667,7 +706,7 @@ int clk_disable(struct clk *clk)
        struct clk *clkp = NULL;
        int ret;
 
-       debug("%s(clk=%p)\n", __func__, clk);
+       pr_debug("%s(clk=%p)\n", __func__, clk);
        if (!clk_valid(clk))
                return 0;
        ops = clk_dev_ops(clk->dev);
@@ -678,7 +717,7 @@ int clk_disable(struct clk *clk)
                                return 0;
 
                        if (clkp->enable_count == 0) {
-                               printf("clk %s already disabled\n",
+                               pr_debug("clk %s already disabled\n",
                                       clkp->dev->name);
                                return 0;
                        }
@@ -697,7 +736,7 @@ int clk_disable(struct clk *clk)
                    device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
                        ret = clk_disable(dev_get_clk_ptr(clkp->dev->parent));
                        if (ret) {
-                               printf("Disable %s failed\n",
+                               pr_debug("Disable %s failed\n",
                                       clkp->dev->parent->name);
                                return ret;
                        }
diff --git a/drivers/clk/spacemit/Kconfig b/drivers/clk/spacemit/Kconfig
new file mode 100644 (file)
index 0000000..8a78dc8
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+# common clock support for SPACEMIT SoC family.
+
+config SPACEMIT_K1PRO_CCU
+       tristate "Clock support for Spacemit k1pro SoCs"
+       depends on CLK
+        depends on CLK_CCF
+       help
+         Build the driver for Spacemit K1pro Clock Driver.
+
+config SPACEMIT_K1X_CCU
+        tristate "Clock support for Spacemit k1x SoCs"
+        select CLK
+        select CLK_CCF
+        help
+          Build the driver for Spacemit K1x Clock Driver.
+
+
diff --git a/drivers/clk/spacemit/Makefile b/drivers/clk/spacemit/Makefile
new file mode 100644 (file)
index 0000000..cef90d6
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Spacemit Clock specific Makefile
+#
+#SoC support
+obj-$(CONFIG_SPACEMIT_K1PRO_CCU) += ccu-k1pro.o ccu-pll-k1pro.o
+obj-$(CONFIG_SPACEMIT_K1X_CCU) += ccu-k1x.o ccu_mix.o
+obj-$(CONFIG_$(SPL_TPL_)SPACEMIT_K1X_CCU) += ccu_ddn.o ccu_pll.o
diff --git a/drivers/clk/spacemit/ccu-k1x.c b/drivers/clk/spacemit/ccu-k1x.c
new file mode 100644 (file)
index 0000000..1a199e6
--- /dev/null
@@ -0,0 +1,1765 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit k1x clock controller driver
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <dt-bindings/clock/spacemit-k1x-clock.h>
+#include <linux/clk-provider.h>
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/io.h>
+#include "ccu-k1x.h"
+#include "ccu_mix.h"
+#include "ccu_pll.h"
+#include "ccu_ddn.h"
+
+/* APBS register offset */
+//pll1
+#define APB_SPARE1_REG          0x100
+#define APB_SPARE2_REG          0x104
+#define APB_SPARE3_REG          0x108
+//pll2
+#define APB_SPARE7_REG          0x118
+#define APB_SPARE8_REG          0x11c
+#define APB_SPARE9_REG          0x120
+//pll3
+#define APB_SPARE10_REG         0x124
+#define APB_SPARE11_REG         0x128
+#define APB_SPARE12_REG         0x12c
+/* end of APBS register offset */
+
+/* APBC register offset */
+#define APBC_UART1_CLK_RST      0x0
+#define APBC_UART2_CLK_RST      0x4
+#define APBC_GPIO_CLK_RST       0x8
+#define APBC_PWM0_CLK_RST       0xc
+#define APBC_PWM1_CLK_RST       0x10
+#define APBC_PWM2_CLK_RST       0x14
+#define APBC_PWM3_CLK_RST       0x18
+#define APBC_TWSI8_CLK_RST      0x20
+#define APBC_UART3_CLK_RST      0x24
+#define APBC_RTC_CLK_RST        0x28 //reserved
+#define APBC_TWSI0_CLK_RST      0x2c
+#define APBC_TWSI1_CLK_RST      0x30
+#define APBC_TIMERS1_CLK_RST    0x34
+#define APBC_TWSI2_CLK_RST      0x38
+#define APBC_AIB_CLK_RST        0x3c
+#define APBC_TWSI4_CLK_RST      0x40
+#define APBC_TIMERS2_CLK_RST    0x44
+#define APBC_ONEWIRE_CLK_RST    0x48
+#define APBC_TWSI5_CLK_RST      0x4c
+#define APBC_DRO_CLK_RST        0x58
+#define APBC_IR_CLK_RST         0x5c
+#define APBC_TWSI6_CLK_RST      0x60
+#define APBC_COUNTER_CLK_SEL    0x64
+
+#define APBC_TWSI7_CLK_RST      0x68
+#define APBC_TSEN_CLK_RST       0x6c
+
+#define APBC_UART4_CLK_RST      0x70
+#define APBC_UART5_CLK_RST      0x74
+#define APBC_UART6_CLK_RST      0x78
+#define APBC_SSP3_CLK_RST       0x7c
+
+#define APBC_SSPA0_CLK_RST      0x80
+#define APBC_SSPA1_CLK_RST      0x84
+
+#define APBC_IPC_AP2AUD_CLK_RST 0x90
+#define APBC_UART7_CLK_RST      0x94
+#define APBC_UART8_CLK_RST      0x98
+#define APBC_UART9_CLK_RST      0x9c
+
+#define APBC_CAN0_CLK_RST       0xa0
+#define APBC_PWM4_CLK_RST       0xa8
+#define APBC_PWM5_CLK_RST       0xac
+#define APBC_PWM6_CLK_RST       0xb0
+#define APBC_PWM7_CLK_RST       0xb4
+#define APBC_PWM8_CLK_RST       0xb8
+#define APBC_PWM9_CLK_RST       0xbc
+#define APBC_PWM10_CLK_RST      0xc0
+#define APBC_PWM11_CLK_RST      0xc4
+#define APBC_PWM12_CLK_RST      0xc8
+#define APBC_PWM13_CLK_RST      0xcc
+#define APBC_PWM14_CLK_RST      0xd0
+#define APBC_PWM15_CLK_RST      0xd4
+#define APBC_PWM16_CLK_RST      0xd8
+#define APBC_PWM17_CLK_RST      0xdc
+#define APBC_PWM18_CLK_RST      0xe0
+#define APBC_PWM19_CLK_RST      0xe4
+/* end of APBC register offset */
+
+/* MPMU register offset */
+#define MPMU_POSR                      0x10 //no define
+#define POSR_PLL1_LOCK                 BIT(27)
+#define POSR_PLL2_LOCK                 BIT(28)
+#define POSR_PLL3_LOCK                 BIT(29)
+
+#define MPMU_VRCR                      0x18 //no define
+#define MPMU_VRCR_REQ_EN0              BIT(0)
+#define MPMU_VRCR_REQ_EN2              BIT(2)
+#define MPMU_VRCR_REQ_POL2             BIT(6)
+#define MPMU_VRCR_VCXO_OUT_REQ_EN2     BIT(14)
+
+#define MPMU_WDTPCR     0x200
+#define MPMU_RIPCCR     0x210 //no define
+#define MPMU_ACGR       0x1024
+#define MPMU_SUCCR      0x14
+#define MPMU_SUCCR_1    0x10b0
+#define MPMU_APBCSCR    0x1050
+
+/* end of MPMU register offset */
+
+/* APMU register offset */
+#define APMU_JPG_CLK_RES_CTRL       0x20
+#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24
+#define APMU_ISP_CLK_RES_CTRL       0x38
+#define APMU_LCD_CLK_RES_CTRL1      0x44
+#define APMU_LCD_SPI_CLK_RES_CTRL   0x48
+#define APMU_LCD_CLK_RES_CTRL2      0x4c
+#define APMU_CCIC_CLK_RES_CTRL      0x50
+#define APMU_SDH0_CLK_RES_CTRL      0x54
+#define APMU_SDH1_CLK_RES_CTRL      0x58
+#define APMU_USB_CLK_RES_CTRL       0x5c
+#define APMU_QSPI_CLK_RES_CTRL      0x60
+#define APMU_USB_CLK_RES_CTRL       0x5c
+#define APMU_DMA_CLK_RES_CTRL       0x64
+#define APMU_AES_CLK_RES_CTRL       0x68
+#define APMU_VPU_CLK_RES_CTRL       0xa4
+#define APMU_GPU_CLK_RES_CTRL       0xcc
+#define APMU_SDH2_CLK_RES_CTRL      0xe0
+#define APMU_PMUA_MC_CTRL           0xe8
+#define APMU_PMU_CC2_AP             0x100
+#define APMU_PMUA_EM_CLK_RES_CTRL   0x104
+
+#define APMU_AUDIO_CLK_RES_CTRL     0x14c
+#define APMU_HDMI_CLK_RES_CTRL      0x1B8
+#define APMU_CCI550_CLK_CTRL        0x300
+#define APMU_ACLK_CLK_CTRL          0x388
+#define APMU_CPU_C0_CLK_CTRL        0x38C
+#define APMU_CPU_C1_CLK_CTRL        0x390
+
+#define APMU_PCIE_CLK_RES_CTRL_0    0x3cc
+#define APMU_PCIE_CLK_RES_CTRL_1    0x3d4
+#define APMU_PCIE_CLK_RES_CTRL_2    0x3dc
+
+#define APMU_EMAC0_CLK_RES_CTRL     0x3e4
+#define APMU_EMAC1_CLK_RES_CTRL     0x3ec
+/* end of APMU register offset */
+
+/* APBC2 register offset */
+#define APBC2_UART1_CLK_RST            0x00
+#define APBC2_SSP2_CLK_RST             0x04
+#define APBC2_TWSI3_CLK_RST            0x08
+#define APBC2_RTC_CLK_RST              0x0c
+#define APBC2_TIMERS0_CLK_RST          0x10
+#define APBC2_KPC_CLK_RST              0x14
+#define APBC2_GPIO_CLK_RST             0x1c
+/* end of APBC2 register offset */
+
+struct spacemit_k1x_clk k1x_clock_controller;
+struct clk vctcxo_24, vctcxo_3, vctcxo_1, pll1_vco, clk_32k, clk_dummy;
+
+#ifdef CONFIG_SPL_BUILD
+//apbs
+static SPACEMIT_CCU_FACTOR(pll1_2457p6_vco, "pll1_2457p6_vco", "pll1_vco",
+       1, 100);
+
+//pll1
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d2, "pll1_d2", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d4, "pll1_d4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d6, "pll1_d6", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d8, "pll1_d8", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d23_106p8, "pll1_d23_106p8", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(20), BIT(20), 0x0,
+       23, 1, 0);
+//pll1_d6
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d12_204p8, "pll1_d12_204p8", "pll1_d6",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(5), BIT(5), 0x0,
+       2, 1, 0);
+static SPACEMIT_CCU_GATE(pll1_d6_409p6, "pll1_d6_409p6", "pll1_d6",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(0), BIT(0), 0x0,
+       0);
+//pll1_d4
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d78_31p5, "pll1_d78_31p5", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(6), BIT(6), 0x0,
+       39, 2, 0);
+//pll1_d2
+static SPACEMIT_CCU_GATE(pll1_d2_1228p8, "pll1_d2_1228p8", "pll1_d2",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(16), BIT(16), 0x0,
+       0);
+//pll1_d8
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d24_102p4, "pll1_d24_102p4", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(12), BIT(12), 0x0,
+       3, 1, 0);
+//apbc
+static const char *twsi_parent_names[] = {
+       "pll1_d78_31p5",
+};
+static SPACEMIT_CCU_MUX_GATE(twsi6_clk, "twsi6_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI6_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi8_clk, "twsi8_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI8_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(sdh_axi_aclk, "sdh_axi_aclk", NULL,
+       BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const sdh01_parent_names[] = {
+       "pll1_d6_409p6",
+ };
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh0_clk, "sdh0_clk", sdh01_parent_names,
+       BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const sdh2_parent_names[] = {
+       "pll1_d6_409p6",
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh2_clk, "sdh2_clk", sdh2_parent_names,
+       BASE_TYPE_APMU, APMU_SDH2_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb_axi_clk, "usb_axi_clk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb_p1_aclk, "usb_p1_aclk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb30_clk, "usb30_clk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(8), BIT(8), 0x0,
+       0);
+static const char * const qspi_parent_names[] = {"clk_dummy", "clk_dummy", "clk_dummy",
+               "clk_dummy", "clk_dummy", "pll1_d23_106p8"};
+static SPACEMIT_CCU_DIV_MFC_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names,
+       BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
+       9, 3, BIT(12),
+       6, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(qspi_bus_clk, "qspi_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const aes_parent_names[] = {
+       "clk_dummy", "pll1_d24_102p4"
+};
+static SPACEMIT_CCU_MUX_GATE(aes_clk, "aes_clk", aes_parent_names,
+       BASE_TYPE_APMU, APMU_AES_CLK_RES_CTRL,
+       6, 1, BIT(5), BIT(5), 0x0,
+       0);
+
+static u32 transfer_to_spl_list[][2] = {
+       {CLK_TWSI6, CLK_TWSI6_SPL},
+       {CLK_TWSI8, CLK_TWSI8_SPL},
+       {CLK_SDH_AXI, CLK_SDH_AXI_SPL},
+       {CLK_SDH0, CLK_SDH0_SPL},
+       {CLK_SDH2, CLK_SDH2_SPL},
+       {CLK_USB_P1, CLK_USB_P1_SPL},
+       {CLK_USB_AXI, CLK_USB_AXI_SPL},
+       {CLK_USB30, CLK_USB30_SPL},
+       {CLK_QSPI, CLK_QSPI_SPL},
+       {CLK_QSPI_BUS, CLK_QSPI_BUS_SPL},
+       {CLK_AES, CLK_AES_SPL},
+};
+
+static struct spacemit_clk_table spacemit_k1x_clks = {
+       .clks   = {
+               [CLK_PLL1_2457P6_SPL]    = &pll1_2457p6_vco.common.clk,
+               [CLK_PLL1_D2_SPL]        = &pll1_d2.common.clk,
+               [CLK_PLL1_D4_SPL]        = &pll1_d4.common.clk,
+               [CLK_PLL1_D6_SPL]        = &pll1_d6.common.clk,
+               [CLK_PLL1_D23_SPL]       = &pll1_d23_106p8.common.clk,
+               [CLK_PLL1_409P6_SPL] = &pll1_d6_409p6.common.clk,
+               [CLK_PLL1_D8_SPL]               = &pll1_d8.common.clk,
+               [CLK_PLL1_31P5_SPL]      = &pll1_d78_31p5.common.clk,
+               [CLK_PLL1_1228_SPL]      = &pll1_d2_1228p8.common.clk,
+               [CLK_TWSI6_SPL]      = &twsi6_clk.common.clk,
+               [CLK_TWSI8_SPL]      = &twsi8_clk.common.clk,
+               [CLK_SDH_AXI_SPL]        = &sdh_axi_aclk.common.clk,
+               [CLK_SDH0_SPL]       = &sdh0_clk.common.clk,
+               [CLK_SDH2_SPL]       = &sdh2_clk.common.clk,
+               [CLK_USB_P1_SPL]     = &usb_p1_aclk.common.clk,
+               [CLK_USB_AXI_SPL]        = &usb_axi_clk.common.clk,
+               [CLK_USB30_SPL]      = &usb30_clk.common.clk,
+               [CLK_QSPI_SPL]       = &qspi_clk.common.clk,
+               [CLK_QSPI_BUS_SPL]       = &qspi_bus_clk.common.clk,
+               [CLK_PLL1_204P8_SPL]    = &pll1_d12_204p8.common.clk,
+               [CLK_PLL1_102P4_SPL]    = &pll1_d24_102p4.common.clk,
+               [CLK_AES_SPL]           = &aes_clk.common.clk,
+       },
+       .num = CLK_MAX_NO_SPL,
+};
+
+ulong transfer_clk_id_to_spl(ulong id)
+{
+       u32 listsize = ARRAY_SIZE(transfer_to_spl_list);
+
+       for (int i = 0; i < listsize; i++){
+               if (id == transfer_to_spl_list[i][0]){
+                       pr_info("id:%ld, %d,\n", id, transfer_to_spl_list[i][1]);
+                       return transfer_to_spl_list[i][1];
+               }
+       }
+       return id;
+}
+#else
+
+//apbs
+static SPACEMIT_CCU_FACTOR(pll1_2457p6_vco, "pll1_2457p6_vco", "pll1_vco",
+       1, 100);
+
+static const struct ccu_pll_rate_tbl pll2_rate_tbl[] = {
+       PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000),
+       PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab),
+       PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd),
+       PLL_RATE(2800000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3a, 0x155555),
+};
+
+static const struct ccu_pll_rate_tbl pll3_rate_tbl[] = {
+       PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000),
+       PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab),
+       PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd),
+};
+
+static SPACEMIT_CCU_PLL(pll2, "pll2", &pll2_rate_tbl, ARRAY_SIZE(pll2_rate_tbl),
+       BASE_TYPE_APBS, APB_SPARE7_REG, APB_SPARE8_REG, APB_SPARE9_REG,
+       MPMU_POSR, POSR_PLL2_LOCK, 1,
+       0);
+
+static SPACEMIT_CCU_PLL(pll3, "pll3", &pll3_rate_tbl, ARRAY_SIZE(pll3_rate_tbl),
+       BASE_TYPE_APBS, APB_SPARE10_REG, APB_SPARE11_REG, APB_SPARE12_REG,
+       MPMU_POSR, POSR_PLL3_LOCK, 1,
+       0);
+
+//pll1
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d2, "pll1_d2", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d3, "pll1_d3", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(2), BIT(2), 0x0,
+       3, 1, 0);
+
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d4, "pll1_d4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d5, "pll1_d5", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(4), BIT(4), 0x0,
+       5, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d6, "pll1_d6", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d7, "pll1_d7", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(6), BIT(6), 0x0,
+       7, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d8, "pll1_d8", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d11_223p4, "pll1_d11_223p4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(15), BIT(15), 0x0,
+       11, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d13_189, "pll1_d13_189", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(16), BIT(16), 0x0,
+       13, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d23_106p8, "pll1_d23_106p8", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(20), BIT(20), 0x0,
+       23, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d64_38p4, "pll1_d64_38p4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(0), BIT(0), 0x0,
+       64, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_245p7, "pll1_aud_245p7", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(10), BIT(10), 0x0,
+       10, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_24p5, "pll1_aud_24p5", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(11), BIT(11), 0x0,
+       100, 1, 0);
+
+//pll2
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d1, "pll2_d1", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(0), BIT(0), 0x0,
+       1, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d2, "pll2_d2", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d3, "pll2_d3", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(2), BIT(2), 0x0,
+       3, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d4, "pll2_d4", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d5, "pll2_d5", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(4), BIT(4), 0x0,
+       5, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d6, "pll2_d6", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d7, "pll2_d7", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(6), BIT(6), 0x0,
+       7, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d8, "pll2_d8", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, 0);
+
+//pll3
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d1, "pll3_d1", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(0), BIT(0), 0x0,
+       1, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d2, "pll3_d2", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d3, "pll3_d3", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(2), BIT(2), 0x0,
+       3, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d4, "pll3_d4", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d5, "pll3_d5", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(4), BIT(4), 0x0,
+       5, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d6, "pll3_d6", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d7, "pll3_d7", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(6), BIT(6), 0x0,
+       7, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d8, "pll3_d8", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, 0);
+
+//pll1_d8
+static SPACEMIT_CCU_GATE(pll1_d8_307p2, "pll1_d8_307p2", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(13), BIT(13), 0x0,
+       0);
+static SPACEMIT_CCU_FACTOR(pll1_d32_76p8, "pll1_d32_76p8", "pll1_d8_307p2",
+       4, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d40_61p44, "pll1_d40_61p44", "pll1_d8_307p2",
+       5, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d16_153p6, "pll1_d16_153p6", "pll1_d8",
+       2, 1);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d24_102p4, "pll1_d24_102p4", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(12), BIT(12), 0x0,
+       3, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2, "pll1_d48_51p2", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(7), BIT(7), 0x0,
+       6, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2_ap, "pll1_d48_51p2_ap", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(11), BIT(11), 0x0,
+       6, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_m3d128_57p6, "pll1_m3d128_57p6", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(8), BIT(8), 0x0,
+       16, 3, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d96_25p6, "pll1_d96_25p6", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(4), BIT(4), 0x0,
+       12, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8, "pll1_d192_12p8", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(3), BIT(3), 0x0,
+       24, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8_wdt, "pll1_d192_12p8_wdt", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(19), BIT(19), 0x0,
+       24, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d384_6p4, "pll1_d384_6p4", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(2), BIT(2), 0x0,
+       48, 1, 0);
+static SPACEMIT_CCU_FACTOR(pll1_d768_3p2, "pll1_d768_3p2", "pll1_d384_6p4",
+       2, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d1536_1p6, "pll1_d1536_1p6", "pll1_d384_6p4",
+       4, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d3072_0p8, "pll1_d3072_0p8", "pll1_d384_6p4",
+       8, 1);
+//pll1_d7
+static SPACEMIT_CCU_FACTOR(pll1_d7_351p08, "pll1_d7_351p08", "pll1_d7",
+       1, 1);
+//pll1_d6
+static SPACEMIT_CCU_GATE(pll1_d6_409p6, "pll1_d6_409p6", "pll1_d6",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(0), BIT(0), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d12_204p8, "pll1_d12_204p8", "pll1_d6",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(5), BIT(5), 0x0,
+       2, 1, 0);
+//pll1_d5
+static SPACEMIT_CCU_GATE(pll1_d5_491p52, "pll1_d5_491p52", "pll1_d5",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(21), BIT(21), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d10_245p76, "pll1_d10_245p76", "pll1_d5",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(18), BIT(18), 0x0,
+       2, 1, 0);
+//pll1_d4
+static SPACEMIT_CCU_GATE(pll1_d4_614p4, "pll1_d4_614p4", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(15), BIT(15), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d52_47p26, "pll1_d52_47p26", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(10), BIT(10), 0x0,
+       13, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d78_31p5, "pll1_d78_31p5", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(6), BIT(6), 0x0,
+       39, 2, 0);
+//pll1_d3
+static SPACEMIT_CCU_GATE(pll1_d3_819p2, "pll1_d3_819p2", "pll1_d3",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(14), BIT(14), 0x0,
+       0);
+//pll1_d2
+static SPACEMIT_CCU_GATE(pll1_d2_1228p8, "pll1_d2_1228p8", "pll1_d2",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(16), BIT(16), 0x0,
+       0);
+
+//mpmu
+static struct ccu_ddn_info uart_ddn_mask_info = {
+       .factor = 2,
+       .num_mask = 0x1fff,
+       .den_mask = 0x1fff,
+       .num_shift = 16,
+       .den_shift = 0,
+};
+static struct ccu_ddn_tbl slow_uart1_tbl[] = {
+       {.num = 125, .den = 24}, /*rate = parent_rate*24/125/2) */
+};
+static struct ccu_ddn_tbl slow_uart2_tbl[] = {
+       {.num = 6144, .den = 960},/*rate = parent_rate*960/6144/2) */
+};
+static SPACEMIT_CCU_DDN_GATE(slow_uart1_14p74, "slow_uart1_14p74", "pll1_d16_153p6",
+       &uart_ddn_mask_info, &slow_uart1_tbl, ARRAY_SIZE(slow_uart1_tbl),
+       BASE_TYPE_MPMU, MPMU_SUCCR, MPMU_ACGR, BIT(1),
+       0);
+static SPACEMIT_CCU_DDN_GATE(slow_uart2_48, "slow_uart2_48", "pll1_d4_614p4",
+       &uart_ddn_mask_info, &slow_uart2_tbl, ARRAY_SIZE(slow_uart2_tbl),
+       BASE_TYPE_MPMU, MPMU_SUCCR_1, MPMU_ACGR, BIT(1),
+       0);
+
+//apbc
+static const char * const uart_parent_names[] = {
+       "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48"
+};
+static SPACEMIT_CCU_MUX_GATE(uart1_clk, "uart1_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart2_clk, "uart2_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart3_clk, "uart3_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart4_clk, "uart4_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART4_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart5_clk, "uart5_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART5_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart6_clk, "uart6_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART6_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart7_clk, "uart7_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART7_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart8_clk, "uart8_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART8_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart9_clk, "uart9_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART9_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(gpio_clk, "gpio_clk", "vctcxo_24",
+       BASE_TYPE_APBC, APBC_GPIO_CLK_RST,
+       0x3, 0x3, 0x0,
+       0);
+static const char *pwm_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k"
+};
+static SPACEMIT_CCU_MUX_GATE(pwm0_clk, "pwm0_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm1_clk, "pwm1_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm2_clk, "pwm2_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm3_clk, "pwm3_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm4_clk, "pwm4_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM4_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm5_clk, "pwm5_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM5_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm6_clk, "pwm6_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM6_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm7_clk, "pwm7_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM7_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm8_clk, "pwm8_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM8_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm9_clk, "pwm9_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM9_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm10_clk, "pwm10_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM10_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm11_clk, "pwm11_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM11_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm12_clk, "pwm12_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM12_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm13_clk, "pwm13_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM13_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm14_clk, "pwm14_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM14_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm15_clk, "pwm15_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM15_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm16_clk, "pwm16_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM16_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm17_clk, "pwm17_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM17_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm18_clk, "pwm18_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM18_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm19_clk, "pwm19_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM19_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static const char *ssp_parent_names[] = { "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6",
+       "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8"
+};
+static SPACEMIT_CCU_MUX_GATE(ssp3_clk, "ssp3_clk", ssp_parent_names,
+       BASE_TYPE_APBC, APBC_SSP3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(rtc_clk, "rtc_clk", "clk_32k",
+       BASE_TYPE_APBC, APBC_RTC_CLK_RST,
+       0x83, 0x83, 0x0, 0);
+static const char *twsi_parent_names[] = {
+       "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44"
+};
+static SPACEMIT_CCU_MUX_GATE(twsi0_clk, "twsi0_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi1_clk, "twsi1_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi2_clk, "twsi2_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi4_clk, "twsi4_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI4_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi5_clk, "twsi5_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI5_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi6_clk, "twsi6_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI6_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi7_clk, "twsi7_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI7_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi8_clk, "twsi8_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI8_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static const char *timer_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1"
+};
+static SPACEMIT_CCU_MUX_GATE(timers1_clk, "timers1_clk", timer_parent_names,
+       BASE_TYPE_APBC, APBC_TIMERS1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(timers2_clk, "timers2_clk", timer_parent_names,
+       BASE_TYPE_APBC, APBC_TIMERS2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(aib_clk, "aib_clk", "vctcxo_24",
+       BASE_TYPE_APBC, APBC_AIB_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(onewire_clk, "onewire_clk", NULL,
+       BASE_TYPE_APBC, APBC_ONEWIRE_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+
+static const char *sspa_parent_names[] = { "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6",
+       "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8"
+};
+static SPACEMIT_CCU_MUX_GATE(sspa0_clk, "sspa0_clk", sspa_parent_names,
+       BASE_TYPE_APBC, APBC_SSPA0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(sspa1_clk, "sspa1_clk", sspa_parent_names,
+       BASE_TYPE_APBC, APBC_SSPA1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dro_clk, "dro_clk", NULL,
+       BASE_TYPE_APBC, APBC_DRO_CLK_RST,
+       0x1, 0x1, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(ir_clk, "ir_clk", NULL,
+       BASE_TYPE_APBC, APBC_IR_CLK_RST,
+       0x1, 0x1, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(tsen_clk, "tsen_clk", NULL,
+       BASE_TYPE_APBC, APBC_TSEN_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(ipc_ap2aud_clk, "ipc_ap2aud_clk", NULL,
+       BASE_TYPE_APBC, APBC_IPC_AP2AUD_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+static const char *can_parent_names[] = {
+       "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48"
+};
+static SPACEMIT_CCU_MUX_GATE(can0_clk, "can0_clk", can_parent_names,
+       BASE_TYPE_APBC, APBC_CAN0_CLK_RST,
+       4, 3, BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(can0_bus_clk, "can0_bus_clk", NULL,
+       BASE_TYPE_APBC, APBC_CAN0_CLK_RST,
+       BIT(0), BIT(0), 0x0, 0);
+
+//mpmu
+static SPACEMIT_CCU_GATE(wdt_clk, "wdt_clk", "pll1_d96_25p6",
+       BASE_TYPE_MPMU, MPMU_WDTPCR,
+       0x3, 0x3, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(ripc_clk, "ripc_clk", NULL,
+       BASE_TYPE_MPMU, MPMU_RIPCCR,
+       0x3, 0x3, 0x0, 0);
+
+//apmu
+static const char * const jpg_parent_names[] = {
+        "pll1_d4_614p4", "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d3_819p2",
+        "pll1_d2_1228p8", "pll2_d4", "pll2_d3"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(jpg_clk, "jpg_clk", jpg_parent_names,
+       BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL,
+       5, 3, BIT(15),
+       2, 3, BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(jpg_4kafbc_clk, "jpg_4kafbc_clk", NULL,
+       BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL,
+       BIT(16), BIT(16), 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(jpg_2kafbc_clk, "jpg_2kafbc_clk", NULL,
+       BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL,
+       BIT(17), BIT(17), 0x0, 0);
+static const char * const ccic2phy_parent_names[] = {
+       "pll1_d24_102p4", "pll1_d48_51p2_ap"
+};
+static SPACEMIT_CCU_MUX_GATE(ccic2phy_clk, "ccic2phy_clk", ccic2phy_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       7, 1, BIT(5), BIT(5), 0x0,
+       0);
+static const char * const ccic3phy_parent_names[] = {
+       "pll1_d24_102p4", "pll1_d48_51p2_ap"
+};
+static SPACEMIT_CCU_MUX_GATE(ccic3phy_clk, "ccic3phy_clk", ccic3phy_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       31, 1, BIT(30), BIT(30), 0x0, 0);
+static const char * const csi_parent_names[] = {
+        "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2",
+        "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(csi_clk, "csi_clk", csi_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       20, 3, BIT(15),
+       16, 3, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const camm_parent_names[] = {
+       "pll1_d8_307p2", "pll2_d5", "pll1_d6_409p6", "vctcxo_24"
+};
+static SPACEMIT_CCU_DIV_MUX_GATE(camm0_clk, "camm0_clk", camm_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       23, 4, 8, 2,
+       BIT(28), BIT(28), 0x0,
+       0);
+static SPACEMIT_CCU_DIV_MUX_GATE(camm1_clk, "camm1_clk", camm_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       23, 4, 8, 2,
+       BIT(6), BIT(6), 0x0,
+       0);
+static SPACEMIT_CCU_DIV_MUX_GATE(camm2_clk, "camm2_clk", camm_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       23, 4, 8, 2,
+       BIT(27), BIT(27), 0x0,
+       0);
+static const char * const isp_cpp_parent_names[] = {
+        "pll1_d8_307p2", "pll1_d6_409p6"
+};
+static SPACEMIT_CCU_DIV_MUX_GATE(isp_cpp_clk, "isp_cpp_clk", isp_cpp_parent_names,
+       BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL,
+       24, 2, 26, 1,
+       BIT(28), BIT(28), 0x0,
+       0);
+static const char * const isp_bus_parent_names[] = {
+        "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d8_307p2", "pll1_d10_245p76"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_bus_clk, "isp_bus_clk", isp_bus_parent_names,
+       BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL,
+       18, 3, BIT(23),
+       21, 2, BIT(17), BIT(17), 0x0,
+       0);
+static const char * const isp_parent_names[] = {
+        "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_clk, "isp_clk", isp_parent_names,
+       BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL,
+       4, 3, BIT(7),
+       8, 2, BIT(1), BIT(1), 0x0,
+       0);
+static const char * const dpumclk_parent_names[] = {
+       "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_mclk, "dpu_mclk", dpumclk_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2,
+       1, 4, BIT(29),
+       5, 3, BIT(0), BIT(0), 0x0,
+       0);
+static const char * const dpuesc_parent_names[] = {
+       "pll1_d48_51p2_ap", "pll1_d52_47p26", "pll1_d96_25p6", "pll1_d32_76p8"
+};
+static SPACEMIT_CCU_MUX_GATE(dpu_esc_clk, "dpu_esc_clk", dpuesc_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       0, 2, BIT(2), BIT(2), 0x0,
+       0);
+static const char * const dpubit_parent_names[] = { "pll1_d3_819p2", "pll2_d2", "pll2_d3",
+       "pll1_d2_1228p8", "pll2_d4", "pll2_d5", "pll2_d8", "pll2_d8" //6 should be 429M?
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_bit_clk, "dpu_bit_clk", dpubit_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       17, 3, BIT(31),
+       20, 3, BIT(16), BIT(16), 0x0,
+       0);
+static const char * const dpupx_parent_names[] = {
+       "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2", "pll2_d7", "pll2_d8"
+};
+static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_pxclk, "dpu_pxclk", dpupx_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2,
+       17, 4, BIT(30),
+       21, 3, BIT(16), BIT(16), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_hclk, "dpu_hclk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       BIT(5), BIT(5), 0x0,
+       0);
+static const char * const dpu_spi_parent_names[] = {
+        "pll1_d8_307p2", "pll1_d6_409p6", "pll1_d10_245p76", "pll1_d11_223p4",
+        "pll1_d13_189", "pll1_d23_106p8", "pll2_d3", "pll2_d5"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_spi_clk, "dpu_spi_clk", dpu_spi_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       8, 3, BIT(7),
+       12, 3, BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_hbus_clk, "dpu_spi_hbus_clk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_bus_clk, "dpu_spi_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_aclk, "dpu_spi_aclk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       BIT(6), BIT(6), 0x0,
+       0);
+static const char * const v2d_parent_names[] = {
+       "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d8_307p2", "pll1_d4_614p4",
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(v2d_clk, "v2d_clk", v2d_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       9, 3, BIT(28),
+       12, 2, BIT(8), BIT(8), 0x0,
+       0);
+static const char * const ccic_4x_parent_names[] = {
+        "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2",
+        "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(ccic_4x_clk, "ccic_4x_clk", ccic_4x_parent_names,
+       BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL,
+       18, 3, BIT(15),
+       23, 2, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const ccic1phy_parent_names[] = {
+       "pll1_d24_102p4", "pll1_d48_51p2_ap"
+};
+static SPACEMIT_CCU_MUX_GATE(ccic1phy_clk, "ccic1phy_clk", ccic1phy_parent_names,
+       BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL,
+       7, 1, BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(sdh_axi_aclk, "sdh_axi_aclk", NULL,
+       BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const sdh01_parent_names[] = {"pll1_d6_409p6",
+       "pll1_d4_614p4", "pll2_d8", "pll2_d5", "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" };
+
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh0_clk, "sdh0_clk", sdh01_parent_names,
+       BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh1_clk, "sdh1_clk", sdh01_parent_names,
+       BASE_TYPE_APMU, APMU_SDH1_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const sdh2_parent_names[] = {"pll1_d6_409p6",
+       "pll1_d4_614p4", "pll2_d8", "pll1_d3_819p2", "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" };
+
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh2_clk, "sdh2_clk", sdh2_parent_names,
+       BASE_TYPE_APMU, APMU_SDH2_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb_axi_clk, "usb_axi_clk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb_p1_aclk, "usb_p1_aclk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb30_clk, "usb30_clk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(8), BIT(8), 0x0,
+       0);
+static const char * const qspi_parent_names[] = {"pll1_d6_409p6", "pll2_d8", "pll1_d8_307p2",
+               "pll1_d10_245p76", "pll1_d11_223p4", "pll1_d23_106p8", "pll1_d5_491p52", "pll1_d13_189"};
+static SPACEMIT_CCU_DIV_MFC_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names,
+       BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
+       9, 3, BIT(12),
+       6, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(qspi_bus_clk, "qspi_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dma_clk, "dma_clk", NULL,
+       BASE_TYPE_APMU, APMU_DMA_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const aes_parent_names[] = {
+       "pll1_d12_204p8", "pll1_d24_102p4"
+};
+static SPACEMIT_CCU_MUX_GATE(aes_clk, "aes_clk", aes_parent_names,
+       BASE_TYPE_APMU, APMU_AES_CLK_RES_CTRL,
+       6, 1, BIT(5), BIT(5), 0x0,
+       0);
+static const char * const vpu_parent_names[] = {
+       "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(vpu_clk, "vpu_clk", vpu_parent_names,
+       BASE_TYPE_APMU, APMU_VPU_CLK_RES_CTRL,
+       13, 3, BIT(21),
+       10, 3,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const gpu_parent_names[] = {
+       "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(gpu_clk, "gpu_clk", gpu_parent_names,
+       BASE_TYPE_APMU, APMU_GPU_CLK_RES_CTRL,
+       12, 3, BIT(15),
+       18, 3,
+       BIT(4), BIT(4), 0x0,
+       0);
+static const char * const emmc_parent_names[] = {
+       "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d52_47p26", "pll1_d3_819p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(emmc_clk, "emmc_clk", emmc_parent_names,
+       BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       6, 2,
+       0x18, 0x18, 0x0,
+       0);
+static SPACEMIT_CCU_DIV_GATE(emmc_x_clk, "emmc_x_clk", "pll1_d2_1228p8",
+       BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL,
+       12, 3, BIT(15), BIT(15), 0x0,
+       0);
+static const char * const audio_parent_names[] = {
+        "pll1_aud_245p7", "pll1_d8_307p2", "pll1_d6_409p6"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(audio_clk, "audio_clk", audio_parent_names,
+       BASE_TYPE_APMU, APMU_AUDIO_CLK_RES_CTRL,
+       4, 3, BIT(15),
+       7, 3,
+       BIT(12), BIT(12), 0x0,
+       0);
+static const char * const hdmi_parent_names[] = {
+        "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(hdmi_mclk, "hdmi_mclk", hdmi_parent_names,
+       BASE_TYPE_APMU, APMU_HDMI_CLK_RES_CTRL,
+       1, 4, BIT(29),
+       5, 3,
+       BIT(0), BIT(0), 0x0,
+       0);
+static const char * const cci550_parent_names[] = {
+        "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d3_819p2", "pll2_d3"
+};
+static SPACEMIT_CCU_DIV_FC_MUX(cci550_clk, "cci550_clk", cci550_parent_names,
+       BASE_TYPE_APMU, APMU_CCI550_CLK_CTRL,
+       8, 3, BIT(12),
+       0, 2,
+       0);
+static const char * const pmua_aclk_parent_names[] = {
+        "pll1_d10_245p76", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX(pmua_aclk, "pmua_aclk", pmua_aclk_parent_names,
+       BASE_TYPE_APMU, APMU_ACLK_CLK_CTRL,
+       1, 2, BIT(4),
+       0, 1,
+       0);
+static const char * const cpu_c0_hi_parent_names[] = {
+        "pll3_d2", "pll3_d1"
+};
+static SPACEMIT_CCU_MUX(cpu_c0_hi_clk, "cpu_c0_hi_clk", cpu_c0_hi_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       13, 1,
+       0);
+static const char * const cpu_c0_parent_names[] = { "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c0_hi_clk"
+};
+static SPACEMIT_CCU_MUX_FC(cpu_c0_core_clk, "cpu_c0_core_clk", cpu_c0_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       BIT(12),
+       0, 3,
+       0);
+static SPACEMIT_CCU_DIV(cpu_c0_ace_clk, "cpu_c0_ace_clk", "cpu_c0_core_clk",
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       6, 3,
+       0);
+static SPACEMIT_CCU_DIV(cpu_c0_tcm_clk, "cpu_c0_tcm_clk", "cpu_c0_core_clk",
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       9, 3,
+       0);
+static const char * const cpu_c1_hi_parent_names[] = {
+        "pll3_d2", "pll3_d1"
+};
+static SPACEMIT_CCU_MUX(cpu_c1_hi_clk, "cpu_c1_hi_clk", cpu_c1_hi_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL,
+       13, 1,
+       0);
+static const char * const cpu_c1_parent_names[] = { "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c1_hi_clk"
+};
+static SPACEMIT_CCU_MUX_FC(cpu_c1_pclk, "cpu_c1_pclk", cpu_c1_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL,
+       BIT(12),
+       0, 3,
+       0);
+static SPACEMIT_CCU_DIV(cpu_c1_ace_clk, "cpu_c1_ace_clk", "cpu_c1_pclk",
+       BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL,
+       6, 3,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(pcie0_clk, "pcie0_clk", NULL,
+       BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_0,
+       0x7, 0x7, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(pcie1_clk, "pcie1_clk", NULL,
+       BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_1,
+       0x7, 0x7, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(pcie2_clk, "pcie2_clk", NULL,
+       BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_2,
+       0x7, 0x7, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(emac0_bus_clk, "emac0_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL,
+       BIT(0), BIT(0), 0x0,
+       0);
+static SPACEMIT_CCU_GATE(emac0_ptp_clk, "emac0_ptp_clk", "pll1_d3_819p2",
+       BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL,
+       BIT(15), BIT(15), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(emac1_bus_clk, "emac1_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL,
+       BIT(0), BIT(0), 0x0,
+       0);
+static SPACEMIT_CCU_GATE(emac1_ptp_clk, "emac1_ptp_clk", "pll1_d3_819p2",
+       BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL,
+       BIT(15), BIT(15), 0x0,
+       0);
+
+//apbc2
+static const char * const uart1_sec_parent_names[] = {
+       "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48"
+};
+static SPACEMIT_CCU_MUX_GATE(uart1_sec_clk, "uart1_sec_clk", uart1_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_UART1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+
+static const char *ssp2_sec_parent_names[] = { "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6",
+       "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8"
+};
+static SPACEMIT_CCU_MUX_GATE(ssp2_sec_clk, "ssp2_sec_clk", ssp2_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_SSP2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static const char *twsi3_sec_parent_names[] = {
+       "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44"
+};
+static SPACEMIT_CCU_MUX_GATE(twsi3_sec_clk, "twsi3_sec_clk", twsi3_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_TWSI3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(rtc_sec_clk, "rtc_sec_clk", "clk_32k",
+       BASE_TYPE_APBC2, APBC2_RTC_CLK_RST,
+       0x83, 0x83, 0x0, 0);
+static const char *timer_sec_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1"
+};
+static SPACEMIT_CCU_MUX_GATE(timers0_sec_clk, "timers0_sec_clk", timer_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_TIMERS0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static const char *kpc_sec_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1"
+};
+static SPACEMIT_CCU_MUX_GATE(kpc_sec_clk, "kpc_sec_clk", kpc_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_KPC_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(gpio_sec_clk, "gpio_sec_clk", "vctcxo_24",
+       BASE_TYPE_APBC2, APBC2_GPIO_CLK_RST,
+       0x3, 0x3, 0x0,
+       0);
+
+static const char * const apb_parent_names[] = {
+       "pll1_d96_25p6", "pll1_d48_51p2", "pll1_d96_25p6", "pll1_d24_102p4"
+};
+static SPACEMIT_CCU_MUX(apb_clk, "apb_clk", apb_parent_names,
+       BASE_TYPE_MPMU, MPMU_APBCSCR,
+       0, 2, 0);
+
+static struct spacemit_clk_table spacemit_k1x_clks = {
+       .clks   = {
+               [CLK_PLL1_2457P6]       = &pll1_2457p6_vco.common.clk,
+               [CLK_PLL2]              = &pll2.common.clk,
+               [CLK_PLL3]              = &pll3.common.clk,
+               [CLK_PLL1_D2]           = &pll1_d2.common.clk,
+               [CLK_PLL1_D3]           = &pll1_d3.common.clk,
+               [CLK_PLL1_D4]           = &pll1_d4.common.clk,
+               [CLK_PLL1_D5]           = &pll1_d5.common.clk,
+               [CLK_PLL1_D6]           = &pll1_d6.common.clk,
+               [CLK_PLL1_D7]           = &pll1_d7.common.clk,
+               [CLK_PLL1_D8]           = &pll1_d8.common.clk,
+               [CLK_PLL1_D11]          = &pll1_d11_223p4.common.clk,
+               [CLK_PLL1_D13]          = &pll1_d13_189.common.clk,
+               [CLK_PLL1_D23]          = &pll1_d23_106p8.common.clk,
+               [CLK_PLL1_D64]          = &pll1_d64_38p4.common.clk,
+               [CLK_PLL1_D10_AUD]      = &pll1_aud_245p7.common.clk,
+               [CLK_PLL1_D100_AUD]     = &pll1_aud_24p5.common.clk,
+               [CLK_PLL2_D1]           = &pll2_d1.common.clk,
+               [CLK_PLL2_D2]           = &pll2_d2.common.clk,
+               [CLK_PLL2_D3]           = &pll2_d3.common.clk,
+               [CLK_PLL2_D4]           = &pll2_d4.common.clk,
+               [CLK_PLL2_D5]           = &pll2_d5.common.clk,
+               [CLK_PLL2_D6]           = &pll2_d6.common.clk,
+               [CLK_PLL2_D7]           = &pll2_d7.common.clk,
+               [CLK_PLL2_D8]           = &pll2_d8.common.clk,
+               [CLK_PLL3_D1]           = &pll3_d1.common.clk,
+               [CLK_PLL3_D2]           = &pll3_d2.common.clk,
+               [CLK_PLL3_D3]           = &pll3_d3.common.clk,
+               [CLK_PLL3_D4]           = &pll3_d4.common.clk,
+               [CLK_PLL3_D5]           = &pll3_d5.common.clk,
+               [CLK_PLL3_D6]           = &pll3_d6.common.clk,
+               [CLK_PLL3_D7]           = &pll3_d7.common.clk,
+               [CLK_PLL3_D8]           = &pll3_d8.common.clk,
+               [CLK_PLL1_307P2]        = &pll1_d8_307p2.common.clk,
+               [CLK_PLL1_76P8]         = &pll1_d32_76p8.common.clk,
+               [CLK_PLL1_61P44]        = &pll1_d40_61p44.common.clk,
+               [CLK_PLL1_153P6]        = &pll1_d16_153p6.common.clk,
+               [CLK_PLL1_102P4]        = &pll1_d24_102p4.common.clk,
+               [CLK_PLL1_51P2]         = &pll1_d48_51p2.common.clk,
+               [CLK_PLL1_51P2_AP]      = &pll1_d48_51p2_ap.common.clk,
+               [CLK_PLL1_57P6]         = &pll1_m3d128_57p6.common.clk,
+               [CLK_PLL1_25P6]         = &pll1_d96_25p6.common.clk,
+               [CLK_PLL1_12P8]         = &pll1_d192_12p8.common.clk,
+               [CLK_PLL1_12P8_WDT]     = &pll1_d192_12p8_wdt.common.clk,
+               [CLK_PLL1_6P4]          = &pll1_d384_6p4.common.clk,
+               [CLK_PLL1_3P2]          = &pll1_d768_3p2.common.clk,
+               [CLK_PLL1_1P6]          = &pll1_d1536_1p6.common.clk,
+               [CLK_PLL1_0P8]          = &pll1_d3072_0p8.common.clk,
+               [CLK_PLL1_351]          = &pll1_d7_351p08.common.clk,
+               [CLK_PLL1_409P6]        = &pll1_d6_409p6.common.clk,
+               [CLK_PLL1_204P8]        = &pll1_d12_204p8.common.clk,
+               [CLK_PLL1_491]          = &pll1_d5_491p52.common.clk,
+               [CLK_PLL1_245P76]       = &pll1_d10_245p76.common.clk,
+               [CLK_PLL1_614]          = &pll1_d4_614p4.common.clk,
+               [CLK_PLL1_47P26]        = &pll1_d52_47p26.common.clk,
+               [CLK_PLL1_31P5]         = &pll1_d78_31p5.common.clk,
+               [CLK_PLL1_819]          = &pll1_d3_819p2.common.clk,
+               [CLK_PLL1_1228]         = &pll1_d2_1228p8.common.clk,
+               [CLK_SLOW_UART1]        = &slow_uart1_14p74.common.clk,
+               [CLK_SLOW_UART2]        = &slow_uart2_48.common.clk,
+               [CLK_UART1]             = &uart1_clk.common.clk,
+               [CLK_UART2]             = &uart2_clk.common.clk,
+               [CLK_UART3]             = &uart3_clk.common.clk,
+               [CLK_UART4]             = &uart4_clk.common.clk,
+               [CLK_UART5]             = &uart5_clk.common.clk,
+               [CLK_UART6]             = &uart6_clk.common.clk,
+               [CLK_UART7]             = &uart7_clk.common.clk,
+               [CLK_UART8]             = &uart8_clk.common.clk,
+               [CLK_UART9]             = &uart9_clk.common.clk,
+               [CLK_GPIO]              = &gpio_clk.common.clk,
+               [CLK_PWM0]              = &pwm0_clk.common.clk,
+               [CLK_PWM1]              = &pwm1_clk.common.clk,
+               [CLK_PWM2]              = &pwm2_clk.common.clk,
+               [CLK_PWM3]              = &pwm3_clk.common.clk,
+               [CLK_PWM4]              = &pwm4_clk.common.clk,
+               [CLK_PWM5]              = &pwm5_clk.common.clk,
+               [CLK_PWM6]              = &pwm6_clk.common.clk,
+               [CLK_PWM7]              = &pwm7_clk.common.clk,
+               [CLK_PWM8]              = &pwm8_clk.common.clk,
+               [CLK_PWM9]              = &pwm9_clk.common.clk,
+               [CLK_PWM10]             = &pwm10_clk.common.clk,
+               [CLK_PWM11]             = &pwm11_clk.common.clk,
+               [CLK_PWM12]             = &pwm12_clk.common.clk,
+               [CLK_PWM13]             = &pwm13_clk.common.clk,
+               [CLK_PWM14]             = &pwm14_clk.common.clk,
+               [CLK_PWM15]             = &pwm15_clk.common.clk,
+               [CLK_PWM16]             = &pwm16_clk.common.clk,
+               [CLK_PWM17]             = &pwm17_clk.common.clk,
+               [CLK_PWM18]             = &pwm18_clk.common.clk,
+               [CLK_PWM19]             = &pwm19_clk.common.clk,
+               [CLK_SSP3]              = &ssp3_clk.common.clk,
+               [CLK_RTC]               = &rtc_clk.common.clk,
+               [CLK_TWSI0]             = &twsi0_clk.common.clk,
+               [CLK_TWSI1]             = &twsi1_clk.common.clk,
+               [CLK_TWSI2]             = &twsi2_clk.common.clk,
+               [CLK_TWSI4]             = &twsi4_clk.common.clk,
+               [CLK_TWSI5]             = &twsi5_clk.common.clk,
+               [CLK_TWSI6]             = &twsi6_clk.common.clk,
+               [CLK_TWSI7]             = &twsi7_clk.common.clk,
+               [CLK_TWSI8]             = &twsi8_clk.common.clk,
+               [CLK_TIMERS1]           = &timers1_clk.common.clk,
+               [CLK_TIMERS2]           = &timers2_clk.common.clk,
+               [CLK_AIB]               = &aib_clk.common.clk,
+               [CLK_ONEWIRE]           = &onewire_clk.common.clk,
+               [CLK_SSPA0]             = &sspa0_clk.common.clk,
+               [CLK_SSPA1]             = &sspa1_clk.common.clk,
+               [CLK_DRO]               = &dro_clk.common.clk,
+               [CLK_IR]                = &ir_clk.common.clk,
+               [CLK_TSEN]              = &tsen_clk.common.clk,
+               [CLK_IPC_AP2AUD]        = &ipc_ap2aud_clk.common.clk,
+               [CLK_CAN0]              = &can0_clk.common.clk,
+               [CLK_CAN0_BUS]          = &can0_bus_clk.common.clk,
+               [CLK_WDT]               = &wdt_clk.common.clk,
+               [CLK_RIPC]              = &ripc_clk.common.clk,
+               [CLK_JPG]               = &jpg_clk.common.clk,
+               [CLK_JPF_4KAFBC]        = &jpg_4kafbc_clk.common.clk,
+               [CLK_JPF_2KAFBC]        = &jpg_2kafbc_clk.common.clk,
+               [CLK_CCIC2PHY]          = &ccic2phy_clk.common.clk,
+               [CLK_CCIC3PHY]          = &ccic3phy_clk.common.clk,
+               [CLK_CSI]               = &csi_clk.common.clk,
+               [CLK_CAMM0]             = &camm0_clk.common.clk,
+               [CLK_CAMM1]             = &camm1_clk.common.clk,
+               [CLK_CAMM2]             = &camm2_clk.common.clk,
+               [CLK_ISP_CPP]           = &isp_cpp_clk.common.clk,
+               [CLK_ISP_BUS]           = &isp_bus_clk.common.clk,
+               [CLK_ISP]               = &isp_clk.common.clk,
+               [CLK_DPU_MCLK]          = &dpu_mclk.common.clk,
+               [CLK_DPU_ESC]           = &dpu_esc_clk.common.clk,
+               [CLK_DPU_BIT]           = &dpu_bit_clk.common.clk,
+               [CLK_DPU_PXCLK]         = &dpu_pxclk.common.clk,
+               [CLK_DPU_HCLK]          = &dpu_hclk.common.clk,
+               [CLK_DPU_SPI]           = &dpu_spi_clk.common.clk,
+               [CLK_DPU_SPI_HBUS]      = &dpu_spi_hbus_clk.common.clk,
+               [CLK_DPU_SPIBUS]        = &dpu_spi_bus_clk.common.clk,
+               [CLK_SPU_SPI_ACLK]      = &dpu_spi_aclk.common.clk,
+               [CLK_V2D]               = &v2d_clk.common.clk,
+               [CLK_CCIC_4X]           = &ccic_4x_clk.common.clk,
+               [CLK_CCIC1PHY]          = &ccic1phy_clk.common.clk,
+               [CLK_SDH_AXI]           = &sdh_axi_aclk.common.clk,
+               [CLK_SDH0]              = &sdh0_clk.common.clk,
+               [CLK_SDH1]              = &sdh1_clk.common.clk,
+               [CLK_SDH2]              = &sdh2_clk.common.clk,
+               [CLK_USB_P1]            = &usb_p1_aclk.common.clk,
+               [CLK_USB_AXI]           = &usb_axi_clk.common.clk,
+               [CLK_USB30]             = &usb30_clk.common.clk,
+               [CLK_QSPI]              = &qspi_clk.common.clk,
+               [CLK_QSPI_BUS]          = &qspi_bus_clk.common.clk,
+               [CLK_DMA]               = &dma_clk.common.clk,
+               [CLK_AES]               = &aes_clk.common.clk,
+               [CLK_VPU]               = &vpu_clk.common.clk,
+               [CLK_GPU]               = &gpu_clk.common.clk,
+               [CLK_EMMC]              = &emmc_clk.common.clk,
+               [CLK_EMMC_X]            = &emmc_x_clk.common.clk,
+               [CLK_AUDIO]             = &audio_clk.common.clk,
+               [CLK_HDMI]              = &hdmi_mclk.common.clk,
+               [CLK_CCI550]            = &cci550_clk.common.clk,
+               [CLK_PMUA_ACLK]         = &pmua_aclk.common.clk,
+               [CLK_CPU_C0_HI]         = &cpu_c0_hi_clk.common.clk,
+               [CLK_CPU_C0_CORE]       = &cpu_c0_core_clk.common.clk,
+               [CLK_CPU_C0_ACE]        = &cpu_c0_ace_clk.common.clk,
+               [CLK_CPU_C0_TCM]        = &cpu_c0_tcm_clk.common.clk,
+               [CLK_CPU_C1_HI]         = &cpu_c1_hi_clk.common.clk,
+               [CLK_CPU_C1_CORE]       = &cpu_c1_pclk.common.clk,
+               [CLK_CPU_C1_ACE]        = &cpu_c1_ace_clk.common.clk,
+               [CLK_PCIE0]             = &pcie0_clk.common.clk,
+               [CLK_PCIE1]             = &pcie1_clk.common.clk,
+               [CLK_PCIE2]             = &pcie2_clk.common.clk,
+               [CLK_EMAC0_BUS]         = &emac0_bus_clk.common.clk,
+               [CLK_EMAC0_PTP]         = &emac0_ptp_clk.common.clk,
+               [CLK_EMAC1_BUS]         = &emac1_bus_clk.common.clk,
+               [CLK_EMAC1_PTP]         = &emac1_ptp_clk.common.clk,
+               [CLK_SEC_UART1]         = &uart1_sec_clk.common.clk,
+               [CLK_SEC_SSP2]          = &ssp2_sec_clk.common.clk,
+               [CLK_SEC_TWSI3]         = &twsi3_sec_clk.common.clk,
+               [CLK_SEC_RTC]           = &rtc_sec_clk.common.clk,
+               [CLK_SEC_TIMERS0]       = &timers0_sec_clk.common.clk,
+               [CLK_SEC_KPC]           = &kpc_sec_clk.common.clk,
+               [CLK_SEC_GPIO]          = &gpio_sec_clk.common.clk,
+               [CLK_APB]               = &apb_clk.common.clk,
+       },
+       .num = CLK_MAX_NO,
+};
+
+#endif
+
+struct spacemit_clk_init_rate init_rate_tbl[] = {
+#ifdef CONFIG_SPL_BUILD
+       {CLK_PMUA_ACLK_SPL, 307200000},
+       {CLK_APB_SPL,   102400000},
+#else
+       {CLK_PMUA_ACLK, 307200000},
+       {CLK_APB,       102400000},
+       {CLK_SLOW_UART1, 14745600},
+#endif
+};
+
+static inline const struct clk_ops *ccu_clk_dev_ops(struct udevice *dev)
+{
+       return (const struct clk_ops *)dev->driver->ops;
+}
+
+#ifndef CONFIG_SPL_BUILD
+ulong ccu_clk_get_rate(struct clk *clk)
+{
+       const struct clk_ops *ops;
+       struct clk *c = spacemit_k1x_clks.clks[clk->id];
+       if (!clk_valid(c))
+               return 0;
+       ops = ccu_clk_dev_ops(c->dev);
+       if(ops->get_rate)
+               return ops->get_rate(c);
+       return 0;
+}
+
+ulong ccu_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       const struct clk_ops *ops;
+       struct clk *c = spacemit_k1x_clks.clks[clk->id];
+       if (!clk_valid(c))
+               return 0;
+       ops = ccu_clk_dev_ops(c->dev);
+       if(ops->round_rate)
+               return ops->round_rate(c, rate);
+       return 0;
+}
+
+int ccu_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       const struct clk_ops *ops;
+
+       struct clk *c = spacemit_k1x_clks.clks[clk->id];
+       struct clk *p = spacemit_k1x_clks.clks[parent->id];
+       if (!clk_valid(c))
+               return 0;
+       ops = ccu_clk_dev_ops(c->dev);
+       if(ops->set_parent)
+               return ops->set_parent(c, p);
+       return 0;
+}
+#endif
+
+int ccu_clk_disable(struct clk *clk)
+{
+       const struct clk_ops *ops;
+
+#ifdef CONFIG_SPL_BUILD
+       clk->id = transfer_clk_id_to_spl(clk->id);
+#endif
+       struct clk *c = spacemit_k1x_clks.clks[clk->id];
+       if (!clk_valid(c))
+               return 0;
+       ops = ccu_clk_dev_ops(c->dev);
+       if(ops->disable)
+               return ops->disable(c);
+       return 0;
+}
+
+ulong ccu_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       const struct clk_ops *ops;
+
+#ifdef CONFIG_SPL_BUILD
+       clk->id = transfer_clk_id_to_spl(clk->id);
+#endif
+       struct clk *c = spacemit_k1x_clks.clks[clk->id];
+
+       if (!clk_valid(c))
+               return 0;
+       ops = ccu_clk_dev_ops(c->dev);
+       if(ops->set_rate)
+               return ops->set_rate(c, rate);
+       return 0;
+}
+
+int ccu_clk_enable(struct clk *clk)
+{
+       const struct clk_ops *ops;
+
+#ifdef CONFIG_SPL_BUILD
+       clk->id = transfer_clk_id_to_spl(clk->id);
+#endif
+       struct clk *c = spacemit_k1x_clks.clks[clk->id];
+
+       if (!clk_valid(c))
+               return 0;
+       ops = ccu_clk_dev_ops(c->dev);
+       if(ops->enable)
+               return ops->enable(c);
+       return 0;
+}
+
+const struct clk_ops ccu_clk_ops = {
+#ifndef CONFIG_SPL_BUILD
+       .get_rate = ccu_clk_get_rate,
+       .round_rate = ccu_clk_round_rate,
+       .set_parent = ccu_clk_set_parent,
+#endif
+       .disable = ccu_clk_disable,
+       .set_rate = ccu_clk_set_rate,
+       .enable = ccu_clk_enable,
+};
+
+int ccu_common_init(struct clk * clk, struct spacemit_k1x_clk *clk_info, struct spacemit_clk_table *clks)
+{
+       struct ccu_common *common = clk_to_ccu_common(clk);
+       struct ccu_pll *pll = clk_to_ccu_pll(clk);
+       int ret;
+
+       if (!common)
+               return -1;
+
+       switch(common->base_type){
+       case BASE_TYPE_MPMU:
+               common->base = clk_info->mpmu_base;
+               break;
+       case BASE_TYPE_APMU:
+               common->base = clk_info->apmu_base;
+               break;
+       case BASE_TYPE_APBC:
+               common->base = clk_info->apbc_base;
+               break;
+       case BASE_TYPE_APBS:
+               common->base = clk_info->apbs_base;
+               break;
+#ifndef CONFIG_SPL_BUILD
+       case BASE_TYPE_CIU:
+               common->base = clk_info->ciu_base;
+               break;
+       case BASE_TYPE_DCIU:
+               common->base = clk_info->dciu_base;
+               break;
+       case BASE_TYPE_DDRC:
+               common->base = clk_info->ddrc_base;
+               break;
+       case BASE_TYPE_AUDC:
+               common->base = clk_info->audio_ctrl_base;
+               break;
+       case BASE_TYPE_APBC2:
+               common->base = clk_info->apbc2_base;
+               break;
+#endif
+       default:
+               common->base = clk_info->apbc_base;
+               break;
+
+       }
+       common->clk_tbl = clks;
+       if(common->is_pll)
+               pll->pll.lock_base = clk_info->mpmu_base;
+
+       if(common->parent_name == NULL && common->parent_names != NULL)
+               common->parent_name = common->parent_names[ccu_mix_get_parent(clk)];
+
+       ret = clk_register(clk, common->driver_name, common->name, common->parent_name);
+
+       return 0;
+}
+
+int spacemit_ccu_probe(struct spacemit_k1x_clk *clk_info,
+                   struct spacemit_clk_table *clks)
+{
+       int i;
+
+#ifdef CONFIG_SPL_BUILD
+       for (i = CLK_PLL1_2457P6_SPL; i < clks->num ; i++) {
+#else
+       for (i = CLK_PLL1_2457P6; i < clks->num ; i++) {
+#endif
+               struct clk *clk = clks->clks[i];
+               if (!clk)
+                       continue;
+
+#ifdef CONFIG_SPL_BUILD
+               if(clk->id >= CLK_VCTCXO_24_SPL)
+#else
+               if(clk->id >= CLK_VCTCXO_24)
+#endif
+                       continue;
+
+               clk->id = i;
+               ccu_common_init(clk, clk_info, clks);
+       }
+#ifndef CONFIG_SPL_BUILD
+       //init pll2 freq
+       if (clk_info->pll2_freq) {
+               struct clk *clk =clks->clks[CLK_PLL2];
+               if (clk)
+                       clk_set_rate(clk, clk_info->pll2_freq);
+       }
+#endif
+       //init clk default rate
+       for (i = 0; i < ARRAY_SIZE(init_rate_tbl); i++) {
+               struct clk *clk =clks->clks[init_rate_tbl[i].clk_id];
+               if (!clk)
+                       continue;
+
+               clk_set_rate(clk, init_rate_tbl[i].dft_rate);
+       }
+
+       return 0;
+}
+
+static inline void ccu_clk_dm(ulong id, struct clk *clk)
+{
+       if (!IS_ERR(clk)){
+
+#ifdef CONFIG_SPL_BUILD
+               id = transfer_clk_id_to_spl(id);
+#endif
+               clk->id = id;
+               spacemit_k1x_clks.clks[id] = clk;
+       }
+}
+
+static int spacemit_k1x_ccu_probe(struct udevice *dev)
+{
+       int ret = 0;
+       struct spacemit_k1x_clk *clk_info = &k1x_clock_controller;
+       struct spacemit_clk_table *clks = &spacemit_k1x_clks;
+
+       pr_debug("init clock start \n");
+
+       clk_info->mpmu_base = (void __iomem *)dev_remap_addr_index(dev, 0);
+       if (!clk_info->mpmu_base) {
+               pr_err("failed to map mpmu registers\n");
+               goto out;
+       }
+
+       clk_info->apmu_base = (void __iomem *)dev_remap_addr_index(dev, 1);
+       if (!clk_info->apmu_base) {
+               pr_err("failed to map apmu registers\n");
+               goto out;
+       }
+
+       clk_info->apbc_base = (void __iomem *)dev_remap_addr_index(dev, 2);
+       if (!clk_info->apbc_base) {
+               pr_err("failed to map apbc registers\n");
+               goto out;
+       }
+
+       clk_info->apbs_base = (void __iomem *)dev_remap_addr_index(dev, 3);
+       if (!clk_info->apbs_base) {
+               pr_err("failed to map apbs registers\n");
+               goto out;
+       }
+
+       clk_info->ciu_base = (void __iomem *)dev_remap_addr_index(dev, 4);
+       if (!clk_info->ciu_base) {
+               pr_err("failed to map ciu registers\n");
+               goto out;
+       }
+
+       clk_info->dciu_base = (void __iomem *)dev_remap_addr_index(dev, 5);
+       if (!clk_info->dciu_base) {
+               pr_err("failed to map dragon ciu registers\n");
+               goto out;
+       }
+
+       clk_info->ddrc_base = (void __iomem *)dev_remap_addr_index(dev, 6);
+       if (!clk_info->ddrc_base) {
+               pr_err("failed to map ddrc registers\n");
+               goto out;
+       }
+
+       clk_info->apbc2_base = (void __iomem *)dev_remap_addr_index(dev, 7);
+       if (!clk_info->apbc2_base) {
+               pr_err("failed to map apbc2 registers\n");
+               goto out;
+       }
+
+#ifdef CONFIG_SPL_BUILD
+       clk_get_by_name(dev, "vctcxo_24", &vctcxo_24);
+       ccu_clk_dm(CLK_VCTCXO_24_SPL, dev_get_clk_ptr(vctcxo_24.dev));
+       clk_get_by_name(dev, "vctcxo_3", &vctcxo_3);
+       ccu_clk_dm(CLK_VCTCXO_3_SPL, dev_get_clk_ptr(vctcxo_3.dev));
+       clk_get_by_name(dev, "vctcxo_1", &vctcxo_1);
+       ccu_clk_dm(CLK_VCTCXO_1_SPL, dev_get_clk_ptr(vctcxo_1.dev));
+       clk_get_by_name(dev, "pll1_vco", &pll1_vco);
+       ccu_clk_dm(CLK_PLL1_SPL, dev_get_clk_ptr(pll1_vco.dev));
+       clk_get_by_name(dev, "clk_32k", &clk_32k);
+       ccu_clk_dm(CLK_32K_SPL, dev_get_clk_ptr(clk_32k.dev));
+       clk_get_by_name(dev, "clk_dummy", &clk_dummy);
+       ccu_clk_dm(CLK_DUMMY_SPL, dev_get_clk_ptr(clk_dummy.dev));
+#else
+       clk_get_by_name(dev, "vctcxo_24", &vctcxo_24);
+       ccu_clk_dm(CLK_VCTCXO_24, dev_get_clk_ptr(vctcxo_24.dev));
+       clk_get_by_name(dev, "vctcxo_3", &vctcxo_3);
+       ccu_clk_dm(CLK_VCTCXO_3, dev_get_clk_ptr(vctcxo_3.dev));
+       clk_get_by_name(dev, "vctcxo_1", &vctcxo_1);
+       ccu_clk_dm(CLK_VCTCXO_1, dev_get_clk_ptr(vctcxo_1.dev));
+       clk_get_by_name(dev, "pll1_vco", &pll1_vco);
+       ccu_clk_dm(CLK_PLL1, dev_get_clk_ptr(pll1_vco.dev));
+       clk_get_by_name(dev, "clk_32k", &clk_32k);
+       ccu_clk_dm(CLK_32K, dev_get_clk_ptr(clk_32k.dev));
+       clk_get_by_name(dev, "clk_dummy", &clk_dummy);
+       ccu_clk_dm(CLK_DUMMY, dev_get_clk_ptr(clk_dummy.dev));
+#endif
+
+       clk_info->pll2_freq = dev_read_u32_default(dev, "pll2-freq", 0);
+       ret = spacemit_ccu_probe(clk_info, clks);
+       pr_debug("init clock finish ret=%d \n", ret);
+       if (!ret)
+               return 0;
+out:
+       return -1;
+}
+
+static const struct udevice_id ccu_clk_ids[] = {
+       { .compatible = "spacemit,k1x-ccu" },
+       { },
+};
+
+U_BOOT_DRIVER(spacemit_k1x_ccu) = {
+       .name = "k1x-ccu",
+       .id = UCLASS_CLK,
+       .of_match = ccu_clk_ids,
+       .ops = &ccu_clk_ops,
+       .probe = spacemit_k1x_ccu_probe,
+};
+
diff --git a/drivers/clk/spacemit/ccu-k1x.h b/drivers/clk/spacemit/ccu-k1x.h
new file mode 100644 (file)
index 0000000..20f9153
--- /dev/null
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_SPACEMIT_K1X_H_
+#define _CCU_SPACEMIT_K1X_H_
+
+#include <clk.h>
+#include <clk-uclass.h>
+#include <dt-bindings/clock/spacemit-k1x-clock.h>
+
+#define SPACEMIT_CLK_NO_PARENT "clk_dummy"
+
+enum ccu_base_type{
+       BASE_TYPE_MPMU       = 0,
+       BASE_TYPE_APMU       = 1,
+       BASE_TYPE_APBC       = 2,
+       BASE_TYPE_APBS       = 3,
+       BASE_TYPE_CIU        = 4,
+       BASE_TYPE_DCIU       = 5,
+       BASE_TYPE_DDRC       = 6,
+       BASE_TYPE_AUDC       = 7,
+       BASE_TYPE_APBC2      = 8,
+};
+
+enum {
+       CLK_DIV_TYPE_1REG_NOFC_V1 = 0,
+       CLK_DIV_TYPE_1REG_FC_V2,
+       CLK_DIV_TYPE_2REG_NOFC_V3,
+       CLK_DIV_TYPE_2REG_FC_V4,
+       CLK_DIV_TYPE_1REG_FC_DIV_V5,
+       CLK_DIV_TYPE_1REG_FC_MUX_V6,
+};
+
+struct ccu_common {
+       void __iomem    *base;
+       enum ccu_base_type base_type;
+       u32     reg_type;
+       u32     reg_ctrl;
+       u32     reg_sel;
+       u32     reg_xtc;
+       u32     fc;
+       bool    is_pll;
+       const char              *name;
+       const char              *driver_name;
+       const char              *parent_name;
+       const char              * const *parent_names;
+       u8      num_parents;
+       unsigned long   flags;
+       struct clk      clk;
+       struct spacemit_clk_table * clk_tbl;
+};
+
+struct spacemit_k1x_clk {
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbc_base;
+       void __iomem *apbs_base;
+       void __iomem *ciu_base;
+       void __iomem *dciu_base;
+       void __iomem *ddrc_base;
+       void __iomem *audio_ctrl_base;
+       void __iomem *apbc2_base;
+       u32 pll2_freq;
+};
+
+/* u-boot-spl would used this clk */
+enum {
+       CLK_PLL1_2457P6_SPL = 0,
+       CLK_PLL1_D2_SPL,
+       CLK_PLL1_D4_SPL,
+       CLK_PLL1_D6_SPL,
+       CLK_PLL1_D8_SPL,
+       CLK_PLL1_D23_SPL,
+       CLK_PLL1_102P4_SPL,
+       CLK_PLL1_409P6_SPL,
+       CLK_PLL1_204P8_SPL,
+       CLK_PLL1_31P5_SPL,
+       CLK_PLL1_1228_SPL,
+       CLK_TWSI6_SPL,
+       CLK_TWSI8_SPL,
+       CLK_SDH_AXI_SPL,
+       CLK_SDH0_SPL,
+       CLK_SDH2_SPL,
+       CLK_USB_P1_SPL,
+       CLK_USB_AXI_SPL,
+       CLK_USB30_SPL,
+       CLK_QSPI_SPL,
+       CLK_QSPI_BUS_SPL,
+       CLK_AES_SPL,
+
+       CLK_PMUA_ACLK_SPL,
+       CLK_APB_SPL,
+
+       CLK_VCTCXO_24_SPL,
+       CLK_VCTCXO_3_SPL,
+       CLK_VCTCXO_1_SPL,
+       CLK_PLL1_SPL,
+       CLK_32K_SPL,
+       CLK_DUMMY_SPL,
+
+       CLK_MAX_NO_SPL,
+};
+
+struct spacemit_clk_table{
+#ifdef CONFIG_SPL_BUILD
+       struct clk* clks[CLK_MAX_NO_SPL];
+#else
+       struct clk* clks[CLK_MAX_NO];
+#endif
+       unsigned int num;
+};
+
+struct spacemit_clk_init_rate{
+       u32 clk_id;
+       unsigned int dft_rate;
+};
+
+static inline struct ccu_common *clk_to_ccu_common(struct clk *clk)
+{
+       return container_of(clk, struct ccu_common, clk);
+}
+
+int spacemit_ccu_probe(struct spacemit_k1x_clk *clk_info,
+                   struct spacemit_clk_table *clks);
+
+ulong transfer_clk_id_to_spl(ulong id);
+
+#endif /* _CCU_SPACEMIT_K1X_H_ */
diff --git a/drivers/clk/spacemit/ccu_ddn.c b/drivers/clk/spacemit/ccu_ddn.c
new file mode 100644 (file)
index 0000000..42f50bb
--- /dev/null
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit clock type ddn
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <div64.h>
+
+#include "ccu_ddn.h"
+/*
+ * It is M/N clock
+ *
+ * Fout from synthesizer can be given from two equations:
+ * numerator/denominator = Fin / (Fout * factor)
+ */
+
+static int ccu_ddn_disable(struct clk *clk)
+{
+       struct ccu_ddn *ddn = clk_to_ccu_ddn(clk);
+       struct ccu_common * common = &ddn->common;
+       u32 reg;
+
+       if (!ddn->gate)
+               return 0;
+
+       reg = readl(common->base + common->reg_sel);
+
+       writel(reg & ~ddn->gate, common->base + common->reg_sel);
+       return 0;
+
+}
+
+static int ccu_ddn_enable(struct clk *clk)
+{
+       struct ccu_ddn *ddn = clk_to_ccu_ddn(clk);
+       struct ccu_common * common = &ddn->common;
+       u32 reg;
+
+       if (!ddn->gate)
+               return 0;
+
+       reg = readl(common->base + common->reg_sel);
+
+       writel(reg | ddn->gate, common->base + common->reg_sel);
+
+       return 0;
+}
+
+static ulong clk_ddn_round_rate(struct clk *clk, ulong drate)
+{
+       struct ccu_ddn *ddn = clk_to_ccu_ddn(clk);
+       struct ccu_ddn_config *params = &ddn->ddn;
+       unsigned long parent_rate = clk_get_parent_rate(clk);
+       unsigned long rate = 0, prev_rate;
+       unsigned long result;
+       int i;
+
+       for (i = 0; i < params->tbl_size; i++) {
+               prev_rate = rate;
+               rate = (((parent_rate / 10000) * params->tbl[i].den) /
+                       (params->tbl[i].num * params->info->factor)) * 10000;
+               if (rate > drate)
+                       break;
+       }
+       if ((i == 0) || (i == params->tbl_size)) {
+               result = rate;
+       } else {
+               if ((drate - prev_rate) > (rate - drate))
+                       result = rate;
+               else
+                       result = prev_rate;
+       }
+       return result;
+}
+
+static ulong clk_ddn_get_rate(struct clk *clk)
+{
+       struct ccu_ddn *ddn = clk_to_ccu_ddn(clk);
+       struct ccu_ddn_config *params = &ddn->ddn;
+       unsigned long parent_rate = clk_get_parent_rate(clk);
+       unsigned int val, num, den;
+       unsigned long rate;
+
+       val = readl(ddn->common.base + ddn->common.reg_ctrl);
+
+       /* calculate numerator */
+       num = (val >> params->info->num_shift) & params->info->num_mask;
+
+       /* calculate denominator */
+       den = (val >> params->info->den_shift) & params->info->den_mask;
+       if (!den)
+               return 0;
+       rate = (((parent_rate / 10000)  * den) /
+                       (num * params->info->factor)) * 10000;
+       return rate;
+}
+
+/* Configures new clock rate*/
+static ulong clk_ddn_set_rate(struct clk *clk, unsigned long drate)
+{
+       struct ccu_ddn *ddn = clk_to_ccu_ddn(clk);
+       struct ccu_ddn_config *params = &ddn->ddn;
+       unsigned long prate = clk_get_parent_rate(clk);
+       int i;
+       unsigned long val;
+       unsigned long prev_rate, rate = 0;
+
+       for (i = 0; i < params->tbl_size; i++) {
+               prev_rate = rate;
+               rate = (((prate / 10000) * params->tbl[i].den) /
+                       (params->tbl[i].num * params->info->factor)) * 10000;
+               if (rate > drate)
+                       break;
+       }
+
+       if (i > 0)
+               i--;
+
+       val = readl(ddn->common.base + ddn->common.reg_ctrl);
+
+       val &= ~(params->info->num_mask << params->info->num_shift);
+       val |= (params->tbl[i].num & params->info->num_mask) << params->info->num_shift;
+
+       val &= ~(params->info->den_mask << params->info->den_shift);
+       val |= (params->tbl[i].den & params->info->den_mask) << params->info->den_shift;
+
+       writel(val, ddn->common.base + ddn->common.reg_ctrl);
+
+       return 0;
+}
+
+const struct clk_ops ccu_ddn_ops = {
+       .disable        = ccu_ddn_disable,
+       .enable         = ccu_ddn_enable,
+       .get_rate       = clk_ddn_get_rate,
+       .round_rate     = clk_ddn_round_rate,
+       .set_rate       = clk_ddn_set_rate,
+};
+
+U_BOOT_DRIVER(ccu_clk_ddn) = {
+       .name   = CCU_CLK_DDN,
+       .id     = UCLASS_CLK,
+       .ops    = &ccu_ddn_ops,
+};
+
diff --git a/drivers/clk/spacemit/ccu_ddn.h b/drivers/clk/spacemit/ccu_ddn.h
new file mode 100644 (file)
index 0000000..205caa4
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_DDN_H_
+#define _CCU_DDN_H_
+
+
+#include "ccu-k1x.h"
+
+#define CCU_CLK_DDN "ccu_clk_ddn"
+struct ccu_ddn_tbl {
+       unsigned int num;
+       unsigned int den;
+};
+
+struct ccu_ddn_info {
+       unsigned int factor;
+       unsigned int num_mask;
+       unsigned int den_mask;
+       unsigned int num_shift;
+       unsigned int den_shift;
+};
+
+struct ccu_ddn_config {
+       struct ccu_ddn_info * info;
+       struct ccu_ddn_tbl * tbl;
+       u32 tbl_size;
+};
+
+#define PLL_DDN_TBL(_num, _den)                \
+       {                                               \
+               .num    =       (_num),         \
+               .den    =       (_den),                 \
+       }
+
+struct ccu_ddn {
+       u32 gate;
+       struct ccu_ddn_config  ddn;
+       struct ccu_common       common;
+};
+
+#define _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size) \
+       {                                               \
+               .info   = (struct ccu_ddn_info *)_info,                 \
+               .tbl    = (struct ccu_ddn_tbl *)_table,                 \
+               .tbl_size       = _size,                        \
+       }
+
+#define SPACEMIT_CCU_DDN(_struct, _name, _parent, _info, _table, _size,        \
+                                                _base_type, _reg_ctrl,         \
+                                                _flags)                                \
+       struct ccu_ddn _struct = {                                      \
+               .ddn    = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size),       \
+               .common = {                                     \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .base_type              = _base_type,      \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_DDN, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_DDN_GATE(_struct, _name, _parent, _info, _table, _size,   \
+                                                        _base_type, _reg_ddn, __reg_gate, _gate_mask, \
+                                                        _flags)                                \
+       struct ccu_ddn _struct = {                                      \
+               .gate   = _gate_mask,    \
+               .ddn    = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size),       \
+               .common = {                                     \
+                       .reg_ctrl               = _reg_ddn,                     \
+                       .reg_sel                = __reg_gate,                   \
+                       .base_type              = _base_type,      \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_DDN, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+
+static inline struct ccu_ddn *clk_to_ccu_ddn(struct clk *clk)
+{
+       struct ccu_common *common = clk_to_ccu_common(clk);
+
+       return container_of(common, struct ccu_ddn, common);
+}
+
+#endif
diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c
new file mode 100644 (file)
index 0000000..bb0e2b6
--- /dev/null
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit clock type mix(div/mux/gate/factor)
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <div64.h>
+
+#include "ccu_mix.h"
+
+#define TIMEOUT_LIMIT (20000) /* max timeout 10000us */
+static int twsi8_reg_val = 0x04;
+
+static int ccu_mix_trigger_fc(struct clk *clk)
+{
+#ifdef CONFIG_SPL_BUILD
+       return 0;
+#else
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       unsigned long val = 0;
+
+       int ret = 0, timeout = 50;
+
+       if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
+
+               timeout = 50;
+               val = readl(common->base + common->reg_ctrl);
+               val |= common->fc;
+               writel(val, common->base + common->reg_ctrl);
+
+               do {
+                       val = readl(common->base + common->reg_ctrl);
+                       timeout--;
+                       if (!(val & (common->fc)))
+                               break;
+               } while (timeout);
+
+               if (timeout == 0) {
+                       timeout = 5000;
+                       do {
+                               val = readl(common->base + common->reg_ctrl);
+                               timeout--;
+                               if (!(val & (common->fc)))
+                                       break;
+                       } while (timeout);
+                       if (timeout != 0) {
+                               ret = 0;
+
+                       } else {
+                               ret = -1;
+                       }
+               }
+       }
+
+       return ret;
+#endif
+}
+
+#ifndef CONFIG_SPL_BUILD
+static int ccu_mix_disable(struct clk *clk)
+{
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_gate_config *gate = mix->gate;
+       u32 tmp;
+
+       if (!gate)
+               return 0;
+
+#ifdef CONFIG_SPL_BUILD
+       if (clk->id == CLK_TWSI8_SPL){
+#else
+       if (clk->id == CLK_TWSI8){
+#endif
+               twsi8_reg_val &= ~0x7;
+               twsi8_reg_val |= 0x4;
+               tmp = twsi8_reg_val;
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       writel(tmp, common->base + common->reg_sel);
+               else
+                       writel(tmp, common->base + common->reg_ctrl);
+
+               return 0;
+       }
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               tmp = readl(common->base + common->reg_sel);
+       else
+               tmp = readl(common->base + common->reg_ctrl);
+
+       tmp &= ~gate->gate_mask;
+       tmp |= gate->val_disable;
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(tmp, common->base + common->reg_sel);
+       else
+               writel(tmp, common->base + common->reg_ctrl);
+
+       if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) {
+               udelay(200);
+       }
+
+       return 0;
+}
+
+static ulong ccu_mix_round_rate(struct clk *clk, ulong rate)
+{
+       return rate;
+}
+
+static int ccu_mix_set_parent(struct clk *clk, struct clk *parent)
+{
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_mux_config *mux = mix->mux;
+       int index;
+       u32 reg, i;
+       int ret;
+
+       if (!parent)
+               return -EINVAL;
+
+       for (i = 0; i < common->num_parents; i++) {
+               if (!strcmp(parent->dev->name, common->parent_names[i])){
+                       index = i;
+                       break;
+               }
+       }
+
+       if (index < 0) {
+               pr_info("Could not fetch index\n");
+               return index;
+       }
+
+#ifdef CONFIG_SPL_BUILD
+       if (clk->id == CLK_TWSI8_SPL){
+#else
+       if (clk->id == CLK_TWSI8){
+#endif
+               twsi8_reg_val &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
+               twsi8_reg_val |= (index << mux->shift);
+               reg = twsi8_reg_val;
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+                       || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       writel(reg, common->base + common->reg_sel);
+               else
+                       writel(reg, common->base + common->reg_ctrl);
+
+               return 0;
+       }
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(reg | (index << mux->shift), common->base + common->reg_sel);
+       else
+               writel(reg | (index << mux->shift), common->base + common->reg_ctrl);
+
+       if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
+
+               ret = ccu_mix_trigger_fc(clk);
+               if(ret)
+                       pr_info("%s of %s timeout\n", __func__, clk->dev->name);
+       }
+
+       return 0;
+}
+#endif
+
+static int ccu_mix_enable(struct clk *clk)
+{
+#ifdef CONFIG_SPL_BUILD
+       clk->id = transfer_clk_id_to_spl(clk->id);
+#endif
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_gate_config *gate = mix->gate;
+       u32 tmp;
+       u32 val = 0;
+       int timeout_power = 1;
+
+       if (!gate)
+               return 0;
+
+#ifdef CONFIG_SPL_BUILD
+       if (clk->id == CLK_TWSI8_SPL){
+#else
+       if (clk->id == CLK_TWSI8){
+#endif
+               twsi8_reg_val &= ~0x7;
+               twsi8_reg_val |= 0x3;
+               tmp = twsi8_reg_val;
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       writel(tmp, common->base + common->reg_sel);
+               else
+                       writel(tmp, common->base + common->reg_ctrl);
+
+               return 0;
+       }
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               tmp = readl(common->base + common->reg_sel);
+       else
+               tmp = readl(common->base + common->reg_ctrl);
+
+       tmp &= ~gate->gate_mask;
+       tmp |= gate->val_enable;
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(tmp, common->base + common->reg_sel);
+       else
+               writel(tmp, common->base + common->reg_ctrl);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               val = readl(common->base + common->reg_sel);
+       else
+               val = readl(common->base + common->reg_ctrl);
+
+       while ((val & gate->gate_mask) != gate->val_enable && (timeout_power < TIMEOUT_LIMIT)) {
+               udelay(timeout_power);
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       val = readl(common->base + common->reg_sel);
+               else
+                       val = readl(common->base + common->reg_ctrl);
+               timeout_power *= 10;
+       }
+
+       if (timeout_power > 1) {
+               if (val == tmp)
+                       pr_info("write clk_gate %s timeout occur, read pass after %d us delay\n",
+                       clk_hw_get_name(&common->clk), timeout_power);
+               else
+                       pr_info("write clk_gate  %s timeout after %d us!\n", clk_hw_get_name(&common->clk), timeout_power);
+       }
+
+       if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) {
+               udelay(200);
+       }
+
+       return 0;
+}
+
+static ulong ccu_mix_get_rate(struct clk *clk)
+{
+#ifdef CONFIG_SPL_BUILD
+       clk->id = transfer_clk_id_to_spl(clk->id);
+#endif
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_div_config *div = mix->div;
+       unsigned long parent_rate = clk_get_parent_rate(clk);
+       unsigned long val;
+       u32 reg;
+
+#ifdef CONFIG_SPL_BUILD
+       if (clk->id == CLK_TWSI8_SPL){
+#else
+       if (clk->id == CLK_TWSI8){
+#endif
+               val = parent_rate;
+               return val;
+       }
+
+       if (!div){
+               if (mix->factor)
+                       val =  parent_rate * mix->factor->mul / mix->factor->div;
+               else
+                   val =  parent_rate;
+               return val;
+       }
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       val = reg >> div->shift;
+       val &= (1 << div->width) - 1;
+
+       val = divider_recalc_rate(clk, parent_rate, val, div->table,
+                                 div->flags, div->width);
+
+       return val;
+}
+
+unsigned long ccu_mix_calc_best_rate(struct clk *clk, unsigned long rate,
+u32 *mux_val, u32 *div_val, u32 *parent_id)
+{
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_div_config *div = mix->div? mix->div: NULL;
+       struct ccu_mux_config *mux = mix->mux? mix->mux: NULL;
+       struct clk *parent;
+       unsigned long parent_rate = 0, best_rate = 0;
+       u32 i, j, p_id, div_max;
+
+       if(mux){
+               for (i = 0; i < common->num_parents; i++) {
+                       for(p_id = 0; p_id < common->clk_tbl->num; p_id++){
+                               if(!common->clk_tbl->clks[p_id])
+                                       continue;
+                               if(!strcmp(common->clk_tbl->clks[p_id]->dev->name, common->parent_names[i])){
+                                       break;
+                               }
+                       }
+                       clk_get_by_id(p_id, &parent);
+                       if (!parent)
+                               continue;
+                       parent_rate = clk_get_rate(parent);
+                       if(div)
+                               div_max = 1 << div->width;
+                       else
+                               div_max = 1;
+                       for(j = 1; j <= div_max; j++){
+                               if(abs(parent_rate/j - rate) < abs(best_rate - rate)){
+                                       best_rate = DIV_ROUND_UP_ULL(parent_rate, j);
+                                       *mux_val = i;
+                                       *div_val = j - 1;
+                                       *parent_id = p_id;
+                               }
+                       }
+               }
+       }
+       else{
+               parent_rate = clk_get_parent_rate(clk);
+               if(div)
+                       div_max = 1 << div->width;
+               else
+                       div_max = 1;
+               for(j = 1; j <= div_max; j++){
+                       if(abs(parent_rate/j - rate) < abs(best_rate - rate)){
+                               best_rate = DIV_ROUND_UP_ULL(parent_rate, j);
+                               *div_val = j - 1;
+                       }
+               }
+       }
+    return best_rate;
+}
+
+static ulong ccu_mix_set_rate(struct clk *clk, unsigned long rate)
+{
+#ifdef CONFIG_SPL_BUILD
+       clk->id = transfer_clk_id_to_spl(clk->id);
+#endif
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_div_config *div_config = mix->div? mix->div: NULL;
+       struct ccu_mux_config *mux_config = mix->mux? mix->mux: NULL;
+       unsigned long best_rate = 0;
+       u32 cur_mux, cur_div, mux_val = 0, div_val = 0, parent_id = 0;
+       struct clk *parent;
+       unsigned long val;
+       u32 reg;
+       int ret;
+
+#ifdef CONFIG_SPL_BUILD
+       if (clk->id == CLK_TWSI8_SPL)
+#else
+       if (clk->id == CLK_TWSI8)
+#endif
+               return 0;
+
+       if(!div_config && !mux_config){
+               return 0;
+       }
+
+       best_rate = ccu_mix_calc_best_rate(clk, rate, &mux_val, &div_val, &parent_id);
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       if(mux_config){
+               cur_mux = reg >> mux_config->shift;
+               cur_mux &= (1 << mux_config->width) - 1;
+               if(cur_mux != mux_val){
+                       clk_get_by_id(parent_id, &parent);
+                       clk_set_parent(clk, parent);
+               }
+       }
+       if(div_config){
+               cur_div = reg >> div_config->shift;
+               cur_div &= (1 << div_config->width) - 1;
+               if(cur_div == div_val)
+                       return 0;
+       }else{
+               return 0;
+       }
+       val = div_val;
+       if (val > BIT(div_config->width) - 1)
+               return 0;
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       reg &= ~GENMASK(div_config->width + div_config->shift - 1, div_config->shift);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(reg | (val << div_config->shift),
+              common->base + common->reg_sel);
+       else
+               writel(reg | (val << div_config->shift),
+              common->base + common->reg_ctrl);
+
+       if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5) {
+
+               ret = ccu_mix_trigger_fc(clk);
+               if(ret)
+                       pr_info("%s of %s timeout\n", __func__, clk->dev->name);
+       }
+       return 0;
+
+}
+
+unsigned int ccu_mix_get_parent(struct clk *clk)
+{
+       struct ccu_mix *mix = clk_to_ccu_mix(clk);
+       struct ccu_common * common = &mix->common;
+       struct ccu_mux_config *mux = mix->mux;
+       u32 reg;
+       unsigned int parent;
+
+       if(!mux)
+               return 0;
+
+#ifdef CONFIG_SPL_BUILD
+       if (clk->id == CLK_TWSI8_SPL){
+#else
+       if (clk->id == CLK_TWSI8){
+#endif
+               parent = (twsi8_reg_val >> 4) & 0x7;
+               return parent;
+       }
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       parent = reg >> mux->shift;
+       parent &= (1 << mux->width) - 1;
+
+       if (mux->table) {
+               int num_parents = common->num_parents;
+               int i;
+
+               for (i = 0; i < num_parents; i++)
+                       if (mux->table[i] == parent)
+                               return i;
+       }
+       return parent;
+}
+
+const struct clk_ops ccu_mix_ops = {
+#ifndef CONFIG_SPL_BUILD
+       .disable        = ccu_mix_disable,
+       .round_rate     = ccu_mix_round_rate,
+       .set_parent     = ccu_mix_set_parent,
+#endif
+       .enable         = ccu_mix_enable,
+       .get_rate       = ccu_mix_get_rate,
+       .set_rate       = ccu_mix_set_rate,
+};
+
+U_BOOT_DRIVER(ccu_clk_mix) = {
+       .name   = CCU_CLK_MIX,
+       .id     = UCLASS_CLK,
+       .ops    = &ccu_mix_ops,
+};
+
diff --git a/drivers/clk/spacemit/ccu_mix.h b/drivers/clk/spacemit/ccu_mix.h
new file mode 100644 (file)
index 0000000..e1937a1
--- /dev/null
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_MIX_H_
+#define _CCU_MIX_H_
+
+#include "ccu-k1x.h"
+
+#define CCU_CLK_MIX  "ccu_clk_mix"
+#define SPACEMIT_CLK_GATE_NEED_DELAY BIT(0)
+
+struct ccu_gate_config {
+       u32             gate_mask;
+       u32             val_enable;
+       u32             val_disable;
+       u32             flags;
+};
+
+struct ccu_factor_config {
+       u32             div;
+       u32             mul;
+};
+
+struct ccu_mux_config {
+       u8              shift;
+       u8              width;
+       const u8        *table;
+       u32             flags;
+};
+
+struct ccu_div_config {
+       u8                      shift;
+       u8                      width;
+       u32                     max;
+       u32                     offset;
+       u32                     flags;
+       struct clk_div_table    *table;
+};
+
+struct ccu_mix {
+       struct ccu_gate_config  *gate;
+       struct ccu_factor_config  *factor;
+       struct ccu_div_config   *div;
+       struct ccu_mux_config   *mux;
+       struct ccu_common       common;
+};
+
+#define CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, _flags)           \
+       (&(struct ccu_gate_config) {                            \
+               .gate_mask   = _gate_mask,                      \
+               .val_enable  = _val_enable,                     \
+               .val_disable = _val_disable,    \
+               .flags  = _flags,                               \
+       })
+
+#define CCU_FACTOR_INIT(_div, _mul)            \
+       (&(struct ccu_factor_config) {                          \
+               .div = _div,                    \
+               .mul = _mul,                    \
+       })
+
+
+#define CCU_MUX_INIT(_shift, _width, _table, _flags)           \
+       (&(struct ccu_mux_config) {                             \
+               .shift  = _shift,                       \
+               .width  = _width,                       \
+               .table  = _table,                       \
+               .flags  = _flags,                               \
+       })
+
+#define CCU_DIV_INIT(_shift, _width, _table, _flags)           \
+       (&(struct ccu_div_config) {                             \
+               .shift  = _shift,                                       \
+               .width  = _width,                                       \
+               .flags  = _flags,                                       \
+               .table  = _table,                                       \
+       })
+
+#define SPACEMIT_CCU_GATE(_struct, _name, _parent, _base_type, _reg,   \
+                                     _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .common = {                                             \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,       \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+#define SPACEMIT_CCU_GATE_NO_PARENT(_struct, _name, _parent, _base_type, _reg, \
+                                                 _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_name    = SPACEMIT_CLK_NO_PARENT,       \
+                       .num_parents    = 0, \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_FACTOR(_struct, _name, _parent,   \
+                                                 _div, _mul) \
+       struct ccu_mix _struct = {                                      \
+               .factor = CCU_FACTOR_INIT(_div, _mul),   \
+               .common = {                                     \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_MIX, \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_MUX(_struct, _name, _parents, _base_type, _reg,   \
+                                                 _shift, _width, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .mux    = CCU_MUX_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents,     \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_DIV(_struct, _name, _parent, _base_type, _reg,    \
+                                                         _shift, _width, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .div    = CCU_DIV_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_GATE_FACTOR(_struct, _name, _parent, _base_type, _reg,    \
+                                                 _gate_mask, _val_enable, _val_disable,  \
+                                                 _div, _mul, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .factor = CCU_FACTOR_INIT(_div, _mul),   \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+
+#define SPACEMIT_CCU_MUX_GATE(_struct, _name, _parents, _base_type, _reg,      \
+                                                         _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .mux    = CCU_MUX_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents,     \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_DIV_GATE(_struct, _name, _parent, _base_type, _reg,       \
+                                                                _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .div    = CCU_DIV_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               }                                                       \
+       }
+
+
+#define SPACEMIT_CCU_DIV_MUX_GATE(_struct, _name, _parents,            \
+                                       _base_type, _reg_ctrl,                          \
+                                       _mshift, _mwidth,               \
+                                       _muxshift, _muxwidth,           \
+                                       _gate_mask, _val_enable, _val_disable, _flags)                  \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),                              \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                             \
+                       .reg_ctrl               = _reg_ctrl,                            \
+                       .base_type              = _base_type,       \
+                       .name                   = _name,        \
+                       .parent_names   = _parents,     \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV2_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, _reg_sel,       \
+                                                 _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable,           \
+                                                 _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                   .reg_type = CLK_DIV_TYPE_2REG_FC_V4,   \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .reg_sel                = _reg_sel,      \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents,     \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+
+#define SPACEMIT_CCU_DIV_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl,  \
+                                                 _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable,           \
+                                                 _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                   .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents,     \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV_MFC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \
+                                                 _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable,           \
+                                                 _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_MUX_V6,        \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents, \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV_FC_WITH_GATE(_struct, _name, _parent, _base_type, _reg_ctrl,          \
+                                         _mshift, _mwidth, _fc, _gate_mask, _val_enable, _val_disable,                 \
+                                         _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_name    = _parent,      \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV_FC_MUX(_struct, _name, _parents, _base_type, _reg_ctrl,               \
+                                         _mshift, _mwidth, _fc, _muxshift, _muxwidth, _flags)                                  \
+       struct ccu_mix _struct = {                                      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents,     \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_MUX_FC(_struct, _name, _parents, _base_type, _reg_ctrl,           \
+                       _fc, _muxshift, _muxwidth, _flags)                                      \
+       struct ccu_mix _struct = {                                      \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,        \
+                       .parent_names   = _parents, \
+                       .num_parents    = ARRAY_SIZE(_parents), \
+                       .driver_name    = CCU_CLK_MIX, \
+                       .flags                  = _flags, \
+               },                                                      \
+       }
+
+static inline struct ccu_mix *clk_to_ccu_mix(struct clk *clk)
+{
+       struct ccu_common *common = clk_to_ccu_common(clk);
+
+       return container_of(common, struct ccu_mix, common);
+}
+
+unsigned int ccu_mix_get_parent(struct clk *clk);
+
+#endif /* _CCU_DIV_H_ */
diff --git a/drivers/clk/spacemit/ccu_pll.c b/drivers/clk/spacemit/ccu_pll.c
new file mode 100644 (file)
index 0000000..e7e432a
--- /dev/null
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit clock type pll
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <div64.h>
+#include "ccu_pll.h"
+
+#define PLL_MIN_FREQ 600000000
+#define PLL_MAX_FREQ 3400000000
+#define PLL_DELAYTIME 590 //(590*5)us
+
+#define pll_readl(reg)         readl(reg)
+#define pll_readl_pll_swcr1(p) pll_readl(p.base + p.reg_ctrl)
+#define pll_readl_pll_swcr2(p) pll_readl(p.base + p.reg_sel)
+#define pll_readl_pll_swcr3(p) pll_readl(p.base + p.reg_xtc)
+
+#define pll_writel(val, reg)           writel(val, reg)
+#define pll_writel_pll_swcr1(val, p)   pll_writel(val, p.base + p.reg_ctrl)
+#define pll_writel_pll_swcr2(val, p)   pll_writel(val, p.base + p.reg_sel)
+#define pll_writel_pll_swcr3(val, p)   pll_writel(val, p.base + p.reg_xtc)
+
+/* unified pllx_swcr1 for pll1~3 */
+union pllx_swcr1 {
+       struct {
+               unsigned int reg5:8;
+               unsigned int reg6:8;
+               unsigned int reg7:8;
+               unsigned int reg8:8;
+       } b;
+       unsigned int v;
+};
+
+/* unified pllx_swcr2 for pll1~3 */
+union pllx_swcr2 {
+       struct {
+               unsigned int div1_en:1;
+               unsigned int div2_en:1;
+               unsigned int div3_en:1;
+               unsigned int div4_en:1;
+               unsigned int div5_en:1;
+               unsigned int div6_en:1;
+               unsigned int div7_en:1;
+               unsigned int div8_en:1;
+               unsigned int reserved1:4;
+               unsigned int atest_en:1;
+               unsigned int cktest_en:1;
+               unsigned int dtest_en:1;
+               unsigned int rdo:2;
+               unsigned int mon_cfg:4;
+               unsigned int reserved2:11;
+       } b;
+       unsigned int v;
+};
+
+/* unified pllx_swcr3 for pll1~3 */
+union pllx_swcr3{
+       struct {
+               unsigned int div_frc:24;
+               unsigned int div_int:7;
+               unsigned int pll_en:1;
+       } b;
+
+       unsigned int v;
+};
+
+static int ccu_pll_is_enabled(struct clk *clk)
+{
+       struct ccu_pll *p = clk_to_ccu_pll(clk);
+       union pllx_swcr3 swcr3;
+       unsigned int enabled;
+
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       enabled = swcr3.b.pll_en;
+
+       return enabled;
+}
+
+/* frequency unit Mhz, return pll vco freq */
+static ulong __get_vco_freq(struct clk *clk)
+{
+       unsigned int reg5, reg6, reg7, reg8, size, i;
+       unsigned int div_int, div_frc;
+       struct ccu_pll_rate_tbl *freq_pll_regs_table;
+       struct ccu_pll *p = clk_to_ccu_pll(clk);
+       union pllx_swcr1 swcr1;
+       union pllx_swcr3 swcr3;
+
+       swcr1.v = pll_readl_pll_swcr1(p->common);
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+
+       reg5 = swcr1.b.reg5;
+       reg6 = swcr1.b.reg6;
+       reg7 = swcr1.b.reg7;
+       reg8 = swcr1.b.reg8;
+
+       div_int = swcr3.b.div_int;
+       div_frc = swcr3.b.div_frc;
+
+       freq_pll_regs_table = p->pll.rate_tbl;
+       size = p->pll.tbl_size;
+
+       for (i = 0; i < size; i++) {
+               if ((freq_pll_regs_table[i].reg5 == reg5)
+               && (freq_pll_regs_table[i].reg6 == reg6)
+               && (freq_pll_regs_table[i].reg7 == reg7)
+               && (freq_pll_regs_table[i].reg8 == reg8)
+               && (freq_pll_regs_table[i].div_int == div_int)
+               && (freq_pll_regs_table[i].div_frac == div_frc))
+                       return freq_pll_regs_table[i].rate;
+    }
+
+       pr_info("Unknown rate for clock\n");
+       return 0;
+}
+
+static int ccu_pll_enable(struct clk *clk)
+{
+       unsigned int delaytime = PLL_DELAYTIME;
+       unsigned long flags;
+       struct ccu_pll *p = clk_to_ccu_pll(clk);
+       union pllx_swcr3 swcr3;
+
+       if (ccu_pll_is_enabled(clk))
+               return 0;
+
+       spin_lock_irqsave(p->common.lock, flags);
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       swcr3.b.pll_en = 1;
+       pll_writel_pll_swcr3(swcr3.v, p->common);
+       spin_unlock_irqrestore(p->common.lock, flags);
+
+       /* check lock status */
+       udelay(50);
+
+       while ((!(readl(p->pll.lock_base + p->pll.reg_lock) & p->pll.lock_enable_bit))
+              && delaytime) {
+               udelay(5);
+               delaytime--;
+       }
+       if (unlikely(!delaytime)) {
+               pr_err("ccu_pll_enable enabling didn't get stable within 3000us!!!\n" );
+       }
+
+       return 0;
+}
+
+static int ccu_pll_disable(struct clk *clk)
+{
+       struct ccu_pll *p = clk_to_ccu_pll(clk);
+       union pllx_swcr3 swcr3;
+
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       swcr3.b.pll_en = 0;
+       pll_writel_pll_swcr3(swcr3.v, p->common);
+       return 0;
+
+}
+
+/*
+ * pll rate change requires sequence:
+ * clock off -> change rate setting -> clock on
+ * This function doesn't really change rate, but cache the config
+ */
+static ulong ccu_pll_set_rate(struct clk *clk, ulong rate)
+{
+       unsigned int i, reg5 = 0, reg6 = 0, reg7 = 0, reg8 = 0;
+       unsigned int div_int, div_frc;
+       unsigned long old_rate;
+       struct ccu_pll *p = clk_to_ccu_pll(clk);
+       struct ccu_pll_config *params = &p->pll;
+       union pllx_swcr1 swcr1;
+       union pllx_swcr3 swcr3;
+       bool found = false;
+
+       if (ccu_pll_is_enabled(clk)) {
+               pr_info("%s is enabled, ignore the setrate!\n", clk->dev->name);
+               return 0;
+       }
+
+       old_rate = __get_vco_freq(clk);
+       /* setp 1: calculate fbd frcd kvco and band */
+       if (params->rate_tbl) {
+               for (i = 0; i < params->tbl_size; i++) {
+                       if (rate == params->rate_tbl[i].rate) {
+                               found = true;
+
+                               reg5 = params->rate_tbl[i].reg5;
+                               reg6 = params->rate_tbl[i].reg6;
+                               reg7 = params->rate_tbl[i].reg7;
+                               reg8 = params->rate_tbl[i].reg8;
+                               div_int = params->rate_tbl[i].div_int;
+                               div_frc = params->rate_tbl[i].div_frac;
+                               break;
+                       }
+               }
+
+       } else {
+               pr_err("don't find freq table for pll\n");
+               return -EINVAL;
+       }
+
+       /* setp 2: set pll kvco/band and fbd/frcd setting */
+       swcr1.v = pll_readl_pll_swcr1(p->common);
+       swcr1.b.reg5 = reg5;
+       swcr1.b.reg6 = reg6;
+       swcr1.b.reg7 = reg7;
+       swcr1.b.reg8 = reg8;
+       pll_writel_pll_swcr1(swcr1.v, p->common);
+
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       swcr3.b.div_int = div_int;
+       swcr3.b.div_frc = div_frc;
+       pll_writel_pll_swcr3(swcr3.v, p->common);
+
+       return 0;
+}
+
+static ulong ccu_pll_get_rate(struct clk *clk)
+{
+       ulong val;
+       val = __get_vco_freq(clk);
+       return val;
+}
+
+static ulong ccu_pll_round_rate(struct clk *clk, ulong rate)
+{
+       struct ccu_pll *p = clk_to_ccu_pll(clk);
+       unsigned long max_rate = 0;
+       unsigned int i;
+       struct ccu_pll_config *params = &p->pll;
+
+       if (rate > PLL_MAX_FREQ || rate < PLL_MIN_FREQ) {
+               pr_err("%lu rate out of range!\n", rate);
+               return -EINVAL;
+       }
+
+       if (params->rate_tbl) {
+               for (i = 0; i < params->tbl_size; i++) {
+                       if (params->rate_tbl[i].rate <= rate) {
+                               if (max_rate < params->rate_tbl[i].rate)
+                                       max_rate = params->rate_tbl[i].rate;
+                       }
+               }
+       } else {
+               pr_info("don't find freq table for pll\n");
+       }
+       return max_rate;
+}
+
+const struct clk_ops ccu_pll_ops = {
+       .enable         = ccu_pll_enable,
+       .disable        = ccu_pll_disable,
+       .set_rate       = ccu_pll_set_rate,
+       .get_rate       = ccu_pll_get_rate,
+       .round_rate     = ccu_pll_round_rate,
+};
+
+U_BOOT_DRIVER(ccu_clk_pll) = {
+       .name   = CCU_CLK_PLL,
+       .id     = UCLASS_CLK,
+       .ops    = &ccu_pll_ops,
+};
+
diff --git a/drivers/clk/spacemit/ccu_pll.h b/drivers/clk/spacemit/ccu_pll.h
new file mode 100644 (file)
index 0000000..fff7f9b
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_PLL_H_
+#define _CCU_PLL_H_
+
+#include "ccu-k1x.h"
+
+#define CCU_CLK_PLL "ccu_clk_pll"
+struct ccu_pll_rate_tbl {
+       unsigned long long rate;
+       u32 reg5;
+       u32 reg6;
+       u32 reg7;
+       u32 reg8;
+       unsigned int div_int;
+       unsigned int div_frac;
+};
+
+struct ccu_pll_config {
+       struct ccu_pll_rate_tbl * rate_tbl;
+       u32 tbl_size;
+       void __iomem    *lock_base;
+       u32             reg_lock;
+       u32 lock_enable_bit;
+};
+
+#define PLL_RATE(_rate, _reg5, _reg6, _reg7, _reg8, _div_int, _div_frac)               \
+       {                                               \
+               .rate   =       (_rate),                \
+               .reg5   =       (_reg5),                        \
+               .reg6   =       (_reg6),                        \
+               .reg7   =       (_reg7),                        \
+               .reg8   =       (_reg8),                        \
+               .div_int        =       (_div_int),                     \
+               .div_frac       =       (_div_frac),                    \
+       }
+
+struct ccu_pll {
+       struct ccu_pll_config   pll;
+       struct ccu_common       common;
+};
+
+#define _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit)   \
+       {                                               \
+               .rate_tbl       = (struct ccu_pll_rate_tbl *)_table,                    \
+               .tbl_size       = _size,                        \
+               .reg_lock       = _reg_lock,        \
+               .lock_enable_bit        = _lock_enable_bit,                     \
+       }
+
+#define SPACEMIT_CCU_PLL(_struct, _name, _table, _size,        \
+                                                _base_type, _reg_ctrl, _reg_sel, _reg_xtc,\
+                                                _reg_lock, _lock_enable_bit, _is_pll,  \
+                                                _flags)                                \
+       struct ccu_pll _struct = {                                      \
+               .pll    = _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit), \
+               .common = {                                     \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .reg_sel                = _reg_sel,                     \
+                       .reg_xtc                = _reg_xtc,                     \
+                       .base_type              = _base_type,      \
+                       .is_pll                 = _is_pll,       \
+                       .name                   = _name,        \
+                       .parent_name    = SPACEMIT_CLK_NO_PARENT,       \
+                       .num_parents    = 1, \
+                       .driver_name    = CCU_CLK_PLL, \
+               }                                                       \
+       }
+
+
+static inline struct ccu_pll *clk_to_ccu_pll(struct clk *clk)
+{
+       struct ccu_common *common = clk_to_ccu_common(clk);
+
+       return container_of(common, struct ccu_pll, common);
+}
+
+#endif
index bce0a3f65cbeba8e32383a368947bddcf122cd0c..e18a7a6da22c3ddecae5ac562fd0a8b0ba7a1773 100644 (file)
@@ -8,13 +8,13 @@ obj-$(CONFIG_$(SPL_TPL_)DEVRES) += devres.o
 obj-$(CONFIG_$(SPL_TPL_)DM_DEVICE_REMOVE)      += device-remove.o
 obj-$(CONFIG_$(SPL_)SIMPLE_BUS)        += simple-bus.o
 obj-$(CONFIG_SIMPLE_PM_BUS)    += simple-pm-bus.o
-obj-$(CONFIG_DM)       += dump.o
-obj-$(CONFIG_$(SPL_TPL_)REGMAP)        += regmap.o
-obj-$(CONFIG_$(SPL_TPL_)SYSCON)        += syscon-uclass.o
+obj-$(CONFIG_$(SPL_)DM)        += dump.o
+obj-$(CONFIG_$(SPL_)$(SPL_TPL_)REGMAP) += regmap.o
+obj-$(CONFIG_$(SPL_)$(SPL_TPL_)SYSCON) += syscon-uclass.o
 obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o
 ifndef CONFIG_DM_DEV_READ_INLINE
 obj-$(CONFIG_OF_CONTROL) += read.o
 endif
 obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o
 
-ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG
+ccflags-$(CONFIG_$(SPL_)DM_DEBUG) += -DDEBUG
index 738b7884012f3fbfdd6d24b96f7e69da4ef5937f..3d3179ea2d03bccb511f66c952d762d87cfe615d 100644 (file)
@@ -3,7 +3,7 @@ choice
        default STATIC_DDR_CLK_FREQ
        depends on ARCH_P1010 || ARCH_P1020 || ARCH_P2020 || ARCH_T1024 \
                || ARCH_T1042 || ARCH_T2080 || ARCH_T4240 || ARCH_LS1021A \
-               || FSL_LSCH2 || FSL_LSCH3 || TARGET_KMCENT2
+               || FSL_LSCH2 || FSL_LSCH3 || TARGET_KMCENT2 || TARGET_SPACEMIT_K1X
        help
          The DDR clock frequency can either be defined statically now at
          build time, or can be determined at run-time via the
diff --git a/drivers/ddr/spacemit/k1x/Makefile b/drivers/ddr/spacemit/k1x/Makefile
new file mode 100644 (file)
index 0000000..0275799
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2023 Spacemit
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-y += ddr_init.o lpddr4_silicon_init.o ddr_freq.o
+else
+obj-$(CONFIG_DYNAMIC_DDR_CLK_FREQ) += ddr_freq.o
+endif
diff --git a/drivers/ddr/spacemit/k1x/ddr_freq.c b/drivers/ddr/spacemit/k1x/ddr_freq.c
new file mode 100644 (file)
index 0000000..938e989
--- /dev/null
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Spacemit
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include "ddr_freq.h"
+
+#define AP_ALLOW_FREQ_CHG                      BIT(18)
+#define MC_REG_TABLE_EN                                BIT(10)
+#define AP_DCLK_FC_DONE_INT_MSK                        BIT(15)
+
+#define K1X_APMU_BASE                          0xd4282800
+#define PMUAP_REG(n)                           (K1X_APMU_BASE + n)
+#define PMU_CC_CP                              PMUAP_REG(0x000)
+/* sub-bits of PMU_CC_AP */
+#define CP_RD_ST_CLEAR                         BIT(31)
+
+#define PMU_CC_AP                              PMUAP_REG(0x004)
+/* sub-bits of PMU_CC_AP */
+#define AP_RD_ST_CLEAR                         BIT(31)
+#define AP_ALLOW_FREQ_CHG                      BIT(18)
+
+#define PMU_DEBUG_REG                          PMUAP_REG(0x088)
+/* sub-bits of PMU_DEBUG_REG */
+#define AP_WFI_FC                              BIT(22)
+#define CP_WFI_FC                              BIT(21)
+#define AP_IDLE_IND                            BIT(12)
+#define CP_IDLE_IND                            BIT(11)
+#define AP_CLK_OFF_ACK                         BIT(4)
+#define CP_CLK_OFF_ACK                         BIT(3)
+#define MC_HALT                                        BIT(2)
+#define AP_HALT                                        BIT(1)
+#define CP_HALT                                        BIT(0)
+
+#define PMU_AP_IMR                             PMUAP_REG(0x098)
+/* sub-bits of  */
+#define AP_DCLK_FC_DONE_INT_MSK                        BIT(15)
+#define DCLK_FC_DONE_INT_MSK                   BIT(4)
+
+#define PMU_AP_ISR                             PMUAP_REG(0x0a0)
+/* sub-bits of  */
+#define AP_DCLK_FC_DONE_INT_STS                        BIT(15)
+#define DCLK_FC_DONE_INT_STS                   BIT(4)
+#define AP_FC_STS                              BIT(1)
+
+#define PMU_MC_HW_SLP_TYPE                     PMUAP_REG(0x0b0)
+/* sub-bits of PMU_MC_HW_SLP_TYPE */
+#define MC_REG_TABLE_EN                                BIT(10)
+
+
+#define DFC_AP                                 PMUAP_REG(0x180)
+/* sub-bits of DFC_AP */
+#define DFC_FREQ_LV                            0x1
+#define DFC_REQ                                        BIT(0)
+
+#define DFC_STATUS                             PMUAP_REG(0x188)
+/* sub-bits of DFC_STATUS */
+#define DFC_CAUSE_SHIFT                                0x7
+#define DFC_STS                                        BIT(0)
+
+#define DFC_LEVEL_0                            PMUAP_REG(0x190)
+/* sub-bits of  */
+#define dfc_level_reg(n)                       (DFC_LEVEL_0 + (n << 2))
+
+#define FC_LOCK_STATUS                         PMUAP_REG(0x334)
+/* sub-bits of FC_LOCK_STATUS */
+#define CP_RD_STATUS                           BIT(1)
+#define AP_RD_STATUS                           BIT(0)
+
+#define DDR_BYPASS_26M                         26
+#define DDR_BYPASS_312M                                312
+#define DDR_BYPASS_416M                                416
+
+#define DDR_BASE                               0xc0000000
+#define DDR_MR_DATA                            (DDR_BASE + 0x370)
+#define DDR_MR_REG                             (DDR_BASE + 0x24)
+#define DDR_RFSH_TIMING                                (DDR_BASE + 0x394)
+
+#define DDR_FP_NUM                             4
+#define DDR_PLL_NUM                            3
+
+
+enum DCLK_BYPASS_sel {
+       BYPASS_312M = 0,
+       BYPASS_416M,
+       BYPASS_26M,
+       BYPASS_MAX = BYPASS_26M,
+};
+
+#define DCLK_BYPASS_SHIFT              19
+#define DCLK_BYPASS_CLK_EN             22
+#define DCLK_BYPASS_CLK_FC             23
+#define DCLK_BYPASS_MASK               (0x3 << DCLK_BYPASS_SHIFT)
+
+#define DDR_CONS               4
+#define KHZ                    1000
+#define FREQ_MAX               ~(0U)
+
+u32 ddr_cs_num = DDR_CS_NUM;
+
+static u32 mode_register_read(u32 MR, u32 CH, u32 CS)
+{
+       u32 read_data;
+       u32 UI3 = 0;
+
+       writel((0x10010000 + ((CS + 1) << 24) + (CH << 18) + MR), (void __iomem*)DDR_MR_REG);
+       read_data = readl((void __iomem*)DDR_MR_DATA);
+
+       while(!(read_data & 0x80000000)) {
+               read_data = readl((void __iomem*)DDR_MR_DATA);
+       }
+
+       UI3 = readl((void __iomem*)(DDR_BASE + 0x234)) & 0xFF;
+       return UI3;
+}
+
+static u32 format_size(u32 density, u32 io_width)
+{
+       u32 size = 0;
+
+       switch (density) {
+       case DDR_2Gb:
+               size = 256;
+               break;
+       case DDR_3Gb:
+               size = 384;
+               break;
+       case DDR_4Gb:
+               size = 512;
+               break;
+       case DDR_6Gb:
+               size = 768;
+               break;
+       case DDR_8Gb:
+               size = 1024;
+               break;
+       case DDR_12Gb:
+               size = 1536;
+               break;
+       case DDR_16Gb:
+               size = 2048;
+               break;
+       default:
+               pr_err("donot support such density=0x%x device\n", density);
+               return -EINVAL;
+       }
+       if (io_width == 1)
+               size *= 2;
+
+       return size;
+}
+
+u32 ddr_get_mr8(void)
+{
+       u32 mr8;
+       mr8 = mode_register_read(8, 0, 0);
+       return (mr8&0xff);
+}
+
+u32 ddr_get_density(void)
+{
+       u32 ddr_size = 0;
+       u32 mr8_cs00, mr8_cs01, mr8_cs10, mr8_cs11;
+       u32 io_width_cs00, io_width_cs01, io_width_cs10, io_width_cs11;
+       u32 cs0_size = 0;
+       u32 cs1_size = 0;
+
+       mr8_cs00 = mode_register_read(8, 0, 0);
+       mr8_cs01 = mode_register_read(8, 1, 0);
+
+       io_width_cs00 = mr8_cs00 ? mr8_cs00 >> 6 : 0;
+       io_width_cs01 = mr8_cs01 ? mr8_cs01 >> 6 : 0;
+
+       cs0_size = mr8_cs00 ? format_size(((mr8_cs00 >> 2) & 0xf), io_width_cs00) : 0;
+       cs0_size += mr8_cs01 ? format_size(((mr8_cs01 >> 2) & 0xf), io_width_cs01) : 0;
+
+       if (ddr_cs_num > 1) {
+               mr8_cs10 = mode_register_read(8, 0, 1);
+               mr8_cs11 = mode_register_read(8, 1, 1);
+
+               io_width_cs10 = mr8_cs10 ? mr8_cs10 >> 6 : 0;
+               io_width_cs11 = mr8_cs11 ? mr8_cs11 >> 6 : 0;
+
+               cs1_size = mr8_cs10 ? format_size(((mr8_cs10 >> 2) & 0xf), io_width_cs10) : 0;
+               cs1_size += mr8_cs11 ? format_size(((mr8_cs11 >> 2) & 0xf), io_width_cs11) : 0;
+       }
+
+       ddr_size = cs0_size + cs1_size;
+       pr_info("DDR size = %d MB\n", ddr_size);
+
+       return ddr_size;
+}
+
+uint32_t get_manufacture_id(void)
+{
+       uint32_t mr5;
+
+       mr5 = mode_register_read(5, 0, 0);
+       pr_info("MR5 = 0x%x\n",mr5);
+       return (mr5&0xff);
+}
+
+uint32_t get_ddr_rev_id(void)
+{
+       uint32_t mr6;
+
+       mr6 = mode_register_read(6, 0, 0);
+       pr_info("MR6 = 0x%x\n",mr6);
+       return (mr6&0xff);
+}
+
+
+/* adjust ddr frequency to the max value */
+int ddr_freq_max(void)
+{
+//     return ddr_freq_change(MAX_FREQ_LV - 1);
+       return 0;
+}
+
+#ifndef CONFIG_SPL_BUILD
+
+static struct dfc_level_config freq_levels[MAX_FREQ_LV] =
+{
+/*     freq_lv, timing, pll, pll_div, data_rate, high_freq, vol_lv */
+/*     fp 0 == fp 1 just fill in the blanks */
+       {0, 0, DPLL_PLL1, DPLL_DIV4, DPLL_DIV1,  600, 0, 0},
+       {1, 0, DPLL_PLL1, DPLL_DIV4, DPLL_DIV1,  600, 0, 0},
+       {2, 0, DPLL_PLL1, DPLL_DIV3, DPLL_DIV1,  800, 0, 0},
+       {3, 0, DPLL_PLL2, DPLL_DIV3, DPLL_DIV1, 1066, 0, 0},
+       {4, 0, DPLL_PLL1, DPLL_DIV2, DPLL_DIV1, 1200, 0, 1},
+       {5, 1, DPLL_PLL2, DPLL_DIV2, DPLL_DIV1, 1600, 0, 2},
+       {6, 2, DPLL_PLL1, DPLL_DIV1, DPLL_DIV1, 2400, 1, 3},
+       {7, 3, DPLL_PLL2, DPLL_DIV1, DPLL_DIV1, 3200, 1, 3},
+};
+
+
+static int get_cur_freq_level(void)
+{
+       u32 level = readl((void __iomem *)DFC_STATUS);
+       level = (level >> 1) & 0x7;
+
+       return level;
+}
+
+static int dfc_bypass_conf(struct dfc_level_config *cfg)
+{
+       int bypass_sel, timeout = 1000;
+       void __iomem *reg;
+       u32 val;
+
+       switch (cfg->data_rate) {
+       case DDR_BYPASS_26M:
+               bypass_sel = BYPASS_26M;
+               break;
+       case DDR_BYPASS_312M:
+               bypass_sel = BYPASS_312M;
+               break;
+       case DDR_BYPASS_416M:
+               bypass_sel = BYPASS_416M;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       /* set bypass clock */
+       reg = (void __iomem *)PMU_MC_HW_SLP_TYPE;
+       val = readl(reg);
+       val &= ~DCLK_BYPASS_MASK;
+       val |= (bypass_sel << DCLK_BYPASS_SHIFT);
+
+       /* bypass clk enable */
+       val |= (1 << DCLK_BYPASS_CLK_EN);
+       /* bypass clk frequency change request */
+       val |= (1 << DCLK_BYPASS_CLK_FC);
+
+       writel(val, reg);
+
+       val = readl(reg);
+       while ((val & (1 << DCLK_BYPASS_CLK_FC)) && timeout--) {
+               udelay(10);
+               val = readl(reg);
+       }
+
+       if (timeout <= 0) {
+               pr_err("error: switch to bypass clk fail. bypass_sel: %d\n", bypass_sel);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int dfc_level_cfg(struct dfc_level_config *cfg)
+{
+       union dfc_level_ctrl level_ctrl;
+       u32 level = cfg->freq_lv;
+       void __iomem *reg;
+
+       if (level > MAX_FREQ_LV) {
+               pr_err("%s: invalid freq level: 0x%x.\n", __func__, level);
+               return -EINVAL;
+       }
+
+       reg = (void __iomem *)dfc_level_reg((long)level);
+       level_ctrl.ctrl = readl(reg);
+
+       if (cfg->pll_sel == DPLL_PLL_BYPASS) {
+               level_ctrl.bit.pll_bypass = 1;
+               dfc_bypass_conf(cfg);
+       } else
+               level_ctrl.bit.pll_bypass = 0;
+
+       level_ctrl.bit.vol_lv = cfg->vol_lv & 0xf;
+       level_ctrl.bit.mc_timing_num = cfg->mc_timing_num & 0x3;
+       level_ctrl.bit.pll_sel = cfg->pll_sel & 0x1;
+       level_ctrl.bit.dclk_pdiv = cfg->dclk_pdiv & 0x1;
+       level_ctrl.bit.pll_div = cfg->pll_div & 0x3;
+       level_ctrl.bit.high_freq = cfg->high_freq & 0x1;
+       level_ctrl.bit.pll_off = 0x1;
+       writel(level_ctrl.ctrl, reg);
+
+       return 0;
+}
+
+static int ddr_vftbl_cfg(void)
+{
+       int i, ret;
+
+       for (i = 0; i < MAX_FREQ_LV; i++) {
+               ret = dfc_level_cfg(&freq_levels[i]);
+               if (ret < 0) {
+                       pr_err("%s: config freq table failed, %d\n", __func__, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int config_core(void)
+{
+       u32 val;
+
+       /* ap allow freq-change voting */
+       val = readl((void __iomem *)PMU_CC_AP);
+       val |= AP_ALLOW_FREQ_CHG;
+       writel(val, (void __iomem *)PMU_CC_AP);
+
+       /* enable FFC DDR clock change */
+       val = readl((void __iomem *)PMU_MC_HW_SLP_TYPE);
+       val &= ~MC_REG_TABLE_EN;
+       writel(val, (void __iomem *)PMU_MC_HW_SLP_TYPE);
+
+       return 0;
+}
+
+/* enable/disable ddr frequency change done interrupt */
+static void enable_dfc_int(bool en)
+{
+       u32 val;
+
+       val = readl((void __iomem *)PMU_AP_IMR);
+       if (en) {
+               val |= AP_DCLK_FC_DONE_INT_MSK;
+       } else {
+               val &= ~AP_DCLK_FC_DONE_INT_MSK;
+       }
+       writel(val, (void __iomem *)PMU_AP_IMR);
+}
+
+/* clear ddr frequency change done interrupt status*/
+static void clear_dfc_int_status(void)
+{
+       u32 val;
+
+       val = readl((void __iomem *)PMU_AP_ISR);
+       val &= ~(AP_DCLK_FC_DONE_INT_STS | AP_FC_STS);
+       writel(val, (void __iomem *)PMU_AP_ISR);
+}
+
+static int ddrc_freq_chg(u32 level)
+{
+       u32 timeout;
+
+       if (level >= MAX_FREQ_LV) {
+               pr_err("%s: invalid %d freq level\n", __func__, level);
+               return -EINVAL;
+       }
+
+       /* check if dfc in progress */
+       timeout = 1000;
+       while (--timeout) {
+               if (!(readl((void __iomem *)DFC_STATUS) & DFC_STS))
+                       break;
+               udelay(10);
+       }
+
+       if (!timeout) {
+               pr_err("%s: another dfc is in pregress. status:0x%x\n", __func__, readl((void __iomem *)DFC_STATUS));
+               return -EBUSY;
+       }
+
+       /* trigger frequence change */
+       writel(((level & 0x7) << DFC_FREQ_LV) | DFC_REQ, (void __iomem *)DFC_AP);
+
+       timeout = 1000;
+       while (--timeout) {
+               udelay(10);
+               if (!(readl((void __iomem *)DFC_STATUS) & DFC_STS))
+                       break;
+       }
+
+       if (!timeout) {
+               pr_err("dfc error! status:0x%x\n", readl((void __iomem *)DFC_STATUS));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int wait_freq_change_done(void)
+{
+       int timeout = 100;
+       u32 val;
+
+       while (--timeout) {
+               udelay(10);
+               val = readl((void __iomem *)PMU_AP_ISR);
+               if (val & AP_DCLK_FC_DONE_INT_STS)
+                       break;
+       }
+
+       if (!timeout) {
+               pr_err("%s: timeout! can not wait dfc done interrupt\n", __func__);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int ddr_freq_init(void)
+{
+       int ret;
+       static bool ddr_freq_init_flag = false; 
+
+       if(ddr_freq_init_flag == true) {
+               return 0;
+       }
+
+       #ifdef CONFIG_K1_X_BOARD_ASIC
+       ret = ddr_vftbl_cfg();
+       if (ret < 0) {
+               pr_err("%s failed!\n", __func__);
+               return ret;
+       }
+       #endif
+
+       ddr_freq_init_flag = true;
+
+       return 0;
+}
+
+static int ddr_freq_change(u32 freq_level)
+{
+       int ret, freq_curr;
+
+       ret = ddr_freq_init();
+       if (ret < 0) {
+               pr_err("ddr_freq_init failed: %d\n", -ret);
+               return ret;
+       }
+
+       freq_curr = get_cur_freq_level();
+
+       if(freq_curr == freq_level) {
+               /* dram frequency is same as the target already */
+               return 0;
+       }
+
+       config_core();
+
+       /* request change begin */
+       enable_dfc_int(true);
+       ret = ddrc_freq_chg(freq_level);
+       if (ret < 0) {
+               pr_err("%s: ddrc_freq_chg fail. ret = %d\n", __func__, ret);
+               return ret;
+       }
+
+       /* wait for frequency change done */
+       ret = wait_freq_change_done();
+       if (ret < 0) {
+               pr_err("%s: wait_freq_change_done timeout. ret = %d\n", __func__, ret);
+               return ret;
+       }
+
+       clear_dfc_int_status();
+       enable_dfc_int(false);
+
+       pr_info("%s: ddr frequency change from level %d to %d\n", __func__, freq_curr, get_cur_freq_level());
+
+       return 0;
+}
+
+int do_ddr_freq(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+       u32 freq_level;
+       int i;
+
+       if (argc <= 1 || argc > 2) {
+               /* invalid parameter, report error */
+               return CMD_RET_USAGE;
+       }
+
+       if (0 == strcmp(argv[1], "list")) {
+               /* show valid frequency list */
+               pr_info("support frequency list as shown below:\n");
+               for (i = 0; i < ARRAY_SIZE(freq_levels); i++) {
+                       pr_info("Frequency level: %d, data rate: %dMT/s\n",
+                               freq_levels[i].freq_lv, freq_levels[i].data_rate);
+               }
+
+               return CMD_RET_SUCCESS;
+       }
+
+       freq_level = simple_strtoul(argv[1], NULL, 0);
+       if(freq_level >= MAX_FREQ_LV) {
+               /* invalid parameter, report error */
+               return CMD_RET_USAGE;
+       }
+
+       ddr_freq_change(freq_level);
+       pr_info("Change DDR data rate to %dMT/s\n", freq_levels[get_cur_freq_level()].data_rate);
+
+       return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+       ddrfreq, CONFIG_SYS_MAXARGS, 1, do_ddr_freq,
+       "Adjusting the DRAM working frequency",
+       "ddrfreq list   - display the valid frequncy points\n"
+       "ddrfreq [0~7]  - adjust dram working frequency to level[0~7]"
+);
+#endif
diff --git a/drivers/ddr/spacemit/k1x/ddr_freq.h b/drivers/ddr/spacemit/k1x/ddr_freq.h
new file mode 100644 (file)
index 0000000..ca6cf14
--- /dev/null
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Spacemit
+ */
+
+#ifndef _DDR_FREQ_H_
+#define _DDR_FREQ_H_
+
+#define PMUA_REG_BASE                  0xd4282800
+#define DCLK_BYPASS_CLK                        (PMUA_REG_BASE + 0x0b0)
+#define DDR_CKPHY_PLL1_CTRL1_ADDR      (PMUA_REG_BASE + 0x39c)
+#define DDR_CKPHY_PLL1_CTRL2_ADDR      (PMUA_REG_BASE + 0x3a0)
+#define DDR_CKPHY_PLL2_CTRL1_ADDR      (PMUA_REG_BASE + 0x3a8)
+#define DDR_CKPHY_PLL2_CTRL2_ADDR      (PMUA_REG_BASE + 0x3ac)
+
+#define MAX_FREQ_LV            8
+
+typedef enum {
+       DDR_1Gb = 12,
+       DDR_2Gb = 0,
+       DDR_3Gb,
+       DDR_4Gb,
+       DDR_6Gb,
+       DDR_8Gb,
+       DDR_12Gb,
+       DDR_16Gb,
+       RESERVEDX,
+} lpddr4_density_type;
+
+typedef enum {
+       DPLL_DIV1,
+       DPLL_DIV2,
+       DPLL_DIV3,
+       DPLL_DIV4,
+} pll_div_v2;
+
+typedef enum {
+       DPLL_PLL2,
+       DPLL_PLL1,
+       DPLL_PLL_BYPASS,
+} pll_sel_v2;
+
+struct dfc_level_config {
+       u32 freq_lv;
+       u32 mc_timing_num;
+       u32 pll_sel;
+       u32 pll_div;
+       u32 dclk_pdiv;
+       u32 data_rate;
+       u32 high_freq;
+       u32 vol_lv;
+};
+
+union dfc_level_ctrl {
+       struct {
+               u32 vol_lv:4;
+               u32 mc_timing_num:2;
+               u32 high_freq:1;
+               u32 pll_off:1;
+               u32 pll_sel:1;
+               u32 kvco:3;
+               u32 pll_bypass:1;
+               u32 dclk_pdiv:1;
+               u32 pll_div:2;
+               u32 pll_fbdiv:7;
+               u32 band_sel:1;
+               u32 pll_frcdiv:8;
+       } bit;
+       u32 ctrl;
+};
+
+u32 ddr_get_density(void);
+
+#endif /* _DDR_FREQ_H_ */
diff --git a/drivers/ddr/spacemit/k1x/ddr_init.c b/drivers/ddr/spacemit/k1x/ddr_init.c
new file mode 100644 (file)
index 0000000..1529a79
--- /dev/null
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Spacemit
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <div64.h>
+#include <fdtdec.h>
+#include <init.h>
+#include <log.h>
+#include <ram.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/sizes.h>
+#ifdef CONFIG_K1_X_BOARD_FPGA
+#include "ddr_init_fpga.h"
+#endif
+
+#define DDR_CHECK_SIZE                 (0x2000)
+#define DDR_CHECK_STEP                 (0x2000)
+#define DDR_CHECK_CNT                  (0x1000)
+#define TOP_DDR_NUM                            1
+
+extern u32 ddr_cs_num;
+
+static int test_pattern(fdt_addr_t base, fdt_size_t size)
+{
+       fdt_addr_t addr;
+       fdt_size_t check_size;
+       uint32_t offset;
+       uint32_t *ddr_data = NULL;
+       uint32_t *save_data;
+       int err = 0;
+
+       check_size = (DDR_CHECK_SIZE / DDR_CHECK_STEP) * DDR_CHECK_CNT;
+       ddr_data = malloc(check_size);
+       if (!ddr_data) {
+               pr_err("test zone malloc fail size 0x%llx\n", check_size);
+               return -1;
+       }
+
+       save_data = ddr_data;
+       /* to avoid overlap important data as image or ramdump  */
+       for (addr = base; addr < base + size; addr += DDR_CHECK_STEP) {
+               for (offset = 0; offset < DDR_CHECK_CNT; offset += 4) {
+                       *save_data = readl((void*)addr + offset);
+                       save_data++;
+               }
+       }
+
+       for (addr = base; addr < base + size; addr += DDR_CHECK_STEP) {
+               for (offset = 0; offset < DDR_CHECK_CNT; offset += 4) {
+                       writel((uint32_t)(addr + offset), (void*)addr + offset);
+               }
+       }
+
+       /* writeback and invalid cache */
+       flush_dcache_range(base,base+size);
+       invalidate_dcache_range(base,base+size);
+
+       for (addr = base; addr < base + size; addr += DDR_CHECK_STEP) {
+               for (offset = 0; offset < DDR_CHECK_CNT; offset += 4) {
+                       if (readl((void*)addr + offset) != (uint32_t)(addr + offset)) {
+                               pr_err("ddr check error %x vs %x\n", (uint32_t)(addr + offset), readl((void*)addr + offset));
+                               err++;
+                               if (err > 10)
+                                       goto ERR_HANDLE;
+                       }
+               }
+       }
+
+       for (addr = base; addr < base + size; addr += DDR_CHECK_STEP) {
+               for (offset = 0; offset < DDR_CHECK_CNT; offset += 4) {
+                       writel((~(uint32_t)(addr + offset)), (void*)addr + offset);
+               }
+       }
+
+       /* writeback and invalid cache */
+       flush_dcache_range(base,base+size);
+       invalidate_dcache_range(base,base+size);
+
+       for (addr = base; addr < base + size; addr += DDR_CHECK_STEP) {
+               for (offset = 0; offset < DDR_CHECK_CNT; offset += 4) {
+                       if (readl((void*)addr + offset) != (~(uint32_t)(addr + offset))) {
+                               pr_err("ddr check error %x vs %x\n", (uint32_t)(~(addr + offset)), readl((void*)addr + offset));
+                               err++;
+                               if (err > 10)
+                                       goto ERR_HANDLE;
+
+                       }
+               }
+       }
+
+ERR_HANDLE:
+       save_data = ddr_data;
+       for (addr = base; addr < base + size; addr += DDR_CHECK_STEP) {
+               for (offset = 0; offset < DDR_CHECK_CNT; offset += 4) {
+                       writel(*save_data, (void*)addr + offset);
+                       save_data++;
+               }
+       }
+       if (err != 0) {
+               pr_emerg("dram pattern test failed!\n");
+       }
+
+       free(ddr_data);
+
+       return err;
+}
+
+#ifdef CONFIG_K1_X_BOARD_ASIC
+extern void lpddr4_silicon_init(uint32_t base, uint32_t data_rate);
+#endif
+
+static int spacemit_ddr_probe(struct udevice *dev)
+{
+       int ret;
+
+#ifdef CONFIG_K1_X_BOARD_FPGA
+       void (*ddr_init)(void);
+#else
+       uint32_t ddr_datarate;
+       fdt_addr_t ddrc_base;
+
+       ddrc_base = dev_read_addr(dev);
+#endif
+
+#ifdef CONFIG_K1_X_BOARD_FPGA
+       ddr_init = (void(*)(void))(lpddr4_init_fpga_data + 0x144);
+       ddr_init();
+#else
+
+       /* check if dram data-rate is configued in dts */
+       if(dev_read_u32u(dev, "datarate", &ddr_datarate)) {
+               pr_info("ddr data rate not configed in dts, use 1200 as default!\n");
+               ddr_datarate = 1200;
+       } else {
+               pr_info("ddr data rate is %u configured in dts\n", ddr_datarate);
+       }
+
+       /* if DDR cs number is NOT configued in eeprom or in dts, use default value */
+       if((0 == ddr_cs_num) && dev_read_u32u(dev, "cs-num", &ddr_cs_num)) {
+               pr_info("ddr cs number not configed in dts!\n");
+               ddr_cs_num = DDR_CS_NUM;
+       }
+
+       /* init dram */
+       uint64_t start = get_timer(0);
+       lpddr4_silicon_init(ddrc_base, ddr_datarate);
+       start = get_timer(start);
+       printf("lpddr4_silicon_init consume %lldms\n", start);
+#endif
+
+       ret = test_pattern(CONFIG_SYS_SDRAM_BASE, DDR_CHECK_SIZE);
+       if (ret < 0) {
+               pr_err("dram init failed!\n");
+               return -EIO;
+       }
+       pr_info("dram init done\n");
+
+       return 0;
+}
+
+static const struct udevice_id spacemit_ddr_ids[] = {
+       { .compatible = "spacemit,ddr-ctl" },
+       {}
+};
+
+U_BOOT_DRIVER(spacemit_ddr) = {
+       .name = "spacemit_ddr_ctrl",
+       .id = UCLASS_RAM,
+       .of_match = spacemit_ddr_ids,
+       .probe = spacemit_ddr_probe,
+};
diff --git a/drivers/ddr/spacemit/k1x/ddr_init_asic.h b/drivers/ddr/spacemit/k1x/ddr_init_asic.h
new file mode 100644 (file)
index 0000000..a6b05e0
--- /dev/null
@@ -0,0 +1,1696 @@
+#ifndef _DDR_INIT_ASIC_H_
+#define _DDR_INIT_ASIC_H_
+
+#define MC_CH0_BASE            0x200
+#define        MC_CH0_PHY_BASE         0x1000
+#define        ANALOG_CONTROL_OFFSET   0x0
+#define        OTHER_CONTROL_OFFSET    0x10000
+#define        TRAINING_CONTROL_OFFSET 0x18000
+
+#define        subPHY_A_OFFSET         0x0
+#define        subPHY_B_OFFSET         0x200
+#define        subPHY_C_OFFSET         0x400
+#define        subPHY_D_OFFSET         0x600
+
+#define        CS0_OFFSET              0x0
+#define        CS1_OFFSET              0x100
+
+#define        CAPHY_OFFSET            0x2000
+#define        DATAPHY0_OFFSET         0x0
+#define        DATAPHY1_OFFSET         0x1000
+#define        COMMON_OFFSET           0x3000
+#define        FREQ_POINT_OFFSET       0x4000
+
+#define TOP_EXT_CLK_DIV_OFFSET         0
+#define TOP_EXT_CLK_SEL_OFFSET         1
+#define TOP_PLL2_DIV_OFFSET            2
+#define TOP_PLL1_DIV_OFFSET            4
+#define TOP_PLL1_2_SEL_OFFSET          6
+#define TOP_PLL2_EN_OFFSET             8
+#define TOP_PLL1_EN_OFFSET             9
+#define TOP_DDRPHY1_EN_OFFSET          31
+#define TOP_DDRPHY0_EN_OFFSET          30
+#define TOP_DCLK_BYPASS_FC_REQ_OFFSET  23
+#define TOP_DCLK_BYPASS_CLK_EN_OFFSET  22
+#define TOP_DCLK_BYPASS_RST_OFFSET     21
+#define TOP_DCLK_BYPASS_SEL_OFFSET     19
+#define TOP_DCLK_BYPASS_DIV_OFFSET     16
+#define TOP_MC_REG_TABLE_EN_OFFSET     10
+#define TOP_FREQ_PLL_CHG_MODE_OFFSET   9
+#define TOP_MC_REQ_TABLE_NUM_OFFSET    3
+#define TOP_AP_ALLOW_SPD_CHG           18
+#define TOP_DDR_FREQ_CHG_REQ           22
+
+// emu for device density
+typedef enum {
+       BANK_2 = 0,
+       BANK_4,
+       BANK_8,
+       BANK_RESERVED,
+} bank_num;
+
+typedef enum {
+       ROW_11 = 1,
+       ROW_12,
+       ROW_13,
+       ROW_14,
+       ROW_15,
+       ROW_16,
+       ROW_17,
+       ROW_18,
+} row_num;
+
+typedef enum {
+       COL_8 = 1,
+       COL_9,
+       COL_10,
+       COL_11,
+       COL_12,
+} col_num;
+
+typedef enum {
+       IO_X16 = 0,
+       IO_X8,
+} io_width;
+
+static const unsigned char lpddr4_training_img[] = {
+       0x79, 0x71, 0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18, 0x23, 0x3c, 0xa4, 0xfc,
+       0x83, 0x37, 0x84, 0xfd, 0x9c, 0x63, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x37,
+       0x84, 0xfd, 0xa1, 0x07, 0x9c, 0x63, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x37,
+       0x84, 0xfd, 0xc1, 0x07, 0x9c, 0x63, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x37,
+       0x84, 0xfd, 0xe1, 0x07, 0x9c, 0x63, 0x3e, 0x87, 0x97, 0x57, 0x00, 0x00,
+       0x93, 0x87, 0x07, 0xc2, 0x98, 0xe3, 0x83, 0x26, 0x44, 0xfe, 0x03, 0x27,
+       0x84, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x36, 0x86, 0xba, 0x85, 0x3e, 0x85,
+       0xef, 0x40, 0xe0, 0x24, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74, 0x45, 0x61,
+       0x82, 0x80, 0x79, 0x71, 0x22, 0xf4, 0x00, 0x18, 0xaa, 0x87, 0xae, 0x86,
+       0x32, 0x87, 0x23, 0x2e, 0xf4, 0xfc, 0xb6, 0x87, 0x23, 0x2c, 0xf4, 0xfc,
+       0xba, 0x87, 0x23, 0x2a, 0xf4, 0xfc, 0x23, 0x20, 0x04, 0xfe, 0x83, 0x27,
+       0x84, 0xfd, 0x1b, 0x87, 0x07, 0x00, 0x89, 0x47, 0x63, 0x1a, 0xf7, 0x00,
+       0x8d, 0x47, 0x23, 0x20, 0xf4, 0xfe, 0x93, 0x07, 0x40, 0x04, 0x23, 0x22,
+       0xf4, 0xfe, 0x39, 0xa0, 0x85, 0x47, 0x23, 0x20, 0xf4, 0xfe, 0x91, 0x47,
+       0x23, 0x22, 0xf4, 0xfe, 0x83, 0x27, 0x44, 0xfd, 0x81, 0x27, 0x89, 0xc7,
+       0x85, 0x47, 0x23, 0x26, 0xf4, 0xfe, 0x21, 0xa0, 0x89, 0x47, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0x04, 0xfe, 0x9b, 0x97, 0x87, 0x01, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x27, 0xc4, 0xfe, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0xd9, 0x8f, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0x1b, 0x07, 0x07, 0x02,
+       0x01, 0x27, 0x02, 0x17, 0x01, 0x93, 0xbe, 0x86, 0xb7, 0x07, 0x00, 0x10,
+       0xd5, 0x8f, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x27, 0x44, 0xfd, 0x81, 0x27,
+       0xb1, 0xc3, 0x83, 0x27, 0xc4, 0xfd, 0xa1, 0x27, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x9c, 0x43, 0x23, 0x24, 0xf4, 0xfe, 0x11, 0xa8, 0x83, 0x27,
+       0xc4, 0xfd, 0xa1, 0x27, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43,
+       0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe, 0x3e, 0x87, 0x83, 0x27,
+       0x44, 0xfe, 0xf9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x44, 0xfe,
+       0x81, 0x27, 0xe3, 0x9c, 0xe7, 0xfc, 0x25, 0xa8, 0x83, 0x27, 0xc4, 0xfd,
+       0xa1, 0x27, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x24,
+       0xf4, 0xfe, 0x11, 0xa8, 0x83, 0x27, 0xc4, 0xfd, 0xa1, 0x27, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27,
+       0x84, 0xfe, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfe, 0xf9, 0x8f, 0x81, 0x27,
+       0xe5, 0xf3, 0x01, 0x00, 0x22, 0x74, 0x45, 0x61, 0x82, 0x80, 0x79, 0x71,
+       0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18, 0x23, 0x3c, 0xa4, 0xfc, 0xa3, 0x07,
+       0x04, 0xfe, 0xe1, 0xa2, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x87, 0xac,
+       0x9c, 0x63, 0x03, 0x47, 0xf4, 0xfe, 0x01, 0x27, 0xba, 0x85, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0x65, 0x1b, 0x82, 0x97, 0x23, 0x07, 0x04, 0xfe,
+       0x7d, 0xa8, 0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27, 0x91, 0xc7, 0x3e, 0x87,
+       0x85, 0x47, 0x63, 0x0e, 0xf7, 0x00, 0x3d, 0xa0, 0x97, 0x57, 0x00, 0x00,
+       0x93, 0x87, 0x47, 0xa9, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05,
+       0xa5, 0x1c, 0x82, 0x97, 0x21, 0xa8, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0xa7, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x45, 0x1d,
+       0x82, 0x97, 0x01, 0x00, 0xa3, 0x06, 0x04, 0xfe, 0xb9, 0xa0, 0x97, 0x57,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0xa6, 0x98, 0x63, 0x83, 0x47, 0xf4, 0xfe,
+       0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27, 0x83, 0x46,
+       0xd4, 0xfe, 0x81, 0x26, 0x03, 0x36, 0x84, 0xfd, 0x86, 0x05, 0xae, 0x97,
+       0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x83, 0xc7,
+       0xb7, 0x92, 0x81, 0x27, 0xbe, 0x85, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05,
+       0xa5, 0x1a, 0x02, 0x97, 0x83, 0x47, 0xd4, 0xfe, 0x85, 0x27, 0xa3, 0x06,
+       0xf4, 0xfe, 0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xfd, 0x47,
+       0xe3, 0xf5, 0xe7, 0xfa, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x87, 0xa0,
+       0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x65, 0x18, 0x82, 0x97,
+       0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07, 0xf4, 0xfe, 0x83, 0x47,
+       0xe4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x85, 0x47, 0xe3, 0xfd, 0xe7, 0xf2,
+       0x23, 0x07, 0x04, 0xfe, 0x7d, 0xa8, 0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27,
+       0x91, 0xc7, 0x3e, 0x87, 0x85, 0x47, 0x63, 0x0e, 0xf7, 0x00, 0x3d, 0xa0,
+       0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x47, 0x9c, 0x9c, 0x63, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0x14, 0x82, 0x97, 0x21, 0xa8, 0x97, 0x57,
+       0x00, 0x00, 0x93, 0x87, 0xe7, 0x9a, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00,
+       0x13, 0x05, 0x45, 0x15, 0x82, 0x97, 0x01, 0x00, 0xa3, 0x06, 0x04, 0xfe,
+       0xb9, 0xa0, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x27, 0x99, 0x98, 0x63,
+       0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe,
+       0x81, 0x27, 0x83, 0x46, 0xd4, 0xfe, 0x81, 0x26, 0x03, 0x36, 0x84, 0xfd,
+       0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66,
+       0xb6, 0x97, 0x83, 0xc7, 0xd7, 0xd3, 0x81, 0x27, 0xbe, 0x85, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0x0d, 0x02, 0x97, 0x83, 0x47, 0xd4, 0xfe,
+       0x85, 0x27, 0xa3, 0x06, 0xf4, 0xfe, 0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7,
+       0xf7, 0x0f, 0xfd, 0x47, 0xe3, 0xf5, 0xe7, 0xfa, 0x97, 0x57, 0x00, 0x00,
+       0x93, 0x87, 0x87, 0x93, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05,
+       0x65, 0x0b, 0x82, 0x97, 0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07,
+       0xf4, 0xfe, 0x83, 0x47, 0xe4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x85, 0x47,
+       0xe3, 0xfd, 0xe7, 0xf2, 0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07,
+       0xf4, 0xfe, 0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47,
+       0xe3, 0xf8, 0xe7, 0xe2, 0x01, 0x00, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74,
+       0x45, 0x61, 0x82, 0x80, 0x79, 0x71, 0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18,
+       0x23, 0x3c, 0xa4, 0xfc, 0xa3, 0x07, 0x04, 0xfe, 0xf1, 0xa2, 0x97, 0x57,
+       0x00, 0x00, 0x93, 0x87, 0x67, 0x8d, 0x9c, 0x63, 0x03, 0x47, 0xf4, 0xfe,
+       0x01, 0x27, 0x83, 0x36, 0x84, 0xfd, 0x36, 0x97, 0x03, 0x47, 0x07, 0x00,
+       0x01, 0x27, 0xba, 0x85, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x85, 0x08,
+       0x82, 0x97, 0x23, 0x07, 0x04, 0xfe, 0x6d, 0xa8, 0x83, 0x47, 0xe4, 0xfe,
+       0x81, 0x27, 0x91, 0xc7, 0x3e, 0x87, 0x85, 0x47, 0x63, 0x0e, 0xf7, 0x00,
+       0x3d, 0xa0, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x67, 0x89, 0x9c, 0x63,
+       0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x07, 0x82, 0x97, 0x21, 0xa8,
+       0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x07, 0x88, 0x9c, 0x63, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0x65, 0x08, 0x82, 0x97, 0x01, 0x00, 0xa3, 0x06,
+       0x04, 0xfe, 0xa9, 0xa0, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87, 0x47, 0x86,
+       0x98, 0x63, 0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47,
+       0xe4, 0xfe, 0x81, 0x27, 0x83, 0x46, 0xd4, 0xfe, 0x81, 0x26, 0x03, 0x36,
+       0x84, 0xfd, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97,
+       0x83, 0xc7, 0x07, 0x41, 0x81, 0x27, 0xbe, 0x85, 0x17, 0x45, 0x00, 0x00,
+       0x13, 0x05, 0x05, 0xfb, 0x02, 0x97, 0x83, 0x47, 0xd4, 0xfe, 0x85, 0x27,
+       0xa3, 0x06, 0xf4, 0xfe, 0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0xfd, 0x47, 0xe3, 0xf7, 0xe7, 0xfa, 0x97, 0x57, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0x80, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xc5, 0xf8,
+       0x82, 0x97, 0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07, 0xf4, 0xfe,
+       0x83, 0x47, 0xe4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x85, 0x47, 0xe3, 0xff,
+       0xe7, 0xf2, 0x23, 0x07, 0x04, 0xfe, 0x6d, 0xa8, 0x83, 0x47, 0xe4, 0xfe,
+       0x81, 0x27, 0x91, 0xc7, 0x3e, 0x87, 0x85, 0x47, 0x63, 0x0e, 0xf7, 0x00,
+       0x3d, 0xa0, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0xa7, 0x7c, 0x9c, 0x63,
+       0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x05, 0xff, 0x82, 0x97, 0x21, 0xa8,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x47, 0x7b, 0x9c, 0x63, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0xff, 0x82, 0x97, 0x01, 0x00, 0xa3, 0x06,
+       0x04, 0xfe, 0xa9, 0xa0, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0x79,
+       0x98, 0x63, 0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47,
+       0xe4, 0xfe, 0x81, 0x27, 0x83, 0x46, 0xd4, 0xfe, 0x81, 0x26, 0x03, 0x36,
+       0x84, 0xfd, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97,
+       0x83, 0xc7, 0x07, 0x01, 0x81, 0x27, 0xbe, 0x85, 0x17, 0x45, 0x00, 0x00,
+       0x13, 0x05, 0x45, 0xee, 0x02, 0x97, 0x83, 0x47, 0xd4, 0xfe, 0x85, 0x27,
+       0xa3, 0x06, 0xf4, 0xfe, 0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0xfd, 0x47, 0xe3, 0xf7, 0xe7, 0xfa, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87,
+       0x27, 0x74, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x05, 0xec,
+       0x82, 0x97, 0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07, 0xf4, 0xfe,
+       0x83, 0x47, 0xe4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x85, 0x47, 0xe3, 0xff,
+       0xe7, 0xf2, 0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe,
+       0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xf6,
+       0xe7, 0xe2, 0xa3, 0x07, 0x04, 0xfe, 0xd1, 0xaa, 0x97, 0x47, 0x00, 0x00,
+       0x93, 0x87, 0x87, 0x6f, 0x9c, 0x63, 0x03, 0x47, 0xf4, 0xfe, 0x01, 0x27,
+       0x83, 0x36, 0x84, 0xfd, 0x36, 0x97, 0x03, 0x47, 0x07, 0x00, 0x01, 0x27,
+       0xba, 0x85, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xa5, 0xea, 0x82, 0x97,
+       0x23, 0x07, 0x04, 0xfe, 0x7d, 0xa8, 0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27,
+       0x91, 0xc7, 0x3e, 0x87, 0x85, 0x47, 0x63, 0x0e, 0xf7, 0x00, 0x3d, 0xa0,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0x6b, 0x9c, 0x63, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xe5, 0xf1, 0x82, 0x97, 0x21, 0xa8, 0x97, 0x47,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0x6a, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00,
+       0x13, 0x05, 0x05, 0xf2, 0x82, 0x97, 0x01, 0x00, 0xa3, 0x06, 0x04, 0xfe,
+       0xb9, 0xa0, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x67, 0x68, 0x98, 0x63,
+       0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe,
+       0x81, 0x27, 0x83, 0x46, 0xd4, 0xfe, 0x81, 0x26, 0x03, 0x36, 0x84, 0xfd,
+       0x86, 0x05, 0xae, 0x97, 0x8a, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66,
+       0xb6, 0x97, 0x83, 0xc7, 0x17, 0x8a, 0x81, 0x27, 0xbe, 0x85, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xe5, 0xdc, 0x02, 0x97, 0x83, 0x47, 0xd4, 0xfe,
+       0x85, 0x27, 0xa3, 0x06, 0xf4, 0xfe, 0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7,
+       0xf7, 0x0f, 0x8d, 0x47, 0xe3, 0xf5, 0xe7, 0xfa, 0x97, 0x47, 0x00, 0x00,
+       0x93, 0x87, 0xc7, 0x62, 0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05,
+       0xa5, 0xda, 0x82, 0x97, 0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07,
+       0xf4, 0xfe, 0x83, 0x47, 0xe4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x85, 0x47,
+       0xe3, 0xfd, 0xe7, 0xf2, 0x23, 0x07, 0x04, 0xfe, 0x7d, 0xa8, 0x83, 0x47,
+       0xe4, 0xfe, 0x81, 0x27, 0x91, 0xc7, 0x3e, 0x87, 0x85, 0x47, 0x63, 0x0e,
+       0xf7, 0x00, 0x3d, 0xa0, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0x5e,
+       0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xe5, 0xe7, 0x82, 0x97,
+       0x21, 0xa8, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x27, 0x5d, 0x9c, 0x63,
+       0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x85, 0xe8, 0x82, 0x97, 0x01, 0x00,
+       0xa3, 0x06, 0x04, 0xfe, 0xb9, 0xa0, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87,
+       0x67, 0x5b, 0x98, 0x63, 0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85, 0x07, 0x00,
+       0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27, 0x83, 0x46, 0xd4, 0xfe, 0x81, 0x26,
+       0x03, 0x36, 0x84, 0xfd, 0x86, 0x05, 0xae, 0x97, 0x8a, 0x07, 0xb2, 0x97,
+       0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x83, 0xc7, 0x17, 0x82, 0x81, 0x27,
+       0xbe, 0x85, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xe5, 0xcf, 0x02, 0x97,
+       0x83, 0x47, 0xd4, 0xfe, 0x85, 0x27, 0xa3, 0x06, 0xf4, 0xfe, 0x83, 0x47,
+       0xd4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x8d, 0x47, 0xe3, 0xf5, 0xe7, 0xfa,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0xc7, 0x55, 0x9c, 0x63, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0xcd, 0x82, 0x97, 0x83, 0x47, 0xe4, 0xfe,
+       0x85, 0x27, 0x23, 0x07, 0xf4, 0xfe, 0x83, 0x47, 0xe4, 0xfe, 0x13, 0xf7,
+       0xf7, 0x0f, 0x85, 0x47, 0xe3, 0xfd, 0xe7, 0xf2, 0x83, 0x47, 0xf4, 0xfe,
+       0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe, 0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7,
+       0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xf2, 0xe7, 0xe2, 0x01, 0x00, 0x01, 0x00,
+       0xa2, 0x70, 0x02, 0x74, 0x45, 0x61, 0x82, 0x80, 0x79, 0x71, 0x06, 0xf4,
+       0x22, 0xf0, 0x00, 0x18, 0x23, 0x3c, 0xa4, 0xfc, 0xae, 0x87, 0x23, 0x2a,
+       0xf4, 0xfc, 0xa3, 0x07, 0x04, 0xfe, 0xed, 0xa8, 0x83, 0x47, 0xf4, 0xfe,
+       0x81, 0x27, 0x03, 0x47, 0xf4, 0xfe, 0x9b, 0x06, 0x07, 0x00, 0x03, 0x37,
+       0x84, 0xfd, 0x9a, 0x07, 0xba, 0x97, 0x05, 0x67, 0xba, 0x97, 0x03, 0xc7,
+       0xb7, 0x92, 0x83, 0x37, 0x84, 0xfd, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97,
+       0xa3, 0x85, 0xe7, 0xd2, 0x23, 0x07, 0x04, 0xfe, 0x75, 0xa0, 0xa3, 0x06,
+       0x04, 0xfe, 0x79, 0xa0, 0x83, 0x47, 0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37,
+       0x84, 0xfd, 0xba, 0x97, 0x05, 0x67, 0xba, 0x97, 0x83, 0xc5, 0xb7, 0xd2,
+       0x83, 0x47, 0xf4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe,
+       0x81, 0x27, 0x03, 0x47, 0xd4, 0xfe, 0x01, 0x27, 0x83, 0x36, 0x84, 0xfd,
+       0x06, 0x06, 0xb2, 0x97, 0x96, 0x07, 0xb6, 0x97, 0xba, 0x97, 0x05, 0x67,
+       0xba, 0x97, 0x83, 0xc7, 0xb7, 0x92, 0x2e, 0x87, 0x63, 0xf1, 0xe7, 0x04,
+       0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe,
+       0x81, 0x27, 0x03, 0x47, 0xd4, 0xfe, 0x01, 0x27, 0x83, 0x46, 0xf4, 0xfe,
+       0x81, 0x26, 0x03, 0x36, 0x84, 0xfd, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07,
+       0xb2, 0x97, 0xba, 0x97, 0x05, 0x67, 0xba, 0x97, 0x03, 0xc7, 0xb7, 0x92,
+       0x83, 0x37, 0x84, 0xfd, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x85,
+       0xe7, 0xd2, 0x83, 0x47, 0xd4, 0xfe, 0x85, 0x27, 0xa3, 0x06, 0xf4, 0xfe,
+       0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xfd, 0x47, 0xe3, 0xf5,
+       0xe7, 0xf6, 0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07, 0xf4, 0xfe,
+       0x83, 0x47, 0xe4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x44, 0xfd,
+       0x81, 0x27, 0xe3, 0x64, 0xf7, 0xf4, 0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27,
+       0xa3, 0x07, 0xf4, 0xfe, 0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0xbd, 0x47, 0xe3, 0xff, 0xe7, 0xee, 0x03, 0x37, 0x84, 0xfd, 0x85, 0x67,
+       0xba, 0x97, 0x03, 0xc7, 0xb7, 0xd2, 0x83, 0x36, 0x84, 0xfd, 0x85, 0x67,
+       0xb6, 0x97, 0xa3, 0x8d, 0xe7, 0xd2, 0xa3, 0x07, 0x04, 0xfe, 0x8d, 0xa0,
+       0x03, 0x37, 0x84, 0xfd, 0x85, 0x67, 0xba, 0x97, 0x83, 0xc6, 0xb7, 0xd3,
+       0x83, 0x47, 0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x84, 0xfd, 0xba, 0x97,
+       0x05, 0x67, 0xba, 0x97, 0x83, 0xc7, 0xb7, 0xd2, 0x36, 0x87, 0x63, 0x7a,
+       0xf7, 0x02, 0x83, 0x47, 0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x84, 0xfd,
+       0xba, 0x97, 0x05, 0x67, 0xba, 0x97, 0x03, 0xc7, 0xb7, 0xd2, 0x83, 0x36,
+       0x84, 0xfd, 0x85, 0x67, 0xb6, 0x97, 0xa3, 0x8d, 0xe7, 0xd2, 0x03, 0x37,
+       0x84, 0xfd, 0x85, 0x67, 0xba, 0x97, 0x03, 0x47, 0xf4, 0xfe, 0x23, 0x8e,
+       0xe7, 0xd2, 0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe,
+       0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xfb,
+       0xe7, 0xf8, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x27, 0x36, 0x9c, 0x63,
+       0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x85, 0xc3, 0x82, 0x97, 0xa3, 0x07,
+       0x04, 0xfe, 0x25, 0xa8, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0x34,
+       0x9c, 0x63, 0x03, 0x47, 0xf4, 0xfe, 0x01, 0x27, 0x83, 0x36, 0x84, 0xfd,
+       0x36, 0x97, 0x85, 0x66, 0x36, 0x97, 0x03, 0x47, 0xb7, 0xd2, 0x01, 0x27,
+       0xba, 0x85, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x65, 0xaa, 0x82, 0x97,
+       0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe, 0x83, 0x47,
+       0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xf0, 0xe7, 0xfc,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x47, 0x30, 0x9c, 0x63, 0x17, 0x45,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0xc0, 0x82, 0x97, 0x97, 0x47, 0x00, 0x00,
+       0x93, 0x87, 0x07, 0x2f, 0x9c, 0x63, 0x83, 0x36, 0x84, 0xfd, 0x05, 0x67,
+       0x36, 0x97, 0x03, 0x47, 0xc7, 0xd3, 0x9b, 0x05, 0x07, 0x00, 0x83, 0x36,
+       0x84, 0xfd, 0x05, 0x67, 0x36, 0x97, 0x03, 0x47, 0xb7, 0xd3, 0x01, 0x27,
+       0x3a, 0x86, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xe5, 0xbd, 0x82, 0x97,
+       0x01, 0x00, 0xa2, 0x70, 0x02, 0x74, 0x45, 0x61, 0x82, 0x80, 0x79, 0x71,
+       0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18, 0x23, 0x3c, 0xa4, 0xfc, 0xae, 0x87,
+       0x23, 0x2a, 0xf4, 0xfc, 0xa3, 0x07, 0x04, 0xfe, 0xfd, 0xa0, 0x83, 0x47,
+       0xf4, 0xfe, 0x81, 0x27, 0x03, 0x47, 0xf4, 0xfe, 0x9b, 0x06, 0x07, 0x00,
+       0x03, 0x37, 0x84, 0xfd, 0x9a, 0x07, 0xba, 0x97, 0x03, 0xc7, 0x07, 0x41,
+       0x83, 0x37, 0x84, 0xfd, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x23, 0x88,
+       0xe7, 0x80, 0x23, 0x07, 0x04, 0xfe, 0x55, 0xa0, 0xa3, 0x06, 0x04, 0xfe,
+       0x59, 0xa0, 0x83, 0x47, 0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x84, 0xfd,
+       0xba, 0x97, 0x05, 0x67, 0xba, 0x97, 0x83, 0xc5, 0x07, 0x81, 0x83, 0x47,
+       0xf4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27,
+       0x03, 0x47, 0xd4, 0xfe, 0x01, 0x27, 0x83, 0x36, 0x84, 0xfd, 0x06, 0x06,
+       0xb2, 0x97, 0x96, 0x07, 0xb6, 0x97, 0xba, 0x97, 0x83, 0xc7, 0x07, 0x41,
+       0x2e, 0x87, 0x63, 0xff, 0xe7, 0x02, 0x83, 0x47, 0xf4, 0xfe, 0x9b, 0x85,
+       0x07, 0x00, 0x83, 0x47, 0xe4, 0xfe, 0x81, 0x27, 0x03, 0x47, 0xd4, 0xfe,
+       0x01, 0x27, 0x83, 0x46, 0xf4, 0xfe, 0x81, 0x26, 0x03, 0x36, 0x84, 0xfd,
+       0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xba, 0x97, 0x03, 0xc7,
+       0x07, 0x41, 0x83, 0x37, 0x84, 0xfd, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97,
+       0x23, 0x88, 0xe7, 0x80, 0x83, 0x47, 0xd4, 0xfe, 0x85, 0x27, 0xa3, 0x06,
+       0xf4, 0xfe, 0x83, 0x47, 0xd4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xfd, 0x47,
+       0xe3, 0xf9, 0xe7, 0xf6, 0x83, 0x47, 0xe4, 0xfe, 0x85, 0x27, 0x23, 0x07,
+       0xf4, 0xfe, 0x83, 0x47, 0xe4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0x44, 0xfd, 0x81, 0x27, 0xe3, 0x68, 0xf7, 0xf4, 0x83, 0x47, 0xf4, 0xfe,
+       0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe, 0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7,
+       0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xf5, 0xe7, 0xf0, 0x03, 0x37, 0x84, 0xfd,
+       0x85, 0x67, 0xba, 0x97, 0x03, 0xc7, 0x07, 0x81, 0x83, 0x36, 0x84, 0xfd,
+       0x85, 0x67, 0xb6, 0x97, 0x23, 0x80, 0xe7, 0x82, 0x83, 0x37, 0x84, 0xfd,
+       0x03, 0xc7, 0x07, 0x00, 0x83, 0x36, 0x84, 0xfd, 0x85, 0x67, 0xb6, 0x97,
+       0xa3, 0x84, 0xe7, 0x92, 0x03, 0x37, 0x84, 0xfd, 0x85, 0x67, 0xba, 0x97,
+       0x23, 0x85, 0x07, 0x92, 0xa3, 0x07, 0x04, 0xfe, 0xbd, 0xa8, 0x03, 0x37,
+       0x84, 0xfd, 0x85, 0x67, 0xba, 0x97, 0x83, 0xc6, 0x07, 0x82, 0x83, 0x47,
+       0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x84, 0xfd, 0xba, 0x97, 0x05, 0x67,
+       0xba, 0x97, 0x83, 0xc7, 0x07, 0x81, 0x36, 0x87, 0x63, 0x78, 0xf7, 0x04,
+       0x83, 0x47, 0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x84, 0xfd, 0xba, 0x97,
+       0x05, 0x67, 0xba, 0x97, 0x03, 0xc7, 0x07, 0x81, 0x83, 0x36, 0x84, 0xfd,
+       0x85, 0x67, 0xb6, 0x97, 0x23, 0x80, 0xe7, 0x82, 0x03, 0x37, 0x84, 0xfd,
+       0x85, 0x67, 0xba, 0x97, 0x03, 0x47, 0xf4, 0xfe, 0x23, 0x85, 0xe7, 0x92,
+       0x83, 0x47, 0xf4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x84, 0xfd, 0xba, 0x97,
+       0x03, 0xc7, 0x07, 0x00, 0x83, 0x36, 0x84, 0xfd, 0x85, 0x67, 0xb6, 0x97,
+       0xa3, 0x84, 0xe7, 0x92, 0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07,
+       0xf4, 0xfe, 0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47,
+       0xe3, 0xfd, 0xe7, 0xf6, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0x0d,
+       0x9c, 0x63, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x65, 0xa2, 0x82, 0x97,
+       0xa3, 0x07, 0x04, 0xfe, 0x25, 0xa8, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0x0b, 0x9c, 0x63, 0x03, 0x47, 0xf4, 0xfe, 0x01, 0x27, 0x83, 0x36,
+       0x84, 0xfd, 0x36, 0x97, 0x85, 0x66, 0x36, 0x97, 0x03, 0x47, 0x07, 0x81,
+       0x01, 0x27, 0xba, 0x85, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x81,
+       0x82, 0x97, 0x83, 0x47, 0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe,
+       0x83, 0x47, 0xf4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xf0,
+       0xe7, 0xfc, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0xa7, 0x07, 0x9c, 0x63,
+       0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x05, 0x98, 0x82, 0x97, 0x97, 0x47,
+       0x00, 0x00, 0x93, 0x87, 0x67, 0x06, 0x9c, 0x63, 0x83, 0x36, 0x84, 0xfd,
+       0x05, 0x67, 0x36, 0x97, 0x03, 0x47, 0x97, 0x92, 0x9b, 0x05, 0x07, 0x00,
+       0x83, 0x36, 0x84, 0xfd, 0x05, 0x67, 0x36, 0x97, 0x03, 0x47, 0x07, 0x82,
+       0x01, 0x27, 0x3a, 0x86, 0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x45, 0x9c,
+       0x82, 0x97, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74, 0x45, 0x61, 0x82, 0x80,
+       0x39, 0x71, 0x22, 0xfc, 0x80, 0x00, 0xaa, 0x87, 0x2e, 0x87, 0x23, 0x26,
+       0xf4, 0xfc, 0xba, 0x87, 0x23, 0x24, 0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfc,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x3e, 0xb9, 0x9f, 0x23, 0x22,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87,
+       0x07, 0x3d, 0xb9, 0x9f, 0x23, 0x20, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0xc7, 0x3f, 0xb9, 0x9f, 0x23, 0x2e,
+       0xf4, 0xfc, 0x83, 0x27, 0x84, 0xfc, 0x1b, 0x87, 0x07, 0x00, 0x91, 0x47,
+       0x63, 0x15, 0xf7, 0x00, 0x23, 0x24, 0x04, 0xfe, 0x29, 0xa0, 0x83, 0x27,
+       0x84, 0xfc, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x9b, 0x87,
+       0x47, 0x30, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0xd0,
+       0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x9b, 0x97, 0xc7, 0x01, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xd9, 0x8f,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x9b, 0x87, 0x47, 0x30,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfe,
+       0x1c, 0xc3, 0x83, 0x67, 0x44, 0xfe, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe,
+       0x83, 0x27, 0xc4, 0xfe, 0xcd, 0x9b, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0x84, 0xfe, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe,
+       0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x67, 0x44, 0xfe, 0x3e, 0x87,
+       0x83, 0x27, 0xc4, 0xfe, 0x1c, 0xc3, 0x83, 0x67, 0x04, 0xfe, 0x3e, 0x87,
+       0xb7, 0x07, 0x00, 0x13, 0x89, 0x07, 0x1c, 0xc3, 0x83, 0x67, 0xc4, 0xfd,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67, 0xc4, 0xfd,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87,
+       0xb7, 0x07, 0x00, 0x20, 0xf9, 0x8f, 0x81, 0x27, 0xe5, 0xd7, 0x01, 0x00,
+       0x01, 0x00, 0x62, 0x74, 0x21, 0x61, 0x82, 0x80, 0x79, 0x71, 0x22, 0xf4,
+       0x00, 0x18, 0xaa, 0x87, 0x23, 0x2e, 0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfd,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x3d, 0xb9, 0x9f, 0x23, 0x24,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfd, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87,
+       0xc7, 0x3f, 0xb9, 0x9f, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x67, 0x84, 0xfe,
+       0x3e, 0x87, 0xb7, 0x07, 0x00, 0x13, 0x91, 0x07, 0x1c, 0xc3, 0x83, 0x67,
+       0x44, 0xfe, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67,
+       0x44, 0xfe, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x3e, 0x87, 0xb7, 0x07, 0x00, 0x40, 0xf9, 0x8f, 0x81, 0x27, 0xe5, 0xd7,
+       0x01, 0x00, 0x01, 0x00, 0x22, 0x74, 0x45, 0x61, 0x82, 0x80, 0x79, 0x71,
+       0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18, 0xaa, 0x87, 0x23, 0x2e, 0xf4, 0xfc,
+       0x83, 0x27, 0xc4, 0xfd, 0x1b, 0x87, 0x07, 0x00, 0x91, 0x47, 0x63, 0xe9,
+       0xe7, 0x36, 0x83, 0x67, 0xc4, 0xfd, 0x13, 0x97, 0x27, 0x00, 0x97, 0x47,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0x9f, 0xba, 0x97, 0x9c, 0x43, 0x1b, 0x87,
+       0x07, 0x00, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x27, 0x9e, 0xba, 0x97,
+       0x82, 0x87, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x27, 0xe5, 0x9c, 0x63,
+       0x17, 0x45, 0x00, 0x00, 0x13, 0x05, 0x05, 0x81, 0x82, 0x97, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0xd7, 0xae, 0x8a, 0x07, 0x11, 0x67, 0x13, 0x07,
+       0x47, 0xb0, 0x98, 0xc3, 0xb7, 0x87, 0x42, 0x0d, 0x93, 0x87, 0xb7, 0x28,
+       0x92, 0x07, 0x37, 0x07, 0x60, 0x40, 0x13, 0x07, 0x07, 0x60, 0x98, 0xc3,
+       0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x37, 0x07,
+       0x00, 0x04, 0x98, 0xc3, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0xe0,
+       0x9c, 0x63, 0x37, 0x17, 0x0a, 0x35, 0x13, 0x07, 0xd7, 0xae, 0x0a, 0x07,
+       0x18, 0x43, 0x01, 0x27, 0x3a, 0x86, 0x37, 0x37, 0x28, 0xd4, 0x93, 0x05,
+       0x47, 0xbb, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0x65, 0x7d, 0x82, 0x97,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0xc7, 0xdd, 0x9c, 0x63, 0x37, 0x87,
+       0x42, 0x0d, 0x13, 0x07, 0xb7, 0x28, 0x12, 0x07, 0x18, 0x43, 0x01, 0x27,
+       0x3a, 0x86, 0x37, 0x37, 0x28, 0xd4, 0x93, 0x05, 0x07, 0x8b, 0x17, 0x35,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0x7a, 0x82, 0x97, 0x97, 0x47, 0x00, 0x00,
+       0x93, 0x87, 0x07, 0xdb, 0x9c, 0x63, 0x37, 0x17, 0x0a, 0x35, 0x13, 0x07,
+       0x17, 0xa0, 0x0a, 0x07, 0x18, 0x43, 0x01, 0x27, 0x3a, 0x86, 0x37, 0x37,
+       0x28, 0xd4, 0x93, 0x05, 0x47, 0x80, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05,
+       0xe5, 0x77, 0x82, 0x97, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x47, 0xd8,
+       0x9c, 0x63, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xa5, 0x78, 0x82, 0x97,
+       0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x9c, 0x43,
+       0x23, 0x26, 0xf4, 0xfe, 0x09, 0xa8, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87,
+       0x17, 0xa0, 0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x04, 0xf9, 0x8f, 0x81, 0x27,
+       0xed, 0xf3, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0xe7, 0xd3, 0x9c, 0x63,
+       0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x76, 0x82, 0x97, 0x25, 0xac,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0xd2, 0x9c, 0x63, 0x17, 0x35,
+       0x00, 0x00, 0x13, 0x05, 0xe5, 0x77, 0x82, 0x97, 0xb7, 0x17, 0x0a, 0x35,
+       0x93, 0x87, 0xd7, 0xae, 0x8a, 0x07, 0x11, 0x67, 0x13, 0x07, 0x07, 0xb5,
+       0x98, 0xc3, 0xb7, 0x87, 0x42, 0x0d, 0x93, 0x87, 0xb7, 0x28, 0x92, 0x07,
+       0x37, 0x07, 0x60, 0x40, 0x13, 0x07, 0x07, 0x40, 0x98, 0xc3, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x37, 0x07, 0x00, 0x04,
+       0x98, 0xc3, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0xe7, 0xcd, 0x9c, 0x63,
+       0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x75, 0x82, 0x97, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x09, 0xa8, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0,
+       0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x3e, 0x87, 0xb7, 0x07, 0x00, 0x04, 0xf9, 0x8f, 0x81, 0x27, 0xed, 0xf3,
+       0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0xc9, 0x9c, 0x63, 0x17, 0x35,
+       0x00, 0x00, 0x13, 0x05, 0xe5, 0x73, 0x82, 0x97, 0x49, 0xaa, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0xd7, 0xae, 0x8a, 0x07, 0x11, 0x67, 0x13, 0x07,
+       0x07, 0xb0, 0x98, 0xc3, 0xb7, 0x87, 0x42, 0x0d, 0x93, 0x87, 0xb7, 0x28,
+       0x92, 0x07, 0x37, 0x07, 0x60, 0x40, 0x13, 0x07, 0x07, 0x40, 0x98, 0xc3,
+       0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x37, 0x07,
+       0x00, 0x04, 0x98, 0xc3, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0,
+       0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x09, 0xa8, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x04,
+       0xf9, 0x8f, 0x81, 0x27, 0xed, 0xf3, 0x25, 0xa2, 0xb7, 0x17, 0x0a, 0x35,
+       0x93, 0x87, 0xd7, 0xae, 0x8a, 0x07, 0x11, 0x67, 0x13, 0x07, 0x07, 0xb4,
+       0x98, 0xc3, 0xb7, 0x87, 0x42, 0x0d, 0x93, 0x87, 0xb7, 0x28, 0x92, 0x07,
+       0x37, 0x07, 0x60, 0x40, 0x13, 0x07, 0x07, 0x40, 0x98, 0xc3, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x37, 0x07, 0x00, 0x04,
+       0x98, 0xc3, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x09, 0xa8, 0xb7, 0x17, 0x0a, 0x35,
+       0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe,
+       0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x04, 0xf9, 0x8f,
+       0x81, 0x27, 0xed, 0xf3, 0x7d, 0xa8, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0xba, 0x9c, 0x63, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x67,
+       0x82, 0x97, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0xd7, 0xae, 0x8a, 0x07,
+       0x11, 0x67, 0x13, 0x07, 0x27, 0xb0, 0x98, 0xc3, 0xb7, 0x87, 0x42, 0x0d,
+       0x93, 0x87, 0xb7, 0x28, 0x92, 0x07, 0x37, 0x07, 0x60, 0x40, 0x13, 0x07,
+       0x07, 0x40, 0x98, 0xc3, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0,
+       0x8a, 0x07, 0x37, 0x07, 0x00, 0x04, 0x98, 0xc3, 0x97, 0x47, 0x00, 0x00,
+       0x93, 0x87, 0x47, 0xb6, 0x9c, 0x63, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05,
+       0xa5, 0x65, 0x82, 0x97, 0xb7, 0x17, 0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0,
+       0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x09, 0xa8, 0xb7, 0x17,
+       0x0a, 0x35, 0x93, 0x87, 0x17, 0xa0, 0x8a, 0x07, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x04,
+       0xf9, 0x8f, 0x81, 0x27, 0xed, 0xf3, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0xb1, 0x9c, 0x63, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0x45, 0x64,
+       0x82, 0x97, 0x21, 0xa8, 0x97, 0x47, 0x00, 0x00, 0x93, 0x87, 0x87, 0xb0,
+       0x9c, 0x63, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xe5, 0x65, 0x82, 0x97,
+       0x01, 0x00, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74, 0x45, 0x61, 0x82, 0x80,
+       0x79, 0x71, 0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18, 0xaa, 0x87, 0xae, 0x86,
+       0x32, 0x87, 0x23, 0x2e, 0xf4, 0xfc, 0xb6, 0x87, 0xa3, 0x0d, 0xf4, 0xfc,
+       0xba, 0x87, 0x23, 0x0d, 0xf4, 0xfc, 0x83, 0x47, 0xa4, 0xfd, 0x93, 0xf7,
+       0xf7, 0x0f, 0xa1, 0xc7, 0x83, 0x27, 0xc4, 0xfd, 0x3e, 0x87, 0x85, 0x67,
+       0x9b, 0x87, 0xc7, 0x3f, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa8, 0x83, 0x27, 0xc4, 0xfd,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0xc7, 0x3f, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x80, 0x00, 0xf9, 0x8f, 0x81, 0x27,
+       0xe1, 0xdf, 0x83, 0x47, 0xb4, 0xfd, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0xc4, 0xfd, 0xba, 0x85, 0x3e, 0x85, 0xef, 0xf0, 0x3f, 0xa4, 0x83, 0x27,
+       0xc4, 0xfd, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x00, 0x03, 0x63, 0x19,
+       0xf7, 0x00, 0x83, 0x47, 0xb4, 0xfd, 0x81, 0x27, 0x3e, 0x85, 0xef, 0xf0,
+       0xdf, 0xbb, 0x39, 0xa0, 0x83, 0x47, 0xb4, 0xfd, 0x81, 0x27, 0x3e, 0x85,
+       0xef, 0xf0, 0xff, 0xba, 0x83, 0x27, 0xc4, 0xfd, 0x3e, 0x85, 0xef, 0xf0,
+       0x7f, 0xb3, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74, 0x45, 0x61, 0x82, 0x80,
+       0x01, 0x11, 0x22, 0xec, 0x00, 0x10, 0xaa, 0x87, 0x2e, 0x87, 0x23, 0x26,
+       0xf4, 0xfe, 0xba, 0x87, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x9b, 0x87, 0x47, 0x02, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87,
+       0x83, 0x27, 0x84, 0xfe, 0xbe, 0x86, 0xb7, 0x07, 0x02, 0x13, 0xd5, 0x8f,
+       0x81, 0x27, 0x1c, 0xc3, 0x01, 0x00, 0x62, 0x64, 0x05, 0x61, 0x82, 0x80,
+       0x19, 0x71, 0x86, 0xfc, 0xa2, 0xf8, 0x00, 0x01, 0xaa, 0x87, 0x23, 0x38,
+       0xb4, 0xf8, 0x36, 0x87, 0x23, 0x2e, 0xf4, 0xf8, 0xb2, 0x87, 0x23, 0x2c,
+       0xf4, 0xf8, 0xba, 0x87, 0x23, 0x26, 0xf4, 0xf8, 0x89, 0x47, 0xa3, 0x04,
+       0xf4, 0xfe, 0xd1, 0x47, 0x23, 0x22, 0xf4, 0xfe, 0x93, 0x07, 0x80, 0x03,
+       0x23, 0x20, 0xf4, 0xfe, 0x93, 0x07, 0x80, 0x03, 0x23, 0x2e, 0xf4, 0xfc,
+       0x23, 0x2c, 0x04, 0xfc, 0x85, 0x47, 0x23, 0x2a, 0xf4, 0xfc, 0x93, 0x07,
+       0xb0, 0x03, 0x23, 0x28, 0xf4, 0xfc, 0x23, 0x26, 0x04, 0xfc, 0x85, 0x47,
+       0x23, 0x24, 0xf4, 0xfc, 0xbd, 0x47, 0x23, 0x22, 0xf4, 0xfc, 0x83, 0x27,
+       0xc4, 0xf9, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x3f, 0xb9, 0x9f,
+       0x23, 0x20, 0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xf9, 0x3e, 0x87, 0x85, 0x67,
+       0x9b, 0x87, 0x47, 0x3f, 0xb9, 0x9f, 0x23, 0x2e, 0xf4, 0xfa, 0x83, 0x27,
+       0xc4, 0xf9, 0x3e, 0x87, 0xb7, 0x07, 0x04, 0x00, 0xb9, 0x9f, 0x23, 0x2c,
+       0xf4, 0xfa, 0x83, 0x27, 0x84, 0xfb, 0x3e, 0x87, 0xe1, 0x67, 0x91, 0x27,
+       0xb9, 0x9f, 0x23, 0x2a, 0xf4, 0xfa, 0x83, 0x27, 0xc4, 0xf9, 0x3e, 0x87,
+       0x85, 0x67, 0x9b, 0x87, 0x07, 0x3d, 0xb9, 0x9f, 0x23, 0x28, 0xf4, 0xfa,
+       0x83, 0x27, 0xc4, 0xf9, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0xc7, 0x3f,
+       0xb9, 0x9f, 0x23, 0x26, 0xf4, 0xfa, 0x83, 0x27, 0xc4, 0xf9, 0x9b, 0x87,
+       0x47, 0x30, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x40,
+       0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xf9,
+       0x9b, 0x97, 0xe7, 0x01, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xd9, 0x8f,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xf9, 0x9b, 0x87, 0x47, 0x30,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfe,
+       0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xf9, 0x9b, 0x87, 0x87, 0x02, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xb7, 0x07, 0x01, 0x13, 0x1c, 0xc3,
+       0x83, 0x27, 0xc4, 0xf9, 0xb5, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0x1f, 0xe9,
+       0x83, 0x27, 0xc4, 0xf9, 0x85, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0x5f, 0xe8,
+       0x83, 0x27, 0xc4, 0xf9, 0x89, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0x9f, 0xe7,
+       0x83, 0x27, 0xc4, 0xf9, 0x8d, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0xdf, 0xe6,
+       0x83, 0x27, 0xc4, 0xf9, 0xad, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0x1f, 0xe6,
+       0x83, 0x27, 0xc4, 0xf9, 0xb1, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0x5f, 0xe5,
+       0x83, 0x27, 0xc4, 0xf9, 0xb9, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0x9f, 0xe4,
+       0x83, 0x27, 0xc4, 0xf9, 0xd9, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0xdf, 0xe3,
+       0x83, 0x27, 0x44, 0xfd, 0x9b, 0x97, 0xa7, 0x01, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0x97, 0x01, 0x81, 0x27, 0xd9, 0x8f,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x04, 0xfe, 0x9b, 0x97, 0x37, 0x01,
+       0x81, 0x27, 0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0xc4, 0xfd,
+       0x9b, 0x97, 0xd7, 0x00, 0x81, 0x27, 0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x44, 0xfe, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0xd9, 0x8f,
+       0x81, 0x27, 0x03, 0x67, 0x04, 0xfc, 0x93, 0xe7, 0xf7, 0x0f, 0x81, 0x27,
+       0x1c, 0xc3, 0x83, 0x27, 0x04, 0xfd, 0x9b, 0x97, 0xa7, 0x01, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x27, 0x44, 0xfc, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27,
+       0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97,
+       0x77, 0x00, 0x81, 0x27, 0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0xc4, 0xfc, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0xd9, 0x8f, 0x81, 0x27,
+       0x03, 0x67, 0xc4, 0xfb, 0x93, 0xe7, 0x97, 0x01, 0x81, 0x27, 0x1c, 0xc3,
+       0x85, 0x47, 0xa3, 0x05, 0xf4, 0xfe, 0x95, 0xa2, 0x83, 0x67, 0x04, 0xfc,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87,
+       0xb7, 0x07, 0x00, 0x10, 0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26, 0xf4, 0xfe,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0xc7, 0x01, 0x81, 0x27,
+       0x03, 0x27, 0xc4, 0xfe, 0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x67,
+       0x04, 0xfc, 0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfe, 0x1c, 0xc3, 0x23, 0x05,
+       0x04, 0xfe, 0x01, 0xa2, 0x83, 0x47, 0xa4, 0xfe, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x97, 0x00, 0x01, 0x93, 0x87, 0x07, 0x87, 0xd9, 0x8f, 0x81, 0x27,
+       0x03, 0x67, 0x44, 0xfb, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x01, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07,
+       0x80, 0x10, 0xd9, 0x8f, 0x81, 0x27, 0x03, 0x67, 0x04, 0xfb, 0x81, 0x27,
+       0x1c, 0xc3, 0x83, 0x27, 0x84, 0xf9, 0x13, 0xf7, 0xf7, 0x0f, 0x83, 0x27,
+       0xc4, 0xf9, 0x05, 0x46, 0xba, 0x85, 0x3e, 0x85, 0xef, 0xf0, 0x5f, 0xc4,
+       0x83, 0x67, 0x04, 0xfc, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0xf8, 0xfd, 0x17, 0xf9, 0x8f,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07,
+       0x00, 0x08, 0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x67, 0x04, 0xfc,
+       0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfe, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xf9,
+       0x05, 0x46, 0x91, 0x45, 0x3e, 0x85, 0xef, 0xf0, 0xff, 0xbf, 0x83, 0x67,
+       0x04, 0xfc, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x3e, 0x87, 0xb7, 0x07, 0x00, 0xf8, 0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x08,
+       0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x67, 0x04, 0xfc, 0x3e, 0x87,
+       0x83, 0x27, 0xc4, 0xfe, 0x1c, 0xc3, 0x83, 0x67, 0xc4, 0xfa, 0x9c, 0x43,
+       0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67, 0xc4, 0xfa, 0x9c, 0x43,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0xe1, 0x8b, 0x81, 0x27,
+       0x3e, 0x87, 0xe1, 0x47, 0xe3, 0x15, 0xf7, 0xfe, 0x83, 0x47, 0xa4, 0xfe,
+       0x85, 0x27, 0x23, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xa4, 0xfe, 0x3e, 0x87,
+       0x83, 0x47, 0x94, 0xfe, 0x13, 0x77, 0xf7, 0x0f, 0x93, 0xf7, 0xf7, 0x0f,
+       0xe3, 0x68, 0xf7, 0xee, 0x83, 0x47, 0xb4, 0xfe, 0x85, 0x27, 0xa3, 0x05,
+       0xf4, 0xfe, 0x83, 0x47, 0xb4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0xc4, 0xf8, 0x81, 0x27, 0xe3, 0xf8, 0xe7, 0xe8, 0x83, 0x27, 0xc4, 0xf9,
+       0x9b, 0x87, 0x87, 0x02, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87,
+       0xb7, 0x87, 0x00, 0x13, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xf9, 0xb5, 0x45,
+       0x3e, 0x85, 0xef, 0xf0, 0x3f, 0xc0, 0x83, 0x27, 0x84, 0xf9, 0x13, 0xf7,
+       0xf7, 0x0f, 0x83, 0x27, 0xc4, 0xf9, 0x01, 0x46, 0xba, 0x85, 0x3e, 0x85,
+       0xef, 0xf0, 0xdf, 0xb2, 0x01, 0x00, 0xe6, 0x70, 0x46, 0x74, 0x09, 0x61,
+       0x82, 0x80, 0x1d, 0x71, 0xa2, 0xec, 0x80, 0x10, 0x2a, 0x8e, 0x23, 0x30,
+       0xb4, 0xfc, 0x32, 0x83, 0x36, 0x85, 0xba, 0x85, 0x3e, 0x86, 0xc2, 0x86,
+       0x46, 0x87, 0xf2, 0x87, 0x23, 0x26, 0xf4, 0xfc, 0x9a, 0x87, 0x23, 0x24,
+       0xf4, 0xfc, 0xaa, 0x87, 0x23, 0x2e, 0xf4, 0xfa, 0xae, 0x87, 0x23, 0x2c,
+       0xf4, 0xfa, 0xb2, 0x87, 0x23, 0x2a, 0xf4, 0xfa, 0xb6, 0x87, 0x23, 0x28,
+       0xf4, 0xfa, 0xba, 0x87, 0x23, 0x26, 0xf4, 0xfa, 0x83, 0x27, 0xc4, 0xfc,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x87, 0x3e, 0xb9, 0x9f, 0x23, 0x22,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87,
+       0x07, 0x3d, 0xb9, 0x9f, 0x23, 0x20, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0xc7, 0x3f, 0xb9, 0x9f, 0x23, 0x2e,
+       0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfb, 0x9b, 0x97, 0xf7, 0x01, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0x87, 0x01, 0x81, 0x27,
+       0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x44, 0xfb, 0x9b, 0x97,
+       0x07, 0x01, 0x81, 0x27, 0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0x04, 0xfb, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0xd9, 0x8f, 0x81, 0x27,
+       0x03, 0x67, 0x44, 0xfe, 0x83, 0x26, 0xc4, 0xfa, 0xd5, 0x8f, 0x81, 0x27,
+       0x1c, 0xc3, 0x85, 0x47, 0xa3, 0x05, 0xf4, 0xfe, 0xa9, 0xa0, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x01, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0x40, 0x10, 0xd9, 0x8f, 0x81, 0x27, 0x03, 0x67, 0x04, 0xfe,
+       0x81, 0x27, 0x1c, 0xc3, 0x83, 0x67, 0xc4, 0xfd, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67, 0xc4, 0xfd, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x85, 0x8b, 0x81, 0x27, 0xfd, 0xd7,
+       0x83, 0x47, 0xb4, 0xfe, 0x85, 0x27, 0xa3, 0x05, 0xf4, 0xfe, 0x83, 0x47,
+       0xb4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x1c, 0x40, 0x81, 0x27, 0xe3, 0xf6,
+       0xe7, 0xfa, 0x01, 0x00, 0x01, 0x00, 0x66, 0x64, 0x25, 0x61, 0x82, 0x80,
+       0x39, 0x71, 0x06, 0xfc, 0x22, 0xf8, 0x80, 0x00, 0xaa, 0x87, 0xae, 0x86,
+       0x32, 0x87, 0x23, 0x26, 0xf4, 0xfc, 0xb6, 0x87, 0x23, 0x24, 0xf4, 0xfc,
+       0xba, 0x87, 0x23, 0x22, 0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87,
+       0xb7, 0x07, 0x04, 0x00, 0xb9, 0x9f, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfc, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x3d, 0xb9, 0x9f,
+       0x23, 0x20, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87, 0x85, 0x67,
+       0x9b, 0x87, 0xc7, 0x3f, 0xb9, 0x9f, 0x23, 0x2e, 0xf4, 0xfc, 0x85, 0x47,
+       0xa3, 0x05, 0xf4, 0xfe, 0x51, 0xa8, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0x9b, 0x97, 0x87, 0x01, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x10, 0x10,
+       0xd9, 0x8f, 0x81, 0x27, 0x03, 0x67, 0x04, 0xfe, 0x81, 0x27, 0x1c, 0xc3,
+       0x83, 0x67, 0xc4, 0xfd, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0,
+       0x83, 0x67, 0xc4, 0xfd, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x89, 0x8b, 0x81, 0x27, 0xfd, 0xd7, 0x83, 0x27, 0xc4, 0xfe,
+       0x99, 0x8b, 0x81, 0x27, 0x3e, 0x87, 0x99, 0x47, 0x63, 0x1d, 0xf7, 0x00,
+       0x97, 0x37, 0x00, 0x00, 0x93, 0x87, 0x47, 0x43, 0x9c, 0x63, 0x17, 0x35,
+       0x00, 0x00, 0x13, 0x05, 0x25, 0xfc, 0x82, 0x97, 0x1d, 0xa0, 0x83, 0x27,
+       0xc4, 0xfe, 0x99, 0x8b, 0x81, 0x27, 0x3e, 0x87, 0x89, 0x47, 0x63, 0x1c,
+       0xf7, 0x00, 0x97, 0x37, 0x00, 0x00, 0x93, 0x87, 0xe7, 0x40, 0x9c, 0x63,
+       0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xc5, 0xfb, 0x82, 0x97, 0x83, 0x47,
+       0xb4, 0xfe, 0x85, 0x27, 0xa3, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xb4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x81, 0x27, 0xe3, 0xf0,
+       0xe7, 0xf6, 0x97, 0x37, 0x00, 0x00, 0x93, 0x87, 0xe7, 0x3d, 0x9c, 0x63,
+       0x03, 0x27, 0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00, 0x01, 0x27, 0x83, 0x26,
+       0x44, 0xfe, 0x35, 0x9f, 0x01, 0x27, 0x1b, 0x07, 0x07, 0x07, 0x9b, 0x06,
+       0x07, 0x00, 0x03, 0x27, 0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00, 0x01, 0x27,
+       0x03, 0x26, 0x44, 0xfe, 0x31, 0x9f, 0x01, 0x27, 0x1b, 0x07, 0x07, 0x07,
+       0x01, 0x27, 0x02, 0x17, 0x01, 0x93, 0x18, 0x43, 0x01, 0x27, 0x3a, 0x86,
+       0xb6, 0x85, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xe5, 0xf6, 0x82, 0x97,
+       0x97, 0x37, 0x00, 0x00, 0x93, 0x87, 0xc7, 0x38, 0x9c, 0x63, 0x03, 0x27,
+       0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00, 0x01, 0x27, 0x83, 0x26, 0x44, 0xfe,
+       0x35, 0x9f, 0x01, 0x27, 0x1b, 0x07, 0x07, 0x17, 0x9b, 0x06, 0x07, 0x00,
+       0x03, 0x27, 0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00, 0x01, 0x27, 0x03, 0x26,
+       0x44, 0xfe, 0x31, 0x9f, 0x01, 0x27, 0x1b, 0x07, 0x07, 0x17, 0x01, 0x27,
+       0x02, 0x17, 0x01, 0x93, 0x18, 0x43, 0x01, 0x27, 0x3a, 0x86, 0xb6, 0x85,
+       0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0xc5, 0xf1, 0x82, 0x97, 0x97, 0x37,
+       0x00, 0x00, 0x93, 0x87, 0xa7, 0x33, 0x9c, 0x63, 0x03, 0x27, 0x44, 0xfc,
+       0x1b, 0x17, 0xe7, 0x00, 0x01, 0x27, 0x83, 0x26, 0x44, 0xfe, 0x35, 0x9f,
+       0x9b, 0x06, 0x07, 0x00, 0x05, 0x67, 0x1b, 0x07, 0x07, 0x07, 0x35, 0x9f,
+       0x9b, 0x05, 0x07, 0x00, 0x03, 0x27, 0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00,
+       0x01, 0x27, 0x83, 0x26, 0x44, 0xfe, 0x35, 0x9f, 0x9b, 0x06, 0x07, 0x00,
+       0x05, 0x67, 0x1b, 0x07, 0x07, 0x07, 0x35, 0x9f, 0x01, 0x27, 0x02, 0x17,
+       0x01, 0x93, 0x18, 0x43, 0x01, 0x27, 0x3a, 0x86, 0x17, 0x35, 0x00, 0x00,
+       0x13, 0x05, 0x05, 0xec, 0x82, 0x97, 0x97, 0x37, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0x2d, 0x9c, 0x63, 0x03, 0x27, 0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00,
+       0x01, 0x27, 0x83, 0x26, 0x44, 0xfe, 0x35, 0x9f, 0x9b, 0x06, 0x07, 0x00,
+       0x05, 0x67, 0x1b, 0x07, 0x07, 0x17, 0x35, 0x9f, 0x9b, 0x05, 0x07, 0x00,
+       0x03, 0x27, 0x44, 0xfc, 0x1b, 0x17, 0xe7, 0x00, 0x01, 0x27, 0x83, 0x26,
+       0x44, 0xfe, 0x35, 0x9f, 0x9b, 0x06, 0x07, 0x00, 0x05, 0x67, 0x1b, 0x07,
+       0x07, 0x17, 0x35, 0x9f, 0x01, 0x27, 0x02, 0x17, 0x01, 0x93, 0x18, 0x43,
+       0x01, 0x27, 0x3a, 0x86, 0x17, 0x35, 0x00, 0x00, 0x13, 0x05, 0x45, 0xe6,
+       0x82, 0x97, 0x01, 0x00, 0xe2, 0x70, 0x42, 0x74, 0x21, 0x61, 0x82, 0x80,
+       0x1d, 0x71, 0x86, 0xec, 0xa2, 0xe8, 0x80, 0x10, 0xaa, 0x88, 0x23, 0x38,
+       0xb4, 0xfa, 0x32, 0x85, 0xb6, 0x85, 0x3a, 0x86, 0xbe, 0x86, 0x42, 0x87,
+       0xc6, 0x87, 0x23, 0x2e, 0xf4, 0xfa, 0xaa, 0x87, 0x23, 0x2c, 0xf4, 0xfa,
+       0xae, 0x87, 0x23, 0x26, 0xf4, 0xfa, 0xb2, 0x87, 0x23, 0x24, 0xf4, 0xfa,
+       0xb6, 0x87, 0x23, 0x22, 0xf4, 0xfa, 0xba, 0x87, 0x23, 0x20, 0xf4, 0xfa,
+       0x23, 0x22, 0x04, 0xfe, 0x83, 0x27, 0xc4, 0xfb, 0x3e, 0x87, 0xb7, 0x07,
+       0x04, 0x00, 0xb9, 0x9f, 0x23, 0x20, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfb,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x3d, 0xb9, 0x9f, 0x23, 0x2e,
+       0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfb, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87,
+       0xc7, 0x3f, 0xb9, 0x9f, 0x23, 0x2c, 0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfb,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0xc7, 0x3e, 0xb9, 0x9f, 0x23, 0x2a,
+       0xf4, 0xfc, 0x23, 0x28, 0x04, 0xfc, 0x83, 0x27, 0x44, 0xfa, 0x9b, 0x97,
+       0x07, 0x01, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0xc4, 0xfa, 0x9b, 0x97,
+       0x87, 0x00, 0x81, 0x27, 0xd9, 0x8f, 0x81, 0x27, 0x03, 0x67, 0x44, 0xfd,
+       0x83, 0x26, 0x84, 0xfa, 0xd5, 0x8f, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x27,
+       0x04, 0xfd, 0x23, 0x22, 0xf4, 0xfe, 0xbd, 0xa5, 0x83, 0x27, 0x84, 0xfb,
+       0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x91, 0x27, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfc, 0x83, 0x27,
+       0xc4, 0xfc, 0x3e, 0x87, 0xc1, 0x67, 0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26,
+       0xf4, 0xfc, 0x83, 0x27, 0x44, 0xfe, 0x9b, 0x97, 0x07, 0x01, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x27, 0x44, 0xfe, 0x9b, 0x97, 0x47, 0x01, 0x81, 0x27,
+       0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x44, 0xfe, 0x9b, 0x97,
+       0x87, 0x01, 0x81, 0x27, 0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0x44, 0xfe, 0x9b, 0x97, 0xc7, 0x01, 0x81, 0x27, 0xd9, 0x8f, 0x81, 0x27,
+       0x03, 0x27, 0xc4, 0xfc, 0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfc, 0x83, 0x27,
+       0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27, 0x04, 0xfe,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x91, 0x27, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfc,
+       0x1c, 0xc3, 0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27,
+       0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67,
+       0x9b, 0x87, 0x47, 0x20, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfc, 0x1c, 0xc3, 0x85, 0x47, 0xa3, 0x05,
+       0xf4, 0xfe, 0xbd, 0xab, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0x9b, 0x97,
+       0x87, 0x01, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x20, 0x10, 0xd9, 0x8f,
+       0x81, 0x27, 0x03, 0x67, 0xc4, 0xfd, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x67,
+       0x84, 0xfd, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67,
+       0x84, 0xfd, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x99, 0x8b, 0x81, 0x27, 0x3e, 0x87, 0x99, 0x47, 0xe3, 0x15, 0xf7, 0xfe,
+       0x23, 0x05, 0x04, 0xfe, 0x4d, 0xa2, 0x83, 0x47, 0xa4, 0xfe, 0x81, 0x27,
+       0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x87,
+       0x05, 0xc0, 0x9b, 0x87, 0x07, 0x20, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x9c, 0x43, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x03, 0x47, 0xa4, 0xfe, 0x01, 0x27,
+       0x1b, 0x17, 0x27, 0x00, 0x9b, 0x06, 0x07, 0x00, 0x32, 0x87, 0x13, 0x77,
+       0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe, 0x86, 0x05,
+       0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97,
+       0xa3, 0x85, 0xe7, 0x92, 0x83, 0x47, 0xa4, 0xfe, 0x81, 0x27, 0x9b, 0x97,
+       0x27, 0x00, 0x81, 0x27, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x87, 0x05, 0xc0,
+       0x9b, 0x87, 0x07, 0x20, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x9c, 0x43, 0x81, 0x27, 0x9b, 0xd7, 0x87, 0x00, 0x1b, 0x86, 0x07, 0x00,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x03, 0x47,
+       0xa4, 0xfe, 0x01, 0x27, 0x1b, 0x17, 0x27, 0x00, 0x01, 0x27, 0x05, 0x27,
+       0x9b, 0x06, 0x07, 0x00, 0x32, 0x87, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36,
+       0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07,
+       0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x85, 0xe7, 0x92,
+       0x83, 0x47, 0xa4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x87, 0x05, 0xc0, 0x9b, 0x87, 0x07, 0x20,
+       0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27,
+       0x9b, 0xd7, 0x07, 0x01, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x03, 0x47, 0xa4, 0xfe, 0x01, 0x27,
+       0x1b, 0x17, 0x27, 0x00, 0x01, 0x27, 0x09, 0x27, 0x9b, 0x06, 0x07, 0x00,
+       0x32, 0x87, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfb, 0x83, 0x65,
+       0x44, 0xfe, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97,
+       0x85, 0x66, 0xb6, 0x97, 0xa3, 0x85, 0xe7, 0x92, 0x83, 0x47, 0xa4, 0xfe,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x87, 0x05, 0xc0, 0x9b, 0x87, 0x07, 0x20, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x9b, 0xd7, 0x87, 0x01,
+       0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37,
+       0x81, 0x27, 0x03, 0x47, 0xa4, 0xfe, 0x01, 0x27, 0x1b, 0x17, 0x27, 0x00,
+       0x01, 0x27, 0x0d, 0x27, 0x9b, 0x06, 0x07, 0x00, 0x32, 0x87, 0x13, 0x77,
+       0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe, 0x86, 0x05,
+       0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97,
+       0xa3, 0x85, 0xe7, 0x92, 0x83, 0x47, 0xa4, 0xfe, 0x85, 0x27, 0x23, 0x05,
+       0xf4, 0xfe, 0x83, 0x47, 0xa4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x9d, 0x47,
+       0xe3, 0xfb, 0xe7, 0xe4, 0xb7, 0xb7, 0x00, 0x18, 0x8e, 0x07, 0x93, 0x87,
+       0x07, 0x22, 0x9c, 0x43, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36,
+       0x04, 0xfb, 0x03, 0x66, 0x44, 0xfe, 0x06, 0x06, 0xb2, 0x97, 0x93, 0x87,
+       0xc7, 0x46, 0x8a, 0x07, 0xb6, 0x97, 0xa3, 0x86, 0xe7, 0x00, 0xb7, 0xb7,
+       0x00, 0x18, 0x8e, 0x07, 0x93, 0x87, 0x07, 0x22, 0x9c, 0x43, 0x81, 0x27,
+       0x9b, 0xd7, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36,
+       0x04, 0xfb, 0x03, 0x66, 0x44, 0xfe, 0x06, 0x06, 0xb2, 0x97, 0x8a, 0x07,
+       0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x23, 0x8f, 0xe7, 0x1a, 0xb7, 0xb7,
+       0x00, 0x18, 0x8e, 0x07, 0x93, 0x87, 0x07, 0x22, 0x9c, 0x43, 0x81, 0x27,
+       0x9b, 0xd7, 0x07, 0x01, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36,
+       0x04, 0xfb, 0x03, 0x66, 0x44, 0xfe, 0x06, 0x06, 0xb2, 0x97, 0x8a, 0x07,
+       0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x8f, 0xe7, 0x1a, 0xb7, 0xb7,
+       0x00, 0x18, 0x8e, 0x07, 0x93, 0x87, 0x07, 0x22, 0x9c, 0x43, 0x81, 0x27,
+       0x9b, 0xd7, 0x87, 0x01, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36,
+       0x04, 0xfb, 0x03, 0x66, 0x44, 0xfe, 0x06, 0x06, 0xb2, 0x97, 0x8a, 0x07,
+       0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x23, 0x80, 0xe7, 0x1c, 0x23, 0x05,
+       0x04, 0xfe, 0x71, 0xa0, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f,
+       0x81, 0x27, 0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x47, 0xa4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27,
+       0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x87, 0x07, 0x03, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7, 0xf7, 0x0f,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x83, 0x46,
+       0xa4, 0xfe, 0x81, 0x26, 0x7d, 0x8b, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36,
+       0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07,
+       0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x8e, 0xe7, 0xd2,
+       0x83, 0x47, 0xa4, 0xfe, 0x85, 0x27, 0x23, 0x05, 0xf4, 0xfe, 0x83, 0x47,
+       0xa4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x9d, 0x47, 0xe3, 0xf6, 0xe7, 0xf6,
+       0x23, 0x05, 0x04, 0xfe, 0x59, 0xa8, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0x81, 0x27,
+       0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x85, 0x67,
+       0x9b, 0x87, 0x07, 0x03, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7, 0xf7, 0x0f, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x83, 0x46, 0xa4, 0xfe, 0x81, 0x26,
+       0xa1, 0x26, 0x81, 0x26, 0x7d, 0x8b, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36,
+       0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07,
+       0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x8e, 0xe7, 0xd2,
+       0x83, 0x47, 0xa4, 0xfe, 0x85, 0x27, 0x23, 0x05, 0xf4, 0xfe, 0x83, 0x47,
+       0xa4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x9d, 0x47, 0xe3, 0xf1, 0xe7, 0xf6,
+       0x23, 0x05, 0x04, 0xfe, 0x41, 0xa8, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0x81, 0x27,
+       0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x87, 0x07, 0x23,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7,
+       0xf7, 0x0f, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27,
+       0x83, 0x46, 0xa4, 0xfe, 0x81, 0x26, 0xc1, 0x26, 0x81, 0x26, 0x7d, 0x8b,
+       0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe,
+       0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66,
+       0xb6, 0x97, 0xa3, 0x8e, 0xe7, 0xd2, 0x83, 0x47, 0xa4, 0xfe, 0x85, 0x27,
+       0x23, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xa4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0x9d, 0x47, 0xe3, 0xf4, 0xe7, 0xf6, 0x23, 0x05, 0x04, 0xfe, 0x59, 0xa8,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97,
+       0x87, 0x00, 0x81, 0x27, 0x81, 0x27, 0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00,
+       0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x81, 0x27, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x23, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7,
+       0xf7, 0x0f, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27,
+       0x83, 0x46, 0xa4, 0xfe, 0x81, 0x26, 0xe1, 0x26, 0x81, 0x26, 0x7d, 0x8b,
+       0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfb, 0x83, 0x65, 0x44, 0xfe,
+       0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x85, 0x66,
+       0xb6, 0x97, 0xa3, 0x8e, 0xe7, 0xd2, 0x83, 0x47, 0xa4, 0xfe, 0x85, 0x27,
+       0x23, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xa4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0x9d, 0x47, 0xe3, 0xf1, 0xe7, 0xf6, 0x83, 0x47, 0xb4, 0xfe, 0x85, 0x27,
+       0xa3, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xb4, 0xfe, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x04, 0xfa, 0x81, 0x27, 0xe3, 0xfb, 0xe7, 0xa6, 0x83, 0x27,
+       0x44, 0xfe, 0x85, 0x27, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x27, 0x44, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0xbd, 0x47, 0xe3, 0xf5, 0xe7, 0x98, 0x83, 0x27,
+       0x04, 0xfe, 0x3e, 0x87, 0xe1, 0x67, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x9c, 0x43, 0x9b, 0x86, 0x07, 0x00, 0x83, 0x27, 0x04, 0xfe,
+       0x3e, 0x87, 0xe1, 0x67, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0xb6, 0x87, 0xed, 0x9b, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x27,
+       0x04, 0xfa, 0xbe, 0x85, 0x03, 0x35, 0x04, 0xfb, 0xef, 0xe0, 0xcf, 0xdf,
+       0x97, 0x37, 0x00, 0x00, 0x93, 0x87, 0x47, 0xb0, 0x9c, 0x63, 0x83, 0x36,
+       0x04, 0xfb, 0x05, 0x67, 0x36, 0x97, 0x03, 0x47, 0xc7, 0xd3, 0x01, 0x27,
+       0xba, 0x85, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x25, 0x6e, 0x82, 0x97,
+       0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27,
+       0x04, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x91, 0x27,
+       0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87, 0xc1, 0x67, 0xfd, 0x17,
+       0xf9, 0x8f, 0x23, 0x26, 0xf4, 0xfc, 0x03, 0x37, 0x04, 0xfb, 0x85, 0x67,
+       0xba, 0x97, 0x83, 0xc7, 0xc7, 0xd3, 0x81, 0x27, 0x9b, 0x97, 0x07, 0x01,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x36, 0x04, 0xfb, 0x85, 0x67, 0xb6, 0x97,
+       0x83, 0xc7, 0xc7, 0xd3, 0x81, 0x27, 0x9b, 0x97, 0x47, 0x01, 0x81, 0x27,
+       0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x36, 0x04, 0xfb, 0x85, 0x67,
+       0xb6, 0x97, 0x83, 0xc7, 0xc7, 0xd3, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x01,
+       0x81, 0x27, 0xd9, 0x8f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x36, 0x04, 0xfb,
+       0x85, 0x67, 0xb6, 0x97, 0x83, 0xc7, 0xc7, 0xd3, 0x81, 0x27, 0x9b, 0x97,
+       0xc7, 0x01, 0x81, 0x27, 0xd9, 0x8f, 0x81, 0x27, 0x81, 0x27, 0x03, 0x27,
+       0xc4, 0xfc, 0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfc, 0x83, 0x27, 0x84, 0xfb,
+       0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27, 0x04, 0xfe, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x91, 0x27, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfc, 0x1c, 0xc3,
+       0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27,
+       0x04, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x9b, 0x87,
+       0x47, 0x20, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87,
+       0x83, 0x27, 0xc4, 0xfc, 0x1c, 0xc3, 0x85, 0x47, 0xa3, 0x05, 0xf4, 0xfe,
+       0x81, 0xa8, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x01,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x20, 0x10, 0xd9, 0x8f, 0x81, 0x27,
+       0x03, 0x67, 0xc4, 0xfd, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x67, 0x84, 0xfd,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67, 0x84, 0xfd,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x99, 0x8b,
+       0x81, 0x27, 0x3e, 0x87, 0x99, 0x47, 0xe3, 0x15, 0xf7, 0xfe, 0x83, 0x47,
+       0xb4, 0xfe, 0x85, 0x27, 0xa3, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xb4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x04, 0xfa, 0x81, 0x27, 0xe3, 0xf2,
+       0xe7, 0xfa, 0x01, 0x00, 0x01, 0x00, 0xe6, 0x60, 0x46, 0x64, 0x25, 0x61,
+       0x82, 0x80, 0x01, 0x11, 0x22, 0xec, 0x00, 0x10, 0x23, 0x26, 0x04, 0xfe,
+       0x23, 0x26, 0x04, 0xfe, 0x31, 0xa0, 0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00,
+       0xa1, 0x67, 0xe3, 0x66, 0xf7, 0xfe, 0x01, 0x00, 0x62, 0x64, 0x05, 0x61,
+       0x82, 0x80, 0x5d, 0x71, 0x86, 0xe4, 0xa2, 0xe0, 0x80, 0x08, 0x23, 0x30,
+       0xb4, 0xfc, 0xb2, 0x85, 0x36, 0x86, 0xba, 0x86, 0x3e, 0x87, 0xaa, 0x87,
+       0x23, 0x26, 0xf4, 0xfc, 0xae, 0x87, 0x23, 0x24, 0xf4, 0xfc, 0xb2, 0x87,
+       0x23, 0x2e, 0xf4, 0xfa, 0xb6, 0x87, 0x23, 0x2c, 0xf4, 0xfa, 0xba, 0x87,
+       0x23, 0x2a, 0xf4, 0xfa, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87, 0xb7, 0x07,
+       0x04, 0x00, 0xb9, 0x9f, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x3d, 0xb9, 0x9f, 0x23, 0x20,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87,
+       0xc7, 0x3f, 0xb9, 0x9f, 0x23, 0x2e, 0xf4, 0xfc, 0x83, 0x27, 0xc4, 0xfc,
+       0x3e, 0x87, 0x85, 0x67, 0x9b, 0x87, 0x87, 0x3f, 0xb9, 0x9f, 0x23, 0x2c,
+       0xf4, 0xfc, 0x83, 0x27, 0x84, 0xfb, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x03, 0x67, 0x84, 0xfd, 0x83, 0x26, 0xc4, 0xfb, 0xd5, 0x8f, 0x81, 0x27,
+       0x1c, 0xc3, 0x23, 0x05, 0x04, 0xfe, 0xf9, 0xaf, 0x83, 0x27, 0xc4, 0xfc,
+       0x9b, 0x87, 0xc7, 0x30, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07,
+       0xc1, 0xff, 0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x47,
+       0xa4, 0xfe, 0x81, 0x27, 0x03, 0x37, 0x04, 0xfc, 0xba, 0x97, 0x83, 0xc7,
+       0x07, 0x00, 0x81, 0x27, 0x9b, 0x97, 0x07, 0x01, 0x81, 0x27, 0x03, 0x27,
+       0xc4, 0xfe, 0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc,
+       0x9b, 0x87, 0xc7, 0x30, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87,
+       0x83, 0x27, 0xc4, 0xfe, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xfc, 0x9b, 0x87,
+       0x47, 0x02, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xb7, 0x07,
+       0x02, 0x13, 0xb9, 0x07, 0x1c, 0xc3, 0x85, 0x47, 0xa3, 0x05, 0xf4, 0xfe,
+       0x91, 0xa7, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x01,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x08, 0x10, 0xd9, 0x8f, 0x81, 0x27,
+       0x03, 0x67, 0x04, 0xfe, 0x81, 0x27, 0x1c, 0xc3, 0x83, 0x67, 0xc4, 0xfd,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67, 0xc4, 0xfd,
+       0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x93, 0xf7,
+       0x07, 0x06, 0x81, 0x27, 0x3e, 0x87, 0x93, 0x07, 0x00, 0x06, 0xe3, 0x13,
+       0xf7, 0xfe, 0xa3, 0x04, 0x04, 0xfe, 0x4d, 0xa2, 0x83, 0x47, 0x94, 0xfe,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x87, 0x05, 0xc0, 0x9b, 0x87, 0x07, 0x30, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47,
+       0xa4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x03, 0x47, 0x94, 0xfe, 0x01, 0x27, 0x1b, 0x17,
+       0x27, 0x00, 0x9b, 0x06, 0x07, 0x00, 0x32, 0x87, 0x13, 0x77, 0xf7, 0x0f,
+       0x03, 0x36, 0x04, 0xfc, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97,
+       0xb6, 0x97, 0x23, 0x88, 0xe7, 0x40, 0x83, 0x47, 0x94, 0xfe, 0x81, 0x27,
+       0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x87,
+       0x05, 0xc0, 0x9b, 0x87, 0x07, 0x30, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x9b, 0xd7, 0x87, 0x00, 0x1b, 0x86,
+       0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x03, 0x47, 0x94, 0xfe,
+       0x01, 0x27, 0x1b, 0x17, 0x27, 0x00, 0x01, 0x27, 0x05, 0x27, 0x9b, 0x06,
+       0x07, 0x00, 0x32, 0x87, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfc,
+       0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x23, 0x88,
+       0xe7, 0x40, 0x83, 0x47, 0x94, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x87, 0x05, 0xc0, 0x9b, 0x87,
+       0x07, 0x30, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43,
+       0x81, 0x27, 0x9b, 0xd7, 0x07, 0x01, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47,
+       0xa4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x03, 0x47, 0x94, 0xfe, 0x01, 0x27, 0x1b, 0x17,
+       0x27, 0x00, 0x01, 0x27, 0x09, 0x27, 0x9b, 0x06, 0x07, 0x00, 0x32, 0x87,
+       0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfc, 0x86, 0x05, 0xae, 0x97,
+       0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x23, 0x88, 0xe7, 0x40, 0x83, 0x47,
+       0x94, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x1b, 0x87,
+       0x07, 0x00, 0xb7, 0x87, 0x05, 0xc0, 0x9b, 0x87, 0x07, 0x30, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x9b, 0xd7,
+       0x87, 0x01, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe, 0x9b, 0x85,
+       0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27,
+       0x03, 0x47, 0x94, 0xfe, 0x01, 0x27, 0x1b, 0x17, 0x27, 0x00, 0x01, 0x27,
+       0x0d, 0x27, 0x9b, 0x06, 0x07, 0x00, 0x32, 0x87, 0x13, 0x77, 0xf7, 0x0f,
+       0x03, 0x36, 0x04, 0xfc, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97,
+       0xb6, 0x97, 0x23, 0x88, 0xe7, 0x40, 0x83, 0x47, 0x94, 0xfe, 0x85, 0x27,
+       0xa3, 0x04, 0xf4, 0xfe, 0x83, 0x47, 0x94, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0x9d, 0x47, 0xe3, 0xfb, 0xe7, 0xe4, 0xb7, 0xb7, 0x00, 0x18, 0x8e, 0x07,
+       0x93, 0x87, 0x07, 0x32, 0x9c, 0x43, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47,
+       0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36, 0x04, 0xfc,
+       0x06, 0x06, 0xb2, 0x97, 0x93, 0x87, 0x87, 0x22, 0x8a, 0x07, 0xb6, 0x97,
+       0xa3, 0x80, 0xe7, 0x00, 0xb7, 0xb7, 0x00, 0x18, 0x8e, 0x07, 0x93, 0x87,
+       0x07, 0x32, 0x9c, 0x43, 0x81, 0x27, 0x9b, 0xd7, 0x87, 0x00, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f,
+       0x83, 0x36, 0x04, 0xfc, 0x06, 0x06, 0xb2, 0x97, 0x8a, 0x07, 0xb6, 0x97,
+       0x85, 0x66, 0xb6, 0x97, 0x23, 0x81, 0xe7, 0x8a, 0xb7, 0xb7, 0x00, 0x18,
+       0x8e, 0x07, 0x93, 0x87, 0x07, 0x32, 0x9c, 0x43, 0x81, 0x27, 0x9b, 0xd7,
+       0x07, 0x01, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0xa4, 0xfe, 0x1b, 0x86,
+       0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27,
+       0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36, 0x04, 0xfc, 0x06, 0x06, 0xb2, 0x97,
+       0x8a, 0x07, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x81, 0xe7, 0x8a,
+       0xb7, 0xb7, 0x00, 0x18, 0x8e, 0x07, 0x93, 0x87, 0x07, 0x32, 0x9c, 0x43,
+       0x81, 0x27, 0x9b, 0xd7, 0x87, 0x01, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47,
+       0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36, 0x04, 0xfc,
+       0x06, 0x06, 0xb2, 0x97, 0x8a, 0x07, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97,
+       0x23, 0x82, 0xe7, 0x8a, 0xa3, 0x04, 0x04, 0xfe, 0x61, 0xa0, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00,
+       0x81, 0x27, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97,
+       0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x03, 0x27, 0x44, 0xfe,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0x94, 0xfe, 0x81, 0x27,
+       0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7, 0xf7, 0x0f,
+       0x83, 0x47, 0xa4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x83, 0x46, 0x94, 0xfe, 0x81, 0x26,
+       0x13, 0x77, 0xf7, 0x03, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfc,
+       0x86, 0x05, 0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x23, 0x88,
+       0xe7, 0x00, 0x83, 0x47, 0x94, 0xfe, 0x85, 0x27, 0xa3, 0x04, 0xf4, 0xfe,
+       0x83, 0x47, 0x94, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x9d, 0x47, 0xe3, 0xf8,
+       0xe7, 0xf6, 0xa3, 0x04, 0x04, 0xfe, 0x51, 0xa8, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27,
+       0x81, 0x27, 0x03, 0x27, 0x44, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x47, 0x94, 0xfe, 0x81, 0x27, 0x9b, 0x97,
+       0x27, 0x00, 0x81, 0x27, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x85, 0x67, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43,
+       0x81, 0x27, 0x13, 0xf7, 0xf7, 0x0f, 0x83, 0x47, 0xa4, 0xfe, 0x9b, 0x85,
+       0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27,
+       0x83, 0x46, 0x94, 0xfe, 0x81, 0x26, 0xa1, 0x26, 0x81, 0x26, 0x13, 0x77,
+       0xf7, 0x03, 0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfc, 0x86, 0x05,
+       0xae, 0x97, 0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x23, 0x88, 0xe7, 0x00,
+       0x83, 0x47, 0x94, 0xfe, 0x85, 0x27, 0xa3, 0x04, 0xf4, 0xfe, 0x83, 0x47,
+       0x94, 0xfe, 0x13, 0xf7, 0xf7, 0x0f, 0x9d, 0x47, 0xe3, 0xf2, 0xe7, 0xf6,
+       0xa3, 0x04, 0x04, 0xfe, 0x49, 0xa8, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0x81, 0x27,
+       0x03, 0x27, 0x44, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27,
+       0x84, 0xfc, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x47, 0x94, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x87, 0x07, 0x20,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7,
+       0xf7, 0x0f, 0x83, 0x47, 0xa4, 0xfe, 0x9b, 0x85, 0x07, 0x00, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x83, 0x46, 0x94, 0xfe,
+       0x81, 0x26, 0xc1, 0x26, 0x81, 0x26, 0x13, 0x77, 0xf7, 0x03, 0x13, 0x77,
+       0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfc, 0x86, 0x05, 0xae, 0x97, 0x96, 0x07,
+       0xb2, 0x97, 0xb6, 0x97, 0x23, 0x88, 0xe7, 0x00, 0x83, 0x47, 0x94, 0xfe,
+       0x85, 0x27, 0xa3, 0x04, 0xf4, 0xfe, 0x83, 0x47, 0x94, 0xfe, 0x13, 0xf7,
+       0xf7, 0x0f, 0x9d, 0x47, 0xe3, 0xf3, 0xe7, 0xf6, 0xa3, 0x04, 0x04, 0xfe,
+       0x61, 0xa8, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27,
+       0x9b, 0x97, 0x87, 0x00, 0x81, 0x27, 0x81, 0x27, 0x03, 0x27, 0x44, 0xfe,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97,
+       0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x47,
+       0x94, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x81, 0x27,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x20,
+       0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27,
+       0x13, 0xf7, 0xf7, 0x0f, 0x83, 0x47, 0xa4, 0xfe, 0x9b, 0x85, 0x07, 0x00,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x83, 0x46,
+       0x94, 0xfe, 0x81, 0x26, 0xe1, 0x26, 0x81, 0x26, 0x13, 0x77, 0xf7, 0x03,
+       0x13, 0x77, 0xf7, 0x0f, 0x03, 0x36, 0x04, 0xfc, 0x86, 0x05, 0xae, 0x97,
+       0x96, 0x07, 0xb2, 0x97, 0xb6, 0x97, 0x23, 0x88, 0xe7, 0x00, 0x83, 0x47,
+       0x94, 0xfe, 0x85, 0x27, 0xa3, 0x04, 0xf4, 0xfe, 0x83, 0x47, 0x94, 0xfe,
+       0x13, 0xf7, 0xf7, 0x0f, 0x9d, 0x47, 0xe3, 0xf0, 0xe7, 0xf6, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00,
+       0x81, 0x27, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97,
+       0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x03, 0x27, 0x44, 0xfe,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x87, 0x07, 0x02, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7, 0xf7, 0x0f, 0x83, 0x47,
+       0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27,
+       0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x03, 0x13, 0x77, 0xf7, 0x0f,
+       0x83, 0x36, 0x04, 0xfc, 0x06, 0x06, 0xb2, 0x97, 0x93, 0x87, 0x87, 0x20,
+       0x8a, 0x07, 0xb6, 0x97, 0xa3, 0x80, 0xe7, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x81, 0x27,
+       0x81, 0x27, 0x03, 0x27, 0x44, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x02, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7,
+       0xf7, 0x0f, 0x83, 0x47, 0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x03,
+       0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36, 0x04, 0xfc, 0x06, 0x06, 0xb2, 0x97,
+       0x8a, 0x07, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x23, 0x81, 0xe7, 0x82,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97,
+       0x87, 0x00, 0x81, 0x27, 0x81, 0x27, 0x03, 0x27, 0x44, 0xfe, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97, 0xe7, 0x00,
+       0x81, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x87, 0x07, 0x22, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27, 0x13, 0xf7, 0xf7, 0x0f,
+       0x83, 0x47, 0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00, 0x83, 0x47, 0xb4, 0xfe,
+       0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77, 0xf7, 0x03, 0x13, 0x77,
+       0xf7, 0x0f, 0x83, 0x36, 0x04, 0xfc, 0x06, 0x06, 0xb2, 0x97, 0x8a, 0x07,
+       0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0xa3, 0x81, 0xe7, 0x82, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00,
+       0x81, 0x27, 0x81, 0x27, 0x03, 0x27, 0x44, 0xfe, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x27, 0x84, 0xfc, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x85, 0x67, 0x9b, 0x87, 0x07, 0x22,
+       0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x81, 0x27,
+       0x13, 0xf7, 0xf7, 0x0f, 0x83, 0x47, 0xa4, 0xfe, 0x1b, 0x86, 0x07, 0x00,
+       0x83, 0x47, 0xb4, 0xfe, 0x81, 0x27, 0xfd, 0x37, 0x81, 0x27, 0x13, 0x77,
+       0xf7, 0x03, 0x13, 0x77, 0xf7, 0x0f, 0x83, 0x36, 0x04, 0xfc, 0x06, 0x06,
+       0xb2, 0x97, 0x8a, 0x07, 0xb6, 0x97, 0x85, 0x66, 0xb6, 0x97, 0x23, 0x82,
+       0xe7, 0x82, 0x83, 0x47, 0xb4, 0xfe, 0x85, 0x27, 0xa3, 0x05, 0xf4, 0xfe,
+       0x83, 0x47, 0xb4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x44, 0xfb,
+       0x81, 0x27, 0xe3, 0xf8, 0xe7, 0x8a, 0x83, 0x47, 0xa4, 0xfe, 0x85, 0x27,
+       0x23, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xa4, 0xfe, 0x13, 0xf7, 0xf7, 0x0f,
+       0xbd, 0x47, 0xe3, 0xfd, 0xe7, 0x80, 0x83, 0x27, 0x44, 0xfb, 0xbe, 0x85,
+       0x03, 0x35, 0x04, 0xfc, 0xef, 0xd0, 0xbf, 0xe0, 0x97, 0x27, 0x00, 0x00,
+       0x93, 0x87, 0x87, 0x0b, 0x9c, 0x63, 0x83, 0x36, 0x04, 0xfc, 0x05, 0x67,
+       0x36, 0x97, 0x03, 0x47, 0x97, 0x92, 0x01, 0x27, 0xba, 0x85, 0x17, 0x25,
+       0x00, 0x00, 0x13, 0x05, 0xe5, 0xcc, 0x82, 0x97, 0x83, 0x27, 0xc4, 0xfc,
+       0x9b, 0x87, 0xc7, 0x30, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07,
+       0xc1, 0xff, 0xfd, 0x17, 0xf9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x03, 0x37,
+       0x04, 0xfc, 0x85, 0x67, 0xba, 0x97, 0x83, 0xc7, 0x97, 0x92, 0x81, 0x27,
+       0x9b, 0x97, 0x07, 0x01, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xd9, 0x8f,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfc, 0x9b, 0x87, 0xc7, 0x30,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0xc4, 0xfe,
+       0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xfc, 0x9b, 0x87, 0x47, 0x02, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xb7, 0x07, 0x02, 0x13, 0xb9, 0x07,
+       0x1c, 0xc3, 0x85, 0x47, 0xa3, 0x05, 0xf4, 0xfe, 0x91, 0xa8, 0x83, 0x47,
+       0xb4, 0xfe, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x01, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0x08, 0x10, 0xd9, 0x8f, 0x81, 0x27, 0x03, 0x67, 0x04, 0xfe,
+       0x81, 0x27, 0x1c, 0xc3, 0x83, 0x67, 0xc4, 0xfd, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x31, 0xa0, 0x83, 0x67, 0xc4, 0xfd, 0x9c, 0x43, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x93, 0xf7, 0x07, 0x06, 0x81, 0x27,
+       0x3e, 0x87, 0x93, 0x07, 0x00, 0x06, 0xe3, 0x13, 0xf7, 0xfe, 0x83, 0x47,
+       0xb4, 0xfe, 0x85, 0x27, 0xa3, 0x05, 0xf4, 0xfe, 0x83, 0x47, 0xb4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x83, 0x27, 0x44, 0xfb, 0x81, 0x27, 0xe3, 0xf0,
+       0xe7, 0xfa, 0x01, 0x00, 0x01, 0x00, 0xa6, 0x60, 0x06, 0x64, 0x61, 0x61,
+       0x82, 0x80, 0x79, 0x71, 0x22, 0xf4, 0x00, 0x18, 0xaa, 0x87, 0x23, 0x38,
+       0xb4, 0xfc, 0x32, 0x87, 0x23, 0x2e, 0xf4, 0xfc, 0xba, 0x87, 0x23, 0x2c,
+       0xf4, 0xfc, 0xa3, 0x07, 0x04, 0xfe, 0x1d, 0xa0, 0x83, 0x47, 0xf4, 0xfe,
+       0x81, 0x27, 0x03, 0x47, 0xf4, 0xfe, 0x55, 0x27, 0x13, 0x77, 0xf7, 0x0f,
+       0x83, 0x36, 0x04, 0xfd, 0xb6, 0x97, 0x23, 0x80, 0xe7, 0x00, 0x83, 0x47,
+       0xf4, 0xfe, 0x85, 0x27, 0xa3, 0x07, 0xf4, 0xfe, 0x83, 0x47, 0xf4, 0xfe,
+       0x13, 0xf7, 0xf7, 0x0f, 0xbd, 0x47, 0xe3, 0xf9, 0xe7, 0xfc, 0x83, 0x37,
+       0x04, 0xfd, 0x03, 0xc7, 0x47, 0x00, 0x83, 0x36, 0x04, 0xfd, 0x85, 0x67,
+       0xb6, 0x97, 0xa3, 0x84, 0xe7, 0x92, 0x03, 0x37, 0x04, 0xfd, 0x85, 0x67,
+       0xba, 0x97, 0x11, 0x47, 0x23, 0x85, 0xe7, 0x92, 0x01, 0x00, 0x22, 0x74,
+       0x45, 0x61, 0x82, 0x80, 0x79, 0x71, 0x22, 0xf4, 0x00, 0x18, 0xaa, 0x87,
+       0x2e, 0x87, 0x23, 0x2e, 0xf4, 0xfc, 0xba, 0x87, 0x23, 0x2c, 0xf4, 0xfc,
+       0x83, 0x27, 0xc4, 0xfd, 0x3e, 0x87, 0xb7, 0x07, 0x04, 0x00, 0xb9, 0x9f,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xc1, 0x67,
+       0x9b, 0x87, 0x87, 0x02, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0x93, 0x07, 0x00, 0x20, 0x1c, 0xc3, 0x01, 0x00, 0x22, 0x74,
+       0x45, 0x61, 0x82, 0x80, 0x39, 0x71, 0x22, 0xfc, 0x80, 0x00, 0x23, 0x3c,
+       0xa4, 0xfc, 0xae, 0x87, 0x23, 0x34, 0xc4, 0xfc, 0x23, 0x2a, 0xf4, 0xfc,
+       0x83, 0x37, 0x84, 0xfd, 0x23, 0x34, 0xf4, 0xfe, 0x15, 0xa0, 0x83, 0x37,
+       0x84, 0xfe, 0x13, 0x87, 0x17, 0x00, 0x23, 0x34, 0xe4, 0xfe, 0x03, 0x27,
+       0x44, 0xfd, 0x13, 0x77, 0xf7, 0x0f, 0x23, 0x80, 0xe7, 0x00, 0x83, 0x37,
+       0x84, 0xfc, 0xfd, 0x17, 0x23, 0x34, 0xf4, 0xfc, 0x83, 0x37, 0x84, 0xfc,
+       0xe9, 0xff, 0x83, 0x37, 0x84, 0xfd, 0x3e, 0x85, 0x62, 0x74, 0x21, 0x61,
+       0x82, 0x80, 0x13, 0x01, 0x01, 0xd7, 0x23, 0x34, 0x11, 0x28, 0x23, 0x30,
+       0x81, 0x28, 0x00, 0x0d, 0xfd, 0x72, 0x16, 0x91, 0x2a, 0x8f, 0xae, 0x8e,
+       0x32, 0x8e, 0x36, 0x83, 0x3a, 0x85, 0xbe, 0x85, 0x42, 0x86, 0xc6, 0x86,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x7a, 0x87, 0x23, 0xa6, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x76, 0x87, 0x23, 0xa4, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x72, 0x87, 0x23, 0xa2, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x1a, 0x87, 0xa3, 0x81, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x2a, 0x87, 0x23, 0x81, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x2e, 0x87, 0xa3, 0x80, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x32, 0x87, 0x23, 0x80, 0xe7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x36, 0x87, 0xa3, 0x8f, 0xe7, 0xd8,
+       0x23, 0x26, 0x04, 0xfe, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0xc7, 0xda, 0x3e, 0x87, 0xb7, 0x07, 0x04, 0x00, 0xb9, 0x9f, 0x23, 0x24,
+       0xf4, 0xfe, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0xa7, 0xdf, 0x9c, 0x63,
+       0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x85, 0xa5, 0x82, 0x97, 0xfd, 0x77,
+       0x93, 0x87, 0x87, 0xdb, 0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0x85, 0x67,
+       0x13, 0x86, 0xd7, 0x23, 0x81, 0x45, 0x3a, 0x85, 0xef, 0xf0, 0x9f, 0xee,
+       0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0xc7, 0xdc, 0x9c, 0x63, 0x17, 0x25,
+       0x00, 0x00, 0x13, 0x05, 0x25, 0xa4, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x03, 0xa7, 0x87, 0xda, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x83, 0xa7, 0xc7, 0xda, 0xba, 0x85, 0x3e, 0x85, 0xef, 0xf0, 0x1f, 0xe7,
+       0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0xc7, 0xd9, 0x9c, 0x63, 0x17, 0x25,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0xa2, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa6, 0x87, 0xda, 0xfd, 0x77, 0x93, 0x87, 0x87, 0xdb,
+       0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x83, 0xa7, 0xc7, 0xda, 0x36, 0x86, 0xba, 0x85, 0x3e, 0x85, 0xef, 0xf0,
+       0x9f, 0xdb, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xc7, 0x37, 0xda,
+       0x93, 0xf7, 0xf7, 0x0f, 0xa1, 0xc7, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0xd4, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0xc5, 0xa0,
+       0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa6, 0x47, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa6, 0x87, 0xda, 0xfd, 0x77,
+       0x93, 0x87, 0x87, 0xdb, 0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xda, 0xba, 0x85, 0x3e, 0x85,
+       0xef, 0xe0, 0x0f, 0xb2, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xc7,
+       0x27, 0xda, 0x93, 0xf7, 0xf7, 0x0f, 0xb9, 0xcb, 0x97, 0x27, 0x00, 0x00,
+       0x93, 0x87, 0x87, 0xcf, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05,
+       0xe5, 0x9c, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa6,
+       0x87, 0xda, 0xfd, 0x77, 0x93, 0x87, 0x87, 0xdb, 0xc1, 0x17, 0xb3, 0x85,
+       0x87, 0x00, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa5, 0xc7, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x47, 0xda, 0x3e, 0xe0,
+       0x93, 0x08, 0x40, 0x04, 0x79, 0x48, 0x93, 0x07, 0x40, 0x06, 0x29, 0x47,
+       0x81, 0x46, 0xef, 0xe0, 0x4f, 0xea, 0x19, 0xa8, 0x97, 0x27, 0x00, 0x00,
+       0x93, 0x87, 0x47, 0xca, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05,
+       0x25, 0x99, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xc7,
+       0x17, 0xda, 0x93, 0xf7, 0xf7, 0x0f, 0xa1, 0xc3, 0x97, 0x27, 0x00, 0x00,
+       0x93, 0x87, 0x07, 0xc8, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05,
+       0x65, 0x99, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa6,
+       0x87, 0xda, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa7, 0x47, 0xda,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xda, 0x36, 0x86,
+       0xba, 0x85, 0x3e, 0x85, 0xef, 0xe0, 0xcf, 0xf6, 0x19, 0xa8, 0x97, 0x27,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0xc4, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00,
+       0x13, 0x05, 0x85, 0x97, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x83, 0xc7, 0x07, 0xda, 0x93, 0xf7, 0xf7, 0x0f, 0x63, 0x87, 0x07, 0x10,
+       0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0xc7, 0xc1, 0x9c, 0x63, 0x17, 0x25,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0x97, 0x82, 0x97, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0x87, 0xda, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27,
+       0x03, 0x27, 0x84, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67,
+       0x91, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43,
+       0x9b, 0x86, 0x07, 0x00, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0x87, 0xda, 0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27, 0x84, 0xfe,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x91, 0x27, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xb6, 0x87, 0xbd, 0x9b,
+       0x81, 0x27, 0x1c, 0xc3, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa7,
+       0x47, 0xda, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa6, 0x87, 0xda,
+       0xfd, 0x77, 0x93, 0x87, 0x87, 0xdb, 0xc1, 0x17, 0xb3, 0x85, 0x87, 0x00,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa5, 0xc7, 0xda, 0x3a, 0x88,
+       0x81, 0x47, 0x13, 0x07, 0x00, 0x07, 0x93, 0x06, 0x00, 0x05, 0xef, 0xe0,
+       0xff, 0x8f, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0xda,
+       0x9b, 0x97, 0xe7, 0x00, 0x81, 0x27, 0x03, 0x27, 0x84, 0xfe, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0x8d, 0x67, 0x91, 0x27, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x9b, 0x86, 0x07, 0x00, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0xda, 0x9b, 0x97, 0xe7, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0x84, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x8d, 0x67, 0x91, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0xb6, 0x87, 0x93, 0xe7, 0x07, 0x01, 0x81, 0x27, 0x1c, 0xc3,
+       0x19, 0xa8, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0x27, 0xb1, 0x9c, 0x63,
+       0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x85, 0x88, 0x82, 0x97, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xc7, 0xf7, 0xd9, 0x93, 0xf7, 0xf7, 0x0f,
+       0xb9, 0xc7, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0xe7, 0xae, 0x9c, 0x63,
+       0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x45, 0x88, 0x82, 0x97, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa7, 0x47, 0xda, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x03, 0xa6, 0x87, 0xda, 0xfd, 0x77, 0x93, 0x87, 0x87, 0xdb,
+       0xc1, 0x17, 0xb3, 0x85, 0x87, 0x00, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x03, 0xa5, 0xc7, 0xda, 0xba, 0x87, 0x13, 0x07, 0x00, 0x06, 0xc1, 0x46,
+       0xef, 0xf0, 0x2f, 0x96, 0x19, 0xa8, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87,
+       0x27, 0xaa, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x05, 0x85,
+       0x82, 0x97, 0x83, 0x27, 0x84, 0xfe, 0x3e, 0x87, 0xe1, 0x67, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe,
+       0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0x87, 0xa7, 0x9c, 0x63, 0x03, 0x27,
+       0x84, 0xfe, 0xba, 0x86, 0x61, 0x67, 0x35, 0x9f, 0x9b, 0x06, 0x07, 0x00,
+       0x03, 0x27, 0x84, 0xfe, 0x3a, 0x86, 0x61, 0x67, 0x31, 0x9f, 0x01, 0x27,
+       0x02, 0x17, 0x01, 0x93, 0x18, 0x43, 0x01, 0x27, 0x3a, 0x86, 0xb6, 0x85,
+       0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x85, 0x82, 0x82, 0x97, 0x83, 0x27,
+       0xc4, 0xfe, 0x89, 0x8b, 0x81, 0x27, 0x99, 0xcb, 0x97, 0x27, 0x00, 0x00,
+       0x93, 0x87, 0x47, 0xa3, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05,
+       0x25, 0x83, 0x82, 0x97, 0x83, 0x27, 0xc4, 0xfe, 0x91, 0x8b, 0x81, 0x27,
+       0x99, 0xcb, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0x67, 0xa1, 0x9c, 0x63,
+       0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x45, 0x83, 0x82, 0x97, 0x83, 0x27,
+       0xc4, 0xfe, 0xa1, 0x8b, 0x81, 0x27, 0x99, 0xcb, 0x97, 0x27, 0x00, 0x00,
+       0x93, 0x87, 0x87, 0x9f, 0x9c, 0x63, 0x17, 0x25, 0x00, 0x00, 0x13, 0x05,
+       0x65, 0x83, 0x82, 0x97, 0x83, 0x27, 0xc4, 0xfe, 0xc1, 0x8b, 0x81, 0x27,
+       0x81, 0xcf, 0x97, 0x27, 0x00, 0x00, 0x93, 0x87, 0xa7, 0x9d, 0x9c, 0x63,
+       0x17, 0x25, 0x00, 0x00, 0x13, 0x05, 0x85, 0x83, 0x82, 0x97, 0x01, 0x00,
+       0x01, 0x00, 0x85, 0x62, 0x16, 0x91, 0x83, 0x30, 0x81, 0x28, 0x03, 0x34,
+       0x01, 0x28, 0x13, 0x01, 0x01, 0x29, 0x82, 0x80, 0x79, 0x71, 0x06, 0xf4,
+       0x22, 0xf0, 0x00, 0x18, 0xaa, 0x87, 0xae, 0x86, 0x32, 0x87, 0x23, 0x2e,
+       0xf4, 0xfc, 0xb6, 0x87, 0x23, 0x2c, 0xf4, 0xfc, 0xba, 0x87, 0x23, 0x2a,
+       0xf4, 0xfc, 0x23, 0x26, 0x04, 0xfe, 0x23, 0x24, 0x04, 0xfe, 0x23, 0x26,
+       0x04, 0xfe, 0xb1, 0xa0, 0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0xc0, 0x00, 0x9b, 0x87, 0x07, 0x40, 0xb9, 0x9f, 0x81, 0x27,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf6, 0xe7, 0xfa, 0x83, 0x27, 0x84, 0xfd,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x02, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x23, 0x26,
+       0x04, 0xfe, 0xb1, 0xa0, 0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0xc0, 0x00, 0x9b, 0x87, 0x07, 0x41, 0xb9, 0x9f, 0x81, 0x27,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf6, 0xe7, 0xfa, 0x83, 0x27, 0x84, 0xfd,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x17,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x02, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x23, 0x26,
+       0x04, 0xfe, 0xb1, 0xa0, 0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0xc0, 0x00, 0x9b, 0x87, 0x27, 0x40, 0xb9, 0x9f, 0x81, 0x27,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf6, 0xe7, 0xfa, 0x83, 0x27, 0x84, 0xfd,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x22, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x23, 0x26,
+       0x04, 0xfe, 0xb1, 0xa0, 0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0xc0, 0x00, 0x9b, 0x87, 0x27, 0x41, 0xb9, 0x9f, 0x81, 0x27,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93,
+       0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf6, 0xe7, 0xfa, 0x83, 0x27, 0x84, 0xfd,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfd, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x17,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x22, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x23, 0x24,
+       0x04, 0xfe, 0x05, 0xa0, 0x17, 0x17, 0x00, 0x00, 0x03, 0x37, 0xc7, 0x6a,
+       0x83, 0x67, 0x84, 0xfe, 0x8a, 0x07, 0xba, 0x97, 0x23, 0xa0, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfe, 0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27,
+       0x84, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xfc, 0xe7, 0xfc,
+       0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x87, 0x71, 0x9c, 0x63, 0x03, 0x27,
+       0x44, 0xfd, 0xba, 0x85, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x05, 0x59,
+       0x82, 0x97, 0x23, 0x24, 0x04, 0xfe, 0xa9, 0xa0, 0x17, 0x17, 0x00, 0x00,
+       0x03, 0x37, 0x07, 0x66, 0x83, 0x67, 0x84, 0xfe, 0x8a, 0x07, 0xba, 0x97,
+       0x9c, 0x43, 0x81, 0xcf, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x47, 0x6e,
+       0x9c, 0x63, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x25, 0x58, 0x82, 0x97,
+       0x19, 0xa8, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0xe7, 0x6c, 0x9c, 0x63,
+       0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x45, 0x57, 0x82, 0x97, 0x83, 0x27,
+       0x84, 0xfe, 0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xf7, 0xe7, 0xfa, 0x97, 0x17,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0x6a, 0x9c, 0x63, 0x17, 0x15, 0x00, 0x00,
+       0x13, 0x05, 0x05, 0xe2, 0x82, 0x97, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74,
+       0x45, 0x61, 0x82, 0x80, 0x01, 0x11, 0x06, 0xec, 0x22, 0xe8, 0x00, 0x10,
+       0xf9, 0x72, 0x93, 0x82, 0x02, 0x77, 0x16, 0x91, 0x2a, 0x87, 0xae, 0x86,
+       0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x23, 0xa6, 0xe7, 0x76, 0xf9, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x36, 0x87, 0x23, 0xa4, 0xe7, 0x76, 0xfd, 0x57,
+       0x23, 0x22, 0xf4, 0xfe, 0xfd, 0x57, 0x23, 0x20, 0xf4, 0xfe, 0x23, 0x24,
+       0x04, 0xfe, 0x41, 0xa0, 0x83, 0x26, 0x84, 0xfe, 0xf9, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x03, 0xa7, 0x87, 0x76, 0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x83, 0xa7, 0xc7, 0x76, 0x36, 0x86, 0xba, 0x85, 0x3e, 0x85, 0xef, 0xf0,
+       0xbf, 0xc7, 0x23, 0x26, 0x04, 0xfe, 0x81, 0xa0, 0x17, 0x17, 0x00, 0x00,
+       0x03, 0x37, 0x87, 0x58, 0x83, 0x67, 0xc4, 0xfe, 0x8a, 0x07, 0xba, 0x97,
+       0x94, 0x43, 0xf9, 0x77, 0xc1, 0x17, 0x33, 0x86, 0x87, 0x00, 0x83, 0x65,
+       0x84, 0xfe, 0x03, 0x67, 0xc4, 0xfe, 0xba, 0x87, 0x86, 0x07, 0xba, 0x97,
+       0x92, 0x07, 0xae, 0x97, 0x8a, 0x07, 0xb2, 0x97, 0x23, 0xa8, 0xd7, 0x7e,
+       0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xfc, 0xe7, 0xfa,
+       0x83, 0x27, 0x84, 0xfe, 0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27,
+       0x84, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x93, 0x07, 0xf0, 0x02, 0xe3, 0xfb,
+       0xe7, 0xf6, 0x23, 0x26, 0x04, 0xfe, 0x75, 0xa0, 0x23, 0x24, 0x04, 0xfe,
+       0xb9, 0xa0, 0xf9, 0x77, 0xc1, 0x17, 0xb3, 0x86, 0x87, 0x00, 0x03, 0x66,
+       0x84, 0xfe, 0x03, 0x67, 0xc4, 0xfe, 0xba, 0x87, 0x86, 0x07, 0xba, 0x97,
+       0x92, 0x07, 0xb2, 0x97, 0x8a, 0x07, 0xb6, 0x97, 0x83, 0xa7, 0x07, 0x7f,
+       0x85, 0xe3, 0x83, 0x27, 0x44, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x57,
+       0x63, 0x16, 0xf7, 0x00, 0x83, 0x27, 0x84, 0xfe, 0x23, 0x22, 0xf4, 0xfe,
+       0x83, 0x27, 0x84, 0xfe, 0x23, 0x20, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x93, 0x07, 0xf0, 0x02, 0xe3, 0xf4, 0xe7, 0xfa, 0x83, 0x27,
+       0x44, 0xfe, 0x3e, 0x87, 0x83, 0x27, 0x04, 0xfe, 0xb9, 0x9f, 0x81, 0x27,
+       0x1b, 0xd7, 0xf7, 0x01, 0xb9, 0x9f, 0x9b, 0xd7, 0x17, 0x40, 0x81, 0x27,
+       0x1b, 0x87, 0x07, 0x00, 0xf9, 0x77, 0xc1, 0x17, 0xb3, 0x86, 0x87, 0x00,
+       0x83, 0x67, 0xc4, 0xfe, 0x8a, 0x07, 0xb6, 0x97, 0x23, 0xa8, 0xe7, 0x76,
+       0xfd, 0x57, 0x23, 0x22, 0xf4, 0xfe, 0xfd, 0x57, 0x23, 0x20, 0xf4, 0xfe,
+       0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xf6, 0xe7, 0xf4,
+       0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0xc7, 0x4f, 0x9c, 0x63, 0x17, 0x15,
+       0x00, 0x00, 0x13, 0x05, 0xa5, 0xc7, 0x82, 0x97, 0x97, 0x17, 0x00, 0x00,
+       0x93, 0x87, 0x87, 0x4e, 0x9c, 0x63, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97,
+       0x03, 0x27, 0xc7, 0x76, 0xba, 0x85, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05,
+       0xa5, 0x38, 0x82, 0x97, 0x23, 0x26, 0x04, 0xfe, 0x1d, 0xa8, 0x97, 0x17,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0x4c, 0x98, 0x63, 0xf9, 0x77, 0xc1, 0x17,
+       0xb3, 0x86, 0x87, 0x00, 0x83, 0x67, 0xc4, 0xfe, 0x8a, 0x07, 0xb6, 0x97,
+       0x83, 0xa7, 0x07, 0x77, 0xbe, 0x85, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05,
+       0x25, 0xc2, 0x02, 0x97, 0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47,
+       0xe3, 0xf1, 0xe7, 0xfc, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x07, 0x48,
+       0x9c, 0x63, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0xe5, 0xbf, 0x82, 0x97,
+       0x23, 0x26, 0x04, 0xfe, 0xa5, 0xa0, 0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x83, 0xa7, 0x87, 0x76, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x79, 0x77,
+       0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0x76, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0xb7, 0x07, 0xc0, 0x00, 0x9b, 0x87, 0x07, 0x40, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0xbe, 0x86, 0xf9, 0x77, 0xc1, 0x17, 0x33, 0x87, 0x87, 0x00,
+       0x83, 0x67, 0xc4, 0xfe, 0x8a, 0x07, 0xba, 0x97, 0x83, 0xa7, 0x07, 0x77,
+       0x9c, 0xc2, 0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe,
+       0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf8,
+       0xe7, 0xf8, 0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97,
+       0x03, 0x27, 0xc7, 0x76, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x04, 0xc0, 0x9b, 0x87, 0x07, 0x02,
+       0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xf9, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0xc7, 0x78, 0x1c, 0xc3, 0x23, 0x26,
+       0x04, 0xfe, 0x95, 0xa8, 0x83, 0x27, 0xc4, 0xfe, 0xa1, 0x27, 0x1b, 0x86,
+       0x07, 0x00, 0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76,
+       0x9b, 0x97, 0x67, 0x00, 0x81, 0x27, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97,
+       0x03, 0x27, 0xc7, 0x76, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07,
+       0xc0, 0x00, 0x9b, 0x87, 0x07, 0x41, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97,
+       0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x81, 0x27,
+       0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86,
+       0xf9, 0x77, 0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0x93, 0x17, 0x06, 0x02,
+       0x81, 0x93, 0x8a, 0x07, 0xba, 0x97, 0x83, 0xa7, 0x07, 0x77, 0x9c, 0xc2,
+       0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf2, 0xe7, 0xf8,
+       0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76, 0x9b, 0x97,
+       0x67, 0x00, 0x81, 0x27, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27,
+       0xc7, 0x76, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87,
+       0x07, 0x00, 0xb7, 0x17, 0x04, 0xc0, 0x9b, 0x87, 0x07, 0x02, 0xb9, 0x9f,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xf9, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0xc7, 0x7a, 0x1c, 0xc3, 0x23, 0x26, 0x04, 0xfe,
+       0x95, 0xa8, 0x83, 0x27, 0xc4, 0xfe, 0xc1, 0x27, 0x1b, 0x86, 0x07, 0x00,
+       0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76, 0x9b, 0x97,
+       0x67, 0x00, 0x81, 0x27, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27,
+       0xc7, 0x76, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0xc0, 0x00,
+       0x9b, 0x87, 0x27, 0x40, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97,
+       0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86, 0xf9, 0x77,
+       0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0x93, 0x17, 0x06, 0x02, 0x81, 0x93,
+       0x8a, 0x07, 0xba, 0x97, 0x83, 0xa7, 0x07, 0x77, 0x9c, 0xc2, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf2, 0xe7, 0xf8, 0xf9, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0x76,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0x04, 0xc0, 0x9b, 0x87, 0x07, 0x22, 0xb9, 0x9f, 0x81, 0x27,
+       0x82, 0x17, 0x81, 0x93, 0x3e, 0x87, 0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x83, 0xa7, 0xc7, 0x7c, 0x1c, 0xc3, 0x23, 0x26, 0x04, 0xfe, 0x95, 0xa8,
+       0x83, 0x27, 0xc4, 0xfe, 0xe1, 0x27, 0x1b, 0x86, 0x07, 0x00, 0xf9, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x79, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0x76,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0xc0, 0x00, 0x9b, 0x87,
+       0x27, 0x41, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86, 0xf9, 0x77, 0xc1, 0x17,
+       0x33, 0x87, 0x87, 0x00, 0x93, 0x17, 0x06, 0x02, 0x81, 0x93, 0x8a, 0x07,
+       0xba, 0x97, 0x83, 0xa7, 0x07, 0x77, 0x9c, 0xc2, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf2, 0xe7, 0xf8, 0xf9, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0x87, 0x76, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x79, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0x76, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x17,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x22, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0xf9, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0xc7, 0x7e, 0x1c, 0xc3, 0x01, 0x00, 0x89, 0x62, 0x93, 0x82, 0x02, 0x89,
+       0x16, 0x91, 0xe2, 0x60, 0x42, 0x64, 0x05, 0x61, 0x82, 0x80, 0x79, 0x71,
+       0x06, 0xf4, 0x22, 0xf0, 0x00, 0x18, 0xaa, 0x87, 0xae, 0x86, 0x32, 0x87,
+       0x23, 0x2e, 0xf4, 0xfc, 0xb6, 0x87, 0x23, 0x2c, 0xf4, 0xfc, 0xba, 0x87,
+       0x23, 0x2a, 0xf4, 0xfc, 0x23, 0x26, 0x04, 0xfe, 0x23, 0x24, 0x04, 0xfe,
+       0x23, 0x26, 0x04, 0xfe, 0xb1, 0xa0, 0x83, 0x27, 0xc4, 0xfd, 0x9b, 0x97,
+       0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0xc7, 0x00, 0x81, 0x27,
+       0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30, 0xb1, 0x27,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf6, 0xe7, 0xfa, 0x23, 0x26,
+       0x04, 0xfe, 0xb9, 0xa0, 0x83, 0x27, 0xc4, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0xc7, 0x00, 0x81, 0x27, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30, 0x9b, 0x87, 0xc7, 0x40,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf5, 0xe7, 0xfa, 0x23, 0x26,
+       0x04, 0xfe, 0xb9, 0xa0, 0x83, 0x27, 0xc4, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0xc7, 0x00, 0x81, 0x27, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30, 0x9b, 0x87, 0xc7, 0x08,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf5, 0xe7, 0xfa, 0x23, 0x26,
+       0x04, 0xfe, 0xb9, 0xa0, 0x83, 0x27, 0xc4, 0xfd, 0x9b, 0x97, 0x67, 0x00,
+       0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfd, 0x9b, 0x97, 0xc7, 0x00, 0x81, 0x27, 0xb9, 0x9f,
+       0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30, 0x9b, 0x87, 0xc7, 0x48,
+       0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0x83, 0x27, 0x44, 0xfd, 0x1c, 0xc3, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf5, 0xe7, 0xfa, 0x23, 0x24,
+       0x04, 0xfe, 0x05, 0xa0, 0x17, 0x17, 0x00, 0x00, 0x03, 0x37, 0xc7, 0xef,
+       0x83, 0x67, 0x84, 0xfe, 0x8a, 0x07, 0xba, 0x97, 0x23, 0xa0, 0x07, 0x00,
+       0x83, 0x27, 0x84, 0xfe, 0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27,
+       0x84, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xfc, 0xe7, 0xfc,
+       0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x87, 0xf6, 0x9c, 0x63, 0x03, 0x27,
+       0x44, 0xfd, 0xba, 0x85, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x85, 0xe2,
+       0x82, 0x97, 0x23, 0x24, 0x04, 0xfe, 0xa9, 0xa0, 0x17, 0x17, 0x00, 0x00,
+       0x03, 0x37, 0x07, 0xeb, 0x83, 0x67, 0x84, 0xfe, 0x8a, 0x07, 0xba, 0x97,
+       0x9c, 0x43, 0x81, 0xcf, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x47, 0xf3,
+       0x9c, 0x63, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x25, 0xdd, 0x82, 0x97,
+       0x19, 0xa8, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0xe7, 0xf1, 0x9c, 0x63,
+       0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x45, 0xdc, 0x82, 0x97, 0x83, 0x27,
+       0x84, 0xfe, 0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xf7, 0xe7, 0xfa, 0x97, 0x17,
+       0x00, 0x00, 0x93, 0x87, 0x27, 0xef, 0x9c, 0x63, 0x17, 0x05, 0x00, 0x00,
+       0x13, 0x05, 0x05, 0x67, 0x82, 0x97, 0x01, 0x00, 0xa2, 0x70, 0x02, 0x74,
+       0x45, 0x61, 0x82, 0x80, 0x71, 0x71, 0x06, 0xf5, 0x22, 0xf1, 0x00, 0x19,
+       0xfd, 0x72, 0x16, 0x91, 0x2a, 0x87, 0xae, 0x86, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x23, 0xa6, 0xe7, 0xf6, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97,
+       0x36, 0x87, 0x23, 0xa4, 0xe7, 0xf6, 0x23, 0x22, 0x04, 0xfe, 0x23, 0x20,
+       0x04, 0xfe, 0x23, 0x24, 0x04, 0xfe, 0xad, 0xa8, 0x83, 0x26, 0x84, 0xfe,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x03, 0xa7, 0x87, 0xf6, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xf6, 0x36, 0x86, 0xba, 0x85,
+       0x3e, 0x85, 0xef, 0xf0, 0x5f, 0xd4, 0x23, 0x26, 0x04, 0xfe, 0x2d, 0xa8,
+       0x17, 0x17, 0x00, 0x00, 0x03, 0x37, 0x07, 0xde, 0x83, 0x67, 0xc4, 0xfe,
+       0x8a, 0x07, 0xba, 0x97, 0x98, 0x43, 0xfd, 0x77, 0xc1, 0x17, 0xb3, 0x86,
+       0x87, 0x00, 0x83, 0x67, 0x84, 0xfe, 0x03, 0x66, 0xc4, 0xfe, 0x16, 0x06,
+       0xb2, 0x97, 0x8a, 0x07, 0xb6, 0x97, 0x23, 0xa8, 0xe7, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xff, 0xe7, 0xfa, 0x83, 0x27,
+       0x84, 0xfe, 0x85, 0x27, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xff, 0xe7, 0xf6, 0x23, 0x26,
+       0x04, 0xfe, 0x49, 0xa8, 0x23, 0x24, 0x04, 0xfe, 0x89, 0xa0, 0xfd, 0x77,
+       0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0x83, 0x67, 0x84, 0xfe, 0x83, 0x66,
+       0xc4, 0xfe, 0x96, 0x06, 0xb6, 0x97, 0x8a, 0x07, 0xba, 0x97, 0x83, 0xa7,
+       0x07, 0xff, 0x89, 0xef, 0x83, 0x27, 0x44, 0xfe, 0x81, 0x27, 0x89, 0xe7,
+       0x83, 0x27, 0x84, 0xfe, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x23, 0x20, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe, 0x85, 0x27, 0x23, 0x24,
+       0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47,
+       0xe3, 0xfb, 0xe7, 0xfa, 0x83, 0x27, 0x44, 0xfe, 0x3e, 0x87, 0x83, 0x27,
+       0x04, 0xfe, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0xd7, 0x17, 0x00, 0x1b, 0x87,
+       0x07, 0x00, 0xfd, 0x77, 0xc1, 0x17, 0xb3, 0x86, 0x87, 0x00, 0x83, 0x67,
+       0xc4, 0xfe, 0x8a, 0x07, 0xb6, 0x97, 0x23, 0xa8, 0xe7, 0xf6, 0x23, 0x22,
+       0x04, 0xfe, 0x23, 0x20, 0x04, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x85, 0x27,
+       0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87, 0x07, 0x00,
+       0xfd, 0x47, 0xe3, 0xf3, 0xe7, 0xf6, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87,
+       0x67, 0xd7, 0x9c, 0x63, 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x4f,
+       0x82, 0x97, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x27, 0xd6, 0x9c, 0x63,
+       0x7d, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0xf6, 0xba, 0x85,
+       0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0xc5, 0xc3, 0x82, 0x97, 0x23, 0x26,
+       0x04, 0xfe, 0x1d, 0xa8, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0xc7, 0xd3,
+       0x98, 0x63, 0xfd, 0x77, 0xc1, 0x17, 0xb3, 0x86, 0x87, 0x00, 0x83, 0x67,
+       0xc4, 0xfe, 0x8a, 0x07, 0xb6, 0x97, 0x83, 0xa7, 0x07, 0xf7, 0xbe, 0x85,
+       0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x49, 0x02, 0x97, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe,
+       0x1b, 0x87, 0x07, 0x00, 0xfd, 0x47, 0xe3, 0xf1, 0xe7, 0xfc, 0x97, 0x17,
+       0x00, 0x00, 0x93, 0x87, 0xa7, 0xcf, 0x9c, 0x63, 0x17, 0x05, 0x00, 0x00,
+       0x13, 0x05, 0x85, 0x47, 0x82, 0x97, 0x23, 0x26, 0x04, 0xfe, 0xa5, 0xa0,
+       0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xf6, 0x9b, 0x97,
+       0x67, 0x00, 0x81, 0x27, 0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87,
+       0x07, 0x00, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6,
+       0x9b, 0x97, 0xc7, 0x00, 0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00,
+       0xb7, 0x07, 0x01, 0x30, 0xb1, 0x27, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97,
+       0x27, 0x00, 0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86, 0xfd, 0x77,
+       0xc1, 0x17, 0x33, 0x87, 0x87, 0x00, 0x83, 0x67, 0xc4, 0xfe, 0x8a, 0x07,
+       0xba, 0x97, 0x83, 0xa7, 0x07, 0xf7, 0x9c, 0xc2, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf8, 0xe7, 0xf8, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x7d, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0xf6, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x05, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0xc7, 0xf8, 0x1c, 0xc3, 0x23, 0x26, 0x04, 0xfe, 0x9d, 0xa8, 0x83, 0x27,
+       0xc4, 0xfe, 0xa1, 0x27, 0x1b, 0x86, 0x07, 0x00, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0xc7, 0x00,
+       0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30,
+       0x9b, 0x87, 0xc7, 0x40, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86, 0xfd, 0x77, 0xc1, 0x17,
+       0x33, 0x87, 0x87, 0x00, 0x93, 0x17, 0x06, 0x02, 0x81, 0x93, 0x8a, 0x07,
+       0xba, 0x97, 0x83, 0xa7, 0x07, 0xf7, 0x9c, 0xc2, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf1, 0xe7, 0xf8, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x7d, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0xf6, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x17,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x05, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0xc7, 0xfa, 0x1c, 0xc3, 0x23, 0x26, 0x04, 0xfe, 0x9d, 0xa8, 0x83, 0x27,
+       0xc4, 0xfe, 0xc1, 0x27, 0x1b, 0x86, 0x07, 0x00, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0xc7, 0x00,
+       0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30,
+       0x9b, 0x87, 0xc7, 0x08, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86, 0xfd, 0x77, 0xc1, 0x17,
+       0x33, 0x87, 0x87, 0x00, 0x93, 0x17, 0x06, 0x02, 0x81, 0x93, 0x8a, 0x07,
+       0xba, 0x97, 0x83, 0xa7, 0x07, 0xf7, 0x9c, 0xc2, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf1, 0xe7, 0xf8, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x7d, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0xf6, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x25, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0xc7, 0xfc, 0x1c, 0xc3, 0x23, 0x26, 0x04, 0xfe, 0x9d, 0xa8, 0x83, 0x27,
+       0xc4, 0xfe, 0xe1, 0x27, 0x1b, 0x86, 0x07, 0x00, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0xc7, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x03, 0x27, 0xc4, 0xfe, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xfd, 0x77,
+       0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0xc7, 0x00,
+       0x81, 0x27, 0xb9, 0x9f, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x07, 0x01, 0x30,
+       0x9b, 0x87, 0xc7, 0x48, 0xb9, 0x9f, 0x81, 0x27, 0x9b, 0x97, 0x27, 0x00,
+       0x81, 0x27, 0x82, 0x17, 0x81, 0x93, 0xbe, 0x86, 0xfd, 0x77, 0xc1, 0x17,
+       0x33, 0x87, 0x87, 0x00, 0x93, 0x17, 0x06, 0x02, 0x81, 0x93, 0x8a, 0x07,
+       0xba, 0x97, 0x83, 0xa7, 0x07, 0xf7, 0x9c, 0xc2, 0x83, 0x27, 0xc4, 0xfe,
+       0x85, 0x27, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x1b, 0x87,
+       0x07, 0x00, 0x9d, 0x47, 0xe3, 0xf1, 0xe7, 0xf8, 0xfd, 0x77, 0xc1, 0x17,
+       0xa2, 0x97, 0x83, 0xa7, 0x87, 0xf6, 0x9b, 0x97, 0x67, 0x00, 0x81, 0x27,
+       0x7d, 0x77, 0x41, 0x17, 0x22, 0x97, 0x03, 0x27, 0xc7, 0xf6, 0xb9, 0x9f,
+       0x81, 0x27, 0x9b, 0x97, 0x87, 0x00, 0x1b, 0x87, 0x07, 0x00, 0xb7, 0x17,
+       0x04, 0xc0, 0x9b, 0x87, 0x07, 0x25, 0xb9, 0x9f, 0x81, 0x27, 0x82, 0x17,
+       0x81, 0x93, 0x3e, 0x87, 0xfd, 0x77, 0xc1, 0x17, 0xa2, 0x97, 0x83, 0xa7,
+       0xc7, 0xfe, 0x1c, 0xc3, 0x01, 0x00, 0x85, 0x62, 0x16, 0x91, 0xaa, 0x70,
+       0x0a, 0x74, 0x4d, 0x61, 0x82, 0x80, 0x79, 0x71, 0x06, 0xf4, 0x22, 0xf0,
+       0x00, 0x18, 0xaa, 0x87, 0xae, 0x86, 0x32, 0x87, 0x23, 0x2e, 0xf4, 0xfc,
+       0xb6, 0x87, 0x23, 0x2c, 0xf4, 0xfc, 0xba, 0x87, 0x23, 0x2a, 0xf4, 0xfc,
+       0x23, 0x26, 0x04, 0xfe, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0x47, 0x99,
+       0x9c, 0x63, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x25, 0x89, 0x82, 0x97,
+       0x03, 0x27, 0x84, 0xfd, 0x83, 0x27, 0xc4, 0xfd, 0x05, 0x46, 0xba, 0x85,
+       0x3e, 0x85, 0xef, 0xb0, 0xdf, 0xd7, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87,
+       0xe7, 0x96, 0x9c, 0x63, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0xc5, 0x88,
+       0x82, 0x97, 0x97, 0x17, 0x00, 0x00, 0x93, 0x87, 0xa7, 0x95, 0x9c, 0x63,
+       0x83, 0x26, 0x84, 0xfd, 0x03, 0x26, 0x44, 0xfd, 0x03, 0x27, 0xc4, 0xfd,
+       0xba, 0x85, 0x17, 0x15, 0x00, 0x00, 0x13, 0x05, 0x25, 0x89, 0x82, 0x97,
+       0x03, 0x26, 0x84, 0xfd, 0x83, 0x25, 0x44, 0xfd, 0x03, 0x25, 0xc4, 0xfd,
+       0x85, 0x48, 0x05, 0x48, 0x85, 0x47, 0x05, 0x47, 0x81, 0x46, 0xef, 0xe0,
+       0xdf, 0xa8, 0x03, 0x27, 0x84, 0xfd, 0x83, 0x27, 0xc4, 0xfd, 0x01, 0x46,
+       0xba, 0x85, 0x3e, 0x85, 0xef, 0xb0, 0xbf, 0xd1, 0x01, 0x00, 0xa2, 0x70,
+       0x02, 0x74, 0x45, 0x61, 0x82, 0x80, 0x00, 0x00, 0x52, 0x78, 0x20, 0x76,
+       0x72, 0x65, 0x66, 0x3d, 0x25, 0x64, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65,
+       0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x4d, 0x61, 0x72,
+       0x67, 0x69, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x65, 0x74, 0x74,
+       0x69, 0x6e, 0x67, 0x20, 0x61, 0x73, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f,
+       0x77, 0x3a, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x43, 0x53, 0x30, 0x20, 0x44, 0x51, 0x30, 0x7e, 0x44, 0x51, 0x33, 0x31,
+       0x20, 0x52, 0x44, 0x20, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x53, 0x31, 0x20,
+       0x44, 0x51, 0x30, 0x7e, 0x44, 0x51, 0x33, 0x31, 0x20, 0x52, 0x44, 0x20,
+       0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x25, 0x64, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x53, 0x30, 0x20,
+       0x44, 0x51, 0x30, 0x7e, 0x44, 0x51, 0x33, 0x31, 0x20, 0x52, 0x44, 0x20,
+       0x44, 0x6c, 0x79, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x3a,
+       0x20, 0x00, 0x00, 0x00, 0x43, 0x53, 0x31, 0x20, 0x44, 0x51, 0x30, 0x7e,
+       0x44, 0x51, 0x33, 0x31, 0x20, 0x52, 0x44, 0x20, 0x44, 0x6c, 0x79, 0x20,
+       0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x00, 0x00, 0x00,
+       0x56, 0x72, 0x65, 0x66, 0x28, 0x44, 0x51, 0x29, 0x3d, 0x25, 0x64, 0x20,
+       0x63, 0x6f, 0x72, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e,
+       0x67, 0x3a, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x43, 0x53, 0x30, 0x20,
+       0x44, 0x51, 0x30, 0x7e, 0x44, 0x51, 0x33, 0x31, 0x20, 0x57, 0x52, 0x20,
+       0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x43, 0x53, 0x31, 0x20, 0x44, 0x51, 0x30, 0x7e,
+       0x44, 0x51, 0x33, 0x31, 0x20, 0x57, 0x52, 0x20, 0x4d, 0x61, 0x72, 0x67,
+       0x69, 0x6e, 0x3a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x43, 0x53, 0x30, 0x20, 0x44, 0x51, 0x30, 0x7e, 0x44, 0x51, 0x33, 0x31,
+       0x20, 0x57, 0x52, 0x20, 0x44, 0x6c, 0x79, 0x20, 0x53, 0x65, 0x74, 0x74,
+       0x69, 0x6e, 0x67, 0x3a, 0x20, 0x00, 0x00, 0x00, 0x43, 0x53, 0x31, 0x20,
+       0x44, 0x51, 0x30, 0x7e, 0x44, 0x51, 0x33, 0x31, 0x20, 0x57, 0x52, 0x20,
+       0x44, 0x6c, 0x79, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x3a,
+       0x20, 0x00, 0x00, 0x00, 0x43, 0x53, 0x30, 0x20, 0x44, 0x4d, 0x30, 0x7e,
+       0x44, 0x4d, 0x33, 0x20, 0x57, 0x52, 0x20, 0x4d, 0x61, 0x72, 0x67, 0x69,
+       0x6e, 0x3a, 0x20, 0x00, 0x43, 0x53, 0x31, 0x20, 0x44, 0x4d, 0x30, 0x7e,
+       0x44, 0x4d, 0x33, 0x20, 0x57, 0x52, 0x20, 0x4d, 0x61, 0x72, 0x67, 0x69,
+       0x6e, 0x3a, 0x20, 0x00, 0x43, 0x53, 0x30, 0x20, 0x44, 0x4d, 0x30, 0x7e,
+       0x44, 0x4d, 0x33, 0x20, 0x57, 0x52, 0x20, 0x44, 0x6c, 0x79, 0x20, 0x53,
+       0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x00, 0x00, 0x00, 0x00,
+       0x43, 0x53, 0x31, 0x20, 0x44, 0x4d, 0x30, 0x7e, 0x44, 0x4d, 0x33, 0x20,
+       0x57, 0x52, 0x20, 0x44, 0x6c, 0x79, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69,
+       0x6e, 0x67, 0x3a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x65, 0x61, 0x63, 0x68,
+       0x20, 0x52, 0x58, 0x20, 0x56, 0x72, 0x65, 0x66, 0x20, 0x63, 0x6f, 0x72,
+       0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d,
+       0x69, 0x6e, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x20, 0x3d, 0x20,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0a, 0x20, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65,
+       0x20, 0x52, 0x78, 0x20, 0x56, 0x72, 0x65, 0x66, 0x20, 0x61, 0x64, 0x6a,
+       0x75, 0x73, 0x74, 0x3d, 0x25, 0x64, 0x20, 0x2c, 0x63, 0x6f, 0x72, 0x72,
+       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x65,
+       0x73, 0x74, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3d, 0x25, 0x64,
+       0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x61, 0x63, 0x68,
+       0x20, 0x54, 0x58, 0x20, 0x56, 0x72, 0x65, 0x66, 0x20, 0x63, 0x6f, 0x72,
+       0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d,
+       0x69, 0x6e, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x20, 0x3d, 0x20,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0x74, 0x69,
+       0x6d, 0x69, 0x7a, 0x65, 0x20, 0x54, 0x78, 0x20, 0x56, 0x72, 0x65, 0x66,
+       0x20, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x3d, 0x25, 0x64, 0x20, 0x2c,
+       0x63, 0x6f, 0x72, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e,
+       0x67, 0x20, 0x62, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69,
+       0x6e, 0x3d, 0x25, 0x64, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79,
+       0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x31,
+       0x36, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x41, 0x44, 0x44, 0x52, 0x5b, 0x30, 0x78, 0x25,
+       0x30, 0x38, 0x78, 0x5d, 0x3d, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x20,
+       0x21, 0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79,
+       0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x31,
+       0x36, 0x30, 0x30, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x21, 0x21, 0x21,
+       0x21, 0x20, 0x0a, 0x00, 0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75,
+       0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20,
+       0x74, 0x6f, 0x20, 0x31, 0x36, 0x30, 0x30, 0x20, 0x64, 0x6f, 0x6e, 0x65,
+       0x21, 0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x73, 0x77, 0x20, 0x66,
+       0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68, 0x61,
+       0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x31, 0x32, 0x30, 0x30, 0x21,
+       0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x77, 0x61, 0x69, 0x74, 0x20, 0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71,
+       0x75, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+       0x20, 0x74, 0x6f, 0x20, 0x31, 0x32, 0x30, 0x30, 0x21, 0x21, 0x21, 0x21,
+       0x20, 0x0a, 0x00, 0x00, 0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75,
+       0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20,
+       0x74, 0x6f, 0x20, 0x31, 0x32, 0x30, 0x30, 0x20, 0x64, 0x6f, 0x6e, 0x65,
+       0x21, 0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x73, 0x77, 0x20, 0x66,
+       0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68, 0x61,
+       0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x74, 0x20, 0x63,
+       0x6c, 0x6b, 0x21, 0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x77, 0x61, 0x69, 0x74, 0x20, 0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71,
+       0x75, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+       0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x74, 0x20, 0x63, 0x6c, 0x6b, 0x21,
+       0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x73, 0x77, 0x20, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79,
+       0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x65,
+       0x78, 0x74, 0x20, 0x63, 0x6c, 0x6b, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x21,
+       0x21, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x20,
+       0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x63, 0x68,
+       0x61, 0x6e, 0x67, 0x65, 0x20, 0x21, 0x21, 0x21, 0x21, 0x20, 0x0a, 0x00,
+       0x54, 0xc7, 0xff, 0xff, 0x2a, 0xc6, 0xff, 0xff, 0x64, 0xc8, 0xff, 0xff,
+       0xfa, 0xc7, 0xff, 0xff, 0xce, 0xc8, 0xff, 0xff, 0x52, 0x65, 0x61, 0x64,
+       0x5f, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69,
+       0x6e, 0x67, 0x20, 0x50, 0x41, 0x53, 0x53, 0x21, 0x21, 0x20, 0x0a, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x64, 0x5f, 0x67, 0x61, 0x74,
+       0x65, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x54,
+       0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x21, 0x21, 0x20, 0x0a, 0x00, 0x00,
+       0x72, 0x65, 0x61, 0x64, 0x20, 0x67, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6f,
+       0x64, 0x65, 0x5b, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x5d, 0x3d, 0x30,
+       0x78, 0x25, 0x30, 0x38, 0x78, 0x20, 0x0a, 0x00, 0x41, 0x67, 0x61, 0x69,
+       0x6e, 0x21, 0x21, 0x21, 0x20, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e,
+       0x67, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x20, 0x46,
+       0x69, 0x6e, 0x65, 0x20, 0x52, 0x78, 0x20, 0x76, 0x72, 0x65, 0x66, 0x20,
+       0x73, 0x74, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x25, 0x64, 0x20, 0x0a, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x41, 0x67, 0x61, 0x69, 0x6e, 0x21, 0x21, 0x21,
+       0x20, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70,
+       0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x20, 0x46, 0x69, 0x6e, 0x65, 0x20,
+       0x54, 0x78, 0x20, 0x76, 0x72, 0x65, 0x66, 0x20, 0x73, 0x74, 0x65, 0x70,
+       0x20, 0x3d, 0x20, 0x25, 0x64, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x54, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x61,
+       0x72, 0x74, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x54, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x69,
+       0x74, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x64, 0x75, 0x6d, 0x70, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x20,
+       0x61, 0x6e, 0x64, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20,
+       0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e,
+       0x69, 0x6e, 0x67, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x43, 0x41, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x69,
+       0x6e, 0x67, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x69,
+       0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75,
+       0x74, 0x65, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x64, 0x20, 0x47, 0x61, 0x74,
+       0x65, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x52, 0x65, 0x61, 0x64, 0x20, 0x47, 0x61, 0x74, 0x65, 0x20, 0x54, 0x72,
+       0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65,
+       0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a,
+       0x00, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x64, 0x20, 0x54, 0x72, 0x61,
+       0x69, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x64, 0x20, 0x54, 0x72, 0x61,
+       0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78,
+       0x65, 0x63, 0x75, 0x74, 0x65, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00,
+       0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x69,
+       0x6e, 0x67, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x69,
+       0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75,
+       0x74, 0x65, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67,
+       0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5b, 0x30, 0x78, 0x25, 0x30,
+       0x38, 0x58, 0x5d, 0x3d, 0x30, 0x78, 0x25, 0x30, 0x38, 0x58, 0x20, 0x0a,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x72, 0x69, 0x74,
+       0x65, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x65,
+       0x72, 0x72, 0x6f, 0x72, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x64, 0x20, 0x4c, 0x65, 0x76,
+       0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x44, 0x51, 0x20, 0x54, 0x72, 0x61,
+       0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x64,
+       0x20, 0x47, 0x61, 0x74, 0x65, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x69,
+       0x6e, 0x67, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x0a, 0x00, 0x00, 0x74, 0x78, 0x20, 0x64, 0x6c, 0x79, 0x3d, 0x25,
+       0x64, 0x20, 0x62, 0x69, 0x74, 0x30, 0x7e, 0x62, 0x69, 0x74, 0x33, 0x31,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x63, 0x73, 0x25, 0x64, 0x20, 0x33, 0x32, 0x62,
+       0x69, 0x74, 0x20, 0x74, 0x78, 0x20, 0x64, 0x6c, 0x79, 0x3a, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x72, 0x78, 0x20, 0x64, 0x6c, 0x79, 0x3d, 0x25,
+       0x64, 0x20, 0x62, 0x69, 0x74, 0x30, 0x7e, 0x62, 0x69, 0x74, 0x33, 0x31,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x63, 0x73, 0x25, 0x64, 0x20, 0x33, 0x32, 0x62, 0x69, 0x74, 0x20, 0x72,
+       0x78, 0x20, 0x64, 0x6c, 0x79, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x20, 0x72,
+       0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
+       0x20, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x65, 0x6e, 0x74, 0x65,
+       0x72, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65,
+       0x73, 0x68, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x6f, 0x6e,
+       0x65, 0x20, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00,
+       0x25, 0x78, 0x2c, 0x20, 0x25, 0x78, 0x2c, 0x20, 0x25, 0x78, 0x0a, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xd8, 0x1b, 0x83, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#endif /* _DDR_INIT_ASIC_H_ */
diff --git a/drivers/ddr/spacemit/k1x/ddr_init_fpga.h b/drivers/ddr/spacemit/k1x/ddr_init_fpga.h
new file mode 100644 (file)
index 0000000..348f17f
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef _DDR_INIT_FPGA_H_
+#define _DDR_INIT_FPGA_H_
+
+static const unsigned char lpddr4_init_fpga_data[] = {
+       0x1d, 0x71, 0x22, 0xec, 0x00, 0x10, 0x23, 0x34, 0xa4, 0xfe, 0x0c, 0xe4,
+       0x10, 0xe8, 0x14, 0xec, 0x18, 0xf0, 0x1c, 0xf4, 0x23, 0x38, 0x04, 0x03,
+       0x23, 0x3c, 0x14, 0x03, 0x01, 0x00, 0x62, 0x64, 0x25, 0x61, 0x82, 0x80,
+       0x01, 0x11, 0x22, 0xec, 0x00, 0x10, 0x23, 0x34, 0xa4, 0xfe, 0x83, 0x37,
+       0x84, 0xfe, 0x93, 0x87, 0x07, 0x20, 0x37, 0x07, 0x0e, 0x00, 0x05, 0x07,
+       0x98, 0xc3, 0x83, 0x37, 0x84, 0xfe, 0x93, 0x87, 0x47, 0x20, 0x23, 0xa0,
+       0x07, 0x00, 0x83, 0x37, 0x84, 0xfe, 0x93, 0x87, 0x87, 0x20, 0x37, 0x07,
+       0x0e, 0x40, 0x05, 0x07, 0x98, 0xc3, 0x83, 0x37, 0x84, 0xfe, 0x93, 0x87,
+       0xc7, 0x20, 0x23, 0xa0, 0x07, 0x00, 0x83, 0x37, 0x84, 0xfe, 0x93, 0x87,
+       0x07, 0x22, 0x37, 0x07, 0x02, 0x05, 0x13, 0x07, 0x27, 0x53, 0x98, 0xc3,
+       0x83, 0x37, 0x84, 0xfe, 0x93, 0x87, 0x47, 0x22, 0x37, 0x07, 0x02, 0x05,
+       0x13, 0x07, 0x27, 0x53, 0x98, 0xc3, 0x83, 0x37, 0x84, 0xfe, 0x93, 0x87,
+       0x87, 0x04, 0x05, 0x47, 0x98, 0xc3, 0x01, 0x00, 0x62, 0x64, 0x05, 0x61,
+       0x82, 0x80, 0x01, 0x11, 0x22, 0xec, 0x00, 0x10, 0xb7, 0x87, 0x42, 0x0d,
+       0x93, 0x87, 0xb7, 0x28, 0x92, 0x07, 0x9c, 0x43, 0x23, 0x26, 0xf4, 0xfe,
+       0x83, 0x27, 0xc4, 0xfe, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe,
+       0x3e, 0x87, 0xb7, 0x07, 0x00, 0x80, 0x93, 0xc7, 0xf7, 0xbf, 0xf9, 0x8f,
+       0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe, 0x3e, 0x87, 0x85, 0x67,
+       0x93, 0x87, 0x07, 0x80, 0xd9, 0x8f, 0x23, 0x24, 0xf4, 0xfe, 0xb7, 0x87,
+       0x42, 0x0d, 0x93, 0x87, 0xb7, 0x28, 0x92, 0x07, 0x03, 0x27, 0x84, 0xfe,
+       0x98, 0xc3, 0xb7, 0x07, 0x85, 0x1a, 0x93, 0x87, 0xd7, 0x51, 0x8e, 0x07,
+       0x13, 0x07, 0x30, 0x30, 0x98, 0xc3, 0xb7, 0x07, 0x85, 0x1a, 0x93, 0x87,
+       0x37, 0x57, 0x8e, 0x07, 0x9c, 0x43, 0x23, 0x22, 0xf4, 0xfe, 0x83, 0x27,
+       0x44, 0xfe, 0x23, 0x24, 0xf4, 0xfe, 0x83, 0x27, 0x84, 0xfe, 0x3e, 0x87,
+       0x85, 0x67, 0x93, 0x87, 0x07, 0xc0, 0xd9, 0x8f, 0x23, 0x24, 0xf4, 0xfe,
+       0xb7, 0x07, 0x85, 0x1a, 0x93, 0x87, 0x37, 0x57, 0x8e, 0x07, 0x03, 0x27,
+       0x84, 0xfe, 0x98, 0xc3, 0x01, 0x00, 0x62, 0x64, 0x05, 0x61, 0x82, 0x80,
+       0x1d, 0x71, 0x86, 0xec, 0xa2, 0xe8, 0x80, 0x10, 0x8d, 0x47, 0xfa, 0x07,
+       0x23, 0x30, 0xf4, 0xfe, 0x23, 0x2e, 0x04, 0xfc, 0x23, 0x26, 0x04, 0xfe,
+       0x83, 0x37, 0x04, 0xfe, 0x23, 0x38, 0xf4, 0xfc, 0x03, 0x37, 0x04, 0xfd,
+       0xb7, 0x07, 0x04, 0x00, 0xba, 0x97, 0x23, 0x34, 0xf4, 0xfc, 0xef, 0xf0,
+       0xdf, 0xf2, 0x13, 0x05, 0x00, 0x5c, 0xef, 0xf0, 0x7f, 0xe8, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0x47, 0x04, 0x37, 0x07, 0x04, 0x00, 0x13, 0x07,
+       0x07, 0x30, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x87, 0x2c,
+       0x9c, 0x43, 0x23, 0x22, 0xf4, 0xfc, 0x83, 0x27, 0x44, 0xfc, 0x23, 0x26,
+       0xf4, 0xfe, 0x83, 0x27, 0xc4, 0xfe, 0x3e, 0x87, 0xb7, 0x07, 0x00, 0x02,
+       0xd9, 0x8f, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x87, 0x2c, 0x03, 0x27, 0xc4, 0xfe, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x87, 0x04, 0x05, 0x47, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x87, 0x05, 0x37, 0x47, 0xd5, 0x3f, 0x13, 0x07, 0x57, 0xfd,
+       0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x47, 0x06, 0x13, 0x07,
+       0x10, 0x10, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x07, 0x18,
+       0x41, 0x67, 0x13, 0x07, 0x07, 0x06, 0x98, 0xc3, 0x03, 0x35, 0x04, 0xfd,
+       0xef, 0xf0, 0x1f, 0xe2, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x07, 0x2c,
+       0x23, 0xa0, 0x07, 0x00, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x47, 0x2c,
+       0x13, 0x07, 0x80, 0x0b, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x07, 0x30, 0x13, 0x07, 0x60, 0x40, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x07, 0x38, 0x3d, 0x47, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x47, 0x38, 0x09, 0x47, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x87, 0x38, 0x0d, 0x47, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0xc7, 0x38, 0x37, 0x07, 0x03, 0x00, 0x98, 0xc3, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0x07, 0x39, 0x37, 0x07, 0x14, 0x00, 0x21, 0x07,
+       0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x47, 0x39, 0x37, 0x07,
+       0x04, 0x00, 0x51, 0x07, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x87, 0x39, 0x37, 0x07, 0x04, 0x00, 0x11, 0x07, 0x98, 0xc3, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0xc7, 0x39, 0x13, 0x07, 0x30, 0x30, 0x98, 0xc3,
+       0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x07, 0x3a, 0x37, 0x07, 0x03, 0x05,
+       0x13, 0x07, 0x37, 0x30, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x47, 0x3a, 0x0d, 0x47, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x87, 0x3a, 0x13, 0x07, 0xa0, 0x20, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0xc7, 0x3a, 0x37, 0x07, 0x02, 0x08, 0x13, 0x07, 0x17, 0x30,
+       0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x07, 0x3b, 0x37, 0x07,
+       0x04, 0x03, 0x13, 0x07, 0x37, 0x40, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x47, 0x3b, 0x37, 0x17, 0x00, 0x08, 0x13, 0x07, 0x07, 0x80,
+       0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x87, 0x3b, 0x13, 0x07,
+       0x00, 0x20, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0xc7, 0x3b,
+       0x23, 0xa0, 0x07, 0x00, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x07, 0x3c,
+       0x37, 0x07, 0x00, 0x10, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x47, 0x3c, 0x23, 0xa0, 0x07, 0x00, 0x83, 0x37, 0x04, 0xfd, 0x93, 0x87,
+       0x87, 0x3c, 0x05, 0x67, 0x13, 0x07, 0xa7, 0xa0, 0x98, 0xc3, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0xc7, 0x3c, 0x23, 0xa0, 0x07, 0x00, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0x07, 0x3d, 0x23, 0xa0, 0x07, 0x00, 0x03, 0x37,
+       0x04, 0xfd, 0x85, 0x67, 0x93, 0x87, 0x47, 0x3e, 0xba, 0x97, 0x37, 0x07,
+       0x06, 0x08, 0x13, 0x07, 0x17, 0x10, 0x98, 0xc3, 0x83, 0x27, 0xc4, 0xfd,
+       0x81, 0x27, 0xa1, 0xe7, 0x83, 0x37, 0x84, 0xfc, 0x93, 0x87, 0x47, 0x06,
+       0x13, 0x07, 0x90, 0x08, 0x98, 0xc3, 0x03, 0x37, 0x84, 0xfc, 0x85, 0x67,
+       0x93, 0x87, 0x47, 0x06, 0xba, 0x97, 0x13, 0x07, 0x90, 0x08, 0x98, 0xc3,
+       0x03, 0x37, 0x84, 0xfc, 0x89, 0x67, 0x93, 0x87, 0x47, 0x06, 0xba, 0x97,
+       0x13, 0x07, 0x90, 0x08, 0x98, 0xc3, 0x03, 0x37, 0x84, 0xfc, 0x8d, 0x67,
+       0x93, 0x87, 0x47, 0x06, 0xba, 0x97, 0x13, 0x07, 0x90, 0x08, 0x98, 0xc3,
+       0x99, 0xa0, 0x83, 0x37, 0x84, 0xfc, 0x93, 0x87, 0x47, 0x06, 0x13, 0x07,
+       0x90, 0x08, 0x98, 0xc3, 0x03, 0x37, 0x84, 0xfc, 0x91, 0x67, 0x93, 0x87,
+       0x47, 0x06, 0xba, 0x97, 0x13, 0x07, 0x90, 0x08, 0x98, 0xc3, 0x03, 0x37,
+       0x84, 0xfc, 0xa1, 0x67, 0x93, 0x87, 0x47, 0x06, 0xba, 0x97, 0x13, 0x07,
+       0x90, 0x08, 0x98, 0xc3, 0x03, 0x37, 0x84, 0xfc, 0xb1, 0x67, 0x93, 0x87,
+       0x47, 0x06, 0xba, 0x97, 0x13, 0x07, 0x90, 0x08, 0x98, 0xc3, 0x03, 0x37,
+       0x04, 0xfd, 0x85, 0x67, 0x93, 0x87, 0x07, 0x3d, 0xba, 0x97, 0x37, 0x07,
+       0x00, 0x13, 0x05, 0x07, 0x98, 0xc3, 0x03, 0x37, 0x04, 0xfd, 0x85, 0x67,
+       0x93, 0x87, 0xc7, 0x3f, 0xba, 0x97, 0x9c, 0x43, 0x23, 0x20, 0xf4, 0xfc,
+       0x83, 0x27, 0x04, 0xfc, 0x23, 0x26, 0xf4, 0xfe, 0x31, 0xa8, 0x03, 0x37,
+       0x04, 0xfd, 0x85, 0x67, 0x93, 0x87, 0xc7, 0x3f, 0xba, 0x97, 0x9c, 0x43,
+       0x23, 0x22, 0xf4, 0xfa, 0x83, 0x27, 0x44, 0xfa, 0x23, 0x26, 0xf4, 0xfe,
+       0x83, 0x27, 0xc4, 0xfe, 0xe3, 0xd1, 0x07, 0xfe, 0x03, 0x37, 0x04, 0xfd,
+       0x85, 0x67, 0x93, 0x87, 0x07, 0x3d, 0xba, 0x97, 0x37, 0x07, 0x00, 0x13,
+       0x13, 0x07, 0x07, 0x10, 0x98, 0xc3, 0x03, 0x37, 0x04, 0xfd, 0x85, 0x67,
+       0x93, 0x87, 0x07, 0x3d, 0xba, 0x97, 0x23, 0xa0, 0x07, 0x00, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0x07, 0x08, 0x23, 0xa0, 0x07, 0x00, 0x03, 0x37,
+       0x04, 0xfd, 0x85, 0x67, 0x93, 0x87, 0x07, 0xa0, 0xba, 0x97, 0x23, 0xa0,
+       0x07, 0x00, 0x03, 0x37, 0x04, 0xfd, 0x85, 0x67, 0x93, 0x87, 0x07, 0xac,
+       0xba, 0x97, 0x23, 0xa0, 0x07, 0x00, 0x03, 0x37, 0x04, 0xfd, 0x85, 0x67,
+       0x93, 0x87, 0xc7, 0xac, 0xba, 0x97, 0x7d, 0x57, 0x98, 0xc3, 0x83, 0x37,
+       0x04, 0xfd, 0x93, 0x87, 0x07, 0x08, 0x9c, 0x43, 0x23, 0x2e, 0xf4, 0xfa,
+       0x83, 0x27, 0xc4, 0xfb, 0x3e, 0x86, 0x93, 0x05, 0x00, 0x08, 0x13, 0x05,
+       0x80, 0x5c, 0xef, 0xf0, 0xbf, 0xb2, 0x03, 0x37, 0x04, 0xfd, 0x85, 0x67,
+       0x93, 0x87, 0x07, 0xa0, 0xba, 0x97, 0x9c, 0x43, 0x23, 0x2c, 0xf4, 0xfa,
+       0x83, 0x27, 0x84, 0xfb, 0x3e, 0x86, 0x85, 0x67, 0x93, 0x85, 0x07, 0xa0,
+       0x13, 0x05, 0x80, 0x5c, 0xef, 0xf0, 0x5f, 0xb0, 0x03, 0x37, 0x04, 0xfd,
+       0x85, 0x67, 0x93, 0x87, 0x07, 0xac, 0xba, 0x97, 0x9c, 0x43, 0x23, 0x2a,
+       0xf4, 0xfa, 0x83, 0x27, 0x44, 0xfb, 0x3e, 0x86, 0x85, 0x67, 0x93, 0x85,
+       0x07, 0xac, 0x13, 0x05, 0x80, 0x5c, 0xef, 0xf0, 0xff, 0xad, 0x03, 0x37,
+       0x04, 0xfd, 0x85, 0x67, 0x93, 0x87, 0xc7, 0xac, 0xba, 0x97, 0x9c, 0x43,
+       0x23, 0x28, 0xf4, 0xfa, 0x83, 0x27, 0x04, 0xfb, 0x3e, 0x86, 0x85, 0x67,
+       0x93, 0x85, 0xc7, 0xac, 0x13, 0x05, 0x80, 0x5c, 0xef, 0xf0, 0x9f, 0xab,
+       0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x07, 0x02, 0x37, 0x07, 0x00, 0x13,
+       0x05, 0x07, 0x98, 0xc3, 0x83, 0x37, 0x04, 0xfd, 0xa1, 0x07, 0x9c, 0x43,
+       0x23, 0x26, 0xf4, 0xfa, 0x83, 0x27, 0xc4, 0xfa, 0x23, 0x26, 0xf4, 0xfe,
+       0x19, 0xa8, 0x83, 0x37, 0x04, 0xfd, 0xa1, 0x07, 0x9c, 0x43, 0x23, 0x24,
+       0xf4, 0xfa, 0x83, 0x27, 0x84, 0xfa, 0x23, 0x26, 0xf4, 0xfe, 0x83, 0x27,
+       0xc4, 0xfe, 0x85, 0x8b, 0x81, 0x27, 0xf5, 0xd3, 0x83, 0x37, 0x04, 0xfd,
+       0x93, 0x87, 0x47, 0x02, 0x37, 0x07, 0x02, 0x13, 0x09, 0x07, 0x98, 0xc3,
+       0x83, 0x37, 0x04, 0xfd, 0x93, 0x87, 0x47, 0x02, 0x37, 0x07, 0x02, 0x13,
+       0x05, 0x07, 0x98, 0xc3, 0x01, 0x00, 0xe6, 0x60, 0x46, 0x64, 0x25, 0x61,
+       0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x6f, 0x6e, 0x65,
+       0x0a, 0x00, 0x00, 0x00, 0x41, 0x44, 0x44, 0x52, 0x5b, 0x30, 0x78, 0x25,
+       0x78, 0x5d, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x25, 0x78, 0x0a, 0x0d, 0x00
+};
+
+#endif /* _DDR_INIT_FPGA_H_ */
diff --git a/drivers/ddr/spacemit/k1x/lpddr4_silicon_init.c b/drivers/ddr/spacemit/k1x/lpddr4_silicon_init.c
new file mode 100644 (file)
index 0000000..c41ab53
--- /dev/null
@@ -0,0 +1,1085 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Spacemit
+ */
+
+#ifdef CONFIG_K1_X_BOARD_ASIC
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <div64.h>
+#include <fdtdec.h>
+#include <init.h>
+#include <log.h>
+#include <ram.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/sizes.h>
+#include "ddr_init_asic.h"
+#include <mapmem.h>
+#include <u-boot/crc.h>
+#include "ddr_freq.h"
+
+#define BOOT_PP                0
+#define PMUA_REG_BASE  0xd4282800
+#define PMUA_MCK_CTRL  (PMUA_REG_BASE + 0xe8)
+#define PMUA_MC_HW_SLP_TYPE    (PMUA_REG_BASE + 0xb0)
+#define REG32(x)       (*((volatile uint32_t *)((uintptr_t)(x))))
+
+#define LOGLEVEL 0
+#if (LOGLEVEL > 0)
+#define LogMsg(level, format, args...) \
+       do { \
+               if (level < LOGLEVEL) \
+                       printf(format, ##args); \
+       } while (0)
+#else
+#define LogMsg(level, format, args...)
+#endif
+
+extern u32 ddr_cs_num;
+extern u32 ddr_get_mr8(void);
+extern uint32_t get_manufacture_id(void);
+extern uint32_t get_ddr_rev_id(void);
+
+struct addrmap_info {
+       u32 io_width_per_channel;
+       u32 density_per_channel;
+       u32 bank_num;
+       u32 row_num;
+       u32 col_num;
+};
+
+static const struct addrmap_info ddr_addrmap[] = {
+       {IO_X16, DDR_1Gb , BANK_8, ROW_13, COL_10},
+       {IO_X16, DDR_2Gb , BANK_8, ROW_14, COL_10},
+       {IO_X16, DDR_3Gb , BANK_8, ROW_15, COL_10},
+       {IO_X16, DDR_4Gb , BANK_8, ROW_15, COL_10},
+       {IO_X16, DDR_6Gb , BANK_8, ROW_16, COL_10},
+       {IO_X16, DDR_8Gb , BANK_8, ROW_16, COL_10},
+       {IO_X16, DDR_12Gb, BANK_8, ROW_17, COL_10},
+       {IO_X16, DDR_16Gb, BANK_8, ROW_17, COL_10},
+       {IO_X8 , DDR_1Gb , BANK_8, ROW_14, COL_10},
+       {IO_X8 , DDR_2Gb , BANK_8, ROW_15, COL_10},
+       {IO_X8 , DDR_3Gb , BANK_8, ROW_16, COL_10},
+       {IO_X8 , DDR_4Gb , BANK_8, ROW_16, COL_10},
+       {IO_X8 , DDR_6Gb , BANK_8, ROW_17, COL_10},
+       {IO_X8 , DDR_8Gb , BANK_8, ROW_17, COL_10},
+       {IO_X8 , DDR_12Gb, BANK_8, ROW_18, COL_10},
+       {IO_X8 , DDR_16Gb, BANK_8, ROW_18, COL_10},
+};
+
+void enable_PLL(void)
+{
+       unsigned read_data = 0;
+       REG32(0xd4282800 + 0x3b4) &= 0xFFFFFCFF;
+       REG32(0xd4282800 + 0x3b4) |= (0x1 << 11) | (0x1 << 8) | (0x1 << 9);
+
+       /* wait pll stable */
+       read_data = REG32(0xd4282800 + 0x3b4);
+       while ((read_data & 0x30000) != 0x30000) {
+               read_data = REG32(0xd4282800 + 0x3b4);
+
+       }
+
+       return;
+}
+
+void ddr_dfc(unsigned freqNo)
+{
+       unsigned read_data;
+
+       REG32(0xd4282800 + 0x098) |= 0x10;
+       REG32(0xc0000000 + 0x148) = 0x80ac0000;
+       switch (freqNo) {
+       case 0:
+               LogMsg(0, "change to 1200 \n");
+               REG32(0xd4282800 + 0x3b4) = 0x00003B50;
+               REG32(0xd4282800 + 0x0b0) =
+                       (1 << TOP_DDRPHY0_EN_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_RST_OFFSET) |
+                       (1 << TOP_FREQ_PLL_CHG_MODE_OFFSET) |
+                       (0x0 << TOP_MC_REQ_TABLE_NUM_OFFSET);
+               break;
+
+       case 1:
+               LogMsg(0, "change to 1600 \n");
+               REG32(0xd4282800 + 0x3b4) = 0x00003B04;
+               REG32(0xd4282800 + 0x0b0) =
+                       (1 << TOP_DDRPHY0_EN_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_RST_OFFSET) |
+                       (1 << TOP_FREQ_PLL_CHG_MODE_OFFSET) |
+                       (0x1 << TOP_MC_REQ_TABLE_NUM_OFFSET);
+               break;
+
+       case 2:
+               LogMsg(0, "change to 2400 \n");
+               REG32(0xd4282800 + 0x3b4) = 0x00003b40;
+               REG32(0xd4282800 + 0x0b0) =
+                       (1 << TOP_DDRPHY0_EN_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_RST_OFFSET) |
+                       (1 << TOP_FREQ_PLL_CHG_MODE_OFFSET) |
+                       (0x2 << TOP_MC_REQ_TABLE_NUM_OFFSET);
+               break;
+
+       case 3:
+               LogMsg(0, "change to 3200 \n");
+               REG32(0xd4282800 + 0x3b4) = 0x00003b00;
+               REG32(0xd4282800 + 0x0b0) =
+                       (1 << TOP_DDRPHY0_EN_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_RST_OFFSET) |
+                       (1 << TOP_FREQ_PLL_CHG_MODE_OFFSET) |
+                       (0x3 << TOP_MC_REQ_TABLE_NUM_OFFSET);
+               break;
+
+       case 4:
+               LogMsg(0, "change to ext clock\n");
+               REG32(0xd4282800 + 0x3b4) = 0x00003b02;
+               REG32(0xd4282800 + 0x0b0) =
+                       (1 << TOP_DDRPHY0_EN_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_RST_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_CLK_EN_OFFSET) |
+                       (1 << TOP_DCLK_BYPASS_DIV_OFFSET);
+               break;
+
+       default:
+               LogMsg(0, "no this case\n");
+               break;
+       }
+
+       REG32(0xd4282800 + 0x004) = (0x1 << TOP_DDR_FREQ_CHG_REQ);
+       read_data = REG32(0xd4282800 + 0x004);
+       while ((read_data & 0x400000) != 0x0) {
+               read_data = REG32(0xd4282800 + 0x004);
+       }
+       LogMsg(0, "frequency change done!!!! \n");
+
+       return;
+}
+
+void mck6_sw_fc_top(unsigned freqNo)
+{
+       unsigned read_data;
+
+       switch (freqNo) {
+       case 0:
+               /* 1200MT */
+               REG32(0xd4282800 + 0x3b4) = 0x00003B50;
+               break;
+
+       case 1:
+               /* 1600MT */
+               REG32(0xd4282800 + 0x3b4) = 0x00003B04;
+               break;
+
+       case 2:
+               /* 2400MT */
+               REG32(0xd4282800 + 0x3b4) = 0x00003B40;
+               break;
+
+       case 3:
+               /* 3200MT */
+               REG32(0xd4282800 + 0x3b4) = 0x00003B00;
+               break;
+
+       case 4:
+               LogMsg(0, "sw frequency change to ext clk!!!! \n");
+               REG32(0xd4282800 + 0x3b4) = 0x00003B02;
+               LogMsg(0, "sw frequency change to ext clk done!!!! \n");
+               break;
+
+       default:
+               LogMsg(0, "not support frequency change !!!! \n");
+               return;
+
+       }
+
+       REG32(0xd4282800 + 0x0b0) = 0x40600400;
+       REG32(0xd4282800 + 0x004) = 0x04000000;
+       do {
+               read_data = REG32(0xd4282800 + 0x004);
+       } while ((read_data & 0x4000000) != 0x0);
+}
+
+void fp_timing_init(unsigned DDRC_BASE)
+{
+       unsigned int read_data=0;
+
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0104)= 0xF0800400;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0100)= 0x00000E20;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x010c)= 0x19194314;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0110)= 0x20440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0114)= 0x20440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x018c) = 0x00000030;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0190) = 0x06400030;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0194) = 0x80e001c0;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0198) = 0x01CC01CC;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x019c) = 0x00181818;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a0) = 0x08180C0C;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a4) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a8) = 0x00000217;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01ac) = 0x30651D44;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b0) = 0x1120080F;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b4) = 0x08001000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b8) = 0x00000C00;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01bc) = 0x02020404;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c0) = 0x10000004;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c4) = 0x00000006;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01d8) = 0x00010190;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x014c) = 0x000c4090;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03e4) = 0x15000A02;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03ec) = 0x0000046c;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0104)= 0xA0800400;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0100)= 0x00000C18;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x010c)= 0x9d194314;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0110)= 0x00440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0114)= 0x00440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x018c) = 0x00430000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0190) = 0x05350028;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0194) = 0x80A80151;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0198) = 0x017F017F;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x019c) = 0x00141414;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a0) = 0x07140A0A;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a4) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a8) = 0x00000213;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01ac) = 0x36541838;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b0) = 0x1c180a18;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b4) = 0x08000E00;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b8) = 0x00000E00;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01bc) = 0x02020404;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c0) = 0x10000004;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c4) = 0x00000004;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01d8) = 0x0000D94E;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x014c) = 0x0007204a;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03e4) = 0x13000802;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03ec) = 0x00000450;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0104)= 0x50800400;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0100)= 0x0000080e;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x010c)= 0x9d194314;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0110)= 0x00440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0114)= 0x00440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x018c) = 0x00280018;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0190) = 0x03200018;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0194) = 0x807000e0;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0198) = 0x00e600e6;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x019c) = 0x000c0c0c;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a0) = 0x050c0606;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a4) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a8) = 0x0000020c;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01ac) = 0x18330f22;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b0) = 0x110f080f;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b4) = 0x08000800;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b8) = 0x00000600;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01bc) = 0x02020404;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c0) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c4) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01d8) = 0x00008190;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x014c) = 0x00030848;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03e4) = 0x0a000402;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03ec) = 0x00000480;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0104)= 0x00800400;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0100)= 0x0000080e;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x010c)= 0x9d194314;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0110)= 0x00440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0114)= 0x00440000;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x018c) = 0x00280018;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0190) = 0x03200018;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0194) = 0x805400A8;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0198) = 0x00e600e6;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x019c) = 0x000c0c0c;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a0) = 0x050c0606;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a4) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01a8) = 0x0000020c;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01ac) = 0x18330f22;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b0) = 0x110f080f;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b4) = 0x08000800;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01b8) = 0x00000600;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01bc) = 0x02020404;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c0) = 0x00000002;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01c4) = 0x00000003;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x01d8) = 0x00008190;
+       REG32(DDRC_BASE+MC_CH0_BASE+0x014c) = 0x00030848;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03e4) = 0x0a000402;
+       REG32(DDRC_BASE+MC_CH0_PHY_BASE+0x03ec) = 0x00000480;
+
+       read_data=REG32(DDRC_BASE+MC_CH0_BASE+0x0108);
+       read_data &= 0xF00FFFFF;
+       read_data |= (0x10<<20);
+       REG32(DDRC_BASE+MC_CH0_BASE+0x0108)=read_data;
+
+       return;
+}
+
+void fp_sel(unsigned DDRC_BASE,unsigned int fp)
+{
+       uint32_t data;
+       data = REG32(DDRC_BASE + MC_CH0_BASE + 0x0104);
+       data &= ~(0xf << 28);
+       data |= (fp << 28) | (fp << 30);
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0104) = data;
+       LogMsg(0, "ADDR[0x%08x]=0x%08x !!!! \n", (DDRC_BASE + MC_CH0_BASE + 0x104), REG32(DDRC_BASE + MC_CH0_BASE + 0x104));
+
+       return;
+}
+
+void init_table_mc_tim (uint32_t ddrc_base, uint32_t *idx) {
+        uint32_t i;
+        uint32_t read_data;
+        uint32_t mc_ch0_phy_base = 0x1000;
+        volatile unsigned addrs[ ] = {
+                MC_CH0_BASE+0x0100,
+                MC_CH0_BASE+0x010c,
+                MC_CH0_BASE+0x0110,
+                MC_CH0_BASE+0x0114,
+                MC_CH0_BASE+0x018c,
+                MC_CH0_BASE+0x0190,
+                MC_CH0_BASE+0x0194,
+                MC_CH0_BASE+0x0198,
+                MC_CH0_BASE+0x019c,
+                MC_CH0_BASE+0x01a0,
+                MC_CH0_BASE+0x01a4,
+                MC_CH0_BASE+0x01a8,
+                MC_CH0_BASE+0x01ac,
+                MC_CH0_BASE+0x01b0,
+                MC_CH0_BASE+0x01b4,
+                MC_CH0_BASE+0x01b8,
+                MC_CH0_BASE+0x01bc,
+                MC_CH0_BASE+0x01c0,
+                MC_CH0_BASE+0x01c4,
+                MC_CH0_BASE+0x0200,
+                MC_CH0_BASE+0x01d8,
+                MC_CH0_BASE+0x014c,
+                mc_ch0_phy_base+0x03e4,
+                mc_ch0_phy_base+0x03ec
+        };
+        uint32_t tim_size = sizeof(addrs)>>2;
+
+        for(i=0;i<tim_size;i++) {
+                read_data = REG32(ddrc_base + addrs[i]);
+                REG32(ddrc_base + 0x0074) = read_data;
+                REG32(ddrc_base + 0x0078) = addrs[i];
+                REG32(ddrc_base + 0x0070) = (*idx)++;
+        }
+}
+
+
+void init_table_mc_a0(uint32_t ddrc_base)
+{
+       uint32_t idx = 0x200;
+       uint32_t i = 0;
+       volatile unsigned mc_cfg2_addr = MC_CH0_BASE + 0x0104;
+       uint32_t temp_data, mc_cfg2_org, mc_cfg2_fp, mc_ctl0_org;
+       volatile unsigned addrs[] = {
+               0x0048,
+               0x0054,
+               0x0058,
+               0x0060,
+               0x0064,
+               0x0148,
+               0x014c,
+               MC_CH0_BASE + 0x0000,
+               MC_CH0_BASE + 0x0004,
+               MC_CH0_BASE + 0x0008,
+               MC_CH0_BASE + 0x000c,
+               MC_CH0_BASE + 0x0020,
+               MC_CH0_BASE + 0x0024,
+               MC_CH0_BASE + 0x00c4,
+               MC_CH0_BASE + 0x00c0,
+               MC_CH0_BASE + 0x0180,
+               MC_CH0_BASE + 0x0184,
+               MC_CH0_BASE + 0x0188,
+               0x80,
+               0xa00,
+               0xac0,
+               0xacc,
+       };
+
+       mc_ctl0_org = REG32(ddrc_base + 0x44);
+       temp_data = mc_ctl0_org | (BIT(2) | BIT(12));
+       REG32(ddrc_base + 0x74) = temp_data;
+       REG32(ddrc_base + 0x78) = 0x00000044 | (0x1 << 16);
+       REG32(ddrc_base + 0x70) = idx++;
+
+       uint32_t cfg_size = sizeof(addrs) >> 2;
+       for (i = 0; i < cfg_size; i++) {
+               temp_data = REG32(ddrc_base + addrs[i]);
+               REG32(ddrc_base + 0x74) = temp_data;
+               REG32(ddrc_base + 0x78) = addrs[i] & 0xffff;
+               REG32(ddrc_base + 0x70) = idx++;
+       }
+
+       mc_cfg2_org = REG32(ddrc_base + mc_cfg2_addr);
+       temp_data = mc_cfg2_org;
+       temp_data &= ~(0xf << 28);
+
+       mc_cfg2_fp = temp_data;
+       REG32(ddrc_base + mc_cfg2_addr) = mc_cfg2_fp;
+       REG32(ddrc_base + 0x0074) = mc_cfg2_fp;
+       REG32(ddrc_base + 0x0078) = mc_cfg2_addr;
+       REG32(ddrc_base + 0x0070) = idx++;
+       init_table_mc_tim(ddrc_base, &idx);
+
+       mc_cfg2_fp = temp_data | (0x5 << 28);
+       REG32(ddrc_base + mc_cfg2_addr) = mc_cfg2_fp;
+       mc_cfg2_fp &= ~(0x3 << 28);
+       REG32(ddrc_base + 0x0074) = mc_cfg2_fp;
+       REG32(ddrc_base + 0x0078) = mc_cfg2_addr;
+       REG32(ddrc_base + 0x0070) = idx++;
+       init_table_mc_tim(ddrc_base, &idx);
+
+       mc_cfg2_fp = temp_data | (0xa << 28);
+       REG32(ddrc_base + mc_cfg2_addr) = mc_cfg2_fp;
+       mc_cfg2_fp &= ~(0x3 << 28);
+       REG32(ddrc_base + 0x0074) = mc_cfg2_fp;
+       REG32(ddrc_base + 0x0078) = mc_cfg2_addr;
+       REG32(ddrc_base + 0x0070) = idx++;
+       init_table_mc_tim(ddrc_base, &idx);
+
+       mc_cfg2_fp = temp_data | (0xf << 28);
+       REG32(ddrc_base + mc_cfg2_addr) = mc_cfg2_fp;
+       mc_cfg2_fp &= ~(0x3 << 28);
+       REG32(ddrc_base + 0x0074) = mc_cfg2_fp;
+       REG32(ddrc_base + 0x0078) = mc_cfg2_addr;
+       REG32(ddrc_base + 0x0070) = idx++;
+       init_table_mc_tim(ddrc_base, &idx);
+
+       REG32(ddrc_base + 0x0074) = 0x00020200;
+       REG32(ddrc_base + 0x0078) = 0x000013e0;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x13000010;
+       REG32(ddrc_base + 0x0078) = 0x000013d0;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x00010000;
+       REG32(ddrc_base + 0x0078) = 0x000033fc;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x00010000;
+       REG32(ddrc_base + 0x0078) = 0x000033fc;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x13000008;
+       REG32(ddrc_base + 0x0078) = 0x00000020;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x13000004;
+       REG32(ddrc_base + 0x0078) = 0x00000020;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x13020000;
+       REG32(ddrc_base + 0x0078) = 0x00000028;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x13000001;
+       REG32(ddrc_base + 0x0078) = 0x000013d0;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x00008000;
+       REG32(ddrc_base + 0x0078) = 0x000033fc;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x00008000;
+       REG32(ddrc_base + 0x0078) = 0x000033fc;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x10000100;
+       REG32(ddrc_base + 0x0078) = 0x000013d0;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x00008000;
+       REG32(ddrc_base + 0x0078) = 0x000033fc;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x00008000;
+       REG32(ddrc_base + 0x0078) = 0x000033fc;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x1302000d;
+       REG32(ddrc_base + 0x0078) = 0x00000024;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = 0x13020003;
+       REG32(ddrc_base + 0x0078) = 0x00000024;
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x0074) = mc_ctl0_org;
+       REG32(ddrc_base + 0x0078) = 0x44 | (0x1 << 17);
+       REG32(ddrc_base + 0x0070) = idx++;
+
+       REG32(ddrc_base + 0x40000 + 0x10104) = 0x00001100;
+       REG32(ddrc_base + 0x40000 + 0x10108) = 0x00010000;
+       REG32(ddrc_base + 0x40000 + 0x10100) = 0x00000020;
+       REG32(ddrc_base + 0x40000 + 0x10104) = 0x000000ff;
+       REG32(ddrc_base + 0x40000 + 0x10108) = 0x0001001c;
+       REG32(ddrc_base + 0x40000 + 0x10100) = 0x00000021;
+       REG32(ddrc_base + 0x40000 + 0x10104) = 0x00000000;
+       REG32(ddrc_base + 0x40000 + 0x10108) = 0x0005001c;
+       REG32(ddrc_base + 0x40000 + 0x10100) = 0x00000022;
+       REG32(ddrc_base + mc_cfg2_addr) = mc_cfg2_org;
+}
+
+void ddr_dfc_table_init(unsigned int DDRC_BASE)
+{
+       REG32(DDRC_BASE + 0x74) = 0x00040303;
+       REG32(DDRC_BASE + 0x78) = 0x00000044;
+       REG32(DDRC_BASE + 0x70) = 0x00000000;
+       REG32(DDRC_BASE + 0x74) = 0x13000008;
+       REG32(DDRC_BASE + 0x78) = 0x00000020;
+       REG32(DDRC_BASE + 0x70) = 0x00000001;
+       REG32(DDRC_BASE + 0x74) = 0x13010000;
+       REG32(DDRC_BASE + 0x78) = 0x00000028;
+       REG32(DDRC_BASE + 0x70) = 0x00000002;
+       REG32(DDRC_BASE + 0x74) = 0x1302000d;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000003;
+       REG32(DDRC_BASE + 0x74) = 0x13020001;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000004;
+       REG32(DDRC_BASE + 0x74) = 0x13020002;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000005;
+       REG32(DDRC_BASE + 0x74) = 0x13020003;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000006;
+       REG32(DDRC_BASE + 0x74) = 0x1302000b;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000007;
+       REG32(DDRC_BASE + 0x74) = 0x1302000c;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000008;
+       REG32(DDRC_BASE + 0x74) = 0x1302000e;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000009;
+       REG32(DDRC_BASE + 0x74) = 0x13020016;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x0000000a;
+       REG32(DDRC_BASE + 0x74) = 0x13008000;
+       REG32(DDRC_BASE + 0x78) = 0x00000028;
+       REG32(DDRC_BASE + 0x70) = 0x0000000b;
+       REG32(DDRC_BASE + 0x74) = 0x1302000d;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x0000000c;
+       REG32(DDRC_BASE + 0x74) = 0x13000010;
+       REG32(DDRC_BASE + 0x78) = 0x00000020;
+       REG32(DDRC_BASE + 0x70) = 0x0000000d;
+       REG32(DDRC_BASE + 0x74) = 0x00000002;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x0000000e;
+       REG32(DDRC_BASE + 0x74) = 0x00000002;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x0000000f;
+       REG32(DDRC_BASE + 0x74) = 0x13000001;
+       REG32(DDRC_BASE + 0x78) = 0x000013d0;
+       REG32(DDRC_BASE + 0x70) = 0x00000010;
+       REG32(DDRC_BASE + 0x74) = 0x00008000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000011;
+       REG32(DDRC_BASE + 0x74) = 0x00000000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000012;
+       REG32(DDRC_BASE + 0x74) = 0x00040303;
+       REG32(DDRC_BASE + 0x78) = 0x00010044;
+       REG32(DDRC_BASE + 0x70) = 0x00000013;
+       REG32(DDRC_BASE + 0x74) = 0x10000100;
+       REG32(DDRC_BASE + 0x78) = 0x000013d0;
+       REG32(DDRC_BASE + 0x70) = 0x00000014;
+       REG32(DDRC_BASE + 0x74) = 0x00008000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000015;
+       REG32(DDRC_BASE + 0x74) = 0x00008000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000016;
+       REG32(DDRC_BASE + 0x74) = 0x13000004;
+       REG32(DDRC_BASE + 0x78) = 0x00000020;
+       REG32(DDRC_BASE + 0x70) = 0x00000017;
+       REG32(DDRC_BASE + 0x74) = 0x1302000d;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x00000018;
+       REG32(DDRC_BASE + 0x74) = 0x00000002;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x00000019;
+       REG32(DDRC_BASE + 0x74) = 0x00000000;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x0000001a;
+       REG32(DDRC_BASE + 0x74) = 0x00040380;
+       REG32(DDRC_BASE + 0x78) = 0x00020044;
+       REG32(DDRC_BASE + 0x70) = 0x0000001b;
+       REG32(DDRC_BASE + 0x74) = 0x00040380;
+       REG32(DDRC_BASE + 0x78) = 0x00020044;
+       REG32(DDRC_BASE + 0x70) = 0x0000012e;
+       REG32(DDRC_BASE + 0x74) = 0x00040b43;
+       REG32(DDRC_BASE + 0x78) = 0x00000044;
+       REG32(DDRC_BASE + 0x70) = 0x00000180;
+       REG32(DDRC_BASE + 0x74) = 0x13000010;
+       REG32(DDRC_BASE + 0x78) = 0x00000020;
+       REG32(DDRC_BASE + 0x70) = 0x00000181;
+       REG32(DDRC_BASE + 0x74) = 0x00000002;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x00000182;
+       REG32(DDRC_BASE + 0x74) = 0x00000002;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x00000183;
+       REG32(DDRC_BASE + 0x74) = 0x13000001;
+       REG32(DDRC_BASE + 0x78) = 0x000013d0;
+       REG32(DDRC_BASE + 0x70) = 0x00000184;
+       REG32(DDRC_BASE + 0x74) = 0x00008000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000185;
+       REG32(DDRC_BASE + 0x74) = 0x00000000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000186;
+       REG32(DDRC_BASE + 0x74) = 0x00040b43;
+       REG32(DDRC_BASE + 0x78) = 0x00010044;
+       REG32(DDRC_BASE + 0x70) = 0x00000187;
+       REG32(DDRC_BASE + 0x74) = 0x10000100;
+       REG32(DDRC_BASE + 0x78) = 0x000013d0;
+       REG32(DDRC_BASE + 0x70) = 0x00000188;
+       REG32(DDRC_BASE + 0x74) = 0x00008000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x00000189;
+       REG32(DDRC_BASE + 0x74) = 0x00008000;
+       REG32(DDRC_BASE + 0x78) = 0x000033fc;
+       REG32(DDRC_BASE + 0x70) = 0x0000018a;
+       REG32(DDRC_BASE + 0x74) = 0x1302000d;
+       REG32(DDRC_BASE + 0x78) = 0x00000024;
+       REG32(DDRC_BASE + 0x70) = 0x0000018b;
+       REG32(DDRC_BASE + 0x74) = 0x00000002;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x0000018c;
+       REG32(DDRC_BASE + 0x74) = 0x00000000;
+       REG32(DDRC_BASE + 0x78) = 0x00002008;
+       REG32(DDRC_BASE + 0x70) = 0x0000018d;
+       REG32(DDRC_BASE + 0x74) = 0x00040b00;
+       REG32(DDRC_BASE + 0x78) = 0x00020044;
+       REG32(DDRC_BASE + 0x70) = 0x0000018e;
+}
+
+void top_DDR_MC_init(unsigned DDRC_BASE, unsigned int fp)
+{
+       REG32(DDRC_BASE + 0x44) = 0x00040300;
+       REG32(DDRC_BASE + 0x48) = 0x00000001;
+       REG32(DDRC_BASE + 0x64) = 0x100d0803;
+       REG32(DDRC_BASE + 0x50) = 0x000000ff;
+       REG32(DDRC_BASE + 0x58) = 0x3fd53fd5;
+       REG32(DDRC_BASE + 0x180) = 0x00010200;
+       REG32(DDRC_BASE + MC_CH0_BASE) = 0x100001;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x4) = 0x0;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x8) = 0x100001;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0xc) = 0x1;
+       REG32(DDRC_BASE + 0x0080) = 0x00000000;
+       REG32(DDRC_BASE + 0x0a00) = 0x00000000;
+       REG32(DDRC_BASE + 0x0ac0) = 0x00000000;
+       REG32(DDRC_BASE + 0x0acc) = 0xffffffff;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x20) = 0x05030732;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x24) = 0x05030732;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0xc0) = 0x14008000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0xc4) = 0x000000b8;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0xc8) = 0x0000FFFF;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0xcc) = 0x200;
+       fp_timing_init(DDRC_BASE);
+       fp_sel(DDRC_BASE, fp);
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0180) = 0x30D400;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0184) = 0x4E200;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0188) = 0xC800000;
+       REG32(DDRC_BASE + MC_CH0_PHY_BASE + 0x3E0) |= fp << 2;
+
+       return;
+}
+void top_DDR_wr_ds_odt_vref(unsigned DPHY0_BASE,unsigned combination)
+{
+       unsigned data = 0;
+       unsigned d_reg2 = 0;
+
+       data = REG32(DPHY0_BASE + COMMON_OFFSET + 0xc);
+       switch (combination) {
+       case 2:
+               d_reg2 = 0xd8;
+               data &= 0xFFFF00FF;
+               data |= (d_reg2 << 8);
+               REG32(DPHY0_BASE + COMMON_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0xc) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0xc) = data;
+
+               break;
+
+       default:
+               LogMsg(0, "not support.....\n");
+               break;
+       }
+}
+
+void top_DDR_rx_ds_odt_vref(unsigned DPHY0_BASE,unsigned combination)
+{
+       unsigned data = 0;
+       unsigned d_reg3 = 0;
+       unsigned rx_ref_d1 = 0x0, rx_ref_d2 = 0x0;
+
+       switch (combination) {
+       case 2:
+               data = REG32(DPHY0_BASE + COMMON_OFFSET + 0xc);
+               data &= 0xFF00FFFF;
+               d_reg3 = 0xE4;
+               data |= (d_reg3 << 16);
+               REG32(DPHY0_BASE + COMMON_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0xc) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0xc) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0xc) = data;
+
+               data = REG32(DPHY0_BASE + COMMON_OFFSET + 0x4);
+               data &= 0x0000FFFF;
+               rx_ref_d1 = 0x55;
+               rx_ref_d2 = 0x55;
+               data |= (rx_ref_d1 << 16) | (rx_ref_d2 << 24);
+               REG32(DPHY0_BASE + COMMON_OFFSET + 0x4) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x4) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x4) = data;
+               REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x4) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + 0x4) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x4) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x4) = data;
+               REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x4) = data;
+               break;
+
+       default:
+               LogMsg(0, "not support.....\n");
+               break;
+       }
+}
+
+void top_DDR_amble_config(unsigned DPHY0_BASE)
+{
+       unsigned data = 0;
+       data = REG32(DPHY0_BASE + COMMON_OFFSET + 0x4);
+       data &= 0xFFFF0FFF;
+       data |= (1 << 11) | (1 << 13) | (1 << 15);
+       REG32(DPHY0_BASE + COMMON_OFFSET + 0x4) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x4) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x4) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x4) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + 0x4) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x4) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x4) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x4) = data;
+
+       return;
+}
+
+void top_DDR_phy_init(unsigned DDRC_BASE,unsigned fp)
+{
+       unsigned DPHY0_BASE = DDRC_BASE + 0x040000;
+       unsigned data = 0;
+
+       REG32(0xd4282800 + 0x3A4) &= 0xFFFF00FF;
+       REG32(0xd4282800 + 0x3A4) |= (0xF << 8);
+       REG32(0xd4282800 + 0x398) |= (0x3 << 10);
+       REG32(DPHY0_BASE + COMMON_OFFSET) = 0x0;
+       REG32(DPHY0_BASE + COMMON_OFFSET + subPHY_B_OFFSET) = 0x0;
+       REG32(DPHY0_BASE + COMMON_OFFSET) = 0x1;
+       REG32(DPHY0_BASE + COMMON_OFFSET + subPHY_B_OFFSET) = 0x1;
+       REG32(DPHY0_BASE + 0x0064) = 0x4349;
+       REG32(DPHY0_BASE + FREQ_POINT_OFFSET + 0x0064) = 0x4349;
+       REG32(DPHY0_BASE + FREQ_POINT_OFFSET * 2 + 0x064) = 0x4349;
+       REG32(DPHY0_BASE + FREQ_POINT_OFFSET * 3 + 0x064) = 0x4349;
+       top_DDR_amble_config(DPHY0_BASE);
+       top_DDR_wr_ds_odt_vref(DPHY0_BASE, 2);
+       top_DDR_rx_ds_odt_vref(DPHY0_BASE, 2);
+
+       data = REG32(DPHY0_BASE + COMMON_OFFSET + 0x14);
+       data &= 0xFF9FFFEF;
+       data |= (0x3 << 21);
+       REG32(DPHY0_BASE + COMMON_OFFSET + 0x14) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + 0x14) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x14) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x14) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x14) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x14) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x14) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x14) = data;
+
+       data = REG32(DPHY0_BASE + COMMON_OFFSET + 0x10);
+       data |= 0x10000000;
+       REG32(DPHY0_BASE + COMMON_OFFSET + 0x10) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + 0x10) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x10) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET + 0x10) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x10) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 2 + 0x10) = data;
+       REG32(DPHY0_BASE + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x10) = data;
+       REG32(DPHY0_BASE + subPHY_B_OFFSET + COMMON_OFFSET + FREQ_POINT_OFFSET * 3 + 0x10) = data;
+
+       REG32(DPHY0_BASE + COMMON_OFFSET + 0x30) = 0x1077;
+       REG32(DPHY0_BASE + OTHER_CONTROL_OFFSET + 0x24) = 0x0;
+       REG32(DPHY0_BASE + OTHER_CONTROL_OFFSET) |= 0x1;
+
+       return;
+}
+
+void top_Common_config(void)
+{
+       REG32(0xd4282800 + 0x39c) &= 0xFFFF00FF;
+       REG32(0xd4282800 + 0x39c) |= (0x3B << 8);
+       enable_PLL();
+       mck6_sw_fc_top(BOOT_PP);
+       REG32(0xd42828e8) &= 0xFFFFFFFC;
+       REG32(0xd42828e8) |= 0x3;
+
+       return;
+}
+
+void top_DDR_MC_Phy_Device_Init(unsigned int DDRC_BASE,unsigned int cs_val,unsigned int fp)
+{
+       unsigned DFI_PHY_USER_COMMAND_0 = DDRC_BASE + 0x13D0;
+       __maybe_unused unsigned DPHY0_BASE = DDRC_BASE + 0x40000;
+       unsigned read_data = 0;
+       unsigned cs_num;
+
+       if (cs_val == 1) {
+               cs_num = 0x1;
+       } else {
+               cs_num = 0x3;
+       }
+
+       top_DDR_MC_init(DDRC_BASE, fp);
+       top_DDR_phy_init(DDRC_BASE, fp);
+
+       REG32(DFI_PHY_USER_COMMAND_0) = 0x13000001;
+       read_data = REG32(DDRC_BASE + MC_CH0_PHY_BASE + 0x3fc);
+       while ((read_data & 0x80000000) != 0x80000000) {
+               read_data = REG32(DDRC_BASE + MC_CH0_PHY_BASE + 0x3fc);
+       }
+       LogMsg(0, "PHY INIT done \n");
+
+       REG32(DFI_PHY_USER_COMMAND_0) = 0x13000100;
+       REG32(DDRC_BASE + 0x20) = (0x10000001 | (cs_num << 24));
+
+       LogMsg(0, "wait DRAM INIT \n");
+       read_data = REG32(DDRC_BASE + 0x8);
+       while ((read_data & 0x00000011) != 0x00011) {
+               read_data = REG32(DDRC_BASE + 0x8);
+       }
+       LogMsg(0, "DRAM INIT done \n");
+
+       REG32(DDRC_BASE + 0x24) = (0x10020001 | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x10020002 | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x1002000d | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x10020003 | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x10020016 | (cs_num << 24));
+
+       REG32(DDRC_BASE + 0x20) = 0x11002000;
+       REG32(DDRC_BASE + 0x20) = 0x11001000;
+       if (cs_val != 1) {
+               REG32(DDRC_BASE + 0x20) = 0x12002000;
+               REG32(DDRC_BASE + 0x20) = 0x12001000;
+       }
+
+       REG32(DDRC_BASE + 0x24) = (0x1002000C | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x1002000E | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x1002000B | (cs_num << 24));
+       REG32(DDRC_BASE + 0x24) = (0x10020017 | (cs_num << 24));
+       LogMsg(0, "DRAM Mode register Init done.....\n");
+
+       return;
+}
+
+void adjust_timing(u32 DDRC_BASE)
+{
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0104) = 0xF0800400;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0110)= 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0114)= 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x01b0) = 0x221D0C1D;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0104) = 0xA0800400;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0100) = 0x00000C1C;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0110)= 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0114)= 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE + MC_CH0_PHY_BASE + 0x03e4) = 0x13000802;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0104) = 0x50800400;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0110) = 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0114) = 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x01fc) = 0x000C005E;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0104) = 0x00800400;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0110) = 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x0114) = 0x40440000;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x01fc) = 0x000C005E;
+}
+
+void adjust_mapping(u32 DDRC_BASE, u32 cs_num, u32 size_mb, u32 mr8_value)
+{
+       u32 area_length_mb, area_length_cfg;
+       u32 cs1_start_addr_l, cs1_start_addr_h;
+       u32 io_width, density;
+       u32 i, read_data;
+       const struct addrmap_info *addrmap = &ddr_addrmap[13]; 
+
+       area_length_mb = size_mb / cs_num;
+       // area_length_mb = size_mb >> (cs_num -1);
+       switch (area_length_mb) {
+       case 1024: // 1GB
+               area_length_cfg = 0xE;
+               break;
+       case 2048: // 2GB
+               area_length_cfg = 0xF;
+               break;
+       case 4096: // 4GB
+               area_length_cfg = 0x10;
+               break;
+       case 8192: // 8GB
+               area_length_cfg = 0x11;
+               break;
+       case 16384: // 16GB
+               area_length_cfg = 0x12;
+               break;
+       default:
+               pr_err("do not support such area length =0x%x MB\n", area_length_mb);
+               area_length_cfg = 0x10;
+               break;
+       }
+
+       cs1_start_addr_l = ((area_length_mb >> 3) & 0x1FF);
+       cs1_start_addr_h = ((area_length_mb >> 12) & 0xFFFFFFFF);
+
+       io_width = (mr8_value >> 6);
+       density = (mr8_value >> 2) & 0xf;
+
+       for (i = 0; i < ARRAY_SIZE(ddr_addrmap); i++) {
+               if ((io_width == ddr_addrmap[i].io_width_per_channel) && (density == ddr_addrmap[i].density_per_channel) ) {
+                       addrmap = &ddr_addrmap[i];
+                       break;
+               }
+       }
+
+       read_data = REG32(DDRC_BASE + MC_CH0_BASE);
+       read_data &= 0x0060FFFF;
+       read_data |= (area_length_cfg << 16);
+       REG32(DDRC_BASE + MC_CH0_BASE) = read_data;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x4) = 0x0;
+
+       read_data = REG32(DDRC_BASE + MC_CH0_BASE + 0x8);
+       read_data &= 0x0060FFFF;
+       read_data |= (cs1_start_addr_l << 23) |(area_length_cfg << 16);
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x8) = read_data;
+       REG32(DDRC_BASE + MC_CH0_BASE + 0xc) = cs1_start_addr_h;
+
+       read_data = REG32(DDRC_BASE + MC_CH0_BASE + 0x20);
+       read_data &= 0xFFFFF00C;
+       read_data |= (addrmap->row_num << 8) | (addrmap->col_num << 4) | (addrmap->bank_num);
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x20) = read_data;
+
+       read_data = REG32(DDRC_BASE + MC_CH0_BASE + 0x24);
+       read_data &= 0xFFFFF00C;
+       read_data |= (addrmap->row_num << 8) | (addrmap->col_num << 4) | (addrmap->bank_num);
+       REG32(DDRC_BASE + MC_CH0_BASE + 0x24) = read_data;
+
+//     REG32(DDRC_BASE + MC_CH0_BASE) = 0xf0001;
+//     REG32(DDRC_BASE + MC_CH0_BASE + 0x4) = 0x0;
+//     REG32(DDRC_BASE + MC_CH0_BASE + 0x8) = 0x800f0001;
+//     REG32(DDRC_BASE + MC_CH0_BASE + 0xc) = 0x0;
+//     REG32(DDRC_BASE + MC_CH0_BASE + 0x20) = 0x05030632;//8 bank, 17 row, 10 column
+//     REG32(DDRC_BASE + MC_CH0_BASE + 0x24) = 0x05030632;//8 bank, 17 row, 10 column
+
+       LogMsg("DEBUG-ADDR[0x%x]:0x%x\n", (DDRC_BASE + MC_CH0_BASE), REG32(DDRC_BASE + MC_CH0_BASE));
+       LogMsg("DEBUG-ADDR[0x%x]:0x%x\n", (DDRC_BASE + MC_CH0_BASE + 0x4), REG32(DDRC_BASE + MC_CH0_BASE + 0x4));
+       LogMsg("DEBUG-ADDR[0x%x]:0x%x\n", (DDRC_BASE + MC_CH0_BASE + 0x8), REG32(DDRC_BASE + MC_CH0_BASE + 0x8));
+       LogMsg("DEBUG-ADDR[0x%x]:0x%x\n", (DDRC_BASE + MC_CH0_BASE + 0xc), REG32(DDRC_BASE + MC_CH0_BASE + 0xc));
+       LogMsg("DEBUG-ADDR[0x%x]:0x%x\n", (DDRC_BASE + MC_CH0_BASE + 0x20), REG32(DDRC_BASE + MC_CH0_BASE + 0x20));
+       LogMsg("DEBUG-ADDR[0x%x]:0x%x\n", (DDRC_BASE + MC_CH0_BASE + 0x24), REG32(DDRC_BASE + MC_CH0_BASE + 0x24));
+}
+__maybe_unused static int printf_no_output(const char *fmt, ...)
+{
+        return 0;
+}
+
+static void top_training_fp_all(u32 ddr_base, u32 cs_num, u32 boot_pp, void *input)
+{
+       u64 to_traning_param[10];
+       int (*func)(const char*, ...) = printf;
+       void (*training)(void* param);
+       unsigned long flush_lenth;
+
+       #if !(LOGLEVEL > 0)
+       func = printf_no_output;
+       #endif
+
+       to_traning_param[0] = ddr_base;
+       to_traning_param[1] = cs_num;
+       to_traning_param[2] = boot_pp;
+       to_traning_param[3] = (u64)func;
+       to_traning_param[4] = (u64)input;
+       memcpy((void*)DDR_TRAINING_DATA_BASE, lpddr4_training_img, sizeof(lpddr4_training_img));
+       flush_lenth = round_up(sizeof(lpddr4_training_img), CONFIG_RISCV_CBOM_BLOCK_SIZE);
+       flush_dcache_range(DDR_TRAINING_DATA_BASE, DDR_TRAINING_DATA_BASE + flush_lenth);
+
+       training = (void (*)(void * param))DDR_TRAINING_DATA_BASE;
+       training(to_traning_param);
+}
+
+void lpddr4_silicon_init(u32 ddr_base, u32 data_rate)
+{
+       u32 fp=0;
+       u32 size_mb, mr8_value, cs_num;;
+       struct ddr_training_info_t *info;
+
+       cs_num = ddr_cs_num;
+       info = (struct ddr_training_info_t*)map_sysmem(DDR_TRAINING_INFO_BUFF, 0);
+       top_Common_config();
+
+       top_DDR_MC_Phy_Device_Init(ddr_base, cs_num, 0);
+
+       size_mb = ddr_get_density();
+       mr8_value = ddr_get_mr8();
+       adjust_mapping(ddr_base, cs_num, size_mb, mr8_value);
+       LogMsg(0,"ddr density: %u MB \n", size_mb);
+
+       ddr_dfc_table_init(0xF0000000);
+       init_table_mc_a0(0xF0000000);
+
+       top_training_fp_all(ddr_base, cs_num, 0, info->para);
+
+       fp=1;
+       ddr_dfc(fp);
+       top_training_fp_all(ddr_base, cs_num, fp, info->para);
+
+       fp=2;
+       ddr_dfc(fp);
+       top_training_fp_all(ddr_base, cs_num, fp, info->para);
+
+       /* change dram frequency */
+       switch(data_rate) {
+       case 1600:
+               ddr_dfc(1);
+               break;
+
+       case 2400:
+               ddr_dfc(2);
+               break;
+
+       case 1200:
+       default:
+               data_rate = 1200;
+               ddr_dfc(0);
+               break;
+       }
+
+       return;
+}
+
+#endif
+
index 0af5460421193b035215ffc693890d72f8e60afe..f68c5fdebead149819eaa2b11c0890015cefb868 100644 (file)
@@ -76,6 +76,13 @@ config XILINX_DPDMA
          this file is used as placeholder for driver. The main reason is
          to record compatible string and calling power domain driver.
 
+config AXI_DMA
+       bool "Support DW_AXI DMA"
+       depends on DMA
+       select DMA_LEGACY
+       help
+         Enable dw_axi_dma driver
+
 if APBH_DMA
 config APBH_DMA_BURST
        bool "Enable DMA BURST"
index a75572fe5dec31073363f09dbae4ee4bf4b3fdf5..9626118b962e13250ad15224f428bfd7338abac5 100644 (file)
@@ -14,5 +14,6 @@ obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
 obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o
 obj-$(CONFIG_XILINX_DPDMA) += xilinx_dpdma.o
+obj-$(CONFIG_AXI_DMA) += axi-dma.o
 
 obj-y += ti/
diff --git a/drivers/dma/axi-dma.c b/drivers/dma/axi-dma.c
new file mode 100644 (file)
index 0000000..19c406a
--- /dev/null
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+
+#include<malloc.h>
+#include<common.h>
+#include<dma.h>
+#include<dma-uclass.h>
+#include<cpu_func.h>
+#include<asm/io.h>
+#include<dm/device.h>
+#include<dm.h>
+#include<dm/ofnode.h>
+#include<dm/uclass.h>
+#include<linux/kernel.h>
+#include"axi-dma.h"
+
+static int axi_dma_transfer(struct udevice *dev,int direction,void *dst,void *src,size_t len)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dev);
+       struct axi_dma_chan *uc = ud->axi_chan[0];
+
+       u32 data_width,burst_axi_len,burst_len;
+       u32 reg = 0;
+       u64 block_ts;
+       data_width = DEF_WIDTH;
+       burst_len = DWAXIDMAC_BURST_TRANS_LEN_4;
+
+       block_ts = len>>data_width;
+       if(block_ts >= ud->max_block_ts) {
+               block_ts = ud->max_block_ts;
+               printf("transfer size too large\n");
+       }
+
+       /*write dma_chan_ctl register*/
+       reg = CH_CTL_H_LLI_VALID|CH_CTL_H_LLI_LAST;
+       burst_axi_len = DEF_AXI_BURST_LEN;
+       reg |= (CH_CTL_H_ARLEN_EN |
+               burst_axi_len << CH_CTL_H_ARLEN_POS |
+               CH_CTL_H_AWLEN_EN |
+               burst_axi_len << CH_CTL_H_AWLEN_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->ctl_hi);
+       reg = (burst_len << CH_CTL_L_DST_MSIZE_POS |
+               burst_len << CH_CTL_L_SRC_MSIZE_POS |
+               data_width << CH_CTL_L_DST_WIDTH_POS |
+               data_width << CH_CTL_L_SRC_WIDTH_POS |
+               DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
+               DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->ctl_lo);
+
+       /*write dma_chan_cfg register*/
+       reg = (DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC << CH_CFG_H_TT_FC_POS |
+                       DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_DST_POS |
+                       DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_SRC_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->cfg_hi);
+
+       /*write dma sar,dar,block_ts*/
+       writeq((u64)src,(volatile void __iomem*)&uc->regs->sar);
+       writeq((u64)dst,(volatile void __iomem*)&uc->regs->dar);
+       writeq(block_ts-1,(volatile void __iomem*)&uc->regs->block_ts);
+       return 0;
+}
+
+static int axi_dma_of_xlate(struct dma *dma,struct ofnode_phandle_args *args)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc;
+
+       dma->id = args->args[0];
+       uc = ud->axi_chan[dma->id];
+       uc->config->hs_if = args->args[1];
+       uc->config->burst_len = args->args[2];
+       return 0;
+}
+
+static int axi_dma_enable(struct dma* dma)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc = ud->axi_chan[dma->id];
+       u32 val;
+
+       if(uc->status == UNUSED)
+               printf("channel %ld has nothing to transfer\n",dma->id);
+       writel(0,&uc->regs->int_en);
+       val = readl(ud->iorebase+DMAC_CHEN);
+       val |= BIT(dma->id);
+       val |= BIT(dma->id)<<DMAC_CHAN_EN_WE_SHIFT;
+       writel(val,ud->iorebase+DMAC_CHEN);
+       while(1) {
+               val = readl(ud->iorebase+DMAC_CHEN);
+               if(val&&BIT(dma->id) == 0){
+                       uc->status = UNUSED;
+                       printf("dma_transfer complete\n");
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int axi_dma_disable(struct dma* dma)
+{
+       u32 val;
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+
+       /*disable dma_channel*/
+       val = readl(ud->iorebase+DMAC_CHAN_EN_SHIFT);
+       val &= ~BIT(dma->id);
+       val |= BIT(dma->id)<<DMAC_CHAN_EN_WE_SHIFT;
+       writel(val,ud->iorebase+DMAC_CHAN_EN_SHIFT);
+
+       /*disable dma*/
+       val = readl(ud->iorebase+DMAC_CFG);
+       val &= ~DMAC_EN_MASK;
+       writel(val,ud->iorebase+DMAC_CFG);
+       return 0;
+}
+
+static int axi_dma_alloc_chan(struct axi_dma_dev *ud)
+{
+       int i;
+
+       /*find a idle chan*/
+       for(i = 1;i < DMA_CHAN_NUM;i++) {
+               if(ud->axi_chan[i]->status == UNUSED) {
+                       ud->axi_chan[i]->status = USED;
+                       return i;
+               }
+       }
+       return 0;
+}
+static int axi_dma_request(struct dma *dma)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc = ud->axi_chan[dma->id];
+
+       /*alloc chan0 for memcpy*/
+       if(dma->id == 0) {
+               if(uc->status == UNUSED) {
+                       printf("channel %ld is ready\n",dma->id);
+                       uc->status = USED;
+                       return 0;
+               }
+               else {
+                       printf("channel %ld is busy\n",dma->id);
+                       return -1;
+               }
+       }
+       else {
+               /*alloc requested channel ,if busy ,return another*/
+               if(uc->status == UNUSED) {
+                       printf("channel %ld is ready\n",dma->id);
+                       uc->status = USED;
+                       return 0;
+               }
+               else {
+                       int i = axi_dma_alloc_chan(ud);
+                       if(dma->id > 0) {
+                               printf("channel %ld is busy,change to channel %d\n",dma->id,i);
+                               dma->id = (u64)i;
+                               return 0;
+                       }
+                       else
+                               printf("all chan busy\n");
+               }
+       }
+       return -1;
+}
+
+static int axi_dma_rfree(struct dma* dma)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc = ud->axi_chan[dma->id];
+
+       u32 val;
+       /*disable dma_chan set use flag to unused*/
+       writel(0,(volatile void __iomem*)&uc->regs->int_en);
+       val = readl(ud->iorebase+DMAC_CHAN_EN_SHIFT);
+       val &= ~BIT(dma->id);
+       val |= BIT(dma->id)<<DMAC_CHAN_EN_WE_SHIFT;
+       writel(val,(volatile void __iomem*)ud->iorebase+DMAC_CHAN_EN_SHIFT);
+       uc->status = UNUSED;
+
+       return 0;
+}
+
+static int axi_dma_send(struct dma* dma,void *src,size_t len,void *metadata)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc = ud->axi_chan[dma->id];
+       u32 data_width,burst_len,burst_axi_len;
+       u32 reg = 0;
+       u64 block_ts;
+       data_width = DEF_WIDTH;
+       block_ts = len>>data_width;
+
+       if(uc->status!=USED)
+               return -1;
+
+       /*write back data in tx_buffer*/
+       flush_cache((u64)src,len);
+       block_ts = len>>data_width;
+       if(block_ts >= ud->max_block_ts) {
+               block_ts = ud->max_block_ts;
+               printf("transfer size too large\n");
+       }
+
+       /*write dma_chan_ctl register*/
+       if(!uc->config->burst_len)
+               burst_len = DWAXIDMAC_BURST_TRANS_LEN_4;
+       else
+               burst_len = uc->config->burst_len;
+       reg = CH_CTL_H_LLI_VALID|CH_CTL_H_LLI_LAST;
+       reg |= (CH_CTL_H_ARLEN_EN |
+                       burst_axi_len << CH_CTL_H_ARLEN_POS |
+                       CH_CTL_H_AWLEN_EN |
+                       burst_axi_len << CH_CTL_H_AWLEN_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->ctl_hi);
+       reg = (burst_len << CH_CTL_L_DST_MSIZE_POS |
+                       burst_len << CH_CTL_L_SRC_MSIZE_POS |
+                       data_width << CH_CTL_L_DST_WIDTH_POS |
+                       data_width << CH_CTL_L_SRC_WIDTH_POS |
+                       DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
+                       DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->ctl_lo);
+
+       /*write dma_chan_cfg register*/
+       reg = (DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC << CH_CFG_H_TT_FC_POS |
+                       DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_DST_POS |
+                       DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_SRC_POS) |
+                       uc->config->hs_if << CH_CFG2_L_DST_PER_POS;
+       writel(reg,(volatile void __iomem*)&uc->regs->cfg_hi);
+
+       /*write dma sar,dar,block_ts*/
+       writeq((u64)src,(volatile void __iomem*)&uc->regs->sar);
+       writeq((u64)metadata,(volatile void __iomem*)&uc->regs->dar);
+       writeq(block_ts-1,(volatile void __iomem*)&uc->regs->block_ts);
+
+       return 0;
+}
+
+static int axi_dma_receive(struct dma *dma, void **dst,void *metadata)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc = ud->axi_chan[dma->id];
+       u32 data_width,burst_len,burst_axi_len,len;
+       u32 reg = 0;
+       u64 block_ts;
+       data_width = DEF_WIDTH;
+
+       len = uc->info->buf_len;
+       *dst = (void*)uc->info->address;
+       u64 dar = (u64)*dst;
+       if(uc->status!=USED)
+               return -1;
+
+       /*invalid receive buffer cache*/
+       invalidate_dcache_range(dar,dar+len);
+       block_ts = len>>data_width;
+       if(block_ts >= ud->max_block_ts) {
+               block_ts = ud->max_block_ts;
+               printf("transfer size too large\n");
+       }
+
+       /*write dma_chan_ctl register*/
+       if(!uc->config->burst_len)
+               burst_len = DWAXIDMAC_BURST_TRANS_LEN_4;
+       else
+               burst_len = uc->config->burst_len;
+       reg = CH_CTL_H_LLI_VALID|CH_CTL_H_LLI_LAST;
+       reg |= (CH_CTL_H_ARLEN_EN |
+                       burst_axi_len << CH_CTL_H_ARLEN_POS |
+                       CH_CTL_H_AWLEN_EN |
+                       burst_axi_len << CH_CTL_H_AWLEN_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->ctl_hi);
+       reg = (burst_len << CH_CTL_L_DST_MSIZE_POS |
+                       burst_len << CH_CTL_L_SRC_MSIZE_POS |
+                       data_width << CH_CTL_L_DST_WIDTH_POS |
+                       data_width << CH_CTL_L_SRC_WIDTH_POS |
+                       DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
+                       DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
+       writel(reg,(volatile void __iomem*)&uc->regs->ctl_lo);
+
+       /*write dma_chan_cfg register*/
+       reg = (DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC << CH_CFG_H_TT_FC_POS |
+                       DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_DST_POS |
+                       DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_SRC_POS) |
+                       uc->config->hs_if << CH_CFG2_L_SRC_PER_POS;
+       writel(reg,(volatile void __iomem*)&uc->regs->cfg_hi);
+
+       /*write dma sar,dar,block_ts*/
+       writeq((u64)metadata,(volatile void __iomem*)&uc->regs->sar);
+       writeq(dar,(volatile void __iomem*)&uc->regs->dar);
+       writeq(block_ts-1,(volatile void __iomem*)&uc->regs->block_ts);
+
+       return 0;
+}
+
+static int axi_dma_prepare_rcv_buf(struct dma *dma,void *dst,size_t size)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dma->dev);
+       struct axi_dma_chan *uc = ud->axi_chan[dma->id];
+
+       /*record info of rcv_buf*/
+       uc->info->address = (u64)dst;
+       uc->info->type = RX;
+       uc->info->buf_len = size;
+
+       /*invalid receive buffer cache*/
+       invalidate_dcache_range((u64)dst,(u64)(dst+size));
+
+       return 0;
+}
+
+static const struct dma_ops axi_dma_ops={
+       .transfer = axi_dma_transfer,
+       .of_xlate = axi_dma_of_xlate,
+       .request = axi_dma_request,
+       .rfree = axi_dma_rfree,
+       .enable = axi_dma_enable,
+       .disable = axi_dma_disable,
+       .send = axi_dma_send,
+       .receive = axi_dma_receive,
+       .prepare_rcv_buf = axi_dma_prepare_rcv_buf,
+};
+
+#define CHAN_REG_SHIFT 0x100
+
+static int axi_dma_probe(struct udevice *dev)
+{
+       struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct axi_dma_dev *ud = dev_get_priv(dev);
+       u32 val = 0;
+       u32 i,ret;
+
+       ud->iorebase = dev_read_addr_ptr(dev);
+       ud->max_block_ts = dev_read_u32_default(dev,"max_block_ts",0x400000);
+       ud->n_channels = dev_read_u32_default(dev,"dma-channels",8);
+
+       ret = reset_get_by_index(dev, 0, &ud->reset);
+       if (ret)
+               return ret;
+       ret = reset_deassert(&ud->reset);
+       if (ret) {
+               pr_err("Failed to de-assert reset for DMA (error %d)\n",ret);
+               return ret; 
+       }
+
+       ret = clk_get_by_index(dev,0,&ud->clk);
+       if(ret)
+               return ret;
+       ret = clk_enable(&ud->clk);
+       if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
+               return ret;
+
+       val = readl(ud->iorebase+DMAC_CFG);
+       val |= DMAC_EN_MASK;
+       val &= ~INT_EN_MASK;
+       writeq(val,ud->iorebase+DMAC_CFG);
+       for(i=0;i<DMA_CHAN_NUM;i++) {
+               ud->axi_chan[i]=malloc(sizeof(struct axi_dma_chan));
+               ud->axi_chan[i]->regs=ud->iorebase+(i+1)*CHAN_REG_SHIFT;
+               ud->axi_chan[i]->status = UNUSED;
+       }
+       uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM |
+                                DMA_SUPPORTS_MEM_TO_DEV |
+                                DMA_SUPPORTS_DEV_TO_MEM;
+
+       return 0;
+}
+
+static int axi_dma_remove(struct udevice *dev)
+{
+       struct axi_dma_dev *ud = dev_get_priv(dev);
+       int ret;
+
+       ret = reset_assert(&ud->reset);
+       if (ret)
+               return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+       ret = clk_disable(&ud->clk);
+       if (ret)
+               return ret;
+
+       clk_free(&ud->clk);
+       if (ret)
+               return ret;
+#endif
+       return 0;
+}
+
+static const struct udevice_id designware_dma_ids[] = {
+       { .compatible = "dw_axi_dma" },
+       { }
+};
+
+U_BOOT_DRIVER(dw_axi_dma) = {
+       .name   = "dw_axi_dma",
+       .id     = UCLASS_DMA,
+       .of_match = designware_dma_ids,
+       .ops    = &axi_dma_ops,
+       .probe = axi_dma_probe,
+       .remove = axi_dma_remove,
+       .priv_auto      = sizeof(struct axi_dma_dev),
+};
+
diff --git a/drivers/dma/axi-dma.h b/drivers/dma/axi-dma.h
new file mode 100644 (file)
index 0000000..a6603e8
--- /dev/null
@@ -0,0 +1,227 @@
+#include <clk.h>
+#include <reset.h>
+
+enum chan_stat{
+       UNUSED = 0,
+       USED,
+};
+
+enum direction{
+       MEM_TO_MEM,
+       MEM_TO_DEV,
+       DEV_TO_MEM,
+};
+
+enum buf_type{
+       TX = 1,
+       RX,
+};
+
+struct buf_info{
+       u64 address;
+       enum buf_type type;
+       u32 buf_len;
+};
+
+struct axi_dma_chan{
+       struct axi_chan_regs *regs;
+       struct dma_dev_config *config;
+       enum chan_stat status;
+       enum direction dir;
+       struct buf_info *info;
+};
+
+struct dma_dev_config{
+       u32 hs_if;
+       u32 burst_len;
+};
+
+struct axi_dma_dev{
+       struct udevice *dev;
+       struct axi_dma_chan *axi_chan[8];
+       void __iomem *iorebase;
+       struct clk clk;
+       struct reset_ctl reset;
+       u32 n_channels;
+       u32 max_block_ts;
+};
+
+struct axi_chan_regs{
+       u64 sar;
+       u64 dar;
+       u64 block_ts;
+       u32 ctl_lo;
+       u32 ctl_hi;
+       u32 cfg_lo;
+       u32 cfg_hi;
+       u64 llp;
+       u64 unused_regs_1[10];
+       u64 int_en;
+       u64 int_status;
+       u64 unused_regs_2[2];
+};
+
+#define DMA_CHAN_NUM           8
+#define DMAC_ID                        0x000 /* R DMAC ID */
+#define DMAC_COMPVER           0x008 /* R DMAC Component Version */
+#define DMAC_CFG               0x010 /* R/W DMAC Configuration */
+#define DMAC_CHEN              0x018 /* R/W DMAC Channel Enable */
+#define DMAC_CHEN_L            0x018 /* R/W DMAC Channel Enable 00-31 */
+#define DMAC_CHEN_H            0x01C /* R/W DMAC Channel Enable 32-63 */
+#define DMAC_CHSUSPREG         0x020 /* R/W DMAC Channel Suspend */
+#define DMAC_CHABORTREG                0x028 /* R/W DMAC Channel Abort */
+#define DMAC_INTSTATUS         0x030 /* R DMAC Interrupt Status */
+#define DMAC_COMMON_INTCLEAR   0x038 /* W DMAC Interrupt Clear */
+#define DMAC_COMMON_INTSTATUS_ENA 0x040 /* R DMAC Interrupt Status Enable */
+#define DMAC_COMMON_INTSIGNAL_ENA 0x048 /* R/W DMAC Interrupt Signal Enable */
+#define DMAC_COMMON_INTSTATUS  0x050 /* R DMAC Interrupt Status */
+#define DMAC_RESET             0x058 /* R DMAC Reset Register1 */
+
+/* DMA channel registers offset */
+#define CH_SAR                 0x000 /* R/W Chan Source Address */
+#define CH_DAR                 0x008 /* R/W Chan Destination Address */
+#define CH_BLOCK_TS            0x010 /* R/W Chan Block Transfer Size */
+#define CH_CTL                 0x018 /* R/W Chan Control */
+#define CH_CTL_L               0x018 /* R/W Chan Control 00-31 */
+#define CH_CTL_H               0x01C /* R/W Chan Control 32-63 */
+#define CH_CFG                 0x020 /* R/W Chan Configuration */
+#define CH_CFG_L               0x020 /* R/W Chan Configuration 00-31 */
+#define CH_CFG_H               0x024 /* R/W Chan Configuration 32-63 */
+#define CH_LLP                 0x028 /* R/W Chan Linked List Pointer */
+#define CH_STATUS              0x030 /* R Chan Status */
+#define CH_SWHSSRC             0x038 /* R/W Chan SW Handshake Source */
+#define CH_SWHSDST             0x040 /* R/W Chan SW Handshake Destination */
+#define CH_BLK_TFR_RESUMEREQ   0x048 /* W Chan Block Transfer Resume Req */
+#define CH_AXI_ID              0x050 /* R/W Chan AXI ID */
+#define CH_AXI_QOS             0x058 /* R/W Chan AXI QOS */
+#define CH_SSTAT               0x060 /* R Chan Source Status */
+#define CH_DSTAT               0x068 /* R Chan Destination Status */
+#define CH_SSTATAR             0x070 /* R/W Chan Source Status Fetch Addr */
+#define CH_DSTATAR             0x078 /* R/W Chan Destination Status Fetch Addr */
+#define CH_INTSTATUS_ENA       0x080 /* R/W Chan Interrupt Status Enable */
+#define CH_INTSTATUS           0x088 /* R/W Chan Interrupt Status */
+#define CH_INTSIGNAL_ENA       0x090 /* R/W Chan Interrupt Signal Enable */
+#define CH_INTCLEAR            0x098 /* W Chan Interrupt Clear */
+
+#define DMAC_EN_POS                    0
+#define DMAC_EN_MASK                   BIT(DMAC_EN_POS)
+
+#define INT_EN_POS                     1
+#define INT_EN_MASK                    BIT(INT_EN_POS)
+
+/* DMAC_CHEN */
+#define DMAC_CHAN_EN_SHIFT             0
+#define DMAC_CHAN_EN_WE_SHIFT          8
+
+#define DMAC_CHAN_SUSP_SHIFT           16
+#define DMAC_CHAN_SUSP_WE_SHIFT                24
+
+/* DMAC_CHEN2 */
+#define DMAC_CHAN_EN2_WE_SHIFT         16
+
+/* DMAC_CHSUSP */
+#define DMAC_CHAN_SUSP2_SHIFT          0
+#define DMAC_CHAN_SUSP2_WE_SHIFT       16
+
+/* CH_CTL_H */
+#define CH_CTL_H_ARLEN_EN              BIT(6)
+#define CH_CTL_H_ARLEN_POS             7
+#define CH_CTL_H_AWLEN_EN              BIT(15)
+#define CH_CTL_H_AWLEN_POS             16
+
+enum {
+       DWAXIDMAC_ARWLEN_1              = 0,
+       DWAXIDMAC_ARWLEN_2              = 1,
+       DWAXIDMAC_ARWLEN_4              = 3,
+       DWAXIDMAC_ARWLEN_8              = 7,
+       DWAXIDMAC_ARWLEN_16             = 15,
+       DWAXIDMAC_ARWLEN_32             = 31,
+       DWAXIDMAC_ARWLEN_64             = 63,
+       DWAXIDMAC_ARWLEN_128            = 127,
+       DWAXIDMAC_ARWLEN_256            = 255,
+       DWAXIDMAC_ARWLEN_MIN            = DWAXIDMAC_ARWLEN_1,
+       DWAXIDMAC_ARWLEN_MAX            = DWAXIDMAC_ARWLEN_256
+};
+
+#define DEF_WIDTH  0
+#define DEF_AXI_BURST_LEN  16
+
+
+#define CH_CTL_H_LLI_LAST              BIT(30)
+#define CH_CTL_H_LLI_VALID             BIT(31)
+
+/* CH_CTL_L */
+#define CH_CTL_L_LAST_WRITE_EN         BIT(30)
+
+#define CH_CTL_L_DST_MSIZE_POS         18
+#define CH_CTL_L_SRC_MSIZE_POS         14
+
+enum {
+       DWAXIDMAC_BURST_TRANS_LEN_1     = 0,
+       DWAXIDMAC_BURST_TRANS_LEN_4,
+       DWAXIDMAC_BURST_TRANS_LEN_8,
+       DWAXIDMAC_BURST_TRANS_LEN_16,
+       DWAXIDMAC_BURST_TRANS_LEN_32,
+       DWAXIDMAC_BURST_TRANS_LEN_64,
+       DWAXIDMAC_BURST_TRANS_LEN_128,
+       DWAXIDMAC_BURST_TRANS_LEN_256,
+       DWAXIDMAC_BURST_TRANS_LEN_512,
+       DWAXIDMAC_BURST_TRANS_LEN_1024
+};
+
+#define CH_CTL_L_DST_WIDTH_POS         11
+#define CH_CTL_L_SRC_WIDTH_POS         8
+
+#define CH_CTL_L_DST_INC_POS           6
+#define CH_CTL_L_SRC_INC_POS           4
+
+enum {
+       DWAXIDMAC_CH_CTL_L_INC          = 0,
+       DWAXIDMAC_CH_CTL_L_NOINC
+};
+
+#define CH_CTL_L_DST_MAST              BIT(2)
+#define CH_CTL_L_SRC_MAST              BIT(0)
+
+/* CH_CFG_H */
+#define CH_CFG_H_PRIORITY_POS          17
+#define CH_CFG_H_DST_PER_POS           12
+#define CH_CFG_H_SRC_PER_POS           7
+#define CH_CFG_H_HS_SEL_DST_POS                4
+#define CH_CFG_H_HS_SEL_SRC_POS                3
+enum {
+       DWAXIDMAC_HS_SEL_HW             = 0,
+       DWAXIDMAC_HS_SEL_SW
+};
+
+#define CH_CFG_H_TT_FC_POS             0
+enum {
+       DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC = 0,
+       DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC,
+       DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC,
+       DWAXIDMAC_TT_FC_PER_TO_PER_DMAC,
+       DWAXIDMAC_TT_FC_PER_TO_MEM_SRC,
+       DWAXIDMAC_TT_FC_PER_TO_PER_SRC,
+       DWAXIDMAC_TT_FC_MEM_TO_PER_DST,
+       DWAXIDMAC_TT_FC_PER_TO_PER_DST
+};
+
+/* CH_CFG_L */
+#define CH_CFG_L_DST_MULTBLK_TYPE_POS  2
+#define CH_CFG_L_SRC_MULTBLK_TYPE_POS  0
+enum {
+       DWAXIDMAC_MBLK_TYPE_CONTIGUOUS  = 0,
+       DWAXIDMAC_MBLK_TYPE_RELOAD,
+       DWAXIDMAC_MBLK_TYPE_SHADOW_REG,
+       DWAXIDMAC_MBLK_TYPE_LL
+};
+
+/* CH_CFG2 */
+#define CH_CFG2_L_SRC_PER_POS          4
+#define CH_CFG2_L_DST_PER_POS          11
+
+#define CH_CFG2_H_TT_FC_POS            0
+#define CH_CFG2_H_HS_SEL_SRC_POS       3
+#define CH_CFG2_H_HS_SEL_DST_POS       4
+#define CH_CFG2_H_PRIORITY_POS         20
+
index b97c67bf6094fc3dce22e239c99caab15074123d..34825d12ff3912773ed2c5f780250d4ff384e77a 100644 (file)
@@ -72,7 +72,7 @@ config FASTBOOT_USB_DEV
 config FASTBOOT_FLASH
        bool "Enable FASTBOOT FLASH command"
        default y if ARCH_SUNXI || ARCH_ROCKCHIP
-       depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS)
+       depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS) || MTD
        select IMAGE_SPARSE
        help
          The fastboot protocol includes a "flash" command for writing
@@ -87,9 +87,18 @@ config FASTBOOT_UUU_SUPPORT
          including working with memory and may open a huge backdoor,
          when enabling this option.
 
+config FASTBOOT_MULTI_FLASH_OPTION
+       bool "Enable FASTBOOT flash multi option"
+       select FASTBOOT_MULTI_FLASH_OPTION_MMC
+       select FASTBOOT_MULTI_FLASH_OPTION_MTD
+       help
+         normally it would flash one dev such as mmc or mtd devices.
+         but sometime user want to flash mmc or mtd devices while detect
+         the mmc/mtd dev.
+
 choice
        prompt "Flash provider for FASTBOOT"
-       depends on FASTBOOT_FLASH
+       depends on FASTBOOT_FLASH && !FASTBOOT_MULTI_FLASH_OPTION
 
 config FASTBOOT_FLASH_MMC
        bool "FASTBOOT on MMC"
@@ -99,11 +108,24 @@ config FASTBOOT_FLASH_NAND
        bool "FASTBOOT on NAND"
        depends on MTD_RAW_NAND && CMD_MTDPARTS
 
+config FASTBOOT_FLASH_MTD
+       bool "FASTBOOT on MTD"
+       depends on MTD
+
 endchoice
 
+
+config FASTBOOT_MULTI_FLASH_OPTION_MMC
+       bool "FASTBOOT on MMC"
+       depends on FASTBOOT_MULTI_FLASH_OPTION
+
+config FASTBOOT_MULTI_FLASH_OPTION_MTD
+       bool "FASTBOOT on MTD"
+       depends on FASTBOOT_MULTI_FLASH_OPTION
+
 config FASTBOOT_FLASH_MMC_DEV
        int "Define FASTBOOT MMC FLASH default device"
-       depends on FASTBOOT_FLASH_MMC
+       depends on FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC
        default 0 if ARCH_ROCKCHIP
        default 0 if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1
        default 1 if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1
@@ -121,7 +143,7 @@ config FASTBOOT_FLASH_NAND_TRIMFFS
 
 config FASTBOOT_MMC_BOOT_SUPPORT
        bool "Enable EMMC_BOOT flash/erase"
-       depends on FASTBOOT_FLASH_MMC
+       depends on FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC
        help
          The fastboot "flash" and "erase" commands normally does operations
          on eMMC userdata. Define this to enable the special commands to
@@ -153,7 +175,7 @@ config FASTBOOT_MMC_BOOT2_NAME
 
 config FASTBOOT_MMC_USER_SUPPORT
        bool "Enable eMMC userdata partition flash/erase"
-       depends on FASTBOOT_FLASH_MMC
+       depends on FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC
        help
          Define this to enable the support "flash" and "erase" command on
          eMMC userdata. The "flash" command only update the MBR and GPT
@@ -175,7 +197,7 @@ config FASTBOOT_MMC_USER_NAME
 
 config FASTBOOT_GPT_NAME
        string "Target name for updating GPT"
-       depends on FASTBOOT_FLASH_MMC && EFI_PARTITION
+       depends on (FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC) && EFI_PARTITION
        default "gpt"
        help
          The fastboot "flash" command supports writing the downloaded
@@ -188,7 +210,7 @@ config FASTBOOT_GPT_NAME
 
 config FASTBOOT_MBR_NAME
        string "Target name for updating MBR"
-       depends on FASTBOOT_FLASH_MMC && DOS_PARTITION
+       depends on (FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC) && DOS_PARTITION
        default "mbr"
        help
          The fastboot "flash" command allows to write the downloaded image
@@ -198,7 +220,7 @@ config FASTBOOT_MBR_NAME
 
 config FASTBOOT_CMD_OEM_FORMAT
        bool "Enable the 'oem format' command"
-       depends on FASTBOOT_FLASH_MMC && CMD_GPT
+       depends on (FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC) && CMD_GPT
        help
          Add support for the "oem format" command from a client. This
          relies on the env variable partitions to contain the list of
@@ -206,18 +228,65 @@ config FASTBOOT_CMD_OEM_FORMAT
 
 config FASTBOOT_CMD_OEM_PARTCONF
        bool "Enable the 'oem partconf' command"
-       depends on FASTBOOT_FLASH_MMC && SUPPORT_EMMC_BOOT
+       depends on (FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC) && SUPPORT_EMMC_BOOT
        help
          Add support for the "oem partconf" command from a client. This set
          the mmc boot-partition for the selecting eMMC device.
 
 config FASTBOOT_CMD_OEM_BOOTBUS
        bool "Enable the 'oem bootbus' command"
-       depends on FASTBOOT_FLASH_MMC && SUPPORT_EMMC_BOOT
+       depends on (FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC) && SUPPORT_EMMC_BOOT
        help
          Add support for the "oem bootbus" command from a client. This set
          the mmc boot configuration for the selecting eMMC device.
 
+config FASTBOOT_CMD_OEM_READ
+       bool "Enable the 'oem read' command"
+       depends on FASTBOOT_FLASH_MMC || FASTBOOT_MULTI_FLASH_OPTION_MMC
+       help
+         Add support for the "oem read" command from a client. This only
+         load data to ddr, and should use upload command to load data to
+         host.
+
+config FASTBOOT_SUPPORT_BLOCK_DEV
+       bool "Support blk device such as mmc/nvme/usb/sata"
+       depends on FASTBOOT_FLASH_MTD || FASTBOOT_MULTI_FLASH_OPTION_MTD
+       help
+         If support blk dev on mtd flash, it should choice an block device such
+         as mmc/nvme/usb/sata and combine to the boot falash.
+
+config FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+       string "Target name for block device"
+       depends on FASTBOOT_SUPPORT_BLOCK_DEV
+       default "nvme"
+       help
+         The block device name, such as mmc/nvme/usb/sata
+
+config FASTBOOT_SUPPORT_BLOCK_DEV_INDEX
+       int "The block device number"
+       depends on FASTBOOT_SUPPORT_BLOCK_DEV
+       default 0
+       help
+         The block device number.
+
+config FASTBOOT_CMD_OEM_CONFIG_ACCESS
+       bool "Enable the 'oem config' command"
+       help
+         Add support for the "oem config:read/write/flush" command from a fastboot client. This command
+         include configuration read, write and flush operation.
+
+config FASTBOOT_CMD_OEM_ENV_ACCESS
+       bool "Enable the 'oem env' command"
+       help
+         Add support for the "oem env:get/set" command from a fastboot client. This command
+         include read, write and delete env variabes.
+
+config SPL_FASTBOOT_CMD_OEM_ENV_ACCESS
+       bool "Enable the 'oem env' command in SPL"
+       help
+         Add support for the "oem env:get/set" command from a fastboot client. This command
+         include read, write env variabes in SPL stage.
+
 endif # FASTBOOT
 
 endmenu
index 048af5aa823436956142a536c5f7dcf1a8948726..a124e0c27d355500b13e757ad3669f8060b0aa85 100644 (file)
@@ -3,5 +3,11 @@
 obj-y += fb_common.o
 obj-y += fb_getvar.o
 obj-y += fb_command.o
-obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o
-obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
+obj-y += fb_spacemit.o
+obj-$(CONFIG_$(SPL_)FASTBOOT_FLASH_MMC) += fb_mmc.o
+obj-$(CONFIG_$(SPL_)FASTBOOT_FLASH_NAND) += fb_nand.o
+obj-$(CONFIG_$(SPL_)FASTBOOT_FLASH_MTD) += fb_mtd.o
+
+obj-$(CONFIG_$(SPL_)FASTBOOT_MULTI_FLASH_OPTION_MMC) += fb_mmc.o
+obj-$(CONFIG_$(SPL_)FASTBOOT_MULTI_FLASH_OPTION_MTD) += fb_mtd.o
+obj-$(CONFIG_$(SPL_)FASTBOOT_SUPPORT_BLOCK_DEV) += fb_blk.o
diff --git a/drivers/fastboot/fb_blk.c b/drivers/fastboot/fb_blk.c
new file mode 100644 (file)
index 0000000..e82deb8
--- /dev/null
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Broadcom Corporation.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <blk.h>
+#include <env.h>
+#include <fastboot.h>
+#include <fastboot-internal.h>
+#include <fb_blk.h>
+#include <image-sparse.h>
+#include <image.h>
+#include <log.h>
+#include <part.h>
+#include <div64.h>
+#include <linux/compat.h>
+#include <android_image.h>
+#include <fb_spacemit.h>
+#include <u-boot/crc.h>
+#include <mmc.h>
+#include <gzip.h>
+
+#define FASTBOOT_MAX_BLK_WRITE 16384
+
+struct fb_blk_sparse {
+       struct blk_desc *dev_desc;
+};
+
+
+static int do_get_part_info(struct blk_desc **dev_desc, const char *name,
+                           struct disk_partition *info)
+{
+       int ret = -1;
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+       if (strlen(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME) > 0){
+
+               /* First try partition names on the default device */
+               *dev_desc = blk_get_dev(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME,
+                                                        CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX);
+               if (*dev_desc) {
+                       ret = part_get_info_by_name(*dev_desc, name, info);
+                       if (ret >= 0)
+                               return ret;
+               }
+       }
+#endif
+
+       printf("has not define block device name \n");
+       return ret;
+}
+
+
+/**
+ * fb_blk_write() - Write/erase blk device in chunks of FASTBOOT_MAX_BLK_WRITE
+ *
+ * @block_dev: Pointer to block device
+ * @start: First block to write/erase
+ * @blkcnt: Count of blocks
+ * @buffer: Pointer to data buffer for write or NULL for erase
+ */
+static lbaint_t fb_blk_write(struct blk_desc *block_dev, lbaint_t start,
+                                lbaint_t blkcnt, const void *buffer)
+{
+       lbaint_t blk = start;
+       lbaint_t blks_written;
+       lbaint_t cur_blkcnt;
+       lbaint_t blks = 0;
+       int i;
+
+       for (i = 0; i < blkcnt; i += FASTBOOT_MAX_BLK_WRITE) {
+               cur_blkcnt = min((int)blkcnt - i, FASTBOOT_MAX_BLK_WRITE);
+               if (buffer) {
+                       if (fastboot_progress_callback)
+                               fastboot_progress_callback("writing");
+                       blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
+                                                 buffer + (i * block_dev->blksz));
+               } else {
+                       if (fastboot_progress_callback)
+                               fastboot_progress_callback("erasing");
+                       blks_written = blk_derase(block_dev, blk, cur_blkcnt);
+               }
+               blk += blks_written;
+               blks += blks_written;
+       }
+       return blks;
+}
+
+static lbaint_t fb_blk_sparse_write(struct sparse_storage *info,
+               lbaint_t blk, lbaint_t blkcnt, const void *buffer)
+{
+       struct fb_blk_sparse *sparse = info->priv;
+       struct blk_desc *dev_desc = sparse->dev_desc;
+
+       return fb_blk_write(dev_desc, blk, blkcnt, buffer);
+}
+
+static lbaint_t fb_blk_sparse_reserve(struct sparse_storage *info,
+               lbaint_t blk, lbaint_t blkcnt)
+{
+       return blkcnt;
+}
+
+static void write_raw_image(struct blk_desc *dev_desc,
+                           struct disk_partition *info, const char *part_name,
+                           void *buffer, u32 download_bytes, char *response)
+{
+       lbaint_t blkcnt;
+       lbaint_t blks;
+
+       /* determine number of blocks to write */
+       blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1));
+       blkcnt = lldiv(blkcnt, info->blksz);
+
+       if (blkcnt > info->size) {
+               pr_err("too large for partition: '%s'\n", part_name);
+               fastboot_fail("too large for partition", response);
+               return;
+       }
+
+       puts("Flashing Raw Image\n");
+
+       blks = fb_blk_write(dev_desc, info->start, blkcnt, buffer);
+
+       if (blks != blkcnt) {
+               pr_err("failed writing to device %d\n", dev_desc->devnum);
+               fastboot_fail("failed writing to device", response);
+               return;
+       }
+
+       printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz,
+              part_name);
+       fastboot_okay(NULL, response);
+}
+
+
+/**
+ * fastboot_blk_get_part_info() - Lookup blk device partion by name
+ *
+ * @part_name: Named partition to lookup
+ * @dev_desc: Pointer to returned blk_desc pointer
+ * @part_info: Pointer to returned struct disk_partition
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_blk_get_part_info(const char *part_name,
+                              struct blk_desc **dev_desc,
+                              struct disk_partition *part_info, char *response)
+{
+       int ret;
+
+       if (!part_name || !strcmp(part_name, "")) {
+               fastboot_fail("partition not given", response);
+               return -ENOENT;
+       }
+
+       ret = do_get_part_info(dev_desc, part_name, part_info);
+       if (ret < 0) {
+               fastboot_fail("can not find partition or devices", response);
+       }
+
+       return ret;
+}
+
+
+/**
+ * fastboot_blk_flash_write() - Write image to blk device for fastboot
+ *
+ * @cmd: Named partition to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_blk_flash_write(const char *cmd, void *download_buffer,
+                             u32 download_bytes, char *response)
+{
+       struct blk_desc *dev_desc;
+       struct disk_partition info = {0};
+#ifdef CONFIG_SPACEMIT_FLASH
+       static struct flash_dev *fdev = NULL;
+       u32 __maybe_unused fsbl_offset = 0;
+       /*save crc value to compare after flash image*/
+       u64 compare_val = 0;
+       /*use for gzip image*/
+       static u32 __maybe_unused part_offset_t = 0;
+       static char __maybe_unused part_name_t[20] = "";
+       unsigned long __maybe_unused src_len = ~0UL;
+       bool gzip_image = false;
+
+       if (fdev == NULL){
+               fdev = malloc(sizeof(struct flash_dev));
+               if (!fdev) {
+                       printf("Memory allocation failed!\n");
+               }
+               memset(fdev, 0, sizeof(struct flash_dev));
+               fdev->gptinfo.fastboot_flash_gpt = false;
+               /*would realloc the size while parsing the partition table*/
+               fdev->gptinfo.gpt_table = malloc(10);
+               fdev->mtd_table = malloc(10);
+               memset(fdev->gptinfo.gpt_table, '\0', 10);
+               memset(fdev->mtd_table, '\0', 10);
+               printf("init fdev success\n");
+       }
+
+       /*blk device would not flash bootinfo except emmc*/
+       if (strcmp(cmd, "bootinfo") == 0) {
+               fastboot_okay(NULL, response);
+               return;
+       }
+
+       if (strcmp(cmd, "gpt") == 0) {
+               fastboot_oem_flash_gpt(cmd, fastboot_buf_addr, download_bytes,
+                                               response, fdev);
+               return;
+       }
+#endif
+
+       if (fastboot_blk_get_part_info(cmd, &dev_desc, &info, response) < 0)
+               return;
+
+       if (gzip_parse_header((uchar *)download_buffer, src_len) >= 0) {
+               /*is gzip data and equal part name*/
+               gzip_image = true;
+               if (strcmp(cmd, part_name_t)){
+                       pr_info("flash part name %s is not equal to %s, \n", cmd, part_name_t);
+                       strcpy(part_name_t, cmd);
+                       part_offset_t = 0;
+               }
+
+               void *decompress_addr = (void *)GZIP_DECOMPRESS_ADDR;
+               pr_info("decompress_addr:%p\n", decompress_addr);
+               if (run_commandf("unzip %x %x", download_buffer, decompress_addr)){
+                       printf("unzip gzip data fail, \n");
+                       fastboot_fail("unzip gzip data fail", response);
+                       return;
+               }
+
+               u32 decompress_size = env_get_hex("filesize", 0);
+               pr_info("get decompress_size:%x, \n", decompress_size);
+               download_buffer = decompress_addr;
+               download_bytes = decompress_size;
+               info.start += part_offset_t / info.blksz;
+
+               pr_info("write gzip raw data to part:%s, %p, %x, blkaddr:%lx\n", cmd, download_buffer, download_bytes, info.start);
+       } else {
+               strcpy(part_name_t, cmd);
+               part_offset_t = 0;
+       }
+
+       if (download_bytes > info.size * info.blksz){
+               printf("download_bytes is greater than part size\n");
+               fastboot_fail("download_bytes is greater than part size", response);
+               return;
+       }
+
+       if (!gzip_image && is_sparse_image(download_buffer)) {
+               struct fb_blk_sparse sparse_priv;
+               struct sparse_storage sparse = { .erase = NULL };;
+               int err;
+
+               sparse_priv.dev_desc = dev_desc;
+
+               sparse.blksz = info.blksz;
+               sparse.start = info.start;
+               sparse.size = info.size;
+               sparse.write = fb_blk_sparse_write;
+               sparse.reserve = fb_blk_sparse_reserve;
+               sparse.mssg = fastboot_fail;
+
+               printf("Flashing sparse image at offset " LBAFU "\n",
+                      sparse.start);
+
+               sparse.priv = &sparse_priv;
+               err = write_sparse_image(&sparse, cmd, download_buffer,
+                                        response);
+               if (!err)
+                       fastboot_okay(NULL, response);
+       } else {
+               write_raw_image(dev_desc, &info, cmd, download_buffer,
+                               download_bytes, response);
+#ifdef CONFIG_SPACEMIT_FLASH
+               /*if download and flash div to many time, that the crc is not correct*/
+               printf("write_raw_image, \n");
+               // compare_val = crc32_wd(compare_val, (const uchar *)download_buffer, download_bytes, CHUNKSZ_CRC32);
+               compare_val += checksum64(download_buffer, download_bytes);
+               if (compare_blk_image_val(dev_desc, compare_val, info.start, info.blksz, download_bytes))
+                       fastboot_fail("compare crc fail", response);
+#endif
+               part_offset_t += download_bytes;
+       }
+}
+
+/**
+ * fastboot_blk_flash_erase() - Erase blk device for fastboot
+ *
+ * @cmd: Named partition to erase
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_blk_erase(const char *cmd, char *response)
+{
+       struct blk_desc *dev_desc;
+       struct disk_partition info;
+       lbaint_t blks, blks_start, blks_size;
+
+       if (fastboot_blk_get_part_info(cmd, &dev_desc, &info, response) < 0)
+               return;
+
+       /* Align blocks to erase group size to avoid erasing other partitions */
+       //TODO: align to blk dev erase size.
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+       if (!strncmp("mmc", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 3)){
+               struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX);
+               lbaint_t grp_size;
+
+               grp_size = mmc->erase_grp_size;
+               blks_start = (info.start + grp_size - 1) & ~(grp_size - 1);
+               if (info.size >= grp_size)
+                       blks_size = (info.size - (blks_start - info.start)) &
+                                       (~(grp_size - 1));
+               else
+                       blks_size = 0;
+       }else{
+               blks_start = info.start;
+               blks_size = info.size;
+       }
+#else
+       return;
+#endif
+
+       blks = fb_blk_write(dev_desc, blks_start, blks_size, NULL);
+
+       if (blks != blks_size) {
+               pr_err("failed erasing from device %d\n", dev_desc->devnum);
+               fastboot_fail("failed erasing from device", response);
+               return;
+       }
+
+       printf("........ erased " LBAFU " bytes from '%s'\n",
+              blks_size * info.blksz, cmd);
+       fastboot_okay(NULL, response);
+}
+
+/**
+ * fastboot_blk_read() - load data from blk device for fastboot
+ *
+ * @part: Named partition to erase
+ * @response: Pointer to fastboot response buffer
+ */
+u32 fastboot_blk_read(const char *part, u32 offset,
+                                       void *download_buffer, char *response)
+{
+       struct blk_desc *dev_desc;
+       struct disk_partition info = {0};
+       lbaint_t hdr_sectors, off_blk, size_blk;
+       lbaint_t res;
+
+       if (do_get_part_info(&dev_desc, part, &info) < 0){
+               if (dev_desc && dev_desc->blksz > 0){
+                       info.blksz = dev_desc->blksz;
+                       info.size = dev_desc->lba;
+                       info.start = 0;
+               }else{
+                       fastboot_response("OKAY", response, "%08x", 0);
+                       return 0;
+               }
+       }
+
+       if (offset >= (info.size * info.blksz)){
+               fastboot_response("OKAY", response, "%08x", 0);
+               return 0;
+       }
+
+       printf("info.size:%lx, info.start:%lx\n", info.size, info.start);
+       /*transfer offset to blk size*/
+       off_blk = (offset / info.blksz) + info.start;
+       size_blk = info.size - (offset / info.blksz);
+
+       if (offset % info.blksz)
+               printf("offset should be align to 0x%lx, would change offset to 0x%lx\n",
+                                                               info.blksz, (offset / info.blksz) * info.blksz);
+
+       debug("info->blksize:%lx, off_blk:%lx, size_blk:%lx\n", info.blksz, off_blk, size_blk);
+
+       /*if size > buffer_size, it would only load buffer_size, and return offset*/
+       if (size_blk * info.blksz > fastboot_buf_size){
+               /* Read the boot image header */
+               hdr_sectors = fastboot_buf_size / info.blksz;
+       }else{
+               hdr_sectors = size_blk;
+       }
+
+       res = blk_dread(dev_desc, off_blk, hdr_sectors, download_buffer);
+       if (res != hdr_sectors) {
+               fastboot_fail("cannot read data from blk dev", response);
+               return 0;
+       }
+
+       /*return had read size*/
+       fastboot_response("OKAY", response, "0x%08x", (u32)(hdr_sectors * info.blksz));
+       return hdr_sectors * info.blksz;
+}
index bdfdf262c8a33b097fade98f9801f1cf72834dd2..dfdb7c6dfc609ef0fd4e2f6b0146b9d9c3aaf54f 100644 (file)
 #include <fastboot-internal.h>
 #include <fb_mmc.h>
 #include <fb_nand.h>
+#include <fb_mtd.h>
 #include <part.h>
 #include <stdlib.h>
+#include <spl.h>
+#include <image.h>
+#include <fb_spacemit.h>
+#include <fb_mtd.h>
+#include <fb_blk.h>
+#include <dm.h>
 
 /**
  * image_size - final fastboot image size
@@ -31,13 +38,19 @@ static u32 fastboot_bytes_expected;
 static void okay(char *, char *);
 static void getvar(char *, char *);
 static void download(char *, char *);
+
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 static void flash(char *, char *);
 static void erase(char *, char *);
 #endif
+
+#if !defined(CONFIG_SPL_BUILD)
+static void upload(char *, char *);
 static void reboot_bootloader(char *, char *);
 static void reboot_fastbootd(char *, char *);
 static void reboot_recovery(char *, char *);
+#endif
+
 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
 static void oem_format(char *, char *);
 #endif
@@ -48,11 +61,24 @@ static void oem_partconf(char *, char *);
 static void oem_bootbus(char *, char *);
 #endif
 
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_READ)
+static void oem_read(char *cmd_parameter, char *response);
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
+static void oem_config(char *cmd_parameter, char *response);
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
+static void oem_env(char *cmd_parameter, char *response);
+#endif
+
 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
 static void run_ucmd(char *, char *);
 static void run_acmd(char *, char *);
 #endif
 
+
 static const struct {
        const char *command;
        void (*dispatch)(char *cmd_parameter, char *response);
@@ -65,6 +91,11 @@ static const struct {
                .command = "download",
                .dispatch = download
        },
+#if !defined(CONFIG_SPL_BUILD)
+       [FASTBOOT_COMMAND_UPLOAD] = {
+               .command = "upload",
+               .dispatch = upload
+       },
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
        [FASTBOOT_COMMAND_FLASH] =  {
                .command = "flash",
@@ -79,10 +110,12 @@ static const struct {
                .command = "boot",
                .dispatch = okay
        },
+#endif /*!defined(CONFIG_SPL_BUILD)*/
        [FASTBOOT_COMMAND_CONTINUE] =  {
                .command = "continue",
                .dispatch = okay
        },
+#if !defined(CONFIG_SPL_BUILD)
        [FASTBOOT_COMMAND_REBOOT] =  {
                .command = "reboot",
                .dispatch = okay
@@ -103,6 +136,7 @@ static const struct {
                .command = "set_active",
                .dispatch = okay
        },
+#endif /*!defined(CONFIG_SPL_BUILD)*/
 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
        [FASTBOOT_COMMAND_OEM_FORMAT] = {
                .command = "oem format",
@@ -121,6 +155,24 @@ static const struct {
                .dispatch = oem_bootbus,
        },
 #endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_READ)
+       [FASTBOOT_COMMAND_OEM_READ] = {
+               .command = "oem read",
+               .dispatch = oem_read,
+       },
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
+       [FASTBOOT_COMMAND_CONFIG_ACCESS] = {
+               .command = "oem config",
+               .dispatch = oem_config,
+       },
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
+       [FASTBOOT_COMMAND_ENV_ACCESS] = {
+               .command = "oem env",
+               .dispatch = oem_env,
+       },
+#endif
 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
        [FASTBOOT_COMMAND_UCMD] = {
                .command = "UCmd",
@@ -221,12 +273,44 @@ static void download(char *cmd_parameter, char *response)
        if (fastboot_bytes_expected > fastboot_buf_size) {
                fastboot_fail(cmd_parameter, response);
        } else {
-               printf("Starting download of %d bytes\n",
+               pr_info("Starting download of %d bytes\n",
                       fastboot_bytes_expected);
                fastboot_response("DATA", response, "%s", cmd_parameter);
        }
 }
 
+#if !defined(CONFIG_SPL_BUILD)
+/**
+ * fastboot_upload() - Start a upload transfer from the host
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void upload(char *cmd_parameter, char *response)
+{
+       /*fastboot_bytes_received would record had send byte*/
+       fastboot_bytes_received = 0;
+
+       if (fastboot_bytes_expected == 0) {
+               fastboot_fail("Expected nonzero image size", response);
+               return;
+       }
+       /*
+        * Nothing to upload yet. Response is of the form:
+        * [DATA|FAIL]$cmd_parameter
+        *
+        * where cmd_parameter is an 8 digit hexadecimal number
+        */
+       if (fastboot_bytes_expected > fastboot_buf_size) {
+               fastboot_fail(cmd_parameter, response);
+       } else {
+               pr_info("Starting upload of %d bytes\n",
+                      fastboot_bytes_expected);
+               fastboot_response("PUSH", response, "%08x", fastboot_bytes_expected);
+       }
+}
+#endif
+
 /**
  * fastboot_data_remaining() - return bytes remaining in current transfer
  *
@@ -281,6 +365,50 @@ void fastboot_data_download(const void *fastboot_data,
        *response = '\0';
 }
 
+
+/**
+ * fastboot_data_upload() - Copy image data to fastboot_buf_addr.
+ *
+ * @fastboot_data: Pointer to received fastboot data
+ * @fastboot_data_len: Length of received fastboot data
+ * @response: Pointer to fastboot response buffer
+ *
+ * Copies image data from fastboot_buf_addr to fastboot_data. Writes to
+ * response. fastboot_bytes_received is updated to indicate the number
+ * of bytes that have been transferred.
+ */
+void fastboot_data_upload(const void *fastboot_data,
+                           unsigned int fastboot_data_len,
+                           char *response)
+{
+#define BYTES_PER_DOT  0x20000
+       u32 pre_dot_num, now_dot_num;
+
+       if (fastboot_data_len == 0 ||
+           (fastboot_bytes_received + fastboot_data_len) >
+           fastboot_bytes_expected) {
+               fastboot_fail("Received invalid data length",
+                             response);
+               return;
+       }
+
+       /* copy data to buffer */
+       memcpy((void *)fastboot_data,
+              fastboot_buf_addr + fastboot_bytes_received, fastboot_data_len);
+
+       pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
+       fastboot_bytes_received += fastboot_data_len;
+       now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
+
+       if (pre_dot_num != now_dot_num) {
+               putc('.');
+               if (!(now_dot_num % 74))
+                       putc('\n');
+       }
+       *response = '\0';
+}
+
+
 /**
  * fastboot_data_complete() - Mark current transfer complete
  *
@@ -292,7 +420,7 @@ void fastboot_data_complete(char *response)
 {
        /* Download complete. Respond with "OKAY" */
        fastboot_okay(NULL, response);
-       printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
+       pr_info("\ndownloading/uploading of %d bytes finished\n", fastboot_bytes_received);
        image_size = fastboot_bytes_received;
        env_set_hex("filesize", image_size);
        fastboot_bytes_expected = 0;
@@ -311,10 +439,37 @@ void fastboot_data_complete(char *response)
  */
 static void flash(char *cmd_parameter, char *response)
 {
-#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
-       fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
-                                response);
+       u32 boot_mode = get_boot_pin_select();
+
+       switch(boot_mode){
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MTD) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MTD)
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               static bool mtd_flash = false;
+               if (!strncmp("mtd", cmd_parameter, 3))
+                       mtd_flash = true;
+               if (!strncmp("gpt", cmd_parameter, 3))
+                       mtd_flash = false;
+
+               if (mtd_flash){
+                       fastboot_mtd_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
+                                               response);
+               }else{
+                       /* flash blk dev */
+                       fastboot_blk_flash_write(cmd_parameter, fastboot_buf_addr, image_size, response);
+               }
+
+               return;
+#endif
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+               fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
+                                       response);
+               return;
 #endif
+       }
+
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
        fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
                                  response);
@@ -332,9 +487,37 @@ static void flash(char *cmd_parameter, char *response)
  */
 static void erase(char *cmd_parameter, char *response)
 {
-#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
-       fastboot_mmc_erase(cmd_parameter, response);
+       u32 boot_mode = get_boot_pin_select();
+
+       switch(boot_mode){
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               static bool mtd_flash = false;
+               if (!strncmp("mtd", cmd_parameter, 3))
+                       mtd_flash = true;
+               if (!strncmp("gpt", cmd_parameter, 3))
+                       mtd_flash = false;
+
+               if (mtd_flash){
+                       fastboot_mtd_flash_erase(cmd_parameter, response);
+
+                       if (!strncmp("OKAY", response, 4))
+                               return;
+               }
+
+               /* erase blk dev */
+               fastboot_blk_erase(cmd_parameter, response);
+               return;
+#endif
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+               fastboot_mmc_erase(cmd_parameter, response);
+               return;
 #endif
+       }
+
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
        fastboot_nand_erase(cmd_parameter, response);
 #endif
@@ -394,6 +577,7 @@ static void run_acmd(char *cmd_parameter, char *response)
 }
 #endif
 
+#if !defined(CONFIG_SPL_BUILD)
 /**
  * reboot_bootloader() - Sets reboot bootloader flag.
  *
@@ -435,6 +619,7 @@ static void reboot_recovery(char *cmd_parameter, char *response)
        else
                fastboot_okay(NULL, response);
 }
+#endif
 
 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
 /**
@@ -479,7 +664,7 @@ static void oem_partconf(char *cmd_parameter, char *response)
        /* execute 'mmc partconfg' command with cmd_parameter arguments*/
        snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
                 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
-       printf("Execute: %s\n", cmdbuf);
+       pr_info("Execute: %s\n", cmdbuf);
        if (run_command(cmdbuf, 0))
                fastboot_fail("Cannot set oem partconf", response);
        else
@@ -506,10 +691,147 @@ static void oem_bootbus(char *cmd_parameter, char *response)
        /* execute 'mmc bootbus' command with cmd_parameter arguments*/
        snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s",
                 CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
-       printf("Execute: %s\n", cmdbuf);
+       pr_info("Execute: %s\n", cmdbuf);
        if (run_command(cmdbuf, 0))
                fastboot_fail("Cannot set oem bootbus", response);
        else
                fastboot_okay(NULL, response);
 }
 #endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_READ)
+/**
+ * read_console_log() - Read data from console log buffer
+ *
+ * @fb_buf: Pointer to buffer where data will be copied
+ *
+ * @return: Actual size of data read
+ */
+static u32 read_console_log(char *fb_buf) {
+       char *log_start = gd->console_log.buffer;
+       char *log_end = log_start + LOG_BUFFER_SIZE;
+       char *log_ptr = gd->console_log.read_ptr;
+       u32 read_size = 0;
+
+       while (log_ptr != gd->console_log.write_ptr) {
+               u32 copy_size = (log_ptr < gd->console_log.write_ptr) ?
+                                               (gd->console_log.write_ptr - log_ptr) :
+                                               (log_end - log_ptr);
+
+               memcpy(fb_buf + read_size, log_ptr, copy_size);
+               read_size += copy_size;
+               log_ptr += copy_size;
+
+               if (log_ptr == log_end) {
+                       log_ptr = log_start;
+               }
+       }
+
+       gd->console_log.read_ptr = log_ptr;
+
+       return read_size;
+}
+
+/**
+ * oem_read() - Execute the OEM read command
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void oem_read(char *cmd_parameter, char *response)
+{
+       char *part, *offset_str, *cmd_str;
+       u32 off, boot_mode;
+
+       cmd_str = cmd_parameter;
+       part = strsep(&cmd_str, " ");
+       if (!part){
+               fastboot_fail("miss part, send command:\
+                       fastboot oem read:part [offset]", response);
+               return;
+       }
+
+       if (strcmp(part, "console") == 0) {
+               char *fb_buf = (char *)fastboot_buf_addr;
+               u32 read_size = read_console_log(fb_buf);
+
+               fastboot_bytes_expected = read_size;
+               fastboot_response("OKAY", response, "%08x", read_size);
+               return;
+       }
+
+       offset_str = strsep(&cmd_str, " ");
+       if (!offset_str){
+               pr_info("miss offset, would set offset to 0\n");
+               off = 0;
+       }else{
+               off = simple_strtoul(offset_str, NULL, 0);
+       }
+
+       debug("get part:%s, offset:%x\n", part, off);
+
+       boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               /*mtd read part not support read raw data*/
+               fastboot_bytes_expected = fastboot_mtd_flash_read(part, off, fastboot_buf_addr, response);
+
+               /* if read data from mtd partition success, it would not try to read from blk dev*/
+               if (fastboot_bytes_expected > 0)
+                       return;
+               pr_info("read data from blk dev\n");
+               fastboot_bytes_expected = fastboot_blk_read(part, off, fastboot_buf_addr, response);
+
+               return;
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+               fastboot_bytes_expected = fastboot_mmc_read(part, off, fastboot_buf_addr, response);
+               return;
+#endif
+       }
+
+       fastboot_okay(NULL, response);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
+void fastboot_config_access(char *operation, char *config, char *response);
+/**
+ * oem_config() - Execute the OEM config command
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void oem_config(char *cmd_parameter, char *response)
+{
+    char *cmd_str, *operation;
+
+       cmd_str = cmd_parameter;
+       operation = strsep(&cmd_str, " ");
+
+    fastboot_config_access(operation, cmd_str, response);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
+void fastboot_env_access(char *operation, char *env, char *response);
+/**
+ * oem_env() - Execute the OEM env operation command
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void oem_env(char *cmd_parameter, char *response)
+{
+    char *cmd_str, *operation;
+
+       cmd_str = cmd_parameter;
+       operation = strsep(&cmd_str, " ");
+
+    fastboot_env_access(operation, cmd_str, response);
+}
+#endif
index ef399d0c4abbf55d1730ae6c012254ea68da98b9..22c03eaeea9948958d6c31d3a7c7928166619805 100644 (file)
@@ -79,6 +79,7 @@ void fastboot_okay(const char *reason, char *response)
                fastboot_response("OKAY", response, NULL);
 }
 
+#if !defined(CONFIG_SPL_BUILD)
 /**
  * fastboot_set_reboot_flag() - Set flag to indicate reboot-bootloader
  *
@@ -142,7 +143,7 @@ void fastboot_boot(void)
 
                snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
                         "0x%p", fastboot_buf_addr);
-               printf("Booting kernel at %s...\n\n\n", boot_addr_start);
+               pr_info("Booting kernel at %s...\n\n\n", boot_addr_start);
 
                do_bootm(NULL, 0, 2, bootm_args);
 
@@ -154,6 +155,7 @@ void fastboot_boot(void)
                do_reset(NULL, 0, 0, NULL);
        }
 }
+#endif /*#!defined(CONFIG_SPL_BUILD)*/
 
 /**
  * fastboot_set_progress_callback() - set progress callback
index 018989dd166785744070fefd64992e8bf58e5f88..cc656fa8b37e2757588e838cef846f1f7b38afbd 100644 (file)
@@ -9,22 +9,34 @@
 #include <fastboot-internal.h>
 #include <fb_mmc.h>
 #include <fb_nand.h>
+#include <fb_mtd.h>
 #include <fs.h>
 #include <part.h>
 #include <version.h>
+#include <asm/global_data.h>
+#include <mtd.h>
+#include <fb_spacemit.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 static void getvar_version(char *var_parameter, char *response);
 static void getvar_version_bootloader(char *var_parameter, char *response);
+static void getvar_version_IC(char *var_parameter, char *response);
 static void getvar_downloadsize(char *var_parameter, char *response);
 static void getvar_serialno(char *var_parameter, char *response);
 static void getvar_version_baseband(char *var_parameter, char *response);
 static void getvar_product(char *var_parameter, char *response);
 static void getvar_platform(char *var_parameter, char *response);
 static void getvar_current_slot(char *var_parameter, char *response);
+#if CONFIG_IS_ENABLED(SPACEMIT_FLASH)
+static void getvar_mtd_size(char *var_parameter, char *response);
+static void getvar_blk_size(char *var_parameter, char *response);
+#endif
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 static void getvar_has_slot(char *var_parameter, char *response);
 #endif
-#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
 static void getvar_partition_type(char *part_name, char *response);
 #endif
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
@@ -42,6 +54,9 @@ static const struct {
        }, {
                .variable = "version-bootloader",
                .dispatch = getvar_version_bootloader
+       }, {
+               .variable = "version-IC",
+               .dispatch = getvar_version_IC
        }, {
                .variable = "downloadsize",
                .dispatch = getvar_downloadsize
@@ -60,6 +75,14 @@ static const struct {
        }, {
                .variable = "platform",
                .dispatch = getvar_platform
+#if CONFIG_IS_ENABLED(SPACEMIT_FLASH)
+       }, {
+               .variable = "mtd-size",
+               .dispatch = getvar_mtd_size
+       }, {
+               .variable = "blk-size",
+               .dispatch = getvar_blk_size
+#endif
        }, {
                .variable = "current-slot",
                .dispatch = getvar_current_slot
@@ -68,7 +91,7 @@ static const struct {
                .variable = "has-slot",
                .dispatch = getvar_has_slot
 #endif
-#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
        }, {
                .variable = "partition-type",
                .dispatch = getvar_partition_type
@@ -102,24 +125,41 @@ static int getvar_get_part_info(const char *part_name, char *response,
                                size_t *size)
 {
        int r;
-# if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
-       struct blk_desc *dev_desc;
-       struct disk_partition part_info;
+       u32 boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MTD) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MTD)
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               struct part_info *mtd_part_info;
+               r = fastboot_mtd_get_part_info(part_name, &mtd_part_info, response);
+               if (r >= 0 && size)
+                       *size = mtd_part_info->size;
+               break;
+#endif
 
-       r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
-                                      response);
-       if (r >= 0 && size)
-               *size = part_info.size * part_info.blksz;
-# elif CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
-       struct part_info *part_info;
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+               struct blk_desc *dev_desc;
+               struct disk_partition part_info;
+
+               r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
+                                               response);
+               if (r >= 0 && size)
+                       *size = part_info.size * part_info.blksz;
+               break;
+#endif
+       default:
+               fastboot_fail("this storage is not supported in bootloader", response);
+               r = -ENODEV;
+       }
 
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+       struct part_info *part_info;
        r = fastboot_nand_get_part_info(part_name, &part_info, response);
        if (r >= 0 && size)
                *size = part_info->size;
-# else
-       fastboot_fail("this storage is not supported in bootloader", response);
-       r = -ENODEV;
-# endif
+#endif
 
        return r;
 }
@@ -135,6 +175,19 @@ static void getvar_version_bootloader(char *var_parameter, char *response)
        fastboot_okay(U_BOOT_VERSION, response);
 }
 
+static void getvar_version_IC(char *var_parameter, char *response)
+{
+       struct fdt_header *working_fdt = (struct fdt_header *)gd->fdt_blob;
+       int len_fdt_size;
+       int  nodeoffset = fdt_path_offset(working_fdt, "/");
+       const char *nodep = fdt_getprop(working_fdt, nodeoffset, "compatible", &len_fdt_size);
+
+       if (nodep && len_fdt_size > 0) {
+               fastboot_okay(nodep, response);
+       }else
+               fastboot_okay("", response);
+}
+
 static void getvar_downloadsize(char *var_parameter, char *response)
 {
        fastboot_response("OKAY", response, "0x%08x", fastboot_buf_size);
@@ -181,6 +234,103 @@ static void getvar_current_slot(char *var_parameter, char *response)
        fastboot_okay("a", response);
 }
 
+#if CONFIG_IS_ENABLED(SPACEMIT_FLASH)
+/**
+ * @brief Get the mtd size and return, if not mtd dev exists, it would return NULL.
+       if there have multi mtd devices, it would only return the first one.
+ *
+ * @param var_parameter
+ * @param response
+ * @return return
+*/
+static void getvar_mtd_size(char *var_parameter, char *response)
+{
+       u32 boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MTD) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MTD)
+               /*if select nor/nand, it would check if mtd dev exists or not*/
+               struct mtd_info *mtd;
+               mtd_probe_devices();
+               mtd_for_each_device(mtd) {
+                       if (!mtd_is_partition(mtd)) {
+                               if (mtd->size / 0x40000000){
+                                       fastboot_response("OKAY", response, "%lldG", mtd->size / 0x40000000);
+                                       return;
+                               }
+                               if (mtd->size / 0x100000){
+                                       fastboot_response("OKAY", response, "%lldM", mtd->size / 0x100000);
+                                       return;
+                               }
+                               if (mtd->size / 0x400){
+                                       fastboot_response("OKAY", response, "%lldK", mtd->size / 0x400);
+                                       return;
+                               }
+                               return;
+
+                       }
+               }
+               fastboot_fail("flash to mtd dev but can not get mtd size", response);
+               return;
+#endif
+       default:
+               fastboot_okay("NULL", response);
+               return;
+       }
+}
+
+/**
+ * @brief Get the var blk size object,  if has blk device, it would return
+       string universal, or return NULL.
+ *
+ * @param var_parameter
+ * @param response
+ */
+static void getvar_blk_size(char *var_parameter, char *response)
+{
+       struct blk_desc *dev_desc = NULL;
+       const char *blk_name;
+       int blk_index;
+
+       u32 boot_mode = get_boot_pin_select();
+       switch(boot_mode){
+       case BOOT_MODE_NOR:
+#ifdef CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME
+               blk_name = CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME;
+               blk_index = CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX;
+
+               /*nvme devices need scan at first*/
+               if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)){
+                       run_command("nvme scan", 0);
+               }
+
+               dev_desc = blk_get_devnum_by_typename(blk_name, blk_index);
+               if (dev_desc != NULL)
+                       fastboot_okay("universal", response);
+               else
+                       fastboot_okay("NULL", response);
+               return;
+#endif
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+               blk_name = "mmc";
+               blk_index = CONFIG_FASTBOOT_FLASH_MMC_DEV;
+               dev_desc = blk_get_devnum_by_typename(blk_name, blk_index);
+               if (dev_desc != NULL)
+                       fastboot_okay("universal", response);
+               else
+                       fastboot_okay("NULL", response);
+               return;
+#endif
+       default:
+               fastboot_okay("NULL", response);
+               return;
+       }
+}
+#endif
+
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 static void getvar_has_slot(char *part_name, char *response)
 {
@@ -215,7 +365,7 @@ fail:
 }
 #endif
 
-#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
 static void getvar_partition_type(char *part_name, char *response)
 {
        int r;
@@ -238,7 +388,7 @@ static void getvar_partition_type(char *part_name, char *response)
 static void getvar_partition_size(char *part_name, char *response)
 {
        int r;
-       size_t size;
+       size_t size = 0;
 
        r = getvar_get_part_info(part_name, response, &size);
        if (r >= 0)
index 033c510bc0961ded09c37fcd93e013566e1d8256..ac965a8eea7c05c5540e0eafd492bf749527d3cb 100644 (file)
@@ -18,6 +18,9 @@
 #include <div64.h>
 #include <linux/compat.h>
 #include <android_image.h>
+#include <fb_spacemit.h>
+#include <u-boot/crc.h>
+#include <gzip.h>
 
 #define FASTBOOT_MAX_BLK_WRITE 16384
 
@@ -157,10 +160,17 @@ static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info,
 {
        struct fb_mmc_sparse *sparse = info->priv;
        struct blk_desc *dev_desc = sparse->dev_desc;
-
        return fb_mmc_blk_write(dev_desc, blk, blkcnt, buffer);
 }
 
+static lbaint_t fb_mmc_sparse_erase(struct sparse_storage *info,
+               lbaint_t blk, lbaint_t blkcnt, const void *buffer)
+{
+       struct fb_mmc_sparse *sparse = info->priv;
+       struct blk_desc *dev_desc = sparse->dev_desc;
+       return fb_mmc_blk_write(dev_desc, blk, blkcnt, NULL);
+}
+
 static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info,
                lbaint_t blk, lbaint_t blkcnt)
 {
@@ -494,6 +504,7 @@ static struct blk_desc *fastboot_mmc_get_dev(char *response)
        return ret;
 }
 
+
 /**
  * fastboot_mmc_flash_write() - Write image to eMMC for fastboot
  *
@@ -507,13 +518,61 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
 {
        struct blk_desc *dev_desc;
        struct disk_partition info = {0};
+#ifdef CONFIG_SPACEMIT_FLASH
+       static struct flash_dev *fdev = NULL;
+       u32 __maybe_unused fsbl_offset = 0;
+       /*save crc value to compare after flash image*/
+       u64 compare_val = 0;
+       /*use for gzip image*/
+       static u32 __maybe_unused part_offset_t = 0;
+       static char __maybe_unused part_name_t[20] = "";
+       unsigned long __maybe_unused src_len = ~0UL;
+       bool gzip_image = false;
+
+       if (fdev == NULL){
+               fdev = malloc(sizeof(struct flash_dev));
+               if (!fdev) {
+                       printf("Memory allocation failed!\n");
+               }
+               memset(fdev, 0, sizeof(struct flash_dev));
+               fdev->gptinfo.fastboot_flash_gpt = false;
+               /*would realloc the size while parsing the partition table*/
+               fdev->gptinfo.gpt_table = malloc(10);
+               fdev->mtd_table = malloc(10);
+               memset(fdev->gptinfo.gpt_table, '\0', 10);
+               memset(fdev->mtd_table, '\0', 10);
+               printf("init fdev success\n");
+       }
+
+       /* flash env */
+       /*if (strcmp(cmd, "env") == 0) {*/
+       /*      printf("flash env to emmc\n");*/
+       /*      fastboot_oem_flash_env(cmd, fastboot_buf_addr, download_bytes,*/
+       /*                                                      response, fdev);*/
+       /*      return;*/
+       /*}*/
+       if (strcmp(cmd, "bootinfo") == 0) {
+               printf("flash bootinfo\n");
+               fastboot_oem_flash_bootinfo(cmd, fastboot_buf_addr, download_bytes,
+                                                                       response, fdev);
+               return;
+       }
+
+#endif
 
 #ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
        if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) {
                dev_desc = fastboot_mmc_get_dev(response);
-               if (dev_desc)
+               if (dev_desc){
+#ifdef CONFIG_SPACEMIT_FLASH
+                       flash_mmc_boot_op(dev_desc, download_buffer, 1,
+                                       download_bytes, BOOT_INFO_EMMC_SPL0_OFFSET);
+                       fastboot_okay(NULL, response);
+#else
                        fb_mmc_boot_ops(dev_desc, download_buffer, 1,
                                        download_bytes, response);
+#endif
+               }
                return;
        }
        if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) {
@@ -527,6 +586,13 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
 
 #if CONFIG_IS_ENABLED(EFI_PARTITION)
        if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) {
+
+#ifdef CONFIG_SPACEMIT_FLASH
+               fastboot_oem_flash_gpt(cmd, fastboot_buf_addr, download_bytes,
+                                                               response, fdev);
+               return;
+#endif
+
                dev_desc = fastboot_mmc_get_dev(response);
                if (!dev_desc)
                        return;
@@ -604,9 +670,44 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
            fastboot_mmc_get_part_info(cmd, &dev_desc, &info, response) < 0)
                return;
 
-       if (is_sparse_image(download_buffer)) {
+       if (gzip_parse_header((uchar *)download_buffer, src_len) >= 0) {
+               /*is gzip data and equal part name*/
+               gzip_image = true;
+               if (strcmp(cmd, part_name_t)){
+                       pr_info("flash part name %s is not equal to %s, \n", cmd, part_name_t);
+                       strcpy(part_name_t, cmd);
+                       part_offset_t = 0;
+               }
+
+               void *decompress_addr = (void *)GZIP_DECOMPRESS_ADDR;
+               pr_info("decompress_addr:%p\n", decompress_addr);
+               if (run_commandf("unzip %x %x", download_buffer, decompress_addr)){
+                       printf("unzip gzip data fail, \n");
+                       fastboot_fail("unzip gzip data fail", response);
+                       return;
+               }
+
+               u32 decompress_size = env_get_hex("filesize", 0);
+               pr_info("get decompress_size:%x, \n", decompress_size);
+               download_buffer = decompress_addr;
+               download_bytes = decompress_size;
+               info.start += part_offset_t / info.blksz;
+
+               pr_info("write gzip raw data to part:%s, %p, %x, blkaddr:%lx\n", cmd, download_buffer, download_bytes, info.start);
+       } else {
+               strcpy(part_name_t, cmd);
+               part_offset_t = 0;
+       }
+
+       if (download_bytes > info.size * info.blksz){
+               printf("download_bytes is greater than part size\n");
+               fastboot_fail("download_bytes is greater than part size", response);
+               return;
+       }
+
+       if (!gzip_image && is_sparse_image(download_buffer)) {
                struct fb_mmc_sparse sparse_priv;
-               struct sparse_storage sparse;
+               struct sparse_storage sparse = { .erase = NULL };
                int err;
 
                sparse_priv.dev_desc = dev_desc;
@@ -615,6 +716,7 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
                sparse.start = info.start;
                sparse.size = info.size;
                sparse.write = fb_mmc_sparse_write;
+               sparse.erase = fb_mmc_sparse_erase;
                sparse.reserve = fb_mmc_sparse_reserve;
                sparse.mssg = fastboot_fail;
 
@@ -629,6 +731,15 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
        } else {
                write_raw_image(dev_desc, &info, cmd, download_buffer,
                                download_bytes, response);
+#ifdef CONFIG_SPACEMIT_FLASH
+               /*if download and flash div to many time, that the crc is not correct*/
+               printf("write_raw_image end\n");
+               // compare_val = crc32_wd(compare_val, (const uchar *)download_buffer, download_bytes, CHUNKSZ_CRC32);
+               compare_val += checksum64(download_buffer, download_bytes);
+               if (compare_blk_image_val(dev_desc, compare_val, info.start, info.blksz, download_bytes))
+                       fastboot_fail("compare crc fail", response);
+#endif
+               part_offset_t += download_bytes;
        }
 }
 
@@ -704,3 +815,96 @@ void fastboot_mmc_erase(const char *cmd, char *response)
               blks_size * info.blksz, cmd);
        fastboot_okay(NULL, response);
 }
+
+/**
+ * fastboot_mmc_read() - load data from eMMC for fastboot
+ *
+ * @part: Named partition to read
+ * @response: Pointer to fastboot response buffer
+ */
+u32 fastboot_mmc_read(const char *part, u32 offset,
+                                       void *download_buffer, char *response)
+{
+       struct blk_desc *dev_desc;
+       struct disk_partition info = {0};
+       lbaint_t hdr_sectors, off_blk, size_blk;
+       lbaint_t res;
+
+       if (do_get_part_info(&dev_desc, part, &info) < 0){
+               if (dev_desc && dev_desc->blksz > 0){
+                       info.blksz = dev_desc->blksz;
+                       info.size = dev_desc->lba;
+                       info.start = 0;
+               }else{
+                       fastboot_response("OKAY", response, "%08x", 0);
+                       return 0;
+               }
+       }
+
+       if (offset >= (info.size * info.blksz)){
+               fastboot_response("OKAY", response, "%08x", 0);
+               return 0;
+       }
+
+       /*transfer offset to blk size*/
+       off_blk = (offset / info.blksz) + info.start;
+       size_blk = info.size - (offset / info.blksz);
+
+       if (offset % info.blksz)
+               printf("offset should be align to 0x%lx, would change offset to 0x%lx\n",
+                                                               info.blksz, (offset / info.blksz) * info.blksz);
+
+       debug("info->blksize:%lx, off_blk:%lx, size_blk:%lx\n", info.blksz, off_blk, size_blk);
+
+       /*if size > buffer_size, it would only load buffer_size, and return offset*/
+       if (size_blk * info.blksz > fastboot_buf_size){
+               /* Read the boot image header */
+               hdr_sectors = fastboot_buf_size / info.blksz;
+       }else{
+               hdr_sectors = size_blk;
+       }
+
+       res = blk_dread(dev_desc, off_blk, hdr_sectors, download_buffer);
+       if (res != hdr_sectors) {
+               fastboot_fail("cannot read data from mmc", response);
+               return 0;
+       }
+
+       /*return had read size*/
+       fastboot_response("OKAY", response, "%08x", (u32)(hdr_sectors * info.blksz));
+       return hdr_sectors * info.blksz;
+}
+
+int get_partition_index_by_name(const char *part_name, int *part_index) {
+       struct blk_desc *dev_desc;
+       struct disk_partition part_info;
+       int ret;
+       int dev_index;
+
+       dev_index = mmc_get_env_dev();
+
+       dev_desc = blk_get_dev("mmc", dev_index);
+       if (!dev_desc) {
+               printf("Cannot find MMC device %d\n", dev_index);
+               return -ENODEV;
+       }
+
+       for (int p = 1; ; ++p) {
+               ret = part_get_info(dev_desc, p, &part_info);
+               if (ret == -ENOENT) {
+                       break;
+               } else if (ret < 0) {
+                       printf("Error getting partition info for partition %d: %d\n", p, ret);
+                       return ret;
+               }
+
+               if (strcmp(part_info.name, part_name) == 0) {
+                       *part_index = p;
+                       return 0;
+               }
+       }
+
+       printf("Cannot find partition: %s\n", part_name);
+       return -ENOENT;
+}
+
diff --git a/drivers/fastboot/fb_mtd.c b/drivers/fastboot/fb_mtd.c
new file mode 100644 (file)
index 0000000..491a71b
--- /dev/null
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <config.h>
+#include <common.h>
+#include <blk.h>
+#include <fb_mtd.h>
+#include <fastboot.h>
+#include <image-sparse.h>
+#include <image.h>
+#include <linux/mtd/mtd.h>
+#include <linux/compat.h>
+#include <android_image.h>
+#include <fb_spacemit.h>
+#include <fastboot-internal.h>
+#include <u-boot/crc.h>
+#include <mapmem.h>
+#include <mtd.h>
+
+struct fb_mtd_sparse {
+       struct mtd_info         *mtd;
+       struct part_info        *part;
+};
+
+static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
+{
+       return !do_div(size, mtd->writesize);
+}
+
+static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
+{
+       return !do_div(size, mtd->erasesize);
+}
+
+int fb_mtd_lookup(const char *partname,
+                         struct mtd_info **mtd,
+                         struct part_info **part)
+{
+       struct mtd_info *mtd_info;
+       int ret;
+       u8 pnum;
+
+       mtd_probe_devices();
+
+       struct mtd_device *dev;
+
+       ret = mtdparts_init();
+       if (ret) {
+               printf("Cannot initialize MTD partitions\n");
+               return -1;
+       }
+
+       ret = find_dev_and_part(partname, &dev, &pnum, part);
+       if (ret) {
+               printf("cannot find partition: '%s'\n", partname);
+               return -1;
+       }
+
+       mtd_info = get_mtd_device_nm(partname);
+       if(mtd_info == NULL)
+               printf("get mtd info is NULL\n");
+       if(*part == NULL)
+               printf("get mtd info is NULL\n");
+
+       if (IS_ERR_OR_NULL(mtd_info)){
+               printf("MTD device %s not found\n", partname);
+               *mtd = NULL;
+               return -1;
+       }else{
+               *mtd = mtd_info;
+               return 0;
+       }
+}
+
+int _fb_mtd_erase(struct mtd_info *mtd, u32 erase_size)
+{
+       bool scrub = false;
+       u64 len = 0;
+       struct erase_info erase_op = {};
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(mtd))
+               return -1;
+
+       printf("........ erased mtd part\n");
+       if (erase_size > mtd->size){
+               printf("erase size:%x is larger than mtd size:%llx\n", erase_size, mtd->size);
+               return -1;
+       }
+
+       if (!mtd_is_aligned_with_block_size(mtd, mtd->offset)) {
+               printf("mtd offset:%llx is not align to erase_size\n", mtd->offset);
+               return -1;
+       }
+
+       if (!mtd_is_aligned_with_block_size(mtd, erase_size)) {
+               printf("align erase_size to mtd->erase_size:%x\n", mtd->erasesize);
+               erase_size += mtd->erasesize - (erase_size % mtd->erasesize);
+       }
+
+       if (erase_size == 0)
+               len = mtd->size;
+       else
+               len = erase_size;
+
+       scrub = false;
+       erase_op.mtd = mtd;
+       erase_op.addr = 0;
+       erase_op.len = mtd->erasesize;
+       erase_op.scrub = scrub;
+
+       while (len) {
+               ret = mtd_erase(mtd, &erase_op);
+               if (ret) {
+                       /* Abort if its not a bad block error */
+                       if (ret != -EIO)
+                               break;
+                       printf("Skipping bad block at 0x%08llx\n",
+                              erase_op.addr);
+               }
+
+               len -= mtd->erasesize;
+               erase_op.addr += mtd->erasesize;
+       }
+
+       if (ret && ret != -EIO)
+               return -1;
+       else
+               return 0;
+}
+
+/**
+ * @brief read or write to mtd devices.
+ * 
+ * @param mtd 
+ * @return return 0 if read/write success.
+ */
+static int _fb_mtd_rw(struct mtd_info *mtd, ulong sector, ulong count,
+                                               void *buf, bool read)
+{
+       bool raw, woob, has_pages = false;
+       u64 start_off, off, len, remaining;
+       struct mtd_oob_ops io_op = {};
+       int ret = -1;
+
+       u8 *buffer = map_sysmem((u64)buf, 0);
+       if (!buffer)
+               return -1;
+
+       start_off = sector;
+       if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
+               printf("Offset not aligned with a page (0x%x)\n",
+                      mtd->writesize);
+               return ret;
+       }
+
+       len = count;
+       if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
+               len = round_up(len, mtd->writesize);
+               printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
+                      mtd->writesize, len);
+       }
+       if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
+               has_pages = true;
+
+       remaining = len;
+
+       io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
+       io_op.len = has_pages ? mtd->writesize : len;
+       io_op.ooblen = woob ? mtd->oobsize : 0;
+       io_op.datbuf = buffer;
+       io_op.oobbuf = woob ? &buffer[len] : NULL;
+
+       /* Search for the first good block after the given offset */
+       off = start_off;
+       while (mtd_block_isbad(mtd, off))
+               off += mtd->erasesize;
+
+       /* Loop over the pages to do the actual read/write */
+       while (remaining) {
+               /* Skip the block if it is bad */
+               if (mtd_is_aligned_with_block_size(mtd, off) &&
+                   mtd_block_isbad(mtd, off)) {
+                       off += mtd->erasesize;
+                       continue;
+               }
+
+               if (read)
+                       ret = mtd_read_oob(mtd, off, &io_op);
+               else
+                       ret = mtd_write_oob(mtd, off, &io_op);
+
+               if (ret) {
+                       printf("Failure while %s at offset 0x%llx\n",
+                              read ? "reading" : "writing", off);
+                       break;
+               }
+
+               off += io_op.retlen;
+               remaining -= io_op.retlen;
+               io_op.datbuf += io_op.retlen;
+               io_op.oobbuf += io_op.oobretlen;
+       }
+
+       if (ret) {
+               printf("%s on %s failed with error %d\n",
+                      read ? "Read" : "Write", mtd->name, ret);
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+
+int _fb_mtd_write(struct mtd_info *mtd, void *buffer, u32 offset,
+                         size_t length, size_t *written)
+{
+       int ret;
+
+       ret = _fb_mtd_rw(mtd, offset, length, buffer, false);
+       if (ret)
+               return -1;
+       else
+               return 0;
+}
+
+
+int _fb_mtd_read(struct mtd_info *mtd, void *buffer, u32 offset,
+                         size_t length, size_t *written)
+{
+       int ret;
+
+       /*if the length is not align to 4, data cannot be read from nor*/
+       length = roundup(length, 4);
+
+       ret = _fb_mtd_rw(mtd, offset, length, buffer, true);
+       if (ret)
+               return -1;
+       else
+               return 0;
+}
+
+static lbaint_t fb_mtd_sparse_write(struct sparse_storage *info,
+               lbaint_t blk, lbaint_t blkcnt, const void *buffer)
+{
+       struct fb_mtd_sparse *sparse = info->priv;
+       size_t written;
+       int ret;
+
+       ret = _fb_mtd_write(sparse->mtd, (void *)buffer,
+                            blk * info->blksz,
+                            blkcnt * info->blksz, &written);
+       if (ret < 0) {
+               printf("Failed to write sparse chunk\n");
+               return ret;
+       }
+
+       /*
+        * the return value must be 'blkcnt' ("good-blocks") plus the
+        * number of "bad-blocks" encountered within this space...
+        */
+       return written / info->blksz;
+}
+
+static lbaint_t fb_mtd_sparse_reserve(struct sparse_storage *info,
+               lbaint_t blk, lbaint_t blkcnt)
+{
+       int bad_blocks = 0;
+       return blkcnt + bad_blocks;
+}
+
+
+/**
+ * fastboot_mtd_get_part_info() - Lookup MTD partion by name
+ *
+ * @part_name: Named device to lookup
+ * @part_info: Pointer to returned part_info pointer
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_mtd_get_part_info(const char *part_name,
+                               struct part_info **part_info, char *response)
+{
+       struct mtd_info *mtd = NULL;
+
+       if(fb_mtd_lookup(part_name, &mtd, part_info)){
+               fastboot_fail("can not find mtd part", response);
+               return -1;
+       }
+       else{
+               fastboot_okay(NULL, response);
+               return 0;
+       }
+}
+
+/**
+ * fastboot_mtd_flash_write() - Write image to MTD for fastboot
+ *
+ * @cmd: Named device to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_mtd_flash_write(const char *cmd, void *download_buffer,
+                              u32 download_bytes, char *response)
+{
+       struct part_info *part;
+       struct mtd_info *mtd = NULL;
+       int ret;
+       char mtd_partition[20] = {'\0'};
+       char ubi_volume[20] = {'\0'};
+       char *token;
+       char cmd_buf[256];
+       int need_erase = 1;
+       u64 compare_val = 0;
+
+       printf("Starting fastboot_mtd_flash_write for %s\n", cmd);
+#ifdef CONFIG_SPACEMIT_FLASH
+       static struct flash_dev *fdev = NULL;
+
+       if (fdev == NULL){
+               fdev = malloc(sizeof(struct flash_dev));
+               if (!fdev) {
+                       printf("Memory allocation failed!\n");
+               }
+               memset(fdev, 0, sizeof(struct flash_dev));
+               fdev->gptinfo.fastboot_flash_gpt = false;
+               /*would realloc the size while parsing the partition table*/
+               fdev->gptinfo.gpt_table = malloc(10);
+               fdev->mtd_table = malloc(10);
+               memset(fdev->gptinfo.gpt_table, '\0', 10);
+               memset(fdev->mtd_table, '\0', 10);
+       }
+
+       /* Check commands and process them */
+       if (strchr(cmd, '-') != NULL) {
+               char *cmd_copy = strdup(cmd);
+               token = strtok(cmd_copy, "-");
+               if (token != NULL) {
+                       strcpy(mtd_partition, token);
+                       cmd = mtd_partition;
+
+                       token = strtok(NULL, "-");
+                       if (token != NULL) {
+                               strcpy(ubi_volume, token);
+                       }
+               }
+
+               free(cmd_copy);
+               printf("mtd_partition: %s\n", mtd_partition);
+               printf("ubi_volume: %s\n", ubi_volume);
+               const char *last_erased = env_get("last_erased_partition");
+               need_erase = last_erased == NULL || strcmp(last_erased, mtd_partition) != 0;
+       } else {
+               ubi_volume[0] = '\0';
+               printf("Normal mtd partition ......\n");
+       }
+
+       if (!strncmp(cmd, "mtd", 3)){
+               fastboot_oem_flash_gpt(cmd, fastboot_buf_addr, download_bytes,
+                                               response, fdev);
+               return;
+       }
+
+       /*flash env*/
+       /*if (strcmp(cmd, "env") == 0) {*/
+       /*      printf("flash env \n");*/
+       /*      fastboot_oem_flash_env(cmd, fastboot_buf_addr, download_bytes,*/
+       /*                                                      response, fdev);*/
+       /*      return;*/
+       /*}*/
+#endif
+
+       ret = fb_mtd_lookup(cmd, &mtd, &part);
+       printf("fb_mtd_lookup returned %d for %s\n", ret, cmd);
+       if (ret) {
+               pr_err("invalid mtd device \n");
+               fastboot_fail("invalid mtd device or partition", response);
+               return;
+       }
+
+       if (need_erase) {
+               /*must erase at first when write data to mtd devices*/
+               printf("Erasing MTD partition %s\n", part->name);
+               ret = _fb_mtd_erase(mtd, download_bytes);
+               if (ret) {
+                       printf("failed erasing from device %s\n", mtd->name);
+                       fastboot_fail("failed erasing from device", response);
+                       return;
+               }
+               env_set("last_erased_partition", mtd_partition);
+       }
+       printf("need_erase: %d\n", need_erase);
+
+       if (ubi_volume[0] != '\0') {
+
+               /* Select NAND device and attach to UBI subsystem */
+               snprintf(cmd_buf, sizeof(cmd_buf), "ubi part %s", mtd_partition);
+               printf("Executing command: %s\n", cmd_buf);
+               run_command(cmd_buf, 0);
+
+               /* Check if UBI volume exists */
+               printf("Checking if UBI volume '%s' exists.\n", ubi_volume);
+               snprintf(cmd_buf, sizeof(cmd_buf), "ubi check %s", ubi_volume);
+               printf("Executing command: %s\n", cmd_buf);
+               int ret = run_command(cmd_buf, 0);
+
+               /* If the UBI volume does not exist, create it */
+               if (ret != 0) {
+                       printf("UBI volume '%s' not found. Creating it.\n", ubi_volume);
+                       snprintf(cmd_buf, sizeof(cmd_buf), "ubi create %s 0x%X d", ubi_volume, download_bytes);
+                       printf("Executing command: %s\n", cmd_buf);
+                       run_command(cmd_buf, 0);
+               } else {
+                       printf("UBI volume '%s' already exists.\n", ubi_volume);
+               }
+
+               /* Write the downloaded data to the UBI volume */
+               printf("Writing data to UBI volume '%s'.\n", ubi_volume);
+               snprintf(cmd_buf, sizeof(cmd_buf), "ubi write %p %s 0x%X", download_buffer, ubi_volume, download_bytes);
+               printf("Executing command: %s\n", cmd_buf);
+               run_command(cmd_buf, 0);
+
+               fastboot_okay(NULL, response);
+               return;
+       }
+
+       if (is_sparse_image(download_buffer)) {
+               struct fb_mtd_sparse sparse_priv;
+               struct sparse_storage sparse = { .erase = NULL };
+
+               sparse_priv.mtd = mtd;
+               sparse_priv.part = part;
+
+               sparse.blksz = mtd->writesize;
+               sparse.start = part->offset / sparse.blksz;
+               sparse.size = part->size / sparse.blksz;
+               sparse.write = fb_mtd_sparse_write;
+               sparse.reserve = fb_mtd_sparse_reserve;
+               sparse.mssg = fastboot_fail;
+
+               printf("Flashing sparse image at offset %lx\n", sparse.start);
+               sparse.priv = &sparse_priv;
+               ret = write_sparse_image(&sparse, cmd, download_buffer,
+                                        response);
+       } else {
+               printf("Flashing raw image at offset \n");
+
+               ret = _fb_mtd_write(mtd, download_buffer, 0,
+                                    download_bytes, NULL);
+
+               if (ret < 0) {
+                       printf("Failed to write mtd part:%s\n", cmd);
+               }else{
+                       printf("........ wrote %u bytes to '%s'\n",
+                               download_bytes, part->name);
+               }
+
+               pr_info("compare data valid or not\n");
+               // crc_val = crc32_wd(crc_val, (const uchar *)download_buffer, download_bytes, CHUNKSZ_CRC32);
+               compare_val += checksum64(download_buffer, download_bytes);
+               if (compare_mtd_image_val(mtd, compare_val, download_bytes)){
+                       fastboot_fail("compare crc fail", response);
+                       return;
+               }
+       }
+
+       if (ret)
+               fastboot_fail("error writing the image", response);
+       else
+               fastboot_okay(NULL, response);
+       return;
+}
+
+/**
+ * fastboot_mtd_flash_erase() - Erase MTD for fastboot
+ *
+ * @cmd: Named device to erase
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_mtd_flash_erase(const char *cmd, char *response)
+{
+       struct part_info *part;
+       struct mtd_info *mtd = NULL;
+       int ret;
+
+       ret = fb_mtd_lookup(cmd, &mtd, &part);
+       if (ret) {
+               printf("invalid mtd device\n");
+               fastboot_fail("invalid mtd device or partition", response);
+               return;
+       }
+
+       ret = _fb_mtd_erase(mtd, 0);
+       if (ret) {
+               pr_err("failed erasing from device %s", mtd->name);
+               fastboot_fail("failed erasing from device", response);
+               return;
+       }
+
+       fastboot_okay(NULL, response);
+}
+
+/**
+ * fastboot_mtd_flash_read() - load data from mtd for fastboot
+ *
+ * @part_name: Named partition to read
+ * @response: Pointer to fastboot response buffer
+ */
+u32 fastboot_mtd_flash_read(const char *part_name, u32 offset,
+                                       void *download_buffer, char *response)
+{
+       struct part_info *part;
+       struct mtd_info *mtd = NULL;
+       int ret;
+       u32 hdr_size, hdr_off;
+
+       if (fb_mtd_lookup(part_name, &mtd, &part)) {
+               /*can not find mtd part, try to read raw data*/
+               if (strncmp("mtd", part_name, 3))
+                       return 0;
+
+               mtd_for_each_device(mtd) {
+                       if (!mtd_is_partition(mtd))
+                               break;
+               }
+
+               if (IS_ERR_OR_NULL(mtd)){
+                       printf("can not find mtd devices\n");
+                       return 0;
+               }
+
+               debug("get mtd name :%s, mtd->offset:%llx, %llx\n", mtd->name, mtd->offset, mtd->size);
+       }
+
+       if (offset >= mtd->size){
+               fastboot_response("OKAY", response, "%08x", 0);
+               return 0;
+       }
+       debug("mtd->offset:%llx, %llx\n", mtd->offset, mtd->size);
+
+       hdr_off = offset;
+       hdr_size = (u32)mtd->size - offset;
+
+       /*if size > buffer_size, it would only load buffer_size, and return offset*/
+       if (hdr_size > fastboot_buf_size){
+               /* Read the boot image header */
+               hdr_size = fastboot_buf_size;
+       }
+
+       ret = _fb_mtd_read(mtd, download_buffer, hdr_off, hdr_size, NULL);
+       if (ret){
+               fastboot_fail("cannot read data from mtd dev", response);
+               return -1;
+       }
+
+       fastboot_response("OKAY", response, "0x%08x", hdr_size);
+       return hdr_size;
+}
index 6d3a900c772884e00af166ebcfedb8d829772a99..7866141a3897f7d24c938a3db12667591108f49d 100644 (file)
@@ -189,7 +189,7 @@ void fastboot_nand_flash_write(const char *cmd, void *download_buffer,
 
        if (is_sparse_image(download_buffer)) {
                struct fb_nand_sparse sparse_priv;
-               struct sparse_storage sparse;
+               struct sparse_storage sparse = { .erase = NULL };
 
                sparse_priv.mtd = mtd;
                sparse_priv.part = part;
diff --git a/drivers/fastboot/fb_spacemit.c b/drivers/fastboot/fb_spacemit.c
new file mode 100644 (file)
index 0000000..e0a6b29
--- /dev/null
@@ -0,0 +1,1148 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <config.h>
+#include <fastboot.h>
+#include <malloc.h>
+#include <common.h>
+#include <fastboot-internal.h>
+#include <image-sparse.h>
+#include <image.h>
+#include <part.h>
+#include <mmc.h>
+#include <div64.h>
+#include <fb_spacemit.h>
+#include <mapmem.h>
+#include <memalign.h>
+#include <u-boot/crc.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <cJSON.h>
+#include <mtd.h>
+#include <spl.h>
+#include <linux/io.h>
+#include <fb_mtd.h>
+#include <nvme.h>
+#include <tlv_eeprom.h>
+#include <misc.h>
+#include <search.h>
+#include <env_internal.h>
+
+#define EMMC_MAX_BLK_WRITE 16384
+
+#if CONFIG_IS_ENABLED(SPACEMIT_FLASH)
+static int _write_gpt_partition(struct flash_dev *fdev, char *response)
+{
+       __maybe_unused char write_part_command[300] = {"\0"};
+       char *gpt_table_str = NULL;
+
+       u32 boot_mode = get_boot_pin_select();
+
+       if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 0){
+               gpt_table_str = malloc(strlen(fdev->gptinfo.gpt_table) + 32);
+               if (gpt_table_str == NULL){
+                       return -1;
+               }
+               sprintf(gpt_table_str, "env set -f partitions '%s'", fdev->gptinfo.gpt_table);
+               run_command(gpt_table_str, 0);
+               free(gpt_table_str);
+       }
+
+       switch(boot_mode){
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+               sprintf(write_part_command, "gpt write mmc %x '%s'",
+                       CONFIG_FASTBOOT_FLASH_MMC_DEV, fdev->gptinfo.gpt_table);
+               if (run_command(write_part_command, 0)){
+                       fastboot_fail("write gpt fail", response);
+                       return -1;
+               }
+               break;
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_SUPPORT_BLOCK_DEV)
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               pr_info("write gpt to dev:%s\n", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME);
+
+               /*nvme need scan at first*/
+               if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)
+                                               && nvme_scan_namespace()){
+                       fastboot_fail("can not can nvme devices!", response);
+                       return -1;
+               }
+
+               sprintf(write_part_command, "gpt write %s %x '%s'",
+                       CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX,
+                       fdev->gptinfo.gpt_table);
+               if (run_command(write_part_command, 0)){
+                       fastboot_fail("write gpt fail", response);
+                       return -1;
+               }
+               break;
+#endif
+       default:
+               break;
+       }
+
+
+       fastboot_okay("parse gpt/mtd table okay", response);
+       return 0;
+}
+
+int _clear_env_part(void *download_buffer, u32 download_bytes,
+                                                                struct flash_dev *fdev)
+{
+       u32 boot_mode = get_boot_pin_select();
+
+       /* char cmdbuf[64] = {"\0"}; */
+       /* sprintf(cmdbuf, "env export -c -s 0x%lx 0x%lx", (ulong)CONFIG_ENV_SIZE, (ulong)download_buffer); */
+       /* if (run_command(cmdbuf, 0)){ */
+       /*      return -1; */
+       /* } */
+
+       switch(boot_mode){
+#ifdef CONFIG_ENV_IS_IN_MMC
+       case BOOT_MODE_EMMC:
+       case BOOT_MODE_SD:
+               /*write to emmc default offset*/
+               debug("write env to mmc offset:%lx\n", (ulong)FLASH_ENV_OFFSET_MMC);
+
+               /*should not write env to env part*/
+               memset(download_buffer, 0, CONFIG_ENV_SIZE);
+               fastboot_mmc_flash_offset((u32)FLASH_ENV_OFFSET_MMC, download_buffer, (u32)CONFIG_ENV_SIZE);
+               break;
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MTD) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MTD)
+       case BOOT_MODE_NOR:
+       case BOOT_MODE_NAND:
+               if (strlen(fdev->mtd_table) > 0){
+                       pr_info("updata mtd env, table:%s\n", fdev->mtd_table);
+
+                       /* find env partition and write env data to mtd part*/
+                       struct part_info *part;
+                       struct mtd_info *mtd;
+                       int ret;
+                       ret = fb_mtd_lookup("env", &mtd, &part);
+                       if (ret) {
+                               pr_err("invalid mtd device\n");
+                               return -1;
+                       }
+                       ret = _fb_mtd_erase(mtd, CONFIG_ENV_SIZE);
+                       if (ret)
+                               return -1;
+
+                       /*should not write env to env part*/
+                       /* ret = _fb_mtd_write(mtd, download_buffer, 0, CONFIG_ENV_SIZE, NULL); */
+                       /* if (ret){ */
+                       /*      pr_err("can not write env to mtd flash\n"); */
+                       /* } */
+               }
+               break;
+#endif
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int _write_mtd_partition(char mtd_table[128], char *response)
+{
+#ifdef CONFIG_MTD
+       struct mtd_info *mtd;
+       char mtd_ids[36] = {"\0"};
+       char mtd_parts[128] = {"\0"};
+
+       mtd_probe_devices();
+
+       /*
+       try to find the first mtd device, it there have mutil mtd device such as nand and nor,
+       it only use the first one.
+       */
+       mtd_for_each_device(mtd) {
+               if (!mtd_is_partition(mtd))
+                       break;
+       }
+
+       if (mtd == NULL){
+               fastboot_fail("can not get mtd device", response);
+               return -1;
+       }
+
+       /*to mtd device, it should write mtd table to env.*/
+       sprintf(mtd_ids, "%s=spi-dev", mtd->name);
+       sprintf(mtd_parts, "spi-dev:%s", mtd_table);
+
+       env_set("mtdids", mtd_ids);
+       env_set("mtdparts", mtd_parts);
+#endif
+       fastboot_okay("parse gpt/mtd table okay", response);
+       return 0;
+}
+
+/**
+ * @brief transfer the string of size 'K' or 'M' to u32 type.
+ *
+ * @param reserve_size , the string of size
+ * @return int , return the transfer result.
+ */
+int transfer_string_to_ul(const char *reserve_size)
+{
+       char *ret, *token;
+       char ch[3] = {"\0"};
+       char strnum[10] = {"\0"};
+       u32 get_size = 0;
+       const char *get_char = reserve_size;
+
+       if (get_char == NULL || strlen(get_char) == 0)
+               return 0;
+
+       if (!strncmp("-", get_char, 1)){
+               return 0;
+       }
+
+       ret = strpbrk(get_char, "KMG");
+       if (ret == NULL){
+               pr_debug("can not get char\n");
+               return 0;
+       }
+       strncpy(ch, ret, 1);
+       if (ch[0] == 'K' || ch[0] == 'M' || ch[0] == 'G'){
+               pr_debug("reserve_size:%s, reserve_size len:%ld\n", reserve_size, strlen(reserve_size));
+               strncpy(strnum, reserve_size, strlen(reserve_size));
+               token = strtok(strnum, ch);
+               pr_debug("token:%s, ch:%s\n", token, ch);
+               get_size = simple_strtoul(token, NULL, 0);
+       }else{
+               pr_debug("not support size %s, should use K/M/G\n", reserve_size);
+               return 0;
+       }
+
+       switch(ch[0]){
+       case 'K':
+               return get_size;
+       case 'M':
+               return get_size * 1024;
+       case 'G':
+               return get_size * 1024 * 1024;
+       }
+       return 0;
+}
+
+/**
+ * @brief parse the flash_config and save partition info
+ *
+ * @param fdev , struct flash_dev
+ * @return u32 , return 0 if parse config success.
+ */
+int _parse_flash_config(struct flash_dev *fdev, void *load_flash_addr)
+{
+       u32 part_index = 0;
+       bool parse_mtd_partition = false;
+       cJSON *json_root;
+
+       int result = 0;
+       char *combine_str = NULL;
+       int combine_len = 1;
+       int combine_size = 0;
+       int combine_len_extra = 0;
+       int off = 0;
+
+       /*init and would remalloc while size is increasing*/
+       combine_str = malloc(combine_len);
+       memset(combine_str, '\0', combine_len);
+
+       json_root = cJSON_Parse(load_flash_addr);
+       if (!json_root){
+               pr_err("can not parse json, check your flash_config.cfg is json format or not\n");
+               return -1;
+       }
+
+       /*judge if parse mtd or gpt partition*/
+       cJSON *cj_format = cJSON_GetObjectItem(json_root, "format");
+       if (cj_format && cj_format->type == cJSON_String){
+               if (!strncmp("gpt", cj_format->valuestring, 3)){
+                       fdev->gptinfo.fastboot_flash_gpt = true;
+                       combine_len_extra = 20;
+               }else if(!strncmp("mtd", cj_format->valuestring, 3)){
+                       parse_mtd_partition = true;
+                       combine_len_extra = 6;
+               }
+       }
+
+       cJSON *cj_parts = cJSON_GetObjectItem(json_root, "partitions");
+       if (cj_parts && cj_parts->type == cJSON_Array){
+               for(int i = 0; i < cJSON_GetArraySize(cj_parts); i++){
+                       const char *node_part = NULL;
+                       const char *node_file = NULL;
+                       const char *node_offset = NULL;
+                       const char *node_size = NULL;
+
+                       cJSON *arraypart = cJSON_GetArrayItem(cj_parts, i);
+                       cJSON *cj_name = cJSON_GetObjectItem(arraypart, "name");
+                       if (cj_name && cj_name->type == cJSON_String)
+                               node_part = cj_name->valuestring;
+                       else
+                               node_part = "";
+
+                       /*only blk dev would not add bootinfo partition*/
+                       if (!parse_mtd_partition){
+                               if (strlen(node_part) > 0 && !strncmp("bootinfo", node_part, 8)){
+                                       pr_info("bootinfo would not add as partition\n");
+                                       continue;
+                               }
+                       }
+
+                       cJSON *cj_filename = cJSON_GetObjectItem(arraypart, "image");
+                       if (cj_filename && cj_filename->type == cJSON_String)
+                               node_file = cj_filename->valuestring;
+                       else
+                               node_file = "";
+
+                       cJSON *cj_volume_images = cJSON_GetObjectItem(arraypart, "volume_images");
+                       if (cj_volume_images) {
+                               int volume_count = cJSON_GetArraySize(cj_volume_images);
+                               fdev->parts_info[part_index].volume_images = malloc(volume_count * sizeof(struct flash_volume_image));
+                               fdev->parts_info[part_index].volume_images_count = volume_count;
+
+                               int volume_index = 0;
+                               cJSON *cj_volume_image = NULL;
+                               cJSON_ArrayForEach(cj_volume_image, cj_volume_images) {
+                                       const char *volume_name = cj_volume_image->string;
+                                       const char *image_file = cj_volume_image->valuestring;
+
+                                       fdev->parts_info[part_index].volume_images[volume_index].name = strdup(volume_name);
+                                       fdev->parts_info[part_index].volume_images[volume_index].file_name = strdup(image_file);
+                                       volume_index++;
+                               }
+                       }
+
+                       cJSON *cj_offset = cJSON_GetObjectItem(arraypart, "offset");
+                       if (cj_offset && cj_offset->type == cJSON_String)
+                               node_offset = cj_offset->valuestring;
+                       else
+                               node_offset = "";
+
+                       cJSON *cj_size = cJSON_GetObjectItem(arraypart, "size");
+                       if (cj_size && cj_size->type == cJSON_String)
+                               node_size = cj_size->valuestring;
+                       else
+                               node_size = "";
+
+                       /*make sure that offset would not over than previous size and offset*/
+                       off = transfer_string_to_ul(node_offset);
+
+                       if (off > 0 && off < combine_size){
+                               pr_err("offset must larger then previous, off:%x, combine_size:%x\n", off, combine_size);
+                               return -5;
+                       }
+
+                       combine_len += strlen(node_part) + strlen(node_offset) + strlen(node_size) + combine_len_extra;
+                       combine_str = realloc(combine_str, combine_len);
+                       if (combine_str == NULL){
+                               pr_err("realloc combine_str fail\n");
+                               return -1;
+                       }
+
+                       /*if next part has define offset, use it offset, or it would caculate front part offset and size*/
+                       if (off > 0)
+                               combine_size = off;
+
+                       if (parse_mtd_partition){
+                               /*parse mtd partition*/
+                               if (strlen(combine_str) == 0)
+                                       sprintf(combine_str, "%s%s@%dK(%s)", combine_str, node_size, combine_size, node_part);
+                               else
+                                       sprintf(combine_str, "%s,%s@%dK(%s)", combine_str, node_size, combine_size, node_part);
+                       }else if (fdev->gptinfo.fastboot_flash_gpt){
+                               /*parse gpt partition*/
+                               if (strlen(node_offset) == 0)
+                                       sprintf(combine_str, "%sname=%s,size=%s;", combine_str, node_part, node_size);
+                               else
+                                       sprintf(combine_str, "%sname=%s,start=%s,size=%s;", combine_str, node_part, node_offset, node_size);
+                       }
+                       combine_size += transfer_string_to_ul(node_size);
+
+                       /*after finish recovery, it would free the malloc paramenter at func recovery_show_result*/
+                       fdev->parts_info[part_index].part_name = malloc(strlen(node_part));
+                       if (!fdev->parts_info[part_index].part_name){
+                               pr_err("malloc part_name fail\n");
+                               result = RESULT_FAIL;
+                               goto free_cjson;
+                       }
+                       strcpy(fdev->parts_info[part_index].part_name, node_part);
+
+                       fdev->parts_info[part_index].size = malloc(strlen(node_size));
+                       if (!fdev->parts_info[part_index].size){
+                               pr_err("malloc size fail\n");
+                               result = RESULT_FAIL;
+                               goto free_cjson;
+                       }
+
+                       strcpy(fdev->parts_info[part_index].size, node_size);
+
+                       if (node_file == NULL){
+                               pr_err("not set file name, set to null\n");
+                               fdev->parts_info[part_index].file_name = NULL;
+                       }else{
+                               fdev->parts_info[part_index].file_name = malloc(strlen(node_file) + strlen(FLASH_IMG_FOLDER) + 2);
+                               if (!fdev->parts_info[part_index].file_name){
+                                       pr_err("malloc file_name fail\n");
+                                       result = RESULT_FAIL;
+                                       goto free_cjson;
+                               }
+                               if (strlen(FLASH_IMG_FOLDER) > 0){
+                                       strcpy(fdev->parts_info[part_index].file_name, FLASH_IMG_FOLDER);
+                                       strcat(fdev->parts_info[part_index].file_name, "/");
+                                       strcat(fdev->parts_info[part_index].file_name, node_file);
+                               }else{
+                                       strcpy(fdev->parts_info[part_index].file_name, node_file);
+                               }
+                       }
+
+                       pr_info("Part info: %s, %s\n", fdev->parts_info[part_index].part_name, fdev->parts_info[part_index].file_name ? fdev->parts_info[part_index].file_name : "None");
+                       if (fdev->parts_info[part_index].volume_images_count > 0) {
+                               for (int j = 0; j < fdev->parts_info[part_index].volume_images_count; j++) {
+                                       pr_info("Volume name: %s, Image file: %s\n",
+                                               fdev->parts_info[part_index].volume_images[j].name,
+                                               fdev->parts_info[part_index].volume_images[j].file_name);
+                               }
+                       }
+                       part_index++;
+               }
+       }else{
+               pr_err("do not get partition info, check the input file\n");
+               return -1;
+       }
+       if (parse_mtd_partition){
+               fdev->mtd_table = realloc(fdev->mtd_table, combine_len);
+               strcpy(fdev->mtd_table, combine_str);
+       }
+       else{
+               fdev->gptinfo.gpt_table = realloc(fdev->gptinfo.gpt_table, combine_len);
+               strcpy(fdev->gptinfo.gpt_table, combine_str);
+       }
+
+free_cjson:
+       cJSON_free(json_root);
+       free(combine_str);
+       return result;
+}
+
+
+
+/**
+ * fastboot_oem_flash_gpt() - parse flash_config and write gpt table.
+ *
+ * @cmd: Named partition to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_oem_flash_gpt(const char *cmd, void *download_buffer, u32 download_bytes,
+                                                       char *response, struct flash_dev *fdev)
+{
+       int ret = 0;
+
+       ret = _parse_flash_config(fdev, (void *)fastboot_buf_addr);
+       if (ret){
+               if (ret == -1){
+                       pr_err("parsing config fail\n");
+               }
+               if (ret == -5)
+                       fastboot_fail("offset must larger then previous size and offset", response);
+               return;
+       }
+
+       if (strlen(fdev->gptinfo.gpt_table) > 0 && fdev->gptinfo.fastboot_flash_gpt){
+               _write_gpt_partition(fdev, response);
+       }
+
+       if (strlen(fdev->mtd_table) > 0){
+               _write_mtd_partition(fdev->mtd_table, response);
+       }
+
+       /*set partition to env*/
+       if (_clear_env_part(download_buffer, download_bytes, fdev)){
+               fastboot_fail("clear env fail", response);
+               return;
+       }
+
+       /*maybe there doesn't have gpt/mtd partition, should not return fail*/
+       fastboot_okay("parse gpt/mtd table okay", response);
+       return;
+}
+
+/**
+ * @brief flash env to reserve partition.
+ *
+ * @param cmd env
+ * @param download_buffer load env.bin to addr
+ * @param download_bytes env.bin size
+ * @param response
+ * @param fdev
+ */
+void fastboot_oem_flash_env(const char *cmd, void *download_buffer, u32 download_bytes,
+                                                       char *response, struct flash_dev *fdev)
+{
+       char cmdbuf[64] = {'\0'};
+
+       /*load env.bin*/
+       sprintf(cmdbuf, "env import -c 0x%lx 0x%lx", (ulong)download_buffer, (ulong)CONFIG_ENV_SIZE);
+
+       if (run_command(cmdbuf, 0)){
+               pr_err("can not import env, try to load env.txt\n");
+               memset(cmdbuf, '\0', 32);
+               /*load env.txt*/
+               sprintf(cmdbuf, "env import -t 0x%lx", (ulong)download_buffer);
+               if (run_command(cmdbuf, 0)){
+                       fastboot_fail("Cannot flash env partition", response);
+                       return;
+               }
+       }
+
+       if (_clear_env_part(download_buffer, download_bytes, fdev)){
+               fastboot_fail("clear env fail", response);
+               return;
+       }
+
+       fastboot_okay("flash env partition okay", response);
+       return;
+}
+
+
+/**
+ * fb_mmc_blk_write() - Write/erase MMC in chunks of EMMC_MAX_BLK_WRITE
+ *
+ * @block_dev: Pointer to block device
+ * @start: First block to write/erase
+ * @blkcnt: Count of blocks
+ * @buffer: Pointer to data buffer for write or NULL for erase
+ */
+static __maybe_unused lbaint_t fb_mmc_blk_write(struct blk_desc *block_dev, lbaint_t start,
+                                lbaint_t blkcnt, const void *buffer)
+{
+       lbaint_t blk = start;
+       lbaint_t blks_written;
+       lbaint_t cur_blkcnt;
+       lbaint_t blks = 0;
+       int i;
+
+       for (i = 0; i < blkcnt; i += EMMC_MAX_BLK_WRITE) {
+               cur_blkcnt = min((int)blkcnt - i, EMMC_MAX_BLK_WRITE);
+               if (buffer) {
+                       if (fastboot_progress_callback)
+                               fastboot_progress_callback("writing");
+                       blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
+                                                 buffer + (i * block_dev->blksz));
+               } else {
+                       if (fastboot_progress_callback)
+                               fastboot_progress_callback("erasing");
+                       blks_written = blk_derase(block_dev, blk, cur_blkcnt);
+               }
+               blk += blks_written;
+               blks += blks_written;
+       }
+       return blks;
+}
+
+int flash_mmc_boot_op(struct blk_desc *dev_desc, void *buffer,
+                                                       int hwpart, u32 buff_sz, u32 offset)
+{
+       lbaint_t blkcnt;
+       lbaint_t blks;
+       lbaint_t blkoff;
+       unsigned long blksz;
+
+       // To operate on EMMC_BOOT1/2 (mmc0boot0/1) we first change the hwpart
+       if (blk_dselect_hwpart(dev_desc, hwpart)) {
+               pr_err("Failed to select hwpart\n");
+               return -1;
+       }
+
+       if (buffer) { /* flash */
+               pr_info("%s, %p\n", __func__, buffer);
+               /* determine number of blocks to write */
+               blksz = dev_desc->blksz;
+               blkcnt = ((buff_sz + (blksz - 1)) & ~(blksz - 1));
+               blkcnt = lldiv(blkcnt, blksz);
+
+               if (blkcnt > dev_desc->lba) {
+                       pr_err("Image size too large\n");
+                       return -1;
+               }
+               if (offset % blksz) {
+                               pr_err("offset must be %lx align\n", blksz);
+                               return -1;
+               }
+
+               debug("Start Flashing Image to EMMC_BOOT%d...\n", hwpart);
+               blkoff = offset / blksz;
+               blks = fb_mmc_blk_write(dev_desc, blkoff, blkcnt, buffer);
+
+               if (blks != blkcnt) {
+                       pr_err("Failed to write EMMC_BOOT%d\n", hwpart);
+                       return -1;
+               }
+
+               pr_info("........ wrote %lu bytes to EMMC_BOOT%d\n",
+                          blkcnt * blksz, hwpart);
+       }
+
+       return 0;
+}
+
+/**
+ * fastboot_mmc_flash_offset() - Write fsbl image to eMMC
+ *
+ * @start_offset: start offset to write.
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ */
+int fastboot_mmc_flash_offset(u32 start_offset, void *download_buffer,
+                                                        u32 download_bytes)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       struct blk_desc *dev_desc;
+       struct disk_partition info = {0};
+       lbaint_t blkcnt;
+       u32 offset = start_offset;
+       lbaint_t blks;
+
+       dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+       if (!dev_desc){
+               return -1;
+       }
+       part_get_info(dev_desc, 1, &info);
+       info.blksz = dev_desc->blksz;
+       if(info.blksz == 0)
+               return -1;
+       if (!download_bytes){
+               pr_err("it should run command 'fastboot stage fsbl.bin' before run flash fsbl\n");
+               return -1;
+       }
+
+       info.start = offset / info.blksz;
+       /* determine number of blocks to write */
+       blkcnt = ((download_bytes + (info.blksz - 1)) & ~(info.blksz - 1));
+       blkcnt = lldiv(blkcnt, info.blksz);
+
+       blks = fb_mmc_blk_write(dev_desc, info.start, blkcnt, download_buffer);
+
+       if (blks != blkcnt) {
+                       pr_err("failed writing to device %d\n", dev_desc->devnum);
+                       return -1;
+       }
+
+       pr_info("........ wrote 0x%lx sector bytes to blk offset 0x%lx\n", blkcnt, info.start);
+#endif
+       return 0;
+}
+
+
+u64 checksum64(u64 *baseaddr, u64 size)
+{
+       u64 sum = 0;
+       u64 i, cachelines;
+       u64 dwords, bytes;
+       u8 *data;
+
+       // each cache line has 64bytes
+       cachelines = size / 64;
+       bytes = size % 64;
+       dwords = bytes / 8;
+       bytes = bytes % 8;
+
+       for (i = 0; i < cachelines; i++) {
+               u64 val1 = *(baseaddr + 0);
+               u64 val2 = *(baseaddr + 1);
+               u64 val3 = *(baseaddr + 2);
+               u64 val4 = *(baseaddr + 3);
+               u64 val5 = *(baseaddr + 4);
+               u64 val6 = *(baseaddr + 5);
+               u64 val7 = *(baseaddr + 6);
+               u64 val8 = *(baseaddr + 7);
+
+               sum += val1;
+               sum += val2;
+               sum += val3;
+               sum += val4;
+               sum += val5;
+               sum += val6;
+               sum += val7;
+               sum += val8;
+               baseaddr += 8;
+       }
+
+       /*calculate the rest of dowrd*/
+       for (i = 0; i < dwords; i++) {
+               sum += *baseaddr;
+               baseaddr++;
+       }
+
+       data = (u8*)baseaddr;
+       /*calculate the rest of byte*/
+       for (i = 0; i < bytes; i++) {
+               sum += data[i];
+       }
+
+       return sum;
+}
+
+int compare_blk_image_val(struct blk_desc *dev_desc, u64 compare_val, lbaint_t part_start_cnt,
+                       ulong blksz, uint64_t image_size)
+{
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+       u32 div_times = (image_size + RECOVERY_LOAD_IMG_SIZE - 1) / RECOVERY_LOAD_IMG_SIZE;
+       u64 calculate = 0;
+       uint64_t byte_remain = image_size;
+       uint64_t download_bytes = 0;
+       u32 blk_size, n;
+       unsigned long time_start_flash = get_timer(0);
+
+       /*if compare_val is 0, return 0 directly*/
+       if (!compare_val)
+               return 0;
+
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid mmc device\n");
+               return -1;
+       }
+
+       for (int i = 0; i < div_times; i++) {
+               pr_info("\ndownload and flash div %d\n", i);
+               download_bytes = byte_remain > RECOVERY_LOAD_IMG_SIZE ? RECOVERY_LOAD_IMG_SIZE : byte_remain;
+
+               blk_size = (download_bytes + (blksz - 1)) / blksz;
+               n = blk_dread(dev_desc, part_start_cnt, blk_size, load_addr);
+               if (n != blk_size) {
+                       pr_err("mmc read blk not equal it should be\n");
+                       return -1;
+               }
+               // calculate = crc32_wd(crc, (const uchar *)load_addr, download_bytes, CHUNKSZ_CRC32);
+               calculate += checksum64(load_addr, download_bytes);
+
+               part_start_cnt += blk_size;
+               byte_remain -= download_bytes;
+       }
+
+       pr_info("get calculate value:%llx, compare calculate:%llx\n", calculate, compare_val);
+       time_start_flash = get_timer(time_start_flash);
+       pr_info("\ncompare over, use time:%lu ms\n\n", time_start_flash);
+       return (calculate == compare_val) ? 0 : -1;
+}
+
+
+int compare_mtd_image_val(struct mtd_info *mtd, u64 compare_val, uint64_t image_size)
+{
+       void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
+       u32 div_times = (image_size + RECOVERY_LOAD_IMG_SIZE - 1) / RECOVERY_LOAD_IMG_SIZE;
+       u64 calculate = 0;
+       uint64_t byte_remain = image_size;
+       uint64_t download_bytes = 0;
+       u32 hdr_off = 0;
+       int ret;
+
+       debug("mtd size:%llx, image_size:%llx\n", mtd->size, image_size);
+       unsigned long time_start_flash = get_timer(0);
+
+       /*if compare_val is 0, return 0 directly*/
+       if (!compare_val)
+               return 0;
+
+       for (int i = 0; i < div_times; i++) {
+               pr_info("\ndownload and flash div %d\n", i);
+               download_bytes = byte_remain > RECOVERY_LOAD_IMG_SIZE ? RECOVERY_LOAD_IMG_SIZE : byte_remain;
+               ret = _fb_mtd_read(mtd, load_addr, hdr_off, download_bytes, NULL);
+               if (ret){
+                       pr_err("cannot read data from mtd dev\n");
+                       return -1;
+               }
+
+               // calculate = crc32_wd(calculate, (const uchar *)load_addr, download_bytes, CHUNKSZ_CRC32);
+               calculate += checksum64(load_addr, download_bytes);
+               hdr_off += download_bytes;
+               byte_remain -= download_bytes;
+       }
+
+       pr_info("get calculate value:%llx, compare calculate:%llx\n", calculate, compare_val);
+       time_start_flash = get_timer(time_start_flash);
+       pr_info("compare over, use time:%lu ms\n\n", time_start_flash);
+       return (calculate == compare_val) ? 0 : -1;
+}
+
+
+/**
+ * @brief flash bootinfo to reserve partition.
+ *
+ * @param cmd
+ * @param download_buffer
+ * @param download_bytes
+ * @param response
+ * @param fdev
+ */
+void fastboot_oem_flash_bootinfo(const char *cmd, void *download_buffer, 
+               u32 download_bytes, char *response, struct flash_dev *fdev)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
+       debug("%s\n", __func__);
+       struct blk_desc *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+
+       if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+               pr_err("invalid mmc device\n");
+               if (response)
+                       fastboot_fail("invalid mmc device", response);
+               return;
+       }
+
+       /*fill up emmc bootinfo*/
+       struct boot_parameter_info *boot_info;
+       boot_info = (struct boot_parameter_info *)download_buffer;
+       memset(boot_info, 0, sizeof(boot_info));
+       boot_info->magic_code = BOOT_INFO_EMMC_MAGICCODE;
+       boot_info->version_number = BOOT_INFO_EMMC_VERSION;
+       boot_info->page_size = BOOT_INFO_EMMC_PAGESIZE;
+       boot_info->block_size = BOOT_INFO_EMMC_BLKSIZE;
+       boot_info->total_size = BOOT_INFO_EMMC_TOTALSIZE;
+       boot_info->spl0_offset = BOOT_INFO_EMMC_SPL0_OFFSET;
+       boot_info->spl1_offset = BOOT_INFO_EMMC_SPL1_OFFSET;
+       boot_info->spl_size_limit = BOOT_INFO_EMMC_LIMIT;
+       strcpy(boot_info->flash_type, "eMMC");
+       boot_info->crc32 = crc32_wd(0, (const uchar *)boot_info, 0x40, CHUNKSZ_CRC32);
+
+       /*flash bootinfo*/
+       pr_info("bootinfo:%p, boot_info->crc32:%x, sizeof(boot_info):%lx, download_buffer:%p\n", boot_info, boot_info->crc32, sizeof(boot_info), download_buffer);
+
+       if (flash_mmc_boot_op(dev_desc, download_buffer, 1, sizeof(boot_info), 0)){
+               if (response)
+                       fastboot_fail("flash mmc boot fail", response);
+               return;
+       }
+       if (response)
+               fastboot_okay(NULL, response);
+#endif
+
+       return;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
+struct oem_config_info
+{
+       const char *name;
+       uint32_t id;
+       uint32_t max_len;
+       char* (*convert)(char *);
+};
+const struct oem_config_info config_info[] = {
+       { "product_name", TLV_CODE_PRODUCT_NAME, 16, NULL },
+       { "serial#", TLV_CODE_SERIAL_NUMBER, 12, NULL },
+       { "ethaddr", TLV_CODE_MAC_BASE, 17, NULL },
+       { "manufacture_date", TLV_CODE_MANUF_DATE, 19, NULL },
+       { "device_version", TLV_CODE_DEVICE_VERSION, 3, NULL },
+       { "manufacturer", TLV_CODE_MANUF_NAME, 32, NULL },
+       { "sdk_version", TLV_CODE_SDK_VERSION, 3, NULL},
+       { "ddr_cs_num", TLV_CODE_DDR_CSNUM, 3, NULL},
+       { "pmic_type", TLV_CODE_PMIC_TYPE, 3, NULL},
+       { "eeprom_i2c_index", TLV_CODE_EEPROM_I2C_INDEX, 3, NULL},
+       { "eeprom_pin_group", TLV_CODE_EEPROM_PIN_GROUP, 3, NULL},
+};
+
+static int write_config_info_to_eeprom(uint32_t id, char *value)
+{
+       char *cmd_str;
+
+       cmd_str = malloc(256);
+       if (NULL == cmd_str) {
+               pr_err("malloc buffer for cmd string fail\n");
+               return -1;
+       }
+
+       pr_info("write data to EEPROM, ID:%d, string:%s\n", id, value);
+       /* read eeprom */
+       sprintf(cmd_str, "tlv_eeprom read");
+       if (run_command(cmd_str, 0)) {
+               free(cmd_str);
+               pr_err("tlv_eeprom read fail\n");
+               return 1;
+       }
+
+       // update eeprom data, need add '' for value string that may have space inside
+       sprintf(cmd_str, "tlv_eeprom set %d '%s'", id, value);
+       if (run_command(cmd_str, 0)) {
+               free(cmd_str);
+               pr_err("tlv_eeprom set %s to %d fail\n", value, id);
+               return 2;
+       }
+
+       if (run_command("tlv_eeprom write", 0)) {
+               free(cmd_str);
+               pr_err("tlv_eeprom write fail\n");
+               return 3;
+       }
+
+       free(cmd_str);
+       return 0;
+}
+
+#if CONFIG_IS_ENABLED(SPACEMIT_K1X_EFUSE)
+static int write_config_info_to_efuse(uint32_t id, char *value)
+{
+       struct udevice *dev;
+       uint8_t fuses[2];
+       int ret;
+
+       /* retrieve the device */
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                                         DM_DRIVER_GET(spacemit_k1x_efuse), &dev);
+       if (ret) {
+               return ret;
+       }
+
+       memset(fuses, 0, sizeof(fuses));
+       if (TLV_CODE_PMIC_TYPE == id)
+               fuses[1] |= dectoul(value, NULL) & 0x0F;
+       else if (TLV_CODE_EEPROM_I2C_INDEX == id)
+               fuses[0] |= dectoul(value, NULL) & 0x0F;
+       else if (TLV_CODE_EEPROM_PIN_GROUP == id)
+               fuses[0] |= (dectoul(value, NULL) & 0x03) << 4;
+       else {
+               pr_err("NOT support efuse ID %d\n", id);
+               return EFAULT;
+       }
+
+       // write to efuse, each bank has 32byte efuse data
+       return misc_write(dev, K1_EFUSE_USER_BANK0 * 32, fuses, sizeof(fuses));
+}
+#endif
+
+static struct oem_config_info* get_config_info(char *key)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(config_info); i++) {
+               if (0 == strcmp(key, config_info[i].name))
+                       return (struct oem_config_info*)&config_info[i];
+       }
+
+       return NULL;
+}
+
+static void read_oem_configuration(char *config, char *response)
+{
+       char *key;
+       struct oem_config_info* info;
+       char *ack, *value, *temp;
+       int i = 0, j;
+
+       ack = malloc(256);
+       if (NULL == ack) {
+               pr_err("malloc buffer for ack fail\n");
+               return;
+       }
+
+       temp = malloc(256);
+       if (NULL == temp) {
+               free(ack);
+               pr_err("malloc buffer for temp fail\n");
+               return;
+       }
+       memset(ack, 0, 256);
+
+       key = strsep(&config, ",");
+       while (NULL != key) {
+               pr_debug("try to find config info for %s\n", key);
+               info = get_config_info(key);
+               if (NULL != info) {
+                       value = env_get(key);
+                       if (NULL != info->convert)
+                               value = info->convert(value);
+                       // make sure value string is NOT exceed temp buffer
+                       if ((NULL != value) && (strlen(value) < 128)) {
+                               memset(temp, 0, 256);
+                               sprintf(temp, "%s", value);
+                               j = strlen(temp);
+                               if ((i + j) < 256) {
+                                       // add comma between two info dictionary
+                                       if (0 != i)
+                                               ack[i++] = ',';
+                                       memcpy(ack + i, temp, j);
+                                       i += j;
+                               }
+                       }
+               }
+               key = strsep(&config, ",");
+       }
+
+       if (0 != i) {
+               fastboot_okay(ack, response);
+       } else {
+               fastboot_fail("NOT exist", response);
+       }
+
+       free(ack);
+       free(temp);
+}
+
+static void write_oem_configuration(char *config, char *response)
+{
+       char *key, *value, *dest;
+       const struct oem_config_info* info;
+       int (*config_write)(uint32_t id, char *value), ret = -1;
+
+       dest = strsep(&config, ":");
+       key = strsep(&dest, "@");
+       value = config;
+       pr_info("try to set config info for %s: %s@%s\n", key, value, dest);
+
+       if (0 == strcmp(dest, "eeprom"))
+               config_write = write_config_info_to_eeprom;
+#if CONFIG_IS_ENABLED(SPACEMIT_K1X_EFUSE)
+       else if (0 == strcmp(dest, "efuse"))
+               config_write = write_config_info_to_efuse;
+#endif
+       else {
+               fastboot_fail("NOT support destination", response);
+               return;
+       }
+
+       info = get_config_info(key);
+       if ((NULL != info) && (strlen(value) <= info->max_len)) {
+               if (0 == config_write(info->id, value)) {
+                       env_set(key, value);
+                       ret = 0;
+               }
+       }
+
+       if (0 == ret)
+               fastboot_okay(NULL, response);
+       else
+               fastboot_fail("NOT exist", response);
+}
+
+static void flush_oem_configuration(char *config, char *response)
+{
+       fastboot_okay(NULL, response);
+}
+
+/**
+ * fastboot_config_access() - Access configurations.
+ *
+ * @operation: Pointer to operation string
+ *                       read: read configuration
+ *                       write: write configuration
+ * @config: Pointer to config string
+ *                       if is read operation, then
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_config_access(char *operation, char *config, char *response)
+{
+       if (0 == strcmp(operation, "read"))
+               read_oem_configuration(config, response);
+       else if (0 == strcmp(operation, "write"))
+               write_oem_configuration(config, response);
+       else if (0 == strcmp(operation, "flush"))
+               flush_oem_configuration(config, response);
+       else
+               fastboot_fail("NOT support", response);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
+#if defined(CONFIG_SPL_BUILD)
+extern char *product_name;
+static void read_oem_env(char *env, char *response)
+{
+       char *key = env;
+       char *value = NULL;
+
+       if (NULL != key) {
+               pr_debug("try to find env info for %s\n", key);
+               if ((0 == strcmp(key, "product_name")) && (NULL != product_name))
+                       value = product_name;
+               else
+                       value = env_get(key);
+       }
+
+       if (NULL != value) {
+               fastboot_okay(value, response);
+       } else {
+               fastboot_fail("NOT exist", response);
+       }
+}
+
+static void write_oem_env(char *env, char *response)
+{
+       char *key, *value = env;
+
+       key = strsep(&value, ":");
+       if ((NULL != key) && (NULL != value) && (0 == strcmp(key, "product_name"))) {
+               pr_debug("try to set env %s to %s\n", key, value);
+               // NOT support env_set API in SPL stage
+               if (NULL != product_name)
+                       free(product_name);
+               product_name = strdup(value);
+               fastboot_okay(NULL, response);
+       } else {
+               fastboot_fail("NOT support", response);
+       }
+}
+#else
+static void read_oem_env(char *env, char *response)
+{
+       char *key = env;
+       char *value = NULL;
+
+       if (NULL != key) {
+               pr_debug("try to find env info for %s\n", key);
+               value = env_get(key);
+       }
+
+       if (NULL != value) {
+               fastboot_okay(value, response);
+       } else {
+               fastboot_fail("NOT exist", response);
+       }
+}
+
+static void write_oem_env(char *env, char *response)
+{
+       char *key, *value = env;
+
+       key = strsep(&value, ":");
+       if ((NULL != key) && (NULL != value)) {
+               pr_debug("try to set env %s to %s\n", key, value);
+               env_set(key, value);
+               fastboot_okay(NULL, response);
+       } else {
+               fastboot_fail("NOT support", response);
+       }
+}
+#endif
+
+/**
+ * fastboot_env_access() - Access env variables.
+ *
+ * @operation: Pointer to env operation string
+ *                       get: read env
+ *                       set: write env
+ * @env: Pointer to env string
+ *                       if is read operation, then
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_env_access(char *operation, char *env, char *response)
+{
+       if (0 == strcmp(operation, "get"))
+               read_oem_env(env, response);
+       else if (0 == strcmp(operation, "set"))
+               write_oem_env(env, response);
+       else
+               fastboot_fail("NOT support", response);
+}
+#endif
index 7e4c3577b366491b4dd95c452cf39c40bbd564d6..91954f60791964e7aa348cef8e7f6c714fa33376 100644 (file)
@@ -444,6 +444,13 @@ config SIFIVE_GPIO
          Device model driver for GPIO controller present in SiFive FU540 SoC. This
          driver enables GPIO interface on HiFive Unleashed A00 board.
 
+config K1X_GPIO
+       bool "Spacemit k1x GPIO driver"
+       depends on DM_GPIO
+       default n
+       help
+         Support for Spacemit k1x GPIO driver.
+
 config MVEBU_GPIO
        bool "Marvell MVEBU GPIO driver"
        depends on DM_GPIO && (ARCH_MVEBU || ARCH_KIRKWOOD)
index 39762fa06ce9a7eb39900a0fcfc2828d579f7ed3..9584c60ad4d4a45dd22b0950e201138e3e1a43b5 100644 (file)
@@ -69,6 +69,7 @@ obj-$(CONFIG_MT7621_GPIO)     += mt7621_gpio.o
 obj-$(CONFIG_MSCC_SGPIO)       += mscc_sgpio.o
 obj-$(CONFIG_NX_GPIO)          += nx_gpio.o
 obj-$(CONFIG_SIFIVE_GPIO)      += sifive-gpio.o
+obj-$(CONFIG_K1X_GPIO) += k1x_gpio.o
 obj-$(CONFIG_NOMADIK_GPIO)     += nmk_gpio.o
 obj-$(CONFIG_MAX7320_GPIO)     += max7320_gpio.o
 obj-$(CONFIG_SL28CPLD_GPIO)    += sl28cpld-gpio.o
diff --git a/drivers/gpio/k1x_gpio.c b/drivers/gpio/k1x_gpio.c
new file mode 100644 (file)
index 0000000..201121b
--- /dev/null
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * spacemit k1x gpio driver
+ *
+ * Copyright (C) 2023 Spacemit
+ *
+ */
+
+#include <common.h>
+#include <asm/arch/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <clk.h>
+#include "k1x_gpio.h"
+
+#ifdef CONFIG_DM_GPIO
+#include <dm/read.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/pinctrl.h>
+
+static void __iomem *k1x_gpio_base;
+#else
+#define K1X_GPIO_BASE   0xd4019000
+#endif
+
+#ifndef K1X_MAX_GPIO
+#define K1X_MAX_GPIO   128
+#endif
+
+#define GPIO_TO_REG(gp)                (gp >> 5)
+#define GPIO_TO_BIT(gp)                (1 << (gp & 0x1f))
+#define GPIO_VAL(gp, val)      ((val >> (gp & 0x1f)) & 0x01)
+
+/**
+ * struct k1x_gpio_pctrl_map - gpio and pinctrl mapping
+ * @gpio_pin:  start of gpio number in gpio-ranges
+ * @pctrl_pin: start of pinctrl number in gpio-ranges
+ * @npins:     total number of pins in gpio-ranges
+ * @node:      list node
+ */
+struct k1x_gpio_pctrl_map {
+       u32 gpio_pin;
+       u32 pctrl_pin;
+       u32 npins;
+       struct list_head node;
+};
+
+/**
+ * struct k1x_gpio_pctrl_map - gpio device instance
+ * @pinctrl_dev:pointer to gpio device
+ * @gpiomap:   list node having mapping between gpio and pinctrl
+ * @base:      I/O register base address of gpio device
+ * @name:      gpio device name, ex GPIO0, GPIO1
+ * @ngpios:    total number of gpios
+ */
+struct k1x_gpio_plat {
+       struct udevice *pinctrl_dev;
+       struct list_head gpiomap;
+       void __iomem *base;
+};
+
+static inline void *get_gpio_base(int bank)
+{
+       const unsigned long offset[] = {0, 4, 8, 0x100};
+       /* gpio register bank offset */
+#ifdef CONFIG_DM_GPIO
+       return (struct gpio_reg *)(k1x_gpio_base + offset[bank]);
+#else
+       return (struct gpio_reg *)(K1X_GPIO_BASE + offset[bank]);
+#endif
+}
+
+static int _gpio_direction_input(unsigned gpio)
+{
+       struct gpio_reg *gpio_reg_bank;
+
+       if (gpio >= K1X_MAX_GPIO) {
+               printf("%s: Invalid GPIO %d\n", __func__, gpio);
+               return -1;
+       }
+
+       gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+       writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gcdr);
+       return 0;
+}
+
+static int _gpio_set_value(unsigned gpio, int value)
+{
+       struct gpio_reg *gpio_reg_bank;
+
+       if (gpio >= K1X_MAX_GPIO) {
+               printf("%s: Invalid GPIO %d\n", __func__, gpio);
+               return -1;
+       }
+
+       gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+       if (value)
+               writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gpsr);
+       else
+               writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gpcr);
+
+       return 0;
+}
+
+static int _gpio_direction_output(unsigned gpio, int value)
+{
+       struct gpio_reg *gpio_reg_bank;
+
+       if (gpio >= K1X_MAX_GPIO) {
+               printf("%s: Invalid GPIO %d\n", __func__, gpio);
+               return -1;
+       }
+
+       gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+       writel(GPIO_TO_BIT(gpio), &gpio_reg_bank->gsdr);
+       _gpio_set_value(gpio, value);
+       return 0;
+}
+
+static int _gpio_get_value(unsigned gpio)
+{
+       struct gpio_reg *gpio_reg_bank;
+       u32 gpio_val;
+
+       if (gpio >= K1X_MAX_GPIO) {
+               printf("%s: Invalid GPIO %d\n", __func__, gpio);
+               return -1;
+       }
+
+       gpio_reg_bank = get_gpio_base(GPIO_TO_REG(gpio));
+       gpio_val = readl(&gpio_reg_bank->gplr);
+
+       return GPIO_VAL(gpio, gpio_val);
+}
+
+#ifdef CONFIG_DM_GPIO
+/**
+ * k1x_get_gpio_pctrl_mapping() - get associated pinctrl pin from gpio pin
+ *
+ * @plat: k1x GPIO device
+ * @gpio: GPIO pin
+ */
+static int k1x_get_pctrl_from_gpio(struct k1x_gpio_plat *plat, u32 gpio, u32 *pctrl_pin)
+{
+       struct k1x_gpio_pctrl_map *range = NULL;
+       struct list_head *pos, *tmp;
+       int ret = -EINVAL;
+
+       list_for_each_safe(pos, tmp, &plat->gpiomap) {
+               range = list_entry(pos, struct k1x_gpio_pctrl_map, node);
+               if (gpio >= range->gpio_pin &&
+                   gpio < (range->gpio_pin + range->npins)) {
+                       *pctrl_pin = range->pctrl_pin + (gpio - range->gpio_pin);
+                       ret = 0;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * k1x_get_gpio_pctrl_mapping() - get mapping between gpio and pinctrl
+ *
+ * Read dt node "gpio-ranges" to get gpio and pinctrl mapping and store
+ * in private data structure to use it later while enabling gpio.
+ *
+ * @dev: pointer to GPIO device
+ * Return: 0 on success and -ENOMEM on failure
+ */
+static int k1x_get_gpio_pctrl_mapping(struct udevice *dev)
+{
+       struct k1x_gpio_plat *plat = dev_get_plat(dev);
+       struct k1x_gpio_pctrl_map *range = NULL;
+       struct ofnode_phandle_args args;
+       int index = 0, ret;
+
+       for (;; index++) {
+               ret = dev_read_phandle_with_args(dev, "gpio-ranges",
+                                                NULL, 3, index, &args);
+               if (ret)
+                       break;
+
+               range = (struct k1x_gpio_pctrl_map *)devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
+               if (!range)
+                       return -ENOMEM;
+
+               range->gpio_pin = args.args[0];
+               range->pctrl_pin = args.args[1];
+               range->npins = args.args[2];
+               list_add_tail(&range->node, &plat->gpiomap);
+       }
+
+       return 0;
+}
+
+static int gpio_k1x_probe(struct udevice *dev)
+{
+       struct k1x_gpio_plat *plat = dev_get_plat(dev);
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct clk gpio_clk;
+       int ret = 0;
+
+       plat->base = dev_remap_addr_index(dev, 0);
+       if (!plat->base) {
+               debug("%s: Failed to get base address\n", __func__);
+               return -EINVAL;
+       }
+       k1x_gpio_base = plat->base;
+
+       uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
+       ret = uclass_get_device_by_phandle(UCLASS_PINCTRL, dev, "gpio-ranges",
+                                    &plat->pinctrl_dev);
+       if (ret == 0) {
+               INIT_LIST_HEAD(&plat->gpiomap);
+               ret = k1x_get_gpio_pctrl_mapping(dev);
+               if (ret < 0) {
+                       dev_err(dev, "%s: Failed to get gpio to pctrl map ret(%d)\n",
+                               __func__, ret);
+                       return ret;
+               }
+       } else {
+               dev_info(dev, "%s: has no gpio-ranges\n", __func__);
+       }
+
+       ret = clk_get_by_index(dev, 0, &gpio_clk);
+       if (ret) 
+               return ret;
+       clk_enable(&gpio_clk);
+
+       return 0;
+}
+
+static const struct udevice_id gpio_k1x_ids[] = {
+       { .compatible = "spacemit,k1x-gpio" },
+       { }
+};
+
+static int k1x_gpio_request(struct udevice *dev, unsigned gpio,
+                            const char *label)
+{
+       struct k1x_gpio_plat *plat = dev_get_plat(dev);
+       u32 pctrl;
+       int ret = 0;
+
+       /* nothing to do if there is no corresponding pinctrl device */
+       if (!plat->pinctrl_dev)
+               return 0;
+
+       ret = k1x_get_pctrl_from_gpio(plat, gpio, &pctrl);
+       if (ret < 0)
+               return 0;
+
+       return pinctrl_request(plat->pinctrl_dev, pctrl, 0);
+}
+
+static int k1x_gpio_get_value(struct udevice *dev, unsigned int gpio)
+{
+       return _gpio_get_value(gpio);
+}
+
+static int k1x_gpio_set_value(struct udevice *dev, unsigned int gpio,
+                                  int value)
+{
+       return _gpio_set_value(gpio, value);
+}
+
+static int k1x_gpio_direction_input(struct udevice *dev, unsigned int gpio)
+{
+       return _gpio_direction_input(gpio);
+}
+
+static int k1x_gpio_direction_output(struct udevice *dev, unsigned int gpio,
+                                         int value)
+{
+       return _gpio_direction_output(gpio, value);
+}
+
+static const struct dm_gpio_ops gpio_k1x_ops = {
+       .request                = k1x_gpio_request,
+       .direction_input        = k1x_gpio_direction_input,
+       .direction_output       = k1x_gpio_direction_output,
+       .get_value              = k1x_gpio_get_value,
+       .set_value              = k1x_gpio_set_value,
+};
+U_BOOT_DRIVER(gpio_k1x) = {
+       .name   = "gpio_k1x",
+       .id     = UCLASS_GPIO,
+       .ops    = &gpio_k1x_ops,
+       .of_match = gpio_k1x_ids,
+       .probe  = gpio_k1x_probe,
+       .plat_auto      = sizeof(struct k1x_gpio_plat),
+};
+
+#else
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       if (gpio >= K1X_MAX_GPIO) {
+               printf("%s: Invalid GPIO requested %d\n", __func__, gpio);
+               return -1;
+       }
+       return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+       return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+       return _gpio_direction_input(gpio);
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+       return _gpio_direction_output(gpio, value);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+       return _gpio_get_value(gpio);
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+       return _gpio_set_value(gpio, value);
+}
+#endif
diff --git a/drivers/gpio/k1x_gpio.h b/drivers/gpio/k1x_gpio.h
new file mode 100644 (file)
index 0000000..2d9f673
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __K1X_GPIO_H__
+#define __K1X_GPIO_H__
+
+#include <common.h>
+
+/*
+ * GPIO Register map for k1x
+ */
+struct gpio_reg {
+       u32 gplr;       /* Pin Level Register - 0x0000 */
+       u32 pad0[2];
+       u32 gpdr;       /* Pin Direction Register - 0x000C */
+       u32 pad1[2];
+       u32 gpsr;       /* Pin Output Set Register - 0x0018 */
+       u32 pad2[2];
+       u32 gpcr;       /* Pin Output Clear Register - 0x0024 */
+       u32 pad3[2];
+       u32 grer;       /* Rising-Edge Detect Enable Register - 0x0030 */
+       u32 pad4[2];
+       u32 gfer;       /* Falling-Edge Detect Enable Register - 0x003C */
+       u32 pad5[2];
+       u32 gedr;       /* Edge Detect Status Register - 0x0048 */
+       u32 pad6[2];
+       u32 gsdr;       /* Bitwise Set of GPIO Direction Register - 0x0054 */
+       u32 pad7[2];
+       u32 gcdr;       /* Bitwise Clear of GPIO Direction Register - 0x0060 */
+       u32 pad8[2];
+       u32 gsrer;      /* Bitwise Set of Rising-Edge Detect Enable
+                          Register - 0x006C */
+       u32 pad9[2];
+       u32 gcrer;      /* Bitwise Clear of Rising-Edge Detect Enable
+                          Register - 0x0078 */
+       u32 pad10[2];
+       u32 gsfer;      /* Bitwise Set of Falling-Edge Detect Enable
+                          Register - 0x0084 */
+       u32 pad11[2];
+       u32 gcfer;      /* Bitwise Clear of Falling-Edge Detect Enable
+                          Register - 0x0090 */
+       u32 pad12[2];
+       u32 apmask;     /* Bitwise Mask of Edge Detect Register - 0x009C */
+};
+
+#endif /* __K1X_GPIO_H__ */
index be4724bf8ef64c70bfcb3f177e8d791427eb9009..0306b1be7b063a611cded5bb8bbe20091c724a0f 100644 (file)
@@ -87,6 +87,18 @@ config SYS_I2C_EARLY_INIT
          Add the function prototype for i2c_early_init_f which is called in
          board_early_init_f.
 
+config SYS_I2C_SPACEMIT
+        bool "SPACEMIT I2C driver"
+        depends on DM_I2C
+        help
+          Support for SPACEMIT I2C controllers.
+
+config SPL_SYS_I2C_SPACEMIT
+        bool "SPACEMIT I2C SPL driver"
+        depends on SPL_SYS_I2C_LEGACY
+        help
+          Support for SPACEMIT I2C controllers in SPL.
+
 config I2C_CROS_EC_TUNNEL
        tristate "Chrome OS EC tunnel I2C bus"
        depends on CROS_EC
index 7e046f809a445786c8228739465e742f4833c896..7c683ab38f52a10032a791306153c75b7ec9f645 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o
 obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
 obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
 
+obj-$(CONFIG_$(SPL_)SYS_I2C_SPACEMIT) += spacemit_i2c.o
 obj-$(CONFIG_$(SPL_)SYS_I2C_LEGACY) += i2c_core.o
 obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
 obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
@@ -18,8 +19,10 @@ obj-$(CONFIG_SYS_I2C_CA) += i2c-cortina.o
 obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
 obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
 ifdef CONFIG_PCI
+ifdef CONFIG_ACPIGEN
 obj-$(CONFIG_SYS_I2C_DW) += designware_i2c_pci.o
 endif
+endif
 obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
 obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
 obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
index e54de42abc3957a98f21437c190a05694cf0ed4c..a148d31e759e16f641ac5eabbdc93b450e6b8e8f 100644 (file)
@@ -771,8 +771,15 @@ int designware_i2c_of_to_plat(struct udevice *bus)
 int designware_i2c_probe(struct udevice *bus)
 {
        struct dw_i2c *priv = dev_get_priv(bus);
+       int ret;
        uint comp_type;
 
+       ret = reset_get_bulk(bus, &priv->resets);
+       ret = reset_deassert_bulk(&priv->resets);
+       if (ret){
+               dev_err(bus, "failed to reset \n");
+                return ret;
+       }
        comp_type = readl(&priv->regs->comp_type);
        if (comp_type != DW_I2C_COMP_TYPE) {
                log_err("I2C bus %s has unknown type %#x\n", bus->name,
index 46c2545f214566f16714a84922b793ba3675b5bc..e4a2732cec5574fe83196415ece9b3f717f070f2 100644 (file)
@@ -56,7 +56,7 @@ static int designware_i2c_pci_of_to_plat(struct udevice *dev)
 
        if (spl_phase() < PHASE_BOARD_F) {
                /* Handle early, fixed mapping into a different address space */
-               priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
+               priv->regs = (struct i2c_regs *)(long)dm_pci_read_bar32(dev, 0);
        } else {
                priv->regs = (struct i2c_regs *)
                        dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
index 09f91e674d441af342818f4c185d8315d93da950..c34628ded4e52baf511d3511f8a5fb6e4de50042 100644 (file)
@@ -20,7 +20,7 @@ struct i2c_adapter *i2c_get_adapter(int index)
        int i;
 
        if (index >= max) {
-               printf("Error, wrong i2c adapter %d max %d possible\n",
+               pr_err("Error, wrong i2c adapter %d max %d possible\n",
                       index, max);
                return i2c_adap_p;
        }
@@ -67,8 +67,9 @@ static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip,
        if (channel < 0) {
                buf = 0;
                ret = adap->write(adap, chip, 0, 0, &buf, 1);
-               if (ret)
-                       printf("%s: Could not turn off the mux.\n", __func__);
+               if (ret){
+                       pr_err("%s: Could not turn off the mux.\n", __func__);
+               }
                return ret;
        }
 
@@ -95,13 +96,13 @@ static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip,
                buf = (uint8_t)(0x01 << channel);
                break;
        default:
-               printf("%s: wrong mux id: %d\n", __func__, mux_id);
+               pr_err("%s: wrong mux id: %d\n", __func__, mux_id);
                return -1;
        }
 
        ret = adap->write(adap, chip, 0, 0, &buf, 1);
        if (ret)
-               printf("%s: could not set mux: id: %d chip: %x channel: %d\n",
+               pr_err("%s: could not set mux: id: %d chip: %x channel: %d\n",
                       __func__, mux_id, chip, channel);
        return ret;
 }
@@ -154,7 +155,7 @@ static int i2c_mux_disconnect_all(void)
 
                        ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1);
                        if (ret != 0) {
-                               printf("i2c: mux disconnect error\n");
+                               pr_err("i2c: mux disconnect error\n");
                                return ret;
                        }
                } while (i > 0);
@@ -244,7 +245,7 @@ int i2c_set_bus_num(unsigned int bus)
 
        max = ll_entry_count(struct i2c_adapter, i2c);
        if (I2C_ADAPTER(bus) >= max) {
-               printf("Error, wrong i2c adapter %d max %d possible\n",
+               pr_err("Error, wrong i2c adapter %d max %d possible\n",
                       I2C_ADAPTER(bus), max);
                return -2;
        }
@@ -322,7 +323,7 @@ uint8_t i2c_reg_read(uint8_t addr, uint8_t reg)
        i2c_read(addr, reg, 1, &buf, 1);
 
 #ifdef DEBUG
-       printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
+       pr_debug("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
               __func__, i2c_get_bus_num(), addr, reg, buf);
 #endif
 
@@ -332,7 +333,7 @@ uint8_t i2c_reg_read(uint8_t addr, uint8_t reg)
 void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val)
 {
 #ifdef DEBUG
-       printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
+       pr_debug("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
               __func__, i2c_get_bus_num(), addr, reg, val);
 #endif
 
diff --git a/drivers/i2c/spacemit_i2c.c b/drivers/i2c/spacemit_i2c.c
new file mode 100644 (file)
index 0000000..2ed5707
--- /dev/null
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Spacemit
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset.h>
+#include <clk.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "spacemit_i2c.h"
+
+/* All transfers are described by this data structure */
+struct spacemit_i2c_msg {
+       u8 condition;
+       u8 acknack;
+       u8 direction;
+       u8 data;
+};
+
+struct spacemit_i2c {
+       u32 icr;
+       u32 isr;
+       u32 isar;
+       u32 idbr;
+       u32 ilcr;
+       u32 iwcr;
+       u32 irst_cyc;
+       u32 ibmr;
+};
+
+/*
+ * i2c_reset: - reset the host controller
+ *
+ */
+static void i2c_reset(struct spacemit_i2c *base)
+{
+       u32 icr_mode;
+
+       /* Save bus mode (standard or fast speed) for later use */
+       icr_mode = readl(&base->icr) & ICR_MODE_MASK;
+       writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
+       writel(readl(&base->icr) | ICR_UR, &base->icr);   /* reset the unit */
+       udelay(100);
+       writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
+
+#ifdef CONFIG_SYS_I2C_SLAVE
+       writel(CONFIG_SYS_I2C_SLAVE, &base->isar); /* set our slave address */
+#else
+       writel(0x00, &base->isar); /* set our slave address */
+#endif
+       /* set control reg values */
+       writel(I2C_ICR_INIT | icr_mode, &base->icr);
+       writel(I2C_ISR_INIT, &base->isr); /* set clear interrupt bits */
+       writel(readl(&base->icr) | ICR_IUE, &base->icr); /* enable unit */
+       udelay(1e0);
+}
+
+/*
+ * i2c_isr_set_cleared: - wait until certain bits of the I2C status register
+ *                       are set and cleared
+ *
+ * @return: 1 in case of success, 0 means timeout (no match within 10 ms).
+ */
+static int i2c_isr_set_cleared(struct spacemit_i2c *base, unsigned long set_mask,
+                              unsigned long cleared_mask)
+{
+       int timeout = 1000, isr;
+
+       do {
+               isr = readl(&base->isr);
+               udelay(10);
+               if (timeout-- < 0)
+                       return 0;
+       } while (((isr & set_mask) != set_mask)
+               || ((isr & cleared_mask) != 0));
+
+       return 1;
+}
+
+/*
+ * i2c_transfer: - Transfer one byte over the i2c bus
+ *
+ * This function can tranfer a byte over the i2c bus in both directions.
+ * It is used by the public API functions.
+ *
+ * @return:  0: transfer successful
+ *          -1: message is empty
+ *          -2: transmit timeout
+ *          -3: ACK missing
+ *          -4: receive timeout
+ *          -5: illegal parameters
+ *          -6: bus is busy and couldn't be aquired
+ */
+static int i2c_transfer(struct spacemit_i2c *base, struct spacemit_i2c_msg *msg)
+{
+       int ret;
+
+       if (!msg)
+               goto transfer_error_msg_empty;
+
+       switch (msg->direction) {
+       case I2C_WRITE:
+               /* check if bus is not busy */
+               if (!i2c_isr_set_cleared(base, 0, ISR_IBB))
+                       goto transfer_error_bus_busy;
+
+               /* start transmission */
+               writel(readl(&base->icr) & ~ICR_START, &base->icr);
+               writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
+               writel(msg->data, &base->idbr);
+               if (msg->condition == I2C_COND_START)
+                       writel(readl(&base->icr) | ICR_START, &base->icr);
+               if (msg->condition == I2C_COND_STOP)
+                       writel(readl(&base->icr) | ICR_STOP, &base->icr);
+               if (msg->acknack == I2C_ACKNAK_SENDNAK)
+                       writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
+               if (msg->acknack == I2C_ACKNAK_SENDACK)
+                       writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
+               writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
+               writel(readl(&base->icr) | ICR_TB, &base->icr);
+
+               /* transmit register empty? */
+               if (!i2c_isr_set_cleared(base, ISR_ITE, 0))
+                       goto transfer_error_transmit_timeout;
+
+               /* clear 'transmit empty' state */
+               writel(readl(&base->isr) | ISR_ITE, &base->isr);
+
+               /* wait for ACK from slave */
+               if (msg->acknack == I2C_ACKNAK_WAITACK)
+                       if (!i2c_isr_set_cleared(base, 0, ISR_ACKNAK))
+                               goto transfer_error_ack_missing;
+               break;
+
+       case I2C_READ:
+
+               /* check if bus is not busy */
+               if (!i2c_isr_set_cleared(base, 0, ISR_IBB))
+                       goto transfer_error_bus_busy;
+
+               /* start receive */
+               writel(readl(&base->icr) & ~ICR_START, &base->icr);
+               writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
+               if (msg->condition == I2C_COND_START)
+                       writel(readl(&base->icr) | ICR_START, &base->icr);
+               if (msg->condition == I2C_COND_STOP)
+                       writel(readl(&base->icr) | ICR_STOP, &base->icr);
+               if (msg->acknack == I2C_ACKNAK_SENDNAK)
+                       writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
+               if (msg->acknack == I2C_ACKNAK_SENDACK)
+                       writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
+               writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
+               writel(readl(&base->icr) | ICR_TB, &base->icr);
+
+               /* receive register full? */
+               if (!i2c_isr_set_cleared(base, ISR_IRF, 0))
+                       goto transfer_error_receive_timeout;
+
+               msg->data = readl(&base->idbr);
+
+               /* clear 'receive empty' state */
+               writel(readl(&base->isr) | ISR_IRF, &base->isr);
+               break;
+       default:
+               goto transfer_error_illegal_param;
+       }
+
+       return 0;
+
+transfer_error_msg_empty:
+       debug("i2c_transfer: error: 'msg' is empty\n");
+       ret = -1;
+       goto i2c_transfer_finish;
+
+transfer_error_transmit_timeout:
+       debug("i2c_transfer: error: transmit timeout\n");
+       ret = -2;
+       goto i2c_transfer_finish;
+
+transfer_error_ack_missing:
+       debug("i2c_transfer: error: ACK missing\n");
+       ret = -3;
+       goto i2c_transfer_finish;
+
+transfer_error_receive_timeout:
+       debug("i2c_transfer: error: receive timeout\n");
+       ret = -4;
+       goto i2c_transfer_finish;
+
+transfer_error_illegal_param:
+       debug("i2c_transfer: error: illegal parameters\n");
+       ret = -5;
+       goto i2c_transfer_finish;
+
+transfer_error_bus_busy:
+       debug("i2c_transfer: error: bus is busy\n");
+       ret = -6;
+       goto i2c_transfer_finish;
+
+i2c_transfer_finish:
+       debug("i2c_transfer: ISR: 0x%04x\n", readl(&base->isr));
+       i2c_reset(base);
+       return ret;
+}
+
+static int __i2c_read(struct spacemit_i2c *base, uchar chip, u8 *addr, int alen,
+                     uchar *buffer, int len)
+{
+       struct spacemit_i2c_msg msg;
+
+       debug("i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
+             "len=0x%02x)\n", chip, *addr, alen, len);
+
+       if (len == 0) {
+               pr_err("reading zero byte is invalid\n");
+               return -EINVAL;
+       }
+
+       i2c_reset(base);
+
+       /* dummy chip address write */
+       debug("i2c_read: dummy chip address write\n");
+       msg.condition = I2C_COND_START;
+       msg.acknack   = I2C_ACKNAK_WAITACK;
+       msg.direction = I2C_WRITE;
+       msg.data = (chip << 1);
+       msg.data &= 0xFE;
+       if (i2c_transfer(base, &msg))
+               return -1;
+
+       /*
+        * send memory address bytes;
+        * alen defines how much bytes we have to send.
+        */
+       while (--alen >= 0) {
+               debug("i2c_read: send address byte %02x (alen=%d)\n",
+                     *addr, alen);
+               msg.condition = I2C_COND_NORMAL;
+               msg.acknack   = I2C_ACKNAK_WAITACK;
+               msg.direction = I2C_WRITE;
+               msg.data      = addr[alen];
+               if (i2c_transfer(base, &msg))
+                       return -1;
+       }
+
+       /* start read sequence */
+       debug("i2c_read: start read sequence\n");
+       msg.condition = I2C_COND_START;
+       msg.acknack   = I2C_ACKNAK_WAITACK;
+       msg.direction = I2C_WRITE;
+       msg.data      = (chip << 1);
+       msg.data     |= 0x01;
+       if (i2c_transfer(base, &msg))
+               return -1;
+
+       /* read bytes; send NACK at last byte */
+       while (len--) {
+               if (len == 0) {
+                       msg.condition = I2C_COND_STOP;
+                       msg.acknack   = I2C_ACKNAK_SENDNAK;
+               } else {
+                       msg.condition = I2C_COND_NORMAL;
+                       msg.acknack   = I2C_ACKNAK_SENDACK;
+               }
+
+               msg.direction = I2C_READ;
+               msg.data      = 0x00;
+               if (i2c_transfer(base, &msg))
+                       return -1;
+
+               *buffer = msg.data;
+               debug("i2c_read: reading byte (%p)=0x%02x\n",
+                     buffer, *buffer);
+               buffer++;
+       }
+
+       i2c_reset(base);
+
+       return 0;
+}
+
+static int __i2c_write(struct spacemit_i2c *base, uchar chip, u8 *addr, int alen,
+                      uchar *buffer, int len)
+{
+       struct spacemit_i2c_msg msg;
+
+       debug("i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
+             "len=0x%02x)\n", chip, *addr, alen, len);
+
+       i2c_reset(base);
+
+       /* chip address write */
+       debug("i2c_write: chip address write\n");
+       msg.condition = I2C_COND_START;
+       msg.acknack   = I2C_ACKNAK_WAITACK;
+       msg.direction = I2C_WRITE;
+       msg.data = (chip << 1);
+       msg.data &= 0xFE;
+       if (i2c_transfer(base, &msg))
+               return -1;
+
+       /*
+        * send memory address bytes;
+        * alen defines how much bytes we have to send.
+        */
+       while (--alen >= 0) {
+               debug("i2c_read: send address byte %02x (alen=%d)\n",
+                     *addr, alen);
+               msg.condition = I2C_COND_NORMAL;
+               msg.acknack   = I2C_ACKNAK_WAITACK;
+               msg.direction = I2C_WRITE;
+               msg.data      = addr[alen];
+               if (i2c_transfer(base, &msg))
+                       return -1;
+       }
+
+       /* write bytes; send NACK at last byte */
+       while (len--) {
+               debug("i2c_write: writing byte (%p)=0x%02x\n",
+                     buffer, *buffer);
+
+               if (len == 0)
+                       msg.condition = I2C_COND_STOP;
+               else
+                       msg.condition = I2C_COND_NORMAL;
+
+               msg.acknack   = I2C_ACKNAK_WAITACK;
+               msg.direction = I2C_WRITE;
+               msg.data      = *(buffer++);
+
+               if (i2c_transfer(base, &msg))
+                       return -1;
+       }
+
+       i2c_reset(base);
+
+       return 0;
+}
+
+#if CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
+
+#define SPACEMIT_APBC_BASE             0xd4015000      /* APB Clock Unit */
+#define REG_APBC_APBC_TWSI0_CLK_RST    (SPACEMIT_APBC_BASE + 0x2c)
+#define REG_APBC_APBC_TWSI1_CLK_RST    (SPACEMIT_APBC_BASE + 0x30)
+#define REG_APBC_APBC_TWSI2_CLK_RST    (SPACEMIT_APBC_BASE + 0x38)
+#define REG_APBC_APBC_TWSI3_CLK_RST    (0xf0610000    + 0x08)
+#define REG_APBC_APBC_TWSI4_CLK_RST    (SPACEMIT_APBC_BASE + 0x40)
+#define REG_APBC_APBC_TWSI5_CLK_RST    (SPACEMIT_APBC_BASE + 0x4c)
+#define REG_APBC_APBC_TWSI6_CLK_RST    (SPACEMIT_APBC_BASE + 0x60)
+#define REG_APBC_APBC_TWSI7_CLK_RST    (SPACEMIT_APBC_BASE + 0x68)
+#define REG_APBC_APBC_TWSI8_CLK_RST    (SPACEMIT_APBC_BASE + 0x20)
+
+typedef enum {
+       I2C_FUNCLK_33MHz = 0,   /*up to 3.4M bps for HS */
+       I2C_FUNCLK_52MHz = 1,
+       I2C_FUNCLK_62P4MHz = 2, /*up to 1.8M bps for HS */
+} I2C_FUNCTION_CLK;
+
+static struct spacemit_i2c *i2c_base[] = {
+       (struct spacemit_i2c *)0xd4010800,
+       (struct spacemit_i2c *)0xd4011000,
+       (struct spacemit_i2c *)0xd4012000,
+       (struct spacemit_i2c *)0xf0614000,
+       (struct spacemit_i2c *)0xd4012800,
+       (struct spacemit_i2c *)0xd4013800,
+       (struct spacemit_i2c *)0xd4018800,
+       (struct spacemit_i2c *)0xd401d000,
+       (struct spacemit_i2c *)0xd401d800,
+};
+
+static uint32_t apbc_clk_reg[] = {
+       REG_APBC_APBC_TWSI0_CLK_RST,
+       REG_APBC_APBC_TWSI1_CLK_RST,
+       REG_APBC_APBC_TWSI2_CLK_RST,
+       REG_APBC_APBC_TWSI3_CLK_RST,
+       REG_APBC_APBC_TWSI4_CLK_RST,
+       REG_APBC_APBC_TWSI5_CLK_RST,
+       REG_APBC_APBC_TWSI6_CLK_RST,
+       REG_APBC_APBC_TWSI7_CLK_RST,
+       REG_APBC_APBC_TWSI8_CLK_RST,
+};
+
+static inline void mmio_write_32(uintptr_t addr, uint32_t val)
+{
+       *(volatile uint32_t *)addr = val;
+}
+static inline uint32_t mmio_read_32(uintptr_t addr)
+{
+       return *(volatile uint32_t *)addr;
+}
+
+void i2c_init_board(void)
+{
+       int i = 0;
+
+       mmio_write_32(0xd4051024, (*(unsigned int *)0xd4051024) | (1 << 6));
+       mmio_write_32(0xd4090104, (*(unsigned int *)0xd4090104) | (1 << 4));
+       mmio_write_32(0xd4090108, (*(unsigned int *)0xd4090108) | (1 << 31));
+
+       mmio_write_32(0xd401e228, (*(unsigned int *)0xd401e228) | (1 << 1));
+        mmio_write_32(0xd401e22c, (*(unsigned int *)0xd401e22c) | (1 << 1));
+       /* init the clk & reset or pinctrl */
+       for (i = 0; i < sizeof(apbc_clk_reg) / sizeof(apbc_clk_reg[0]); ++i) {
+               mmio_write_32(apbc_clk_reg[i], (I2C_FUNCLK_33MHz << 4) | 0x4);
+               mmio_write_32(apbc_clk_reg[i], (I2C_FUNCLK_33MHz << 4) | 0x7);
+               mmio_write_32(apbc_clk_reg[i], (I2C_FUNCLK_33MHz << 4) | 0x3);
+       }
+}
+
+static void __i2c_init_chip(struct spacemit_i2c *base, int speed, int slaveaddr)
+{
+       u32 val;
+
+       if (speed > 100000)
+               val = ICR_FM;
+       else
+               val = ICR_SM;
+
+       clrsetbits_le32(&base->icr, ICR_MODE_MASK, val);
+}
+
+static int __i2c_probe_chip(struct spacemit_i2c *base, uchar chip)
+{
+       struct spacemit_i2c_msg msg;
+
+       i2c_reset(base);
+
+       msg.condition = I2C_COND_START;
+       msg.acknack   = I2C_ACKNAK_WAITACK;
+       msg.direction = I2C_WRITE;
+       msg.data      = (chip << 1) + 1;
+       if (i2c_transfer(base, &msg))
+               return -1;
+
+       msg.condition = I2C_COND_STOP;
+       msg.acknack   = I2C_ACKNAK_SENDNAK;
+       msg.direction = I2C_READ;
+       msg.data      = 0x00;
+       if (i2c_transfer(base, &msg))
+               return -1;
+
+       return 0;
+}
+
+static void spacemit_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+{
+       __i2c_init_chip(i2c_base[adap->hwadapnr], speed, slaveadd);
+}
+
+/*
+ * spacemit_i2c_probe: - Test if a chip answers for a given i2c address
+ */
+static int spacemit_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+       return __i2c_probe_chip(i2c_base[adap->hwadapnr], chip);
+}
+
+/*
+ * i2c_read: - Read multiple bytes from an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:      address of the chip which is to be read
+ * @addr:      i2c data address within the chip
+ * @alen:      length of the i2c data address (1..2 bytes)
+ * @buffer:    where to write the data
+ * @len:       how much byte do we want to read
+ * @return:    0 in case of success
+ */
+static int spacemit_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+       u8 addr_bytes[4];
+
+       addr_bytes[0] = (addr >> 0) & 0xFF;
+       addr_bytes[1] = (addr >> 8) & 0xFF;
+       addr_bytes[2] = (addr >> 16) & 0xFF;
+       addr_bytes[3] = (addr >> 24) & 0xFF;
+
+       return __i2c_read(i2c_base[adap->hwadapnr], chip, addr_bytes, alen, buffer, len);
+}
+
+/*
+ * spacemit_i2c_write: -  Write multiple bytes to an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:      address of the chip which is to be written
+ * @addr:      i2c data address within the chip
+ * @alen:      length of the i2c data address (1..2 bytes)
+ * @buffer:    where to find the data to be written
+ * @len:       how much byte do we want to read
+ * @return:    0 in case of success
+ */
+static int spacemit_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+       u8 addr_bytes[4];
+
+       addr_bytes[0] = (addr >> 0) & 0xFF;
+       addr_bytes[1] = (addr >> 8) & 0xFF;
+       addr_bytes[2] = (addr >> 16) & 0xFF;
+       addr_bytes[3] = (addr >> 24) & 0xFF;
+
+       return __i2c_write(i2c_base[adap->hwadapnr], chip, addr_bytes, alen, buffer, len);
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c0, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               0);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c1, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               1);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c2, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               2);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c3, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               3);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c4, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               4);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c5, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               5);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c6, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x50,
+               6);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c7, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               7);
+U_BOOT_I2C_ADAP_COMPLETE(spacemit_i2c8, spacemit_i2c_init, spacemit_i2c_probe,
+               spacemit_i2c_read, spacemit_i2c_write,
+               NULL, 100000, 0x31,
+               8);
+#else /* SYS_I2C_LEGACY */
+
+struct spacemit_i2c_priv {
+       struct spacemit_i2c *base;
+       struct reset_ctl_bulk resets;
+#if CONFIG_IS_ENABLED(CLK)
+        struct clk clk;
+#endif
+       u32 clk_rate;
+
+};
+
+static int spacemit_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+       struct spacemit_i2c_priv *i2c = dev_get_priv(bus);
+       struct i2c_msg *dmsg, *omsg, dummy;
+
+       memset(&dummy, 0, sizeof(struct i2c_msg));
+
+       /*
+        * We expect either two messages (one with an offset and one with the
+        * actual data) or one message (just data or offset/data combined)
+        */
+       if (nmsgs > 2 || nmsgs == 0) {
+               debug("%s: Only one or two messages are supported.", __func__);
+               return -1;
+       }
+
+       omsg = nmsgs == 1 ? &dummy : msg;
+       dmsg = nmsgs == 1 ? msg : msg + 1;
+
+       if (dmsg->flags & I2C_M_RD)
+               return __i2c_read(i2c->base, dmsg->addr, omsg->buf,
+                                 omsg->len, dmsg->buf, dmsg->len);
+       else
+               return __i2c_write(i2c->base, dmsg->addr, omsg->buf,
+                                  omsg->len, dmsg->buf, dmsg->len);
+}
+
+static int spacemit_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+       struct spacemit_i2c_priv *priv = dev_get_priv(bus);
+       u32 val;
+
+       if (speed > 100000)
+               val = ICR_FM;
+       else
+               val = ICR_SM;
+       clrsetbits_le32(&priv->base->icr, ICR_MODE_MASK, val);
+
+       return 0;
+}
+
+static int spacemit_i2c_bind(struct udevice *bus)
+{
+       return 0;
+}
+
+static int spacemit_i2c_probe(struct udevice *bus)
+{
+       struct spacemit_i2c_priv *priv = dev_get_priv(bus);
+       int ret;
+
+       ret = reset_get_bulk(bus, &priv->resets);
+        ret = reset_deassert_bulk(&priv->resets);
+        if (ret){
+                debug("I2C probe: failed to reset \n");
+                return ret;
+        }
+
+#if CONFIG_IS_ENABLED(CLK)
+        ret = clk_get_by_name(bus, NULL, &priv->clk);
+        if (ret)
+                return ret;
+
+        ret = clk_enable(&priv->clk);
+        if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+                clk_free(&priv->clk);
+                debug("I2C probe: failed to enable clock\n");
+                return ret;
+        }
+#endif
+       priv->base = (void *)devfdt_get_addr_ptr(bus);
+       ret = dev_read_u32(bus, "clock-frequency", &priv->clk_rate);
+        if (ret) {
+                pr_info("Default to 100kHz\n");
+               /* default clock rate: 100k */
+                priv->clk_rate = 100000;
+        }
+
+       ret = spacemit_i2c_set_bus_speed(bus, priv->clk_rate);
+       return 0;
+}
+
+static const struct dm_i2c_ops spacemit_i2c_ops = {
+       .xfer           = spacemit_i2c_xfer,
+       .set_bus_speed  = spacemit_i2c_set_bus_speed,
+};
+
+static const struct udevice_id spacemit_i2c_ids[] = {
+       { .compatible = "spacemit,i2c" },
+       { }
+};
+
+U_BOOT_DRIVER(i2c_spacemit) = {
+       .name   = "i2c_spacemit",
+       .id     = UCLASS_I2C,
+       .of_match = spacemit_i2c_ids,
+       .bind   = spacemit_i2c_bind,
+       .probe  = spacemit_i2c_probe,
+       .priv_auto = sizeof(struct spacemit_i2c_priv),
+       .ops    = &spacemit_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/spacemit_i2c.h b/drivers/i2c/spacemit_i2c.h
new file mode 100644 (file)
index 0000000..7f91fcd
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 Spacemit
+ */
+
+#ifndef _SPACEMIT_I2C_H_
+#define _SPACEMIT_I2C_H_
+extern void i2c_clk_enable(void);
+
+/* Shall the current transfer have a start/stop condition? */
+#define I2C_COND_NORMAL                0
+#define I2C_COND_START         1
+#define I2C_COND_STOP          2
+
+/* Shall the current transfer be ack/nacked or being waited for it? */
+#define I2C_ACKNAK_WAITACK     1
+#define I2C_ACKNAK_SENDACK     2
+#define I2C_ACKNAK_SENDNAK     4
+
+/* Specify who shall transfer the data (master or slave) */
+#define I2C_READ               0
+#define I2C_WRITE              1
+
+#if (CONFIG_SYS_I2C_SPEED == 400000)
+#define I2C_ICR_INIT   (ICR_FM | ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD \
+               | ICR_SCLE)
+#else
+#define I2C_ICR_INIT   (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
+#endif
+
+/* ----- Control register bits ---------------------------------------- */
+
+#define ICR_START      0x1             /* start bit */
+#define ICR_STOP       0x2             /* stop bit */
+#define ICR_ACKNAK     0x4             /* send ACK(0) or NAK(1) */
+#define ICR_TB         0x8             /* transfer byte bit */
+#define ICR_MA         BIT(12)         /* master abort */
+#define ICR_SCLE       BIT(13)         /* master clock enable, mona SCLEA */
+#define ICR_IUE                BIT(14)         /* unit enable */
+#define ICR_GCD                BIT(21)         /* general call disable */
+#define ICR_ITEIE      BIT(19)         /* enable tx interrupts */
+#define ICR_IRFIE      BIT(20)         /* enable rx interrupts, mona: DRFIE */
+#define ICR_BEIE       BIT(22)         /* enable bus error ints */
+#define ICR_SSDIE      BIT(24)         /* slave STOP detected int enable */
+#define ICR_ALDIE      BIT(18)         /* enable arbitration interrupt */
+#define ICR_SADIE      BIT(23)         /* slave address detected int enable */
+#define ICR_UR         BIT(10)         /* unit reset */
+#define ICR_SM         (0x0)           /* Standard Mode */
+#define ICR_FM         BIT(8)          /* Fast Mode */
+#define ICR_MODE_MASK  (0x300)         /* Mode mask */
+/* ----- Status register bits ----------------------------------------- */
+
+#define ISR_RWM                BIT(13)         /* read/write mode */
+#define ISR_ACKNAK     BIT(14)         /* ack/nak status */
+#define ISR_UB         BIT(15)         /* unit busy */
+#define ISR_IBB                BIT(16)         /* bus busy */
+#define ISR_SSD                BIT(24)         /* slave stop detected */
+#define ISR_ALD                BIT(18)         /* arbitration loss detected */
+#define ISR_ITE                BIT(19)         /* tx buffer empty */
+#define ISR_IRF                BIT(20)         /* rx buffer full */
+#define ISR_GCAD       BIT(21)         /* general call address detected */
+#define ISR_SAD                BIT(23)         /* slave address detected */
+#define ISR_BED                BIT(22)         /* bus error no ACK/NAK */
+
+#define I2C_ISR_INIT   0x1FDE000
+
+#endif
index a6da6e215decf65451f4762084d349bc760c1c14..2d9a3089424b33ba8623efb176a424a87e330019 100644 (file)
@@ -645,4 +645,23 @@ config SL28CPLD
          the base driver which provides common access methods for the
          sub-drivers.
 
+config MCP4725
+       bool "Enable simple DAC mcp4725 driver"
+       depends on DM_I2C
+       help
+         Support for the mcp4725 device, which is a simple DAC chip used
+         for i2c debug.
+
+config SPACEMIT_K1X_EFUSE
+       bool "Spacemit K1x soc eFUSE operation support"
+       depends on MISC
+       help
+         This enable efuse read/porgram support, on Spacemit K1x SoCs.
+
+config SPL_SPACEMIT_K1X_EFUSE
+       bool "Support Spacemit K1x soc eFUSE read in spl"
+       depends on MISC
+       help
+         This enable efuse read support in SPL, on Spacemit K1x SoCs.
+
 endmenu
index d494639cd9509143180d267a718ca1c53235f936..7463a3a02efe8e4667edee84ff4a1ad8a03cf9cb 100644 (file)
@@ -89,3 +89,5 @@ obj-$(CONFIG_K3_AVS0) += k3_avs.o
 obj-$(CONFIG_ESM_K3) += k3_esm.o
 obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
 obj-$(CONFIG_SL28CPLD) += sl28cpld.o
+obj-$(CONFIG_MCP4725) += mcp4725.o
+obj-$(CONFIG_$(SPL_)SPACEMIT_K1X_EFUSE) += spacemit_k1x_efuse.o
diff --git a/drivers/misc/mcp4725.c b/drivers/misc/mcp4725.c
new file mode 100644 (file)
index 0000000..b4f5ffc
--- /dev/null
@@ -0,0 +1,48 @@
+#include <common.h>
+#include <bootm.h>
+#include <command.h>
+#include <errno.h>
+#include <image.h>
+#include <malloc.h>
+#include <nand.h>
+#include <asm/byteorder.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <u-boot/zlib.h>
+#include <dm.h>
+#include <i2c.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <mapmem.h>
+#include <fdt_support.h>
+#include <stdlib.h>
+
+static int mcp5725_i2c_xfer(struct udevice * dev, struct i2c_msg * msg, int nmsgs)
+{
+
+        int ret;
+       ret = dm_i2c_xfer(dev, msg, nmsgs);
+
+        return 0;
+}
+
+static const struct dm_i2c_ops mcp5725_i2c_ops = {
+        .xfer          = mcp5725_i2c_xfer,
+};
+
+
+static const struct udevice_id mcp5725_i2c_ids[] = {
+        { .compatible = "microchip,mcp4725" },
+        { }
+};
+
+U_BOOT_DRIVER(i2c_mcp4725) = {
+        .name     = "mcp4725",
+        .id       = UCLASS_I2C_GENERIC,
+        .of_match = mcp5725_i2c_ids,
+        .ops      = &mcp5725_i2c_ops,
+};
+
+
diff --git a/drivers/misc/spacemit-onboard-hub.c b/drivers/misc/spacemit-onboard-hub.c
new file mode 100644 (file)
index 0000000..c89ba04
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * spacemit-onboard-hub.c - Spacemit k1-x onboard usb hub
+ *
+ * Copyright (c) 2023 Spacemit Co., Ltd.
+ *
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <dt-bindings/phy/phy.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+
+#define GPIOD_OUT_HIGH (GPIOD_IS_OUT | GPIOD_PULL_UP)
+
+struct spacemit_hub_priv {
+       struct gpio_desc *gpio_usb;
+       struct gpio_desc *gpio_hub;
+       struct gpio_desc *gpio_reset;
+};
+
+static int spacemit_hub_probe(struct udevice *dev)
+{
+       struct spacemit_hub_priv *spacemit;
+
+       spacemit = dev_get_priv(dev);
+       if (!spacemit)
+               return -ENOMEM;
+
+       spacemit->gpio_usb = devm_gpiod_get(dev, "usb", GPIOD_OUT_HIGH);
+       if (IS_ERR_OR_NULL(spacemit->gpio_usb)) {
+               dev_err(dev, "can not find usb-gpio\n");
+               return -ENODEV;
+       }
+       dm_gpio_set_value(spacemit->gpio_usb, 1);
+
+       spacemit->gpio_hub = devm_gpiod_get(dev, "hub", GPIOD_OUT_HIGH);
+       if (IS_ERR_OR_NULL(spacemit->gpio_hub)) {
+               dev_err(dev, "can not find hub-gpio\n");
+               return -ENODEV;
+       }
+       dm_gpio_set_value(spacemit->gpio_hub, 1);
+
+       spacemit->gpio_reset= devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR_OR_NULL(spacemit->gpio_reset)) {
+               dev_err(dev, "can not find reset-gpio\n");
+               return -ENODEV;
+       }
+       dm_gpio_set_value(spacemit->gpio_reset, 1);
+
+       dev_info(dev, "onboard usb hub driver probe, hub configured\n");
+
+       return 0;
+}
+
+static int spacemit_hub_remove(struct udevice *dev)
+{
+       struct spacemit_hub_priv *spacemit =  dev_get_priv(dev);
+
+       dm_gpio_set_value(spacemit->gpio_usb, 0);
+       dm_gpio_set_value(spacemit->gpio_reset, 0);
+       dm_gpio_set_value(spacemit->gpio_reset, 0);
+
+       dev_info(dev, "onboard usb hub driver exit, disable hub\n");
+       return 0;
+}
+
+static int spacemit_hub_bind(struct udevice *dev)
+{
+       dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+       return 0;
+}
+
+static const struct udevice_id spacemit_hub_ids[] = {
+       {.compatible = "spacemit,usb3-hub",},
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(spacemit_onboard_hub) = {
+       .name   = "spacemit_onboard_hub",
+       .id     = UCLASS_MISC,
+       .of_match = spacemit_hub_ids,
+       .bind = spacemit_hub_bind,
+       .probe = spacemit_hub_probe,
+       .remove = spacemit_hub_remove,
+       .priv_auto      = sizeof(struct spacemit_hub_priv),
+};
diff --git a/drivers/misc/spacemit_k1x_efuse.c b/drivers/misc/spacemit_k1x_efuse.c
new file mode 100644 (file)
index 0000000..ab030ed
--- /dev/null
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * spacemit_k1x_efuse.c - Spacemit k1-x efuse
+ *
+ * Copyright (c) 2024 Spacemit Co., Ltd.
+ *
+ */
+
+#include <asm/io.h>
+#include <command.h>
+#include <display_options.h>
+#include <dm.h>
+#include <clk.h>
+#include <reset-uclass.h>
+#include <linux/delay.h>
+#include <misc.h>
+#include <power/regulator.h>
+
+// #define EFUSE_DEBUG
+
+#define EFUSE_UUID_OFFSET      (0x104)  /* bank 0,chip UUID */
+#define EFUSE_HUK_OFFSET       (0x124)  /* bank 1,Hardware Unique Key */
+#define EFUSE_SSK_OFFSET       (0x144)  /* bank 2,Secret Symmetric Key */
+#define EFUSE_CDPKH_OFFSET     (0x280)  /* bank 3,Chip Debug Public Key Hash */
+#define EFUSE_ROTPKH_OFFSET    (0x2A0)  /* bank 4,Root of Trust Public Key Hash */
+#define EFUSE_ARCN_OFFSET      (0x2C0)  /* bank 5,Anti-rollback Counter Number */
+#define EFUSE_HWLOCK_OFFSET    (0x164)  /* bank 6,hwlock and lcs */
+#define EFUSE_BANK7_OFFSET     (0x190)  /* bank 7, reserved */
+#define EFUSE_BANK8_OFFSET     (0x200)  /* bank 8, reserved */
+#define EFUSE_BANK9_OFFSET     (0x220)  /* bank 9, reserved */
+#define EFUSE_BANK10_OFFSET    (0x240)  /* bank 10, reserved */
+#define EFUSE_BANK11_OFFSET    (0x260)  /* bank 11, reserved */
+#define GEU_CONFIG             (0x004)
+#define EFUSE_PROG_VAL1                (0x038)
+#define EFUSE_PROG_VAL2                (0x048)
+#define EFUSE_STATUS           (0x184)
+#define EFUSE_SCLK_DIV_CNTR    (0x3FC)
+
+#define FUSE_BANK_WORDS                (256/32)
+#define FUSE_BANK_BYTES                (256/8)
+#define FUSE_MAX_BANK_NUM      (12)
+
+/* bits definitions for register REG_GEU_FUSE_STATUS */
+#define FUSE_READY             BIT(1)
+#define FUSE_BURN_DONE         BIT(0)
+
+/* life cycle  state */
+struct lcs_config {
+       unsigned cm:3;          /* 3bits,chip manufacturing state,LSB */
+       unsigned dm:3;          /* 3bits,device manufacturing state */
+       unsigned sp:3;          /* 3bits,secure product state */
+       unsigned rma:3;         /* 3bits,RMA Label */
+       unsigned dft:8;         /* 8bits,DFT password change */
+       unsigned reserved:12;   /* 12bits,reserved,MSB */
+};
+
+/*efuse data, bank0 is regarded as uuid[32] */
+struct efuse_data_core {
+       uint8_t apcp_config[32];        /* bank 0,16bits top config,80bits app top config,160bits Manufacturing Parameters */
+       uint8_t huk[32];                /* bank 1,256bits Hardware Unique Key (HUK) from SoC Vendor */
+       uint8_t ssk[32];                /* bank 2,256bits Secret Symmetric Key (SSK) from OEM Vendor */
+       uint8_t cdpkh[32];              /* bank 3,256bits Chip Debug Public Key Hash (CDPKH) from SoC/OEM Vendor */
+       uint8_t rotpkh[32];             /* bank 4,256bits Root of Trust Public Key Hash (ROTPKH) from OEM Vendor */
+       uint8_t arcnns[28];             /* bank 5,224bits Anti-Rollback Counter Number for Non-Secure Image (ARCN-NS) */
+       uint8_t arcnse[4];              /* bank 5,32bits  Anti-rollback Counter Number for Secure Image (ARCN-Sec) */
+       uint8_t hwlock[2];              /* bank 6,16bits  hardware lock */
+       uint8_t reserved[2];            /* bank 6,16bits  reserved */
+       struct lcs_config lcs;          /* bank 6,32bits  life cycle state */
+       uint8_t reserved1[8];           /* bank 6,64bits */
+       uint8_t reserved2[16];          /* bank 6,bottom half,128bits,hotfix code */
+       uint8_t manu_param[32];         /* bank 7, manufactory infomation */
+};
+
+/*efuse data, bank0 is regarded as uuid[32] */
+struct efuse_data {
+       struct efuse_data_core efuse_core;
+       uint8_t bank8[32];              /* bank 8 */
+       uint8_t bank9[32];              /* bank 9 */
+       uint8_t bank10[32];             /* bank 10 */
+       uint8_t bank11[32];             /* bank 11 */
+};
+
+static const uint32_t efuse_bank_register_offset[] = {
+       EFUSE_UUID_OFFSET,
+       EFUSE_HUK_OFFSET,
+       EFUSE_SSK_OFFSET,
+       EFUSE_CDPKH_OFFSET,
+       EFUSE_ROTPKH_OFFSET,
+       EFUSE_ARCN_OFFSET,
+       EFUSE_HWLOCK_OFFSET,
+       EFUSE_BANK7_OFFSET,
+       EFUSE_BANK8_OFFSET,
+       EFUSE_BANK9_OFFSET,
+       EFUSE_BANK10_OFFSET,
+       EFUSE_BANK11_OFFSET,
+};
+
+struct spacemit_efuse_plat {
+       void __iomem *reg_base;
+       struct reset_ctl_bulk resets;
+       struct clk_bulk clks;
+       struct efuse_data efuse;
+       int efuse_need_reload;
+       int efuse_power_flag;
+       struct udevice *regulator;
+};
+
+static inline int se_clock_on(struct udevice *dev)
+{
+       int ret;
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+
+       ret = clk_enable_bulk(&plat->clks);
+       if (ret) {
+               pr_err("Failed to enable clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_deassert_bulk(&plat->resets);
+       if (ret) {
+               pr_err("Failed to reset: %d\n", ret);
+       }
+
+       return ret;
+}
+
+static inline __maybe_unused int se_clock_off(struct udevice *dev)
+{
+       int ret;
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+
+       ret = reset_assert_bulk(&plat->resets);
+       if (ret) {
+               pr_err("Failed to assert: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static inline __maybe_unused int efuse_power_on(struct udevice *dev)
+{
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+
+       if (NULL != plat->regulator) {
+               pr_info("Power on regulatore device %s\n", plat->regulator->name);
+               regulator_set_value(plat->regulator, 1800000);
+               return regulator_set_enable(plat->regulator, true);
+       }
+       else
+               return -EIO;
+}
+
+static inline __maybe_unused int efuse_power_off(struct udevice *dev)
+{
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+
+       if (NULL != plat->regulator) {
+               pr_info("Power off regulatore device %s\n", plat->regulator->name);
+               return regulator_set_enable(plat->regulator, false);
+       }
+       else
+               return -EIO;
+}
+
+/* load efuse data from efuse bank reg_offset address */
+void efuse_load_all(struct udevice *dev)
+{
+       uint32_t reg_offset;
+       uint32_t *buffer, bank, i, n = 0;
+       uint32_t *bank_reg_offset = (uint32_t *)efuse_bank_register_offset;
+       uint32_t bank_num = ARRAY_SIZE(efuse_bank_register_offset);
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+       void __iomem *reg_base = plat->reg_base;
+
+       buffer = (uint32_t *)&plat->efuse;
+
+       se_clock_on(dev);
+       for (bank = 0; bank < bank_num; bank++) {
+               reg_offset = bank_reg_offset[bank];
+               for (i = 0; i < FUSE_BANK_WORDS; i++) {
+                       buffer[n++] = readl(reg_base + reg_offset + i * 4);
+               }
+       }
+       se_clock_off(dev);
+}
+
+int efuse_reload(struct udevice *dev)
+{
+       int timeout;
+       uint32_t value;
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+       void __iomem *reg_base = plat->reg_base;
+
+       se_clock_on(dev);
+
+       /* trigger GEU update */
+       writel(0x0c424000, reg_base + GEU_CONFIG);
+       mdelay(200);
+       writel(0x0c024000, reg_base + GEU_CONFIG);
+
+       timeout = 3000;
+       while (1) {
+               value = readl(reg_base + EFUSE_STATUS);
+               if (value & FUSE_READY) {
+                       break;
+               }
+
+               timeout--;
+               mdelay(1);
+               if (!timeout) {
+                       log_err("efuse operation timeout.\n");
+                       se_clock_off(dev);
+                       return -2;
+               }
+       }
+
+       se_clock_off(dev);
+       return 0;
+}
+
+int efuse_read_bank(struct udevice *dev, int offset, void *buf, int size)
+{
+       uint8_t *ptr;
+       int bank_end;
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+
+       bank_end = (offset + size + FUSE_BANK_BYTES - 1) / FUSE_BANK_BYTES;
+
+       if ((!buf) || bank_end > 16 || offset < 0) {
+               log_err("invalid parameters. %d: %d\n", offset, size);
+               return -1;
+       }
+
+       if (plat->efuse_need_reload) {
+               efuse_reload(dev);
+               efuse_load_all(dev);
+               plat->efuse_need_reload = 0;
+       }
+
+       ptr = (uint8_t *)&(plat->efuse);
+       memcpy(buf, ptr + offset, size);
+
+       return 0;
+}
+
+/* write  data to efuse, buffer point to 256bit bank data*/
+int efuse_write_bank_core(struct udevice *dev, uint32_t bank_index, uint32_t *buffer)
+{
+       uint32_t value, i = 0;
+       uint32_t select_fuse_b = 0;
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+       void __iomem *reg_base = plat->reg_base;
+
+       se_clock_on(dev);
+       value = (readl(reg_base + EFUSE_STATUS) >> 14) & 0x7fff;
+       if (value & (0x1 << bank_index)) {
+               log_err("bank_index(%d) locked\n", bank_index);
+               se_clock_off(dev);
+               return -2;
+       }
+
+       /*
+       ------------------------------------------
+        initial fuse block num: bank_index
+       ------------------------------------------
+       SCLK high level timer must between 11000ns and 13000ns
+       EFUSE_SCLK_DIV_CNTR only takes effect when geu_config[27:25] = 0x7
+       */
+
+       // 1S/(104MHz/0x9c4)=24.04us divded by 2 (high level) is 12.02us
+       writel(0x9c4, reg_base + EFUSE_SCLK_DIV_CNTR);
+       log_debug("GEU_CONFIG is 0x%x\n", readl(reg_base + GEU_CONFIG));
+       for (i = 0; i < FUSE_BANK_WORDS; i++) {
+               writel(buffer[i], reg_base + (EFUSE_PROG_VAL1 + i * 4));
+       }
+
+       for (select_fuse_b = 0; select_fuse_b < 2; select_fuse_b++) {
+               log_debug("select_fuse_b is 0x%x start\n", select_fuse_b);
+               /*CLOCK_DIVIDER:7|bank_index|HIGH_VOLT_ENABLE|BURN_FUSE_ENABLE|ENABLE_SOFT_FUSE_PROG|SEL_FUSE_B*/
+               writel(0x0e030000 | (select_fuse_b << 13) | ((bank_index % 16) << 18), reg_base + GEU_CONFIG); // 0x0e0b6000
+               while (1) {
+                       value = readl(reg_base + EFUSE_STATUS);
+                       log_debug("EFUSE_STATUS(expect FUSE_BURN_DONE) is 0x%x\n", value);
+                       if (value & FUSE_BURN_DONE)
+                               break;
+               }
+
+               /*CLOCK_DIVIDER:6|HIGH_VOLT_ENABLE|ENABLE_SOFT_FUSE_PROG*/
+               writel(0x0c024000, reg_base + GEU_CONFIG); // write cfg of GEU to finish burn
+               mdelay(100);
+
+               /*CLOCK_DIVIDER:6|FUSE_SOFTWARE_RESET|HIGH_VOLT_ENABLE|ENABLE_SOFT_FUSE_PROG*/
+               writel(0x0c424000, reg_base + GEU_CONFIG); // write FUSE_SOFTWARE_RESET to start update efuse value to regs
+               mdelay(200);
+               writel(0x0c024000, reg_base + GEU_CONFIG); // write cfg of GEU to finish update
+               while (1) {
+                       value = readl(reg_base + EFUSE_STATUS);
+                       log_debug("EFUSE_STATUS(expect FUSE_READY) is 0x%x\n", value);
+                       if (value & FUSE_READY)
+                               break;
+               }
+               log_debug("select_fuse_b is 0x%x end\n", select_fuse_b);
+       }
+
+       se_clock_off(dev);
+       plat->efuse_need_reload = 1;
+
+       return 0;
+}
+
+int efuse_write_bank(struct udevice *dev, int offset, const void *buf, int size)
+{
+       int bank_start, bank_end, i, j, byte_offset, byte_size;
+       uint8_t efuse_data[FUSE_BANK_BYTES];
+       uint8_t efuse_cmp_data[FUSE_BANK_BYTES];
+
+       byte_offset = offset % FUSE_BANK_BYTES;
+       bank_start = offset / FUSE_BANK_BYTES;
+       bank_end = (offset + size + FUSE_BANK_BYTES - 1) / FUSE_BANK_BYTES;
+
+       if ((!buf) || bank_end > FUSE_MAX_BANK_NUM || bank_start < 8) {
+               log_err("efuse_write_bank: invalid parameters. %d: %d\n", offset, size);
+               return -1;
+       }
+
+       for (i = 0; bank_start < bank_end; bank_start++) {
+               // read original efuse data
+               efuse_read_bank(dev, bank_start * FUSE_BANK_BYTES,
+                                               efuse_data, FUSE_BANK_BYTES);
+
+               memcpy(efuse_cmp_data, efuse_data, FUSE_BANK_BYTES);
+               byte_size = min(size, FUSE_BANK_BYTES - byte_offset);
+               for (j = 0; j < size; j++) {
+                       efuse_data[byte_offset + j] |=  ((uint8_t*)buf)[i + j];
+               }
+
+               // no need to program if data is NOT changed
+               if (0 != memcmp(efuse_cmp_data, efuse_data, FUSE_BANK_BYTES)) {
+                       efuse_write_bank_core(dev, bank_start, (uint32_t*)efuse_data);
+#ifdef EFUSE_DEBUG
+                       print_buffer(0, efuse_data, 1, FUSE_BANK_BYTES, 16);
+#endif
+                       efuse_read_bank(dev, bank_start * FUSE_BANK_BYTES,
+                                                       efuse_cmp_data, FUSE_BANK_BYTES);
+                       if (0 != memcmp(efuse_cmp_data, efuse_data, FUSE_BANK_BYTES)) {
+                               print_buffer(0, efuse_cmp_data, 1, FUSE_BANK_BYTES, 16);
+                               log_err("Efuse write fail\n");
+                               return -2;
+                       }
+               }
+
+               byte_offset = 0;
+               i += byte_size;
+       }
+
+       return 0;
+}
+
+int efuse_lock_bank(struct udevice *dev, uint32_t bank_index)
+{
+       uint32_t efuse_data[FUSE_BANK_WORDS];
+
+       if (bank_index > FUSE_MAX_BANK_NUM || bank_index < 8) {
+               log_err("efuse_lock_bank: invalid parameters. %d\n", bank_index);
+               return -1;
+       }
+
+       memset((uint8_t *)efuse_data, 0x0, sizeof(efuse_data));
+       efuse_data[0] |= 1 << bank_index;
+       /*bank 6, 16bits  hardware lock*/
+       return efuse_write_bank_core(dev, 6, (uint32_t *)efuse_data);
+}
+
+static int spacemit_efuse_read(struct udevice *dev, int offset, void *buf, int size)
+{
+       return efuse_read_bank(dev, offset, buf, size);
+}
+
+static __maybe_unused int spacemit_efuse_program(struct udevice *dev, int offset, const void *buf, int size)
+{
+       int ret;
+
+       ret = efuse_power_on(dev);
+       if (0 == ret){
+               ret = efuse_write_bank(dev, offset, buf, size);
+               efuse_power_off(dev);
+       }
+       return ret;
+}
+
+static const struct misc_ops spacemit_efuse_ops = {
+       .read = spacemit_efuse_read,
+#if !defined(CONFIG_SPL_BUILD)
+       .write = spacemit_efuse_program,
+#endif
+};
+
+static struct udevice* find_efuse_regulator(void)
+{
+       int ret;
+       const char *name;
+       char *path, *path_origin, *regulator_name;
+       struct udevice *rdev = NULL;
+
+       name = fdt_get_alias(gd->fdt_blob, "efuse_power");
+       if (NULL == name) {
+               pr_err("fail to get alias node efuse_power\n");
+               return NULL;
+       }
+
+       path_origin = strdup(name);
+       path = path_origin;
+       // search the last node in the path
+       while (NULL != path) {
+               regulator_name = strsep(&path, "/");
+       }
+       pr_debug("Find regulator %s\n", regulator_name);
+
+       ret = regulator_get_by_devname(regulator_name, &rdev);
+       if (ret) {
+               pr_err("fail to get regulatore device %s\n", regulator_name);
+       }
+
+       free(path_origin);
+       return rdev;
+}
+
+static int spacemit_efuse_of_to_plat(struct udevice *dev)
+{
+       int ret;
+       struct spacemit_efuse_plat *plat = dev_get_plat(dev);
+
+       plat->reg_base = dev_read_addr_ptr(dev);
+       plat->efuse_need_reload = 1;
+
+       ret = clk_get_bulk(dev, &plat->clks);
+       if (ret) {
+               pr_err("Can't get clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_get_bulk(dev, &plat->resets);
+       if (ret) {
+               pr_err("Can't get reset: %d\n", ret);
+               return ret;
+       }
+
+       plat->regulator = find_efuse_regulator();
+       return 0;
+}
+
+static const struct udevice_id spacemit_efuse_ids[] = {
+       { .compatible = "spacemit,k1x-efuse" },
+       {}
+};
+
+U_BOOT_DRIVER(spacemit_k1x_efuse) = {
+       .name = "spacemit_k1x_efuse",
+       .id = UCLASS_MISC,
+       .of_match = spacemit_efuse_ids,
+       .of_to_plat = spacemit_efuse_of_to_plat,
+       .plat_auto = sizeof(struct spacemit_efuse_plat),
+       .ops = &spacemit_efuse_ops,
+};
+
+#if defined(EFUSE_DEBUG) && !defined(CONFIG_SPL_BUILD)
+static int dump_efuses(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+       struct udevice *dev;
+       uint8_t fuses[FUSE_BANK_BYTES];
+       int ret, i;
+
+       /* retrieve the device */
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                       DM_DRIVER_GET(spacemit_k1x_efuse), &dev);
+       if (ret) {
+               pr_err("%s: no misc-device found\n", __func__);
+               return 0;
+       }
+
+       for (i = 0; i < FUSE_MAX_BANK_NUM; i++) {
+               ret = misc_read(dev, i * FUSE_BANK_BYTES, fuses, sizeof(fuses));
+               if (ret < 0) {
+                       pr_err("%s: misc_read failed\n", __func__);
+                       return 0;
+               }
+
+               pr_info("efuse bank %d:\n", i);
+               print_buffer(0, fuses, 1, FUSE_BANK_BYTES, 16);
+       }
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       dump_efuses, 1, 1, dump_efuses,
+       "Dump the content of the efuses",
+       ""
+);
+#endif
index 0dcec8adcee88e8ee8fbf37b2c0f08d892d56ca6..372977480eacddaf7849bb9a8432c59981038178 100644 (file)
@@ -748,6 +748,20 @@ config ZYNQ_HISPD_BROKEN
        help
          Set if high speed mode is broken.
 
+config MMC_SDHCI_SPACEMIT
+       bool "SDHCI support for Spacemit controller"
+       depends on DM_MMC && OF_CONTROL && BLK
+       depends on MMC_SDHCI
+       help
+         Support for Spacemit SDHCI host controller on RISCV SoCs platform
+
+config MMC_SDHCI_K1X
+       bool "SDHCI support for the K1X SD/MMC Controller"
+       depends on DM_MMC && BLK
+       depends on MMC_SDHCI
+       help
+         Support for Spacemit K1x SDHCI host controller on RISCV SoCs platform
+
 config MMC_SUNXI
        bool "Allwinner sunxi SD/MMC Host Controller support"
        depends on ARCH_SUNXI
index 5d5104bbf1d64a67e0bb36978333fca4b4789726..b67f8628434923888b344ade4a01c88cf086f12a 100644 (file)
@@ -76,6 +76,8 @@ obj-$(CONFIG_MMC_SDHCI_TANGIER)               += tangier_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)          += tegra_mmc.o
 obj-$(CONFIG_MMC_SDHCI_XENON)          += xenon_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_ZYNQ)           += zynq_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_SPACEMIT)       += spacemit_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_K1X)            += k1x_sdhci.o
 
 obj-$(CONFIG_MMC_SUNXI)                        += sunxi_mmc.o
 obj-$(CONFIG_MMC_PITON)                        += piton_mmc.o
diff --git a/drivers/mmc/k1x_sdhci.c b/drivers/mmc/k1x_sdhci.c
new file mode 100644 (file)
index 0000000..cb09177
--- /dev/null
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Spacemit K1x Mobile Storage Host Controller
+ *
+ * Copyright (C) 2023 Spacemit Inc.
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <linux/libfdt.h>
+#include <linux/delay.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <reset-uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* SDH registers define */
+#define SDHC_OP_EXT_REG                        0x108
+#define OVRRD_CLK_OEN                  0x0800
+#define FORCE_CLK_ON                   0x1000
+
+#define SDHC_LEGACY_CTRL_REG           0x10C
+#define GEN_PAD_CLK_ON                 0x0040
+
+#define SDHC_MMC_CTRL_REG              0x114
+#define MISC_INT_EN                    0x0002
+#define MISC_INT                       0x0004
+#define ENHANCE_STROBE_EN              0x0100
+#define MMC_HS400                      0x0200
+#define MMC_HS200                      0x0400
+#define MMC_CARD_MODE                  0x1000
+
+#define SDHC_TX_CFG_REG                        0x11C
+#define TX_INT_CLK_SEL                 0x40000000
+#define TX_MUX_SEL                     0x80000000
+
+#define SDHC_PHY_CTRL_REG              0x160
+#define PHY_FUNC_EN                    0x0001
+#define PHY_PLL_LOCK                   0x0002
+#define HOST_LEGACY_MODE               0x80000000
+
+#define SDHC_PHY_FUNC_REG              0x164
+#define PHY_TEST_EN                    0x0080
+#define HS200_USE_RFIFO                        0x8000
+
+#define SDHC_PHY_DLLCFG                        0x168
+#define DLL_PREDLY_NUM                 0x04
+#define DLL_FULLDLY_RANGE              0x10
+#define DLL_VREG_CTRL                  0x40
+#define DLL_ENABLE                     0x80000000
+#define DLL_REFRESH_SWEN_SHIFT         0x1C
+#define DLL_REFRESH_SW_SHIFT           0x1D
+
+#define SDHC_PHY_DLLCFG1               0x16C
+#define DLL_REG2_CTRL                  0x0C
+#define DLL_REG3_CTRL_MASK             0xFF
+#define DLL_REG3_CTRL_SHIFT            0x10
+#define DLL_REG2_CTRL_MASK             0xFF
+#define DLL_REG2_CTRL_SHIFT            0x08
+#define DLL_REG1_CTRL                  0x92
+#define DLL_REG1_CTRL_MASK             0xFF
+#define DLL_REG1_CTRL_SHIFT            0x00
+
+#define SDHC_PHY_DLLSTS                        0x170
+#define DLL_LOCK_STATE                 0x01
+
+#define SDHC_PHY_DLLSTS1               0x174
+#define DLL_MASTER_DELAY_MASK          0xFF
+#define DLL_MASTER_DELAY_SHIFT         0x10
+
+#define SDHC_PHY_PADCFG_REG            0x178
+#define RX_BIAS_CTRL_SHIFT             0x5
+#define PHY_DRIVE_SEL_SHIFT            0x0
+#define PHY_DRIVE_SEL_MASK             0x7
+#define PHY_DRIVE_SEL_DEFAULT          0x4
+
+#define RPM_DELAY                      50
+#define MAX_74CLK_WAIT_COUNT           74
+
+#define MMC1_IO_V18EN                  0x04
+#define AKEY_ASFAR                     0xBABA
+#define AKEY_ASSAR                     0xEB10
+
+#define SDHC_RX_CFG_REG                        0x118
+#define RX_SDCLK_SEL0_MASK             0x03
+#define RX_SDCLK_SEL0_SHIFT            0x00
+#define RX_SDCLK_SEL0                  0x02
+#define RX_SDCLK_SEL1_MASK             0x03
+#define RX_SDCLK_SEL1_SHIFT            0x02
+#define RX_SDCLK_SEL1                  0x01
+
+#define SDHC_DLINE_CTRL_REG            0x130
+#define DLINE_PU                       0x01
+#define RX_DLINE_CODE_MASK             0xFF
+#define RX_DLINE_CODE_SHIFT            0x10
+#define TX_DLINE_CODE_MASK             0xFF
+#define TX_DLINE_CODE_SHIFT            0x18
+
+#define SDHC_DLINE_CFG_REG             0x134
+#define RX_DLINE_REG_MASK              0xFF
+#define RX_DLINE_REG_SHIFT             0x00
+#define RX_DLINE_GAIN_MASK             0x1
+#define RX_DLINE_GAIN_SHIFT            0x8
+#define RX_DLINE_GAIN                  0x1
+#define TX_DLINE_REG_MASK              0xFF
+#define TX_DLINE_REG_SHIFT             0x10
+
+#define SDHC_RX_TUNE_DELAY_MIN         0x0
+#define SDHC_RX_TUNE_DELAY_MAX         0xFF
+#define SDHC_RX_TUNE_DELAY_STEP                0x1
+
+
+struct spacemit_sdhci_plat {
+       struct mmc_config cfg;
+       struct mmc mmc;
+       struct reset_ctl_bulk resets;
+       struct clk_bulk clks;
+};
+
+struct spacemit_sdhci_priv {
+       struct sdhci_host host;
+       u32 clk_src_freq;
+       u32 phy_module;
+};
+
+struct spacemit_sdhci_driver_data {
+       const struct sdhci_ops *ops;
+       u32 flags;
+};
+
+/*
+ * refer to PMU_SDH0_CLK_RES_CTRL<0x054>, SDH0_CLK_SEL:0x0, SDH0_CLK_DIV:0x1
+ * the default clock source is 204800000Hz [409.6MHz(pll1_d6_409p6Mhz)/2]
+ *
+ * in the start-up phase, use the 200KHz frequency
+ */
+#define SDHC_DEFAULT_MAX_CLOCK (204800000)
+#define SDHC_MIN_CLOCK (200*1000)
+
+static int is_emulator_platform(void)
+{
+#ifdef CONFIG_K1_X_BOARD_FPGA
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+static int spacemit_reg[] = {
+       0x100, 0x104, 0x108, 0x10c, 0x110, 0x114, 0x118, 0x11c,
+       0x120, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x160, 0x164,
+       0x168, 0x16c, 0x170, 0x174, 0x178, 0x17c, 0x180, 0x184,
+       0x188, 0x18c, 0x190, 0x1f0, 0x1f4, 0xFFF,
+};
+static u8 cur_com_reg[960]; /* 8 line, 120  character  per line */
+static u8 cur_pri_reg[960];
+
+static void __maybe_unused dump_sdh_regs(struct sdhci_host *host, u8 is_emmc)
+{
+       int val;
+       int offset;
+       int i;
+       int len;
+       char *buf;
+
+       buf = (char *)&cur_com_reg[0];
+       len = 0;
+       i = 0;
+       for (offset = 0; offset < 0x70; offset += 4) {
+               val = sdhci_readl(host, offset);
+               if (i % 4 == 0)
+                       len += sprintf(buf + len, "\n");
+               len += sprintf(buf + len, "\toffset:0x%03x 0x%08x\t", offset, val);
+               i++;
+       }
+
+       if (i % 4 == 0)
+               len += sprintf(buf + len, "\n");
+       val = sdhci_readl(host, 0xe0);
+       len += sprintf(buf + len, "\toffset:0x%03x 0x%08x\t", 0xe0, val);
+       val = sdhci_readl(host, 0xfc);
+       len += sprintf(buf + len, "\toffset:0x%03x 0x%08x\t\n", 0xfc, val);
+
+       buf = (char *)&cur_pri_reg[0];
+       len = 0;
+       i = 0;
+       do {
+               if (!is_emmc && (spacemit_reg[i] > 0x134))
+                       break;
+               val = sdhci_readl(host, spacemit_reg[i]);
+               if (i % 4 == 0)
+                       len += sprintf(buf + len, "\n");
+               len += sprintf(buf + len, "\toffset:0x%03x 0x%08x\t", spacemit_reg[i], val);
+               i++;
+       } while (spacemit_reg[i] != 0xFFF);
+       len += sprintf(buf + len, "\n");
+
+       pr_debug("%s", cur_com_reg);
+       pr_debug("%s", cur_pri_reg);
+}
+
+static void spacemit_mmc_phy_init(struct sdhci_host *host)
+{
+       struct udevice *dev = host->mmc->dev;
+       struct spacemit_sdhci_priv *priv = dev_get_priv(dev);
+       unsigned int value = 0;
+
+       if (priv->phy_module) {
+               /* mmc card mode */
+               value = sdhci_readl(host, SDHC_MMC_CTRL_REG);
+               value |= MMC_CARD_MODE;
+               sdhci_writel(host, value, SDHC_MMC_CTRL_REG);
+
+               if (is_emulator_platform()) {
+                       /* mmc phy bypass */
+                       value = sdhci_readl(host, SDHC_TX_CFG_REG);
+                       value |= TX_INT_CLK_SEL;
+                       sdhci_writel (host, value, SDHC_TX_CFG_REG);
+
+                       value = sdhci_readl(host, SDHC_PHY_CTRL_REG);
+                       value |= HOST_LEGACY_MODE;
+                       sdhci_writel (host, value, SDHC_PHY_CTRL_REG);
+
+                       value = sdhci_readl(host, SDHC_PHY_FUNC_REG);
+                       value |= PHY_TEST_EN;
+                       sdhci_writel (host, value, SDHC_PHY_FUNC_REG);
+                       pr_debug("%s: mmc phy bypass.\n", host->name);
+               } else {
+                       /* use phy func mode */
+                       value = sdhci_readl(host, SDHC_PHY_CTRL_REG);
+                       value |= (PHY_FUNC_EN | PHY_PLL_LOCK);
+                       sdhci_writel(host, value, SDHC_PHY_CTRL_REG);
+
+                       value = sdhci_readl(host, SDHC_PHY_PADCFG_REG);
+                       value |= (1 << RX_BIAS_CTRL_SHIFT);
+                       sdhci_writel(host, value, SDHC_PHY_PADCFG_REG);
+                       pr_debug("%s: use mmc phy func.\n", host->name);
+               }
+       } else {
+               pr_debug("%s: not support phy module.\n", host->name);
+               value = sdhci_readl (host, SDHC_TX_CFG_REG);
+               value |= TX_INT_CLK_SEL;
+               sdhci_writel (host, value, SDHC_TX_CFG_REG);
+       }
+
+       value = sdhci_readl(host, SDHC_MMC_CTRL_REG);
+       value &= ~ENHANCE_STROBE_EN;
+       sdhci_writel(host, value, SDHC_MMC_CTRL_REG);
+}
+
+#define MAX_WAIT_COUNT 100
+int spacemit_set_sdh_74_clk(struct udevice *dev)
+{
+       struct spacemit_sdhci_priv *priv = dev_get_priv(dev);
+       struct sdhci_host *host = &priv->host;
+       u32 tmp = 0;
+       int count = 0;
+
+       tmp = sdhci_readl(host, SDHC_MMC_CTRL_REG);
+       tmp |= MISC_INT | MISC_INT_EN;
+       sdhci_writel(host, tmp, SDHC_MMC_CTRL_REG);
+
+       tmp = sdhci_readl(host, SDHC_LEGACY_CTRL_REG);
+       tmp |= GEN_PAD_CLK_ON;
+       sdhci_writel(host, tmp, SDHC_LEGACY_CTRL_REG);
+
+       while (count < MAX_WAIT_COUNT) {
+               if (sdhci_readl(host, SDHC_MMC_CTRL_REG) & MISC_INT)
+                       break;
+
+               udelay(10);
+               count++;
+       }
+       if (count >= MAX_WAIT_COUNT){
+               pr_err("%s: 74 clk wait timeout(%d)\n", host->name, count);
+       }
+       return 0;
+}
+
+void spacemit_sdhci_set_control_reg(struct sdhci_host *host)
+{
+       struct mmc *mmc = (struct mmc *)host->mmc;
+       u32 reg;
+
+       if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+               reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               reg |= SDHCI_CTRL_VDD_180;
+               sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
+       }
+
+       if (mmc->selected_mode > SD_HS &&
+           mmc->selected_mode <= MMC_HS_400_ES)
+               sdhci_set_uhs_timing(host);
+
+       /* according to the SDHC_TX_CFG_REG(0x11c<bit>),
+        * set TX_INT_CLK_SEL to gurantee the hold time
+        * at default speed mode or HS/SDR12/SDR25/SDR50 mode.
+        */
+       reg = sdhci_readl(host, SDHC_TX_CFG_REG);
+       if ((mmc->selected_mode == MMC_LEGACY) ||
+           (mmc->selected_mode == MMC_HS) ||
+           (mmc->selected_mode == SD_HS) ||
+           (mmc->selected_mode == UHS_SDR12) ||
+           (mmc->selected_mode == UHS_SDR25) ||
+           (mmc->selected_mode == UHS_SDR50)) {
+               reg |= TX_INT_CLK_SEL;
+       } else {
+               reg &= ~TX_INT_CLK_SEL;
+       }
+       sdhci_writel(host, reg, SDHC_TX_CFG_REG);
+
+       if ((mmc->selected_mode == MMC_HS_200) ||
+           (mmc->selected_mode == MMC_HS_400) ||
+           (mmc->selected_mode == MMC_HS_400_ES)) {
+               reg = sdhci_readw(host, SDHC_MMC_CTRL_REG);
+               reg |= (mmc->selected_mode == MMC_HS_200) ? MMC_HS200 : MMC_HS400;
+               sdhci_writew(host, reg, SDHC_MMC_CTRL_REG);
+       } else {
+               reg = sdhci_readw(host, SDHC_MMC_CTRL_REG);
+               reg &= ~(MMC_HS200 | MMC_HS400 | ENHANCE_STROBE_EN);
+               sdhci_writew(host, reg, SDHC_MMC_CTRL_REG);
+       }
+}
+
+#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
+static int spacemit_sdhci_phy_dll_init(struct sdhci_host *host)
+{
+       u32 reg;
+       int i;
+
+       /* config dll_reg1 & dll_reg2 */
+       reg = sdhci_readl(host, SDHC_PHY_DLLCFG);
+       reg |= (DLL_PREDLY_NUM | DLL_FULLDLY_RANGE | DLL_VREG_CTRL);
+       sdhci_writel(host, reg, SDHC_PHY_DLLCFG);
+
+       reg = sdhci_readl(host, SDHC_PHY_DLLCFG1);
+       reg |= (DLL_REG1_CTRL & DLL_REG1_CTRL_MASK);
+       sdhci_writel(host, reg, SDHC_PHY_DLLCFG1);
+
+       /* dll enable */
+       reg = sdhci_readl(host, SDHC_PHY_DLLCFG);
+       reg |= DLL_ENABLE;
+       sdhci_writel(host, reg, SDHC_PHY_DLLCFG);
+
+       /* wait dll lock */
+       i = 0;
+       while (i++ < 100) {
+               if (sdhci_readl(host, SDHC_PHY_DLLSTS) & DLL_LOCK_STATE)
+                       break;
+               udelay(10);
+       }
+       if (i == 100) {
+               pr_err("%s: phy dll lock timeout\n", host->name);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int spacemit_sdhci_hs400_enhanced_strobe(struct sdhci_host *host)
+{
+       u32 reg;
+
+       reg = sdhci_readl(host, SDHC_MMC_CTRL_REG);
+       reg |= ENHANCE_STROBE_EN;
+       sdhci_writel(host, reg, SDHC_MMC_CTRL_REG);
+
+       return spacemit_sdhci_phy_dll_init(host);
+}
+#endif
+
+static int spacemit_sdhci_probe(struct udevice *dev)
+{
+       struct spacemit_sdhci_driver_data *drv_data =
+                       (struct spacemit_sdhci_driver_data *)dev_get_driver_data(dev);
+       struct spacemit_sdhci_plat *plat = dev_get_plat(dev);
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       struct spacemit_sdhci_priv *priv = dev_get_priv(dev);
+       struct sdhci_host *host = &priv->host;
+       struct dm_mmc_ops *mmc_driver_ops = (struct dm_mmc_ops *)dev->driver->ops;
+       struct clk clk;
+       int ret = 0;
+
+       host->mmc = &plat->mmc;
+       host->mmc->priv = host;
+       host->mmc->dev = dev;
+       upriv->mmc = host->mmc;
+
+       ret = clk_get_bulk(dev, &plat->clks);
+       if (ret) {
+               pr_err("Can't get clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable_bulk(&plat->clks);
+       if (ret) {
+               pr_err("Failed to enable clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_get_bulk(dev, &plat->resets);
+       if (ret) {
+               pr_err("Can't get reset: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_deassert_bulk(&plat->resets);
+       if (ret) {
+               pr_err("Failed to reset: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_index(dev, 0, &clk);
+       if (ret) {
+               pr_err("Can't get io clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_rate(&clk, priv->clk_src_freq);
+       if (ret) {
+               pr_err("Failed to set io clk: %d\n", ret);
+               return ret;
+       }
+
+       /* Set quirks */
+#if defined(CONFIG_SPL_BUILD)
+       host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
+#else
+       host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_32BIT_DMA_ADDR;
+#endif
+       host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+       host->max_clk = priv->clk_src_freq;
+
+       plat->cfg.f_max = priv->clk_src_freq;
+       plat->cfg.f_min = SDHC_MIN_CLOCK;
+       host->ops = drv_data->ops;
+
+       mmc_driver_ops->deferred_probe = spacemit_set_sdh_74_clk;
+
+       ret = sdhci_setup_cfg(&plat->cfg, host, priv->clk_src_freq, SDHC_MIN_CLOCK);
+       if (ret)
+               return ret;
+
+       ret = sdhci_probe(dev);
+       if (ret)
+               return ret;
+
+       /* emmc phy bypass if need */
+       spacemit_mmc_phy_init(host);
+
+       pr_info("%s: probe done.\n", host->name);
+       return ret;
+}
+
+static int spacemit_sdhci_of_to_plat(struct udevice *dev)
+{
+       struct spacemit_sdhci_plat *plat = dev_get_plat(dev);
+       struct spacemit_sdhci_priv *priv = dev_get_priv(dev);
+       struct sdhci_host *host = &priv->host;
+       const void *blob = gd->fdt_blob;
+       int node = dev_of_offset(dev);
+       int ret = 0;
+
+       host->name = dev->name;
+       host->ioaddr = (void *)devfdt_get_addr(dev);
+       priv->phy_module = fdtdec_get_uint(blob, node, "sdh-phy-module", 0);
+
+       priv->clk_src_freq = fdtdec_get_uint(blob, node, "clk-src-freq", SDHC_DEFAULT_MAX_CLOCK);
+       ret = mmc_of_parse(dev, &plat->cfg);
+
+       return ret;
+}
+
+static int spacemit_sdhci_bind(struct udevice *dev)
+{
+       struct spacemit_sdhci_plat *plat = dev_get_plat(dev);
+
+       return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+const struct sdhci_ops spacemit_sdhci_ops = {
+       .set_control_reg = spacemit_sdhci_set_control_reg,
+#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
+       .set_enhanced_strobe = spacemit_sdhci_hs400_enhanced_strobe,
+#endif
+};
+
+const struct spacemit_sdhci_driver_data spacemit_sdhci_drv_data = {
+       .ops = &spacemit_sdhci_ops,
+};
+
+static const struct udevice_id spacemit_sdhci_ids[] = {
+       { .compatible = "spacemit,k1-x-sdhci",
+         .data = (ulong)&spacemit_sdhci_drv_data,
+       },
+       { }
+};
+
+U_BOOT_DRIVER(spacemit_sdhci_drv) = {
+       .name           = "spacemit_sdhci",
+       .id             = UCLASS_MMC,
+       .of_match       = spacemit_sdhci_ids,
+       .of_to_plat = spacemit_sdhci_of_to_plat,
+       .ops            = &sdhci_ops,
+       .bind           = spacemit_sdhci_bind,
+       .probe          = spacemit_sdhci_probe,
+       .priv_auto = sizeof(struct spacemit_sdhci_priv),
+       .plat_auto = sizeof(struct spacemit_sdhci_plat),
+};
index 688bdc06d4267fff8641e218396006a66b1987e9..87303a7e77cbb844578285a6cc12d15a6c7c43c9 100644 (file)
@@ -294,7 +294,7 @@ struct mmc *find_mmc_device(int dev_num)
 
        if (ret) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
-               printf("MMC Device %d not found\n", dev_num);
+               pr_err("MMC Device %d not found\n", dev_num);
 #endif
                return NULL;
        }
@@ -378,7 +378,7 @@ void print_mmc_devices(char separator)
                struct mmc *m = mmc_get_mmc_dev(dev);
 
                if (!first) {
-                       printf("%c", separator);
+                       pr_info("%c", separator);
                        if (separator != '\n')
                                puts(" ");
                }
@@ -387,7 +387,7 @@ void print_mmc_devices(char separator)
                else
                        mmc_type = NULL;
 
-               printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
+               pr_info("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
                if (mmc_type)
                        printf(" (%s)", mmc_type);
        }
index 0b7c0be8cbc2a2ad6a10229dbc6f11b3c6ad5a32..bcc8997b5b138721c0842620433bb7041ea7c385 100644 (file)
@@ -70,8 +70,8 @@ __weak int board_mmc_getcd(struct mmc *mmc)
 #ifdef CONFIG_MMC_TRACE
 void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
 {
-       printf("CMD_SEND:%d\n", cmd->cmdidx);
-       printf("\t\tARG\t\t\t 0x%08x\n", cmd->cmdarg);
+       pr_debug("CMD_SEND:%d\n", cmd->cmdidx);
+       pr_debug("\t\tARG\t\t\t 0x%08x\n", cmd->cmdarg);
 }
 
 void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
@@ -80,47 +80,48 @@ void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
        u8 *ptr;
 
        if (ret) {
-               printf("\t\tRET\t\t\t %d\n", ret);
+               pr_debug("\t\tRET\t\t\t %d\n", ret);
        } else {
                switch (cmd->resp_type) {
                case MMC_RSP_NONE:
-                       printf("\t\tMMC_RSP_NONE\n");
+                       pr_debug("\t\tMMC_RSP_NONE\n");
                        break;
                case MMC_RSP_R1:
-                       printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08x \n",
+                       pr_debug("\t\tMMC_RSP_R1,5,6,7 \t 0x%08x \n",
                                cmd->response[0]);
                        break;
                case MMC_RSP_R1b:
-                       printf("\t\tMMC_RSP_R1b\t\t 0x%08x \n",
+                       pr_debug("\t\tMMC_RSP_R1b\t\t 0x%08x \n",
                                cmd->response[0]);
                        break;
                case MMC_RSP_R2:
-                       printf("\t\tMMC_RSP_R2\t\t 0x%08x \n",
+                       pr_debug("\t\tMMC_RSP_R2\t\t 0x%08x \n",
                                cmd->response[0]);
-                       printf("\t\t          \t\t 0x%08x \n",
+                       pr_debug("\t\t          \t\t 0x%08x \n",
                                cmd->response[1]);
-                       printf("\t\t          \t\t 0x%08x \n",
+                       pr_debug("\t\t          \t\t 0x%08x \n",
                                cmd->response[2]);
-                       printf("\t\t          \t\t 0x%08x \n",
+                       pr_debug("\t\t          \t\t 0x%08x \n",
                                cmd->response[3]);
-                       printf("\n");
-                       printf("\t\t\t\t\tDUMPING DATA\n");
+                       pr_debug("\n");
+                       pr_debug("\t\t\t\t\tDUMPING DATA\n");
                        for (i = 0; i < 4; i++) {
                                int j;
-                               printf("\t\t\t\t\t%03d - ", i*4);
+                               pr_debug("\t\t\t\t\t%03d - ", i*4);
                                ptr = (u8 *)&cmd->response[i];
                                ptr += 3;
-                               for (j = 0; j < 4; j++)
-                                       printf("%02x ", *ptr--);
-                               printf("\n");
+                               for (j = 0; j < 4; j++){
+                                       pr_debug("%02x ", *ptr--);
+                               }
+                               pr_debug("\n");
                        }
                        break;
                case MMC_RSP_R3:
-                       printf("\t\tMMC_RSP_R3,4\t\t 0x%08x \n",
+                       pr_debug("\t\tMMC_RSP_R3,4\t\t 0x%08x \n",
                                cmd->response[0]);
                        break;
                default:
-                       printf("\t\tERROR MMC rsp not supported\n");
+                       pr_debug("\t\tERROR MMC rsp not supported\n");
                        break;
                }
        }
@@ -131,7 +132,7 @@ void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
        int status;
 
        status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
-       printf("CURR STATE:%d\n", status);
+       pr_debug("CURR STATE:%d\n", status);
 }
 #endif
 
@@ -1789,6 +1790,12 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
                return 0;
        }
 
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+       err = sd_read_ssr(mmc);
+       if (err)
+               pr_warn("unable to read ssr\n");
+#endif
+
        /* Restrict card's capabilities by what the host can do */
        caps = card_caps & mmc->host_caps;
 
@@ -1833,11 +1840,6 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
                                }
 #endif
 
-#if CONFIG_IS_ENABLED(MMC_WRITE)
-                               err = sd_read_ssr(mmc);
-                               if (err)
-                                       pr_warn("unable to read ssr\n");
-#endif
                                if (!err)
                                        return 0;
 
@@ -2066,7 +2068,7 @@ static int mmc_select_hs400es(struct mmc *mmc)
                         EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG |
                         EXT_CSD_BUS_WIDTH_STROBE);
        if (err) {
-               printf("switch to bus width for hs400 failed\n");
+               pr_err("switch to bus width for hs400 failed\n");
                return err;
        }
        /* TODO: driver strength */
@@ -2165,13 +2167,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
                        if (mwt->mode == MMC_HS_400) {
                                err = mmc_select_hs400(mmc);
                                if (err) {
-                                       printf("Select HS400 failed %d\n", err);
+                                       pr_err("Select HS400 failed %d\n", err);
                                        goto error;
                                }
                        } else if (mwt->mode == MMC_HS_400_ES) {
                                err = mmc_select_hs400es(mmc);
                                if (err) {
-                                       printf("Select HS400ES failed %d\n",
+                                       pr_err("Select HS400ES failed %d\n",
                                               err);
                                        goto error;
                                }
@@ -2757,7 +2759,7 @@ static int mmc_power_on(struct mmc *mmc)
                int ret = regulator_set_enable(mmc->vmmc_supply, true);
 
                if (ret && ret != -EACCES) {
-                       printf("Error enabling VMMC supply : %d\n", ret);
+                       pr_err("Error enabling VMMC supply : %d\n", ret);
                        return ret;
                }
        }
index bf989a594f7e38c85262b9a56d6e4a8ceb592871..ad9d7dfa03302af8f431a2db571660be9a9ad7d0 100644 (file)
@@ -31,7 +31,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
        while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
                if (timeout == 0) {
-                       printf("%s: Reset 0x%x never completed.\n",
+                       pr_err("%s: Reset 0x%x never completed.\n",
                               __func__, (int)mask);
                        return;
                }
@@ -172,7 +172,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
                if (timeout-- > 0)
                        udelay(10);
                else {
-                       printf("%s: Transfer data timeout\n", __func__);
+                       pr_err("%s: Transfer data timeout\n", __func__);
                        return -ETIMEDOUT;
                }
        } while (!(stat & SDHCI_INT_DATA_END));
@@ -231,10 +231,10 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 
        while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
                if (time >= cmd_timeout) {
-                       printf("%s: MMC: %d busy ", __func__, mmc_dev);
+                       pr_debug("%s: MMC: %d busy ", __func__, mmc_dev);
                        if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) {
                                cmd_timeout += cmd_timeout;
-                               printf("timeout increasing to: %u ms.\n",
+                               pr_err("timeout increasing to: %u ms.\n",
                                       cmd_timeout);
                        } else {
                                puts("timeout.\n");
@@ -307,7 +307,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
                        if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) {
                                return 0;
                        } else {
-                               printf("%s: Timeout for status update!\n",
+                               pr_err("%s: Timeout for status update!\n",
                                       __func__);
                                return -ETIMEDOUT;
                        }
@@ -372,7 +372,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
        while (sdhci_readl(host, SDHCI_PRESENT_STATE) &
                           (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
                if (timeout == 0) {
-                       printf("%s: Timeout to wait cmd & data inhibit\n",
+                       pr_err("%s: Timeout to wait cmd & data inhibit\n",
                               __func__);
                        return -EBUSY;
                }
@@ -389,7 +389,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
        if (host->ops && host->ops->set_delay) {
                ret = host->ops->set_delay(host);
                if (ret) {
-                       printf("%s: Error while setting tap delay\n", __func__);
+                       pr_err("%s: Error while setting tap delay\n", __func__);
                        return ret;
                }
        }
@@ -448,7 +448,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
        while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
                & SDHCI_CLOCK_INT_STABLE)) {
                if (timeout == 0) {
-                       printf("%s: Internal clock never stabilised.\n",
+                       pr_err("%s: Internal clock never stabilised.\n",
                               __func__);
                        return -EBUSY;
                }
@@ -709,7 +709,7 @@ static int sdhci_init(struct mmc *mmc)
        if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) {
                host->align_buffer = memalign(8, 512 * 1024);
                if (!host->align_buffer) {
-                       printf("%s: Aligned buffer alloc failed!!!\n",
+                       pr_err("%s: Aligned buffer alloc failed!!!\n",
                               __func__);
                        return -ENOMEM;
                }
@@ -864,7 +864,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
 #endif
 #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
        if (!(caps & SDHCI_CAN_DO_ADMA2)) {
-               printf("%s: Your controller doesn't support SDMA!!\n",
+               pr_err("%s: Your controller doesn't support SDMA!!\n",
                       __func__);
                return -EINVAL;
        }
@@ -914,7 +914,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
                        host->max_clk *= host->clk_mul;
        }
        if (host->max_clk == 0) {
-               printf("%s: Hardware doesn't specify base clock frequency\n",
+               pr_err("%s: Hardware doesn't specify base clock frequency\n",
                       __func__);
                return -EINVAL;
        }
@@ -1004,7 +1004,7 @@ int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min)
 
        host->mmc = mmc_create(&host->cfg, host);
        if (host->mmc == NULL) {
-               printf("%s: mmc create fail!\n", __func__);
+               pr_err("%s: mmc create fail!\n", __func__);
                return -ENOMEM;
        }
 
diff --git a/drivers/mmc/spacemit_sdhci.c b/drivers/mmc/spacemit_sdhci.c
new file mode 100644 (file)
index 0000000..10a1358
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <reset-uclass.h>
+#include <asm/global_data.h>
+
+#define SPACEMIT_SDHC_MIN_FREQ    (400000)
+#define SDHCI_CTRL_ADMA2_LEN_MODE BIT(10)
+#define SDHCI_CTRL_CMD23_ENABLE BIT(11)
+#define SDHCI_CTRL_HOST_VERSION_4_ENABLE BIT(12)
+#define SDHCI_CTRL_ADDRESSING BIT(13)
+#define SDHCI_CTRL_ASYNC_INT_ENABLE BIT(14)
+
+#define SDHCI_CLOCK_PLL_EN BIT(3)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct spacemit_sdhci_plat {
+       struct mmc_config cfg;
+       struct mmc mmc;
+       struct reset_ctl *reset;
+};
+
+static const struct sdhci_ops spacemit_ops = {
+       .set_control_reg = &sdhci_set_control_reg,
+};
+
+static void sdhci_do_enable_v4_mode(struct udevice *dev)
+{
+       struct sdhci_host *host = dev_get_priv(dev);
+       u16 ctrl2;
+       ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       ctrl2 |= SDHCI_CTRL_ADMA2_LEN_MODE
+                       | SDHCI_CTRL_CMD23_ENABLE
+                       | SDHCI_CTRL_HOST_VERSION_4_ENABLE
+                       | SDHCI_CTRL_ADDRESSING
+                       | SDHCI_CTRL_ASYNC_INT_ENABLE;
+
+       sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+}
+
+static struct dm_mmc_ops spacemit_mmc_ops;
+
+static int spacemit_sdhci_probe(struct udevice *dev)
+{
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       struct spacemit_sdhci_plat *plat = dev_get_plat(dev);
+       struct sdhci_host *host = dev_get_priv(dev);
+       u32 max_clk;
+       int ret;
+
+       struct clk clk;
+       ret = clk_get_by_index(dev, 0, &clk);
+       if (ret)
+               return ret;
+
+       ret = clk_enable(&clk);
+       if (ret)
+               return ret;
+
+       plat->reset = devm_reset_control_get_by_index(dev, 0);
+       if (IS_ERR(plat->reset)) {
+               pr_err("get optional reset failed\n");
+               return -EINVAL;
+       }
+
+       ret = reset_deassert(plat->reset);
+       if (ret < 0) {
+               pr_err("MMC1 deassert failed: %d", ret);
+               return ret;
+       }
+
+       max_clk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+                                       "max-frequency", 50000000);
+
+       host->name = dev->name;
+       host->ioaddr = dev_read_addr_ptr(dev);
+       host->ops = &spacemit_ops;
+       host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
+       host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+                                        "bus-width", 4);
+
+       ret = mmc_of_parse(dev, &plat->cfg);
+       if (ret)
+               return ret;
+
+       host->max_clk = max_clk;
+       host->mmc = &plat->mmc;
+       host->mmc->dev = dev;
+       spacemit_mmc_ops = sdhci_ops;
+       spacemit_mmc_ops.reinit = sdhci_probe;
+
+       ret = sdhci_setup_cfg(&plat->cfg, host, max_clk, SPACEMIT_SDHC_MIN_FREQ);
+       if (ret)
+               return ret;
+
+       host->mmc->priv = host;
+       upriv->mmc = host->mmc;
+
+       /* clk_free(&clk); */
+       
+       ret = sdhci_probe(dev);
+       if (ret)
+               return ret;
+
+       /*
+       enable v4 should execute after sdhci_probe, because sdhci reset would
+       clear the SDHCI_HOST_CONTROL2 register.
+       */
+       sdhci_do_enable_v4_mode(dev);
+       return 0;
+}
+
+static int spacemit_sdhci_bind(struct udevice *dev)
+{
+       struct spacemit_sdhci_plat *plat = dev_get_plat(dev);
+
+       return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id spacemit_sdhci_ids[] = {
+       { .compatible = "spacemit,k1-pro-sdhci" },
+       { }
+};
+
+U_BOOT_DRIVER(spacemit_sdhci_drv) = {
+       .name           = "spacemit_sdhci",
+       .id             = UCLASS_MMC,
+       .of_match       = spacemit_sdhci_ids,
+       .ops            = &spacemit_mmc_ops,
+       .bind           = spacemit_sdhci_bind,
+       .probe          = spacemit_sdhci_probe,
+       .priv_auto      = sizeof(struct sdhci_host),
+       .plat_auto      = sizeof(struct spacemit_sdhci_plat),
+};
index 3a78590aaaa1d03d66cc598b706e606516a49ef4..27e371b304d53d85bc7da97ddec8642dbe453633 100644 (file)
@@ -36,5 +36,6 @@ obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += nand/
 obj-$(CONFIG_SPL_ONENAND_SUPPORT) += onenand/
 obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += spi/
 obj-$(CONFIG_SPL_UBI) += ubispl/
+obj-$(CONFIG_SPL_NAND_DRIVERS) += mtdcore.o nand/
 
 endif
index 495041070650f70a5f0cbc5f5356698e87a55b93..f9358e36e1fbb91ccae2e6405bf504e7be35f192 100644 (file)
@@ -587,7 +587,7 @@ static int flash_status_check(flash_info_t *info, flash_sect_t sector,
        WATCHDOG_RESET();
        while (flash_is_busy(info, sector)) {
                if (get_timer(start) > tout) {
-                       printf("Flash %s timeout at address %lx data %lx\n",
+                       pr_err("Flash %s timeout at address %lx data %lx\n",
                               prompt, info->start[sector],
                               flash_read_long(info, sector, 0));
                        flash_write_cmd(info, sector, 0, info->cmd_reset);
@@ -618,7 +618,7 @@ static int flash_full_status_check(flash_info_t *info, flash_sect_t sector,
                if (retcode == ERR_OK &&
                    !flash_isset(info, sector, 0, FLASH_STATUS_DONE)) {
                        retcode = ERR_INVAL;
-                       printf("Flash %s error at address %lx\n", prompt,
+                       pr_err("Flash %s error at address %lx\n", prompt,
                               info->start[sector]);
                        if (flash_isset(info, sector, 0, FLASH_STATUS_ECLBS |
                                         FLASH_STATUS_PSLBS)) {
@@ -699,7 +699,7 @@ static int flash_status_poll(flash_info_t *info, void *src, void *dst,
                if (ready)
                        break;
                if (get_timer(start) > tout) {
-                       printf("Flash %s timeout at address %lx data %lx\n",
+                       pr_err("Flash %s timeout at address %lx data %lx\n",
                               prompt, (ulong)dst, (ulong)flash_read8(dst));
                        return ERR_TIMEOUT;
                }
@@ -1074,7 +1074,7 @@ int flash_erase(flash_info_t *info, int s_first, int s_last)
                if (info->protect[sect])
                        prot++;
        if (prot) {
-               printf("- Warning: %d protected sectors will not be erased!\n",
+               pr_debug("- Warning: %d protected sectors will not be erased!\n",
                       prot);
        } else if (flash_verbose) {
                putc('\n');
@@ -1082,7 +1082,7 @@ int flash_erase(flash_info_t *info, int s_first, int s_last)
 
        for (sect = s_first; sect <= s_last; sect++) {
                if (ctrlc()) {
-                       printf("\n");
+                       pr_debug("\n");
                        return 1;
                }
 
@@ -1212,57 +1212,59 @@ void flash_print_info(flash_info_t *info)
                return;
        }
 
-       printf("%s flash (%d x %d)",
+       pr_debug("%s flash (%d x %d)",
               info->name,
               (info->portwidth << 3), (info->chipwidth << 3));
-       if (info->size < 1024 * 1024)
-               printf("  Size: %ld kB in %d Sectors\n",
+       if (info->size < 1024 * 1024){
+               pr_debug("  Size: %ld kB in %d Sectors\n",
                       info->size >> 10, info->sector_count);
-       else
-               printf("  Size: %ld MB in %d Sectors\n",
+       }else{
+               pr_debug("  Size: %ld MB in %d Sectors\n",
                       info->size >> 20, info->sector_count);
-       printf("  ");
+       }
+       pr_debug("  ");
        switch (info->vendor) {
        case CFI_CMDSET_INTEL_PROG_REGIONS:
-               printf("Intel Prog Regions");
+               pr_debug("Intel Prog Regions");
                break;
        case CFI_CMDSET_INTEL_STANDARD:
-               printf("Intel Standard");
+               pr_debug("Intel Standard");
                break;
        case CFI_CMDSET_INTEL_EXTENDED:
-               printf("Intel Extended");
+               pr_debug("Intel Extended");
                break;
        case CFI_CMDSET_AMD_STANDARD:
-               printf("AMD Standard");
+               pr_debug("AMD Standard");
                break;
        case CFI_CMDSET_AMD_EXTENDED:
-               printf("AMD Extended");
+               pr_debug("AMD Extended");
                break;
 #ifdef CONFIG_FLASH_CFI_LEGACY
        case CFI_CMDSET_AMD_LEGACY:
-               printf("AMD Legacy");
+               pr_debug("AMD Legacy");
                break;
 #endif
        default:
-               printf("Unknown (%d)", info->vendor);
+               pr_debug("Unknown (%d)", info->vendor);
                break;
        }
-       printf(" command set, Manufacturer ID: 0x%02X, Device ID: 0x",
+       pr_debug(" command set, Manufacturer ID: 0x%02X, Device ID: 0x",
               info->manufacturer_id);
-       printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X",
+       pr_debug(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X",
               info->device_id);
        if ((info->device_id & 0xff) == 0x7E) {
-               printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X",
+               pr_debug(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X",
                       info->device_id2);
        }
-       if (info->vendor == CFI_CMDSET_AMD_STANDARD && info->legacy_unlock)
-               printf("\n  Advanced Sector Protection (PPB) enabled");
-       printf("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
+       if (info->vendor == CFI_CMDSET_AMD_STANDARD && info->legacy_unlock){
+               pr_debug("\n  Advanced Sector Protection (PPB) enabled");
+       }
+       pr_debug("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
               info->erase_blk_tout, info->write_tout);
        if (info->buffer_size > 1) {
-               printf("  Buffer write timeout: %ld ms, ",
+               pr_debug("  Buffer write timeout: %ld ms, ",
                       info->buffer_write_tout);
-               printf("buffer size: %d bytes\n", info->buffer_size);
+               pr_debug("buffer size: %d bytes\n", info->buffer_size);
        }
 
        puts("\n  Sector Start Addresses:");
@@ -1273,12 +1275,12 @@ void flash_print_info(flash_info_t *info)
                        putc('\n');
 #ifdef CONFIG_SYS_FLASH_EMPTY_INFO
                /* print empty and read-only info */
-               printf("  %08lX %c %s ",
+               pr_debug("  %08lX %c %s ",
                       info->start[i],
                       sector_erased(info, i) ? 'E' : ' ',
                       info->protect[i] ? "RO" : "  ");
 #else  /* ! CONFIG_SYS_FLASH_EMPTY_INFO */
-               printf("  %08lX   %s ",
+               pr_debug("  %08lX   %s ",
                       info->start[i],
                       info->protect[i] ? "RO" : "  ");
 #endif
@@ -1553,7 +1555,7 @@ int flash_real_protect(flash_info_t *info, long sector, int prot)
                        if (flash_status_check(info, sector,
                                               info->erase_blk_tout,
                                               prot ? "protect" : "unprotect"))
-                               printf("status check error\n");
+                               pr_debug("status check error\n");
 
                        flash_write_cmd(info, 0, 0,
                                        AMD_CMD_SET_PPB_EXIT_BC1);
@@ -2146,7 +2148,7 @@ ulong flash_get_size(phys_addr_t base, int banknum)
                        cmdset_amd_init(info, &qry);
                        break;
                default:
-                       printf("CFI: Unknown command set 0x%x\n",
+                       pr_debug("CFI: Unknown command set 0x%x\n",
                               info->vendor);
                        /*
                         * Unfortunately, this means we don't know how
@@ -2205,7 +2207,7 @@ ulong flash_get_size(phys_addr_t base, int banknum)
                sector = base;
                for (i = 0; i < num_erase_regions; i++) {
                        if (i > NUM_ERASE_REGIONS) {
-                               printf("%d erase regions found, only %d used\n",
+                               pr_debug("%d erase regions found, only %d used\n",
                                       num_erase_regions, NUM_ERASE_REGIONS);
                                break;
                        }
@@ -2224,7 +2226,7 @@ ulong flash_get_size(phys_addr_t base, int banknum)
                                if (sector - base >= info->size)
                                        break;
                                if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
-                                       printf("ERROR: too many flash sectors\n");
+                                       pr_debug("ERROR: too many flash sectors\n");
                                        break;
                                }
                                info->start[sect_cnt] =
@@ -2424,8 +2426,8 @@ unsigned long flash_init(void)
                size += flash_info[i].size;
                if (flash_info[i].flash_id == FLASH_UNKNOWN) {
 #ifndef CONFIG_SYS_FLASH_QUIET_TEST
-                       printf("## Unknown flash on Bank %d ", i + 1);
-                       printf("- Size = 0x%08lx = %ld MB\n",
+                       pr_debug("## Unknown flash on Bank %d ", i + 1);
+                       pr_debug("- Size = 0x%08lx = %ld MB\n",
                               flash_info[i].size,
                               flash_info[i].size >> 20);
 #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
index dd0b0242f95fa4b0b6d05fb3efc676eb0f1c5af4..a71e7d438413277fb8d51e2cbbf3f3a264b949d7 100644 (file)
@@ -168,9 +168,10 @@ static int mtd_del_parts(struct mtd_info *mtd, bool quiet)
 
        /* do not delete partitions if they are in use. */
        if (mtd_partitions_used(mtd)) {
-               if (!quiet)
-                       printf("\"%s\" partitions still in use, can't delete them\n",
+               if (!quiet){
+                       pr_info("\"%s\" partitions still in use, can't delete them\n",
                               mtd->name);
+               }
                return -EACCES;
        }
 
@@ -234,13 +235,13 @@ static int parse_mtdparts(const char *mtdparts, const char *mtdids)
                        colon = NULL;
 
                if (!colon) {
-                       printf("Wrong mtdparts: %s\n", mtdparts);
+                       pr_info("Wrong mtdparts: %s\n", mtdparts);
                        return -EINVAL;
                }
 
                mtd_name_len = (unsigned int)(colon - mtdparts);
                if (mtd_name_len + 1 > sizeof(mtd_name)) {
-                       printf("MTD name too long: %s\n", mtdparts);
+                       pr_info("MTD name too long: %s\n", mtdparts);
                        return -EINVAL;
                }
 
@@ -268,7 +269,7 @@ static int parse_mtdparts(const char *mtdparts, const char *mtdids)
                         * pointer forward until the next set of partitions.
                         */
                        if (ret || IS_ERR_OR_NULL(mtd)) {
-                               printf("Could not find a valid device for %s\n",
+                               pr_info("Could not find a valid device for %s\n",
                                       mtd_name);
                                mtdparts = mtdparts_next;
                                continue;
@@ -293,7 +294,7 @@ static int parse_mtdparts(const char *mtdparts, const char *mtdids)
                 */
                ret = mtd_parse_partitions(mtd, &mtdparts, &parts, &nparts);
                if (ret) {
-                       printf("Could not parse device %s\n", mtd->name);
+                       pr_info("Could not parse device %s\n", mtd->name);
                        put_mtd_device(mtd);
                        return -EINVAL;
                }
@@ -358,16 +359,18 @@ int mtd_probe_devices(void)
 
        /* If both mtdparts and mtdids are non-empty, parse */
        if (mtdparts && mtdids) {
-               if (parse_mtdparts(mtdparts, mtdids) < 0)
-                       printf("Failed parsing MTD partitions from mtdparts!\n");
+               if (parse_mtdparts(mtdparts, mtdids) < 0){
+                       pr_info("Failed parsing MTD partitions from mtdparts!\n");
+               }
        }
 
        /* Fallback to OF partitions */
        mtd_for_each_device(mtd) {
                if (list_empty(&mtd->partitions)) {
-                       if (add_mtd_partitions_of(mtd) < 0)
-                               printf("Failed parsing MTD %s OF partitions!\n",
+                       if (add_mtd_partitions_of(mtd) < 0){
+                               pr_info("Failed parsing MTD %s OF partitions!\n",
                                        mtd->name);
+                       }
                }
        }
 
index aa78d41a55e6747586252ee0046496949888e090..268200f01acfbebdfd60132cc0f8db193e05d8de 100644 (file)
@@ -78,7 +78,13 @@ static struct class mtd_class = {
        .resume = mtd_cls_resume,
 };
 #else
+
+#if defined (CONFIG_SPL_BUILD)
+// NO need to support so many MTD partition during SPL stage
+#define MAX_IDR_ID     16
+#else
 #define MAX_IDR_ID     64
+#endif
 
 struct idr_layer {
        int     used;
@@ -146,7 +152,17 @@ int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
 }
 #endif
 
+
+#if defined (CONFIG_SPL_BUILD)
+// change mtd idr item data from bss to data section, otherwise it will be memset
+// and cause mtd partition parse fail in below scenario
+// board_init_f: mtd_probe_devices, get_mtd_device_nm
+// bss section memset
+// board_init_r: mtd_probe_devices(bypass), get_mtd_device_nm(FAIL)
+__section(".data.mtd_idr") static DEFINE_IDR(mtd_idr);
+#else
 static DEFINE_IDR(mtd_idr);
+#endif
 
 /* These are exported solely for the purpose of mtd_blkdevs.c. You
    should not use them for _anything_ else */
@@ -812,9 +828,11 @@ struct mtd_info *get_mtd_device_nm(const char *name)
        mtd_for_each_device(other) {
 #ifdef __UBOOT__
                if (mtd_device_matches_name(other, name)) {
-                       if (mtd)
-                               printf("\nWarning: MTD name \"%s\" is not unique!\n\n",
+                       if (mtd){
+                               pr_debug("\nWarning: MTD name \"%s\" is not unique!\n\n",
                                       name);
+                       }
+
                        mtd = other;
                }
 #else /* !__UBOOT__ */
index 56aa58b58bb7f62d9d166e6bf81342d8cc300839..7454e96f5c4cfdbdccc9fd5ec99fa5f7e05057bf 100644 (file)
@@ -110,7 +110,7 @@ static int mtd_parse_partition(const char **_mtdparts,
        } else {
                partition->size = ustrtoull(mtdparts, (char **)&mtdparts, 0);
                if (partition->size < SZ_4K) {
-                       printf("Minimum partition size 4kiB, %lldB requested\n",
+                       pr_err("Minimum partition size 4kiB, %lldB requested\n",
                               partition->size);
                        return -EINVAL;
                }
@@ -128,12 +128,12 @@ static int mtd_parse_partition(const char **_mtdparts,
                name = ++mtdparts;
                mtdparts = strchr(name, ')');
                if (!mtdparts) {
-                       printf("No closing ')' found in partition name\n");
+                       pr_err("No closing ')' found in partition name\n");
                        return -EINVAL;
                }
                name_len = mtdparts - name + 1;
                if ((name_len - 1) == 0) {
-                       printf("Empty partition name\n");
+                       pr_err("Empty partition name\n");
                        return -EINVAL;
                }
                mtdparts++;
@@ -151,14 +151,14 @@ static int mtd_parse_partition(const char **_mtdparts,
        /* Check for a potential next partition definition */
        if (*mtdparts == ',') {
                if (partition->size == MTD_SIZE_REMAINING) {
-                       printf("No partitions allowed after a fill-up\n");
+                       pr_err("No partitions allowed after a fill-up\n");
                        return -EINVAL;
                }
                ++mtdparts;
        } else if ((*mtdparts == ';') || (*mtdparts == '\0')) {
                /* NOP */
        } else {
-               printf("Unexpected character '%c' in mtdparts\n", *mtdparts);
+               pr_err("Unexpected character '%c' in mtdparts\n", *mtdparts);
                return -EINVAL;
        }
 
@@ -225,7 +225,7 @@ int mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
        /* Allocate an array of partitions to give back to the caller */
        parts = malloc(sizeof(*parts) * nparts);
        if (!parts) {
-               printf("Not enough space to save partitions meta-data\n");
+               pr_err("Not enough space to save partitions meta-data\n");
                return -ENOMEM;
        }
 
@@ -241,7 +241,7 @@ int mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
 
                sz = parts[idx].size;
                if (sz < parent->writesize || do_div(sz, parent->writesize)) {
-                       printf("Partition size must be a multiple of %d\n",
+                       pr_err("Partition size must be a multiple of %d\n",
                               parent->writesize);
                        return -EINVAL;
                }
@@ -533,7 +533,7 @@ static int do_del_mtd_partitions(struct mtd_info *master)
                debug("Deleting %s MTD partition\n", slave->name);
                ret = del_mtd_device(slave);
                if (ret < 0) {
-                       printf("Error when deleting partition \"%s\" (%d)\n",
+                       pr_err("Error when deleting partition \"%s\" (%d)\n",
                               slave->name, ret);
                        err = ret;
                        continue;
index 96e186600a185e81b827f447a81ff3ec865afa98..ba935cbda5c69f8c34eb20f03fbc832e8f1b09d9 100644 (file)
@@ -7,4 +7,5 @@ obj-$(CONFIG_MTD_RAW_NAND) += raw/
 obj-$(CONFIG_MTD_SPI_NAND) += spi/
 else
 obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += raw/
+obj-$(CONFIG_SPL_NAND_DRIVERS) += core.o bbt.o spi/
 endif
index 6c65b187e86e8515427f548e38c613f100dc14a8..e1b013b5dfd35c2882a4ff437073860a672d1494 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o other.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
index e5330958c7e135b6ecac7e06b862d43b1b5cdfb2..200163ee2f47ed5e70340908986182d94208d3c5 100644 (file)
@@ -834,6 +834,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
        &micron_spinand_manufacturer,
        &toshiba_spinand_manufacturer,
        &winbond_spinand_manufacturer,
+       &other_spinand_manufacturer,
 };
 
 static int spinand_manufacturer_detect(struct spinand_device *spinand)
diff --git a/drivers/mtd/nand/spi/other.c b/drivers/mtd/nand/spi/other.c
new file mode 100644 (file)
index 0000000..b340f66
--- /dev/null
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Macronix
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef __UBOOT__
+#include <malloc.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/bug.h>
+#include <linux/mtd/spinand.h>
+
+#define MACRONIX_ECCSR_MASK            0x0F
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                     struct mtd_oob_region *region)
+{
+       return -ERANGE;
+}
+
+static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
+                                      struct mtd_oob_region *region)
+{
+       if (section)
+               return -ERANGE;
+
+       region->offset = 2;
+       region->length = mtd->oobsize - 2;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
+       .ecc = mx35lfxge4ab_ooblayout_ecc,
+       .rfree = mx35lfxge4ab_ooblayout_free,
+};
+
+static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
+{
+       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
+                                         SPI_MEM_OP_NO_ADDR,
+                                         SPI_MEM_OP_DUMMY(1, 1),
+                                         SPI_MEM_OP_DATA_IN(1, eccsr, 1));
+
+       int ret = spi_mem_exec_op(spinand->slave, &op);
+
+       if (ret)
+               return ret;
+
+       *eccsr &= MACRONIX_ECCSR_MASK;
+       return 0;
+}
+
+static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
+                                      u8 status)
+{
+       struct nand_device *nand = spinand_to_nand(spinand);
+       u8 eccsr;
+
+       switch (status & STATUS_ECC_MASK) {
+       case STATUS_ECC_NO_BITFLIPS:
+               return 0;
+
+       case STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       case STATUS_ECC_HAS_BITFLIPS:
+               /*
+                * Let's try to retrieve the real maximum number of bitflips
+                * in order to avoid forcing the wear-leveling layer to move
+                * data around if it's not necessary.
+                */
+               if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
+                       return nand->eccreq.strength;
+
+               if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
+                       return nand->eccreq.strength;
+
+               return eccsr;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct spinand_info dosilicon_spinand_table[] = {
+       SPINAND_INFO("DS35M1GA", 0x21,
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+
+};
+
+
+static const struct spinand_info foresee_spinand_table[] = {
+       SPINAND_INFO("jiangbolong", 0x60,
+                    NAND_MEMORG(1, 2048, 64, 64, 512, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+
+};
+
+static int other_spinand_detect(struct spinand_device *spinand)
+{
+       u8 *id = spinand->id.data;
+       int ret = 0;
+
+       /*
+        * dosilicon nand flash
+        */
+       if (id[1] == 0xe5)
+               ret = spinand_match_and_init(spinand, dosilicon_spinand_table,
+                                    ARRAY_SIZE(dosilicon_spinand_table),
+                                    id[2]);
+
+       /*FORESEE nand flash*/
+       if (id[1] == 0xcd)
+               ret = spinand_match_and_init(spinand, foresee_spinand_table,
+                                    ARRAY_SIZE(foresee_spinand_table),
+                                    id[2]);
+       if (ret)
+               return ret;
+
+       return 1;
+}
+
+static const struct spinand_manufacturer_ops other_spinand_manuf_ops = {
+       .detect = other_spinand_detect,
+};
+
+const struct spinand_manufacturer other_spinand_manufacturer = {
+       .name = "other",
+       .ops = &other_spinand_manuf_ops,
+};
index 096338f27bf1e3fbe251a35eaeed919bf5ac4451..87e218e0e9318349502149aa8cfe3aa5833db1df 100644 (file)
@@ -209,6 +209,21 @@ config SPI_FLASH_XTX
          Add support for various XTX (XTX Technology Limited)
          SPI flash chips (XT25xxx).
 
+config SPI_FLASH_FM
+       bool "FM SPI flash support"
+       help
+         Add support for various FM SPI flash chips (FM25Q64AI3)
+
+config SPINOR_BLOCK_SUPPORT
+       bool "Enable SquashFS block support for SPI NOR"
+       depends on FS_SQUASHFS
+       default n
+       help
+         This option enables block support for SPI NOR devices.
+         Enabling this feature allows filesystem to work with the SPI NOR block interface,
+         providing a compressed read-only filesystem optimized for low overhead
+         in embedded systems.
+
 endif
 
 config SPI_FLASH_USE_4K_SECTORS
index 99cc4185522331af8d6597f8670c4c2892615790..8a9b0746ded576b7c7b62a5e5daabefdf4c8f0fd 100644 (file)
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_$(SPL_TPL_)DM_SPI_FLASH) += sf-uclass.o
 spi-nor-y := sf_probe.o spi-nor-ids.o
+obj-$(CONFIG_SPINOR_BLOCK_SUPPORT) += spi-nor-blk.o
 
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_SPI_BOOT)     += fsl_espi_spl.o
index 071b25ac67f2d4e14f8ea3cf846716cbe926df85..815a2ec6b57373737a0ca93e2031f7fed5dad6e2 100644 (file)
@@ -156,7 +156,7 @@ void spi_flash_mtd_unregister(struct spi_flash *flash)
         * spi_flash object from being destroyed when del_mtd_device() fails.
         */
        sf_mtd_info.priv = NULL;
-       printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
+       pr_err("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
               sf_mtd_info.name);
 }
 
index f461082e03de22b4b26d29a2ad25f854c8541261..3e2e795471eef9a795e0d962f5a7de198db096cd 100644 (file)
@@ -14,6 +14,8 @@
 #include <malloc.h>
 #include <spi.h>
 #include <spi_flash.h>
+#include <blk.h>
+#include <dm/device-internal.h>
 
 #include "sf_internal.h"
 
@@ -30,7 +32,7 @@ static int spi_flash_probe_slave(struct spi_flash *flash)
 
        /* Setup spi_slave */
        if (!spi) {
-               printf("SF: Failed to set up slave\n");
+               pr_err("SF: Failed to set up slave\n");
                return -ENODEV;
        }
 
@@ -163,6 +165,38 @@ static int spi_flash_std_remove(struct udevice *dev)
        return 0;
 }
 
+#ifdef CONFIG_SPINOR_BLOCK_SUPPORT
+int spacemit_spinor_bind(struct udevice *dev)
+{
+       struct blk_desc *bdesc;
+       struct udevice *bdev;
+       int ret;
+       struct udevice *parent_dev = dev->parent;
+
+       // Create the block device interface for the SPI NOR device with the same parent as dev
+       ret = blk_create_devicef(parent_dev, "nor_blk", "blk", IF_TYPE_NOR,
+                                                        dev_seq(dev), SPI_NOR_BLOCK_SIZE, 0, &bdev);
+       if (ret) {
+               pr_err("Cannot create block device\n");
+               return ret;
+       }
+
+       // Obtain the block device descriptor
+       bdesc = dev_get_uclass_plat(bdev);
+       if (!bdesc) {
+               pr_err("Failed to get block device descriptor\n");
+               return -ENODEV;
+       }
+
+       // Initialize block device descriptor
+       bdesc->if_type = IF_TYPE_NOR;
+       bdesc->removable = 0;
+
+       dev_set_priv(bdev, dev);
+       return 0;
+}
+#endif /* CONFIG_SPINOR_BLOCK_SUPPORT */
+
 static const struct dm_spi_flash_ops spi_flash_std_ops = {
        .read = spi_flash_std_read,
        .write = spi_flash_std_write,
@@ -183,6 +217,9 @@ U_BOOT_DRIVER(jedec_spi_nor) = {
        .remove         = spi_flash_std_remove,
        .priv_auto      = sizeof(struct spi_nor),
        .ops            = &spi_flash_std_ops,
+#ifdef CONFIG_SPINOR_BLOCK_SUPPORT
+       .bind           = spacemit_spinor_bind,
+#endif /* CONFIG_SPINOR_BLOCK_SUPPORT */
        .flags          = DM_FLAG_OS_PREPARE,
 };
 
diff --git a/drivers/mtd/spi/spi-nor-blk.c b/drivers/mtd/spi/spi-nor-blk.c
new file mode 100644 (file)
index 0000000..d0a9e12
--- /dev/null
@@ -0,0 +1,81 @@
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <blk.h>
+#include <dm/device-internal.h>
+
+
+static unsigned long nor_blk_read(struct udevice *bdev, lbaint_t start, lbaint_t blkcnt, void *buffer)
+{
+
+       // Retrieve the original SPI NOR device from nor_blk device's private data
+       struct udevice *orig_dev = dev_get_priv(bdev);
+       if (!orig_dev) {
+               printf("%s:%d: Failed to get original device\n", __func__, __LINE__);
+               return -ENODEV;
+       }
+
+       struct spi_flash *flash = dev_get_uclass_priv(orig_dev);
+       struct mtd_info *mtd = &flash->mtd;
+       if (!mtd) {
+               printf("%s:%d: Failed to get MTD info\n", __func__, __LINE__);
+               return -ENODEV;
+       }
+
+       // Calculate the offset and length for the read operation
+       loff_t offset = (loff_t)start * SPI_NOR_BLOCK_SIZE;
+       size_t len = blkcnt * SPI_NOR_BLOCK_SIZE;
+
+       size_t retlen = 0;
+       int result = mtd->_read(mtd, offset, len, &retlen, buffer);
+       if (result) {
+               printf("%s:%d: MTD read error %d\n", __func__, __LINE__, result);
+               return result;
+       }
+
+       unsigned long blocks_read = retlen / SPI_NOR_BLOCK_SIZE;
+       return blocks_read;
+}
+
+static const struct blk_ops nor_blk_ops = {
+       .read = nor_blk_read,
+};
+
+int nor_blk_probe(struct udevice *dev)
+{
+       struct blk_desc *desc = dev_get_uclass_plat(dev);
+       if (!desc) {
+               printf("Failed to get block device descriptor\n");
+               return -ENODEV;
+       }
+
+       // The private data should already be the SPI NOR device ('nor_dev')
+       struct udevice *nor_dev = dev_get_priv(dev);
+       if (!nor_dev) {
+               printf("Failed to get the SPI NOR device from private data\n");
+               return -ENODEV;
+       }
+
+       // Retrieve the SPI flash structure from the SPI NOR device
+       struct spi_flash *flash = dev_get_uclass_priv(nor_dev);
+       if (!flash) {
+               printf("Failed to get SPI flash data\n");
+               return -ENODEV;
+       }
+
+       // Configure block device descriptor properties based on the flash data
+       desc->blksz = SPI_NOR_BLOCK_SIZE;
+       desc->lba = flash->mtd.size / desc->blksz;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(nor_blk) = {
+       .name  = "nor_blk",
+       .id    = UCLASS_BLK,
+       .probe = nor_blk_probe,
+       .ops   = &nor_blk_ops,
+       .priv_auto = sizeof(struct blk_desc),
+};
\ No newline at end of file
index 4fe8b0d92c4a74f263fea6e8ae04c1002fb0e75e..14a797468eb3b458c0c2c2cbc0ab6dce8d36c32a 100644 (file)
@@ -173,6 +173,7 @@ const struct flash_info spi_nor_ids[] = {
        { INFO("mx25l4005a",  0xc22013, 0, 64 * 1024,   8, SECT_4K) },
        { INFO("mx25l8005",   0xc22014, 0, 64 * 1024,  16, 0) },
        { INFO("mx25l1606e",  0xc22015, 0, 64 * 1024,  32, SECT_4K) },
+       { INFO("mx25l16xxx",  0xc22515, 0, 64 * 1024,  32, SECT_4K) },
        { INFO("mx25l3205d",  0xc22016, 0, 64 * 1024,  64, SECT_4K) },
        { INFO("mx25l6405d",  0xc22017, 0, 64 * 1024, 128, SECT_4K) },
        { INFO("mx25u2033e",  0xc22532, 0, 64 * 1024,   4, SECT_4K) },
@@ -331,6 +332,7 @@ const struct flash_info spi_nor_ids[] = {
        { INFO("m25pe16", 0x208015,  0, 64 * 1024, 32, SECT_4K) },
        { INFO("m25px16",    0x207115,  0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { INFO("m25px64",    0x207117,  0, 64 * 1024, 128, 0) },
+       { INFO("m45pe16",    0x204015,  0, 64 * 1024, 32,  0) },
 #endif
 #ifdef CONFIG_SPI_FLASH_WINBOND                /* WINBOND */
        /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
@@ -452,6 +454,9 @@ const struct flash_info spi_nor_ids[] = {
 #ifdef CONFIG_SPI_FLASH_XTX
        /* XTX Technology (Shenzhen) Limited */
        { INFO("xt25f128b", 0x0b4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+#endif
+#ifdef CONFIG_SPI_FLASH_FM
+       { INFO("FM25Q64AI3", 0xa14017, 0, 4 * 1024, 2048, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
 #endif
        { },
 };
index 6bbbadc5eef3260034e3899203ba736559a55736..4963d21405f335162d22c5307823c656a26c7ced 100644 (file)
@@ -225,6 +225,14 @@ config DWC_ETH_QOS_TEGRA186
          The Synopsys Designware Ethernet QOS IP block with specific
          configuration used in NVIDIA's Tegra186 chip.
 
+config DWC_ETH_QOS_SPACEMIT
+       bool "Synopsys DWC Ethernet QOS device support for Spacemit"
+       depends on DWC_ETH_QOS
+       default y if CONFIG_TARGET_SPACEMIT_K1PRO
+       help
+         The Synopsys Designware Ethernet QOS IP block with specific
+         configuration used in Spacemit's k1pro chip.
+
 config E1000
        bool "Intel PRO/1000 Gigabit Ethernet support"
        depends on PCI
@@ -649,6 +657,7 @@ config SH_ETHER
          This driver supports the Ethernet for Renesas SH and ARM SoCs.
 
 source "drivers/net/ti/Kconfig"
+source "drivers/net/spacemit/Kconfig"
 
 config TULIP
        bool "DEC Tulip DC2114x Ethernet support"
index 96b7678e9882c3f98f4f2817130c62b7101de828..ad8253de376008e97e01b3fd5919d50c561c332a 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
 obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
 obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
 obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
+obj-$(CONFIG_DWC_ETH_QOS_SPACEMIT) += dwc_eth_qos_spacemit.o
 obj-$(CONFIG_E1000) += e1000.o
 obj-$(CONFIG_E1000_SPI) += e1000_spi.o
 obj-$(CONFIG_EEPRO100) += eepro100.o
@@ -95,3 +96,4 @@ obj-y += mscc_eswitch/
 obj-y += phy/
 obj-y += qe/
 obj-y += ti/
+obj-y += spacemit/
index 0e63f70934c0c9eac0ece55ed18be285b0835e61..cb2858a967882545ba1bae607805d256bcf1986f 100644 (file)
@@ -233,14 +233,20 @@ static void tx_descs_init(struct dw_eth_dev *priv)
 {
        struct eth_dma_regs *dma_p = priv->dma_regs_p;
        struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
+       struct dmamachaddr *h_addr_p = &priv->tx_mac_haddr[0];
        char *txbuffs = &priv->txbuffs[0];
        struct dmamacdescr *desc_p;
+       struct dmamachaddr *addr_p;
        u32 idx;
 
        for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
                desc_p = &desc_table_p[idx];
-               desc_p->dmamac_addr = (ulong)&txbuffs[idx * CONFIG_ETH_BUFSIZE];
-               desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1];
+               desc_p->dmamac_addr = lower_32_bits((ulong)&txbuffs[idx * CONFIG_ETH_BUFSIZE]);
+               desc_p->dmamac_next = lower_32_bits((ulong)&desc_table_p[idx + 1]);
+
+               addr_p = &h_addr_p[idx];
+               addr_p->dmamac_haddr = upper_32_bits((ulong)&txbuffs[idx * CONFIG_ETH_BUFSIZE]);
+               addr_p->dmamac_hnext = upper_32_bits((ulong)&desc_table_p[idx + 1]);
 
 #if defined(CONFIG_DW_ALTDESCRIPTOR)
                desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
@@ -265,7 +271,7 @@ static void tx_descs_init(struct dw_eth_dev *priv)
                           (ulong)priv->tx_mac_descrtable +
                           sizeof(priv->tx_mac_descrtable));
 
-       writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
+       writel(lower_32_bits((ulong)&desc_table_p[0]), &dma_p->txdesclistaddr);
        priv->tx_currdescnum = 0;
 }
 
@@ -273,8 +279,10 @@ static void rx_descs_init(struct dw_eth_dev *priv)
 {
        struct eth_dma_regs *dma_p = priv->dma_regs_p;
        struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
+       struct dmamachaddr *h_addr_p = &priv->rx_mac_haddr[0];
        char *rxbuffs = &priv->rxbuffs[0];
        struct dmamacdescr *desc_p;
+       struct dmamachaddr *addr_p;
        u32 idx;
 
        /* Before passing buffers to GMAC we need to make sure zeros
@@ -287,8 +295,12 @@ static void rx_descs_init(struct dw_eth_dev *priv)
 
        for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
                desc_p = &desc_table_p[idx];
-               desc_p->dmamac_addr = (ulong)&rxbuffs[idx * CONFIG_ETH_BUFSIZE];
-               desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1];
+               desc_p->dmamac_addr = lower_32_bits((ulong)&rxbuffs[idx * CONFIG_ETH_BUFSIZE]);
+               desc_p->dmamac_next = lower_32_bits((ulong)&desc_table_p[idx + 1]);
+
+               addr_p = &h_addr_p[idx];
+               addr_p->dmamac_haddr = upper_32_bits((ulong)&rxbuffs[idx * CONFIG_ETH_BUFSIZE]);
+               addr_p->dmamac_hnext = upper_32_bits((ulong)&desc_table_p[idx + 1]);
 
                desc_p->dmamac_cntl =
                        (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) |
@@ -305,7 +317,7 @@ static void rx_descs_init(struct dw_eth_dev *priv)
                           (ulong)priv->rx_mac_descrtable +
                           sizeof(priv->rx_mac_descrtable));
 
-       writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
+       writel(lower_32_bits((ulong)&desc_table_p[0]), &dma_p->rxdesclistaddr);
        priv->rx_currdescnum = 0;
 }
 
@@ -455,7 +467,8 @@ static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
        ulong desc_start = (ulong)desc_p;
        ulong desc_end = desc_start +
                roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
-       ulong data_start = desc_p->dmamac_addr;
+       struct dmamachaddr *haddr_p = &priv->tx_mac_haddr[desc_num];
+       ulong data_start = ((u64)(haddr_p->dmamac_haddr) << 32) + (desc_p->dmamac_addr);
        ulong data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
        /*
         * Strictly we only need to invalidate the "txrx_status" field
@@ -522,7 +535,8 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
        ulong desc_start = (ulong)desc_p;
        ulong desc_end = desc_start +
                roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
-       ulong data_start = desc_p->dmamac_addr;
+       struct dmamachaddr *haddr_p = &priv->rx_mac_haddr[desc_num];
+       ulong data_start = ((u64)(haddr_p->dmamac_haddr) << 32) + (desc_p->dmamac_addr);
        ulong data_end;
 
        /* Invalidate entire buffer descriptor */
@@ -539,7 +553,7 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
                /* Invalidate received data */
                data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
                invalidate_dcache_range(data_start, data_end);
-               *packetp = (uchar *)(ulong)desc_p->dmamac_addr;
+               *packetp = (uchar *)(ulong)(((u64)(haddr_p->dmamac_haddr) << 32) + desc_p->dmamac_addr);
        }
 
        return length;
@@ -948,6 +962,7 @@ static const struct udevice_id designware_eth_ids[] = {
        { .compatible = "amlogic,meson6-dwmac" },
        { .compatible = "st,stm32-dwmac" },
        { .compatible = "snps,arc-dwmac-3.70a" },
+       { .compatible = "snps,dwmac" },
        { }
 };
 
index 3793d550980e673dc122b1e211a7cd70d5f32097..82394c99937e7418de12c118eff7cefcb3c1a333 100644 (file)
@@ -118,6 +118,11 @@ struct dmamacdescr {
        u32 dmamac_next;
 } __aligned(ARCH_DMA_MINALIGN);
 
+struct dmamachaddr {
+       u32 dmamac_haddr;
+       u32 dmamac_hnext;
+ } __aligned(ARCH_DMA_MINALIGN);
+
 /*
  * txrx_status definitions
  */
@@ -222,7 +227,9 @@ struct dmamacdescr {
 
 struct dw_eth_dev {
        struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];
+       struct dmamachaddr tx_mac_haddr[CONFIG_TX_DESCR_NUM];
        struct dmamacdescr rx_mac_descrtable[CONFIG_RX_DESCR_NUM];
+       struct dmamachaddr rx_mac_haddr[CONFIG_RX_DESCR_NUM];
        char txbuffs[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
        char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
 
index 001b028fa13bdcbd9edb7e6681e556245fffb243..b3dee5df25c047321f8aad509a20053a3aeb600c 100644 (file)
@@ -1010,8 +1010,10 @@ static int eqos_start(struct udevice *dev)
 
        for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) {
                struct eqos_desc *rx_desc = eqos_get_desc(eqos, i, true);
-               rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
-                                            (i * EQOS_MAX_PACKET_SIZE));
+               rx_desc->des0 = lower_32_bits((ulong)(eqos->rx_dma_buf +
+                                            (i * EQOS_MAX_PACKET_SIZE)));
+               rx_desc->des1 = upper_32_bits((ulong)(eqos->rx_dma_buf +
+                                            (i * EQOS_MAX_PACKET_SIZE)));
                rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
                mb();
                eqos->config->ops->eqos_flush_desc(rx_desc);
@@ -1020,13 +1022,15 @@ static int eqos_start(struct udevice *dev)
                                                EQOS_MAX_PACKET_SIZE);
        }
 
-       writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
+       val = upper_32_bits((ulong)eqos_get_desc(eqos, 0, false));
+       writel(val, &eqos->dma_regs->ch0_txdesc_list_haddress);
        writel((ulong)eqos_get_desc(eqos, 0, false),
                &eqos->dma_regs->ch0_txdesc_list_address);
        writel(EQOS_DESCRIPTORS_TX - 1,
               &eqos->dma_regs->ch0_txdesc_ring_length);
 
-       writel(0, &eqos->dma_regs->ch0_rxdesc_list_haddress);
+       val = upper_32_bits((ulong)eqos_get_desc(eqos, 0, true));
+       writel(val, &eqos->dma_regs->ch0_rxdesc_list_haddress);
        writel((ulong)eqos_get_desc(eqos, 0, true),
                &eqos->dma_regs->ch0_rxdesc_list_address);
        writel(EQOS_DESCRIPTORS_RX - 1,
@@ -1133,8 +1137,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length)
        eqos->tx_desc_idx++;
        eqos->tx_desc_idx %= EQOS_DESCRIPTORS_TX;
 
-       tx_desc->des0 = (ulong)eqos->tx_dma_buf;
-       tx_desc->des1 = 0;
+       tx_desc->des0 = lower_32_bits((ulong)eqos->tx_dma_buf);
+       tx_desc->des1 = upper_32_bits((ulong)eqos->tx_dma_buf);
        tx_desc->des2 = length;
        /*
         * Make sure that if HW sees the _OWN write below, it will see all the
@@ -1208,8 +1212,8 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
        mb();
        eqos->config->ops->eqos_flush_desc(rx_desc);
        eqos->config->ops->eqos_inval_buffer(packet, length);
-       rx_desc->des0 = (u32)(ulong)packet;
-       rx_desc->des1 = 0;
+       rx_desc->des0 = lower_32_bits((ulong)packet);
+       rx_desc->des1 = upper_32_bits((ulong)packet);
        rx_desc->des2 = 0;
        /*
         * Make sure that if HW sees the _OWN write below, it will see all the
@@ -1670,6 +1674,13 @@ static const struct udevice_id eqos_ids[] = {
        },
 #endif
 
+#if IS_ENABLED(CONFIG_DWC_ETH_QOS_SPACEMIT)
+       {
+               .compatible = "spacemit,k1pro-dwmac-eqos",
+               .data = (ulong)&eqos_spacemit_config
+       },
+#endif
+
        { }
 };
 
index b35e7742634e5b6f4ac3f6f08757549a14a578a5..25c57b798edfa30681c6481a0ed6ef9455902ed4 100644 (file)
@@ -282,3 +282,4 @@ void eqos_flush_buffer_generic(void *buf, size_t size);
 int eqos_null_ops(struct udevice *dev);
 
 extern struct eqos_config eqos_imx_config;
+extern struct eqos_config eqos_spacemit_config;
diff --git a/drivers/net/dwc_eth_qos_spacemit.c b/drivers/net/dwc_eth_qos_spacemit.c
new file mode 100644 (file)
index 0000000..c464ffa
--- /dev/null
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Spacemit
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <eth_phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <miiphy.h>
+#include <net.h>
+#include <netdev.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/cache.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#include "dwc_eth_qos.h"
+
+__weak u32 spacemit_get_eqos_csr_clk(void)
+{
+       return 50 * 1000000;
+}
+
+__weak int spacemit_eqos_txclk_set_rate(unsigned long rate)
+{
+       return 0;
+}
+
+static ulong eqos_get_tick_clk_rate_spacemit(struct udevice *dev)
+{
+       return spacemit_get_eqos_csr_clk();
+}
+
+static int eqos_probe_resources_spacemit(struct udevice *dev)
+{
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       phy_interface_t interface;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+
+       interface = eqos->config->interface(dev);
+
+       if (interface == PHY_INTERFACE_MODE_NA) {
+               pr_err("Invalid PHY interface\n");
+               return -EINVAL;
+       }
+
+       debug("%s: OK\n", __func__);
+       return 0;
+}
+
+static int eqos_stop_resets_spacemit(struct udevice *dev)
+{
+       struct reset_ctl_bulk reset_bulk;
+       int ret;
+
+       ret = reset_get_bulk(dev, &reset_bulk);
+       if (ret)
+               printf("%s, Can't get reset: %d\n", __func__, ret);
+       else
+               reset_assert_bulk(&reset_bulk);
+       return 0;
+}
+
+static int eqos_start_resets_spacemit(struct udevice *dev)
+{
+       struct reset_ctl_bulk reset_bulk;
+       int ret;
+
+       ret = reset_get_bulk(dev, &reset_bulk);
+       if (ret)
+               printf("%s, Can't get reset: %d\n", __func__, ret);
+       else
+               reset_deassert_bulk(&reset_bulk);
+
+       return 0;
+}
+
+static int eqos_set_tx_clk_speed_spacemit(struct udevice *dev)
+{
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       ulong rate;
+       int ret;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+
+       switch (eqos->phy->speed) {
+       case SPEED_1000:
+               rate = 125 * 1000 * 1000;
+               break;
+       case SPEED_100:
+               rate = 25 * 1000 * 1000;
+               break;
+       case SPEED_10:
+               rate = 2.5 * 1000 * 1000;
+               break;
+       default:
+               pr_err("invalid speed %d", eqos->phy->speed);
+               return -EINVAL;
+       }
+
+       ret = spacemit_eqos_txclk_set_rate(rate);
+       if (ret < 0) {
+               pr_err("spacemit (tx_clk, %lu) failed: %d", rate, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int eqos_get_enetaddr_spacemit(struct udevice *dev)
+{
+       return 0;
+}
+
+static struct eqos_ops eqos_spacemit_ops = {
+       .eqos_inval_desc = eqos_inval_desc_generic,
+       .eqos_flush_desc = eqos_flush_desc_generic,
+       .eqos_inval_buffer = eqos_inval_buffer_generic,
+       .eqos_flush_buffer = eqos_flush_buffer_generic,
+       .eqos_probe_resources = eqos_probe_resources_spacemit,
+       .eqos_remove_resources = eqos_null_ops,
+       .eqos_stop_resets = eqos_stop_resets_spacemit,
+       .eqos_start_resets = eqos_start_resets_spacemit,
+       .eqos_stop_clks = eqos_null_ops,
+       .eqos_start_clks = eqos_null_ops,
+       .eqos_calibrate_pads = eqos_null_ops,
+       .eqos_disable_calibration = eqos_null_ops,
+       .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_spacemit,
+       .eqos_get_enetaddr = eqos_get_enetaddr_spacemit,
+       .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_spacemit,
+};
+
+struct eqos_config __maybe_unused eqos_spacemit_config = {
+       .reg_access_always_ok = false,
+       .mdio_wait = 10,
+       .swr_wait = 50,
+       .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+       .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
+       .axi_bus_width = EQOS_AXI_WIDTH_64,
+       .interface = dev_read_phy_mode,
+       .ops = &eqos_spacemit_ops
+};
diff --git a/drivers/net/spacemit/Kconfig b/drivers/net/spacemit/Kconfig
new file mode 100644 (file)
index 0000000..ebe069e
--- /dev/null
@@ -0,0 +1,8 @@
+config SPACEMIT_K1X_EMAC
+       bool "Sapcemit k1-x Emac Driver"
+       depends on DM_ETH
+       select PHYLIB
+       select DM_RESET
+       help
+         This Driver support Spacemit k1-x Ethernet MAC
+         Say Y to enable support for the Spacemit Ethernet.
diff --git a/drivers/net/spacemit/Makefile b/drivers/net/spacemit/Makefile
new file mode 100644 (file)
index 0000000..5eac9b5
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2023 Spacemit
+
+obj-$(CONFIG_SPACEMIT_K1X_EMAC) += k1x_emac.o
diff --git a/drivers/net/spacemit/k1x_emac.c b/drivers/net/spacemit/k1x_emac.c
new file mode 100644 (file)
index 0000000..0a76a12
--- /dev/null
@@ -0,0 +1,1245 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * spacemit emac driver
+ *
+ * Copyright (C) 2023 Spacemit
+ *
+ */
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include <cpu_func.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <memalign.h>
+#include <miiphy.h>
+#include <net.h>
+#include <netdev.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include "k1x_emac.h"
+
+#define TX_PHASE                1
+#define RX_PHASE                0
+
+#define CLK_PHASE_REVERT        180
+
+
+/* Clock */
+#define K1X_APMU_BASE           0xd4282800
+
+#define EMAC_AXI_CLK_ENABLE     BIT(0)
+#define EMAC_AXI_CLK_RESET      BIT(1)
+/* emac phy interface selection 0:RMII 1:RGMII */
+#define EMAC_PHY_SEL_RGMII      BIT(2)
+
+/*
+ * only valid for rmii mode
+ * 0: ref clock from external phy
+ * 1: ref clock from soc
+ */
+#define REF_CLK_SEL             BIT(3)
+
+/*
+ * emac function clock select
+ * 0: 208M
+ * 1: 312M
+ */
+#define FUNC_CLK_SEL            BIT(4)
+
+/* only valid for rmii, invert tx clk */
+#define RMII_TX_CLK_SEL         BIT(6)
+
+/* only valid for rmii, invert rx clk */
+#define RMII_RX_CLK_SEL         BIT(7)
+
+/*
+ * only valid for rgmiii
+ * 0: tx clk from rx clk
+ * 1: tx clk from soc
+ */
+#define RGMII_TX_CLK_SEL        BIT(8)
+
+#define PHY_IRQ_EN              BIT(12)
+#define AXI_SINGLE_ID           BIT(13)
+
+#define RMII_TX_PHASE_OFFSET            (16)
+#define RMII_TX_PHASE_MASK              GENMASK(18, 16)
+#define RMII_RX_PHASE_OFFSET            (20)
+#define RMII_RX_PHASE_MASK              GENMASK(22, 20)
+
+#define RGMII_TX_PHASE_OFFSET           (24)
+#define RGMII_TX_PHASE_MASK             GENMASK(26, 24)
+#define RGMII_RX_PHASE_OFFSET           (28)
+#define RGMII_RX_PHASE_MASK             GENMASK(30, 28)
+
+#define EMAC_RX_DLINE_EN                BIT(0)
+#define EMAC_RX_DLINE_STEP_OFFSET       (4)
+#define EMAC_RX_DLINE_STEP_MASK         GENMASK(5, 4)
+#define EMAC_RX_DLINE_CODE_OFFSET       (8)
+#define EMAC_RX_DLINE_CODE_MASK         GENMASK(15, 8)
+
+#define EMAC_TX_DLINE_EN                BIT(16)
+#define EMAC_TX_DLINE_STEP_OFFSET       (20)
+#define EMAC_TX_DLINE_STEP_MASK         GENMASK(21, 20)
+#define EMAC_TX_DLINE_CODE_OFFSET       (24)
+#define EMAC_TX_DLINE_CODE_MASK         GENMASK(31, 24)
+
+/* Descriptors */
+
+#define EQOS_DESCRIPTOR_WORDS           4
+#define EQOS_DESCRIPTOR_SIZE            (EQOS_DESCRIPTOR_WORDS * 4)
+/* We assume ARCH_DMA_MINALIGN >= 16; 16 is the EQOS HW minimum */
+#define EQOS_DESCRIPTOR_ALIGN           ARCH_DMA_MINALIGN
+#define EQOS_DESCRIPTORS_TX             4
+#define EQOS_DESCRIPTORS_RX             32
+#define EQOS_DESCRIPTORS_NUM            (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX)
+#define EQOS_DESCRIPTORS_SIZE           ALIGN(EQOS_DESCRIPTORS_NUM * \
+                                            EQOS_DESCRIPTOR_SIZE, ARCH_DMA_MINALIGN)
+#define EQOS_BUFFER_ALIGN               ARCH_DMA_MINALIGN
+#define EQOS_MAX_PACKET_SIZE            ALIGN(1568, ARCH_DMA_MINALIGN)
+#define EQOS_RX_BUFFER_SIZE             (EQOS_DESCRIPTORS_RX * EQOS_MAX_PACKET_SIZE)
+#define CACHE_FLUSH_CNT                 (ARCH_DMA_MINALIGN / EQOS_DESCRIPTOR_SIZE)
+
+/*
+ * Warn if the cache-line size is larger than the descriptor size. In such
+ * cases the driver will likely fail because the CPU needs to flush the cache
+ * when requeuing RX buffers, therefore descriptors written by the hardware
+ * may be discarded. Architectures with full IO coherence, such as x86, do not
+ * experience this issue, and hence are excluded from this condition.
+ *
+ * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause
+ * the driver to allocate descriptors from a pool of non-cached memory.
+ *
+ * #if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN
+ * #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \
+ *    !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86)
+ * #warning Cache line size is larger than descriptor size
+ * #endif
+ * #endif
+ */
+
+struct emac_desc {
+    u32 des0;
+    u32 des1;
+    u32 des2;
+    u32 des3;
+};
+
+#define EMAC_DESC_OWN           BIT(31)
+#define EMAC_DESC_FD            BIT(30)
+#define EMAC_DESC_LD            BIT(29)
+#define EMAC_DESC_EOR           BIT(26)
+#define EMAC_DESC_BUFF_SIZE1    GENMASK(11, 0)
+
+enum clk_tuning_way {
+    /* fpga rgmii/rmii clk tuning register */
+    CLK_TUNING_BY_REG,
+    /* rgmii evb delayline register */
+    CLK_TUNING_BY_DLINE,
+    /* rmii evb only revert tx/rx clock for clk tuning */
+    CLK_TUNING_BY_CLK_REVERT,
+    CLK_TUNING_MAX,
+};
+
+struct emac_priv {
+    struct udevice *dev;
+    void __iomem *io_base;
+    struct clk mac_clk;
+    struct reset_ctl reset;
+    struct mii_dev *mii;
+    struct phy_device *phy;
+    int phy_interface;
+    int duplex;
+    int speed;
+    void *descs;
+    struct emac_desc *tx_descs;
+    struct emac_desc *rx_descs;
+    int tx_desc_idx, rx_desc_idx;
+    void *tx_dma_buf;
+    void *rx_dma_buf;
+    bool started;
+    int phy_reset_gpio;
+    int ldo_gpio;
+    int phy_addr;
+    int tx_phase;
+    int rx_phase;
+    int clk_tuning_enable;
+    int ref_clk_frm_soc;
+    void __iomem *ctrl_reg;
+    void __iomem *dline_reg;
+    int clk_tuning_way;
+};
+
+void print_pkt(unsigned char *buf, int len)
+{
+    int i = 0;
+
+    printf("data len = %d byte, buf addr: %p\n", len, buf);
+    for (i = 0; i < len; i = i + 8) {
+        printf("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+            *(buf + i),
+            *(buf + i + 1),
+            *(buf + i + 2),
+            *(buf + i + 3),
+            *(buf + i + 4),
+            *(buf + i + 5),
+            *(buf + i + 6),
+            *(buf + i + 7));
+    }
+}
+
+void print_desc(unsigned char *buf, int len)
+{
+    int i;
+
+    printf("descriptor len = %d byte, buf addr: %p\n",
+           len, buf);
+    for (i = 0; i < len; i = i + 4) {
+        printf("0x%02x 0x%02x 0x%02x 0x%02x\n",
+            *(buf + i + 3),
+            *(buf + i + 2),
+            *(buf + i + 1),
+            *(buf + i));
+    }
+}
+
+static inline void emac_wr(struct emac_priv *priv, u32 reg, u32 val)
+{
+    writel(val, (priv->io_base + reg));
+}
+
+static inline int emac_rd(struct emac_priv *priv, u32 reg)
+{
+    return readl(priv->io_base + reg);
+}
+
+int emac_reset_hw(struct emac_priv *priv)
+{
+    /* disable all the interrupts */
+    emac_wr(priv, MAC_INTERRUPT_ENABLE, 0x0000);
+    emac_wr(priv, DMA_INTERRUPT_ENABLE, 0x0000);
+
+    /* disable transmit and receive units */
+    emac_wr(priv, MAC_RECEIVE_CONTROL, 0x0000);
+    emac_wr(priv, MAC_TRANSMIT_CONTROL, 0x0000);
+
+    /* stop the DMA */
+    emac_wr(priv, DMA_CONTROL, 0x0000);
+
+    /* reset mac, statistic counters */
+    emac_wr(priv, MAC_GLOBAL_CONTROL, 0x0018);
+
+    emac_wr(priv, MAC_GLOBAL_CONTROL, 0x0000);
+    return 0;
+}
+
+int emac_init_hw(struct emac_priv *priv)
+{
+    u32 val = 0;
+
+    /* MAC Init
+     * disable transmit and receive units
+     */
+    emac_wr(priv, MAC_RECEIVE_CONTROL, 0x0000);
+    emac_wr(priv, MAC_TRANSMIT_CONTROL, 0x0000);
+
+    /* enable mac address 1 filtering */
+    emac_wr(priv, MAC_ADDRESS_CONTROL, 0x0001);
+
+    /* zero initialize the multicast hash table */
+    emac_wr(priv, MAC_MULTICAST_HASH_TABLE1, 0x0000);
+    emac_wr(priv, MAC_MULTICAST_HASH_TABLE2, 0x0000);
+    emac_wr(priv, MAC_MULTICAST_HASH_TABLE3, 0x0000);
+    emac_wr(priv, MAC_MULTICAST_HASH_TABLE4, 0x0000);
+
+    emac_wr(priv, MAC_TRANSMIT_FIFO_ALMOST_FULL, 0x1f8);
+
+    emac_wr(priv, MAC_TRANSMIT_PACKET_START_THRESHOLD,
+        TX_STORE_FORWARD_MODE);
+
+    emac_wr(priv, MAC_RECEIVE_PACKET_START_THRESHOLD, 0xc);
+
+    /* reset dma */
+    emac_wr(priv, DMA_CONTROL, 0x0000);
+
+    emac_wr(priv, DMA_CONFIGURATION, 0x01);
+    mdelay(10);
+    emac_wr(priv, DMA_CONFIGURATION, 0x00);
+    mdelay(10);
+
+    val |= MREGBIT_WAIT_FOR_DONE;
+    val |= MREGBIT_STRICT_BURST;
+    val |= MREGBIT_DMA_64BIT_MODE;
+
+    val |= MREGBIT_BURST_16WORD;
+
+    emac_wr(priv, DMA_CONFIGURATION, val);
+
+    return 0;
+}
+
+static void emac_configure_tx(struct emac_priv *priv)
+{
+    u32 val;
+
+    /* set the transmit base address */
+    val = (ulong)(priv->tx_descs);
+
+    emac_wr(priv, DMA_TRANSMIT_BASE_ADDRESS, val);
+
+    debug("%s tx descriptor:0x%x\n", __func__,
+           emac_rd(priv,DMA_TRANSMIT_BASE_ADDRESS));
+    /* Tx Inter Packet Gap value and enable the transmit */
+    val = emac_rd(priv, MAC_TRANSMIT_CONTROL);
+    val &= (~MREGBIT_IFG_LEN);
+    val |= MREGBIT_TRANSMIT_ENABLE;
+    val |= MREGBIT_TRANSMIT_AUTO_RETRY;
+    emac_wr(priv, MAC_TRANSMIT_CONTROL, val);
+
+    emac_wr(priv, DMA_TRANSMIT_AUTO_POLL_COUNTER, 0x00);
+
+    /* start tx dma */
+    val = emac_rd(priv, DMA_CONTROL);
+    val |= MREGBIT_START_STOP_TRANSMIT_DMA;
+    emac_wr(priv, DMA_CONTROL, val);
+}
+
+static void emac_configure_rx(struct emac_priv *priv)
+{
+    u32 val;
+
+    /* set the receive base address */
+    val = (ulong)(priv->rx_descs);
+    emac_wr(priv, DMA_RECEIVE_BASE_ADDRESS, val);
+
+    debug("%s rx descriptor:0x%x\n", __func__,
+            emac_rd(priv,DMA_RECEIVE_BASE_ADDRESS));
+    /* enable the receive */
+    val = emac_rd(priv, MAC_RECEIVE_CONTROL);
+    val |= MREGBIT_RECEIVE_ENABLE;
+    val |= MREGBIT_STORE_FORWARD;
+    emac_wr(priv, MAC_RECEIVE_CONTROL, val);
+
+    /* start rx dma */
+    val = emac_rd(priv, DMA_CONTROL);
+    val |= MREGBIT_START_STOP_RECEIVE_DMA;
+    emac_wr(priv, DMA_CONTROL, val);
+}
+
+/* tx and rX descriptors are 16 bytes. This causes problems with the cache
+ * maintenance on CPUs where the cache-line size exceeds the size of these
+ * descriptors. What will happen is that when the driver receives a packet
+ * it will be immediately requeued for the hardware to reuse. The CPU will
+ * therefore need to flush the cache-line containing the descriptor, which
+ * will cause all other descriptors in the same cache-line to be flushed
+ * along with it. If one of those descriptors had been written to by the
+ * device those changes (and the associated packet) will be lost.
+ *
+ * to work around this, we make use of non-cached memory if available. If
+ * descriptors are mapped uncached there's no need to manually flush them
+ * or invalidate them.
+ *
+ * note that this only applies to descriptors. The packet data buffers do
+ * not have the same constraints since they are 1536 bytes large, so they
+ * are unlikely to share cache-lines.
+ */
+static void *emac_alloc_descs(unsigned int num)
+{
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+    return (void *)noncached_alloc(EQOS_DESCRIPTORS_SIZE,
+                      EQOS_DESCRIPTOR_ALIGN);
+#else
+    return memalign(EQOS_DESCRIPTOR_ALIGN, EQOS_DESCRIPTORS_SIZE);
+#endif
+}
+
+static void emac_free_descs(void *descs)
+{
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+    /* FIXME: noncached_alloc() has no opposite */
+#else
+    free(descs);
+#endif
+}
+
+static void emac_inval_desc(void *desc)
+{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
+    unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
+    unsigned long end = ALIGN(start + EQOS_DESCRIPTOR_SIZE,
+                  ARCH_DMA_MINALIGN);
+
+    invalidate_dcache_range(start, end);
+#endif
+}
+
+static void emac_flush_desc(void *desc)
+{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
+    unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
+    unsigned long end = ALIGN(start + EQOS_DESCRIPTOR_SIZE,
+                  ARCH_DMA_MINALIGN);
+    flush_dcache_range(start, end);
+#endif
+}
+
+static void emac_inval_buffer(void *buf, size_t size)
+{
+    unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1);
+    unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN);
+
+    invalidate_dcache_range(start, end);
+}
+
+static void emac_flush_buffer(void *buf, size_t size)
+{
+    unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1);
+    unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN);
+
+    flush_dcache_range(start, end);
+}
+
+bool emac_is_rmii(struct emac_priv *priv)
+{
+    return priv->phy_interface == PHY_INTERFACE_MODE_RMII;
+}
+
+static int emac_mdio_read(struct mii_dev *bus, int mdio_addr, 
+                int mdio_devad, int mdio_reg)
+{
+    struct emac_priv *priv = bus->priv;
+    u32 cmd = 0;
+    u32 val;
+
+    cmd |= mdio_addr & 0x1F;
+    cmd |= (mdio_reg & 0x1F) << 5;
+    cmd |= MREGBIT_START_MDIO_TRANS | MREGBIT_MDIO_READ_WRITE;
+
+    emac_wr(priv, MAC_MDIO_DATA, 0x0);
+    emac_wr(priv, MAC_MDIO_CONTROL, cmd);
+
+    val = emac_rd(priv, MAC_MDIO_CONTROL);
+    val = val >> 15 & 0x01;
+
+    while (val != 0) {
+        val = emac_rd(priv, MAC_MDIO_CONTROL);
+        val = val >> 15 & 0x01;
+        mdelay(5);
+    }
+
+    val = emac_rd(priv, MAC_MDIO_DATA);
+
+    return val;
+}
+
+static int emac_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad,
+                int mdio_reg, u16 mdio_val)
+{
+    struct emac_priv *priv = bus->priv;
+    u32 val;
+    u32 cmd = 0;
+
+    emac_wr(priv, MAC_MDIO_DATA, mdio_val);
+
+    cmd |= mdio_addr & 0x1F;
+    cmd |= (mdio_reg & 0x1F) << 5;
+    cmd |= MREGBIT_START_MDIO_TRANS;
+
+    emac_wr(priv, MAC_MDIO_CONTROL, cmd);
+
+    val = emac_rd(priv, MAC_MDIO_CONTROL);
+    val = val >> 15 & 0x01;
+
+    while (val != 0) {
+        val = emac_rd(priv, MAC_MDIO_CONTROL);
+        val = val >> 15 & 0x01;
+    }
+    return 0;
+}
+
+static int emac_adjust_link(struct udevice *dev)
+{
+    u32 ctrl;
+    struct emac_priv *priv = dev_get_priv(dev);
+
+    debug("%s(dev=%p):\n", __func__, dev);
+
+    ctrl = emac_rd(priv, MAC_GLOBAL_CONTROL);
+
+    if (priv->phy->duplex != priv->duplex) {
+        if (!priv->phy->duplex)
+            ctrl &= ~MREGBIT_FULL_DUPLEX_MODE;
+        else
+            ctrl |= MREGBIT_FULL_DUPLEX_MODE;
+
+        priv->duplex = priv->phy->duplex;
+    }
+
+    if (priv->phy->speed != priv->speed) {
+        ctrl &= ~MREGBIT_SPEED;
+        switch (priv->phy->speed) {
+        case SPEED_1000:
+            ctrl |= MREGBIT_SPEED_1000M;
+            break;
+        case SPEED_100:
+            ctrl |= MREGBIT_SPEED_100M;
+            break;
+        case SPEED_10:
+            ctrl |= MREGBIT_SPEED_10M;
+            break;
+        }
+        priv->speed = priv->phy->speed;
+    }
+    emac_wr(priv, MAC_GLOBAL_CONTROL, ctrl);
+    printf("%s link:%d speed:%d duplex:%s\n",
+           __func__, priv->phy->link,
+           priv->phy->speed,
+           priv->phy->duplex ? "full" : "half");
+
+    return 0;
+}
+
+static int emac_write_hwaddr(struct udevice *dev)
+{
+    struct eth_pdata *plat = dev_get_plat(dev);
+    struct emac_priv *priv = dev_get_priv(dev);
+
+    /* This function may be called before start() or after stop(). At that
+     * time, on at least some configurations of the EQoS HW, all clocks to
+     * the EQoS HW block will be stopped, and a reset signal applied. If
+     * any register access is attempted in this state, bus timeouts or CPU
+     * hangs may occur. This check prevents that.
+     *
+     * A simple solution to this problem would be to not implement
+     * write_hwaddr(), since start() always writes the MAC address into HW
+     * anyway. However, it is desirable to implement write_hwaddr() to
+     * support the case of SW that runs subsequent to U-Boot which expects
+     * the MAC address to already be programmed into the EQoS registers,
+     * which must happen irrespective of whether the U-Boot user (or
+     * scripts) actually made use of the EQoS device, and hence
+     * irrespective of whether start() was ever called.
+     *
+     * Note that this requirement by subsequent SW is not valid for
+     * Tegra186, and is likely not valid for any non-PCI instantiation of
+     * the EQoS HW block. This function is implemented solely as
+     * future-proofing with the expectation the driver will eventually be
+     * ported to some system where the expectation above is true.
+     */
+    /* Update the MAC address */
+    emac_wr(priv, MAC_ADDRESS1_HIGH,
+        (plat->enetaddr[1] << 8 | plat->enetaddr[0]));
+    emac_wr(priv, MAC_ADDRESS1_MED,
+        (plat->enetaddr[3] << 8 | plat->enetaddr[2]));
+    emac_wr(priv, MAC_ADDRESS1_LOW,
+        (plat->enetaddr[5] << 8 | plat->enetaddr[4]));
+
+    return 0;
+}
+
+static int emac_phy_reset(struct emac_priv *priv)
+{
+
+#ifdef CONFIG_GPIO  /* gpio driver is not ready for fpga platform */
+    int ret;
+
+    ret = gpio_direction_output(priv->phy_reset_gpio, 1);
+    if (ret < 0) {
+        pr_err("gpio_direction_output(phy_reset, assert) failed: %d", ret);
+        return ret;
+    }
+
+    udelay(2);
+
+    ret = gpio_direction_output(priv->phy_reset_gpio, 0);
+    if (ret < 0) {
+        pr_err("gpio_direction_output(phy_reset, deassert) failed: %d", ret);
+        return ret;
+    }
+
+    mdelay(10);
+
+    ret = gpio_direction_output(priv->phy_reset_gpio, 1);
+    if (ret < 0) {
+        pr_err("gpio_direction_output(phy_reset, assert) failed: %d", ret);
+        return ret;
+    }
+    mdelay(15);
+#else
+    void __iomem *reg;
+    u32 reg_gbase = 0, reg_goff = 0, bit_no = 0;
+
+    if (priv->phy_reset_gpio < 96) {
+        reg_goff = (priv->phy_reset_gpio >> 5) * (0x4);
+    } else {
+        reg_goff = 0x100;
+    }
+    reg_gbase = 0xD4019000 + reg_goff;
+    bit_no = (priv->phy_reset_gpio) & 0x1f;
+
+    reg =  (void *)(ulong)(reg_gbase + 0xc);
+    u32 val = readl(reg);
+    val |= 1 << bit_no;
+    writel(val, reg);
+
+    udelay(2);
+
+    reg =  (void *)(ulong)(reg_gbase + 0x18);
+    val = readl(reg);
+    val |= 1 << bit_no;
+    writel(val, reg);
+
+    mdelay(10);
+    reg =  (void *)(ulong)(reg_gbase + 0x24);
+    val = readl(reg);
+    val |= 1 << bit_no;
+    writel(val, reg);
+
+    mdelay(15);
+    reg =  (void *)(ulong)(reg_gbase + 0x18);
+    val = readl(reg);
+    val |= 1 << bit_no;
+    writel(val, reg);
+
+#endif
+    return 0;
+}
+
+static int emac_start(struct udevice *dev)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+    int ret, i;
+
+    debug("%s(dev=%p):\n", __func__, dev);
+
+    priv->tx_desc_idx = 0;
+    priv->rx_desc_idx = 0;
+
+    emac_phy_reset(priv);
+
+    priv->phy = phy_connect(priv->mii, priv->phy_addr, dev,
+                    priv->phy_interface);
+    if (!priv->phy) {
+        ret = -1;
+        pr_err("phy_connect() failed");
+        goto err_connect_phy;
+    }
+
+    if (emac_is_rmii(priv))
+        priv->phy->supported &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full);
+
+    ret = phy_config(priv->phy);
+    if (ret < 0) {
+        pr_err("phy_config() failed: %d", ret);
+        goto err_shutdown_phy;
+    }
+
+    ret = phy_startup(priv->phy);
+    if (ret < 0) {
+        pr_err("phy_startup() failed: %d", ret);
+        goto err_shutdown_phy;
+    }
+
+    if (!priv->phy->link) {
+        pr_err("No link");
+        goto err_shutdown_phy;
+    }
+
+    ret = emac_adjust_link(dev);
+    if (ret < 0) {
+        pr_err("emac_adjust_link() failed: %d", ret);
+        goto err_shutdown_phy;
+    }
+
+    /* Set up descriptors */
+    memset(priv->descs, 0, EQOS_DESCRIPTORS_SIZE);
+    for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) {
+        struct emac_desc *rx_desc = &priv->rx_descs[i];
+        rx_desc->des2 = (u32)(ulong)(priv->rx_dma_buf +
+                    (i * EQOS_MAX_PACKET_SIZE));
+        rx_desc->des1 = EQOS_MAX_PACKET_SIZE & 0xFFF;
+
+        if (i == (EQOS_DESCRIPTORS_RX - 1))
+            rx_desc->des1 |= EMAC_DESC_EOR;
+
+        rx_desc->des0 |= EMAC_DESC_OWN;
+        if (!((i+1) % CACHE_FLUSH_CNT))
+            emac_flush_desc(rx_desc);
+    }
+
+    emac_inval_buffer(priv->rx_dma_buf, EQOS_RX_BUFFER_SIZE);
+
+    emac_init_hw(priv);
+
+    emac_write_hwaddr(dev);
+
+    emac_configure_tx(priv);
+
+    emac_configure_rx(priv);
+
+    priv->started = true;
+    return 0;
+
+err_shutdown_phy:
+    phy_shutdown(priv->phy);
+    priv->phy = NULL;
+err_connect_phy:
+    pr_err("FAILED: %d", ret);
+    return ret;
+}
+
+void emac_stop(struct udevice *dev)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+
+    debug("%s(dev=%p):\n", __func__, dev);
+
+    if (!priv->started)
+        return;
+    priv->started = false;
+
+    emac_reset_hw(priv);
+    if (priv->phy)
+        phy_shutdown(priv->phy);
+
+    priv->speed = -1;
+    priv->duplex = -1;
+}
+
+int emac_send(struct udevice *dev, void *packet, int length)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+    struct emac_desc *tx_desc;
+    int i;
+
+    debug("%s(dev=%p, packet=%p, length=%d):\n", __func__, dev, packet,
+          length);
+
+    memcpy(priv->tx_dma_buf, packet, length);
+    emac_flush_buffer(priv->tx_dma_buf, length);
+
+    tx_desc = &priv->tx_descs[priv->tx_desc_idx];
+    priv->tx_desc_idx++;
+    priv->tx_desc_idx %= EQOS_DESCRIPTORS_TX;
+
+    memset(tx_desc, 0x0, sizeof(struct emac_desc));
+
+    tx_desc->des2 = (ulong)priv->tx_dma_buf;
+    tx_desc->des1 = EMAC_DESC_BUFF_SIZE1 & length;
+    tx_desc->des1 |= EMAC_DESC_FD | EMAC_DESC_LD;
+
+    if (priv->tx_desc_idx == 0)
+        tx_desc->des1 |= EMAC_DESC_EOR;
+
+    /* Make sure that if HW sees the _OWN emac_wr below, it will see all the
+     * writes to the rest of the descriptor too.
+     */
+    mb();
+    tx_desc->des0 = EMAC_DESC_OWN;
+    emac_flush_desc(tx_desc);
+
+    emac_wr(priv, DMA_TRANSMIT_POLL_DEMAND, 0xFF);
+
+    for (i = 0; i < 1000; i++) {
+        emac_inval_desc(tx_desc);
+        if (!(readl(&tx_desc->des0) & EMAC_DESC_OWN))
+            return 0;
+        mdelay(1);
+    }
+
+    printf("%s: TX timeout\n", __func__);
+
+    return -ETIMEDOUT;
+}
+
+int emac_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+    struct emac_desc *rx_desc;
+    int length;
+
+    rx_desc = &priv->rx_descs[priv->rx_desc_idx];
+
+    emac_inval_desc(rx_desc);
+
+    if (rx_desc->des0 & EMAC_DESC_OWN) {
+        debug("%s: RX packet not available\n", __func__);
+        return -EAGAIN;
+    }
+
+    *packetp = priv->rx_dma_buf +
+        (priv->rx_desc_idx * EQOS_MAX_PACKET_SIZE);
+    /* use frame length */
+    if (rx_desc->des0 & EMAC_DESC_LD)
+        length = (rx_desc->des0 & 0x3fff) - ETHERNET_FCS_SIZE;
+    else
+        length = EQOS_MAX_PACKET_SIZE;
+
+    emac_inval_buffer(*packetp, length);
+    return length;
+}
+
+int emac_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+    uchar *packet_expected;
+    struct emac_desc *rx_desc;
+    int desc_idx;
+
+    debug("%s(packet=%p, length=%d)\n", __func__, packet, length);
+
+    packet_expected = priv->rx_dma_buf +
+        (priv->rx_desc_idx * EQOS_MAX_PACKET_SIZE);
+    if (packet != packet_expected) {
+        printf("%s: Unexpected packet (expected %p)\n", __func__,
+               packet_expected);
+        return -EINVAL;
+    }
+
+    emac_inval_buffer((void *)packet, length);
+
+    if (!((priv->rx_desc_idx + 1) % CACHE_FLUSH_CNT)) {
+        for (desc_idx = (priv->rx_desc_idx + 1 - CACHE_FLUSH_CNT); desc_idx <= priv->rx_desc_idx; desc_idx++) {
+            rx_desc = &priv->rx_descs[desc_idx];
+            memset(rx_desc, 0x0, sizeof(struct emac_desc));
+
+            rx_desc->des1 = EQOS_MAX_PACKET_SIZE & 0xFFF;
+            if (desc_idx == (EQOS_DESCRIPTORS_RX - 1))
+                rx_desc->des1 |= EMAC_DESC_EOR;
+
+            rx_desc->des2 = (u32)(ulong)(priv->rx_dma_buf +
+                    (desc_idx * EQOS_MAX_PACKET_SIZE));
+
+            /* Make sure that if HW sees the _OWN write below, it will see all the
+             * writes to the rest of the descriptor too.
+             */
+            mb();
+            rx_desc->des0 |= EMAC_DESC_OWN;
+        }
+
+        emac_flush_desc(rx_desc);
+        emac_wr(priv, DMA_RECEIVE_POLL_DEMAND, 0xFF);
+    }
+    priv->rx_desc_idx++;
+
+    priv->rx_desc_idx %= EQOS_DESCRIPTORS_RX;
+    return 0;
+}
+
+void emac_enable_axi_single_id_mode(struct emac_priv *priv, int en)
+{
+    u32 val;
+
+    val = readl(priv->ctrl_reg);
+    if (en)
+        val |= AXI_SINGLE_ID;
+    else
+        val &= ~AXI_SINGLE_ID;
+    writel(val, priv->ctrl_reg);
+}
+
+int emac_phy_interface_select(struct emac_priv *priv)
+{
+    u32 val;
+
+    val = readl(priv->ctrl_reg);
+    if (emac_is_rmii(priv)) {
+        printf("RMII interface\n");
+        val &= ~EMAC_PHY_SEL_RGMII;
+        if (priv->ref_clk_frm_soc)
+            val |= REF_CLK_SEL;
+        else
+            val &= ~REF_CLK_SEL;
+    } else {
+        printf("RGMII interface\n");
+        val |= EMAC_PHY_SEL_RGMII;
+        if (priv->ref_clk_frm_soc)
+            val |= RGMII_TX_CLK_SEL;
+        else
+            val &= ~RGMII_TX_CLK_SEL;
+    }
+    writel(val, priv->ctrl_reg);
+    return 0;
+}
+
+int emac_enable_clk(struct emac_priv *priv)
+{
+    /* enable mac clock */
+    clk_enable(&priv->mac_clk);
+    reset_deassert(&priv->reset);
+
+#if 0   /* CLK driver is not ready on fpga platform */
+    /* enable phy clock */
+    clk_enable_pll(PLL1, DIV_8);
+    clk_enable_gate(CLK_104);
+#endif
+    return 0;
+}
+
+int emac_disable_clk(struct emac_priv *priv)
+{
+    /* disable mac clock */
+    reset_assert(&priv->reset);
+    clk_disable(&priv->mac_clk);
+
+#if 0   /* CLK driver is not ready on fpga platform */
+    /* disable phy clock */
+    clk_disable_gate(CLK_104);
+    clk_disable_pll(PLL1, DIV_8);
+#endif
+    return 0;
+}
+
+static int emac_bind(struct udevice *bus)
+{
+    return 0;
+}
+
+static int emac_probe_resources_core(struct udevice *dev)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+    int ret;
+
+    debug("%s(dev=%p):\n", __func__, dev);
+
+    priv->descs = emac_alloc_descs(EQOS_DESCRIPTORS_TX +
+                       EQOS_DESCRIPTORS_RX);
+    if (!priv->descs) {
+        debug("%s: emac_alloc_descs() failed\n", __func__);
+        ret = -ENOMEM;
+        goto err;
+    }
+    priv->tx_descs = (struct emac_desc *)priv->descs;
+    priv->rx_descs = (priv->tx_descs + EQOS_DESCRIPTORS_TX);
+    debug("%s: tx_descs=%p, rx_descs=%p\n", __func__, priv->tx_descs,
+          priv->rx_descs);
+
+    priv->tx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_MAX_PACKET_SIZE);
+    if (!priv->tx_dma_buf) {
+        debug("%s: memalign(tx_dma_buf) failed\n", __func__);
+        ret = -ENOMEM;
+        goto err_free_descs;
+    }
+    debug("%s: tx_dma_buf=%p\n", __func__, priv->tx_dma_buf);
+
+    priv->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_RX_BUFFER_SIZE);
+    if (!priv->rx_dma_buf) {
+        debug("%s: memalign(rx_dma_buf) failed\n", __func__);
+        ret = -ENOMEM;
+        goto err_free_tx_dma_buf;
+    }
+    debug("%s: rx_dma_buf=%p\n", __func__, priv->rx_dma_buf);
+
+    debug("%s: OK\n", __func__);
+    return 0;
+
+err_free_tx_dma_buf:
+    free(priv->tx_dma_buf);
+err_free_descs:
+    emac_free_descs(priv->descs);
+err:
+    debug("%s: returns %d\n", __func__, ret);
+    return ret;
+}
+
+static int emac_remove_resources_core(struct udevice *dev)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+
+    debug("%s(dev=%p):\n", __func__, dev);
+
+    free(priv->rx_dma_buf);
+    free(priv->tx_dma_buf);
+    emac_free_descs(priv->descs);
+
+    debug("%s: OK\n", __func__);
+    return 0;
+}
+
+static int emac_eth_ofdata_to_platdata(struct udevice *dev)
+{
+    struct eth_pdata *pdata = dev_get_plat(dev);
+    struct emac_priv *priv = dev_get_priv(dev);
+    u32 ctrl_reg;
+
+    pdata->iobase = devfdt_get_addr(dev);
+    /* Interface mode is required */
+    pdata->phy_interface = dev_read_phy_mode(dev);
+    priv->phy_interface = pdata->phy_interface;
+    if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
+        printf("error: phy-mode is not set\n");
+        return -ENODEV;
+    }
+
+    priv->phy_addr = dev_read_u32_default(dev, "phy-addr", 0);
+    priv->ref_clk_frm_soc = !dev_read_bool(dev, "ref-clock-from-phy");
+
+    ctrl_reg = dev_read_u32_default(dev, "ctrl-reg", 0);
+    if (!ctrl_reg) {
+        printf("ethernet ctrl_reg NOT CONFIG!!!!\n");
+        return -EINVAL;
+    }
+
+    priv->ctrl_reg = (void *)((ulong)(K1X_APMU_BASE + ctrl_reg));
+
+    priv->phy_reset_gpio = dev_read_s32_default(dev, "phy-reset-pin", -1);
+    if(priv->phy_reset_gpio < 0)
+        goto err_tuning_gpio;
+
+    priv->ldo_gpio = dev_read_s32_default(dev, "ldo-pwr-pin", -1);
+
+    priv->clk_tuning_enable = dev_read_bool(dev, "clk_tuning_enable");
+    if (priv->clk_tuning_enable) {
+        if (dev_read_bool(dev, "clk-tuning-by-reg"))
+            priv->clk_tuning_way = CLK_TUNING_BY_REG;
+        else if (dev_read_bool(dev, "clk-tuning-by-clk-revert"))
+            priv->clk_tuning_way = CLK_TUNING_BY_CLK_REVERT;
+        else if (dev_read_bool(dev, "clk-tuning-by-delayline")) {
+            priv->clk_tuning_way = CLK_TUNING_BY_DLINE;
+            ctrl_reg = dev_read_u32_default(dev, "dline-reg", 0);
+            if (!ctrl_reg) {
+                printf("ethernet dline_reg NOT CONFIG!!!!\n");
+                return -EINVAL;
+            }
+            priv->dline_reg = (void *)((ulong)(K1X_APMU_BASE + ctrl_reg));
+        } else
+            priv->clk_tuning_way = CLK_TUNING_BY_REG;
+
+        priv->tx_phase = dev_read_u32_default(dev, "tx-phase", 0);
+        priv->rx_phase = dev_read_u32_default(dev, "rx-phase", 0);
+
+        debug("tx_phase:%d  rx_phase:%d clk_tuning:%d\n",
+              priv->tx_phase, priv->rx_phase, priv->clk_tuning_enable);
+    }
+    return 0;
+err_tuning_gpio:
+    printf("error: gpio get failed from dts\n");
+    return -EINVAL;
+}
+
+static int clk_phase_rgmii_set(struct emac_priv *priv, bool is_tx)
+{
+    u32 val;
+
+    switch (priv->clk_tuning_way) {
+    case CLK_TUNING_BY_REG:
+        val = readl(priv->ctrl_reg);
+        if (is_tx) {
+            val &= ~RGMII_TX_PHASE_MASK;
+            val |= (priv->tx_phase & 0x7) << RGMII_TX_PHASE_OFFSET;
+        } else {
+            val &= ~RGMII_RX_PHASE_MASK;
+            val |= (priv->rx_phase & 0x7) << RGMII_RX_PHASE_OFFSET;
+        }
+        writel(val, priv->ctrl_reg);
+        break;
+    case CLK_TUNING_BY_DLINE:
+        val = readl(priv->dline_reg);
+        if (is_tx) {
+            val &= ~EMAC_TX_DLINE_CODE_MASK;
+            val |= priv->tx_phase << EMAC_TX_DLINE_CODE_OFFSET;
+            val |= EMAC_TX_DLINE_EN;
+        } else {
+            val &= ~EMAC_RX_DLINE_CODE_MASK;
+            val |= priv->rx_phase << EMAC_RX_DLINE_CODE_OFFSET;
+            val |= EMAC_RX_DLINE_EN;
+        }
+        writel(val, priv->dline_reg);
+        break;
+    default:
+        printf("wrong clk tuning way:%d !!\n", priv->clk_tuning_way);
+        return -1;
+    }
+    debug("%s tx phase:%d rx phase:%d\n",
+        __func__, priv->tx_phase, priv->rx_phase);
+    return 0;
+}
+
+static int clk_phase_rmii_set(struct emac_priv *priv, bool is_tx)
+{
+    u32 val;
+
+    switch (priv->clk_tuning_way) {
+    case CLK_TUNING_BY_REG:
+        val = readl(priv->ctrl_reg);
+        if (is_tx) {
+            val &= ~RMII_TX_PHASE_MASK;
+            val |= (priv->tx_phase & 0x7) << RMII_TX_PHASE_OFFSET;
+        } else {
+            val &= ~RMII_RX_PHASE_MASK;
+            val |= (priv->rx_phase & 0x7) << RMII_RX_PHASE_OFFSET;
+        }
+        writel(val, priv->ctrl_reg);
+        break;
+    case CLK_TUNING_BY_CLK_REVERT:
+        val = readl(priv->ctrl_reg);
+        if (is_tx) {
+            if (priv->tx_phase == CLK_PHASE_REVERT)
+                val |= RMII_TX_CLK_SEL;
+            else
+                val &= ~RMII_TX_CLK_SEL;
+        } else {
+            if (priv->rx_phase == CLK_PHASE_REVERT)
+                val |= RMII_RX_CLK_SEL;
+            else
+                val &= ~RMII_RX_CLK_SEL;
+        }
+        writel(val, priv->ctrl_reg);
+        break;
+    default:
+        printf("wrong clk tuning way:%d !!\n", priv->clk_tuning_way);
+        return -1;
+    }
+    debug("%s tx phase:%d rx phase:%d\n",
+        __func__, priv->tx_phase, priv->rx_phase);
+    return 0;
+}
+
+static int emac_set_clock_phase(struct udevice *dev, int is_tx)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+
+    if (priv->clk_tuning_enable) {
+        if (emac_is_rmii(priv))
+            clk_phase_rmii_set(priv, is_tx);
+        else
+            clk_phase_rgmii_set(priv, is_tx);
+    }
+
+    return 0;
+}
+
+static int emac_probe(struct udevice *dev)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+    struct eth_pdata *pdata = dev_get_plat(dev);
+    int ret;
+
+    debug("%s(dev=%p):\n", __func__, dev);
+    priv->dev = dev;
+
+    priv->io_base = (void *)(pdata->iobase);
+
+    ret = emac_probe_resources_core(dev);
+    if (ret < 0) {
+        pr_err("emac_probe_resources_core() failed: %d", ret);
+        return ret;
+    }
+
+    ret = clk_get_by_index(dev, 0, &priv->mac_clk);
+    if (ret) {
+        pr_err("It has no clk: %d\n", ret);
+        return ret;
+    }
+
+    ret = reset_get_by_index(dev, 0, &priv->reset);
+    if (ret) {
+        pr_err("It has no reset: %d\n", ret);
+        return ret;
+    }
+
+    emac_enable_clk(priv);
+
+    priv->mii = mdio_alloc();
+    if (!priv->mii) {
+        pr_err("mdio_alloc() failed");
+        ret = -ENOMEM;
+        goto err_remove_resources_core;
+    }
+    priv->mii->read = emac_mdio_read;
+    priv->mii->write = emac_mdio_write;
+    priv->mii->priv = priv;
+    strncpy(priv->mii->name, dev->name, MDIO_NAME_LEN - 1);
+
+    ret = mdio_register(priv->mii);
+    if (ret < 0) {
+        pr_err("mdio_register() failed: %d", ret);
+        goto err_free_mdio;
+    }
+
+    emac_phy_interface_select(priv);
+
+    emac_enable_axi_single_id_mode(priv, 1);
+
+#ifdef CONFIG_GPIO  /* gpio driver is not ready for fpga platform! */
+    ret = gpio_request(priv->phy_reset_gpio, "phy-reset-pin");
+    if (ret < 0) {
+        pr_err("gpio_request_by_name(phy reset) failed: %d", ret);
+        goto err_free_mdio;
+    }
+
+    if (priv->ldo_gpio >= 0) {
+        ret = gpio_request(priv->ldo_gpio, "ldo-pwr-pin");
+        if (ret < 0) {
+            pr_err("gpio_request_by_name(ldo pwr) failed: %d", ret);
+            goto err_free_gpio;
+        }
+        gpio_direction_output(priv->ldo_gpio, 1);
+    }
+#endif
+    if (priv->clk_tuning_enable) {
+        emac_set_clock_phase(dev, TX_PHASE);
+        emac_set_clock_phase(dev, RX_PHASE);
+    }
+    debug("%s: OK\n", __func__);
+    return 0;
+
+#ifdef CONFIG_GPIO  /* gpio driver is not ready for fpga platform! */
+err_free_gpio:
+    gpio_free(priv->phy_reset_gpio);
+#endif
+err_free_mdio:
+    mdio_free(priv->mii);
+err_remove_resources_core:
+    emac_disable_clk(priv);
+    emac_remove_resources_core(dev);
+
+    debug("%s: returns %d\n", __func__, ret);
+    return ret;
+}
+
+static int emac_remove(struct udevice *dev)
+{
+    struct emac_priv *priv = dev_get_priv(dev);
+
+    debug("%s(dev=%p):\n", __func__, dev);
+
+    emac_disable_clk(priv);
+    mdio_unregister(priv->mii);
+    mdio_free(priv->mii);
+    emac_remove_resources_core(dev);
+
+    return 0;
+}
+
+static const struct eth_ops emac_ops = {
+    .start = emac_start,
+    .stop = emac_stop,
+    .send = emac_send,
+    .recv = emac_recv,
+    .free_pkt = emac_free_pkt,
+    .write_hwaddr = emac_write_hwaddr,
+};
+
+static const struct udevice_id emac_ids[] = {
+    {
+        .compatible = "spacemit,k1x-emac",
+    },
+    { }
+};
+
+U_BOOT_DRIVER(k1x_emac) = {
+    .name = "k1x_emac",
+    .id = UCLASS_ETH,
+    .of_match = emac_ids,
+    .of_to_plat = emac_eth_ofdata_to_platdata,
+    .probe = emac_probe,
+    .remove = emac_remove,
+    .bind = emac_bind,
+    .ops = &emac_ops,
+    .priv_auto = sizeof(struct emac_priv),
+    .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/spacemit/k1x_emac.h b/drivers/net/spacemit/k1x_emac.h
new file mode 100644 (file)
index 0000000..8f71273
--- /dev/null
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * spacemit emac driver
+ *
+ * Copyright (C) 2023 Spacemit
+ *
+ */
+
+#ifndef _SPACEMIT_K1X_EMAC_H_
+#define _SPACEMIT_K1X_EMAC_H_
+
+/* DMA register set */
+#define DMA_CONFIGURATION                   0x0000
+#define DMA_CONTROL                         0x0004
+#define DMA_STATUS_IRQ                      0x0008
+#define DMA_INTERRUPT_ENABLE                0x000C
+
+#define DMA_TRANSMIT_AUTO_POLL_COUNTER      0x0010
+#define DMA_TRANSMIT_POLL_DEMAND            0x0014
+#define DMA_RECEIVE_POLL_DEMAND             0x0018
+
+#define DMA_TRANSMIT_BASE_ADDRESS           0x001C
+#define DMA_RECEIVE_BASE_ADDRESS            0x0020
+#define DMA_MISSED_FRAME_COUNTER            0x0024
+#define DMA_STOP_FLUSH_COUNTER              0x0028
+
+#define DMA_CURRENT_TRANSMIT_DESCRIPTOR_POINTER     0x0030
+#define DMA_CURRENT_TRANSMIT_BUFFER_POINTER         0x0034
+#define DMA_CURRENT_RECEIVE_DESCRIPTOR_POINTER      0x0038
+#define DMA_CURRENT_RECEIVE_BUFFER_POINTER          0x003C
+
+/* MAC Register set */
+#define MAC_GLOBAL_CONTROL                  0x0100
+#define MAC_TRANSMIT_CONTROL                0x0104
+#define MAC_RECEIVE_CONTROL                 0x0108
+#define MAC_MAXIMUM_FRAME_SIZE              0x010C
+#define MAC_TRANSMIT_JABBER_SIZE            0x0110
+#define MAC_RECEIVE_JABBER_SIZE             0x0114
+#define MAC_ADDRESS_CONTROL                 0x0118
+#define MAC_ADDRESS1_HIGH                   0x0120
+#define MAC_ADDRESS1_MED                    0x0124
+#define MAC_ADDRESS1_LOW                    0x0128
+#define MAC_ADDRESS2_HIGH                   0x012C
+#define MAC_ADDRESS2_MED                    0x0130
+#define MAC_ADDRESS2_LOW                    0x0134
+#define MAC_ADDRESS3_HIGH                   0x0138
+#define MAC_ADDRESS3_MED                    0x013C
+#define MAC_ADDRESS3_LOW                    0x0140
+#define MAC_ADDRESS4_HIGH                   0x0144
+#define MAC_ADDRESS4_MED                    0x0148
+#define MAC_ADDRESS4_LOW                    0x014C
+#define MAC_MULTICAST_HASH_TABLE1           0x0150
+#define MAC_MULTICAST_HASH_TABLE2           0x0154
+#define MAC_MULTICAST_HASH_TABLE3           0x0158
+#define MAC_MULTICAST_HASH_TABLE4           0x015C
+#define MAC_FC_CONTROL                      0x0160
+#define MAC_FC_PAUSE_FRAME_GENERATE         0x0164
+#define MAC_FC_SOURCE_ADDRESS_HIGH          0x0168
+#define MAC_FC_SOURCE_ADDRESS_MED           0x016C
+#define MAC_FC_SOURCE_ADDRESS_LOW           0x0170
+#define MAC_FC_DESTINATION_ADDRESS_HIGH     0x0174
+#define MAC_FC_DESTINATION_ADDRESS_MED      0x0178
+#define MAC_FC_DESTINATION_ADDRESS_LOW      0x017C
+#define MAC_FC_PAUSE_TIME_VALUE             0x0180
+#define MAC_MDIO_CONTROL                    0x01A0
+#define MAC_MDIO_DATA                       0x01A4
+#define MAC_RX_STATCTR_CONTROL              0x01A8
+#define MAC_RX_STATCTR_DATA_HIGH            0x01AC
+#define MAC_RX_STATCTR_DATA_LOW             0x01B0
+#define MAC_TX_STATCTR_CONTROL              0x01B4
+#define MAC_TX_STATCTR_DATA_HIGH            0x01B8
+#define MAC_TX_STATCTR_DATA_LOW             0x01BC
+#define MAC_TRANSMIT_FIFO_ALMOST_FULL       0x01C0
+#define MAC_TRANSMIT_PACKET_START_THRESHOLD 0x01C4
+#define MAC_RECEIVE_PACKET_START_THRESHOLD  0x01C8
+#define MAC_STATUS_IRQ                      0x01E0
+#define MAC_INTERRUPT_ENABLE                0x01E4
+
+/* DMA_CONFIGURATION (0x0000) register bit info
+ * 0-DMA controller in normal operation mode,
+ * 1-DMA controller reset to default state,
+ * clearing all internal state information
+ */
+#define MREGBIT_SOFTWARE_RESET              BIT(0)
+#define MREGBIT_BURST_1WORD                 BIT(1)
+#define MREGBIT_BURST_2WORD                 BIT(2)
+#define MREGBIT_BURST_4WORD                 BIT(3)
+#define MREGBIT_BURST_8WORD                 BIT(4)
+#define MREGBIT_BURST_16WORD                BIT(5)
+#define MREGBIT_BURST_32WORD                BIT(6)
+#define MREGBIT_BURST_64WORD                BIT(7)
+#define MREGBIT_BURST_LENGTH                GENMASK(7, 1)
+#define MREGBIT_DESCRIPTOR_SKIP_LENGTH      GENMASK(12, 8)
+/* For Receive and Transmit DMA operate in Big-Endian mode for Descriptors. */
+#define MREGBIT_DESCRIPTOR_BYTE_ORDERING    BIT(13)
+#define MREGBIT_BIG_LITLE_ENDIAN            BIT(14)
+#define MREGBIT_TX_RX_ARBITRATION           BIT(15)
+#define MREGBIT_WAIT_FOR_DONE               BIT(16)
+#define MREGBIT_STRICT_BURST                BIT(17)
+#define MREGBIT_DMA_64BIT_MODE              BIT(18)
+
+/* DMA_CONTROL (0x0004) register bit info */
+#define MREGBIT_START_STOP_TRANSMIT_DMA     BIT(0)
+#define MREGBIT_START_STOP_RECEIVE_DMA      BIT(1)
+
+/* DMA_STATUS_IRQ (0x0008) register bit info */
+#define MREGBIT_TRANSMIT_TRANSFER_DONE_IRQ          BIT(0)
+#define MREGBIT_TRANSMIT_DES_UNAVAILABLE_IRQ        BIT(1)
+#define MREGBIT_TRANSMIT_DMA_STOPPED_IRQ            BIT(2)
+#define MREGBIT_RECEIVE_TRANSFER_DONE_IRQ           BIT(4)
+#define MREGBIT_RECEIVE_DES_UNAVAILABLE_IRQ         BIT(5)
+#define MREGBIT_RECEIVE_DMA_STOPPED_IRQ             BIT(6)
+#define MREGBIT_RECEIVE_MISSED_FRAME_IRQ            BIT(7)
+#define MREGBIT_MAC_IRQ                             BIT(8)
+#define MREGBIT_TRANSMIT_DMA_STATE                  GENMASK(18, 16)
+#define MREGBIT_RECEIVE_DMA_STATE                   GENMASK(23, 20)
+
+/* DMA_INTERRUPT_ENABLE ( 0x000C) register bit info */
+#define MREGBIT_TRANSMIT_TRANSFER_DONE_INTR_ENABLE      BIT(0)
+#define MREGBIT_TRANSMIT_DES_UNAVAILABLE_INTR_ENABLE    BIT(1)
+#define MREGBIT_TRANSMIT_DMA_STOPPED_INTR_ENABLE        BIT(2)
+#define MREGBIT_RECEIVE_TRANSFER_DONE_INTR_ENABLE       BIT(4)
+#define MREGBIT_RECEIVE_DES_UNAVAILABLE_INTR_ENABLE     BIT(5)
+#define MREGBIT_RECEIVE_DMA_STOPPED_INTR_ENABLE         BIT(6)
+#define MREGBIT_RECEIVE_MISSED_FRAME_INTR_ENABLE        BIT(7)
+#define MREGBIT_MAC_INTR_ENABLE                         BIT(8)
+
+/* MAC_GLOBAL_CONTROL (0x0100) register bit info */
+#define MREGBIT_SPEED                       GENMASK(1, 0)
+#define MREGBIT_SPEED_10M                   0x0
+#define MREGBIT_SPEED_100M                  BIT(0)
+#define MREGBIT_SPEED_1000M                 BIT(1)
+#define MREGBIT_FULL_DUPLEX_MODE            BIT(2)
+#define MREGBIT_RESET_RX_STAT_COUNTERS      BIT(3)
+#define MREGBIT_RESET_TX_STAT_COUNTERS      BIT(4)
+
+/* MAC_TRANSMIT_CONTROL (0x0104) register bit info */
+#define MREGBIT_TRANSMIT_ENABLE             BIT(0)
+#define MREGBIT_INVERT_FCS                  BIT(1)
+#define MREGBIT_DISABLE_FCS_INSERT          BIT(2)
+#define MREGBIT_TRANSMIT_AUTO_RETRY         BIT(3)
+#define MREGBIT_IFG_LEN                     GENMASK(6, 4)
+#define MREGBIT_PREAMBLE_LENGTH             GENMASK(9, 7)
+
+/* MAC_RECEIVE_CONTROL (0x0108) register bit info */
+#define MREGBIT_RECEIVE_ENABLE              BIT(0)
+#define MREGBIT_DISABLE_FCS_CHECK           BIT(1)
+#define MREGBIT_STRIP_FCS                   BIT(2)
+#define MREGBIT_STORE_FORWARD               BIT(3)
+#define MREGBIT_STATUS_FIRST                BIT(4)
+#define MREGBIT_PASS_BAD_FRAMES             BIT(5)
+#define MREGBIT_ACOOUNT_VLAN                BIT(6)
+
+/* MAC_MAXIMUM_FRAME_SIZE (0x010C) register bit info */
+#define MREGBIT_MAX_FRAME_SIZE              GENMASK(13, 0)
+
+/* MAC_TRANSMIT_JABBER_SIZE (0x0110) register bit info */
+#define MREGBIT_TRANSMIT_JABBER_SIZE        GENMASK(15, 0)
+
+/* MAC_RECEIVE_JABBER_SIZE (0x0114) register bit info */
+#define MREGBIT_RECEIVE_JABBER_SIZE         GENMASK(15, 0)
+
+/* MAC_ADDRESS_CONTROL     (0x0118) register bit info */
+#define MREGBIT_MAC_ADDRESS1_ENABLE             BIT(0)
+#define MREGBIT_MAC_ADDRESS2_ENABLE             BIT(1)
+#define MREGBIT_MAC_ADDRESS3_ENABLE             BIT(2)
+#define MREGBIT_MAC_ADDRESS4_ENABLE             BIT(3)
+#define MREGBIT_INVERSE_MAC_ADDRESS1_ENABLE     BIT(4)
+#define MREGBIT_INVERSE_MAC_ADDRESS2_ENABLE     BIT(5)
+#define MREGBIT_INVERSE_MAC_ADDRESS3_ENABLE     BIT(6)
+#define MREGBIT_INVERSE_MAC_ADDRESS4_ENABLE     BIT(7)
+#define MREGBIT_PROMISCUOUS_MODE                BIT(8)
+
+/* MAC_ADDRESSx_HIGH (0x0120) register bit info */
+#define MREGBIT_MAC_ADDRESS1_01_BYTE            GENMASK(7, 0)
+#define MREGBIT_MAC_ADDRESS1_02_BYTE            GENMASK(15, 8)
+/* MAC_ADDRESSx_MED (0x0124) register bit info */
+#define MREGBIT_MAC_ADDRESS1_03_BYTE            GENMASK(7, 0)
+#define MREGBIT_MAC_ADDRESS1_04_BYTE            GENMASK(15, 8)
+/* MAC_ADDRESSx_LOW (0x0128) register bit info */
+#define MREGBIT_MAC_ADDRESS1_05_BYTE            GENMASK(7, 0)
+#define MREGBIT_MAC_ADDRESS1_06_BYTE            GENMASK(15, 8)
+
+/* MAC_FC_CONTROL (0x0160) register bit info */
+#define MREGBIT_FC_DECODE_ENABLE                BIT(0)
+#define MREGBIT_FC_GENERATION_ENABLE            BIT(1)
+#define MREGBIT_AUTO_FC_GENERATION_ENABLE       BIT(2)
+#define MREGBIT_MULTICAST_MODE                  BIT(3)
+#define MREGBIT_BLOCK_PAUSE_FRAMES              BIT(4)
+
+/* MAC_FC_PAUSE_FRAME_GENERATE (0x0164) register bit info */
+#define MREGBIT_GENERATE_PAUSE_FRAME            BIT(0)
+
+/* MAC_FC_SRC/DST_ADDRESS_HIGH (0x0168) register bit info */
+#define MREGBIT_MAC_ADDRESS_01_BYTE             GENMASK(7, 0)
+#define MREGBIT_MAC_ADDRESS_02_BYTE             GENMASK(15, 8)
+/* MAC_FC_SRC/DST_ADDRESS_MED (0x016C) register bit info */
+#define MREGBIT_MAC_ADDRESS_03_BYTE             GENMASK(7, 0)
+#define MREGBIT_MAC_ADDRESS_04_BYTE             GENMASK(15, 8)
+/* MAC_FC_SRC/DSTD_ADDRESS_LOW (0x0170) register bit info */
+#define MREGBIT_MAC_ADDRESS_05_BYTE             GENMASK(7, 0)
+#define MREGBIT_MAC_ADDRESS_06_BYTE             GENMASK(15, 8)
+
+/* MAC_FC_PAUSE_TIME_VALUE (0x0180) register bit info */
+#define MREGBIT_MAC_FC_PAUSE_TIME               GENMASK(15, 0)
+
+/* MAC_MDIO_CONTROL (0x01A0) register bit info */
+#define MREGBIT_PHY_ADDRESS                     GENMASK(4, 0)
+#define MREGBIT_REGISTER_ADDRESS                GENMASK(9, 5)
+#define MREGBIT_MDIO_READ_WRITE                 BIT(10)
+#define MREGBIT_START_MDIO_TRANS                BIT(15)
+
+/* MAC_MDIO_DATA (0x01A4) register bit info */
+#define MREGBIT_MDIO_DATA                       GENMASK(15, 0)
+
+/* MAC_RX_STATCTR_CONTROL (0x01A8) register bit info */
+#define MREGBIT_RX_COUNTER_NUMBER               GENMASK(4, 0)
+#define MREGBIT_START_RX_COUNTER_READ           BIT(15)
+
+/* MAC_RX_STATCTR_DATA_HIGH (0x01AC) register bit info */
+#define MREGBIT_RX_STATCTR_DATA_HIGH            GENMASK(15, 0)
+/* MAC_RX_STATCTR_DATA_LOW (0x01B0) register bit info */
+#define MREGBIT_RX_STATCTR_DATA_LOW             GENMASK(15, 0)
+
+/* MAC_TX_STATCTR_CONTROL (0x01B4) register bit info */
+#define MREGBIT_TX_COUNTER_NUMBER               GENMASK(4, 0)
+#define MREGBIT_START_TX_COUNTER_READ           BIT(15)
+
+/* MAC_TX_STATCTR_DATA_HIGH (0x01B8) register bit info */
+#define MREGBIT_TX_STATCTR_DATA_HIGH            GENMASK(15, 0)
+/* MAC_TX_STATCTR_DATA_LOW (0x01BC) register bit info */
+#define MREGBIT_TX_STATCTR_DATA_LOW             GENMASK(15, 0)
+
+/* MAC_TRANSMIT_FIFO_ALMOST_FULL (0x01C0) register bit info */
+#define MREGBIT_TX_FIFO_AF                      GENMASK(13, 0)
+
+/* MAC_TRANSMIT_PACKET_START_THRESHOLD (0x01C4) register bit info */
+#define MREGBIT_TX_PACKET_START_THRESHOLD       GENMASK(13, 0)
+
+/* MAC_RECEIVE_PACKET_START_THRESHOLD (0x01C8) register bit info */
+#define MREGBIT_RX_PACKET_START_THRESHOLD       GENMASK(13, 0)
+
+/* MAC_STATUS_IRQ  (0x01E0) register bit info */
+#define MREGBIT_MAC_UNDERRUN_IRQ                BIT(0)
+#define MREGBIT_MAC_JABBER_IRQ                  BIT(1)
+
+/* MAC_INTERRUPT_ENABLE (0x01E4) register bit info */
+#define MREGBIT_MAC_UNDERRUN_INTERRUPT_ENABLE   BIT(0)
+#define MREGBIT_JABBER_INTERRUPT_ENABLE         BIT(1)
+
+/* Receive Descriptors */
+/* MAC_RECEIVE_DESCRIPTOR0 () register bit info */
+#define MREGBIT_FRAME_LENGTH                    GENMASK(13, 0)
+#define MREGBIT_APPLICATION_STATUS              GENMASK(28, 14)
+#define MREGBIT_LAST_DESCRIPTOR                 BIT(29)
+#define MREGBIT_FIRST_DESCRIPTOR                BIT(30)
+#define MREGBIT_OWN_BIT                         BIT(31)
+
+/* MAC_RECEIVE_DESCRIPTOR1 () register bit info */
+#define MREGBIT_BUFFER1_SIZE                    GENMASK(11, 0)
+#define MREGBIT_BUFFER2_SIZE                    GENMASK(23, 12)
+#define MREGBIT_SECOND_ADDRESS_CHAINED          BIT(25)
+#define MREGBIT_END_OF_RING                     BIT(26)
+
+/* MAC_RECEIVE_DESCRIPTOR2 () register bit info */
+#define MREGBIT_BUFFER_ADDRESS1                 GENMASK(31, 0)
+
+/* MAC_RECEIVE_DESCRIPTOR3 () register bit info */
+#define MREGBIT_BUFFER_ADDRESS1                 GENMASK(31, 0)
+
+/* Transmit Descriptors */
+/* TD_TRANSMIT_DESCRIPTOR0 () register bit info */
+#define MREGBIT_TX_PACKET_STATUS                GENMASK(29, 0)
+#define MREGBIT_OWN_BIT                         BIT(31)
+
+/* TD_TRANSMIT_DESCRIPTOR1 () register bit info */
+#define MREGBIT_BUFFER1_SIZE                    GENMASK(11, 0)
+#define MREGBIT_BUFFER2_SIZE                    GENMASK(23, 12)
+#define MREGBIT_FORCE_EOP_ERROR                 BIT(24)
+#define MREGBIT_SECOND_ADDRESS_CHAINED          BIT(25)
+#define MREGBIT_END_OF_RING                     BIT(26)
+#define MREGBIT_DISABLE_PADDING                 BIT(27)
+#define MREGBIT_ADD_CRC_DISABLE                 BIT(28)
+#define MREGBIT_FIRST_SEGMENT                   BIT(29)
+#define MREGBIT_LAST_SEGMENT                    BIT(30)
+#define MREGBIT_INTERRUPT_ON_COMPLETION         BIT(31)
+
+/* TD_TRANSMIT_DESCRIPTOR2 () register bit info */
+#define MREGBIT_BUFFER_ADDRESS1                 GENMASK(31, 0)
+
+/* TD_TRANSMIT_DESCRIPTOR3 () register bit info */
+#define MREGBIT_BUFFER_ADDRESS1                 GENMASK(31, 0)
+
+#define EMAC_RX_BUFFER_1024                 1024
+#define EMAC_RX_BUFFER_2048                 2048
+#define EMAC_RX_BUFFER_4096                 4096
+
+#define MAX_DATA_PWR_TX_DES                 11
+#define MAX_DATA_LEN_TX_DES                 2048 //2048=1<<11
+
+#define MAX_TX_STATS_NUM                    12
+#define MAX_RX_STATS_NUM                    25
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ETHERNET_HEADER_SIZE                14
+#define MAXIMUM_ETHERNET_FRAME_SIZE         1518  //With FCS
+#define MINIMUM_ETHERNET_FRAME_SIZE         64  //With FCS
+#define ETHERNET_FCS_SIZE                   4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+        (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+        (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+
+#define CRC_LENGTH                  ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE        0x3F00
+
+#define TX_STORE_FORWARD_MODE       0x5EE
+
+/* only works for sizes that are powers of 2 */
+#define EMAC_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
+
+/* number of descriptors are required for len */
+#define EMAC_TXD_COUNT(S, X) (((S) >> (X)) + 1)
+
+/* calculate the number of descriptors unused */
+#define EMAC_DESC_UNUSED(R) \
+    ((((R)->nxt_clean > (R)->nxt_use) ? 0 : (R)->total_cnt) + \
+    (R)->nxt_clean - (R)->nxt_use - 1)
+
+
+#endif //_SPACEMIT_K1X_EMAC_H_
index 22f4995453ed0a25551fc5dce2e0bb6895810e25..1a7528489b965abeb1a8716e26bd7686fc443d72 100644 (file)
@@ -133,6 +133,20 @@ config PCIE_DW_SIFIVE
          Say Y here if you want to enable PCIe controller support on
          FU740.
 
+config PCIE_DW_K1PRO
+       bool "Enable Spacemit k1pro PCIe"
+       select PCIE_DW_COMMON
+       help
+         Say Y here if you want to enable PCIe controller support on
+         Spacemit SoCs.
+
+config PCIE_DW_K1X
+       bool "Enable Spacemit k1x PCIe"
+       select PCIE_DW_COMMON
+       help
+         Say Y here if you want to enable PCIe controller support on
+         Spacemit k1x SoCs.
+
 config SYS_FSL_PCI_VER_3_X
        bool
 
index cfcd6fd6c52f8df2026ec3c943f9bcce10cf11ee..9da35702630ac6acf359c19f4ade6ce8c8766fc2 100644 (file)
@@ -48,4 +48,6 @@ obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
 obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
 obj-$(CONFIG_PCIE_OCTEON) += pcie_octeon.o
 obj-$(CONFIG_PCIE_DW_SIFIVE) += pcie_dw_sifive.o
+obj-$(CONFIG_PCIE_DW_K1PRO) += pcie_dw_k1pro.o
+obj-$(CONFIG_PCIE_DW_K1X) += pcie_dw_k1x.o
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o
diff --git a/drivers/pci/pcie_dw_k1x.c b/drivers/pci/pcie_dw_k1x.c
new file mode 100644 (file)
index 0000000..a51ade0
--- /dev/null
@@ -0,0 +1,816 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Spacemit k1x DesignWare based PCIe host controller driver
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <generic-phy.h>
+#include <power-domain.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <clk.h>
+#include <reset.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PCIE_VENDORID_MASK     GENMASK(15, 0)
+#define PCIE_DEVICEID_SHIFT    16
+
+#define PCIE_LINK_CAPABILITY           0x7c
+#define PCIE_LINK_CTL_2                        0xa0
+#define TARGET_LINK_SPEED_MASK         0xf
+#define LINK_SPEED_GEN_1               0x1
+#define LINK_SPEED_GEN_2               0x2
+#define LINK_SPEED_GEN_3               0x3
+
+#define PCIE_MISC_CONTROL_1_OFF                0x8bc
+#define PCIE_DBI_RO_WR_EN              BIT(0)
+
+#define PLR_OFFSET                     0x700
+#define PCIE_PORT_DEBUG0               (PLR_OFFSET + 0x28)
+#define PORT_LOGIC_LTSSM_STATE_MASK    0x1f
+#define PORT_LOGIC_LTSSM_STATE_L0      0x11
+
+#define PCIE_LINK_UP_TIMEOUT_MS                1000
+
+/* Offsets from App base */
+#define PCIE_CMD_STATUS                        0x04
+#define LTSSM_EN_VAL                   BIT(0)
+
+
+
+#define        PCIECTRL_K1X_CONF_DEVICE_CMD                    0x0000
+#define        LTSSM_EN                                        BIT(6)
+/* Perst input value in ep mode */
+#define        PCIE_PERST_IN                                   BIT(7)
+/* Perst GPIO en in RC mode 1: perst# low, 0: perst# high */
+#define        PCIE_RC_PERST                                   BIT(12)
+/* Wake# GPIO in EP mode 1: Wake# low, 0: Wake# high */
+#define        PCIE_EP_WAKE                                    BIT(13)
+#define        APP_HOLD_PHY_RST                                BIT(30)
+/* BIT31 0: EP, 1: RC*/
+#define        DEVICE_TYPE_RC                                  BIT(31)
+
+#define        PCIE_CTRL_LOGIC                                 0x0004
+#define        PCIE_IGNORE_PERSTN                              BIT(2)
+
+#define        K1X_PHY_AHB_LINK_STS                            0x0004
+#define        SMLH_LINK_UP                                    BIT(1)
+#define        RDLH_LINK_UP                                    BIT(12)
+
+/**
+ *
+ * @pci: The common PCIe DW structure
+ * @app_base: The base address of application register space
+ */
+struct pcie_dw_k1x {
+       /* Must be first member of the struct */
+       struct pcie_dw dw;
+       void __iomem            *base;          /* DT k1x_conf */
+       void __iomem            *phy_ahb;               /* DT phy_ahb */
+       void __iomem            *phy_addr;              /* DT phy_addr */
+       void __iomem            *conf0_addr;            /* DT conf0_addr */
+       void __iomem            *phy0_addr;             /* DT phy0_addr */
+       int                     port_id;
+
+       /* reset, clock resources */
+       struct clk clock;
+       struct reset_ctl reset;
+};
+
+enum dw_pcie_device_mode {
+       DW_PCIE_UNKNOWN_TYPE,
+       DW_PCIE_EP_TYPE,
+       DW_PCIE_RC_TYPE,
+};
+
+static inline u32 k1x_pcie_readl(struct pcie_dw_k1x *pcie, u32 offset)
+{
+       return readl(pcie->base + offset);
+}
+
+static inline void k1x_pcie_writel(struct pcie_dw_k1x *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->base + offset);
+}
+
+static inline u32 k1x_pcie_phy_ahb_readl(struct pcie_dw_k1x *pcie, u32 offset)
+{
+       return readl(pcie->phy_ahb + offset);
+}
+
+static inline void k1x_pcie_phy_ahb_writel(struct pcie_dw_k1x *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->phy_ahb + offset);
+}
+
+static inline u32 k1x_pcie_phy_reg_readl(struct pcie_dw_k1x *pcie, u32 offset)
+{
+       return readl(pcie->phy_addr + offset);
+}
+
+static inline void k1x_pcie_phy_reg_writel(struct pcie_dw_k1x *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->phy_addr + offset);
+}
+
+static inline u32 k1x_pcie_conf0_reg_readl(struct pcie_dw_k1x *pcie, u32 offset)
+{
+       return readl(pcie->conf0_addr + offset);
+}
+
+static inline void k1x_pcie_conf0_reg_writel(struct pcie_dw_k1x *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->conf0_addr + offset);
+}
+
+static inline u32 k1x_pcie_phy0_reg_readl(struct pcie_dw_k1x *pcie, u32 offset)
+{
+       return readl(pcie->phy0_addr + offset);
+}
+
+static inline void k1x_pcie_phy0_reg_writel(struct pcie_dw_k1x *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->phy0_addr + offset);
+}
+
+/**
+ * pcie_dw_configure() - Configure link capabilities and speed
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ * @cap_speed: The capabilities and speed to configure
+ *
+ * Configure the link capabilities and speed in the PCIe root complex.
+ */
+static void pcie_dw_configure(struct pcie_dw_k1x *pci, u32 cap_speed)
+{
+       u32 val;
+
+       dw_pcie_dbi_write_enable(&pci->dw, true);
+
+       val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
+       val &= ~TARGET_LINK_SPEED_MASK;
+       val |= cap_speed;
+       writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
+
+       val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2);
+       val &= ~TARGET_LINK_SPEED_MASK;
+       val |= cap_speed;
+       writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2);
+
+       dw_pcie_dbi_write_enable(&pci->dw, false);
+}
+
+/**
+ * is_link_up() - Return the link state
+ *
+ * @regs_base: A pointer to the PCIe DBICS registers
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link
+ */
+static int is_link_up(struct pcie_dw_k1x *pci)
+{
+       u32 val;
+
+       val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0);
+       val &= PORT_LOGIC_LTSSM_STATE_MASK;
+
+       return (val == PORT_LOGIC_LTSSM_STATE_L0);
+}
+
+/**
+ * wait_link_up() - Wait for the link to come up
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link (timeout)
+ */
+static int wait_link_up(struct pcie_dw_k1x *pci)
+{
+       unsigned long timeout;
+
+       timeout = get_timer(0) + PCIE_LINK_UP_TIMEOUT_MS;
+       while (!is_link_up(pci)) {
+               if (get_timer(0) > timeout)
+                       return 0;
+       };
+
+       return 1;
+}
+
+static int pcie_dw_k1x_pcie_link_up(struct pcie_dw_k1x *pci, u32 cap_speed)
+{
+       u32 reg;
+
+       if (is_link_up(pci)) {
+               printf("PCI Link already up before configuration!\n");
+               return 1;
+       }
+
+       /* DW pre link configurations */
+       pcie_dw_configure(pci, cap_speed);
+
+       /* Initiate link training */
+       reg = k1x_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+       reg |= LTSSM_EN;
+       reg &= ~APP_HOLD_PHY_RST;
+       k1x_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+       /* Check that link was established */
+       if (!wait_link_up(pci))
+               return 0;
+
+       /*
+        * Link can be established in Gen 1. still need to wait
+        * till MAC nagaotiation is completed
+        */
+       udelay(100);
+
+       return 1;
+}
+
+static int pcie_set_mode(struct pcie_dw_k1x *pci,
+                              enum dw_pcie_device_mode mode)
+{
+       u32 reg;
+
+       switch (mode) {
+       case DW_PCIE_RC_TYPE:
+               reg = k1x_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+               reg |= DEVICE_TYPE_RC;
+               k1x_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+               reg = k1x_pcie_readl(pci, PCIE_CTRL_LOGIC);
+               reg |= PCIE_IGNORE_PERSTN;
+               k1x_pcie_writel(pci, PCIE_CTRL_LOGIC, reg);
+               break;
+       case DW_PCIE_EP_TYPE:
+               reg = k1x_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+               reg &= ~DEVICE_TYPE_RC;
+               k1x_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+               break;
+       default:
+               dev_err(pci->dw.dev, "INVALID device type %d\n", mode);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int k1x_pcie_host_init(struct pcie_dw_k1x *pci)
+{
+       u32 reg;
+
+       mdelay(100);
+       /* set Perst# gpio high state*/
+       reg = k1x_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+       reg &= ~PCIE_RC_PERST;
+       k1x_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+       return 0;
+}
+
+#define PCIE_REF_CLK_OUTPUT
+static int porta_init_done = 0;
+// wait porta rterm done
+void porta_rterm(struct pcie_dw_k1x *k1x)
+{
+       int rd_data;
+       u32 val;
+
+       //REG32(PMUA_REG_BASE + 0x3CC) = 0x4000003f;
+       val = k1x_pcie_conf0_reg_readl(k1x, 0);
+       val = 0x4000003f;
+       k1x_pcie_conf0_reg_writel(k1x, 0 , val);
+
+       //REG32(PMUA_REG_BASE + 0x3CC) &= 0xbfffffff; // clear hold phy reset
+       val = k1x_pcie_conf0_reg_readl(k1x, 0);
+       val &= 0xbfffffff;
+       k1x_pcie_conf0_reg_writel(k1x, 0 , val);
+
+       // set refclk model
+       //REG32(0xC0B10000 + (0x17 << 2)) |= (0x1 << 10);
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x17 << 2));
+       val |= (0x1 << 10);
+       k1x_pcie_phy0_reg_writel(k1x, (0x17 << 2), val);
+
+       //REG32(0xC0B10000 + (0x17 << 2)) &= ~(0x3 << 8);
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x17 << 2));
+       val &= ~(0x3 << 8);
+       k1x_pcie_phy0_reg_writel(k1x, (0x17 << 2), val);
+
+
+#ifndef PCIE_REF_CLK_OUTPUT
+       // receiver mode
+       //REG32(0xC0B10000 + (0x17 << 2)) |= 0x2 << 8;
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x17 << 2));
+       val |= 0x2 << 8;
+       k1x_pcie_phy0_reg_writel(k1x, (0x17 << 2), val);
+
+       //REG32(0xC0B10000 + (0x8 << 2)) &= ~(0x1 << 29);
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x8 << 2));
+       val &= ~(0x1 << 29);
+       k1x_pcie_phy0_reg_writel(k1x, (0x8 << 2), val);
+#ifdef PCIE_SEL_24M_REF_CLK
+       //REG32(0xC0B10000 + (0x12 << 2)) &= 0xffff0fff;
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x12 << 2));
+       val &= 0xffff0fff;
+       k1x_pcie_phy0_reg_writel(k1x, (0x12 << 2), val);
+
+       //REG32(0xC0B10000 + (0x12 << 2)) |= 0x00002000; // select 24Mhz refclock input pll_reg1[15:13]=2
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x12 << 2));
+       val |= 0x00002000;
+       k1x_pcie_phy0_reg_writel(k1x, (0x12 << 2), val);
+
+       //REG32(0xC0B10000 + (0x8 << 2)) |= 0x3 << 29;     // rc_cal_reg2 0x68
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x8 << 2));
+       val |= 0x3 << 29;
+       k1x_pcie_phy0_reg_writel(k1x, (0x8 << 2), val);
+#elif PCIE_SEL_100M_REF_CLK
+       //REG32(0xC0B10000 + (0x8 << 2)) |= 0x1 << 30; // rc_cal_reg2 0x48
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x8 << 2));
+       val |= 0x1 << 30;
+       k1x_pcie_phy0_reg_writel(k1x, (0x8 << 2), val);
+#endif
+       //REG32(0xC0B10000 + (0x14 << 2)) |= (0x1 << 3); // pll_reg9[3] en_rterm,only enable in receiver mode
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x14 << 2));
+       val |= (0x1 << 3);
+       k1x_pcie_phy0_reg_writel(k1x, (0x14 << 2), val);
+#else
+       // driver mode
+       //REG32(0xC0B10000 + (0x17 << 2)) |= 0x1 << 8;
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x17 << 2));
+       val |= 0x1 << 8;
+       k1x_pcie_phy0_reg_writel(k1x, (0x17 << 2), val);
+
+       //REG32(0xC0B10000 + 0x400 + (0x17 << 2)) |= 0x1 << 8;
+       val = k1x_pcie_phy0_reg_readl(k1x, 0x400 + (0x17 << 2));
+       val |= 0x1 << 8;
+       k1x_pcie_phy0_reg_writel(k1x, 0x400 + (0x17 << 2), val);
+
+       //REG32(0xC0B10000 + (0x12 << 2)) &= 0xffff0fff;
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x12 << 2));
+       val &= 0xffff0fff;
+       k1x_pcie_phy0_reg_writel(k1x, (0x12 << 2), val);
+
+       //REG32(0xC0B10000 + (0x12 << 2)) |= 0x00002000; // select 24Mhz refclock input pll_reg1[15:13]=2
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x12 << 2));
+       val |= 0x00002000;
+       k1x_pcie_phy0_reg_writel(k1x, (0x12 << 2), val);
+
+       //REG32(0xC0B10000 + (0x13 << 2)) |= (0x1 << 4); // pll_reg5[4] of lane0, enable refclk_100_n/p 100Mhz output
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x13 << 2));
+       val |= (0x1 << 4);
+       k1x_pcie_phy0_reg_writel(k1x, (0x13 << 2), val);
+
+       //// REG32(0xC0B10000+(0x14<<2)) |= (0x1<<3);//pll_reg9[3] en_rterm,only enable in receiver mode
+#endif
+
+       //REG32(0xC0B10000 + (0x12 << 2)) &= 0xfff0ffff; // pll_reg1 of lane0, disable ssc pll_reg4[3:0]=4'h0
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x12 << 2));
+       val &= 0xfff0ffff;
+       k1x_pcie_phy0_reg_writel(k1x, (0x12 << 2), val);
+
+       //REG32(0xC0B10000 + (0x02 << 2)) = 0x00000B78; // PU_ADDR_CLK_CFG of lane0
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x02 << 2));
+       val = 0x00000B78;
+       k1x_pcie_phy0_reg_writel(k1x, (0x02 << 2), val);
+
+       //REG32(0xC0B10000 + (0x06 << 2)) = 0x00000400; // force rcv done
+       val = k1x_pcie_phy0_reg_readl(k1x, (0x06 << 2));
+       val = 0x00000400;
+       k1x_pcie_phy0_reg_writel(k1x, (0x06 << 2), val);
+       printk("Now waiting portA resister tuning done...\n");
+
+       // force PCIE mpu_u3/pu_rx_lfps
+       //REG32(PCIE_PUPHY_REG_BASE + 0x6 * 4) |= (0x1 << 17) | (0x1 << 15);
+       val = k1x_pcie_phy_reg_readl(k1x, (0x6 * 4));
+       val |= ((0x1 << 17) | (0x1 << 15));
+       k1x_pcie_phy_reg_writel(k1x, (0x6 * 4), val);
+
+       // wait pm0 rterm done
+       do
+       {
+               //rd_data = REG32(0xC0B10000 + 0x21 * 4);
+               rd_data = k1x_pcie_phy0_reg_readl(k1x, (0x21 * 4));
+               printk("porta redonly_reg2: %08x\n", rd_data);
+       } while (((rd_data >> 10) & 0x1) == 0); // waiting PCIe portA readonly_reg2[2] r_tune_done==1
+}
+
+// force rterm value to porta/b/c
+void rterm_force(struct pcie_dw_k1x *k1x, u32 pcie_rcal)
+{
+       int i, lane;
+       u32 val = 0;
+
+       if (k1x->port_id != 0x0) {
+               lane = 2;
+       } else {
+               lane = 1;
+       }
+
+       printk("pcie_rcal = 0x%08x\n", pcie_rcal);
+       printk("pcie port id = %d, lane num = %d\n", k1x->port_id, lane);
+
+       // 2.write pma0 rterm value LSB[3:0](read0nly1[3:0]) to lane0/1 rx_reg1
+       for (i = 0; i < lane; i++)
+       {
+               val = k1x_pcie_phy_reg_readl(k1x, ((0x14 << 2) + 0x400 * i));
+               val |= ((pcie_rcal & 0xf) << 8);
+               k1x_pcie_phy_reg_writel(k1x, ((0x14 << 2) + 0x400 * i), val);
+       }
+       // 3.set lane0/1 rx_reg4 bit5=0
+       for (i = 0; i < lane; i++)
+       {
+               val = k1x_pcie_phy_reg_readl(k1x, ((0x15 << 2) + 0x400 * i));
+               val &= ~(1 << 5);
+               k1x_pcie_phy_reg_writel(k1x, ((0x15 << 2) + 0x400 * i), val);
+       }
+
+       // 4.write pma0 rterm value MSB[7:4](readonly1[7:4]) to lane0/1 tx_reg1[7:4]
+       for (i = 0; i < lane; i++)
+       {
+               val = k1x_pcie_phy_reg_readl(k1x, ((0x19 << 2) + 0x400 * i));
+               val |= ((pcie_rcal >> 4) & 0xf) << 12;
+               k1x_pcie_phy_reg_writel(k1x, ((0x19 << 2) + 0x400 * i), val);
+       }
+
+       // 5.set lane0/1 tx_reg3 bit1=1
+       for (i = 0; i < lane; i++)
+       {
+               val = k1x_pcie_phy_reg_readl(k1x, ((0x19 << 2) + 0x400 * i));
+               val |= (1 << 25);
+               k1x_pcie_phy_reg_writel(k1x, ((0x19 << 2) + 0x400 * i), val);
+       }
+
+       // 6.adjust rc calrefclk freq
+#ifndef PCIE_REF_CLK_OUTPUT
+       //REG32(PCIE_PUPHY_REG_BASE + (0x8 << 2)) &= ~(0x1 << 29);
+       val = k1x_pcie_phy_reg_readl(k1x,  (0x8 << 2));
+       val &= ~(0x1 << 29);
+       k1x_pcie_phy_reg_writel(k1x,  (0x8 << 2), val);
+#ifdef PCIE_SEL_24M_REF_CLK
+       //REG32(PCIE_PUPHY_REG_BASE + (0x8 << 2)) |= 0x3 << 29; // rc_cal_reg2 0x68
+       val = k1x_pcie_phy_reg_readl(k1x,  (0x8 << 2));
+       val |= 0x3 << 29;
+       k1x_pcie_phy_reg_writel(k1x,  (0x8 << 2), val);
+#elif PCIE_SEL_100M_REF_CLK
+       //REG32(PCIE_PUPHY_REG_BASE + (0x8 << 2)) |= 0x1 << 30; // rc_cal_reg2 0x48
+       val = k1x_pcie_phy_reg_readl(k1x,  (0x8 << 2));
+       val |= 0x1 << 30;
+       k1x_pcie_phy_reg_writel(k1x,  (0x8 << 2), val);
+#endif
+#else
+       //REG32(PCIE_PUPHY_REG_BASE + (0x8 << 2)) |= 0x3 << 29;
+       val = k1x_pcie_phy_reg_readl(k1x,  (0x8 << 2));
+       val |= 0x3 << 29;
+       k1x_pcie_phy_reg_writel(k1x,  (0x8 << 2), val);
+#endif
+
+       // 7.set lane0/1 rc_cal_reg1[6]=1
+       for (i = 0; i < lane; i++)
+       {
+               val = k1x_pcie_phy_reg_readl(k1x, ((0x8 << 2) + 0x400 * i));
+               val &= ~(1 << 22);
+               k1x_pcie_phy_reg_writel(k1x, ((0x8 << 2) + 0x400 * i), val);
+       }
+       for (i = 0; i < lane; i++)
+       {
+               val = k1x_pcie_phy_reg_readl(k1x, ((0x8 << 2) + 0x400 * i));
+               val |= (1 << 22);
+               k1x_pcie_phy_reg_writel(k1x, ((0x8 << 2) + 0x400 * i), val);
+       }
+
+       // release forc PCIE mpu_u3/pu_rx_lfps
+       val = k1x_pcie_phy_reg_readl(k1x, 0x6 * 4);
+       val &= 0xFFFD7FFF;
+       k1x_pcie_phy_reg_writel(k1x, 0x6 * 4, val);
+}
+
+static int init_phy(struct pcie_dw_k1x *k1x)
+{
+       u32 rd_data, pcie_rcal;
+       u32 val = 0;
+
+       printk("Now init Rterm...\n");
+       printk("pcie prot id = %d, porta_init_done = %d\n", k1x->port_id, porta_init_done);
+       if (k1x->port_id != 0) {
+           if (porta_init_done == 0) {
+                       porta_rterm(k1x);
+                       //pcie_rcal = REG32(0xC0B10000 + (0x21 << 2));
+                       pcie_rcal = k1x_pcie_phy0_reg_readl(k1x,  (0x21 << 2));
+
+                       //REG32(PMUA_REG_BASE + 0x3CC) &= ~0x4000003f;
+                       val = k1x_pcie_conf0_reg_readl(k1x, 0);
+                       val &= ~0x4000003f;
+                       k1x_pcie_conf0_reg_writel(k1x, 0, val);
+               } else {
+                       //pcie_rcal = REG32(0xC0B10000 + (0x21 << 2));
+                       pcie_rcal = k1x_pcie_phy0_reg_readl(k1x,  (0x21 << 2));
+               }
+       } else {
+               do {
+                       //rd_data = REG32(0xC0B10000 + 0x21 * 4);
+                       rd_data = k1x_pcie_phy0_reg_readl(k1x,  (0x21 * 4));
+               } while (((rd_data >> 10) & 0x1) == 0);
+               //pcie_rcal = REG32(0xC0B10000 + (0x21 << 2));
+               pcie_rcal = k1x_pcie_phy0_reg_readl(k1x,  (0x21 << 2));
+       }
+
+       rterm_force(k1x, pcie_rcal);
+
+       printk("Now int init_puphy...\n");
+       val = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD);
+       val &= 0xbfffffff;
+       k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, val);
+
+       // set refclk model
+       val = k1x_pcie_phy_reg_readl(k1x, (0x17 << 2));
+       val |= (0x1 << 10);
+       k1x_pcie_phy_reg_writel(k1x, (0x17 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, (0x17 << 2));
+       val &= ~(0x3 << 8);
+       k1x_pcie_phy_reg_writel(k1x, (0x17 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2));
+       val |= (0x1 << 10);
+       k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2));
+       val &= ~(0x3 << 8);
+       k1x_pcie_phy_reg_writel(k1x, 0x400+ (0x17 << 2), val);
+#ifndef PCIE_REF_CLK_OUTPUT
+       // receiver mode
+       REG32(PCIE_PUPHY_REG_BASE + (0x17 << 2)) |= 0x2 << 8;
+       REG32(PCIE_PUPHY_REG_BASE + 0x400 + (0x17 << 2)) |= 0x2 << 8;
+#ifdef PCIE_SEL_24M_REF_CLK
+       val = k1x_pcie_phy_reg_readl(k1x, (0x12 << 2));
+       val &= 0xffff0fff;
+       k1x_pcie_phy_reg_writel(k1x, (0x12 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, (0x12 << 2));
+       val |= 0x00002000;
+       k1x_pcie_phy_reg_writel(k1x, (0x12 << 2), val);
+#endif
+#else
+       // driver mode
+       val = k1x_pcie_phy_reg_readl(k1x, (0x17 << 2));
+       val |= 0x1 << 8;
+       k1x_pcie_phy_reg_writel(k1x, (0x17 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2));
+       val |= 0x1 << 8;
+       k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, (0x12 << 2));
+       val &= 0xffff0fff;
+       k1x_pcie_phy_reg_writel(k1x, (0x12 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, (0x12 << 2));
+       val |= 0x00002000;
+       k1x_pcie_phy_reg_writel(k1x, (0x12 << 2), val);
+
+       val = k1x_pcie_phy_reg_readl(k1x, (0x13 << 2));
+       val |= (0x1 << 4);
+       k1x_pcie_phy_reg_writel(k1x, (0x13 << 2), val);
+
+       if (k1x->port_id == 0x0) {
+               //REG32(0xC0B10000+(0x14<<2)) |= (0x1<<3);//pll_reg9[3] en_rterm,only enable in receiver mode
+               val = k1x_pcie_phy0_reg_readl(k1x,  (0x14 << 2));
+               val |= (0x1 << 3);
+               k1x_pcie_phy0_reg_writel(k1x,  (0x14 << 2), val);
+       }
+#endif
+
+       // pll_reg1 of lane0, disable ssc pll_reg4[3:0]=4'h0
+       val = k1x_pcie_phy_reg_readl(k1x, (0x12 << 2));
+       val &= 0xfff0ffff;
+       k1x_pcie_phy_reg_writel(k1x, (0x12 << 2), val);
+
+       // PU_ADDR_CLK_CFG of lane0
+       val = k1x_pcie_phy_reg_readl(k1x, (0x02 << 2));
+       val = 0x00000B78;
+       k1x_pcie_phy_reg_writel(k1x, (0x02 << 2), val);
+
+        // PU_ADDR_CLK_CFG of lane1
+       val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x02 << 2));
+       val = 0x00000B78;
+       k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x02 << 2), val);
+
+       // force rcv done
+       val = k1x_pcie_phy_reg_readl(k1x, (0x06 << 2));
+       val = 0x00000400;
+       k1x_pcie_phy_reg_writel(k1x, (0x06 << 2), val);
+
+       // force rcv done
+       val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x06 << 2));
+       val = 0x00000400;
+       k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x06 << 2), val);
+
+       // waiting pll lock
+       printk("waiting pll lock...\n");
+       do
+       {
+               rd_data = k1x_pcie_phy_reg_readl(k1x, 0x8);
+       } while ((rd_data & 0x1) == 0);
+
+       if (k1x->port_id == 0)
+               porta_init_done = 0x1;
+       printk("Now finish init_puphy....\n");
+       return 0;
+}
+
+/**
+ * pcie_dw_k1x_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int pcie_dw_k1x_probe(struct udevice *dev)
+{
+       struct pcie_dw_k1x *pci = dev_get_priv(dev);
+       struct udevice *ctlr = pci_get_controller(dev);
+       struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+       struct phy phy0, phy1;
+       int ret;
+       u32 reg;
+
+       printf("%s, %d\n", __FUNCTION__, __LINE__);
+
+       /* enable pcie clk */
+       clk_enable(&pci->clock);
+       reset_deassert(&pci->reset);
+
+       reg = k1x_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+       reg &= ~LTSSM_EN;
+       k1x_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+       /* set Perst# (fundamental reset) gpio low state*/
+       reg = k1x_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD);
+       reg |= PCIE_RC_PERST;
+       k1x_pcie_writel(pci, PCIECTRL_K1X_CONF_DEVICE_CMD, reg);
+
+       init_phy(pci);
+
+       ret = generic_phy_get_by_name(dev,  "pcie-phy0", &phy0);
+       if (ret) {
+               dev_err(dev, "Unable to get phy0");
+       } else {
+               generic_phy_reset(&phy0);
+               generic_phy_init(&phy0);
+               generic_phy_power_on(&phy0);
+       }
+
+       ret = generic_phy_get_by_name(dev,  "pcie-phy1", &phy1);
+       if (ret) {
+               dev_err(dev, "Unable to get phy1");
+       } else {
+               generic_phy_reset(&phy1);
+               generic_phy_init(&phy1);
+               generic_phy_power_on(&phy1);
+       }
+
+       pci->dw.first_busno = dev_seq(dev);
+       pci->dw.dev = dev;
+
+       pcie_set_mode(pci, DW_PCIE_RC_TYPE);
+
+       k1x_pcie_host_init(pci);
+       pcie_dw_setup_host(&pci->dw);
+
+       if (!pcie_dw_k1x_pcie_link_up(pci, LINK_SPEED_GEN_2)) {
+               printf("PCIE-%d: Link down\n", dev_seq(dev));
+               return -ENODEV;
+       }
+
+       printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
+              pcie_dw_get_link_speed(&pci->dw),
+              pcie_dw_get_link_width(&pci->dw),
+              hose->first_busno);
+
+       ret = pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0,
+                                        PCIE_ATU_TYPE_MEM,
+                                        pci->dw.mem.phys_start,
+                                        pci->dw.mem.bus_start, pci->dw.mem.size);
+       return 0;
+}
+
+/**
+ * pcie_dw_k1x_of_to_plat() - Translate from DT to device state
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pcie_dw_k1x_of_to_plat(struct udevice *dev)
+{
+       int ret = 0;
+       struct pcie_dw_k1x *pcie = dev_get_priv(dev);
+
+       /* Get the controller base address */
+       pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi");
+       if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the config space base address and size */
+       pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+                                                        &pcie->dw.cfg_size);
+       if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the iATU base address and size */
+       pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+       if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the app base address */
+       pcie->phy_ahb = (void *)dev_read_addr_name(dev, "phy_ahb");
+       if ((fdt_addr_t)pcie->phy_ahb == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the PMU base address */
+       pcie->base = (void *)dev_read_addr_name(dev, "k1x_conf");
+       if ((fdt_addr_t)pcie->base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the phy base address and size */
+       pcie->phy_addr = (void *)dev_read_addr_name(dev, "phy_addr");
+       if ((fdt_addr_t)pcie->phy_addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the pcie0 conf base address */
+       pcie->conf0_addr = (void *)dev_read_addr_name(dev, "conf0_addr");
+       if ((fdt_addr_t)pcie->conf0_addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the pcie0 phy base address and size */
+       pcie->phy0_addr = (void *)dev_read_addr_name(dev, "phy0_addr");
+       if ((fdt_addr_t)pcie->phy0_addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       ret = dev_read_u32(dev, "k1x,pcie-port", &pcie->port_id);
+       if (ret)
+               return ret;
+
+       ret = clk_get_by_index(dev, 0, &pcie->clock);
+       if (ret) {
+               dev_warn(dev, "It has no clk: %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = reset_get_by_index(dev, 0, &pcie->reset);
+       if (ret) {
+               dev_warn(dev, "It has no reset: %d\n", ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct dm_pci_ops pcie_dw_k1x_ops = {
+       .read_config    = pcie_dw_read_config,
+       .write_config   = pcie_dw_write_config,
+};
+
+static const struct udevice_id pcie_dw_k1x_ids[] = {
+       { .compatible = "k1x,dwc-pcie" },
+       { }
+};
+
+U_BOOT_DRIVER(pcie_dw_k1x) = {
+       .name                   = "pcie_dw_k1x",
+       .id                     = UCLASS_PCI,
+       .of_match               = pcie_dw_k1x_ids,
+       .ops                    = &pcie_dw_k1x_ops,
+       .of_to_plat     = pcie_dw_k1x_of_to_plat,
+       .probe                  = pcie_dw_k1x_probe,
+       .priv_auto      = sizeof(struct pcie_dw_k1x),
+};
index c25b42c68f52718cb3154f9e2f9f817d73be79a2..1b24ef5a9ca67f1a88a4c935eb3c469672ddc407 100644 (file)
@@ -298,5 +298,6 @@ config PHY_XILINX_ZYNQMP
 source "drivers/phy/rockchip/Kconfig"
 source "drivers/phy/cadence/Kconfig"
 source "drivers/phy/ti/Kconfig"
+source "drivers/phy/spacemit/Kconfig"
 
 endmenu
index d95439c4257b7cb41abf4c55078444477ed28699..a9e259c62217cd27c739016f7b6d6ed34be2c72f 100644 (file)
@@ -7,6 +7,7 @@ obj-y += allwinner/
 obj-y += marvell/
 obj-y += rockchip/
 obj-y += socionext/
+obj-y += spacemit/
 
 obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
 obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
new file mode 100644 (file)
index 0000000..55a2a16
--- /dev/null
@@ -0,0 +1,23 @@
+config PHY_SPACEMIT_K1X_USB2
+       bool "Spacemit k1-x USB2 PHY Driver"
+       depends on PHY
+       help
+         Support for Spacemit k1-x USB 2 PHY
+
+config SPL_PHY_SPACEMIT_K1X_USB2
+       bool "Spacemit k1-x USB2 PHY Driver in SPL"
+       depends on PHY
+       help
+         Support for Spacemit k1-x USB 2 PHY
+
+config PHY_SPACEMIT_K1X_COMBPHY
+       tristate "Spacemit K1-x USB3&PCIE combo PHY driver"
+       depends on PHY
+       help
+         USB3 and PCIE Combo PHY Support for Spacemit k1-x Soc
+
+config SPL_PHY_SPACEMIT_K1X_COMBPHY
+       tristate "Spacemit K1-x USB3&PCIE combo PHY driver in SPL"
+       depends on PHY
+       help
+         USB3 and PCIE Combo PHY Support for Spacemit k1-x Soc
diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
new file mode 100644 (file)
index 0000000..df85048
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Phy supports for Spacemit k1x SoCs
+#
+
+obj-$(CONFIG_$(SPL_)PHY_SPACEMIT_K1X_USB2)     += k1x-usb2-ci-phy.o
+obj-$(CONFIG_$(SPL_)PHY_SPACEMIT_K1X_COMBPHY)  += k1x-combphy.o
diff --git a/drivers/phy/spacemit/k1x-combphy.c b/drivers/phy/spacemit/k1x-combphy.c
new file mode 100644 (file)
index 0000000..161b0b3
--- /dev/null
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-spacemit-k1x-combphy.c - Spacemit k1-x combo PHY for USB3 and PCIE
+ *
+ * Copyright (c) 2023 Spacemit Co., Ltd.
+ *
+ */
+#include <common.h>
+#include <reset.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <dt-bindings/phy/phy.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+
+#define SPACEMIT_COMBPHY_WAIT_TIMEOUT 1000
+#define SPACEMIT_COMBPHY_MODE_SEL BIT(3)
+
+// Registers for USB3 PHY
+#define SPACEMIT_COMBPHY_USB_REG1 0x68
+#define SPACEMIT_COMBPHY_USB_REG1_VAL 0x0
+#define SPACEMIT_COMBPHY_USB_REG2 (0x12 << 2)
+#define SPACEMIT_COMBPHY_USB_REG2_VAL 0x603a2276
+#define SPACEMIT_COMBPHY_USB_REG3 (0x02 << 2)
+#define SPACEMIT_COMBPHY_USB_REG3_VAL 0x97c
+#define SPACEMIT_COMBPHY_USB_REG4 (0x06 << 2)
+#define SPACEMIT_COMBPHY_USB_REG4_VAL 0x0
+#define SPACEMIT_COMBPHY_USB_PLL_REG 0x8
+#define SPACEMIT_COMBPHY_USB_PLL_MASK 0x1
+#define SPACEMIT_COMBPHY_USB_PLL_VAL 0x1
+
+struct spacemit_combphy_priv {
+       struct udevice *dev;
+       struct reset_ctl_bulk phy_rst;
+       void __iomem *phy_sel;
+       void __iomem *puphy_base;
+       struct phy *phy;
+       u8 type;
+};
+
+static inline void spacemit_reg_updatel(void __iomem *reg, u32 offset, u32 mask, u32 val)
+{
+       u32 tmp;
+       tmp = readl(reg + offset);
+       tmp = (tmp & ~(mask)) | val;
+       writel(tmp, reg + offset);
+}
+
+static int spacemit_combphy_wait_ready(struct spacemit_combphy_priv *priv,
+                                          u32 offset, u32 mask, u32 val)
+{
+       int timeout = SPACEMIT_COMBPHY_WAIT_TIMEOUT;
+       while (((readl(priv->puphy_base + offset) & mask) != val) && --timeout)
+               ;
+       if (!timeout) {
+               return -ETIMEDOUT;
+       }
+       dev_dbg(priv->dev, "phy init timeout remain: %d", timeout);
+       return 0;
+}
+
+static int spacemit_combphy_set_mode(struct spacemit_combphy_priv *priv)
+{
+       u8 mode = priv->type;
+       if (mode == PHY_TYPE_USB3) {
+               spacemit_reg_updatel(priv->phy_sel, 0, 0,
+                                        SPACEMIT_COMBPHY_MODE_SEL);
+       } else {
+               dev_err(priv->dev, "PHY type %x not supported\n", mode);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int spacemit_combphy_init_usb(struct spacemit_combphy_priv *priv)
+{
+       int ret;
+       void __iomem *base = priv->puphy_base;
+       dev_info(priv->dev, "USB3 PHY init.\n");
+
+       writel(SPACEMIT_COMBPHY_USB_REG1_VAL, base + SPACEMIT_COMBPHY_USB_REG1);
+       writel(SPACEMIT_COMBPHY_USB_REG2_VAL, base + SPACEMIT_COMBPHY_USB_REG2);
+       writel(SPACEMIT_COMBPHY_USB_REG3_VAL, base + SPACEMIT_COMBPHY_USB_REG3);
+       writel(SPACEMIT_COMBPHY_USB_REG4_VAL, base + SPACEMIT_COMBPHY_USB_REG4);
+
+       ret = spacemit_combphy_wait_ready(priv, SPACEMIT_COMBPHY_USB_PLL_REG,
+                                         SPACEMIT_COMBPHY_USB_PLL_MASK,
+                                         SPACEMIT_COMBPHY_USB_PLL_VAL);
+
+       if (ret)
+               dev_err(priv->dev, "USB3 PHY init timeout!\n");
+
+       return ret;
+}
+
+
+static int spacemit_combphy_init(struct phy *phy)
+{
+       struct spacemit_combphy_priv *priv = dev_get_priv(phy->dev);
+       int ret;
+
+       ret = spacemit_combphy_set_mode(priv);
+
+       if (ret) {
+               dev_err(priv->dev, "failed to set mode for PHY type %x\n",
+                       priv->type);
+               goto out;
+       }
+
+       ret = reset_deassert_bulk(&priv->phy_rst);
+       if (ret) {
+               dev_err(priv->dev, "failed to deassert rst\n");
+               goto out;
+       }
+
+       switch (priv->type) {
+       case PHY_TYPE_USB3:
+               ret = spacemit_combphy_init_usb(priv);
+               break;
+       default:
+               dev_err(priv->dev, "PHY type %x not supported\n", priv->type);
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret)
+               goto err_rst;
+
+       return 0;
+
+err_rst:
+       reset_assert_bulk(&priv->phy_rst);
+out:
+       return ret;
+}
+
+static int spacemit_combphy_exit(struct phy *phy)
+{
+       struct spacemit_combphy_priv *priv =  dev_get_priv(phy->dev);
+
+       reset_assert_bulk(&priv->phy_rst);
+
+       return 0;
+}
+
+static int spacemit_combphy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+       struct spacemit_combphy_priv *priv =  dev_get_priv(phy->dev);
+
+       if (args->args_count != 1) {
+               dev_err(phy->dev, "invalid number of arguments\n");
+               return -EINVAL;
+       }
+
+       if (priv->type != PHY_NONE && priv->type != args->args[0])
+               dev_warn(phy->dev, "PHY type %d is selected to override %d\n",
+                        args->args[0], priv->type);
+
+       priv->type = args->args[0];
+
+       return 0;
+}
+
+static int spacemit_combphy_probe(struct udevice *dev)
+{
+       struct spacemit_combphy_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       if (!priv)
+               return -ENOMEM;
+
+       priv->puphy_base = (void*)dev_read_addr_name(dev, "puphy");
+       if (IS_ERR(priv->puphy_base)) {
+               ret = PTR_ERR(priv->puphy_base);
+               return ret;
+       }
+
+       priv->phy_sel = (void*)dev_read_addr_name(dev, "phy_sel");
+       if (IS_ERR(priv->phy_sel)) {
+               ret = PTR_ERR(priv->phy_sel);
+               return ret;
+       }
+
+       priv->dev = dev;
+       priv->type = PHY_NONE;
+
+       ret = reset_get_bulk(dev, &priv->phy_rst);
+       if (ret && ret != -ENOENT) {
+               dev_err(dev, "Failed to get resets (err=%d)\n", ret);
+               return ret;
+       }
+
+       ret = reset_assert_bulk(&priv->phy_rst);
+       if (ret) {
+               dev_err(dev, "failed to reset phy\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct udevice_id spacemit_combphy_ids[] = {
+       {.compatible = "spacemit,k1x-combphy",},
+       { /* sentinel */ }
+};
+
+static struct phy_ops spacemit_combphy_ops = {
+       .init = spacemit_combphy_init,
+       .exit = spacemit_combphy_exit,
+       .of_xlate = spacemit_combphy_xlate,
+};
+
+U_BOOT_DRIVER(k1x_combphy) = {
+       .name   = "k1x_combphy",
+       .id     = UCLASS_PHY,
+       .of_match = spacemit_combphy_ids,
+       .ops = &spacemit_combphy_ops,
+       .probe = spacemit_combphy_probe,
+       .priv_auto      = sizeof(struct spacemit_combphy_priv),
+};
\ No newline at end of file
diff --git a/drivers/phy/spacemit/k1x-usb2-ci-phy.c b/drivers/phy/spacemit/k1x-usb2-ci-phy.c
new file mode 100644 (file)
index 0000000..17949ce
--- /dev/null
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * USB2.0 Phy for Spacemit k1x SoCs
+ *
+ * Copyright (c) 2023 Spacemit Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#define PHY_28LP       0x2800
+#define PHY_40LP       0x4000
+#define PHY_55LP       0x5500
+
+#define MV_PHY_FLAG_PLL_LOCK_BYPASS    (1 << 0)
+
+#define USB2_PHY_REG01                 0x4
+#define USB2_PHY_REG01_PLL_IS_READY    (0x1 << 0)
+#define USB2_PHY_REG04                 0x10
+#define USB2_PHY_REG04_EN_HSTSOF       (0x1 << 0)
+#define USB2_PHY_REG04_AUTO_CLEAR_DIS  (0x1 << 2)
+#define USB2_PHY_REG08                 0x20
+#define USB2_PHY_REG08_DISCON_DET      (0x1 << 9)
+#define USB2_PHY_REG0D                 0x34
+#define USB2_PHY_REG26                 0x98
+#define USB2_PHY_REG22                 0x88
+#define USB2_CFG_FORCE_CDRCLK          (0x1 << 6)
+#define USB2_PHY_REG06                 0x18
+#define USB2_CFG_HS_SRC_SEL            (0x1 << 0)
+
+#define USB2D_CTRL_RESET_TIME_MS       50
+
+struct mv_usb_phy_priv {
+       void __iomem            *phy_base;
+};
+
+static int mv_usb_phy_init(struct phy *phy)
+{
+       struct mv_usb_phy_priv *priv = dev_get_priv(phy->dev);
+       void __iomem *base = priv->phy_base;
+       uint32_t loops, temp;
+
+       // make sure the usb controller is not under reset process before any configuration
+       udelay(50);
+       writel(0xbec4, base + USB2_PHY_REG26); //24M ref clk
+       udelay(150);
+
+       loops = USB2D_CTRL_RESET_TIME_MS * 1000;
+
+       //wait for usb2 phy PLL ready
+       do {
+               temp = readl(base + USB2_PHY_REG01);
+               if (temp & USB2_PHY_REG01_PLL_IS_READY)
+                       break;
+               udelay(50);
+       } while(--loops);
+
+       if (loops == 0)
+               dev_err(phy->dev, "Wait PHY_REG01[PLLREADY] timeout\n");
+
+       //release usb2 phy internal reset and enable clock gating
+       writel(0x60ef, base + USB2_PHY_REG01);
+       writel(0x1c, base + USB2_PHY_REG0D);
+
+       //select HS parallel data path
+       temp = readl(base + USB2_PHY_REG06);
+       // temp |= USB2_CFG_HS_SRC_SEL;
+       temp &= ~(USB2_CFG_HS_SRC_SEL);
+       writel(temp, base + USB2_PHY_REG06);
+
+       /* auto clear host disc*/
+       temp = readl(base + USB2_PHY_REG04);
+       temp |= USB2_PHY_REG04_AUTO_CLEAR_DIS;
+       writel(temp, base + USB2_PHY_REG04);
+
+       return 0;
+}
+
+static int mv_usb_phy_exit(struct phy *phy)
+{
+       return 0;
+}
+
+static int mv_usb_phy_power_on(struct phy *phy)
+{
+       return 0;
+}
+
+static int mv_usb_phy_power_off(struct phy *phy)
+{
+       return 0;
+}
+
+static int mv_usb_phy_probe(struct udevice *dev)
+{
+       struct mv_usb_phy_priv *priv = dev_get_priv(dev);
+       dev_info(dev, "k1x-ci-usb-phy-probe: Enter...\n");
+       priv->phy_base = (void*)dev_read_addr(dev);
+       if (priv->phy_base == NULL){
+               dev_err(dev, "cannot get phy base addr");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static const struct udevice_id mv_usb_phy_ids[] = {
+       {.compatible = "spacemit,usb2-phy",},
+       { /* sentinel */ }
+};
+
+static struct phy_ops mv_usb_phy_ops = {
+       .init = mv_usb_phy_init,
+       .exit = mv_usb_phy_exit,
+       .power_on = mv_usb_phy_power_on,
+       .power_off = mv_usb_phy_power_off,
+};
+
+U_BOOT_DRIVER(mv_usb_phy) = {
+       .name   = "mv_usb_phy",
+       .id     = UCLASS_PHY,
+       .of_match = mv_usb_phy_ids,
+       .ops = &mv_usb_phy_ops,
+       .probe = mv_usb_phy_probe,
+       .priv_auto      = sizeof(struct mv_usb_phy_priv),
+};
index b6ef2acced2d9b7bd95cd418209975f4944f4294..6e7bdf0c7fee5d0c13df0a4a23a6011fafb69a1c 100644 (file)
@@ -357,6 +357,7 @@ source "drivers/pinctrl/nuvoton/Kconfig"
 source "drivers/pinctrl/nxp/Kconfig"
 source "drivers/pinctrl/renesas/Kconfig"
 source "drivers/pinctrl/rockchip/Kconfig"
+source "drivers/pinctrl/spacemit/Kconfig"
 source "drivers/pinctrl/sunxi/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 
index 3b167d099fcae23915eeb8aec22c2a3cb52dc1b5..d7d7cd9de1fd5dcac11471751f52c15024904b21 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
 obj-$(CONFIG_ARCH_NPCM)         += nuvoton/
 obj-$(CONFIG_ARCH_RMOBILE) += renesas/
 obj-$(CONFIG_PINCTRL_SANDBOX)  += pinctrl-sandbox.o
+obj-$(CONFIG_PINCTRL_SPACEMIT) += spacemit/
 obj-$(CONFIG_PINCTRL_SUNXI)    += sunxi/
 obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
 obj-$(CONFIG_PINCTRL_PIC32)    += pinctrl_pic32.o
index bc9c17bce848f481bd47ec0cdc356c2484bb4858..af492705714f90d7b4c345f74af561878eeefd31 100644 (file)
@@ -103,14 +103,14 @@ static unsigned int single_read(struct udevice *dev, fdt_addr_t reg)
 
        switch (pdata->width) {
        case 8:
-               return readb(reg);
+               return readb((void *)reg);
        case 16:
-               return readw(reg);
+               return readw((void *)reg);
        default: /* 32 bits */
-               return readl(reg);
+               return readl((void *)reg);
        }
 
-       return readb(reg);
+       return readb((void *)reg);
 }
 
 static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg)
@@ -119,13 +119,13 @@ static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg)
 
        switch (pdata->width) {
        case 8:
-               writeb(val, reg);
+               writeb(val, (void *)reg);
                break;
        case 16:
-               writew(val, reg);
+               writew(val, (void *)reg);
                break;
        default: /* 32 bits */
-               writel(val, reg);
+               writel(val, (void *)reg);
        }
 }
 
diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig
new file mode 100644 (file)
index 0000000..dff2944
--- /dev/null
@@ -0,0 +1,10 @@
+config PINCTRL_SPACEMIT
+       bool
+
+config PINCTRL_K1PRO
+       bool "Spacemit K1PRO pinctrl driver"
+       depends on TARGET_SPACEMIT_K1PRO && PINCTRL_FULL
+       select DEVRES
+       select PINCTRL_SPACEMIT
+       help
+         Say Y here to enable the k1-pro pinctrl driver
diff --git a/drivers/pinctrl/spacemit/Makefile b/drivers/pinctrl/spacemit/Makefile
new file mode 100644 (file)
index 0000000..d115567
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_SPACEMIT)         += pinctrl-spacemit.o
+obj-$(CONFIG_PINCTRL_K1PRO)            += pinctrl-k1pro.o
diff --git a/drivers/pinctrl/spacemit/pinctrl-spacemit.c b/drivers/pinctrl/spacemit/pinctrl-spacemit.c
new file mode 100644 (file)
index 0000000..2394975
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ */
+#include <common.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <reset.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+
+#include "pinctrl-spacemit.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int spacemit_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+       struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+       struct spacemit_pinctrl_soc_info *info = priv->info;
+       const struct spacemit_regs *regs = info->regs;
+       const struct spacemit_pin_conf *pin_conf = info->pinconf;
+       int node = dev_of_offset(config);
+       const struct fdt_property *prop;
+       u32 *pin_data;
+       int npins, size, pin_size;
+       u32 pin_id, mux_sel, pull_val, drv_strength;
+       u8 bank;
+       u16 offset;
+       u32 fs, od, pull_en, pull, ds, st, rte;
+       u64 reg;
+       int i, j = 0;
+
+       dev_dbg(dev, "%s: %s\n", __func__, config->name);
+       pin_size = SPACEMIT_PIN_SIZE;
+
+       prop = fdt_getprop(gd->fdt_blob, node, "spacemit,pins", &size);
+       if (!prop) {
+               dev_err(dev, "No spacemit,pins property in node %s\n", config->name);
+               return -EINVAL;
+       }
+
+       if (!size || size % pin_size) {
+               dev_err(dev, "Invalid spacemit,pins property in node %s\n",
+                       config->name);
+               return -EINVAL;
+       }
+
+       pin_data = devm_kzalloc(dev, size, 0);
+       if (!pin_data)
+               return -ENOMEM;
+
+       if (fdtdec_get_int_array(gd->fdt_blob, node, "spacemit,pins",
+                                pin_data, size >> 2)) {
+               dev_err(dev, "Error reading pin data.\n");
+               devm_kfree(dev, pin_data);
+               return -EINVAL;
+       }
+
+       npins = size / pin_size;
+
+       /*
+        * set pin config to pinctrl reg
+        */
+       for (i = 0; i < npins; i++) {
+               volatile long mux_config;
+
+               pin_id = pin_data[j++];
+               mux_sel = pin_data[j++];
+               pull_val = pin_data[j++];
+               drv_strength = pin_data[j++];
+
+               dev_dbg(dev, "pin_id 0x%x, mux_sel 0x%x, \
+                       pull_val 0x%x, drv_strength 0x%x\n",
+                       pin_id, mux_sel, pull_val, drv_strength);
+
+               bank = PINID_TO_BANK(pin_id);
+               offset = PINID_TO_PIN(pin_id);
+               reg = (u64)info->base + (u64)regs->cfg;
+               reg += bank * regs->reg_len + offset * 4;
+
+               fs = mux_sel << pin_conf->fs_shift;
+               od =  OD_DIS << pin_conf->od_shift;
+               pull_en = PE_EN << pin_conf->pe_shift;
+               pull = pull_val << pin_conf->pull_shift;
+               ds = drv_strength << pin_conf->ds_shift;
+               st = ST_DIS << pin_conf->st_shift;
+               rte = RTE_EN << pin_conf->rte_shift;
+
+               mux_config = (fs | od | pull_en | pull | ds | st | rte);
+               writel(mux_config, (void __iomem *)reg);
+               dev_dbg(dev, "write: bank %d 0ffset %d val 0x%lx\n",
+                       bank, offset, mux_config);
+       }
+
+       devm_kfree(dev, pin_data);
+
+       return 0;
+}
+
+const struct pinctrl_ops spacemit_pinctrl_ops  = {
+       .set_state = spacemit_pinctrl_set_state,
+};
+
+int spacemit_pinctrl_probe(struct udevice *dev,
+               struct spacemit_pinctrl_soc_info *info)
+{
+       struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+       fdt_addr_t addr;
+       fdt_size_t size;
+
+       if (!info) {
+               dev_err(dev, "wrong pinctrl info\n");
+               return -EINVAL;
+       }
+
+       priv->dev = dev;
+       priv->info = info;
+
+       addr = devfdt_get_addr_size_index(dev, 0, &size);
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       info->base = map_sysmem(addr, size);
+       if (!info->base)
+               return -ENOMEM;
+       priv->info = info;
+
+       info->rstc = devm_reset_control_get_by_index(dev, 0);
+       if (IS_ERR(info->rstc)) {
+               dev_warn(dev, "get optional reset failed\n");
+               return -EINVAL;
+       }
+       reset_deassert(info->rstc);
+
+       dev_dbg(dev, "initialized spacemit pinctrl driver\n");
+
+       return 0;
+}
+
+int spacemit_pinctrl_remove(struct udevice *dev)
+{
+       struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+       struct spacemit_pinctrl_soc_info *info = priv->info;
+
+       reset_assert(info->rstc);
+       if (info->base)
+               unmap_sysmem(info->base);
+
+       return 0;
+}
diff --git a/drivers/pinctrl/spacemit/pinctrl-spacemit.h b/drivers/pinctrl/spacemit/pinctrl-spacemit.h
new file mode 100644 (file)
index 0000000..16c2edc
--- /dev/null
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ */
+#ifndef __DRIVERS_PINCTRL_SPACEMIT_H
+#define __DRIVERS_PINCTRL_SPACEMIT_H
+
+#define PINID_TO_BANK(p)       ((p) >> 5)
+#define PINID_TO_PIN(p)                ((p) % 32)
+
+/*
+ * pin config bit field definitions
+ *
+ * od: open drain
+ * pe:  pull enable
+ * st: schmit trigger
+ * rte:        retention signal bus
+ *
+ * MSB of each field is presence bit for the config.
+ */
+#define OD_EN          1
+#define OD_DIS         0
+#define PE_EN          1
+#define PE_DIS         0
+#define ST_EN          1
+#define ST_DIS         0
+#define RTE_EN         1
+#define RTE_DIS                0
+
+/*
+ * Each pin represented in spacemit,pins consists:
+ * - u32 PIN_FUNC_ID
+ * - u32 pin muxsel
+ * - u32 pin pull_up/down
+ * - u32 pin driving strength
+ */
+#define SPACEMIT_PIN_SIZE 16
+
+struct spacemit_regs {
+       u16 cfg;
+       u16 reg_len;
+};
+
+struct spacemit_pin_conf {
+       u8  fs_shift;
+       u8  od_shift;
+       u8  pe_shift;
+       u8  pull_shift;
+       u8  ds_shift;
+       u8  st_shift;
+       u8  rte_shift;
+};
+
+/**
+ * @base: the address to the controller in virtual memory
+ * @rstc: reset signal handle.
+ */
+struct spacemit_pinctrl_soc_info {
+       const struct spacemit_regs *regs;
+       const struct spacemit_pin_conf *pinconf;
+       void __iomem *base;
+       struct reset_ctl *rstc;
+};
+
+/**
+ * @dev: a pointer back to containing device
+ * @info: the soc info
+ */
+struct spacemit_pinctrl_priv {
+       struct udevice *dev;
+       struct spacemit_pinctrl_soc_info *info;
+};
+
+extern const struct pinctrl_ops spacemit_pinctrl_ops;
+
+int spacemit_pinctrl_probe(struct udevice *dev,
+               struct spacemit_pinctrl_soc_info *info);
+int spacemit_pinctrl_remove(struct udevice *dev);
+
+#endif /* __DRIVERS_PINCTRL_SPACEMIT_H */
index bc47cf144dd0885f8c31c64e470d8cb45d101b37..0d34296f8ebd3ef20bb03cd8df638589cf20af27 100644 (file)
@@ -452,3 +452,15 @@ config SPL_POWER_I2C
          the new PMIC interface based on driver model.
 
 endif
+
+if SPL_POWER
+
+config SPL_SPACEMIT_POWER
+       bool "Power support in SPL for SPM8XX"
+       depends on SPL
+       help
+         Note: This is a legacy option. Use SPL_DM_PMIC instead.
+
+         Enable support for power control in SPL for SPM8XX PMICs.
+
+endif
index f805027784db39ffcd9017385e4a02976b60c6cb..8f4a127d87fecd8fd23e9ba008132445053b0044 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o
 obj-$(CONFIG_$(SPL_TPL_)POWER_I2C) += power_i2c.o
 obj-$(CONFIG_POWER_SPI) += power_spi.o
 obj-$(CONFIG_POWER_MT6323) += mt6323.o
+obj-$(CONFIG_$(SPL_)SPACEMIT_POWER) += power_spm8xx.o
index 7e1b8c072fa271f0399c0f9a6dbcd08001b07fa9..6e90bf203dff49982b2d45ae3210e01ebeec5a16 100644 (file)
@@ -105,4 +105,9 @@ config ZYNQMP_POWER_DOMAIN
          configuration and it is extended at run time. Then enabling
          the driver will ensure that PMUFW enable access to requested IP.
 
+config K1X_POWER_DOMAIN
+       bool "Enable the K1X Power domain driver"
+       depends on POWER_DOMAIN
+       help
+         Generic power domain implementation for K1X devices.
 endmenu
index e6244776216da97fca4ad2f1bb4ddf6ac4f642a0..3d365b79a648912417b70a61b9052ecf29538c33 100644 (file)
@@ -18,3 +18,4 @@ obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
 obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
 obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
 obj-$(CONFIG_ZYNQMP_POWER_DOMAIN) += zynqmp-power-domain.o
+obj-$(CONFIG_K1X_POWER_DOMAIN) += k1x-power-domain.o 
diff --git a/drivers/power/domain/k1x-power-domain.c b/drivers/power/domain/k1x-power-domain.c
new file mode 100644 (file)
index 0000000..1cfeed2
--- /dev/null
@@ -0,0 +1,331 @@
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <power-domain-uclass.h>
+
+#define MAX_REGMAP              5
+
+#define MPMU_REGMAP_INDEX       0
+#define APMU_REGMAP_INDEX       1
+
+#define APMU_POWER_STATUS_REG   0xf0
+
+enum pm_domain_id {
+       K1X_PMU_VPU_PWR_DOMAIN,
+       K1X_PMU_GPU_PWR_DOMAIN,
+       K1X_PMU_LCD_PWR_DOMAIN,
+       K1X_PMU_ISP_PWR_DOMAIN,
+       K1X_PMU_AUD_PWR_DOMAIN,
+       K1X_PMU_GNSS_PWR_DOMAIN,
+       K1X_PMU_HDMI_PWR_DOMAIN,
+};
+
+struct pm_domain_desc {
+       int reg_pwr_ctrl;
+       int pm_qos;
+       int bit_hw_mode;
+       int bit_sleep2;
+       int bit_sleep1;
+       int bit_isolation;
+       int bit_auto_pwr_on;
+       int bit_hw_pwr_stat;
+       int bit_pwr_stat;
+       int use_hw;
+       int pm_index;
+};
+
+struct spacemit_k1x_pd_platdata {
+       struct regmap *regmap[MAX_REGMAP];
+       struct pm_domain_desc *desc;
+};
+
+static struct pm_domain_desc k1x_pm_domain_desc[] = {
+       [K1X_PMU_VPU_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0xa8,
+               .pm_qos = 12,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_pwr_stat = 1,
+               .bit_hw_pwr_stat = 9,
+               .pm_index = K1X_PMU_VPU_PWR_DOMAIN,
+       },
+
+       [K1X_PMU_GPU_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0xd0,
+               .pm_qos = 12,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_pwr_stat = 0,
+               .pm_index = K1X_PMU_GPU_PWR_DOMAIN,
+       },
+
+       [K1X_PMU_LCD_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0x380,
+               .pm_qos = 12,
+               .bit_hw_mode = 4,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_auto_pwr_on = 0,
+               .bit_pwr_stat = 4,
+               .bit_hw_pwr_stat = 12,
+               .use_hw = 1,
+               .pm_index = K1X_PMU_LCD_PWR_DOMAIN,
+       },
+
+       [K1X_PMU_ISP_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0x37c,
+               .pm_qos = 12,
+               .bit_hw_mode = 4,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_auto_pwr_on = 0,
+               .bit_pwr_stat = 2,
+               .bit_hw_pwr_stat = 10,
+               .pm_index = K1X_PMU_ISP_PWR_DOMAIN,
+       },
+
+       [K1X_PMU_AUD_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0x378,
+               .pm_qos = 15,
+               .bit_hw_mode = 4,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_auto_pwr_on = 0,
+               .bit_pwr_stat = 3,
+               .bit_hw_pwr_stat = 11,
+               .use_hw = 1,
+               .pm_index = K1X_PMU_AUD_PWR_DOMAIN,
+       },
+
+       [K1X_PMU_GNSS_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0x13c,
+               .pm_qos = 15,
+               .bit_hw_mode = 4,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_auto_pwr_on = 0,
+               .bit_pwr_stat = 6,
+               .bit_hw_pwr_stat = 14,
+               .pm_index = K1X_PMU_GNSS_PWR_DOMAIN,
+       },
+
+       [K1X_PMU_HDMI_PWR_DOMAIN] = {
+               .reg_pwr_ctrl = 0x3f4,
+               .pm_qos = 12,
+               .bit_hw_mode = 4,
+               .bit_sleep2 = 3,
+               .bit_sleep1 = 2,
+               .bit_isolation = 1,
+               .bit_auto_pwr_on = 0,
+               .bit_pwr_stat = 7,
+               .bit_hw_pwr_stat = 15,
+               .use_hw = 1,
+               .pm_index = K1X_PMU_HDMI_PWR_DOMAIN,
+       },
+};
+
+static const struct udevice_id spacemit_power_domain_of_match[] = {
+       { .compatible = "spacemit,k1x-pm-domain", .data = (ulong)k1x_pm_domain_desc, },
+       { /* sentinel */ }
+};
+
+static int spacemit_power_domain_of_xlate(struct power_domain *pd, struct ofnode_phandle_args *args)
+{
+       struct spacemit_k1x_pd_platdata *priv = dev_get_priv(pd->dev);
+
+       debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
+
+       if (args->args_count < 1) {
+               printf("Invalid args_count: %d\n", args->args_count);
+               return -EINVAL;
+       }
+
+       pd->priv = (void *)(priv->desc + args->args[0]);
+       pd->id = args->args[0];
+
+       return 0;
+}
+
+static int k1x_pd_power_off(struct spacemit_k1x_pd_platdata *skp, struct pm_domain_desc *desc)
+{
+       unsigned int val;
+       int loop;
+
+       if (!desc->use_hw) {
+               /* this is the sw type */
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val &= ~(1 << desc->bit_isolation);
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(15);
+
+               /* mcu power off */
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val &= ~((1 << desc->bit_sleep1) | (1 << desc->bit_sleep2));
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(15);
+
+               for (loop = 10000; loop >= 0; --loop) {
+                       regmap_read(skp->regmap[APMU_REGMAP_INDEX], APMU_POWER_STATUS_REG, &val);
+                       if ((val & (1 << desc->bit_pwr_stat)) == 0)
+                               break;
+                       udelay(5);
+               }
+       } else {
+               /* LCD */
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val &= ~(1 << desc->bit_auto_pwr_on);
+               val &= ~(1 << desc->bit_hw_mode);
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(30);
+
+               for (loop = 10000; loop >= 0; --loop) {
+                       regmap_read(skp->regmap[APMU_REGMAP_INDEX], APMU_POWER_STATUS_REG, &val);
+                       if ((val & (1 << desc->bit_hw_pwr_stat)) == 0)
+                               break;
+                       udelay(5);
+               }
+       }
+
+       if (loop < 0) {
+               debug("power-off domain: %d, error\n", desc->pm_index);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int k1x_pd_power_on(struct spacemit_k1x_pd_platdata *skp, struct pm_domain_desc *desc)
+{
+       int loop;
+       unsigned int val;
+
+       regmap_read(skp->regmap[APMU_REGMAP_INDEX], APMU_POWER_STATUS_REG, &val);
+       if (val & (1 << desc->bit_pwr_stat))
+               return 0;
+
+       if (!desc->use_hw) {
+               /* mcu power on */
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val |= (1 << desc->bit_sleep1);
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(25);
+
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val |= (1 << desc->bit_sleep2) | (1 << desc->bit_sleep1);
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(25);
+
+               /* disable isolation */
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val |= (1 << desc->bit_isolation);
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(15);
+
+               for (loop = 10000; loop >= 0; --loop) {
+                       regmap_read(skp->regmap[APMU_REGMAP_INDEX], APMU_POWER_STATUS_REG, &val);
+                       if (val & (1 << desc->bit_pwr_stat))
+                               break;
+                       udelay(6);
+               }
+       } else {
+               /* LCD */
+               regmap_read(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, &val);
+               val |= (1 << desc->bit_auto_pwr_on);
+               val |= (1 << desc->bit_hw_mode);
+               regmap_write(skp->regmap[APMU_REGMAP_INDEX], desc->reg_pwr_ctrl, val);
+
+               udelay(310);
+
+               for (loop = 10000; loop >= 0; --loop) {
+                       regmap_read(skp->regmap[APMU_REGMAP_INDEX], APMU_POWER_STATUS_REG, &val);
+                       if (val & (1 << desc->bit_hw_pwr_stat))
+                               break;
+                       udelay(6);
+               }
+       }
+
+       if (loop < 0) {
+               pr_err("power-off domain: %d, error\n", desc->pm_index);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int spacemit_power_domain_on(struct power_domain *pd)
+{
+       struct pm_domain_desc *pd_priv = pd->priv;
+       struct spacemit_k1x_pd_platdata *priv = dev_get_priv(pd->dev);
+
+       debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
+
+       /* domain_on */
+       k1x_pd_power_on(priv, pd_priv);
+
+       return 0;
+}
+
+static int spacemit_power_domain_off(struct power_domain *pd)
+{
+       struct pm_domain_desc *pd_priv = pd->priv;
+       struct spacemit_k1x_pd_platdata *priv = dev_get_priv(pd->dev);
+
+       debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
+       /* domain_off */
+       k1x_pd_power_off(priv, pd_priv);
+
+       return 0;
+}
+
+static int spacemit_power_domain_probe(struct udevice *dev)
+{
+       int ret;
+       struct spacemit_k1x_pd_platdata *priv = dev_get_priv(dev);
+       ulong driver_data = dev_get_driver_data(dev);
+
+       priv->desc = (struct pm_domain_desc *)driver_data;
+       ret = regmap_init_mem_index(dev_ofnode(dev),
+                       &priv->regmap[MPMU_REGMAP_INDEX], 0);
+       if (ret) {
+               printf("%s:%d, error\n", __func__, __LINE__);
+               return ret;
+       }
+
+       ret = regmap_init_mem_index(dev_ofnode(dev),
+                       &priv->regmap[APMU_REGMAP_INDEX], 1);
+       if (ret) {
+               printf("%s:%d, error\n", __func__, __LINE__);
+               return ret;
+       }
+       return 0;
+}
+
+static struct power_domain_ops spacemit_power_domain_ops = {
+       .on = spacemit_power_domain_on,
+       .off = spacemit_power_domain_off,
+       .of_xlate = spacemit_power_domain_of_xlate,
+};
+
+U_BOOT_DRIVER(spacemit_pm_domains) = {
+       .name = "spacemit-k1x-pm-domains",
+       .id = UCLASS_POWER_DOMAIN,
+       .of_match = spacemit_power_domain_of_match,
+       .probe = spacemit_power_domain_probe,
+       .priv_auto = sizeof(struct spacemit_k1x_pd_platdata),
+       .ops = &spacemit_power_domain_ops,
+};
index 66b16b06e0bb0ab235bbe81e2f17ee6451a9b617..1fac5e5b2da96f960cc5e6d5b758bda47114dea1 100644 (file)
@@ -79,6 +79,13 @@ config SPL_PMIC_AXP
          This config enables driver-model PMIC uclass features in the SPL for
          X-Powers AXP152, AXP2xx, and AXP8xx PMICs.
 
+config PMIC_SPM8XX
+       bool "Enable Driver Model for SPM8XX PMICs"
+       depends on DM_I2C
+       help
+         This config enables driver-model PMIC uclass features for
+         spm8821, pm853 PMICs.
+
 config DM_PMIC_DA9063
        bool "Enable Driver Model for the Dialog DA9063 PMIC"
        help
index f73b3262559ecfd653fd285ee849f1e1f139733a..a8296901f93edf575c1bdcde9a6fbc9725d60b8c 100644 (file)
@@ -44,3 +44,4 @@ obj-$(CONFIG_POWER_HI6553) += pmic_hi6553.o
 obj-$(CONFIG_POWER_MC34VR500) += pmic_mc34vr500.o
 obj-$(CONFIG_PMIC_TPS65941) += tps65941.o
 obj-$(CONFIG_PMIC_TPS65219) += tps65219.o
+obj-$(CONFIG_$(SPL_)PMIC_SPM8XX) += spacemit_pmic.o
diff --git a/drivers/power/pmic/spacemit_pmic.c b/drivers/power/pmic/spacemit_pmic.c
new file mode 100644 (file)
index 0000000..0530de6
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <errno.h>
+#include <log.h>
+#include <power/spacemit/spacemit_pmic.h>
+#include <power/pmic.h>
+#include <sysreset.h>
+
+DECLEAR_PM853_REGULATOR_MATCH_DATA;
+DECLEAR_SPM8821_REGULATOR_MATCH_DATA;
+DECLEAR_SY8810L_REGULATOR_MATCH_DATA;
+
+static int pm8xx_reg_count(struct udevice *dev)
+{
+       struct pm8xx_priv *priv = dev_get_priv(dev);
+
+       return priv->match->max_registers;
+}
+
+static int pm8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+       int ret;
+
+       ret = dm_i2c_read(dev, reg, buff, len);
+       if (ret) {
+               debug("read error from device: %p register: %#x!\n", dev, reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pm8xx_write(struct udevice *dev, uint reg, const uint8_t *buff,
+                         int len)
+{
+       int ret;
+
+       ret = dm_i2c_write(dev, reg, buff, len);
+       if (ret) {
+               debug("write error to device: %p register: %#x!\n", dev, reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct dm_pmic_ops pm8xx_ops = {
+       .reg_count = pm8xx_reg_count,
+       .read = pm8xx_read,
+       .write = pm8xx_write,
+};
+
+static const struct udevice_id pm8xx_ids[] = {
+       { .compatible = "spacemit,spm8821", .data = (ulong)&spm8821_regulator_match_data, },
+       { .compatible = "spacemit,pm853", .data = (ulong)&pm853_regulator_match_data, },
+       { .compatible = "spacemit,sy8810l", .data = (ulong)&sy8810l_regulator_match_data, },
+       { }
+};
+
+static int pm8xx_probe(struct udevice *dev)
+{
+       struct pm8xx_priv *priv = dev_get_priv(dev);
+       ulong driver_data = dev_get_driver_data(dev);
+
+       priv->match = (struct regulator_match_data *)driver_data;
+
+       return 0;
+}
+
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+static const struct pmic_child_info pmic_children_info[] = {
+       { .prefix = "DCDC_REG", .driver = "pm8xx_buck"},
+       { .prefix = "EDCDC_REG", .driver = "pm8xx_buck"},
+       { .prefix = "LDO_REG", .driver = "pm8xx_ldo"},
+       { .prefix = "SWITCH_REG", .driver = "pm8xx_switch"},
+       { },
+};
+
+static int pm8xx_bind(struct udevice *dev)
+{
+       ofnode regulators_node;
+       int children;
+
+       regulators_node = dev_read_subnode(dev, "regulators");
+       if (!ofnode_valid(regulators_node)) {
+               debug("%s: %s regulators subnode not found!\n", __func__,
+                     dev->name);
+               return -ENXIO;
+       }
+
+       debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+       children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+       if (!children)
+               debug("%s: %s - no child found\n", __func__, dev->name);
+
+       /* Always return success for this device */
+       return 0;
+}
+#endif
+
+U_BOOT_DRIVER(spacemit_pm8xx) = {
+       .name = "spacemit_pm8xx",
+       .id = UCLASS_PMIC,
+       .of_match = pm8xx_ids,
+#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
+       .bind = pm8xx_bind,
+#endif
+       .priv_auto        = sizeof(struct pm8xx_priv),
+       .probe = pm8xx_probe,
+       .ops = &pm8xx_ops,
+};
diff --git a/drivers/power/power_spm8xx.c b/drivers/power/power_spm8xx.c
new file mode 100644 (file)
index 0000000..0ae2785
--- /dev/null
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <i2c.h>
+#include <common.h>
+#include <asm/global_data.h>
+#include <linux/bug.h>
+#include <asm/barrier.h>
+#include <power/spacemit/spacemit_pmic.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+SPM8821_BUCK_LINER_RANGE; SPM8821_LDO_LINER_RANGE /* ; SPM8821_SWITCH_LINER_RANGE */;
+SPM8821_REGULATOR_BUCK_DESC; SPM8821_REGULATOR_LDO_DESC/* ; SPM8821_REGULATOR_SWITCH_DESC */;
+
+PM853_BUCK_LINER_RANGE1; PM853_BUCK_LINER_RANGE2; PM853_LDO_LINER_RANGE1; PM853_LDO_LINER_RANGE2;
+PM853_LDO_LINER_RANGE3; PM853_LDO_LINER_RANGE4; /* PM853_SWITCH_LINER_RANGE; */
+PM853_REGULATOR_BUCK_DESC; PM853_REGULATOR_LDO_DESC; /* PM853_REGULATOR_SWITCH_DESC; */
+
+SY8810L_BUCK_LINER_RANGE;SY8810L_REGULATOR_DESC;
+
+static const char *global_compatible[] = {
+       "spacemit,pm853",
+       "spacemit,spm8821",
+       "spacemit,sy8810l",
+};
+
+void __regulator_desc_find(const char *name, const struct pm8xx_buck_desc **buck_desc,
+               const struct pm8xx_buck_desc **ldo_desc, int *num_buck, int *num_ldo)
+{
+       if (strcmp(name, global_compatible[0]) == 0) {
+               *buck_desc = pm853_buck_desc;
+               *num_buck = sizeof(pm853_buck_desc) / sizeof(pm853_buck_desc[0]);
+               *ldo_desc = pm853_ldo_desc;
+               *num_ldo = sizeof(pm853_ldo_desc) / sizeof(pm853_ldo_desc[0]);
+       }
+
+       if (strcmp(name, global_compatible[1]) == 0) {
+               *buck_desc = spm8821_buck_desc;
+               *num_buck = sizeof(spm8821_buck_desc) / sizeof(spm8821_buck_desc[0]);
+               *ldo_desc = spm8821_ldo_desc;
+               *num_ldo = sizeof(spm8821_ldo_desc) / sizeof(spm8821_ldo_desc[0]);
+       }
+
+       if (strcmp(name, global_compatible[2]) == 0) {
+               *buck_desc = sy8810l_buck_desc;
+               *num_buck = sizeof(sy8810l_buck_desc) / sizeof(sy8810l_buck_desc[0]);
+               *ldo_desc = NULL;
+               *num_ldo = 0;
+       }
+}
+
+/**
+ * linear_range_get_value - fetch a value from given range
+ * @r:   pointer to linear range where value is looked from
+ * @selector:   selector for which the value is searched
+ * @val:       address where found value is updated
+ *
+ * Search given ranges for value which matches given selector.
+ *
+ * Return: 0 on success, -EINVAL given selector is not found from any of the
+ * ranges.
+ */
+static int linear_range_get_value(const struct pm8xx_linear_range *r, unsigned int selector,
+                          unsigned int *val)
+{
+       if (r->min_sel > selector || r->max_sel < selector)
+               return -EINVAL;
+
+       *val = r->min + (selector - r->min_sel) * r->step;
+
+       return 0;
+}
+
+/**
+ * linear_range_get_value_array - fetch a value from array of ranges
+ * @r:   pointer to array of linear ranges where value is looked from
+ * @ranges:     amount of ranges in an array
+ * @selector:   selector for which the value is searched
+ * @val:       address where found value is updated
+ *
+ * Search through an array of ranges for value which matches given selector.
+ *
+ * Return: 0 on success, -EINVAL given selector is not found from any of the
+ * ranges.
+ */
+static int linear_range_get_value_array(const struct pm8xx_linear_range *r, int ranges,
+                                unsigned int selector, unsigned int *val)
+{
+       int i;
+
+       for (i = 0; i < ranges; i++)
+               if (r[i].min_sel <= selector && r[i].max_sel >= selector)
+                       return linear_range_get_value(&r[i], selector, val);
+
+       return -EINVAL;
+}
+
+/**
+ * regulator_desc_list_voltage_linear_range - List voltages for linear ranges
+ *
+ * @desc: Regulator desc for regulator which volatges are to be listed
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a series of simple linear mappings between voltages
+ * and selectors who have set linear_ranges in the regulator descriptor
+ * can use this function prior regulator registration to list voltages.
+ * This is useful when voltages need to be listed during device-tree
+ * parsing.
+ */
+static int regulator_desc_list_voltage_linear_range(const struct pm8xx_buck_desc *desc,
+                                            unsigned int selector)
+{
+       unsigned int val;
+       int ret;
+
+       BUG_ON(!desc->n_linear_ranges);
+
+       ret = linear_range_get_value_array(desc->linear_ranges,
+                                          desc->n_linear_ranges, selector,
+                                          &val);
+       if (ret)
+               return ret;
+
+       return val;
+}
+
+/**
+ * linear_range_get_max_value - return the largest value in a range
+ * @r:   pointer to linear range where value is looked from
+ *
+ * Return: the largest value in the given range
+ */
+static unsigned int linear_range_get_max_value(const struct pm8xx_linear_range *r)
+{
+       return r->min + (r->max_sel - r->min_sel) * r->step;
+}
+
+/**
+ * linear_range_get_selector_high - return linear range selector for value
+ * @r:   pointer to linear range where selector is looked from
+ * @val:       value for which the selector is searched
+ * @selector:   address where found selector value is updated
+ * @found:      flag to indicate that given value was in the range
+ *
+ * Return selector for which range value is closest match for given
+ * input value. Value is matching if it is equal or higher than given
+ * value. If given value is in the range, then @found is set true.
+ *
+ * Return: 0 on success, -EINVAL if range is invalid or does not contain
+ * value greater or equal to given value
+ */
+static int linear_range_get_selector_high(const struct pm8xx_linear_range *r,
+                                  unsigned int val, unsigned int *selector,
+                                  bool *found)
+{
+       *found = false;
+
+       if (linear_range_get_max_value(r) < val)
+               return -EINVAL;
+
+       if (r->min > val) {
+               *selector = r->min_sel;
+               return 0;
+       }
+
+       *found = true;
+
+       if (r->step == 0)
+               *selector = r->max_sel;
+       else
+               *selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel;
+
+       return 0;
+}
+
+/**
+ * regulator_map_voltage_linear_range - map_voltage() for multiple linear ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing linear_ranges in their descriptor can use this as
+ * their map_voltage() callback.
+ */
+static int regulator_map_voltage_linear_range(const struct pm8xx_buck_desc *desc,
+                                      int min_uV, int max_uV)
+{
+       const struct pm8xx_linear_range *range;
+       int ret = -EINVAL;
+       unsigned int sel;
+       bool found;
+       int voltage, i;
+
+       if (!desc->n_linear_ranges) {
+               BUG_ON(!desc->n_linear_ranges);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < desc->n_linear_ranges; i++) {
+               range = &desc->linear_ranges[i];
+
+               ret = linear_range_get_selector_high(range, min_uV, &sel,
+                                                    &found);
+               if (ret)
+                       continue;
+               ret = sel;
+
+               /*
+                * Map back into a voltage to verify we're still in bounds.
+                * If we are not, then continue checking rest of the ranges.
+                */
+               voltage = regulator_desc_list_voltage_linear_range(desc, sel);
+               if (voltage >= min_uV && voltage <= max_uV)
+                       break;
+       }
+
+       if (i == desc->n_linear_ranges)
+               return -EINVAL;
+
+       return ret;
+}
+
+static int __board_pmic_init(const char *name)
+{
+       unsigned char regval;
+       const char *s;
+       u32 value, min, max;
+       const struct pm8xx_buck_desc *buck_desc, *ldo_desc;
+       int offset, bus, ret, sub_offset, len, saddr, i, num_buck, num_ldo, sel;
+
+       offset = fdt_node_offset_by_compatible(gd->fdt_blob, -1, name);
+       if (offset < 0) {
+               pr_info("%s Get %s node error\n", __func__, name);
+               return -EINVAL;
+       }
+
+       saddr = fdtdec_get_uint(gd->fdt_blob, offset, "reg", 0);
+       if (!saddr) {
+               pr_info("%s: %s Node has no reg\n", __func__, name);
+               return -EINVAL;
+       }
+
+       bus = fdtdec_get_uint(gd->fdt_blob, offset, "bus", 0);
+       if (!bus) {
+               pr_info("%s: %s Node has no bus\n", __func__, name);
+               return -EINVAL;
+       }
+
+       ret = i2c_set_bus_num(bus);
+       if (ret < 0) {
+               pr_info("%s: %s set i2c bus number error\n", __func__, name);
+               return -EINVAL;
+       }
+
+       ret = i2c_probe(saddr);
+       if (ret < 0) {
+//             pr_info("%s: %s probe i2c failed\n", __func__, name);
+               return -EINVAL;
+       }
+
+       __regulator_desc_find(name, &buck_desc, &ldo_desc, &num_buck, &num_ldo);
+
+       offset = fdt_first_subnode(gd->fdt_blob, offset);
+
+       for (sub_offset = fdt_first_subnode(gd->fdt_blob, offset);
+               sub_offset >= 0;
+               sub_offset = fdt_next_subnode(gd->fdt_blob, sub_offset)) {
+
+               /* find regulator-boot-on property */
+               if (!fdt_getprop(gd->fdt_blob, sub_offset, "regulator-boot-on", &len))
+                       continue;
+
+               max = fdtdec_get_uint(gd->fdt_blob, sub_offset, "regulator-max-microvolt", 0);
+               if (!max)
+                       continue;
+
+               min = fdtdec_get_uint(gd->fdt_blob, sub_offset, "regulator-min-microvolt", 0);
+               if (!min)
+                       continue;
+
+               value = fdtdec_get_uint(gd->fdt_blob, sub_offset, "regulator-init-microvolt", 0);
+
+               /* find wich dcdc or ldo */
+               s = fdt_get_name(gd->fdt_blob, sub_offset, &len);
+
+               if ((strncmp(s, "DCDC_REG", 8) == 0) || (strncmp(s, "EDCDC_REG", 9) == 0)) {
+                       for (i = 0; i < num_buck; ++i) {
+                               if (strcmp(buck_desc[i].name, s) == 0) {
+
+                                       /* enable the regulator */
+                                       i2c_read(saddr, buck_desc[i].enable_reg, 1, &regval, 1);
+                                       regval |= (1 << (ffs(buck_desc[i].enable_msk) - 1));
+                                       i2c_write(saddr, buck_desc[i].enable_reg, 1, &regval, 1);
+
+
+                                       /* set the regulator */
+                                       if (value) {
+                                               sel = regulator_map_voltage_linear_range(buck_desc + i, value, value);
+
+                                               if (sel >= 0) {
+                                                       sel <<= ffs(buck_desc[i].vsel_msk) - 1;
+                                                       i2c_read(saddr, buck_desc[i].vsel_reg, 1, &regval, 1);
+                                                       regval = (regval & ~buck_desc[i].vsel_msk) | sel;
+                                                       i2c_write(saddr, buck_desc[i].vsel_reg, 1, &regval, 1);
+                                               }
+                                       }
+                                       break;
+                               }
+                       }
+               }
+
+               if (strncmp(s, "LDO_REG", 7) == 0) {
+                       for (i = 0; i < num_ldo; ++i) {
+                               if (strcmp(ldo_desc[i].name, s) == 0) {
+                                       /* enable the regulator */
+                                       i2c_read(saddr, ldo_desc[i].enable_reg, 1, &regval, 1);
+                                       regval |= (1 << (ffs(ldo_desc[i].enable_msk) - 1));
+                                       i2c_write(saddr, ldo_desc[i].enable_reg, 1, &regval, 1);
+
+                                       /* set the regulator */
+                                       if (value) {
+                                               sel = regulator_map_voltage_linear_range(ldo_desc + i, value, value);
+
+                                               if (sel >= 0) {
+                                                       sel <<= ffs(ldo_desc[i].vsel_msk) - 1;
+                                                       i2c_read(saddr, ldo_desc[i].vsel_reg, 1, &regval, 1);
+                                                       regval = (regval & ~ldo_desc[i].vsel_msk) | sel;
+                                                       i2c_write(saddr, ldo_desc[i].vsel_reg, 1, &regval, 1);
+                                               }
+                                       }
+
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int board_pmic_init(void)
+{
+       int i;
+
+       for (i = 0; i < sizeof(global_compatible) / sizeof(global_compatible[0]); ++i)
+               __board_pmic_init(global_compatible[i]);
+
+       return 0;
+}
index c519e066ef028503d2c10822148308a5a27b25e6..4cdf6bd2f91feedc3c24bcc66c8030cf212fb64f 100644 (file)
@@ -395,3 +395,25 @@ config DM_REGULATOR_TPS65219
        features for REGULATOR TPS65219 and the family of TPS65219 PMICs.
        TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs.
        The driver implements get/set api for value and enable.
+
+config DM_REGULATOR_SPM8XX
+       bool "Enable Driver Model for SPM8XX regulators"
+       depends on DM_REGULATOR && PMIC_SPM8XX
+       help
+       This config enables implementation of driver-model regulator uclass
+       features for regulators on spm8xx & pm8xx PMICs.
+
+config DM_REGULATOR_SPACEMIT_HUB
+       tristate "Spacemit onboard USB hub regulator wrapper support"
+       default SOC_SPACEMIT_K1X
+       depends on DM_REGULATOR
+       help
+         Say Y here if you want to support onboard usb hubs on Spacemit
+         platform. If unsure, say Y when compile for Spacemit platform.
+
+config SPL_DM_REGULATOR_SPACEMIT_HUB
+       tristate "Spacemit onboard USB hub regulator wrapper support in SPL"
+       depends on SPL_DM_REGULATOR && DM_REGULATOR_SPACEMIT_HUB
+       help
+         Say Y here if you want to support onboard usb hubs on Spacemit
+         platform in SPL.
index bc736068bca7feef4796831b6961ca0bb95160ee..514d4128ec65501618d46766a35a66ec9e5baeef 100644 (file)
@@ -34,3 +34,5 @@ obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
 obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o
 obj-$(CONFIG_DM_REGULATOR_TPS65219) += tps65219_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_SPM8XX) += spacemit_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_SPACEMIT_HUB) += spacemit-hub-regulator.o
index aca00e56bbefeb35e6f042bbd080849ac4acec73..06d2fae43bbaee52da7fde7704ddb3e8b02bdc68 100644 (file)
@@ -330,15 +330,15 @@ static void regulator_show(struct udevice *dev, int ret)
 
        uc_pdata = dev_get_uclass_plat(dev);
 
-       printf("%s@%s: ", dev->name, uc_pdata->name);
+       pr_info("%s@%s: ", dev->name, uc_pdata->name);
        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
-               printf("set %d uV", uc_pdata->min_uV);
+               pr_info("set %d uV", uc_pdata->min_uV);
        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
-               printf("; set %d uA", uc_pdata->min_uA);
-       printf("; enabling");
+               pr_info("; set %d uA", uc_pdata->min_uA);
+       pr_info("; enabling");
        if (ret)
-               printf(" (ret: %d)", ret);
-       printf("\n");
+               pr_info(" (ret: %d)", ret);
+       pr_info("\n");
 }
 
 int regulator_autoset_by_name(const char *platname, struct udevice **devp)
diff --git a/drivers/power/regulator/spacemit-hub-regulator.c b/drivers/power/regulator/spacemit-hub-regulator.c
new file mode 100644 (file)
index 0000000..c93cb8c
--- /dev/null
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * spacemit-hubpwr-regulator.c -
+ *             Regulator Wrapper for Spacemit k1-x onboard usb hub
+ *
+ * Copyright (c) 2023 Spacemit Co., Ltd.
+ *
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <dt-bindings/phy/phy.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+#include <power/regulator.h>
+
+#define GPIOD_OUT_HIGH (GPIOD_IS_OUT | GPIOD_PULL_UP)
+#define GPIOD_OUT_LOW (GPIOD_IS_OUT | GPIOD_PULL_DOWN)
+#define GPIO_MAX_COUNT 4
+
+struct spacemit_hub_regulator_plat {
+       struct udevice *dev;
+       bool is_on;
+       struct gpio_desc vbus_gpios[GPIO_MAX_COUNT];
+       struct gpio_desc hub_gpios[GPIO_MAX_COUNT];
+       u8 vbus_gpio_cnt;
+       u8 hub_gpio_cnt;
+       bool hub_gpio_active_low;
+       bool vbus_gpio_active_low;
+       struct udevice *vbus_regulator;
+       struct udevice *hub_regulator;
+       u32 hub_inter_delay_ms;
+       u32 vbus_delay_ms;
+       u32 vbus_inter_delay_ms;
+};
+
+static int spacemit_hub_enable(struct spacemit_hub_regulator_plat *spacemit, bool on)
+{
+       unsigned i;
+       int ret = 0;
+       int active_val = spacemit->hub_gpio_active_low ? 0 : 1;
+
+       if (!spacemit->hub_gpio_cnt && !spacemit->hub_regulator)
+               return 0;
+       dev_dbg(spacemit->dev, "do hub enable %s\n", on ? "on" : "off");
+       if (spacemit->hub_regulator) {
+               ret = regulator_set_enable(spacemit->hub_regulator, on);
+               if (ret)
+                       return ret;
+       }
+       if (on) {
+               for (i = 0; i < spacemit->hub_gpio_cnt; i++) {
+                       ret = dm_gpio_set_value(&spacemit->hub_gpios[i],
+                                       active_val);
+                       if (ret)
+                               return ret;
+                       if (spacemit->hub_inter_delay_ms) {
+                               mdelay(spacemit->hub_inter_delay_ms);
+                       }
+               }
+       } else {
+               for (i = spacemit->hub_gpio_cnt; i > 0; --i) {
+                       ret = dm_gpio_set_value(&spacemit->hub_gpios[i - 1],
+                                       !active_val);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int spacemit_hub_vbus_enable(struct spacemit_hub_regulator_plat *spacemit,
+                                        bool on)
+{
+       unsigned i;
+       int ret = 0;
+       int active_val = spacemit->vbus_gpio_active_low ? 0 : 1;
+
+       if (!spacemit->vbus_gpio_cnt && !spacemit->vbus_regulator)
+               return 0;
+       dev_dbg(spacemit->dev, "do hub vbus on %s\n", on ? "on" : "off");
+       if (spacemit->vbus_regulator) {
+               regulator_set_enable(spacemit->vbus_regulator, on);
+               if (ret)
+                       return ret;
+       }
+       if (on) {
+               for (i = 0; i < spacemit->vbus_gpio_cnt; i++) {
+                       ret = dm_gpio_set_value(&spacemit->vbus_gpios[i],
+                                       active_val);
+                       if (ret)
+                               return ret;
+                       if (spacemit->vbus_inter_delay_ms) {
+                               mdelay(spacemit->vbus_inter_delay_ms);
+                       }
+               }
+       } else {
+               for (i = spacemit->vbus_gpio_cnt; i > 0; --i) {
+                       ret = dm_gpio_set_value(&spacemit->vbus_gpios[i - 1],
+                                       !active_val);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+static int spacemit_hub_configure(struct spacemit_hub_regulator_plat *spacemit, bool on)
+{
+       int ret = 0;
+       dev_dbg(spacemit->dev, "do hub configure %s\n", on ? "on" : "off");
+       if (on) {
+               ret = spacemit_hub_enable(spacemit, true);
+               if (ret)
+                       return ret;
+               if (spacemit->vbus_delay_ms && spacemit->vbus_gpio_cnt) {
+                       mdelay(spacemit->vbus_delay_ms);
+               }
+               ret = spacemit_hub_vbus_enable(spacemit, true);
+               if (ret)
+                       return ret;
+       } else {
+               ret = spacemit_hub_vbus_enable(spacemit, false);
+               if (ret)
+                       return ret;
+               ret = spacemit_hub_enable(spacemit, false);
+               if (ret)
+                       return ret;
+       }
+       spacemit->is_on = on;
+       return 0;
+}
+
+static int spacemit_hub_regulator_of_to_plat(struct udevice *dev)
+{
+       struct dm_regulator_uclass_plat *uc_pdata;
+       struct spacemit_hub_regulator_plat *spacemit;
+       int ret;
+
+       spacemit = dev_get_plat(dev);
+       uc_pdata = dev_get_uclass_plat(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
+       /* Set type to fixed to support boot-on/off */
+       uc_pdata->type = REGULATOR_TYPE_FIXED;
+
+       spacemit->hub_inter_delay_ms = dev_read_u32_default(dev, "hub_inter_delay_ms", 0);
+       spacemit->vbus_inter_delay_ms = dev_read_u32_default(dev, "vbus_inter_delay_ms", 0);
+       spacemit->vbus_delay_ms = dev_read_u32_default(dev, "vbus_delay_ms", 10);
+
+       spacemit->hub_gpio_active_low = dev_read_bool(dev, "hub_gpio_active_low");
+       spacemit->vbus_gpio_active_low = dev_read_bool(dev, "vbus_gpio_active_low");
+
+       ret = gpio_request_list_by_name(dev, "hub-gpios", spacemit->hub_gpios,
+                        ARRAY_SIZE(spacemit->hub_gpios),
+                        spacemit->hub_gpio_active_low ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW);
+
+       if (ret < 0) {
+               dev_err(dev, "failed to retrieve hub-gpios from dts: %d\n", ret);
+               return ret;
+       }
+       spacemit->hub_gpio_cnt = ret;
+       ret = device_get_supply_regulator(dev, "hub-supply", &spacemit->hub_regulator);
+       if (ret < 0 && ret != -ENOENT) {
+               dev_err(dev, "failed to retrieve hub-supply from dts: %d\n", ret);
+               return ret;
+       }
+       dev_dbg(dev, "got %d hub-supply, hubs: %p\n", ret, spacemit->hub_regulator);
+
+       ret = gpio_request_list_by_name(dev, "vbus-gpios", spacemit->vbus_gpios,
+                       ARRAY_SIZE(spacemit->vbus_gpios),
+                       spacemit->vbus_gpio_active_low ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW);
+       if (ret < 0) {
+               dev_err(dev, "failed to retrieve hub-gpios from dts: %d\n", ret);
+               return ret;
+       }
+       spacemit->vbus_gpio_cnt = ret;
+       ret = device_get_supply_regulator(dev, "vbus-supply", &spacemit->vbus_regulator);
+       if (ret < 0 && ret != -ENOENT) {
+               dev_err(dev, "failed to retrieve vbus-supply from dts: %d\n", ret);
+               return ret;
+       }
+       dev_dbg(dev, "got vbus-supply ret %d %p\n", ret, spacemit->vbus_regulator);
+       dev_dbg(dev, "found hub gpios: %d vbus gpios: %d\n", spacemit->hub_gpio_cnt,
+               spacemit->vbus_gpio_cnt);
+
+       return 0;
+}
+
+static int spacemit_hub_regulator_get_enable(struct udevice *dev)
+{
+       struct spacemit_hub_regulator_plat *spacemit = dev_get_plat(dev);
+       return spacemit->is_on;
+}
+
+static int spacemit_hub_regulator_set_enable(struct udevice *dev, bool enable)
+{
+       struct spacemit_hub_regulator_plat *spacemit = dev_get_plat(dev);
+       return spacemit_hub_configure(spacemit, enable);
+}
+
+static const struct dm_regulator_ops spacemit_hub_regulator_ops = {
+       .get_enable     = spacemit_hub_regulator_get_enable,
+       .set_enable     = spacemit_hub_regulator_set_enable,
+};
+
+static const struct udevice_id spacemit_hub_regulator_ids[] = {
+       {.compatible = "spacemit,usb-hub",},
+       { },
+};
+
+U_BOOT_DRIVER(spacemit_hub_regulator) = {
+       .name = "gpio regulator",
+       .id = UCLASS_REGULATOR,
+       .ops = &spacemit_hub_regulator_ops,
+       .of_match = spacemit_hub_regulator_ids,
+       .of_to_plat = spacemit_hub_regulator_of_to_plat,
+       .plat_auto      = sizeof(struct spacemit_hub_regulator_plat),
+};
diff --git a/drivers/power/regulator/spacemit_regulator.c b/drivers/power/regulator/spacemit_regulator.c
new file mode 100644 (file)
index 0000000..0ccf484
--- /dev/null
@@ -0,0 +1,697 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include "regulator_common.h"
+#include <power/spacemit/spacemit_pmic.h>
+
+SPM8821_BUCK_LINER_RANGE; SPM8821_LDO_LINER_RANGE; SPM8821_SWITCH_LINER_RANGE;
+SPM8821_REGULATOR_BUCK_DESC; SPM8821_REGULATOR_LDO_DESC; SPM8821_REGULATOR_SWITCH_DESC;
+SPM8821_REGULATOR_MATCH_DATA;
+
+PM853_BUCK_LINER_RANGE1; PM853_BUCK_LINER_RANGE2; PM853_LDO_LINER_RANGE1; PM853_LDO_LINER_RANGE2;
+PM853_LDO_LINER_RANGE3; PM853_LDO_LINER_RANGE4; PM853_SWITCH_LINER_RANGE;
+PM853_REGULATOR_BUCK_DESC; PM853_REGULATOR_LDO_DESC; PM853_REGULATOR_SWITCH_DESC;
+PM853_REGULATOR_MATCH_DATA;
+
+SY8810L_BUCK_LINER_RANGE; SY8810L_REGULATOR_DESC; SY8810L_REGULATOR_MATCH_DATA;
+
+/**
+ * linear_range_get_value - fetch a value from given range
+ * @r:          pointer to linear range where value is looked from
+ * @selector:   selector for which the value is searched
+ * @val:        address where found value is updated
+ *
+ * Search given ranges for value which matches given selector.
+ *
+ * Return: 0 on success, -EINVAL given selector is not found from any of the
+ * ranges.
+ */
+static int linear_range_get_value(const struct pm8xx_linear_range *r, unsigned int selector,
+                           unsigned int *val)
+{
+        if (r->min_sel > selector || r->max_sel < selector)
+                return -EINVAL;
+
+        *val = r->min + (selector - r->min_sel) * r->step;
+
+        return 0;
+}
+
+/**
+ * linear_range_get_value_array - fetch a value from array of ranges
+ * @r:          pointer to array of linear ranges where value is looked from
+ * @ranges:     amount of ranges in an array
+ * @selector:   selector for which the value is searched
+ * @val:        address where found value is updated
+ *
+ * Search through an array of ranges for value which matches given selector.
+ *
+ * Return: 0 on success, -EINVAL given selector is not found from any of the
+ * ranges.
+ */
+static int linear_range_get_value_array(const struct pm8xx_linear_range *r, int ranges,
+                                 unsigned int selector, unsigned int *val)
+{
+        int i;
+
+        for (i = 0; i < ranges; i++)
+                if (r[i].min_sel <= selector && r[i].max_sel >= selector)
+                        return linear_range_get_value(&r[i], selector, val);
+
+        return -EINVAL;
+}
+
+/**
+ * regulator_desc_list_voltage_linear_range - List voltages for linear ranges
+ *
+ * @desc: Regulator desc for regulator which volatges are to be listed
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a series of simple linear mappings between voltages
+ * and selectors who have set linear_ranges in the regulator descriptor
+ * can use this function prior regulator registration to list voltages.
+ * This is useful when voltages need to be listed during device-tree
+ * parsing.
+ */
+static int regulator_desc_list_voltage_linear_range(const struct pm8xx_buck_desc *desc,
+                                             unsigned int selector)
+{
+        unsigned int val;
+        int ret;
+
+        BUG_ON(!desc->n_linear_ranges);
+
+        ret = linear_range_get_value_array(desc->linear_ranges,
+                                           desc->n_linear_ranges, selector,
+                                           &val);
+        if (ret)
+                return ret;
+
+        return val;
+}
+
+/**
+ * linear_range_get_max_value - return the largest value in a range
+ * @r:          pointer to linear range where value is looked from
+ *
+ * Return: the largest value in the given range
+ */
+static unsigned int linear_range_get_max_value(const struct pm8xx_linear_range *r)
+{
+        return r->min + (r->max_sel - r->min_sel) * r->step;
+}
+
+/**
+ * linear_range_get_selector_high - return linear range selector for value
+ * @r:          pointer to linear range where selector is looked from
+ * @val:        value for which the selector is searched
+ * @selector:   address where found selector value is updated
+ * @found:      flag to indicate that given value was in the range
+ *
+ * Return selector for which range value is closest match for given
+ * input value. Value is matching if it is equal or higher than given
+ * value. If given value is in the range, then @found is set true.
+ *
+ * Return: 0 on success, -EINVAL if range is invalid or does not contain
+ * value greater or equal to given value
+ */
+static int linear_range_get_selector_high(const struct pm8xx_linear_range *r,
+                                   unsigned int val, unsigned int *selector,
+                                   bool *found)
+{
+        *found = false;
+
+        if (linear_range_get_max_value(r) < val)
+                return -EINVAL;
+
+        if (r->min > val) {
+                *selector = r->min_sel;
+                return 0;
+        }
+
+        *found = true;
+
+        if (r->step == 0)
+                *selector = r->max_sel;
+        else
+                *selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel;
+
+        return 0;
+}
+
+/**
+ * regulator_map_voltage_linear_range - map_voltage() for multiple linear ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing linear_ranges in their descriptor can use this as
+ * their map_voltage() callback.
+ */
+static int regulator_map_voltage_linear_range(const struct pm8xx_buck_desc *desc,
+                                       int min_uV, int max_uV)
+{
+        const struct pm8xx_linear_range *range;
+        int ret = -EINVAL;
+        unsigned int sel;
+        bool found;
+        int voltage, i;
+
+        if (!desc->n_linear_ranges) {
+                BUG_ON(!desc->n_linear_ranges);
+                return -EINVAL;
+        }
+
+        for (i = 0; i < desc->n_linear_ranges; i++) {
+                range = &desc->linear_ranges[i];
+
+                ret = linear_range_get_selector_high(range, min_uV, &sel,
+                                                     &found);
+                if (ret)
+                        continue;
+                ret = sel;
+
+                /*
+                 * Map back into a voltage to verify we're still in bounds.
+                 * If we are not, then continue checking rest of the ranges.
+                 */
+               voltage = regulator_desc_list_voltage_linear_range(desc, sel);
+                if (voltage >= min_uV && voltage <= max_uV)
+                        break;
+        }
+
+        if (i == desc->n_linear_ranges)
+                return -EINVAL;
+
+        return ret;
+}
+
+static const struct pm8xx_buck_desc *get_buck_reg(struct udevice *pmic, int num)
+{
+       struct pm8xx_priv *priv = dev_get_priv(pmic);
+       struct regulator_match_data *math = (struct regulator_match_data *)priv->match;
+
+       return math->buck_desc + num;
+
+       return NULL;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_buck_reg(dev->parent, buck);
+       int mask = info->vsel_msk;
+       int ret;
+       unsigned int val;
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       ret = pmic_reg_read(dev->parent, info->vsel_reg);
+       if (ret < 0)
+               return ret;
+       val = ret & mask;
+
+       val >>= ffs(mask) - 1;
+
+       return regulator_desc_list_voltage_linear_range(info, val);
+}
+
+static int buck_set_value(struct udevice *dev, int uvolt)
+{
+       int sel, ret = -EINVAL;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_buck_reg(dev->parent, buck);
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       sel = regulator_map_voltage_linear_range(info, uvolt, uvolt);
+       if (sel >=0) {
+               /* has get the selctor */
+                sel <<= ffs(info->vsel_msk) - 1;
+                ret = pmic_clrsetbits(dev->parent, info->vsel_reg, info->vsel_msk, sel);
+       }
+
+       return ret;
+}
+
+static int buck_set_suspend_value(struct udevice *dev, int uvolt)
+{
+       /* the hardware has already support the function */
+/**
+ *     int sel, ret = -EINVAL;
+ *     int buck = dev->driver_data - 1;
+ *     const struct pm8xx_buck_desc *info = get_buck_reg(dev->parent, buck);
+ *
+ *     if (info == NULL)
+ *             return -ENOSYS;
+ *
+ *     sel = regulator_map_voltage_linear_range(info, uvolt, uvolt);
+ *     if (sel >=0) {
+ *              // has get the selctor
+ *              sel <<= ffs(info->vsel_sleep_msk) - 1;
+ *              ret = pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, info->vsel_sleep_msk, sel);
+ *     }
+ *
+ *     return ret;
+ */
+       return 0;
+}
+
+static int buck_get_suspend_value(struct udevice *dev)
+{
+       /* the hardware has already support the function */
+/**
+ *     int buck = dev->driver_data - 1;
+ *     const struct pm8xx_buck_desc *info = get_buck_reg(dev->parent, buck);
+ *     int mask = info->vsel_sleep_msk;
+ *     int ret;
+ *     unsigned int val;
+ *
+ *     if (info == NULL)
+ *             return -ENOSYS;
+ *
+ *     ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
+ *     if (ret < 0)
+ *             return ret;
+ *     val = ret & mask;
+ *
+ *     val >>= ffs(mask) - 1;
+ *
+ *     return regulator_desc_list_voltage_linear_range(info, val);
+ */
+       return 0;
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+       int ret, val;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_buck_reg(dev->parent, buck);
+       int mask = info->enable_msk;
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       ret = pmic_reg_read(dev->parent, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       val = ret & mask;
+
+       val >>= ffs(mask) - 1;
+
+       return val;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+       int ret;
+       unsigned int val = 0;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_buck_reg(dev->parent, buck);
+       int mask = info->enable_msk;
+
+       ret = pmic_reg_read(dev->parent, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       val = (unsigned int)ret;
+       val &= mask;
+       val >>= ffs(mask) - 1;
+
+       if (enable == val)
+               return 0;
+
+       val = enable << (ffs(mask) - 1);
+
+       ret = pmic_clrsetbits(dev->parent, info->enable_reg, info->enable_msk, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int buck_set_suspend_enable(struct udevice *dev, bool enable)
+{
+       /* TODO */
+       return 0;
+}
+
+static int buck_get_suspend_enable(struct udevice *dev)
+{
+       /* TODO */
+       return 0;
+}
+
+static int pm8xx_buck_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_plat *uc_pdata;
+
+       uc_pdata = dev_get_uclass_plat(dev);
+
+       uc_pdata->type = REGULATOR_TYPE_BUCK;
+       uc_pdata->mode_count = 0;
+
+       return 0;
+}
+
+static const struct dm_regulator_ops pm8xx_buck_ops = {
+       .get_value  = buck_get_value,
+       .set_value  = buck_set_value,
+       .set_suspend_value = buck_set_suspend_value,
+       .get_suspend_value = buck_get_suspend_value,
+       .get_enable = buck_get_enable,
+       .set_enable = buck_set_enable,
+       .set_suspend_enable = buck_set_suspend_enable,
+       .get_suspend_enable = buck_get_suspend_enable,
+};
+
+U_BOOT_DRIVER(pm8xx_buck) = {
+       .name = "pm8xx_buck",
+       .id = UCLASS_REGULATOR,
+       .ops = &pm8xx_buck_ops,
+       .probe = pm8xx_buck_probe,
+};
+
+static const struct pm8xx_buck_desc *get_ldo_reg(struct udevice *pmic, int num)
+{
+       struct pm8xx_priv *priv = dev_get_priv(pmic);
+       struct regulator_match_data *math = (struct regulator_match_data *)priv->match;
+
+       return math->ldo_desc + num;
+
+       return NULL;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_ldo_reg(dev->parent, buck);
+       int mask = info->vsel_msk;
+       int ret;
+       unsigned int val;
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       ret = pmic_reg_read(dev->parent, info->vsel_reg);
+       if (ret < 0)
+               return ret;
+
+       val = ret & mask;
+
+       val >>= ffs(mask) - 1;
+
+       return regulator_desc_list_voltage_linear_range(info, val);
+}
+
+static int ldo_set_value(struct udevice *dev, int uvolt)
+{
+       int sel, ret = -EINVAL;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_ldo_reg(dev->parent, buck);
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       sel = regulator_map_voltage_linear_range(info, uvolt, uvolt);
+       if (sel >=0) {
+               /* has get the selctor */
+                sel <<= ffs(info->vsel_msk) - 1;
+                ret = pmic_clrsetbits(dev->parent, info->vsel_reg, info->vsel_msk, sel);
+       }
+
+       return ret;
+}
+
+static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
+{
+/**
+ *     int sel, ret = -EINVAL;
+ *     int buck = dev->driver_data - 1;
+ *     const struct pm8xx_buck_desc *info = get_ldo_reg(dev->parent, buck);
+ *
+ *     if (info == NULL)
+ *             return -ENOSYS;
+ *
+ *     sel = regulator_map_voltage_linear_range(info, uvolt, uvolt);
+ *     if (sel >=0) {
+ *     
+ *              sel <<= ffs(info->vsel_sleep_msk) - 1;
+ *              ret = pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, info->vsel_sleep_msk, sel);
+ *     }
+ *
+ *     return ret;
+ */
+       return 0;
+}
+
+static int ldo_get_suspend_value(struct udevice *dev)
+{
+/**
+ *     int buck = dev->driver_data - 1;
+ *     const struct pm8xx_buck_desc *info = get_ldo_reg(dev->parent, buck);
+ *     int mask = info->vsel_sleep_msk;
+ *     int ret;
+ *     unsigned int val;
+ *
+ *     if (info == NULL)
+ *             return -ENOSYS;
+ *
+ *     ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
+ *     if (ret < 0)
+ *             return ret;
+ *     val = ret & mask;
+ *
+ *     val >>= ffs(mask) - 1;
+ *
+ *     return regulator_desc_list_voltage_linear_range(info, val);
+ */
+       return 0;
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+       int ret;
+       unsigned int val;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_ldo_reg(dev->parent, buck);
+       int mask = info->enable_msk;
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       ret = pmic_reg_read(dev->parent, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       val = ret & mask;
+
+       val >>= ffs(mask) - 1;
+
+       return val;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+       int ret;
+       unsigned int val = 0;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_ldo_reg(dev->parent, buck);
+       int mask = info->enable_msk;
+
+       ret = pmic_reg_read(dev->parent, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       val = (unsigned int)ret;
+       val &= mask;
+       val >>= ffs(mask) - 1;
+
+       if (enable == val)
+               return 0;
+
+       val = enable << (ffs(mask) - 1);
+
+       ret = pmic_clrsetbits(dev->parent, info->enable_reg, info->enable_msk, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
+{
+       /* TODO */
+       return 0;
+}
+
+static int ldo_get_suspend_enable(struct udevice *dev)
+{
+       /* TODO */
+       return 0;
+}
+
+static const struct dm_regulator_ops pm8xx_ldo_ops = {
+       .get_value  = ldo_get_value,
+       .set_value  = ldo_set_value,
+       .set_suspend_value = ldo_set_suspend_value,
+       .get_suspend_value = ldo_get_suspend_value,
+       .get_enable = ldo_get_enable,
+       .set_enable = ldo_set_enable,
+       .set_suspend_enable = ldo_set_suspend_enable,
+       .get_suspend_enable = ldo_get_suspend_enable,
+};
+
+static int pm8xx_ldo_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_plat *uc_pdata;
+
+       uc_pdata = dev_get_uclass_plat(dev);
+
+       uc_pdata->type = REGULATOR_TYPE_LDO;
+       uc_pdata->mode_count = 0;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(pm8xx_ldo) = {
+       .name = "pm8xx_ldo",
+       .id = UCLASS_REGULATOR,
+       .ops = &pm8xx_ldo_ops,
+       .probe = pm8xx_ldo_probe,
+};
+
+static const struct pm8xx_buck_desc *get_switch_reg(struct udevice *pmic, int num)
+{
+       struct pm8xx_priv *priv = dev_get_priv(pmic);
+       struct regulator_match_data *math = (struct regulator_match_data *)priv->match;
+
+       return math->switch_desc + num;
+
+       return NULL;
+}
+
+static int switch_get_value(struct udevice *dev)
+{
+       return 0;
+}
+
+static int switch_set_value(struct udevice *dev, int uvolt)
+{
+       return 0;
+}
+
+static int switch_get_enable(struct udevice *dev)
+{
+       int ret;
+       unsigned int val;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_switch_reg(dev->parent, buck);
+       int mask = info->enable_msk;
+
+       if (info == NULL)
+               return -ENOSYS;
+
+       ret = pmic_reg_read(dev->parent, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       val = ret & mask;
+
+       val >>= ffs(mask) - 1;
+
+       return val;
+}
+
+static int switch_set_enable(struct udevice *dev, bool enable)
+{
+       int ret;
+       unsigned int val = 0;
+       int buck = dev->driver_data - 1;
+       const struct pm8xx_buck_desc *info = get_switch_reg(dev->parent, buck);
+       int mask = info->enable_msk;
+
+       ret = pmic_reg_read(dev->parent, info->enable_reg);
+       if (ret < 0)
+               return ret;
+
+       val = (unsigned int)ret;
+       val &= mask;
+       val >>= ffs(mask) - 1;
+
+       if (enable == val)
+               return 0;
+
+       val = enable << (ffs(mask) - 1);
+
+       ret = pmic_clrsetbits(dev->parent, info->enable_reg, info->enable_msk, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+
+}
+
+static int switch_set_suspend_enable(struct udevice *dev, bool enable)
+{
+       /* TODO */
+       return 0;
+}
+
+static int switch_get_suspend_enable(struct udevice *dev)
+{
+       /* TODO */
+       return 0;
+}
+
+static int switch_set_suspend_value(struct udevice *dev, int uvolt)
+{
+       return 0;
+}
+
+static int switch_get_suspend_value(struct udevice *dev)
+{
+       return 0;
+}
+
+static const struct dm_regulator_ops pm8xx_switch_ops = {
+       .get_value  = switch_get_value,
+       .set_value  = switch_set_value,
+       .get_enable = switch_get_enable,
+       .set_enable = switch_set_enable,
+       .set_suspend_enable = switch_set_suspend_enable,
+       .get_suspend_enable = switch_get_suspend_enable,
+       .set_suspend_value = switch_set_suspend_value,
+       .get_suspend_value = switch_get_suspend_value,
+};
+
+static int pm8xx_switch_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_plat *uc_pdata;
+
+       uc_pdata = dev_get_uclass_plat(dev);
+
+       uc_pdata->type = REGULATOR_TYPE_FIXED;
+       uc_pdata->mode_count = 0;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(pm8xx_switch) = {
+       .name = "pm8xx_switch",
+       .id = UCLASS_REGULATOR,
+       .ops = &pm8xx_switch_ops,
+       .probe = pm8xx_switch_probe,
+};
index 69a7b4ccbad6bb11d45e2d2b892e092202010520..beb502c3460798e965e01ff5ff79834c1e102d69 100644 (file)
@@ -212,4 +212,18 @@ config RESET_DRA7
        help
          Support for TI DRA7-RESET subsystem. Basic Assert/Deassert
          is supported.
+
+config RESET_SPACEMIT_K1PRO
+       bool "Support for SPACEMIT's K1-PRO Reset driver"
+       depends on DM_RESET
+       help
+         Support for SPACEMIT's K1-PRO Reset system. Basic Assert/Deassert
+         is supported.
+
+config RESET_SPACEMIT_K1X
+       bool "Support for SPACEMIT's K1X Reset driver"
+       depends on DM_RESET
+       help
+         Support for SPACEMIT's K1X Reset system. Basic Assert/Deassert
+         is supported.
 endmenu
index 97e3a782c0d804240d563e306ac5243dbd080989..b97c4fd5796269fa88833baea90b911c2cb1c80b 100644 (file)
@@ -31,3 +31,5 @@ obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
 obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o
 obj-$(CONFIG_RESET_DRA7) += reset-dra7.o
+obj-$(CONFIG_RESET_SPACEMIT_K1PRO) += reset-spacemit-k1pro.o
+obj-$(CONFIG_RESET_SPACEMIT_K1X) += reset-spacemit-k1x.o
diff --git a/drivers/reset/reset-spacemit-k1x.c b/drivers/reset/reset-spacemit-k1x.c
new file mode 100644 (file)
index 0000000..1cb4955
--- /dev/null
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for reset of spacemit k1x in uboot
+ *
+ * Copyright (C) 2023 Spacemit
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset-uclass.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/bitops.h>
+#include <dt-bindings/reset/reset-spacemit-k1x.h>
+
+/* APBC register offset */
+#define APBC_UART1_CLK_RST      0x0
+#define APBC_UART2_CLK_RST      0x4
+#define APBC_GPIO_CLK_RST       0x8
+#define APBC_PWM0_CLK_RST       0xc
+#define APBC_PWM1_CLK_RST       0x10
+#define APBC_PWM2_CLK_RST       0x14
+#define APBC_PWM3_CLK_RST       0x18
+#define APBC_TWSI8_CLK_RST      0x20
+#define APBC_UART3_CLK_RST      0x24
+#define APBC_RTC_CLK_RST        0x28
+#define APBC_TWSI0_CLK_RST      0x2c
+#define APBC_TWSI1_CLK_RST      0x30
+#define APBC_TIMERS1_CLK_RST    0x34
+#define APBC_TWSI2_CLK_RST      0x38
+#define APBC_AIB_CLK_RST        0x3c
+#define APBC_TWSI4_CLK_RST      0x40
+#define APBC_TIMERS2_CLK_RST    0x44
+#define APBC_ONEWIRE_CLK_RST    0x48
+#define APBC_TWSI5_CLK_RST      0x4c
+#define APBC_DRO_CLK_RST        0x58
+#define APBC_IR_CLK_RST         0x5c
+#define APBC_TWSI6_CLK_RST      0x60
+#define APBC_TWSI7_CLK_RST      0x68
+#define APBC_TSEN_CLK_RST       0x6c
+
+#define APBC_UART4_CLK_RST      0x70
+#define APBC_UART5_CLK_RST      0x74
+#define APBC_UART6_CLK_RST      0x78
+#define APBC_SSP3_CLK_RST       0x7c
+
+#define APBC_SSPA0_CLK_RST      0x80
+#define APBC_SSPA1_CLK_RST      0x84
+
+#define APBC_IPC_AP2AUD_CLK_RST 0x90
+#define APBC_UART7_CLK_RST      0x94
+#define APBC_UART8_CLK_RST      0x98
+#define APBC_UART9_CLK_RST      0x9c
+
+#define APBC_CAN0_CLK_RST       0xa0
+#define APBC_PWM4_CLK_RST       0xa8
+#define APBC_PWM5_CLK_RST       0xac
+#define APBC_PWM6_CLK_RST       0xb0
+#define APBC_PWM7_CLK_RST       0xb4
+#define APBC_PWM8_CLK_RST       0xb8
+#define APBC_PWM9_CLK_RST       0xbc
+#define APBC_PWM10_CLK_RST      0xc0
+#define APBC_PWM11_CLK_RST      0xc4
+#define APBC_PWM12_CLK_RST      0xc8
+#define APBC_PWM13_CLK_RST      0xcc
+#define APBC_PWM14_CLK_RST      0xd0
+#define APBC_PWM15_CLK_RST      0xd4
+#define APBC_PWM16_CLK_RST      0xd8
+#define APBC_PWM17_CLK_RST      0xdc
+#define APBC_PWM18_CLK_RST      0xe0
+#define APBC_PWM19_CLK_RST      0xe4
+/* end of APBC register offset */
+
+/* MPMU register offset */
+#define MPMU_WDTPCR     0x200
+/* end of MPMU register offset */
+
+/* APMU register offset */
+#define APMU_JPG_CLK_RES_CTRL       0x20
+#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24
+#define APMU_ISP_CLK_RES_CTRL       0x38
+#define APMU_LCD_CLK_RES_CTRL1      0x44
+#define APMU_LCD_SPI_CLK_RES_CTRL   0x48
+#define APMU_LCD_CLK_RES_CTRL2      0x4c
+#define APMU_CCIC_CLK_RES_CTRL      0x50
+#define APMU_SDH0_CLK_RES_CTRL      0x54
+#define APMU_SDH1_CLK_RES_CTRL      0x58
+#define APMU_USB_CLK_RES_CTRL       0x5c
+#define APMU_QSPI_CLK_RES_CTRL      0x60
+#define APMU_USB_CLK_RES_CTRL       0x5c
+#define APMU_DMA_CLK_RES_CTRL       0x64
+#define APMU_AES_CLK_RES_CTRL       0x68
+#define APMU_VPU_CLK_RES_CTRL       0xa4
+#define APMU_GPU_CLK_RES_CTRL       0xcc
+#define APMU_SDH2_CLK_RES_CTRL      0xe0
+#define APMU_PMUA_MC_CTRL           0xe8
+#define APMU_PMU_CC2_AP             0x100
+#define APMU_PMUA_EM_CLK_RES_CTRL   0x104
+
+#define APMU_AUDIO_CLK_RES_CTRL     0x14c
+#define APMU_HDMI_CLK_RES_CTRL      0x1B8
+
+#define APMU_PCIE_CLK_RES_CTRL_0    0x3cc
+#define APMU_PCIE_CLK_RES_CTRL_1    0x3d4
+#define APMU_PCIE_CLK_RES_CTRL_2    0x3dc
+
+#define APMU_EMAC0_CLK_RES_CTRL     0x3e4
+#define APMU_EMAC1_CLK_RES_CTRL     0x3ec
+/* end of APMU register offset */
+
+/* APBC2 register offset */
+#define APBC2_UART1_CLK_RST            0x00
+#define APBC2_SSP2_CLK_RST             0x04
+#define APBC2_TWSI3_CLK_RST            0x08
+#define APBC2_RTC_CLK_RST              0x0c
+#define APBC2_TIMERS0_CLK_RST          0x10
+#define APBC2_KPC_CLK_RST              0x14
+#define APBC2_GPIO_CLK_RST             0x1c
+/* end of APBC2 register offset */
+
+enum spacemit_reset_base_type{
+       RST_BASE_TYPE_MPMU       = 0,
+       RST_BASE_TYPE_APMU       = 1,
+       RST_BASE_TYPE_APBC       = 2,
+       RST_BASE_TYPE_APBS       = 3,
+       RST_BASE_TYPE_CIU        = 4,
+       RST_BASE_TYPE_DCIU       = 5,
+       RST_BASE_TYPE_DDRC       = 6,
+       RST_BASE_TYPE_AUDC       = 7,
+       RST_BASE_TYPE_APBC2      = 8,
+};
+
+struct spacemit_reset_signal {
+       u32 offset;
+       u32 mask;
+       u32 deassert_val;
+       u32 assert_val;
+       enum spacemit_reset_base_type type;
+};
+
+struct spacemit_reset {
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbc_base;
+       void __iomem *apbs_base;
+       void __iomem *ciu_base;
+       void __iomem *dciu_base;
+       void __iomem *ddrc_base;
+       void __iomem *audio_ctrl_base;
+       void __iomem *apbc2_base;
+       const struct spacemit_reset_signal *signals;
+};
+
+enum {
+       RESET_TWSI6_SPL = 0,
+       RESET_TWSI8_SPL,
+       RESET_SDH_AXI_SPL,
+       RESET_SDH0_SPL,
+       RESET_USB_AXI_SPL,
+       RESET_USBP1_AXI_SPL,
+       RESET_USB3_0_SPL,
+       RESET_QSPI_SPL,
+       RESET_QSPI_BUS_SPL,
+       RESET_AES_SPL,
+       RESET_SDH2_SPL,
+       RESET_NUMBER_SPL,
+};
+
+#ifdef CONFIG_SPL_BUILD
+static u32 transfer_to_spl_list[][2] = {
+       {RESET_TWSI6, RESET_TWSI6_SPL},
+       {RESET_TWSI8, RESET_TWSI8_SPL},
+       {RESET_SDH_AXI, RESET_SDH_AXI_SPL},
+       {RESET_SDH0, RESET_SDH0_SPL},
+       {RESET_USB_AXI, RESET_USB_AXI_SPL},
+       {RESET_USBP1_AXI, RESET_USBP1_AXI_SPL},
+       {RESET_USB3_0, RESET_USB3_0_SPL},
+       {RESET_QSPI, RESET_QSPI_SPL},
+       {RESET_QSPI_BUS, RESET_QSPI_BUS_SPL},
+       {RESET_SDH2, RESET_SDH2_SPL},
+       {RESET_AES, RESET_AES_SPL},
+};
+
+static const struct spacemit_reset_signal
+       k1x_reset_signals[RESET_NUMBER_SPL] = {
+       [RESET_TWSI6_SPL]   = { APBC_TWSI6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI8_SPL]   = { APBC_TWSI8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_SDH_AXI_SPL]     = { APMU_SDH0_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_SDH0_SPL]      = { APMU_SDH0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_USB_AXI_SPL]   = { APMU_USB_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_USBP1_AXI_SPL] = { APMU_USB_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+       [RESET_USB3_0_SPL]    = { APMU_USB_CLK_RES_CTRL, BIT(9)|BIT(10)|BIT(11), BIT(9)|BIT(10)|BIT(11), 0, RST_BASE_TYPE_APMU },
+       [RESET_QSPI_SPL]  = { APMU_QSPI_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_QSPI_BUS_SPL]  = { APMU_QSPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_SDH2_SPL] = { APMU_SDH2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_AES_SPL]  = { APMU_AES_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+       };
+
+static u32 transfer_reset_id_to_spl(u32 id)
+{
+       u32 listsize = ARRAY_SIZE(transfer_to_spl_list);
+
+       for (int i = 0; i < listsize; i++){
+               if (id == transfer_to_spl_list[i][0]){
+                       pr_info("id:%d, %d,\n", id, transfer_to_spl_list[i][1]);
+                       return transfer_to_spl_list[i][1];
+               }
+       }
+       return id;
+}
+#else
+static const struct spacemit_reset_signal
+       k1x_reset_signals[RESET_NUMBER] = {
+       [RESET_UART1]   = { APBC_UART1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART2]   = { APBC_UART2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_GPIO]    = { APBC_GPIO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM0]    = { APBC_PWM0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM1]    = { APBC_PWM1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM2]    = { APBC_PWM2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM3]    = { APBC_PWM3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM4]    = { APBC_PWM4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM5]    = { APBC_PWM5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM6]    = { APBC_PWM6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM7]    = { APBC_PWM7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM8]    = { APBC_PWM8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM9]    = { APBC_PWM9_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM10]   = { APBC_PWM10_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM11]   = { APBC_PWM11_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM12]   = { APBC_PWM12_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM13]   = { APBC_PWM13_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM14]   = { APBC_PWM14_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM15]   = { APBC_PWM15_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM16]   = { APBC_PWM16_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM17]   = { APBC_PWM17_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM18]   = { APBC_PWM18_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_PWM19]   = { APBC_PWM19_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_SSP3]    = { APBC_SSP3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART3]   = { APBC_UART3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_RTC]     = { APBC_RTC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI0]   = { APBC_TWSI0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TIMERS1] = { APBC_TIMERS1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_AIB]     = { APBC_AIB_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TIMERS2] = { APBC_TIMERS2_CLK_RST,BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_ONEWIRE] = { APBC_ONEWIRE_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_SSPA0]   = { APBC_SSPA0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_SSPA1]   = { APBC_SSPA1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_DRO]     = { APBC_DRO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_IR]      = { APBC_IR_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI1]   = { APBC_TWSI1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TSEN]    = { APBC_TSEN_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI2]   = { APBC_TWSI2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI4]   = { APBC_TWSI4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI5]   = { APBC_TWSI5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI6]   = { APBC_TWSI6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI7]   = { APBC_TWSI7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_TWSI8]   = { APBC_TWSI8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_IPC_AP2AUD]   = { APBC_IPC_AP2AUD_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART4]   = { APBC_UART4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART5]   = { APBC_UART5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART6]   = { APBC_UART6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART7]   = { APBC_UART7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART8]   = { APBC_UART8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_UART9]   = { APBC_UART9_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       [RESET_CAN0]    = { APBC_CAN0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+       //MPMU
+       [RESET_WDT]     = { MPMU_WDTPCR, BIT(2), 0, BIT(2), RST_BASE_TYPE_MPMU },
+       //APMU
+       [RESET_JPG]     = { APMU_JPG_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_CSI]     = { APMU_CSI_CCIC2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_CCIC2_PHY]   = { APMU_CSI_CCIC2_CLK_RES_CTRL, BIT(2), BIT(2), 0, RST_BASE_TYPE_APMU },
+       [RESET_CCIC3_PHY]   = { APMU_CSI_CCIC2_CLK_RES_CTRL, BIT(29), BIT(29), 0, RST_BASE_TYPE_APMU },
+       [RESET_ISP]     = { APMU_ISP_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_ISP_AHB] = { APMU_ISP_CLK_RES_CTRL, BIT(3), BIT(3), 0, RST_BASE_TYPE_APMU },
+       [RESET_ISP_CI]  = { APMU_ISP_CLK_RES_CTRL, BIT(16), BIT(16), 0, RST_BASE_TYPE_APMU },
+       [RESET_ISP_CPP] = { APMU_ISP_CLK_RES_CTRL, BIT(27), BIT(27), 0, RST_BASE_TYPE_APMU },
+       [RESET_LCD]     = { APMU_LCD_CLK_RES_CTRL1, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+       [RESET_DSI_ESC] = { APMU_LCD_CLK_RES_CTRL1, BIT(3), BIT(3), 0, RST_BASE_TYPE_APMU },
+       [RESET_V2D]     = { APMU_LCD_CLK_RES_CTRL1, BIT(27), BIT(27), 0, RST_BASE_TYPE_APMU },
+       [RESET_MIPI]    = { APMU_LCD_CLK_RES_CTRL1, BIT(15), BIT(15), 0, RST_BASE_TYPE_APMU },
+       [RESET_LCD_SPI] = { APMU_LCD_SPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_LCD_SPI_BUS]     = { APMU_LCD_SPI_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+       [RESET_LCD_SPI_HBUS]    = { APMU_LCD_SPI_CLK_RES_CTRL, BIT(2), BIT(2), 0, RST_BASE_TYPE_APMU },
+       [RESET_LCD_MCLK]    = { APMU_LCD_CLK_RES_CTRL2, BIT(9), BIT(9), 0, RST_BASE_TYPE_APMU },
+       [RESET_CCIC_4X]     = { APMU_CCIC_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_CCIC1_PHY]   = { APMU_CCIC_CLK_RES_CTRL, BIT(2), BIT(2), 0, RST_BASE_TYPE_APMU },
+       [RESET_SDH_AXI]     = { APMU_SDH0_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_SDH0]      = { APMU_SDH0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_SDH1]      = { APMU_SDH1_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_USB_AXI]   = { APMU_USB_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_USBP1_AXI] = { APMU_USB_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+       [RESET_USB3_0]    = { APMU_USB_CLK_RES_CTRL, BIT(9)|BIT(10)|BIT(11), BIT(9)|BIT(10)|BIT(11), 0, RST_BASE_TYPE_APMU },
+       [RESET_QSPI]  = { APMU_QSPI_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_QSPI_BUS]  = { APMU_QSPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_DMA]      = { APMU_DMA_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_AES]      = { APMU_AES_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+       [RESET_VPU]      = { APMU_VPU_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_GPU]      = { APMU_GPU_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_SDH2] = { APMU_SDH2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_MC]       = { APMU_PMUA_MC_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_EM_AXI] = { APMU_PMUA_EM_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+       [RESET_EM]         = { APMU_PMUA_EM_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_AUDIO_SYS]        = { APMU_AUDIO_CLK_RES_CTRL, BIT(0)|BIT(2)|BIT(3), BIT(0)|BIT(2)|BIT(3), 0, RST_BASE_TYPE_APMU },
+       [RESET_HDMI]     = { APMU_HDMI_CLK_RES_CTRL, BIT(9), BIT(9), 0, RST_BASE_TYPE_APMU },
+       [RESET_PCIE0]    = { APMU_PCIE_CLK_RES_CTRL_0, BIT(3)|BIT(4)|BIT(5)|BIT(8), BIT(3)|BIT(4)|BIT(5), BIT(8), RST_BASE_TYPE_APMU },
+       [RESET_PCIE1]    = { APMU_PCIE_CLK_RES_CTRL_1, BIT(3)|BIT(4)|BIT(5)|BIT(8), BIT(3)|BIT(4)|BIT(5), BIT(8), RST_BASE_TYPE_APMU },
+       [RESET_PCIE2]    = { APMU_PCIE_CLK_RES_CTRL_2, 0x138, 0x38, 0x100, RST_BASE_TYPE_APMU },
+       [RESET_EMAC0]    = { APMU_EMAC0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_EMAC1]    = { APMU_EMAC1_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+       [RESET_SEC_UART1]       = { APBC2_UART1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       [RESET_SEC_SSP2]        = { APBC2_SSP2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       [RESET_SEC_TWSI3]       = { APBC2_TWSI3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       [RESET_SEC_RTC]         = { APBC2_RTC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       [RESET_SEC_TIMERS0]     = { APBC2_TIMERS0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       [RESET_SEC_KPC]         = { APBC2_KPC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       [RESET_SEC_GPIO]        = { APBC2_GPIO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+       };
+#endif
+
+
+static u32 spacemit_reset_read(struct spacemit_reset *reset,
+       u32 id)
+{
+       void __iomem *base;
+       switch(reset->signals[id].type){
+       case RST_BASE_TYPE_APMU:
+               base = reset->apmu_base;
+               break;
+       case RST_BASE_TYPE_APBC:
+               base = reset->apbc_base;
+               break;
+#ifndef CONFIG_SPL_BUILD
+       case RST_BASE_TYPE_MPMU:
+               base = reset->mpmu_base;
+               break;
+       case RST_BASE_TYPE_APBS:
+               base = reset->apbs_base;
+               break;
+       case RST_BASE_TYPE_CIU:
+               base = reset->ciu_base;
+               break;
+       case RST_BASE_TYPE_DCIU:
+               base = reset->dciu_base;
+               break;
+       case RST_BASE_TYPE_DDRC:
+               base = reset->ddrc_base;
+               break;
+       case RST_BASE_TYPE_AUDC:
+               base = reset->audio_ctrl_base;
+               break;
+       case RST_BASE_TYPE_APBC2:
+               base = reset->apbc2_base;
+               break;
+#endif
+       default:
+               base = reset->apbc_base;
+               break;
+       }
+       return readl(base + reset->signals[id].offset);
+}
+
+static void spacemit_reset_write(struct spacemit_reset *reset, u32 value,
+       u32 id)
+{
+       void __iomem *base;
+       switch (reset->signals[id].type) {
+       case RST_BASE_TYPE_APMU:
+               base = reset->apmu_base;
+               break;
+       case RST_BASE_TYPE_APBC:
+               base = reset->apbc_base;
+               break;
+#ifndef CONFIG_SPL_BUILD
+       case RST_BASE_TYPE_MPMU:
+               base = reset->mpmu_base;
+               break;
+       case RST_BASE_TYPE_APBS:
+               base = reset->apbs_base;
+               break;
+       case RST_BASE_TYPE_CIU:
+               base = reset->ciu_base;
+               break;
+       case RST_BASE_TYPE_DCIU:
+               base = reset->dciu_base;
+               break;
+       case RST_BASE_TYPE_DDRC:
+               base = reset->ddrc_base;
+               break;
+       case RST_BASE_TYPE_AUDC:
+               base = reset->audio_ctrl_base;
+               break;
+       case RST_BASE_TYPE_APBC2:
+               base = reset->apbc2_base;
+               break;
+#endif
+       default:
+               base = reset->apbc_base;
+               break;
+       }
+
+       writel(value, base + reset->signals[id].offset);
+}
+
+static void spacemit_reset_set(struct reset_ctl *rst,
+       u32 id, bool assert)
+{
+       u32 value;
+       struct spacemit_reset *reset = dev_get_priv(rst->dev);
+
+       pr_info("[RESET]spacemit_reset_set assert=%d, id=%d \r\n", assert, id);
+       value = spacemit_reset_read(reset, id);
+       if(assert == true) {
+               value &= ~ reset->signals[id].mask;
+               value |=reset->signals[id].assert_val;
+       } else {
+               value &= ~reset->signals[id].mask;
+               value |= reset->signals[id].deassert_val;
+       }
+
+       spacemit_reset_write(reset, value, id);
+}
+
+static int spacemit_reset_update(struct reset_ctl *rst, bool assert)
+{
+#ifdef CONFIG_SPL_BUILD
+       rst->id = transfer_reset_id_to_spl(rst->id);
+       if(rst->id < RESET_TWSI6_SPL || rst->id >= RESET_NUMBER_SPL)
+               return 0;
+
+       /* can not write to twsi8*/
+       if (rst->id == RESET_TWSI8_SPL)
+               return 0;
+#else
+       if(rst->id < RESET_UART1 || rst->id >= RESET_NUMBER)
+               return 0;
+
+       /* can not write to twsi8*/
+       if (rst->id == RESET_TWSI8)
+               return 0;
+#endif
+
+       spacemit_reset_set(rst, rst->id, assert);
+       return 0;
+}
+
+static int spacemit_reset_assert(struct reset_ctl *rst)
+{
+       return spacemit_reset_update(rst, true);
+}
+
+static int spacemit_reset_deassert(struct reset_ctl *rst)
+{
+       return spacemit_reset_update(rst, false);
+}
+
+
+static int spacemit_k1x_reset_probe(struct udevice *dev)
+{
+       struct spacemit_reset *reset = dev_get_priv(dev);
+       pr_info("[RESET]probe start \r\n");
+
+       reset->mpmu_base = (void __iomem *)dev_remap_addr_index(dev, 0);
+       if (!reset->mpmu_base) {
+               pr_err("failed to map mpmu registers\n");
+               goto out;
+       }
+
+       reset->apmu_base = (void __iomem *)dev_remap_addr_index(dev, 1);
+       if (!reset->apmu_base) {
+               pr_err("failed to map apmu registers\n");
+               goto out;
+       }
+
+       reset->apbc_base = (void __iomem *)dev_remap_addr_index(dev, 2);
+       if (!reset->apbc_base) {
+               pr_err("failed to map apbc registers\n");
+               goto out;
+       }
+
+       reset->apbs_base = (void __iomem *)dev_remap_addr_index(dev, 3);
+       if (!reset->apbs_base) {
+               pr_err("failed to map apbs registers\n");
+               goto out;
+       }
+
+       reset->ciu_base = (void __iomem *)dev_remap_addr_index(dev, 4);
+       if (!reset->ciu_base) {
+               pr_err("failed to map ciu registers\n");
+               goto out;
+       }
+
+       reset->dciu_base = (void __iomem *)dev_remap_addr_index(dev, 5);
+       if (!reset->dciu_base) {
+               pr_err("failed to map dragon ciu registers\n");
+               goto out;
+       }
+
+       reset->ddrc_base = (void __iomem *)dev_remap_addr_index(dev, 6);
+       if (!reset->ddrc_base) {
+               pr_err("failed to map ddrc registers\n");
+               goto out;
+       }
+
+       reset->apbc2_base = (void __iomem *)dev_remap_addr_index(dev, 7);
+       if (!reset->apbc2_base) {
+               pr_err("failed to map apbc2 registers\n");
+               goto out;
+       }
+       reset->signals = k1x_reset_signals;
+       pr_info("[RESET]probe finish \r\n");
+out:
+       return 0;
+}
+
+const struct reset_ops k1x_reset_ops = {
+       .rst_assert = spacemit_reset_assert,
+       .rst_deassert = spacemit_reset_deassert,
+};
+
+static const struct udevice_id k1x_reset_ids[] = {
+       { .compatible = "spacemit,k1x-reset", },
+       {},
+};
+
+U_BOOT_DRIVER(k1x_reset) = {
+       .name           = "spacemit,k1x-reset",
+       .id             = UCLASS_RESET,
+       .ops            = &k1x_reset_ops,
+       .of_match = k1x_reset_ids,
+       .probe          = spacemit_k1x_reset_probe,
+       .priv_auto      = sizeof(struct spacemit_reset),
+};
index de02e08a299620e8ccd779d1f8c37f2aa49933c4..aba66b00609462cac50afad39cb5cf0b0603f926 100644 (file)
@@ -751,6 +751,13 @@ config NS16550_DYNAMIC
          UARTs in a system. This option avoids this problem at the cost of a
          slightly increased code size.
 
+config SYS_NS16550_IER
+       hex "NS16550 ier bit"
+       depends on SYS_NS16550
+       default 0x00
+       help
+         Set ier bit for ns16550.
+
 config INTEL_MID_SERIAL
        bool "Intel MID platform UART support"
        depends on DM_SERIAL && OF_CONTROL
index 47bad6f8e2a9613f97e3c3756de0a6c5f09590e1..ef4b5f833d895fed3417b186575d6bd7035dd56e 100644 (file)
@@ -219,8 +219,18 @@ static void ns16550_setbrg(struct ns16550 *com_port, int baud_divisor)
        int lcr_val = serial_in(&com_port->lcr) & ~UART_LCR_BKSE;
 
        serial_out(UART_LCR_BKSE | lcr_val, &com_port->lcr);
+#ifdef CONFIG_TARGET_SPACEMIT_K1X
+       /*
+        * the right DLL/DLH setting sequence is:
+        * write DLH --> read DLH --> write DLL
+        */
+       serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
+       (void) serial_in(&com_port->dlm);
+       serial_out(baud_divisor & 0xff, &com_port->dll);
+#else
        serial_out(baud_divisor & 0xff, &com_port->dll);
        serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
+#endif
        serial_out(lcr_val, &com_port->lcr);
 }
 
@@ -345,8 +355,20 @@ static inline void _debug_uart_init(void)
        serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
 
        serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+
+#ifdef CONFIG_TARGET_SPACEMIT_K1X
+       /*
+        * the right DLL/DLH setting sequence is:
+        * write DLH --> read DLH --> write DLL
+        */
+       serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
+       (void) serial_din(&com_port->dlm);
+       serial_dout(&com_port->dll, baud_divisor & 0xff);
+#else
        serial_dout(&com_port->dll, baud_divisor & 0xff);
        serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
+#endif
+
        serial_dout(&com_port->lcr, UART_LCRVAL);
 }
 
index 75b794548b224a9df43716b9cbd0640afcaba8ab..c5993e67033be8748e8c2965fe49f7e0ce60fd73 100644 (file)
@@ -156,6 +156,13 @@ config DAVINCI_SPI
        help
          Enable the Davinci SPI driver
 
+config K1X_QSPI
+       tristate "Spacemit K1X QuadSPI driver"
+       depends on SPI_MEM
+       help
+         Enable the Spacemit K1X Quad-SPI (QSPI) driver.
+         This driver support spi flash single, quad and memory reads.
+
 config DESIGNWARE_SPI
        bool "Designware SPI driver"
        help
index 4de77c260adf8ece653f87dbdfecdf4bdc92002d..410a24dfb474e7ce934b17e20f03344430dc6045 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o
 obj-$(CONFIG_CF_SPI) += cf_spi.o
 obj-$(CONFIG_CORTINA_SFLASH) += ca_sflash.o
 obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
+obj-$(CONFIG_K1X_QSPI) += k1x_qspi.o
 obj-$(CONFIG_DESIGNWARE_SPI) += designware_spi.o
 obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
 obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
index 1c7d0ca310b6e8d0c37b23bf41b2e9dd36192a62..e97cb19fce926aa0254f840e73eef4501d2fa4fd 100644 (file)
@@ -667,7 +667,19 @@ static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
 /* The size of ctrl1 limits data transfers to 64K */
 static int dw_spi_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
 {
-       op->data.nbytes = min(op->data.nbytes, (unsigned int)SZ_64K);
+       struct dw_spi_priv *priv = dev_get_priv(slave->dev->parent);
+       u8 op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+
+       if (op->data.nbytes + op_len <= priv->fifo_len) {
+               return 0;
+       }
+
+       if (op->data.dir == SPI_MEM_DATA_IN) {
+               if (op->data.nbytes > priv->fifo_len)
+                       op->data.nbytes = priv->fifo_len;
+       } else {
+               op->data.nbytes = (priv->fifo_len - op_len);
+       }
 
        return 0;
 }
diff --git a/drivers/spi/k1x_qspi.c b/drivers/spi/k1x_qspi.c
new file mode 100644 (file)
index 0000000..42de3f4
--- /dev/null
@@ -0,0 +1,1041 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit k1x qspi controller driver
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <dm.h>
+#include <clk.h>
+#include <reset.h>
+#include <dm/device_compat.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <linux/iopoll.h>
+#include <linux/bug.h>
+#include <linux/ioport.h>
+
+#define K1X_DUMP_QSPI_REG              0
+
+/* QSPI PMUap register */
+#define PMUA_QSPI_CLK_RES_CTRL         0xd4282860
+#define QSPI_CLK_SEL(x)                        ((x) << 6)
+#define QSPI_CLK_SEL_MASK              GENMASK(8, 6)
+#define QSPI_CLK_EN                    BIT(4)
+#define QSPI_BUS_CLK_EN                        BIT(3)
+#define QSPI_CLK_RST                   BIT(1)
+#define QSPI_BUS_RST                   BIT(0)
+
+/* QSPI memory base */
+#define QSPI_AMBA_BASE                 0xb8000000
+#define QSPI_FLASH_A1_BASE             QSPI_AMBA_BASE
+#define QSPI_FLASH_A1_TOP              (QSPI_FLASH_A1_BASE + 0xa00000)
+#define QSPI_FLASH_A2_BASE             QSPI_FLASH_A1_TOP
+#define QSPI_FLASH_A2_TOP              (QSPI_FLASH_A2_BASE + 0x100000)
+#define QSPI_FLASH_B1_BASE             QSPI_FLASH_A2_TOP
+#define QSPI_FLASH_B1_TOP              (QSPI_FLASH_B1_BASE + 0x100000)
+#define QSPI_FLASH_B2_BASE             QSPI_FLASH_B1_TOP
+#define QSPI_FLASH_B2_TOP              (QSPI_FLASH_B2_BASE + 0x100000)
+
+/* TX/RX/ABH buffer max */
+#define QSPI_RX_BUFF_MAX               SZ_128
+#define QSPI_TX_BUFF_MAX               SZ_256
+#define QSPI_TX_BUFF_POP_MIN           16
+#define QSPI_AHB_BUFF_MAX_SIZE         SZ_512
+
+#define QSPI_WAIT_BIT_CLEAR            0
+#define QSPI_WAIT_BIT_SET              1
+
+#define k1x_QSPI_DEFAULT_CLK_FREQ      26000000
+
+/* QSPI Host Registers used by the driver */
+#define QSPI_MCR                       0x00
+#define QSPI_MCR_ISD_MASK              GENMASK(19, 16)
+#define QSPI_MCR_MDIS_MASK             BIT(14)
+#define QSPI_MCR_CLR_TXF_MASK          BIT(11)
+#define QSPI_MCR_CLR_RXF_MASK          BIT(10)
+#define QSPI_MCR_DDR_EN_MASK           BIT(7)
+#define QSPI_MCR_END_CFG_MASK          GENMASK(3, 2)
+#define QSPI_MCR_SWRSTHD_MASK          BIT(1)
+#define QSPI_MCR_SWRSTSD_MASK          BIT(0)
+
+#define QSPI_TCR                       0x04
+#define QSPI_IPCR                      0x08
+#define QSPI_IPCR_SEQID(x)             ((x) << 24)
+
+#define QSPI_FLSHCR                    0x0c
+
+#define QSPI_BUF0CR                    0x10
+#define QSPI_BUF1CR                    0x14
+#define QSPI_BUF2CR                    0x18
+#define QSPI_BUF3CR                    0x1c
+#define QSPI_BUF3CR_ALLMST_MASK                BIT(31)
+#define QSPI_BUF3CR_ADATSZ(x)          ((x) << 8)
+#define QSPI_BUF3CR_ADATSZ_MASK                GENMASK(15, 8)
+
+#define QSPI_BFGENCR                   0x20
+#define QSPI_BFGENCR_SEQID(x)          ((x) << 12)
+
+#define QSPI_SOCCR                     0x24
+
+#define QSPI_BUF0IND                   0x30
+#define QSPI_BUF1IND                   0x34
+#define QSPI_BUF2IND                   0x38
+
+#define QSPI_SFAR                      0x100
+#define QSPI_SFACR                     0x104
+
+#define QSPI_SMPR                      0x108
+#define QSPI_SMPR_DDRSMP_MASK          GENMASK(18, 16)
+#define QSPI_SMPR_FSDLY_MASK           BIT(6)
+#define QSPI_SMPR_FSPHS_MASK           BIT(5)
+#define QSPI_SMPR_HSENA_MASK           BIT(0)
+
+#define QSPI_RBSR                      0x10c
+
+#define QSPI_RBCT                      0x110
+#define QSPI_RBCT_WMRK_MASK            GENMASK(4, 0)
+#define QSPI_RBCT_RXBRD_MASK           BIT(8)
+
+#define QSPI_TBSR                      0x150
+#define QSPI_TBDR                      0x154
+#define QSPI_TBCT                      0x158
+
+#define QSPI_SR                                0x15c
+#define QSPI_SR_BUSY                   BIT(0)
+#define QSPI_SR_IP_ACC_MASK            BIT(1)
+#define QSPI_SR_AHB_ACC_MASK           BIT(2)
+#define QSPI_SR_TXFULL                 BIT(27)
+
+#define QSPI_FR                                0x160
+#define QSPI_FR_TFF_MASK               BIT(0)
+#define QSPI_FR_XIP_ON                 BIT(1)
+#define QSPI_FR_IPIEF                  BIT(6)
+
+#define QSPI_RSER                      0x164
+#define QSPI_RSER_TFIE                 BIT(0)
+
+#define QSPI_SPNDST                    0x168
+#define QSPI_SPTRCLR                   0x16c
+#define QSPI_SPTRCLR_IPPTRC            BIT(8)
+#define QSPI_SPTRCLR_BFPTRC            BIT(0)
+
+#define QSPI_SFA1AD                    0x180
+#define QSPI_SFA2AD                    0x184
+#define QSPI_SFB1AD                    0x188
+#define QSPI_SFB2AD                    0x18c
+#define QSPI_DLPR                      0x190
+#define QSPI_RBDR(x)                   (0x200 + ((x) * 4))
+
+#define QSPI_LUTKEY                    0x300
+#define QSPI_LUTKEY_VALUE              0x5af05af0
+
+#define QSPI_LCKCR                     0x304
+#define QSPI_LCKER_LOCK                        BIT(0)
+#define QSPI_LCKER_UNLOCK              BIT(1)
+
+#define QSPI_LUT_BASE                  0x310
+/* 16Bytes per sequence */
+#define QSPI_LUT_REG(seqid, i)         (QSPI_LUT_BASE + (seqid) * 16 + (i) * 4)
+
+/*
+ * QSPI Sequence index.
+ * index 0 is preset at boot for AHB read,
+ * index 1 is used for other command.
+ */
+#define        SEQID_LUT_AHBREAD_ID            0
+#define        SEQID_LUT_SHARED_ID             1
+
+/* QSPI Instruction set for the LUT register */
+#define LUT_INSTR_STOP                 0
+#define LUT_INSTR_CMD                  1
+#define LUT_INSTR_ADDR                 2
+#define LUT_INSTR_DUMMY                        3
+#define LUT_INSTR_MODE                 4
+#define LUT_INSTR_MODE2                        5
+#define LUT_INSTR_MODE4                        6
+#define LUT_INSTR_READ                 7
+#define LUT_INSTR_WRITE                        8
+#define LUT_INSTR_JMP_ON_CS            9
+#define LUT_INSTR_ADDR_DDR             10
+#define LUT_INSTR_MODE_DDR             11
+#define LUT_INSTR_MODE2_DDR            12
+#define LUT_INSTR_MODE4_DDR            13
+#define LUT_INSTR_READ_DDR             14
+#define LUT_INSTR_WRITE_DDR            15
+#define LUT_INSTR_DATA_LEARN           16
+
+/*
+ * The PAD definitions for LUT register.
+ *
+ * The pad stands for the number of IO lines [0:3].
+ * For example, the quad read needs four IO lines,
+ * so you should use LUT_PAD(4).
+ */
+#define LUT_PAD(x) (fls(x) - 1)
+
+/*
+ * One sequence must be consisted of 4 LUT enteries(16Bytes).
+ * LUT entries with the following register layout:
+ * b'31                                                                     b'0
+ *  ---------------------------------------------------------------------------
+ *  |INSTR1[15~10]|PAD1[9~8]|OPRND1[7~0] | INSTR0[15~10]|PAD0[9~8]|OPRND0[7~0]|
+ *  ---------------------------------------------------------------------------
+ */
+#define LUT_DEF(idx, ins, pad, opr)                                    \
+       ((((ins) << 10) | ((pad) << 8) | (opr)) << (((idx) & 0x1) * 16))
+
+#define READ_FROM_CACHE_OP             0x03
+#define READ_FROM_CACHE_OP_Fast                0x0b
+#define READ_FROM_CACHE_OP_X2          0x3b
+#define READ_FROM_CACHE_OP_X4          0x6b
+#define READ_FROM_CACHE_OP_DUALIO      0xbb
+#define READ_FROM_CACHE_OP_QUADIO      0xeb
+
+u32 reg_offset_table[] = {
+       QSPI_MCR,       QSPI_TCR,       QSPI_IPCR,      QSPI_FLSHCR,
+       QSPI_BUF0CR,    QSPI_BUF1CR,    QSPI_BUF2CR,    QSPI_BUF3CR,
+       QSPI_BFGENCR,   QSPI_SOCCR,     QSPI_BUF0IND,   QSPI_BUF1IND,
+       QSPI_BUF2IND,   QSPI_SFAR,      QSPI_SFACR,     QSPI_SMPR,
+       QSPI_RBSR,      QSPI_RBCT,      QSPI_TBSR,      QSPI_TBDR,
+       QSPI_TBCT,      QSPI_SR,        QSPI_FR,        QSPI_RSER,
+       QSPI_SPNDST,    QSPI_SPTRCLR,   QSPI_SFA1AD,    QSPI_SFA2AD,
+       QSPI_SFB1AD,    QSPI_SFB2AD,    QSPI_DLPR,      QSPI_LUTKEY,
+       QSPI_LCKCR
+};
+
+/* k1x qspi host priv */
+struct k1x_qspi {
+       struct udevice *dev;
+       void __iomem *iobase;
+       void __iomem *ahb_addr;
+       u32 memmap_phy;
+       u32 memmap_phy_size;
+       u32 pmuap_reg;
+    struct clk clk, bus_clk;
+    struct reset_ctl_bulk resets;
+       u32 qspi_id;
+       u32 sfa1ad;
+       u32 sfa2ad;
+       u32 sfb1ad;
+       u32 sfb2ad;
+
+       u32 rxfifo;
+       u32 txfifo;
+       u32 ahb_buf_size;
+       u32 ahb_read_enable;
+       u32 tx_unit_size;
+       u32 rx_unit_size;
+
+       u32 cs_selected;
+       u32 max_hz;
+       u32 endian_xchg;
+       u32 dma_enable;
+};
+
+enum qpsi_cs {
+       QSPI_CS_A1 = 0,
+       QSPI_CS_A2,
+       QSPI_CS_B1,
+       QSPI_CS_B2,
+       QSPI_CS_MAX,
+};
+
+enum qpsi_mode {
+       QSPI_NORMAL_MODE = 0,
+       QSPI_DISABLE_MODE,
+       QSPI_STOP_MODE,
+};
+
+static void qspi_writel(struct k1x_qspi *qspi, u32 val, void __iomem *addr)
+{
+       if (qspi->endian_xchg)
+               out_be32(addr, val);
+       else
+               out_le32(addr, val);
+}
+
+static u32 qspi_readl(struct k1x_qspi *qspi, void __iomem *addr)
+{
+       if (qspi->endian_xchg)
+               return in_be32(addr);
+       else
+               return in_le32(addr);
+}
+
+static void qspi_set_func_clk(struct k1x_qspi *qspi)
+{
+       reset_assert_bulk(&qspi->resets);
+       clk_disable(&qspi->bus_clk);
+       clk_disable(&qspi->clk);
+
+       reset_deassert_bulk(&qspi->resets);
+       clk_enable(&qspi->bus_clk);
+       clk_set_rate(&qspi->clk, qspi->max_hz);
+       clk_enable(&qspi->clk);
+}
+
+static int qspi_reset(struct k1x_qspi *qspi)
+{
+       uint32_t reg, sr, fr;
+       int count = 0;
+
+       do {
+               sr = qspi_readl(qspi, qspi->iobase + QSPI_SR);
+               fr = qspi_readl(qspi, qspi->iobase + QSPI_FR);
+               if (!(sr & QSPI_SR_BUSY) && !(fr & QSPI_FR_XIP_ON))
+                       break;
+               mdelay(3);
+       } while(count++ < 1000);
+
+       if (count >= 1000) {
+               dev_err(qspi->dev, "reset failed\r\n");
+               return -1;
+       }
+
+       /* qspi softreset first */
+       reg = qspi_readl(qspi, qspi->iobase + QSPI_MCR);
+       reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
+       qspi_writel(qspi, reg, qspi->iobase + QSPI_MCR);
+       reg = qspi_readl(qspi, qspi->iobase + QSPI_MCR);
+       if ((reg & 0x3) != 0x3)
+               dev_info(qspi->dev, "reset ignored 0x%x\r\n", reg);
+
+       udelay(1);
+       reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
+       qspi_writel(qspi, reg, qspi->iobase + QSPI_MCR);
+
+       return 0;
+}
+
+
+static void qspi_enter_mode(struct k1x_qspi *qspi, uint32_t mode)
+{
+       uint32_t mcr;
+
+       mcr = qspi_readl(qspi, qspi->iobase + QSPI_MCR);
+       if (mode == QSPI_NORMAL_MODE)
+               mcr &= ~QSPI_MCR_MDIS_MASK;
+       else if (mode == QSPI_DISABLE_MODE)
+               mcr |= QSPI_MCR_MDIS_MASK;
+       qspi_writel(qspi, mcr, qspi->iobase + QSPI_MCR);
+}
+
+
+static int qspi_write_sfar(struct k1x_qspi *qspi, uint32_t val)
+{
+       uint32_t fr;
+       int count = 0;
+
+       do {
+               qspi_writel(qspi, val, qspi->iobase + QSPI_SFAR);
+               fr = qspi_readl(qspi, qspi->iobase + QSPI_FR);
+               if (!(fr & QSPI_FR_IPIEF))
+                       break;
+
+               fr &= QSPI_FR_IPIEF;
+               qspi_writel(qspi, fr, qspi->iobase + QSPI_FR);
+
+               mdelay(3);
+       } while (count++ < 1000);
+
+       if (count >= 1000) {
+               dev_err(qspi->dev, "write sfar failed\r\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/*
+ * IP Command Trigger could not be executed Error Flag may happen for write
+ * access to RBCT/SFAR register, need retry for these two register
+ */
+static int qspi_write_rbct(struct k1x_qspi *qspi, uint32_t val)
+{
+       uint32_t fr;
+       int count = 0;
+
+       do {
+               qspi_writel(qspi, val, qspi->iobase + QSPI_RBCT);
+               fr = qspi_readl(qspi, qspi->iobase + QSPI_FR);
+               if (!(fr & QSPI_FR_IPIEF))
+                       break;
+               fr &= QSPI_FR_IPIEF;
+               qspi_writel(qspi, fr, qspi->iobase + QSPI_FR);
+
+               mdelay(3);
+       } while (count++ < 1000);
+
+       if (count >= 1000) {
+               dev_err(qspi->dev, "write sfar rbct\r\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void qspi_init_ahbread(struct k1x_qspi *qspi, int seq_id)
+{
+       u32 buf_cfg = 0;
+
+       /* Disable BUF0~BUF1, use BUF3 for all masters */
+       qspi_writel(qspi, 0, qspi->iobase + QSPI_BUF0IND);
+       qspi_writel(qspi, 0, qspi->iobase + QSPI_BUF1IND);
+       qspi_writel(qspi, 0, qspi->iobase + QSPI_BUF2IND);
+
+       buf_cfg = QSPI_BUF3CR_ALLMST_MASK |
+                       QSPI_BUF3CR_ADATSZ((qspi->ahb_buf_size / 8));
+
+       /* AHB Master port */
+       qspi_writel(qspi, 0xe, qspi->iobase + QSPI_BUF0CR);
+       qspi_writel(qspi, 0xe, qspi->iobase + QSPI_BUF1CR);
+       qspi_writel(qspi, 0xe, qspi->iobase + QSPI_BUF2CR);
+       qspi_writel(qspi, buf_cfg, qspi->iobase + QSPI_BUF3CR); // other masters
+
+       /* set AHB read sequence id */
+       qspi_writel(qspi, QSPI_BFGENCR_SEQID(seq_id), qspi->iobase + QSPI_BFGENCR);
+       dev_info(qspi->dev, "AHB buf size: %d\n", qspi->ahb_buf_size);
+}
+
+void qspi_dump_reg(struct k1x_qspi *qspi)
+{
+#if (K1X_DUMP_QSPI_REG)
+       u32 reg = 0;
+       void __iomem *base = qspi->iobase;
+       int i;
+
+       dev_notice(qspi->dev, "dump qspi host register:\n");
+       for (i = 0; i < ARRAY_SIZE(reg_offset_table); i++) {
+               if (i > 0 && (i % 4 == 0))
+                       dev_notice(qspi->dev, "\n");
+               reg = qspi_readl(qspi, base + reg_offset_table[i]);
+               dev_notice(qspi->dev, "offset[0x%03x]:0x%08x\t\t",
+                               reg_offset_table[i], reg);
+       }
+
+       dev_notice(qspi->dev, "\ndump AHB read LUT:\n");
+       for (i = 0; i < 4; i++) {
+               reg = qspi_readl(qspi, base + QSPI_LUT_REG(SEQID_LUT_AHBREAD_ID, i));
+               dev_notice(qspi->dev, "lut_reg[0x%03x]:0x%08x\t\t",
+                               QSPI_LUT_REG(SEQID_LUT_AHBREAD_ID, i), reg);
+       }
+
+       dev_notice(qspi->dev, "\ndump shared LUT:\n");
+       for (i = 0; i < 4; i++) {
+               reg = qspi_readl(qspi, base + QSPI_LUT_REG(SEQID_LUT_SHARED_ID, i));
+               dev_notice(qspi->dev, "lut_reg[0x%03x]:0x%08x\t\t",
+                               QSPI_LUT_REG(SEQID_LUT_SHARED_ID, i), reg);
+       }
+       dev_notice(qspi->dev, "\n");
+#endif
+}
+
+static int k1x_qspi_readl_poll_tout(struct k1x_qspi *qspi, void __iomem *base,
+                                       u32 mask, u32 timeout_us, u8 wait_set)
+{
+       u32 reg;
+
+       if (qspi->endian_xchg)
+               mask = swab32(mask);
+
+       if (wait_set)
+               return readl_poll_timeout(base, reg, (reg & mask), timeout_us);
+       else
+               return readl_poll_timeout(base, reg, !(reg & mask), timeout_us);
+}
+
+/*
+ * If the slave device content being changed by Write/Erase, need to
+ * invalidate the AHB buffer. This can be achieved by doing the reset
+ * of controller after setting MCR0[SWRESET] bit.
+ */
+static inline void k1x_qspi_invalid(struct k1x_qspi *qspi)
+{
+       u32 reg;
+
+       reg = qspi_readl(qspi, qspi->iobase + QSPI_MCR);
+       reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
+       qspi_writel(qspi, reg, qspi->iobase + QSPI_MCR);
+
+       /*
+        * The minimum delay : 1 AHB + 2 SFCK clocks.
+        * Delay 1 us is enough.
+        */
+       udelay(1);
+
+       reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
+       qspi_writel(qspi, reg, qspi->iobase + QSPI_MCR);
+}
+
+static void k1x_qspi_prepare_lut(struct k1x_qspi *qspi,
+                               const struct spi_mem_op *op, u32 seq_id)
+{
+       u32 lutval[4] = {0,};
+       int lutidx = 0;
+       int i;
+
+       /* qspi cmd */
+       lutval[0] |= LUT_DEF(lutidx, LUT_INSTR_CMD,
+                            LUT_PAD(op->cmd.buswidth),
+                            op->cmd.opcode);
+       lutidx++;
+
+       /* addr bytes */
+       if (op->addr.nbytes) {
+               lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_ADDR,
+                                             LUT_PAD(op->addr.buswidth),
+                                             op->addr.nbytes * 8);
+               lutidx++;
+       }
+
+       /* dummy bytes, if needed */
+       if (op->dummy.nbytes) {
+               lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_DUMMY,
+                                             LUT_PAD(op->dummy.buswidth),
+                                             op->dummy.nbytes * 8 /
+                                             op->dummy.buswidth);
+               lutidx++;
+       }
+
+       /* read/write data bytes */
+       if (op->data.nbytes) {
+               lutval[lutidx / 2] |= LUT_DEF(lutidx,
+                                             op->data.dir == SPI_MEM_DATA_IN ?
+                                             LUT_INSTR_READ : LUT_INSTR_WRITE,
+                                             LUT_PAD(op->data.buswidth),
+                                             0);
+               lutidx++;
+       }
+
+       /* stop condition. */
+       lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_STOP, 0, 0);
+
+       /* unlock LUT */
+       qspi_writel(qspi, QSPI_LUTKEY_VALUE, qspi->iobase + QSPI_LUTKEY);
+       qspi_writel(qspi, QSPI_LCKER_UNLOCK, qspi->iobase + QSPI_LCKCR);
+
+       /* fill LUT register */
+       for (i = 0; i < ARRAY_SIZE(lutval); i++)
+               qspi_writel(qspi, lutval[i], qspi->iobase + QSPI_LUT_REG(seq_id, i));
+
+       /* lock LUT */
+       qspi_writel(qspi, QSPI_LUTKEY_VALUE, qspi->iobase + QSPI_LUTKEY);
+       qspi_writel(qspi, QSPI_LCKER_LOCK, qspi->iobase + QSPI_LCKCR);
+
+       dev_dbg(qspi->dev, "opcode:0x%x, lut_reg[0:0x%x, 1:0x%x, 2:0x%x, 3:0x%x]\n",
+               op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3]);
+}
+
+static void k1x_qspi_select_mem(struct k1x_qspi *qspi, int chip_select)
+{
+       u64 size_kb;
+
+       size_kb = (qspi->memmap_phy + qspi->memmap_phy_size) & 0xFFFFFC00;
+       qspi_writel(qspi, size_kb, qspi->iobase + (QSPI_SFA1AD + 4 * chip_select));
+
+       dev_dbg(qspi->dev, "slave device[cs:%d] selected\n", chip_select);
+}
+
+static void k1x_qspi_ahb_read(struct k1x_qspi *qspi,
+                               const struct spi_mem_op *op)
+{
+       u32 len = op->data.nbytes;
+
+       /* Read out the data directly from the AHB buffer. */
+       dev_dbg(qspi->dev, "ahb read %d bytes from address:0x%llx\n",
+                               len, (qspi->memmap_phy + op->addr.val));
+       memcpy(op->data.buf.in, (qspi->ahb_addr + op->addr.val), len);
+}
+
+static void k1x_qspi_fill_txfifo(struct k1x_qspi *qspi,
+                                const struct spi_mem_op *op)
+{
+       void __iomem *base = qspi->iobase;
+       int i;
+       u32 val;
+
+       for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 4); i += 4) {
+               memcpy(&val, op->data.buf.out + i, 4);
+               qspi_writel(qspi, val, base + QSPI_TBDR);
+       }
+
+       if (i < op->data.nbytes) {
+               memcpy(&val, op->data.buf.out + i, op->data.nbytes - i);
+               qspi_writel(qspi, val, base + QSPI_TBDR);
+       }
+
+       /*
+        * There must be atleast 128bit data available in TX FIFO
+        * for any pop operation otherwise QSPI_FR[TBUF] will be set
+        */
+       for (i = op->data.nbytes; i < QSPI_TX_BUFF_POP_MIN; i += 4)
+               qspi_writel(qspi, 0, base + QSPI_TBDR);
+}
+
+static void k1x_qspi_read_rxfifo(struct k1x_qspi *qspi,
+                         const struct spi_mem_op *op)
+{
+       void __iomem *base = qspi->iobase;
+       int i;
+       u8 *buf = op->data.buf.in;
+       u32 val;
+
+       dev_dbg(qspi->dev, "ip read %d bytes\n", op->data.nbytes);
+       for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 4); i += 4) {
+               val = qspi_readl(qspi, base + QSPI_RBDR(i / 4));
+               memcpy(buf + i, &val, 4);
+       }
+
+       if (i < op->data.nbytes) {
+               val = qspi_readl(qspi, base + QSPI_RBDR(i / 4));
+               memcpy(buf + i, &val, op->data.nbytes - i);
+       }
+}
+
+static int k1x_qspi_do_op(struct k1x_qspi *qspi, const struct spi_mem_op *op)
+{
+       void __iomem *base = qspi->iobase;
+       int err = 0;
+
+       /* dump reg if need */
+       qspi_dump_reg(qspi);
+
+       /* trigger LUT */
+       qspi_writel(qspi, op->data.nbytes | QSPI_IPCR_SEQID(SEQID_LUT_SHARED_ID),
+                   base + QSPI_IPCR);
+
+       /* wait for the transaction complete */
+       err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_FR, QSPI_FR_TFF_MASK,
+                                       100*1000, QSPI_WAIT_BIT_SET);
+       if (!err)
+               err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_SR, QSPI_SR_BUSY,
+                                       300*1000, QSPI_WAIT_BIT_CLEAR);
+       if (err)
+               dev_err(qspi->dev, "opcode:0x%x transaction timeout!\n", op->cmd.opcode);
+
+       /* read RX buffer for IP command read */
+       if (!err && op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN) {
+               qspi_dump_reg(qspi);
+               k1x_qspi_read_rxfifo(qspi, op);
+       }
+
+       return err;
+}
+
+static void dump_spi_mem_op_info(struct k1x_qspi *qspi,
+                               const struct spi_mem_op *op)
+{
+       dev_dbg(qspi->dev, "cmd.opcode:0x%x\n", op->cmd.opcode);
+       dev_dbg(qspi->dev, "cmd.buswidth:%d\n", op->cmd.buswidth);
+       dev_dbg(qspi->dev, "addr.nbytes:%d,\n", op->addr.nbytes);
+       dev_dbg(qspi->dev, "addr.buswidth:%d\n", op->addr.buswidth);
+       dev_dbg(qspi->dev, "addr.val:0x%llx\n", op->addr.val);
+       dev_dbg(qspi->dev, "dummy.nbytes:%d\n", op->dummy.nbytes);
+       dev_dbg(qspi->dev, "dummy.buswidth:%d\n", op->dummy.buswidth);
+       dev_dbg(qspi->dev, "%s data.nbytes:%d\n",
+               (op->data.dir == SPI_MEM_DATA_IN) ? "read" :"write",
+               op->data.nbytes);
+       dev_dbg(qspi->dev, "data.buswidth:%d\n", op->data.buswidth);
+       dev_dbg(qspi->dev, "data.buf:0x%p\n", op->data.buf.in);
+}
+
+
+static int is_read_from_cache_opcode(u8 opcode)
+{
+       int ret;
+
+       ret = ((opcode == READ_FROM_CACHE_OP) ||
+               (opcode == READ_FROM_CACHE_OP_Fast) ||
+               (opcode == READ_FROM_CACHE_OP_X2) ||
+               (opcode == READ_FROM_CACHE_OP_X4) ||
+               (opcode == READ_FROM_CACHE_OP_DUALIO) ||
+               (opcode == READ_FROM_CACHE_OP_QUADIO));
+
+       return ret;
+}
+
+static int k1x_qspi_exec_op(struct spi_slave *slave,
+                           const struct spi_mem_op *op)
+{
+       struct k1x_qspi *qspi;
+       struct udevice *bus;
+       void __iomem *base;
+       u32 mask;
+       u32 reg;
+       int err;
+
+       bus = slave->dev->parent;
+       qspi = dev_get_priv(bus);
+       base = qspi->iobase;
+
+       dump_spi_mem_op_info(qspi, op);
+
+       /* wait for controller being ready */
+       mask = QSPI_SR_BUSY | QSPI_SR_IP_ACC_MASK | QSPI_SR_AHB_ACC_MASK;
+       err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_SR, mask, 100*1000, QSPI_WAIT_BIT_CLEAR);
+       if (err) {
+               dev_err(qspi->dev, "controller not ready!\n");
+               return err;
+       }
+
+       /* clear TX/RX buffer before transaction */
+       reg = qspi_readl(qspi, base + QSPI_MCR);
+       reg |= QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_CLR_RXF_MASK;
+       qspi_writel(qspi, reg, base + QSPI_MCR);
+
+       /*
+        * reset the sequence pointers whenever the sequence ID is changed by
+        * updating the SEDID filed in QSPI_IPCR OR QSPI_BFGENCR.
+        */
+       reg = qspi_readl(qspi, base + QSPI_SPTRCLR);
+       reg |= (QSPI_SPTRCLR_IPPTRC | QSPI_SPTRCLR_BFPTRC);
+       qspi_writel(qspi, reg, base + QSPI_SPTRCLR);
+
+       /* set the flash address into the QSPI_SFAR */
+       err = qspi_write_sfar(qspi, qspi->memmap_phy + op->addr.val);
+       if (err) {
+               return err;
+       }
+
+       /* clear QSPI_FR before trigger LUT command */
+       reg = qspi_readl(qspi, base + QSPI_FR);
+       if (reg)
+               qspi_writel(qspi, reg, base + QSPI_FR);
+
+       /*
+        * read page command 13h must be done by IP command.
+        * read from cache through the AHB bus by accessing the mapped memory.
+        * In all other cases we use IP commands to access the flash.
+        */
+       if (op->data.nbytes > (qspi->rxfifo - 4) &&
+               op->data.dir == SPI_MEM_DATA_IN &&
+               qspi->ahb_read_enable &&
+               is_read_from_cache_opcode(op->cmd.opcode)) {
+               k1x_qspi_prepare_lut(qspi, op, SEQID_LUT_AHBREAD_ID);
+               k1x_qspi_ahb_read(qspi, op);
+       } else {
+               /* IP command */
+               k1x_qspi_prepare_lut(qspi, op, SEQID_LUT_SHARED_ID);
+               if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
+                       k1x_qspi_fill_txfifo(qspi, op);
+
+               err = k1x_qspi_do_op(qspi, op);
+       }
+
+       /* invalidate the data in the AHB buffer. */
+       k1x_qspi_invalid(qspi);
+
+       return err;
+}
+
+static int k1x_qspi_check_buswidth(struct k1x_qspi *qspi, u8 width)
+{
+       switch (width) {
+       case 1:
+       case 2:
+       case 4:
+               return 0;
+       }
+
+       return -ENOTSUPP;
+}
+
+static bool k1x_qspi_supports_op(struct spi_slave *slave,
+                                const struct spi_mem_op *op)
+{
+       struct k1x_qspi *qspi;
+       struct udevice *bus;
+       int ret;
+
+       bus = slave->dev->parent;
+       qspi = dev_get_priv(bus);
+
+       ret = k1x_qspi_check_buswidth(qspi, op->cmd.buswidth);
+
+       if (op->addr.nbytes)
+               ret |= k1x_qspi_check_buswidth(qspi, op->addr.buswidth);
+
+       if (op->dummy.nbytes)
+               ret |= k1x_qspi_check_buswidth(qspi, op->dummy.buswidth);
+
+       if (op->data.nbytes)
+               ret |= k1x_qspi_check_buswidth(qspi, op->data.buswidth);
+
+       if (ret)
+               return false;
+
+       /* address bytes should be equal to or less than 4 bytes */
+       if (op->addr.nbytes > 4)
+               return false;
+
+       /* check controller TX/RX buffer limits and alignment */
+       if (op->data.dir == SPI_MEM_DATA_IN &&
+           (op->data.nbytes > qspi->rx_unit_size ||
+           (op->data.nbytes > qspi->rxfifo - 4 && !IS_ALIGNED(op->data.nbytes, 4)))) {
+               return false;
+       }
+
+       if (op->data.dir == SPI_MEM_DATA_OUT && op->data.nbytes > qspi->tx_unit_size)
+               return false;
+
+       /*
+        * If requested address value is greater than controller assigned
+        * memory mapped space, return error as it didn't fit in the range.
+        */
+       if (op->addr.val >= qspi->memmap_phy_size)
+               return false;
+
+       /* number of dummy clock cycles should be <= 64 cycles */
+       if (op->dummy.buswidth &&
+           (op->dummy.nbytes * 8 / op->dummy.buswidth > 64))
+               return false;
+
+       return true;
+}
+
+static int k1x_qspi_adjust_op_size(struct spi_slave *slave,
+                                  struct spi_mem_op *op)
+{
+       struct k1x_qspi *qspi;
+       struct udevice *bus;
+
+       bus = slave->dev->parent;
+       qspi = dev_get_priv(bus);
+
+       if (op->data.dir == SPI_MEM_DATA_OUT) {
+               if (op->data.nbytes > qspi->tx_unit_size)
+                       op->data.nbytes = qspi->tx_unit_size;
+       } else {
+               if (op->data.nbytes > qspi->rx_unit_size) {
+                       op->data.nbytes = qspi->rx_unit_size;
+               } else if (op->data.nbytes > qspi->rxfifo - 4 && !IS_ALIGNED(op->data.nbytes, 4)) {
+                       op->data.nbytes = qspi->rxfifo - 4;
+               }
+       }
+
+       return 0;
+}
+
+static int k1x_qspi_host_init(struct k1x_qspi *qspi)
+{
+       void __iomem *base = qspi->iobase;
+       u32 reg;
+       int ret = 0;
+
+       /* set PMUap */
+       qspi_set_func_clk(qspi);
+
+       /* rest qspi */
+       ret = qspi_reset(qspi);
+       if (ret < 0) {
+               goto dis_clk;
+       }
+
+       /* clock settings */
+       qspi_enter_mode(qspi, QSPI_DISABLE_MODE);
+
+       /* sampled by sfif_clk_b; half cycle delay; */
+       if (qspi->max_hz < 104000000)
+               qspi_writel(qspi, 0x0, base + QSPI_SMPR);
+       else
+               qspi_writel(qspi, QSPI_SMPR_FSPHS_MASK, base + QSPI_SMPR);
+
+       /* Fix wirte failure issue*/
+       qspi_writel(qspi, 0x8, base + QSPI_SOCCR);
+
+       /* Give the default source address */
+       ret = qspi_write_sfar(qspi, qspi->memmap_phy);
+       if (ret < 0) {
+               goto dis_clk;
+       }
+       qspi_writel(qspi, 0x0, base + QSPI_SFACR);
+
+        /* config ahb read */
+       qspi_init_ahbread(qspi, SEQID_LUT_AHBREAD_ID);
+
+       /* Set flash memory map */
+       qspi_writel(qspi, (qspi->memmap_phy + qspi->sfa1ad) & 0xfffffc00, base + QSPI_SFA1AD);
+       qspi_writel(qspi, (qspi->memmap_phy + qspi->sfa2ad) & 0xfffffc00, base + QSPI_SFA2AD);
+       qspi_writel(qspi, (qspi->memmap_phy + qspi->sfb1ad) & 0xfffffc00, base + QSPI_SFB1AD);
+       qspi_writel(qspi, (qspi->memmap_phy + qspi->sfb2ad) & 0xfffffc00, base + QSPI_SFB2AD);
+
+       /* ISD3FB, ISD2FB, ISD3FA, ISD2FA = 1; END_CFG=0x3 */
+       reg = qspi_readl(qspi, base + QSPI_MCR);
+       reg |= QSPI_MCR_END_CFG_MASK | QSPI_MCR_ISD_MASK;
+       qspi_writel(qspi, reg, base + QSPI_MCR);
+
+       /* Module enabled */
+       qspi_enter_mode(qspi, QSPI_NORMAL_MODE);
+
+       /* Read using the IP Bus registers QSPI_RBDR0 to QSPI_RBDR31*/
+       ret = qspi_write_rbct(qspi, QSPI_RBCT_RXBRD_MASK);
+       if (ret < 0) {
+               goto dis_clk;
+       }
+
+       /* clear all interrupt status */
+       qspi_writel(qspi, 0xffffffff, base + QSPI_FR);
+
+       dev_dbg(qspi->dev, "dump registers after qspi host init\n");
+       qspi_dump_reg(qspi);
+       return 0;
+
+dis_clk:
+       reset_assert_bulk(&qspi->resets);
+       clk_disable(&qspi->bus_clk);
+       clk_disable(&qspi->clk);
+       return ret;
+}
+
+static int k1x_qspi_probe(struct udevice *bus)
+{
+       struct k1x_qspi *host = dev_get_priv(bus);
+
+       return k1x_qspi_host_init(host);
+}
+
+static int k1x_qspi_claim_bus(struct udevice *dev)
+{
+       struct k1x_qspi *qspi;
+       struct udevice *bus;
+       struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+
+       bus = dev->parent;
+       qspi = dev_get_priv(bus);
+
+       k1x_qspi_select_mem(qspi, slave_plat->cs);
+
+       return 0;
+}
+
+static int k1x_qspi_set_speed(struct udevice *bus, uint speed)
+{
+       /* TODO: if need */
+       return 0;
+}
+
+static int k1x_qspi_set_mode(struct udevice *bus, uint mode)
+{
+       /* TODO: if need */
+       return 0;
+}
+
+static int k1x_qspi_ofdata_to_platdata(struct udevice *bus)
+{
+       struct k1x_qspi *qspi = dev_get_priv(bus);
+       int ret;
+       struct resource res;
+       fdt_addr_t iobase;
+       fdt_addr_t iobase_size;
+       fdt_addr_t ahb_addr;
+       fdt_addr_t ahb_size;
+       const void *blob = gd->fdt_blob;
+       int node = dev_of_offset(bus);
+
+       qspi->dev = bus;
+
+       ret = dev_read_resource_byname(bus, "qspi-base", &res);
+       if (ret) {
+               dev_err(bus, "can't get qspi-base addresses(ret:%d)!\n", ret);
+               return ret;
+       }
+       iobase = (fdt_addr_t)res.start;
+       iobase_size = resource_size(&res);
+       qspi->iobase = map_physmem(iobase, iobase_size, MAP_NOCACHE);
+
+       ret = dev_read_resource_byname(bus, "qspi-mmap", &res);
+       if (ret) {
+               dev_err(bus, "can't get qspi-mmap addresses(ret:%d)!\n", ret);
+               return ret;
+       }
+
+       ahb_addr = (fdt_addr_t)res.start;
+       ahb_size = resource_size(&res);
+       qspi->ahb_addr = map_physmem(ahb_addr, ahb_size, MAP_NOCACHE);
+       qspi->memmap_phy_size = ahb_size;
+       qspi->memmap_phy = (u32)ahb_addr;
+
+    ret = clk_get_by_index(bus, 0, &qspi->clk);
+       if (ret) {
+               dev_err(bus, "can not find the clock\n");
+               return ret;
+       }
+
+    ret = clk_get_by_index(bus, 1, &qspi->bus_clk);
+       if (ret) {
+               dev_err(bus, "can not find bus clock\n");
+               return ret;
+       }
+
+    ret = reset_get_bulk(bus, &qspi->resets);
+    if (ret) {
+               dev_err(bus, "can not find resets\n");
+               return ret;
+       }
+
+       qspi->qspi_id = fdtdec_get_int(blob, node, "qspi-id", 0);
+       qspi->sfa1ad = fdtdec_get_int(blob, node, "qspi-sfa1ad", (QSPI_FLASH_A1_TOP - QSPI_AMBA_BASE));
+       qspi->sfa2ad = fdtdec_get_int(blob, node, "qspi-sfa2ad", (QSPI_FLASH_A2_TOP - QSPI_AMBA_BASE));
+       qspi->sfb1ad = fdtdec_get_int(blob, node, "qspi-sfb1ad", (QSPI_FLASH_B1_TOP - QSPI_AMBA_BASE));
+       qspi->sfb2ad = fdtdec_get_int(blob, node, "qspi-sfb2ad", (QSPI_FLASH_B2_TOP - QSPI_AMBA_BASE));
+
+       qspi->pmuap_reg = fdtdec_get_int(blob, node, "qspi-pmuap-reg", PMUA_QSPI_CLK_RES_CTRL);
+       qspi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", k1x_QSPI_DEFAULT_CLK_FREQ);
+       qspi->rxfifo = fdtdec_get_int(blob, node, "qspi-rxbuf", QSPI_RX_BUFF_MAX);
+       qspi->txfifo = fdtdec_get_int(blob, node, "qspi-txfifo", QSPI_TX_BUFF_MAX);
+       qspi->ahb_buf_size = fdtdec_get_int(blob, node, "qspi-ahbbuf", QSPI_AHB_BUFF_MAX_SIZE);
+       qspi->ahb_read_enable = fdtdec_get_int(blob, node, "qspi-ahbread", 1);
+       qspi->endian_xchg = fdtdec_get_int(blob, node, "qspi-little", 0);
+
+       qspi->cs_selected = QSPI_CS_A1;
+
+       dev_info(bus, "qspi iobase:0x%pa, ahb_addr:0x%pa, max_hz:%dHz\n",
+                               &iobase, &ahb_addr, qspi->max_hz);
+       dev_info(bus, "rx buf size:%d, tx buf size:%d, ahb buf size=%d\n",
+                               qspi->rxfifo, qspi->txfifo, qspi->ahb_buf_size);
+       dev_info(bus, "AHB read %s\n", qspi->ahb_read_enable ? "enabled" : "disabled");
+
+       qspi->tx_unit_size = qspi->txfifo;
+       if (qspi->ahb_read_enable)
+               qspi->rx_unit_size = SZ_4K;
+       else
+               qspi->rx_unit_size = qspi->rxfifo;
+
+       return 0;
+}
+
+static const struct spi_controller_mem_ops k1x_qspi_mem_ops = {
+       .adjust_op_size = k1x_qspi_adjust_op_size,
+       .supports_op = k1x_qspi_supports_op,
+       .exec_op = k1x_qspi_exec_op,
+};
+
+static const struct dm_spi_ops k1x_qspi_ops = {
+       .claim_bus      = k1x_qspi_claim_bus,
+       .set_speed      = k1x_qspi_set_speed,
+       .set_mode       = k1x_qspi_set_mode,
+       .mem_ops        = &k1x_qspi_mem_ops,
+};
+
+static const struct udevice_id k1x_qspi_ids[] = {
+       { .compatible = "spacemit,k1x-qspi", },
+       { }
+};
+
+U_BOOT_DRIVER(k1x_qspi) = {
+       .name   = "k1x_qspi",
+       .id     = UCLASS_SPI,
+       .of_match = k1x_qspi_ids,
+       .ops    = &k1x_qspi_ops,
+       .of_to_plat = k1x_qspi_ofdata_to_platdata,
+       .priv_auto = sizeof(struct k1x_qspi),
+       .probe  = k1x_qspi_probe,
+};
index 03f7fdd59785212af044290fde14b5044a680e4c..1eb6ee6d030298974ce0f42d72239136483d990b 100644 (file)
@@ -193,6 +193,11 @@ config SYSRESET_MPC83XX
        help
          Reboot support for NXP MPC83xx SoCs.
 
+config SYSRESET_SPACEMIT
+       bool "Enable support spacemit SoC family reboot driver"
+       help
+         Reboot support for spacemit SoCs.
+
 endif
 
 endmenu
index 0ed3bbf356a35f799e3cf2c27592ad754a8a29eb..934e428bd5c287f7114e6d691e94d8b130f523e6 100644 (file)
@@ -23,3 +23,4 @@ obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o
 obj-$(CONFIG_SYSRESET_$(SPL_TPL_)AT91) += sysreset_at91.o
 obj-$(CONFIG_$(SPL_TPL_)SYSRESET_X86) += sysreset_x86.o
 obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
+obj-$(CONFIG_SYSRESET_SPACEMIT) += sysreset_spacemit.o
diff --git a/drivers/sysreset/sysreset_spacemit.c b/drivers/sysreset/sysreset_spacemit.c
new file mode 100644 (file)
index 0000000..76e012a
--- /dev/null
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023, Spacemit
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+/*wdt*/
+#define K1X_WDT_REG (0xd4080000)
+#define K1X_WDT_ENABLE (0xd4080000 + 0xb8)
+#define K1X_WDT_TIMEOUT (0xd4080000 + 0xbc)
+#define K1X_WDT_RESET (0xd4080000 + 0xc8)
+#define K1X_WDT_STATUS (0xd4080000 + 0xc0)
+#define K1X_WDT_WSAR        (0xd4080000 + 0x00b4)
+#define K1X_WDT_WFAR        (0xd4080000 + 0x00b0)
+
+#define WDT_CLEAR_STATUS (0x0)
+#define WDT_RESET_ENABLE (0x1)
+#define WDT_ENABLE (0x3)
+#define WDT_TIMEOUT (0x1)
+
+#define K1X_WDT_START_REG  (0xd4051020)
+#define K1X_WDT_START_ENABLE  (BIT(4))
+
+#define K1X_WDT_CLK_RESET_REG (0xd4050200)
+#define K1X_WDT_MPU_REG (0xd4051024)
+#define K1X_WDT_CLK_RESET_ENABLE (0x3)
+#define K1X_WDT_CLK_RESET_FLAG (BIT(2))
+#define K1X_WDT_CLK_ENABLE_MPU (BIT(19))
+
+static void spa_wdt_write_access(void)
+{
+       writel(0xbaba, (void *)K1X_WDT_WFAR);
+       writel(0xeb10, (void *)K1X_WDT_WSAR);
+}
+
+static void spa_wdt_write(u32 val, void *reg)
+{
+       spa_wdt_write_access();
+       writel(val, reg);
+}
+
+static void enable_wdt(void)
+{
+       u32 reg;
+
+       /*enable wdt clk reset*/
+       reg = readl((void *)K1X_WDT_MPU_REG);
+       writel(K1X_WDT_CLK_ENABLE_MPU | reg, (void *)K1X_WDT_MPU_REG);
+
+       reg = readl((void *)K1X_WDT_CLK_RESET_REG);
+       writel(K1X_WDT_CLK_RESET_ENABLE | reg, (void *)K1X_WDT_CLK_RESET_REG);
+       reg = readl((void *)K1X_WDT_CLK_RESET_REG);
+       writel((~K1X_WDT_CLK_RESET_FLAG) & reg,(void *)K1X_WDT_CLK_RESET_REG);
+
+
+       /*set watch dog*/
+       spa_wdt_write(WDT_CLEAR_STATUS, (void *)K1X_WDT_STATUS);
+       spa_wdt_write(WDT_TIMEOUT, (void *)K1X_WDT_TIMEOUT);
+       spa_wdt_write(WDT_ENABLE, (void *)K1X_WDT_ENABLE);
+       spa_wdt_write(WDT_RESET_ENABLE, (void *)K1X_WDT_RESET);
+
+       reg = readl((void*)K1X_WDT_START_REG);
+       writel(K1X_WDT_START_ENABLE | reg, (void *)K1X_WDT_START_REG);
+}
+
+static int spacemit_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+       enable_wdt();
+       /*wait for reset*/
+       mdelay(5000);
+
+       /*if reset success, it would never return*/
+       return -EINPROGRESS;
+}
+
+static int spacemit_sysreset_probe(struct udevice *dev)
+{
+       return 0;
+}
+
+
+static struct sysreset_ops spacemit_sysreset = {
+       .request        = spacemit_sysreset_request,
+};
+
+U_BOOT_DRIVER(spacemit_sysreset) = {
+       .name   = "spacemit_sysreset",
+       .id     = UCLASS_SYSRESET,
+       .ops    = &spacemit_sysreset,
+       .probe  = spacemit_sysreset_probe,
+};
index 939b99d937d166127ff12087cb050563f3619605..31ac62319927999d631edc21564f3f8b31fe4c4c 100644 (file)
@@ -9,6 +9,7 @@
 #include <dm.h>
 #include <timer.h>
 #include <asm/io.h>
+#include <asm/csr.h>
 #include <dm/device-internal.h>
 #include <linux/err.h>
 
 
 static u64 notrace sifive_clint_get_count(struct udevice *dev)
 {
-       return readq((void __iomem *)MTIME_REG(dev_get_priv(dev)));
+       __maybe_unused u32 hi, lo;
+
+       if (IS_ENABLED(CONFIG_64BIT))
+               return csr_read(CSR_TIME);
+
+       do {
+               hi = csr_read(CSR_TIMEH);
+               lo = csr_read(CSR_TIME);
+       } while (hi != csr_read(CSR_TIMEH));
+
+       return ((u64)hi << 32) | lo;
 }
 
 #if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
@@ -35,7 +46,7 @@ unsigned long notrace timer_early_get_rate(void)
  */
 u64 notrace timer_early_get_count(void)
 {
-       return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE));
+       return sifive_clint_get_count(NULL);
 }
 #endif
 
index b592a487e001f576a092cb2efc67b8a8985c4afa..c471516ca2a46a3f8dd4fda836264f34700b9876 100644 (file)
@@ -523,13 +523,18 @@ static int dwc3_core_init(struct dwc3 *dwc)
        int                     ret;
 
        reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+
        /* This should read as U3 followed by revision number */
-       if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
-               dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+       if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
+               dev_err(dwc->dev, "this is a DesignWare USB3 DRD Core\n");
+               dwc->revision = reg;
+       }else if((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
+               dev_err(dwc->dev, "this is a DesignWare USB31 DRD Core\n");
+               dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
+       }else{
                ret = -ENODEV;
                goto err0;
        }
-       dwc->revision = reg;
 
        /* Handle USB2.0-only core configuration */
        if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
index d7cce3a861a7d1f6887856b42b15d78cf871bc13..4fd25e970616c824fbe12535a460b7b4267311d4 100644 (file)
@@ -99,6 +99,9 @@
 #define DWC3_GPRTBIMAP_FS0     0xc188
 #define DWC3_GPRTBIMAP_FS1     0xc18c
 
+#define DWC3_VER_NUMBER                0xc1a0
+#define DWC3_VER_TYPE          0xc1a4
+
 #define DWC3_GUSB2PHYCFG(n)    (0xc200 + (n * 0x04))
 #define DWC3_GUSB2I2CCTL(n)    (0xc240 + (n * 0x04))
 
index 466b25a0c38ea42ff0699d07ed893b124093f00e..1d3be7a6fb618f652aada5c4260681ab3919e3d5 100644 (file)
@@ -27,6 +27,8 @@
 #include <clk.h>
 #include <usb/xhci.h>
 #include <asm/gpio.h>
+#include <dm/device_compat.h>
+#include <power/regulator.h>
 
 struct dwc3_glue_data {
        struct clk_bulk         clks;
@@ -50,6 +52,9 @@ struct dwc3_generic_priv {
 struct dwc3_generic_host_priv {
        struct xhci_ctrl xhci_ctrl;
        struct dwc3_generic_priv gen_priv;
+#if defined(CONFIG_K1_X_BOARD_ASIC)
+       struct udevice *vbus_supply;
+#endif
 };
 
 static int dwc3_generic_probe(struct udevice *dev,
@@ -217,6 +222,19 @@ static int dwc3_generic_host_probe(struct udevice *dev)
        if (rc)
                return rc;
 
+#if CONFIG_IS_ENABLED(K1_X_BOARD_ASIC)
+       if (device_is_compatible(dev->parent, "spacemit,k1-x-dwc3")) {
+               rc = device_get_supply_regulator(dev->parent, "vbus-supply",
+                                               &priv->vbus_supply);
+               if (rc && rc != -ENOENT) {
+                       dev_err(dev, "Failed to retrieve vbus-supply regulator, (err=%d)", rc);
+                       return rc;
+               }
+               if (priv->vbus_supply)
+                       regulator_set_enable(priv->vbus_supply, true);
+       }
+#endif
+
        hccr = (struct xhci_hccr *)priv->gen_priv.base;
        hcor = (struct xhci_hcor *)(priv->gen_priv.base +
                        HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
@@ -229,6 +247,12 @@ static int dwc3_generic_host_remove(struct udevice *dev)
        struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
        int rc;
 
+#if CONFIG_IS_ENABLED(K1_X_BOARD_ASIC)
+       if (device_is_compatible(dev->parent, "spacemit,k1-x-dwc3") && priv->vbus_supply) {
+               regulator_set_enable(priv->vbus_supply, false);
+       }
+#endif
+
        rc = xhci_deregister(dev);
        if (rc)
                return rc;
@@ -568,6 +592,8 @@ static const struct udevice_id dwc3_glue_ids[] = {
        { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops },
        { .compatible = "fsl,imx8mq-dwc3" },
        { .compatible = "intel,tangier-dwc3" },
+       { .compatible = "spacemit,k1-pro-dwc3" },
+       { .compatible = "spacemit,k1-x-dwc3" },
        { }
 };
 
index da9c9e3f10d496fbd46ac85c31a0a47eadb8ee13..8760e60f6a5999edfc26ffc6bbe5d564d9ae86c3 100644 (file)
@@ -149,6 +149,12 @@ config SDP_LOADADDR
        hex "Default load address at SDP_WRITE and SDP_JUMP"
        default 0
 
+config USB2_K1X_CI
+       bool "Enable Spacemit K1x USB2.0 Controller"
+       select USB_GADGET_DUALSPEED
+       help
+           K1x's usb controller is an integrated high speed USB 2.0 controller.
+
 # Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
        bool
index dd09ee01959023cf41a49f2fa0e1f2275f47ff9f..03813d66e10cef1763ba41bed21d7638d0035bd0 100644 (file)
@@ -10,6 +10,7 @@ ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_USB_GADGET) += g_dnl.o
 obj-$(CONFIG_SPL_DFU) += f_dfu.o
 obj-$(CONFIG_SPL_USB_SDP_SUPPORT) += f_sdp.o
+obj-$(CONFIG_SPL_FASTBOOT) += f_fastboot.o
 endif
 
 # new USB gadget layer dependencies
@@ -22,6 +23,7 @@ obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o
 obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o
 obj-$(CONFIG_CI_UDC)   += ci_udc.o
+obj-$(CONFIG_USB2_K1X_CI)      += k1x_usb2_ci.o
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o
 obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o
index 77988f78ab3095270a28dfd9b7600ddfcbad71b5..a22a4c3b316cbfe54f3a24dc630858a8c220c998 100644 (file)
@@ -41,8 +41,6 @@
 #include <asm/unaligned.h>
 #include <asm/io.h>
 
-#include <asm/mach-types.h>
-
 #include <power/regulator.h>
 
 #include "dwc2_udc_otg_regs.h"
@@ -455,12 +453,13 @@ static void reconfig_usbd(struct dwc2_udc *dev)
 {
        /* 2. Soft-reset OTG Core and then unreset again. */
        int i;
-       unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
+       unsigned int uTemp;
        uint32_t dflt_gusbcfg;
        uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
        u32 max_hw_ep;
        int pdata_hw_ep;
 
+    writel(CORE_SOFT_RESET, &reg->grstctl);
        debug("Resetting OTG controller\n");
 
        dflt_gusbcfg =
@@ -1040,6 +1039,26 @@ static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_plat_otg_data *p)
                p->usb_gusbcfg |= 1 << 30; /* FDMOD: Force device mode */
 }
 
+static void dwc2_set_spacemit_hsotg_params(struct dwc2_plat_otg_data *p)
+{
+       p->activate_stm_id_vb_detection = true;
+       p->usb_gusbcfg =
+               0<<15           /* PHY Low Power Clock sel*/
+               |1<<14          /* Non-Periodic TxFIFO Rewind Enable*/
+               |0x5<<10        /* Turnaround time*/
+               |0<<9 | 0<<8    /* [0:HNP disable,1:HNP enable][ 0:SRP disable*/
+                               /* 1:SRP enable] H1= 1,1*/
+               |0<<7           /* Ulpi DDR sel*/
+               |0<<6           /* 0: high speed utmi+, 1: full speed serial*/
+               |1<<4           /* 0: utmi+, 1:ulpi*/
+#ifdef CONFIG_USB_GADGET_DWC2_OTG_PHY_BUS_WIDTH_8
+               |0<<3           /* phy i/f  0:8bit, 1:16bit*/
+#else
+               |1<<3           /* phy i/f  0:8bit, 1:16bit*/
+#endif
+               |0x7<<0;        /* HS/FS Timeout**/
+}
+
 static int dwc2_udc_otg_reset_init(struct udevice *dev,
                                   struct reset_ctl_bulk *resets)
 {
@@ -1174,6 +1193,8 @@ static int dwc2_udc_otg_remove(struct udevice *dev)
 
 static const struct udevice_id dwc2_udc_otg_ids[] = {
        { .compatible = "snps,dwc2" },
+       { .compatible = "spacemit,k1-pro-usb",
+         .data = (ulong)dwc2_set_spacemit_hsotg_params },
        { .compatible = "brcm,bcm2835-usb" },
        { .compatible = "st,stm32mp15-hsotg",
          .data = (ulong)dwc2_set_stm32mp1_hsotg_params },
index 7f8e9564b9e5d5259d4728420a7e4941d5f95916..1919cd0e323992bb177cd9467e23377739bd200d 100644 (file)
@@ -30,8 +30,6 @@
 #include <asm/unaligned.h>
 #include <asm/io.h>
 
-#include <asm/mach-types.h>
-
 #include "dwc2_udc_otg_regs.h"
 #include "dwc2_udc_otg_priv.h"
 
@@ -39,7 +37,7 @@
 
 void otg_phy_init(struct dwc2_udc *dev)
 {
-       unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl;
+       unsigned int* usb_phy_ctrl = (unsigned int*)(size_t)dev->pdata->usb_phy_ctrl;
        struct dwc2_usbotg_phy *phy =
                (struct dwc2_usbotg_phy *)dev->pdata->regs_phy;
 
@@ -59,11 +57,13 @@ void otg_phy_init(struct dwc2_udc *dev)
                writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
                        &~FORCE_SUSPEND_0), &phy->phypwr);
 
+#if CONFIG_IS_ENABLED(ARCH_EXYNOS5)
        if (s5p_cpu_id == 0x4412)
                writel((readl(&phy->phyclk) & ~(EXYNOS4X12_ID_PULLUP0 |
                        EXYNOS4X12_COMMON_ON_N0)) | EXYNOS4X12_CLK_SEL_24MHZ,
                       &phy->phyclk); /* PLL 24Mhz */
        else
+#endif
                writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)) |
                       CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
 
@@ -77,7 +77,7 @@ void otg_phy_init(struct dwc2_udc *dev)
 
 void otg_phy_off(struct dwc2_udc *dev)
 {
-       unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl;
+       unsigned int* usb_phy_ctrl = (unsigned int*)(size_t)dev->pdata->usb_phy_ctrl;
        struct dwc2_usbotg_phy *phy =
                (struct dwc2_usbotg_phy *)dev->pdata->regs_phy;
 
index d0e92c7a071fc66db78822246bb674bbb6e6c631..ad44b81fc7699d9dd0f9125d5ace4c51ba2c961b 100644 (file)
@@ -200,7 +200,7 @@ static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
        int status = req->status;
        if (!status)
                return;
-       printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+       pr_debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
 }
 
 static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
@@ -409,8 +409,9 @@ static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
        usb_ep_dequeue(fastboot_func->in_ep, in_req);
 
        ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
-       if (ret)
-               printf("Error %d on queue\n", ret);
+       if (ret){
+               pr_err("Error %d on queue\n", ret);
+       }
        return 0;
 }
 
@@ -419,10 +420,12 @@ static int fastboot_tx_write_str(const char *buffer)
        return fastboot_tx_write(buffer, strlen(buffer));
 }
 
+#if !defined(CONFIG_SPL_BUILD)
 static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
 {
        do_reset(NULL, 0, 0, NULL);
 }
+#endif /* !defined(CONFIG_SPL_BUILD) */
 
 static unsigned int rx_bytes_expected(struct usb_ep *ep)
 {
@@ -448,6 +451,66 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep)
        return rx_remain;
 }
 
+#ifndef CONFIG_SPL_BUILD
+static unsigned int tx_bytes_expected(struct usb_ep *ep)
+{
+       int tx_remain = fastboot_data_remaining();
+       unsigned int rem;
+       unsigned int maxpacket = usb_endpoint_maxp(ep->desc);
+
+       if (tx_remain <= 0)
+               return 0;
+       else if (tx_remain > EP_BUFFER_SIZE)
+               return EP_BUFFER_SIZE;
+
+       rem = tx_remain % maxpacket;
+       if (rem > 0)
+               tx_remain = tx_remain + (maxpacket - rem);
+
+       return tx_remain;
+}
+
+static void tx_handler_up_image(struct usb_ep *ep, struct usb_request *in_req)
+{
+       char response[FASTBOOT_RESPONSE_LEN] = {0};
+       unsigned int remain_size = fastboot_data_remaining();
+       const unsigned char *buffer = in_req->buf;
+
+       unsigned int transfer_size = tx_bytes_expected(ep);
+
+       if (in_req->status != 0) {
+               pr_err("Bad status: %d\n", in_req->status);
+               return;
+       }
+
+       if (!fastboot_data_remaining()) {
+               fastboot_data_complete(response);
+
+               /*
+                * Reset global transfer variable
+                */
+               in_req->complete = fastboot_complete;
+
+               fastboot_tx_write_str(response);
+               return ;
+       }
+
+       if (transfer_size > remain_size)
+               transfer_size = remain_size;
+
+
+       fastboot_data_upload(buffer, transfer_size, response);
+
+       if (response[0]) {
+               fastboot_tx_write_str(response);
+               return;
+       }
+
+       in_req->length = transfer_size;
+       usb_ep_queue(ep, in_req, 0);
+}
+#endif
+
 static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
 {
        char response[FASTBOOT_RESPONSE_LEN] = {0};
@@ -456,7 +519,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
        unsigned int buffer_size = req->actual;
 
        if (req->status != 0) {
-               printf("Bad status: %d\n", req->status);
+               pr_debug("Bad status: %d\n", req->status);
                return;
        }
 
@@ -489,6 +552,7 @@ static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
        g_dnl_trigger_detach();
 }
 
+#if !defined(CONFIG_SPL_BUILD)
 static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
 {
        fastboot_boot();
@@ -506,6 +570,7 @@ static void do_acmd_complete(struct usb_ep *ep, struct usb_request *req)
                fastboot_acmd_complete();
 }
 #endif
+#endif /* !defined(CONFIG_SPL_BUILD) */
 
 static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
 {
@@ -529,16 +594,28 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
                req->length = rx_bytes_expected(ep);
        }
 
+#ifndef CONFIG_SPL_BUILD
+       if (!strncmp("PUSH", response, 4)) {
+               fastboot_func->in_req->complete = tx_handler_up_image;
+
+               /* must replace 'PUSH' to 'DATA' */
+               strncpy(response, "DATA", 4);
+       }
+#endif
+
        if (!strncmp("OKAY", response, 4)) {
                switch (cmd) {
+#if !defined(CONFIG_SPL_BUILD)
                case FASTBOOT_COMMAND_BOOT:
                        fastboot_func->in_req->complete = do_bootm_on_complete;
                        break;
+#endif /* !defined(CONFIG_SPL_BUILD) */
 
                case FASTBOOT_COMMAND_CONTINUE:
                        fastboot_func->in_req->complete = do_exit_on_complete;
                        break;
 
+#if !defined(CONFIG_SPL_BUILD)
                case FASTBOOT_COMMAND_REBOOT:
                case FASTBOOT_COMMAND_REBOOT_BOOTLOADER:
                case FASTBOOT_COMMAND_REBOOT_FASTBOOTD:
@@ -550,6 +627,7 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
                        fastboot_func->in_req->complete = do_acmd_complete;
                        break;
 #endif
+#endif /* !defined(CONFIG_SPL_BUILD) */
                }
        }
 
index 0fa7230b992a58c9a5825c020949d26ba6e0a7a8..e2279faab625c160fe5d359875344a6c454a65ac 100644 (file)
@@ -318,7 +318,7 @@ static void sdp_rx_command_complete(struct usb_ep *ep, struct usb_request *req)
                sdp->dnl_address = be32_to_cpu(cmd->addr);
                sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
                sdp->next_state = SDP_STATE_TX_REGISTER;
-               printf("Reading %d registers at 0x%08x... ",
+               pr_debug("Reading %d registers at 0x%08x... ",
                       sdp->dnl_bytes_remaining, sdp->dnl_address);
                break;
        case SDP_WRITE_FILE:
@@ -331,7 +331,7 @@ static void sdp_rx_command_complete(struct usb_ep *ep, struct usb_request *req)
                sdp->dnl_bytes = sdp->dnl_bytes_remaining;
                sdp->next_state = SDP_STATE_IDLE;
 
-               printf("Downloading file of size %d to 0x%08x... ",
+               pr_debug("Downloading file of size %d to 0x%08x... ",
                       sdp->dnl_bytes_remaining, sdp->dnl_address);
 
                break;
@@ -413,7 +413,7 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req)
 #ifndef CONFIG_SPL_BUILD
        env_set_hex("filesize", sdp->dnl_bytes);
 #endif
-       printf("done\n");
+       pr_debug("done\n");
 
        switch (sdp->state) {
        case SDP_STATE_RX_FILE_DATA_BUSY:
@@ -704,7 +704,7 @@ static int sdp_bind_config(struct usb_configuration *c)
 
 int sdp_init(int controller_index)
 {
-       printf("SDP: initialize...\n");
+       pr_debug("SDP: initialize...\n");
        while (!sdp_func->configuration_done) {
                if (ctrlc()) {
                        puts("\rCTRL+C - Operation aborted.\n");
@@ -724,11 +724,11 @@ static u32 sdp_jump_imxheader(void *address)
        ulong (*entry)(void);
 
        if (headerv2->header.tag != IVT_HEADER_TAG) {
-               printf("Header Tag is not an IMX image\n");
+               pr_debug("Header Tag is not an IMX image\n");
                return SDP_ERROR_IMXHEADER;
        }
 
-       printf("Jumping to 0x%08x\n", headerv2->entry);
+       pr_debug("Jumping to 0x%08x\n", headerv2->entry);
        entry = sdp_ptr(headerv2->entry);
        entry();
 
@@ -820,7 +820,7 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image,
                sdp_func->state = SDP_STATE_TX_REGISTER_BUSY;
                break;
        case SDP_STATE_JUMP:
-               printf("Jumping to header at 0x%08x\n", sdp_func->jmp_address);
+               pr_debug("Jumping to header at 0x%08x\n", sdp_func->jmp_address);
                status = sdp_jump_imxheader(sdp_ptr(sdp_func->jmp_address));
 
                /* If imx header fails, try some U-Boot specific headers */
@@ -833,7 +833,7 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image,
                        if (sdp_func->jmp_address == 0)
                                panic("Error in search header, failed to jump\n");
 
-                       printf("Found header at 0x%08x\n", sdp_func->jmp_address);
+                       pr_debug("Found header at 0x%08x\n", sdp_func->jmp_address);
 
                        image_header_t *header =
                                sdp_ptr(sdp_func->jmp_address);
@@ -895,16 +895,18 @@ static void sdp_handle_out_ep(void)
        if (sdp_func->state == SDP_STATE_IDLE) {
                sdp_func->out_req->complete = sdp_rx_command_complete;
                rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
-               if (rc)
-                       printf("error in submission: %s\n",
+               if (rc){
+                       pr_debug("error in submission: %s\n",
                               sdp_func->out_ep->name);
+               }
                sdp_func->state = SDP_STATE_RX_CMD;
        } else if (sdp_func->state == SDP_STATE_RX_FILE_DATA) {
                sdp_func->out_req->complete = sdp_rx_data_complete;
                rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
-               if (rc)
-                       printf("error in submission: %s\n",
+               if (rc){
+                       pr_debug("error in submission: %s\n",
                               sdp_func->out_ep->name);
+               }
                sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
        }
 }
@@ -917,7 +919,7 @@ int spl_sdp_handle(int controller_index, struct spl_image_info *spl_image,
 #endif
 {
        int flag = 0;
-       printf("SDP: handle requests...\n");
+       pr_debug("SDP: handle requests...\n");
        while (1) {
                if (ctrlc()) {
                        puts("\rCTRL+C - Operation aborted.\n");
index afb7b74f3057047f21e580fca4808c8302247551..b33cfc32779f91b74468284ec5959e39086a1925 100644 (file)
@@ -18,7 +18,7 @@
 #include <usb_mass_storage.h>
 #include <dfu.h>
 #include <thor.h>
-
+#include <asm/io.h>
 #include <env_callback.h>
 
 #include "gadget_chips.h"
@@ -225,6 +225,16 @@ static int on_serialno(const char *name, const char *value, enum env_op op,
 }
 U_BOOT_ENV_CALLBACK(serialno, on_serialno);
 
+#if defined(CONFIG_K1_X_BOARD_FPGA) || defined(CONFIG_K1_X_BOARD_ASIC)
+static bool g_dnl_is_bootfromusb(void)
+{
+       if(readl((void __iomem *)0xd4282d10) == 0x55a)
+               return true;
+       else
+               return false;
+}
+#endif
+
 static int g_dnl_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget *gadget = cdev->gadget;
@@ -271,6 +281,18 @@ static int g_dnl_bind(struct usb_composite_dev *cdev)
                device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
        }
 
+#if defined(CONFIG_K1_X_BOARD_FPGA) || defined(CONFIG_K1_X_BOARD_ASIC)
+       /*
+        * In brom stage usb product id is 0x1001, if boot from usb, 
+        * hold usb product id, ignore CONFIG_USB_GADGET_PRODUCT_NUM
+        */
+       if (g_dnl_is_bootfromusb()) {
+               debug("%s: controller '%s' is already initiated by brom\n",
+                       __func__, gadget->name);
+               device_desc.idProduct = __constant_cpu_to_le16(0x1001);
+       }
+#endif
+
        debug("%s: calling usb_gadget_connect for "
                        "controller '%s'\n", __func__, gadget->name);
        usb_gadget_connect(gadget);
@@ -306,7 +328,7 @@ int g_dnl_register(const char *name)
 
        ret = usb_composite_register(&g_dnl_driver);
        if (ret) {
-               printf("%s: failed!, error: %d\n", __func__, ret);
+               pr_err("%s: failed!, error: %d\n", __func__, ret);
                return ret;
        }
        return 0;
diff --git a/drivers/usb/gadget/k1x_usb2_ci.c b/drivers/usb/gadget/k1x_usb2_ci.c
new file mode 100644 (file)
index 0000000..2f4a6e7
--- /dev/null
@@ -0,0 +1,1136 @@
+/*
+ * Copyright 2023, Spacemit Inc.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <config.h>
+#include <cpu_func.h>
+#include <net.h>
+#include <malloc.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "../host/ehci.h"
+#include "k1x_usb2_ci.h"
+
+/*
+ * Check if the system has too long cachelines. If the cachelines are
+ * longer then 128b, the driver will not be able flush/invalidate data
+ * cache over separate QH entries. We use 128b because one QH entry is
+ * 64b long and there are always two QH list entries for each endpoint.
+ */
+#if ARCH_DMA_MINALIGN > 128
+#error This driver can not work on systems with caches longer than 128b
+#endif
+
+/*
+ * Every QTD must be individually aligned, since we can program any
+ * QTD's address into HW. Cache flushing requires ARCH_DMA_MINALIGN,
+ * and the USB HW requires 32-byte alignment. Align to both:
+ */
+#define ILIST_ALIGN            roundup(ARCH_DMA_MINALIGN, 32)
+/* Each QTD is this size */
+#define ILIST_ENT_RAW_SZ       sizeof(struct ept_queue_item)
+/*
+ * Align the size of the QTD too, so we can add this value to each
+ * QTD's address to get another aligned address.
+ */
+#define ILIST_ENT_SZ           roundup(ILIST_ENT_RAW_SZ, ARCH_DMA_MINALIGN)
+/* For each endpoint, we need 2 QTDs, one for each of IN and OUT */
+#define ILIST_SZ               (NUM_ENDPOINTS * 2 * ILIST_ENT_SZ)
+
+//#define DEBUG 1
+#ifndef DEBUG
+#define DBG(x...) do {} while (0)
+#else
+#define DBG(x...) printf(x)
+#endif
+
+static const char *reqname(unsigned r)
+{
+       switch (r) {
+       case USB_REQ_GET_STATUS: return "GET_STATUS";
+       case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE";
+       case USB_REQ_SET_FEATURE: return "SET_FEATURE";
+       case USB_REQ_SET_ADDRESS: return "SET_ADDRESS";
+       case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
+       case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
+       case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION";
+       case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION";
+       case USB_REQ_GET_INTERFACE: return "GET_INTERFACE";
+       case USB_REQ_SET_INTERFACE: return "SET_INTERFACE";
+       default: return "*UNKNOWN*";
+       }
+}
+
+static struct usb_endpoint_descriptor ep0_out_desc = {
+       .bLength = sizeof(struct usb_endpoint_descriptor),
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bEndpointAddress = 0,
+       .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static struct usb_endpoint_descriptor ep0_in_desc = {
+       .bLength = sizeof(struct usb_endpoint_descriptor),
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bEndpointAddress = USB_DIR_IN,
+       .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+#define EP_MAX_PACKET_SIZE     0x200
+#define EP0_MAX_PACKET_SIZE    64
+
+#define WAIT_FOR_SETUP         0
+#define DATA_STATE_XMIT                1
+#define DATA_STATE_RECV                2
+#define WAIT_FOR_OUT_STATUS    3
+static unsigned int ep0_state = WAIT_FOR_SETUP;
+static unsigned short testmode;
+static unsigned short windex;
+static int mv_pullup(struct usb_gadget *gadget, int is_on);
+static int mv_ep_enable(struct usb_ep *ep,
+               const struct usb_endpoint_descriptor *desc);
+static int mv_ep_disable(struct usb_ep *ep);
+static int mv_ep_queue(struct usb_ep *ep,
+               struct usb_request *req, gfp_t gfp_flags);
+static int mv_ep_dequeue(struct usb_ep *ep, struct usb_request *req);
+static struct usb_request *
+mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
+static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
+
+static struct usb_gadget_ops mv_udc_ops = {
+       .pullup = mv_pullup,
+};
+
+static struct usb_ep_ops mv_ep_ops = {
+       .enable         = mv_ep_enable,
+       .disable        = mv_ep_disable,
+       .queue          = mv_ep_queue,
+       .dequeue        = mv_ep_dequeue,
+       .alloc_request  = mv_ep_alloc_request,
+       .free_request   = mv_ep_free_request,
+};
+
+/* Init values for USB endpoints. */
+static const struct usb_ep mv_ep_init[2] = {
+       [0] = { /* EP 0 */
+               .maxpacket      = 64,
+               .name           = "ep0",
+               .ops            = &mv_ep_ops,
+       },
+       [1] = { /* EP 1..n */
+               .maxpacket      = 512,
+               .name           = "ep-",
+               .ops            = &mv_ep_ops,
+       },
+};
+
+static struct mv_drv controller = {
+       .gadget = {
+               .name   = "mv_udc",
+               .ops    = &mv_udc_ops,
+               .is_dualspeed = 1,
+               .max_speed = USB_SPEED_HIGH,
+       },
+};
+
+static struct ehci_ctrl *ehci_ctrl;
+/**
+ * mv_get_qh() - return queue head for endpoint
+ * @ep_num:    Endpoint number
+ * @dir_in:    Direction of the endpoint (IN = 1, OUT = 0)
+ *
+ * This function returns the QH associated with particular endpoint
+ * and it's direction.
+ */
+static struct ept_queue_head *mv_get_qh(int ep_num, int dir_in)
+{
+       return &controller.epts[(ep_num * 2) + dir_in];
+}
+
+/**
+ * mv_get_qtd() - return queue item for endpoint
+ * @ep_num:    Endpoint number
+ * @dir_in:    Direction of the endpoint (IN = 1, OUT = 0)
+ *
+ * This function returns the QH associated with particular endpoint
+ * and it's direction.
+ */
+static struct ept_queue_item *mv_get_qtd(int ep_num, int dir_in)
+{
+       return controller.items[(ep_num * 2) + dir_in];
+}
+
+/**
+ * mv_flush_qh - flush cache over queue head
+ * @ep_num:    Endpoint number
+ *
+ * This function flushes cache over QH for particular endpoint.
+ */
+static void mv_flush_qh(int ep_num)
+{
+       struct ept_queue_head *head = mv_get_qh(ep_num, 0);
+       const ulong start = (ulong)head;
+       const ulong end = start + 2 * sizeof(*head);
+
+       flush_dcache_range(start, end);
+       dmb();
+}
+
+/**
+ * mv_invalidate_qh - invalidate cache over queue head
+ * @ep_num:    Endpoint number
+ *
+ * This function invalidates cache over QH for particular endpoint.
+ */
+static void mv_invalidate_qh(int ep_num)
+{
+       struct ept_queue_head *head = mv_get_qh(ep_num, 0);
+       ulong start = (ulong)head;
+       ulong end = start + 2 * sizeof(*head);
+
+       invalidate_dcache_range(start, end);
+}
+
+/**
+ * mv_flush_qtd - flush cache over queue item
+ * @ep_num:    Endpoint number
+ *
+ * This function flushes cache over qTD pair for particular endpoint.
+ */
+static void mv_flush_qtd(int ep_num)
+{
+       struct ept_queue_item *item = mv_get_qtd(ep_num, 0);
+       const ulong start = (ulong)item;
+       const ulong end = start + 2 * ILIST_ENT_SZ;
+
+       flush_dcache_range(start, end);
+       dmb();
+}
+
+/**
+ * mv_invalidate_qtd - invalidate cache over queue item
+ * @ep_num:    Endpoint number
+ *
+ * This function invalidates cache over qTD pair for particular endpoint.
+ */
+static void mv_invalidate_qtd(int ep_num)
+{
+       struct ept_queue_item *item = mv_get_qtd(ep_num, 0);
+       const ulong start = (ulong)item;
+       const ulong end = start + 2 * ILIST_ENT_SZ;
+
+       invalidate_dcache_range(start, end);
+}
+
+static struct usb_request *
+mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
+{
+       struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+       int num = -1;
+       struct mv_req *mv_req;
+
+       if (mv_ep->desc)
+               num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       if (num == 0 && controller.ep0_req)
+               return &controller.ep0_req->req;
+
+       mv_req = memalign(ARCH_DMA_MINALIGN, sizeof(*mv_req));
+       if (!mv_req)
+               return NULL;
+
+       INIT_LIST_HEAD(&mv_req->queue);
+       mv_req->b_buf = 0;
+
+       if (num == 0)
+               controller.ep0_req = mv_req;
+
+       return &mv_req->req;
+}
+
+static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+       struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+       struct mv_req *mv_req = container_of(req, struct mv_req, req);
+       int num = -1;
+
+       if (mv_ep->desc)
+               num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       if (num == 0) {
+               if (!controller.ep0_req)
+                       return;
+               controller.ep0_req = 0;
+       }
+
+       if (mv_req->b_buf)
+               free(mv_req->b_buf);
+       free(mv_req);
+}
+
+static void ep_enable(int num, int in, int maxpacket)
+{
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+       unsigned n;
+
+       n = readl(&udc->epctrl[num]);
+       if (in)
+               n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
+       else
+               n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
+
+       if (num != 0) {
+               struct ept_queue_head *head = mv_get_qh(num, in);
+
+               head->config = CONFIG_MAX_PKT(maxpacket) | CONFIG_ZLT;
+               mv_flush_qh(num);
+       }
+       writel(n, &udc->epctrl[num]);
+}
+
+static int mv_ep_enable(struct usb_ep *ep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+       int num, in;
+       num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+       mv_ep->desc = desc;
+       ep->desc = desc;
+
+       if (num) {
+               int max = get_unaligned_le16(&desc->wMaxPacketSize);
+
+               if ((max > 64) && (controller.gadget.speed == USB_SPEED_FULL))
+                       max = 64;
+               if (ep->maxpacket != max) {
+                       DBG("%s: from %d to %d\n", __func__,
+                           ep->maxpacket, max);
+                       ep->maxpacket = max;
+               }
+       }
+       ep_enable(num, in, ep->maxpacket);
+       DBG("%s: num=%d maxpacket=%d\n", __func__, num, ep->maxpacket);
+       return 0;
+}
+
+static int mv_ep_disable(struct usb_ep *ep)
+{
+       struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+
+       mv_ep->desc = NULL;
+       ep->desc = NULL;
+       return 0;
+}
+
+static void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall)
+{
+       u32 epctrlx;
+
+       epctrlx = readl(&udc->epctrl[ep_num]);
+
+       if (stall) {
+               if (direction == USB_DIR_IN)
+                       epctrlx |= EPCTRL_TX_EP_STALL;
+               else
+                       epctrlx |= EPCTRL_RX_EP_STALL;
+       } else {
+               if (direction == USB_DIR_IN) {
+                       epctrlx &= ~EPCTRL_TX_EP_STALL;
+                       epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST;
+               } else {
+                       epctrlx &= ~EPCTRL_RX_EP_STALL;
+                       epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST;
+               }
+       }
+       writel(epctrlx, &udc->epctrl[ep_num]);
+}
+static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction)
+{
+       u32 epctrlx;
+
+       epctrlx = readl(&udc->epctrl[ep_num]);
+
+       if (direction == USB_DIR_OUT)
+               return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0;
+       else
+               return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0;
+}
+
+static int mv_bounce(struct mv_req *mv_req, int in)
+{
+       struct usb_request *req = &mv_req->req;
+       unsigned long addr = (unsigned long)req->buf;
+       unsigned long hwaddr;
+       uint32_t aligned_used_len;
+
+       /* Input buffer address is not aligned. */
+       if (addr & (ARCH_DMA_MINALIGN - 1))
+               goto align;
+
+       /* Input buffer length is not aligned. */
+       if (req->length & (ARCH_DMA_MINALIGN - 1))
+               goto align;
+
+       /* The buffer is well aligned, only flush cache. */
+       mv_req->hw_len = req->length;
+       mv_req->hw_buf = req->buf;
+       goto flush;
+
+align:
+       if (mv_req->b_buf && req->length > mv_req->b_len) {
+               free(mv_req->b_buf);
+               mv_req->b_buf = 0;
+       }
+
+       if (!mv_req->b_buf) {
+               mv_req->b_len = roundup(req->length, ARCH_DMA_MINALIGN);
+               mv_req->b_buf = memalign(ARCH_DMA_MINALIGN, mv_req->b_len);
+               if (!mv_req->b_buf)
+                       return -ENOMEM;
+       }
+       mv_req->hw_len = mv_req->b_len;
+       mv_req->hw_buf = mv_req->b_buf;
+
+       if (in)
+               memcpy(mv_req->hw_buf, req->buf, req->length);
+
+flush:
+       hwaddr = (unsigned long)mv_req->hw_buf;
+       if (!hwaddr)
+               return 0;
+       aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN);
+       flush_dcache_range(hwaddr, hwaddr + aligned_used_len);
+
+       return 0;
+}
+
+static void mv_debounce(struct mv_req *mv_req, int in)
+{
+       struct usb_request *req = &mv_req->req;
+       unsigned long addr = (unsigned long)req->buf;
+       unsigned long hwaddr = (unsigned long)mv_req->hw_buf;
+       uint32_t aligned_used_len;
+
+       if (in)
+               return;
+
+       aligned_used_len = roundup(req->actual, ARCH_DMA_MINALIGN);
+       invalidate_dcache_range(hwaddr, hwaddr + aligned_used_len);
+
+       if (addr == hwaddr)
+               return; /* not a bounce */
+
+       memcpy(req->buf, mv_req->hw_buf, req->actual);
+}
+
+static void mv_ep_submit_next_request(struct mv_ep *mv_ep)
+{
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+       struct ept_queue_item *item;
+       struct ept_queue_head *head;
+       int bit, num, len, in;
+       struct mv_req *mv_req;
+
+       mv_ep->req_primed = true;
+
+       num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+       item = mv_get_qtd(num, in);
+       head = mv_get_qh(num, in);
+
+       mv_req = list_first_entry(&mv_ep->queue, struct mv_req, queue);
+       len = mv_req->req.length;
+
+       item->info = INFO_BYTES(len) | INFO_ACTIVE;
+       item->page0 =  (uint32_t)(ulong)mv_req->hw_buf;
+       item->page1 = ((uint32_t)(ulong)mv_req->hw_buf & 0xfffff000) + 0x1000;
+       item->page2 = ((uint32_t)(ulong)mv_req->hw_buf & 0xfffff000) + 0x2000;
+       item->page3 = ((uint32_t)(ulong)mv_req->hw_buf & 0xfffff000) + 0x3000;
+       item->page4 = ((uint32_t)(ulong)mv_req->hw_buf & 0xfffff000) + 0x4000;
+
+       head->next = (unsigned)(ulong)item;
+       head->info = 0;
+
+
+       /*
+        * When sending the data for an IN transaction, the attached host
+        * knows that all data for the IN is sent when one of the following
+        * occurs:
+        * a) A zero-length packet is transmitted.
+        * b) A packet with length that isn't an exact multiple of the ep's
+        *    maxpacket is transmitted.
+        * c) Enough data is sent to exactly fill the host's maximum expected
+        *    IN transaction size.
+        *
+        * One of these conditions MUST apply at the end of an IN transaction,
+        * or the transaction will not be considered complete by the host. If
+        * none of (a)..(c) already applies, then we must force (a) to apply
+        * by explicitly sending an extra zero-length packet.
+        */
+       /*  IN    !a     !b                              !c */
+#if 0
+       if (in && len && !(len % mv_ep->ep.maxpacket) && mv_req->req.zero) {
+               /*
+                * Each endpoint has 2 items allocated, even though typically
+                * only 1 is used at a time since either an IN or an OUT but
+                * not both is queued. For an IN transaction, item currently
+                * points at the second of these items, so we know that we
+                * can use the other to transmit the extra zero-length packet.
+                */
+               struct ept_queue_item *other_item = mv_get_qtd(num, 0);
+               item->next = (ulong)other_item;
+               item = other_item;
+               item->info = INFO_ACTIVE;
+       }
+#endif
+
+       item->next = TERMINATE;
+       item->info |= INFO_IOC;
+
+       mv_flush_qtd(num);
+
+       DBG("ept%d %s queue len %x, req %p buffer %p\n",
+           num, in ? "in" : "out", len, mv_req, mv_req->hw_buf);
+       mv_flush_qh(num);
+
+       udelay(10);
+
+       if (in)
+               bit = EPT_TX(num);
+       else
+               bit = EPT_RX(num);
+
+       writel(bit, &udc->epprime);
+}
+
+static int mv_ep_queue(struct usb_ep *ep,
+               struct usb_request *req, gfp_t gfp_flags)
+{
+       struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+       struct mv_req *mv_req = container_of(req, struct mv_req, req);
+       int in, ret;
+       int __maybe_unused num;
+
+       num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+
+       if (!num && mv_ep->req_primed) {
+               /*
+                * The flipping of ep0 between IN and OUT relies on
+                * ci_ep_queue consuming the current IN/OUT setting
+                * immediately. If this is deferred to a later point when the
+                * req is pulled out of ci_req->queue, then the IN/OUT setting
+                * may have been changed since the req was queued, and state
+                * will get out of sync. This condition doesn't occur today,
+                * but could if bugs were introduced later, and this error
+                * check will save a lot of debugging time.
+                */
+               pr_err("%s: ep0 transaction already in progress\n", __func__);
+               return -EPROTO;
+       }
+
+       ret = mv_bounce(mv_req, in);
+       if (ret)
+               return ret;
+
+       DBG("ept%d %s pre-queue req %p, buffer %p\n",
+               num, in ? "in" : "out", mv_req, mv_req->hw_buf);
+       list_add_tail(&mv_req->queue, &mv_ep->queue);
+
+       if (!mv_ep->req_primed)
+               mv_ep_submit_next_request(mv_ep);
+
+       return 0;
+}
+
+static int mv_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+       struct mv_req *mv_req;
+
+       list_for_each_entry(mv_req, &mv_ep->queue, queue) {
+               if (&mv_req->req == req)
+                       break;
+       }
+
+       if (&mv_req->req != req)
+               return -EINVAL;
+
+       list_del_init(&mv_req->queue);
+
+       if (mv_req->req.status == -EINPROGRESS) {
+               mv_req->req.status = -ECONNRESET;
+               if (mv_req->req.complete)
+                       mv_req->req.complete(ep, req);
+       }
+
+       return 0;
+}
+
+/*
+ *  Test Mode Selectors, these are not defined
+ *  in ch9.h, so define here
+ */
+#define TEST_J      1
+#define TEST_K      2
+#define TEST_SE0_NAK    3
+#define TEST_PACKET 4
+#define TEST_FORCE_EN   5
+#define TEST_DISABLE 0
+
+static void mv_set_ptc(struct mv_udc *udc, u32 mode)
+{
+       u32 portsc;
+       portsc = readl(&udc->portsc);
+       portsc |= mode << 16;
+       writel(portsc, &udc->portsc);
+}
+
+static void mv_udc_testmode(struct mv_udc *udc, u16 index)
+{
+       if (index <= TEST_FORCE_EN){
+               mv_set_ptc(udc, index);
+       }else{
+               pr_info("This test mode(%d) is not supported\n", index);
+       }
+}
+
+static void handle_ep_complete(struct mv_ep *ep)
+{
+       struct ept_queue_item *item;
+       int num, in, len;
+       struct mv_req *mv_req;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+
+       num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+
+       item = mv_get_qtd(num, in);
+       mv_invalidate_qtd(num);
+
+       len = (item->info >> 16) & 0x7fff;
+       if (item->info & 0xff)
+               pr_err("EP%d/%s FAIL info=%x pg0=%x\n",
+                      num, in ? "in" : "out", item->info, item->page0);
+
+       mv_req = list_first_entry(&ep->queue, struct mv_req, queue);
+       list_del_init(&mv_req->queue);
+       ep->req_primed = false;
+
+       if (!list_empty(&ep->queue))
+               mv_ep_submit_next_request(ep);
+
+       mv_req->req.actual = mv_req->req.length - len;
+       mv_debounce(mv_req, in);
+
+       DBG("ept%d %s req %p complete %x\n",
+                       num, in ? "in" : "out", mv_req, len);
+
+       mv_req->req.status = 0;
+
+       mv_req->req.complete(&ep->ep, &mv_req->req);
+       if (num == 0) {
+               switch (ep0_state) {
+               case DATA_STATE_XMIT:
+                       /* receive status phase */
+                       mv_req->req.length = 0;
+                       ep->desc = &ep0_out_desc;
+                       ep0_state = WAIT_FOR_OUT_STATUS;
+                       usb_ep_queue(&ep->ep, &mv_req->req, 0);
+                       break;
+               case DATA_STATE_RECV:
+                       /* send status phase */
+                       mv_req->req.length = 0;
+                       ep->desc = &ep0_in_desc;
+                       ep0_state = WAIT_FOR_OUT_STATUS;
+                       usb_ep_queue(&ep->ep, &mv_req->req, 0);
+                       break;
+               case WAIT_FOR_OUT_STATUS:
+                       ep0_state = WAIT_FOR_SETUP;
+                       if (testmode == USB_DEVICE_TEST_MODE) {
+                               pr_info("enter test mode too!!!\n");
+                               mv_udc_testmode(udc, windex);
+                               windex = 0x0;
+                               testmode = 0x0;
+                       }
+                       break;
+               }
+       }
+}
+
+#define SETUP(type, request) (((type) << 8) | (request))
+
+static void handle_setup(void)
+{
+       struct mv_ep *mv_ep = &controller.ep[0];
+       struct mv_req *mv_req;
+       struct usb_request *req;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+       struct ept_queue_head *head;
+       struct usb_ctrlrequest r;
+       int status = 0;
+       int num, dir, _num, _dir, i;
+       char *buf;
+
+       mv_req = controller.ep0_req;
+
+       req = &mv_req->req;
+
+       head = mv_get_qh(0, 0); /* EP0 OUT */
+
+       mv_invalidate_qh(0);
+       memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest));
+       writel(EPT_RX(0), &udc->epsetupstat);
+       pr_info("handle setup %s, 0x%x, 0x%x index 0x%x value 0x%x length 0x%x\n",
+           reqname(r.bRequest), r.bRequestType, r.bRequest, r.wIndex,
+           r.wValue, r.wLength);
+
+       list_del_init(&mv_req->queue);
+       mv_ep->req_primed = false;
+
+       switch (SETUP(r.bRequestType, r.bRequest)) {
+       case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
+       case SETUP(USB_RECIP_ENDPOINT, USB_REQ_SET_FEATURE):
+               _num = r.wIndex & 15;
+               _dir = (r.wIndex & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+
+               if ((r.wValue == 0) && (r.wLength == 0)) {
+                       req->length = 0;
+                       for (i = 0; i < NUM_ENDPOINTS * 2; i++) {
+                               if (!controller.ep[i].desc)
+                                       continue;
+                               num = controller.ep[i].desc->bEndpointAddress
+                                       & USB_ENDPOINT_NUMBER_MASK;
+                               dir = (controller.ep[i].desc->bEndpointAddress
+                                               & USB_DIR_IN) != 0 ? USB_DIR_IN : USB_DIR_OUT;
+                               if ((num == _num) && (dir == _dir)) {
+                                       if (r.bRequest == USB_REQ_SET_FEATURE) {
+                                               ep_set_stall(udc, num, dir, 1);
+                                       } else {
+                                               ep_enable(num, dir, controller.ep[i].ep.maxpacket);
+                                               ep_set_stall(udc, num, dir, 0);
+                                       }
+                                       controller.ep[0].desc = &ep0_in_desc;
+                                       ep0_state = WAIT_FOR_OUT_STATUS;
+                                       usb_ep_queue(controller.gadget.ep0, req, 0);
+                                       break;
+                               }
+                       }
+               }
+               return;
+
+       case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_FEATURE):
+               if (r.wValue == USB_DEVICE_TEST_MODE) {
+                       pr_info("enter test mode\n");
+                       testmode = r.wValue;
+                       windex = (r.wIndex >> 8);
+               }
+               req->length = 0;
+               controller.ep[0].desc = &ep0_in_desc;
+               ep0_state = WAIT_FOR_OUT_STATUS;
+               usb_ep_queue(controller.gadget.ep0, req, 0);
+               return;
+
+       case SETUP(USB_RECIP_DEVICE, USB_REQ_CLEAR_FEATURE):
+               if (r.wValue == USB_DEVICE_TEST_MODE) {
+                       pr_info("leave test mode\n");
+                       mv_udc_testmode(udc, TEST_DISABLE);
+               }
+               return;
+
+       case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS):
+               /*
+                * write address delayed (will take effect
+                * after the next IN txn)
+                */
+
+               writel((r.wValue << 25) | (1 << 24), &udc->devaddr);
+
+               req->length = 0;
+               controller.ep[0].desc = &ep0_in_desc;
+               ep0_state = WAIT_FOR_OUT_STATUS;
+               usb_ep_queue(controller.gadget.ep0, req, 0);
+               return;
+
+       case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS):
+               req->length = 2;
+               buf = (char *)req->buf;
+               buf[0] = 1 << USB_DEVICE_SELF_POWERED;
+               buf[1] = 0;
+               controller.ep[0].desc = &ep0_in_desc;
+               usb_ep_queue(controller.gadget.ep0, req, 0);
+               ep0_state = DATA_STATE_XMIT;
+               return;
+
+       case SETUP(USB_DIR_IN | USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS):
+               _num = r.wIndex & 15;
+               _dir = (r.wIndex & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+               req->length = 2;
+               buf = (char *)req->buf;
+               buf[0] = ep_is_stall(udc, _num, _dir) << USB_ENDPOINT_HALT;
+               buf[1] = 0;
+               controller.ep[0].desc = &ep0_in_desc;
+               usb_ep_queue(controller.gadget.ep0, req, 0);
+               ep0_state = DATA_STATE_XMIT;
+               return;
+       }
+
+       if (r.wLength) {
+               if (r.bRequestType & USB_DIR_IN)
+                       controller.ep[0].desc = &ep0_in_desc;
+               else
+                       controller.ep[0].desc = &ep0_out_desc;
+       } else {
+               controller.ep[0].desc = &ep0_in_desc;
+       }
+
+       /* pass request up to the gadget driver */
+       if (controller.driver)
+               status = controller.driver->setup(&controller.gadget, &r);
+       else
+               status = -ENODEV;
+
+       if (!status) {
+               if (r.wLength)
+                       /* DATA phase from gadget, STATUS phase from udc */
+                       ep0_state = (r.bRequestType & USB_DIR_IN)
+                               ?  DATA_STATE_XMIT : DATA_STATE_RECV;
+               else
+                       ep0_state = WAIT_FOR_OUT_STATUS;
+               return;
+       }
+       DBG("STALL reqname %s type %x value %x, index %x\n",
+           reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex);
+       writel((1<<16) | (1 << 0), &udc->epctrl[0]);
+}
+
+static void stop_activity(void)
+{
+       int i, num, in;
+       struct ept_queue_head *head;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+
+       controller.ep[0].desc = &ep0_out_desc;
+       ep0_state = WAIT_FOR_SETUP;
+
+       writel(readl(&udc->epsetupstat), &udc->epsetupstat);
+       writel(readl(&udc->epcomp), &udc->epcomp);
+       writel(0xffffffff, &udc->epflush);
+
+       /* error out any pending reqs */
+       for (i = 0; i < NUM_ENDPOINTS; i++) {
+               if (i != 0)
+                       writel(0, &udc->epctrl[i]);
+               if (controller.ep[i].desc) {
+                       num = controller.ep[i].desc->bEndpointAddress
+                               & USB_ENDPOINT_NUMBER_MASK;
+                       in = (controller.ep[i].desc->bEndpointAddress
+                               & USB_DIR_IN) != 0;
+                       head = mv_get_qh(num, in);
+                       head->next = TERMINATE;
+                       head->info = 0;
+                       mv_flush_qh(num);
+                       controller.ep[i].req_primed = false;
+               }
+       }
+}
+
+void udc_irq(void)
+{
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+       unsigned n = readl(&udc->usbsts);
+       writel(n, &udc->usbsts);
+       int bit, i, num, in;
+
+       n &= (STS_SLI | STS_URI | STS_SEI | STS_PCI | STS_UI | STS_UEI);
+       if (n == 0)
+               return;
+
+       if (n & STS_SEI){
+               pr_err("-- system error -- \n");
+       }
+
+       if (n & STS_URI) {
+               DBG("-- reset --:epsetupstat= 0x%x\n", readl(&udc->epsetupstat));
+               stop_activity();
+       }
+       if (n & STS_SLI){
+               pr_info("-- suspend --\n");
+       }
+
+       if (n & STS_PCI) {
+               int max = 64;
+               int speed = USB_SPEED_FULL;
+
+               bit = (readl(&udc->portsc) >> 26) & 3;
+//             DBG("-- portchange %x %s\n", bit, (bit == 2) ? "High" : "Full");
+               if (bit == 2) {
+                       speed = USB_SPEED_HIGH;
+                       max = 512;
+               }
+               controller.gadget.speed = speed;
+               for (i = 1; i < NUM_ENDPOINTS * 2; i++) {
+                       if (controller.ep[i].ep.maxpacket > max)
+                               controller.ep[i].ep.maxpacket = max;
+               }
+       }
+
+       if (n & STS_UEI)
+               DBG("<UEI %x>\n", readl(&udc->epcomp));
+
+       if (n & STS_UI) {
+               DBG("-- STS_UI --\n");
+               n = readl(&udc->epcomp);
+               if (n != 0) {
+                       writel(n, &udc->epcomp);
+
+                       for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+                               if (controller.ep[i].desc) {
+                                       num = controller.ep[i].desc->bEndpointAddress
+                                               & USB_ENDPOINT_NUMBER_MASK;
+                                       in = (controller.ep[i].desc->bEndpointAddress
+                                             & USB_DIR_IN) != 0;
+                                       bit = (in) ? EPT_TX(num) : EPT_RX(num);
+
+                                       if (n & bit)
+                                               handle_ep_complete(&controller.ep[i]);
+                               }
+                       }
+               }
+               n = readl(&udc->epsetupstat);
+               if (n & EPT_RX(0))
+                       handle_setup();
+       }
+}
+
+int usb_gadget_handle_interrupts(int index)
+{
+       u32 value;
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+
+       value = readl(&udc->usbsts);
+       if (value)
+               udc_irq();
+
+       return value;
+}
+
+void udc_disconnect(void)
+{
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+       /* disable pullup */
+       stop_activity();
+       writel(USBCMD_FS2, &udc->usbcmd);
+       udelay(800);
+       if (controller.driver)
+               controller.driver->disconnect(&controller.gadget);
+}
+
+static int mv_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hccr;
+       u32 value;
+
+       pr_info("k1xci_udc: pullup %d \n", is_on);
+
+       if (is_on) {
+               /* RESET */
+               writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd);
+               udelay(200);
+
+               writel((unsigned)(ulong)controller.epts, &udc->epinitaddr);
+
+               /* select DEVICE mode */
+               value = readl(&udc->usbmode);
+               value &= ~USBMODE_CM_MASK;
+               value |= USBMODE_DEVICE;
+               writel(value, &udc->usbmode);
+
+               writel(0xffffffff, &udc->epflush);
+
+               //writel(STS_UI | STS_PCI | STS_URI, &udc->usbintr);
+               //writel(STS_UI | STS_PCI | STS_URI, &udc->usbsts);
+
+               /* Turn on the USB connection by enabling the pullup resistor */
+               value = readl(&udc->usbcmd);
+               value |= (USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN);
+               writel(value, &udc->usbcmd);
+       } else {
+               udc_disconnect();
+       }
+
+       return 0;
+}
+
+static int mvudc_probe(void)
+{
+       struct ept_queue_head *head;
+       uint8_t *imem;
+       int i;
+
+       const int num = 2 * NUM_ENDPOINTS;
+
+       const int eplist_min_align = 4096;
+       const int eplist_align = roundup(eplist_min_align, ARCH_DMA_MINALIGN);
+       const int eplist_raw_sz = num * sizeof(struct ept_queue_head);
+       const int eplist_sz = roundup(eplist_raw_sz, ARCH_DMA_MINALIGN);
+
+       /* The QH list must be aligned to 4096 bytes. */
+       controller.epts = memalign(eplist_align, eplist_sz);
+       if (!controller.epts)
+               return -ENOMEM;
+       memset(controller.epts, 0, eplist_sz);
+
+       ehci_ctrl = malloc(sizeof(struct ehci_ctrl));
+       ehci_ctrl->hccr = (struct ehci_hccr *)(K1X_USB_BASE + 0x100);
+       controller.ctrl = ehci_ctrl;
+
+       controller.items_mem = memalign(ILIST_ALIGN, ILIST_SZ);
+       if (!controller.items_mem) {
+               free(controller.epts);
+               return -ENOMEM;
+       }
+       memset(controller.items_mem, 0, ILIST_SZ);
+
+       for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+               /*
+                * Configure QH for each endpoint. The structure of the QH list
+                * is such that each two subsequent fields, N and N+1 where N is
+                * even, in the QH list represent QH for one endpoint. The Nth
+                * entry represents OUT configuration and the N+1th entry does
+                * represent IN configuration of the endpoint.
+                */
+               head = controller.epts + i;
+               if (i < 2)
+                       head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE)
+                               | CONFIG_ZLT | CONFIG_IOS;
+               else
+                       head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE)
+                               | CONFIG_ZLT;
+               head->next = TERMINATE;
+               head->info = 0;
+
+               imem = controller.items_mem + (i * ILIST_ENT_SZ);
+               controller.items[i] = (struct ept_queue_item *)imem;
+
+               if (i & 1) {
+                       mv_flush_qh(i/2);
+                       mv_flush_qtd(i/2);
+               }
+       }
+
+       INIT_LIST_HEAD(&controller.gadget.ep_list);
+
+       /* Init EP 0 */
+       memcpy(&controller.ep[0].ep, &mv_ep_init[0], sizeof(*mv_ep_init));
+       controller.ep[0].desc = &ep0_out_desc;
+       INIT_LIST_HEAD(&controller.ep[0].queue);
+       controller.ep[0].req_primed = false;
+       controller.gadget.ep0 = &controller.ep[0].ep;
+       INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
+
+       /* Init EP 1..n */
+       for (i = 1; i < 2 * NUM_ENDPOINTS; i++) {
+               memcpy(&controller.ep[i].ep, &mv_ep_init[1],
+                      sizeof(*mv_ep_init));
+               INIT_LIST_HEAD(&controller.ep[i].queue);
+               controller.ep[i].req_primed = false;
+               list_add_tail(&controller.ep[i].ep.ep_list,
+                             &controller.gadget.ep_list);
+               controller.ep[i].desc = NULL;
+       }
+
+       mv_ep_alloc_request(&controller.ep[0].ep, 0);
+       if (!controller.ep0_req) {
+               free(controller.items_mem);
+               free(controller.epts);
+               return -ENOMEM;
+       }
+
+       pr_info("k1xci_udc probe\n");
+
+       return 0;
+}
+
+void usbphy_init(void)
+{
+       uint32_t loops, temp;
+
+       pr_info("k1xci_udc: phy_init \n");
+       reg32_modify(PMUA_USB_CLK_RES_CTRL, 0, PMUA_USB_CLK_RES_CTRL_USB_AXICLK_EN);
+       reg32_modify(PMUA_USB_CLK_RES_CTRL, PMUA_USB_CLK_RES_CTRL_USB_AXI_RST, 0);
+       reg32_modify(PMUA_USB_CLK_RES_CTRL, 0, PMUA_USB_CLK_RES_CTRL_USB_AXI_RST);
+
+       udelay(200);
+
+       loops = 200;
+       do {
+               temp = reg32_read(USB2_PHY_REG01);
+               if (temp & USB2_PLL_PLLREADY)
+                       break;
+               udelay(5);
+       } while(--loops);
+
+       if (loops == 0){
+               pr_err("Wait PHY_REG01[PLLREADY] timeout \n");
+       }
+
+       reg32_write(USB2_PHY_REG01, 0x60ef);
+       reg32_write(USB2_PHY_REG0D, 0x1c);
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct mv_udc *udc;
+       int ret;
+
+       if (!driver)
+               return -EINVAL;
+       if (!driver->bind || !driver->setup || !driver->disconnect)
+               return -EINVAL;
+
+       usbphy_init();
+
+       ret = mvudc_probe();
+       if (ret) {
+               DBG("udc probe failed, returned %d\n", ret);
+               return ret;
+       }
+
+       udc = (struct mv_udc *)controller.ctrl->hccr;
+       /* select ULPI phy */
+       writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc);
+
+       ret = driver->bind(&controller.gadget);
+       if (ret) {
+               DBG("driver->bind() returned %d\n", ret);
+               return ret;
+       }
+       controller.driver = driver;
+
+       return 0;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       udc_disconnect();
+       driver->unbind(&controller.gadget);
+       controller.driver = NULL;
+
+       mv_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
+       free(controller.items_mem);
+       free(controller.epts);
+
+       return 0;
+}
diff --git a/drivers/usb/gadget/k1x_usb2_ci.h b/drivers/usb/gadget/k1x_usb2_ci.h
new file mode 100644 (file)
index 0000000..dcdcbf9
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2023, Spacemit Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef __GADGET__MV_UDC_H__
+#define __GADGET__MV_UDC_H__
+
+#ifdef CONFIG_SPL_BUILD
+#define NUM_ENDPOINTS          2
+#else
+#define NUM_ENDPOINTS          6
+#endif
+
+struct mv_udc {
+       u32 pad0[16];
+#define MICRO_8FRAME   0x8
+#define USBCMD_ITC(x)  ((((x) > 0xff) ? 0xff : x) << 16)
+#define USBCMD_FS2     (1 << 15)
+#define USBCMD_SETUP_TRIPWIRE_SET      (1 << 13)
+#define USBCMD_RST     (1 << 1)
+#define USBCMD_RUN     (1)
+       u32 usbcmd;             /* 0x140 */
+#define STS_SLI                (1 << 8)
+#define STS_URI                (1 << 6)
+#define STS_SEI                (1 << 4)
+#define STS_PCI                (1 << 2)
+#define STS_UEI                (1 << 1)
+#define STS_UI         (1 << 0)
+       u32 usbsts;             /* 0x144 */
+       u32 usbintr;            /* 0x148 */
+       u32 frindex;            /* 0x14c */
+       u32 pad1[1];
+       u32 devaddr;            /* 0x154 */
+       u32 epinitaddr;         /* 0x158 */
+       u32 pad2[10];
+#define PTS_ENABLE     2
+#define PTS(x)         (((x) & 0x3) << 30)
+#define PFSC           (1 << 24)
+       u32 portsc;             /* 0x184 */
+       u32 pad3[8];
+#define USBMODE_CM_MASK        3
+#define USBMODE_DEVICE 2
+       u32 usbmode;            /* 0x1a8 */
+       u32 epsetupstat;                /* 0x1ac */
+#define EPT_TX(x)      (1 << (((x) & 0xffff) + 16))
+#define EPT_RX(x)      (1 << ((x) & 0xffff))
+       u32 epprime;            /* 0x1b0 */
+       u32 epflush;            /* 0x1b4 */
+       u32 pad4;
+       u32 epcomp;             /* 0x1bc */
+#define CTRL_TXE       (1 << 23)
+#define CTRL_TXR       (1 << 22)
+#define CTRL_RXE       (1 << 7)
+#define CTRL_RXR       (1 << 6)
+#define CTRL_TXT_BULK  (2 << 18)
+#define CTRL_RXT_BULK  (2 << 2)
+       u32 epctrl[16];         /* 0x1c0 */
+#define EPCTRL_TX_DATA_TOGGLE_RST       (0x00400000)
+#define EPCTRL_TX_EP_STALL          (0x00010000)
+#define EPCTRL_RX_EP_STALL          (0x00000001)
+#define EPCTRL_RX_DATA_TOGGLE_RST       (0x00000040)
+};
+
+struct mv_req {
+       struct usb_request      req;
+       struct list_head        queue;
+       /* Bounce buffer allocated if needed to align the transfer */
+       uint8_t *b_buf;
+       uint32_t b_len;
+       /* Buffer for the current transfer. Either req.buf/len or b_buf/len */
+       uint8_t *hw_buf;
+       uint32_t hw_len;
+};
+
+struct mv_ep {
+       struct usb_ep ep;
+       struct list_head queue;
+       bool req_primed;
+       const struct usb_endpoint_descriptor *desc;
+};
+
+struct mv_drv {
+       struct usb_gadget               gadget;
+       struct mv_req                   *ep0_req;
+       struct usb_gadget_driver        *driver;
+       struct ehci_ctrl                *ctrl;
+       struct ept_queue_head           *epts;
+       struct ept_queue_item           *items[2 * NUM_ENDPOINTS];
+       uint8_t                         *items_mem;
+       struct mv_ep                    ep[2 * NUM_ENDPOINTS];
+};
+
+struct ept_queue_head {
+       unsigned config;
+       unsigned current;       /* read-only */
+
+       unsigned next;
+       unsigned info;
+       unsigned page0;
+       unsigned page1;
+       unsigned page2;
+       unsigned page3;
+       unsigned page4;
+       unsigned reserved_0;
+
+       unsigned char setup_data[8];
+
+       unsigned reserved_1;
+       unsigned reserved_2;
+       unsigned reserved_3;
+       unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)      ((n) << 16)
+#define CONFIG_ZLT             (1 << 29)       /* stop on zero-len xfer */
+#define CONFIG_IOS             (1 << 15)       /* IRQ on setup */
+
+struct ept_queue_item {
+       unsigned next;
+       unsigned info;
+       unsigned page0;
+       unsigned page1;
+       unsigned page2;
+       unsigned page3;
+       unsigned page4;
+       unsigned reserved;
+};
+
+#define TERMINATE 1
+#define INFO_BYTES(n)          ((n) << 16)
+#define INFO_IOC               (1 << 15)
+#define INFO_ACTIVE            (1 << 7)
+#define INFO_HALTED            (1 << 6)
+#define INFO_BUFFER_ERROR      (1 << 5)
+#define INFO_TX_ERROR          (1 << 3)
+
+#define K1X_APMU_BASE          0xd4282800
+#define PMUA_USB_CLK_RES_CTRL                  (K1X_APMU_BASE + 0x5c)
+#define PMUA_USB_CLK_RES_CTRL_USB_AXICLK_EN    (0x1 << 1)
+#define PMUA_USB_CLK_RES_CTRL_USB_AXI_RST      (0x1 << 0)
+
+#define K1X_USB_BASE           0xC0900000
+
+#define USB2_PHY_REG_BASE   0xC0940000
+#define USB2_PHY_REG01      (USB2_PHY_REG_BASE + 0x04)
+#define USB2_PHY_REG04      (USB2_PHY_REG_BASE + 0x10)
+#define USB2_PHY_REG06      (USB2_PHY_REG_BASE + 0x18)
+#define USB2_PHY_REG08      (USB2_PHY_REG_BASE + 0x20)
+#define USB2_PHY_REG0D      (USB2_PHY_REG_BASE + 0x34)
+#define USB2_PHY_REG26      (USB2_PHY_REG_BASE + 0x98)
+#define USB2_PHY_REG22      (USB2_PHY_REG_BASE + 0x88)
+
+#define USB2_PLL_PLLREADY   (1 << 0)
+#define USB2_CFG_FORCE_CDRCLK   (1 << 6)
+#define USB2_CFG_HS_SRC_SEL    (1 << 0)
+
+static inline uint32_t reg32_read(uintptr_t reg)
+{
+       return (*(volatile uint32_t *)(reg));
+}
+
+static inline void reg32_write(uintptr_t reg, uint32_t value)
+{
+       (*(volatile uint32_t *)(reg)) = value;
+}
+
+static inline void reg32_modify(uintptr_t reg, uint32_t clear_mask, uint32_t set_mask)
+{
+       reg32_write(reg, (reg32_read(reg) & ~clear_mask) | set_mask);
+}
+
+#endif
index 1aabe062fb34fc9d9625967d805a19cf581a3cb3..f9d603b9096b63ba4d91e50adcc8bde201ad5fdb 100644 (file)
@@ -239,6 +239,14 @@ config USB_EHCI_VF
        help
          Enables support for the on-chip EHCI controller on Vybrid SoCs.
 
+config USB_EHCI_K1X
+       bool "EHCI support for Spacemit k1x USB controller"
+       select USB_EHCI_IS_TDI
+       select PHY
+       select PHY_SPACEMIT_K1X_USB2
+       help
+         Enable support for Spacemit k1x SoC's on-chip EHCI controller.
+
 if USB_EHCI_MX6 || USB_EHCI_MX7
 
 config MXC_USB_OTG_HACTIVE
index ddc366320690060404e87fb45af0508f60b8d678..bf7a5e088234819528f25cf894d6228b4081c154 100644 (file)
@@ -13,53 +13,54 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += usb_bootdev.o
 endif
 
 # ohci
-obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
-obj-$(CONFIG_USB_ATMEL) += ohci-at91.o
-obj-$(CONFIG_USB_OHCI_DA8XX) += ohci-da8xx.o
-obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-obj-$(CONFIG_USB_SL811HS) += sl811-hcd.o
-obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o
-obj-$(CONFIG_USB_OHCI_PCI) += ohci-pci.o
-obj-$(CONFIG_USB_OHCI_GENERIC) += ohci-generic.o
-obj-$(CONFIG_USB_OHCI_NPCM) += ohci-npcm.o
+obj-$(CONFIG_$(SPL_)USB_OHCI_NEW) += ohci-hcd.o
+obj-$(CONFIG_$(SPL_)USB_ATMEL) += ohci-at91.o
+obj-$(CONFIG_$(SPL_)USB_OHCI_DA8XX) += ohci-da8xx.o
+obj-$(CONFIG_$(SPL_)USB_R8A66597_HCD) += r8a66597-hcd.o
+obj-$(CONFIG_$(SPL_)USB_SL811HS) += sl811-hcd.o
+obj-$(CONFIG_$(SPL_)USB_OHCI_LPC32XX) += ohci-lpc32xx.o
+obj-$(CONFIG_$(SPL_)USB_OHCI_PCI) += ohci-pci.o
+obj-$(CONFIG_$(SPL_)USB_OHCI_GENERIC) += ohci-generic.o
+obj-$(CONFIG_$(SPL_)USB_OHCI_NPCM) += ohci-npcm.o
 
 # echi
-obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
-obj-$(CONFIG_USB_EHCI_ARMADA100) += ehci-armada100.o utmi-armada100.o
-obj-$(CONFIG_USB_EHCI_ATMEL) += ehci-atmel.o
-obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
-obj-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
-obj-$(CONFIG_USB_EHCI_GENERIC) += ehci-generic.o
-obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
-obj-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
-obj-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o
-obj-$(CONFIG_USB_EHCI_MX6) += ehci-mx6.o
-obj-$(CONFIG_USB_EHCI_MX7) += ehci-mx6.o
-obj-$(CONFIG_USB_EHCI_NPCM) += ehci-npcm.o
-obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
-obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
-obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o
-obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
-obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
-obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
-obj-$(CONFIG_USB_EHCI_VF) += ehci-vf.o
-obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
-obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_HCD) += ehci-hcd.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_ARMADA100) += ehci-armada100.o utmi-armada100.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_ATMEL) += ehci-atmel.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_FSL) += ehci-fsl.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_FARADAY) += ehci-faraday.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_GENERIC) += ehci-generic.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_EXYNOS) += ehci-exynos.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_MXS) += ehci-mxs.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_MX5) += ehci-mx5.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_MX6) += ehci-mx6.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_MX7) += ehci-mx6.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_NPCM) += ehci-npcm.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_OMAP) += ehci-omap.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_MARVELL) += ehci-marvell.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_MSM) += ehci-msm.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_PCI) += ehci-pci.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_TEGRA) += ehci-tegra.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_VCT) += ehci-vct.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_VF) += ehci-vf.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_RMOBILE) += ehci-rmobile.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_ZYNQ) += ehci-zynq.o
+obj-$(CONFIG_$(SPL_)USB_EHCI_K1X) += ehci-k1x-ci.o
 
 # xhci
-obj-$(CONFIG_USB_XHCI_BRCM) += xhci-brcm.o
-obj-$(CONFIG_USB_XHCI_HCD) += xhci.o xhci-mem.o xhci-ring.o
-obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o
-obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
-obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
-obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o
-obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
-obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
-obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
-obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
-obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o
-obj-$(CONFIG_USB_XHCI_STI) += dwc3-sti-glue.o
-obj-$(CONFIG_USB_XHCI_OCTEON) += dwc3-octeon-glue.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_BRCM) += xhci-brcm.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_HCD) += xhci.o xhci-mem.o xhci-ring.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_DWC3) += xhci-dwc3.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_EXYNOS) += xhci-exynos5.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_FSL) += xhci-fsl.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_MTK) += xhci-mtk.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_MVEBU) += xhci-mvebu.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_OMAP) += xhci-omap.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_PCI) += xhci-pci.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_RCAR) += xhci-rcar.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_STI) += dwc3-sti-glue.o
+obj-$(CONFIG_$(SPL_)USB_XHCI_OCTEON) += dwc3-octeon-glue.o
 
 # designware
-obj-$(CONFIG_USB_DWC2) += dwc2.o
+obj-$(CONFIG_$(SPL_)USB_DWC2) += dwc2.o
index 23060fc369c0c418faefdf551fbb872700b742c8..4c1ca78061c5ae65600676e051fd4d676eebcfe2 100644 (file)
@@ -1192,7 +1192,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
                 snpsid >> 12 & 0xf, snpsid & 0xfff);
 
        if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
-           (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
+               (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx &&
+               (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_4xx) {
                dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
                         snpsid);
                return -ENODEV;
index a6f562fe60e25f03d29ee0cf669ec5aaa6a52b3d..e54e37d6799ee8b90718dcffe9988236843adf9c 100644 (file)
@@ -735,6 +735,7 @@ struct dwc2_core_regs {
 #define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET                 7
 #define DWC2_SNPSID_DEVID_VER_2xx                      (0x4f542 << 12)
 #define DWC2_SNPSID_DEVID_VER_3xx                      (0x4f543 << 12)
+#define DWC2_SNPSID_DEVID_VER_4xx                      (0x4f544 << 12)
 #define DWC2_SNPSID_DEVID_MASK                         (0xfffff << 12)
 #define DWC2_SNPSID_DEVID_OFFSET                       12
 
@@ -767,13 +768,13 @@ struct dwc2_core_regs {
 #define DWC2_HOST_RX_FIFO_SIZE         (516 + DWC2_MAX_CHANNELS)
 #define DWC2_HOST_NPERIO_TX_FIFO_SIZE  0x100   /* nPeriodic TX FIFO */
 #define DWC2_HOST_PERIO_TX_FIFO_SIZE   0x200   /* Periodic TX FIFO */
-#define DWC2_MAX_TRANSFER_SIZE         65535
+#define DWC2_MAX_TRANSFER_SIZE         524287
 #define DWC2_MAX_PACKET_COUNT          511
 
 #define DWC2_PHY_TYPE_FS               0
 #define DWC2_PHY_TYPE_UTMI             1
 #define DWC2_PHY_TYPE_ULPI             2
-#define DWC2_PHY_TYPE          DWC2_PHY_TYPE_UTMI      /* PHY type */
+#define DWC2_PHY_TYPE          DWC2_PHY_TYPE_ULPI      /* PHY type */
 #ifndef DWC2_UTMI_WIDTH
 #define DWC2_UTMI_WIDTH                8       /* UTMI bus width (8/16) */
 #endif
diff --git a/drivers/usb/host/ehci-k1x-ci.c b/drivers/usb/host/ehci-k1x-ci.c
new file mode 100644 (file)
index 0000000..2f5ad8f
--- /dev/null
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * EHCI Driver Wrapper for Spacemit k1x SoCs
+ *
+ * Copyright (c) 2023 Spacemit Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/ofnode.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <dm.h>
+#include "ehci.h"
+#include <stdbool.h>
+#include <power/regulator.h>
+
+/* PMU */
+#define PMU_SD_ROT_WAKE_CLR                            0x7C
+#define PMU_SD_ROT_WAKE_CLR_VBUS_DRV   (0x1 << 21)
+
+struct ehci_mv_priv {
+       struct ehci_ctrl ctrl;
+       struct clk_bulk clocks;
+       struct reset_ctl_bulk resets;
+       struct phy phy;
+       void __iomem *apmu_base;
+       struct udevice *vbus_supply;
+};
+
+static int mv_ehci_enable_vbus_supply(struct udevice *dev, bool enable)
+{
+       struct ehci_mv_priv *priv = dev_get_priv(dev);
+       if (priv->vbus_supply)
+               return regulator_set_enable(priv->vbus_supply, enable);
+       else
+               return 0;
+}
+
+static void mv_ehci_enable(struct udevice *dev, bool enable)
+{
+       struct ehci_mv_priv *priv = dev_get_priv(dev);
+       uint32_t temp;
+
+       temp = readl(priv->apmu_base + PMU_SD_ROT_WAKE_CLR);
+       if (enable)
+               writel(PMU_SD_ROT_WAKE_CLR_VBUS_DRV | temp, priv->apmu_base + PMU_SD_ROT_WAKE_CLR);
+       else
+               writel(temp & ~PMU_SD_ROT_WAKE_CLR_VBUS_DRV , priv->apmu_base + PMU_SD_ROT_WAKE_CLR);
+}
+
+static int ehci_mv_probe(struct udevice *dev)
+{
+       struct ehci_mv_priv *priv = dev_get_priv(dev);
+       struct ehci_hccr *hccr;
+       struct ehci_hcor *hcor;
+       ofnode apmu_node;
+
+       int err, ret;
+       err = 0;
+
+       dev_info(dev, "ehci_mv_probe Enter ... \n");
+
+       apmu_node = ofnode_by_compatible(ofnode_null(), "spacemit,k1x-pm-domain");
+       if (ofnode_valid(apmu_node)) {
+               priv->apmu_base = (void*)ofnode_get_addr_index(apmu_node, 1);
+       } else {
+               dev_err(dev, "Cannot find apmu node, check dts!\n");
+               return -ENOENT;
+       }
+
+       ret = clk_get_bulk(dev, &priv->clocks);
+       if (ret && ret != -ENOENT) {
+               dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
+               return ret;
+       }
+
+       err = clk_enable_bulk(&priv->clocks);
+       if (err) {
+               dev_err(dev, "Failed to enable clocks (err=%d)\n", err);
+               goto err_clk;
+       }
+
+       err = reset_get_bulk(dev, &priv->resets);
+       if (err && err != -ENOENT) {
+               dev_err(dev, "Failed to get resets (err=%d)\n", err);
+               goto err_clk;
+       }
+
+       err = reset_deassert_bulk(&priv->resets);
+       if (err) {
+               dev_err(dev, "Failed to get deassert resets (err=%d)\n", err);
+               goto err_reset;
+       }
+
+       err = ehci_setup_phy(dev, &priv->phy, 0);
+       if (err)
+               goto err_reset;
+
+       mv_ehci_enable(dev, true);
+
+       hccr = (struct ehci_hccr *)dev_read_addr(dev);
+       hcor = (struct ehci_hcor *)((uintptr_t)hccr +
+                                       HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+       dev_info(dev, "ehci-k1x-ci: init hccr %lx and hcor %lx hc_length %ld\n",
+                 (uintptr_t)hccr, (uintptr_t)hcor, (uintptr_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+       err = device_get_supply_regulator(dev, "vbus-supply",
+                                         &priv->vbus_supply);
+       if (err && err != -ENOENT) {
+               dev_err(dev, "Failed to retrieve vbus-supply regulator, (err=%d)", err);
+               goto err_vbus;
+       }
+       err = mv_ehci_enable_vbus_supply(dev, true);
+       if (err) {
+               dev_err(dev, "Failed to enable vbus (err=%d)\n", err);
+               priv->vbus_supply = NULL;
+               goto err_vbus;
+       }
+
+       err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+       if (err)
+               goto err_vbus;
+
+       return 0;
+
+err_vbus:
+       mv_ehci_enable_vbus_supply(dev, false);
+       mv_ehci_enable(dev, false);
+       ehci_shutdown_phy(dev, &priv->phy);
+err_reset:
+       reset_release_bulk(&priv->resets);
+err_clk:
+       clk_release_bulk(&priv->clocks);
+       return err;
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+       struct ehci_mv_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = ehci_deregister(dev);
+       if (ret)
+               return ret;
+
+       mv_ehci_enable_vbus_supply(dev, false);
+       mv_ehci_enable(dev, false);
+
+       ret = ehci_shutdown_phy(dev, &priv->phy);
+       if (ret)
+               return ret;
+
+       ret = reset_release_bulk(&priv->resets);
+       if (ret)
+               return ret;
+
+       return clk_release_bulk(&priv->clocks);
+}
+
+static const struct udevice_id ehci_mv_ids[] = {
+       { .compatible = "spacemit,mv-ehci" },
+       { }
+};
+
+U_BOOT_DRIVER(ehci_generic) = {
+       .name   = "ehci_k1x_ci",
+       .id     = UCLASS_USB,
+       .of_match = ehci_mv_ids,
+       .probe = ehci_mv_probe,
+       .remove = ehci_usb_remove,
+       .ops    = &ehci_usb_ops,
+       .priv_auto      = sizeof(struct ehci_mv_priv),
+       .flags  = DM_FLAG_ALLOC_PRIV_DMA,
+};
index 4ecc158c4605e05f2923be568ea41f4cc2afec0f..781d94a7394be2679096c29e25e557a0894568e5 100644 (file)
@@ -939,4 +939,6 @@ config VIDEO_VCXK
          This enables VCXK driver which can be used with VC2K, VC4K
          and VC8K devices on various boards from BuS Elektronik GmbH.
 
+source "drivers/video/spacemit/Kconfig"
+
 endmenu
index 7019b26396393e36d822975e803beef7e8aaf358..43998f2ae586c66e05582c5fb718a3d1e2186a8d 100644 (file)
@@ -26,6 +26,7 @@ obj-${CONFIG_EXYNOS_FB} += exynos/
 obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
 obj-${CONFIG_VIDEO_STM32} += stm32/
 obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
+obj-${CONFIG_VIDEO_SPACEMIT} += spacemit/
 obj-y += ti/
 
 obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
index c04b449a6d5d6b9b2e26839b00a04a88e01f977e..06691772886a9352512557979dd0c5872f561b1d 100644 (file)
@@ -171,6 +171,115 @@ static int console_truetype_set_row(struct udevice *dev, uint row, int clr)
        return 0;
 }
 
+int console_truetype_fill_rect(struct udevice *dev, int xstart, int ystart, int width, int height, int clr) {
+       struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+       void *line;
+
+       if(width == 0 && height == 0)
+               return 0;
+
+       /* Use the same calculation method as in console_truetype_putc_xy */
+       for (int row = 0; row < height; ++row) {
+               void *start = vid_priv->fb + (ystart + row) * vid_priv->line_length + VID_TO_PIXEL(xstart) * VNBYTES(vid_priv->bpix);
+               line = start;
+
+               switch (vid_priv->bpix) {
+               #ifdef CONFIG_VIDEO_BPP8
+                       case VIDEO_BPP8: {
+                               u8 *dst = (u8 *)line;
+                               for (int col = 0; col < width; ++col) {
+                                       *dst++ = clr;
+                               }
+                               break;
+                       }
+               #endif
+               #ifdef CONFIG_VIDEO_BPP16
+                       case VIDEO_BPP16: {
+                               u16 *dst = (u16 *)line;
+                               for (int col = 0; col < width; ++col) {
+                                       *dst++ = clr;
+                               }
+                               break;
+                       }
+               #endif
+               #ifdef CONFIG_VIDEO_BPP32
+                       case VIDEO_BPP32: {
+                               u32 *dst = (u32 *)line;
+                               for (int col = 0; col < width; ++col) {
+                                       *dst++ = clr;
+                               }
+                               break;
+                       }
+               #endif
+                       default:
+                               return -ENOSYS;
+               }
+       }
+
+       int ret = vidconsole_sync_copy(dev, vid_priv->fb + ystart * vid_priv->line_length, vid_priv->fb + (ystart + height) * vid_priv->line_length);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+void calculate_text_dimensions(struct udevice *dev, const char *str, int *text_width, int *text_height) {
+       /* First, check if str is empty */
+       if (!str || *str == '\0') {
+               *text_width = 0;
+               *text_height = 0;
+               return; /* Early return, no further processing needed */
+       }
+
+       struct console_tt_priv *priv = dev_get_priv(dev);
+       stbtt_fontinfo *font = &priv->font;
+       double scale = priv->scale;
+       int line_height = priv->font_size;
+
+       *text_width = 0;
+       *text_height = 0;
+       int max_line_width = 0;
+       int current_line_width = 0;
+       int lines = 1;
+
+       /* use 1/9 of the font size as spacing */
+       int char_spacing = priv->font_size / 9;
+
+       for (; *str; ++str) {
+               if (*str == '\n') {
+                       if (current_line_width > max_line_width) {
+                               max_line_width = current_line_width;
+                       }
+                       current_line_width = 0;
+                       lines++;
+                       continue;
+               }
+
+               int width, height, xoff, yoff;
+               /* Get the bitmap for the character to calculate width and height */
+               unsigned char *bitmap = stbtt_GetCodepointBitmapSubpixel(font, scale, scale, 0, 0, *str, &width, &height, &xoff, &yoff);
+               if (bitmap) {
+                       /* Add character spacing to the character width */
+                       current_line_width += width + char_spacing;
+                       stbtt_FreeBitmap(bitmap, NULL);
+               }
+       }
+
+       *text_width = max(max_line_width, current_line_width);
+       *text_height = lines * line_height;
+}
+
+int get_string_dimensions(struct udevice *dev, const char *str, int *width, int *height) {
+    if (!dev || !str || !width || !height) {
+        printf("Invalid parameters\n");
+        return -EINVAL;
+    }
+
+    calculate_text_dimensions(dev, str, width, height);
+
+    return 0;
+}
+
 static int console_truetype_move_rows(struct udevice *dev, uint rowdst,
                                     uint rowsrc, uint count)
 {
index c4fbb182944673f8616a336200a359d055aca7f8..a74c786f623dcd7933788176f16b36c4404bd01e 100644 (file)
@@ -78,10 +78,10 @@ static void dw_hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
 {
        switch (hdmi->reg_io_width) {
        case 1:
-               writeb(val, hdmi->ioaddr + offset);
+               writeb(val, (volatile void __iomem *)(hdmi->ioaddr + offset));
                break;
        case 4:
-               writel(val, hdmi->ioaddr + (offset << 2));
+               writel(val, (volatile void __iomem *)(hdmi->ioaddr + (offset << 2)));
                break;
        default:
                debug("reg_io_width has unsupported width!\n");
@@ -93,9 +93,9 @@ static u8 dw_hdmi_read(struct dw_hdmi *hdmi, int offset)
 {
        switch (hdmi->reg_io_width) {
        case 1:
-               return readb(hdmi->ioaddr + offset);
+               return readb((const volatile void __iomem *)(hdmi->ioaddr + offset));
        case 4:
-               return readl(hdmi->ioaddr + (offset << 2));
+               return readl((const volatile void __iomem *)(hdmi->ioaddr + (offset << 2)));
        default:
                debug("reg_io_width has unsupported width!\n");
                break;
diff --git a/drivers/video/spacemit/Kconfig b/drivers/video/spacemit/Kconfig
new file mode 100644 (file)
index 0000000..5e2ba84
--- /dev/null
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig VIDEO_SPACEMIT
+       bool "Enable SPACEMIT Video Support"
+       depends on DM_VIDEO
+       help
+         SPACEMIT SoCs provide video output capabilities for High-Definition
+         Multimedia Interface (HDMI) and Display Serial Interface (DSI).
+
+         This driver supports the on-chip video output device.
+
+config VIDEO_SPACEMIT_MAX_XRES
+        int "Maximum horizontal resolution (for memory allocation purposes)"
+       depends on VIDEO_SPACEMIT
+       default 1920
+       help
+         The maximum horizontal resolution to support for the framebuffer.
+         This configuration is used for reserving/allocating memory for the
+         framebuffer during device-model binding/probing.
+
+config VIDEO_SPACEMIT_MAX_YRES
+        int "Maximum vertical resolution (for memory allocation purposes)"
+       depends on VIDEO_SPACEMIT
+       default 1200
+       help
+         The maximum vertical resolution to support for the framebuffer.
+         This configuration is used for reserving/allocating memory for the
+         framebuffer during device-model binding/probing.
+
+if VIDEO_SPACEMIT
+
+config DISPLAY_SPACEMIT_HDMI
+       bool "HDMI port"
+       select VIDEO_DW_HDMI
+       depends on VIDEO_SPACEMIT
+       help
+         This enables High-Definition Multimedia Interface display support.
+
+config DISPLAY_SPACEMIT_MIPI
+       bool "MIPI Port"
+       depends on VIDEO_SPACEMIT
+       help
+         This enables Mobile Industry Processor Interface(MIPI) display
+         support.
+
+endif
diff --git a/drivers/video/spacemit/Makefile b/drivers/video/spacemit/Makefile
new file mode 100644 (file)
index 0000000..c5849bd
--- /dev/null
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ifdef CONFIG_VIDEO_SPACEMIT
+obj-y += dsi/
+obj-y += spacemit_dpu.o
+obj-$(CONFIG_DISPLAY_SPACEMIT_MIPI) += spacemit_mipi.o
+obj-$(CONFIG_DISPLAY_SPACEMIT_HDMI) += spacemit_hdmi.o
+
+endif
diff --git a/drivers/video/spacemit/dsi/Makefile b/drivers/video/spacemit/dsi/Makefile
new file mode 100644 (file)
index 0000000..00d52e3
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += video/spacemit_video_tx.o \
+               video/spacemit_mipi_port.o \
+               drv/spacemit_dphy.o \
+               drv/spacemit_dsi_common.o \
+               drv/spacemit_dsi_drv.o
+
+obj-y += video/lcd/lcd_icnl9911c.o
+obj-y += video/lcd/lcd_gx09inx101.o
+
diff --git a/drivers/video/spacemit/dsi/drv/spacemit_dphy.c b/drivers/video/spacemit/dsi/drv/spacemit_dphy.c
new file mode 100644 (file)
index 0000000..887627d
--- /dev/null
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <stdio.h>
+#include <linux/delay.h>
+
+#include "spacemit_dsi_hw.h"
+#include "spacemit_dphy.h"
+
+
+static unsigned int spacemit_dphy_lane[5] = {0, 0x1, 0x3, 0x7, 0xf};
+
+static void dphy_ana_reset(void)
+{
+       dsi_clear_bits(DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+       udelay(5);
+       dsi_set_bits(DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+}
+
+static void dphy_set_power(bool poweron)
+{
+       if(poweron) {
+               dsi_set_bits(DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+               dsi_set_bits(DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_PU);
+       } else {
+               dsi_clear_bits(DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_PU);
+               dsi_clear_bits(DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+       }
+}
+
+static void dphy_set_cont_clk(bool cont_clk)
+{
+       if(cont_clk)
+               dsi_set_bits(DSI_PHY_CTRL_1, CFG_DPHY_CONT_CLK);
+       else
+               dsi_clear_bits(DSI_PHY_CTRL_1, CFG_DPHY_CONT_CLK);
+
+       dsi_set_bits(DSI_PHY_CTRL_1, CFG_DPHY_ADD_VALID);
+       dsi_set_bits(DSI_PHY_CTRL_1, CFG_DPHY_VDD_VALID);
+}
+
+static void dphy_set_lane_num(uint32_t lane_num)
+{
+       dsi_write_bits(DSI_PHY_CTRL_2,
+               CFG_DPHY_LANE_EN_MASK, spacemit_dphy_lane[lane_num] << CFG_DPHY_LANE_EN_SHIFT);
+}
+
+static void dphy_set_bit_clk_src(uint32_t bit_clk_src,
+       uint32_t half_pll5)
+{
+       if(bit_clk_src >= DPHY_BIT_CLK_SRC_MAX) {
+               pr_info("%s: Invalid bit clk src (%d)\n", __func__, bit_clk_src);
+               return;
+       }
+}
+
+static void dphy_set_timing(struct spacemit_dphy_ctx *dphy_ctx)
+{
+    uint32_t bitclk;
+       int ui, wakeup;
+       int hs_prep, hs_zero, hs_trail, hs_exit, ck_zero, ck_trail;
+       int esc_clk, esc_clk_t;
+       struct spacemit_dphy_timing *phy_timing;
+
+       if(NULL == dphy_ctx) {
+               pr_info("%s: Invalid param!\n", __func__);
+               return;
+       }
+
+       phy_timing = &(dphy_ctx->dphy_timing);
+
+       esc_clk = dphy_ctx->esc_clk/1000;
+       esc_clk_t = 1000/esc_clk;
+
+       bitclk = dphy_ctx->phy_freq / 1000;
+       ui = 1000/bitclk + 1;
+
+       /*Jessica: Why no wakeup_ui?*/
+       wakeup = phy_timing->wakeup_constant;
+       wakeup = wakeup / esc_clk_t + 1;
+
+       hs_prep = phy_timing->hs_prep_constant + phy_timing->hs_prep_ui * ui;
+       hs_prep = hs_prep / esc_clk_t + 1;
+
+       /* Our hardware added 3-byte clk automatically.
+        * 3-byte 3 * 8 * ui.
+        */
+       hs_zero = phy_timing->hs_zero_constant + phy_timing->hs_zero_ui * ui -
+               (hs_prep + 1) * esc_clk_t;
+       hs_zero = (hs_zero - (3 * ui << 3)) / esc_clk_t + 4;
+       if (hs_zero < 0)
+               hs_zero = 0;
+
+       hs_trail = phy_timing->hs_trail_constant + phy_timing->hs_trail_ui * ui;
+       hs_trail = ((8 * ui) >= hs_trail) ? (8 * ui) : hs_trail;
+       hs_trail = hs_trail / esc_clk_t + 1;
+       if (hs_trail > 3)
+               hs_trail -= 3;
+       else
+               hs_trail = 0;
+
+       hs_exit = phy_timing->hs_exit_constant + phy_timing->hs_exit_ui * ui;
+       hs_exit = hs_exit / esc_clk_t + 1;
+
+       ck_zero = phy_timing->ck_zero_constant + phy_timing->ck_zero_ui * ui -
+               (hs_prep + 1) * esc_clk_t;
+       ck_zero = ck_zero / esc_clk_t + 1;
+
+       ck_trail = phy_timing->ck_trail_constant + phy_timing->ck_trail_ui * ui;
+       ck_trail = ck_trail / esc_clk_t + 1;
+
+       //dsi_write(DSI_PHY_TIME_0, reg);
+       dsi_write(DSI_PHY_TIME_0, 0x06010603);
+
+       //dsi_write(DSI_PHY_TIME_1, reg);
+       dsi_write(DSI_PHY_TIME_1, 0x130fcd98);
+
+       //dsi_write(DSI_PHY_TIME_2, reg);
+       dsi_write(DSI_PHY_TIME_2, 0x06040c04);
+
+       //dsi_write(DSI_PHY_TIME_3, reg);
+       dsi_write(DSI_PHY_TIME_3, 0x43c);
+
+       /* calculated timing on brownstone:
+        * DSI_PHY_TIME_0 0x06080204
+        * DSI_PHY_TIME_1 0x6d2bfff0
+        * DSI_PHY_TIME_2 0x603130a
+        * DSI_PHY_TIME_3 0xa3c
+        */
+}
+
+void spacemit_dphy_get_status(struct spacemit_dphy_ctx *dphy_ctx)
+{
+       if(NULL == dphy_ctx){
+               pr_info("%s: Invalid param\n", __func__);
+               return;
+       }
+
+       dphy_ctx->dphy_status0 = dsi_read(DSI_PHY_STATUS_0);
+       dphy_ctx->dphy_status1 = dsi_read(DSI_PHY_STATUS_1);
+       dphy_ctx->dphy_status2 = dsi_read(DSI_PHY_STATUS_2);
+}
+
+void spacemit_dphy_reset(struct spacemit_dphy_ctx *dphy_ctx)
+{
+       if(NULL == dphy_ctx){
+               pr_info("%s: Invalid param\n", __func__);
+               return;
+       }
+
+       dphy_ana_reset();
+}
+
+/**
+ * spacemit_dphy_init - int spacemit dphy
+ *
+ * @dphy_ctx: pointer to the spacemit_dphy_ctx
+ *
+ * This function will be called by the dsi driver in order to init the dphy
+ * This function will do phy power on, enable continous clk, set dphy timing
+ * and set lane number.
+ *
+ * This function has no return value.
+ *
+ */
+void spacemit_dphy_init(struct spacemit_dphy_ctx *dphy_ctx)
+{
+       if(NULL == dphy_ctx){
+               pr_info("%s: Invalid param\n", __func__);
+               return;
+       }
+
+       if(DPHY_STATUS_UNINIT != dphy_ctx->status){
+               pr_info("%s: dphy_ctx has been initialized (%d)\n",
+                       __func__, dphy_ctx->status);
+               return;
+       }
+
+       /*use DPHY_BIT_CLK_SRC_MUX as default clk src*/
+       dphy_set_bit_clk_src(dphy_ctx->clk_src, dphy_ctx->half_pll5);
+
+       /* digital and analog power on */
+       dphy_set_power(true);
+
+       /* turn on DSI continuous clock for HS */
+       dphy_set_cont_clk(true);
+
+       /* set dphy */
+       dphy_set_timing(dphy_ctx);
+
+       /* enable data lanes */
+       dphy_set_lane_num(dphy_ctx->lane_num);
+
+       dphy_ctx->status = DPHY_STATUS_INIT;
+
+       /* add delay for dsi phy stable */
+       mdelay(1);
+}
+
+/**
+ * spacemit_dphy_uninit - unint spacemit dphy
+ *
+ * @dphy_ctx: pointer to the spacemit_dphy_ctx
+ *
+ * This function will be called by the dsi driver in order to unint the dphy
+ * This function will disable continous clk, reset dephy, power down dphy
+ *
+ * This function has no return value.
+ *
+ */
+void spacemit_dphy_uninit(struct spacemit_dphy_ctx *dphy_ctx)
+{
+       if(NULL == dphy_ctx){
+               pr_info("%s: Invalid param\n", __func__);
+               return;
+       }
+
+       if(DPHY_STATUS_INIT != dphy_ctx->status){
+               pr_info("%s: dphy_ctx has not been initialized (%d)\n",
+                       __func__, dphy_ctx->status);
+               return;
+       }
+
+       dphy_set_cont_clk(false);
+       dphy_ana_reset();
+       dphy_set_power(false);
+
+       dphy_ctx->status = DPHY_STATUS_UNINIT;
+}
diff --git a/drivers/video/spacemit/dsi/drv/spacemit_dphy.h b/drivers/video/spacemit/dsi/drv/spacemit_dphy.h
new file mode 100644 (file)
index 0000000..35f3367
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DPHY_H_
+#define _SPACEMIT_DPHY_H_
+
+#include <linux/types.h>
+
+enum spacemit_dphy_lane_map {
+       DPHY_LANE_MAP_0123 = 0,
+       DPHY_LANE_MAP_0312 = 1,
+       DPHY_LANE_MAP_0231 = 2,
+       DPHY_LANE_MAP_MAX
+};
+
+enum spacemit_dphy_status {
+       DPHY_STATUS_UNINIT = 0,
+       DPHY_STATUS_INIT = 1,
+       DPHY_STATUS_MAX
+};
+
+enum spacemit_dphy_bit_clk_src {
+       DPHY_BIT_CLK_SRC_PLL5 = 1,
+       DPHY_BIT_CLK_SRC_MUX = 2,
+       DPHY_BIT_CLK_SRC_MAX
+};
+
+struct spacemit_dphy_timing {
+       uint32_t hs_prep_constant;    /* Unit: ns. */
+       uint32_t hs_prep_ui;
+       uint32_t hs_zero_constant;
+       uint32_t hs_zero_ui;
+       uint32_t hs_trail_constant;
+       uint32_t hs_trail_ui;
+       uint32_t hs_exit_constant;
+       uint32_t hs_exit_ui;
+       uint32_t ck_zero_constant;
+       uint32_t ck_zero_ui;
+       uint32_t ck_trail_constant;
+       uint32_t ck_trail_ui;
+       uint32_t req_ready;
+       uint32_t wakeup_constant;
+       uint32_t wakeup_ui;
+       uint32_t lpx_constant;
+       uint32_t lpx_ui;
+};
+
+
+struct spacemit_dphy_ctx {
+       uint32_t phy_freq; /*kHz*/
+       uint32_t lane_num;
+       uint32_t esc_clk; /*kHz*/
+       uint32_t half_pll5;
+       enum spacemit_dphy_bit_clk_src clk_src;
+       struct spacemit_dphy_timing dphy_timing;
+       uint32_t dphy_status0; /*status0 reg*/
+       uint32_t dphy_status1; /*status1 reg*/
+       uint32_t dphy_status2; /*status2 reg*/
+
+       enum spacemit_dphy_status status;
+};
+
+void spacemit_dphy_init(struct spacemit_dphy_ctx *dphy_ctx);
+void spacemit_dphy_get_status(struct spacemit_dphy_ctx *dphy_ctx);
+void spacemit_dphy_reset(struct spacemit_dphy_ctx *dphy_ctx);
+void spacemit_dphy_uninit(struct spacemit_dphy_ctx *dphy_ctx);
+
+#endif /*_SPACEMIT_DPHY_H_*/
diff --git a/drivers/video/spacemit/dsi/drv/spacemit_dsi_common.c b/drivers/video/spacemit/dsi/drv/spacemit_dsi_common.c
new file mode 100644 (file)
index 0000000..45df6c7
--- /dev/null
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include "spacemit_dsi_drv.h"
+#include "../include/spacemit_dsi_common.h"
+
+#define MAX_DSI_NUM 1
+
+struct spacemit_dsi_device *g_spacemit_dsi_list[MAX_DSI_NUM];
+
+/*API for panel*/
+int spacemit_mipi_open(int id, struct spacemit_mipi_info *mipi_info, bool ready)
+{
+       if(id >= MAX_DSI_NUM) {
+               pr_info("%s: Invalid param (%d)\n", __func__, id);
+               return -1;
+       }
+
+       if(NULL == g_spacemit_dsi_list[id]){
+               pr_info("%s: dsi (%d) has not been registed\n", __func__, id);
+               return -1;
+       }
+
+       return g_spacemit_dsi_list[id]->driver_ctx->dsi_open(g_spacemit_dsi_list[id], mipi_info, ready);
+}
+
+int spacemit_mipi_close(int id)
+{
+       if(id >= MAX_DSI_NUM) {
+               pr_info("%s: Invalid param (%d)\n", __func__, id);
+               return -1;
+       }
+
+       if(NULL == g_spacemit_dsi_list[id]){
+               pr_info("%s: dsi (%d) has not been registed\n", __func__, id);
+               return -1;
+       }
+
+       return g_spacemit_dsi_list[id]->driver_ctx->dsi_close(g_spacemit_dsi_list[id]);
+}
+
+int spacemit_mipi_write_cmds(int id, struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+       if(id >= MAX_DSI_NUM) {
+               pr_info("%s: Invalid param (%d)\n", __func__, id);
+               return -1;
+       }
+
+       if(NULL == g_spacemit_dsi_list[id]){
+               pr_info("%s: dsi (%d) has not been registed\n", __func__, id);
+               return -1;
+       }
+
+       return g_spacemit_dsi_list[id]->driver_ctx->dsi_write_cmds(g_spacemit_dsi_list[id], cmds, count);
+}
+
+int spacemit_mipi_read_cmds(int id, struct spacemit_dsi_rx_buf *dbuf,
+                                                       struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+       if(id >= MAX_DSI_NUM) {
+               pr_info("%s: Invalid param (%d)\n", __func__, id);
+               return -1;
+       }
+
+       if(NULL == g_spacemit_dsi_list[id]){
+               pr_info("%s: dsi (%d) has not been registed\n", __func__, id);
+               return -1;
+       }
+
+       return g_spacemit_dsi_list[id]->driver_ctx->dsi_read_cmds(g_spacemit_dsi_list[id], dbuf, cmds, count);
+}
+
+int spacemit_mipi_ready_for_datatx(int id, struct spacemit_mipi_info *mipi_info)
+{
+       if(id >= MAX_DSI_NUM) {
+               pr_info("%s: Invalid param (%d)\n", __func__, id);
+               return -1;
+       }
+
+       if(NULL == g_spacemit_dsi_list[id]){
+               pr_info("%s: dsi (%d) has not been registed\n", __func__, id);
+               return -1;
+       }
+
+       return g_spacemit_dsi_list[id]->driver_ctx->dsi_ready_for_datatx(g_spacemit_dsi_list[id], mipi_info);
+}
+
+int spacemit_mipi_close_datatx(int id)
+{
+       if(id >= MAX_DSI_NUM) {
+               pr_info("%s: Invalid param (%d)\n", __func__, id);
+               return -1;
+       }
+
+       if(NULL == g_spacemit_dsi_list[id]){
+               pr_info("%s: dsi (%d) has not been registed\n", __func__, id);
+               return -1;
+       }
+
+       return g_spacemit_dsi_list[id]->driver_ctx->dsi_close_datatx(g_spacemit_dsi_list[id]);
+}
+
+/*API for dsi driver*/
+int spacemit_dsi_register_device(void *device)
+{
+       struct spacemit_dsi_device *dsi_device = (struct spacemit_dsi_device*)device;
+
+       if(NULL == dsi_device){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       if(dsi_device->id >= MAX_DSI_NUM){
+               pr_info("%s: error id(%d)!\n", __func__, dsi_device->id);
+               return -1;
+       }
+
+       if(dsi_device->driver_ctx == NULL){
+               pr_info("%s: error driver_ctx!\n", __func__);
+               return -1;
+       }
+
+       if(g_spacemit_dsi_list[dsi_device->id] != NULL){
+               pr_info("%s: %d id has been registed!\n",  __func__, dsi_device->id);
+               return -1;
+       }
+
+       g_spacemit_dsi_list[dsi_device->id] = dsi_device;
+
+       return 0;
+}
diff --git a/drivers/video/spacemit/dsi/drv/spacemit_dsi_drv.c b/drivers/video/spacemit/dsi/drv/spacemit_dsi_drv.c
new file mode 100644 (file)
index 0000000..affbbc1
--- /dev/null
@@ -0,0 +1,895 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/delay.h>
+#include <common.h>
+
+#include "../include/spacemit_dsi_common.h"
+#include "spacemit_dsi_drv.h"
+#include "spacemit_dsi_hw.h"
+#include "spacemit_dphy.h"
+
+#define SPACEMIT_DSI_NAME "spacemit_dsi"
+#define SPACEMIT_DSI_VERSION   "1.0.0"
+
+#define SPACEMIT_ESC_CLK_DEFAULT 52000000
+#define MIPI_CLK_MIN 800000000
+
+#define SPACEMIT_DSI_MAX_TX_FIFO_BYTES 256
+#define SPACEMIT_DSI_MAX_RX_FIFO_BYTES 64
+
+#define SPACEMIT_DSI_MAX_CMD_FIFO_BYTES        1024
+
+#define LPM_FRAME_EN_DEFAULT 0
+#define LAST_LINE_TURN_DEFAULT 0
+#define HEX_SLOT_EN_DEFAULT 0
+#define HSA_PKT_EN_DEFAULT_SYNC_PULSE 1
+#define HSA_PKT_EN_DEFAULT_OTHER 0
+#define HSE_PKT_EN_DEFAULT_SYNC_PULSE 1
+#define HSE_PKT_EN_DEFAULT_OTHER 0
+#define HBP_PKT_EN_DEFAULT 1
+//#define HFP_PKT_EN_DEFAULT 1
+#define HFP_PKT_EN_DEFAULT 0
+#define HEX_PKT_EN_DEFAULT 0
+#define HLP_PKT_EN_DEFAULT 0
+#define AUTO_DLY_DIS_DEFAULT 0
+#define TIMING_CHECK_DIS_DEFAULT 0
+#define HACT_WC_EN_DEFAULT 1
+#define AUTO_WC_DIS_DEFAULT 0
+#define VSYNC_RST_EN_DEFAULT 1
+
+#define HS_PREP_CONSTANT_DEFAULT 40
+#define HS_PREP_UI_DEFAULT 4
+#define HS_ZERO_CONSTANT_DEFAULT 145
+#define HS_ZERO_UI_DEFAULT 10
+#define HS_TRAIL_CONSTANT_DEFAULT 60
+#define HS_TRAIL_UI_DEFAULT 4
+#define HS_EXIT_CONSTANT_DEFAULT 100
+#define HS_EXIT_UI_DEFAULT 0
+#define CK_ZERO_CONSTANT_DEFAULT 300
+#define CK_ZERO_UI_DEFAULT 0
+#define CK_TRAIL_CONSTANT_DEFAULT 60
+#define CK_TRAIL_UI_DEFAULT 0
+#define REQ_READY_DEFAULT 0x3C
+#define WAKEUP_CONSTANT_DEFAULT 1000000
+#define WAKEUP_UI_DEFAULT 0
+#define LPX_CONSTANT_DEFAULT 60
+#define LPX_UI_DEFAULT 0
+#define PLL5_VCO_DEF 1540000000
+#define CLK_CALCU_DIFF 24
+#define PXCLK_PLL5_DIV 3
+
+
+#define to_dsi_bcnt(timing, bpp)        (((timing) * (bpp)) >> 3)
+
+static unsigned int spacemit_dsi_lane[5] = {0, 0x1, 0x3, 0x7, 0xf};
+
+static unsigned char dsi_bit(unsigned int index, unsigned char *pdata)
+{
+       unsigned char ret;
+       unsigned int cindex, bindex;
+       cindex = index / 8;
+       bindex = index % 8;
+
+       if (pdata[cindex] & (0x1 << bindex))
+               ret = (unsigned char) 0x1;
+       else
+               ret = (unsigned char) 0x0;
+
+       return ret;
+}
+
+static unsigned char calculate_ecc(unsigned char *pdata)
+{
+       unsigned char ret;
+       unsigned char p[8];
+
+       p[7] = (unsigned char) 0x0;
+       p[6] = (unsigned char) 0x0;
+
+       p[5] = (unsigned char) (
+       (
+               dsi_bit(10, pdata) ^
+               dsi_bit(11, pdata) ^
+               dsi_bit(12, pdata) ^
+               dsi_bit(13, pdata) ^
+               dsi_bit(14, pdata) ^
+               dsi_bit(15, pdata) ^
+               dsi_bit(16, pdata) ^
+               dsi_bit(17, pdata) ^
+               dsi_bit(18, pdata) ^
+               dsi_bit(19, pdata) ^
+               dsi_bit(21, pdata) ^
+               dsi_bit(22, pdata) ^
+               dsi_bit(23, pdata)
+               )
+       );
+       p[4] = (unsigned char) (
+               dsi_bit(4, pdata) ^
+               dsi_bit(5, pdata) ^
+               dsi_bit(6, pdata) ^
+               dsi_bit(7, pdata) ^
+               dsi_bit(8, pdata) ^
+               dsi_bit(9, pdata) ^
+               dsi_bit(16, pdata) ^
+               dsi_bit(17, pdata) ^
+               dsi_bit(18, pdata) ^
+               dsi_bit(19, pdata) ^
+               dsi_bit(20, pdata) ^
+               dsi_bit(22, pdata) ^
+               dsi_bit(23, pdata)
+       );
+       p[3] = (unsigned char) (
+       (
+               dsi_bit(1, pdata) ^
+               dsi_bit(2, pdata) ^
+               dsi_bit(3, pdata) ^
+               dsi_bit(7, pdata) ^
+               dsi_bit(8, pdata) ^
+               dsi_bit(9, pdata) ^
+               dsi_bit(13, pdata) ^
+               dsi_bit(14, pdata) ^
+               dsi_bit(15, pdata) ^
+               dsi_bit(19, pdata) ^
+               dsi_bit(20, pdata) ^
+               dsi_bit(21, pdata) ^
+               dsi_bit(23, pdata)
+               )
+       );
+       p[2] = (unsigned char) (
+       (
+               dsi_bit(0, pdata) ^
+               dsi_bit(2, pdata) ^
+               dsi_bit(3, pdata) ^
+               dsi_bit(5, pdata) ^
+               dsi_bit(6, pdata) ^
+               dsi_bit(9, pdata) ^
+               dsi_bit(11, pdata) ^
+               dsi_bit(12, pdata) ^
+               dsi_bit(15, pdata) ^
+               dsi_bit(18, pdata) ^
+               dsi_bit(20, pdata) ^
+               dsi_bit(21, pdata) ^
+               dsi_bit(22, pdata)
+               )
+       );
+       p[1] = (unsigned char) (
+               (
+               dsi_bit(0, pdata) ^
+               dsi_bit(1, pdata) ^
+               dsi_bit(3, pdata) ^
+               dsi_bit(4, pdata) ^
+               dsi_bit(6, pdata) ^
+               dsi_bit(8, pdata) ^
+               dsi_bit(10, pdata) ^
+               dsi_bit(12, pdata) ^
+               dsi_bit(14, pdata) ^
+               dsi_bit(17, pdata) ^
+               dsi_bit(20, pdata) ^
+               dsi_bit(21, pdata) ^
+               dsi_bit(22, pdata) ^
+               dsi_bit(23, pdata)
+               )
+       );
+       p[0] = (unsigned char) (
+               (
+               dsi_bit(0, pdata) ^
+               dsi_bit(1, pdata) ^
+               dsi_bit(2, pdata) ^
+               dsi_bit(4, pdata) ^
+               dsi_bit(5, pdata) ^
+               dsi_bit(7, pdata) ^
+               dsi_bit(10, pdata) ^
+               dsi_bit(11, pdata) ^
+               dsi_bit(13, pdata) ^
+               dsi_bit(16, pdata) ^
+               dsi_bit(20, pdata) ^
+               dsi_bit(21, pdata) ^
+               dsi_bit(22, pdata) ^
+               dsi_bit(23, pdata)
+               )
+       );
+       ret = (unsigned char)(
+               p[0] |
+               (p[1] << 0x1) |
+               (p[2] << 0x2) |
+               (p[3] << 0x3) |
+               (p[4] << 0x4) |
+               (p[5] << 0x5)
+       );
+       return   ret;
+}
+
+static unsigned short gs_crc16_generation_code = 0x8408;
+static unsigned short calculate_crc16(unsigned char *pdata, unsigned
+               short count)
+{
+       unsigned short byte_counter;
+       unsigned char bit_counter;
+       unsigned char data;
+       unsigned short crc16_result = 0xFFFF;
+       if (count > 0) {
+               for (byte_counter = 0; byte_counter < count;
+                       byte_counter++) {
+                       data = *(pdata + byte_counter);
+                       for (bit_counter = 0; bit_counter < 8; bit_counter++) {
+                               if (((crc16_result & 0x0001) ^ ((0x0001 *
+                                       data) & 0x0001)) > 0)
+                                       crc16_result = ((crc16_result >> 1)
+                                       & 0x7FFF) ^ gs_crc16_generation_code;
+                               else
+                                       crc16_result = (crc16_result >> 1)
+                                       & 0x7FFF;
+                               data = (data >> 1) & 0x7F;
+                       }
+               }
+       }
+       return crc16_result;
+}
+
+static void dsi_get_advanced_setting(struct spacemit_dsi_device *dev, struct spacemit_mipi_info *mipi_info)
+{
+       struct spacemit_dsi_advanced_setting *adv_setting = &dev->adv_setting;
+
+       adv_setting->lpm_frame_en = LPM_FRAME_EN_DEFAULT;
+       adv_setting->last_line_turn = LAST_LINE_TURN_DEFAULT;
+       adv_setting->hex_slot_en = HEX_SLOT_EN_DEFAULT;
+
+       if(mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE)
+               adv_setting->hsa_pkt_en = HSA_PKT_EN_DEFAULT_SYNC_PULSE;
+       else
+               adv_setting->hsa_pkt_en = HSA_PKT_EN_DEFAULT_OTHER;
+
+       if(mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE)
+               adv_setting->hse_pkt_en = HSE_PKT_EN_DEFAULT_SYNC_PULSE;
+       else
+               adv_setting->hse_pkt_en = HSE_PKT_EN_DEFAULT_OTHER;
+
+       adv_setting->hbp_pkt_en = HBP_PKT_EN_DEFAULT;
+       adv_setting->hfp_pkt_en = HFP_PKT_EN_DEFAULT;
+       adv_setting->hex_pkt_en = HEX_PKT_EN_DEFAULT;
+       adv_setting->hlp_pkt_en = HLP_PKT_EN_DEFAULT;
+       adv_setting->auto_dly_dis = AUTO_DLY_DIS_DEFAULT;
+       adv_setting->timing_check_dis = TIMING_CHECK_DIS_DEFAULT;
+       adv_setting->hact_wc_en = HACT_WC_EN_DEFAULT;
+       adv_setting->auto_wc_dis = AUTO_WC_DIS_DEFAULT;
+       adv_setting->vsync_rst_en = VSYNC_RST_EN_DEFAULT;
+}
+
+static void dsi_get_dphy_setting(struct spacemit_dsi_device *dev)
+{
+       struct spacemit_dphy_timing *dphy_timing;
+
+       if(NULL == dev){
+               pr_info("%s: Invalid param\n",__func__);
+               return;
+       }
+
+       dphy_timing = &dev->dphy_config.dphy_timing;
+
+       dphy_timing->hs_prep_constant = HS_PREP_CONSTANT_DEFAULT;
+       dphy_timing->hs_prep_ui = HS_PREP_UI_DEFAULT;
+       dphy_timing->hs_zero_constant = HS_ZERO_CONSTANT_DEFAULT;
+       dphy_timing->hs_zero_ui = HS_ZERO_UI_DEFAULT;
+       dphy_timing->hs_trail_constant = HS_TRAIL_CONSTANT_DEFAULT;
+       dphy_timing->hs_trail_ui = HS_TRAIL_UI_DEFAULT;
+       dphy_timing->hs_exit_constant = HS_EXIT_CONSTANT_DEFAULT;
+       dphy_timing->hs_exit_ui = HS_EXIT_UI_DEFAULT;
+       dphy_timing->ck_zero_constant = CK_ZERO_CONSTANT_DEFAULT;
+       dphy_timing->ck_zero_ui = CK_ZERO_UI_DEFAULT;
+       dphy_timing->ck_trail_constant = CK_TRAIL_CONSTANT_DEFAULT;
+       dphy_timing->ck_zero_ui = CK_TRAIL_UI_DEFAULT;
+       dphy_timing->req_ready = REQ_READY_DEFAULT;
+       dphy_timing->wakeup_constant = WAKEUP_CONSTANT_DEFAULT;
+       dphy_timing->wakeup_ui = WAKEUP_UI_DEFAULT;
+       dphy_timing->lpx_constant = LPX_CONSTANT_DEFAULT;
+       dphy_timing->lpx_ui = LPX_UI_DEFAULT;
+}
+
+static void dsi_reset(void)
+{
+       uint32_t reg;
+
+       reg = CFG_SOFT_RST | CFG_SOFT_RST_REG | CFG_CLR_PHY_FIFO | CFG_RST_TXLP |
+               CFG_RST_CPU | CFG_RST_CPN | CFG_RST_VPN | CFG_DSI_PHY_RST;
+
+       /* software reset DSI module */
+       dsi_write(DSI_CTRL_0, reg);
+       /* Note: there need some delay after set CFG_SOFT_RST */
+       udelay(100);
+       dsi_write(DSI_CTRL_0, 0);
+}
+
+static void dsi_enable_video_mode(bool enable)
+{
+       if(enable)
+               dsi_set_bits(DSI_CTRL_0, CFG_VPN_TX_EN | CFG_VPN_SLV | CFG_VPN_EN);
+       else
+               dsi_clear_bits(DSI_CTRL_0, CFG_VPN_TX_EN | CFG_VPN_EN);
+}
+
+static void dsi_enable_cmd_mode(bool enable)
+{
+       if(enable)
+               dsi_set_bits(DSI_CTRL_0, CFG_CPN_EN);
+       else
+               dsi_clear_bits(DSI_CTRL_0, CFG_CPN_EN);
+}
+
+static void dsi_enable_eotp(bool enable)
+{
+       if(enable)
+               dsi_set_bits(DSI_CTRL_1, CFG_EOTP_EN);
+       else
+               dsi_clear_bits(DSI_CTRL_1, CFG_EOTP_EN);
+}
+
+static void dsi_enable_lptx_lanes(uint32_t lane_num)
+{
+       dsi_write_bits(DSI_CPU_CMD_1,
+               CFG_TXLP_LPDT_MASK, lane_num << CFG_TXLP_LPDT_SHIFT);
+}
+
+static void dsi_enable_split_mode(bool splite_mode)
+{
+       if(splite_mode){
+               dsi_set_bits(DSI_LCD_BDG_CTRL0, CFG_SPLIT_EN);
+       } else {
+               dsi_clear_bits(DSI_LCD_BDG_CTRL0, CFG_SPLIT_EN);
+       }
+}
+
+static int dsi_write_cmd(uint8_t *parameter, uint8_t count, bool lp)
+{
+       uint32_t send_data = 0, reg, timeout, tmp, i;
+       bool turnaround;
+       uint32_t len;
+
+       /* write all packet bytes to packet data buffer */
+       for (i = 0; i < count; i++) {
+               send_data |= parameter[i] << ((i % 4) * 8);
+               if (0 ==((i + 1) % 4)) {
+                       dsi_write(DSI_CPU_WDAT, send_data);
+                       reg = CFG_CPU_DAT_REQ | CFG_CPU_DAT_RW |((i - 3) << CFG_CPU_DAT_ADDR_SHIFT);
+                       dsi_write(DSI_CPU_CMD_3, reg);
+                       /* wait write operation done */
+                       timeout = 1000;
+                       do {
+                               timeout--;
+                               tmp = dsi_read(DSI_CPU_CMD_3);
+                       } while ((tmp & CFG_CPU_DAT_REQ) && timeout);
+                       if (timeout == 0)
+                               pr_info("DSI write data to the packet data buffer not done.\n");
+                       send_data = 0;
+               }
+       }
+
+       /* handle last none 4Byte align data */
+       if (0 != i % 4) {
+               dsi_write(DSI_CPU_WDAT, send_data);
+               reg = CFG_CPU_DAT_REQ | CFG_CPU_DAT_RW |((4 * (i / 4)) << CFG_CPU_DAT_ADDR_SHIFT);
+               dsi_write(DSI_CPU_CMD_3, reg);
+               /* wait write operation done */
+               timeout = 1000;
+               do {
+                       timeout--;
+                       tmp = dsi_read(DSI_CPU_CMD_3);
+               } while ((tmp & CFG_CPU_DAT_REQ) && timeout);
+               if (timeout == 0)
+                       pr_info("DSI write data to the packet data buffer not done.\n");
+               send_data = 0;
+       }
+
+       if (parameter[0] == SPACEMIT_DSI_DCS_READ ||
+               parameter[0] == SPACEMIT_DSI_GENERIC_READ1)
+               turnaround = true;
+       else
+               turnaround = false;
+
+       len = count;
+#if 0
+       /* The packet length should contain  CRC_bytes_length in Aquilac_DSI version */
+       if ((parameter[0] == SPACEMIT_DSI_DCS_LWRITE ||
+               parameter[0] == SPACEMIT_DSI_GENERIC_LWRITE) && !lp)
+               len = count - 6;
+#endif
+       reg = CFG_CPU_CMD_REQ |
+               ((count == 4) ? CFG_CPU_SP : 0) |
+               (turnaround ? CFG_CPU_TURN : 0) |
+               (lp ? CFG_CPU_TXLP : 0) |
+               (len << CFG_CPU_WC_SHIFT);
+
+       /* send out the packet */
+       dsi_write(DSI_CPU_CMD_0, reg);
+       /* wait packet be sent out */
+       timeout = 1000;
+       do {
+               timeout--;
+               tmp = dsi_read(DSI_CPU_CMD_0);
+               udelay(20);
+       } while ((tmp & CFG_CPU_CMD_REQ) && timeout);
+       if (0 == timeout) {
+               pr_info("%s: DSI send out packet maybe failed.\n", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void dsi_config_video_mode(struct spacemit_dsi_device *dsi_ctx, struct spacemit_mipi_info *mipi_info)
+{
+       uint32_t hsync_b, hbp_b, hact_b, hex_b, hfp_b, httl_b;
+       uint32_t hsync, hbp, hact, httl, v_total;
+       uint32_t hsa_wc, hbp_wc, hact_wc, hex_wc, hfp_wc, hlp_wc;
+       uint32_t bpp, hss_bcnt = 4, hse_bct = 4, lgp_over_head = 6, reg;
+       uint32_t slot_cnt0, slot_cnt1;
+       uint32_t dsi_ex_pixel_cnt = 0;
+       uint32_t dsi_hex_en = 0;
+       uint32_t width, lane_number;
+       struct spacemit_dsi_advanced_setting *adv_setting = &dsi_ctx->adv_setting;
+
+       switch(mipi_info->rgb_mode){
+       case DSI_INPUT_DATA_RGB_MODE_565:
+               bpp = 16;
+               break;
+       case DSI_INPUT_DATA_RGB_MODE_666PACKET:
+               bpp = 18;
+               break;
+       case DSI_INPUT_DATA_RGB_MODE_666UNPACKET:
+               bpp = 18;
+               break;
+       case DSI_INPUT_DATA_RGB_MODE_888:
+               bpp = 24;
+               break;
+       default:
+               bpp = 24;
+       }
+
+       v_total = mipi_info->height + mipi_info->vfp + mipi_info->vbp + mipi_info->vsync;
+
+       if(mipi_info->split_enable) {
+               if(( 0 != (mipi_info->width & 0x1)) || (0 != (mipi_info->lane_number & 0x1))){
+                       pr_info("%s: warning:Invalid split config(lane = %d, width = %d)\n",
+                               __func__, mipi_info->lane_number, mipi_info->width);
+               }
+               width = mipi_info->width >> 1;
+               lane_number = mipi_info->lane_number >> 1;
+       } else {
+               width = mipi_info->width;
+               lane_number = mipi_info->lane_number;
+       }
+
+       hact_b = to_dsi_bcnt(width, bpp);
+       hfp_b = to_dsi_bcnt(mipi_info->hfp, bpp);
+       hbp_b = to_dsi_bcnt(mipi_info->hbp, bpp);
+       hsync_b = to_dsi_bcnt(mipi_info->hsync, bpp);
+       hex_b = to_dsi_bcnt(dsi_ex_pixel_cnt, bpp);
+       httl_b = hact_b + hsync_b + hfp_b + hbp_b + hex_b;
+       slot_cnt0 = (httl_b - hact_b) / lane_number + 3;
+       slot_cnt1 = slot_cnt0;
+
+       hact = hact_b / lane_number;
+       hbp = hbp_b / lane_number;
+       hsync = hsync_b / lane_number;
+       httl = (hact_b + hfp_b + hbp_b + hsync_b) / lane_number;
+
+       /* word count in the unit of byte */
+       hsa_wc = (mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE) ?
+               (hsync_b - hss_bcnt - lgp_over_head) : 0;
+
+       /* Hse is with backporch */
+       hbp_wc = (mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE) ?
+               (hbp_b - hse_bct - lgp_over_head)
+               : (hsync_b + hbp_b - hss_bcnt - lgp_over_head);
+
+       hfp_wc = ((mipi_info->burst_mode == DSI_BURST_MODE_BURST) && (dsi_hex_en == 0)) ?
+               (hfp_b + hex_b - lgp_over_head - lgp_over_head) :
+               (hfp_b - lgp_over_head - lgp_over_head);
+
+       hact_wc =  (width * bpp) >> 3;
+
+       /* disable Hex currently */
+       hex_wc = 0;
+
+       /*  There is no hlp with active data segment.  */
+       hlp_wc = (mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE) ?
+               (httl_b - hsync_b - hse_bct - lgp_over_head) :
+               (httl_b - hss_bcnt - lgp_over_head);
+
+       /* FIXME - need to double check the (*3) is bytes_per_pixel
+       * from input data or output to panel
+       */
+
+       /*Jessica: need be calculated by really case*/
+       dsi_write(DSI_VPN_CTRL_0, (0x50<<16) | 0xc08);
+
+       /* SET UP LCD1 TIMING REGISTERS FOR DSI BUS */
+       dsi_write(DSI_VPN_TIMING_0, (hact << 16) | httl);
+       dsi_write(DSI_VPN_TIMING_1, (hsync << 16) | hbp);
+       dsi_write(DSI_VPN_TIMING_2, ((mipi_info->height)<<16) | (v_total));
+       dsi_write(DSI_VPN_TIMING_3, ((mipi_info->vsync) << 16) | (mipi_info->vbp));
+
+       /* SET UP LCD1 WORD COUNT REGISTERS FOR DSI BUS */
+       dsi_write(DSI_VPN_WC_0, (hbp_wc << 16) | hsa_wc);
+       dsi_write(DSI_VPN_WC_1, (hfp_wc << 16) | hact_wc);
+       dsi_write(DSI_VPN_WC_2, (hex_wc << 16) | hlp_wc);
+
+       dsi_write(DSI_VPN_SLOT_CNT_0, (slot_cnt0 << 16) | slot_cnt0);
+       dsi_write(DSI_VPN_SLOT_CNT_1, (slot_cnt1 << 16) | slot_cnt1);
+
+       /* Configure LCD control register 1 FOR DSI BUS */
+       reg = adv_setting->vsync_rst_en << CFG_VPN_VSYNC_RST_EN_SHIFT |
+                       adv_setting->auto_wc_dis << CFG_VPN_AUTO_WC_DIS_SHIFT |
+                       adv_setting->hact_wc_en << CFG_VPN_HACT_WC_EN_SHIFT |
+                       adv_setting->timing_check_dis << CFG_VPN_TIMING_CHECK_DIS_SHIFT |
+                       adv_setting->auto_dly_dis << CFG_VPN_AUTO_DLY_DIS_SHIFT |
+                       adv_setting->hlp_pkt_en << CFG_VPN_HLP_PKT_EN_SHIFT |
+                       adv_setting->hex_pkt_en << CFG_VPN_HEX_PKT_EN_SHIFT |
+                       adv_setting->hfp_pkt_en << CFG_VPN_HFP_PKT_EN_SHIFT |
+                       adv_setting->hbp_pkt_en << CFG_VPN_HBP_PKT_EN_SHIFT |
+                       adv_setting->hse_pkt_en << CFG_VPN_HSE_PKT_EN_SHIFT |
+                       adv_setting->hsa_pkt_en << CFG_VPN_HSA_PKT_EN_SHIFT |
+                       adv_setting->hex_slot_en<< CFG_VPN_HEX_SLOT_EN_SHIFT |
+                       adv_setting->last_line_turn << CFG_VPN_LAST_LINE_TURN_SHIFT |
+                       adv_setting->lpm_frame_en << CFG_VPN_LPM_FRAME_EN_SHIFT |
+                       mipi_info->burst_mode << CFG_VPN_BURST_MODE_SHIFT |
+                       mipi_info->rgb_mode << CFG_VPN_RGB_TYPE_SHIFT;
+       dsi_write(DSI_VPN_CTRL_1,reg);
+
+       dsi_write_bits(DSI_LCD_BDG_CTRL0, CFG_VPN_FIFO_AFULL_CNT_MASK,
+               0 << CFG_VPN_FIFO_AFULL_CNT_SHIT);
+       dsi_set_bits(DSI_LCD_BDG_CTRL0, CFG_VPN_FIFO_AFULL_BYPASS);
+       dsi_set_bits(DSI_LCD_BDG_CTRL0, CFG_PIXEL_SWAP);
+
+       dsi_enable_cmd_mode(false);
+       dsi_enable_video_mode(true);
+}
+
+static void dsi_config_cmd_mode(struct spacemit_dsi_device *dsi_ctx, struct spacemit_mipi_info *mipi_info)
+{
+       int reg;
+       int rgb_mode, bpp;
+
+       switch(mipi_info -> rgb_mode){
+       case DSI_INPUT_DATA_RGB_MODE_565:
+               bpp = 16;
+               rgb_mode = 2;
+               break;
+       case DSI_INPUT_DATA_RGB_MODE_666UNPACKET:
+               bpp = 18;
+               rgb_mode = 1;
+               break;
+       case DSI_INPUT_DATA_RGB_MODE_888:
+               bpp = 24;
+               rgb_mode = 0;
+               break;
+       default:
+               pr_info("%s: unsupported rgb format!\n", __func__);
+               bpp = 24;
+               rgb_mode = 0;
+       }
+
+       reg = mipi_info->te_enable << CFG_CPN_TE_EN_SHIFT |
+                       rgb_mode << CFG_CPN_RGB_TYPE_SHIFT |
+                       1 << CFG_CPN_BURST_MODE_SHIFT |
+                       0 << CFG_CPN_DMA_DIS_SHIFT |
+                       0 << CFG_CPN_ADDR0_EN_SHIFT;
+       dsi_write(DSI_CPN_CMD, reg);
+
+       reg = mipi_info->width * bpp / 8 << CFG_CPN_PKT_CNT_SHIFT |
+               SPACEMIT_DSI_MAX_CMD_FIFO_BYTES << CFG_CPN_FIFO_FULL_LEVEL_SHIFT;
+       dsi_write(DSI_CPN_CTRL_1,reg);
+
+       dsi_write_bits(DSI_LCD_BDG_CTRL0, CFG_CPN_TE_EDGE_MASK,
+               mipi_info->te_pol << CFG_CPN_TE_EDGE_SHIFT);
+       dsi_write_bits(DSI_LCD_BDG_CTRL0, CFG_CPN_VSYNC_EDGE_MASK,
+               mipi_info->vsync_pol << CFG_CPN_VSYNC_EDGE_SHIFT);
+       dsi_write_bits(DSI_LCD_BDG_CTRL0, CFG_CPN_TE_MODE_MASK,
+               mipi_info->te_mode << CFG_CPN_TE_MODE_SHIFT);
+
+       reg = 0x80 << CFG_CPN_TE_DLY_CNT_SHIFT |
+                       0 << CFG_CPN_TE_LINE_CNT_SHIFT;
+       dsi_write(DSI_LCD_BDG_CTRL1, reg);
+
+       dsi_enable_video_mode(false);
+       dsi_enable_cmd_mode(true);
+}
+
+static int dsi_write_cmd_array(struct spacemit_dsi_device *dsi_ctx,
+                                                                       struct spacemit_dsi_cmd_desc *cmds,int count)
+{
+       struct spacemit_dsi_cmd_desc cmd_line;
+       uint8_t type, parameter[SPACEMIT_DSI_MAX_TX_FIFO_BYTES], len;
+       uint32_t crc, loop;
+       int ret = 0;
+
+       if(NULL == dsi_ctx) {
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       for (loop = 0; loop < count; loop++) {
+               cmd_line = cmds[loop];
+               type = cmd_line.cmd_type;
+               len = cmd_line.length;
+               memset(parameter, 0x00, len + 6);
+               parameter[0] = type & 0xff;
+               switch (type) {
+               case SPACEMIT_DSI_DCS_SWRITE:
+               case SPACEMIT_DSI_DCS_SWRITE1:
+               case SPACEMIT_DSI_DCS_READ:
+               case SPACEMIT_DSI_GENERIC_READ1:
+               case SPACEMIT_DSI_SET_MAX_PKT_SIZE:
+                       memcpy(&parameter[1], cmd_line.data, len);
+                       len = 4;
+                       break;
+               case SPACEMIT_DSI_GENERIC_LWRITE:
+               case SPACEMIT_DSI_DCS_LWRITE:
+                       parameter[1] = len & 0xff;
+                       parameter[2] = 0;
+                       memcpy(&parameter[4], cmd_line.data, len);
+                       crc = calculate_crc16(&parameter[4], len);
+                       parameter[len + 4] = crc & 0xff;
+                       parameter[len + 5] = (crc >> 8) & 0xff;
+                       len += 6;
+                       break;
+               default:
+                       pr_info("%s: data type not supported 0x%8x\n",__func__, type);
+                       break;
+               }
+
+               parameter[3] = calculate_ecc(parameter);
+
+               /* send dsi commands */
+               ret = dsi_write_cmd(parameter, len, cmd_line.lp);
+               if(ret)
+                       return -1;
+
+               if (0 != cmd_line.delay)
+                       mdelay(cmd_line.delay);
+       }
+       return 0;
+}
+
+static int dsi_read_cmd_array(struct spacemit_dsi_device *dsi_ctx, struct spacemit_dsi_rx_buf *dbuf,
+                                       struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+       uint8_t parameter[SPACEMIT_DSI_MAX_RX_FIFO_BYTES];
+       uint32_t i, rx_reg, timeout, tmp, packet,
+           data_pointer, byte_count;
+
+       if(NULL == dsi_ctx) {
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       memset(dbuf, 0x0, sizeof(struct spacemit_dsi_rx_buf));
+       dsi_write_cmd_array(dsi_ctx, cmds, count);
+
+       timeout = 1000;
+       do {
+               timeout--;
+               tmp = dsi_read(DSI_IRQ_ST);
+       } while (((tmp & IRQ_RX_PKT) == 0) && timeout);
+       if (0 == timeout) {
+               pr_info("%s: dsi didn't receive packet, irq status 0x%x\n", __func__, tmp);
+               return -1;
+       }
+
+       if (tmp & IRQ_RX_TRG3)
+               pr_info("%s: not defined package is received\n", __func__);
+       if (tmp & IRQ_RX_TRG2)
+               pr_info("%s: ACK package is received\n", __func__);
+       if (tmp & IRQ_RX_TRG1)
+               pr_info("%s: TE trigger is received\n", __func__);
+       if (tmp & IRQ_RX_ERR) {
+               tmp = dsi_read(DSI_RX_PKT_HDR_0);
+               pr_info("%s: error: ACK with error report (0x%x)\n", __func__, tmp);
+       }
+
+       packet = dsi_read(DSI_RX_PKT_ST_0);
+
+       data_pointer = (packet & CFG_RX_PKT0_PTR_MASK) >> CFG_RX_PKT0_PTR_SHIFT;
+       tmp = dsi_read(DSI_RX_PKT_CTRL_1);
+       byte_count = tmp & CFG_RX_PKT_BCNT_MASK;
+
+       memset(parameter, 0x00, byte_count);
+       for (i = data_pointer; i < data_pointer + byte_count; i++) {
+               rx_reg = dsi_read(DSI_RX_PKT_CTRL);
+               rx_reg &= ~CFG_RX_PKT_RD_PTR_MASK;
+               rx_reg |= CFG_RX_PKT_RD_REQ | (i << CFG_RX_PKT_RD_PTR_SHIFT);
+               dsi_write(DSI_RX_PKT_CTRL, rx_reg);
+               count = 10000;
+               do {
+                       count--;
+                       rx_reg = dsi_read(DSI_RX_PKT_CTRL);
+               } while (rx_reg & CFG_RX_PKT_RD_REQ && count);
+               if ( 0 == count)
+                       pr_info("%s: error: read Rx packet FIFO error\n", __func__);
+               parameter[i - data_pointer] = rx_reg & 0xff;
+       }
+       switch (parameter[0]) {
+       case SPACEMIT_DSI_ACK_ERR_RESP:
+               pr_info("%s: error: Acknowledge with error report\n", __func__);
+               break;
+       case SPACEMIT_DSI_EOTP:
+               pr_info("%s: error: End of Transmission packet\n", __func__);
+               break;
+       case SPACEMIT_DSI_GEN_READ1_RESP:
+       case SPACEMIT_DSI_DCS_READ1_RESP:
+               dbuf->data_type = parameter[0];
+               dbuf->length = 1;
+               memcpy(dbuf->data, &parameter[1], dbuf->length);
+               break;
+       case SPACEMIT_DSI_GEN_READ2_RESP:
+       case SPACEMIT_DSI_DCS_READ2_RESP:
+               dbuf->data_type = parameter[0];
+               dbuf->length = 2;
+               memcpy(dbuf->data, &parameter[1], dbuf->length);
+               break;
+       case SPACEMIT_DSI_GEN_LREAD_RESP:
+       case SPACEMIT_DSI_DCS_LREAD_RESP:
+               dbuf->data_type = parameter[0];
+               dbuf->length = (parameter[2] << 8) | parameter[1];
+               memcpy(dbuf->data, &parameter[4], dbuf->length);
+               break;
+       }
+       return 0;
+}
+
+static void dsi_open_dphy(struct spacemit_dsi_device* device_ctx,
+                                                               struct spacemit_mipi_info *mipi_info, bool ready)
+{
+       struct spacemit_dphy_ctx *dphy_config = NULL;
+
+       dsi_get_dphy_setting(device_ctx);
+       dphy_config = &device_ctx->dphy_config;
+       dphy_config->phy_freq = device_ctx->bit_clk_rate / 1000;
+       dphy_config->esc_clk = device_ctx->esc_clk_rate / 1000;
+       if(mipi_info->split_enable)
+               dphy_config->lane_num = mipi_info->lane_number >> 1;
+       else
+               dphy_config->lane_num = mipi_info->lane_number;
+       dphy_config->status = DPHY_STATUS_UNINIT;
+
+       if(ready){
+               dphy_config->status = DPHY_STATUS_INIT;
+               return;
+       }
+
+       spacemit_dphy_init(dphy_config);
+}
+
+static void dsi_close_dphy(struct spacemit_dsi_device* device_ctx)
+{
+       spacemit_dphy_uninit(&device_ctx->dphy_config);
+}
+
+int spacemit_dsi_open(struct spacemit_dsi_device* device_ctx, struct spacemit_mipi_info *mipi_info, bool ready)
+{
+       int lane_number;
+
+       if((NULL == device_ctx) || (NULL == mipi_info)){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       if(mipi_info->split_enable)
+               lane_number = mipi_info->lane_number >> 1;
+       else
+               lane_number = mipi_info->lane_number;
+
+       dsi_get_advanced_setting(device_ctx, mipi_info);
+
+       if(!ready)
+               dsi_reset();
+
+       dsi_open_dphy(device_ctx, mipi_info, ready);
+       if(!ready) {
+               dsi_enable_split_mode(mipi_info->split_enable);
+               dsi_enable_lptx_lanes(spacemit_dsi_lane[lane_number]);
+               dsi_enable_eotp(mipi_info->eotp_enable);
+       }
+
+       device_ctx->status = DSI_STATUS_OPENED;
+       return 0;
+}
+
+int spacemit_dsi_close(struct spacemit_dsi_device* device_ctx)
+{
+       if(NULL == device_ctx){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       dsi_close_dphy(device_ctx);
+
+       device_ctx->status = DSI_STATUS_UNINIT;
+       return 0;
+}
+
+int spacemit_dsi_ready_for_datatx(struct spacemit_dsi_device* device_ctx, struct spacemit_mipi_info *mipi_info)
+{
+       if((NULL == device_ctx) || (NULL == mipi_info)){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       if(mipi_info->work_mode == SPACEMIT_DSI_MODE_CMD){
+           dsi_config_cmd_mode(device_ctx, mipi_info);
+       } else {
+       dsi_config_video_mode(device_ctx, mipi_info);
+       }
+
+    return 0;
+}
+
+int spacemit_dsi_close_datatx(struct spacemit_dsi_device* device_ctx)
+{
+       if(NULL == device_ctx){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       dsi_enable_cmd_mode(false);
+       dsi_enable_video_mode(false);
+
+    return 0;
+}
+
+int spacemit_dsi_write_cmds(struct spacemit_dsi_device* device_ctx,
+                                                                       struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+       if((NULL == device_ctx) || (NULL == cmds)){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       return dsi_write_cmd_array(device_ctx, cmds, count);
+}
+
+int spacemit_dsi_read_cmds(struct spacemit_dsi_device* device_ctx, struct spacemit_dsi_rx_buf *dbuf,
+                                                               struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+       if((NULL == device_ctx) || (NULL == cmds)){
+               pr_info("%s: Invalid param\n", __func__);
+               return -1;
+       }
+
+       return dsi_read_cmd_array(device_ctx, dbuf, cmds, count);
+}
+
+struct spacemit_dsi_driver_ctx dsi_driver_ctx = {
+       .dsi_open = spacemit_dsi_open,
+       .dsi_close = spacemit_dsi_close,
+       .dsi_write_cmds = spacemit_dsi_write_cmds,
+       .dsi_read_cmds = spacemit_dsi_read_cmds,
+       .dsi_ready_for_datatx = spacemit_dsi_ready_for_datatx,
+       .dsi_close_datatx = spacemit_dsi_close_datatx,
+};
+
+struct spacemit_dsi_device spacemit_dsi_dev = {0};
+
+int spacemit_dsi_probe(void)
+{
+       int ret;
+
+       spacemit_dsi_dev.driver_ctx = &dsi_driver_ctx;
+       spacemit_dsi_dev.status = DSI_STATUS_UNINIT;
+       spacemit_dsi_dev.id = 0;
+
+       spacemit_dsi_dev.esc_clk_rate = SPACEMIT_ESC_CLK_DEFAULT;
+
+       ret = spacemit_dsi_register_device(&spacemit_dsi_dev);
+       if(ret != 0){
+               pr_info("%s: register dsi (%d) device fail!\n", __func__, spacemit_dsi_dev.id);
+               return -1;
+       }
+
+       spacemit_dsi_dev.status = DSI_STATUS_INIT;
+
+       return 0;
+}
diff --git a/drivers/video/spacemit/dsi/drv/spacemit_dsi_drv.h b/drivers/video/spacemit/dsi/drv/spacemit_dsi_drv.h
new file mode 100644 (file)
index 0000000..acac92f
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DSI_H_
+#define _SPACEMIT_DSI_H_
+
+#include <string.h>
+#include "../include/spacemit_dsi_common.h"
+#include "spacemit_dphy.h"
+
+enum spacemit_dsi_event_id {
+       SPACEMIT_DSI_EVENT_ERROR,
+       SPACEMIT_DSI_EVENT_MAX,
+};
+
+enum spacemit_dsi_status {
+       DSI_STATUS_UNINIT = 0,
+       DSI_STATUS_OPENED = 1,
+       DSI_STATUS_INIT = 2,
+       DSI_STATUS_MAX
+};
+
+struct spacemit_dsi_device;
+
+struct spacemit_dsi_driver_ctx {
+       int (*dsi_open)(struct spacemit_dsi_device* device_ctx, struct spacemit_mipi_info *mipi_info, bool ready);
+       int (*dsi_close)(struct spacemit_dsi_device* device_ctx);
+       int (*dsi_write_cmds)(struct spacemit_dsi_device* device_ctx, struct spacemit_dsi_cmd_desc *cmds, int count);
+       int (*dsi_read_cmds)(struct spacemit_dsi_device* device_ctx, struct spacemit_dsi_rx_buf *dbuf,
+                                                               struct spacemit_dsi_cmd_desc *cmds, int count);
+       int (*dsi_ready_for_datatx)(struct spacemit_dsi_device* device_ctx, struct spacemit_mipi_info *mipi_info);
+       int (*dsi_close_datatx)(struct spacemit_dsi_device* device_ctx);
+};
+
+struct spacemit_dsi_advanced_setting {
+       uint32_t lpm_frame_en; /*return to LP mode every frame*/
+       uint32_t last_line_turn;
+       uint32_t hex_slot_en;
+       uint32_t hsa_pkt_en;
+       uint32_t hse_pkt_en;
+       uint32_t hbp_pkt_en; /*bit:18*/
+       uint32_t hfp_pkt_en; /*bit:20*/
+       uint32_t hex_pkt_en;
+       uint32_t hlp_pkt_en; /*bit:22*/
+       uint32_t auto_dly_dis;
+       uint32_t timing_check_dis;
+       uint32_t hact_wc_en;
+       uint32_t auto_wc_dis;
+       uint32_t vsync_rst_en;
+};
+
+struct spacemit_dsi_device {
+       uint32_t id; /*dsi id*/
+
+       unsigned long esc_clk_rate, bit_clk_rate;
+
+       struct spacemit_dsi_driver_ctx *driver_ctx;
+
+       struct spacemit_dphy_ctx dphy_config;
+       struct spacemit_dsi_advanced_setting adv_setting;
+       int status;
+};
+
+#endif /*_SPACEMIT_DSI_H_*/
diff --git a/drivers/video/spacemit/dsi/drv/spacemit_dsi_hw.h b/drivers/video/spacemit/dsi/drv/spacemit_dsi_hw.h
new file mode 100644 (file)
index 0000000..a56edd2
--- /dev/null
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DSI_HW_H_
+#define _SPACEMIT_DSI_HW_H_
+
+#include <linux/io.h>
+#include <stdio.h>
+
+#define DSI_REG_BASE   0xd421a800
+
+#define DSI_CTRL_0 0x0
+#define DSI_CTRL_1 0x4
+#define DSI_IRQ_ST1  0x8
+#define DSI_IRQ_MASK1 0xC
+#define DSI_IRQ_ST 0x10
+#define DSI_IRQ_MASK 0x14
+
+#ifdef CONFIG_SPACEMIT_FPGA
+#define DSI_FPGA_PHY_CTRL_0 0x18
+#define DSI_FPGA_PHY_CTRL_1 0x1C
+#endif
+
+#define DSI_CPU_CMD_0 0x20
+#define DSI_CPU_CMD_1 0x24
+#define DSI_CPU_CMD_3 0x2C
+#define DSI_CPU_WDAT 0x30
+#define DSI_CPU_STATUS_0 0x34
+#define DSI_CPU_STATUS_1 0x38
+#define DSI_CPU_STATUS_2 0x3C
+#define DSI_CPU_STATUS_3 0x40
+#define DSI_CPU_STATUS_4 0x44
+
+#define DSI_CPN_STATUS_1 0x4C
+#define DSI_CPN_CMD 0x50
+#define DSI_CPN_CTRL_0 0x54
+#define DSI_CPN_CTRL_1 0x58
+#define DSI_CPN_STATUS_0 0x5C
+
+#define DSI_RX_PKT_ST_0 0x60
+#define DSI_RX_PKT_HDR_0 0x64
+#define DSI_RX_PKT_ST_1 0x68
+#define DSI_RX_PKT_HDR_1 0x6C
+#define DSI_RX_PKT_CTRL 0x70
+#define DSI_RX_PKT_CTRL_1 0x74
+#define DSI_RX_PKT_ST_2 0x78
+#define DSI_RX_PKT_HDR_2 0x7C
+
+#define DSI_LCD_BDG_CTRL0 0x84
+#define DSI_LCD_BDG_CTRL1 0x88
+
+#define DSI_TX_TIMER 0xE4
+#define DSI_RX_TIMER 0xE8
+#define DSI_TURN_TIMER 0xEC
+
+#define DSI_VPN_CTRL_0 0x100
+#define DSI_VPN_CTRL_1 0x104
+#define DSI_VPN_TIMING_0 0x110
+#define DSI_VPN_TIMING_1 0x114
+#define DSI_VPN_TIMING_2 0x118
+#define DSI_VPN_TIMING_3 0x11C
+#define DSI_VPN_WC_0 0x120
+#define DSI_VPN_WC_1 0x124
+#define DSI_VPN_WC_2 0x128
+#define DSI_VPN_SLOT_CNT_0 0x130
+#define DSI_VPN_SLOT_CNT_1 0x134
+#define DSI_VPN_SYNC_CODE 0x138
+#define DSI_VPN_STATUS_0 0x140
+#define DSI_VPN_STATUS_1 0x144
+#define DSI_VPN_STATUS_2 0x148
+#define DSI_VPN_STATUS_3 0x14C
+#define DSI_VPN_STATUS_4 0x150
+
+#define DSI_PHY_CTRL_0 0x180
+#define DSI_PHY_CTRL_1 0x184
+#define DSI_PHY_CTRL_2 0x188
+#define DSI_PHY_CTRL_3 0x18C
+#define DSI_PHY_STATUS_0 0x190
+#define DSI_PHY_STATUS_1 0x194
+#define DSI_PHY_LPRX_0 0x198
+#define DSI_PHY_LPRX_1 0x19C
+#define DSI_PHY_LPTX_0 0x1A0
+#define DSI_PHY_LPTX_1 0x1A4
+#define DSI_PHY_LPTX_2 0x1A8
+#define DSI_PHY_STATUS_2 0x1AC
+#define DSI_PHY_TIME_0 0x1C0
+#define DSI_PHY_TIME_1 0x1C4
+#define DSI_PHY_TIME_2 0x1C8
+#define DSI_PHY_TIME_3 0x1CC
+#define DSI_PHY_CODE_0 0x1D0
+#define DSI_PHY_CODE_1 0x1D4
+#define DSI_PHY_ANA_PWR_CTRL 0x1E0
+#define DSI_PHY_ANA_CTRL0 0x1E4
+#define DSI_PHY_ANA_CTRL1 0x1E8
+
+//DSI_CTRL_0 0x0
+#define CFG_SOFT_RST (1<<31)
+#define CFG_SOFT_RST_REG (1<<30)
+#define CFG_CLR_PHY_FIFO (1<<29)
+#define CFG_RST_TXLP (1<<28)
+#define CFG_RST_CPU (1<<27)
+#define CFG_RST_CPN (1<<26)
+#define CFG_RST_VPN (1<<24)
+#define CFG_DSI_PHY_RST (1<<23)
+#define CFG_VPN_TX_EN (1<<8)
+#define CFG_VPN_SLV (1<<4)
+#define CFG_CPN_EN (1<<2)
+#define CFG_VPN_EN (1<<0)
+
+//DSI_CTRL_1 0x4
+#define CFG_EOTP_EN (1<<8)
+
+//DSI_IRQ_ST 0x10
+#define IRQ_RX_ERR (1<<25)
+#define IRQ_RX_TRG3 (1<<7)
+#define IRQ_RX_TRG2 (1<<6)
+#define IRQ_RX_TRG1 (1<<5)
+#define IRQ_RX_TRG0 (1<<4)
+#define IRQ_RX_PKT (1<<2)
+
+#ifdef CONFIG_SPACEMIT_FPGA
+//DSI_FPGA_PHY_CTRL_0 0x18
+#define CFG_DPHY_RSETZ 0
+#define CFG_DPHY_SHUTDOWN 1
+#define CFG_DPHY_RSTZCAL 2
+#define CFG_DPHY_TXRXZ 3
+#define CFG_DPHY_MASSLVZ 4
+#define CFG_DPHY_ENABLE0 5
+#define CFG_DPHY_ENABLE1 6
+#define CFG_DPHY_ENABLECLK 7
+#define CFG_DPHY_HSREQ_LANECLK 8
+#define CFG_DPHY_HSREQ_LANE0 9
+#define CFG_DPHY_HSREQ_LANE1 10
+#define CFG_DPHY_HSREQ_LANE2 11
+#define CFG_DPHY_HSREQ_LANE3 12
+#define CFG_DPHY_TXRX_BYTECLK_REV 13
+#define CFG_DPHY_FCLK_REV 14
+
+//DSI_FPGA_PHY_CTRL_1 0x1C
+#define CFG_DPHY_TESTCLK 0
+#define CFG_DPHY_TESTCLR 1
+#define CFG_DPHY_TESTEN 2
+#define CFG_DPHY_TXRXZ 3
+#define CFG_DPHY_TESTDIN 8
+#define CFG_DPHY_TESTDOUT 16
+#define CFG_DPHY_LOCK 24
+#endif
+
+//DSI_CPU_CMD_0 0x20
+#define CFG_CPU_CMD_REQ (1<<31)
+#define CFG_CPU_SP (1<<30)
+#define CFG_CPU_TURN (1<<29)
+#define CFG_CPU_TXLP (1<<27)
+#define CFG_CPU_WC_SHIFT 0
+
+//DSI_CPU_CMD_1 0x24
+#define CFG_TXLP_LPDT_SHIFT 20
+
+#define CFG_TXLP_LPDT_MASK (0xF << CFG_TXLP_LPDT_SHIFT)
+
+//DSI_CPU_CMD_3 0x2C
+#define CFG_CPU_DAT_REQ (1<<31)
+#define CFG_CPU_DAT_RW (1<<30)
+#define CFG_CPU_DAT_ADDR_SHIFT 16
+
+//DSI_CPN_CMD 0x50
+#define CFG_CPN_TE_EN_SHIFT 28
+#define CFG_CPN_RGB_TYPE_SHIFT 24
+#define CFG_CPN_BURST_MODE_SHIFT 3
+#define CFG_CPN_FIRSTP_SEL_SHIFT 2
+#define CFG_CPN_DMA_DIS_SHIFT 1
+#define CFG_CPN_ADDR0_EN_SHIFT 0
+
+//DSI_CPN_CTRL_1 0X58
+#define CFG_CPN_PKT_CNT_SHIFT  16
+#define CFG_CPN_FIFO_FULL_LEVEL_SHIFT 0
+
+//DSI_RX_PKT_ST_0 0x60
+#define CFG_RX_PKT0_PTR_SHIFT 16
+#define CFG_RX_PKT0_PTR_MASK (0x3F << CFG_RX_PKT0_PTR_SHIFT)
+
+//DSI_RX_PKT_CTRL 0x70
+#define CFG_RX_PKT_RD_REQ (1<<31)
+#define CFG_RX_PKT_RD_PTR_SHIFT 16
+#define CFG_RX_PKT_RD_PTR_MASK (0x3F << CFG_RX_PKT_RD_PTR_SHIFT)
+#define CFG_RX_PKT_RD_DATA_SHIFT 0
+#define CFG_RX_PKT_RD_DATA_MASK (0x3F << CFG_RX_PKT_RD_DATA_SHIFT)
+
+//DSI_RX_PKT_CTRL_1 0x74
+#define CFG_RX_PKT_BCNT_SHIFT 0
+#define CFG_RX_PKT_BCNT_MASK (0xff << CFG_RX_PKT_BCNT_SHIFT)
+
+//DSI_LCD_BDG_CTRL0 0x84
+#define CFG_VPN_FIFO_AFULL_CNT_SHIT 16
+#define CFG_VPN_FIFO_AFULL_CNT_MASK (0xfff << CFG_VPN_FIFO_AFULL_CNT_SHIT)
+#define CFG_VPN_FIFO_AFULL_BYPASS (1<<6)
+#define CFG_CPN_VSYNC_EDGE_SHIFT 5
+#define CFG_CPN_VSYNC_EDGE_MASK (1 << CFG_CPN_VSYNC_EDGE_SHIFT)
+#define CFG_CPN_TE_EDGE_SHIFT 4
+#define CFG_CPN_TE_EDGE_MASK (1 << CFG_CPN_TE_EDGE_SHIFT)
+#define CFG_CPN_TE_MODE_SHIFT 2
+#define CFG_CPN_TE_MODE_MASK (3 << CFG_CPN_TE_MODE_SHIFT)
+#define CFG_PIXEL_SWAP (1<<1)
+#define CFG_SPLIT_EN (1<<0)
+
+//DSI_LCD_BDG_CTRL1 0x88
+#define CFG_CPN_TE_DLY_CNT_SHIFT 16
+#define CFG_CPN_TE_LINE_CNT_SHIFT 0
+
+//DSI_VPN_CTRL_1 0x104
+#define CFG_VPN_VSYNC_RST_EN_SHIFT 31
+#define CFG_VPN_AUTO_WC_DIS_SHIFT 27
+#define CFG_VPN_HACT_WC_EN_SHIFT 26
+#define CFG_VPN_TIMING_CHECK_DIS_SHIFT 25
+#define CFG_VPN_AUTO_DLY_DIS_SHIFT 24
+#define CFG_VPN_HLP_PKT_EN_SHIFT 22
+#define CFG_VPN_HEX_PKT_EN_SHIFT 21
+#define CFG_VPN_HFP_PKT_EN_SHIFT 20
+#define CFG_VPN_HBP_PKT_EN_SHIFT 18
+#define CFG_VPN_HSE_PKT_EN_SHIFT 17
+#define CFG_VPN_HSA_PKT_EN_SHIFT 16
+#define CFG_VPN_HEX_SLOT_EN_SHIFT 14
+#define CFG_VPN_LAST_LINE_TURN_SHIFT 10
+#define CFG_VPN_LPM_FRAME_EN_SHIFT 9
+#define CFG_VPN_BURST_MODE_SHIFT 2
+#define CFG_VPN_BURST_MODE_MASK (0x3 << CFG_VPN_BURST_MODE_SHIFT)
+#define CFG_VPN_RGB_TYPE_SHIFT 0
+#define CFG_VPN_RGB_TYPE_MASK (0x3 << CFG_VPN_RGB_TYPE_SHIFT)
+
+//DSI_PHY_CTRL_1 0x184
+#define CFG_DPHY_ADD_VALID (1<<17)
+#define CFG_DPHY_VDD_VALID (1<<16)
+#define CFG_DPHY_ULPS_DATA (1<<2)
+#define CFG_DPHY_ULPS_CLK (1<<1)
+#define CFG_DPHY_CONT_CLK (1<<0)
+
+//DSI_PHY_CTRL_2 0x188
+#define CFG_DPHY_HSTX_RX (1<<14)
+#define CFG_DPHY_LANE_MAP_SHIFT 12
+#define CFG_DPHY_LANE_EN_SHIFT 4
+#define CFG_DPHY_FORCE_BTA (1<<0)
+
+#define CFG_DPHY_LANE_MAP_MASK (0x3 << CFG_DPHY_LANE_MAP_SHIFT)
+#define CFG_DPHY_LANE_EN_MASK (0xF << CFG_DPHY_LANE_EN_SHIFT)
+
+//DSI_PHY_TIME_0 0x1C0
+#define CFG_DPHY_TIME_HS_EXIT_SHIFT 24
+#define CFG_DPHY_TIME_HS_TRAIL_SHIFT 16
+#define CFG_DPHY_TIME_HS_ZERO_SHIFT 8
+#define CFG_DPHY_TIME_HS_PREP_SHIFT 0
+
+#define CFG_DPHY_TIME_HS_EXIT_MASK (0xFF << CFG_DPHY_TIME_HS_EXIT_SHIFT)
+#define CFG_DPHY_TIME_HS_TRAIL_MASK (0xFF << CFG_DPHY_TIME_HS_TRAIL_SHIFT)
+#define CFG_DPHY_TIME_HS_ZERO_MASK (0xFF << CFG_DPHY_TIME_HS_ZERO_SHIFT)
+#define CFG_DPHY_TIME_HS_PREP_MASK (0xFF << CFG_DPHY_TIME_HS_PREP_SHIFT)
+
+//DSI_PHY_TIME_1 0x1C4
+#define CFG_DPHY_TIME_TA_GET_SHIFT 24
+#define CFG_DPHY_TIME_TA_GO_SHIFT 16
+#define CFG_DPHY_TIME_WAKEUP_SHIFT 0
+
+#define CFG_DPHY_TIME_TA_GET_MASK (0xFF << CFG_DPHY_TIME_TA_GET_SHIFT)
+#define CFG_DPHY_TIME_TA_GO_MASK (0xFF << CFG_DPHY_TIME_TA_GO_SHIFT)
+#define CFG_DPHY_TIME_WAKEUP_MASK (0xFFFF << CFG_DPHY_TIME_WAKEUP_SHIFT)
+
+//DSI_PHY_TIME_2 0x1C8
+#define CFG_DPHY_TIME_CLK_EXIT_SHIFT 24
+#define CFG_DPHY_TIME_CLK_TRAIL_SHIFT 16
+#define CFG_DPHY_TIME_CLK_ZERO_SHIFT 8
+#define CFG_DPHY_TIME_CLK_LPX_SHIFT 0
+
+#define CFG_DPHY_TIME_CLK_EXIT_MASK (0xFF << CFG_DPHY_TIME_CLK_EXIT_SHIFT)
+#define CFG_DPHY_TIME_CLK_TRAIL_MASK (0xFF << CFG_DPHY_TIME_CLK_TRAIL_SHIFT)
+#define CFG_DPHY_TIME_CLK_ZERO_MASK (0xFF << CFG_DPHY_TIME_CLK_ZERO_SHIFT)
+#define CFG_DPHY_TIME_CLK_LPX_MASK (0xFF << CFG_DPHY_TIME_CLK_LPX_SHIFT)
+
+//DSI_PHY_TIME_3 0x1CC
+#define CFG_DPHY_TIME_LPX_SHIFT 8
+#define CFG_DPHY_TIME_REQRDY_SHIFT 0
+
+#define CFG_DPHY_TIME_LPX_MASK (0xFF << CFG_DPHY_TIME_LPX_SHIFT)
+#define CFG_DPHY_TIME_REQRDY_MASK (0xFF << CFG_DPHY_TIME_REQRDY_SHIFT)
+
+//DSI_PHY_ANA_PWR_CTRL 0x1E0
+#define CFG_DPHY_ANA_RESET (1<<8)
+#define CFG_DPHY_ANA_PU (1<<0)
+
+//DSI_PHY_ANA_CTRL1 0x1E8
+#ifdef CONFIG_SPACEMIT_FPGA
+#define CFG_CLK_SEL (1<<23)
+#else
+#define CFG_CLK_SEL (1<<21)
+#endif
+#define CFG_CLK_DIV2 (1<<11)
+
+static inline uint32_t dsi_read(uint32_t offset)
+{
+       pr_debug("read  [0x%x] = 0x%x\n", DSI_REG_BASE + offset, readl((void __iomem *)(DSI_REG_BASE + (unsigned long)offset)));
+       return readl((void __iomem *)(DSI_REG_BASE + (unsigned long)offset));
+}
+
+static inline void dsi_write(uint32_t offset, uint32_t data)
+{
+       pr_debug("write [0x%x] = 0x%x\n", DSI_REG_BASE + offset, data);
+       writel(data, (void __iomem *)(DSI_REG_BASE + (unsigned long)offset));
+}
+
+static inline void dsi_set_bits(uint32_t offset, uint32_t bits)
+{
+       dsi_write(offset, (dsi_read(offset) | bits));
+}
+
+static inline void dsi_clear_bits(uint32_t offset, uint32_t bits)
+{
+       dsi_write(offset, (dsi_read(offset) & ~bits));
+}
+
+static inline void dsi_write_bits(uint32_t offset, uint32_t mask, uint32_t value)
+{
+       uint32_t tmp = 0;
+
+       tmp = dsi_read(offset);
+       tmp &= ~mask;
+       tmp |= value;
+       dsi_write(offset, tmp);
+}
+#endif /*_SPACEMIT_DSI_HW_H_*/
diff --git a/drivers/video/spacemit/dsi/include/spacemit_dsi_common.h b/drivers/video/spacemit/dsi/include/spacemit_dsi_common.h
new file mode 100644 (file)
index 0000000..1ec3a5d
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DSI_COMMON_H_
+#define _SPACEMIT_DSI_COMMON_H_
+
+#include <linux/types.h>
+#include <common.h>
+#include <stdio.h>
+
+#define MAX_TX_CMD_COUNT 100
+#define MAX_RX_DATA_COUNT 64
+
+enum spacemit_mipi_burst_mode{
+       DSI_BURST_MODE_NON_BURST_SYNC_PULSE = 0,
+       DSI_BURST_MODE_NON_BURST_SYNC_EVENT = 1,
+       DSI_BURST_MODE_BURST = 2,
+       DSI_BURST_MODE_MAX
+};
+
+enum spacemit_mipi_input_data_mode{
+       DSI_INPUT_DATA_RGB_MODE_565 = 0,
+       DSI_INPUT_DATA_RGB_MODE_666PACKET = 1,
+       DSI_INPUT_DATA_RGB_MODE_666UNPACKET = 2,
+       DSI_INPUT_DATA_RGB_MODE_888 = 3,
+       DSI_INPUT_DATA_RGB_MODE_MAX
+};
+
+enum spacemit_dsi_work_mode {
+       SPACEMIT_DSI_MODE_VIDEO,
+       SPACEMIT_DSI_MODE_CMD,
+       SPACEMIT_DSI_MODE_MAX
+};
+
+enum spacemit_dsi_cmd_type {
+       SPACEMIT_DSI_DCS_SWRITE = 0x5,
+       SPACEMIT_DSI_DCS_SWRITE1 = 0x15,
+       SPACEMIT_DSI_DCS_LWRITE = 0x39,
+       SPACEMIT_DSI_DCS_READ = 0x6,
+       SPACEMIT_DSI_GENERIC_LWRITE = 0x29,
+       SPACEMIT_DSI_GENERIC_READ1 = 0x14,
+       SPACEMIT_DSI_SET_MAX_PKT_SIZE = 0x37,
+};
+
+enum spacemit_dsi_tx_mode {
+       SPACEMIT_DSI_HS_MODE = 0,
+       SPACEMIT_DSI_LP_MODE = 1,
+};
+
+enum spacemit_dsi_rx_data_type {
+       SPACEMIT_DSI_ACK_ERR_RESP = 0x2,
+       SPACEMIT_DSI_EOTP = 0x8,
+       SPACEMIT_DSI_GEN_READ1_RESP = 0x11,
+       SPACEMIT_DSI_GEN_READ2_RESP = 0x12,
+       SPACEMIT_DSI_GEN_LREAD_RESP = 0x1A,
+       SPACEMIT_DSI_DCS_READ1_RESP = 0x21,
+       SPACEMIT_DSI_DCS_READ2_RESP = 0x22,
+       SPACEMIT_DSI_DCS_LREAD_RESP = 0x1C,
+};
+
+enum spacemit_dsi_polarity {
+       SPACEMIT_DSI_POLARITY_POS = 0,
+       SPACEMIT_DSI_POLARITY_NEG,
+       SPACEMIT_DSI_POLARITY_MAX
+};
+
+enum spacemit_dsi_te_mode {
+       SPACEMIT_DSI_TE_MODE_NO = 0,
+       SPACEMIT_DSI_TE_MODE_A,
+       SPACEMIT_DSI_TE_MODE_B,
+       SPACEMIT_DSI_TE_MODE_C,
+       SPACEMIT_DSI_TE_MODE_MAX,
+
+};
+
+struct spacemit_mipi_info {
+       unsigned int height;
+       unsigned int width;
+       unsigned int hfp; /*pixel*/
+       unsigned int hbp;
+       unsigned int hsync;
+       unsigned int vfp; /*line*/
+       unsigned int vbp;
+       unsigned int vsync;
+       unsigned int fps;
+
+       unsigned int work_mode; /*command_mode, video_mode*/
+       unsigned int rgb_mode;
+       unsigned int lane_number;
+       unsigned int phy_freq;
+       unsigned int split_enable;
+       unsigned int eotp_enable;
+
+       /*for video mode*/
+       unsigned int burst_mode;
+
+       /*for cmd mode*/
+       unsigned int te_enable;
+       unsigned int vsync_pol;
+       unsigned int te_pol;
+       unsigned int te_mode;
+
+       /*The following fields need not be set by panel*/
+       unsigned int real_fps;
+};
+
+struct spacemit_dsi_cmd_desc {
+       enum spacemit_dsi_cmd_type cmd_type;
+       uint8_t  lp;            /*command tx through low power mode or hs mode */
+       uint32_t delay; /* time to delay */
+       uint32_t length;        /* cmds length */
+       uint8_t data[MAX_TX_CMD_COUNT];
+};
+
+struct spacemit_dsi_rx_buf {
+       enum spacemit_dsi_rx_data_type data_type;
+       uint32_t length; /* cmds length */
+       uint8_t data[MAX_RX_DATA_COUNT];
+};
+
+/*API for mipi panel*/
+int spacemit_mipi_open(int id, struct spacemit_mipi_info *mipi_info, bool ready);
+int spacemit_mipi_close(int id);
+int spacemit_mipi_write_cmds(int id, struct spacemit_dsi_cmd_desc *cmds, int count);
+int spacemit_mipi_read_cmds(int id, struct spacemit_dsi_rx_buf *dbuf,
+                                                       struct spacemit_dsi_cmd_desc *cmds, int count);
+int spacemit_mipi_ready_for_datatx(int id, struct spacemit_mipi_info *mipi_info);
+int spacemit_mipi_close_datatx(int id);
+
+/*API for dsi driver*/
+int spacemit_dsi_register_device(void *device);
+
+int spacemit_dsi_probe(void);
+int lcd_mipi_probe(void);
+
+int lcd_icnl9911c_init(void);
+int lcd_gx09inx101_init(void);
+
+#endif /*_SPACEMIT_DSI_COMMON_H_*/
diff --git a/drivers/video/spacemit/dsi/include/spacemit_video_tx.h b/drivers/video/spacemit/dsi/include/spacemit_video_tx.h
new file mode 100644 (file)
index 0000000..05e6058
--- /dev/null
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_VIDEO_TX_H_
+#define _SPACEMIT_VIDEO_TX_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <stdio.h>
+#include <common.h>
+#include <asm-generic/gpio.h>
+
+
+#define INVALID_GPIO   0x0FFFFFFF
+#define LCD_DUMMY              0xFFFF
+#define DEFAULT_ID             0x1901
+
+enum {
+       DPMS_OFF = 0,
+       DPMS_ON = 1,
+};
+
+enum panel_type {
+       LCD_MIPI = 0,
+       LCD_HDMI = 1,
+       LCD_NULL
+};
+
+#define OUTFMT_RGB121212       0
+#define OUTFMT_RGB101010       1
+#define OUTFMT_RGB888          2
+#define OUTFMT_RGB666          12
+#define OUTFMT_RGB565          13
+
+enum pix_fmt {
+       PIXFMT_RGB565 = 0,
+       PIXFMT_RGB1555,
+       PIXFMT_RGB888PACK,
+       PIXFMT_RGB888UNPACK,
+       PIXFMT_RGBA888,
+       PIXFMT_YUV422_PACK,
+       PIXFMT_YUV422P,
+       PIXFMT_YUV420P,
+       PIXFMT_RGB888A = 0xB,
+       PIXFMT_YUV420SP = 0xC,
+
+       PIXFMT_PSEUDOCOLOR = 0x200,
+};
+
+enum vdma_fmt {
+       DMA_FMT_RGB = 0x0,
+       DMA_FMT_YUV422P = 0x4,
+       DMA_FMT_YUV420P = 0x6,  /*3 planes*/
+       DMA_FMT_YUV420SP = 0x7, /*2 planes*/
+};
+
+struct spacemit_mode_modeinfo {
+       const char *name;
+       unsigned int refresh;
+       unsigned int xres;
+       unsigned int yres;
+       unsigned int real_xres;
+       unsigned int real_yres;
+       unsigned int left_margin;
+       unsigned int right_margin;
+       unsigned int upper_margin;
+       unsigned int lower_margin;
+       unsigned int hsync_len;
+       unsigned int vsync_len;
+       unsigned int hsync_invert;
+       unsigned int vsync_invert;
+       unsigned int invert_pixclock;
+       unsigned int pixclock_freq;
+       int pix_fmt_out;
+       uint32_t height; /* screen height in mm */
+       uint32_t width; /* screen width in mm */
+};
+
+struct lcd_mipi_panel_info {
+       char *lcd_name;
+       unsigned int lcd_id;
+       unsigned int panel_id0;
+       unsigned int panel_id1;
+       unsigned int panel_id2;
+       unsigned int power_value;
+       enum panel_type panel_type;
+       uint32_t width_mm;
+       uint32_t height_mm;
+       uint32_t dft_pwm_bl;
+       unsigned int set_power_cmds_num;
+       unsigned int read_power_cmds_num;
+       unsigned int set_id_cmds_num;
+       unsigned int set_backlight_value_cmds_num;
+       unsigned int set_backlight_pwm_freq_cmds_num;
+       unsigned int read_id_cmds_num;
+       unsigned int init_cmds_num;
+       unsigned int sleep_out_cmds_num;
+       unsigned int sleep_in_cmds_num;
+       struct drm_mode_modeinfo *drm_modeinfo;
+       struct spacemit_mode_modeinfo *spacemit_modeinfo;
+       struct spacemit_mipi_info *mipi_info;
+       struct spacemit_dsi_cmd_desc *set_power_cmds;
+       struct spacemit_dsi_cmd_desc *set_backlight_value_cmds;
+       struct spacemit_dsi_cmd_desc *set_backlight_pwm_freq_cmds;
+       struct spacemit_dsi_cmd_desc *read_power_cmds;
+       struct spacemit_dsi_cmd_desc *set_id_cmds;
+       struct spacemit_dsi_cmd_desc *read_id_cmds;
+       struct spacemit_dsi_cmd_desc *init_cmds;
+       struct spacemit_dsi_cmd_desc *sleep_out_cmds;
+       struct spacemit_dsi_cmd_desc *sleep_in_cmds;
+       void (*set_backlight_value)(int, int);
+       unsigned int bitclk_sel;
+       unsigned int bitclk_div;
+       unsigned int pxclk_sel;
+       unsigned int pxclk_div;
+};
+
+struct video_tx_device {
+       const struct video_tx_driver *driver;
+       enum panel_type panel_type;
+       void *private;
+};
+
+struct video_tx_driver {
+       /* client driver ops */
+       /* Retrieve a list of modes supported by the display */
+       int (*get_modes)(struct video_tx_device *, struct spacemit_mode_modeinfo *);
+       /* Set the DPMS status of the display */
+       int (*dpms)(struct video_tx_device *, int);
+       int (*identify)(struct video_tx_device *);
+       bool (*esd_check)(struct video_tx_device *);
+       int (*panel_reset)(struct video_tx_device *);
+       int (*bl_enable)(struct video_tx_device *, bool enable);
+};
+
+struct lcd_mipi_tx_data {
+       int dpms_status;
+       enum panel_type panel_type;
+       struct lcd_mipi_panel_info *panel_info;
+       struct spacemit_panel_priv *priv;
+};
+
+struct spacemit_panel_priv {
+       struct gpio_desc ldo_1v2_gpio;
+       unsigned int ldo_1v8;
+       unsigned int ldo_2v8;
+       unsigned int ldo_1v2;
+       unsigned int bl_pwm;
+
+       struct gpio_desc dcp;
+       struct gpio_desc dcn;
+       struct gpio_desc bl;
+       struct gpio_desc enable;
+       struct gpio_desc reset;
+
+};
+extern int lcd_id;
+extern int lcd_width;
+extern int lcd_height;
+extern char *lcd_name;
+
+/* Host functions */
+struct video_tx_device *find_video_tx(void);
+int video_tx_get_modes(struct video_tx_device *video_tx,
+                      struct spacemit_mode_modeinfo *modelist);
+int video_tx_dpms(struct video_tx_device *video_tx, int mode);
+void video_tx_esd_check(struct video_tx_device *video_tx);
+
+/* Client functions */
+int video_tx_register_device(struct video_tx_device *tx_device);
+void *video_tx_get_drvdata(struct video_tx_device *tx_device);
+
+int lcd_mipi_register_panel(struct lcd_mipi_panel_info *panel_info);
+
+#endif /* _SPACEMIT_VIDEO_TX_H_ */
diff --git a/drivers/video/spacemit/dsi/video/lcd/lcd_gx09inx101.c b/drivers/video/spacemit/dsi/video/lcd/lcd_gx09inx101.c
new file mode 100644 (file)
index 0000000..b73206e
--- /dev/null
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include "../../include/spacemit_dsi_common.h"
+#include "../../include/spacemit_video_tx.h"
+#include <linux/delay.h>
+
+#define UNLOCK_DELAY 0
+
+struct spacemit_mode_modeinfo gx09inx101_spacemit_modelist[] = {
+       {
+               .name = "1200x1920-60",
+               .refresh = 60,
+               .xres = 1200,
+               .yres = 1920,
+               .real_xres = 1200,
+               .real_yres = 1920,
+               .left_margin = 40,
+               .right_margin = 80,
+               .hsync_len = 10,
+               .upper_margin = 16,
+               .lower_margin = 20,
+               .vsync_len = 4,
+               .hsync_invert = 0,
+               .vsync_invert = 0,
+               .invert_pixclock = 0,
+               .pixclock_freq = 156*1000,
+               .pix_fmt_out = OUTFMT_RGB888,
+               .width = 142,
+               .height = 228,
+       },
+};
+
+struct spacemit_mipi_info gx09inx101_mipi_info = {
+       .height = 1920,
+       .width = 1200,
+       .hfp = 80,/* unit: pixel */
+       .hbp = 40,
+       .hsync = 10,
+       .vfp = 20, /*unit: line*/
+       .vbp = 16,
+       .vsync = 4,
+       .fps = 60,
+
+       .work_mode = SPACEMIT_DSI_MODE_VIDEO, /*command_mode, video_mode*/
+       .rgb_mode = DSI_INPUT_DATA_RGB_MODE_888,
+       .lane_number = 4,
+       .phy_freq = 624*1000,
+       .split_enable = 0,
+       .eotp_enable = 0,
+
+       .burst_mode = DSI_BURST_MODE_BURST,
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_set_id_cmds[] = {
+       {SPACEMIT_DSI_SET_MAX_PKT_SIZE, SPACEMIT_DSI_LP_MODE, UNLOCK_DELAY, 1, {0x01}},
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_read_id_cmds[] = {
+       {SPACEMIT_DSI_GENERIC_READ1, SPACEMIT_DSI_LP_MODE, UNLOCK_DELAY, 1, {0xfb}},
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_set_power_cmds[] = {
+       {SPACEMIT_DSI_SET_MAX_PKT_SIZE, SPACEMIT_DSI_HS_MODE, UNLOCK_DELAY, 1, {0x1}},
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_read_power_cmds[] = {
+       {SPACEMIT_DSI_GENERIC_READ1, SPACEMIT_DSI_HS_MODE, UNLOCK_DELAY, 1, {0xA}},
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_init_cmds[] = {
+       //8279 + INX10.1
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xB0,0x01}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC3,0x4F}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC4,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC5,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC6,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC7,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC8,0x4D}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC9,0x52}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCA,0x51}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCD,0x5D}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCE,0x5B}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCF,0x4B}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD0,0x49}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD1,0x47}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD2,0x45}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD3,0x41}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD7,0x50}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD8,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD9,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDA,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDB,0x40}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDC,0x4E}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDD,0x52}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDE,0x51}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE1,0x5E}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE2,0x5C}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE3,0x4C}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE4,0x4A}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE5,0x48}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE6,0x46}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE7,0x42}},
+       //Page0x03
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xB0,0x03}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xBE,0x03}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCC,0x44}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC8,0x07}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC9,0x05}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCA,0x42}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCD,0x3E}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCF,0x60}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD2,0x04}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD3,0x04}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD4,0x01}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD5,0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD6,0x03}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD7,0x04}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD9,0x01}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDB,0x01}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE4,0xF0}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE5,0x0A}},
+       //Page0x00
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xB0,0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xBD,0x50}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC2,0x08}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC4,0x10}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCC,0x00}},
+       //Page0x02
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xB0,0x02}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC0,0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC1,0x0A}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC2,0x20}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC3,0x24}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC4,0x23}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC5,0x29}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC6,0x23}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC7,0x1C}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC8,0x19}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC9,0x17}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCA,0x17}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCB,0x18}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCC,0x1A}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCD,0x1E}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCE,0x20}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xCF,0x23}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD0,0x07}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD1,0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD2,0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD3,0x0A}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD4,0x13}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD5,0x1C}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD6,0x1A}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD7,0x13}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD8,0x17}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xD9,0x1C}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDA,0x19}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDB,0x17}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDC,0x17}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDD,0x18}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDE,0x1A}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xDF,0x1E}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE0,0x20}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE1,0x23}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xE2,0x07}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 200, 2, {0x11, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE,  50, 2, {0x29, 0x00}},
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_sleep_out_cmds[] = {
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,200,1,{0x11}},
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,50,1,{0x29}},
+};
+
+static struct spacemit_dsi_cmd_desc gx09inx101_sleep_in_cmds[] = {
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,50,1,{0x28}},
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,200,1,{0x10}},
+};
+
+
+struct lcd_mipi_panel_info lcd_gx09inx101 = {
+       .lcd_name = "gx09inx101",
+       .lcd_id = 0x8279,
+       .panel_id0 = 0x1,
+       .power_value = 0x14,
+       .panel_type = LCD_MIPI,
+       .width_mm = 142,
+       .height_mm = 228,
+       .dft_pwm_bl = 128,
+       .set_id_cmds_num = ARRAY_SIZE(gx09inx101_set_id_cmds),
+       .read_id_cmds_num = ARRAY_SIZE(gx09inx101_read_id_cmds),
+       .init_cmds_num = ARRAY_SIZE(gx09inx101_init_cmds),
+       .set_power_cmds_num = ARRAY_SIZE(gx09inx101_set_power_cmds),
+       .read_power_cmds_num = ARRAY_SIZE(gx09inx101_read_power_cmds),
+       .sleep_out_cmds_num = ARRAY_SIZE(gx09inx101_sleep_out_cmds),
+       .sleep_in_cmds_num = ARRAY_SIZE(gx09inx101_sleep_in_cmds),
+       //.drm_modeinfo = gx09inx101_modelist,
+       .spacemit_modeinfo = gx09inx101_spacemit_modelist,
+       .mipi_info = &gx09inx101_mipi_info,
+       .set_id_cmds = gx09inx101_set_id_cmds,
+       .read_id_cmds = gx09inx101_read_id_cmds,
+       .set_power_cmds = gx09inx101_set_power_cmds,
+       .read_power_cmds = gx09inx101_read_power_cmds,
+       .init_cmds = gx09inx101_init_cmds,
+       .sleep_out_cmds = gx09inx101_sleep_out_cmds,
+       .sleep_in_cmds = gx09inx101_sleep_in_cmds,
+       .bitclk_sel = 3,
+       .bitclk_div = 1,
+       .pxclk_sel = 2,
+       .pxclk_div = 6,
+};
+
+int lcd_gx09inx101_init(void)
+{
+       int ret;
+
+       ret = lcd_mipi_register_panel(&lcd_gx09inx101);
+       return ret;
+}
diff --git a/drivers/video/spacemit/dsi/video/lcd/lcd_icnl9911c.c b/drivers/video/spacemit/dsi/video/lcd/lcd_icnl9911c.c
new file mode 100644 (file)
index 0000000..d6e0bc5
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include "../../include/spacemit_dsi_common.h"
+#include "../../include/spacemit_video_tx.h"
+#include <linux/delay.h>
+
+#define UNLOCK_DELAY 0
+
+struct spacemit_mode_modeinfo icnl9911c_spacemit_modelist[] = {
+       {
+               .name = "720x1600-60",
+               .refresh = 60,
+               .xres = 720,
+               .yres = 1600,
+               .real_xres = 720,
+               .real_yres = 1600,
+               .left_margin = 48,
+               .right_margin = 48,
+               .hsync_len = 4,
+               .upper_margin = 32,
+               .lower_margin = 150,
+               .vsync_len = 4,
+               .hsync_invert = 0,
+               .vsync_invert = 0,
+               .invert_pixclock = 0,
+               .pixclock_freq = 87*1000,
+               .pix_fmt_out = OUTFMT_RGB888,
+               .width = 72,
+               .height = 126,
+       },
+};
+
+struct spacemit_mipi_info icnl9911c_mipi_info = {
+       .height = 1600,
+       .width = 720,
+       .hfp = 48,/* unit: pixel */
+       .hbp = 48,
+       .hsync = 4,
+       .vfp = 150, /*unit: line*/
+       .vbp = 32,
+       .vsync = 4,
+       .fps = 60,
+
+       .work_mode = SPACEMIT_DSI_MODE_VIDEO, /*command_mode, video_mode*/
+       .rgb_mode = DSI_INPUT_DATA_RGB_MODE_888,
+       .lane_number = 4,
+       .phy_freq = 624*1000,
+       .split_enable = 0,
+       .eotp_enable = 0,
+
+       .burst_mode = DSI_BURST_MODE_BURST,
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_set_id_cmds[] = {
+       {SPACEMIT_DSI_SET_MAX_PKT_SIZE, SPACEMIT_DSI_LP_MODE, UNLOCK_DELAY, 1, {0x01}},
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_read_id_cmds[] = {
+       {SPACEMIT_DSI_GENERIC_READ1, SPACEMIT_DSI_LP_MODE, UNLOCK_DELAY, 1, {0x04}},
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_set_power_cmds[] = {
+       {SPACEMIT_DSI_SET_MAX_PKT_SIZE, SPACEMIT_DSI_HS_MODE, UNLOCK_DELAY, 1, {0x1}},
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_read_power_cmds[] = {
+       {SPACEMIT_DSI_GENERIC_READ1, SPACEMIT_DSI_HS_MODE, UNLOCK_DELAY, 1, {0xA}},
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_init_cmds[] = {
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   3, {0xF0, 0x5A, 0x59}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   3, {0xF1, 0xA5, 0xA6}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  33, {0xB0, 0x83, 0x82, 0x86, 0x87, 0x06, 0x07, 0x04, 0x05, 0x33, 0x33, 0x33, 0x33, 0x20, 0x00, 0x00, 0x77, 0x00, 0x00, 0x3F, 0x05, 0x04, 0x03, 0x02, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  30, {0xB1, 0x13, 0x91, 0x8E, 0x81, 0x20, 0x00, 0x00, 0x77, 0x00, 0x00, 0x04, 0x08, 0x54, 0x00, 0x00, 0x00, 0x44, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  18, {0xB2, 0x54, 0xC4, 0x82, 0x05, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x05, 0x05, 0x54, 0x0C, 0x0C, 0x0D, 0x0B}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  32, {0xB3, 0x12, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0x91, 0x91, 0x91, 0x91, 0x3C, 0x26, 0x00, 0x18, 0x01, 0x02, 0x08, 0x20, 0x30, 0x08, 0x09, 0x44, 0x20, 0x40, 0x20, 0x40, 0x08, 0x09, 0x22, 0x33}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  29, {0xB4, 0x03, 0x00, 0x00, 0x06, 0x1E, 0x1F, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  29, {0xB5, 0x03, 0x00, 0x00, 0x07, 0x1E, 0x1F, 0x0D, 0x0F, 0x11, 0x13, 0x15, 0x17, 0x05, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  25, {0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   3, {0xBA, 0x6B, 0x6B}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  14, {0xBB, 0x01, 0x05, 0x09, 0x11, 0x0D, 0x19, 0x1D, 0x55, 0x25, 0x69, 0x00, 0x21, 0x25}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  15, {0xBC, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xFF, 0x00, 0x03, 0x33, 0x01, 0x73, 0x33, 0x02}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  11, {0xBD, 0xE9, 0x02, 0x4F, 0xCF, 0x72, 0xA4, 0x08, 0x44, 0xAE, 0x15}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  13, {0xBE, 0x7D, 0x7D, 0x5A, 0x46, 0x0C, 0x77, 0x43, 0x07, 0x0E, 0x0E, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   9, {0xBF, 0x07, 0x25, 0x07, 0x25, 0x7F, 0x00, 0x11, 0x04}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  13, {0xC0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  20, {0xC1, 0xC0, 0x20, 0x20, 0x96, 0x04, 0x32, 0x32, 0x04, 0x2A, 0x40, 0x36, 0x00, 0x07, 0xCF, 0xFF, 0xFF, 0xC0, 0x00, 0xC0}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0xC2, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  16, {0xC2, 0xCC, 0x01, 0x10, 0x00, 0x01, 0x30, 0x02, 0x21, 0x43, 0x00, 0x01, 0x30, 0x02, 0x21, 0x43}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  13, {0xC3, 0x06, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  13, {0xC4, 0x84, 0x03, 0x2B, 0x41, 0x00, 0x3C, 0x00, 0x03, 0x03, 0x3E, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  12, {0xC5, 0x03, 0x1C, 0xC0, 0xC0, 0x40, 0x10, 0x42, 0x44, 0x0F, 0x0A, 0x14}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  11, {0xC6, 0x87, 0xA0, 0x2A, 0x29, 0x29, 0x00, 0x64, 0x37, 0x08, 0x04}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  23, {0xC7, 0xF7, 0xD3, 0xBA, 0xA5, 0x80, 0x63, 0x36, 0x8B, 0x56, 0x2A, 0xFF, 0xCE, 0x23, 0xF4, 0xD3, 0xA4, 0x86, 0x5A, 0x1A, 0x7F, 0xE4, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  23, {0xC8, 0xF7, 0xD3, 0xBA, 0xA5, 0x80, 0x63, 0x36, 0x8B, 0x56, 0x2A, 0xFF, 0xCE, 0x23, 0xF4, 0xD3, 0xA4, 0x86, 0x5A, 0x1A, 0x7F, 0xE4, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   9, {0xD0, 0x80, 0x0D, 0xFF, 0x0F, 0x61, 0x0B, 0x08, 0x0C}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,  15, {0xD2, 0x42, 0x0C, 0x30, 0x01, 0x80, 0x26, 0x04, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   3, {0xF1, 0x5A, 0x59}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   3, {0xF0, 0xA5, 0xA6}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 0,   2, {0x35, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE, 150, 2, {0x11, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE,  50, 2, {0x29, 0x00}},
+       {SPACEMIT_DSI_DCS_LWRITE, SPACEMIT_DSI_LP_MODE,   5, 2, {0x26, 0x00}},
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_sleep_out_cmds[] = {
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,150,1,{0x11}},
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,50,1,{0x29}},
+};
+
+static struct spacemit_dsi_cmd_desc icnl9911c_sleep_in_cmds[] = {
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,50,1,{0x28}},
+       {SPACEMIT_DSI_DCS_SWRITE,SPACEMIT_DSI_LP_MODE,150,1,{0x10}},
+};
+
+
+struct lcd_mipi_panel_info lcd_icnl9911c = {
+       .lcd_name = "icnl9911c",
+       .lcd_id = 0x7202,
+       .panel_id0 = 0x99,
+       .power_value = 0x9c,
+       .panel_type = LCD_MIPI,
+       .width_mm = 72,
+       .height_mm = 126,
+       .dft_pwm_bl = 128,
+       .set_id_cmds_num = ARRAY_SIZE(icnl9911c_set_id_cmds),
+       .read_id_cmds_num = ARRAY_SIZE(icnl9911c_read_id_cmds),
+       .init_cmds_num = ARRAY_SIZE(icnl9911c_init_cmds),
+       .set_power_cmds_num = ARRAY_SIZE(icnl9911c_set_power_cmds),
+       .read_power_cmds_num = ARRAY_SIZE(icnl9911c_read_power_cmds),
+       .sleep_out_cmds_num = ARRAY_SIZE(icnl9911c_sleep_out_cmds),
+       .sleep_in_cmds_num = ARRAY_SIZE(icnl9911c_sleep_in_cmds),
+       //.drm_modeinfo = icnl9911c_modelist,
+       .spacemit_modeinfo = icnl9911c_spacemit_modelist,
+       .mipi_info = &icnl9911c_mipi_info,
+       .set_id_cmds = icnl9911c_set_id_cmds,
+       .read_id_cmds = icnl9911c_read_id_cmds,
+       .set_power_cmds = icnl9911c_set_power_cmds,
+       .read_power_cmds = icnl9911c_read_power_cmds,
+       .init_cmds = icnl9911c_init_cmds,
+       .sleep_out_cmds = icnl9911c_sleep_out_cmds,
+       .sleep_in_cmds = icnl9911c_sleep_in_cmds,
+       .bitclk_sel = 3,
+       .bitclk_div = 1,
+       .pxclk_sel = 2,
+       .pxclk_div = 6,
+};
+
+int lcd_icnl9911c_init(void)
+{
+       int ret;
+
+       ret = lcd_mipi_register_panel(&lcd_icnl9911c);
+       return ret;
+}
diff --git a/drivers/video/spacemit/dsi/video/spacemit_mipi_port.c b/drivers/video/spacemit/dsi/video/spacemit_mipi_port.c
new file mode 100644 (file)
index 0000000..05e2d90
--- /dev/null
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include "../include/spacemit_dsi_common.h"
+#include "../include/spacemit_video_tx.h"
+#include <linux/delay.h>
+#include <command.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <video.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+
+#define PANEL_NUM_MAX  5
+
+int panel_num = 0;
+struct lcd_mipi_panel_info *panels[PANEL_NUM_MAX] = {0};
+int lcd_id = 0;
+int lcd_width = 0;
+int lcd_height = 0;
+char *lcd_name = NULL;
+
+//extern unsigned int board_id;
+
+
+static int set_bit_value(int value, int low_bit, int high_bit, int bits_val)
+{
+       int mask;
+
+       mask = (1 << (high_bit - low_bit + 1)) - 1;
+       mask = mask << low_bit;
+       value &= ~mask;
+       value |= (bits_val << low_bit);
+
+       return value;
+}
+
+static bool __maybe_unused lcd_mipi_readid(struct lcd_mipi_tx_data *video_tx_client)
+{
+       struct spacemit_dsi_rx_buf dbuf;
+       uint32_t read_id[3] = {0};
+       int i;
+       int ret = 0;
+
+       for(i=0;i<1;i++){
+               spacemit_mipi_write_cmds(0, video_tx_client->panel_info->set_id_cmds,
+                       video_tx_client->panel_info->set_id_cmds_num);
+
+               ret = spacemit_mipi_read_cmds(0, &dbuf, video_tx_client->panel_info->read_id_cmds,
+                                video_tx_client->panel_info->read_id_cmds_num);
+               if (ret)
+                       return false;
+               read_id[0] = dbuf.data[0];
+               read_id[1] = dbuf.data[1];
+               read_id[2] = dbuf.data[2];
+
+           if((read_id[0] != video_tx_client->panel_info->panel_id0)
+                       || (read_id[1] != video_tx_client->panel_info->panel_id1)
+                       || (read_id[2] != video_tx_client->panel_info->panel_id2)) {
+                       pr_info("read panel id: read value = 0x%x, 0x%x, 0x%x\n", read_id[0], read_id[1], read_id[2]);
+           } else {
+                       pr_info("read panel id OK: read value = 0x%x, 0x%x, 0x%x\n", read_id[0], read_id[1], read_id[2]);
+                       return true;
+           }
+       }
+       return false;
+}
+
+static int lcd_mipi_reset(struct spacemit_panel_priv *priv)
+{
+       /* reset lcm */
+       dm_gpio_set_value(&priv->reset, 1);
+       mdelay(10);
+       dm_gpio_set_value(&priv->reset, 0);
+       mdelay(10);
+       dm_gpio_set_value(&priv->reset, 1);
+       mdelay(120);
+
+       return 0;
+}
+
+static int lcd_mipi_dc_enable(bool power_on, struct spacemit_panel_priv *priv)
+{
+       if(power_on){
+               dm_gpio_set_value(&priv->dcp, 1);
+               dm_gpio_set_value(&priv->dcn, 1);
+       } else {
+               dm_gpio_set_value(&priv->dcp, 0);
+               dm_gpio_set_value(&priv->dcn, 0);
+       }
+
+       return 0;
+}
+
+static uint32_t lcd_mipi_readpower(struct lcd_mipi_tx_data *video_tx_client)
+{
+       struct spacemit_dsi_rx_buf dbuf;
+       uint32_t power = 0;
+
+       spacemit_mipi_write_cmds(0, video_tx_client->panel_info->set_power_cmds,
+               video_tx_client->panel_info->set_power_cmds_num);
+
+       spacemit_mipi_read_cmds(0, &dbuf, video_tx_client->panel_info->read_power_cmds,
+               video_tx_client->panel_info->read_power_cmds_num);
+
+       power = dbuf.data[0];
+
+       return power;
+}
+
+static bool lcd_mipi_esd_check(struct video_tx_device *dev)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+       int power = 0;
+       int i;
+
+       if (video_tx_client->panel_info->set_power_cmds_num == 0)
+               return true;
+
+       for(i = 0; i < 3; i++) {
+               power = lcd_mipi_readpower(video_tx_client);
+
+               if(power == video_tx_client->panel_info->power_value) {
+                       pr_debug("lcd esd check ok! 0x%x\n", power);
+                       return true;
+               } else {
+                       pr_info("lcd esd check fail, value (0x%x)\n", power);
+               }
+       }
+
+       return false;
+}
+
+static int lcd_mipi_panel_reset(struct video_tx_device *dev)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+       int ret = 0;
+
+
+       spacemit_mipi_close_datatx(0);
+
+       ret = lcd_mipi_reset(video_tx_client->priv);
+       if (ret) {
+               pr_info("lcd_mipi gpio reset failded!\n");
+               return -1;
+       }
+
+       ret = spacemit_mipi_write_cmds(0, video_tx_client->panel_info->init_cmds,
+                       video_tx_client->panel_info->init_cmds_num);
+       if(ret) {
+               pr_info("send init cmd fail!\n ");
+       }
+       ret = spacemit_mipi_write_cmds(0, video_tx_client->panel_info->sleep_out_cmds,
+                       video_tx_client->panel_info->sleep_out_cmds_num);
+       if(ret) {
+               pr_info("send sleep out fail!\n ");
+       }
+       ret = spacemit_mipi_ready_for_datatx(0, video_tx_client->panel_info->mipi_info);
+       if (0 != ret) {
+               pr_info("lcd_mipi spacemit_mipi_ready_for_datatx fail!\n ");
+               spacemit_mipi_close(0);
+       }
+
+       return 0;
+}
+
+void dpc_update_clocks(struct lcd_mipi_panel_info *panel_info)
+{
+       unsigned int value = 0;
+       unsigned int freq_sel = 0;
+       unsigned int freq_div = 0;
+       unsigned int timeout = 50;
+
+       /* bitclk */
+
+       freq_sel = panel_info->bitclk_sel;
+       freq_div = panel_info->bitclk_div;
+       value = readl((void *)(uintptr_t)0xd4282844);
+       value = set_bit_value(value, 20, 21, freq_sel);
+       value = set_bit_value(value, 17, 19, freq_div);
+       writel(value, (void *)(uintptr_t)0xd4282844);
+       value |= BIT(31);
+       writel(value, (void *)(uintptr_t)0xd4282844);
+
+       /* wait freq change successful */
+       while (true) {
+               value = readl((void *)(uintptr_t)0xd4282844);
+
+               if ((value & BIT(31)) == 0)
+                       break;
+
+               if (timeout == 0) {
+                       pr_info("failed to change dpu bitclk frequency\n");
+                       break;
+               }
+
+               timeout--;
+
+               udelay(10);
+       }
+
+       /* pxclk */
+       timeout = 50;
+       freq_sel = panel_info->pxclk_sel;
+       freq_div = panel_info->pxclk_div;
+       value = readl((void *)(uintptr_t)0xd428284c);
+       value = set_bit_value(value, 21, 23, freq_sel);
+       value = set_bit_value(value, 17, 20, freq_div);
+       writel(value, (void *)(uintptr_t)0xd428284c);
+
+       value = readl((void *)(uintptr_t)0xd4282844);
+       value |= BIT(30);
+       writel(value,(void *)(uintptr_t) 0xd4282844);
+
+       /* wait freq change successful */
+       while (true) {
+               value = readl((void *)(uintptr_t)0xd4282844);
+
+               if ((value & BIT(30)) == 0)
+                       break;
+
+               if (timeout == 0) {
+                       pr_info("failed to change dpu pxclk frequency\n");
+                       break;
+               }
+
+               timeout--;
+
+               udelay(10);
+       }
+
+       pr_debug("dpu clk1 = 0x%x\n", readl((void *)(uintptr_t)0xd4282844));
+       pr_debug("dpu clk2 = 0x%x\n", readl((void *)(uintptr_t)0xd428284c));
+}
+static int lcd_mipi_identify(struct video_tx_device *dev)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+       struct lcd_mipi_panel_info *panel_info = NULL;
+       bool is_panel = false;
+       int ret = 0;
+       int i, num;
+
+       ret = lcd_mipi_dc_enable(true, video_tx_client->priv);
+       if (ret) {
+               pr_info("lcd_mipi gpio dc failded!\n");
+       }
+
+       for(i=0; i<panel_num; i++) {
+               panel_info = panels[i];
+               if(!panel_info)
+                       continue;
+
+               dpc_update_clocks(panel_info);
+
+               pr_debug("now check lcd (%s)\n",panel_info->lcd_name);
+
+               video_tx_client->panel_info = panel_info;
+
+               for (num = 0; num < 1; num++) {
+                       ret = lcd_mipi_reset(video_tx_client->priv);
+                       if (ret) {
+                               pr_info("lcd_mipi gpio reset failded!\n");
+                               continue;
+                       }
+
+                       ret = spacemit_mipi_open(0, video_tx_client->panel_info->mipi_info, false);
+                       if(0 != ret) {
+                               pr_info("%s, lcd_mipi open mipi fai!\n", __func__);
+                               continue;
+                       }
+
+                       is_panel = lcd_mipi_readid(video_tx_client);
+
+                       spacemit_mipi_close(0);
+
+                       if (is_panel)
+                               break;
+               }
+
+               if (!is_panel) {
+                       //dev_info(video_tx_client->dev, "lcd_mipi read (%s) chip id failded!\n", video_tx_client->panel_info->lcd_name);
+                       video_tx_client->panel_info = NULL;
+                       continue;
+               }else{
+                       lcd_mipi_dc_enable(false, video_tx_client->priv);
+                       pr_info("Panel is %s\n", video_tx_client->panel_info->lcd_name);
+                       lcd_id = video_tx_client->panel_info->lcd_id;
+                       lcd_name = video_tx_client->panel_info->lcd_name;
+                       lcd_width = video_tx_client->panel_info->spacemit_modeinfo->xres;
+                       lcd_height = video_tx_client->panel_info->spacemit_modeinfo->yres;
+                       return 1;
+               }
+       }
+       lcd_mipi_dc_enable(false, video_tx_client->priv);
+
+       return 0;
+}
+
+static int lcd_mipi_init(struct video_tx_device *dev)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+       int ret = 0;
+
+       ret = spacemit_mipi_open(0, video_tx_client->panel_info->mipi_info, false);
+       if(0 != ret) {
+               pr_info("lcd_mipi open mipi fai!\n ");
+               return -1;
+       }
+
+       ret = spacemit_mipi_write_cmds(0, video_tx_client->panel_info->init_cmds,
+                       video_tx_client->panel_info->init_cmds_num);
+
+       return ret;
+}
+
+static int lcd_mipi_sleep_out(struct video_tx_device *dev)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+       int ret = 0;
+
+       pr_debug("lcd_mipi_sleep_out enter!\n");
+
+       ret = lcd_mipi_dc_enable(true, video_tx_client->priv);
+       if (ret) {
+               pr_info("lcd_mipi gpio dc failded!\n");
+               return -1;
+       }
+
+       ret = lcd_mipi_init(dev);
+       if(0 != ret) {
+               pr_info("lcd_mipi init fai!\n ");
+               return -1;
+       }
+
+       ret = spacemit_mipi_write_cmds(0, video_tx_client->panel_info->sleep_out_cmds,
+                       video_tx_client->panel_info->sleep_out_cmds_num);
+
+       ret = spacemit_mipi_ready_for_datatx(0, video_tx_client->panel_info->mipi_info);
+       if(0 != ret) {
+               pr_info("lcd_mipi spacemit_mipi_ready_for_datatx fail!\n ");
+               spacemit_mipi_close(0);
+       }
+
+       return 0;
+}
+
+static int lcd_mipi_get_modes(struct video_tx_device *dev,
+                         struct spacemit_mode_modeinfo *mode_info)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+
+       if (mode_info == NULL)
+               return 0;
+
+       memcpy(mode_info, (void *)(video_tx_client->panel_info->spacemit_modeinfo), sizeof(struct spacemit_mode_modeinfo));
+       return 1;
+}
+
+static int lcd_mipi_dpms(struct video_tx_device *dev, int status)
+{
+       char *str_dpms;
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+
+       if(status == video_tx_client->dpms_status){
+               pr_info("lcd has been in (%d) status\n", status);
+               return 0;
+       }
+
+       switch (status) {
+       case DPMS_ON:
+               str_dpms = "DRM_MODE_DPMS_ON";
+               lcd_mipi_sleep_out(dev);
+               break;
+       case DPMS_OFF:
+               str_dpms = "DRM_MODE_DPMS_OFF";
+               break;
+       default:
+               pr_info("DPMS: unknown status!\n");
+               return -EINVAL;
+       }
+
+       video_tx_client->dpms_status = status;
+       pr_debug("driver->dpms( %s )\n", str_dpms);
+
+       return 0;
+}
+
+static int lcd_bl_enable(struct video_tx_device *dev, bool enable)
+{
+       struct lcd_mipi_tx_data  *video_tx_client =
+                               video_tx_get_drvdata(dev);
+       struct spacemit_panel_priv *priv = video_tx_client->priv;
+
+       dm_gpio_set_value(&priv->bl, 1);
+
+       return 0;
+}
+
+int lcd_mipi_register_panel(struct lcd_mipi_panel_info *panel_info)
+{
+       if(panel_num >= PANEL_NUM_MAX) {
+               pr_info("%s, panel_num is full!\n", __func__);
+               return 0;
+       }
+
+       panels[panel_num] = panel_info;
+       panel_num++;
+
+       pr_debug("fb: panel %s registered in lcd_mipi!\n", panel_info->lcd_name);
+
+       return 0;
+}
+
+static struct video_tx_driver lcd_mipi_driver_tx = {
+       .get_modes = lcd_mipi_get_modes,
+       .dpms = lcd_mipi_dpms,
+       .identify = lcd_mipi_identify,
+       .esd_check = lcd_mipi_esd_check,
+       .panel_reset = lcd_mipi_panel_reset,
+       .bl_enable = lcd_bl_enable,
+};
+
+struct lcd_mipi_tx_data tx_device_client = {0};
+struct video_tx_device tx_device = {0};
+
+static int lcd_mipi_client_init(struct spacemit_panel_priv *priv)
+{
+       tx_device_client.panel_type = LCD_MIPI;
+       tx_device_client.panel_info = NULL;
+       tx_device_client.dpms_status = DPMS_OFF;
+       tx_device_client.priv = priv;
+
+       tx_device.driver = &lcd_mipi_driver_tx;
+       tx_device.panel_type = tx_device_client.panel_type;
+       tx_device.private = &tx_device_client;
+
+       video_tx_register_device(&tx_device);
+
+       return 0;
+}
+
+int lcd_mipi_probe(void)
+{
+       int ret;
+       struct udevice *dev = NULL;
+       struct spacemit_panel_priv *priv = NULL;
+
+       ret = uclass_get_device_by_driver(UCLASS_NOP,
+               DM_DRIVER_GET(spacemit_panel), &dev);
+       if (ret) {
+               pr_info("spacemit_panel probe failed %d\n", ret);
+               return ret;
+       }
+
+       priv = dev_get_priv(dev);
+
+       ret = lcd_mipi_client_init(priv);
+       if (ret) {
+               pr_info("lcd_mipi client init failed\n");
+               return ret;
+       }
+
+       ret = spacemit_dsi_probe();
+       if (ret < 0) {
+               pr_info("spacemit_dsi_probe failed\n");
+               return ret;
+       }
+
+       lcd_icnl9911c_init();
+       lcd_gx09inx101_init();
+
+
+       return 0;
+}
+
+static const struct udevice_id spacemit_panel_ids[] = {
+        { .compatible = "spacemit,panel" },
+        { }
+};
+
+static int spacemit_panel_of_to_plat(struct udevice *dev)
+{
+
+       struct spacemit_panel_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = gpio_request_by_name(dev, "dcp-gpios", 0, &priv->dcp,
+                                  GPIOD_IS_OUT);
+       if (ret) {
+               pr_info("%s: Warning: cannot get dcp GPIO: ret=%d\n",
+                     __func__, ret);
+       }
+
+       ret = gpio_request_by_name(dev, "dcn-gpios", 0, &priv->dcn,
+                                  GPIOD_IS_OUT);
+       if (ret) {
+               pr_info("%s: Warning: cannot get dcn GPIO: ret=%d\n",
+                     __func__, ret);
+       }
+
+       ret = gpio_request_by_name(dev, "bl-gpios", 0, &priv->bl,
+                                  GPIOD_IS_OUT);
+       if (ret) {
+               pr_info("%s: Warning: cannot get bl GPIO: ret=%d\n",
+                     __func__, ret);
+       }
+
+       ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset,
+                                  GPIOD_IS_OUT);
+       if (ret) {
+               pr_info("%s: Warning: cannot get reset GPIO: ret=%d\n",
+                     __func__, ret);
+       }
+
+       return 0;
+}
+
+U_BOOT_DRIVER(spacemit_panel) = {
+        .name   = "spacemit-panel",
+        .id     = UCLASS_NOP,
+        .of_to_plat     = spacemit_panel_of_to_plat,
+        .of_match = spacemit_panel_ids,
+        .priv_auto      = sizeof(struct spacemit_panel_priv),
+};
diff --git a/drivers/video/spacemit/dsi/video/spacemit_video_tx.c b/drivers/video/spacemit/dsi/video/spacemit_video_tx.c
new file mode 100644 (file)
index 0000000..3647eb6
--- /dev/null
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <stddef.h>
+#include "../include/spacemit_video_tx.h"
+
+
+int tx_device_num = 0;
+struct video_tx_device *tx_devices[2] = {0};
+
+struct video_tx_device *find_video_tx(void)
+{
+       struct video_tx_device *tx_device = NULL;
+       int is_panel = 0;
+       int i;
+
+       for(i=0; i<tx_device_num; i++) {
+               tx_device = tx_devices[i];
+               if(!tx_device)
+                       continue;
+               if(NULL == tx_device->driver->identify)
+                       continue;
+               is_panel = tx_device->driver->identify(tx_device);
+               if(is_panel){
+                       pr_debug("lcd (port %d) is opened by kernel!\n", tx_device->panel_type);
+                       return tx_device;
+               } else {
+                       pr_info("lcd_port (%d) is not the corrected video_tx!\n", tx_device->panel_type);
+               }
+       }
+
+       pr_info("Can not found the corrected panel!\n");
+       return NULL;
+}
+
+int video_tx_get_modes(struct video_tx_device *video_tx,
+                      struct spacemit_mode_modeinfo *modelist)
+{
+       if (!video_tx->driver->get_modes)
+               return -EINVAL;
+
+       return video_tx->driver->get_modes(video_tx, modelist);
+}
+
+/**
+ * video_tx_dpms - set the power status of a video tx
+ *
+ * @video_tx: pointer to the video tx device
+ * @mode: the power status we want to put the device into
+ *     (follows the  DRM_MODE_DPMS definitions)
+ *
+ * This function will be called by a host in order to change the power
+ * mode of a video tx client.
+ *
+ * It will return 0 on success and negative on error.
+ *
+ */
+int video_tx_dpms(struct video_tx_device *video_tx, int mode)
+{
+       int ret;
+
+       if (!video_tx->driver->dpms)
+               return -EINVAL;
+
+       ret = video_tx->driver->dpms(video_tx, mode);
+
+       return ret;
+}
+
+void video_tx_esd_check(struct video_tx_device *video_tx)
+{
+       bool esd_status = false;
+       int ret;
+
+       if (!video_tx->driver->esd_check || !video_tx->driver->panel_reset) {
+               pr_info("esd_check() not implemented\n");
+               return;
+       }
+
+       esd_status = video_tx->driver->esd_check(video_tx);
+       if(!esd_status) {
+               ret = video_tx->driver->panel_reset(video_tx);
+               if(ret) {
+                       pr_info("panel reset fail!\n");
+               }
+       }
+}
+
+
+/**
+ * video_tx_register_device - register a video tx with the framework
+ *
+ * @dev: pointer to the video transmitter device structure
+ * @driver: pointer to the driver structure that contains all the ops
+ *
+ * This function will register a video transmitter client with the video_tx
+ * framework.
+ * It will return a pointer to the newly allocated video_tx_device structure or
+ * NULL in case of an error.
+ *
+ * The video tx driver needs to call this function before using any of the
+ * other facilities of the framework.
+ *
+ */
+int video_tx_register_device(struct video_tx_device *tx_device)
+{
+       if(tx_device_num >= 2) {
+               pr_info("%s, video_tx_device is full!\n", __func__);
+               return 0;
+       }
+
+       tx_devices[tx_device_num] = tx_device;
+       tx_device_num++;
+
+       pr_info("fb: video_tx (port %d) register device!\n", tx_device->panel_type);
+       return 0;
+}
+
+void *video_tx_get_drvdata(struct video_tx_device *tx_device)
+{
+       return tx_device->private;
+}
diff --git a/drivers/video/spacemit/spacemit_dpu.c b/drivers/video/spacemit/spacemit_dpu.c
new file mode 100644 (file)
index 0000000..53f70a7
--- /dev/null
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <common.h>
+#include <display.h>
+#include <dm.h>
+#include <dm/uclass.h>
+#include <dm/device.h>
+#include <dm/uclass-internal.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+#include <regmap.h>
+#include <syscon.h>
+#include <video.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#include <power-domain-uclass.h>
+#include <power-domain.h>
+#include <clk.h>
+#include <video_bridge.h>
+#include <power/pmic.h>
+#include <panel.h>
+
+#include "spacemit_dpu.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fb_info fbi = {0};
+
+struct spacemit_mode_modeinfo hdmi_1080p_modeinfo = {
+       .name = "1920x1080-60",
+       .refresh = 60,
+       .xres = 1920,
+       .yres = 1080,
+       .real_xres = 1920,
+       .real_yres = 1080,
+       .left_margin = 148,
+       .right_margin = 88,
+       .hsync_len = 44,
+       .upper_margin = 36,
+       .lower_margin = 4,
+       .vsync_len = 5,
+       .hsync_invert = 0,
+       .vsync_invert = 0,
+       .invert_pixclock = 0,
+       .pixclock_freq = 148500,
+       .pix_fmt_out = OUTFMT_RGB888,
+       .width = 0,
+       .height = 0,
+};
+
+#if 0
+static unsigned int hdmi_dpu_read(void __iomem *addr)
+{
+       unsigned int val = readl(addr + 0xc0440000);
+       return val;
+}
+#endif
+
+static void hdmi_dpu_write(void __iomem *addr, unsigned int val)
+{
+       writel(val, addr + 0xc0440000);
+}
+
+static void hdmi_dpu_init(struct spacemit_mode_modeinfo *hdmi_modeinfo, ulong fbbase)
+{
+       unsigned int vsync, hsync, vbp, vfp, hbp, hfp, vsp, hsp;
+       unsigned int reg_val = 0;
+
+       vsync = hdmi_modeinfo->vsync_len & 0x3ff;
+       hsync = hdmi_modeinfo->hsync_len & 0x3ff;
+       vbp = hdmi_modeinfo->upper_margin & 0xfff;
+       vfp = hdmi_modeinfo->lower_margin & 0xfff;
+       hbp = hdmi_modeinfo->left_margin & 0xfff;
+       hfp = hdmi_modeinfo->right_margin & 0xfff;
+       vsp = hdmi_modeinfo->hsync_invert ? 0 : 1;
+       hsp = hdmi_modeinfo->hsync_invert ? 0 : 1;
+
+       pr_debug("%s vsync %d hsync %d \n", __func__, vsync, hsync);
+       pr_debug("%s vbp %d vfp %d vsp %d\n", __func__, vbp, vfp, vsp);
+       pr_debug("%s hbp %d hfp %d hsp %d\n", __func__, hbp, hfp, hsp);
+
+       hdmi_dpu_write((void __iomem *)0xa1c, 0x2223);
+       hdmi_dpu_write((void __iomem *)0x18000, (hdmi_modeinfo->yres << 16) | hdmi_modeinfo->xres);
+       hdmi_dpu_write((void __iomem *)0x18018, 0x20);
+       hdmi_dpu_write((void __iomem *)0x1807c, 0x100);
+       reg_val = (hbp << 16) | hfp;
+       hdmi_dpu_write((void __iomem *)0x18080, reg_val);
+       reg_val = (vbp << 16) | vfp;
+       hdmi_dpu_write((void __iomem *)0x18084, reg_val);
+       reg_val = (vsp << 28) | (vsync << 16) | (hsp << 12) | (hsync);
+       hdmi_dpu_write((void __iomem *)0x18088, reg_val);
+       hdmi_dpu_write((void __iomem *)0x1808c, (hdmi_modeinfo->yres << 16) | hdmi_modeinfo->xres);
+       hdmi_dpu_write((void __iomem *)0x18090, hdmi_modeinfo->pix_fmt_out);
+       hdmi_dpu_write((void __iomem *)0xd80, 0x202040);
+       hdmi_dpu_write((void __iomem *)0xda0, (unsigned int)(fbbase & 0xffffffff));
+       hdmi_dpu_write((void __iomem *)0xda4, (unsigned int)(fbbase >> 32));
+       hdmi_dpu_write((void __iomem *)0xdb8, hdmi_modeinfo->xres * 4);
+       hdmi_dpu_write((void __iomem *)0xdbc, (hdmi_modeinfo->yres << 16) | hdmi_modeinfo->xres);
+       hdmi_dpu_write((void __iomem *)0xdc0, 0x0);
+       hdmi_dpu_write((void __iomem *)0xdc4, ((hdmi_modeinfo->yres - 1) << 16) | (hdmi_modeinfo->xres - 1));
+       hdmi_dpu_write((void __iomem *)0xdf0, 0x4);
+
+       hdmi_dpu_write((void __iomem *)0x4c00, (hdmi_modeinfo->xres << 8) | 0x01);
+       hdmi_dpu_write((void __iomem *)0x4c04, hdmi_modeinfo->yres);
+       hdmi_dpu_write((void __iomem *)0x4c10, 0xff0000);
+       hdmi_dpu_write((void __iomem *)0x4c14, 0xff);
+       hdmi_dpu_write((void __iomem *)0x4c38, 0x7);
+       hdmi_dpu_write((void __iomem *)0x4c48, 0x0);
+       hdmi_dpu_write((void __iomem *)0x4c4c, (hdmi_modeinfo->xres - 1) << 16);
+       hdmi_dpu_write((void __iomem *)0x4c50, hdmi_modeinfo->yres - 1);
+       hdmi_dpu_write((void __iomem *)0x4c54, 0xff0000);
+
+       hdmi_dpu_write((void __iomem *)0x560, 0x40008);
+       hdmi_dpu_write((void __iomem *)0x588, 0x821);
+       hdmi_dpu_write((void __iomem *)0x56c, 0x1);
+       hdmi_dpu_write((void __iomem *)0x58c, 0x1);
+
+}
+
+static int spacemit_panel_init(void)
+{
+       struct video_tx_device *tx = NULL;
+       int modes_num = 0;
+
+       tx = find_video_tx();
+       if (!tx) {
+               pr_info("probe: failed to find video tx\n");
+               return -1;
+       }
+       fbi.tx = tx;
+
+       modes_num = video_tx_get_modes(fbi.tx, &fbi.mode);
+       if (!modes_num) {
+               pr_info("can't get videomode num\n");
+               return -1;
+       }
+
+       video_tx_dpms(fbi.tx, DPMS_ON);
+
+       return 0;
+}
+
+#if 0
+static unsigned int dsi_dpu_read(void __iomem *addr)
+{
+       unsigned int val = readl(addr + 0xc0340000);
+       pr_debug("## dpu read [0x%lx] = 0x%x\n", (unsigned long)addr + 0xc0340000, val);
+       return val;
+}
+#endif
+
+static void dsi_dpu_write(void __iomem *addr, unsigned int val)
+{
+       pr_debug("## dpu write [0x%lx] = 0x%x\n", (unsigned long)addr + 0xc0340000, val);
+       writel(val, addr + 0xc0340000);
+}
+
+static void dsi_dpu_init(struct spacemit_mode_modeinfo *spacemit_mode, ulong fbbase)
+{
+       unsigned int vsync, hsync, vbp, vfp, hbp, hfp, vsp, hsp;
+       unsigned int reg_val = 0;
+
+       vsync = spacemit_mode->vsync_len & 0x3ff;
+       hsync = spacemit_mode->hsync_len & 0x3ff;
+       vbp = spacemit_mode->upper_margin & 0xfff;
+       vfp = spacemit_mode->lower_margin & 0xfff;
+       hbp = spacemit_mode->left_margin & 0xfff;
+       hfp = spacemit_mode->right_margin & 0xfff;
+       vsp = spacemit_mode->hsync_invert ? 0 : 1;
+       hsp = spacemit_mode->hsync_invert ? 0 : 1;
+
+       dsi_dpu_write((void __iomem *)0xa1c, 0x2223);
+       dsi_dpu_write((void __iomem *)0x18000, (spacemit_mode->yres << 16) | spacemit_mode->xres);
+       dsi_dpu_write((void __iomem *)0x18018, 0x20);
+       dsi_dpu_write((void __iomem *)0x1807c, 0x100);
+       reg_val = (hbp << 16) | hfp;
+       dsi_dpu_write((void __iomem *)0x18080, reg_val);
+       reg_val = (vbp << 16) | vfp;
+       dsi_dpu_write((void __iomem *)0x18084, reg_val);
+       reg_val = (vsp << 28) | (vsync << 16) | (hsp << 12) | (hsync);
+       dsi_dpu_write((void __iomem *)0x18088, reg_val);
+       dsi_dpu_write((void __iomem *)0x1808c, (spacemit_mode->yres << 16) | spacemit_mode->xres);
+       dsi_dpu_write((void __iomem *)0x18090, spacemit_mode->pix_fmt_out);
+       dsi_dpu_write((void __iomem *)0xd80, 0x202040);
+       dsi_dpu_write((void __iomem *)0xda0, (unsigned int)(fbbase & 0xffffffff));
+       dsi_dpu_write((void __iomem *)0xda4, (unsigned int)(fbbase >> 32));
+       dsi_dpu_write((void __iomem *)0xdb8, spacemit_mode->xres * 4);
+       dsi_dpu_write((void __iomem *)0xdbc, (spacemit_mode->yres << 16) | spacemit_mode->xres);
+       dsi_dpu_write((void __iomem *)0xdc0, 0x0);
+       dsi_dpu_write((void __iomem *)0xdc4, ((spacemit_mode->yres - 1) << 16) | (spacemit_mode->xres - 1));
+       dsi_dpu_write((void __iomem *)0xdf0, 0x4);
+       /* PP3 will impact display light */
+       dsi_dpu_write((void __iomem *)0x4c00, (spacemit_mode->xres << 8) | 0x01);
+       dsi_dpu_write((void __iomem *)0x4c04, spacemit_mode->yres);
+       dsi_dpu_write((void __iomem *)0x4c10, 0xff0000);
+       dsi_dpu_write((void __iomem *)0x4c14, 0xff);
+       dsi_dpu_write((void __iomem *)0x4c38, 0x7);
+       dsi_dpu_write((void __iomem *)0x4c48, 0x0);
+       dsi_dpu_write((void __iomem *)0x4c4c, (spacemit_mode->xres - 1) << 16);
+       dsi_dpu_write((void __iomem *)0x4c50, spacemit_mode->yres - 1);
+       dsi_dpu_write((void __iomem *)0x4c54, 0xff0000);
+
+       dsi_dpu_write((void __iomem *)0x560, 0x40008);
+       dsi_dpu_write((void __iomem *)0x588, 0x821);
+       dsi_dpu_write((void __iomem *)0x56c, 0x1);
+       dsi_dpu_write((void __iomem *)0x58c, 0x1);
+}
+
+static int spacemit_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
+{
+       // struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+       // struct spacemit_dpu_priv *priv = dev_get_priv(dev);
+       struct display_timing timing;
+       int dpu_id, remote_dpu_id;
+       struct udevice *disp;
+       int ret;
+       u32 remote_phandle;
+       ofnode remote;
+       const char *compat;
+       struct display_plat *disp_uc_plat;
+       // struct udevice *panel = NULL;
+
+       struct spacemit_mode_modeinfo *spacemit_mode = NULL;
+
+
+       pr_debug("%s(%s, 0x%lx, %s)\n", __func__,
+                         dev_read_name(dev), fbbase, ofnode_get_name(ep_node));
+
+       ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle);
+       if (ret)
+               return ret;
+
+       remote = ofnode_get_by_phandle(remote_phandle);
+       if (!ofnode_valid(remote))
+               return -EINVAL;
+       remote_dpu_id = ofnode_read_u32_default(remote, "reg", -1);
+       uc_priv->bpix = VIDEO_BPP32;
+       pr_debug("remote_dpu_id  %d\n", remote_dpu_id);
+
+       while (ofnode_valid(remote)) {
+               remote = ofnode_get_parent(remote);
+               if (!ofnode_valid(remote)) {
+                       pr_debug("%s(%s): no UCLASS_DISPLAY for remote-endpoint\n",
+                             __func__, dev_read_name(dev));
+                       return -EINVAL;
+               }
+               pr_debug("%s(dev: %s, 0x%lx,remote node: %s)\n", __func__,
+                 dev_read_name(dev), fbbase, ofnode_get_name(remote));
+
+               uclass_find_device_by_ofnode(UCLASS_DISPLAY, remote, &disp);
+               if (disp)
+                       break;
+
+       };
+       compat = ofnode_get_property(remote, "compatible", NULL);
+       if (!compat) {
+               pr_info("%s(%s): Failed to find compatible property\n",
+                     __func__, dev_read_name(dev));
+               return -EINVAL;
+       }
+
+       if (strstr(compat, "mipi")) {
+               dpu_id = DPU_MODE_MIPI;
+       } else if (strstr(compat, "hdmi")) {
+               dpu_id = DPU_MODE_HDMI;
+       } else {
+               pr_info("%s(%s): Failed to find dpu mode for %s\n",
+                     __func__, dev_read_name(dev), compat);
+               return -EINVAL;
+       }
+
+       pr_debug("dpu_id %d,compat = %s\n", dpu_id, compat);
+
+       if(dpu_id == DPU_MODE_HDMI)
+       {
+               disp_uc_plat = dev_get_uclass_plat(disp);
+
+               pr_info("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
+
+               disp_uc_plat->source_id = remote_dpu_id;
+               disp_uc_plat->src_dev = dev;
+
+               ret = device_probe(disp);
+               if (ret) {
+                       pr_info("%s: device '%s' display won't probe (ret=%d)\n",
+                         __func__, dev->name, ret);
+                       return ret;
+               }
+
+               ret = display_enable(disp, 1 << VIDEO_BPP32, &timing);
+               if (ret) {
+                       pr_info("%s: Failed to read timings\n", __func__);
+                       return ret;
+               }
+
+               hdmi_dpu_init(&hdmi_1080p_modeinfo, fbbase);
+
+               uc_priv->xsize = 1920;
+               uc_priv->ysize = 1080;
+
+               pr_info("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize);
+
+               return 0;
+       } else if (dpu_id == DPU_MODE_MIPI) {
+
+               struct video_tx_device *video_tx;
+
+               disp_uc_plat = dev_get_uclass_plat(disp);
+
+               pr_info("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
+
+               disp_uc_plat->source_id = remote_dpu_id;
+               disp_uc_plat->src_dev = dev;
+
+               ret = device_probe(disp);
+               if (ret) {
+                       pr_info("%s: device '%s' display won't probe (ret=%d)\n",
+                         __func__, dev->name, ret);
+                       return ret;
+               }
+
+               ret = display_read_timing(disp, &timing);
+               if (ret) {
+                       pr_info("%s: Failed to read timings\n", __func__);
+                       return ret;
+               }
+
+               ret = display_enable(disp, 1 << VIDEO_BPP32, &timing);
+               if (ret) {
+                       pr_info("%s: Failed to display enable\n", __func__);
+                       return ret;
+               }
+
+               ret = spacemit_panel_init();
+               if (ret) {
+                       pr_info("%s: Failed to init panel\n", __func__);
+                       return ret;
+               }
+
+               spacemit_mode = &fbi.mode;
+               uc_priv->xsize = spacemit_mode->xres;
+               uc_priv->ysize = spacemit_mode->yres;
+
+               dsi_dpu_init(spacemit_mode, fbbase);
+               video_tx_esd_check(fbi.tx);
+               video_tx = fbi.tx;
+               video_tx->driver->bl_enable(video_tx, true);
+
+               pr_info("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize);
+
+               return 0;
+       }
+
+       return 0;
+}
+
+static int spacemit_dpu_probe(struct udevice *dev)
+{
+       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+       struct spacemit_dpu_priv *priv = dev_get_priv(dev);
+       struct udevice *udev;
+       ofnode port, node;
+       int ret;
+
+       priv->regs_dsi = dev_remap_addr_name(dev, "dsi");
+       if (!priv->regs_dsi)
+               return -EINVAL;
+
+       priv->regs_hdmi = dev_remap_addr_name(dev, "hdmi");
+       if (!priv->regs_hdmi)
+               return -EINVAL;
+
+       port = dev_read_subnode(dev, "port");
+       if (!ofnode_valid(port)) {
+               pr_info("%s(%s): 'port' subnode not found\n",
+                     __func__, dev_read_name(dev));
+               return -EINVAL;
+       }
+
+       for (uclass_find_first_device(UCLASS_VIDEO, &udev);
+               udev;
+               uclass_find_next_device(&udev)) {
+               pr_info("%s:video device %s \n", __func__, udev->name);
+       }
+
+       for (uclass_find_first_device(UCLASS_DISPLAY, &udev);
+               udev;
+               uclass_find_next_device(&udev)) {
+
+               pr_info("%s:display device %s\n", __func__, udev->name);
+       }
+
+       for (uclass_find_first_device(UCLASS_VIDEO_BRIDGE, &udev);
+               udev;
+               uclass_find_next_device(&udev)) {
+
+               pr_info("%s:bridge device %s\n", __func__, udev->name);
+       }
+
+       for (node = ofnode_first_subnode(port);
+               ofnode_valid(node);
+               node = dev_read_next_subnode(node)) {
+
+               ret = spacemit_display_init(dev, plat->base, node);
+               if (ret)
+                       pr_debug("Device failed: ret=%d\n", ret);
+               if (!ret)
+                       break;
+       }
+
+       video_set_flush_dcache(dev, 1);
+
+       return 0;
+}
+
+static int spacemit_dpu_remove(struct udevice *dev)
+{
+       return 0;
+}
+
+struct spacemit_dpu_driverdata dpu_driverdata = {
+       .features = DPU_FEATURE_OUTPUT_10BIT,
+};
+
+static const struct udevice_id spacemit_dc_ids[] = {
+       { .compatible = "spacemit,dpu",
+         .data = (ulong)&dpu_driverdata },
+       { }
+};
+
+static const struct video_ops spacemit_dpu_ops = {
+};
+
+int spacemit_dpu_bind(struct udevice *dev)
+{
+       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+       pr_debug("%s,%d,plat->size = %d plat->base 0x%lx\n",__func__,__LINE__,plat->size, plat->base);
+
+       plat->size = 4 * (CONFIG_VIDEO_SPACEMIT_MAX_XRES *
+                         CONFIG_VIDEO_SPACEMIT_MAX_YRES);
+
+       return 0;
+}
+
+U_BOOT_DRIVER(spacemit_dpu) = {
+       .name   = "spacemit_dpu",
+       .id     = UCLASS_VIDEO,
+       .of_match = spacemit_dc_ids,
+       .ops    = &spacemit_dpu_ops,
+       .bind   = spacemit_dpu_bind,
+       .probe  = spacemit_dpu_probe,
+    .remove = spacemit_dpu_remove,
+       .priv_auto      = sizeof(struct spacemit_dpu_priv),
+};
diff --git a/drivers/video/spacemit/spacemit_dpu.h b/drivers/video/spacemit/spacemit_dpu.h
new file mode 100644 (file)
index 0000000..263ac6e
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DPU_H_
+#define _SPACEMIT_DPU_H_
+#include <clk.h>
+#include <reset.h>
+#include "./dsi/include/spacemit_video_tx.h"
+
+
+#define DPU_INT_REG_24 0x960
+#define DPU_INT_REG_14 0x938
+
+#define OUTFMT_RGB121212       0
+#define OUTFMT_RGB101010       1
+#define OUTFMT_RGB888          2
+#define OUTFMT_RGB666          12
+#define OUTFMT_RGB565          13
+
+enum dpu_modes {
+       DPU_MODE_EDP = 0,
+       DPU_MODE_MIPI,
+       DPU_MODE_HDMI,
+       DPU_MODE_LVDS,
+       DPU_MODE_DP,
+};
+
+enum dpu_features {
+       DPU_FEATURE_OUTPUT_10BIT = (1 << 0),
+};
+
+enum {
+       POWER_INVALID = 0,
+       POWER_OFF,
+       POWER_ON,
+};
+
+struct fb_info {
+       struct spacemit_mode_modeinfo mode;
+       struct video_tx_device *tx;
+};
+
+struct spacemit_dpu_priv {
+       void __iomem *regs_dsi;
+       void __iomem *regs_hdmi;
+       struct udevice *conn_dev;
+       struct display_timing timing;
+};
+
+struct spacemit_dpu_driverdata {
+       /* configuration */
+       u32 features;
+       /* block-specific setters/getters */
+       void (*set_pin_polarity)(struct udevice *, enum dpu_modes, u32);
+};
+
+#endif
diff --git a/drivers/video/spacemit/spacemit_hdmi.c b/drivers/video/spacemit/spacemit_hdmi.c
new file mode 100644 (file)
index 0000000..8472230
--- /dev/null
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include <clk.h>
+#include <display.h>
+#include <dm.h>
+#include <dw_hdmi.h>
+#include <edid.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include <power-domain-uclass.h>
+#include <power-domain.h>
+#include <power/regulator.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "spacemit_hdmi.h"
+
+#define SPACEMIT_HDMI_PHY_STATUS        0xC
+#define SPACEMIT_HDMI_PHY_HPD           0x1000
+int is_hdmi_connected;
+
+static int hdmi_get_plug_in_status(struct dw_hdmi *hdmi)
+{
+       void __iomem *hdmi_addr;
+       hdmi_addr = ioremap(0xC0400500, 0x200);
+       u32 value;
+
+       pr_debug("%s() \n", __func__);
+       value = readl(hdmi_addr + SPACEMIT_HDMI_PHY_STATUS) & SPACEMIT_HDMI_PHY_HPD;
+
+       return !!value;
+}
+
+static int hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi)
+{
+       ulong start;
+
+       pr_debug("%s() \n", __func__);
+
+       start = get_timer(0);
+       do {
+               if (hdmi_get_plug_in_status(hdmi)) {
+                       pr_info("%s() hdmi get hpd signal \n", __func__);
+                       return 0;
+               }
+               udelay(100);
+       } while (get_timer(start) < 100);
+
+       return -1;
+}
+
+
+static int hdmi_enable(struct udevice *dev, int panel_bpp,
+                             const struct display_timing *edid)
+{
+       void __iomem *hdmi_addr;
+       hdmi_addr = ioremap(0xC0400500, 0x200);
+       u32 value;
+
+       // hdmi phy param config
+       #if 0
+
+       writel(0x4d, hdmi_addr + 0x34);
+       writel(0x20200000, hdmi_addr + 0xe8);
+       writel(0x509D453E, hdmi_addr + 0xec);
+       writel(0x821, hdmi_addr + 0xf0);
+       writel(0x3, hdmi_addr + 0xe4);
+
+       udelay(2);
+       value = readl(hdmi_addr + 0xe4);
+       pr_debug("%s() hdmi 0xe4 0x%x\n", __func__, value);
+
+       writel(0x30184000, hdmi_addr + 0x28);
+
+       #else
+
+       writel(0xEE40410F, hdmi_addr + 0xe0);
+       writel(0x0000005d, hdmi_addr + 0x34);
+       writel(0x2022C000, hdmi_addr + 0xe8);
+       writel(0x508D414D, hdmi_addr + 0xec);
+
+       writel(0x00000901, hdmi_addr + 0xf0);
+       writel(0x3, hdmi_addr + 0xe4);
+
+       udelay(2);
+       value = readl(hdmi_addr + 0xe4);
+       pr_debug("%s() hdmi 0xe4 0x%x\n", __func__, value);
+
+       writel(0x3018C001, hdmi_addr + 0x28);
+
+       #endif
+
+       udelay(1000);
+
+       return 0;
+}
+
+int hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
+{
+       struct spacemit_hdmi_priv *priv = dev_get_priv(dev);
+
+       return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size);
+}
+
+static int spacemit_hdmi_of_to_plat(struct udevice *dev)
+{
+       return 0;
+}
+
+static int spacemit_hdmi_probe(struct udevice *dev)
+{
+       struct spacemit_hdmi_priv *priv = dev_get_priv(dev);
+       struct power_domain pm_domain;
+       unsigned long rate;
+       int ret;
+
+       pr_debug("%s() \n", __func__);
+
+       priv->base = dev_remap_addr_name(dev, "hdmi");
+       if (!priv->base)
+               return -EINVAL;
+
+       ret = power_domain_get(dev, &pm_domain);
+       if (ret) {
+               pr_err("power_domain_get hdmi failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "hmclk", &priv->hdmi_mclk);
+       if (ret) {
+               pr_err("clk_get_by_name hdmi mclk failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&priv->hdmi_mclk);
+       if (ret < 0) {
+               pr_err("clk_enable hdmi mclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_get_by_name(dev, "hdmi_reset", &priv->hdmi_reset);
+       if (ret) {
+               pr_err("reset_get_by_name hdmi reset failed: %d\n", ret);
+               return ret;
+       }
+       ret = reset_deassert(&priv->hdmi_reset);
+       if (ret) {
+               pr_err("reset_assert hdmi reset failed: %d\n", ret);
+               goto free_reset;
+       }
+
+       rate = clk_get_rate(&priv->hdmi_mclk);
+       pr_debug("%s clk_get_rate hdmi mclk %ld\n", __func__, rate);
+
+
+       priv->hdmi.ioaddr = (ulong)priv->base;
+       priv->hdmi.reg_io_width = 4;
+
+       ret = hdmi_phy_wait_for_hpd(&priv->hdmi);
+       is_hdmi_connected = ret;
+       if (ret < 0) {
+               pr_info("hdmi can not get hpd signal\n");
+               return ret;
+       }
+
+       return ret;
+
+free_reset:
+       clk_disable(&priv->hdmi_mclk);
+
+       return 0;
+}
+
+static const struct dm_display_ops spacemit_hdmi_ops = {
+       .read_edid = hdmi_read_edid,
+       .enable = hdmi_enable,
+};
+
+static const struct udevice_id spacemit_hdmi_ids[] = {
+       { .compatible = "spacemit,hdmi" },
+       { }
+};
+
+U_BOOT_DRIVER(spacemit_hdmi) = {
+       .name = "spacemit_hdmi",
+       .id = UCLASS_DISPLAY,
+       .of_match = spacemit_hdmi_ids,
+       .ops = &spacemit_hdmi_ops,
+       .of_to_plat = spacemit_hdmi_of_to_plat,
+       .probe = spacemit_hdmi_probe,
+       .priv_auto      = sizeof(struct spacemit_hdmi_priv),
+};
diff --git a/drivers/video/spacemit/spacemit_hdmi.h b/drivers/video/spacemit/spacemit_hdmi.h
new file mode 100644 (file)
index 0000000..ca205d7
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_HDMI_H_
+#define _SPACEMIT_HDMI_H_
+
+#include <clk.h>
+#include <reset.h>
+
+
+#define HDMI_STATUS                            0xc8
+#define m_HOTPLUG                              (1 << 7)
+#define m_MASK_INT_HOTPLUG             (1 << 5)
+#define m_INT_HOTPLUG                  (1 << 1)
+#define v_MASK_INT_HOTPLUG(n)  ((n & 0x1) << 5)
+
+
+struct spacemit_hdmi_priv {
+       struct dw_hdmi hdmi;
+       void __iomem *base;
+
+       struct clk hdmi_mclk;
+       struct reset_ctl hdmi_reset;
+};
+
+#endif
diff --git a/drivers/video/spacemit/spacemit_mipi.c b/drivers/video/spacemit/spacemit_mipi.c
new file mode 100644 (file)
index 0000000..a292301
--- /dev/null
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include <clk.h>
+#include <display.h>
+#include <dm.h>
+#include <regmap.h>
+#include <panel.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <power-domain-uclass.h>
+#include <power-domain.h>
+#include <power/regulator.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <mipi_dsi.h>
+#include <reset.h>
+
+#include "spacemit_mipi.h"
+#include "./dsi/include/spacemit_dsi_common.h"
+
+
+static int spacemit_mipi_dsi_enable(struct udevice *dev,
+                      const struct display_timing *timing)
+{
+       ofnode node, timing_node;
+       int val;
+       // struct spacemit_mipi_priv *priv = dev_get_priv(dev);
+
+       /* Set dpi color coding depth 24 bit */
+       timing_node = ofnode_find_subnode(dev_ofnode(dev), "display-timings");
+       node = ofnode_first_subnode(timing_node);
+
+       val = ofnode_read_u32_default(node, "bits-per-pixel", -1);
+
+       return 0;
+}
+
+static int spacemit_mipi_phy_enable(struct udevice *dev)
+{
+       // struct spacemit_mipi_priv *priv = dev_get_priv(dev);
+       return 0;
+}
+
+
+static int mipi_dsi_read_timing(struct udevice *dev,
+                       struct display_timing *timing)
+{
+       // int ret;
+
+       // ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
+       // if (ret) {
+       //      pr_debug("%s: Failed to decode display timing (ret=%d)\n",
+       //            __func__, ret);
+       //      return -EINVAL;
+       // }
+
+       return 0;
+}
+
+static int mipi_dsi_display_enable(struct udevice *dev, int panel_bpp,
+                         const struct display_timing *timing)
+{
+       int ret;
+       // struct spacemit_mipi_priv *priv = dev_get_priv(dev);
+
+       /* Config  and enable mipi dsi according to timing */
+       ret = spacemit_mipi_dsi_enable(dev, timing);
+       if (ret) {
+               pr_debug("%s: spacemit_mipi_dsi_enable() failed (err=%d)\n",
+                     __func__, ret);
+               return ret;
+       }
+
+       /* Config and enable mipi phy */
+       ret = spacemit_mipi_phy_enable(dev);
+       if (ret) {
+               pr_debug("%s: spacemit_mipi_phy_enable() failed (err=%d)\n",
+                     __func__, ret);
+               return ret;
+       }
+
+       /* Enable backlight */
+       // ret = panel_enable_backlight(priv->panel);
+       // if (ret) {
+       //      pr_debug("%s: panel_enable_backlight() failed (err=%d)\n",
+       //            __func__, ret);
+       //      return ret;
+       // }
+
+       return 0;
+}
+
+static int spacemit_mipi_dsi_of_to_plat(struct udevice *dev)
+{
+       lcd_mipi_probe();
+       return 0;
+}
+
+static int spacemit_mipi_dsi_probe(struct udevice *dev)
+{
+       struct spacemit_mipi_priv *priv = dev_get_priv(dev);
+       struct power_domain pm_domain;
+       unsigned long rate;
+       int ret;
+
+       ret = power_domain_get(dev, &pm_domain);
+       if (ret) {
+               pr_err("power_domain_get mipi dsi failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "pxclk", &priv->pxclk);
+       if (ret) {
+               pr_err("clk_get_by_name mipi dsi pxclk failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "mclk", &priv->mclk);
+       if (ret) {
+               pr_err("clk_get_by_name mipi dsi mclk failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "hclk", &priv->hclk);
+       if (ret) {
+               pr_err("clk_get_by_name mipi dsi hclk failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "escclk", &priv->escclk);
+       if (ret) {
+               pr_err("clk_get_by_name mipi dsi escclk failed: %d", ret);
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "bitclk", &priv->bitclk);
+       if (ret) {
+               pr_err("clk_get_by_name mipi dsi bitclk failed: %d", ret);
+               return ret;
+       }
+
+       ret = reset_get_by_name(dev, "dsi_reset", &priv->dsi_reset);
+       if (ret) {
+               pr_err("reset_get_by_name dsi_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_get_by_name(dev, "mclk_reset", &priv->mclk_reset);
+       if (ret) {
+               pr_err("reset_get_by_name mclk_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_get_by_name(dev, "esc_reset", &priv->esc_reset);
+       if (ret) {
+               pr_err("reset_get_by_name esc_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_get_by_name(dev, "lcd_reset", &priv->lcd_reset);
+       if (ret) {
+               pr_err("reset_get_by_name lcd_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&priv->pxclk);
+       if (ret < 0) {
+               pr_err("clk_enable mipi dsi pxclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&priv->mclk);
+       if (ret < 0) {
+               pr_err("clk_enable mipi dsi mclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&priv->hclk);
+       if (ret < 0) {
+               pr_err("clk_enable mipi dsi hclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&priv->escclk);
+       if (ret < 0) {
+               pr_err("clk_enable mipi dsi escclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_enable(&priv->bitclk);
+       if (ret < 0) {
+               pr_err("clk_enable mipi dsi bitclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_rate(&priv->pxclk, 88000000);
+       if (ret < 0) {
+               pr_err("clk_set_rate mipi dsi pxclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_rate(&priv->mclk, 307200000);
+       if (ret < 0) {
+               pr_err("clk_set_rate mipi dsi mclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_rate(&priv->escclk, 51200000);
+       if (ret < 0) {
+               pr_err("clk_set_rate mipi dsi escclk failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_rate(&priv->bitclk, 614400000);
+       if (ret < 0) {
+               pr_err("clk_set_rate mipi dsi bitclk failed: %d\n", ret);
+               return ret;
+       }
+
+       rate = clk_get_rate(&priv->pxclk);
+       pr_debug("%s clk_get_rate pxclk rate = %ld\n", __func__, rate);
+
+       rate = clk_get_rate(&priv->mclk);
+       pr_debug("%s clk_get_rate mclk rate = %ld\n", __func__, rate);
+
+       rate = clk_get_rate(&priv->hclk);
+       pr_debug("%s clk_get_rate hclk rate = %ld\n", __func__, rate);
+
+       rate = clk_get_rate(&priv->escclk);
+       pr_debug("%s clk_get_rate escclk rate = %ld\n", __func__, rate);
+
+       rate = clk_get_rate(&priv->bitclk);
+       pr_debug("%s clk_get_rate bitclk rate = %ld\n", __func__, rate);
+
+       ret = reset_deassert(&priv->dsi_reset);
+       if (ret) {
+               pr_err("reset_assert dsi_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_deassert(&priv->mclk_reset);
+       if (ret) {
+               pr_err("reset_assert mclk_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_deassert(&priv->esc_reset);
+       if (ret) {
+               pr_err("reset_assert esc_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_deassert(&priv->lcd_reset);
+       if (ret) {
+               pr_err("reset_assert lcd_reset failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct dm_display_ops spacemit_mipi_dsi_ops = {
+       .read_timing = mipi_dsi_read_timing,
+       .enable = mipi_dsi_display_enable,
+};
+
+static const struct udevice_id spacemit_mipi_dsi_ids[] = {
+       { .compatible = "spacemit,mipi-dsi" },
+       { }
+};
+
+U_BOOT_DRIVER(spacemit_mipi_dsi) = {
+       .name = "spacemit_mipi_dsi",
+       .id = UCLASS_DISPLAY,
+       .of_match = spacemit_mipi_dsi_ids,
+       .ops = &spacemit_mipi_dsi_ops,
+       .of_to_plat = spacemit_mipi_dsi_of_to_plat,
+       .probe = spacemit_mipi_dsi_probe,
+       .priv_auto      = sizeof(struct spacemit_mipi_priv),
+};
diff --git a/drivers/video/spacemit/spacemit_mipi.h b/drivers/video/spacemit/spacemit_mipi.h
new file mode 100644 (file)
index 0000000..9305bfe
--- /dev/null
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_MIPI_H_
+#define _SPACEMIT_MIPI_H_
+
+#include <clk.h>
+#include <reset.h>
+
+#define HDMI_STATUS                            0xc8
+#define m_HOTPLUG                              (1 << 7)
+#define m_MASK_INT_HOTPLUG             (1 << 5)
+#define m_INT_HOTPLUG                  (1 << 1)
+#define v_MASK_INT_HOTPLUG(n)  ((n & 0x1) << 5)
+
+
+struct spacemit_mipi_priv {
+       void __iomem *base;
+
+       struct udevice *panel;
+       struct mipi_dsi *dsi;
+
+       struct clk pxclk;
+       struct clk mclk;
+       struct clk hclk;
+       struct clk escclk;
+       struct clk bitclk;
+
+       struct reset_ctl dsi_reset;
+       struct reset_ctl mclk_reset;
+       struct reset_ctl esc_reset;
+       struct reset_ctl lcd_reset;
+};
+
+#endif
index 47f1e9b99789584d2f6dd71e954b51927b35d783..6a277a1b0fbd9e3edb381958d159f30ed8b45a8d 100644 (file)
Binary files a/drivers/video/u_boot_logo.bmp and b/drivers/video/u_boot_logo.bmp differ
index f42db40d4cde0de8bdc784ed0364afcb38a5807e..3cd76a5b5ad968549df7b1c78aa70e69c34bf79e 100644 (file)
@@ -18,6 +18,8 @@
 #include <video_console.h>
 #include <video_font.h>                /* Bitmap font for code page 437 */
 #include <linux/ctype.h>
+#include <cpu_func.h>
+#include <malloc.h>
 
 /*
  * Structure to describe a console color
@@ -33,6 +35,18 @@ struct vid_rgb {
 #define CONFIG_CONSOLE_SCROLL_LINES 1
 #endif
 
+#ifdef CONFIG_CONSOLE_TRUETYPE
+int reverse_video_active;
+int collecting = 0;
+char *reverse_video_text = NULL;
+int reverse_video_text_length = 0;
+int reverse_video_text_capacity = 1024;
+
+int console_truetype_fill_rect(struct udevice *dev, int xstart, int ystart, int width, int height, int clr);
+int get_string_dimensions(struct udevice *dev, const char *str, int *width, int *height);
+#endif
+extern int is_direction_key;
+
 int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
 {
        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
@@ -77,10 +91,14 @@ static int vidconsole_back(struct udevice *dev)
        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
        int ret;
 
-       if (ops->backspace) {
-               ret = ops->backspace(dev);
-               if (ret != -ENOSYS)
-                       return ret;
+       if(is_direction_key){
+               is_direction_key = 0;
+       }else {
+               if (ops->backspace) {
+                       ret = ops->backspace(dev);
+                       if (ret != -ENOSYS)
+                               return ret;
+               }
        }
 
        priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
@@ -514,6 +532,7 @@ static int vidconsole_output_glyph(struct udevice *dev, char ch)
 int vidconsole_put_char(struct udevice *dev, char ch)
 {
        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+       struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
        int ret;
 
        if (priv->escape) {
@@ -551,6 +570,11 @@ int vidconsole_put_char(struct udevice *dev, char ch)
                ret = vidconsole_output_glyph(dev, ch);
                if (ret < 0)
                        return ret;
+
+               void *start = vid_priv->fb + priv->ycur * vid_priv->line_length;
+               void *end = start + vid_priv->line_length;
+
+               flush_dcache_range((unsigned long)start, (unsigned long)end);
                break;
        }
 
@@ -559,15 +583,34 @@ int vidconsole_put_char(struct udevice *dev, char ch)
 
 int vidconsole_put_string(struct udevice *dev, const char *str)
 {
+    struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
        const char *s;
        int ret;
+#ifdef CONFIG_CONSOLE_TRUETYPE
+       if (reverse_video_active) {
+               struct udevice *vid = dev->parent;
+               struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+               struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+               int text_width, text_height;
+               /* Calculate the dimensions of the text */
+               get_string_dimensions(dev, reverse_video_text, &text_width, &text_height);
+               /* Draw a background rectangle based on the text dimensions and current position */
+               console_truetype_fill_rect(dev, priv->xcur_frac, priv->ycur, text_width, text_height, vid_priv->colour_bg);
+
+               memset(reverse_video_text, 0, reverse_video_text_capacity);
+               reverse_video_text_length = 0;
+       }
+#endif
 
        for (s = str; *s; s++) {
                ret = vidconsole_put_char(dev, *s);
                if (ret)
                        return ret;
        }
+       void *start = vid_priv->fb;
+       void *end = start + vid_priv->fb_size;
 
+       flush_dcache_range((unsigned long)start, (unsigned long)end);
        return 0;
 }
 
@@ -590,11 +633,94 @@ static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
        }
 }
 
+#ifdef CONFIG_CONSOLE_TRUETYPE
+void clear_screen_colour_bg(struct udevice *dev) {
+       struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+       int xstart = 0, ystart = 0;
+       int width = vid_priv->xsize, height = vid_priv->ysize;
+       int clr = vid_priv->colour_bg;
+
+       for (int row = ystart; row < (ystart + height); ++row) {
+               void *line = vid_priv->fb + row * vid_priv->line_length + VID_TO_PIXEL(xstart) * VNBYTES(vid_priv->bpix);
+
+               switch (vid_priv->bpix) {
+               #ifdef CONFIG_VIDEO_BPP8
+                       case VIDEO_BPP8: {
+                               u8 *dst = (u8 *)line;
+                               for (int col = 0; col < width; ++col) {
+                                       *dst++ = clr;
+                               }
+                               break;
+                       }
+               #endif
+               #ifdef CONFIG_VIDEO_BPP16
+                       case VIDEO_BPP16: {
+                               u16 *dst = (u16 *)line;
+                               for (int col = 0; col < width; ++col) {
+                                       *dst++ = clr;
+                               }
+                               break;
+                       }
+               #endif
+               #ifdef CONFIG_VIDEO_BPP32
+                       case VIDEO_BPP32: {
+                               u32 *dst = (u32 *)line;
+                               for (int col = 0; col < width; ++col) {
+                                       *dst++ = clr;
+                               }
+                               break;
+                       }
+               #endif
+                       default:
+                               break;
+               }
+       }
+
+       /* Ensure the changes are written to the frame buffer */
+       video_sync(dev->parent, false);
+}
+#endif
+
 static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
 {
        struct udevice *dev = sdev->priv;
        int ret;
 
+#ifdef CONFIG_CONSOLE_TRUETYPE
+       const char *temp = s;
+       if (!reverse_video_text) {
+               reverse_video_text = (char *)malloc(reverse_video_text_capacity);
+               reverse_video_text_length = 0;
+               if (!reverse_video_text) {
+                       return;
+               }
+               memset(reverse_video_text, 0, reverse_video_text_capacity);
+       }
+
+       if (strncmp(temp, "\033[1;1H", strlen("\033[1;1H")) == 0){
+               clear_screen_colour_bg(dev);
+       }
+
+       for (; *temp; temp++) {
+               /* Check for the start or end of reverse video sequences */
+               if (!collecting && strncmp(temp, "\033[7m", 4) == 0) {
+                       reverse_video_active = 1;
+                       collecting = 1;
+                       temp += 4;
+                       continue;
+               } else if (strncmp(temp, "\033[0m", 4) == 0) {
+                       reverse_video_active = 0;
+                       collecting = 0;
+                       temp += 4;
+                       continue;
+               }
+
+               if (collecting && reverse_video_text_length < reverse_video_text_capacity - 1) {
+                       reverse_video_text[reverse_video_text_length++] = *temp;
+               }
+       }
+#endif
+
        ret = vidconsole_put_string(dev, s);
        if (ret) {
 #ifdef DEBUG
index 01e8af5ac677a85ef2117e43419dd7e3d83ea7c7..25182c399138051ceab31a0a1ca054a9d63a74df 100644 (file)
@@ -21,6 +21,7 @@
 #include <dm/device_compat.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
+#include <splash.h>
 #ifdef CONFIG_SANDBOX
 #include <asm/sdl.h>
 #endif
@@ -213,6 +214,14 @@ int video_sync(struct udevice *vid, bool force)
                sandbox_sdl_sync(priv->fb);
                last_sync = get_timer(0);
        }
+#elif defined(CONFIG_RISCV) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
+       struct video_priv *priv = dev_get_uclass_priv(vid);
+
+       if (priv->flush_dcache) {
+               ulong flush_dcache_addr = round_down((ulong)priv->fb, CONFIG_RISCV_CBOM_BLOCK_SIZE);
+               ulong flush_length = round_up((ulong)priv->fb + priv->fb_size - flush_dcache_addr, CONFIG_RISCV_CBOM_BLOCK_SIZE);
+               flush_dcache_range(flush_dcache_addr, flush_dcache_addr + flush_length);
+       }
 #endif
        return 0;
 }
@@ -337,7 +346,8 @@ static int show_splash(struct udevice *dev)
        u8 *data = SPLASH_START(u_boot_logo);
        int ret;
 
-       ret = video_bmp_display(dev, map_to_sysmem(data), -4, 4, true);
+       // Set the position of the center of the framebuffer
+       ret = video_bmp_display(dev, map_to_sysmem(data), BMP_ALIGN_CENTER, BMP_ALIGN_CENTER, true);
 
        return 0;
 }
index 238e4c70cf05fe4f02f2b2dd20a12ac020620f8e..e3d3101a76fc9ff50ad1714bbb57ec519817a162 100644 (file)
@@ -244,7 +244,7 @@ config ENV_IS_IN_MMC
 
 config ENV_IS_IN_NAND
        bool "Environment in a NAND device"
-       depends on !CHAIN_OF_TRUST
+       depends on !CHAIN_OF_TRUST && !ENV_IS_IN_SPI_FLASH && !ENV_IS_IN_MTD
        help
          Define this if you have a NAND device which you want to use for the
          environment.
@@ -330,7 +330,7 @@ config ENV_IS_IN_REMOTE
 
 config ENV_IS_IN_SPI_FLASH
        bool "Environment is in SPI flash"
-       depends on !CHAIN_OF_TRUST && SPI
+       depends on !CHAIN_OF_TRUST && SPI && !ENV_IS_IN_MTD
        default y if ARMADA_XP
        default y if INTEL_BAYTRAIL
        default y if INTEL_BRASWELL
@@ -362,6 +362,30 @@ config ENV_IS_IN_SPI_FLASH
          during a "saveenv" operation. CONFIG_ENV_OFFSET_REDUND must be
          aligned to an erase sector boundary.
 
+config ENV_IS_IN_MTD
+       bool "Environment is in MTD"
+       depends on !CHAIN_OF_TRUST && SPI
+       help
+         Define this if you have a MTD device which you
+         want to use for the environment.
+
+         - CONFIG_ENV_OFFSET:
+         - CONFIG_ENV_SIZE:
+
+         These two #defines specify the offset and size of the
+         environment area within the MTD devices. CONFIG_ENV_OFFSET must be
+         aligned to an erase sector boundary.
+
+         Define the MTD devices's sector size.
+
+         - CONFIG_ENV_OFFSET_REDUND (optional):
+
+         This setting describes a second storage area of CONFIG_ENV_SIZE
+         size used to hold a redundant copy of the environment data, so
+         that there is a valid backup copy in case there is a power failure
+         during a "saveenv" operation. CONFIG_ENV_OFFSET_REDUND must be
+         aligned to an erase sector boundary.
+
 config ENV_SECT_SIZE_AUTO
        bool "Use automatically detected sector size"
        depends on ENV_IS_IN_SPI_FLASH
@@ -544,7 +568,7 @@ config ENV_ADDR
 
 config ENV_ADDR_REDUND
        hex "Redundant environment address"
-       depends on ENV_IS_IN_FLASH && SYS_REDUNDAND_ENVIRONMENT
+       depends on ENV_IS_IN_FLASH && ENV_IS_IN_MTD && SYS_REDUNDAND_ENVIRONMENT
        help
          Offset from the start of the device (or partition) of the redundant
          environment location.
@@ -552,7 +576,8 @@ config ENV_ADDR_REDUND
 config ENV_OFFSET
        hex "Environment offset"
        depends on ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \
-                   ENV_IS_IN_SPI_FLASH
+                   ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD
+       default 0x80000 if ENV_IS_IN_MTD
        default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC
        default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH
        default 0xF0000 if ARCH_SUNXI
@@ -569,7 +594,7 @@ config ENV_OFFSET
 config ENV_OFFSET_REDUND
        hex "Redundant environment offset"
        depends on (ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \
-                   ENV_IS_IN_SPI_FLASH) && SYS_REDUNDAND_ENVIRONMENT
+                   ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD) && SYS_REDUNDAND_ENVIRONMENT
        default 0
        help
          Offset from the start of the device (or partition) of the redundant
@@ -577,6 +602,7 @@ config ENV_OFFSET_REDUND
 
 config ENV_SIZE
        hex "Environment Size"
+       default 0x10000 if ENV_IS_IN_MTD
        default 0x40000 if ENV_IS_IN_SPI_FLASH && ARCH_ZYNQMP
        default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
        default 0x10000 if ARCH_SUNXI
@@ -590,7 +616,8 @@ config ENV_SIZE
 
 config ENV_SECT_SIZE
        hex "Environment Sector-Size"
-       depends on ENV_IS_IN_FLASH || ENV_IS_IN_SPI_FLASH
+       depends on ENV_IS_IN_FLASH || ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD
+       default 0x10000 if ENV_IS_IN_MTD
        default 0x2000 if ARCH_ROCKCHIP
        default 0x40000 if ARCH_ZYNQMP || ARCH_VERSAL
        default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
index c4ad65432865ac301b8323407d719869529dfc8a..54674565c2daeb3857bf04c6e845ca82bb7748c7 100644 (file)
@@ -29,5 +29,6 @@ obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_EXT4) += ext4.o
 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_NAND) += nand.o
 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_SPI_FLASH) += sf.o
 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FLASH) += flash.o
+obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_MTD) += mtd.o
 
 CFLAGS_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
index a958c714828315ad069b831a84992d152abe1a9f..b6231e8e110c75c0d08b7518f503e19a9aa98fcd 100644 (file)
@@ -155,7 +155,7 @@ static int regex_callback(const char *name, const char *attributes, void *priv)
                        }
                }
        } else {
-               printf("Error compiling regex: %s\n", slre.err_str);
+               pr_err("Error compiling regex: %s\n", slre.err_str);
                retval = -EINVAL;
        }
 done:
index f9226e0690d0a01f8316e4c6ba8acd50a1f73ebf..395f30430d3657269d71c19ec7084cd2a2b490ea 100644 (file)
@@ -142,8 +142,9 @@ char *from_env(const char *envvar)
 
        ret = env_get(envvar);
 
-       if (!ret)
-               printf("missing environment variable: %s\n", envvar);
+       if (!ret){
+               pr_err("missing environment variable: %s\n", envvar);
+       }
 
        return ret;
 }
@@ -176,7 +177,7 @@ static int env_get_from_linear(const char *env, const char *name, char *buf,
 
                if (len <= res) {
                        buf[len - 1] = '\0';
-                       printf("env_buf [%u bytes] too small for value of \"%s\"\n",
+                       pr_err("env_buf [%u bytes] too small for value of \"%s\"\n",
                               len, name);
                }
 
@@ -257,7 +258,7 @@ void env_set_default(const char *s, int flags)
 {
        if (s) {
                if ((flags & H_INTERACTIVE) == 0) {
-                       printf("*** Warning - %s, "
+                       pr_err("*** Warning - %s, "
                                "using default environment\n\n", s);
                } else {
                        puts(s);
@@ -535,7 +536,7 @@ void env_import_fdt(void)
 
        node = ofnode_path(path);
        if (!ofnode_valid(node)) {
-               printf("Warning: device tree node '%s' not found\n", path);
+               pr_err("Warning: device tree node '%s' not found\n", path);
                return;
        }
 
index 69848fb060807e928990cc600082cb04ff291a18..5a91fba6e5761e4882facff1d700543f6fb6addf 100644 (file)
--- a/env/env.c
+++ b/env/env.c
@@ -54,6 +54,9 @@ static struct env_driver *_env_driver_lookup(enum env_location loc)
 }
 
 static enum env_location env_locations[] = {
+#ifdef CONFIG_ENV_IS_IN_NVRAM
+       ENVL_NVRAM,
+#endif
 #ifdef CONFIG_ENV_IS_IN_EEPROM
        ENVL_EEPROM,
 #endif
@@ -72,9 +75,7 @@ static enum env_location env_locations[] = {
 #ifdef CONFIG_ENV_IS_IN_NAND
        ENVL_NAND,
 #endif
-#ifdef CONFIG_ENV_IS_IN_NVRAM
-       ENVL_NVRAM,
-#endif
+
 #ifdef CONFIG_ENV_IS_IN_REMOTE
        ENVL_REMOTE,
 #endif
@@ -201,7 +202,7 @@ int env_load(void)
                if (!env_has_inited(drv->location))
                        continue;
 
-               printf("Loading Environment from %s... ", drv->name);
+               pr_info("Loading Environment from %s... ", drv->name);
                /*
                 * In error case, the error message must be printed during
                 * drv->load() in some underlying API, and it must be exactly
@@ -209,7 +210,7 @@ int env_load(void)
                 */
                ret = drv->load();
                if (!ret) {
-                       printf("OK\n");
+                       pr_info("OK\n");
                        gd->env_load_prio = prio;
 
 #if !CONFIG_IS_ENABLED(ENV_APPEND)
@@ -251,18 +252,19 @@ int env_reload(void)
        if (drv) {
                int ret;
 
-               printf("Loading Environment from %s... ", drv->name);
+               pr_info("Loading Environment from %s... ", drv->name);
 
                if (!env_has_inited(drv->location)) {
-                       printf("not initialized\n");
+                       pr_info("not initialized\n");
                        return -ENODEV;
                }
 
                ret = drv->load();
-               if (ret)
-                       printf("Failed (%d)\n", ret);
-               else
-                       printf("OK\n");
+               if (ret){
+                       pr_err("Failed (%d)\n", ret);
+               }else{
+                       pr_info("OK\n");
+               }
 
                if (!ret)
                        return 0;
@@ -279,22 +281,23 @@ int env_save(void)
        if (drv) {
                int ret;
 
-               printf("Saving Environment to %s... ", drv->name);
+               pr_info("Saving Environment to %s... ", drv->name);
                if (!drv->save) {
-                       printf("not possible\n");
+                       pr_err("not possible\n");
                        return -ENODEV;
                }
 
                if (!env_has_inited(drv->location)) {
-                       printf("not initialized\n");
+                       pr_err("not initialized\n");
                        return -ENODEV;
                }
 
                ret = drv->save();
-               if (ret)
-                       printf("Failed (%d)\n", ret);
-               else
-                       printf("OK\n");
+               if (ret){
+                       pr_err("Failed (%d)\n", ret);
+               }else{
+                       pr_info("OK\n");
+               }
 
                if (!ret)
                        return 0;
@@ -317,12 +320,13 @@ int env_erase(void)
                if (!env_has_inited(drv->location))
                        return -ENODEV;
 
-               printf("Erasing Environment on %s... ", drv->name);
+               pr_info("Erasing Environment on %s... ", drv->name);
                ret = drv->erase();
-               if (ret)
-                       printf("Failed (%d)\n", ret);
-               else
-                       printf("OK\n");
+               if (ret){
+                       pr_err("Failed (%d)\n", ret);
+               }else{
+                       pr_info("OK\n");
+               }       
 
                if (!ret)
                        return 0;
@@ -371,7 +375,7 @@ int env_select(const char *name)
        int prio;
        bool found = false;
 
-       printf("Select Environment on %s: ", name);
+       pr_info("Select Environment on %s: ", name);
 
        /* search ENV driver by name */
        drv = ll_entry_start(struct env_driver, env_driver);
@@ -383,7 +387,7 @@ int env_select(const char *name)
        }
 
        if (!found) {
-               printf("driver not found\n");
+               pr_info("driver not found\n");
                return -ENODEV;
        }
 
@@ -396,11 +400,11 @@ int env_select(const char *name)
                                gd->env_valid = ENV_INVALID;
                                gd->flags &= ~GD_FLG_ENV_DEFAULT;
                        }
-                       printf("OK\n");
+                       pr_info("OK\n");
                        return 0;
                }
        }
-       printf("priority not found\n");
+       pr_info("priority not found\n");
 
        return -ENODEV;
 }
index e3e833c4333c440f7ff72fcf6d0c0ee15834edc3..7c29ddf1598a54883d7e98c4af14ea2bb0bc6daa 100644 (file)
@@ -80,7 +80,7 @@ void env_flags_print_vartypes(void)
        enum env_flags_vartype curtype = (enum env_flags_vartype)0;
 
        while (curtype != env_flags_vartype_end) {
-               printf("\t%c   -\t%s\n", env_flags_vartype_rep[curtype],
+               pr_info("\t%c   -\t%s\n", env_flags_vartype_rep[curtype],
                        env_flags_vartype_names[curtype]);
                curtype++;
        }
@@ -94,7 +94,7 @@ void env_flags_print_varaccess(void)
        enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
 
        while (curaccess != env_flags_varaccess_end) {
-               printf("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess],
+               pr_info("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess],
                        env_flags_varaccess_names[curaccess]);
                curaccess++;
        }
@@ -134,7 +134,7 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags)
                return (enum env_flags_vartype)
                        (type - &env_flags_vartype_rep[0]);
 
-       printf("## Warning: Unknown environment variable type '%c'\n",
+       pr_info("## Warning: Unknown environment variable type '%c'\n",
                flags[ENV_FLAGS_VARTYPE_LOC]);
        return env_flags_vartype_string;
 }
@@ -160,7 +160,7 @@ enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
                return va;
        }
 
-       printf("## Warning: Unknown environment variable access method '%c'\n",
+       pr_info("## Warning: Unknown environment variable access method '%c'\n",
                flags[ENV_FLAGS_VARACCESS_LOC]);
        return va_default;
 }
@@ -181,7 +181,7 @@ enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
                        return va;
        }
 
-       printf("Warning: Non-standard access flags. (0x%x)\n",
+       pr_info("Warning: Non-standard access flags. (0x%x)\n",
                binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
 
        return va_default;
@@ -372,7 +372,7 @@ int env_flags_validate_type(const char *name, const char *value)
                return 0;
        type = env_flags_get_type(name);
        if (_env_flags_validate_type(value, type) < 0) {
-               printf("## Error: flags type check failure for "
+               pr_info("## Error: flags type check failure for "
                        "\"%s\" <= \"%s\" (type: %c)\n",
                        name, value, env_flags_vartype_rep[type]);
                return -1;
@@ -408,7 +408,7 @@ int env_flags_validate_env_set_params(char *name, char * const val[], int count)
                 * one argument
                 */
                if (type != env_flags_vartype_string && count > 1) {
-                       printf("## Error: too many parameters for setting \"%s\"\n",
+                       pr_info("## Error: too many parameters for setting \"%s\"\n",
                               name);
                        return -1;
                }
@@ -542,7 +542,7 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
                        (ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
 
                if (_env_flags_validate_type(newval, type) < 0) {
-                       printf("## Error: flags type check failure for "
+                       pr_info("## Error: flags type check failure for "
                                "\"%s\" <= \"%s\" (type: %c)\n",
                                name, newval, env_flags_vartype_rep[type]);
                        return -1;
@@ -565,7 +565,7 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
 
        if (flag & H_FORCE) {
 #ifdef CONFIG_ENV_ACCESS_IGNORE_FORCE
-               printf("## Error: Can't force access to \"%s\"\n", name);
+               pr_info("## Error: Can't force access to \"%s\"\n", name);
 #else
                return 0;
 #endif
@@ -573,13 +573,13 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
        switch (op) {
        case env_op_delete:
                if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
-                       printf("## Error: Can't delete \"%s\"\n", name);
+                       pr_err("## Error: Can't delete \"%s\"\n", name);
                        return 1;
                }
                break;
        case env_op_overwrite:
                if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
-                       printf("## Error: Can't overwrite \"%s\"\n", name);
+                       pr_info("## Error: Can't overwrite \"%s\"\n", name);
                        return 1;
                } else if (item->flags &
                    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
@@ -587,9 +587,9 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
 
                        if (defval == NULL)
                                defval = "";
-                       printf("oldval: %s  defval: %s\n", oldval, defval);
+                       pr_info("oldval: %s  defval: %s\n", oldval, defval);
                        if (strcmp(oldval, defval) != 0) {
-                               printf("## Error: Can't overwrite \"%s\"\n",
+                               pr_err("## Error: Can't overwrite \"%s\"\n",
                                        name);
                                return 1;
                        }
@@ -597,7 +597,7 @@ int env_flags_validate(const struct env_entry *item, const char *newval,
                break;
        case env_op_create:
                if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
-                       printf("## Error: Can't create \"%s\"\n", name);
+                       pr_err("## Error: Can't create \"%s\"\n", name);
                        return 1;
                }
                break;
index 0c498d9a46b51b9661327a5c9cef1b61a006ae4d..85cfd5038c3bf9e1462379eb27ed5ef0c8af95ff 100644 (file)
--- a/env/mmc.c
+++ b/env/mmc.c
@@ -209,7 +209,7 @@ static int env_mmc_save(void)
 
        errmsg = init_mmc_for_env(mmc);
        if (errmsg) {
-               printf("%s\n", errmsg);
+               pr_info("%s\n", errmsg);
                return 1;
        }
 
@@ -234,7 +234,7 @@ static int env_mmc_save(void)
                goto fini;
        }
 
-       printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
+       pr_info("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
        if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
                puts("failed\n");
                ret = 1;
@@ -264,7 +264,7 @@ static inline int erase_env(struct mmc *mmc, unsigned long size,
        blk_cnt = ALIGN(size, erase_size) / desc->blksz;
 
        n = blk_derase(desc, blk_start, blk_cnt);
-       printf("%d blocks erased at 0x%x: %s\n", n, blk_start,
+       pr_info("%d blocks erased at 0x%x: %s\n", n, blk_start,
               (n == blk_cnt) ? "OK" : "ERROR");
 
        return (n == blk_cnt) ? 0 : 1;
@@ -280,7 +280,7 @@ static int env_mmc_erase(void)
 
        errmsg = init_mmc_for_env(mmc);
        if (errmsg) {
-               printf("%s\n", errmsg);
+               pr_info("%s\n", errmsg);
                return 1;
        }
 
@@ -289,7 +289,7 @@ static int env_mmc_erase(void)
                goto fini;
        }
 
-       printf("\n");
+       pr_info("\n");
        ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
 
 #ifdef CONFIG_ENV_OFFSET_REDUND
@@ -398,6 +398,11 @@ static int env_mmc_load(void)
        int dev = mmc_get_env_dev();
        const char *errmsg;
        env_t *ep = NULL;
+#if CONFIG_IS_ENABLED(DM_MMC)
+       ret = mmc_init_device(dev);
+#else
+       ret = mmc_initialize(NULL);
+#endif /* DM_MMC */
 
        mmc = find_mmc_device(dev);
 
diff --git a/env/mtd.c b/env/mtd.c
new file mode 100644 (file)
index 0000000..408fbb4
--- /dev/null
+++ b/env/mtd.c
@@ -0,0 +1,226 @@
+#include <common.h>
+#include <env.h>
+#include <env_internal.h>
+#include <linux/mtd/mtd.h>
+#include <jffs2/load_kernel.h>
+#include <mtd.h>
+#include <dm.h>
+#include <env.h>
+#include <env_internal.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <search.h>
+#include <errno.h>
+#include <uuid.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <dm/device-internal.h>
+#include <u-boot/crc.h>
+#include <config.h>
+
+static struct udevice *env_mtd_dev = NULL;
+
+static int env_mtd_init(void) {
+       if (!env_mtd_dev) {
+               if (uclass_get_device(UCLASS_MTD, 0, &env_mtd_dev)) {
+                       return -ENODEV;
+               }
+       }
+       return 0;
+}
+
+static struct udevice *find_mtd_device(void) {
+       struct udevice *dev;
+       if (uclass_get_device(UCLASS_MTD, 0, &dev)) {
+               printf("Cannot find any MTD device\n");
+               return NULL;
+       }
+       return dev;
+}
+
+static int env_mtd_erase(void) {
+       struct udevice *dev = find_mtd_device();
+       if (!dev) {
+               printf("Failed to initialize MTD device\n");
+               return -ENODEV;
+       }
+
+       struct mtd_info *mtd = dev_get_uclass_priv(dev);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+       loff_t offset = (gd->env_valid == ENV_VALID) ? CONFIG_ENV_OFFSET_REDUND : CONFIG_ENV_OFFSET;
+#else
+       loff_t offset = CONFIG_ENV_OFFSET;
+#endif
+
+       struct erase_info erase_opts = {
+               .addr = offset,
+               .len = CONFIG_ENV_SIZE,
+       };
+
+       if (mtd_erase(mtd, &erase_opts)) {
+               return -EIO;
+       }
+       return 0;
+}
+#if defined(CONFIG_ENV_OFFSET_REDUND)
+
+static int env_mtd_load(void) {
+       struct udevice *dev = find_mtd_device();
+       if (!dev) {
+               printf("MTD device not initialized\n");
+               return -ENODEV;
+       }
+
+       struct mtd_info *mtd = dev_get_uclass_priv(dev);
+       size_t retlen;
+       char *buf1 = malloc(CONFIG_ENV_SIZE);
+       char *buf2 = malloc(CONFIG_ENV_SIZE);
+       if (!buf1 || !buf2) {
+               free(buf1);
+               free(buf2);
+               return -ENOMEM;
+       }
+
+       int read1_fail = mtd_read(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, &retlen, buf1);
+       int read2_fail = mtd_read(mtd, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, &retlen, buf2);
+
+       int ret = env_import_redund(buf1, read1_fail, buf2, read2_fail, H_EXTERNAL);
+       if (ret == 0) {
+               gd->env_valid = (read1_fail == 0) ? ENV_VALID : ENV_REDUND;
+               printf("Loaded environment from %s MTD location\n", 
+                          (gd->env_valid == ENV_VALID) ? "primary" : "redundant");
+       } else {
+               printf("Failed to load environment from MTD device\n");
+               gd->env_valid = ENV_INVALID;
+       }
+
+       free(buf1);
+       free(buf2);
+       return (gd->env_valid == ENV_INVALID) ? -EIO : 0;
+}
+
+static int env_mtd_save(void) {
+       struct udevice *dev = find_mtd_device();
+       if (!dev) {
+               printf("MTD device not initialized\n");
+               return -ENODEV;
+       }
+
+       struct mtd_info *mtd = dev_get_uclass_priv(dev);
+       env_t env_new;
+       char *buf = env_new.data;
+
+       int ret = env_export(&env_new);
+       if (ret)
+               return -EIO;
+
+       env_new.flags = ENV_REDUND_ACTIVE;
+       loff_t env_new_offset, env_offset;
+
+       if (gd->env_valid == ENV_VALID) {
+               env_new_offset = CONFIG_ENV_OFFSET_REDUND;
+               env_offset = CONFIG_ENV_OFFSET;
+       } else {
+               env_new_offset = CONFIG_ENV_OFFSET;
+               env_offset = CONFIG_ENV_OFFSET_REDUND;
+       }
+
+       size_t retlen;
+
+       ret = env_mtd_erase();
+       if (ret) {
+               printf("Failed to erase new environment location on MTD device\n");
+               return -EIO;
+       }
+
+       ret = mtd_write(mtd, env_new_offset, CONFIG_ENV_SIZE, &retlen, buf);
+       if (ret) {
+               printf("Failed to write new environment to MTD device\n");
+               return -EIO;
+       }
+
+       char flag = ENV_REDUND_OBSOLETE;
+       ret = mtd_write(mtd, env_offset + offsetof(env_t, flags), sizeof(env_new.flags), &retlen, &flag);
+       if (ret) {
+               printf("Failed to mark old environment as obsolete\n");
+               return -EIO;
+       }
+
+       printf("Environment successfully saved to MTD device\n");
+       gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
+       return 0;
+}
+
+#else
+
+static int env_mtd_load(void) {
+       struct udevice *dev = find_mtd_device();
+       if (!dev) {
+               printf("MTD device not initialized\n");
+               return -ENODEV;
+       }
+
+       struct mtd_info *mtd = dev_get_uclass_priv(dev);
+       size_t retlen;
+       char *buf = malloc(CONFIG_ENV_SIZE);
+       if (!buf) {
+               return -ENOMEM;
+       }
+
+       int ret = mtd_read(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, &retlen, buf);
+       if (ret) {
+               printf("Failed to read environment from MTD device\n");
+               free(buf);
+               return -EIO;
+       }
+
+       env_import(buf, 1, H_EXTERNAL);
+       free(buf);
+       return 0;
+}
+
+static int env_mtd_save(void) {
+       struct udevice *dev = find_mtd_device();
+       if (!dev) {
+               printf("MTD device not initialized\n");
+               return -ENODEV;
+       }
+
+       struct mtd_info *mtd = dev_get_uclass_priv(dev);
+       env_t env_new;
+       char *buf = env_new.data;
+
+       int ret = env_export(&env_new);
+       if (ret)
+               return -EIO;
+
+       ret = env_mtd_erase();
+       if (ret) {
+               printf("Failed to erase environment on MTD device\n");
+               return -EIO;
+       }
+
+       size_t retlen;
+       ret = mtd_write(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, &retlen, buf);
+       if (ret) {
+               printf("Failed to write environment to MTD device\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+#endif
+
+U_BOOT_ENV_LOCATION(mtd) = {
+       .location = ENVL_MTD,
+       ENV_NAME("mtdENV")
+       .load     = env_mtd_load,
+       .save     = ENV_SAVE_PTR(env_mtd_save),
+       .erase    = ENV_ERASE_PTR(env_mtd_erase),
+       .init     = env_mtd_init,
+};
+
+
index a425ecc11c8e6c27606e7f684b6dd641f4abb934..3c2fdc3c34d798f22541ac90ccedff40ef087a29 100644 (file)
--- a/env/sf.c
+++ b/env/sf.c
@@ -141,7 +141,7 @@ static int env_sf_save(void)
 
        gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
 
-       printf("Valid environment: %d\n", (int)gd->env_valid);
+       pr_err("Valid environment: %d\n", (int)gd->env_valid);
 
 done:
        spi_flash_free(env_flash);
index 0e79c340906258d6ceb042c19f08b98c278e1b77..ef7f5c0d6e99bf69998ed17975b3769f5ce35347 100644 (file)
@@ -17,3 +17,25 @@ config JFFS2_NAND
        depends on FS_JFFS2
        help
          Enable support for NAND flash as the backing store for JFFS2.
+
+config JFFS2_NOR
+       bool "Enable JFFS2 support for NOR flash"
+       depends on FS_JFFS2
+       help
+         Enable support for NOR flash as the backing store for JFFS2.
+
+choice
+       prompt "Method for reading from NOR flash"
+       depends on JFFS2_NOR
+
+config JFFS2_USE_MEMMAP_READ
+       bool "Use memcopy for reading from NOR flash"
+       help
+         Use the memcopy function to read data from NOR flash.
+
+config JFFS2_USE_MTD_READ
+       bool "Use mtd.read for reading from NOR flash"
+       help
+         Use the mtd.read function to read data from NOR flash.
+
+endchoice
index ef7b302725cad76fde3c81d2967eadfdc32cea78..87770a26955ab6a45fec8b75bf03208620f10d13 100644 (file)
@@ -388,6 +388,8 @@ static void put_fl_mem_onenand(void *buf)
  * NOR flash memory is mapped in processor's address space,
  * just return address.
  */
+#ifdef CONFIG_JFFS2_USE_MEMMAP_READ
+
 static inline void *get_fl_mem_nor(u32 off, u32 size, void *ext_buf)
 {
        u32 addr = off;
@@ -415,6 +417,121 @@ static inline void *get_node_mem_nor(u32 off, void *ext_buf)
 }
 #endif
 
+#ifdef CONFIG_JFFS2_USE_MTD_READ
+#include <dm.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include "stat.h"
+
+void put_fl_mem_nor(void *buf)
+{
+       free(buf);
+}
+
+struct mtd_info *get_spi_flash(void)
+{
+       struct udevice *dev = NULL;
+       int ret;
+
+       ret = uclass_first_device(UCLASS_SPI_FLASH, &dev);
+       if (ret || !dev) {
+               pr_err("Failed to get the first SPI NOR device\n");
+               return NULL;
+       }
+
+       struct spi_flash *flash = dev_get_uclass_priv(dev);
+       if (!flash) {
+               pr_err("Found device but failed to get SPI flash data structure\n");
+               return NULL;
+       }
+
+       pr_info("Using the first SPI NOR device: %s\n", dev->name);
+       return &flash->mtd;
+}
+
+static int nor_read(struct mtd_info *mtd, u32 offset, size_t len, void *buf)
+{
+       size_t retlen;
+       int ret;
+
+       ret = mtd_read(mtd, offset, len, &retlen, buf);
+
+       if (ret < 0) {
+               pr_err("Error: mtd_read returned %d\n", ret);
+               return ret;
+       }
+
+       if (retlen != len) {
+               pr_err("Warning: Requested length %zu but got %zu\n", len, retlen);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static inline void *get_fl_mem_nor(u32 off, u32 size, void *ext_buf)
+{
+       static struct mtd_info *cached_mtd = NULL;
+       void *buf = ext_buf;
+
+       if (!buf) {
+               buf = malloc(size);
+               if (!buf) {
+                       pr_err("Failed to allocate memory\n");
+                       return NULL;
+               }
+       }
+
+       if (!cached_mtd) {
+               cached_mtd = get_spi_flash();
+               if (!cached_mtd) {
+                       pr_err("Failed to get SPI NOR device\n");
+                       if (!ext_buf) {
+                               free(buf);
+                       }
+                       return NULL;
+               }
+       }
+
+       if (nor_read(cached_mtd, off, size, buf)) {
+               pr_err("SPI NOR read failed\n");
+               if (!ext_buf) {
+                       free(buf);
+               }
+               return NULL;
+       }
+
+       return buf;
+}
+
+static inline void *get_node_mem_nor(u32 off, void *ext_buf)
+{
+       struct jffs2_unknown_node *pNode;
+
+       pNode = get_fl_mem_nor(off, sizeof(*pNode), NULL);
+       if (!pNode) {
+               pr_err("Failed to read node at offset=%u\n", off);
+               return NULL;
+       }
+
+       if (pNode->magic == JFFS2_MAGIC_BITMASK) {
+               if (!ext_buf) {
+                       free(pNode);
+               }
+               return get_fl_mem_nor(off, pNode->totlen, ext_buf);
+       }
+
+       if (ext_buf) {
+               memcpy(ext_buf, pNode, sizeof(*pNode));
+               free(pNode);
+               return ext_buf;
+       }
+
+       return pNode;
+}
+#endif
+
+#endif
 
 /*
  * Generic jffs2 raw memory and node read routines.
@@ -444,7 +561,7 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
                printf("get_fl_mem: unknown device type, " \
                        "using raw offset!\n");
        }
-       return (void*)off;
+       return (void*)(uintptr_t)off;
 }
 
 static inline void *get_node_mem(u32 off, void *ext_buf)
@@ -472,7 +589,7 @@ static inline void *get_node_mem(u32 off, void *ext_buf)
                printf("get_fl_mem: unknown device type, " \
                        "using raw offset!\n");
        }
-       return (void*)off;
+       return (void*)(uintptr_t)off;
 }
 
 static inline void put_fl_mem(void *buf, void *ext_buf)
@@ -492,6 +609,12 @@ static inline void put_fl_mem(void *buf, void *ext_buf)
        case MTD_DEV_TYPE_ONENAND:
                return put_fl_mem_onenand(buf);
 #endif
+#if defined(CONFIG_JFFS2_NOR) && defined(CONFIG_JFFS2_USE_MTD_READ)
+       case MTD_DEV_TYPE_NOR:
+               return put_fl_mem_nor(buf);
+#endif
+       default:
+               printf("Unknown device type: %d\n", id->type);
        }
 }
 
@@ -752,6 +875,10 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                                put_fl_mem(jNode, pL->readbuf);
                                jNode = (struct jffs2_raw_inode *)
                                        get_node_mem(b->offset, pL->readbuf);
+                               if (!jNode) {
+                                       pr_err("Error: Failed to get jNode at offset=%u\n", b->offset);
+                                       return -1;
+                               }
                                src = ((uchar *)jNode) +
                                        sizeof(struct jffs2_raw_inode);
                                /* ignore data behind latest known EOF */
index 65d19a76f97cc86afc0d90dad4b1479974adab33..5a6f0fb608a2822868966ad81055a91655feecb3 100644 (file)
@@ -95,7 +95,7 @@ static inline int
 data_crc(struct jffs2_raw_inode *node)
 {
        if (node->data_crc != crc32_no_comp(0, (unsigned char *)
-                                           ((int) &node->node_crc + sizeof (node->node_crc)),
+                                           ((uintptr_t) &node->node_crc + sizeof (node->node_crc)),
                                             node->csize)) {
                return 0;
        } else {
diff --git a/fs/jffs2/stat.h b/fs/jffs2/stat.h
new file mode 100644 (file)
index 0000000..236406f
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _STAT_H
+#define _STAT_H
+
+#include <linux/types.h>
+typedef long blksize_t;
+
+struct stat {
+       dev_t   st_dev;      /* device ID of device containing file */
+       ino_t   st_ino;      /* inode number */
+       mode_t  st_mode;     /* protection */
+       nlink_t st_nlink;    /* number of hard links */
+       uid_t   st_uid;      /* user ID of owner */
+       gid_t   st_gid;      /* group ID of owner */
+       dev_t   st_rdev;     /* device ID (if special file) */
+       off_t   st_size;     /* total size, in bytes */
+       blksize_t st_blksize;  /* blocksize for file system I/O */
+       blkcnt_t        st_blocks;   /* number of 512B blocks allocated */
+       time_t  st_atime;    /* time of last access */
+       time_t  st_mtime;    /* time of last modification */
+       time_t  st_ctime;    /* time of last status change */
+};
+
+/* Function prototype for the stat function */
+int stat(const char *pathname, struct stat *statbuf);
+
+#endif /* _STAT_H */
index 2a747d91e16f4ab2ea55e5ac8156f06bafb748ff..caf2ae470d2f5ce85226fd51c77af39f15133460 100644 (file)
@@ -32,6 +32,13 @@ struct driver_rt;
 
 typedef struct global_data gd_t;
 
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+typedef struct {
+       char *buffer;
+       char *write_ptr;
+       char *read_ptr;
+} console_log_t;
+#endif
 /**
  * struct global_data - global data structure
  */
@@ -276,7 +283,7 @@ struct global_data {
        /**
         * @env_buf: buffer for env_get() before reloc
         */
-       char env_buf[32];
+       char env_buf[128];
 #ifdef CONFIG_TRACE
        /**
         * @trace_buff: trace buffer
@@ -482,6 +489,11 @@ struct global_data {
         * @dmtag_list: List of DM tags
         */
        struct list_head dmtag_list;
+
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+       console_log_t console_log;
+#endif
+
 };
 #ifndef DO_DEPS_ONLY
 static_assert(sizeof(struct global_data) == GD_SIZE);
index 9503369db8397042d1e59ec359da60ceb4537b87..cf886ad2782ee540291f74b0036a400ab614689b 100644 (file)
@@ -38,6 +38,7 @@ enum if_type {
        IF_TYPE_PVBLOCK,
        IF_TYPE_VIRTIO,
        IF_TYPE_EFI_MEDIA,
+       IF_TYPE_NOR,
 
        IF_TYPE_COUNT,                  /* Number of interface types */
 };
@@ -49,6 +50,10 @@ enum if_type {
 #define PART_FORMAT_PCAT       0x1
 #define PART_FORMAT_GPT                0x2
 
+#ifdef CONFIG_SPINOR_BLOCK_SUPPORT
+#define SPI_NOR_BLOCK_SIZE 512
+#endif /* CONFIG_SPINOR_BLOCK_SUPPORT */
+
 /*
  * Identifies the partition table type (ie. MBR vs GPT GUID) signature
  */
diff --git a/include/cJSON.h b/include/cJSON.h
new file mode 100644 (file)
index 0000000..592986b
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention.  For windows you have 3 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
+CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
+
+For *nix builds that support visibility attribute, you can define similar behavior by
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+*/
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+/* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type)   type CJSON_STDCALL
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type)   __declspec(dllexport) type CJSON_STDCALL
+#elif defined(CJSON_IMPORT_SYMBOLS)
+#define CJSON_PUBLIC(type)   __declspec(dllimport) type CJSON_STDCALL
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type)   __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+/* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 12
+
+#include <stddef.h>
+
+/* cJSON Types: */
+#define cJSON_Invalid (0)
+#define cJSON_False  (1 << 0)
+#define cJSON_True   (1 << 1)
+#define cJSON_NULL   (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array  (1 << 5)
+#define cJSON_Object (1 << 6)
+#define cJSON_Raw    (1 << 7) /* raw json */
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON
+{
+    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+    struct cJSON *next;
+    struct cJSON *prev;
+    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+    struct cJSON *child;
+
+    /* The type of the item, as above. */
+    int type;
+
+    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
+    char *valuestring;
+    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
+    int valueint;
+    /* The item's number, if type==cJSON_Number */
+    double valuedouble;
+
+    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+    char *string;
+} cJSON;
+
+typedef struct cJSON_Hooks
+{
+      /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
+      void *(CJSON_CDECL *malloc_fn)(size_t sz);
+      void (CJSON_CDECL *free_fn)(void *ptr);
+} cJSON_Hooks;
+
+typedef int cJSON_bool;
+
+/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
+ * This is to prevent stack overflows. */
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
+/* returns the version of cJSON as a string */
+CJSON_PUBLIC(const char*) cJSON_Version(void);
+
+/* Supply malloc, realloc and free functions to cJSON */
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
+
+/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
+
+/* Render a cJSON entity to text for transfer/storage. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. */
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
+/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
+/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
+/* Delete a cJSON entity and all subentities. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
+/* Get item "string" from object. Case insensitive. */
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
+
+/* Check if the item is a string and return its valuestring */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
+
+/* These functions check the type of an item */
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
+
+/* These calls create a cJSON item of the appropriate type. */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
+/* raw json */
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
+
+/* Create a string where valuestring references a string so
+ * it will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
+/* Create an object/arrray that only references it's elements so
+ * they will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
+
+/* These utilities create an Array of count items. */
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
+
+/* Append item to the specified array/object. */
+CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
+ * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
+ * writing to `item->string` */
+CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
+
+/* Update array items. */
+CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
+CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
+ * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
+
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json);
+
+/* Helper functions for creating and adding items to an object at the same time.
+ * They return the added item or NULL on failure. */
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
+/* helper for the cJSON_SetNumberValue macro */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
+#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
+
+/* Macro for iterating over an array or object */
+#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
+
+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
+CJSON_PUBLIC(void) cJSON_free(void *object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 76bb64bb5ee0ffd64d050806c45b1e0f064c2986..c3b965ae0a5e42a0e9cabc79375ece1dbdd7f336 100644 (file)
@@ -166,7 +166,7 @@ int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk);
  * clk_get_by_name() - Get/request a clock by name.
  * @dev:       The client device.
  * @name:      The name of the clock to request, within the client's list of
- *             clocks.
+ *             clocks, or NULL to request the first clock in the list.
  * @clk:       A pointer to a clock struct to initialize.
  *
  * This looks up and requests a clock. The name is relative to the client
@@ -183,7 +183,7 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
  * clk_get_by_name_nodev - Get/request a clock by name without a device.
  * @node:      The client ofnode.
  * @name:      The name of the clock to request, within the client's list of
- *             clocks.
+ *             clocks, or NULL to request the first clock in the list.
  * @clk:       A pointer to a clock struct to initialize.
  *
  * Return: 0 if OK, or a negative error code.
@@ -444,7 +444,7 @@ struct clk *clk_get_parent(struct clk *clk);
  *
  * Return: clock rate in Hz, or -ve error code.
  */
-long long clk_get_parent_rate(struct clk *clk);
+ulong clk_get_parent_rate(struct clk *clk);
 
 /**
  * clk_round_rate() - Adjust a rate to the exact rate a clock can provide
@@ -577,7 +577,7 @@ static inline struct clk *clk_get_parent(struct clk *clk)
        return ERR_PTR(-ENOSYS);
 }
 
-static inline long long clk_get_parent_rate(struct clk *clk)
+static inline ulong clk_get_parent_rate(struct clk *clk)
 {
        return -ENOSYS;
 }
index 966fd23c639fb028e9d1c40e3fd7e5d3933e29e3..b129746a9d74639cbaae42ca8dad41648f7fe4a6 100644 (file)
@@ -279,6 +279,12 @@ int run_commandf(const char *fmt, ...);
  * Return: 0 on success, or != 0 on error.
  */
 int run_command_list(const char *cmd, int len, int flag);
+
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+#define LOG_BUFFER_SIZE 20480
+#endif
+
+
 #endif /* __ASSEMBLY__ */
 
 /*
diff --git a/include/configs/k1-x.h b/include/configs/k1-x.h
new file mode 100644 (file)
index 0000000..82b921a
--- /dev/null
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023, Spacemit
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <linux/sizes.h>
+
+#define SYS_DRAM_OFFS          0x00000000
+#define SZ_1MB                 0x00100000
+#define SZ_2GB                 0x80000000
+#define SZ_4GB                 0x100000000ULL
+#define SZ_8GB                 0x200000000ULL
+#define SEC_IMG_SIZE           0x0000000
+#define CONFIG_SYS_SDRAM_BASE  (SYS_DRAM_OFFS + SEC_IMG_SIZE)
+
+#define RISCV_MMODE_TIMERBASE  0xE4000000
+#define RISCV_MMODE_TIMER_FREQ 24000000
+#define RISCV_SMODE_TIMER_FREQ 24000000
+
+#define CONFIG_IPADDR          10.0.92.253
+#define CONFIG_SERVERIP                10.0.92.134
+#define CONFIG_GATEWAYIP       10.0.92.1
+#define CONFIG_NETMASK         255.255.255.0
+
+#define DEFAULT_PRODUCT_NAME   "k1-x_deb1"
+
+#define K1X_SPL_BOOT_LOAD_ADDR (0x20200000)
+#define DDR_TRAINING_DATA_BASE (0xc0832000)
+
+// sram buffer address that save the DDR software training result
+#define DDR_TRAINING_INFO_BUFF (0xC0800000)
+#define DDR_TRAINING_INFO_SAVE_ADDR    (0)
+// magic string: "DDRT"
+#define DDR_TRAINING_INFO_MAGIC        (0x54524444)
+// ddr training software version: xx.xx.xxxx
+#define DDR_TRAINING_INFO_VER  (0x00010000)
+// default ddr channel number
+#define DDR_CS_NUM     (1)
+
+/*
+ use (ram_base+4MB offset) as the address to loading image.
+ use ram_size-32MB as the max size to loading image, if
+ (ram_size-32MB) more than 500MB, set load image size as
+ 500MB.
+*/
+#define RECOVERY_RAM_SIZE (gd->ram_size - 0x2000000)
+#define RECOVERY_LOAD_IMG_SIZE_MAX (RECOVERY_RAM_SIZE > 0x1f400000 ? 0x1f400000 : RECOVERY_RAM_SIZE)
+#define RECOVERY_LOAD_IMG_ADDR (gd->ram_base + 0x400000)
+#define RECOVERY_LOAD_IMG_SIZE (RECOVERY_LOAD_IMG_SIZE_MAX)
+
+/* boot mode configs */
+#define BOOT_DEV_FLAG_REG      (0xD4282D10)
+#define BOOT_PIN_SELECT                (0xD4282c20)
+
+#define BOOT_STRAP_BIT_OFFSET  (9)
+#define BOOT_STRAP_BIT_STORAGE_MASK (0x3 << BOOT_STRAP_BIT_OFFSET)
+#define BOOT_STRAP_BIT_EMMC    (0x0)
+#define BOOT_STRAP_BIT_NOR     (0x1)
+#define BOOT_STRAP_BIT_NAND    (0x2)
+#define BOOT_STRAP_BIT_SD      (0x3)
+
+/*use CIU register to save boot flag*/
+#define BOOT_CIU_REG           (0xD4282C00)
+#define BOOT_CIU_DEBUG_REG0    (BOOT_CIU_REG + 0x0390)
+#define BOOT_CIU_DEBUG_REG1    (BOOT_CIU_REG + 0x0394)
+#define BOOT_CIU_DEBUG_REG2    (BOOT_CIU_REG + 0x0398)
+
+#define K1_EFUSE_USER_BANK0            8
+#define K1_DEFALT_PMIC_TYPE            0
+#define K1_DEFALT_EEPROM_I2C_INDEX     2
+#define K1_DEFALT_EEPROM_PIN_GROUP     0
+
+#define TLV_CODE_SDK_VERSION           0x40
+#define TLV_CODE_DDR_CSNUM             0x41
+
+#define TLV_CODE_PMIC_TYPE             0x80
+#define TLV_CODE_EEPROM_I2C_INDEX      0x81
+#define TLV_CODE_EEPROM_PIN_GROUP      0x82
+
+#ifndef __ASSEMBLY__
+#include "linux/types.h"
+
+enum board_boot_mode {
+       BOOT_MODE_NONE = 0,
+       BOOT_MODE_USB = 0x55a,
+       BOOT_MODE_EMMC,
+       BOOT_MODE_NAND,
+       BOOT_MODE_NOR,
+       BOOT_MODE_SD,
+       BOOT_MODE_SHELL = 0x55f,
+};
+
+struct ddr_training_info_t {
+       uint32_t magic;
+       uint32_t crc32;
+       uint64_t chipid;
+       uint64_t mac_addr;
+       uint32_t version;
+       uint32_t cs_num;
+       uint8_t reserved[32];
+       uint8_t para[1024];
+       uint8_t reserved2[448];
+};
+
+struct boot_storage_op
+{
+       uint32_t boot_storage;
+       uint32_t address;
+       ulong (*read)(ulong byte_addr, ulong byte_size, void *buff);
+       bool (*write)(ulong byte_addr, ulong byte_size, void *buff);
+};
+#endif
+
+#define MMC_DEV_EMMC   (2)
+#define MMC_DEV_SD     (0)
+
+#define BOOTFS_NAME    ("bootfs")
+
+/* Environment options */
+
+#define BOOT_TARGET_DEVICES(func) \
+       func(QEMU, qemu, na)
+
+#include <config_distro_bootcmd.h>
+
+#define BOOTENV_DEV_QEMU(devtypeu, devtypel, instance) \
+       "bootcmd_qemu=" \
+       "if env exists kernel_start; then " \
+       "bootm ${kernel_start} - ${fdtcontroladdr};" \
+       "fi;\0"
+
+#define BOOTENV_DEV_NAME_QEMU(devtypeu, devtypel, instance) \
+       "qemu "
+
+#define BOOTENV_DEVICE_CONFIG \
+       "product_name=" DEFAULT_PRODUCT_NAME "\0" \
+       "serial#=123456789ABC\0" \
+       "manufacturer=" CONFIG_SYS_VENDOR "\0" \
+       "manufacture_date=01/16/2023 11:02:20\0" \
+       "device_version=1\0" \
+       "sdk_version=1\0" \
+       "pmic_type=" __stringify(K1_DEFALT_PMIC_TYPE) "\0" \
+       "eeprom_i2c_index=" __stringify(K1_DEFALT_EEPROM_I2C_INDEX) "\0" \
+       "eeprom_pin_group=" __stringify(K1_DEFALT_EEPROM_PIN_GROUP) "\0"
+
+/*if env not use for spl, please define to board/spacemit/k1-x/k1-x.env */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+       "stdout_flash=serial,vidconsole\0" \
+       "kernel_comp_addr_r=0x18000000\0" \
+       "kernel_comp_size=0x4000000\0" \
+       "scriptaddr=0x2c100000\0" \
+       "pxefile_addr_r=0x0c200000\0" \
+       "ipaddr=192.168.1.15\0" \
+       "netmask=255.255.255.0\0" \
+       "serverip=10.0.92.134\0" \
+       "gatewayip=192.168.1.1\0" \
+       "net_data_path=spacemit_flash_file/net_flash_file/\0" \
+       "splashimage=" __stringify(CONFIG_FASTBOOT_BUF_ADDR) "\0" \
+       "splashpos=m,m\0" \
+       "splashfile=bianbu.bmp\0" \
+       BOOTENV_DEVICE_CONFIG
+
+
+#endif /* __CONFIG_H */
index 45e8a0a05778b27e6ac453d92222f4acc1da88e9..272387478584945b99969f4cf9281d640635e435 100644 (file)
@@ -60,6 +60,10 @@ void dcache_enable(void);
 void dcache_disable(void);
 void mmu_disable(void);
 int mmu_status(void);
+void branch_predict_enable(void);
+void branch_predict_disable(void);
+void prefetch_enable(void);
+void prefetch_disable(void);
 
 /* arch/$(ARCH)/lib/cache.c */
 void enable_caches(void);
@@ -67,6 +71,7 @@ void flush_cache(unsigned long addr, unsigned long size);
 void flush_dcache_all(void);
 void flush_dcache_range(unsigned long start, unsigned long stop);
 void invalidate_dcache_range(unsigned long start, unsigned long stop);
+void clean_dcache_range(unsigned long start, unsigned long stop);
 void invalidate_dcache_all(void);
 void invalidate_icache_all(void);
 
diff --git a/include/dt-bindings/clock/spacemit-k1x-clock.h b/include/dt-bindings/clock/spacemit-k1x-clock.h
new file mode 100644 (file)
index 0000000..463fe49
--- /dev/null
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+
+#ifndef _DT_BINDINGS_CLK_SPACEMIT_K1X_H_
+#define _DT_BINDINGS_CLK_SPACEMIT_K1X_H_
+
+/*
+    !!! clk list must start with CLK_PLL1_2457P6 !!!
+    in order to differ from spl clk list, CLK_PLL1_2457P6 start with 40.
+*/
+#define CLK_PLL1_2457P6          40
+#define CLK_PLL2                 41
+#define CLK_PLL3                 42
+#define CLK_PLL1_D2              43
+#define CLK_PLL1_D3              44
+#define CLK_PLL1_D4              45
+#define CLK_PLL1_D5              46
+#define CLK_PLL1_D6              47
+#define CLK_PLL1_D7              48
+#define CLK_PLL1_D8              49
+#define CLK_PLL1_D11             50
+#define CLK_PLL1_D13             51
+#define CLK_PLL1_D23             52
+#define CLK_PLL1_D64             53
+#define CLK_PLL1_D10_AUD         54
+#define CLK_PLL1_D100_AUD        55
+#define CLK_PLL2_D1              56
+#define CLK_PLL2_D2              57
+#define CLK_PLL2_D3              58
+#define CLK_PLL2_D4              59
+#define CLK_PLL2_D5              60
+#define CLK_PLL2_D6              61
+#define CLK_PLL2_D7              62
+#define CLK_PLL2_D8              63
+#define CLK_PLL3_D1              64
+#define CLK_PLL3_D2              65
+#define CLK_PLL3_D3              66
+#define CLK_PLL3_D4              67
+#define CLK_PLL3_D5              68
+#define CLK_PLL3_D6              69
+#define CLK_PLL3_D7              70
+#define CLK_PLL3_D8              71
+#define CLK_PLL1_307P2           72
+#define CLK_PLL1_76P8            73
+#define CLK_PLL1_61P44           74
+#define CLK_PLL1_153P6           75
+#define CLK_PLL1_102P4           76
+#define CLK_PLL1_51P2            77
+#define CLK_PLL1_51P2_AP         78
+#define CLK_PLL1_57P6            79
+#define CLK_PLL1_25P6            80
+#define CLK_PLL1_12P8            81
+#define CLK_PLL1_12P8_WDT        82
+#define CLK_PLL1_6P4             83
+#define CLK_PLL1_3P2             84
+#define CLK_PLL1_1P6             85
+#define CLK_PLL1_0P8             86
+#define CLK_PLL1_351             87
+#define CLK_PLL1_409P6           88
+#define CLK_PLL1_204P8           89
+#define CLK_PLL1_491             90
+#define CLK_PLL1_245P76          91
+#define CLK_PLL1_614             92
+#define CLK_PLL1_47P26           93
+#define CLK_PLL1_31P5            94
+#define CLK_PLL1_819             95
+#define CLK_PLL1_1228            96
+#define CLK_SLOW_UART1           97
+#define CLK_SLOW_UART2           98
+#define CLK_UART1                99
+#define CLK_UART2                100
+#define CLK_UART3                101
+#define CLK_UART4                102
+#define CLK_UART5                103
+#define CLK_UART6                104
+#define CLK_UART7                105
+#define CLK_UART8                106
+#define CLK_UART9                107
+#define CLK_GPIO                 108
+#define CLK_PWM0                 109
+#define CLK_PWM1                 110
+#define CLK_PWM2                 111
+#define CLK_PWM3                 112
+#define CLK_PWM4                 113
+#define CLK_PWM5                 114
+#define CLK_PWM6                 115
+#define CLK_PWM7                 116
+#define CLK_PWM8                 117
+#define CLK_PWM9                 118
+#define CLK_PWM10                119
+#define CLK_PWM11                120
+#define CLK_PWM12                121
+#define CLK_PWM13                122
+#define CLK_PWM14                123
+#define CLK_PWM15                124
+#define CLK_PWM16                125
+#define CLK_PWM17                126
+#define CLK_PWM18                127
+#define CLK_PWM19                128
+#define CLK_SSP3                 129
+#define CLK_RTC                  130
+#define CLK_TWSI0                131
+#define CLK_TWSI1                132
+#define CLK_TWSI2                133
+#define CLK_TWSI4                134
+#define CLK_TWSI5                135
+#define CLK_TWSI6                136
+#define CLK_TWSI7                137
+#define CLK_TWSI8                138
+#define CLK_TIMERS1              139
+#define CLK_TIMERS2              140
+#define CLK_AIB                  141
+#define CLK_ONEWIRE              142
+#define CLK_SSPA0                143
+#define CLK_SSPA1                144
+#define CLK_DRO                  145
+#define CLK_IR                   146
+#define CLK_TSEN                 147
+#define CLK_IPC_AP2AUD           148
+#define CLK_CAN0                 149
+#define CLK_CAN0_BUS             150
+#define CLK_WDT                  151
+#define CLK_RIPC                 152
+#define CLK_JPG                  153
+#define CLK_JPF_4KAFBC           154
+#define CLK_JPF_2KAFBC           155
+#define CLK_CCIC2PHY             156
+#define CLK_CCIC3PHY             157
+#define CLK_CSI                  158
+#define CLK_CAMM0                159
+#define CLK_CAMM1                160
+#define CLK_CAMM2                161
+#define CLK_ISP_CPP              162
+#define CLK_ISP_BUS              163
+#define CLK_ISP                  164
+#define CLK_DPU_MCLK             165
+#define CLK_DPU_ESC              166
+#define CLK_DPU_BIT              167
+#define CLK_DPU_PXCLK            168
+#define CLK_DPU_HCLK             169
+#define CLK_DPU_SPI              170
+#define CLK_DPU_SPI_HBUS         171
+#define CLK_DPU_SPIBUS           172
+#define CLK_SPU_SPI_ACLK         173
+#define CLK_V2D                  174
+#define CLK_CCIC_4X              175
+#define CLK_CCIC1PHY             176
+#define CLK_SDH_AXI              177
+#define CLK_SDH0                 178
+#define CLK_SDH1                 179
+#define CLK_SDH2                 180
+#define CLK_USB_P1               181
+#define CLK_USB_AXI              182
+#define CLK_USB30                183
+#define CLK_QSPI                 184
+#define CLK_QSPI_BUS             185
+#define CLK_DMA                  186
+#define CLK_AES                  187
+#define CLK_VPU                  188
+#define CLK_GPU                  189
+#define CLK_EMMC                 190
+#define CLK_EMMC_X               191
+#define CLK_AUDIO                192
+#define CLK_HDMI                 193
+#define CLK_CCI550               194
+#define CLK_PMUA_ACLK            195
+#define CLK_CPU_C0_HI            196
+#define CLK_CPU_C0_CORE          197
+#define CLK_CPU_C0_ACE           198
+#define CLK_CPU_C0_TCM           199
+#define CLK_CPU_C1_HI            200
+#define CLK_CPU_C1_CORE          201
+#define CLK_CPU_C1_ACE           202
+#define CLK_PCIE0                203
+#define CLK_PCIE1                204
+#define CLK_PCIE2                205
+#define CLK_EMAC0_BUS            206
+#define CLK_EMAC0_PTP            207
+#define CLK_EMAC1_BUS            208
+#define CLK_EMAC1_PTP            209
+#define CLK_SEC_UART1            210
+#define CLK_SEC_SSP2             211
+#define CLK_SEC_TWSI3            212
+#define CLK_SEC_RTC              213
+#define CLK_SEC_TIMERS0          214
+#define CLK_SEC_KPC              215
+#define CLK_SEC_GPIO             216
+
+#define CLK_APB                  217
+
+#define CLK_VCTCXO_24            218
+#define CLK_VCTCXO_3             219
+#define CLK_VCTCXO_1             220
+#define CLK_PLL1                 221
+#define CLK_32K                  222
+#define CLK_DUMMY                223
+
+#define CLK_MAX_NO               224
+
+
+#endif /* _DT_BINDINGS_CLK_SPACEMIT_K1X_H_ */
diff --git a/include/dt-bindings/pinctrl/k1-x-pinctrl.h b/include/dt-bindings/pinctrl/k1-x-pinctrl.h
new file mode 100644 (file)
index 0000000..9385062
--- /dev/null
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __DT_BINDINGS_K1X_PINCTRL_H
+#define __DT_BINDINGS_K1X_PINCTRL_H
+
+/* pin offset */
+#define PINID(x)       ((x) + 1)
+
+#define GPIO_00  PINID(0)
+#define GPIO_01  PINID(1)
+#define GPIO_02  PINID(2)
+#define GPIO_03  PINID(3)
+#define GPIO_04  PINID(4)
+#define GPIO_05  PINID(5)
+#define GPIO_06  PINID(6)
+#define GPIO_07  PINID(7)
+#define GPIO_08  PINID(8)
+#define GPIO_09  PINID(9)
+#define GPIO_10  PINID(10)
+#define GPIO_11  PINID(11)
+#define GPIO_12  PINID(12)
+#define GPIO_13  PINID(13)
+#define GPIO_14  PINID(14)
+#define GPIO_15  PINID(15)
+#define GPIO_16  PINID(16)
+#define GPIO_17  PINID(17)
+#define GPIO_18  PINID(18)
+#define GPIO_19  PINID(19)
+#define GPIO_20  PINID(20)
+#define GPIO_21  PINID(21)
+#define GPIO_22  PINID(22)
+#define GPIO_23  PINID(23)
+#define GPIO_24  PINID(24)
+#define GPIO_25  PINID(25)
+#define GPIO_26  PINID(26)
+#define GPIO_27  PINID(27)
+#define GPIO_28  PINID(28)
+#define GPIO_29  PINID(29)
+#define GPIO_30  PINID(30)
+#define GPIO_31  PINID(31)
+
+#define GPIO_32  PINID(32)
+#define GPIO_33  PINID(33)
+#define GPIO_34  PINID(34)
+#define GPIO_35  PINID(35)
+#define GPIO_36  PINID(36)
+#define GPIO_37  PINID(37)
+#define GPIO_38  PINID(38)
+#define GPIO_39  PINID(39)
+#define GPIO_40  PINID(40)
+#define GPIO_41  PINID(41)
+#define GPIO_42  PINID(42)
+#define GPIO_43  PINID(43)
+#define GPIO_44  PINID(44)
+#define GPIO_45  PINID(45)
+#define GPIO_46  PINID(46)
+#define GPIO_47  PINID(47)
+#define GPIO_48  PINID(48)
+#define GPIO_49  PINID(49)
+#define GPIO_50  PINID(50)
+#define GPIO_51  PINID(51)
+#define GPIO_52  PINID(52)
+#define GPIO_53  PINID(53)
+#define GPIO_54  PINID(54)
+#define GPIO_55  PINID(55)
+#define GPIO_56  PINID(56)
+#define GPIO_57  PINID(57)
+#define GPIO_58  PINID(58)
+#define GPIO_59  PINID(59)
+#define GPIO_60  PINID(60)
+#define GPIO_61  PINID(61)
+#define GPIO_62  PINID(62)
+#define GPIO_63  PINID(63)
+
+#define GPIO_64  PINID(64)
+#define GPIO_65  PINID(65)
+#define GPIO_66  PINID(66)
+#define GPIO_67  PINID(67)
+#define GPIO_68  PINID(68)
+#define GPIO_69  PINID(69)
+#define PRI_TDI  PINID(70)
+#define PRI_TMS  PINID(71)
+#define PRI_TCK  PINID(72)
+#define PRI_TDO  PINID(73)
+#define GPIO_74  PINID(74)
+#define GPIO_75  PINID(75)
+#define GPIO_76  PINID(76)
+#define GPIO_77  PINID(77)
+#define GPIO_78  PINID(78)
+#define GPIO_79  PINID(79)
+#define GPIO_80  PINID(80)
+#define GPIO_81  PINID(81)
+#define GPIO_82  PINID(82)
+#define GPIO_83  PINID(83)
+#define GPIO_84  PINID(84)
+#define GPIO_85  PINID(85)
+
+#define QSPI_DAT0   PINID(89)
+#define QSPI_DAT1   PINID(90)
+#define QSPI_DAT2   PINID(91)
+#define QSPI_DAT3   PINID(92)
+#define QSPI_CSI    PINID(93)
+#define QSPI_CLK    PINID(94)
+
+#define MMC1_DAT3   PINID(109)
+#define MMC1_DAT2   PINID(110)
+#define MMC1_DAT1   PINID(111)
+#define MMC1_DAT0   PINID(112)
+#define MMC1_CMD    PINID(113)
+#define MMC1_CLK    PINID(114)
+#define GPIO_110    PINID(115)
+#define PWR_SCL     PINID(116)
+#define PWR_SDA     PINID(117)
+#define VCXO_EN     PINID(118)
+#define DVL0        PINID(119)
+#define DVL1        PINID(120)
+#define PMIC_INT_N  PINID(121)
+#define GPIO_86     PINID(122)
+#define GPIO_87     PINID(123)
+#define GPIO_88     PINID(124)
+#define GPIO_89     PINID(125)
+#define GPIO_90     PINID(126)
+#define GPIO_91     PINID(127)
+#define GPIO_92     PINID(128)
+
+#define GPIO_111    PINID(130)
+#define GPIO_112    PINID(131)
+#define GPIO_113    PINID(132)
+#define GPIO_114    PINID(133)
+#define GPIO_115    PINID(134)
+#define GPIO_116    PINID(135)
+#define GPIO_117    PINID(136)
+#define GPIO_118    PINID(137)
+#define GPIO_119    PINID(138)
+#define GPIO_120    PINID(139)
+#define GPIO_121    PINID(140)
+#define GPIO_122    PINID(141)
+#define GPIO_123    PINID(142)
+#define GPIO_124    PINID(143)
+#define GPIO_125    PINID(144)
+#define GPIO_126    PINID(145)
+#define GPIO_127    PINID(146)
+
+/* pin mux */
+#define MUX_MODE0       0
+#define MUX_MODE1       1
+#define MUX_MODE2       2
+#define MUX_MODE3       3
+#define MUX_MODE4       4
+#define MUX_MODE5       5
+#define MUX_MODE6       6
+#define MUX_MODE7       7
+
+/* strong pull resistor */
+#define SPU_EN          (1 << 3)
+
+/* edge detect */
+#define EDGE_NONE       (1 << 6)
+#define EDGE_RISE       (1 << 4)
+#define EDGE_FALL       (1 << 5)
+#define EDGE_BOTH       (3 << 4)
+
+/* slew rate output control */
+#define SLE_EN          (1 << 7)
+
+/* schmitter trigger input threshhold */
+#define ST00            (0 << 8)
+#define ST01            (1 << 8)
+#define ST02            (2 << 8)
+#define ST03            (3 << 8)
+
+/* driver strength*/
+#define PAD_1V8_DS0     (0 << 11)
+#define PAD_1V8_DS1     (1 << 11)
+#define PAD_1V8_DS2     (2 << 11)
+#define PAD_1V8_DS3     (3 << 11)
+
+/*
+ * notice: !!!
+ * ds2 ---> bit10, ds1 ----> bit12, ds0 ----> bit11
+*/
+#define PAD_3V_DS0      (0 << 10)     /* bit[12:10] 000 */
+#define PAD_3V_DS1      (2 << 10)     /* bit[12:10] 010 */
+#define PAD_3V_DS2      (4 << 10)     /* bit[12:10] 100 */
+#define PAD_3V_DS3      (6 << 10)     /* bit[12:10] 110 */
+#define PAD_3V_DS4      (1 << 10)     /* bit[12:10] 001 */
+#define PAD_3V_DS5      (3 << 10)     /* bit[12:10] 011 */
+#define PAD_3V_DS6      (5 << 10)     /* bit[12:10] 101 */
+#define PAD_3V_DS7      (7 << 10)     /* bit[12:10] 111 */
+
+/* pull up/down */
+#define PULL_DIS        (0 << 13)     /* bit[15:13] 000 */
+#define PULL_UP         (6 << 13)     /* bit[15:13] 110 */
+#define PULL_DOWN       (5 << 13)     /* bit[15:13] 101 */
+
+#define K1X_PADCONF(pinid, conf, mux)  ((pinid) * 4) (conf) (mux)
+
+#endif /* __DT_BINDINGS_K1X_PINCTRL_H */
diff --git a/include/dt-bindings/power-domain/k1x-pmu.h b/include/dt-bindings/power-domain/k1x-pmu.h
new file mode 100644 (file)
index 0000000..216e61c
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_POWER_DOMAIN_K1X_H
+#define __DT_BINDINGS_POWER_DOMAIN_K1X_H
+
+#define K1X_PMU_VPU_PWR_DOMAIN  0
+#define K1X_PMU_GPU_PWR_DOMAIN  1
+#define K1X_PMU_LCD_PWR_DOMAIN  2
+#define K1X_PMU_ISP_PWR_DOMAIN  3
+#define K1X_PMU_AUD_PWR_DOMAIN  4
+#define K1X_PMU_GNSS_PWR_DOMAIN 5
+#define K1X_PMU_HDMI_PWR_DOMAIN 6
+
+#endif /* __DT_BINDINGS_POWER_DOMAIN_K1X_H */
diff --git a/include/dt-bindings/reset/reset-spacemit-k1x.h b/include/dt-bindings/reset/reset-spacemit-k1x.h
new file mode 100644 (file)
index 0000000..d8074e0
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef __DT_BINDINGS_RESET_SAPCEMIT_K1X_H__
+#define __DT_BINDINGS_RESET_SAPCEMIT_K1X_H__
+//APBC
+#define RESET_UART1   1
+#define RESET_UART2   2
+#define RESET_GPIO    3
+#define RESET_PWM0    4
+#define RESET_PWM1    5
+#define RESET_PWM2    6
+#define RESET_PWM3    7
+#define RESET_PWM4    8
+#define RESET_PWM5    9
+#define RESET_PWM6    10
+#define RESET_PWM7    11
+#define RESET_PWM8    12
+#define RESET_PWM9    13
+#define RESET_PWM10   14
+#define RESET_PWM11   15
+#define RESET_PWM12   16
+#define RESET_PWM13   17
+#define RESET_PWM14   18
+#define RESET_PWM15   19
+#define RESET_PWM16   20
+#define RESET_PWM17   21
+#define RESET_PWM18   22
+#define RESET_PWM19   23
+#define RESET_SSP3    24
+#define RESET_UART3   25
+#define RESET_RTC     26
+#define RESET_TWSI0   27
+
+#define RESET_TIMERS1 28
+#define RESET_AIB     29
+#define RESET_TIMERS2 30
+#define RESET_ONEWIRE 31
+#define RESET_SSPA0   32
+#define RESET_SSPA1   33
+#define RESET_DRO     34
+#define RESET_IR      35
+#define RESET_TWSI1   36
+
+#define RESET_TSEN    37
+#define RESET_TWSI2   38
+#define RESET_TWSI4   39
+#define RESET_TWSI5   40
+#define RESET_TWSI6   41
+#define RESET_TWSI7   42
+#define RESET_TWSI8   43
+#define RESET_IPC_AP2AUD  44
+#define RESET_UART4   45
+#define RESET_UART5   46
+#define RESET_UART6   47
+#define RESET_UART7   48
+#define RESET_UART8   49
+#define RESET_UART9   50
+#define RESET_CAN0    51
+
+//MPMU
+#define RESET_WDT     52
+
+//APMU
+#define        RESET_JPG        53
+#define        RESET_CSI        54
+#define        RESET_CCIC2_PHY  55
+#define        RESET_CCIC3_PHY  56
+#define        RESET_ISP        57
+#define        RESET_ISP_AHB    58
+#define        RESET_ISP_CI     59
+#define        RESET_ISP_CPP    60
+#define        RESET_LCD        61
+#define        RESET_DSI_ESC    62
+#define        RESET_V2D        63
+#define        RESET_MIPI       64
+#define        RESET_LCD_SPI    65
+#define        RESET_LCD_SPI_BUS  66
+#define        RESET_LCD_SPI_HBUS 67
+#define        RESET_LCD_MCLK     68
+#define        RESET_CCIC_4X      69
+#define        RESET_CCIC1_PHY    70
+#define        RESET_SDH_AXI      71
+#define        RESET_SDH0         72
+#define        RESET_SDH1         73
+#define        RESET_USB_AXI      74
+#define        RESET_USBP1_AXI    75
+#define        RESET_USB3_0       76
+#define        RESET_QSPI         77
+#define        RESET_QSPI_BUS     78
+#define RESET_DMA          79
+#define        RESET_AES          80
+#define        RESET_VPU          81
+#define        RESET_GPU          82
+#define        RESET_SDH2         83
+#define        RESET_MC           84
+#define        RESET_EM_AXI       85
+#define        RESET_EM           86
+#define        RESET_AUDIO_SYS    87
+#define        RESET_HDMI         88
+#define        RESET_PCIE0        89
+#define        RESET_PCIE1        90
+#define        RESET_PCIE2        91
+#define        RESET_EMAC0        92
+#define        RESET_EMAC1        93
+
+//APBC2
+#define        RESET_SEC_UART1    94
+#define        RESET_SEC_SSP2     95
+#define        RESET_SEC_TWSI3    96
+#define        RESET_SEC_RTC      97
+#define        RESET_SEC_TIMERS0  98
+#define        RESET_SEC_KPC      99
+#define        RESET_SEC_GPIO     100
+
+#define        RESET_NUMBER       101
+
+#endif /* __DT_BINDINGS_RESET_SAPCEMIT_K1X_H__ */
diff --git a/include/dt-bindings/soc/spacemit-k1x.h b/include/dt-bindings/soc/spacemit-k1x.h
new file mode 100644 (file)
index 0000000..4244c4d
--- /dev/null
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Spacemit
+ */
+
+#ifndef _SPACEMIT_K1X_H_
+#define _SPACEMIT_K1X_H_
+
+#define K1X_PLAT_GIC_BASE       0xD8000000
+#define K1X_PLAT_GICC_BASE      0xD8400000
+#define K1X_PLAT_GICR_BASE      0xD8100000
+#define K1X_PLAT_CIU_BASE       0xD8440000
+
+#define K1X_USB_BASE            0xC0900000
+#define USB2_PHY_REG_BASE       0xC0940000
+#define K1X_AXI_BUS_BASE        0xD4200000
+#define K1X_SDH2_BASE           0xD4281000
+#define K1X_SDH0_BASE           0xD4280000
+#define K1X_SDH1_BASE           0xD4280800
+#define K1X_CIU_BASE            0xD4282C00  /* cpu config unit */
+#define K1X_APB_BUS_BASE        0xD4000000
+#define K1X_SOC_RTC_BASE        0xD4010000
+#define K1X_SOC_WDT_BASE        0xD4080000
+#define K1X_MPMU_BASE           0xD4050000
+#define K1X_APMU_BASE           0xD4282800
+#define K1X_APB_SPARE_BASE      0xD4090000
+
+/* THERMAL TSEN & AUXADC */
+#define K1X_APB_SPARE4_BASE     (K1X_APB_SPARE_BASE + 0x10C)    /* AUXADC control */
+#define K1X_AUXADC_BASE         0xD4013300
+#define K1X_AUXADC_DATA         (K1X_AUXADC_BASE + 0x80)
+#define K1X_AUXADC_ISR          (K1X_AUXADC_BASE + 0xF0)
+
+#define K1X_ARCH_TIMER_BASE     0xD5001000
+#define K1X_APBC_BASE           0xD4015000  /* APB Clock Unit */
+#define K1X_SOC_TIMER_BASE      0xD4014000
+#define K1X_PDMA_BASE           0xD4000000
+#define K1X_UART1_BASE          0xD4017000
+#define K1X_UART2_BASE          0xD4018000
+#define K1X_UART3_BASE          0xD4017800
+#define K1X_MFPR_BASE           0xD401e000  /* Multi-Function Pin Registers */
+#define K1X_MFPR_GPIO26_BASE    (0xD401E000 + 0x20C)
+#define K1X_GPIO_BASE           0xD4019000
+#define K1X_SSP0_BASE           0xD401B000
+#define K1X_SSP2_BASE           0xD401C000
+#define K1X_PWM0_BASE           0xD401A000
+#define K1X_PWM1_BASE           0xD401A400
+#define K1X_TWSI0_BASE          0xD4011000
+#define K1X_TWSI1_BASE          0xD4010800
+#define K1X_TWSI2_BASE          0xD4013800
+#define K1X_TWSI3_BASE          0xD4018800
+#define K1X_TWSI4_BASE          0xD4020000
+#define K1X_TWSI5_BASE          0xD4020800
+#define K1X_TWSI6_BASE          0xD4021000
+#define K1X_TWSI7_BASE          0xD4021800
+#define K1X_TWSI8_BASE          0xD4022000
+#define K1X_RIPC3_BASE          0xD40B0300
+
+#define K1X_SWJTAG_BASE         0xD4013100
+#define K1X_EDGE_WAKEUP_BASE    0xD4019800
+#define K1X_DDR_BASE            0xC0000000
+#define K1X_DDR_PHY1_BASE       0xC0100000
+#define K1X_DDRAXI_MON_BASE     0xC0058500
+#define K1X_PORT0_BASE          0xD84400F0
+
+#define K1X_APMU_DEBUG          (K1X_APMU_BASE + 0x88)
+
+/* RTC Backup Registers */
+#define REG_RTC_RTC_BR0         (K1X_SOC_RTC_BASE + 0x14)
+
+#define K1X_DRO_BASE            0xD4013200
+
+#endif /* _SPACEMIT_K1X_H_ */
index 9bb0d44ac8d51f5a7082e6c63f97fc423b2b3291..72e9a62f38330e057abe1aeb340d7138c306c6c8 100644 (file)
@@ -600,6 +600,7 @@ struct efi_device_path_acpi_path {
 #  define DEVICE_PATH_SUB_TYPE_MSG_SD          0x1a
 #  define DEVICE_PATH_SUB_TYPE_MSG_MMC         0x1d
 
+
 struct efi_device_path_atapi {
        struct efi_device_path dp;
        u8 primary_secondary;
@@ -666,6 +667,7 @@ struct efi_device_path_uri {
        u8 uri[];
 } __packed;
 
+
 #define DEVICE_PATH_TYPE_MEDIA_DEVICE          0x04
 #  define DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH 0x01
 #  define DEVICE_PATH_SUB_TYPE_CDROM_PATH      0x02
index 4e461c815a79331cad0b1092474061b578142a4c..ebef62d71399ec51b5800699bc971b7b7f50b807 100644 (file)
@@ -114,10 +114,15 @@ const char default_environment[] = {
 #ifdef CONFIG_MTDPARTS_DEFAULT
        "mtdparts="     CONFIG_MTDPARTS_DEFAULT         "\0"
 #endif
+
+/*spl would not include extra env settings*/
+#ifndef CONFIG_SPL_BUILD
 #ifdef CONFIG_EXTRA_ENV_TEXT
        /* This is created in the Makefile */
        CONFIG_EXTRA_ENV_TEXT
 #endif
+#endif
+
 #ifdef CONFIG_EXTRA_ENV_SETTINGS
        CONFIG_EXTRA_ENV_SETTINGS
 #endif
index f30fd6159d87b8ad282583c3c2cd55ae75548289..ec654b4f1b890c58336dc98a8cf4d745caf647f3 100644 (file)
@@ -131,6 +131,7 @@ enum env_location {
        ENVL_FLASH,
        ENVL_MMC,
        ENVL_NAND,
+       ENVL_MTD,
        ENVL_NVRAM,
        ENVL_ONENAND,
        ENVL_REMOTE,
index 57daaf1298211e1c01f89de944c56913ac8f18ab..b4d36e59a3b72d7f86dcc96bcda97f15ce907d81 100644 (file)
@@ -24,6 +24,7 @@
 enum {
        FASTBOOT_COMMAND_GETVAR = 0,
        FASTBOOT_COMMAND_DOWNLOAD,
+       FASTBOOT_COMMAND_UPLOAD,
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
        FASTBOOT_COMMAND_FLASH,
        FASTBOOT_COMMAND_ERASE,
@@ -44,11 +45,19 @@ enum {
 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
        FASTBOOT_COMMAND_OEM_BOOTBUS,
 #endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_READ)
+       FASTBOOT_COMMAND_OEM_READ,
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
+       FASTBOOT_COMMAND_CONFIG_ACCESS,
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
+       FASTBOOT_COMMAND_ENV_ACCESS,
+#endif
 #if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
        FASTBOOT_COMMAND_ACMD,
        FASTBOOT_COMMAND_UCMD,
 #endif
-
        FASTBOOT_COMMAND_COUNT
 };
 
@@ -164,6 +173,22 @@ u32 fastboot_data_remaining(void);
 void fastboot_data_download(const void *fastboot_data,
                            unsigned int fastboot_data_len, char *response);
 
+/**
+ * fastboot_data_upload() - Copy image data to fastboot_buf_addr.
+ *
+ * @fastboot_data: Pointer to received fastboot data
+ * @fastboot_data_len: Length of received fastboot data
+ * @response: Pointer to fastboot response buffer
+ *
+ * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
+ * response. fastboot_bytes_received is updated to indicate the number
+ * of bytes that have been transferred.
+ */
+void fastboot_data_upload(const void *fastboot_data,
+                           unsigned int fastboot_data_len, char *response);
+
+
+
 /**
  * fastboot_data_complete() - Mark current transfer complete
  *
diff --git a/include/fb_blk.h b/include/fb_blk.h
new file mode 100644 (file)
index 0000000..b3c37d4
--- /dev/null
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#ifndef _FB_BLK_H_
+#define _FB_BLK_H_
+
+struct blk_desc;
+struct disk_partition;
+
+/**
+ * fastboot_blk_get_part_info() - Lookup blk device partion by name
+ *
+ * @part_name: Named partition to lookup
+ * @dev_desc: Pointer to returned blk_desc pointer
+ * @part_info: Pointer to returned struct disk_partition
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_blk_get_part_info(const char *part_name,
+                              struct blk_desc **dev_desc,
+                              struct disk_partition *part_info,
+                              char *response);
+
+/**
+ * fastboot_blk_flash_write() - Write image to blk device for fastboot
+ *
+ * @cmd: Named partition to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_blk_flash_write(const char *cmd, void *download_buffer,
+                             u32 download_bytes, char *response);
+/**
+ * fastboot_blk_flash_erase() - Erase blk device for fastboot
+ *
+ * @cmd: Named partition to erase
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_blk_erase(const char *cmd, char *response);
+
+/**
+ * fastboot_blk_read() - load data from blk device for fastboot
+ *
+ * @part: Named partition to erase
+ * @response: Pointer to fastboot response buffer
+ */
+u32 fastboot_blk_read(const char *part, u32 offset,
+                       void *download_buffer, char *response);
+
+#endif
index 76ed7cd6be11c977d787f57a561ad7df52f67559..72929d608d6f7b0e76fca4aec6a000d00fc589ba 100644 (file)
@@ -39,4 +39,14 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
  * @response: Pointer to fastboot response buffer
  */
 void fastboot_mmc_erase(const char *cmd, char *response);
+
+/**
+ * fastboot_mmc_read() - load data from eMMC for fastboot
+ *
+ * @part: Named partition to erase
+ * @response: Pointer to fastboot response buffer
+ */
+u32 fastboot_mmc_read(const char *part, u32 offset,
+                       void *download_buffer, char *response);
+
 #endif
diff --git a/include/fb_mtd.h b/include/fb_mtd.h
new file mode 100644 (file)
index 0000000..ee75cc5
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#ifndef _FB_MTD_H_
+#define _FB_MTD_H_
+
+#include <jffs2/load_kernel.h>
+#include <mtd.h>
+
+
+/**
+ * @brief find mtd part
+ * 
+ * @param partname: mtd part name.
+ * @param mtd: mtd dev.
+ * @param part: mtd dev part info.
+ * @return int 
+ */
+int fb_mtd_lookup(const char *partname, struct mtd_info **mtd,
+                                       struct part_info **part);
+
+/**
+ * @brief erase mtd partition
+ * 
+ * @param mtd: mtd dev.
+ * @param erase_size: the size to erase at mtd dev.
+ * @return int 
+ */
+int _fb_mtd_erase(struct mtd_info *mtd, u32 erase_size);
+
+
+/**
+ * @brief write data to mtd part.
+ * 
+ * @param mtd: mtd dev.
+ * @param buffer: the data would write from buffer.
+ * @param offset: the offset to write to the mtd dev.
+ * @param length: the length to write to the mtd dev.
+ * @param written
+ * @return int 
+ */
+int _fb_mtd_write(struct mtd_info *mtd, void *buffer, u32 offset,
+                         size_t length, size_t *written);
+
+/**
+ * @brief read data to mtd part.
+ * 
+ * @param mtd: mtd dev.
+ * @param buffer: the data would read to buffer.
+ * @param offset: the offset to read from the mtd dev.
+ * @param length: the length to read from the mtd dev.
+ * @param written
+ * @return int 
+ */
+int _fb_mtd_read(struct mtd_info *mtd, void *buffer, u32 offset,
+                         size_t length, size_t *written);
+
+/**
+ * fastboot_mtd_get_part_info() - Lookup MTD partion by name
+ *
+ * @part_name: Named device to lookup
+ * @part_info: Pointer to returned part_info pointer
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_mtd_get_part_info(const char *part_name,
+                               struct part_info **part_info, char *response);
+
+/**
+ * fastboot_mtd_flash_write() - Write image to MTD for fastboot
+ *
+ * @cmd: Named device to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_mtd_flash_write(const char *cmd, void *download_buffer,
+                              u32 download_bytes, char *response);
+
+/**
+ * fastboot_mtd_flash_erase() - Erase MTD for fastboot
+ *
+ * @cmd: Named device to erase
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_mtd_flash_erase(const char *cmd, char *response);
+
+
+/**
+ * fastboot_mtd_flash_read() - load data from mtd for fastboot
+ *
+ * @part_name: Named partition to read
+ * @response: Pointer to fastboot response buffer
+ */
+u32 fastboot_mtd_flash_read(const char *part_name, u32 offset,
+                                       void *download_buffer, char *response);
+
+#endif
diff --git a/include/fb_spacemit.h b/include/fb_spacemit.h
new file mode 100644 (file)
index 0000000..ad449e8
--- /dev/null
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2023 Spacemit, Inc
+ */
+
+#ifndef _FB_SPACEMIT_H_
+#define _FB_SPACEMIT_H_
+
+#include <mtd.h>
+
+/*define max partition number*/
+#define MAX_PARTITION_NUM (20)
+
+#define MAX_BLK_WRITE (16384)
+#define RESULT_OK (0)
+#define RESULT_FAIL (1)
+
+/*recovery folder name*/
+#define FLASH_IMG_FOLDER ("")
+#define FLASH_IMG_FACTORY_FOLDER ("factory")
+/*FLASH_CONFIG_FILE_NAME would used as flag to excute card flash*/
+#define FLASH_CONFIG_FILE_NAME ("partition_universal.json")
+#define FLASH_IMG_PARTNAME ("bootfs")
+#define BIG_IMG_PARTNAME ("rootfs")
+
+/*if they have different addr, it can define here*/
+#ifdef CONFIG_ENV_OFFSET
+#define FLASH_ENV_OFFSET_MMC (CONFIG_ENV_OFFSET)
+#define FLASH_ENV_OFFSET_NOR (CONFIG_ENV_OFFSET)
+#define FLASH_ENV_OFFSET_NAND (CONFIG_ENV_OFFSET)
+#endif
+
+/*define bootinfo for emmc*/
+#define BOOT_INFO_EMMC_MAGICCODE (0xb00714f0)
+#define BOOT_INFO_EMMC_VERSION (0x00010001)
+#define BOOT_INFO_EMMC_PAGESIZE (0x200)
+#define BOOT_INFO_EMMC_BLKSIZE (0x10000)
+#define BOOT_INFO_EMMC_TOTALSIZE (0x10000000)
+#define BOOT_INFO_EMMC_SPL0_OFFSET (0x200)
+#define BOOT_INFO_EMMC_SPL1_OFFSET (0x0)
+// add 4KB header and 0x100 Byte signature
+#define BOOT_INFO_EMMC_LIMIT ((CONFIG_SPL_SIZE_LIMIT) + 0x1100)
+
+/* use for gzip image*/
+#define GZIP_DECOMPRESS_ADDR (CONFIG_FASTBOOT_BUF_ADDR + CONFIG_FASTBOOT_BUF_SIZE)
+
+typedef enum {
+       DEVICE_MMC,
+       DEVICE_USB,
+       DEVICE_NET,
+} DeviceType;
+
+struct flash_volume_image {
+       char *name;
+       char *file_name;
+};
+
+struct flash_parts_info {
+       char *part_name;
+       char *file_name;
+       /*partition size info, such as 128MiB*/
+       char *size;
+       /*use for fsbl, if hidden that gpt would reserve a raw memeory
+         for fsbl and the partition is not available.
+       */
+       bool hidden;
+       struct flash_volume_image *volume_images;
+       int volume_images_count;
+};
+
+struct gpt_info {
+       char *gpt_table;
+       /*save gpt start offset*/
+       u32 gpt_start_offset;
+       bool fastboot_flash_gpt;
+};
+
+enum mtd_size_type {
+       MTD_SIZE_G = 0,
+       MTD_SIZE_M,
+       MTD_SIZE_K,
+};
+struct _mtd_size_info {
+       /*save mtd size type such as G/M/K*/
+       u32 size_type;
+       u32 size;
+};
+
+struct flash_dev {
+       char *device_name;
+       u32 dev_index;
+       struct flash_parts_info parts_info[MAX_PARTITION_NUM];
+       struct gpt_info gptinfo;
+       struct disk_partition *d_info;
+       struct blk_desc *dev_desc;
+       char *mtd_table;
+
+       /*mtdinfo would use to try to find suitable patition file*/
+       char partition_file_name[30];
+       struct _mtd_size_info mtdinfo;
+
+       /*mtd write func*/
+       int (*mtd_write)(struct mtd_info *mtd,
+                                       const char *part_name,
+                                       void *buffer,
+                                       u32 download_bytes);
+
+       /*blk write func*/
+       int (*blk_write)(struct blk_desc *block_dev,
+                                       struct disk_partition *info,
+                                       const char *part_name,
+                                       void *buffer,
+                                       u32 download_bytes);
+};
+
+/**
+ * @brief boot info struct
+ *
+ */
+struct boot_parameter_info {
+       uint32_t magic_code;
+       uint32_t version_number;
+
+       /* flash info */
+       uint8_t flash_type[4];
+       uint8_t mfr_id;
+       uint8_t reserved1[1];
+       uint16_t dev_id;
+       uint32_t page_size;
+       uint32_t block_size;
+       uint32_t total_size;
+       uint8_t multi_plane;
+       uint8_t reserved2[3];
+
+       /* spl partition */
+       uint32_t spl0_offset;
+       uint32_t spl1_offset;
+       uint32_t spl_size_limit;
+
+       /* partitiontable offset */
+       uint32_t partitiontable0_offset;
+       uint32_t partitiontable1_offset;
+
+       uint32_t reserved[3];
+       uint32_t crc32;
+} __attribute__((packed));
+
+/**
+ * @brief Set the boot mode object, it would set boot mode to register
+ *
+ * @param boot_mode
+ */
+void set_boot_mode(enum board_boot_mode boot_mode);
+
+/**
+ * @brief Get the boot mode object, it would get boot mode from register,
+ * the register would save boot_mode while boot from emmc/nor/nand success.
+ * if not set boot mode, it would return get_boot_pin_select.
+ *
+ * @return u32
+ */
+enum board_boot_mode get_boot_mode(void);
+
+/**
+ * @brief Get the boot pin select object. it would get boot pin select,
+ * which is different from get_boot_mode.
+ *
+ * @return u32
+ */
+enum board_boot_mode get_boot_pin_select(void);
+
+/**
+ * fastboot_oem_flash_gpt() - parse flash config and write gpt table.
+ *
+ * @cmd: Named partition to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ */
+void fastboot_oem_flash_gpt(const char *cmd, void *download_buffer, u32 download_bytes,
+                                                       char *response, struct flash_dev *fdev);
+
+/**
+ * fastboot_mmc_flash_offset() - Write fsbl image to eMMC
+ *
+ * @start_offset: start offset to write.
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ */
+int fastboot_mmc_flash_offset(u32 start_offset, void *download_buffer, u32 download_bytes);
+
+/**
+ * @brief accumulation from the addr and size
+*/
+u64 checksum64(u64 *baseaddr, u64 size);
+
+
+/**
+ * @brief check image crc at blk dev. if crc is same it would return RESULT_OK(0).
+ *
+ * @param dev_desc struct blk_desc.
+ * @param crc_compare need to be compare crc.
+ * @param part_start_cnt read from blk offset.
+ * @param blksz normally is 0x200.
+ * @param image_size
+ * @return int
+ */
+int compare_blk_image_val(struct blk_desc *dev_desc, u64 crc_compare, lbaint_t part_start_cnt,
+                                               ulong blksz, uint64_t image_size);
+
+/**
+ * @brief check image crc at mtd dev. if crc is same it would return RESULT_OK(0).
+ *
+ * @param mtd mtd dev.
+ * @param crc_compare need to be compare crc.
+ * @param image_size
+ * @return int
+*/
+int compare_mtd_image_val(struct mtd_info *mtd, u64 crc_compare, uint64_t image_size);
+
+/**
+ * @brief transfer the string of size 'KiB' or 'MiB' to u32 type.
+ *
+ * @param reserve_size , the string of size 'xiB'
+ * @return int , return the transfer result.
+ */
+int transfer_string_to_ul(const char *reserve_size);
+
+/**
+ * @brief parse the flash_config and save partition info
+ *
+ * @param fdev , struct flash_dev
+ * @return int , return 0 if parse config success.
+ */
+int _parse_flash_config(struct flash_dev *fdev, void *load_flash_addr);
+
+/**
+ * @brief update env to storage.
+ *
+ * @param download_buffer
+ * @param download_bytes
+ * @param response
+ * @param fdev
+ * @return int
+ */
+int _clear_env_part(void *download_buffer, u32 download_bytes,
+                                                       struct flash_dev *fdev);
+
+/**
+ * @brief flash env to reserve partition.
+ *
+ * @param cmd env
+ * @param download_buffer load env.bin to addr
+ * @param download_bytes env.bin size
+ * @param response
+ * @param fdev
+ */
+void fastboot_oem_flash_env(const char *cmd, void *download_buffer, u32 download_bytes,
+                                                       char *response, struct flash_dev *fdev);
+
+/**
+ * @brief flash bootinfo to reserve partition.
+ *
+ * @param cmd
+ * @param download_buffer load env.bin to addr
+ * @param download_bytes env.bin size
+ * @param response
+ * @param fdev
+ */
+void fastboot_oem_flash_bootinfo(const char *cmd, void *download_buffer, u32 download_bytes,
+                                                                char *response, struct flash_dev *fdev);
+
+/**
+ * @brief flash mmc boot option
+ *
+ * @param dev_desc
+ * @param buffer
+ * @param hwpart
+ * @param buff_sz
+ * @return int
+ */
+int flash_mmc_boot_op(struct blk_desc *dev_desc, void *buffer,
+                                         int hwpart, u32 buff_sz, u32 offset);
+
+char *parse_mtdparts_and_find_bootfs(void);
+int get_partition_index_by_name(const char *part_name, int *part_index);
+
+#endif
index 0572dbd0a2832cfd1473b2497f764d340dfa6eba..6e9b515f285542920520046545a28dfde4ddf71c 100644 (file)
@@ -13,6 +13,7 @@ struct sparse_storage {
        lbaint_t        blksz;
        lbaint_t        start;
        lbaint_t        size;
+       lbaint_t        erase_size;
        void            *priv;
 
        lbaint_t        (*write)(struct sparse_storage *info,
@@ -20,6 +21,12 @@ struct sparse_storage {
                                 lbaint_t blkcnt,
                                 const void *buffer);
 
+       lbaint_t        (*erase)(struct sparse_storage *info,
+                                lbaint_t blk,
+                                lbaint_t blkcnt,
+                                const void *buffer);
+
+
        lbaint_t        (*reserve)(struct sparse_storage *info,
                                 lbaint_t blk,
                                 lbaint_t blkcnt);
index 15bcd59f3417d066911fcbfb9fb1b768dbc0011c..f5e9a79633987fa6985b37fe8032fc2a35ba7cc8 100644 (file)
@@ -206,6 +206,7 @@ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
 extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
+extern const struct spinand_manufacturer other_spinand_manufacturer;
 
 /**
  * struct spinand_op_variants - SPI NAND operation variants
index 5e85513853c288f47a76079b087c164d40d2cbb9..6fb3b0e4e600b85dcec0f2d1dbf6c7d4597c2cbf 100644 (file)
 #define KERN_DEBUG
 #define KERN_CONT
 
+#if defined (CONFIG_SPL_BUILD)
+#define PRINTK_LOGLEVEL CONFIG_SPL_LOGLEVEL
+#else
+#define PRINTK_LOGLEVEL CONFIG_LOGLEVEL
+#endif
+
 #define printk(fmt, ...) \
        printf(fmt, ##__VA_ARGS__)
 
 
 #define pr_emerg(fmt, ...)                                             \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 0 ? log_emerg(fmt, ##__VA_ARGS__) : 0;        \
+       PRINTK_LOGLEVEL > 0 ? log_emerg(fmt, ##__VA_ARGS__) : 0;        \
 })
 #define pr_alert(fmt, ...)                                             \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 1 ? log_alert(fmt, ##__VA_ARGS__) : 0;        \
+       PRINTK_LOGLEVEL > 1 ? log_alert(fmt, ##__VA_ARGS__) : 0;        \
 })
 #define pr_crit(fmt, ...)                                              \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 2 ? log_crit(fmt, ##__VA_ARGS__) : 0;         \
+       PRINTK_LOGLEVEL > 2 ? log_crit(fmt, ##__VA_ARGS__) : 0;         \
 })
 #define pr_err(fmt, ...)                                               \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 3 ? log_err(fmt, ##__VA_ARGS__) : 0;          \
+       PRINTK_LOGLEVEL > 3 ? log_err(fmt, ##__VA_ARGS__) : 0;          \
 })
 #define pr_warn(fmt, ...)                                              \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 4 ? log_warning(fmt, ##__VA_ARGS__) : 0;      \
+       PRINTK_LOGLEVEL > 4 ? log_warning(fmt, ##__VA_ARGS__) : 0;      \
 })
 #define pr_notice(fmt, ...)                                            \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 5 ? log_notice(fmt, ##__VA_ARGS__) : 0;       \
+       PRINTK_LOGLEVEL > 5 ? log_notice(fmt, ##__VA_ARGS__) : 0;       \
 })
 #define pr_info(fmt, ...)                                              \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 6 ? log_info(fmt, ##__VA_ARGS__) : 0;         \
+       PRINTK_LOGLEVEL > 6 ? log_info(fmt, ##__VA_ARGS__) : 0;         \
 })
 #define pr_debug(fmt, ...)                                             \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 7 ? log_debug(fmt, ##__VA_ARGS__) : 0;        \
+       PRINTK_LOGLEVEL > 7 ? log_debug(fmt, ##__VA_ARGS__) : 0;        \
 })
 #define pr_devel(fmt, ...)                                             \
 ({                                                                     \
-       CONFIG_LOGLEVEL > 7 ? log_debug(fmt, ##__VA_ARGS__) : 0;        \
+       PRINTK_LOGLEVEL > 7 ? log_debug(fmt, ##__VA_ARGS__) : 0;        \
 })
 
 #ifdef CONFIG_LOG
index df497bad1814d09d86ba82c7c5226e65db6f1dea..13d14be392881359bbec158c042d661b7b764c0e 100644 (file)
@@ -168,7 +168,7 @@ int _log_buffer(enum log_category_t cat, enum log_level_t level,
 #define _LOG_MAX_LEVEL LOGL_INFO
 #endif
 
-#define log_emer(_fmt...)      log(LOG_CATEGORY, LOGL_EMERG, ##_fmt)
+#define log_emerg(_fmt...)     log(LOG_CATEGORY, LOGL_EMERG, ##_fmt)
 #define log_alert(_fmt...)     log(LOG_CATEGORY, LOGL_ALERT, ##_fmt)
 #define log_crit(_fmt...)      log(LOG_CATEGORY, LOGL_CRIT, ##_fmt)
 #define log_err(_fmt...)       log(LOG_CATEGORY, LOGL_ERR, ##_fmt)
index 6f604e7315acad10a342ca4f258ffdd0fd1e54d6..d3f50d59b117839ef11f3c5a065eb1543035233e 100644 (file)
@@ -51,7 +51,12 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+
+#if CONFIG_IS_ENABLED(ENABLE_SET_NUM_PART_SEARCH)
+#define MAX_SEARCH_PARTITIONS CONFIG_MAX_SEARCH_PARTITIONS
+#else
 #define MAX_SEARCH_PARTITIONS 128
+#endif
 
 #define PART_BOOTABLE                  ((int)BIT(0))
 #define PART_EFI_SYSTEM_PARTITION      ((int)BIT(1))
diff --git a/include/power/spacemit/pm853.h b/include/power/spacemit/pm853.h
new file mode 100644 (file)
index 0000000..11344f9
--- /dev/null
@@ -0,0 +1,381 @@
+#ifndef __SPACEMIT_PM853_H__
+#define __SPACEMIT_PM853_H__
+
+#define SPACEMIT_PM853_ID_REG          0x0
+#define SPACEMIT_PM853_MAX_REG         0xf1
+
+#define SPACEMIT_PM853_ID              0x50
+
+#define PM853_LDO_BUCK_EN_REG0         0x11
+#define PM853_LDO_BUCK_EN_REG1         0x12
+#define PM853_LDO_BUCK_EN_REG2         0x13
+#define PM853_LDO_BUCK_EN_REG3         0x14
+
+#define PM853_BUCK1_EN_MSK             0x1
+#define PM853_BUCK2_EN_MSK             0x2
+#define PM853_BUCK3_EN_MSK             0x4
+#define PM853_BUCK4_EN_MSK             0x8
+#define PM853_BUCK5_EN_MSK             0x10
+
+#define PM853_LDO1_EN_MSK              0x20
+#define PM853_LDO2_EN_MSK              0x40
+#define PM853_LDO3_EN_MSK              0x80
+#define PM853_LDO4_EN_MSK              0x1
+#define PM853_LDO5_EN_MSK              0x2
+#define PM853_LDO6_EN_MSK              0x4
+#define PM853_LDO7_EN_MSK              0x8
+#define PM853_LDO8_EN_MSK              0x10
+#define PM853_LDO9_EN_MSK              0x20
+#define PM853_LDO10_EN_MSK             0x40
+#define PM853_LDO11_EN_MSK             0x80
+#define PM853_LDO12_EN_MSK             0x1
+#define PM853_LDO13_EN_MSK             0x2
+#define PM853_LDO14_EN_MSK             0x4
+#define PM853_LDO15_EN_MSK             0x8
+#define PM853_LDO16_EN_MSK             0x10
+#define PM853_LDO17_EN_MSK             0x20
+#define PM853_LDO18_EN_MSK             0x40
+#define PM853_LDO19_EN_MSK             0x80
+#define PM853_LDO20_EN_MSK             0x1
+#define PM853_LDO21_EN_MSK             0x2
+#define PM853_LDO22_EN_MSK             0x4
+#define PM853_SW_EN_MSK                        0x8
+
+
+#define PM853_BUCK1_VSEL_REG           0x30
+#define PM853_BUCK2_VSEL_REG           0x50
+#define PM853_BUCK3_VSEL_REG           0x60
+#define PM853_BUCK4_VSEL_REG           0x80
+#define PM853_BUCK5_VSEL_REG           0x90
+
+#define PM853_BUCK1_VSEL_MSK           0x7f
+#define PM853_BUCK2_VSEL_MSK           0x7f
+#define PM853_BUCK3_VSEL_MSK           0x7f
+#define PM853_BUCK4_VSEL_MSK           0x7f
+#define PM853_BUCK5_VSEL_MSK           0x7f
+
+#define PM853_BUCK1_SVSEL_REG          0x32
+#define PM853_BUCK2_SVSEL_REG          0x51
+#define PM853_BUCK3_SVSEL_REG          0x61
+#define PM853_BUCK4_SVSEL_REG          0x81
+#define PM853_BUCK5_SVSEL_REG          0x91
+
+#define PM853_BUCK_SVSEL_MSK           0x7f
+
+
+#define PM853_LDO_VSEL_MSK             0xf
+#define PM853_LDO1_VSEL_REG            0xb1
+#define PM853_LDO2_VSEL_REG            0xb4
+#define PM853_LDO3_VSEL_REG            0xb7
+#define PM853_LDO4_VSEL_REG            0xba
+#define PM853_LDO5_VSEL_REG            0xbd
+#define PM853_LDO6_VSEL_REG            0xc0
+#define PM853_LDO7_VSEL_REG            0xc3
+#define PM853_LDO8_VSEL_REG            0xc6
+#define PM853_LDO9_VSEL_REG            0xc9
+#define PM853_LDO10_VSEL_REG           0xcc
+#define PM853_LDO11_VSEL_REG           0xcf
+#define PM853_LDO12_VSEL_REG           0xd2
+#define PM853_LDO13_VSEL_REG           0xd5
+#define PM853_LDO14_VSEL_REG           0xd8
+#define PM853_LDO15_VSEL_REG           0xdb
+#define PM853_LDO16_VSEL_REG           0xde
+#define PM853_LDO17_VSEL_REG           0xe1
+#define PM853_LDO18_VSEL_REG           0xe4
+#define PM853_LDO19_VSEL_REG           0xe7
+#define PM853_LDO20_VSEL_REG           0xea
+#define PM853_LDO21_VSEL_REG           0xed
+#define PM853_LDO22_VSEL_REG           0xf0
+
+#define PM853_LDO1_SVSEL_REG           0xb0
+#define PM853_LDO2_SVSEL_REG           0xb3
+#define PM853_LDO3_SVSEL_REG           0xb6
+#define PM853_LDO4_SVSEL_REG           0xb9
+#define PM853_LDO5_SVSEL_REG           0xbc
+#define PM853_LDO6_SVSEL_REG           0xbf
+#define PM853_LDO7_SVSEL_REG           0xc2
+#define PM853_LDO8_SVSEL_REG           0xc5
+#define PM853_LDO9_SVSEL_REG           0xc8
+#define PM853_LDO10_SVSEL_REG          0xcb
+#define PM853_LDO11_SVSEL_REG          0xce
+#define PM853_LDO12_SVSEL_REG          0xd1
+#define PM853_LDO13_SVSEL_REG          0xd4
+#define PM853_LDO14_SVSEL_REG          0xd7
+#define PM853_LDO15_SVSEL_REG          0xda
+#define PM853_LDO16_SVSEL_REG          0xdd
+#define PM853_LDO17_SVSEL_REG          0xe0
+#define PM853_LDO18_SVSEL_REG          0xe3
+#define PM853_LDO19_SVSEL_REG          0xe6
+#define PM853_LDO20_SVSEL_REG          0xe9
+#define PM853_LDO21_SVSEL_REG          0xec
+#define PM853_LDO22_SVSEL_REG          0xef
+
+#define PM853_LDO_SVSEL_MSK            0xf
+
+enum PM853_buck_reg {
+       PM853_ID_DCDC1,
+       PM853_ID_DCDC2,
+       PM853_ID_DCDC3,
+       PM853_ID_DCDC4,
+       PM853_ID_DCDC5,
+};
+
+enum PM853_ldo_reg {
+       PM853_ID_LDO1,
+       PM853_ID_LDO2,
+       PM853_ID_LDO3,
+       PM853_ID_LDO4,
+       PM853_ID_LDO5,
+       PM853_ID_LDO6,
+       PM853_ID_LDO7,
+       PM853_ID_LDO8,
+       PM853_ID_LDO9,
+       PM853_ID_LDO10,
+       PM853_ID_LDO11,
+       PM853_ID_LDO12,
+       PM853_ID_LDO13,
+       PM853_ID_LDO14,
+       PM853_ID_LDO15,
+       PM853_ID_LDO16,
+       PM853_ID_LDO17,
+       PM853_ID_LDO18,
+       PM853_ID_LDO19,
+       PM853_ID_LDO20,
+       PM853_ID_LDO21,
+       PM853_ID_LDO22,
+};
+
+enum PM853_switch_reg {
+       PM853_ID_SWITCH1,
+};
+
+#define PM853_BUCK_LINER_RANGE1                                                \
+static const struct pm8xx_linear_range pm853_buck_ranges1[] = {                \
+        REGULATOR_LINEAR_RANGE(480000, 0x0, 0x50, 10000),              \
+        REGULATOR_LINEAR_RANGE(1320000, 0x51, 0x7F, 40000),            \
+};
+
+#define PM853_BUCK_LINER_RANGE2                                                \
+static const struct pm8xx_linear_range pm853_buck_ranges2[] = {                \
+        REGULATOR_LINEAR_RANGE(600000, 0x0, 0x50, 12500),              \
+        REGULATOR_LINEAR_RANGE(1650000, 0x51, 0x7F, 50000),            \
+};
+
+#define PM853_LDO_LINER_RANGE1                                         \
+static const struct pm8xx_linear_range pm853_ldo_ranges1[] = {         \
+        REGULATOR_LINEAR_RANGE(1200000, 0x0, 0x6, 100000),             \
+        REGULATOR_LINEAR_RANGE(1850000, 0x7, 0x8, 50000),              \
+        REGULATOR_LINEAR_RANGE(2750000, 0x9, 0xc, 50000),              \
+        REGULATOR_LINEAR_RANGE(3000000, 13, 14, 100000),               \
+        REGULATOR_LINEAR_RANGE(3300000, 15, 15, 0),            \
+};
+
+#define PM853_LDO_LINER_RANGE2                                         \
+static const struct pm8xx_linear_range pm853_ldo_ranges2[] = {         \
+        REGULATOR_LINEAR_RANGE(1600000, 0x0, 0x3, 100000),             \
+};
+
+#define PM853_LDO_LINER_RANGE3                                         \
+static const struct pm8xx_linear_range pm853_ldo_ranges3[] = {         \
+        REGULATOR_LINEAR_RANGE(1200000, 0x0, 0xf, 50000),              \
+};
+
+#define PM853_LDO_LINER_RANGE4                                         \
+static const struct pm8xx_linear_range pm853_ldo_ranges4[] = {         \
+        REGULATOR_LINEAR_RANGE(1000000, 0x0, 0x7, 50000),              \
+};
+
+#define PM853_SWITCH_LINER_RANGE                                       \
+static const struct pm8xx_linear_range pm853_switch_ranges[] = {               \
+};
+
+#define PM853_REGULATOR_BUCK_DESC              \
+static const struct pm8xx_buck_desc pm853_buck_desc[] = {      \
+       /* BUCK */              \
+       PM8XX_DESC_COMMON(PM853_ID_DCDC1, "DCDC_REG1",                                  \
+                       128, PM853_BUCK1_VSEL_REG, PM853_BUCK1_VSEL_MSK,        \
+                       PM853_LDO_BUCK_EN_REG0, PM853_BUCK1_EN_MSK,             \
+                       PM853_BUCK1_SVSEL_REG, PM853_BUCK_SVSEL_MSK,            \
+                       pm853_buck_ranges1),    \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_DCDC2, "DCDC_REG2",                                  \
+                       128, PM853_BUCK2_VSEL_REG, PM853_BUCK2_VSEL_MSK,        \
+                       PM853_LDO_BUCK_EN_REG0, PM853_BUCK2_EN_MSK,             \
+                       PM853_BUCK2_SVSEL_REG, PM853_BUCK_SVSEL_MSK,            \
+                       pm853_buck_ranges2),    \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_DCDC3, "DCDC_REG3",                                  \
+                       128, PM853_BUCK3_VSEL_REG, PM853_BUCK3_VSEL_MSK,        \
+                       PM853_LDO_BUCK_EN_REG0, PM853_BUCK3_EN_MSK,             \
+                       PM853_BUCK3_SVSEL_REG, PM853_BUCK_SVSEL_MSK,            \
+                       pm853_buck_ranges2),    \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_DCDC4, "DCDC_REG4",                                  \
+                       128, PM853_BUCK4_VSEL_REG, PM853_BUCK4_VSEL_MSK,        \
+                       PM853_LDO_BUCK_EN_REG0, PM853_BUCK4_EN_MSK,             \
+                       PM853_BUCK4_SVSEL_REG, PM853_BUCK_SVSEL_MSK,            \
+                       pm853_buck_ranges1),    \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_DCDC5, "DCDC_REG5",                                  \
+                       128, PM853_BUCK5_VSEL_REG, PM853_BUCK5_VSEL_MSK,        \
+                       PM853_LDO_BUCK_EN_REG0, PM853_BUCK5_EN_MSK,             \
+                       PM853_BUCK5_SVSEL_REG, PM853_BUCK_SVSEL_MSK,            \
+                       pm853_buck_ranges2),    \
+};
+
+#define PM853_REGULATOR_LDO_DESC               \
+static const struct pm8xx_buck_desc pm853_ldo_desc[] = {       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO1, "LDO_REG1",                                    \
+                       16, PM853_LDO1_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG0, PM853_LDO1_EN_MSK,              \
+                       PM853_LDO1_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO2, "LDO_REG2",                                    \
+                       16, PM853_LDO2_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG0, PM853_LDO2_EN_MSK,              \
+                       PM853_LDO2_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO3, "LDO_REG3",                                    \
+                       16, PM853_LDO3_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG0, PM853_LDO3_EN_MSK,              \
+                       PM853_LDO3_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO4, "LDO_REG4",                                    \
+                       16, PM853_LDO4_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO4_EN_MSK,              \
+                       PM853_LDO4_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO5, "LDO_REG5",                                    \
+                       4, PM853_LDO5_VSEL_REG, PM853_LDO_VSEL_MSK,             \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO5_EN_MSK,              \
+                       PM853_LDO5_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges2),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO6, "LDO_REG6",                    \
+                       16, PM853_LDO6_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO6_EN_MSK,              \
+                       PM853_LDO6_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO7, "LDO_REG7",                    \
+                       16, PM853_LDO7_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO7_EN_MSK,              \
+                       PM853_LDO7_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges3),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO8, "LDO_REG8",                    \
+                       16, PM853_LDO8_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO8_EN_MSK,              \
+                       PM853_LDO8_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO9, "LDO_REG9",                    \
+                       16, PM853_LDO9_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO9_EN_MSK,              \
+                       PM853_LDO9_SVSEL_REG, PM853_LDO_SVSEL_MSK,              \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO10, "LDO_REG10",                  \
+                       16, PM853_LDO10_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO10_EN_MSK,             \
+                       PM853_LDO10_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO11, "LDO_REG11",                  \
+                       16, PM853_LDO11_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG1, PM853_LDO11_EN_MSK,             \
+                       PM853_LDO11_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges3),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO12, "LDO_REG12",                  \
+                       16, PM853_LDO12_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO12_EN_MSK,             \
+                       PM853_LDO12_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO13, "LDO_REG13",                  \
+                       16, PM853_LDO13_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO13_EN_MSK,             \
+                       PM853_LDO13_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO14, "LDO_REG14",                  \
+                       16, PM853_LDO14_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO14_EN_MSK,             \
+                       PM853_LDO14_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO15, "LDO_REG15",                  \
+                       16, PM853_LDO15_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO15_EN_MSK,             \
+                       PM853_LDO15_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges3),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO16, "LDO_REG16",                  \
+                       16, PM853_LDO16_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO16_EN_MSK,             \
+                       PM853_LDO16_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges1),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO17, "LDO_REG17",                  \
+                       8, PM853_LDO17_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO17_EN_MSK,             \
+                       PM853_LDO17_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges4),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO18, "LDO_REG18",                  \
+                       16, PM853_LDO18_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO18_EN_MSK,             \
+                       PM853_LDO18_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges3),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO19, "LDO_REG19",                  \
+                       8, PM853_LDO19_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG2, PM853_LDO19_EN_MSK,             \
+                       PM853_LDO19_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges4),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO20, "LDO_REG20",                  \
+                       8, PM853_LDO20_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG3, PM853_LDO20_EN_MSK,             \
+                       PM853_LDO20_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges4),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO21, "LDO_REG21",                  \
+                       16, PM853_LDO21_VSEL_REG, PM853_LDO_VSEL_MSK,           \
+                       PM853_LDO_BUCK_EN_REG3, PM853_LDO21_EN_MSK,             \
+                       PM853_LDO21_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges3),                                     \
+       \
+       PM8XX_DESC_COMMON(PM853_ID_LDO22, "LDO_REG22",                  \
+                       8, PM853_LDO22_VSEL_REG, PM853_LDO_VSEL_MSK,            \
+                       PM853_LDO_BUCK_EN_REG3, PM853_LDO22_EN_MSK,             \
+                       PM853_LDO22_SVSEL_REG, PM853_LDO_SVSEL_MSK,             \
+                       pm853_ldo_ranges4),                                     \
+};
+
+#define PM853_REGULATOR_SWITCH_DESC            \
+static const struct pm8xx_buck_desc pm853_switch_desc[] = {    \
+       PM8XX_DESC_COMMON(PM853_ID_SWITCH1, "SWITCH_REG1", 0, PM853_LDO_BUCK_EN_REG3, PM853_SW_EN_MSK,  \
+                       0, 0, 0, 0, pm853_switch_ranges),               \
+};
+
+#define PM853_REGULATOR_MATCH_DATA                                     \
+struct regulator_match_data pm853_regulator_match_data = {             \
+       .nr_buck_desc = ARRAY_SIZE(pm853_buck_desc),                            \
+       .buck_desc = pm853_buck_desc,                                           \
+       .nr_ldo_desc = ARRAY_SIZE(pm853_ldo_desc),                              \
+       .ldo_desc = pm853_ldo_desc,                                             \
+       .nr_switch_desc = ARRAY_SIZE(pm853_switch_desc),                        \
+       .switch_desc = pm853_switch_desc,                                       \
+       .name = "pm853",                                                        \
+       .max_registers = 0xf1,                                                  \
+};
+
+#define DECLEAR_PM853_REGULATOR_MATCH_DATA     extern struct regulator_match_data pm853_regulator_match_data;
+
+#endif /* __SPACEMIT_PM853_H__ */
diff --git a/include/power/spacemit/spacemit_pmic.h b/include/power/spacemit/spacemit_pmic.h
new file mode 100644 (file)
index 0000000..c966067
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __SPACEMIT_PMIC_H__
+#define __SPACEMIT_PMIC_H__
+
+#include <linux/kernel.h>
+struct regulator_match_data;
+
+struct pm8xx_priv {
+       struct regulator_match_data *match;
+};
+
+struct pm8xx_linear_range {
+       unsigned int min;
+       unsigned int min_sel;
+       unsigned int max_sel;
+       unsigned int step;
+};
+
+struct pm8xx_buck_desc {
+       const char *name;
+       int n_voltages;
+       int vsel_reg;
+       int vsel_msk;
+       int enable_reg;
+       int enable_msk;
+       int vsel_sleep_reg;
+       int vsel_sleep_msk;
+       int n_linear_ranges;
+       const struct pm8xx_linear_range *linear_ranges;
+};
+
+/* regulator: match data */
+struct regulator_match_data {
+        int nr_buck_desc;
+        const struct pm8xx_buck_desc *buck_desc;
+        int nr_ldo_desc;
+        const struct pm8xx_buck_desc *ldo_desc;
+        int nr_switch_desc;
+        const struct pm8xx_buck_desc *switch_desc;
+       int max_registers;
+        const char *name;
+};
+
+/* Initialize struct linear_range for regulators */
+#define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV)   \
+{                                                                       \
+        .min            = _min_uV,                                      \
+        .min_sel        = _min_sel,                                     \
+        .max_sel        = _max_sel,                                     \
+        .step           = _step_uV,                                     \
+}
+
+/* common regulator defination */
+#define PM8XX_DESC_COMMON(_id, _match, _nv, _vr, _vm, _er, _em, _vs, _vsm, _lr)                \
+       [_id] = {                                                       \
+               .name           = (_match),                             \
+               .n_voltages     = (_nv),                                \
+               .vsel_reg       = (_vr),                                \
+               .vsel_msk       = (_vm),                                \
+               .vsel_sleep_reg = (_vs),                                \
+               .vsel_sleep_msk = (_vsm),                               \
+               .enable_reg     = (_er),                                \
+               .enable_msk     = (_em),                                \
+               .linear_ranges  = (_lr),                                \
+               .n_linear_ranges        = ARRAY_SIZE(_lr),              \
+       }
+
+
+#include "spm8821.h"
+#include "pm853.h"
+#include "sy8810l.h"
+
+#endif /* __SPACEMIT_PMIC_H__ */
diff --git a/include/power/spacemit/spm8821.h b/include/power/spacemit/spm8821.h
new file mode 100644 (file)
index 0000000..ef34b76
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef __SPACEMIT_SPM8821_H__
+#define __SPACEMIT_SPM8821_H__
+
+#define SPACEMIT_SPM8821_ID_REG                0x0
+#define SPACEMIT_SPM8821_MAX_REG       0xA8
+
+#define SPACEMIT_SPM8821_ID            0x2
+
+#define SPM8821_BUCK_VSEL_MASK         0xff
+#define SMP8821_BUCK_EN_MASK           0x1
+
+#define SPM8821_BUCK1_CTRL_REG         0x47
+#define SPM8821_BUCK2_CTRL_REG         0x4a
+#define SPM8821_BUCK3_CTRL_REG         0x4d
+#define SPM8821_BUCK4_CTRL_REG         0x50
+#define SPM8821_BUCK5_CTRL_REG         0x53
+#define SPM8821_BUCK6_CTRL_REG         0x56
+
+#define SPM8821_BUCK1_VSEL_REG         0x48
+#define SPM8821_BUCK2_VSEL_REG         0x4b
+#define SPM8821_BUCK3_VSEL_REG         0x4e
+#define SPM8821_BUCK4_VSEL_REG         0x51
+#define SPM8821_BUCK5_VSEL_REG         0x54
+#define SPM8821_BUCK6_VSEL_REG         0x57
+
+#define SPM8821_BUCK1_SVSEL_REG                0x49
+#define SPM8821_BUCK2_SVSEL_REG                0x4c
+#define SPM8821_BUCK3_SVSEL_REG                0x4f
+#define SPM8821_BUCK4_SVSEL_REG                0x52
+#define SPM8821_BUCK5_SVSEL_REG                0x55
+#define SPM8821_BUCK6_SVSEL_REG                0x58
+
+#define SPM8821_BUCK_SVSEL_MASK                0xff
+
+#define SPM8821_ALDO1_CTRL_REG         0x5b
+#define SPM8821_ALDO2_CTRL_REG         0x5e
+#define SPM8821_ALDO3_CTRL_REG         0x61
+#define SPM8821_ALDO4_CTRL_REG         0x64
+
+#define SPM8821_ALDO1_VOLT_REG         0x5c
+#define SPM8821_ALDO2_VOLT_REG         0x5f
+#define SPM8821_ALDO3_VOLT_REG         0x62
+#define SPM8821_ALDO4_VOLT_REG         0x65
+
+#define SPM8821_ALDO1_SVOLT_REG                0x5d
+#define SPM8821_ALDO2_SVOLT_REG                0x60
+#define SPM8821_ALDO3_SVOLT_REG                0x63
+#define SPM8821_ALDO4_SVOLT_REG                0x66
+#define SPM8821_ALDO_SVSEL_MASK                0x3f
+
+#define SPM8821_ALDO_EN_MASK           0x1
+#define SPM8821_ALDO_VSEL_MASK         0x3f
+
+#define SPM8821_DLDO1_CTRL_REG         0x67
+#define SPM8821_DLDO2_CTRL_REG         0x6a
+#define SPM8821_DLDO3_CTRL_REG         0x6d
+#define SPM8821_DLDO4_CTRL_REG         0x70
+#define SPM8821_DLDO5_CTRL_REG         0x73
+#define SPM8821_DLDO6_CTRL_REG         0x76
+#define SPM8821_DLDO7_CTRL_REG         0x79
+
+#define SPM8821_DLDO1_VOLT_REG         0x68
+#define SPM8821_DLDO2_VOLT_REG         0x6b
+#define SPM8821_DLDO3_VOLT_REG         0x6e
+#define SPM8821_DLDO4_VOLT_REG         0x71
+#define SPM8821_DLDO5_VOLT_REG         0x74
+#define SPM8821_DLDO6_VOLT_REG         0x77
+#define SPM8821_DLDO7_VOLT_REG         0x7a
+
+#define SPM8821_DLDO1_SVOLT_REG                0x69
+#define SPM8821_DLDO2_SVOLT_REG                0x6c
+#define SPM8821_DLDO3_SVOLT_REG                0x6f
+#define SPM8821_DLDO4_SVOLT_REG                0x72
+#define SPM8821_DLDO5_SVOLT_REG                0x75
+#define SPM8821_DLDO6_SVOLT_REG                0x78
+#define SPM8821_DLDO7_SVOLT_REG                0x7b
+
+#define SPM8821_DLDO_SVSEL_MASK                0x3f
+
+#define SPM8821_DLDO_EN_MASK           0x1
+#define SPM8821_DLDO_VSEL_MASK         0x3f
+
+#define SPM8821_SWITCH_CTRL_REG                0x59
+#define SPM8821_SWTICH_EN_MASK         0x1
+
+enum SPM8821_buck_reg {
+       SPM8821_ID_DCDC1,
+       SPM8821_ID_DCDC2,
+       SPM8821_ID_DCDC3,
+       SPM8821_ID_DCDC4,
+       SPM8821_ID_DCDC5,
+       SPM8821_ID_DCDC6,
+};
+
+enum SPM8821_ldo_reg {
+       SPM8821_ID_LDO1,
+       SPM8821_ID_LDO2,
+       SPM8821_ID_LDO3,
+       SPM8821_ID_LDO4,
+       SPM8821_ID_LDO5,
+       SPM8821_ID_LDO6,
+       SPM8821_ID_LDO7,
+       SPM8821_ID_LDO8,
+       SPM8821_ID_LDO9,
+       SPM8821_ID_LDO10,
+       SPM8821_ID_LDO11,
+};
+
+enum SPM8821_switch_reg {
+       SPM8821_ID_SWITCH1,
+};
+
+#define SPM8821_BUCK_LINER_RANGE                                       \
+static const struct pm8xx_linear_range spm8821_buck_ranges[] = {               \
+        REGULATOR_LINEAR_RANGE(500000, 0x0, 0xaa, 5000),               \
+        REGULATOR_LINEAR_RANGE(1375000, 0xab, 0xfe, 25000),            \
+};
+
+#define SPM8821_LDO_LINER_RANGE                                                \
+static const struct pm8xx_linear_range spm8821_ldo_ranges[] = {                \
+        REGULATOR_LINEAR_RANGE(500000, 0xb, 0x7f, 25000),              \
+};
+
+#define SPM8821_SWITCH_LINER_RANGE                                     \
+static const struct pm8xx_linear_range spm8821_switch_ranges[] = {             \
+};
+
+#define SPM8821_REGULATOR_BUCK_DESC            \
+static const struct pm8xx_buck_desc spm8821_buck_desc[] = {    \
+       /* BUCK */              \
+       PM8XX_DESC_COMMON(SPM8821_ID_DCDC1, "DCDC_REG1",                        \
+                       255, SPM8821_BUCK1_VSEL_REG, SPM8821_BUCK_VSEL_MASK,    \
+                       SPM8821_BUCK1_CTRL_REG, SMP8821_BUCK_EN_MASK,           \
+                       SPM8821_BUCK1_SVSEL_REG, SPM8821_BUCK_SVSEL_MASK,       \
+                       spm8821_buck_ranges),   \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_DCDC2, "DCDC_REG2",                                \
+                       255, SPM8821_BUCK2_VSEL_REG, SPM8821_BUCK_VSEL_MASK,    \
+                       SPM8821_BUCK2_CTRL_REG, SMP8821_BUCK_EN_MASK,   \
+                       SPM8821_BUCK2_SVSEL_REG, SPM8821_BUCK_SVSEL_MASK,       \
+                       spm8821_buck_ranges),   \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_DCDC3, "DCDC_REG3",                                \
+                       255, SPM8821_BUCK3_VSEL_REG, SPM8821_BUCK_VSEL_MASK,    \
+                       SPM8821_BUCK3_CTRL_REG, SMP8821_BUCK_EN_MASK,   \
+                       SPM8821_BUCK3_SVSEL_REG, SPM8821_BUCK_SVSEL_MASK,       \
+                       spm8821_buck_ranges),   \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_DCDC4, "DCDC_REG4",                                \
+                       255, SPM8821_BUCK4_VSEL_REG, SPM8821_BUCK_VSEL_MASK,    \
+                       SPM8821_BUCK4_CTRL_REG, SMP8821_BUCK_EN_MASK,   \
+                       SPM8821_BUCK4_SVSEL_REG, SPM8821_BUCK_SVSEL_MASK,       \
+                       spm8821_buck_ranges),   \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_DCDC5, "DCDC_REG5",                                \
+                       255, SPM8821_BUCK5_VSEL_REG, SPM8821_BUCK_VSEL_MASK,    \
+                       SPM8821_BUCK5_CTRL_REG, SMP8821_BUCK_EN_MASK,   \
+                       SPM8821_BUCK5_SVSEL_REG, SPM8821_BUCK_SVSEL_MASK,       \
+                       spm8821_buck_ranges),   \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_DCDC6, "DCDC_REG6",                                \
+                       255, SPM8821_BUCK6_VSEL_REG, SPM8821_BUCK_VSEL_MASK,    \
+                       SPM8821_BUCK6_CTRL_REG, SMP8821_BUCK_EN_MASK,   \
+                       SPM8821_BUCK6_SVSEL_REG, SPM8821_BUCK_SVSEL_MASK,       \
+                       spm8821_buck_ranges),   \
+};
+
+#define SPM8821_REGULATOR_LDO_DESC             \
+static const struct pm8xx_buck_desc spm8821_ldo_desc[] = {     \
+       /* ALDO */      \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO1, "LDO_REG1",  \
+                       128, SPM8821_ALDO1_VOLT_REG, SPM8821_ALDO_VSEL_MASK,    \
+                       SPM8821_ALDO1_CTRL_REG, SPM8821_ALDO_EN_MASK,           \
+                       SPM8821_ALDO1_SVOLT_REG, SPM8821_ALDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO2, "LDO_REG2",\
+                       128, SPM8821_ALDO2_VOLT_REG, SPM8821_ALDO_VSEL_MASK,    \
+                       SPM8821_ALDO2_CTRL_REG, SPM8821_ALDO_EN_MASK,           \
+                       SPM8821_ALDO2_SVOLT_REG, SPM8821_ALDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO3, "LDO_REG3",  \
+                       128, SPM8821_ALDO3_VOLT_REG, SPM8821_ALDO_VSEL_MASK,    \
+                       SPM8821_ALDO3_CTRL_REG, SPM8821_ALDO_EN_MASK,           \
+                       SPM8821_ALDO3_SVOLT_REG, SPM8821_ALDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO4, "LDO_REG4",\
+                       128, SPM8821_ALDO4_VOLT_REG, SPM8821_ALDO_VSEL_MASK,    \
+                       SPM8821_ALDO4_CTRL_REG, SPM8821_ALDO_EN_MASK,           \
+                       SPM8821_ALDO4_SVOLT_REG, SPM8821_ALDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       /* DLDO */      \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO5, "LDO_REG5",\
+                       128, SPM8821_DLDO1_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO1_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO1_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO6, "LDO_REG6",\
+                       128, SPM8821_DLDO2_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO2_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO2_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO7, "LDO_REG7",\
+                       128, SPM8821_DLDO3_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO3_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO3_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO8, "LDO_REG8",\
+                       128, SPM8821_DLDO4_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO4_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO4_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO9, "LDO_REG9",\
+                       128, SPM8821_DLDO5_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO5_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO5_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO10, "LDO_REG10",\
+                       128, SPM8821_DLDO6_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO6_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO6_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+       PM8XX_DESC_COMMON(SPM8821_ID_LDO11, "LDO_REG11",\
+                       128, SPM8821_DLDO7_VOLT_REG, SPM8821_DLDO_VSEL_MASK,    \
+                       SPM8821_DLDO7_CTRL_REG, SPM8821_DLDO_EN_MASK,           \
+                       SPM8821_DLDO7_SVOLT_REG, SPM8821_DLDO_SVSEL_MASK,       \
+                       spm8821_ldo_ranges),    \
+       \
+};
+
+#define SPM8821_REGULATOR_SWITCH_DESC          \
+static const struct pm8xx_buck_desc spm8821_switch_desc[] = {  \
+       /* PWR SWITCH */        \
+       PM8XX_DESC_COMMON(SPM8821_ID_SWITCH1, "SWITCH_REG", 0, SPM8821_SWITCH_CTRL_REG, SPM8821_SWTICH_EN_MASK,         \
+                       0, 0, 0, 0, spm8821_switch_ranges),     \
+};
+
+#define SPM8821_REGULATOR_MATCH_DATA                                   \
+struct regulator_match_data spm8821_regulator_match_data = {   \
+       .nr_buck_desc = ARRAY_SIZE(spm8821_buck_desc),                          \
+       .buck_desc = spm8821_buck_desc,                                         \
+       .nr_ldo_desc = ARRAY_SIZE(spm8821_ldo_desc),                            \
+       .ldo_desc = spm8821_ldo_desc,                                           \
+       .nr_switch_desc = ARRAY_SIZE(spm8821_switch_desc),                      \
+       .switch_desc = spm8821_switch_desc,                                     \
+       .name = "spm8821",                                                      \
+        .max_registers = 0xA8,                                                 \
+};
+
+#define DECLEAR_SPM8821_REGULATOR_MATCH_DATA extern struct regulator_match_data spm8821_regulator_match_data;
+
+#endif /* __SPACEMIT_SPM8821_H__ */
diff --git a/include/power/spacemit/sy8810l.h b/include/power/spacemit/sy8810l.h
new file mode 100644 (file)
index 0000000..e2589fd
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __SY8810L_H__
+#define __SY8810L_H__
+
+enum SY8810L_reg {
+       SY8810L_ID_DCDC1,
+};
+
+#define SPACEMIT_SY8810L_MAX_REG       0x2
+
+#define SY8810L_BUCK_VSEL_MASK         0x3f
+#define SY8810L_BUCK_EN_MASK           0x80
+
+#define SY8810L_BUCK_CTRL_REG          0x1
+#define SY8810L_BUCK_VSEL_REG          0x0
+
+#define SY8810L_BUCK_LINER_RANGE                                       \
+static const struct pm8xx_linear_range sy8810l_buck_ranges[] = {       \
+        REGULATOR_LINEAR_RANGE(600000, 0x0, 0x5a, 10000),              \
+};
+
+#define SY8810L_REGULATOR_DESC         \
+static const struct pm8xx_buck_desc sy8810l_buck_desc[] = {                    \
+       /* BUCK */              \
+       PM8XX_DESC_COMMON(SY8810L_ID_DCDC1, "EDCDC_REG1",                       \
+                       91, SY8810L_BUCK_VSEL_REG, SY8810L_BUCK_VSEL_MASK,      \
+                       SY8810L_BUCK_CTRL_REG, SY8810L_BUCK_EN_MASK,            \
+                       0, 0,                                                   \
+                       sy8810l_buck_ranges),   \
+};
+
+#define SY8810L_REGULATOR_MATCH_DATA                                           \
+struct regulator_match_data sy8810l_regulator_match_data = {                   \
+       .nr_buck_desc = ARRAY_SIZE(sy8810l_buck_desc),                          \
+       .buck_desc = sy8810l_buck_desc,                                         \
+       .nr_ldo_desc = 0,                                                       \
+       .ldo_desc = NULL,                                                       \
+       .nr_switch_desc = 0,                                                    \
+       .switch_desc = NULL,                                                    \
+       .name = "sy8810l",                                                      \
+       .max_registers = 0x2,/* SPACEMIT_SY8810L_MAX_REG */                     \
+};
+
+#define DECLEAR_SY8810L_REGULATOR_MATCH_DATA   extern struct regulator_match_data sy8810l_regulator_match_data;
+
+#endif
index 33e45e6941632dcbc93c663d53de6d18426b41b7..b83e161137cc7a0f75171eb2f232aa319b8c1ea8 100644 (file)
@@ -31,6 +31,7 @@ enum splash_storage {
        SPLASH_STORAGE_USB,
        SPLASH_STORAGE_SATA,
        SPLASH_STORAGE_VIRTIO,
+       SPLASH_STORAGE_NVME,
 };
 
 enum splash_flags {
@@ -50,6 +51,7 @@ struct splash_location {
 };
 
 #ifdef CONFIG_SPLASH_SOURCE
+int splash_video_logo_load(void);
 int splash_source_load(struct splash_location *locations, uint size);
 #else
 static inline int splash_source_load(struct splash_location *locations,
index 6121c80dc818da621d37850e46e70872bfe3abfe..e83ac60857dd77806d0e42cc06e2e87a1c067506 100644 (file)
@@ -130,6 +130,13 @@ config IMAGE_SPARSE_FILLBUF_SIZE
          Set the size of the fill buffer used when processing CHUNK_TYPE_FILL
          chunks.
 
+config IMAGE_SPARSE_TRANSFER_BLK_NUM
+       hex "Android sparse image transfer buffer block num"
+       default 0x400
+       depends on IMAGE_SPARSE
+       help
+         Set the size of the transfer buffer used when transfer data to storage.
+
 config USE_PRIVATE_LIBGCC
        bool "Use private libgcc"
        depends on HAVE_PRIVATE_LIBGCC
index e3deb1528794f484bd3ec4d0d17ecbf634f1d881..d6be61b66bca47ca15f359b9323fb9df60f71812 100644 (file)
@@ -124,6 +124,7 @@ obj-$(CONFIG_TRACE) += trace.o
 obj-$(CONFIG_LIB_UUID) += uuid.o
 obj-$(CONFIG_LIB_RAND) += rand.o
 obj-y += panic.o
+obj-y += cJSON.o
 
 ifeq ($(CONFIG_$(SPL_TPL_)BUILD),y)
 # SPL U-Boot may use full-printf, tiny-printf or none at all
diff --git a/lib/cJSON.c b/lib/cJSON.c
new file mode 100644 (file)
index 0000000..92bbd06
--- /dev/null
@@ -0,0 +1,2976 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning (push)
+/* disable warning about single line comments in system headers */
+#pragma warning (disable : 4001)
+#endif
+
+#include <string.h>
+#include <stdio.h>
+// #include <math.h>
+#include <stdlib.h>
+#include <linux/kernel.h>
+#include <ctype.h>
+#include <common.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include "cJSON.h"
+
+/* define our own boolean type */
+#ifdef true
+#undef true
+#endif
+#define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
+#define false ((cJSON_bool)0)
+
+typedef struct {
+    const unsigned char *json;
+    size_t position;
+} error;
+static error global_error = { NULL, 0 };
+
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
+{
+    return (const char*) (global_error.json + global_error.position);
+}
+
+CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
+    if (!cJSON_IsString(item)) {
+        return NULL;
+    }
+
+    return item->valuestring;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12)
+    #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char*) cJSON_Version(void)
+{
+    static char version[15];
+    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+    return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
+{
+    if ((string1 == NULL) || (string2 == NULL))
+    {
+        return 1;
+    }
+
+    if (string1 == string2)
+    {
+        return 0;
+    }
+
+    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
+    {
+        if (*string1 == '\0')
+        {
+            return 0;
+        }
+    }
+
+    return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks
+{
+    void *(CJSON_CDECL *allocate)(size_t size);
+    void (CJSON_CDECL *deallocate)(void *pointer);
+    void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
+static void * CJSON_CDECL internal_malloc(size_t size)
+{
+    return malloc(size);
+}
+static void CJSON_CDECL internal_free(void *pointer)
+{
+    free(pointer);
+}
+static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
+{
+    return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
+
+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
+{
+    size_t length = 0;
+    unsigned char *copy = NULL;
+
+    if (string == NULL)
+    {
+        return NULL;
+    }
+
+    length = strlen((const char*)string) + sizeof("");
+    copy = (unsigned char*)hooks->allocate(length);
+    if (copy == NULL)
+    {
+        return NULL;
+    }
+    memcpy(copy, string, length);
+
+    return copy;
+}
+
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (hooks == NULL)
+    {
+        /* Reset hooks */
+        global_hooks.allocate = malloc;
+        global_hooks.deallocate = free;
+        global_hooks.reallocate = realloc;
+        return;
+    }
+
+    global_hooks.allocate = malloc;
+    if (hooks->malloc_fn != NULL)
+    {
+        global_hooks.allocate = hooks->malloc_fn;
+    }
+
+    global_hooks.deallocate = free;
+    if (hooks->free_fn != NULL)
+    {
+        global_hooks.deallocate = hooks->free_fn;
+    }
+
+    /* use realloc only if both free and malloc are used */
+    global_hooks.reallocate = NULL;
+    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+    {
+        global_hooks.reallocate = realloc;
+    }
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
+{
+    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
+    if (node)
+    {
+        memset(node, '\0', sizeof(cJSON));
+    }
+
+    return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
+{
+    cJSON *next = NULL;
+    while (item != NULL)
+    {
+        next = item->next;
+        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
+        {
+            cJSON_Delete(item->child);
+        }
+        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
+        {
+            global_hooks.deallocate(item->valuestring);
+        }
+        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+        {
+            global_hooks.deallocate(item->string);
+        }
+        global_hooks.deallocate(item);
+        item = next;
+    }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void)
+{
+#ifdef ENABLE_LOCALES
+    struct lconv *lconv = localeconv();
+    return (unsigned char) lconv->decimal_point[0];
+#else
+    return '.';
+#endif
+}
+
+typedef struct
+{
+    const unsigned char *content;
+    size_t length;
+    size_t offset;
+    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+    internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
+{
+    // double number = 0;
+    // unsigned char *after_end = NULL;
+    unsigned char number_c_string[64];
+    unsigned char decimal_point = get_decimal_point();
+    size_t i = 0;
+
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false;
+    }
+
+    /* copy the number into a temporary buffer and replace '.' with the decimal point
+     * of the current locale (for strtod)
+     * This also takes care of '\0' not necessarily being available for marking the end of the input */
+    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+    {
+        switch (buffer_at_offset(input_buffer)[i])
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case '+':
+            case '-':
+            case 'e':
+            case 'E':
+                number_c_string[i] = buffer_at_offset(input_buffer)[i];
+                break;
+
+            case '.':
+                number_c_string[i] = decimal_point;
+                break;
+
+            default:
+                goto loop_end;
+        }
+    }
+loop_end:
+    printf("not support double element\n");
+    return false;
+    // number_c_string[i] = '\0';
+
+    // number = strtod((const char*)number_c_string, (char**)&after_end);
+    // if (number_c_string == after_end)
+    // {
+    //     return false; /* parse_error */
+    // }
+
+    // item->valuedouble = number;
+
+    // /* use saturation in case of overflow */
+    // if (number >= INT_MAX)
+    // {
+    //     item->valueint = INT_MAX;
+    // }
+    // else if (number <= (double)INT_MIN)
+    // {
+    //     item->valueint = INT_MIN;
+    // }
+    // else
+    // {
+    //     item->valueint = (int)number;
+    // }
+
+    // item->type = cJSON_Number;
+
+    // input_buffer->offset += (size_t)(after_end - number_c_string);
+    // return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
+{
+    if (number >= INT_MAX)
+    {
+        object->valueint = INT_MAX;
+    }
+    else if (number <= (double)INT_MIN)
+    {
+        object->valueint = INT_MIN;
+    }
+    else
+    {
+        object->valueint = (int)number;
+    }
+
+    return object->valuedouble = number;
+}
+
+typedef struct
+{
+    unsigned char *buffer;
+    size_t length;
+    size_t offset;
+    size_t depth; /* current nesting depth (for formatted printing) */
+    cJSON_bool noalloc;
+    cJSON_bool format; /* is this print a formatted print */
+    internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char* ensure(printbuffer * const p, size_t needed)
+{
+    unsigned char *newbuffer = NULL;
+    size_t newsize = 0;
+
+    if ((p == NULL) || (p->buffer == NULL))
+    {
+        return NULL;
+    }
+
+    if ((p->length > 0) && (p->offset >= p->length))
+    {
+        /* make sure that offset is valid */
+        return NULL;
+    }
+
+    if (needed > INT_MAX)
+    {
+        /* sizes bigger than INT_MAX are currently not supported */
+        return NULL;
+    }
+
+    needed += p->offset + 1;
+    if (needed <= p->length)
+    {
+        return p->buffer + p->offset;
+    }
+
+    if (p->noalloc) {
+        return NULL;
+    }
+
+    /* calculate new buffer size */
+    if (needed > (INT_MAX / 2))
+    {
+        /* overflow of int, use INT_MAX if possible */
+        if (needed <= INT_MAX)
+        {
+            newsize = INT_MAX;
+        }
+        else
+        {
+            return NULL;
+        }
+    }
+    else
+    {
+        newsize = needed * 2;
+    }
+
+    if (p->hooks.reallocate != NULL)
+    {
+        /* reallocate with realloc if available */
+        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
+        if (newbuffer == NULL)
+        {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+    }
+    else
+    {
+        /* otherwise reallocate manually */
+        newbuffer = (unsigned char*)p->hooks.allocate(newsize);
+        if (!newbuffer)
+        {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+        if (newbuffer)
+        {
+            memcpy(newbuffer, p->buffer, p->offset + 1);
+        }
+        p->hooks.deallocate(p->buffer);
+    }
+    p->length = newsize;
+    p->buffer = newbuffer;
+
+    return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer * const buffer)
+{
+    const unsigned char *buffer_pointer = NULL;
+    if ((buffer == NULL) || (buffer->buffer == NULL))
+    {
+        return;
+    }
+    buffer_pointer = buffer->buffer + buffer->offset;
+
+    buffer->offset += strlen((const char*)buffer_pointer);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
+{
+    unsigned char *output_pointer = NULL;
+    double d = item->valuedouble;
+    int length = 0;
+    size_t i = 0;
+    unsigned char number_buffer[26]; /* temporary buffer to print the number into */
+    unsigned char decimal_point = get_decimal_point();
+    double test;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* This checks for NaN and Infinity */
+    if ((d * 0) != 0)
+    {
+        length = sprintf((char*)number_buffer, "null");
+    }
+    else
+    {
+        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+        length = sprintf((char*)number_buffer, "%1.15g", d);
+
+        /* Check whether the original double can be recovered */
+        if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
+        {
+            /* If not, print with 17 decimal places of precision */
+            length = sprintf((char*)number_buffer, "%1.17g", d);
+        }
+    }
+
+    /* sprintf failed or buffer overrun occurred */
+    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
+    {
+        return false;
+    }
+
+    /* reserve appropriate space in the output */
+    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    /* copy the printed number to the output and replace locale
+     * dependent decimal point with '.' */
+    for (i = 0; i < ((size_t)length); i++)
+    {
+        if (number_buffer[i] == decimal_point)
+        {
+            output_pointer[i] = '.';
+            continue;
+        }
+
+        output_pointer[i] = number_buffer[i];
+    }
+    output_pointer[i] = '\0';
+
+    output_buffer->offset += (size_t)length;
+
+    return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char * const input)
+{
+    unsigned int h = 0;
+    size_t i = 0;
+
+    for (i = 0; i < 4; i++)
+    {
+        /* parse digit */
+        if ((input[i] >= '0') && (input[i] <= '9'))
+        {
+            h += (unsigned int) input[i] - '0';
+        }
+        else if ((input[i] >= 'A') && (input[i] <= 'F'))
+        {
+            h += (unsigned int) 10 + input[i] - 'A';
+        }
+        else if ((input[i] >= 'a') && (input[i] <= 'f'))
+        {
+            h += (unsigned int) 10 + input[i] - 'a';
+        }
+        else /* invalid */
+        {
+            return 0;
+        }
+
+        if (i < 3)
+        {
+            /* shift left to make place for the next nibble */
+            h = h << 4;
+        }
+    }
+
+    return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
+{
+    long unsigned int codepoint = 0;
+    unsigned int first_code = 0;
+    const unsigned char *first_sequence = input_pointer;
+    unsigned char utf8_length = 0;
+    unsigned char utf8_position = 0;
+    unsigned char sequence_length = 0;
+    unsigned char first_byte_mark = 0;
+
+    if ((input_end - first_sequence) < 6)
+    {
+        /* input ends unexpectedly */
+        goto fail;
+    }
+
+    /* get the first utf16 sequence */
+    first_code = parse_hex4(first_sequence + 2);
+
+    /* check that the code is valid */
+    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
+    {
+        goto fail;
+    }
+
+    /* UTF16 surrogate pair */
+    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
+    {
+        const unsigned char *second_sequence = first_sequence + 6;
+        unsigned int second_code = 0;
+        sequence_length = 12; /* \uXXXX\uXXXX */
+
+        if ((input_end - second_sequence) < 6)
+        {
+            /* input ends unexpectedly */
+            goto fail;
+        }
+
+        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+        {
+            /* missing second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* get the second utf16 sequence */
+        second_code = parse_hex4(second_sequence + 2);
+        /* check that the code is valid */
+        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+        {
+            /* invalid second half of the surrogate pair */
+            goto fail;
+        }
+
+
+        /* calculate the unicode codepoint from the surrogate pair */
+        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+    }
+    else
+    {
+        sequence_length = 6; /* \uXXXX */
+        codepoint = first_code;
+    }
+
+    /* encode as UTF-8
+     * takes at maximum 4 bytes to encode:
+     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+    if (codepoint < 0x80)
+    {
+        /* normal ascii, encoding 0xxxxxxx */
+        utf8_length = 1;
+    }
+    else if (codepoint < 0x800)
+    {
+        /* two bytes, encoding 110xxxxx 10xxxxxx */
+        utf8_length = 2;
+        first_byte_mark = 0xC0; /* 11000000 */
+    }
+    else if (codepoint < 0x10000)
+    {
+        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 3;
+        first_byte_mark = 0xE0; /* 11100000 */
+    }
+    else if (codepoint <= 0x10FFFF)
+    {
+        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 4;
+        first_byte_mark = 0xF0; /* 11110000 */
+    }
+    else
+    {
+        /* invalid unicode codepoint */
+        goto fail;
+    }
+
+    /* encode as utf8 */
+    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
+    {
+        /* 10xxxxxx */
+        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+        codepoint >>= 6;
+    }
+    /* encode first byte */
+    if (utf8_length > 1)
+    {
+        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+    }
+    else
+    {
+        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+    }
+
+    *output_pointer += utf8_length;
+
+    return sequence_length;
+
+fail:
+    return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
+{
+    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+    unsigned char *output_pointer = NULL;
+    unsigned char *output = NULL;
+
+    /* not a string */
+    if (buffer_at_offset(input_buffer)[0] != '\"')
+    {
+        goto fail;
+    }
+
+    {
+        /* calculate approximate size of the output (overestimate) */
+        size_t allocation_length = 0;
+        size_t skipped_bytes = 0;
+        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
+        {
+            /* is escape sequence */
+            if (input_end[0] == '\\')
+            {
+                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+                {
+                    /* prevent buffer overflow when last input character is a backslash */
+                    goto fail;
+                }
+                skipped_bytes++;
+                input_end++;
+            }
+            input_end++;
+        }
+        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
+        {
+            goto fail; /* string ended unexpectedly */
+        }
+
+        /* This is at most how much we need for the output */
+        allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+        output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+        if (output == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+    }
+
+    output_pointer = output;
+    /* loop through the string literal */
+    while (input_pointer < input_end)
+    {
+        if (*input_pointer != '\\')
+        {
+            *output_pointer++ = *input_pointer++;
+        }
+        /* escape sequence */
+        else
+        {
+            unsigned char sequence_length = 2;
+            if ((input_end - input_pointer) < 1)
+            {
+                goto fail;
+            }
+
+            switch (input_pointer[1])
+            {
+                case 'b':
+                    *output_pointer++ = '\b';
+                    break;
+                case 'f':
+                    *output_pointer++ = '\f';
+                    break;
+                case 'n':
+                    *output_pointer++ = '\n';
+                    break;
+                case 'r':
+                    *output_pointer++ = '\r';
+                    break;
+                case 't':
+                    *output_pointer++ = '\t';
+                    break;
+                case '\"':
+                case '\\':
+                case '/':
+                    *output_pointer++ = input_pointer[1];
+                    break;
+
+                /* UTF-16 literal */
+                case 'u':
+                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+                    if (sequence_length == 0)
+                    {
+                        /* failed to convert UTF16-literal to UTF-8 */
+                        goto fail;
+                    }
+                    break;
+
+                default:
+                    goto fail;
+            }
+            input_pointer += sequence_length;
+        }
+    }
+
+    /* zero terminate the output */
+    *output_pointer = '\0';
+
+    item->type = cJSON_String;
+    item->valuestring = (char*)output;
+
+    input_buffer->offset = (size_t) (input_end - input_buffer->content);
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (output != NULL)
+    {
+        input_buffer->hooks.deallocate(output);
+    }
+
+    if (input_pointer != NULL)
+    {
+        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+    }
+
+    return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
+{
+    const unsigned char *input_pointer = NULL;
+    unsigned char *output = NULL;
+    unsigned char *output_pointer = NULL;
+    size_t output_length = 0;
+    /* numbers of additional characters needed for escaping */
+    size_t escape_characters = 0;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* empty string */
+    if (input == NULL)
+    {
+        output = ensure(output_buffer, sizeof("\"\""));
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char*)output, "\"\"");
+
+        return true;
+    }
+
+    /* set "flag" to 1 if something needs to be escaped */
+    for (input_pointer = input; *input_pointer; input_pointer++)
+    {
+        switch (*input_pointer)
+        {
+            case '\"':
+            case '\\':
+            case '\b':
+            case '\f':
+            case '\n':
+            case '\r':
+            case '\t':
+                /* one character escape sequence */
+                escape_characters++;
+                break;
+            default:
+                if (*input_pointer < 32)
+                {
+                    /* UTF-16 escape sequence uXXXX */
+                    escape_characters += 5;
+                }
+                break;
+        }
+    }
+    output_length = (size_t)(input_pointer - input) + escape_characters;
+
+    output = ensure(output_buffer, output_length + sizeof("\"\""));
+    if (output == NULL)
+    {
+        return false;
+    }
+
+    /* no characters have to be escaped */
+    if (escape_characters == 0)
+    {
+        output[0] = '\"';
+        memcpy(output + 1, input, output_length);
+        output[output_length + 1] = '\"';
+        output[output_length + 2] = '\0';
+
+        return true;
+    }
+
+    output[0] = '\"';
+    output_pointer = output + 1;
+    /* copy the string */
+    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
+    {
+        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
+        {
+            /* normal character, copy */
+            *output_pointer = *input_pointer;
+        }
+        else
+        {
+            /* character needs to be escaped */
+            *output_pointer++ = '\\';
+            switch (*input_pointer)
+            {
+                case '\\':
+                    *output_pointer = '\\';
+                    break;
+                case '\"':
+                    *output_pointer = '\"';
+                    break;
+                case '\b':
+                    *output_pointer = 'b';
+                    break;
+                case '\f':
+                    *output_pointer = 'f';
+                    break;
+                case '\n':
+                    *output_pointer = 'n';
+                    break;
+                case '\r':
+                    *output_pointer = 'r';
+                    break;
+                case '\t':
+                    *output_pointer = 't';
+                    break;
+                default:
+                    /* escape and print as unicode codepoint */
+                    sprintf((char*)output_pointer, "u%04x", *input_pointer);
+                    output_pointer += 4;
+                    break;
+            }
+        }
+    }
+    output[output_length + 1] = '\"';
+    output[output_length + 2] = '\0';
+
+    return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
+{
+    return print_string_ptr((unsigned char*)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
+{
+    if ((buffer == NULL) || (buffer->content == NULL))
+    {
+        return NULL;
+    }
+
+    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
+    {
+       buffer->offset++;
+    }
+
+    if (buffer->offset == buffer->length)
+    {
+        buffer->offset--;
+    }
+
+    return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
+{
+    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+    {
+        return NULL;
+    }
+
+    if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+    {
+        buffer->offset += 3;
+    }
+
+    return buffer;
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    cJSON *item = NULL;
+
+    /* reset error position */
+    global_error.json = NULL;
+    global_error.position = 0;
+
+    if (value == NULL)
+    {
+        goto fail;
+    }
+
+    buffer.content = (const unsigned char*)value;
+    buffer.length = strlen((const char*)value) + sizeof("");
+    buffer.offset = 0;
+    buffer.hooks = global_hooks;
+
+    item = cJSON_New_Item(&global_hooks);
+    if (item == NULL) /* memory fail */
+    {
+        goto fail;
+    }
+
+    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
+    {
+        /* parse failure. ep is set. */
+        goto fail;
+    }
+
+    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+    if (require_null_terminated)
+    {
+        buffer_skip_whitespace(&buffer);
+        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
+        {
+            goto fail;
+        }
+    }
+    if (return_parse_end)
+    {
+        *return_parse_end = (const char*)buffer_at_offset(&buffer);
+    }
+
+    return item;
+
+fail:
+    if (item != NULL)
+    {
+        cJSON_Delete(item);
+    }
+
+    if (value != NULL)
+    {
+        error local_error;
+        local_error.json = (const unsigned char*)value;
+        local_error.position = 0;
+
+        if (buffer.offset < buffer.length)
+        {
+            local_error.position = buffer.offset;
+        }
+        else if (buffer.length > 0)
+        {
+            local_error.position = buffer.length - 1;
+        }
+
+        if (return_parse_end != NULL)
+        {
+            *return_parse_end = (const char*)local_error.json + local_error.position;
+        }
+
+        global_error = local_error;
+    }
+
+    return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
+{
+    return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+#define cjson_min(a, b) ((a < b) ? a : b)
+
+static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
+{
+    static const size_t default_buffer_size = 256;
+    printbuffer buffer[1];
+    unsigned char *printed = NULL;
+
+    memset(buffer, 0, sizeof(buffer));
+
+    /* create buffer */
+    buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
+    buffer->length = default_buffer_size;
+    buffer->format = format;
+    buffer->hooks = *hooks;
+    if (buffer->buffer == NULL)
+    {
+        goto fail;
+    }
+
+    /* print the value */
+    if (!print_value(item, buffer))
+    {
+        goto fail;
+    }
+    update_offset(buffer);
+
+    /* check if reallocate is available */
+    if (hooks->reallocate != NULL)
+    {
+        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
+        if (printed == NULL) {
+            goto fail;
+        }
+        buffer->buffer = NULL;
+    }
+    else /* otherwise copy the JSON over to a new buffer */
+    {
+        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
+        if (printed == NULL)
+        {
+            goto fail;
+        }
+        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+        printed[buffer->offset] = '\0'; /* just to be sure */
+
+        /* free the buffer */
+        hooks->deallocate(buffer->buffer);
+    }
+
+    return printed;
+
+fail:
+    if (buffer->buffer != NULL)
+    {
+        hooks->deallocate(buffer->buffer);
+    }
+
+    if (printed != NULL)
+    {
+        hooks->deallocate(printed);
+    }
+
+    return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
+{
+    return (char*)print(item, true, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
+{
+    return (char*)print(item, false, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
+{
+    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+    if (prebuffer < 0)
+    {
+        return NULL;
+    }
+
+    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
+    if (!p.buffer)
+    {
+        return NULL;
+    }
+
+    p.length = (size_t)prebuffer;
+    p.offset = 0;
+    p.noalloc = false;
+    p.format = fmt;
+    p.hooks = global_hooks;
+
+    if (!print_value(item, &p))
+    {
+        global_hooks.deallocate(p.buffer);
+        return NULL;
+    }
+
+    return (char*)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
+{
+    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+    if ((len < 0) || (buf == NULL))
+    {
+        return false;
+    }
+
+    p.buffer = (unsigned char*)buf;
+    p.length = (size_t)len;
+    p.offset = 0;
+    p.noalloc = true;
+    p.format = fmt;
+    p.hooks = global_hooks;
+
+    return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
+{
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false; /* no input */
+    }
+
+    /* parse the different types of values */
+    /* null */
+    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
+    {
+        item->type = cJSON_NULL;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* false */
+    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
+    {
+        item->type = cJSON_False;
+        input_buffer->offset += 5;
+        return true;
+    }
+    /* true */
+    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
+    {
+        item->type = cJSON_True;
+        item->valueint = 1;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* string */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
+    {
+        return parse_string(item, input_buffer);
+    }
+    /* number */
+    if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
+    {
+        return parse_number(item, input_buffer);
+    }
+    /* array */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
+    {
+        return parse_array(item, input_buffer);
+    }
+    /* object */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
+    {
+        return parse_object(item, input_buffer);
+    }
+
+    return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
+{
+    unsigned char *output = NULL;
+
+    if ((item == NULL) || (output_buffer == NULL))
+    {
+        return false;
+    }
+
+    switch ((item->type) & 0xFF)
+    {
+        case cJSON_NULL:
+            output = ensure(output_buffer, 5);
+            if (output == NULL)
+            {
+                return false;
+            }
+            strcpy((char*)output, "null");
+            return true;
+
+        case cJSON_False:
+            output = ensure(output_buffer, 6);
+            if (output == NULL)
+            {
+                return false;
+            }
+            strcpy((char*)output, "false");
+            return true;
+
+        case cJSON_True:
+            output = ensure(output_buffer, 5);
+            if (output == NULL)
+            {
+                return false;
+            }
+            strcpy((char*)output, "true");
+            return true;
+
+        case cJSON_Number:
+            return print_number(item, output_buffer);
+
+        case cJSON_Raw:
+        {
+            size_t raw_length = 0;
+            if (item->valuestring == NULL)
+            {
+                return false;
+            }
+
+            raw_length = strlen(item->valuestring) + sizeof("");
+            output = ensure(output_buffer, raw_length);
+            if (output == NULL)
+            {
+                return false;
+            }
+            memcpy(output, item->valuestring, raw_length);
+            return true;
+        }
+
+        case cJSON_String:
+            return print_string(item, output_buffer);
+
+        case cJSON_Array:
+            return print_array(item, output_buffer);
+
+        case cJSON_Object:
+            return print_object(item, output_buffer);
+
+        default:
+            return false;
+    }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
+{
+    cJSON *head = NULL; /* head of the linked list */
+    cJSON *current_item = NULL;
+
+    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+    {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if (buffer_at_offset(input_buffer)[0] != '[')
+    {
+        /* not an array */
+        goto fail;
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
+    {
+        /* empty array */
+        goto success;
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
+    {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
+    {
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if (new_item == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if (head == NULL)
+        {
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse next value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    }
+    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
+    {
+        goto fail; /* expected end of array */
+    }
+
+success:
+    input_buffer->depth--;
+
+    item->type = cJSON_Array;
+    item->child = head;
+
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
+{
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_element = item->child;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* Compose the output array. */
+    /* opening square bracket */
+    output_pointer = ensure(output_buffer, 1);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    *output_pointer = '[';
+    output_buffer->offset++;
+    output_buffer->depth++;
+
+    while (current_element != NULL)
+    {
+        if (!print_value(current_element, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+        if (current_element->next)
+        {
+            length = (size_t) (output_buffer->format ? 2 : 1);
+            output_pointer = ensure(output_buffer, length + 1);
+            if (output_pointer == NULL)
+            {
+                return false;
+            }
+            *output_pointer++ = ',';
+            if(output_buffer->format)
+            {
+                *output_pointer++ = ' ';
+            }
+            *output_pointer = '\0';
+            output_buffer->offset += length;
+        }
+        current_element = current_element->next;
+    }
+
+    output_pointer = ensure(output_buffer, 2);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    *output_pointer++ = ']';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
+{
+    cJSON *head = NULL; /* linked list head */
+    cJSON *current_item = NULL;
+
+    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+    {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
+    {
+        goto fail; /* not an object */
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
+    {
+        goto success; /* empty object */
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
+    {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
+    {
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if (new_item == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if (head == NULL)
+        {
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse the name of the child */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_string(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse name */
+        }
+        buffer_skip_whitespace(input_buffer);
+
+        /* swap valuestring and string, because we parsed the name */
+        current_item->string = current_item->valuestring;
+        current_item->valuestring = NULL;
+
+        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
+        {
+            goto fail; /* invalid object */
+        }
+
+        /* parse the value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    }
+    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+    {
+        goto fail; /* expected end of object */
+    }
+
+success:
+    input_buffer->depth--;
+
+    item->type = cJSON_Object;
+    item->child = head;
+
+    input_buffer->offset++;
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
+{
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_item = item->child;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* Compose the output: */
+    length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
+    output_pointer = ensure(output_buffer, length + 1);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    *output_pointer++ = '{';
+    output_buffer->depth++;
+    if (output_buffer->format)
+    {
+        *output_pointer++ = '\n';
+    }
+    output_buffer->offset += length;
+
+    while (current_item)
+    {
+        if (output_buffer->format)
+        {
+            size_t i;
+            output_pointer = ensure(output_buffer, output_buffer->depth);
+            if (output_pointer == NULL)
+            {
+                return false;
+            }
+            for (i = 0; i < output_buffer->depth; i++)
+            {
+                *output_pointer++ = '\t';
+            }
+            output_buffer->offset += output_buffer->depth;
+        }
+
+        /* print key */
+        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        length = (size_t) (output_buffer->format ? 2 : 1);
+        output_pointer = ensure(output_buffer, length);
+        if (output_pointer == NULL)
+        {
+            return false;
+        }
+        *output_pointer++ = ':';
+        if (output_buffer->format)
+        {
+            *output_pointer++ = '\t';
+        }
+        output_buffer->offset += length;
+
+        /* print value */
+        if (!print_value(current_item, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        /* print comma if not last */
+        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
+        output_pointer = ensure(output_buffer, length + 1);
+        if (output_pointer == NULL)
+        {
+            return false;
+        }
+        if (current_item->next)
+        {
+            *output_pointer++ = ',';
+        }
+
+        if (output_buffer->format)
+        {
+            *output_pointer++ = '\n';
+        }
+        *output_pointer = '\0';
+        output_buffer->offset += length;
+
+        current_item = current_item->next;
+    }
+
+    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    if (output_buffer->format)
+    {
+        size_t i;
+        for (i = 0; i < (output_buffer->depth - 1); i++)
+        {
+            *output_pointer++ = '\t';
+        }
+    }
+    *output_pointer++ = '}';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
+{
+    cJSON *child = NULL;
+    size_t size = 0;
+
+    if (array == NULL)
+    {
+        return 0;
+    }
+
+    child = array->child;
+
+    while(child != NULL)
+    {
+        size++;
+        child = child->next;
+    }
+
+    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+    return (int)size;
+}
+
+static cJSON* get_array_item(const cJSON *array, size_t index)
+{
+    cJSON *current_child = NULL;
+
+    if (array == NULL)
+    {
+        return NULL;
+    }
+
+    current_child = array->child;
+    while ((current_child != NULL) && (index > 0))
+    {
+        index--;
+        current_child = current_child->next;
+    }
+
+    return current_child;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
+{
+    if (index < 0)
+    {
+        return NULL;
+    }
+
+    return get_array_item(array, (size_t)index);
+}
+
+static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
+{
+    cJSON *current_element = NULL;
+
+    if ((object == NULL) || (name == NULL))
+    {
+        return NULL;
+    }
+
+    current_element = object->child;
+    if (case_sensitive)
+    {
+        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
+        {
+            current_element = current_element->next;
+        }
+    }
+    else
+    {
+        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
+        {
+            current_element = current_element->next;
+        }
+    }
+
+    if ((current_element == NULL) || (current_element->string == NULL)) {
+        return NULL;
+    }
+
+    return current_element;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
+{
+    return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
+{
+    return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
+{
+    return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+    prev->next = item;
+    item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
+{
+    cJSON *reference = NULL;
+    if (item == NULL)
+    {
+        return NULL;
+    }
+
+    reference = cJSON_New_Item(hooks);
+    if (reference == NULL)
+    {
+        return NULL;
+    }
+
+    memcpy(reference, item, sizeof(cJSON));
+    reference->string = NULL;
+    reference->type |= cJSON_IsReference;
+    reference->next = reference->prev = NULL;
+    return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
+{
+    cJSON *child = NULL;
+
+    if ((item == NULL) || (array == NULL))
+    {
+        return false;
+    }
+
+    child = array->child;
+
+    if (child == NULL)
+    {
+        /* list is empty, start new one */
+        array->child = item;
+    }
+    else
+    {
+        /* append to the end */
+        while (child->next)
+        {
+            child = child->next;
+        }
+        suffix_object(child, item);
+    }
+
+    return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+    add_item_to_array(array, item);
+}
+
+#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+    #pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void* cast_away_const(const void* string)
+{
+    return (void*)string;
+}
+#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+    #pragma GCC diagnostic pop
+#endif
+
+
+static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
+{
+    char *new_key = NULL;
+    int new_type = cJSON_Invalid;
+
+    if ((object == NULL) || (string == NULL) || (item == NULL))
+    {
+        return false;
+    }
+
+    if (constant_key)
+    {
+        new_key = (char*)cast_away_const(string);
+        new_type = item->type | cJSON_StringIsConst;
+    }
+    else
+    {
+        new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
+        if (new_key == NULL)
+        {
+            return false;
+        }
+
+        new_type = item->type & ~cJSON_StringIsConst;
+    }
+
+    if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+    {
+        hooks->deallocate(item->string);
+    }
+
+    item->string = new_key;
+    item->type = new_type;
+
+    return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+    add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+    add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+    if (array == NULL)
+    {
+        return;
+    }
+
+    add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+    if ((object == NULL) || (string == NULL))
+    {
+        return;
+    }
+
+    add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
+{
+    cJSON *null = cJSON_CreateNull();
+    if (add_item_to_object(object, name, null, &global_hooks, false))
+    {
+        return null;
+    }
+
+    cJSON_Delete(null);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
+{
+    cJSON *true_item = cJSON_CreateTrue();
+    if (add_item_to_object(object, name, true_item, &global_hooks, false))
+    {
+        return true_item;
+    }
+
+    cJSON_Delete(true_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
+{
+    cJSON *false_item = cJSON_CreateFalse();
+    if (add_item_to_object(object, name, false_item, &global_hooks, false))
+    {
+        return false_item;
+    }
+
+    cJSON_Delete(false_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
+{
+    cJSON *bool_item = cJSON_CreateBool(boolean);
+    if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+    {
+        return bool_item;
+    }
+
+    cJSON_Delete(bool_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
+{
+    cJSON *number_item = cJSON_CreateNumber(number);
+    if (add_item_to_object(object, name, number_item, &global_hooks, false))
+    {
+        return number_item;
+    }
+
+    cJSON_Delete(number_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
+{
+    cJSON *string_item = cJSON_CreateString(string);
+    if (add_item_to_object(object, name, string_item, &global_hooks, false))
+    {
+        return string_item;
+    }
+
+    cJSON_Delete(string_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
+{
+    cJSON *raw_item = cJSON_CreateRaw(raw);
+    if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+    {
+        return raw_item;
+    }
+
+    cJSON_Delete(raw_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
+{
+    cJSON *object_item = cJSON_CreateObject();
+    if (add_item_to_object(object, name, object_item, &global_hooks, false))
+    {
+        return object_item;
+    }
+
+    cJSON_Delete(object_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
+{
+    cJSON *array = cJSON_CreateArray();
+    if (add_item_to_object(object, name, array, &global_hooks, false))
+    {
+        return array;
+    }
+
+    cJSON_Delete(array);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
+{
+    if ((parent == NULL) || (item == NULL))
+    {
+        return NULL;
+    }
+
+    if (item->prev != NULL)
+    {
+        /* not the first element */
+        item->prev->next = item->next;
+    }
+    if (item->next != NULL)
+    {
+        /* not the last element */
+        item->next->prev = item->prev;
+    }
+
+    if (item == parent->child)
+    {
+        /* first element */
+        parent->child = item->next;
+    }
+    /* make sure the detached item doesn't point anywhere anymore */
+    item->prev = NULL;
+    item->next = NULL;
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+    if (which < 0)
+    {
+        return NULL;
+    }
+
+    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+    cJSON *to_detach = cJSON_GetObjectItem(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+    cJSON *after_inserted = NULL;
+
+    if (which < 0)
+    {
+        return;
+    }
+
+    after_inserted = get_array_item(array, (size_t)which);
+    if (after_inserted == NULL)
+    {
+        add_item_to_array(array, newitem);
+        return;
+    }
+
+    newitem->next = after_inserted;
+    newitem->prev = after_inserted->prev;
+    after_inserted->prev = newitem;
+    if (after_inserted == array->child)
+    {
+        array->child = newitem;
+    }
+    else
+    {
+        newitem->prev->next = newitem;
+    }
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
+{
+    if ((parent == NULL) || (replacement == NULL) || (item == NULL))
+    {
+        return false;
+    }
+
+    if (replacement == item)
+    {
+        return true;
+    }
+
+    replacement->next = item->next;
+    replacement->prev = item->prev;
+
+    if (replacement->next != NULL)
+    {
+        replacement->next->prev = replacement;
+    }
+    if (replacement->prev != NULL)
+    {
+        replacement->prev->next = replacement;
+    }
+    if (parent->child == item)
+    {
+        parent->child = replacement;
+    }
+
+    item->next = NULL;
+    item->prev = NULL;
+    cJSON_Delete(item);
+
+    return true;
+}
+
+CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+    if (which < 0)
+    {
+        return;
+    }
+
+    cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
+{
+    if ((replacement == NULL) || (string == NULL))
+    {
+        return false;
+    }
+
+    /* replace the name in the replacement */
+    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+    {
+        cJSON_free(replacement->string);
+    }
+    replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+    replacement->type &= ~cJSON_StringIsConst;
+
+    cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+
+    return true;
+}
+
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+    replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+{
+    replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_NULL;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_True;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = b ? cJSON_True : cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_Number;
+        item->valuedouble = num;
+
+        /* use saturation in case of overflow */
+        if (num >= INT_MAX)
+        {
+            item->valueint = INT_MAX;
+        }
+        else if (num <= (double)INT_MIN)
+        {
+            item->valueint = INT_MIN;
+        }
+        else
+        {
+            item->valueint = (int)num;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_String;
+        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+        if(!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item != NULL)
+    {
+        item->type = cJSON_String | cJSON_IsReference;
+        item->valuestring = (char*)cast_away_const(string);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item != NULL) {
+        item->type = cJSON_Object | cJSON_IsReference;
+        item->child = (cJSON*)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item != NULL) {
+        item->type = cJSON_Array | cJSON_IsReference;
+        item->child = (cJSON*)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_Raw;
+        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
+        if(!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type=cJSON_Array;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Object;
+    }
+
+    return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+    for(i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber(numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber((double)numbers[i]);
+        if(!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0;a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber(numbers[i]);
+        if(!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (strings == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateString(strings[i]);
+        if(!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p,n);
+        }
+        p = n;
+    }
+
+    return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
+{
+    cJSON *newitem = NULL;
+    cJSON *child = NULL;
+    cJSON *next = NULL;
+    cJSON *newchild = NULL;
+
+    /* Bail on bad ptr */
+    if (!item)
+    {
+        goto fail;
+    }
+    /* Create new item */
+    newitem = cJSON_New_Item(&global_hooks);
+    if (!newitem)
+    {
+        goto fail;
+    }
+    /* Copy over all vars */
+    newitem->type = item->type & (~cJSON_IsReference);
+    newitem->valueint = item->valueint;
+    newitem->valuedouble = item->valuedouble;
+    if (item->valuestring)
+    {
+        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
+        if (!newitem->valuestring)
+        {
+            goto fail;
+        }
+    }
+    if (item->string)
+    {
+        newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
+        if (!newitem->string)
+        {
+            goto fail;
+        }
+    }
+    /* If non-recursive, then we're done! */
+    if (!recurse)
+    {
+        return newitem;
+    }
+    /* Walk the ->next chain for the child. */
+    child = item->child;
+    while (child != NULL)
+    {
+        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+        if (!newchild)
+        {
+            goto fail;
+        }
+        if (next != NULL)
+        {
+            /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+            next->next = newchild;
+            newchild->prev = next;
+            next = newchild;
+        }
+        else
+        {
+            /* Set newitem->child and move to it */
+            newitem->child = newchild;
+            next = newchild;
+        }
+        child = child->next;
+    }
+
+    return newitem;
+
+fail:
+    if (newitem != NULL)
+    {
+        cJSON_Delete(newitem);
+    }
+
+    return NULL;
+}
+
+static void skip_oneline_comment(char **input)
+{
+    *input += static_strlen("//");
+
+    for (; (*input)[0] != '\0'; ++(*input))
+    {
+        if ((*input)[0] == '\n') {
+            *input += static_strlen("\n");
+            return;
+        }
+    }
+}
+
+static void skip_multiline_comment(char **input)
+{
+    *input += static_strlen("/*");
+
+    for (; (*input)[0] != '\0'; ++(*input))
+    {
+        if (((*input)[0] == '*') && ((*input)[1] == '/'))
+        {
+            *input += static_strlen("*/");
+            return;
+        }
+    }
+}
+
+static void minify_string(char **input, char **output) {
+    (*output)[0] = (*input)[0];
+    *input += static_strlen("\"");
+    *output += static_strlen("\"");
+
+
+    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+        (*output)[0] = (*input)[0];
+
+        if ((*input)[0] == '\"') {
+            (*output)[0] = '\"';
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+            return;
+        } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+            (*output)[1] = (*input)[1];
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+        }
+    }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
+{
+    char *into = json;
+
+    if (json == NULL)
+    {
+        return;
+    }
+
+    while (json[0] != '\0')
+    {
+        switch (json[0])
+        {
+            case ' ':
+            case '\t':
+            case '\r':
+            case '\n':
+                json++;
+                break;
+
+            case '/':
+                if (json[1] == '/')
+                {
+                    skip_oneline_comment(&json);
+                }
+                else if (json[1] == '*')
+                {
+                    skip_multiline_comment(&json);
+                } else {
+                    json++;
+                }
+                break;
+
+            case '\"':
+                minify_string(&json, (char**)&into);
+                break;
+
+            default:
+                into[0] = json[0];
+                json++;
+                into++;
+        }
+    }
+
+    /* and null-terminate. */
+    *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xff) == cJSON_True;
+}
+
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
+{
+    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
+    {
+        return false;
+    }
+
+    /* check if type is valid */
+    switch (a->type & 0xFF)
+    {
+        case cJSON_False:
+        case cJSON_True:
+        case cJSON_NULL:
+        case cJSON_Number:
+        case cJSON_String:
+        case cJSON_Raw:
+        case cJSON_Array:
+        case cJSON_Object:
+            break;
+
+        default:
+            return false;
+    }
+
+    /* identical objects are equal */
+    if (a == b)
+    {
+        return true;
+    }
+
+    switch (a->type & 0xFF)
+    {
+        /* in these cases and equal type is enough */
+        case cJSON_False:
+        case cJSON_True:
+        case cJSON_NULL:
+            return true;
+
+        case cJSON_Number:
+            if (a->valuedouble == b->valuedouble)
+            {
+                return true;
+            }
+            return false;
+
+        case cJSON_String:
+        case cJSON_Raw:
+            if ((a->valuestring == NULL) || (b->valuestring == NULL))
+            {
+                return false;
+            }
+            if (strcmp(a->valuestring, b->valuestring) == 0)
+            {
+                return true;
+            }
+
+            return false;
+
+        case cJSON_Array:
+        {
+            cJSON *a_element = a->child;
+            cJSON *b_element = b->child;
+
+            for (; (a_element != NULL) && (b_element != NULL);)
+            {
+                if (!cJSON_Compare(a_element, b_element, case_sensitive))
+                {
+                    return false;
+                }
+
+                a_element = a_element->next;
+                b_element = b_element->next;
+            }
+
+            /* one of the arrays is longer than the other */
+            if (a_element != b_element) {
+                return false;
+            }
+
+            return true;
+        }
+
+        case cJSON_Object:
+        {
+            cJSON *a_element = NULL;
+            cJSON *b_element = NULL;
+            cJSON_ArrayForEach(a_element, a)
+            {
+                /* TODO This has O(n^2) runtime, which is horrible! */
+                b_element = get_object_item(b, a_element->string, case_sensitive);
+                if (b_element == NULL)
+                {
+                    return false;
+                }
+
+                if (!cJSON_Compare(a_element, b_element, case_sensitive))
+                {
+                    return false;
+                }
+            }
+
+            /* doing this twice, once on a and b to prevent true comparison if a subset of b
+             * TODO: Do this the proper way, this is just a fix for now */
+            cJSON_ArrayForEach(b_element, b)
+            {
+                a_element = get_object_item(a, b_element->string, case_sensitive);
+                if (a_element == NULL)
+                {
+                    return false;
+                }
+
+                if (!cJSON_Compare(b_element, a_element, case_sensitive))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        default:
+            return false;
+    }
+}
+
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
+{
+    return global_hooks.allocate(size);
+}
+
+CJSON_PUBLIC(void) cJSON_free(void *object)
+{
+    global_hooks.deallocate(object);
+}
index ebffb771228f3ff1ccae89ba4ab4eb280ed72e7a..3bcb8b31a40eff9f712937bb594db742edecdd2d 100644 (file)
@@ -784,6 +784,16 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
 
                return &udp[1];
        }
+#if defined(CONFIG_SPINOR_BLOCK_SUPPORT)
+       case UCLASS_SPI_FLASH:
+       case UCLASS_SPI: {
+               struct efi_device_path_vendor *dp = dp_fill(buf, dev->parent);
+               dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+               dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+               dp->dp.length = sizeof(*dp);
+               return &dp[1];
+       }
+#endif
        default:
                /* If the uclass driver is missing, this will show NULL */
                log_debug("unhandled device class: %s (%s)\n", dev->name,
index 5ec0f94ab3eb6a27ff172b8585b46d1183b91450..3661f8e02781f6ce1e15ca18525c285f537b2ef7 100644 (file)
@@ -56,6 +56,10 @@ static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info,
                                       char *response)
 {
        lbaint_t n = blkcnt, write_blks, blks = 0, aligned_buf_blks = 100;
+#ifdef CONFIG_IMAGE_SPARSE_TRANSFER_BLK_NUM
+       if (CONFIG_IMAGE_SPARSE_TRANSFER_BLK_NUM > 0)
+               aligned_buf_blks = CONFIG_IMAGE_SPARSE_TRANSFER_BLK_NUM;
+#endif
        uint32_t *aligned_buf = NULL;
 
        if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) {
@@ -68,8 +72,12 @@ static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info,
 
        aligned_buf = memalign(ARCH_DMA_MINALIGN, info->blksz * aligned_buf_blks);
        if (!aligned_buf) {
-               info->mssg("Malloc failed for: CHUNK_TYPE_RAW", response);
-               return -ENOMEM;
+               aligned_buf_blks = 100;
+               aligned_buf = memalign(ARCH_DMA_MINALIGN, info->blksz * aligned_buf_blks);
+               if (!aligned_buf){
+                       info->mssg("Malloc failed for: CHUNK_TYPE_RAW", response);
+                       return -ENOMEM;
+               }
        }
 
        while (blkcnt > 0) {
@@ -258,9 +266,22 @@ int write_sparse_image(struct sparse_storage *info,
 
                        for (i = 0; i < blkcnt;) {
                                j = blkcnt - i;
-                               if (j > fill_buf_num_blks)
-                                       j = fill_buf_num_blks;
-                               blks = info->write(info, blk, j, fill_buf);
+                               if (j > fill_buf_num_blks){
+                                       if (blk % fill_buf_num_blks){
+                                               /*align blk addr*/
+                                               j = fill_buf_num_blks - (blk % fill_buf_num_blks);
+                                       }else{
+                                               j = fill_buf_num_blks;
+                                       }
+                               }
+
+                               if (fill_val == 0 && j == fill_buf_num_blks
+                                       && info->erase !=NULL){
+                                       blks = info->erase(info, blk, j, fill_buf);
+                               }else {
+                                       blks = info->write(info, blk, j, fill_buf);
+                               }
+
                                /* blks might be > j (eg. NAND bad-blocks) */
                                if (blks < j) {
                                        printf("%s: %s " LBAFU " [%d]\n",
index bf9cd19cfa34265f889c091de074cd17a7ea6926..53ba1cbc7559bcbcb83e3f22d41cd76f6165b9ac 100644 (file)
@@ -23,7 +23,7 @@ int zstd_decompress(struct abuf *in, struct abuf *out)
        wsize = ZSTD_DStreamWorkspaceBound(abuf_size(in));
        workspace = malloc(wsize);
        if (!workspace) {
-               debug("%s: cannot allocate workspace of size %zu\n", __func__,
+               pr_err("%s: cannot allocate workspace of size %zu\n", __func__,
                        wsize);
                return -ENOMEM;
        }
index 8e13bf2b986da877461159b6fc088e3f61cb8ade..ac45a88478599512ec313acec62c29acea02f424 100644 (file)
@@ -425,9 +425,11 @@ cmd_efi_objcopy = $(OBJCOPY) -j .header -j .text -j .sdata -j .data -j \
 $(obj)/%.efi: $(obj)/%_efi.so
        $(call cmd,efi_objcopy)
 
+KBUILD_EFILDFLAGS = -nostdlib -zexecstack -znocombreloc -znorelro
+KBUILD_EFILDFLAGS += $(call ld-option,--no-warn-rwx-segments)
 quiet_cmd_efi_ld = LD      $@
-cmd_efi_ld = $(LD) -nostdlib -zexecstack -znocombreloc -T $(EFI_LDS_PATH) \
-               -shared -Bsymbolic -znorelro -s $^ -o $@
+cmd_efi_ld = $(LD) $(KBUILD_EFILDFLAGS) -T $(EFI_LDS_PATH) \
+               -shared -Bsymbolic -s $^ -o $@
 
 EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS)
 
index 21997ed892290dc11ed7eb6cb737cfb6aa6b5432..f48de05436bf2abcb6546b5dfce9a33276fc3784 100644 (file)
@@ -26,6 +26,11 @@ static int dm_test_clk_base(struct unit_test_state *uts)
        ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", &dev));
 
        /* Get the same clk port in 2 different ways and compare */
+       ut_assertok(clk_get_by_index(dev, 0, &clk_method1));
+       ut_assertok(clk_get_by_name(dev, NULL, &clk_method2));
+       ut_asserteq(clk_is_match(&clk_method1, &clk_method2), true);
+       ut_asserteq(clk_method1.id, clk_method2.id);
+
        ut_assertok(clk_get_by_index(dev, 1, &clk_method1));
        ut_assertok(clk_get_by_index_nodev(dev_ofnode(dev), 1, &clk_method2));
        ut_asserteq(clk_is_match(&clk_method1, &clk_method2), true);
diff --git a/tools/common_decorator.py b/tools/common_decorator.py
new file mode 100755 (executable)
index 0000000..47c56a9
--- /dev/null
@@ -0,0 +1,163 @@
+# -*- coding: utf-8 -*-
+import time
+import os
+import sys
+import fnmatch
+import re
+import functools
+import argparse
+import traceback
+import logging
+
+class Logger(object):
+    def __init__(self, clevel = 'info'):
+        self.logger = logging.Logger(__name__)
+        # self.logger = logging.getLogger(__name__)
+        # self.logger.setLevel(clevel)
+
+        self.LOGLEVEL = {
+            'NOTSET': logging.NOTSET,   'DEBUG'     : logging.DEBUG,
+            'INFO'  : logging.INFO,     'WARNING'   : logging.WARNING,
+            'ERROR' : logging.ERROR,    'CRITICAL'  : logging.CRITICAL
+        }
+        self.debug      = self.logger.debug
+        self.info       = self.logger.info
+        self.warning    = self.logger.warning
+        self.error      = self.logger.error
+        self.critical   = self.logger.critical
+        self.exception  = self.logger.exception
+
+        self.stream_handler = None
+        self.file_handler = None
+        self.set_debug_level(clevel)
+
+    def set_debug_level(self, clevel = 'info'):
+        clevel = clevel.upper()
+        clevel = self.LOGLEVEL.get(clevel, logging.INFO)
+        if clevel < logging.INFO:
+            formatter = logging.Formatter('[%(module)s]: (%(lineno)d) (%(asctime)s) %(message)s')
+        else:
+            formatter = logging.Formatter('(%(asctime)s) %(message)s')
+
+        # 设置CMD日志
+        if self.stream_handler is not None:
+            self.logger.removeHandler(self.stream_handler)
+        sh = logging.StreamHandler()
+        sh.setFormatter(formatter)
+        sh.setLevel(clevel)
+        self.logger.addHandler(sh)
+        self.stream_handler = sh
+        return True
+
+    def set_file_debug_level(self, flevel = 'info', path = None):
+        if path:
+            flevel = flevel.upper()
+            flevel = self.LOGLEVEL.get(flevel, logging.INFO)
+            if flevel < logging.INFO:
+                formatter = logging.Formatter('[%(module)s]: (%(lineno)d) (%(asctime)s) %(message)s')
+            else:
+                formatter = logging.Formatter('(%(asctime)s) %(message)s')
+
+            # 设置文件日志
+            if self.file_handler is not None:
+                self.logger.removeHandler(self.file_handler)
+            fh = logging.FileHandler(path)
+            fh.setFormatter(formatter)
+            fh.setLevel(flevel)
+            self.logger.addHandler(fh)
+            self.file_handler = fh
+            return True
+        return False
+
+
+def time_consume(func):
+    @functools.wraps(func)
+    def wrapper(*args, **kw):
+        try:
+            stamp_a = time.time()
+            ret = func(*args, **kw)
+            stamp_b = time.time()
+            print("%s consume(second): %.3f." %(func.__name__, stamp_b - stamp_a))
+            return ret
+        except Exception as e:
+            print('%s(%s)' %(type(e), e))
+            # traceback.print_exc()
+            return -1
+    return wrapper
+
+
+def except_wrapper(func):
+    @functools.wraps(func)
+    def wrapper(*args, **kw):
+        try:
+            return func(*args, **kw)
+        except Exception as e:
+            print('%s(%s)' %(type(e), e))
+            traceback.print_exc()
+            return -1
+    return wrapper
+
+
+def search_files(path_list, suffix_pattern_list):
+    """search for file with suffix in suffix_list
+    If suffix_list is empty, return all file in the path.
+    return: matched file list iterator
+    """
+    # matches = []
+    # print("search path: %r, pattern: %r" %(path_list, suffix_pattern_list))
+    hiden_dir_p = re.compile(r'^\.\w+')
+    for path in path_list:
+        for root, dirnames, filenames in os.walk(path):
+            for suffix_pattern in suffix_pattern_list:
+                relative_path = os.path.relpath(root, path)
+                if not hiden_dir_p.match(relative_path):
+                    for filename in fnmatch.filter(filenames, r'%s' %suffix_pattern):
+                        # matches.append(os.path.join(root, filename))
+                        yield os.path.join(root, filename)
+
+    # return matches
+
+
+def PreparseConfig(input_file):
+    """Preprocess input file, filter out all comment line string.
+    """
+    config_list = []
+
+    if os.path.isfile(input_file):
+        with open(input_file, 'r') as p_file:
+            str             = p_file.read()
+            line_str_list   = str.split('\n')
+
+            for line_str in line_str_list:
+                line_str = line_str.strip()
+                # filter out comment string and empty line
+                if line_str and not re.search(r'^\s*($|//|#)', line_str):
+                    config_list.append(line_str)
+
+    return config_list
+
+
+def main(argv):
+    parser = argparse.ArgumentParser(
+        description='Extract interface with key, and generate link script.',
+    )
+    parser.add_argument('-i',   dest = 'input_path',    nargs = '+',    required = True,    help = 'search path')
+
+    args = parser.parse_args()
+    src_path    = args.input_path
+
+    path_list = []
+    for search_path in src_path:
+        if os.path.exists(search_path):
+            path_list.append(search_path)
+        else:
+            print("%s is NOT a file path !" %search_path)
+
+    file_list_iter  = search_files(path_list, ['*.c'])
+    for input_file in file_list_iter:
+        PreparseConfig(input_file)
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
+
diff --git a/tools/logos/bianbu.bmp b/tools/logos/bianbu.bmp
new file mode 100644 (file)
index 0000000..3489997
Binary files /dev/null and b/tools/logos/bianbu.bmp differ
diff --git a/tools/logos/k1-x.bmp b/tools/logos/k1-x.bmp
new file mode 100644 (file)
index 0000000..f0f985c
Binary files /dev/null and b/tools/logos/k1-x.bmp differ