Skip to contentSkip to conversation

riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards

PATCH In review Indrek Kruusa 4 participants 16 messages Nov 1 – Nov 10

Subsystems (10)
Kbuild GPIO Common clk RISC-V +6 more subsystems
lore
Share & tools
lore
#0 lore raw

cover riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards

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 <[email protected]> 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 <[email protected]>               (U-Boot maintainer)
  Andre Przywara <[email protected]>     (sunxi custodian)
  Tim Ouyang <[email protected]>           (RISC-V)
  Leo Liang <[email protected]>            (RISC-V)
  Yao Zi <[email protected]>                        (RISC-V reviewer)
  Peng Fan <[email protected]>                 (MMC)
  Jaehoon Chung <[email protected]>      (MMC)
  Lukasz Majewski <[email protected]>        (CLOCK)
  Stefan Roese <[email protected]>     (WATCHDOG)
  Samuel Holland <[email protected]>        (original d1-wip author)
Signature · 1 line
2.51.0
#1 lore raw

PATCH 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)

---
 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
arch/riscv/Kconfig +1 -0
index 386241efd4a..14c8ca817fb 100644
@@ -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
arch/riscv/cpu/sun20i/Kconfig new file +6 -0
new file mode 100644
index 00000000000..7f459518cfe
@@ -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
arch/riscv/cpu/sun20i/Makefile new file +5 -0
new file mode 100644
index 00000000000..556aa842ec1
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += cache.o
+obj-y += cpu.o
+obj-y += dram.o
arch/riscv/cpu/sun20i/cache.c new file +88 -0

88 lines not on this page · raw message

arch/riscv/cpu/sun20i/cpu.c new file +44 -0

44 lines not on this page · raw message

arch/riscv/cpu/sun20i/dram.c new file +21 -0
new file mode 100644
index 00000000000..91007c0a3d3
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <[email protected]>
+ */
+
+#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();
+}
arch/riscv/include/asm/arch-sun20i/clock.h new file +71 -0

71 lines not on this page · raw message

arch/riscv/include/asm/arch-sun20i/cpu.h new file +18 -0
new file mode 100644
index 00000000000..d20c0139426
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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 */
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +29 -0
new file mode 100644
index 00000000000..4d6e15aab1c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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 */
Signature · 1 line
2.43.0
#2 lore raw

Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support

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.

Quoted 112 lines · 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)

---
 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
arch/riscv/Kconfig +1 -0
index 386241efd4a..14c8ca817fb 100644
@@ -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
arch/riscv/cpu/sun20i/Kconfig new file +6 -0
new file mode 100644
index 00000000000..7f459518cfe
@@ -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
arch/riscv/cpu/sun20i/Makefile new file +5 -0
new file mode 100644
index 00000000000..556aa842ec1
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += cache.o
+obj-y += cpu.o
+obj-y += dram.o
arch/riscv/cpu/sun20i/cache.c new file +41 -0
new file mode 100644
index 00000000000..c961eded109
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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();

arch/riscv/cpu/sun20i/cache.c line 51

Quoted 10 lines
arch/riscv/cpu/sun20i/cache.c new file +10 -0
+}
+
+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.

Quoted 27 lines
arch/riscv/cpu/sun20i/cache.c new file +27 -0
+
+#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)
+{

arch/riscv/cpu/sun20i/cache.c line 88

Quoted 10 lines
arch/riscv/cpu/sun20i/cache.c new file +10 -0
+	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?

[...]

Quoted 25 lines
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +19 -0
new file mode 100644
index 00000000000..4d6e15aab1c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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 */

arch/riscv/include/asm/arch-sun20i/thead_csr.h line 29

Quoted 10 lines
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +10 -0
+#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?

Signature · 2 lines
Best regards,
Junhui Liu
#3 lore raw

Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support

Quoted 36 lines · Junhui Liu

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.

Quoted 29 lines · 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)

---
 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

...

Quoted 55 lines
Quoted 55 lines
arch/riscv/cpu/sun20i/cache.c new file +49 -0
new file mode 100644
index 00000000000..c961eded109
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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");
Quoted 8 lines

arch/riscv/cpu/sun20i/cache.c line 51

Quoted 2 lines
arch/riscv/cpu/sun20i/cache.c new file +2 -0
+	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().

Quoted 33 lines
Quoted 33 lines
arch/riscv/cpu/sun20i/cache.c new file +33 -0
+#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;
Quoted 8 lines

arch/riscv/cpu/sun20i/cache.c line 88

Quoted 3 lines
arch/riscv/cpu/sun20i/cache.c new file +3 -0
+}
+
+#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.

...

Quoted 33 lines
Quoted 33 lines
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +27 -0
new file mode 100644
index 00000000000..4d6e15aab1c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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 */
Quoted 8 lines

