@@ -6,3 +6,4 @@
obj-y := cpu.o
obj-y += cache.o
obj-y += spl.o
+obj-$(CONFIG_SYS_HAS_NONCACHED_MEMORY) += noncache.o
@@ -22,6 +22,9 @@ int cleanup_before_linux(void)
{
disable_interrupts();
+ if (IS_ENABLED(CONFIG_SYS_HAS_NONCACHED_MEMORY))
+ noncached_free();
+
cache_flush();
return 0;
new file mode 100644
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ */
+
+#include <cpu_func.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/sbi.h>
+#include <asm/system.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+static unsigned long noncached_start;
+static unsigned long noncached_end;
+static unsigned long noncached_next;
+
+void noncached_set_region(void)
+{
+}
+
+int noncached_init(void)
+{
+ phys_addr_t start, end;
+ size_t size;
+ int ret;
+
+ /* If this calculation changes, update board_f.c:reserve_noncached() */
+ end = ALIGN(mem_malloc_start, MMU_SECTION_SIZE) - MMU_SECTION_SIZE;
+ size = ALIGN(CONFIG_SYS_NONCACHED_MEMORY, MMU_SECTION_SIZE);
+ start = end - size;
+
+ debug("mapping memory %pa-%pa non-cached\n", &start, &end);
+
+ ret = sbi_pma_probe();
+ if (ret <= 0) {
+ debug("PMA probe failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = sbi_pma_set(start, size,
+ ANDES_PMACFG_ETYP_NAPOT |
+ ANDES_PMACFG_MTYP_MEM_NON_CACHE_BUF);
+ if (ret) {
+ debug("PMA set failed: %d\n", ret);
+ return ret;
+ }
+
+ noncached_start = start;
+ noncached_end = end;
+ noncached_next = start;
+
+ return 0;
+}
+
+phys_addr_t noncached_alloc(size_t size, size_t align)
+{
+ phys_addr_t next = ALIGN(noncached_next, align);
+
+ if (next >= noncached_end || (noncached_end - next) < size)
+ return 0;
+
+ debug("allocated %zu bytes of uncached memory @%pa\n", size, &next);
+ noncached_next = next + size;
+
+ return next;
+}
+
+void noncached_free(void)
+{
+ if (!noncached_start)
+ return;
+
+ if (sbi_pma_probe() <= 0)
+ return;
+
+ sbi_pma_free(noncached_start);
+}
@@ -100,6 +100,7 @@ int noncached_init(void);
void noncached_set_region(void);
phys_addr_t noncached_alloc(size_t size, size_t align);
+void noncached_free(void);
enum {
/* Disable caches (else flush caches but leave them active) */
Implement noncached memory region management for Andes RISC-V platforms using SBI PMA (Physical Memory Attribute) calls: - noncached_init(): Compute region below malloc area, probe PMA support via sbi_pma_probe(), then configure the region as non-cacheable bufferable using sbi_pma_set() with NAPOT and NON_CACHE_BUF flags. - noncached_alloc(): Bump allocator from the noncached region. - noncached_set_region(): No-op since PMA handles attributes. - noncached_free(): Release PMA entry, with probe-before-free guard to avoid calling free on unsupported firmware. Also call noncached_free() in cleanup_before_linux() before cache_flush() so the PMA entry is released before handing off to Linux. Signed-off-by: Leo Yu-Chi Liang <ycliang@andestech.com> --- arch/riscv/cpu/andes/Makefile | 1 + arch/riscv/cpu/andes/cpu.c | 3 ++ arch/riscv/cpu/andes/noncache.c | 79 +++++++++++++++++++++++++++++++++ include/cpu_func.h | 1 + 4 files changed, 84 insertions(+) create mode 100644 arch/riscv/cpu/andes/noncache.c