From: Raymond Mao <[email protected]> Include DDR initialization firmware in the SPL image. The firmware path can be specified via the DDR_FW_FILE environment variable. If the firmware is not found, an empty placeholder file is created to allow the build to proceed without DDR initialization support.
Signed-off-by: Raymond Mao <[email protected]> --- arch/riscv/dts/k1-spl.dts | 34 ++++++++++++++++++++++++++++++++- board/spacemit/k1/Kconfig | 8 ++++++++ board/spacemit/k1/Makefile | 19 ++++++++++++++++++ board/spacemit/k1/spl.c | 30 +++++++++++++++++++++++++++++ include/configs/k1.h | 3 +++ lib/vendor/spacemit/ddr_fw.bin | Bin 0 -> 19416 bytes 6 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 lib/vendor/spacemit/ddr_fw.bin diff --git a/arch/riscv/dts/k1-spl.dts b/arch/riscv/dts/k1-spl.dts index cd7875f3e35..f8b280fa96f 100644 --- a/arch/riscv/dts/k1-spl.dts +++ b/arch/riscv/dts/k1-spl.dts @@ -7,7 +7,6 @@ /dts-v1/; #include "k1.dtsi" -#include "binman.dtsi" / { model = "spacemit k1 spl"; @@ -21,6 +20,39 @@ stdout-path = "serial0:115200n8"; bootph-all; }; + + binman { + section { + filename = "u-boot-spl-ddr.bin"; + pad-byte = <0xff>; + align-size = <4>; + align = <4>; + + spl_section: section { + type = "section"; + size = <CONFIG_SPL_DDR_FIRMWARE_OFFSET>; + + u-boot-spl-nodtb { + type = "blob"; + filename = "spl/u-boot-spl.bin"; + align-end = <4>; + }; + + u-boot-spl-dtb { + type = "blob"; + filename = "spl/u-boot-spl.dtb"; + align-end = <4>; + }; + }; + + ddr_fw: ddr-firmware { + type = "blob"; + offset = <CONFIG_SPL_DDR_FIRMWARE_OFFSET>; + filename = "lib/vendor/spacemit/ddr_fw.bin"; + align-end = <4>; + }; + }; + }; }; &vctcxo_1m { diff --git a/board/spacemit/k1/Kconfig b/board/spacemit/k1/Kconfig index 9f9c806d00d..a5fa788f660 100644 --- a/board/spacemit/k1/Kconfig +++ b/board/spacemit/k1/Kconfig @@ -15,6 +15,14 @@ config SYS_CONFIG_NAME config TEXT_BASE default 0x00200000 +config SPL_DDR_FIRMWARE_OFFSET + hex "DDR firmware offset in SPL image" + depends on SPL + default 0x20000 + help + Offset where DDR firmware should be placed in the SPL + image. + config SPL_OPENSBI_LOAD_ADDR default 0x00000000 diff --git a/board/spacemit/k1/Makefile b/board/spacemit/k1/Makefile index 7bce47bac8c..ebe6e55867c 100644 --- a/board/spacemit/k1/Makefile +++ b/board/spacemit/k1/Makefile @@ -5,3 +5,22 @@ obj-y := board.o obj-$(CONFIG_SPL_BUILD) += spl.o + +DDR_FW_SRC ?= $(DDR_FW_FILE) +FW_TARGET = $(srctree)/lib/vendor/spacemit/ddr_fw.bin + +DDR_FW_HEADER = $(objtree)/include/generated/ddr_fw_info.h + +$(obj)/spl.o: $(DDR_FW_HEADER) + +$(DDR_FW_HEADER): $(FW_TARGET) + @echo "/* DDR firmware info - $$(date) */" > $@ + @if [ -f "$(FW_TARGET)" ]; then \ + SIZE=$$(stat -c%s "$(FW_TARGET)" 2>/dev/null || echo 0); \ + else \ + SIZE=0; \ + fi; \ + echo "#define DDR_FW_FILE_SIZE $$SIZE" >> $@ + @echo "/* Note: Update ADDR if binman layout changes */" >> $@ + +clean-files += $(FW_TARGET) $(DDR_FW_HEADER) diff --git a/board/spacemit/k1/spl.c b/board/spacemit/k1/spl.c index 6fe064bd430..54bad9000fe 100644 --- a/board/spacemit/k1/spl.c +++ b/board/spacemit/k1/spl.c @@ -6,10 +6,12 @@ #include <asm/io.h> #include <clk.h> #include <clk-uclass.h> +#include <cpu_func.h> #include <configs/k1.h> #include <dm/device.h> #include <dm/uclass.h> #include <dt-bindings/pinctrl/k1-pinctrl.h> +#include <generated/ddr_fw_info.h> #include <i2c.h> #include <linux/delay.h> #include <log.h> @@ -115,6 +117,33 @@ void serial_early_init(void) panic("Serial uclass init failed: %d\n", ret); } +/* Load DDR training firmware */ +int init_ddr_firmware(void) +{ + void __iomem *src, *dst; + unsigned long size; + + src = (void __iomem *)(CONFIG_SPL_TEXT_BASE + + CONFIG_SPL_DDR_FIRMWARE_OFFSET); + dst = (void __iomem *)(DDR_TRAINING_DATA_BASE); + memcpy(dst, src, DDR_FW_FILE_SIZE); + size = round_up(DDR_FW_FILE_SIZE, 64); + flush_dcache_range((u32)(u64)dst, (u32)(u64)dst + size); + return 0; +} + +void ddr_early_init(void) +{ + void __iomem *addr; + + init_ddr_firmware(); + addr = (void __iomem *)(CONFIG_SPL_TEXT_BASE + + CONFIG_SPL_DDR_FIRMWARE_OFFSET); + // verify DDR firmware header + log_info("[0x%x]:0x%x, firmware size:%d\n", + (uint)(u64)addr, readl(addr), DDR_FW_FILE_SIZE); +} + void board_init_f(ulong dummy) { u8 i2c_buf[I2C_BUF_SIZE]; @@ -138,6 +167,7 @@ void board_init_f(ulong dummy) log_info("Fail to detect board:%d\n", ret); else log_info("Get board name:%s\n", (char *)i2c_buf); + ddr_early_init(); } u32 spl_boot_device(void) diff --git a/include/configs/k1.h b/include/configs/k1.h index d46fec8b251..4cefdf7c725 100644 --- a/include/configs/k1.h +++ b/include/configs/k1.h @@ -16,4 +16,7 @@ #define RISCV_MMODE_TIMER_FREQ 24000000 #define RISCV_SMODE_TIMER_FREQ 24000000 +#define DDR_TRAINING_DATA_BASE 0xC0832000 +#define DDR_TRAINING_INFO_BUFF 0xC0800000 + #endif /* __CONFIG_H */ diff --git a/lib/vendor/spacemit/ddr_fw.bin b/lib/vendor/spacemit/ddr_fw.bin new file mode 100644 index 0000000000000000000000000000000000000000..cefecae24977ee76c74e6f3b658adc6a81984640 GIT binary patch literal 19416 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 literal 0 HcmV?d00001 -- 2.25.1