arch/riscv/include/asm/arch-sun20i/thead_csr.h line 29

Quoted 2 lines
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +2 -0
+
+#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.

Quoted 3 lines
Signature · 2 lines
Best regards,
Junhui Liu
Signature · 6 lines
Thanks,
Yao Zi

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

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

Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support

In reply to Junhui Liu

Hi Junhui,

thanks for the review!

Quoted 4 lines · On Sat, 07 Nov 2026 17:11:09 +0800 Junhui Liu <[email protected]> wrote:

Hi Indrek,

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

Thanks, I appreciate that!

Quoted 3 lines

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.

[...]

Quoted 55 lines
Quoted 55 lines
arch/riscv/cpu/sun20i/cache.c new file +49 -0
new file mode 100644
index 00000000000..c961eded109
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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");
Quoted 9 lines

arch/riscv/cpu/sun20i/cache.c line 51

Quoted 2 lines
arch/riscv/cpu/sun20i/cache.c new file +2 -0
+	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.

Quoted 34 lines
Quoted 34 lines
arch/riscv/cpu/sun20i/cache.c new file +34 -0
+
+#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;
Quoted 9 lines

arch/riscv/cpu/sun20i/cache.c line 88

Quoted 3 lines
arch/riscv/cpu/sun20i/cache.c new file +3 -0
+}
+
+#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.

Quoted 35 lines

[...]

Quoted 33 lines
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +27 -0
new file mode 100644
index 00000000000..4d6e15aab1c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026, Indrek Kruusa <[email protected]>
+ *
+ * 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 */
Quoted 8 lines

arch/riscv/include/asm/arch-sun20i/thead_csr.h line 29

Quoted 2 lines
arch/riscv/include/asm/arch-sun20i/thead_csr.h new file +2 -0
+
+#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.

Quoted 5 lines
Signature · 3 lines
-- 
Best regards,
Junhui Liu

Thanks,
Indrek

#5 lore raw

PATCH 2/10 sunxi: allow the sunxi drivers to be built for sun20i

In reply to 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.

---
 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(-)
arch/riscv/cpu/sun20i/Kconfig +11 -0
index 7f459518cfe..1e08317cf12 100644
@@ -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.
arch/riscv/include/asm/arch-sun20i/cpu.h +4 -0
index d20c0139426..c57c58495dc 100644
@@ -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 */
drivers/clk/sunxi/Kconfig +1 -1
index 1c1cc82719c..74ce009bc2d 100644
@@ -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
drivers/gpio/Kconfig +1 -1
index 7f12e39dad8..8b75bacdb38 100644
@@ -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.
drivers/mmc/Kconfig +1 -1
index b3731dfe4a1..2586a28ce02 100644
@@ -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
drivers/pinctrl/sunxi/Kconfig +1 -1
index 54314992299..9400d45990b 100644
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-if ARCH_SUNXI
+if ARCH_SUNXI || SUN20I
 
 config PINCTRL_SUNXI
 	select PINCTRL_FULL
drivers/ram/sunxi/Kconfig +1 -1
index 1775cb0d780..9f2dc4a6e66 100644
@@ -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.
drivers/reset/Kconfig +1 -1
index ad61ebf344a..becbd86d59d 100644
@@ -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
drivers/watchdog/Kconfig +2 -1
index 3c56c541505..ce0cec964ed 100644
@@ -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.
Signature · 1 line
2.43.0
#6 lore raw

PATCH 3/10 board: sun20i: add common support for the D1/D1s boards

In reply to 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

---
 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
MAINTAINERS +8 -0
index 95b1f3b5ab3..587d4a30377 100644
@@ -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 <[email protected]>
+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 <[email protected]>
 R:	Heinrich Schuchardt <[email protected]>
arch/riscv/Kconfig +13 -0
index 14c8ca817fb..02304d9f66c 100644
@@ -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"
 
arch/riscv/dts/sun20i-u-boot.dtsi new file +86 -0

86 lines not on this page · raw message

board/sun20i/Kconfig new file +173 -0

173 lines not on this page · raw message

board/sun20i/Makefile new file +4 -0
new file mode 100644
index 00000000000..af4006368b2
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y	+= board.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
board/sun20i/board.c new file +309 -0

309 lines not on this page · raw message

board/sun20i/spl.c new file +142 -0

142 lines not on this page · raw message

include/configs/sun20i.h new file +11 -0
new file mode 100644
index 00000000000..e8ef1b6c4ac
@@ -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 */
scripts/Makefile.xpl +1 -1
index 77746ec07cd..33b7aac61b4 100644
@@ -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
Signature · 1 line
2.43.0
#7 lore raw

PATCH 4/10 sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver

In reply to 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.

---
 drivers/ram/sunxi/dram_sun20i_d1.c | 383 ++++++++++++++++-------------
 1 file changed, 209 insertions(+), 174 deletions(-)
