Add SPL initialization support for SpacemiT K3. Enable instruction and
data caches and cache snooping during early hart initialization, and
provide the timer configuration needed for M-mode execution.

Initialize I2C and read the DDR part number from the board's TLV EEPROM.
Populate the RAM driver's platform data before probing it to initialize
DRAM. Set up the DRAM PMA boundary and record the RAM base and size in
global data.

Loading the next boot stage is not yet supported.

Signed-off-by: Junhui Liu <[email protected]>
---
 arch/riscv/cpu/k3/Kconfig            |   6 +-
 arch/riscv/cpu/k3/Makefile           |   1 +
 arch/riscv/cpu/k3/spl.c              |  52 ++++++++++++++
 arch/riscv/include/asm/arch-k3/csr.h |  20 ++++++
 arch/riscv/include/asm/arch-k3/spl.h |  11 +++
 board/spacemit/k3/Makefile           |   5 ++
 board/spacemit/k3/spl.c              | 127 +++++++++++++++++++++++++++++++++++
 include/configs/spacemit-k3.h        |   3 +
 8 files changed, 224 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/cpu/k3/Kconfig b/arch/riscv/cpu/k3/Kconfig
index 5474ac11243..dee79644b87 100644
--- a/arch/riscv/cpu/k3/Kconfig
+++ b/arch/riscv/cpu/k3/Kconfig
@@ -9,10 +9,14 @@ config SPACEMIT_K3
        select BINMAN
        select ARCH_EARLY_INIT_R
        select SYS_CACHE_SHIFT_6
+       select SUPPORT_SPL
        imply CPU
        imply CPU_RISCV
-       imply RISCV_TIMER if RISCV_SMODE
+       imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
+       imply RISCV_ACLINT if RISCV_MMODE
+       imply SPL_RISCV_ACLINT if SPL_RISCV_MMODE
        imply CMD_CPU
+       imply SPL_CPU
        imply OF_UPSTREAM
 
 endif
diff --git a/arch/riscv/cpu/k3/Makefile b/arch/riscv/cpu/k3/Makefile
index fba4e4b0a3f..6afe6caac69 100644
--- a/arch/riscv/cpu/k3/Makefile
+++ b/arch/riscv/cpu/k3/Makefile
@@ -3,3 +3,4 @@
 # Copyright (C) 2026 Yixun Lan <[email protected]>
 
 obj-y += dram.o
