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]> Signed-off-by: Guodong Xu <[email protected]> --- v4: - DT: binman u-boot-spl-ddr moves into k1-bananapi-f3-u-boot.dtsi. - fence.i instead of flush_dcache_range() after firmware copy. - Log fix: "DDR isn't invalid" -> "DDR is not ready". - Makefile: FORCE, cmp -s, clean-files. --- arch/riscv/dts/k1-bananapi-f3-u-boot.dtsi | 23 ++++++ board/spacemit/k1/Makefile | 21 +++++ board/spacemit/k1/spl.c | 127 ++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) diff --git a/arch/riscv/dts/k1-bananapi-f3-u-boot.dtsi b/arch/riscv/dts/k1-bananapi-f3-u-boot.dtsi index ac56bf512ad..1a6240a9725 100644 --- a/arch/riscv/dts/k1-bananapi-f3-u-boot.dtsi +++ b/arch/riscv/dts/k1-bananapi-f3-u-boot.dtsi @@ -73,3 +73,26 @@ bootph-pre-ram; }; }; + +&binman { + u-boot-spl-ddr { + type = "section"; + filename = "u-boot-spl-ddr.bin"; + pad-byte = <0xff>; + + u-boot-spl { + }; + + ddr-fw { + type = "blob"; + filename = "ddr_fw.bin"; + align = <64>; + }; + + u-boot-any { + type = "section"; + size = <0>; + offset = <0>; + }; + }; +}; diff --git a/board/spacemit/k1/Makefile b/board/spacemit/k1/Makefile index f9cbf4b0e06..a57af2e1f08 100644 --- a/board/spacemit/k1/Makefile +++ b/board/spacemit/k1/Makefile @@ -5,3 +5,24 @@ obj-y := board.o obj-$(CONFIG_SPL_BUILD) += spl.o + +DDR_FW_SRC ?= $(DDR_FW_FILE) +FW_TARGET = $(objtree)/ddr_fw.bin + +$(obj)/spl.o: $(FW_TARGET) + +$(FW_TARGET): FORCE + @if [ -n "$(DDR_FW_SRC)" ] && [ -f "$(DDR_FW_SRC)" ]; then \ + if ! cmp -s "$(DDR_FW_SRC)" $@ 2>/dev/null; then \ + echo " Copying DDR firmware from: $(DDR_FW_SRC)"; \ + cp "$(DDR_FW_SRC)" $@; \ + fi; \ + elif [ -s $@ ]; then \ + : ; \ + else \ + echo " Note: No DDR firmware found, creating empty placeholder"; \ + echo " (Set DDR_FW_FILE to specify firmware location)"; \ + touch $@; \ + fi + +clean-files += $(FW_TARGET) diff --git a/board/spacemit/k1/spl.c b/board/spacemit/k1/spl.c index e862548f980..bab4fac3a13 100644 --- a/board/spacemit/k1/spl.c +++ b/board/spacemit/k1/spl.c @@ -4,8 +4,11 @@ */ #include <asm/io.h> +#include <binman.h> +#include <binman_sym.h> #include <clk.h> #include <clk-uclass.h> +#include <cpu_func.h> #include <configs/k1.h> #include <dm/device.h> #include <dm/uclass.h> @@ -14,6 +17,7 @@ #include <log.h> #include <spl.h> #include <tlv_eeprom.h> +#include "tlv_codes.h" #define MUX_MODE4 4 #define EDGE_NONE BIT(6) @@ -26,6 +30,29 @@ #define MFP_GPIO_84 0xd401e154 #define MFP_GPIO_85 0xd401e158 +#define DDR_FIRMWARE_BASE 0xc082d000 + +#define DDR_DEFAULT_CS_NUM 2 +#define DDR_DEFAULT_TYPE "LPDDR4X" +#define DDR_DEFAULT_TX_ODT 80 +#define DDR_DEFAULT_DATA_RATE 2400 + +#define MAGIC_NUM 0xaa55aa55 + +typedef void (*puts_func_t)(const char *s); +typedef int (*ddr_init_func_t)(u64 ddr_base, u32 cs_num, u32 data_rate, + puts_func_t puts); + +struct ddr_cfg { + u32 data_rate; + u32 cs_num; + u32 tx_odt; + u8 type[I2C_BUF_SIZE]; +}; + +binman_sym_declare(ulong, ddr_fw, image_pos); +binman_sym_declare(ulong, ddr_fw, size); + static void i2c_early_init(void) { struct udevice *bus; @@ -109,6 +136,105 @@ void serial_early_init(void) panic("Serial uclass init failed: %d\n", ret); } +/* Set default value for DDR chips */ +static void ddr_cfg_init(struct ddr_cfg *cfg) +{ + memset(cfg, 0, sizeof(struct ddr_cfg)); + cfg->data_rate = DDR_DEFAULT_DATA_RATE; + cfg->cs_num = DDR_DEFAULT_CS_NUM; + cfg->tx_odt = DDR_DEFAULT_TX_ODT; + strcpy(cfg->type, DDR_DEFAULT_TYPE); +} + +int read_ddr_info(struct ddr_cfg *cfg) +{ + u8 eeprom_data[TLV_TOTAL_LEN_MAX], *p; + struct tlvinfo_header *tlv_hdr; + struct tlvinfo_tlv *tlv_entry; + u32 size, entry_size; + int ret, i; + bool found = false; + + if (!cfg) + return -EINVAL; + ddr_cfg_init(cfg); + ret = read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr, + &tlv_entry, i); + if (ret) + return ret; + p = (u8 *)tlv_entry; + for (i = 0; i < tlv_hdr->totallen; ) { + switch (tlv_entry->type) { + case TLV_CODE_DDR_CSNUM: + memcpy(&cfg->cs_num, &tlv_entry->value[0], 1); + found = true; + break; + case TLV_CODE_DDR_TYPE: + size = min((u32)tlv_entry->length, (u32)I2C_BUF_SIZE); + memcpy(&cfg->type[0], &tlv_entry->value[0], size); + found = true; + break; + case TLV_CODE_DDR_DATARATE: + memcpy(&cfg->data_rate, &tlv_entry->value[0], 2); + found = true; + break; + case TLV_CODE_DDR_TX_ODT: + memcpy(&cfg->tx_odt, &tlv_entry->value[0], 1); + found = true; + break; + case TLV_CODE_CRC_32: + if (!found) + return -ENOENT; + return 0; + } + entry_size = tlv_entry->length + sizeof(struct tlvinfo_tlv); + i += entry_size; + p += entry_size; + tlv_entry = (struct tlvinfo_tlv *)p; + } + if (!found) + return -ENOENT; + return 0; +} + +void ddr_early_init(void) +{ + void __iomem *src, *dst; + ulong pos, size; + struct ddr_cfg cfg; + ddr_init_func_t ddr_init; + + pos = binman_sym(ulong, ddr_fw, image_pos); + size = binman_sym(ulong, ddr_fw, size); + src = (void __iomem *)pos; + dst = (void __iomem *)(DDR_FIRMWARE_BASE); + log_info("DDR firmware: [0x%lx]:0x%x, size:0x%lx\n", pos, readl(src), size); + memcpy((u8 *)dst, (u8 *)src, size); + size = round_up(size, 64); + /* + * Ensure the just-written DDR firmware bytes are observable in the + * instruction stream. RISC-V's fence.i alone is sufficient for the + * single-hart SPL case; skip flush_dcache_range as cbo.flush may + * trap on our current privilege state. + */ + asm volatile ("fence.i" ::: "memory"); + + read_ddr_info(&cfg); + ddr_init = (ddr_init_func_t)DDR_FIRMWARE_BASE; +#ifdef DEBUG + ddr_init(0xc0000000, cfg.cs_num, cfg.data_rate, puts); +#else + ddr_init(0xc0000000, cfg.cs_num, cfg.data_rate, NULL); +#endif + writel(MAGIC_NUM, (void __iomem *)0x00000000); + flush_dcache_range(0, 64); + invalidate_dcache_range(0, 64); + if (readl((void __iomem *)0x00000000) == MAGIC_NUM) + log_info("DDR is ready\n"); + else + log_info("DDR is not ready\n"); +} + void board_init_f(ulong dummy) { u8 i2c_buf[I2C_BUF_SIZE] = { 0 }; @@ -131,6 +257,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) -- 2.43.0