drivers/ram/sunxi/dram_sun20i_d1.c +209 -174
index 79cf0a51e47..68697fb2fa9 100644
@@ -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;
 	}
Signature · 1 line
2.43.0
#8 lore raw

PATCH 5/10 sunxi: dram: count the banks on address bit 11, not A22

In reply to 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.

---
 drivers/ram/sunxi/dram_sun20i_d1.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/ram/sunxi/dram_sun20i_d1.c +16 -9
index 68697fb2fa9..f098329e891 100644
@@ -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 */
Signature · 1 line
2.43.0
#9 lore raw

PATCH 6/10 sunxi: dram: no AC remapping on the co-packaged DRAM parts

In reply to 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.

---
 drivers/ram/sunxi/dram_sun20i_d1.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/ram/sunxi/dram_sun20i_d1.c +7 -2
index f098329e891..2d81e58071c 100644
@@ -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) {
Signature · 1 line
2.43.0
#10 lore raw

PATCH 7/10 sunxi: dram: let the board set the MR1 mode register

In reply to 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.

---
 drivers/ram/sunxi/Kconfig          | 6 ++++++
 drivers/ram/sunxi/dram_sun20i_d1.c | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)
drivers/ram/sunxi/Kconfig +6 -0
index 9f2dc4a6e66..9b0cbca8083 100644
@@ -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
drivers/ram/sunxi/dram_sun20i_d1.c +1 -1
index 2d81e58071c..b8aef9707cc 100644
@@ -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,
Signature · 1 line
2.43.0
#11 lore raw

PATCH 8/10 sunxi: mmc: handle D1 PLL6 clock rate correctly

In reply to Indrek Kruusa

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

---
 drivers/mmc/sunxi_mmc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/mmc/sunxi_mmc.c +2 -1
index 84f4e4c2198..c5a93ebbc80 100644
@@ -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;
 
 		/*
Signature · 1 line
2.43.0
#12 lore raw

PATCH 9/10 configs: add the Lichee RV Dock defconfig

In reply to Indrek Kruusa

Sipeed Lichee RV Dock: D1, 512 MB DDR3.

---
 MAINTAINERS                      |  1 +
 configs/lichee_rv_dock_defconfig | 14 ++++++++++++++
 2 files changed, 15 insertions(+)
 create mode 100644 configs/lichee_rv_dock_defconfig
MAINTAINERS +1 -0
index 587d4a30377..6618000f168 100644
@@ -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
configs/lichee_rv_dock_defconfig new file +14 -0
new file mode 100644
index 00000000000..a4c9821cfa4
@@ -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
Signature · 1 line
2.43.0
#13 lore raw

PATCH 10/10 configs: add the MangoPi MQ D1s(F133) defconfig

In reply to Indrek Kruusa

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

---
 MAINTAINERS                      |  1 +
 configs/mangopi_mq_d1s_defconfig | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)
 create mode 100644 configs/mangopi_mq_d1s_defconfig
MAINTAINERS +1 -0
index 6618000f168..4cca82da801 100644
@@ -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
configs/mangopi_mq_d1s_defconfig new file +20 -0
new file mode 100644
index 00000000000..689f661ee89
@@ -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
Signature · 1 line
2.43.0
#14 lore raw
In reply to Indrek Kruusa

On Sun, 1 Nov 2026 23:04:39 +0200
Indrek Kruusa <[email protected]> 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.

Quoted 1 line

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.

Quoted 6 lines

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.

Quoted 10 lines

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

Quoted 174 lines

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 <[email protected]> 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 <[email protected]>               (U-Boot maintainer)
  Andre Przywara <[email protected]>     (sunxi custodian)
  Tim Ouyang <[email protected]>           (RISC-V)
  Leo Liang <[email protected]>            (RISC-V)
  Yao Zi <[email protected]>                        (RISC-V reviewer)
  Peng Fan <[email protected]>                 (MMC)
  Jaehoon Chung <[email protected]>      (MMC)
  Lukasz Majewski <[email protected]>        (CLOCK)
  Stefan Roese <[email protected]>     (WATCHDOG)
  Samuel Holland <[email protected]>        (original d1-wip author)
#15 lore raw

Hi Andre,

thanks for looking at this.

Quoted 10 lines · On Sat, 7 Nov 2026 00:17:35 +0100 Andre Przywara <[email protected]> wrote:

On Sun, 1 Nov 2026 23:04:39 +0200
Indrek Kruusa <[email protected]> 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.

Quoted 5 lines
Quoted 1 line

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?

Quoted 10 lines
Quoted 6 lines

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?

Quoted 9 lines
Quoted 9 lines

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

Quoted 6 lines
Quoted 1 line

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!

Quoted 4 lines

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