U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards
@ 2026-11-01 21:04 Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support Indrek Kruusa
                   ` (10 more replies)
  0 siblings, 11 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Building upon the work of Samuel Holland [1], this series introduces support
for the Allwinner D1/D1s(F133) RISC-V SoCs and two development boards:

- Sipeed Lichee RV Dock (D1 SoC)
- MangoPi MQ (RISC-V version with D1s/F133-A SoC)

The main difference from Samuel's work is how the boards are wired into the
tree. The original design aimed at one cross-architecture configuration which
covers ARM sun8i and RISC-V sun20i parts from Allwinner. This series does not
do that. The D1/D1s get their own configuration instead:

  - arch/riscv/cpu/sun20i/ and board/sun20i/ hold the RISC-V side
  - SUN20I is a SoC-family symbol, TARGET_SUN20I the board target
  - the shared sunxi drivers accept SUN20I next to ARCH_SUNXI, so they are
    shared as before -- only the Kconfig condition changes

Keeping the two sides apart has a cost: a few things exist twice.
SUNXI_GEN_NCAT2 is declared in both arch trees, because the shared drivers
test it and no Kconfig file is sourced by both. clock_get_pll6() is a C
function for ARM (clock_sun50i_h6.c) and an inline for RISC-V
(arch-sun20i/clock.h), decoding the same NCAT2 registers. The MMC mod-clock
bits, the CCU offsets and parts of board/sunxi/board.c are repeated the same
way.

For the sake of simplicity the image names stay "sunxi"
(u-boot-sunxi-with-spl.bin, inner sunxi-spl.bin) because that is the shared
Allwinner eGON boot format.

Both defconfigs build, and both boards boot from the SD card to a userspace
login. The images were built with custom Buildroot configuration, using
gcc 16.2.0, binutils 2.46.1 and Linux 7.3.0.

One caveat -- reboot does not work yet; it needs fixes outside U-Boot, on the
firmware/OS side.

AI/LLM tools were used as development assistants throughout this work.
Their use included debugging DRAM initialization and probing issues,
assisting with code development, reviewing code, helping with testing and
validation, and reviewing and refining commit messages.

PS. The boards use CONFIG_NS16550_CLK_ENABLE, which comes from a patch
originally posted by khaliforce <kforce@gmail.com> and merged as commit
70f51e1e2ea5 ("serial: ns16550: make probe clock enabling optional") by
Samuel Holland; v2027.01-rc1 already contains it.

[1] https://github.com/smaeul/u-boot/tree/d1-wip


The patches (on tag v2027.01-rc1)
---------------------------------

1/10 riscv: cpu: add Allwinner D1/D1s(F133) CPU support
     Add the C906 support for the D1/D1s(F133) SoCs:

     - T-Head cache operations from the custom cache instructions
     - harts_early_init() programming MXSTATUS, MHCR and MHINT
     - cleanup_before_linux() disabling interrupts and flushing the caches
     - dram_init() from the device tree memory nodes
     - the T-Head CSR, CCU clock and memory map headers
     - SUN20I Kconfig (cache line size, T-Head CMO support)

2/10 sunxi: allow the sunxi drivers to be built for sun20i
     Accept SUN20I next to ARCH_SUNXI for the RAM, clock, pinctrl, GPIO, MMC,
     reset and watchdog drivers, and keep WATCHDOG_AUTOSTART off for it.

     Declare SUNXI_GEN_NCAT2 here as well - the ARM sunxi Kconfig is not read
     by a RISC-V build - and add the MMC base addresses to arch-sun20i/cpu.h
     so sunxi_mmc.c builds.

3/10 board: sun20i: add common support for the D1/D1s boards
     Add the board code used by all D1/D1s(F133) boards:

     - TARGET_SUN20I, board init and CPU probing
     - sunxi eGON/TOC0 SPL header: boot source, FEL mode, SPL size
     - SPL DRAM probing and the /memory fixup
     - FIT DT name matching
     - environment placement for MMC/SPI boot media
     - the u-boot-sunxi-with-spl.bin image
     - a MAINTAINERS section for the new board and CPU files

     CONFIG_ARCH_SUNXI is never set on these RISC-V parts, so extend the SPL
     image rule in scripts/Makefile.xpl to match TARGET_SUN20I as well.

     The board code, the devicetree overlay and include/configs/sun20i.h come
     from Samuel Holland's d1-wip tree [1]. The board code in turn derives from
     the ARM sunxi board code, so its copyright notices are kept.

     [1] https://github.com/smaeul/u-boot/tree/d1-wip

4/10 sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver
     Fix readl()/writel() address types for GCC 15+

     Use typed base address macros and cast remaining register addresses
     to void __iomem * to satisfy GCC 15's stricter type checking.

     No functional change.

5/10 sunxi: dram: count the banks on address bit 11, not A22
     The bank test looks for the BA2 alias at address bit 22, but in the mode
     the probe programs BA2 is bit 11. A four bank part therefore always
     reports eight banks, turning 64MB into 128MB.

     On a MangoPi MQ with F133-A the probe now reports 4 banks, 13 rows and 2KB
     pages - the vendor's dram_para1 = 0xd2. Boot tested on a Lichee RV Dock
     too, where a D1 with external 512MB DDR3 is detected correctly.

6/10 sunxi: dram: no AC remapping on the co-packaged DRAM parts
     The PHY AC remapping tables compensate for the drive strength of the
     DRAM chips connected to the SoC. This compensation must be skipped
     when the DRAM is integrated on-die.

7/10 sunxi: dram: let the board set the MR1 mode register
     The DRAM mode register 1 value belongs to the DRAM part, and the parts in
     use differ: 0x02 for the DDR2 die co-packaged with the D1s and F133-A,
     against the 0x42 that the boards with external DDR3 have booted with so
     far.

     Expose it next to the other vendor DRAM settings, keeping 0x42 as the
     default so nothing changes for the existing users.

8/10 sunxi: mmc: handle D1 PLL6 clock rate correctly
     Apply the existing MMC clock /2 compensation to SUN20I,
     as already done for SUN8I_R528.

9/10 configs: add the Lichee RV Dock defconfig
     Sipeed Lichee RV Dock: D1, 512 MB DDR3.

10/10 configs: add the MangoPi MQ D1s(F133) defconfig
     MangoPi MQ D1s(F133), 64 MB co-packaged DDR2.


 MAINTAINERS                                   |  10 +
 arch/riscv/Kconfig                            |  14 +
 arch/riscv/cpu/sun20i/Kconfig                 |  17 +
 arch/riscv/cpu/sun20i/Makefile                |   5 +
 arch/riscv/cpu/sun20i/cache.c                 |  88 ++++
 arch/riscv/cpu/sun20i/cpu.c                   |  44 ++
 arch/riscv/cpu/sun20i/dram.c                  |  21 +
 arch/riscv/dts/sun20i-u-boot.dtsi             |  86 ++++
 arch/riscv/include/asm/arch-sun20i/clock.h    |  71 +++
 arch/riscv/include/asm/arch-sun20i/cpu.h      |  22 +
 .../riscv/include/asm/arch-sun20i/thead_csr.h |  29 ++
 board/sun20i/Kconfig                          | 173 ++++++++
 board/sun20i/Makefile                         |   4 +
 board/sun20i/board.c                          | 309 +++++++++++++
 board/sun20i/spl.c                            | 142 ++++++
 configs/lichee_rv_dock_defconfig              |  14 +
 configs/mangopi_mq_d1s_defconfig              |  20 +
 drivers/clk/sunxi/Kconfig                     |   2 +-
 drivers/gpio/Kconfig                          |   2 +-
 drivers/mmc/Kconfig                           |   2 +-
 drivers/mmc/sunxi_mmc.c                       |   3 +-
 drivers/pinctrl/sunxi/Kconfig                 |   2 +-
 drivers/ram/sunxi/Kconfig                     |   8 +-
 drivers/ram/sunxi/dram_sun20i_d1.c            | 417 ++++++++++--------
 drivers/reset/Kconfig                         |   2 +-
 drivers/watchdog/Kconfig                      |   3 +-
 include/configs/sun20i.h                      |  11 +
 scripts/Makefile.xpl                          |   2 +-
 28 files changed, 1329 insertions(+), 194 deletions(-)
 create mode 100644 arch/riscv/cpu/sun20i/Kconfig
 create mode 100644 arch/riscv/cpu/sun20i/Makefile
 create mode 100644 arch/riscv/cpu/sun20i/cache.c
 create mode 100644 arch/riscv/cpu/sun20i/cpu.c
 create mode 100644 arch/riscv/cpu/sun20i/dram.c
 create mode 100644 arch/riscv/dts/sun20i-u-boot.dtsi
 create mode 100644 arch/riscv/include/asm/arch-sun20i/clock.h
 create mode 100644 arch/riscv/include/asm/arch-sun20i/cpu.h
 create mode 100644 arch/riscv/include/asm/arch-sun20i/thead_csr.h
 create mode 100644 board/sun20i/Kconfig
 create mode 100644 board/sun20i/Makefile
 create mode 100644 board/sun20i/board.c
 create mode 100644 board/sun20i/spl.c
 create mode 100644 configs/lichee_rv_dock_defconfig
 create mode 100644 configs/mangopi_mq_d1s_defconfig
 create mode 100644 include/configs/sun20i.h

Cc
--

  Tom Rini <trini@konsulko.com>               (U-Boot maintainer)
  Andre Przywara <andre.przywara@arm.com>     (sunxi custodian)
  Tim Ouyang <tim609@andestech.com>           (RISC-V)
  Leo Liang <leo.liang@sifive.com>            (RISC-V)
  Yao Zi <me@ziyao.cc>                        (RISC-V reviewer)
  Peng Fan <peng.fan@nxp.com>                 (MMC)
  Jaehoon Chung <jh80.chung@samsung.com>      (MMC)
  Lukasz Majewski <lukma@nabladev.com>        (CLOCK)
  Stefan Roese <stefan.roese@mailbox.org>     (WATCHDOG)
  Samuel Holland <samuel@sholland.org>        (original d1-wip author)

-- 
2.51.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-07  9:11   ` Junhui Liu
  2026-11-01 21:04 ` [PATCH 02/10] sunxi: allow the sunxi drivers to be built for sun20i Indrek Kruusa
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Add the C906 support for the D1/D1s(F133) SoCs:

- T-Head cache operations from the custom cache instructions
- harts_early_init() programming MXSTATUS, MHCR and MHINT
- cleanup_before_linux() disabling interrupts and flushing the caches
- dram_init() from the device tree memory nodes
- the T-Head CSR, CCU clock and memory map headers
- SUN20I Kconfig (cache line size, T-Head CMO support)

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 arch/riscv/Kconfig                            |  1 +
 arch/riscv/cpu/sun20i/Kconfig                 |  6 ++
 arch/riscv/cpu/sun20i/Makefile                |  5 ++
 arch/riscv/cpu/sun20i/cache.c                 | 88 +++++++++++++++++++
 arch/riscv/cpu/sun20i/cpu.c                   | 44 ++++++++++
 arch/riscv/cpu/sun20i/dram.c                  | 21 +++++
 arch/riscv/include/asm/arch-sun20i/clock.h    | 71 +++++++++++++++
 arch/riscv/include/asm/arch-sun20i/cpu.h      | 18 ++++
 .../riscv/include/asm/arch-sun20i/thead_csr.h | 29 ++++++
 9 files changed, 283 insertions(+)
 create mode 100644 arch/riscv/cpu/sun20i/Kconfig
 create mode 100644 arch/riscv/cpu/sun20i/Makefile
 create mode 100644 arch/riscv/cpu/sun20i/cache.c
 create mode 100644 arch/riscv/cpu/sun20i/cpu.c
 create mode 100644 arch/riscv/cpu/sun20i/dram.c
 create mode 100644 arch/riscv/include/asm/arch-sun20i/clock.h
 create mode 100644 arch/riscv/include/asm/arch-sun20i/cpu.h
 create mode 100644 arch/riscv/include/asm/arch-sun20i/thead_csr.h

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 386241efd4a..14c8ca817fb 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -144,6 +144,7 @@ source "arch/riscv/cpu/jh7110/Kconfig"
 source "arch/riscv/cpu/k1/Kconfig"
 source "arch/riscv/cpu/k3/Kconfig"
 source "arch/riscv/cpu/k230/Kconfig"
+source "arch/riscv/cpu/sun20i/Kconfig"
 source "arch/riscv/cpu/th1520/Kconfig"
 
 # architecture-specific options below
diff --git a/arch/riscv/cpu/sun20i/Kconfig b/arch/riscv/cpu/sun20i/Kconfig
new file mode 100644
index 00000000000..7f459518cfe
--- /dev/null
+++ b/arch/riscv/cpu/sun20i/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+config SUN20I
+	bool
+	select SYS_CACHE_SHIFT_6
+	select SYS_CACHE_THEAD_CMO if !SYS_DCACHE_OFF
diff --git a/arch/riscv/cpu/sun20i/Makefile b/arch/riscv/cpu/sun20i/Makefile
new file mode 100644
index 00000000000..556aa842ec1
--- /dev/null
+++ b/arch/riscv/cpu/sun20i/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += cache.o
+obj-y += cpu.o
+obj-y += dram.o
diff --git a/arch/riscv/cpu/sun20i/cache.c b/arch/riscv/cpu/sun20i/cache.c
new file mode 100644
index 00000000000..c961eded109
--- /dev/null
+++ b/arch/riscv/cpu/sun20i/cache.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * T-Head C906 cache operations for the Allwinner D1 (sun20i).
+ */
+
+#include <asm/arch/thead_csr.h>
+#include <asm/cache.h>
+#include <asm/csr.h>
+#include <cpu_func.h>
+#include <linux/bitops.h>
+
+/*
+ * T-Head cache maintenance instructions, emitted as raw encodings because the
+ * assembler does not know them: dcache.ciall (write back and invalidate all),
+ * dcache.iall (invalidate all), icache.ipa (invalidate the line holding the
+ * physical address in a0) and sync.i (wait for the operation to complete).
+ * They only decode while MXSTATUS.THEADISAEE is set, which harts_early_init()
+ * does before any of them is used.
+ */
+#define THEAD_SYNC_I            ".long 0x01a0000b"
+#define THEAD_DCACHE_CIALL      ".long 0x0030000b"
+#define THEAD_DCACHE_IALL       ".long 0x0020000b"
+#define THEAD_ICACHE_IPA_A0     ".long 0x0385000b"
+
+static inline void sync_i(void)
+{
+	asm volatile (THEAD_SYNC_I ::: "memory");
+}
+
+void flush_dcache_all(void)
+{
+	asm volatile (THEAD_DCACHE_CIALL ::: "memory");
+	sync_i();
+}
+
+void invalidate_dcache_all(void)
+{
+	asm volatile (THEAD_DCACHE_IALL ::: "memory");
+	sync_i();
+}
+
+void invalidate_icache_range(unsigned long start, unsigned long end)
+{
+	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
+
+	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
+		asm volatile (THEAD_ICACHE_IPA_A0 :: "r" (addr) : "memory");
+	sync_i();
+}
+
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
+
+void icache_enable(void)
+{
+	invalidate_icache_all();
+	csr_set(CSR_MHCR, MHCR_IE);
+}
+
+void icache_disable(void)
+{
+	csr_clear(CSR_MHCR, MHCR_IE);
+}
+
+int icache_status(void)
+{
+	return csr_read(CSR_MHCR) & MHCR_IE;
+}
+
+void dcache_enable(void)
+{
+	invalidate_dcache_all();
+	csr_set(CSR_MHCR, MHCR_DE);
+}
+
+void dcache_disable(void)
+{
+	flush_dcache_all();
+	csr_clear(CSR_MHCR, MHCR_DE);
+}
+
+int dcache_status(void)
+{
+	return csr_read(CSR_MHCR) & MHCR_DE;
+}
+
+#endif
diff --git a/arch/riscv/cpu/sun20i/cpu.c b/arch/riscv/cpu/sun20i/cpu.c
new file mode 100644
index 00000000000..503d6fc4a9b
--- /dev/null
+++ b/arch/riscv/cpu/sun20i/cpu.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * Allwinner D1 (sun20i) SoC support, based around the T-Head C906 CPU core.
+ */
+
+#include <irq_func.h>
+#include <asm/arch/thead_csr.h>
+#include <asm/cache.h>
+#include <asm/csr.h>
+#include <linux/bitops.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;
+}
+
+void harts_early_init(void)
+{
+	if (!CONFIG_IS_ENABLED(RISCV_MMODE))
+		return;
+
+	/*
+	 * T-HEAD ISA extensions -- the cache operations in cache.c decode only
+	 * with THEADISAEE set -- and misaligned access.
+	 */
+	csr_set(CSR_MXSTATUS, MXSTATUS_THEADISAEE | MXSTATUS_MM);
+	/* Branch prediction, return stack and the D-cache write policy. */
+	csr_set(CSR_MHCR, MHCR_BTB_C906 | MHCR_BPE | MHCR_RS | MHCR_WA);
+	/* Instruction prefetch and way prediction. */
+	csr_set(CSR_MHINT, MHINT_IWPE | MHINT_IPLD);
+}
diff --git a/arch/riscv/cpu/sun20i/dram.c b/arch/riscv/cpu/sun20i/dram.c
new file mode 100644
index 00000000000..91007c0a3d3
--- /dev/null
+++ b/arch/riscv/cpu/sun20i/dram.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <fdtdec.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	return fdtdec_setup_mem_size_base();
+}
+
+int dram_init_banksize(void)
+{
+	return fdtdec_setup_memory_banksize();
+}
diff --git a/arch/riscv/include/asm/arch-sun20i/clock.h b/arch/riscv/include/asm/arch-sun20i/clock.h
new file mode 100644
index 00000000000..8496c0e814b
--- /dev/null
+++ b/arch/riscv/include/asm/arch-sun20i/clock.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * (C) Copyright 2026 Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * Allwinner D1 (sun20i) clock register definitions.
+ */
+
+#ifndef _ASM_RISCV_ARCH_CLOCK_H
+#define _ASM_RISCV_ARCH_CLOCK_H
+
+#include <linux/bitops.h>
+
+/* MMC clock bit field (common with H6 generation) */
+#define CCM_MMC_CTRL_M(x)               ((x) - 1)
+#define CCM_MMC_CTRL_N(x)               ((x) << 8)
+#define CCM_MMC_CTRL_OSCM24             (0x0 << 24)
+#define CCM_MMC_CTRL_PLL6               (0x1 << 24)
+#define CCM_MMC_CTRL_PLL_PERIPH2X2      (0x2 << 24)
+#define CCM_MMC_CTRL_ENABLE             (0x1 << 31)
+/* H6+ doesn't have these delays */
+#define CCM_MMC_CTRL_OCLK_DLY(a)        ((void)(a), 0)
+#define CCM_MMC_CTRL_SCLK_DLY(a)        ((void)(a), 0)
+
+/* MMC module clock config register offsets */
+#define CCU_MMC0_CLK_CFG                0x830
+#define CCU_MMC1_CLK_CFG                0x834
+#define CCU_MMC2_CLK_CFG                0x838
+
+/*
+ * MMC gate/reset register. The "H6" in the name refers to the
+ * H6-generation CCU register style that the sun20i SoCs share with
+ * the other Allwinner sunxi SoCs. The exact symbol name is dictated
+ * by drivers/mmc/sunxi_mmc.c, which uses it from asm/arch/clock.h.
+ */
+#define CCU_H6_MMC_GATE_RESET           0x84c
+#define RESET_SHIFT                     16
+
+/* PLL6 (PERIPH0) register offset and bitfields */
+#define SUNXI_CCU_PLL6_CFG_OFF          0x020
+#define SUNXI_CCU_PLL6_CTRL_N_SHIFT     8
+#define SUNXI_CCU_PLL6_CTRL_N_MASK      GENMASK(15, 8)
+
+#ifndef __ASSEMBLY__
+#include <asm/arch/cpu.h>
+#include <asm/io.h>
+
+/**
+ * clock_get_pll6() - read the PLL6 (PERIPH0) clock rate
+ *
+ * Returns the PLL6 output frequency in Hz.
+ */
+static inline unsigned int clock_get_pll6(void)
+{
+	u32 rval = readl((void *)(SUNXI_CCM_BASE + SUNXI_CCU_PLL6_CFG_OFF));
+
+	int n = ((rval & SUNXI_CCU_PLL6_CTRL_N_MASK) >>
+		 SUNXI_CCU_PLL6_CTRL_N_SHIFT) + 1;
+	int div2 = ((rval >> 1) & 0x1) + 1;
+	int p0 = ((rval >> 16) & 0x7) + 1;
+	/* The register encodes the doubled PLL6 frequency; the NCAT2
+	 * (D1/R528/T113) PLL_PERIPH0 output is the plain (1x) rate.
+	 */
+	return 24000000UL * n / 2 / p0 / div2;
+}
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_RISCV_ARCH_CLOCK_H */
diff --git a/arch/riscv/include/asm/arch-sun20i/cpu.h b/arch/riscv/include/asm/arch-sun20i/cpu.h
new file mode 100644
index 00000000000..d20c0139426
--- /dev/null
+++ b/arch/riscv/include/asm/arch-sun20i/cpu.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * Allwinner D1 (sun20i) memory map.
+ */
+#ifndef _ASM_RISCV_ARCH_SUN20I_CPU_H
+#define _ASM_RISCV_ARCH_SUN20I_CPU_H
+
+#define SUNXI_CCM_BASE			0x02001000
+
+#define SUNXI_SID_BASE			0x03006200
+
+#define SUNXI_DRAM_COM_BASE		0x03102000
+#define SUNXI_DRAM_COM_BASE2		0x03202000
+#define SUNXI_DRAM_PHY_BASE		0x03103000
+
+#endif /* _ASM_RISCV_ARCH_SUN20I_CPU_H */
diff --git a/arch/riscv/include/asm/arch-sun20i/thead_csr.h b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
new file mode 100644
index 00000000000..4d6e15aab1c
--- /dev/null
+++ b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * T-Head C906 CSR definitions for the Allwinner D1 (sun20i).
+ */
+
+#ifndef _ASM_RISCV_ARCH_THEAD_CSR_H
+#define _ASM_RISCV_ARCH_THEAD_CSR_H
+
+#define CSR_MXSTATUS            0x7c0
+#define CSR_MHCR                0x7c1
+#define CSR_MHINT               0x7c5
+
+#define MXSTATUS_THEADISAEE     BIT(22) /* T-HEAD ISA extensions enable */
+#define MXSTATUS_MAEE           BIT(21) /* MMU honours the PTE memory type */
+#define MXSTATUS_MM             BIT(15) /* misaligned access enable */
+
+#define MHCR_IE                 BIT(0)  /* icache enable */
+#define MHCR_DE                 BIT(1)  /* dcache enable */
+#define MHCR_WA                 BIT(2)  /* dcache write allocate */
+#define MHCR_RS                 BIT(4)  /* return stack enable */
+#define MHCR_BPE                BIT(5)  /* branch prediction enable */
+#define MHCR_BTB_C906           BIT(6)  /* branch target prediction enable */
+
+#define MHINT_IPLD              BIT(8)  /* icache prefetch enable */
+#define MHINT_IWPE              BIT(9)  /* icache way prediction enable */
+
+#endif /* _ASM_RISCV_ARCH_THEAD_CSR_H */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/10] sunxi: allow the sunxi drivers to be built for sun20i
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 03/10] board: sun20i: add common support for the D1/D1s boards Indrek Kruusa
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Accept SUN20I next to ARCH_SUNXI for the RAM, clock, pinctrl, GPIO, MMC,
reset and watchdog drivers, and keep WATCHDOG_AUTOSTART off for it.

Declare SUNXI_GEN_NCAT2 here as well - the ARM sunxi Kconfig is not read
by a RISC-V build - and add the MMC base addresses to arch-sun20i/cpu.h
so sunxi_mmc.c builds.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 arch/riscv/cpu/sun20i/Kconfig            | 11 +++++++++++
 arch/riscv/include/asm/arch-sun20i/cpu.h |  4 ++++
 drivers/clk/sunxi/Kconfig                |  2 +-
 drivers/gpio/Kconfig                     |  2 +-
 drivers/mmc/Kconfig                      |  2 +-
 drivers/pinctrl/sunxi/Kconfig            |  2 +-
 drivers/ram/sunxi/Kconfig                |  2 +-
 drivers/reset/Kconfig                    |  2 +-
 drivers/watchdog/Kconfig                 |  3 ++-
 9 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/arch/riscv/cpu/sun20i/Kconfig b/arch/riscv/cpu/sun20i/Kconfig
index 7f459518cfe..1e08317cf12 100644
--- a/arch/riscv/cpu/sun20i/Kconfig
+++ b/arch/riscv/cpu/sun20i/Kconfig
@@ -4,3 +4,14 @@ config SUN20I
 	bool
 	select SYS_CACHE_SHIFT_6
 	select SYS_CACHE_THEAD_CMO if !SYS_DCACHE_OFF
+
+config SUNXI_GEN_NCAT2
+	bool
+	default y if SUN20I
+	select DRAM_SUN20I_D1
+	select MMC_SUNXI_HAS_NEW_MODE
+	select SUPPORT_SPL
+	help
+	  The D1/D1s(F133) SoCs belong to the same ("NCAT2") peripheral
+	  generation as the R528/T113. Declare this symbol here, so the
+	  sunxi code can take its NCAT2 paths.
diff --git a/arch/riscv/include/asm/arch-sun20i/cpu.h b/arch/riscv/include/asm/arch-sun20i/cpu.h
index d20c0139426..c57c58495dc 100644
--- a/arch/riscv/include/asm/arch-sun20i/cpu.h
+++ b/arch/riscv/include/asm/arch-sun20i/cpu.h
@@ -15,4 +15,8 @@
 #define SUNXI_DRAM_COM_BASE2		0x03202000
 #define SUNXI_DRAM_PHY_BASE		0x03103000
 
+#define SUNXI_MMC0_BASE			0x04020000
+#define SUNXI_MMC1_BASE			0x04021000
+#define SUNXI_MMC2_BASE			0x04022000
+
 #endif /* _ASM_RISCV_ARCH_SUN20I_CPU_H */
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
index 1c1cc82719c..74ce009bc2d 100644
--- a/drivers/clk/sunxi/Kconfig
+++ b/drivers/clk/sunxi/Kconfig
@@ -1,6 +1,6 @@
 config CLK_SUNXI
 	bool "Clock support for Allwinner SoCs"
-	depends on CLK && ARCH_SUNXI
+	depends on CLK && (ARCH_SUNXI || SUN20I)
 	select DM_RESET
 	select SPL_DM_RESET if SPL_CLK
 	default y
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7f12e39dad8..8b75bacdb38 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -460,7 +460,7 @@ config SPACEMIT_GPIO
 
 config SUNXI_GPIO
 	bool "Allwinner GPIO driver"
-	depends on ARCH_SUNXI
+	depends on ARCH_SUNXI || SUN20I
 	select SPL_STRTO if SPL
 	help
 	  Support the GPIO device in Allwinner SoCs.
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index b3731dfe4a1..2586a28ce02 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -842,7 +842,7 @@ config ZYNQ_HISPD_BROKEN
 
 config MMC_SUNXI
 	bool "Allwinner sunxi SD/MMC Host Controller support"
-	depends on ARCH_SUNXI
+	depends on ARCH_SUNXI || SUN20I
 	default y
 	help
 	  This selects support for the SD/MMC Host Controller on
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 54314992299..9400d45990b 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-if ARCH_SUNXI
+if ARCH_SUNXI || SUN20I
 
 config PINCTRL_SUNXI
 	select PINCTRL_FULL
diff --git a/drivers/ram/sunxi/Kconfig b/drivers/ram/sunxi/Kconfig
index 1775cb0d780..9f2dc4a6e66 100644
--- a/drivers/ram/sunxi/Kconfig
+++ b/drivers/ram/sunxi/Kconfig
@@ -1,6 +1,6 @@
 config DRAM_SUN20I_D1
 	bool
-	depends on ARCH_SUNXI
+	depends on ARCH_SUNXI || SUN20I
 	help
 	  This enables support for the DRAM controller driver covering
 	  the Allwinner D1/R528/T113s SoCs.
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index ad61ebf344a..becbd86d59d 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -179,7 +179,7 @@ config RESET_NPCM
 
 config RESET_SUNXI
 	bool "RESET support for Allwinner SoCs"
-	depends on DM_RESET && ARCH_SUNXI
+	depends on DM_RESET && (ARCH_SUNXI || SUN20I)
 	default y
 	help
 	  This enables support for common reset driver for
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3c56c541505..ce0cec964ed 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -17,6 +17,7 @@ config WATCHDOG_AUTOSTART
 	default n if ARCH_SUNXI
 	default n if ARCH_STM32MP
 	default n if ARCH_SNAPDRAGON
+	default n if SUN20I
 	default y
 	help
 	  Automatically start watchdog timer and start servicing it during
@@ -427,7 +428,7 @@ config WDT_STARFIVE
 
 config WDT_SUNXI
 	bool "Allwinner sunxi watchdog timer support"
-	depends on WDT && ARCH_SUNXI
+	depends on WDT && (ARCH_SUNXI || SUN20I)
 	default y
 	help
 	  Enable support for the watchdog timer in Allwinner sunxi SoCs.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/10] board: sun20i: add common support for the D1/D1s boards
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 02/10] sunxi: allow the sunxi drivers to be built for sun20i Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 04/10] sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver Indrek Kruusa
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Add the board code used by all D1/D1s(F133) boards:

- TARGET_SUN20I, board init and CPU probing
- sunxi eGON/TOC0 SPL header: boot source, FEL mode, SPL size
- SPL DRAM probing and the /memory fixup
- FIT DT name matching
- environment placement for MMC/SPI boot media
- the u-boot-sunxi-with-spl.bin image
- a MAINTAINERS section for the new board and CPU files

CONFIG_ARCH_SUNXI is never set on these RISC-V parts, so extend the SPL
image rule in scripts/Makefile.xpl to match TARGET_SUN20I as well.

The board code, the devicetree overlay and include/configs/sun20i.h come
from Samuel Holland's d1-wip tree [1]. The board code in turn derives from
the ARM sunxi board code, so its copyright notices are kept.

[1] https://github.com/smaeul/u-boot/tree/d1-wip

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 MAINTAINERS                       |   8 +
 arch/riscv/Kconfig                |  13 ++
 arch/riscv/dts/sun20i-u-boot.dtsi |  86 +++++++++
 board/sun20i/Kconfig              | 173 +++++++++++++++++
 board/sun20i/Makefile             |   4 +
 board/sun20i/board.c              | 309 ++++++++++++++++++++++++++++++
 board/sun20i/spl.c                | 142 ++++++++++++++
 include/configs/sun20i.h          |  11 ++
 scripts/Makefile.xpl              |   2 +-
 9 files changed, 747 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/dts/sun20i-u-boot.dtsi
 create mode 100644 board/sun20i/Kconfig
 create mode 100644 board/sun20i/Makefile
 create mode 100644 board/sun20i/board.c
 create mode 100644 board/sun20i/spl.c
 create mode 100644 include/configs/sun20i.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 95b1f3b5ab3..587d4a30377 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1543,6 +1543,14 @@ F:	drivers/net/dwmac_thead.c
 F:	drivers/pinctrl/pinctrl-th1520.c
 F:	drivers/ram/thead/th1520_ddr.c
 
+RISC-V ALLWINNER SUN20I (D1)
+M:	Indrek Kruusa <indrek.kruusa@gmail.com>
+S:	Maintained
+F:	arch/riscv/cpu/sun20i/
+F:	arch/riscv/include/asm/arch-sun20i/
+F:	board/sun20i/
+F:	include/configs/sun20i.h
+
 RNG
 M:	Sughosh Ganu <sughosh.ganu@arm.com>
 R:	Heinrich Schuchardt <xypron.glpk@gmx.de>
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 14c8ca817fb..02304d9f66c 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -60,6 +60,18 @@ config TARGET_STARFIVE_VISIONFIVE2
 	bool "Support StarFive VisionFive2 Board"
 	select BOARD_LATE_INIT
 
+config TARGET_SUN20I
+	bool "Support Allwinner D1/D1s(F133) boards"
+	select GENERIC_RISCV
+	select SPECIFY_CONSOLE_INDEX
+	select SUN20I
+	select PINCTRL_SUN20I_D1
+	select CLK_SUN20I_D1
+	select SUNXI_NEW_PINCTRL
+	help
+	  Selecting this option also enables the NCAT2 drivers, which are
+	  shared across several Allwinner RISC-V and ARM SoCs.
+
 config TARGET_TH1520_LPI4A
 	bool "Support Sipeed's TH1520 Lichee PI 4A Board"
 	select SYS_CACHE_SHIFT_6
@@ -129,6 +141,7 @@ source "board/sophgo/licheerv_nano/Kconfig"
 source "board/spacemit/k1/Kconfig"
 source "board/spacemit/k3/Kconfig"
 source "board/starfive/visionfive2/Kconfig"
+source "board/sun20i/Kconfig"
 source "board/thead/th1520_lpi4a/Kconfig"
 source "board/xilinx/mbv/Kconfig"
 
diff --git a/arch/riscv/dts/sun20i-u-boot.dtsi b/arch/riscv/dts/sun20i-u-boot.dtsi
new file mode 100644
index 00000000000..8f9959e6467
--- /dev/null
+++ b/arch/riscv/dts/sun20i-u-boot.dtsi
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+#include "binman.dtsi"
+
+/ {
+	cpus {
+		bootph-all;
+	};
+
+	soc {
+		bootph-all;
+	};
+};
+
+&binman {
+	/*
+	 * "u-boot-sunxi-with-spl" is the shared Allwinner sunxi boot image
+	 * (eGON SPL + U-Boot FIT). It is common to the ARM sunxi and the
+	 * RISC-V sun20i SoCs, so it keeps the "sunxi" name even on RISC-V.
+	 */
+	u-boot-sunxi-with-spl {
+		filename = "u-boot-sunxi-with-spl.bin";
+		pad-byte = <0xff>;
+
+		blob@0 {
+			/*
+			 * This value matches SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
+			 * and SYS_SPI_U_BOOT_OFFS if those are defined.
+			 */
+			min-size = <0x8000>;
+			filename = "spl/sunxi-spl.bin";
+		};
+
+		blob@1 {
+			filename = "u-boot.itb";
+		};
+	};
+};
+
+&ccu {
+	bootph-all;
+};
+
+&cpu0 {
+	bootph-all;
+};
+
+&dcxo {
+	bootph-all;
+};
+
+&mbus {
+	bootph-all;
+};
+
+&mmc0 {
+	bootph-all;
+};
+
+&mmc0_pins {
+	bootph-all;
+};
+
+&pio {
+	bootph-all;
+
+	uart0-pb8-pins {
+		bootph-all;
+	};
+
+	uart3-pb-pins {
+		bootph-all;
+	};
+};
+
+&rtc {
+	bootph-all;
+};
+
+&uart0 {
+	bootph-all;
+};
+
+&uart3 {
+	bootph-all;
+};
diff --git a/board/sun20i/Kconfig b/board/sun20i/Kconfig
new file mode 100644
index 00000000000..55eb50abf34
--- /dev/null
+++ b/board/sun20i/Kconfig
@@ -0,0 +1,173 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+if TARGET_SUN20I
+
+config SYS_BOARD
+	default "sun20i"
+
+config SYS_CPU
+	default "sun20i"
+
+config SYS_SOC
+	default "sun20i"
+
+config SYS_CONFIG_NAME
+	default "sun20i"
+
+config IDENT_STRING
+	default " Allwinner D1"
+
+config SYS_CLK_FREQ
+	default 1008000000
+
+config SYS_LOAD_ADDR
+	default 0x42000000
+
+config TEXT_BASE
+	default 0x42e00000
+
+config HAS_CUSTOM_SYS_INIT_SP_ADDR
+	default y
+
+config CUSTOM_SYS_INIT_SP_ADDR
+	default 0x43e00000
+
+config SUNXI_SRAM_ADDRESS
+	hex
+	default 0x20000
+
+config SUNXI_MINIMUM_DRAM_MB
+	int
+	default 64
+	help
+	  Minimum DRAM size expected on the board.
+
+config DRAM_CLK
+	int "DRAM clock speed"
+	default 792
+
+config DRAM_ZQ
+	int "DRAM ZQ value"
+	default 8092667
+
+config PRE_CON_BUF_ADDR
+	default 0x43000000
+
+config MISC_INIT_R
+	default y
+
+config SPL_MAX_SIZE
+	default 0x27fa0
+
+config SPL_PAD_TO
+	default 0x0
+
+config SPL_BSS_START_ADDR
+	default 0x43f80000
+
+config SPL_TEXT_BASE
+	default 0x20060
+
+config SPL_SHARES_INIT_SP_ADDR
+	default n
+
+config SPL_HAVE_INIT_STACK
+	default y
+
+config SPL_STACK
+	default 0x48000
+
+config SPL_STACK_R_ADDR
+	default 0x43e00000
+
+config SPL_OPENSBI_LOAD_ADDR
+	default 0x40000000
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
+	default 0x40
+
+config SPL_SYS_MMCSD_RAW_MODE
+	default y
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET
+	default 0x10
+
+config SYS_SPI_U_BOOT_OFFS
+	default 0x8000
+
+config MMC_SUNXI_SLOT_EXTRA
+	int "mmc extra slot number"
+	default -1
+	help
+	  D1 builds always enable mmc0. Some boards also have a second SD card
+	  slot or eMMC on mmc1 - mmc3. Setting this to 1, 2, or 3 enables
+	  support for this.
+
+config SPL_IMAGE_TYPE
+	string
+	default "sunxi_egon"
+
+config BOARD_SPECIFIC_OPTIONS
+	def_bool y
+	select BINMAN
+	select CLK
+	select CMD_GPIO if GPIO
+	select CMD_MMC if MMC
+	select CMD_USB if DISTRO_DEFAULTS && USB_HOST
+	select DM
+	select DM_GPIO if GPIO
+	select DM_I2C if I2C
+	select DM_MMC if MMC
+	select DM_SERIAL if SERIAL
+	select DM_SPI if SPI
+	select DM_SPI_FLASH if SPI && MTD
+	select ENV_RELOC_GD_ENV_ADDR
+	select OF_BOARD_SETUP
+	select OF_UPSTREAM
+	select PINCTRL
+	select RAM if SPL_DM
+	select SPL_CLK if SPL_DM
+	select SPL_DM if SPL
+	select SPL_DM_SPI if SPL_DM && SPL_SPI
+	select SPL_DM_SPI_FLASH if SPL_DM && SPL_SPI
+	select SPL_OF_CONTROL if SPL_DM
+	select SPL_PINCONF if SPL_DM
+	select SPL_PINCTRL if SPL_DM
+	select SPL_RAM if SPL_DM
+	select SPL_SEPARATE_BSS if SPL
+	select SUNXI_GPIO if GPIO
+	select SUPPORT_SPL
+	select SYS_NS16550 if SERIAL
+	select USB if DISTRO_DEFAULTS
+	select USB_KEYBOARD if DISTRO_DEFAULTS && USB_HOST
+	select USB_STORAGE if DISTRO_DEFAULTS && USB_HOST
+	select USE_PREBOOT
+	imply CMD_DM
+	imply CMD_GPT
+	imply DISTRO_DEFAULTS
+	imply DM_REGULATOR
+	imply DM_REGULATOR_FIXED
+	imply FAT_WRITE
+	imply FIT
+	imply MMC
+	imply OF_LIBFDT_OVERLAY
+	imply PRE_CONSOLE_BUFFER
+	imply SPL
+	imply SPL_GPIO
+	imply SPL_LIBCOMMON_SUPPORT
+	imply SPL_LIBGENERIC_SUPPORT
+	imply SPL_LOAD_FIT
+	imply SPL_MMC if MMC
+	imply SPL_POWER
+	imply SPL_SERIAL
+	imply SYSRESET
+	imply SYSRESET_SBI
+	imply SYSRESET_WATCHDOG
+	imply SYSRESET_WATCHDOG_AUTO
+	imply USB_EHCI_GENERIC
+	imply USB_EHCI_HCD
+	imply USB_OHCI_GENERIC
+	imply USB_OHCI_HCD
+	imply WDT
+
+endif
diff --git a/board/sun20i/Makefile b/board/sun20i/Makefile
new file mode 100644
index 00000000000..af4006368b2
--- /dev/null
+++ b/board/sun20i/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y	+= board.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
diff --git a/board/sun20i/board.c b/board/sun20i/board.c
new file mode 100644
index 00000000000..e32cc817838
--- /dev/null
+++ b/board/sun20i/board.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ *
+ * (C) Copyright 2026 Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * Board initialization, environment and boot source detection for
+ * Allwinner D1(s) RISC-V SoC.
+ */
+
+#include <asm/csr.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/thead_csr.h>
+#include <cpu.h>
+#include <dm.h>
+#include <env.h>
+#include <env_internal.h>
+#include <fdt_support.h>
+#include <init.h>
+#include <spl.h>
+#include <sunxi_image.h>
+
+int board_init(void)
+{
+	/* https://lore.kernel.org/u-boot/31587574-4cd1-02da-9761-0134ac82b94b@sholland.org/ */
+	return cpu_probe_all();
+}
+
+#define SPL_ADDR		CONFIG_SUNXI_SRAM_ADDRESS
+
+/* The low 8-bits of the 'boot_media' field in the SPL header */
+#define SUNXI_BOOTED_FROM_MMC0	0
+#define SUNXI_BOOTED_FROM_MMC2	2
+#define SUNXI_BOOTED_FROM_SPI	3
+#define SUNXI_BOOTED_FROM_MMC0_HIGH	0x10
+#define SUNXI_BOOTED_FROM_MMC2_HIGH	0x12
+
+#define SUNXI_INVALID_BOOT_SOURCE	-1
+
+static int sunxi_egon_valid(struct boot_file_head *egon_head)
+{
+	return !memcmp(egon_head->magic, BOOT0_MAGIC, 8); /* eGON.BT0 */
+}
+
+static int sunxi_toc0_valid(struct toc0_main_info *toc0_info)
+{
+	return !memcmp(toc0_info->name, TOC0_MAIN_INFO_NAME, 8); /* TOC0.GLH */
+}
+
+static int sunxi_get_boot_source(void)
+{
+	struct boot_file_head *egon_head = (void *)SPL_ADDR;
+	struct toc0_main_info *toc0_info = (void *)SPL_ADDR;
+
+	if (sunxi_egon_valid(egon_head))
+		return readb(&egon_head->boot_media);
+	if (sunxi_toc0_valid(toc0_info))
+		return readb(&toc0_info->platform[0]);
+
+	/* Not a valid image, so we must have been booted via FEL. */
+	return SUNXI_INVALID_BOOT_SOURCE;
+}
+
+/* The sunxi internal BROM will try to load an external bootloader
+ * from mmc0, mmc2, or SPI flash.
+ */
+uint32_t sunxi_get_boot_device(void)
+{
+	int boot_source = sunxi_get_boot_source();
+
+	/*
+	 * When booting from the SD card or NAND memory, the "eGON.BT0"
+	 * signature is expected to be found in memory at the address 0x0004
+	 * (see the "mksunxiboot" tool, which generates this header).
+	 *
+	 * When booting in the FEL mode over USB, this signature is patched in
+	 * memory and replaced with something else by the 'fel' tool. This other
+	 * signature is selected in such a way, that it can't be present in a
+	 * valid bootable SD card image (because the BROM would refuse to
+	 * execute the SPL in this case).
+	 *
+	 * This checks for the signature and if it is not found returns to
+	 * the FEL code in the BROM to wait and receive the main u-boot
+	 * binary over USB. If it is found, it determines where SPL was
+	 * read from.
+	 */
+	switch (boot_source) {
+	case SUNXI_INVALID_BOOT_SOURCE:
+		return BOOT_DEVICE_BOARD;
+	case SUNXI_BOOTED_FROM_MMC0:
+	case SUNXI_BOOTED_FROM_MMC0_HIGH:
+		return BOOT_DEVICE_MMC1;
+	case SUNXI_BOOTED_FROM_MMC2:
+	case SUNXI_BOOTED_FROM_MMC2_HIGH:
+		return BOOT_DEVICE_MMC2;
+	case SUNXI_BOOTED_FROM_SPI:
+		return BOOT_DEVICE_SPI;
+	}
+
+	panic("Unknown boot source %d\n", boot_source);
+	return -1;		/* Never reached */
+}
+
+uint32_t sunxi_get_spl_size(void)
+{
+	struct boot_file_head *egon_head = (void *)SPL_ADDR;
+	struct toc0_main_info *toc0_info = (void *)SPL_ADDR;
+
+	if (sunxi_egon_valid(egon_head))
+		return readl(&egon_head->length);
+	if (sunxi_toc0_valid(toc0_info))
+		return readl(&toc0_info->length);
+
+	/* Not a valid image, so use the default U-Boot offset. */
+	return 0;
+}
+
+/*
+ * The eGON SPL image can be located at 8KB or at 128KB into an SD card or
+ * an eMMC device. The boot source has bit 4 set in the latter case.
+ * By adding 120KB to the normal offset when booting from a "high" location
+ * we can support both cases.
+ * Also U-Boot proper is located at least 32KB after the SPL, but will
+ * immediately follow the SPL if that is bigger than that.
+ */
+unsigned long board_spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
+						 unsigned long raw_sect)
+{
+	unsigned long spl_size = sunxi_get_spl_size();
+	unsigned long sector;
+
+	sector = max(raw_sect, spl_size / 512);
+
+	switch (sunxi_get_boot_source()) {
+	case SUNXI_BOOTED_FROM_MMC0_HIGH:
+	case SUNXI_BOOTED_FROM_MMC2_HIGH:
+		sector += (128 - 8) * 2;
+		break;
+	}
+
+	debug("SPL size = %lu, sector = %lu\n", spl_size, sector);
+
+	return sector;
+}
+
+u32 spl_boot_device(void)
+{
+	return sunxi_get_boot_device();
+}
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Try to use the environment from the boot source first.
+ * For MMC, this means a FAT partition on the boot device (SD or eMMC).
+ * If the raw MMC environment is also enabled, this is tried next.
+ * SPI flash falls back to FAT (on SD card).
+ */
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+	if (prio > 1)
+		return ENVL_UNKNOWN;
+
+	/* NOWHERE is exclusive, no other option can be defined. */
+	if (IS_ENABLED(CONFIG_ENV_IS_NOWHERE))
+		return ENVL_NOWHERE;
+
+	switch (sunxi_get_boot_device()) {
+	case BOOT_DEVICE_MMC1:
+	case BOOT_DEVICE_MMC2:
+		if (prio == 0 && IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
+			return ENVL_FAT;
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
+			return ENVL_MMC;
+		break;
+	case BOOT_DEVICE_SPI:
+		if (prio == 0 && IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
+			return ENVL_SPI_FLASH;
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
+			return ENVL_FAT;
+		break;
+	case BOOT_DEVICE_BOARD:
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * If we come here for the first time, we *must* return a valid
+	 * environment location other than ENVL_UNKNOWN, or the setup sequence
+	 * in board_f() will silently hang. This is arguably a bug in
+	 * env_init(), but for now pick one environment for which we know for
+	 * sure to have a driver for. For all defconfigs this is either FAT
+	 * or UBI, or NOWHERE, which is already handled above.
+	 */
+	if (prio == 0) {
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
+			return ENVL_FAT;
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_UBI))
+			return ENVL_UBI;
+	}
+
+	return ENVL_UNKNOWN;
+}
+
+static struct boot_file_head *get_spl_header(u8 req_version)
+{
+	struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
+	u8 spl_header_version = spl->spl_signature[3];
+
+	/* Is there really the SPL header (still) there? */
+	if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
+		return NULL;
+
+	if (spl_header_version < req_version) {
+		printf("sunxi SPL version mismatch: expected %u, got %u\n",
+		       req_version, spl_header_version);
+		return NULL;
+	}
+
+	return spl;
+}
+
+const char *get_spl_dt_name(void)
+{
+	struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
+
+	/* Check if there is a DT name stored in the SPL header. */
+	if (spl && spl->dt_name_offset)
+		return (char *)spl + spl->dt_name_offset;
+
+	return NULL;
+}
+
+/*
+ * Check the SPL header for the "sunxi" variant. If found: parse values
+ * that might have been passed by the loader ("fel" utility), and update
+ * the environment accordingly.
+ */
+static void parse_spl_header(const uint32_t spl_addr)
+{
+	struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
+
+	if (!spl)
+		return;
+
+	if (!spl->fel_script_address)
+		return;
+
+	if (spl->fel_uEnv_length != 0) {
+		/*
+		 * data is expected in uEnv.txt compatible format, so "env
+		 * import -t" the string(s) at fel_script_address right away.
+		 */
+		himport_r(&env_htab, (char *)(uintptr_t)spl->fel_script_address,
+			  spl->fel_uEnv_length, '\n', H_NOCLEAR, 0, 0, NULL);
+		return;
+	}
+	/* otherwise assume .scr format (mkimage-type script) */
+	env_set_hex("fel_scriptaddr", spl->fel_script_address);
+}
+
+int misc_init_r(void)
+{
+	const char *spl_dt_name;
+	uint boot;
+
+	env_set("fel_booted", NULL);
+	env_set("fel_scriptaddr", NULL);
+	env_set("mmc_bootdev", NULL);
+
+	boot = sunxi_get_boot_device();
+	/* determine if we are running in FEL mode */
+	if (boot == BOOT_DEVICE_BOARD) {
+		env_set("fel_booted", "1");
+		parse_spl_header(SPL_ADDR);
+	} else if (boot == BOOT_DEVICE_MMC1) {
+		env_set("mmc_bootdev", "0");
+	}
+
+	/* Set fdtfile to match the FIT configuration chosen in SPL. */
+	spl_dt_name = get_spl_dt_name();
+	if (spl_dt_name) {
+		char str[64];
+
+		snprintf(str, sizeof(str), "%s.dtb", spl_dt_name);
+		env_set("fdtfile", str);
+	}
+
+	return 0;
+}
+
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+	/*
+	 * The OS tree may be a different blob from the control tree the
+	 * SPL fixed up, and the DRAM size is only known at runtime.
+	 */
+	u64 start = gd->ram_base;
+	u64 size = gd->ram_size;
+
+	return fdt_fixup_memory_banks(blob, &start, &size, 1);
+}
diff --git a/board/sun20i/spl.c b/board/sun20i/spl.c
new file mode 100644
index 00000000000..7ca85f2c3f8
--- /dev/null
+++ b/board/sun20i/spl.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
+ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+ *
+ * (C) Copyright 2026 Indrek Kruusa <indrek.kruusa@gmail.com>
+ *
+ * SPL board initialization for Allwinner D1(s) RISC-V SoC.
+ */
+
+#include <fdt_support.h>
+#include <image.h>
+#include <ram.h>
+#include <spl.h>
+#include <sunxi_image.h>
+#include <asm/cache.h>
+#include <asm/csr.h>
+#include <asm/arch/thead_csr.h>
+#include <cpu.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <init.h>
+
+extern const char *get_spl_dt_name(void);
+
+int spl_board_init_f(void)
+{
+	int ret;
+	struct udevice *dev;
+
+	ret = cpu_probe_all();
+	if (ret)
+		debug("CPU init failed: %d\n", ret);
+
+	/* DDR init */
+	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+	if (ret) {
+		debug("DRAM init failed: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * The C906 leaves reset with both caches disabled (MHCR.IE and
+	 * MHCR.DE are 0) and nothing else in the boot chain turns them on.
+	 * Enable them here, i.e. only once DRAM is usable: with the D-cache
+	 * on, the DRAM controller's training tests observe their own cached
+	 * writes and fail.
+	 *
+	 * The SYS_{I,D}CACHE_OFF options still win: the T-Head cache
+	 * maintenance library (SYS_CACHE_THEAD_CMO) is only built when the
+	 * D-cache may be on, so enabling the D-cache here regardless would
+	 * leave such a build without working range flushes.
+	 */
+	if (!CONFIG_IS_ENABLED(SYS_ICACHE_OFF))
+		icache_enable();
+	if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
+		dcache_enable();
+
+	/*
+	 * MXSTATUS.MAEE makes the MMU take the memory type from PTE[63:59]
+	 * instead of ignoring those bits.  With it clear every mapping is
+	 * cached, so the OS cannot mark its DMA memory non-cacheable, and this
+	 * SoC has no Zicbom to fall back on: drivers then read stale
+	 * descriptors (OHCI reports "frame counter not updating").  The C906
+	 * does not leave the bit set, so set it once DRAM is up, as the vendor
+	 * SPL does.
+	 */
+	csr_set(CSR_MXSTATUS, MXSTATUS_MAEE);
+
+	return 0;
+}
+
+void spl_perform_board_fixups(struct spl_image_info *spl_image)
+{
+	struct ram_info info;
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+	if (ret)
+		panic("No RAM device");
+
+	ret = ram_get_info(dev, &info);
+	if (ret)
+		panic("No RAM info");
+
+	ret = fdt_fixup_memory(spl_image->fdt_addr, info.base, info.size);
+	if (ret)
+		panic("Failed to update DTB");
+
+	/*
+	 * The D-cache is enabled by now, so the image we just loaded and the
+	 * DTB we just patched may still be dirty in it. The next stage is
+	 * fetched through the I-cache, which does not see dirty D-cache
+	 * lines, so push everything out before handing over.
+	 */
+	flush_dcache_all();
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+static void set_spl_dt_name(const char *name)
+{
+	struct boot_file_head *spl = (void *)(ulong)CONFIG_SUNXI_SRAM_ADDRESS;
+
+	/* Promote the header version for U-Boot proper, if needed. */
+	if (spl->spl_signature[3] < SPL_DT_HEADER_VERSION)
+		spl->spl_signature[3] = SPL_DT_HEADER_VERSION;
+
+	strcpy((char *)&spl->string_pool, name);
+	spl->dt_name_offset = offsetof(struct boot_file_head, string_pool);
+}
+
+int board_fit_config_name_match(const char *name)
+{
+	const char *best_dt_name = get_spl_dt_name();
+	int ret;
+
+#ifdef CONFIG_DEFAULT_DEVICE_TREE
+	if (!best_dt_name)
+		best_dt_name = CONFIG_DEFAULT_DEVICE_TREE;
+#endif
+
+	if (!best_dt_name) {
+		/* No DT name was provided, so accept the first config. */
+		return 0;
+	}
+
+	ret = strcmp(name, best_dt_name);
+
+	/*
+	 * If one of the FIT configurations matches the most accurate DT name,
+	 * update the SPL header to provide that DT name to U-Boot proper.
+	 */
+	if (ret == 0)
+		set_spl_dt_name(best_dt_name);
+
+	return ret;
+}
+#endif
diff --git a/include/configs/sun20i.h b/include/configs/sun20i.h
new file mode 100644
index 00000000000..e8ef1b6c4ac
--- /dev/null
+++ b/include/configs/sun20i.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Placeholder wrapper to allow addressing Allwinner D1 (and later) sun20i
+ * CPU based devices separately. Please do not add anything in here.
+ */
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <configs/sunxi-common.h>
+
+#endif /* __CONFIG_H */
diff --git a/scripts/Makefile.xpl b/scripts/Makefile.xpl
index 77746ec07cd..33b7aac61b4 100644
--- a/scripts/Makefile.xpl
+++ b/scripts/Makefile.xpl
@@ -275,7 +275,7 @@ endif
 
 INPUTS-$(CONFIG_ARCH_SOCFPGA_SOC64) += $(obj)/u-boot-spl-dtb.hex
 
-ifdef CONFIG_ARCH_SUNXI
+ifneq ($(CONFIG_ARCH_SUNXI)$(CONFIG_TARGET_SUN20I),)
 INPUTS-y	+= $(obj)/sunxi-spl.bin
 
 ifdef CONFIG_NAND_SUNXI
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/10] sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (2 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 03/10] board: sun20i: add common support for the D1/D1s boards Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 05/10] sunxi: dram: count the banks on address bit 11, not A22 Indrek Kruusa
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Fix readl()/writel() address types for GCC 15+

Use typed base address macros and cast remaining register addresses
to void __iomem * to satisfy GCC 15's stricter type checking.

No functional change.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 drivers/ram/sunxi/dram_sun20i_d1.c | 383 ++++++++++++++++-------------
 1 file changed, 209 insertions(+), 174 deletions(-)

diff --git a/drivers/ram/sunxi/dram_sun20i_d1.c b/drivers/ram/sunxi/dram_sun20i_d1.c
index 79cf0a51e47..68697fb2fa9 100644
--- a/drivers/ram/sunxi/dram_sun20i_d1.c
+++ b/drivers/ram/sunxi/dram_sun20i_d1.c
@@ -12,6 +12,7 @@
  * [1] https://github.com/szemzoa/awboot.git
  */
 
+#include <asm/arch/cpu.h>
 #include <asm/io.h>
 #include <config.h>
 #ifdef CONFIG_RAM
@@ -22,19 +23,25 @@
 
 #include "dram_sun20i_d1.h"
 
-#ifndef SUNXI_SID_BASE
-#define SUNXI_SID_BASE	0x3006200
-#endif
+/*
+ * Typed views of the register block bases: GCC 15 and later reject the plain
+ * integers this file used to pass to readl() and writel(). The CCU and SID
+ * bases come from the arch header, which has them for the ARM build of this
+ * driver as well; the DRAM controller and PHY blocks are private to it.
+ */
+#define SUNXI_CCM_BASE_PTR		((void __iomem *)SUNXI_CCM_BASE)
+#define SUNXI_SID_BASE_PTR		((void __iomem *)SUNXI_SID_BASE)
+
+#define SUNXI_DRAM_COM_BASE_PTR		((u8 __iomem *)0x3102000)
+#define SUNXI_DRAM_COM_BASE2_PTR	((u8 __iomem *)0x3202000)
+#define SUNXI_DRAM_PHY_BASE_PTR		((u8 __iomem *)0x3103000)
 
-#ifndef SUNXI_CCM_BASE
-#define SUNXI_CCM_BASE	0x2001000
-#endif
 
 static void sid_read_ldoB_cal(const dram_para_t *para)
 {
 	uint32_t reg;
 
-	reg = (readl(SUNXI_SID_BASE + 0x1c) & 0xff00) >> 8;
+	reg = (readl(SUNXI_SID_BASE_PTR + 0x1c) & 0xff00) >> 8;
 
 	if (reg == 0)
 		return;
@@ -51,12 +58,12 @@ static void sid_read_ldoB_cal(const dram_para_t *para)
 		break;
 	}
 
-	clrsetbits_le32(0x3000150, 0xff00, reg << 8);
+	clrsetbits_le32((void __iomem *)0x3000150, 0xff00, reg << 8);
 }
 
 static uint32_t sid_read_soc_chipid(void)
 {
-	return readl(SUNXI_SID_BASE + 0x00) & 0xffff;
+	return readl(SUNXI_SID_BASE_PTR + 0x00) & 0xffff;
 }
 
 static void dram_voltage_set(const dram_para_t *para)
@@ -75,7 +82,7 @@ static void dram_voltage_set(const dram_para_t *para)
 		break;
 	}
 
-	clrsetbits_le32(0x3000150, 0x20ff00, vol << 8);
+	clrsetbits_le32((void __iomem *)0x3000150, 0x20ff00, vol << 8);
 
 	udelay(1);
 
@@ -84,70 +91,79 @@ static void dram_voltage_set(const dram_para_t *para)
 
 static void dram_enable_all_master(void)
 {
-	writel(~0, 0x3102020);
-	writel(0xff, 0x3102024);
-	writel(0xffff, 0x3102028);
+	writel(~0, SUNXI_DRAM_COM_BASE_PTR + 0x20);
+	writel(0xff, SUNXI_DRAM_COM_BASE_PTR + 0x24);
+	writel(0xffff, SUNXI_DRAM_COM_BASE_PTR + 0x28);
 	udelay(10);
 }
 
 static void dram_disable_all_master(void)
 {
-	writel(1, 0x3102020);
-	writel(0, 0x3102024);
-	writel(0, 0x3102028);
+	writel(1, SUNXI_DRAM_COM_BASE_PTR + 0x20);
+	writel(0, SUNXI_DRAM_COM_BASE_PTR + 0x24);
+	writel(0, SUNXI_DRAM_COM_BASE_PTR + 0x28);
 	udelay(10);
 }
 
 static void eye_delay_compensation(const dram_para_t *para)
 {
 	uint32_t delay;
-	unsigned long ptr;
+	u8 __iomem *ptr;
 
 	// DATn0IOCR, n =  0...7
 	delay = (para->dram_tpr11 & 0xf) << 9;
 	delay |= (para->dram_tpr12 & 0xf) << 1;
-	for (ptr = 0x3103310; ptr < 0x3103334; ptr += 4)
+	for (ptr = SUNXI_DRAM_PHY_BASE_PTR + 0x310;
+	     ptr < SUNXI_DRAM_PHY_BASE_PTR + 0x334; ptr += 4)
 		setbits_le32(ptr, delay);
 
 	// DATn1IOCR, n =  0...7
 	delay = (para->dram_tpr11 & 0xf0) << 5;
 	delay |= (para->dram_tpr12 & 0xf0) >> 3;
-	for (ptr = 0x3103390; ptr != 0x31033b4; ptr += 4)
+	for (ptr = SUNXI_DRAM_PHY_BASE_PTR + 0x390;
+	     ptr != SUNXI_DRAM_PHY_BASE_PTR + 0x3b4; ptr += 4)
 		setbits_le32(ptr, delay);
 
 	// PGCR0: assert AC loopback FIFO reset
-	clrbits_le32(0x3103100, 0x04000000);
+	clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x100, 0x04000000);
 
 	// ??
 
 	delay = (para->dram_tpr11 & 0xf0000) >> 7;
 	delay |= (para->dram_tpr12 & 0xf0000) >> 15;
-	setbits_le32(0x3103334, delay);
-	setbits_le32(0x3103338, delay);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x334, delay);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x338, delay);
 
 	delay = (para->dram_tpr11 & 0xf00000) >> 11;
 	delay |= (para->dram_tpr12 & 0xf00000) >> 19;
-	setbits_le32(0x31033b4, delay);
-	setbits_le32(0x31033b8, delay);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x3b4, delay);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x3b8, delay);
 
-	setbits_le32(0x310333c, (para->dram_tpr11 & 0xf0000) << 9);
-	setbits_le32(0x31033bc, (para->dram_tpr11 & 0xf00000) << 5);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x33c,
+		     (para->dram_tpr11 & 0xf0000) << 9);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x3bc,
+		     (para->dram_tpr11 & 0xf00000) << 5);
 
 	// PGCR0: release AC loopback FIFO reset
-	setbits_le32(0x3103100, BIT(26));
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x100, BIT(26));
 
 	udelay(1);
 
 	delay = (para->dram_tpr10 & 0xf0) << 4;
-	for (ptr = 0x3103240; ptr != 0x310327c; ptr += 4)
+	for (ptr = SUNXI_DRAM_PHY_BASE_PTR + 0x240;
+	     ptr != SUNXI_DRAM_PHY_BASE_PTR + 0x27c; ptr += 4)
 		setbits_le32(ptr, delay);
-	for (ptr = 0x3103228; ptr != 0x3103240; ptr += 4)
+	for (ptr = SUNXI_DRAM_PHY_BASE_PTR + 0x228;
+	     ptr != SUNXI_DRAM_PHY_BASE_PTR + 0x240; ptr += 4)
 		setbits_le32(ptr, delay);
 
-	setbits_le32(0x3103218, (para->dram_tpr10 & 0x0f) << 8);
-	setbits_le32(0x310321c, (para->dram_tpr10 & 0x0f) << 8);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x218,
+		     (para->dram_tpr10 & 0x0f) << 8);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x21c,
+		     (para->dram_tpr10 & 0x0f) << 8);
 
-	setbits_le32(0x3103280, (para->dram_tpr10 & 0xf00) >> 4);
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x280,
+		     (para->dram_tpr10 & 0xf00) >> 4);
 }
 
 /*
@@ -447,40 +463,42 @@ static void mctl_set_timing_params(const dram_para_t *para,
 	}
 
 	/* Set mode registers */
-	writel(mr0, 0x3103030);
-	writel(mr1, 0x3103034);
-	writel(mr2, 0x3103038);
-	writel(mr3, 0x310303c);
+	writel(mr0, SUNXI_DRAM_PHY_BASE_PTR + 0x30);
+	writel(mr1, SUNXI_DRAM_PHY_BASE_PTR + 0x34);
+	writel(mr2, SUNXI_DRAM_PHY_BASE_PTR + 0x38);
+	writel(mr3, SUNXI_DRAM_PHY_BASE_PTR + 0x3c);
 	/* TODO: dram_odt_en is either 0x0 or 0x1, so right shift looks weird */
-	writel((para->dram_odt_en >> 4) & 0x3, 0x310302c);
+	writel((para->dram_odt_en >> 4) & 0x3, SUNXI_DRAM_PHY_BASE_PTR + 0x2c);
 
 	/* Set dram timing DRAMTMG0 - DRAMTMG5 */
 	writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | (tras << 0),
-		0x3103058);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x58);
 	writel((txp << 16) | (trtp << 8) | (trc << 0),
-		0x310305c);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x5c);
 	writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | (twr2rd << 0),
-		0x3103060);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x60);
 	writel((tmrw << 16) | (tmrd << 12) | (tmod << 0),
-		0x3103064);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x64);
 	writel((trcd << 24) | (tccd << 16) | (trrd << 8) | (trp << 0),
-		0x3103068);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x68);
 	writel((tcksrx << 24) | (tcksrx << 16) | (tckesr << 8) | (tcke << 0),
-		0x310306c);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x6c);
 
 	/* Set dual rank timing */
-	clrsetbits_le32(0x3103078, 0xf000ffff,
+	clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x78, 0xf000ffff,
 			(CONFIG_DRAM_CLK < 800) ? 0xf0006610 : 0xf0007610);
 
 	/* Set phy interface time PITMG0, PTR3, PTR4 */
 	writel((0x2 << 24) | (t_rdata_en << 16) | BIT(8) | (wr_latency << 0),
-		0x3103080);
-	writel(((tdinit0 << 0) | (tdinit1 << 20)), 0x3103050);
-	writel(((tdinit2 << 0) | (tdinit3 << 20)), 0x3103054);
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x80);
+	writel(((tdinit0 << 0) | (tdinit1 << 20)),
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x50);
+	writel(((tdinit2 << 0) | (tdinit3 << 20)),
+	       SUNXI_DRAM_PHY_BASE_PTR + 0x54);
 
 	/* Set refresh timing and mode */
-	writel((trefi << 16) | (trfc << 0), 0x3103090);
-	writel((trefi << 15) & 0x0fff0000, 0x3103094);
+	writel((trefi << 16) | (trfc << 0), SUNXI_DRAM_PHY_BASE_PTR + 0x90);
+	writel((trefi << 15) & 0x0fff0000, SUNXI_DRAM_PHY_BASE_PTR + 0x94);
 }
 
 // Purpose of this routine seems to be to initialize the PLL driving
@@ -499,26 +517,26 @@ static int ccu_set_pll_ddr_clk(int index, const dram_para_t *para,
 	// set VCO clock divider
 	n = (clk * 2) / 24;
 
-	val = readl(SUNXI_CCM_BASE + 0x10);
+	val = readl(SUNXI_CCM_BASE_PTR + 0x10);
 	val &= ~0x0007ff03;			// clear dividers
 	val |= (n - 1) << 8;			// set PLL division
 	val |= BIT(31) | BIT(30);		// enable PLL and LDO
-	writel(val | BIT(29), SUNXI_CCM_BASE + 0x10);
+	writel(val | BIT(29), SUNXI_CCM_BASE_PTR + 0x10);
 
 	// wait for PLL to lock
-	while ((readl(SUNXI_CCM_BASE + 0x10) & BIT(28)) == 0)
+	while ((readl(SUNXI_CCM_BASE_PTR + 0x10) & BIT(28)) == 0)
 		;
 
 	udelay(20);
 
 	// enable PLL output
-	setbits_le32(SUNXI_CCM_BASE + 0x0, BIT(27));
+	setbits_le32(SUNXI_CCM_BASE_PTR + 0x0, BIT(27));
 
 	// turn clock gate on
-	val = readl(SUNXI_CCM_BASE + 0x800);
+	val = readl(SUNXI_CCM_BASE_PTR + 0x800);
 	val &= ~0x03000303;		// select DDR clk source, n=1, m=1
 	val |= BIT(31);			// turn clock on
-	writel(val, SUNXI_CCM_BASE + 0x800);
+	writel(val, SUNXI_CCM_BASE_PTR + 0x800);
 
 	return n * 24;
 }
@@ -527,11 +545,11 @@ static int ccu_set_pll_ddr_clk(int index, const dram_para_t *para,
 static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config)
 {
 	// assert MBUS reset
-	clrbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
+	clrbits_le32(SUNXI_CCM_BASE_PTR + 0x540, BIT(30));
 
 	// turn off sdram clock gate, assert sdram reset
-	clrbits_le32(SUNXI_CCM_BASE + 0x80c, 0x10001);
-	clrsetbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(30), BIT(27));
+	clrbits_le32(SUNXI_CCM_BASE_PTR + 0x80c, 0x10001);
+	clrsetbits_le32(SUNXI_CCM_BASE_PTR + 0x800, BIT(31) | BIT(30), BIT(27));
 	udelay(10);
 
 	// set ddr pll clock
@@ -540,23 +558,23 @@ static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config)
 	dram_disable_all_master();
 
 	// release sdram reset
-	setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(16));
+	setbits_le32(SUNXI_CCM_BASE_PTR + 0x80c, BIT(16));
 
 	// release MBUS reset
-	setbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
-	setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(30));
+	setbits_le32(SUNXI_CCM_BASE_PTR + 0x540, BIT(30));
+	setbits_le32(SUNXI_CCM_BASE_PTR + 0x800, BIT(30));
 
 	udelay(5);
 
 	// turn on sdram clock gate
-	setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(0));
+	setbits_le32(SUNXI_CCM_BASE_PTR + 0x80c, BIT(0));
 
 	// turn dram clock gate on, trigger sdr clock update
-	setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(27));
+	setbits_le32(SUNXI_CCM_BASE_PTR + 0x800, BIT(31) | BIT(27));
 	udelay(5);
 
 	// mCTL clock enable
-	writel(0x8000, 0x310300c);
+	writel(0x8000, SUNXI_DRAM_PHY_BASE_PTR + 0xc);
 	udelay(10);
 }
 
@@ -567,14 +585,14 @@ static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config)
 static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
 {
 	uint32_t val, width;
-	unsigned long ptr;
+	u8 __iomem *ptr;
 	int i;
 
 	// purpose ??
-	clrsetbits_le32(0x3102008, 0x3f00, 0x2000);
+	clrsetbits_le32(SUNXI_DRAM_COM_BASE_PTR + 0x8, 0x3f00, 0x2000);
 
 	// set SDRAM type and word width
-	val  = readl(0x3102000) & ~0x00fff000;
+	val  = readl(SUNXI_DRAM_COM_BASE_PTR) & ~0x00fff000;
 	val |= (para->dram_type & 0x7) << 16;		// DRAM type
 	val |= (~config->dram_para2 & 0x1) << 12;		// DQ width
 	val |= BIT(22);					// ??
@@ -585,7 +603,7 @@ static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
 		if (config->dram_tpr13 & BIT(5))
 			val |= BIT(19);
 	}
-	writel(val, 0x3102000);
+	writel(val, SUNXI_DRAM_COM_BASE_PTR);
 
 	// init rank / bank / row for single/dual or two different ranks
 	if ((config->dram_para2 & BIT(8)) &&
@@ -594,7 +612,7 @@ static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
 	else
 		width = 16;
 
-	ptr = 0x3102000;
+	ptr = SUNXI_DRAM_COM_BASE_PTR;
 	for (i = 0; i < width; i += 16) {
 		val = readl(ptr) & 0xfffff000;
 
@@ -615,17 +633,19 @@ static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
 	}
 
 	// set ODTMAP based on number of ranks in use
-	val = (readl(0x3102000) & 0x1) ? 0x303 : 0x201;
-	writel(val, 0x3103120);
+	val = (readl(SUNXI_DRAM_COM_BASE_PTR) & 0x1) ? 0x303 : 0x201;
+	writel(val, SUNXI_DRAM_PHY_BASE_PTR + 0x120);
 
 	// set mctl reg 3c4 to zero when using half DQ
 	if (config->dram_para2 & BIT(0))
-		writel(0, 0x31033c4);
+		writel(0, SUNXI_DRAM_PHY_BASE_PTR + 0x3c4);
 
 	// purpose ??
 	if (para->dram_tpr4) {
-                setbits_le32(0x3102000, (para->dram_tpr4 & 0x3) << 25);
-                setbits_le32(0x3102004, (para->dram_tpr4 & 0x7fc) << 10);
+		setbits_le32(SUNXI_DRAM_COM_BASE_PTR,
+			     (para->dram_tpr4 & 0x3) << 25);
+		setbits_le32(SUNXI_DRAM_COM_BASE_PTR + 0x4,
+			     (para->dram_tpr4 & 0x7fc) << 10);
 	}
 }
 
@@ -666,7 +686,7 @@ static void mctl_phy_ac_remapping(const dram_para_t *para,
 	    para->dram_type != SUNXI_DRAM_TYPE_DDR3)
 		return;
 
-	fuse = (readl(SUNXI_SID_BASE + 0x28) & 0xf00) >> 8;
+	fuse = (readl(SUNXI_SID_BASE_PTR + 0x28) & 0xf00) >> 8;
 	debug("DDR efuse: 0x%x\n", fuse);
 	debug("SoC Chip ID: 0x%08x\n", sid_read_soc_chipid());
 
@@ -697,23 +717,23 @@ static void mctl_phy_ac_remapping(const dram_para_t *para,
 
 	val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
 	      (cfg[1] << 10) | (cfg[0] << 5);
-	writel(val, 0x3102500);
+	writel(val, SUNXI_DRAM_COM_BASE_PTR + 0x500);
 
 	val = (cfg[10] << 25) | (cfg[9] << 20) | (cfg[8] << 15) |
 	      (cfg[ 7] << 10) | (cfg[6] <<  5) | cfg[5];
-	writel(val, 0x3102504);
+	writel(val, SUNXI_DRAM_COM_BASE_PTR + 0x504);
 
 	val = (cfg[15] << 20) | (cfg[14] << 15) | (cfg[13] << 10) |
 	      (cfg[12] <<  5) | cfg[11];
-	writel(val, 0x3102508);
+	writel(val, SUNXI_DRAM_COM_BASE_PTR + 0x508);
 
 	val = (cfg[21] << 25) | (cfg[20] << 20) | (cfg[19] << 15) |
 	      (cfg[18] << 10) | (cfg[17] <<  5) | cfg[16];
-	writel(val, 0x310250c);
+	writel(val, SUNXI_DRAM_COM_BASE_PTR + 0x50c);
 
 	val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
 	      (cfg[1] << 10) | (cfg[0] <<  5) | 1;
-	writel(val, 0x3102500);
+	writel(val, SUNXI_DRAM_COM_BASE_PTR + 0x500);
 }
 
 // Init the controller channel. The key part is placing commands in the main
@@ -728,10 +748,11 @@ static unsigned int mctl_channel_init(unsigned int ch_index,
 	dqs_gating_mode = (config->dram_tpr13 & 0xc) >> 2;
 
 	// set DDR clock to half of CPU clock
-	clrsetbits_le32(0x310200c, 0xfff, (para->dram_clk / 2) - 1);
+	clrsetbits_le32(SUNXI_DRAM_COM_BASE_PTR + 0xc,
+			0xfff, (para->dram_clk / 2) - 1);
 
 	// MRCTRL0 nibble 3 undocumented
-	clrsetbits_le32(0x3103108, 0xf00, 0x300);
+	clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, 0xf00, 0x300);
 
 	if (para->dram_odt_en)
 		val = 0;
@@ -740,144 +761,149 @@ static unsigned int mctl_channel_init(unsigned int ch_index,
 
 	// DX0GCR0
 	if (para->dram_clk > 672)
-		clrsetbits_le32(0x3103344, 0xf63e, val);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x344, 0xf63e, val);
 	else
-		clrsetbits_le32(0x3103344, 0xf03e, val);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x344, 0xf03e, val);
 
 	// DX1GCR0
 	if (para->dram_clk > 672) {
-                setbits_le32(0x3103344, 0x400);
-		clrsetbits_le32(0x31033c4, 0xf63e, val);
+		setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x344, 0x400);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x3c4, 0xf63e, val);
 	} else {
-		clrsetbits_le32(0x31033c4, 0xf03e, val);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x3c4, 0xf03e, val);
 	}
 
 	// 0x3103208 undocumented
-	setbits_le32(0x3103208, BIT(1));
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x208, BIT(1));
 
 	eye_delay_compensation(para);
 
 	// set PLL SSCG ?
-	val = readl(0x3103108);
+	val = readl(SUNXI_DRAM_PHY_BASE_PTR + 0x108);
 	if (dqs_gating_mode == 1) {
-		clrsetbits_le32(0x3103108, 0xc0, 0);
-		clrbits_le32(0x31030bc, 0x107);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, 0xc0, 0);
+		clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0xbc, 0x107);
 	} else if (dqs_gating_mode == 2) {
-		clrsetbits_le32(0x3103108, 0xc0, 0x80);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, 0xc0, 0x80);
 
-		clrsetbits_le32(0x31030bc, 0x107,
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0xbc, 0x107,
 				(((config->dram_tpr13 >> 16) & 0x1f) - 2) | 0x100);
-		clrsetbits_le32(0x310311c, BIT(31), BIT(27));
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x11c,
+				BIT(31), BIT(27));
 	} else {
-		clrbits_le32(0x3103108, 0x40);
+		clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, 0x40);
 		udelay(10);
-		setbits_le32(0x3103108, 0xc0);
+		setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, 0xc0);
 	}
 
 	if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
 	    para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
 		if (dqs_gating_mode == 1)
-			clrsetbits_le32(0x310311c, 0x080000c0, 0x80000000);
+			clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x11c,
+					0x080000c0, 0x80000000);
 		else
-			clrsetbits_le32(0x310311c, 0x77000000, 0x22000000);
+			clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x11c,
+					0x77000000, 0x22000000);
 	}
 
-	clrsetbits_le32(0x31030c0, 0x0fffffff,
+	clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0xc0, 0x0fffffff,
 			(config->dram_para2 & BIT(12)) ? 0x03000001 : 0x01000007);
 
-	if (readl(0x70005d4) & BIT(16)) {
-		clrbits_le32(0x7010250, 0x2);
+	if (readl((void __iomem *)0x70005d4) & BIT(16)) {
+		clrbits_le32((void __iomem *)0x7010250, 0x2);
 		udelay(10);
 	}
 
 	// Set ZQ config
-	clrsetbits_le32(0x3103140, 0x3ffffff,
+	clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x140, 0x3ffffff,
 			(para->dram_zq & 0x00ffffff) | BIT(25));
 
 	// Initialise DRAM controller
 	if (dqs_gating_mode == 1) {
-		//writel(0x52, 0x3103000); // prep PHY reset + PLL init + z-cal
-		writel(0x53, 0x3103000); // Go
+		//writel(0x52, SUNXI_DRAM_PHY_BASE_PTR); // prep PHY reset + PLL init + z-cal
+		writel(0x53, SUNXI_DRAM_PHY_BASE_PTR); // Go
 
-		while ((readl(0x3103010) & 0x1) == 0) {
+		while ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x10) & 0x1) == 0) {
 		} // wait for IDONE
 		udelay(10);
 
 		// 0x520 = prep DQS gating + DRAM init + d-cal
 		if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
-			writel(0x5a0, 0x3103000);		// + DRAM reset
+			writel(0x5a0, SUNXI_DRAM_PHY_BASE_PTR); // + DRAM reset
 		else
-			writel(0x520, 0x3103000);
+			writel(0x520, SUNXI_DRAM_PHY_BASE_PTR);
 	} else {
-		if ((readl(0x70005d4) & (1 << 16)) == 0) {
+		if ((readl((void __iomem *)0x70005d4) & (1 << 16)) == 0) {
 			// prep DRAM init + PHY reset + d-cal + PLL init + z-cal
 			if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
-				writel(0x1f2, 0x3103000);	// + DRAM reset
+				writel(0x1f2, SUNXI_DRAM_PHY_BASE_PTR); // + DRAM reset
 			else
-				writel(0x172, 0x3103000);
+				writel(0x172, SUNXI_DRAM_PHY_BASE_PTR);
 		} else {
 			// prep PHY reset + d-cal + z-cal
-			writel(0x62, 0x3103000);
+			writel(0x62, SUNXI_DRAM_PHY_BASE_PTR);
 		}
 	}
 
-	setbits_le32(0x3103000, 0x1);		 // GO
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR, 0x1);		 // GO
 
 	udelay(10);
-	while ((readl(0x3103010) & 0x1) == 0) {
+	while ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x10) & 0x1) == 0) {
 	} // wait for IDONE
 
-	if (readl(0x70005d4) & BIT(16)) {
-		clrsetbits_le32(0x310310c, 0x06000000, 0x04000000);
+	if (readl((void __iomem *)0x70005d4) & BIT(16)) {
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x10c,
+				0x06000000, 0x04000000);
 		udelay(10);
 
-		setbits_le32(0x3103004, 0x1);
+		setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x4, 0x1);
 
-		while ((readl(0x3103018) & 0x7) != 0x3) {
+		while ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x18) & 0x7) != 0x3) {
 		}
 
-		clrbits_le32(0x7010250, 0x1);
+		clrbits_le32((void __iomem *)0x7010250, 0x1);
 		udelay(10);
 
-		clrbits_le32(0x3103004, 0x1);
+		clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x4, 0x1);
 
-		while ((readl(0x3103018) & 0x7) != 0x1) {
+		while ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x18) & 0x7) != 0x1) {
 		}
 
 		udelay(15);
 
 		if (dqs_gating_mode == 1) {
-			clrbits_le32(0x3103108, 0xc0);
-			clrsetbits_le32(0x310310c, 0x06000000, 0x02000000);
+			clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, 0xc0);
+			clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x10c,
+					0x06000000, 0x02000000);
 			udelay(1);
-			writel(0x401, 0x3103000);
+			writel(0x401, SUNXI_DRAM_PHY_BASE_PTR);
 
-			while ((readl(0x3103010) & 0x1) == 0) {
+			while ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x10) & 0x1) == 0) {
 			}
 		}
 	}
 
 	// Check for training error
-	if (readl(0x3103010) & BIT(20)) {
+	if (readl(SUNXI_DRAM_PHY_BASE_PTR + 0x10) & BIT(20)) {
 		printf("ZQ calibration error, check external 240 ohm resistor\n");
 		return 0;
 	}
 
 	// STATR = Zynq STAT? Wait for status 'normal'?
-	while ((readl(0x3103018) & 0x1) == 0) {
+	while ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x18) & 0x1) == 0) {
 	}
 
-	setbits_le32(0x310308c, BIT(31));
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x8c, BIT(31));
 	udelay(10);
-	clrbits_le32(0x310308c, BIT(31));
+	clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x8c, BIT(31));
 	udelay(10);
-	setbits_le32(0x3102014, BIT(31));
+	setbits_le32(SUNXI_DRAM_COM_BASE_PTR + 0x14, BIT(31));
 	udelay(10);
 
-	clrbits_le32(0x310310c, 0x06000000);
+	clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x10c, 0x06000000);
 
 	if (dqs_gating_mode == 1)
-		clrsetbits_le32(0x310311c, 0xc0, 0x40);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x11c, 0xc0, 0x40);
 
 	return 1;
 }
@@ -904,12 +930,12 @@ static unsigned int DRAMC_get_dram_size(void)
 	uint32_t val;
 	unsigned int size;
 
-	val = readl(0x3102000);		/* MC_WORK_MODE0 */
+	val = readl(SUNXI_DRAM_COM_BASE_PTR);		/* MC_WORK_MODE0 */
 	size = calculate_rank_size(val);
 	if ((val & 0x3) == 0)		/* single rank? */
 		return size;
 
-	val = readl(0x3102004);		/* MC_WORK_MODE1 */
+	val = readl(SUNXI_DRAM_COM_BASE_PTR + 0x4); /* MC_WORK_MODE1 */
 	if ((val & 0x3) == 0)		/* two identical ranks? */
 		return size * 2;
 
@@ -928,14 +954,14 @@ static int dqs_gate_detect(dram_config_t *config)
 {
 	uint32_t dx0, dx1;
 
-	if ((readl(0x3103010) & BIT(22)) == 0) {
+	if ((readl(SUNXI_DRAM_PHY_BASE_PTR + 0x10) & BIT(22)) == 0) {
 		config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
 		debug("dual rank and full DQ\n");
 
 		return 1;
 	}
 
-	dx0 = (readl(0x3103348) & 0x3000000) >> 24;
+	dx0 = (readl(SUNXI_DRAM_PHY_BASE_PTR + 0x348) & 0x3000000) >> 24;
 	if (dx0 == 0) {
 		config->dram_para2 = (config->dram_para2 & ~0xf) | 0x1001;
 		debug("dual rank and half DQ\n");
@@ -944,7 +970,7 @@ static int dqs_gate_detect(dram_config_t *config)
 	}
 
 	if (dx0 == 2) {
-		dx1 = (readl(0x31033c8) & 0x3000000) >> 24;
+		dx1 = (readl(SUNXI_DRAM_PHY_BASE_PTR + 0x3c8) & 0x3000000) >> 24;
 		if (dx1 == 2) {
 			config->dram_para2 = config->dram_para2 & ~0xf00f;
 			debug("single rank and full DQ\n");
@@ -974,20 +1000,20 @@ static int dramc_simple_wr_test(unsigned int mem_mb, int len)
 
 	addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
 	for (i = 0; i != len; i++, addr++) {
-		writel(patt1 + i, (unsigned long)addr);
-		writel(patt2 + i, (unsigned long)(addr + offs));
+		writel(patt1 + i, (void __iomem *)addr);
+		writel(patt2 + i, (void __iomem *)(addr + offs));
 	}
 
 	addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
 	for (i = 0; i != len; i++) {
-		v1 = readl((unsigned long)(addr + i));
+		v1 = readl((void __iomem *)(addr + i));
 		v2 = patt1 + i;
 		if (v1 != v2) {
 			printf("DRAM: simple test FAIL\n");
 			printf("%x != %x at address %p\n", v1, v2, addr + i);
 			return 1;
 		}
-		v1 = readl((unsigned long)(addr + offs + i));
+		v1 = readl((void __iomem *)(addr + offs + i));
 		v2 = patt2 + i;
 		if (v1 != v2) {
 			printf("DRAM: simple test FAIL\n");
@@ -1002,16 +1028,19 @@ static int dramc_simple_wr_test(unsigned int mem_mb, int len)
 
 // Set the Vref mode for the controller
 //
-static void mctl_vrefzq_init(const dram_para_t *para, const dram_config_t *config)
+static void mctl_vrefzq_init(const dram_para_t *para,
+			     const dram_config_t *config)
 {
 	if (config->dram_tpr13 & BIT(17))
 		return;
 
-	clrsetbits_le32(0x3103110, 0x7f7f7f7f, para->dram_tpr5);
+	clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x110,
+			0x7f7f7f7f, para->dram_tpr5);
 
 	// IOCVR1
 	if ((config->dram_tpr13 & BIT(16)) == 0)
-		clrsetbits_le32(0x3103114, 0x7f, para->dram_tpr6 & 0x7f);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x114,
+				0x7f, para->dram_tpr6 & 0x7f);
 }
 
 // Perform an init of the controller. This is actually done 3 times. The first
@@ -1058,7 +1087,8 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 {
 	unsigned int rval, i, j, rank, maxrank, offs;
 	unsigned int shft;
-	unsigned long ptr, mc_work_mode, chk;
+	unsigned long ptr, chk;
+	u8 __iomem *mc_work_mode;
 
 	if (mctl_core_init(para, config) == 0) {
 		printf("DRAM initialisation error : 0\n");
@@ -1066,12 +1096,12 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 	}
 
 	maxrank	= (config->dram_para2 & 0xf000) ? 2 : 1;
-	mc_work_mode = 0x3102000;
+	mc_work_mode = SUNXI_DRAM_COM_BASE_PTR;
 	offs = 0;
 
 	/* write test pattern */
 	for (i = 0, ptr = CFG_SYS_SDRAM_BASE; i < 64; i++, ptr += 4)
-		writel(get_payload(i & 0x1, ptr), ptr);
+		writel(get_payload(i & 0x1, ptr), (void __iomem *)ptr);
 
 	for (rank = 0; rank < maxrank;) {
 		/* set row mode */
@@ -1083,7 +1113,7 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 			chk = CFG_SYS_SDRAM_BASE + (1U << (i + 11));
 			ptr = CFG_SYS_SDRAM_BASE;
 			for (j = 0; j < 64; j++) {
-				if (readl(chk) != get_payload(j & 0x1, ptr))
+				if (readl((void __iomem *)chk) != get_payload(j & 0x1, ptr))
 					break;
 				ptr += 4;
 				chk += 4;
@@ -1103,7 +1133,7 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 		config->dram_para1 = rval;
 
 		if (rank == 1)		/* Set bank mode for rank0 */
-			clrsetbits_le32(0x3102000, 0xffc, 0x6a4);
+			clrsetbits_le32(SUNXI_DRAM_COM_BASE_PTR, 0xffc, 0x6a4);
 
 		/* Set bank mode for current rank */
 		clrsetbits_le32(mc_work_mode, 0xffc, 0x6a4);
@@ -1113,7 +1143,7 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 		chk = CFG_SYS_SDRAM_BASE + (1U << 22);
 		ptr = CFG_SYS_SDRAM_BASE;
 		for (i = 0, j = 0; i < 64; i++) {
-			if (readl(chk) != get_payload(i & 1, ptr)) {
+			if (readl((void __iomem *)chk) != get_payload(i & 1, ptr)) {
 				j = 1;
 				break;
 			}
@@ -1131,7 +1161,7 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 		config->dram_para1 = rval;
 
 		if (rank == 1)		/* Set page mode for rank0 */
-			clrsetbits_le32(0x3102000, 0xffc, 0xaa0);
+			clrsetbits_le32(SUNXI_DRAM_COM_BASE_PTR, 0xffc, 0xaa0);
 
 		/* Set page mode for current rank */
 		clrsetbits_le32(mc_work_mode, 0xffc, 0xaa0);
@@ -1142,7 +1172,7 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 			chk = CFG_SYS_SDRAM_BASE + (1U << i);
 			ptr = CFG_SYS_SDRAM_BASE;
 			for (j = 0; j < 64; j++) {
-				if (readl(chk) != get_payload(j & 1, ptr))
+				if (readl((void __iomem *)chk) != get_payload(j & 1, ptr))
 					break;
 				ptr += 4;
 				chk += 4;
@@ -1168,10 +1198,12 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 		if (rank != maxrank) {
 			if (rank == 1) {
 				/* MC_WORK_MODE */
-				clrsetbits_le32(0x3202000, 0xffc, 0x6f0);
+				clrsetbits_le32(SUNXI_DRAM_COM_BASE2_PTR,
+						0xffc, 0x6f0);
 
 				/* MC_WORK_MODE2 */
-				clrsetbits_le32(0x3202004, 0xffc, 0x6f0);
+				clrsetbits_le32(SUNXI_DRAM_COM_BASE2_PTR + 0x4,
+						0xffc, 0x6f0);
 			}
 			/* store rank1 config in upper half of para1 */
 			offs += 16;
@@ -1212,7 +1244,7 @@ static int auto_scan_dram_rank_width(const dram_para_t *para,
 
 	mctl_core_init(para, config);
 
-	if (readl(0x3103010) & BIT(20))
+	if (readl(SUNXI_DRAM_PHY_BASE_PTR + 0x10) & BIT(20))
 		return 0;
 
 	if (dqs_gate_detect(config) == 0)
@@ -1271,18 +1303,18 @@ static int init_DRAM(int type, const dram_para_t *para)
 	/* Test ZQ status */
 	if (config.dram_tpr13 & BIT(16)) {
 		debug("DRAM only have internal ZQ\n");
-		setbits_le32(0x3000160, BIT(8));
-		writel(0, 0x3000168);
+		setbits_le32((void __iomem *)0x3000160, BIT(8));
+		writel(0, (void __iomem *)0x3000168);
 		udelay(10);
 	} else {
-		clrbits_le32(0x3000160, 0x3);
-		writel(config.dram_tpr13 & BIT(16), 0x7010254);
+		clrbits_le32((void __iomem *)0x3000160, 0x3);
+		writel(config.dram_tpr13 & BIT(16), (void __iomem *)0x7010254);
 		udelay(10);
-		clrsetbits_le32(0x3000160, 0x108, BIT(1));
+		clrsetbits_le32((void __iomem *)0x3000160, 0x108, BIT(1));
 		udelay(10);
-		setbits_le32(0x3000160, BIT(0));
+		setbits_le32((void __iomem *)0x3000160, BIT(0));
 		udelay(20);
-		debug("ZQ value = 0x%x\n", readl(0x300016c));
+		debug("ZQ value = 0x%x\n", readl((void __iomem *)0x300016c));
 	}
 
 	dram_voltage_set(para);
@@ -1325,41 +1357,44 @@ static int init_DRAM(int type, const dram_para_t *para)
 		rc = para->dram_tpr8;
 		if (rc == 0)
 			rc = 0x10000200;
-		writel(rc, 0x31030a0);
-		writel(0x40a, 0x310309c);
-		setbits_le32(0x3103004, BIT(0));
+		writel(rc, SUNXI_DRAM_PHY_BASE_PTR + 0xa0);
+		writel(0x40a, SUNXI_DRAM_PHY_BASE_PTR + 0x9c);
+		setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x4, BIT(0));
 		debug("Enable Auto SR\n");
 	} else {
-		clrbits_le32(0x31030a0, 0xffff);
-		clrbits_le32(0x3103004, 0x1);
+		clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0xa0, 0xffff);
+		clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x4, 0x1);
 	}
 
 	/* Purpose ?? */
 	if (config.dram_tpr13 & BIT(9)) {
-		clrsetbits_le32(0x3103100, 0xf000, 0x5000);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x100,
+				0xf000, 0x5000);
 	} else {
 		if (para->dram_type != SUNXI_DRAM_TYPE_LPDDR2)
-			clrbits_le32(0x3103100, 0xf000);
+			clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x100, 0xf000);
 	}
 
-	setbits_le32(0x3103140, BIT(31));
+	setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x140, BIT(31));
 
 	/* CHECK: is that really writing to a different register? */
 	if (config.dram_tpr13 & BIT(8))
-		writel(readl(0x3103140) | 0x300, 0x31030b8);
+		writel(readl(SUNXI_DRAM_PHY_BASE_PTR + 0x140) | 0x300,
+		       SUNXI_DRAM_PHY_BASE_PTR + 0xb8);
 
 	if (config.dram_tpr13 & BIT(16))
-		clrbits_le32(0x3103108, BIT(13));
+		clrbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, BIT(13));
 	else
-		setbits_le32(0x3103108, BIT(13));
+		setbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x108, BIT(13));
 
 	/* Purpose ?? */
 	if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR3)
-		clrsetbits_le32(0x310307c, 0xf0000, 0x1000);
+		clrsetbits_le32(SUNXI_DRAM_PHY_BASE_PTR + 0x7c,
+				0xf0000, 0x1000);
 
 	dram_enable_all_master();
 	if (config.dram_tpr13 & BIT(28)) {
-		if ((readl(0x70005d4) & BIT(16)) ||
+		if ((readl((void __iomem *)0x70005d4) & BIT(16)) ||
 		    dramc_simple_wr_test(mem_size_mb, 4096))
 			return 0;
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/10] sunxi: dram: count the banks on address bit 11, not A22
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (3 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 04/10] sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 06/10] sunxi: dram: no AC remapping on the co-packaged DRAM parts Indrek Kruusa
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

The bank test looks for the BA2 alias at address bit 22, but in the mode
the probe programs BA2 is bit 11. A four bank part therefore always
reports eight banks, turning 64MB into 128MB.

On a MangoPi MQ with F133-A the probe now reports 4 banks, 13 rows and 2KB
pages - the vendor's dram_para1 = 0xd2. Boot tested on a Lichee RV Dock
too, where a D1 with external 512MB DDR3 is detected correctly.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 drivers/ram/sunxi/dram_sun20i_d1.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/ram/sunxi/dram_sun20i_d1.c b/drivers/ram/sunxi/dram_sun20i_d1.c
index 68697fb2fa9..f098329e891 100644
--- a/drivers/ram/sunxi/dram_sun20i_d1.c
+++ b/drivers/ram/sunxi/dram_sun20i_d1.c
@@ -1085,7 +1085,7 @@ static uint32_t get_payload(bool odd, unsigned long int ptr)
 
 static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 {
-	unsigned int rval, i, j, rank, maxrank, offs;
+	unsigned int rval, i, j, banks, rank, maxrank, offs;
 	unsigned int shft;
 	unsigned long ptr, chk;
 	u8 __iomem *mc_work_mode;
@@ -1139,25 +1139,32 @@ static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
 		clrsetbits_le32(mc_work_mode, 0xffc, 0x6a4);
 		udelay(1);
 
-		// Test if bit A23 is BA2 or mirror XXX A22?
-		chk = CFG_SYS_SDRAM_BASE + (1U << 22);
+		/*
+		 * Probe for a third bank address line. The bank mode above
+		 * leaves a nine bit column field, so the bank lines sit at
+		 * A9-A11 and BA2 is address bit 11: a part with only four
+		 * banks does not decode it, and mirrors the pattern written
+		 * at the start of the rank. Testing a row line instead (as
+		 * this used to, at A22) always misses the mirror on a four
+		 * bank part and reports eight banks.
+		 */
+		chk = CFG_SYS_SDRAM_BASE + (1U << 11);
 		ptr = CFG_SYS_SDRAM_BASE;
-		for (i = 0, j = 0; i < 64; i++) {
-			if (readl((void __iomem *)chk) != get_payload(i & 1, ptr)) {
-				j = 1;
+		for (j = 0; j < 64; j++) {
+			if (readl((void __iomem *)chk) != get_payload(j & 0x1, ptr))
 				break;
-			}
 			ptr += 4;
 			chk += 4;
 		}
+		banks = (j == 64) ? 0 : 1;
 
-		debug("rank %d bank = %d\n", rank, (j + 1) << 2); /* 4 or 8 */
+		debug("rank %d bank = %d\n", rank, (banks + 1) << 2); /* 4 or 8 */
 
 		/* Store banks in para 1 */
 		shft = 12 + offs;
 		rval = config->dram_para1;
 		rval &= ~(0xf << shft);
-		rval |= j << shft;
+		rval |= banks << shft;
 		config->dram_para1 = rval;
 
 		if (rank == 1)		/* Set page mode for rank0 */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/10] sunxi: dram: no AC remapping on the co-packaged DRAM parts
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (4 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 05/10] sunxi: dram: count the banks on address bit 11, not A22 Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 07/10] sunxi: dram: let the board set the MR1 mode register Indrek Kruusa
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

The PHY AC remapping tables compensate for the drive strength of the
DRAM chips connected to the SoC. This compensation must be skipped
when the DRAM is integrated on-die.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 drivers/ram/sunxi/dram_sun20i_d1.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/ram/sunxi/dram_sun20i_d1.c b/drivers/ram/sunxi/dram_sun20i_d1.c
index f098329e891..2d81e58071c 100644
--- a/drivers/ram/sunxi/dram_sun20i_d1.c
+++ b/drivers/ram/sunxi/dram_sun20i_d1.c
@@ -690,8 +690,13 @@ static void mctl_phy_ac_remapping(const dram_para_t *para,
 	debug("DDR efuse: 0x%x\n", fuse);
 	debug("SoC Chip ID: 0x%08x\n", sid_read_soc_chipid());
 
-	/* No remapping needed on T113-s4 with 256MB co-packaged DRAM */
-	if (sid_read_soc_chipid() == SUNXI_CHIPID_T113M4020DC0)
+	/*
+	 * No remapping needed on the chips with the DRAM die in the package:
+	 * the T113-s4 with 256MB, and the D1s and F133-A.
+	 */
+	if (sid_read_soc_chipid() == SUNXI_CHIPID_T113M4020DC0 ||
+	    sid_read_soc_chipid() == SUNXI_CHIPID_D1S ||
+	    sid_read_soc_chipid() == SUNXI_CHIPID_F133A)
 		return;
 
 	if (para->dram_type == SUNXI_DRAM_TYPE_DDR2) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/10] sunxi: dram: let the board set the MR1 mode register
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (5 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 06/10] sunxi: dram: no AC remapping on the co-packaged DRAM parts Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 08/10] sunxi: mmc: handle D1 PLL6 clock rate correctly Indrek Kruusa
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

The DRAM mode register 1 value belongs to the DRAM part, and the parts in
use differ: 0x02 for the DDR2 die co-packaged with the D1s and F133-A,
against the 0x42 that the boards with external DDR3 have booted with so
far.

Expose it next to the other vendor DRAM settings, keeping 0x42 as the
default so nothing changes for the existing users.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 drivers/ram/sunxi/Kconfig          | 6 ++++++
 drivers/ram/sunxi/dram_sun20i_d1.c | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/ram/sunxi/Kconfig b/drivers/ram/sunxi/Kconfig
index 9f2dc4a6e66..9b0cbca8083 100644
--- a/drivers/ram/sunxi/Kconfig
+++ b/drivers/ram/sunxi/Kconfig
@@ -12,6 +12,12 @@ config DRAM_SUNXI_ODT_EN
 	help
 	  ODT EN value from vendor DRAM settings.
 
+config DRAM_SUNXI_MR1
+	hex "DRAM MR1 parameter"
+	default 0x42
+	help
+	  DRAM mode register 1 value from vendor DRAM settings.
+
 config DRAM_SUNXI_TPR0
 	hex "DRAM TPR0 parameter"
 	help
diff --git a/drivers/ram/sunxi/dram_sun20i_d1.c b/drivers/ram/sunxi/dram_sun20i_d1.c
index 2d81e58071c..b8aef9707cc 100644
--- a/drivers/ram/sunxi/dram_sun20i_d1.c
+++ b/drivers/ram/sunxi/dram_sun20i_d1.c
@@ -1420,7 +1420,7 @@ static const dram_para_t para = {
 	.dram_zq	= CONFIG_DRAM_ZQ,
 	.dram_odt_en	= CONFIG_DRAM_SUNXI_ODT_EN,
 	.dram_mr0	= 0x1c70,
-	.dram_mr1	= 0x42,
+	.dram_mr1	= CONFIG_DRAM_SUNXI_MR1,
 	.dram_mr2	= 0x18,
 	.dram_mr3	= 0,
 	.dram_tpr0	= 0x004a2195,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/10] sunxi: mmc: handle D1 PLL6 clock rate correctly
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (6 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 07/10] sunxi: dram: let the board set the MR1 mode register Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 09/10] configs: add the Lichee RV Dock defconfig Indrek Kruusa
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Apply the existing MMC clock /2 compensation to SUN20I,
as already done for SUN8I_R528.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 drivers/mmc/sunxi_mmc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 84f4e4c2198..c5a93ebbc80 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -97,7 +97,8 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
 		 * like for the older SoCs. However we still have the hidden
 		 * divider of 2x, so compensate for that here.
 		 */
-		if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+		if (IS_ENABLED(CONFIG_MACH_SUN8I_R528) ||
+		    IS_ENABLED(CONFIG_SUN20I))
 			pll_hz /= 2;
 
 		/*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/10] configs: add the Lichee RV Dock defconfig
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (7 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 08/10] sunxi: mmc: handle D1 PLL6 clock rate correctly Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-01 21:04 ` [PATCH 10/10] configs: add the MangoPi MQ D1s(F133) defconfig Indrek Kruusa
  2026-11-06 23:17 ` [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Andre Przywara
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

Sipeed Lichee RV Dock: D1, 512 MB DDR3.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 MAINTAINERS                      |  1 +
 configs/lichee_rv_dock_defconfig | 14 ++++++++++++++
 2 files changed, 15 insertions(+)
 create mode 100644 configs/lichee_rv_dock_defconfig

diff --git a/MAINTAINERS b/MAINTAINERS
index 587d4a30377..6618000f168 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1549,6 +1549,7 @@ S:	Maintained
 F:	arch/riscv/cpu/sun20i/
 F:	arch/riscv/include/asm/arch-sun20i/
 F:	board/sun20i/
+F:	configs/lichee_rv_dock_defconfig
 F:	include/configs/sun20i.h
 
 RNG
diff --git a/configs/lichee_rv_dock_defconfig b/configs/lichee_rv_dock_defconfig
new file mode 100644
index 00000000000..a4c9821cfa4
--- /dev/null
+++ b/configs/lichee_rv_dock_defconfig
@@ -0,0 +1,14 @@
+CONFIG_RISCV=y
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun20i-d1-lichee-rv-dock"
+CONFIG_DRAM_SUNXI_ODT_EN=0x1
+CONFIG_DRAM_SUNXI_TPR0=0x004a2195
+CONFIG_DRAM_SUNXI_TPR11=0x00870000
+CONFIG_DRAM_SUNXI_TPR12=0x00000024
+CONFIG_DRAM_SUNXI_TPR13=0x34050100
+CONFIG_TARGET_SUN20I=y
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+# CONFIG_SPL_SMP is not set
+CONFIG_SPL_SYS_MALLOC=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_NS16550_CLK_ENABLE=y
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/10] configs: add the MangoPi MQ D1s(F133) defconfig
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (8 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 09/10] configs: add the Lichee RV Dock defconfig Indrek Kruusa
@ 2026-11-01 21:04 ` Indrek Kruusa
  2026-11-06 23:17 ` [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Andre Przywara
  10 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-01 21:04 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Indrek Kruusa

MangoPi MQ D1s(F133), 64 MB co-packaged DDR2.

Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
---
 MAINTAINERS                      |  1 +
 configs/mangopi_mq_d1s_defconfig | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)
 create mode 100644 configs/mangopi_mq_d1s_defconfig

diff --git a/MAINTAINERS b/MAINTAINERS
index 6618000f168..4cca82da801 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1550,6 +1550,7 @@ F:	arch/riscv/cpu/sun20i/
 F:	arch/riscv/include/asm/arch-sun20i/
 F:	board/sun20i/
 F:	configs/lichee_rv_dock_defconfig
+F:	configs/mangopi_mq_d1s_defconfig
 F:	include/configs/sun20i.h
 
 RNG
diff --git a/configs/mangopi_mq_d1s_defconfig b/configs/mangopi_mq_d1s_defconfig
new file mode 100644
index 00000000000..689f661ee89
--- /dev/null
+++ b/configs/mangopi_mq_d1s_defconfig
@@ -0,0 +1,20 @@
+CONFIG_RISCV=y
+CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun20i-d1s-mangopi-mq"
+CONFIG_SUNXI_DRAM_TYPE_DDR2=y
+CONFIG_DRAM_ZQ=8092665
+CONFIG_DRAM_CLK=528
+CONFIG_DRAM_SUNXI_ODT_EN=0x0
+CONFIG_DRAM_SUNXI_MR1=0x02
+CONFIG_DRAM_SUNXI_TPR0=0x00471992
+CONFIG_DRAM_SUNXI_TPR11=0x00030010
+CONFIG_DRAM_SUNXI_TPR12=0x00000035
+CONFIG_DRAM_SUNXI_TPR13=0x34004002
+CONFIG_TARGET_SUN20I=y
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+# CONFIG_SPL_SMP is not set
+CONFIG_SPL_SYS_MALLOC=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_IDENT_STRING=" Allwinner D1s/F133-A"
+CONFIG_CONS_INDEX=4
+CONFIG_NS16550_CLK_ENABLE=y
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards
  2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
                   ` (9 preceding siblings ...)
  2026-11-01 21:04 ` [PATCH 10/10] configs: add the MangoPi MQ D1s(F133) defconfig Indrek Kruusa
@ 2026-11-06 23:17 ` Andre Przywara
  2026-11-09 21:44   ` Indrek Kruusa
  10 siblings, 1 reply; 16+ messages in thread
From: Andre Przywara @ 2026-11-06 23:17 UTC (permalink / raw)
  To: Indrek Kruusa
  Cc: u-boot, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan, Jaehoon Chung,
	Lukasz Majewski, Stefan Roese, Samuel Holland, Tom Rini

On Sun,  1 Nov 2026 23:04:39 +0200
Indrek Kruusa <indrek.kruusa@gmail.com> wrote:

Hi Indrek,

thanks for sending this out.
This looks surprisingly simple on a first glance.
I haven't had a detailed look, but wanted to reply with some general
thoughts.

> Building upon the work of Samuel Holland [1], this series introduces support

I guess you took quite some patches from Samuel? I don't see him being
the author of any patch, that doesn't sound likely. Please try to
attribute his work, by keeping this authorship.

> for the Allwinner D1/D1s(F133) RISC-V SoCs and two development boards:
> 
> - Sipeed Lichee RV Dock (D1 SoC)
> - MangoPi MQ (RISC-V version with D1s/F133-A SoC)
> 
> The main difference from Samuel's work is how the boards are wired into the

I think Samuel also used DM_SPL (which I heavily oppose), looks like
this is gone as well? I like that, but it seems to be a major
difference worth mentioning.

> tree. The original design aimed at one cross-architecture configuration which
> covers ARM sun8i and RISC-V sun20i parts from Allwinner. This series does not
> do that. The D1/D1s get their own configuration instead:
> 
>   - arch/riscv/cpu/sun20i/ and board/sun20i/ hold the RISC-V side
>   - SUN20I is a SoC-family symbol, TARGET_SUN20I the board target
>   - the shared sunxi drivers accept SUN20I next to ARCH_SUNXI, so they are
>     shared as before -- only the Kconfig condition changes
> 
> Keeping the two sides apart has a cost: a few things exist twice.

Mmmh, I need to have a closer look, but am wondering if we can avoid
those double definitions and integrate both architectures better.
arch/arm vs. arm/riscv should separate itself naturally, and the
drivers shouldn't care about the architecture.
That's just a hunch, though, I will have a closer look in the next
weeks, as I am busy with other things.

Thanks,
Andre

> SUNXI_GEN_NCAT2 is declared in both arch trees, because the shared drivers
> test it and no Kconfig file is sourced by both. clock_get_pll6() is a C
> function for ARM (clock_sun50i_h6.c) and an inline for RISC-V
> (arch-sun20i/clock.h), decoding the same NCAT2 registers. The MMC mod-clock
> bits, the CCU offsets and parts of board/sunxi/board.c are repeated the same
> way.
> 
> For the sake of simplicity the image names stay "sunxi"
> (u-boot-sunxi-with-spl.bin, inner sunxi-spl.bin) because that is the shared
> Allwinner eGON boot format.
> 
> Both defconfigs build, and both boards boot from the SD card to a userspace
> login. The images were built with custom Buildroot configuration, using
> gcc 16.2.0, binutils 2.46.1 and Linux 7.3.0.
> 
> One caveat -- reboot does not work yet; it needs fixes outside U-Boot, on the
> firmware/OS side.
> 
> AI/LLM tools were used as development assistants throughout this work.
> Their use included debugging DRAM initialization and probing issues,
> assisting with code development, reviewing code, helping with testing and
> validation, and reviewing and refining commit messages.
> 
> PS. The boards use CONFIG_NS16550_CLK_ENABLE, which comes from a patch
> originally posted by khaliforce <kforce@gmail.com> and merged as commit
> 70f51e1e2ea5 ("serial: ns16550: make probe clock enabling optional") by
> Samuel Holland; v2027.01-rc1 already contains it.
> 
> [1] https://github.com/smaeul/u-boot/tree/d1-wip
> 
> 
> The patches (on tag v2027.01-rc1)
> ---------------------------------
> 
> 1/10 riscv: cpu: add Allwinner D1/D1s(F133) CPU support
>      Add the C906 support for the D1/D1s(F133) SoCs:
> 
>      - T-Head cache operations from the custom cache instructions
>      - harts_early_init() programming MXSTATUS, MHCR and MHINT
>      - cleanup_before_linux() disabling interrupts and flushing the caches
>      - dram_init() from the device tree memory nodes
>      - the T-Head CSR, CCU clock and memory map headers
>      - SUN20I Kconfig (cache line size, T-Head CMO support)
> 
> 2/10 sunxi: allow the sunxi drivers to be built for sun20i
>      Accept SUN20I next to ARCH_SUNXI for the RAM, clock, pinctrl, GPIO, MMC,
>      reset and watchdog drivers, and keep WATCHDOG_AUTOSTART off for it.
> 
>      Declare SUNXI_GEN_NCAT2 here as well - the ARM sunxi Kconfig is not read
>      by a RISC-V build - and add the MMC base addresses to arch-sun20i/cpu.h
>      so sunxi_mmc.c builds.
> 
> 3/10 board: sun20i: add common support for the D1/D1s boards
>      Add the board code used by all D1/D1s(F133) boards:
> 
>      - TARGET_SUN20I, board init and CPU probing
>      - sunxi eGON/TOC0 SPL header: boot source, FEL mode, SPL size
>      - SPL DRAM probing and the /memory fixup
>      - FIT DT name matching
>      - environment placement for MMC/SPI boot media
>      - the u-boot-sunxi-with-spl.bin image
>      - a MAINTAINERS section for the new board and CPU files
> 
>      CONFIG_ARCH_SUNXI is never set on these RISC-V parts, so extend the SPL
>      image rule in scripts/Makefile.xpl to match TARGET_SUN20I as well.
> 
>      The board code, the devicetree overlay and include/configs/sun20i.h come
>      from Samuel Holland's d1-wip tree [1]. The board code in turn derives from
>      the ARM sunxi board code, so its copyright notices are kept.
> 
>      [1] https://github.com/smaeul/u-boot/tree/d1-wip
> 
> 4/10 sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver
>      Fix readl()/writel() address types for GCC 15+
> 
>      Use typed base address macros and cast remaining register addresses
>      to void __iomem * to satisfy GCC 15's stricter type checking.
> 
>      No functional change.
> 
> 5/10 sunxi: dram: count the banks on address bit 11, not A22
>      The bank test looks for the BA2 alias at address bit 22, but in the mode
>      the probe programs BA2 is bit 11. A four bank part therefore always
>      reports eight banks, turning 64MB into 128MB.
> 
>      On a MangoPi MQ with F133-A the probe now reports 4 banks, 13 rows and 2KB
>      pages - the vendor's dram_para1 = 0xd2. Boot tested on a Lichee RV Dock
>      too, where a D1 with external 512MB DDR3 is detected correctly.
> 
> 6/10 sunxi: dram: no AC remapping on the co-packaged DRAM parts
>      The PHY AC remapping tables compensate for the drive strength of the
>      DRAM chips connected to the SoC. This compensation must be skipped
>      when the DRAM is integrated on-die.
> 
> 7/10 sunxi: dram: let the board set the MR1 mode register
>      The DRAM mode register 1 value belongs to the DRAM part, and the parts in
>      use differ: 0x02 for the DDR2 die co-packaged with the D1s and F133-A,
>      against the 0x42 that the boards with external DDR3 have booted with so
>      far.
> 
>      Expose it next to the other vendor DRAM settings, keeping 0x42 as the
>      default so nothing changes for the existing users.
> 
> 8/10 sunxi: mmc: handle D1 PLL6 clock rate correctly
>      Apply the existing MMC clock /2 compensation to SUN20I,
>      as already done for SUN8I_R528.
> 
> 9/10 configs: add the Lichee RV Dock defconfig
>      Sipeed Lichee RV Dock: D1, 512 MB DDR3.
> 
> 10/10 configs: add the MangoPi MQ D1s(F133) defconfig
>      MangoPi MQ D1s(F133), 64 MB co-packaged DDR2.
> 
> 
>  MAINTAINERS                                   |  10 +
>  arch/riscv/Kconfig                            |  14 +
>  arch/riscv/cpu/sun20i/Kconfig                 |  17 +
>  arch/riscv/cpu/sun20i/Makefile                |   5 +
>  arch/riscv/cpu/sun20i/cache.c                 |  88 ++++
>  arch/riscv/cpu/sun20i/cpu.c                   |  44 ++
>  arch/riscv/cpu/sun20i/dram.c                  |  21 +
>  arch/riscv/dts/sun20i-u-boot.dtsi             |  86 ++++
>  arch/riscv/include/asm/arch-sun20i/clock.h    |  71 +++
>  arch/riscv/include/asm/arch-sun20i/cpu.h      |  22 +
>  .../riscv/include/asm/arch-sun20i/thead_csr.h |  29 ++
>  board/sun20i/Kconfig                          | 173 ++++++++
>  board/sun20i/Makefile                         |   4 +
>  board/sun20i/board.c                          | 309 +++++++++++++
>  board/sun20i/spl.c                            | 142 ++++++
>  configs/lichee_rv_dock_defconfig              |  14 +
>  configs/mangopi_mq_d1s_defconfig              |  20 +
>  drivers/clk/sunxi/Kconfig                     |   2 +-
>  drivers/gpio/Kconfig                          |   2 +-
>  drivers/mmc/Kconfig                           |   2 +-
>  drivers/mmc/sunxi_mmc.c                       |   3 +-
>  drivers/pinctrl/sunxi/Kconfig                 |   2 +-
>  drivers/ram/sunxi/Kconfig                     |   8 +-
>  drivers/ram/sunxi/dram_sun20i_d1.c            | 417 ++++++++++--------
>  drivers/reset/Kconfig                         |   2 +-
>  drivers/watchdog/Kconfig                      |   3 +-
>  include/configs/sun20i.h                      |  11 +
>  scripts/Makefile.xpl                          |   2 +-
>  28 files changed, 1329 insertions(+), 194 deletions(-)
>  create mode 100644 arch/riscv/cpu/sun20i/Kconfig
>  create mode 100644 arch/riscv/cpu/sun20i/Makefile
>  create mode 100644 arch/riscv/cpu/sun20i/cache.c
>  create mode 100644 arch/riscv/cpu/sun20i/cpu.c
>  create mode 100644 arch/riscv/cpu/sun20i/dram.c
>  create mode 100644 arch/riscv/dts/sun20i-u-boot.dtsi
>  create mode 100644 arch/riscv/include/asm/arch-sun20i/clock.h
>  create mode 100644 arch/riscv/include/asm/arch-sun20i/cpu.h
>  create mode 100644 arch/riscv/include/asm/arch-sun20i/thead_csr.h
>  create mode 100644 board/sun20i/Kconfig
>  create mode 100644 board/sun20i/Makefile
>  create mode 100644 board/sun20i/board.c
>  create mode 100644 board/sun20i/spl.c
>  create mode 100644 configs/lichee_rv_dock_defconfig
>  create mode 100644 configs/mangopi_mq_d1s_defconfig
>  create mode 100644 include/configs/sun20i.h
> 
> Cc
> --
> 
>   Tom Rini <trini@konsulko.com>               (U-Boot maintainer)
>   Andre Przywara <andre.przywara@arm.com>     (sunxi custodian)
>   Tim Ouyang <tim609@andestech.com>           (RISC-V)
>   Leo Liang <leo.liang@sifive.com>            (RISC-V)
>   Yao Zi <me@ziyao.cc>                        (RISC-V reviewer)
>   Peng Fan <peng.fan@nxp.com>                 (MMC)
>   Jaehoon Chung <jh80.chung@samsung.com>      (MMC)
>   Lukasz Majewski <lukma@nabladev.com>        (CLOCK)
>   Stefan Roese <stefan.roese@mailbox.org>     (WATCHDOG)
>   Samuel Holland <samuel@sholland.org>        (original d1-wip author)
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support
  2026-11-01 21:04 ` [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support Indrek Kruusa
@ 2026-11-07  9:11   ` Junhui Liu
  2026-11-07 16:13     ` Yao Zi
  2026-11-10 22:00     ` Indrek Kruusa
  0 siblings, 2 replies; 16+ messages in thread
From: Junhui Liu @ 2026-11-07  9:11 UTC (permalink / raw)
  To: Indrek Kruusa, u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini

Hi Indrek,

Thanks for your work. I'm very happy to finally see someone proposing
this work. But for most of the T-Head/XuanTie CPU support, I think it is
better to make it common code instead of keeping it private to sun20i.

On Mon Nov 2, 2026 at 5:04 AM CST, Indrek Kruusa wrote:
> Add the C906 support for the D1/D1s(F133) SoCs:
>
> - T-Head cache operations from the custom cache instructions
> - harts_early_init() programming MXSTATUS, MHCR and MHINT
> - cleanup_before_linux() disabling interrupts and flushing the caches
> - dram_init() from the device tree memory nodes
> - the T-Head CSR, CCU clock and memory map headers
> - SUN20I Kconfig (cache line size, T-Head CMO support)
>
> Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
> ---
>  arch/riscv/Kconfig                            |  1 +
>  arch/riscv/cpu/sun20i/Kconfig                 |  6 ++
>  arch/riscv/cpu/sun20i/Makefile                |  5 ++
>  arch/riscv/cpu/sun20i/cache.c                 | 88 +++++++++++++++++++
>  arch/riscv/cpu/sun20i/cpu.c                   | 44 ++++++++++
>  arch/riscv/cpu/sun20i/dram.c                  | 21 +++++
>  arch/riscv/include/asm/arch-sun20i/clock.h    | 71 +++++++++++++++
>  arch/riscv/include/asm/arch-sun20i/cpu.h      | 18 ++++
>  .../riscv/include/asm/arch-sun20i/thead_csr.h | 29 ++++++
>  9 files changed, 283 insertions(+)
>  create mode 100644 arch/riscv/cpu/sun20i/Kconfig
>  create mode 100644 arch/riscv/cpu/sun20i/Makefile
>  create mode 100644 arch/riscv/cpu/sun20i/cache.c
>  create mode 100644 arch/riscv/cpu/sun20i/cpu.c
>  create mode 100644 arch/riscv/cpu/sun20i/dram.c
>  create mode 100644 arch/riscv/include/asm/arch-sun20i/clock.h
>  create mode 100644 arch/riscv/include/asm/arch-sun20i/cpu.h
>  create mode 100644 arch/riscv/include/asm/arch-sun20i/thead_csr.h
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 386241efd4a..14c8ca817fb 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -144,6 +144,7 @@ source "arch/riscv/cpu/jh7110/Kconfig"
>  source "arch/riscv/cpu/k1/Kconfig"
>  source "arch/riscv/cpu/k3/Kconfig"
>  source "arch/riscv/cpu/k230/Kconfig"
> +source "arch/riscv/cpu/sun20i/Kconfig"
>  source "arch/riscv/cpu/th1520/Kconfig"
>  
>  # architecture-specific options below
> diff --git a/arch/riscv/cpu/sun20i/Kconfig b/arch/riscv/cpu/sun20i/Kconfig
> new file mode 100644
> index 00000000000..7f459518cfe
> --- /dev/null
> +++ b/arch/riscv/cpu/sun20i/Kconfig
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +
> +config SUN20I
> +	bool
> +	select SYS_CACHE_SHIFT_6
> +	select SYS_CACHE_THEAD_CMO if !SYS_DCACHE_OFF
> diff --git a/arch/riscv/cpu/sun20i/Makefile b/arch/riscv/cpu/sun20i/Makefile
> new file mode 100644
> index 00000000000..556aa842ec1
> --- /dev/null
> +++ b/arch/riscv/cpu/sun20i/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +
> +obj-y += cache.o
> +obj-y += cpu.o
> +obj-y += dram.o
> diff --git a/arch/riscv/cpu/sun20i/cache.c b/arch/riscv/cpu/sun20i/cache.c
> new file mode 100644
> index 00000000000..c961eded109
> --- /dev/null
> +++ b/arch/riscv/cpu/sun20i/cache.c
> @@ -0,0 +1,88 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
> + *
> + * T-Head C906 cache operations for the Allwinner D1 (sun20i).
> + */
> +
> +#include <asm/arch/thead_csr.h>
> +#include <asm/cache.h>
> +#include <asm/csr.h>
> +#include <cpu_func.h>
> +#include <linux/bitops.h>
> +
> +/*
> + * T-Head cache maintenance instructions, emitted as raw encodings because the
> + * assembler does not know them: dcache.ciall (write back and invalidate all),
> + * dcache.iall (invalidate all), icache.ipa (invalidate the line holding the
> + * physical address in a0) and sync.i (wait for the operation to complete).
> + * They only decode while MXSTATUS.THEADISAEE is set, which harts_early_init()
> + * does before any of them is used.
> + */
> +#define THEAD_SYNC_I            ".long 0x01a0000b"
> +#define THEAD_DCACHE_CIALL      ".long 0x0030000b"
> +#define THEAD_DCACHE_IALL       ".long 0x0020000b"
> +#define THEAD_ICACHE_IPA_A0     ".long 0x0385000b"
> +
> +static inline void sync_i(void)
> +{
> +	asm volatile (THEAD_SYNC_I ::: "memory");
> +}
> +
> +void flush_dcache_all(void)
> +{
> +	asm volatile (THEAD_DCACHE_CIALL ::: "memory");
> +	sync_i();
> +}
> +
> +void invalidate_dcache_all(void)
> +{
> +	asm volatile (THEAD_DCACHE_IALL ::: "memory");
> +	sync_i();
> +}
> +
> +void invalidate_icache_range(unsigned long start, unsigned long end)
> +{
> +	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
> +
> +	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
> +		asm volatile (THEAD_ICACHE_IPA_A0 :: "r" (addr) : "memory");
> +	sync_i();
> +}

For these cache operations, arch/riscv/lib/thead_cmo.c already contains
the D-cache range operations. The D-cache all operations and I-cache
operations added here are common T-Head/XuanTie CMO operations, so I
think it's better to add them to that common file instead of being
implemented under sun20i.

> +
> +#if CONFIG_IS_ENABLED(RISCV_MMODE)
> +
> +void icache_enable(void)
> +{
> +	invalidate_icache_all();
> +	csr_set(CSR_MHCR, MHCR_IE);
> +}
> +
> +void icache_disable(void)
> +{
> +	csr_clear(CSR_MHCR, MHCR_IE);
> +}
> +
> +int icache_status(void)
> +{
> +	return csr_read(CSR_MHCR) & MHCR_IE;
> +}
> +
> +void dcache_enable(void)
> +{
> +	invalidate_dcache_all();
> +	csr_set(CSR_MHCR, MHCR_DE);
> +}
> +
> +void dcache_disable(void)
> +{
> +	flush_dcache_all();
> +	csr_clear(CSR_MHCR, MHCR_DE);
> +}
> +
> +int dcache_status(void)
> +{
> +	return csr_read(CSR_MHCR) & MHCR_DE;
> +}
> +
> +#endif

For this part, arch/riscv/cpu/th1520/cache.c already has related
functions. Can we extract them into a common file, for example
arch/riscv/lib/thead_cache.c, and provide a THEAD_CACHE config for the
platforms that need it to select?

[...]

> diff --git a/arch/riscv/include/asm/arch-sun20i/thead_csr.h b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
> new file mode 100644
> index 00000000000..4d6e15aab1c
> --- /dev/null
> +++ b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
> + *
> + * T-Head C906 CSR definitions for the Allwinner D1 (sun20i).
> + */
> +
> +#ifndef _ASM_RISCV_ARCH_THEAD_CSR_H
> +#define _ASM_RISCV_ARCH_THEAD_CSR_H
> +
> +#define CSR_MXSTATUS            0x7c0
> +#define CSR_MHCR                0x7c1
> +#define CSR_MHINT               0x7c5
> +
> +#define MXSTATUS_THEADISAEE     BIT(22) /* T-HEAD ISA extensions enable */
> +#define MXSTATUS_MAEE           BIT(21) /* MMU honours the PTE memory type */
> +#define MXSTATUS_MM             BIT(15) /* misaligned access enable */
> +
> +#define MHCR_IE                 BIT(0)  /* icache enable */
> +#define MHCR_DE                 BIT(1)  /* dcache enable */
> +#define MHCR_WA                 BIT(2)  /* dcache write allocate */
> +#define MHCR_RS                 BIT(4)  /* return stack enable */
> +#define MHCR_BPE                BIT(5)  /* branch prediction enable */
> +#define MHCR_BTB_C906           BIT(6)  /* branch target prediction enable */
> +
> +#define MHINT_IPLD              BIT(8)  /* icache prefetch enable */
> +#define MHINT_IWPE              BIT(9)  /* icache way prediction enable */
> +
> +#endif /* _ASM_RISCV_ARCH_THEAD_CSR_H */

A number of these CSR definitions already exist in
arch/riscv/cpu/th1520/spl.c and arch/riscv/cpu/th1520/cache.c. Can the
common register numbers and bitfields be moved into a common header,
such as arch/riscv/include/asm/thead_csr.h, instead of placing them
under arch-sun20i?

-- 
Best regards,
Junhui Liu

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support
  2026-11-07  9:11   ` Junhui Liu
@ 2026-11-07 16:13     ` Yao Zi
  2026-11-10 22:00     ` Indrek Kruusa
  1 sibling, 0 replies; 16+ messages in thread
From: Yao Zi @ 2026-11-07 16:13 UTC (permalink / raw)
  To: Junhui Liu, Indrek Kruusa, u-boot
  Cc: Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini, Hiago De Franco

On Sat, Nov 07, 2026 at 05:11:09PM +0800, Junhui Liu wrote:
> Hi Indrek,
> 
> Thanks for your work. I'm very happy to finally see someone proposing
> this work. But for most of the T-Head/XuanTie CPU support, I think it is
> better to make it common code instead of keeping it private to sun20i.
> 
> On Mon Nov 2, 2026 at 5:04 AM CST, Indrek Kruusa wrote:
> > Add the C906 support for the D1/D1s(F133) SoCs:
> >
> > - T-Head cache operations from the custom cache instructions
> > - harts_early_init() programming MXSTATUS, MHCR and MHINT
> > - cleanup_before_linux() disabling interrupts and flushing the caches
> > - dram_init() from the device tree memory nodes
> > - the T-Head CSR, CCU clock and memory map headers
> > - SUN20I Kconfig (cache line size, T-Head CMO support)
> >
> > Signed-off-by: Indrek Kruusa <indrek.kruusa@gmail.com>
> > ---
> >  arch/riscv/Kconfig                            |  1 +
> >  arch/riscv/cpu/sun20i/Kconfig                 |  6 ++
> >  arch/riscv/cpu/sun20i/Makefile                |  5 ++
> >  arch/riscv/cpu/sun20i/cache.c                 | 88 +++++++++++++++++++
> >  arch/riscv/cpu/sun20i/cpu.c                   | 44 ++++++++++
> >  arch/riscv/cpu/sun20i/dram.c                  | 21 +++++
> >  arch/riscv/include/asm/arch-sun20i/clock.h    | 71 +++++++++++++++
> >  arch/riscv/include/asm/arch-sun20i/cpu.h      | 18 ++++
> >  .../riscv/include/asm/arch-sun20i/thead_csr.h | 29 ++++++
> >  9 files changed, 283 insertions(+)
> >  create mode 100644 arch/riscv/cpu/sun20i/Kconfig
> >  create mode 100644 arch/riscv/cpu/sun20i/Makefile
> >  create mode 100644 arch/riscv/cpu/sun20i/cache.c
> >  create mode 100644 arch/riscv/cpu/sun20i/cpu.c
> >  create mode 100644 arch/riscv/cpu/sun20i/dram.c
> >  create mode 100644 arch/riscv/include/asm/arch-sun20i/clock.h
> >  create mode 100644 arch/riscv/include/asm/arch-sun20i/cpu.h
> >  create mode 100644 arch/riscv/include/asm/arch-sun20i/thead_csr.h

...

> > diff --git a/arch/riscv/cpu/sun20i/cache.c b/arch/riscv/cpu/sun20i/cache.c
> > new file mode 100644
> > index 00000000000..c961eded109
> > --- /dev/null
> > +++ b/arch/riscv/cpu/sun20i/cache.c
> > @@ -0,0 +1,88 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
> > + *
> > + * T-Head C906 cache operations for the Allwinner D1 (sun20i).
> > + */
> > +
> > +#include <asm/arch/thead_csr.h>
> > +#include <asm/cache.h>
> > +#include <asm/csr.h>
> > +#include <cpu_func.h>
> > +#include <linux/bitops.h>
> > +
> > +/*
> > + * T-Head cache maintenance instructions, emitted as raw encodings because the
> > + * assembler does not know them: dcache.ciall (write back and invalidate all),
> > + * dcache.iall (invalidate all), icache.ipa (invalidate the line holding the
> > + * physical address in a0) and sync.i (wait for the operation to complete).
> > + * They only decode while MXSTATUS.THEADISAEE is set, which harts_early_init()
> > + * does before any of them is used.
> > + */
> > +#define THEAD_SYNC_I            ".long 0x01a0000b"
> > +#define THEAD_DCACHE_CIALL      ".long 0x0030000b"
> > +#define THEAD_DCACHE_IALL       ".long 0x0020000b"
> > +#define THEAD_ICACHE_IPA_A0     ".long 0x0385000b"
> > +
> > +static inline void sync_i(void)
> > +{
> > +	asm volatile (THEAD_SYNC_I ::: "memory");
> > +}
> > +
> > +void flush_dcache_all(void)
> > +{
> > +	asm volatile (THEAD_DCACHE_CIALL ::: "memory");
> > +	sync_i();
> > +}
> > +
> > +void invalidate_dcache_all(void)
> > +{
> > +	asm volatile (THEAD_DCACHE_IALL ::: "memory");
> > +	sync_i();
> > +}
> > +
> > +void invalidate_icache_range(unsigned long start, unsigned long end)
> > +{
> > +	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
> > +
> > +	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
> > +		asm volatile (THEAD_ICACHE_IPA_A0 :: "r" (addr) : "memory");
> > +	sync_i();
> > +}
> 
> For these cache operations, arch/riscv/lib/thead_cmo.c already contains
> the D-cache range operations. The D-cache all operations and I-cache
> operations added here are common T-Head/XuanTie CMO operations, so I
> think it's better to add them to that common file instead of being
> implemented under sun20i.

Agree. The only piece we miss in thead_cmo.c should be
flush_dcache_all() and invalidate_dcache_all().

> > +#if CONFIG_IS_ENABLED(RISCV_MMODE)
> > +
> > +void icache_enable(void)
> > +{
> > +	invalidate_icache_all();
> > +	csr_set(CSR_MHCR, MHCR_IE);
> > +}
> > +
> > +void icache_disable(void)
> > +{
> > +	csr_clear(CSR_MHCR, MHCR_IE);
> > +}
> > +
> > +int icache_status(void)
> > +{
> > +	return csr_read(CSR_MHCR) & MHCR_IE;
> > +}
> > +
> > +void dcache_enable(void)
> > +{
> > +	invalidate_dcache_all();
> > +	csr_set(CSR_MHCR, MHCR_DE);
> > +}
> > +
> > +void dcache_disable(void)
> > +{
> > +	flush_dcache_all();
> > +	csr_clear(CSR_MHCR, MHCR_DE);
> > +}
> > +
> > +int dcache_status(void)
> > +{
> > +	return csr_read(CSR_MHCR) & MHCR_DE;
> > +}
> > +
> > +#endif
> 
> For this part, arch/riscv/cpu/th1520/cache.c already has related
> functions. Can we extract them into a common file, for example
> arch/riscv/lib/thead_cache.c, and provide a THEAD_CACHE config for the
> platforms that need it to select?

Agree, too. I've suggested[1] Hiago, who is working on CV1800B support,
to do similar things. Ccing him here so you could coordinate with each
other to avoid duplicated work.

...

> > diff --git a/arch/riscv/include/asm/arch-sun20i/thead_csr.h b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
> > new file mode 100644
> > index 00000000000..4d6e15aab1c
> > --- /dev/null
> > +++ b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
> > @@ -0,0 +1,29 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
> > + *
> > + * T-Head C906 CSR definitions for the Allwinner D1 (sun20i).
> > + */
> > +
> > +#ifndef _ASM_RISCV_ARCH_THEAD_CSR_H
> > +#define _ASM_RISCV_ARCH_THEAD_CSR_H
> > +
> > +#define CSR_MXSTATUS            0x7c0
> > +#define CSR_MHCR                0x7c1
> > +#define CSR_MHINT               0x7c5
> > +
> > +#define MXSTATUS_THEADISAEE     BIT(22) /* T-HEAD ISA extensions enable */
> > +#define MXSTATUS_MAEE           BIT(21) /* MMU honours the PTE memory type */
> > +#define MXSTATUS_MM             BIT(15) /* misaligned access enable */
> > +
> > +#define MHCR_IE                 BIT(0)  /* icache enable */
> > +#define MHCR_DE                 BIT(1)  /* dcache enable */
> > +#define MHCR_WA                 BIT(2)  /* dcache write allocate */
> > +#define MHCR_RS                 BIT(4)  /* return stack enable */
> > +#define MHCR_BPE                BIT(5)  /* branch prediction enable */
> > +#define MHCR_BTB_C906           BIT(6)  /* branch target prediction enable */
> > +
> > +#define MHINT_IPLD              BIT(8)  /* icache prefetch enable */
> > +#define MHINT_IWPE              BIT(9)  /* icache way prediction enable */
> > +
> > +#endif /* _ASM_RISCV_ARCH_THEAD_CSR_H */
> 
> A number of these CSR definitions already exist in
> arch/riscv/cpu/th1520/spl.c and arch/riscv/cpu/th1520/cache.c. Can the
> common register numbers and bitfields be moved into a common header,
> such as arch/riscv/include/asm/thead_csr.h, instead of placing them
> under arch-sun20i?

I'll second it.

> -- 
> Best regards,
> Junhui Liu

-- 
Thanks,
Yao Zi

Meow-mrrp-mrow, I'm a cat.

[1]: https://lore.kernel.org/all/aunnaN0SOzsRBtlG@pie/

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards
  2026-11-06 23:17 ` [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Andre Przywara
@ 2026-11-09 21:44   ` Indrek Kruusa
  0 siblings, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-09 21:44 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Indrek Kruusa, u-boot, Tim Ouyang, Leo Liang, Yao Zi, Peng Fan,
	Jaehoon Chung, Lukasz Majewski, Stefan Roese, Samuel Holland,
	Tom Rini

Hi Andre,

thanks for looking at this.

On Sat, 7 Nov 2026 00:17:35 +0100
Andre Przywara <andre.przywara@arm.com> wrote:

> On Sun,  1 Nov 2026 23:04:39 +0200
> Indrek Kruusa <indrek.kruusa@gmail.com> wrote:
>
> Hi Indrek,
>
> thanks for sending this out.
> This looks surprisingly simple on a first glance.
> I haven't had a detailed look, but wanted to reply with some general
> thoughts.
>
> > Building upon the work of Samuel Holland [1], this series introduces support
>
> I guess you took quite some patches from Samuel? I don't see him being
> the author of any patch, that doesn't sound likely. Please try to
> attribute his work, by keeping this authorship.

This is the trickiest part of the series. None of the patches are direct
copies of Samuel's original commits. For patches 1, 3, 5-7 and 9 I can
easily add a "Based on a patch by" note, with links to the corresponding
commits from which I inherited the ideas. Would that be an acceptable way
to acknowledge his contribution?

> > for the Allwinner D1/D1s(F133) RISC-V SoCs and two development boards:
> >
> > - Sipeed Lichee RV Dock (D1 SoC)
> > - MangoPi MQ (RISC-V version with D1s/F133-A SoC)
> >
> > The main difference from Samuel's work is how the boards are wired into the
>
> I think Samuel also used DM_SPL (which I heavily oppose), looks like
> this is gone as well? I like that, but it seems to be a major
> difference worth mentioning.

No, I've kept DM in SPL as it was. I looked at it again and actually
nothing in the port requires DM in SPL. Should I switch to non-DM?

> > tree. The original design aimed at one cross-architecture configuration which
> > covers ARM sun8i and RISC-V sun20i parts from Allwinner. This series does not
> > do that. The D1/D1s get their own configuration instead:
> >
> >   - arch/riscv/cpu/sun20i/ and board/sun20i/ hold the RISC-V side
> >   - SUN20I is a SoC-family symbol, TARGET_SUN20I the board target
> >   - the shared sunxi drivers accept SUN20I next to ARCH_SUNXI, so they are
> >     shared as before -- only the Kconfig condition changes
> >
> > Keeping the two sides apart has a cost: a few things exist twice.
>
> Mmmh, I need to have a closer look, but am wondering if we can avoid
> those double definitions and integrate both architectures better.
> arch/arm vs. arm/riscv should separate itself naturally, and the
> drivers shouldn't care about the architecture.

I'd be interested to hear your thoughts on how to approach that!

> That's just a hunch, though, I will have a closer look in the next
> weeks, as I am busy with other things.
> Thanks,
> Andre

Thanks,
Indrek

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support
  2026-11-07  9:11   ` Junhui Liu
  2026-11-07 16:13     ` Yao Zi
@ 2026-11-10 22:00     ` Indrek Kruusa
  1 sibling, 0 replies; 16+ messages in thread
From: Indrek Kruusa @ 2026-11-10 22:00 UTC (permalink / raw)
  To: Junhui Liu, u-boot
  Cc: Indrek Kruusa, Andre Przywara, Tim Ouyang, Leo Liang, Yao Zi,
	Peng Fan, Jaehoon Chung, Lukasz Majewski, Stefan Roese,
	Samuel Holland, Tom Rini, Hiago De Franco

Hi Junhui,

thanks for the review!

On Sat, 07 Nov 2026 17:11:09 +0800
Junhui Liu <junhui.liu@pigmoral.tech> wrote:

> Hi Indrek,
>
> Thanks for your work. I'm very happy to finally see someone proposing
> this work.

Thanks, I appreciate that!

> But for most of the T-Head/XuanTie CPU support, I think it is
> better to make it common code instead of keeping it private to sun20i.
>

Agreed.

[...]

> > diff --git a/arch/riscv/cpu/sun20i/cache.c b/arch/riscv/cpu/sun20i/cache.c
> > new file mode 100644
> > index 00000000000..c961eded109
> > --- /dev/null
> > +++ b/arch/riscv/cpu/sun20i/cache.c
> > @@ -0,0 +1,88 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
> > + *
> > + * T-Head C906 cache operations for the Allwinner D1 (sun20i).
> > + */
> > +
> > +#include <asm/arch/thead_csr.h>
> > +#include <asm/cache.h>
> > +#include <asm/csr.h>
> > +#include <cpu_func.h>
> > +#include <linux/bitops.h>
> > +
> > +/*
> > + * T-Head cache maintenance instructions, emitted as raw encodings because the
> > + * assembler does not know them: dcache.ciall (write back and invalidate all),
> > + * dcache.iall (invalidate all), icache.ipa (invalidate the line holding the
> > + * physical address in a0) and sync.i (wait for the operation to complete).
> > + * They only decode while MXSTATUS.THEADISAEE is set, which harts_early_init()
> > + * does before any of them is used.
> > + */
> > +#define THEAD_SYNC_I            ".long 0x01a0000b"
> > +#define THEAD_DCACHE_CIALL      ".long 0x0030000b"
> > +#define THEAD_DCACHE_IALL       ".long 0x0020000b"
> > +#define THEAD_ICACHE_IPA_A0     ".long 0x0385000b"
> > +
> > +static inline void sync_i(void)
> > +{
> > +	asm volatile (THEAD_SYNC_I ::: "memory");
> > +}
> > +
> > +void flush_dcache_all(void)
> > +{
> > +	asm volatile (THEAD_DCACHE_CIALL ::: "memory");
> > +	sync_i();
> > +}
> > +
> > +void invalidate_dcache_all(void)
> > +{
> > +	asm volatile (THEAD_DCACHE_IALL ::: "memory");
> > +	sync_i();
> > +}
> > +
> > +void invalidate_icache_range(unsigned long start, unsigned long end)
> > +{
> > +	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
> > +
> > +	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
> > +		asm volatile (THEAD_ICACHE_IPA_A0 :: "r" (addr) : "memory");
> > +	sync_i();
> > +}
>
> For these cache operations, arch/riscv/lib/thead_cmo.c already contains
> the D-cache range operations. The D-cache all operations and I-cache
> operations added here are common T-Head/XuanTie CMO operations, so I
> think it's better to add them to that common file instead of being
> implemented under sun20i.
>

Actually, that's what I initially had in mind, but I didn't feel comfortable
doing it. Sure, and as Yao also suggested, I'll move flush_dcache_all() and
invalidate_dcache_all() to arch/riscv/lib/thead_cmo.c in the next version.

I still need to investigate invalidate_icache_range() and whether I can
simply rely on the default implementation in arch/riscv/lib/cache.c. If so,
the local cache.c can go away entirely.

> > +
> > +#if CONFIG_IS_ENABLED(RISCV_MMODE)
> > +
> > +void icache_enable(void)
> > +{
> > +	invalidate_icache_all();
> > +	csr_set(CSR_MHCR, MHCR_IE);
> > +}
> > +
> > +void icache_disable(void)
> > +{
> > +	csr_clear(CSR_MHCR, MHCR_IE);
> > +}
> > +
> > +int icache_status(void)
> > +{
> > +	return csr_read(CSR_MHCR) & MHCR_IE;
> > +}
> > +
> > +void dcache_enable(void)
> > +{
> > +	invalidate_dcache_all();
> > +	csr_set(CSR_MHCR, MHCR_DE);
> > +}
> > +
> > +void dcache_disable(void)
> > +{
> > +	flush_dcache_all();
> > +	csr_clear(CSR_MHCR, MHCR_DE);
> > +}
> > +
> > +int dcache_status(void)
> > +{
> > +	return csr_read(CSR_MHCR) & MHCR_DE;
> > +}
> > +
> > +#endif
>
> For this part, arch/riscv/cpu/th1520/cache.c already has related
> functions. Can we extract them into a common file, for example
> arch/riscv/lib/thead_cache.c, and provide a THEAD_CACHE config for the
> platforms that need it to select?
>

I had a look: th1520/cache.c has only the _enable() and _status() half, and
cv1800b has no cache.c at all (it relies on the defaults in
arch/riscv/lib/cache.c).
Yes, having a common thead_cache.c with all six functions and a THEAD_CACHE
symbol would give all three SoCs the same implementation.

I can add the THEAD_CACHE symbol and arch/riscv/lib/thead_cache.c, but I'm
not sure about touching the other SoCs in this series. What do you think? I
can prepare a separate series if that would be a better way to handle this
consistently across all three SoCs.

> [...]
>
> > diff --git a/arch/riscv/include/asm/arch-sun20i/thead_csr.h b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
> > new file mode 100644
> > index 00000000000..4d6e15aab1c
> > --- /dev/null
> > +++ b/arch/riscv/include/asm/arch-sun20i/thead_csr.h
> > @@ -0,0 +1,29 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (C) 2026, Indrek Kruusa <indrek.kruusa@gmail.com>
> > + *
> > + * T-Head C906 CSR definitions for the Allwinner D1 (sun20i).
> > + */
> > +
> > +#ifndef _ASM_RISCV_ARCH_THEAD_CSR_H
> > +#define _ASM_RISCV_ARCH_THEAD_CSR_H
> > +
> > +#define CSR_MXSTATUS            0x7c0
> > +#define CSR_MHCR                0x7c1
> > +#define CSR_MHINT               0x7c5
> > +
> > +#define MXSTATUS_THEADISAEE     BIT(22) /* T-HEAD ISA extensions enable */
> > +#define MXSTATUS_MAEE           BIT(21) /* MMU honours the PTE memory type */
> > +#define MXSTATUS_MM             BIT(15) /* misaligned access enable */
> > +
> > +#define MHCR_IE                 BIT(0)  /* icache enable */
> > +#define MHCR_DE                 BIT(1)  /* dcache enable */
> > +#define MHCR_WA                 BIT(2)  /* dcache write allocate */
> > +#define MHCR_RS                 BIT(4)  /* return stack enable */
> > +#define MHCR_BPE                BIT(5)  /* branch prediction enable */
> > +#define MHCR_BTB_C906           BIT(6)  /* branch target prediction enable */
> > +
> > +#define MHINT_IPLD              BIT(8)  /* icache prefetch enable */
> > +#define MHINT_IWPE              BIT(9)  /* icache way prediction enable */
> > +
> > +#endif /* _ASM_RISCV_ARCH_THEAD_CSR_H */
>
> A number of these CSR definitions already exist in
> arch/riscv/cpu/th1520/spl.c and arch/riscv/cpu/th1520/cache.c. Can the
> common register numbers and bitfields be moved into a common header,
> such as arch/riscv/include/asm/thead_csr.h, instead of placing them
> under arch-sun20i?

Agreed. I'll create arch/riscv/include/asm/thead_csr.h in the next version,
identify the common register definitions and bitfields, and move them there.

Again, I'm not sure I'd want to convert the other SoCs in the same series.
Would a separate series be better?

One thing I should flag while we're on this: my patch 1 defines
`MHINT_IWPE` as `BIT(9)`.
I did some AI-assisted investigation into these fields, and the finding was:
"In the OpenC906 RTL, bit 9 is LPE (its write decode is commented out and
the field is tied to zero), while bit 10 is IWPE."
So, according to this finding, the series as posted never actually enables
I-cache way prediction. That's a bug in my patch, will fix it.

>
> -- 
> Best regards,
> Junhui Liu
>

Thanks,
Indrek

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-11-10 22:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-01 21:04 [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Indrek Kruusa
2026-11-01 21:04 ` [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support Indrek Kruusa
2026-11-07  9:11   ` Junhui Liu
2026-11-07 16:13     ` Yao Zi
2026-11-10 22:00     ` Indrek Kruusa
2026-11-01 21:04 ` [PATCH 02/10] sunxi: allow the sunxi drivers to be built for sun20i Indrek Kruusa
2026-11-01 21:04 ` [PATCH 03/10] board: sun20i: add common support for the D1/D1s boards Indrek Kruusa
2026-11-01 21:04 ` [PATCH 04/10] sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver Indrek Kruusa
2026-11-01 21:04 ` [PATCH 05/10] sunxi: dram: count the banks on address bit 11, not A22 Indrek Kruusa
2026-11-01 21:04 ` [PATCH 06/10] sunxi: dram: no AC remapping on the co-packaged DRAM parts Indrek Kruusa
2026-11-01 21:04 ` [PATCH 07/10] sunxi: dram: let the board set the MR1 mode register Indrek Kruusa
2026-11-01 21:04 ` [PATCH 08/10] sunxi: mmc: handle D1 PLL6 clock rate correctly Indrek Kruusa
2026-11-01 21:04 ` [PATCH 09/10] configs: add the Lichee RV Dock defconfig Indrek Kruusa
2026-11-01 21:04 ` [PATCH 10/10] configs: add the MangoPi MQ D1s(F133) defconfig Indrek Kruusa
2026-11-06 23:17 ` [PATCH 00/10] riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards Andre Przywara
2026-11-09 21:44   ` Indrek Kruusa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox