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>
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)
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
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
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
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
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
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)
.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
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
. = ALIGN(4);
.data : {
+ __data_start = .;
*(.data*)
+ __data_end = .;
} > .spl_mem
. = ALIGN(4);
--- /dev/null
+# 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
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2023 Spacemit, Inc
+
+obj-y += cpu.o
+obj-y += cache.o
+obj-y += dram.o
--- /dev/null
+// 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;
+ }
+}
--- /dev/null
+// 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;
+}
+
--- /dev/null
+// 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();
+}
+
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
--- /dev/null
+// 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>;
+ };
+};
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
--- /dev/null
+// 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";
+};
+
--- /dev/null
+// 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";
+};
+
--- /dev/null
+// 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";
+};
+
+ð0 {
+ 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";
+};
+
--- /dev/null
+// 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 */
+ >;
+ };
+};
+
--- /dev/null
+// 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;
+ };
+ };
+ };
+ };
+};
--- /dev/null
+// 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 */
+ >;
+ };
+};
+
--- /dev/null
+// 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";
+ };
+ };
+ };
+};
+
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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
* #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
#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
#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);
#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);
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();
}
}
__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)
+{
+}
*/
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;
}
}
#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;
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)
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
}
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)
"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);
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;
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+{
+ "_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
--- /dev/null
+{
+ "_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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "_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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "_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"
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "_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
--- /dev/null
+/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";
+ };
+ };
+};
--- /dev/null
+// 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
+
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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
--- /dev/null
+// 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;
+ }
+}
--- /dev/null
+#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
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
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
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
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
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);
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);
#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)
#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.
*
}
/*
- * '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.
*/
#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)
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
* 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;
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;
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 */
return 0;
}
-#endif /* #ifndef CONFIG_CMD_MTDPARTS */
+#endif /* #ifdef CONFIG_JFFS2_MTDPARTS */
/**
* Return pointer to the partition of a requested number from a requested
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))){
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))){
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))){
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;
}
/* should never happen */
- printf("## Error: cannot export environment\n");
+ pr_err("## Error: cannot export environment\n");
return 0;
}
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;
}
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;
}
}
name = argv[1];
if (strchr(name, '=')) {
- printf("## Error: illegal character '='"
+ pr_err("## Error: illegal character '='"
"in variable name \"%s\"\n", name);
return 1;
}
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) {
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;
}
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;
}
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;
}
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;
}
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));
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));
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");
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");
/* 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;
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;
}
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;
++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)
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;
}
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;
}
}
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;
}
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;
}
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");
}
}
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
}
--- /dev/null
+// 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.");
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
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
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
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
#include <asm-generic/gpio.h>
#include <efi_loader.h>
#include <relocate.h>
+#include <command.h>
DECLARE_GLOBAL_DATA_PTR;
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.
#endif
stdio_add_devices,
jumptable_init,
+#ifdef CONFIG_FASTBOOT_CMD_OEM_READ
+ initialize_console_log_buffer,
+#endif
#ifdef CONFIG_API
api_init,
#endif
#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;
}
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;
}
int rc;
if (!cmd) {
- printf("## Error: Secure boot command not specified\n");
+ pr_err("## Error: Secure boot command not specified\n");
goto err;
}
#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;
}
#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:
/*
#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*/
}
str++;
}
}
-
+int is_direction_key = 0;
static int cread_line(const char *const prompt, char *buf, unsigned int *len,
int timeout)
{
} 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 */
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;
}
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");
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,
/* 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;
}
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;
}
#include <watchdog.h>
#include <asm/global_data.h>
#include <linux/delay.h>
+#include <command.h>
DECLARE_GLOBAL_DATA_PTR;
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:
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);
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);
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
}
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;
}
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;
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;
}
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;
}
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;
}
(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;
}
(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;
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;
}
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;
}
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;
}
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;
}
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,
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;
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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 {
} 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;
}
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;
}
}
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;
}
#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) { }
/* 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;
}
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;
}
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;
}
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;
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;
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
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;
}
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;
}
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;
}
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;
}
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
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;
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;
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;
}
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;
}
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;
}
{
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,
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;
#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;
}
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,
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) {
*key = KEY_NONE;
} else {
/* Alone ESC key was pressed */
- *key = KEY_QUIT;
+ *key = KEY_NONE;
*esc = (c == '\e') ? 1 : 0;
}
break;
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
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
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
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
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
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,
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
/* 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);
}
}
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;
}
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;
#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
}
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();
}
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;
}
#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;
}
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 */
#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;
}
}
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;
}
}
{
int ret;
- debug("%s\n", __func__);
+ pr_debug("%s\n", __func__);
ret = spl_common_init(true);
if (ret)
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);
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");
ret = spl_early_init();
if (ret) {
- debug("spl_early_init() failed: %d\n", ret);
+ pr_debug("spl_early_init() failed: %d\n", ret);
hang();
}
}
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();
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();
#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);
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");
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
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();
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
}
#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;
--- /dev/null
+// 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);
#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;
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;
}
}
if (!found) {
- debug("no string for index %d\n", index);
+ pr_debug("no string for index %d\n", index);
return -E2BIG;
}
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) {
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;
}
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 {
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 */
}
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;
/* 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
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;
}
*/
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;
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);
{
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");
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,
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);
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;
}
/* 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;
}
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;
/* 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;
}
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
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;
}
* 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;
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;
}
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);
/* 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;
}
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
- printf("spl: unsupported mmc boot device.\n");
+ pr_debug("spl: unsupported mmc boot device.\n");
#endif
return -ENODEV;
#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;
}
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;
{
struct disk_partition info;
int err;
+ const char *part_name;
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE
int type_part;
}
#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
#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
}
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;
}
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;
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;
}
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,
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
--- /dev/null
+// 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);
/* 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 */
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;
return 0;
}
+
#if CONFIG_IS_ENABLED(RAM_DEVICE)
SPL_LOAD_IMAGE_METHOD("RAM", 0, BOOT_DEVICE_RAM, spl_ram_load_image);
#endif
#include <bmp_logo_data.h>
-static int splash_video_logo_load(void)
+int splash_video_logo_load(void)
{
char *splashimage;
ulong bmp_load_addr;
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)
#include <usb.h>
#include <virtio.h>
#include <asm/global_data.h>
+#include <stdint.h>
DECLARE_GLOBAL_DATA_PTR;
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);
if (res)
return res;
- sprintf(cmd, "ubifsmount %s", location->ubivol);
+ sprintf(cmd, "ubifsmount ubi0:%s", location->ubivol);
res = run_command(cmd, 0);
return res;
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;
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;
/* 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;
/* 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;
/* 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");
*/
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;
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);
}
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);
+ }
}
}
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);
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;
}
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;
}
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;
}
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;
}
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);
}
}
if (!if_face) {
- printf("selecting invalid interface %d", interface);
+ pr_err("selecting invalid interface %d", interface);
return -EINVAL;
}
/*
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 */
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;
}
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;
}
*/
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);
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;
}
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);
*/
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;
}
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;
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;
}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+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'.
--- /dev/null
+# 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
--- /dev/null
+#!/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:
--- /dev/null
+3.0 (quilt)
--- /dev/null
+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
--- /dev/null
+#!/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
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
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,
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);
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;
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
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 */
}
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;
}
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;
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;
*/
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;
}
/* 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;
}
/* 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;
* 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;
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;
* 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;
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 {
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;
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);
*/
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;
}
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" : ""),
/* 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;
/* 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;
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);
}
}
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;
}
/* 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;
}
/* 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;
}
/* 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);
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;
* 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;
* 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;
}
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);
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 */
/* "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;
}
/* 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;
}
/* 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;
}
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;
}
*/
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 */
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;
}
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;
}
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);
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;
}
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;
}
* 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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
{
/* 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;
}
/* 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;
}
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;
}
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;
}
}
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;
}
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;
}
efi_guid_t unused_guid;
if (!pte) {
- printf("%s: Invalid Argument(s)\n", __func__);
+ pr_err("%s: Invalid Argument(s)\n", __func__);
return 0;
}
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
obj-$(CONFIG_DM_RNG) += rng/
endif
+obj-$(CONFIG_TARGET_SPACEMIT_K1X) += ddr/spacemit/k1x/
obj-y += soc/
[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] = {
[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)
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
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/uniphier/Kconfig"
+source "drivers/clk/spacemit/Kconfig"
endmenu
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/
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/
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;
}
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);
}
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);
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;
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);
}
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;
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);
}
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;
}
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;
}
}
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;
}
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;
}
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)
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);
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)
{
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);
{
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);
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);
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)
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;
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;
{
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;
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;
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);
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);
}
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);
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;
}
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);
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;
}
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;
}
}
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);
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;
}
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;
}
--- /dev/null
+# 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.
+
+
--- /dev/null
+# 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
--- /dev/null
+// 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,
+};
+
--- /dev/null
+// 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_ */
--- /dev/null
+// 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,
+};
+
--- /dev/null
+// 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
--- /dev/null
+// 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,
+};
+
--- /dev/null
+// 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_ */
--- /dev/null
+// 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,
+};
+
--- /dev/null
+// 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
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
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
--- /dev/null
+# 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
--- /dev/null
+// 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
--- /dev/null
+// 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_ */
--- /dev/null
+// 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,
+};
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+// 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
+
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"
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/
--- /dev/null
+// 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),
+};
+
--- /dev/null
+#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
+
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
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"
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
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
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
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
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
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
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
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
--- /dev/null
+// 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;
+}
#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
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
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);
.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",
.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
.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",
.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",
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
*
*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
*
{
/* 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;
*/
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);
*/
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
}
#endif
+#if !defined(CONFIG_SPL_BUILD)
/**
* reboot_bootloader() - Sets reboot bootloader flag.
*
else
fastboot_okay(NULL, response);
}
+#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
/**
/* 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
/* 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
fastboot_response("OKAY", response, NULL);
}
+#if !defined(CONFIG_SPL_BUILD)
/**
* fastboot_set_reboot_flag() - Set flag to indicate reboot-bootloader
*
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);
do_reset(NULL, 0, 0, NULL);
}
}
+#endif /*#!defined(CONFIG_SPL_BUILD)*/
/**
* fastboot_set_progress_callback() - set progress callback
#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)
}, {
.variable = "version-bootloader",
.dispatch = getvar_version_bootloader
+ }, {
+ .variable = "version-IC",
+ .dispatch = getvar_version_IC
}, {
.variable = "downloadsize",
.dispatch = getvar_downloadsize
}, {
.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
.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
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;
}
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);
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)
{
}
#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;
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)
#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
{
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)
{
return ret;
}
+
/**
* fastboot_mmc_flash_write() - Write image to eMMC for fastboot
*
{
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) {
#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;
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;
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;
} 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;
}
}
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;
+}
+
--- /dev/null
+// 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;
+}
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;
--- /dev/null
+// 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
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)
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
--- /dev/null
+// 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
--- /dev/null
+#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__ */
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
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
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
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,
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,
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;
}
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;
}
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;
}
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);
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;
}
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
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
--- /dev/null
+// 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 */
--- /dev/null
+/* 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
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
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
--- /dev/null
+#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,
+};
+
+
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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
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
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
--- /dev/null
+// 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),
+};
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;
}
struct mmc *m = mmc_get_mmc_dev(dev);
if (!first) {
- printf("%c", separator);
+ pr_info("%c", separator);
if (separator != '\n')
puts(" ");
}
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);
}
#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)
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;
}
}
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
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;
}
#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;
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 */
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;
}
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;
}
}
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;
}
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));
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");
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;
}
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;
}
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;
}
}
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;
}
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;
}
#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;
}
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;
}
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;
}
--- /dev/null
+// 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),
+};
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
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);
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)) {
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;
}
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');
for (sect = s_first; sect <= s_last; sect++) {
if (ctrlc()) {
- printf("\n");
+ pr_debug("\n");
return 1;
}
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:");
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
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);
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
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;
}
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] =
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 */
/* 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;
}
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;
}
* 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;
*/
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;
}
/* 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);
+ }
}
}
.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;
}
#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 */
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__ */
} 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;
}
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++;
/* 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;
}
/* 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;
}
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;
}
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;
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
# 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
µn_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
+ &other_spinand_manufacturer,
};
static int spinand_manufacturer_detect(struct spinand_device *spinand)
--- /dev/null
+// 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,
+};
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
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
* 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);
}
#include <malloc.h>
#include <spi.h>
#include <spi_flash.h>
+#include <blk.h>
+#include <dm/device-internal.h>
#include "sf_internal.h"
/* Setup spi_slave */
if (!spi) {
- printf("SF: Failed to set up slave\n");
+ pr_err("SF: Failed to set up slave\n");
return -ENODEV;
}
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,
.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,
};
--- /dev/null
+#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
{ 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) },
{ 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 */
#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
{ },
};
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
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"
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
obj-y += phy/
obj-y += qe/
obj-y += ti/
+obj-y += spacemit/
{
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 |
(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;
}
{
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
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) |
(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;
}
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
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 */
/* 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;
{ .compatible = "amlogic,meson6-dwmac" },
{ .compatible = "st,stm32-dwmac" },
{ .compatible = "snps,arc-dwmac-3.70a" },
+ { .compatible = "snps,dwmac" },
{ }
};
u32 dmamac_next;
} __aligned(ARCH_DMA_MINALIGN);
+struct dmamachaddr {
+ u32 dmamac_haddr;
+ u32 dmamac_hnext;
+ } __aligned(ARCH_DMA_MINALIGN);
+
/*
* txrx_status definitions
*/
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);
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);
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,
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
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
},
#endif
+#if IS_ENABLED(CONFIG_DWC_ETH_QOS_SPACEMIT)
+ {
+ .compatible = "spacemit,k1pro-dwmac-eqos",
+ .data = (ulong)&eqos_spacemit_config
+ },
+#endif
+
{ }
};
int eqos_null_ops(struct udevice *dev);
extern struct eqos_config eqos_imx_config;
+extern struct eqos_config eqos_spacemit_config;
--- /dev/null
+// 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
+};
--- /dev/null
+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.
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2023 Spacemit
+
+obj-$(CONFIG_SPACEMIT_K1X_EMAC) += k1x_emac.o
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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_
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
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
--- /dev/null
+// 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),
+};
source "drivers/phy/rockchip/Kconfig"
source "drivers/phy/cadence/Kconfig"
source "drivers/phy/ti/Kconfig"
+source "drivers/phy/spacemit/Kconfig"
endmenu
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
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+// 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
--- /dev/null
+// 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),
+};
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"
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
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)
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);
}
}
--- /dev/null
+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
--- /dev/null
+obj-$(CONFIG_PINCTRL_SPACEMIT) += pinctrl-spacemit.o
+obj-$(CONFIG_PINCTRL_K1PRO) += pinctrl-k1pro.o
--- /dev/null
+// 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;
+}
--- /dev/null
+/* 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 */
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
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
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
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
--- /dev/null
+#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,
+};
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
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
--- /dev/null
+// 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,
+};
--- /dev/null
+// 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, ®val, 1);
+ regval |= (1 << (ffs(buck_desc[i].enable_msk) - 1));
+ i2c_write(saddr, buck_desc[i].enable_reg, 1, ®val, 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, ®val, 1);
+ regval = (regval & ~buck_desc[i].vsel_msk) | sel;
+ i2c_write(saddr, buck_desc[i].vsel_reg, 1, ®val, 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, ®val, 1);
+ regval |= (1 << (ffs(ldo_desc[i].enable_msk) - 1));
+ i2c_write(saddr, ldo_desc[i].enable_reg, 1, ®val, 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, ®val, 1);
+ regval = (regval & ~ldo_desc[i].vsel_msk) | sel;
+ i2c_write(saddr, ldo_desc[i].vsel_reg, 1, ®val, 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;
+}
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.
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
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)
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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,
+};
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
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
--- /dev/null
+// 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),
+};
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
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);
}
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);
}
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
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
/* 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;
}
--- /dev/null
+// 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,
+};
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
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
--- /dev/null
+/* 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,
+};
#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)
*/
u64 notrace timer_early_get_count(void)
{
- return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE));
+ return sifive_clint_get_count(NULL);
}
#endif
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) ==
#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))
#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;
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,
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)));
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;
{ .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" },
{ }
};
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
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
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
#include <asm/unaligned.h>
#include <asm/io.h>
-#include <asm/mach-types.h>
-
#include <power/regulator.h>
#include "dwc2_udc_otg_regs.h"
{
/* 2. Soft-reset OTG Core and then unreset again. */
int i;
- unsigned int uTemp = writel(CORE_SOFT_RESET, ®->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, ®->grstctl);
debug("Resetting OTG controller\n");
dflt_gusbcfg =
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)
{
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 },
#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"
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;
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 */
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;
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)
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;
}
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)
{
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};
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;
}
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();
fastboot_acmd_complete();
}
#endif
+#endif /* !defined(CONFIG_SPL_BUILD) */
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:
fastboot_func->in_req->complete = do_acmd_complete;
break;
#endif
+#endif /* !defined(CONFIG_SPL_BUILD) */
}
}
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:
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;
#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:
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");
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();
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 */
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);
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;
}
}
#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");
#include <usb_mass_storage.h>
#include <dfu.h>
#include <thor.h>
-
+#include <asm/io.h>
#include <env_callback.h>
#include "gadget_chips.h"
}
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;
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);
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;
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
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
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
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;
#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
#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
--- /dev/null
+// 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,
+};
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
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
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)
{
{
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");
{
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;
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
+
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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_*/
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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(¶meter[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(¶meter[4], cmd_line.data, len);
+ crc = calculate_crc16(¶meter[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, ¶meter[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, ¶meter[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, ¶meter[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;
+}
--- /dev/null
+// 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_*/
--- /dev/null
+// 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_*/
--- /dev/null
+// 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_*/
--- /dev/null
+// 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_ */
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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
--- /dev/null
+// 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),
+};
--- /dev/null
+// 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
#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
#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);
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);
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) {
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;
}
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;
}
}
}
+#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
#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
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;
}
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;
}
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.
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
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
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.
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
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
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
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
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)
}
}
} else {
- printf("Error compiling regex: %s\n", slre.err_str);
+ pr_err("Error compiling regex: %s\n", slre.err_str);
retval = -EINVAL;
}
done:
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;
}
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);
}
{
if (s) {
if ((flags & H_INTERACTIVE) == 0) {
- printf("*** Warning - %s, "
+ pr_err("*** Warning - %s, "
"using default environment\n\n", s);
} else {
puts(s);
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;
}
}
static enum env_location env_locations[] = {
+#ifdef CONFIG_ENV_IS_IN_NVRAM
+ ENVL_NVRAM,
+#endif
#ifdef CONFIG_ENV_IS_IN_EEPROM
ENVL_EEPROM,
#endif
#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
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
*/
ret = drv->load();
if (!ret) {
- printf("OK\n");
+ pr_info("OK\n");
gd->env_load_prio = prio;
#if !CONFIG_IS_ENABLED(ENV_APPEND)
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;
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;
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;
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);
}
if (!found) {
- printf("driver not found\n");
+ pr_info("driver not found\n");
return -ENODEV;
}
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;
}
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++;
}
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++;
}
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;
}
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;
}
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;
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;
* 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;
}
(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;
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
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) {
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;
}
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;
errmsg = init_mmc_for_env(mmc);
if (errmsg) {
- printf("%s\n", errmsg);
+ pr_info("%s\n", errmsg);
return 1;
}
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;
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;
errmsg = init_mmc_for_env(mmc);
if (errmsg) {
- printf("%s\n", errmsg);
+ pr_info("%s\n", errmsg);
return 1;
}
goto fini;
}
- printf("\n");
+ pr_info("\n");
ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
#ifdef CONFIG_ENV_OFFSET_REDUND
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);
--- /dev/null
+#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,
+};
+
+
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);
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
* 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;
}
#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.
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)
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)
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);
}
}
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 */
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 {
--- /dev/null
+#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 */
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
*/
/**
* @env_buf: buffer for env_get() before reloc
*/
- char env_buf[32];
+ char env_buf[128];
#ifdef CONFIG_TRACE
/**
* @trace_buff: trace buffer
* @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);
IF_TYPE_PVBLOCK,
IF_TYPE_VIRTIO,
IF_TYPE_EFI_MEDIA,
+ IF_TYPE_NOR,
IF_TYPE_COUNT, /* Number of interface types */
};
#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
*/
--- /dev/null
+/*
+ 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
* 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
* 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.
*
* 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
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;
}
* 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__ */
/*
--- /dev/null
+/* 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 */
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);
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);
--- /dev/null
+// 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_ */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+// 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__ */
--- /dev/null
+/* 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_ */
# 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;
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
#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
ENVL_FLASH,
ENVL_MMC,
ENVL_NAND,
+ ENVL_MTD,
ENVL_NVRAM,
ENVL_ONENAND,
ENVL_REMOTE,
enum {
FASTBOOT_COMMAND_GETVAR = 0,
FASTBOOT_COMMAND_DOWNLOAD,
+ FASTBOOT_COMMAND_UPLOAD,
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
FASTBOOT_COMMAND_FLASH,
FASTBOOT_COMMAND_ERASE,
#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
};
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
*
--- /dev/null
+// 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
* @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
--- /dev/null
+// 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
--- /dev/null
+/* 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
lbaint_t blksz;
lbaint_t start;
lbaint_t size;
+ lbaint_t erase_size;
void *priv;
lbaint_t (*write)(struct sparse_storage *info,
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);
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
#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
#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)
#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))
--- /dev/null
+#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__ */
--- /dev/null
+#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__ */
--- /dev/null
+#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__ */
--- /dev/null
+#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
SPLASH_STORAGE_USB,
SPLASH_STORAGE_SATA,
SPLASH_STORAGE_VIRTIO,
+ SPLASH_STORAGE_NVME,
};
enum splash_flags {
};
#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,
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
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
--- /dev/null
+/*
+ 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);
+}
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,
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)) {
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) {
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",
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;
}
$(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)
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);
--- /dev/null
+# -*- 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:])
+