riscv: sun20i: add support for the Allwinner D1/D1s(F133) SoCs and boards
Subsystems (10)
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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
- SUN20IKconfig(cache line size, T-Head CMO support)Signed-off-by Indrek Kruusa <[email protected]>--- 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.harch/riscv/Kconfig +1
-0@@ -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 belowarch/riscv/cpu/sun20i/Kconfig new file +6
-0@@ -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_OFFarch/riscv/cpu/sun20i/Makefile new file +5
-0@@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += cache.o +obj-y += cpu.o +obj-y += dram.oarch/riscv/cpu/sun20i/cache.c new file +41
-0@@ -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@@ -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
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
- SUN20IKconfig(cache line size, T-Head CMO support)Signed-off-by Indrek Kruusa <[email protected]>--- 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@@ -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.calready 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.calready has related functions. Can we extract them into a common file, for examplearch/riscv/lib/thead_cache.c, and provide aTHEAD_CACHEconfig 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@@ -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.candarch/riscv/cpu/th1520/cache.c. Can the common register numbers and bitfields be moved into a common header, such asarch/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/
Re: [PATCH 01/10] riscv: cpu: add Allwinner D1/D1s(F133) CPU support
In reply to Junhui LiuHi 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@@ -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.calready 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.calready has related functions. Can we extract them into a common file, for examplearch/riscv/lib/thead_cache.c, and provide aTHEAD_CACHEconfig 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@@ -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.candarch/riscv/cpu/th1520/cache.c. Can the common register numbers and bitfields be moved into a common header, such asarch/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
PATCH 2/10 sunxi: allow the sunxi drivers to be built for sun20i
In reply to Indrek KruusaAccept 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 3/10 board: sun20i: add common support for the D1/D1s boards
In reply to Indrek KruusaAdd 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 4/10 sunxi: dram: fix integer-pointer conversions in the D1 DRAM driver
In reply to Indrek KruusaFix 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
@@ -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
PATCH 5/10 sunxi: dram: count the banks on address bit 11, not A22
In reply to Indrek KruusaThe 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
@@ -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
PATCH 6/10 sunxi: dram: no AC remapping on the co-packaged DRAM parts
In reply to Indrek KruusaThe 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
@@ -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
PATCH 7/10 sunxi: dram: let the board set the MR1 mode register
In reply to Indrek KruusaThe 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
@@ -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
@@ -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
PATCH 8/10 sunxi: mmc: handle D1 PLL6 clock rate correctly
In reply to Indrek KruusaApply 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
@@ -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
PATCH 9/10 configs: add the Lichee RV Dock defconfig
In reply to Indrek KruusaSipeed 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
@@ -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
@@ -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
PATCH 10/10 configs: add the MangoPi MQ D1s(F133) defconfig
In reply to Indrek KruusaMangoPi 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
@@ -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
@@ -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
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_SUN20Ithe board target
- the shared sunxi drivers accept SUN20I next toARCH_SUNXI, so they are shared as before -- only theKconfigcondition changesKeeping 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_NCAT2is declared in both arch trees, because the shared drivers test it and noKconfigfile 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 ofboard/sunxi/board.care 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/OSside.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 commit70f51e1e2ea5("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
- SUN20IKconfig(cache line size, T-Head CMO support)2/10 sunxi: allow the sunxi drivers to be built for sun20i
Accept SUN20I next toARCH_SUNXIfor the RAM, clock, pinctrl, GPIO, MMC, reset and watchdog drivers, and keepWATCHDOG_AUTOSTARToff for it.Declare
SUNXI_GEN_NCAT2here as well - the ARM sunxiKconfigis not read by a RISC-V build - and add the MMC base addresses toarch-sun20i/cpu.hsosunxi_mmc.cbuilds.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
- aMAINTAINERSsection for the new board and CPU files
CONFIG_ARCH_SUNXIis never set on these RISC-V parts, so extend the SPL image rule inscripts/Makefile.xplto matchTARGET_SUN20Ias well.The board code, the devicetree overlay and
include/configs/sun20i.hcome 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 forSUN8I_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.hCc
--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)
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_SUN20Ithe board target
- the shared sunxi drivers accept SUN20I next toARCH_SUNXI, so they are shared as before -- only theKconfigcondition 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/armvs. 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