+obj-$(CONFIG_XPL_BUILD) += spl.o
diff --git a/arch/riscv/cpu/k3/spl.c b/arch/riscv/cpu/k3/spl.c
new file mode 100644
index 00000000000..e8ee32e37fd
--- /dev/null
+++ b/arch/riscv/cpu/k3/spl.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#include <asm/arch/csr.h>
+#include <asm/arch/spl.h>
+#include <asm/csr.h>
+#include <asm/global_data.h>
+#include <dm.h>
+#include <ram.h>
+
+#define K3_DRAM_UPPER_LIMIT_ADDR       0x1100000000ULL
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void setup_dram_pma(void)
+{
+       csr_write(CSR_X100_PMAADDR8, K3_DRAM_UPPER_LIMIT_ADDR >> 2);
+       asm volatile("sfence.vma zero, zero" ::: "memory");
+}
+
+int spl_dram_init(void)
+{
+       struct ram_info info;
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+       if (ret) {
+               printf("DRAM init failed: %d\n", ret);
+               return ret;
+       }
+
+       setup_dram_pma();
+
+       ret = ram_get_info(dev, &info);
+       if (ret)
+               return ret;
+
+       gd->ram_base = info.base;
+       gd->ram_size = info.size;
+
+       return 0;
+}
+
+void harts_early_init(void)
+{
+       csr_set(CSR_X100_CACHE_CTL, CSR_X100_CACHE_CTL_ICACHE_EN |
+                                   CSR_X100_CACHE_CTL_DCACHE_EN);
+       csr_set(CSR_X100_SNOOP_CTL, CSR_X100_SNOOP_CTL_EN);
+}
diff --git a/arch/riscv/include/asm/arch-k3/csr.h 
b/arch/riscv/include/asm/arch-k3/csr.h
new file mode 100644
index 00000000000..a6c3e6af9f5
--- /dev/null
+++ b/arch/riscv/include/asm/arch-k3/csr.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#ifndef _ASM_ARCH_K3_CSR_H_
+#define _ASM_ARCH_K3_CSR_H_
+
+#include <linux/bitops.h>
+
+#define CSR_X100_CACHE_CTL             0x7c0
+#define  CSR_X100_CACHE_CTL_ICACHE_EN  BIT(1)
+#define  CSR_X100_CACHE_CTL_DCACHE_EN  BIT(0)
+
+#define CSR_X100_SNOOP_CTL             0x7f0
+#define  CSR_X100_SNOOP_CTL_EN         BIT(0)
+
+#define CSR_X100_PMAADDR8              0x7e8
+
+#endif /* _ASM_ARCH_K3_CSR_H_ */
diff --git a/arch/riscv/include/asm/arch-k3/spl.h 
b/arch/riscv/include/asm/arch-k3/spl.h
new file mode 100644
index 00000000000..7dda93cfda8
--- /dev/null
+++ b/arch/riscv/include/asm/arch-k3/spl.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#ifndef _ASM_ARCH_K3_SPL_H_
+#define _ASM_ARCH_K3_SPL_H_
+
+int spl_dram_init(void);
+
+#endif /* _ASM_ARCH_K3_SPL_H_ */
diff --git a/board/spacemit/k3/Makefile b/board/spacemit/k3/Makefile
new file mode 100644
index 00000000000..67f30a40e6c
--- /dev/null
+++ b/board/spacemit/k3/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Junhui Liu <[email protected]>
+
+obj-$(CONFIG_SPL_BUILD) += spl.o
diff --git a/board/spacemit/k3/spl.c b/board/spacemit/k3/spl.c
new file mode 100644
index 00000000000..4798e5c9ebc
--- /dev/null
+++ b/board/spacemit/k3/spl.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#include <asm/arch/spl.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <display_options.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <errno.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <soc/spacemit/k3-ddr.h>
+#include <spl.h>
+#include <tlv_eeprom.h>
+
+#define MUX_MODE5              5
+#define EDGE_NONE              BIT(6)
+#define PULL_UP                        (6 << 13)
+#define I2C_PIN_CONFIG(x)      ((x) | EDGE_NONE | PULL_UP)
+
+#define MFP_GPIO_46            0xd401e0b8
+#define MFP_GPIO_47            0xd401e0bc
+
+#define K3_TLV_CODE_DDR_PART_NUMBER    0x45
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void i2c_early_init(void)
+{
+       struct udevice *bus;
+
+       /* EEPROM uses I2C2 on GPIO46 and GPIO47. */
+       writel(I2C_PIN_CONFIG(MUX_MODE5), (void __iomem *)MFP_GPIO_46);
+       writel(I2C_PIN_CONFIG(MUX_MODE5), (void __iomem *)MFP_GPIO_47);
+
+       udelay(100);
+
+       uclass_first_device(UCLASS_I2C, &bus);
+       while (bus) {
+               uclass_next_device(&bus);
+               if (!bus)
+                       break;
+       }
+}
+
+static int read_ddr_part_number(char *part, size_t part_size)
+{
+       struct tlvinfo_header *header;
+       u8 contents[TLV_INFO_MAX_LEN];
+       struct tlvinfo_tlv *entry;
+       u8 *end;
+       int ret;
+
+       ret = read_tlvinfo_tlv_eeprom(contents, &header, &entry, 0);
+       if (ret)
+               return ret;
+
+       end = (u8 *)(header + 1) + be16_to_cpu(header->totallen);
+
+       while ((u8 *)entry + sizeof(*entry) <= end) {
+               if ((u8 *)entry + sizeof(*entry) + entry->length > end)
+                       return -EINVAL;
+
+               if (entry->type == TLV_CODE_CRC_32)
+                       break;
+
+               if (entry->type == K3_TLV_CODE_DDR_PART_NUMBER) {
+                       if (!entry->length || entry->length >= part_size)
+                               return -EINVAL;
+
+                       memcpy(part, entry->value, entry->length);
+                       part[entry->length] = '\0';
+
+                       return 0;
+               }
+
+               entry = (void *)(entry->value + entry->length);
+       }
+
+       return -ENOENT;
+}
+
+static int setup_ddr_plat(void)
+{
+       struct k3_ddr_plat *plat;
+       struct udevice *dev;
+
+       dev = uclass_try_first_device(UCLASS_RAM);
+       if (!dev)
+               return -ENODEV;
+
+       if (!device_is_compatible(dev, "spacemit,k3-ddrc"))
+               return -ENODEV;
+
+       plat = dev_get_plat(dev);
+
+       return read_ddr_part_number(plat->part_number, 
sizeof(plat->part_number));
+}
+
+int spl_board_init_f(void)
+{
+       int ret;
+
+       i2c_early_init();
+
+       ret = setup_ddr_plat();
+       if (ret) {
+               printf("DDR identification failed: %d\n", ret);
+               return ret;
+       }
+
+       puts("DRAM:  ");
+       ret = spl_dram_init();
+       if (ret)
+               return ret;
+       print_size(gd->ram_size, "\n");
+
+       return 0;
+}
+
+u32 spl_boot_device(void)
+{
+       return BOOT_DEVICE_NONE;
+}
diff --git a/include/configs/spacemit-k3.h b/include/configs/spacemit-k3.h
index 9dd545e2a3b..ccd900ce91c 100644
--- a/include/configs/spacemit-k3.h
+++ b/include/configs/spacemit-k3.h
@@ -8,6 +8,9 @@
 
 #define CFG_SYS_NS16550_IER    0x40
 
+#define RISCV_MMODE_TIMERBASE  0xf1810000
+#define RISCV_MMODE_TIMEROFF   0xbff8
+#define RISCV_MMODE_TIMER_FREQ 24000000
 #define RISCV_SMODE_TIMER_FREQ 24000000
 
 #endif /* __SPACEMIT_K3_H */

-- 
2.56.0

Reply via email to