[RFC PATCH 00/13] Add support for Allwinner R329

This patchset adds Allwinner R329 support to U-Boot.
First, some code refactors happen for SoCs w/o SCP/MMC2.
Then the basical support for R329 come as several parts (memory map, clocks, pinmux, DRAM, final Kconfig option).
Then, as the RFC part of this patchset, some device tree related changes.
Finally it comes the defconfig file for a R329 board, Sipeed Maix IIA Dock.
This patchset is RFC mainly because of the DT-related part, as no DT binding is mainlined in Linux now (it's still WIP). All other patches are ready for being reviewed and, if proper, merged.
Icenowy Zheng (13): sunxi: decide the inclusion of SCP by SCP_ADDR existence sunxi: only include alias for eMMC when mmc2 used mmc: sunxi: conditionally include MMC2 initialization code sunxi: add memory addresses for R329 SoC sunxi: add support for R329 clocks sunxi: add support for basical pinmux setup on R329 sunxi: add support for R329 DRAM controller sunxi: add Kconfig option for R329 sunxi: sync R329 CCU binding headers from internal WIP kernel tree clk: sunxi: add support for R329 in sunxi DM clock driver mmc: sunxi: add support for R329 MMC controller sunxi: sync R329 DTs from internal WIP kernel tree sunxi: add support for Sipeed Maix IIA Dock board
arch/arm/cpu/armv8/fel_utils.S | 2 +- arch/arm/dts/Makefile | 2 + arch/arm/dts/sun50i-r329-maix-iia-dock.dts | 36 ++ arch/arm/dts/sun50i-r329-maix-iia.dtsi | 45 +++ arch/arm/dts/sun50i-r329.dtsi | 225 +++++++++++ arch/arm/dts/sunxi-u-boot.dtsi | 8 +- arch/arm/include/asm/arch-sunxi/boot0.h | 4 +- .../include/asm/arch-sunxi/clock_sun50i_h6.h | 17 + arch/arm/include/asm/arch-sunxi/cpu.h | 3 + .../include/asm/arch-sunxi/cpu_sun50i_r329.h | 58 +++ arch/arm/include/asm/arch-sunxi/dram.h | 2 + .../include/asm/arch-sunxi/dram_sun50i_r329.h | 232 +++++++++++ arch/arm/include/asm/arch-sunxi/gpio.h | 3 + arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 33 ++ arch/arm/mach-sunxi/Kconfig | 37 +- arch/arm/mach-sunxi/Makefile | 2 + arch/arm/mach-sunxi/board.c | 4 + arch/arm/mach-sunxi/clock_sun50i_h6.c | 49 ++- arch/arm/mach-sunxi/cpu_info.c | 2 + arch/arm/mach-sunxi/dram_sun50i_r329.c | 377 ++++++++++++++++++ arch/arm/mach-sunxi/dram_timings/Makefile | 1 + arch/arm/mach-sunxi/dram_timings/ddr3_r329.c | 89 +++++ board/sunxi/MAINTAINERS | 5 + board/sunxi/board.c | 20 + common/spl/Kconfig | 1 + configs/sipeed_maix_iia_dock_defconfig | 8 + drivers/clk/sunxi/Kconfig | 7 + drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_r329.c | 94 +++++ drivers/mmc/sunxi_mmc.c | 3 + include/configs/sunxi-common.h | 3 + include/dt-bindings/clock/sun50i-r329-ccu.h | 73 ++++ include/dt-bindings/clock/sun50i-r329-r-ccu.h | 32 ++ include/dt-bindings/reset/sun50i-r329-ccu.h | 45 +++ include/dt-bindings/reset/sun50i-r329-r-ccu.h | 23 ++ 35 files changed, 1535 insertions(+), 11 deletions(-) create mode 100644 arch/arm/dts/sun50i-r329-maix-iia-dock.dts create mode 100644 arch/arm/dts/sun50i-r329-maix-iia.dtsi create mode 100644 arch/arm/dts/sun50i-r329.dtsi create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_r329.h create mode 100644 arch/arm/mach-sunxi/dram_sun50i_r329.c create mode 100644 arch/arm/mach-sunxi/dram_timings/ddr3_r329.c create mode 100644 configs/sipeed_maix_iia_dock_defconfig create mode 100644 drivers/clk/sunxi/clk_r329.c create mode 100644 include/dt-bindings/clock/sun50i-r329-ccu.h create mode 100644 include/dt-bindings/clock/sun50i-r329-r-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-r329-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-r329-r-ccu.h

There are more Allwinner SoCs that do not have a SCP now.
When there's no SCP_ADDR macro defined, we can assume there's no SCP available.
Drop the scp part of FIT description when SCP_ADDR does not exist.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/dts/sunxi-u-boot.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index 06da009fa2..4a6ed3a7dd 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -64,7 +64,7 @@ }; };
-#ifndef CONFIG_MACH_SUN50I_H616 +#ifdef SCP_ADDR scp { description = "SCP firmware"; type = "firmware"; @@ -92,7 +92,7 @@ @config-SEQ { description = "NAME"; firmware = "atf"; -#ifdef CONFIG_MACH_SUN50I_H616 +#ifndef SCP_ADDR loadables = "uboot"; #else loadables = "scp", "uboot";

On Thu, 22 Jul 2021 14:30:03 +0800 Icenowy Zheng icenowy@sipeed.com wrote:
There are more Allwinner SoCs that do not have a SCP now.
When there's no SCP_ADDR macro defined, we can assume there's no SCP available.
Drop the scp part of FIT description when SCP_ADDR does not exist.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
I like that one, unless someone screams, I will take ASAP.
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre
arch/arm/dts/sunxi-u-boot.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index 06da009fa2..4a6ed3a7dd 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -64,7 +64,7 @@ }; };
-#ifndef CONFIG_MACH_SUN50I_H616 +#ifdef SCP_ADDR scp { description = "SCP firmware"; type = "firmware"; @@ -92,7 +92,7 @@ @config-SEQ { description = "NAME"; firmware = "atf"; -#ifdef CONFIG_MACH_SUN50I_H616 +#ifndef SCP_ADDR loadables = "uboot"; #else loadables = "scp", "uboot";

Some Allwinner SoCs (e.g. R329) doesn't have a MMC2 controller at all, and on boards that we do not utilize MMC2, the alias for it is just useless.
Only include the alias when we specify CONFIG_MMC_SUNXI_EXTRA_SLOT to 2.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/dts/sunxi-u-boot.dtsi | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index 4a6ed3a7dd..b7244c1112 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -13,7 +13,9 @@ / { aliases { mmc0 = &mmc0; +#if CONFIG_MMC_SUNXI_EXTRA_SLOT == 2 mmc1 = &mmc2; +#endif };
binman: binman {

On Thu, 22 Jul 2021 14:30:04 +0800 Icenowy Zheng icenowy@sipeed.com wrote:
Some Allwinner SoCs (e.g. R329) doesn't have a MMC2 controller at all, and on boards that we do not utilize MMC2, the alias for it is just useless.
Only include the alias when we specify CONFIG_MMC_SUNXI_EXTRA_SLOT to 2.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
Meh, not a friend of #ifdefs everywhere, but ideally we get rid of this one day anyway, and it's in U-Boot DT "overlay" only, so:
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre
arch/arm/dts/sunxi-u-boot.dtsi | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index 4a6ed3a7dd..b7244c1112 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -13,7 +13,9 @@ / { aliases { mmc0 = &mmc0; +#if CONFIG_MMC_SUNXI_EXTRA_SLOT == 2 mmc1 = &mmc2; +#endif };
binman: binman {

Allwinner R329 has no MMC2.
Only include the code of MMC2 if the base address of it is defined.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- drivers/mmc/sunxi_mmc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 178b8cf106..6b809c001f 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -73,10 +73,12 @@ static int mmc_resource_init(int sdc_no) priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; priv->mclkreg = &ccm->sd1_clk_cfg; break; +#ifdef SUNXI_MMC2_BASE case 2: priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; priv->mclkreg = &ccm->sd2_clk_cfg; break; +#endif #ifdef SUNXI_MMC3_BASE case 3: priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;

On Thu, 22 Jul 2021 14:30:05 +0800 Icenowy Zheng icenowy@sipeed.com wrote:
Hi Icenowy,
Allwinner R329 has no MMC2.
Only include the code of MMC2 if the base address of it is defined.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
One day (TM) we will hopefully get somehow rid of those #ifdefs somehow, but until then it looks OK.
Reviewed-by: Andre Przywara andre.przywara@arm.com
Thanks! Andre
drivers/mmc/sunxi_mmc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 178b8cf106..6b809c001f 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -73,10 +73,12 @@ static int mmc_resource_init(int sdc_no) priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; priv->mclkreg = &ccm->sd1_clk_cfg; break; +#ifdef SUNXI_MMC2_BASE case 2: priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; priv->mclkreg = &ccm->sd2_clk_cfg; break; +#endif #ifdef SUNXI_MMC3_BASE case 3: priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;

Allwinner R329 SoC has a different memory map with previous post-H6 SoCs.
Add the memory map to a dedicated header file, fill everywhere that uses a hardcoded MMIO address and specify the SPL/ATF load address.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/cpu/armv8/fel_utils.S | 2 +- arch/arm/dts/sunxi-u-boot.dtsi | 2 + arch/arm/include/asm/arch-sunxi/boot0.h | 4 +- .../include/asm/arch-sunxi/clock_sun50i_h6.h | 17 ++++++ arch/arm/include/asm/arch-sunxi/cpu.h | 2 + .../include/asm/arch-sunxi/cpu_sun50i_r329.h | 58 +++++++++++++++++++ arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 33 +++++++++++ include/configs/sunxi-common.h | 3 + 8 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h
diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S index 7def44ad1d..aa16d79df9 100644 --- a/arch/arm/cpu/armv8/fel_utils.S +++ b/arch/arm/cpu/armv8/fel_utils.S @@ -40,7 +40,7 @@ ENTRY(return_to_fel) str w2, [x1]
ldr x0, =0xfa50392f // CPU hotplug magic -#ifdef CONFIG_MACH_SUN50I_H616 +#if defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_R329) ldr x2, =(SUNXI_R_CPUCFG_BASE + 0x1c0) str w0, [x2], #0x4 #elif CONFIG_MACH_SUN50I_H6 diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index b7244c1112..9bb6fffeb4 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -5,6 +5,8 @@ #define SCP_ADDR 0x114000 #elif defined(CONFIG_MACH_SUN50I_H616) #define BL31_ADDR 0x40000000 +#elif defined(CONFIG_MACH_SUN50I_R329) +#define BL31_ADDR 0x124000 #else #define BL31_ADDR 0x44000 #define SCP_ADDR 0x50000 diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h index e8e8e38f05..a791c7c403 100644 --- a/arch/arm/include/asm/arch-sunxi/boot0.h +++ b/arch/arm/include/asm/arch-sunxi/boot0.h @@ -39,7 +39,9 @@ .word 0xf57ff06f // isb sy .word 0xe320f003 // wfi .word 0xeafffffd // b @wfi -#ifndef CONFIG_SUN50I_GEN_H6 +#if defined(CONFIG_MACH_SUN50I_R329) + .word 0x08100040 // writeable RVBAR mapping address +#elif !defined(CONFIG_SUN50I_GEN_H6) .word 0x017000a0 // writeable RVBAR mapping address #else .word 0x09010040 // writeable RVBAR mapping address diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index 37df4410ea..6c3b8ea351 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -250,10 +250,19 @@ struct sunxi_ccm_reg { #define CCM_PLL6_LOCK BIT(28) #define CCM_PLL6_CTRL_N_SHIFT 8 #define CCM_PLL6_CTRL_N_MASK (0xff << CCM_PLL6_CTRL_N_SHIFT) +#ifndef CONFIG_MACH_SUN50I_R329 #define CCM_PLL6_CTRL_DIV1_SHIFT 0 #define CCM_PLL6_CTRL_DIV1_MASK (0x1 << CCM_PLL6_CTRL_DIV1_SHIFT) #define CCM_PLL6_CTRL_DIV2_SHIFT 1 #define CCM_PLL6_CTRL_DIV2_MASK (0x1 << CCM_PLL6_CTRL_DIV2_SHIFT) +#else +#define CCM_PLL6_CTRL_M_SHIFT 1 +#define CCM_PLL6_CTRL_M_MASK (0x1 << CCM_PLL6_CTRL_DIV2_SHIFT) +#define CCM_PLL6_CTRL_DIV1_SHIFT 16 +#define CCM_PLL6_CTRL_DIV1_MASK (0x7 << CCM_PLL6_CTRL_DIV1_SHIFT) +#define CCM_PLL6_CTRL_DIV2_SHIFT 20 +#define CCM_PLL6_CTRL_DIV2_MASK (0x7 << CCM_PLL6_CTRL_DIV2_SHIFT) +#endif
/* cpu_axi bit field*/ #define CCM_CPU_AXI_MUX_MASK (0x3 << 24) @@ -285,6 +294,14 @@ struct sunxi_ccm_reg {
/* apb1 bit field */ #define CCM_APB1_DEFAULT 0x03000102 +#elif CONFIG_MACH_SUN50I_R329 +#define CCM_PLL6_DEFAULT 0xa8216300 + +/* ahb bit field */ +#define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000002 + +/* apb1 bit field */ +#define CCM_APB1_DEFAULT 0x02000001 #endif
/* apb2 bit field */ diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h index b08f202374..20d04cac74 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu.h +++ b/arch/arm/include/asm/arch-sunxi/cpu.h @@ -8,6 +8,8 @@
#if defined(CONFIG_MACH_SUN9I) #include <asm/arch/cpu_sun9i.h> +#elif defined(CONFIG_MACH_SUN50I_R329) +#include <asm/arch/cpu_sun50i_r329.h> #elif defined(CONFIG_SUN50I_GEN_H6) #include <asm/arch/cpu_sun50i_h6.h> #else diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h new file mode 100644 index 0000000000..3d2237a59f --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2021 Sipeed + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SUNXI_CPU_SUN50I_H6_H +#define _SUNXI_CPU_SUN50I_H6_H + +#define SUNXI_SRAM_A1_BASE 0x00020000 +#define SUNXI_SRAM_A2_BASE 0x00100000 + +#define SUNXI_TIMER_BASE 0x02000000 +#define SUNXI_PIO_BASE 0x02000400 +#define SUNXI_CCM_BASE 0x02001000 + +#define SUNXI_UART0_BASE 0x02500000 +#define SUNXI_UART1_BASE 0x02500400 +#define SUNXI_UART2_BASE 0x02500800 +#define SUNXI_UART3_BASE 0x02500C00 +#define SUNXI_TWI0_BASE 0x02502000 +#define SUNXI_TWI1_BASE 0x02502400 + +#define SUNXI_SRAMC_BASE 0x03000000 +#define SUNXI_DMA_BASE 0x03002000 +/* SID address space starts at 0x03006000, but e-fuse is at offset 0x200 */ +#define SUNXI_SIDC_BASE 0x03006000 +#define SUNXI_SID_BASE 0x03006200 + +#define SUNXI_GIC400_BASE 0x03020000 +#define SUNXI_SS_BASE 0x03040000 +#define SUNXI_DRAM_COM_BASE 0x03102000 +#define SUNXI_DRAM_CTL0_BASE 0x03103000 + +#define SUNXI_NFC_BASE 0x04011000 +#define SUNXI_MMC0_BASE 0x04020000 +#define SUNXI_MMC1_BASE 0x04021000 +#define SUNXI_SPI0_BASE 0x04025000 +#define SUNXI_SPI1_BASE 0x04026000 +#define SUNXI_USB0_BASE 0x04100000 +#define SUNXI_USB1_BASE 0x04201000 +#define SUNXI_GMAC_BASE 0x04500000 + +#define SUNXI_R_CPUCFG_BASE 0x07000400 +#define SUNXI_PRCM_BASE 0x07010000 +#define SUNXI_R_WDOG_BASE 0x07020400 +#define SUNXI_R_PIO_BASE 0x07022000 +#define SUNXI_R_UART_BASE 0x07080000 +#define SUNXI_R_TWI_BASE 0x07081400 +#define SUNXI_RTC_BASE 0x07090000 + +#ifndef __ASSEMBLY__ +void sunxi_board_init(void); +void sunxi_reset(void); +int sunxi_get_sid(unsigned int *sid); +#endif + +#endif /* _SUNXI_CPU_SUN9I_H */ diff --git a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h index 5f636e8384..1aba5f0122 100644 --- a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h +++ b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h @@ -37,8 +37,41 @@ struct sunxi_prcm_reg { u32 w1_gate_reset; /* 0x1ec */ u8 res10[0x1c]; /* 0x1f0 */ u32 rtc_gate_reset; /* 0x20c */ +#ifdef CONFIG_MACH_SUN50I_R329 + u8 res11[0xdf0]; /* 0x210 */ + + u32 pll1_cfg; /* 0x1000 pll1 (cpux) control */ + u8 reserved_0x1004[0xc]; + u32 pll6_cfg; /* 0x1010 pll6 (periph) control */ + u8 reserved_0x1014[0xc]; + u32 pll2_cfg; /* 0x1020 pll2 (audio) control */ + u8 reserved_0x1024[0xc]; + u32 pll_audio1_cfg; /* 0x1030 pll audio1 control */ + u8 reserved_0x1034[0xdc]; + u32 pll6_pat0; /* 0x1110 pll6 (periph) pattern0 */ + u32 pll6_pat1; /* 0x1114 pll6 (periph) pattern1 */ + u8 reserved_0x1118[0x8]; + u32 pll2_pat0; /* 0x1120 pll2 (audio) pattern0 */ + u32 pll2_pat1; /* 0x1120 pll2 (audio) pattern1 */ + u8 reserved_0x1128[0x8]; + u32 pll_audio1_pat0; /* 0x1130 pll audio1 pattern0 */ + u32 pll_audio1_pat1; /* 0x1130 pll audio1 pattern1 */ + u8 reserved_0x1138[0x1c8]; + u32 pll1_bias; /* 0x1300 pll1 (cpux) bias */ + u8 reserved_0x1304[0xc]; + u32 pll6_bias; /* 0x1310 pll6 (periph) bias */ + u8 reserved_0x1314[0xc]; + u32 pll2_bias; /* 0x1320 pll6 (periph0) bias */ + u8 reserved_0x1324[0xc]; + u32 pll_audio1_bias; /* 0x1330 pll audio1 bias */ + u8 reserved_0x1334[0xcc]; + u32 pll1_tun; /* 0x1400 pll1 (cpux) tunning */ +#endif }; check_member(sunxi_prcm_reg, rtc_gate_reset, 0x20c); +#ifdef CONFIG_MACH_SUN50I_R329 +check_member(sunxi_prcm_reg, pll1_tun, 0x1400); +#endif
#define PRCM_TWI_GATE (1 << 0) #define PRCM_TWI_RESET (1 << 16) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 9e37e99684..a114c1addc 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -181,6 +181,9 @@ /* end of SRAM A2 on H6 for now */ #define LOW_LEVEL_SRAM_STACK 0x00118000 #endif +#elif CONFIG_SUNXI_SRAM_ADDRESS == 0x100000 +#define CONFIG_SPL_MAX_SIZE 0x7fa0 /* 32 KiB */ +#define LOW_LEVEL_SRAM_STACK 0x00120000 /* 64 KiB inside SRAM A2 */ #else #define CONFIG_SPL_MAX_SIZE 0x5fa0 /* 24KB on sun4i/sun7i */ #define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
Allwinner R329 SoC has a different memory map with previous post-H6 SoCs.
Add the memory map to a dedicated header file, fill everywhere that uses a hardcoded MMIO address and specify the SPL/ATF load address.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
arch/arm/cpu/armv8/fel_utils.S | 2 +- arch/arm/dts/sunxi-u-boot.dtsi | 2 + arch/arm/include/asm/arch-sunxi/boot0.h | 4 +- .../include/asm/arch-sunxi/clock_sun50i_h6.h | 17 ++++++ arch/arm/include/asm/arch-sunxi/cpu.h | 2 + .../include/asm/arch-sunxi/cpu_sun50i_r329.h | 58 +++++++++++++++++++ arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 33 +++++++++++ include/configs/sunxi-common.h | 3 + 8 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h
diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S index 7def44ad1d..aa16d79df9 100644 --- a/arch/arm/cpu/armv8/fel_utils.S +++ b/arch/arm/cpu/armv8/fel_utils.S @@ -40,7 +40,7 @@ ENTRY(return_to_fel) str w2, [x1]
ldr x0, =0xfa50392f // CPU hotplug magic -#ifdef CONFIG_MACH_SUN50I_H616 +#if defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_R329) ldr x2, =(SUNXI_R_CPUCFG_BASE + 0x1c0) str w0, [x2], #0x4 #elif CONFIG_MACH_SUN50I_H6 diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index b7244c1112..9bb6fffeb4 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -5,6 +5,8 @@ #define SCP_ADDR 0x114000 #elif defined(CONFIG_MACH_SUN50I_H616) #define BL31_ADDR 0x40000000 +#elif defined(CONFIG_MACH_SUN50I_R329) +#define BL31_ADDR 0x124000
This was changed to 0x00110000 while upstreaming TF-A support. (I see you already updated this in your branch.)
#else #define BL31_ADDR 0x44000 #define SCP_ADDR 0x50000 diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h index e8e8e38f05..a791c7c403 100644 --- a/arch/arm/include/asm/arch-sunxi/boot0.h +++ b/arch/arm/include/asm/arch-sunxi/boot0.h @@ -39,7 +39,9 @@ .word 0xf57ff06f // isb sy .word 0xe320f003 // wfi .word 0xeafffffd // b @wfi -#ifndef CONFIG_SUN50I_GEN_H6 +#if defined(CONFIG_MACH_SUN50I_R329)
- .word 0x08100040 // writeable RVBAR mapping address
+#elif !defined(CONFIG_SUN50I_GEN_H6) .word 0x017000a0 // writeable RVBAR mapping address #else .word 0x09010040 // writeable RVBAR mapping address diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index 37df4410ea..6c3b8ea351 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -250,10 +250,19 @@ struct sunxi_ccm_reg { #define CCM_PLL6_LOCK BIT(28) #define CCM_PLL6_CTRL_N_SHIFT 8 #define CCM_PLL6_CTRL_N_MASK (0xff << CCM_PLL6_CTRL_N_SHIFT) +#ifndef CONFIG_MACH_SUN50I_R329 #define CCM_PLL6_CTRL_DIV1_SHIFT 0 #define CCM_PLL6_CTRL_DIV1_MASK (0x1 << CCM_PLL6_CTRL_DIV1_SHIFT) #define CCM_PLL6_CTRL_DIV2_SHIFT 1 #define CCM_PLL6_CTRL_DIV2_MASK (0x1 << CCM_PLL6_CTRL_DIV2_SHIFT) +#else +#define CCM_PLL6_CTRL_M_SHIFT 1 +#define CCM_PLL6_CTRL_M_MASK (0x1 << CCM_PLL6_CTRL_DIV2_SHIFT)
This should be using CCM_PLL6_CTRL_M_SHIFT.
+#define CCM_PLL6_CTRL_DIV1_SHIFT 16 +#define CCM_PLL6_CTRL_DIV1_MASK (0x7 << CCM_PLL6_CTRL_DIV1_SHIFT) +#define CCM_PLL6_CTRL_DIV2_SHIFT 20 +#define CCM_PLL6_CTRL_DIV2_MASK (0x7 << CCM_PLL6_CTRL_DIV2_SHIFT) +#endif
/* cpu_axi bit field*/ #define CCM_CPU_AXI_MUX_MASK (0x3 << 24) @@ -285,6 +294,14 @@ struct sunxi_ccm_reg {
/* apb1 bit field */ #define CCM_APB1_DEFAULT 0x03000102 +#elif CONFIG_MACH_SUN50I_R329 +#define CCM_PLL6_DEFAULT 0xa8216300
+/* ahb bit field */ +#define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000002
+/* apb1 bit field */ +#define CCM_APB1_DEFAULT 0x02000001 #endif
/* apb2 bit field */ diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h index b08f202374..20d04cac74 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu.h +++ b/arch/arm/include/asm/arch-sunxi/cpu.h @@ -8,6 +8,8 @@
#if defined(CONFIG_MACH_SUN9I) #include <asm/arch/cpu_sun9i.h> +#elif defined(CONFIG_MACH_SUN50I_R329) +#include <asm/arch/cpu_sun50i_r329.h> #elif defined(CONFIG_SUN50I_GEN_H6) #include <asm/arch/cpu_sun50i_h6.h> #else diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h new file mode 100644 index 0000000000..3d2237a59f --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_r329.h @@ -0,0 +1,58 @@ +/*
- (C) Copyright 2021 Sipeed
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _SUNXI_CPU_SUN50I_H6_H +#define _SUNXI_CPU_SUN50I_H6_H
minor: the header guard here does not match (and the comment at the bottom matches even less).
+#define SUNXI_SRAM_A1_BASE 0x00020000 +#define SUNXI_SRAM_A2_BASE 0x00100000
These should probably match the values we used in TF-A, including some similar comment.
+#define SUNXI_TIMER_BASE 0x02000000 +#define SUNXI_PIO_BASE 0x02000400 +#define SUNXI_CCM_BASE 0x02001000
+#define SUNXI_UART0_BASE 0x02500000 +#define SUNXI_UART1_BASE 0x02500400 +#define SUNXI_UART2_BASE 0x02500800 +#define SUNXI_UART3_BASE 0x02500C00 +#define SUNXI_TWI0_BASE 0x02502000 +#define SUNXI_TWI1_BASE 0x02502400
+#define SUNXI_SRAMC_BASE 0x03000000 +#define SUNXI_DMA_BASE 0x03002000 +/* SID address space starts at 0x03006000, but e-fuse is at offset 0x200 */ +#define SUNXI_SIDC_BASE 0x03006000 +#define SUNXI_SID_BASE 0x03006200
+#define SUNXI_GIC400_BASE 0x03020000 +#define SUNXI_SS_BASE 0x03040000 +#define SUNXI_DRAM_COM_BASE 0x03102000 +#define SUNXI_DRAM_CTL0_BASE 0x03103000
+#define SUNXI_NFC_BASE 0x04011000 +#define SUNXI_MMC0_BASE 0x04020000 +#define SUNXI_MMC1_BASE 0x04021000 +#define SUNXI_SPI0_BASE 0x04025000 +#define SUNXI_SPI1_BASE 0x04026000 +#define SUNXI_USB0_BASE 0x04100000 +#define SUNXI_USB1_BASE 0x04201000 +#define SUNXI_GMAC_BASE 0x04500000
+#define SUNXI_R_CPUCFG_BASE 0x07000400 +#define SUNXI_PRCM_BASE 0x07010000 +#define SUNXI_R_WDOG_BASE 0x07020400 +#define SUNXI_R_PIO_BASE 0x07022000 +#define SUNXI_R_UART_BASE 0x07080000 +#define SUNXI_R_TWI_BASE 0x07081400 +#define SUNXI_RTC_BASE 0x07090000
+#ifndef __ASSEMBLY__ +void sunxi_board_init(void); +void sunxi_reset(void); +int sunxi_get_sid(unsigned int *sid); +#endif
+#endif /* _SUNXI_CPU_SUN9I_H */ diff --git a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h index 5f636e8384..1aba5f0122 100644 --- a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h +++ b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h @@ -37,8 +37,41 @@ struct sunxi_prcm_reg { u32 w1_gate_reset; /* 0x1ec */ u8 res10[0x1c]; /* 0x1f0 */ u32 rtc_gate_reset; /* 0x20c */ +#ifdef CONFIG_MACH_SUN50I_R329
- u8 res11[0xdf0]; /* 0x210 */
- u32 pll1_cfg; /* 0x1000 pll1 (cpux) control */
- u8 reserved_0x1004[0xc];
- u32 pll6_cfg; /* 0x1010 pll6 (periph) control */
- u8 reserved_0x1014[0xc];
- u32 pll2_cfg; /* 0x1020 pll2 (audio) control */
- u8 reserved_0x1024[0xc];
- u32 pll_audio1_cfg; /* 0x1030 pll audio1 control */
- u8 reserved_0x1034[0xdc];
- u32 pll6_pat0; /* 0x1110 pll6 (periph) pattern0 */
- u32 pll6_pat1; /* 0x1114 pll6 (periph) pattern1 */
- u8 reserved_0x1118[0x8];
- u32 pll2_pat0; /* 0x1120 pll2 (audio) pattern0 */
- u32 pll2_pat1; /* 0x1120 pll2 (audio) pattern1 */
- u8 reserved_0x1128[0x8];
- u32 pll_audio1_pat0; /* 0x1130 pll audio1 pattern0 */
- u32 pll_audio1_pat1; /* 0x1130 pll audio1 pattern1 */
- u8 reserved_0x1138[0x1c8];
- u32 pll1_bias; /* 0x1300 pll1 (cpux) bias */
- u8 reserved_0x1304[0xc];
- u32 pll6_bias; /* 0x1310 pll6 (periph) bias */
- u8 reserved_0x1314[0xc];
- u32 pll2_bias; /* 0x1320 pll6 (periph0) bias */
- u8 reserved_0x1324[0xc];
- u32 pll_audio1_bias; /* 0x1330 pll audio1 bias */
- u8 reserved_0x1334[0xcc];
- u32 pll1_tun; /* 0x1400 pll1 (cpux) tunning */
spelling: tuning
Regards, Samuel
+#endif }; check_member(sunxi_prcm_reg, rtc_gate_reset, 0x20c); +#ifdef CONFIG_MACH_SUN50I_R329 +check_member(sunxi_prcm_reg, pll1_tun, 0x1400); +#endif
#define PRCM_TWI_GATE (1 << 0) #define PRCM_TWI_RESET (1 << 16) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 9e37e99684..a114c1addc 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -181,6 +181,9 @@ /* end of SRAM A2 on H6 for now */ #define LOW_LEVEL_SRAM_STACK 0x00118000 #endif +#elif CONFIG_SUNXI_SRAM_ADDRESS == 0x100000 +#define CONFIG_SPL_MAX_SIZE 0x7fa0 /* 32 KiB */ +#define LOW_LEVEL_SRAM_STACK 0x00120000 /* 64 KiB inside SRAM A2 */ #else #define CONFIG_SPL_MAX_SIZE 0x5fa0 /* 24KB on sun4i/sun7i */ #define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */

R329 has a quite different clock tree than other SoCs. It has only 4 PLLs and its PLL-PERIPH has two post dividers, one for the normal PLL-PERIPH-2x output and another for a special PLL-PERIPH-800M output. In addition, its PLL configuration registers are in PRCM memory zone, not the ordinary CPUX CCU one.
Add support for basical R329 clock initialization.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/mach-sunxi/clock_sun50i_h6.c | 49 ++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index a947463e0a..28bc5fccd8 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -9,6 +9,13 @@ void clock_init_safe(void) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; +#ifdef CONFIG_MACH_SUN50I_R329 + struct sunxi_prcm_reg *const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; + struct sunxi_prcm_reg *const pllccm = prcm; +#else + struct sunxi_ccm_reg *const pllccm = ccm; +#endif
/* this seems to enable PLLs on H616 */ if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) @@ -16,22 +23,26 @@ void clock_init_safe(void)
clock_set_pll1(408000000);
- writel(CCM_PLL6_DEFAULT, &ccm->pll6_cfg); - while (!(readl(&ccm->pll6_cfg) & CCM_PLL6_LOCK)) + writel(CCM_PLL6_DEFAULT, &pllccm->pll6_cfg); + while (!(readl(&pllccm->pll6_cfg) & CCM_PLL6_LOCK)) ;
clrsetbits_le32(&ccm->cpu_axi_cfg, CCM_CPU_AXI_APB_MASK | CCM_CPU_AXI_AXI_MASK, CCM_CPU_AXI_DEFAULT_FACTORS);
writel(CCM_PSI_AHB1_AHB2_DEFAULT, &ccm->psi_ahb1_ahb2_cfg); +#ifdef CCM_AHB3_DEFAULT writel(CCM_AHB3_DEFAULT, &ccm->ahb3_cfg); +#endif writel(CCM_APB1_DEFAULT, &ccm->apb1_cfg);
+#ifndef CONFIG_MACH_SUN50I_R329 /* * The mux and factor are set, but the clock will be enabled in * DRAM initialization code. */ writel(MBUS_CLK_SRC_PLL6X2 | MBUS_CLK_M(3), &ccm->mbus_cfg); +#endif } #endif
@@ -60,8 +71,20 @@ void clock_set_pll1(unsigned int clk) { struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; +#ifdef CONFIG_MACH_SUN50I_R329 + struct sunxi_prcm_reg *const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; + struct sunxi_prcm_reg *const pllccm = prcm; +#else + struct sunxi_ccm_reg *const pllccm = ccm; +#endif u32 val;
+#ifdef CONFIG_MACH_SUN50I_R329 + /* Fix undervoltage reset threshold */ + clrsetbits_le32(0x070901f4, 0xfff, 0xc0); +#endif + /* Do not support clocks < 288MHz as they need factor P */ if (clk < 288000000) clk = 288000000;
@@ -73,11 +96,11 @@ void clock_set_pll1(unsigned int clk)
/* clk = 24*n/p, p is ignored if clock is >288MHz */ writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 | -#ifdef CONFIG_MACH_SUN50I_H616 +#ifndef CONFIG_MACH_SUN50I_H6 CCM_PLL1_OUT_EN | #endif - CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg); - while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {} + CCM_PLL1_CTRL_N(clk / 24000000), &pllccm->pll1_cfg); + while (!(readl(&pllccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
/* Switch CPU to PLL1 */ val = readl(&ccm->cpu_axi_cfg); @@ -87,6 +110,7 @@ void clock_set_pll1(unsigned int clk) } #endif
+#ifndef CONFIG_MACH_SUN50I_R329 unsigned int clock_get_pll6(void) { struct sunxi_ccm_reg *const ccm = @@ -102,6 +126,21 @@ unsigned int clock_get_pll6(void) /* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */ return 24000000 / m * n / div1 / div2; } +#else +unsigned int clock_get_pll6(void) +{ + struct sunxi_prcm_reg *const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; + + uint32_t rval = readl(&prcm->pll6_cfg); + int m = ((rval & CCM_PLL6_CTRL_M_MASK) >> CCM_PLL6_CTRL_M_SHIFT) + 1; + int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1; + int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >> + CCM_PLL6_CTRL_DIV1_SHIFT) + 1; + /* The register defines PLL6-2X, not plain PLL6 */ + return 24000000 / m * n / div1 / 2; +} +#endif
int clock_twi_onoff(int port, int state) {

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
R329 has a quite different clock tree than other SoCs. It has only 4 PLLs and its PLL-PERIPH has two post dividers, one for the normal PLL-PERIPH-2x output and another for a special PLL-PERIPH-800M output. In addition, its PLL configuration registers are in PRCM memory zone, not the ordinary CPUX CCU one.
Add support for basical R329 clock initialization.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
Reviewed-by: Samuel Holland samuel@sholland.org
One minor comment below.
arch/arm/mach-sunxi/clock_sun50i_h6.c | 49 ++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index a947463e0a..28bc5fccd8 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -9,6 +9,13 @@ void clock_init_safe(void) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; +#ifdef CONFIG_MACH_SUN50I_R329
- struct sunxi_prcm_reg *const prcm =
(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
- struct sunxi_prcm_reg *const pllccm = prcm;
+#else
- struct sunxi_ccm_reg *const pllccm = ccm;
+#endif
/* this seems to enable PLLs on H616 */ if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) @@ -16,22 +23,26 @@ void clock_init_safe(void)
clock_set_pll1(408000000);
- writel(CCM_PLL6_DEFAULT, &ccm->pll6_cfg);
- while (!(readl(&ccm->pll6_cfg) & CCM_PLL6_LOCK))
writel(CCM_PLL6_DEFAULT, &pllccm->pll6_cfg);
while (!(readl(&pllccm->pll6_cfg) & CCM_PLL6_LOCK)) ;
clrsetbits_le32(&ccm->cpu_axi_cfg, CCM_CPU_AXI_APB_MASK | CCM_CPU_AXI_AXI_MASK, CCM_CPU_AXI_DEFAULT_FACTORS);
writel(CCM_PSI_AHB1_AHB2_DEFAULT, &ccm->psi_ahb1_ahb2_cfg);
+#ifdef CCM_AHB3_DEFAULT writel(CCM_AHB3_DEFAULT, &ccm->ahb3_cfg); +#endif writel(CCM_APB1_DEFAULT, &ccm->apb1_cfg);
+#ifndef CONFIG_MACH_SUN50I_R329 /* * The mux and factor are set, but the clock will be enabled in * DRAM initialization code. */ writel(MBUS_CLK_SRC_PLL6X2 | MBUS_CLK_M(3), &ccm->mbus_cfg); +#endif } #endif
@@ -60,8 +71,20 @@ void clock_set_pll1(unsigned int clk) { struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; +#ifdef CONFIG_MACH_SUN50I_R329
- struct sunxi_prcm_reg *const prcm =
(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
- struct sunxi_prcm_reg *const pllccm = prcm;
+#else
- struct sunxi_ccm_reg *const pllccm = ccm;
+#endif u32 val;
+#ifdef CONFIG_MACH_SUN50I_R329
- /* Fix undervoltage reset threshold */
- clrsetbits_le32(0x070901f4, 0xfff, 0xc0);
+#endif
- /* Do not support clocks < 288MHz as they need factor P */ if (clk < 288000000) clk = 288000000;
@@ -73,11 +96,11 @@ void clock_set_pll1(unsigned int clk)
/* clk = 24*n/p, p is ignored if clock is >288MHz */ writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 | -#ifdef CONFIG_MACH_SUN50I_H616 +#ifndef CONFIG_MACH_SUN50I_H6 CCM_PLL1_OUT_EN | #endif
CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg);
- while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
CCM_PLL1_CTRL_N(clk / 24000000), &pllccm->pll1_cfg);
while (!(readl(&pllccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
/* Switch CPU to PLL1 */ val = readl(&ccm->cpu_axi_cfg);
@@ -87,6 +110,7 @@ void clock_set_pll1(unsigned int clk) } #endif
+#ifndef CONFIG_MACH_SUN50I_R329
The negative condition here will make it messier to add more branches in the future, so I suggest flipping the conditional block.
unsigned int clock_get_pll6(void) { struct sunxi_ccm_reg *const ccm = @@ -102,6 +126,21 @@ unsigned int clock_get_pll6(void) /* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */ return 24000000 / m * n / div1 / div2; } +#else +unsigned int clock_get_pll6(void) +{
- struct sunxi_prcm_reg *const prcm =
(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
- uint32_t rval = readl(&prcm->pll6_cfg);
- int m = ((rval & CCM_PLL6_CTRL_M_MASK) >> CCM_PLL6_CTRL_M_SHIFT) + 1;
- int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
- int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
- /* The register defines PLL6-2X, not plain PLL6 */
- return 24000000 / m * n / div1 / 2;
+} +#endif
int clock_twi_onoff(int port, int state) {

Allwinner R329 SoC is the first known Allwinner SoC that has two possible pinmux setups for MMC0 controller.
Support configuration of both setups of MMC0 and UART0 at PB4/5.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/include/asm/arch-sunxi/gpio.h | 3 +++ arch/arm/mach-sunxi/Kconfig | 7 +++++++ arch/arm/mach-sunxi/board.c | 4 ++++ board/sunxi/board.c | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+)
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 2969a530ae..da9acfab78 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -166,12 +166,14 @@ enum sunxi_gpio_number { #define SUN8I_A83T_GPB_UART0 2 #define SUN8I_V3S_GPB_UART0 3 #define SUN50I_GPB_UART0 4 +#define SUN50I_R329_GPB_UART0 2
#define SUNXI_GPC_NAND 2 #define SUNXI_GPC_SPI0 3 #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4 #define SUN50I_GPC_SPI0 4 +#define SUN50I_R329_GPC_SDC0 3
#define SUN8I_GPD_SDC1 3 #define SUNXI_GPD_LCD0 2 @@ -185,6 +187,7 @@ enum sunxi_gpio_number { #define SUNXI_GPF_SDC0 2 #define SUNXI_GPF_UART0 4 #define SUN8I_GPF_UART0 3 +#define SUN50I_R329_GPF_SDC0 5
#define SUN4I_GPG_SDC1 4 #define SUN5I_GPG_SDC1 2 diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 49f94f095c..391a3dd9e5 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -672,6 +672,13 @@ config MMC3_CD_PIN ---help--- See MMC0_CD_PIN help text.
+config MMC0_PINS + string "Pins for mmc0" + default "PF" + depends on MACH_SUN50I_R329 + ---help--- + See MMC1_PINS help text. + config MMC1_PINS string "Pins for mmc1" default "" diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index e979e426dd..1aa31c7e05 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -129,6 +129,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H616_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H616_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I_R329) + sunxi_gpio_set_cfgpin(SUNXI_GPB(4), SUN50I_R329_GPB_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPB(5), SUN50I_R329_GPB_UART0); + sunxi_gpio_set_pull(SUNXI_GPB(5), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_A83T) sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0); diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 67acc01d83..bfc90345d9 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -417,12 +417,32 @@ static void mmc_pinmux_setup(int sdc)
switch (sdc) { case 0: +#if defined(CONFIG_MACH_SUN50I_R329) + pins = sunxi_name_to_gpio_bank(CONFIG_MMC0_PINS); + + if (pins == SUNXI_GPIO_C) { + /* SDC0: PC0-PC6 */ + for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(6); pin++) { + sunxi_gpio_set_cfgpin(pin, SUN50I_R329_GPC_SDC0); + sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); + sunxi_gpio_set_drv(pin, 2); + } + } else { + /* SDC0: PF0-PF5 */ + for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) { + sunxi_gpio_set_cfgpin(pin, SUN50I_R329_GPF_SDC0); + sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); + sunxi_gpio_set_drv(pin, 2); + } + } +#else /* SDC0: PF0-PF5 */ for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) { sunxi_gpio_set_cfgpin(pin, SUNXI_GPF_SDC0); sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); sunxi_gpio_set_drv(pin, 2); } +#endif break;
case 1:

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
Allwinner R329 SoC is the first known Allwinner SoC that has two possible pinmux setups for MMC0 controller.
Support configuration of both setups of MMC0 and UART0 at PB4/5.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
arch/arm/include/asm/arch-sunxi/gpio.h | 3 +++ arch/arm/mach-sunxi/Kconfig | 7 +++++++ arch/arm/mach-sunxi/board.c | 4 ++++ board/sunxi/board.c | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+)
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 2969a530ae..da9acfab78 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -166,12 +166,14 @@ enum sunxi_gpio_number { #define SUN8I_A83T_GPB_UART0 2 #define SUN8I_V3S_GPB_UART0 3 #define SUN50I_GPB_UART0 4 +#define SUN50I_R329_GPB_UART0 2
#define SUNXI_GPC_NAND 2 #define SUNXI_GPC_SPI0 3 #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4 #define SUN50I_GPC_SPI0 4 +#define SUN50I_R329_GPC_SDC0 3
#define SUN8I_GPD_SDC1 3 #define SUNXI_GPD_LCD0 2 @@ -185,6 +187,7 @@ enum sunxi_gpio_number { #define SUNXI_GPF_SDC0 2 #define SUNXI_GPF_UART0 4 #define SUN8I_GPF_UART0 3 +#define SUN50I_R329_GPF_SDC0 5
#define SUN4I_GPG_SDC1 4 #define SUN5I_GPG_SDC1 2 diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 49f94f095c..391a3dd9e5 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -672,6 +672,13 @@ config MMC3_CD_PIN ---help--- See MMC0_CD_PIN help text.
+config MMC0_PINS
- string "Pins for mmc0"
- default "PF"
- depends on MACH_SUN50I_R329
- ---help---
- See MMC1_PINS help text.
Please make this a Boolean MMC0_PINS_PC (this area was changed since you sent these patches).
config MMC1_PINS string "Pins for mmc1" default "" diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index e979e426dd..1aa31c7e05 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -129,6 +129,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H616_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H616_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I_R329)
- sunxi_gpio_set_cfgpin(SUNXI_GPB(4), SUN50I_R329_GPB_UART0);
- sunxi_gpio_set_cfgpin(SUNXI_GPB(5), SUN50I_R329_GPB_UART0);
- sunxi_gpio_set_pull(SUNXI_GPB(5), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_A83T) sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0); diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 67acc01d83..bfc90345d9 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -417,12 +417,32 @@ static void mmc_pinmux_setup(int sdc)
switch (sdc) { case 0: +#if defined(CONFIG_MACH_SUN50I_R329)
Please use if (IS_ENABLED(...)).
Regards, Samuel
pins = sunxi_name_to_gpio_bank(CONFIG_MMC0_PINS);
if (pins == SUNXI_GPIO_C) {
/* SDC0: PC0-PC6 */
for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(6); pin++) {
sunxi_gpio_set_cfgpin(pin, SUN50I_R329_GPC_SDC0);
sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
sunxi_gpio_set_drv(pin, 2);
}
} else {
/* SDC0: PF0-PF5 */
for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) {
sunxi_gpio_set_cfgpin(pin, SUN50I_R329_GPF_SDC0);
sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
sunxi_gpio_set_drv(pin, 2);
}
}
+#else /* SDC0: PF0-PF5 */ for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) { sunxi_gpio_set_cfgpin(pin, SUNXI_GPF_SDC0); sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); sunxi_gpio_set_drv(pin, 2); } +#endif break;
case 1:

R329 has a new DRAM controller, which looks like a combination of the H6/H616 MCTL_COM part and the SUNXI_DW MCTL_CTL part. This design has already got reused by Allwinner, and V831/V833 SoCs have similar memory controller.
Add support for it. To prepare for further support of other SoCs, routines with socid parameter are added, although not checked now.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/include/asm/arch-sunxi/cpu.h | 1 + arch/arm/include/asm/arch-sunxi/dram.h | 2 + .../include/asm/arch-sunxi/dram_sun50i_r329.h | 232 +++++++++++ arch/arm/mach-sunxi/Kconfig | 16 +- arch/arm/mach-sunxi/Makefile | 2 + arch/arm/mach-sunxi/dram_sun50i_r329.c | 377 ++++++++++++++++++ arch/arm/mach-sunxi/dram_timings/Makefile | 1 + arch/arm/mach-sunxi/dram_timings/ddr3_r329.c | 89 +++++ 8 files changed, 719 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_r329.h create mode 100644 arch/arm/mach-sunxi/dram_sun50i_r329.c create mode 100644 arch/arm/mach-sunxi/dram_timings/ddr3_r329.c
diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h index 20d04cac74..a968af6012 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu.h +++ b/arch/arm/include/asm/arch-sunxi/cpu.h @@ -21,5 +21,6 @@ #define SOCID_V3S 0x1681 #define SOCID_H5 0x1718 #define SOCID_R40 0x1701 +#define SOCID_R329 0x1851
#endif /* _SUNXI_CPU_H */ diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index c3b3e1f512..36549a47c5 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -31,6 +31,8 @@ #include <asm/arch/dram_sun50i_h6.h> #elif defined(CONFIG_MACH_SUN50I_H616) #include <asm/arch/dram_sun50i_h616.h> +#elif defined(CONFIG_MACH_SUN50I_R329) +#include <asm/arch/dram_sun50i_r329.h> #else #include <asm/arch/dram_sun4i.h> #endif diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_r329.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_r329.h new file mode 100644 index 0000000000..723c687670 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_r329.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * sun50i R329 platform dram controller register and constant defines + * + * (C) Copyright 2021 Sipeed + * + * based on dram_sun50i_h6.h, which is: + * (C) Copyright 2017 Icenowy Zheng icenowy@aosc.io + * + * based on dram_sun8i_h3.h, which is: + * (C) Copyright 2007-2015 Allwinner Technology Co. + * Jerry Wang wangflord@allwinnertech.com + * (C) Copyright 2015 Vishnu Patekar vishnupatekar0510@gmail.com + * (C) Copyright 2014-2015 Hans de Goede hdegoede@redhat.com + * (C) Copyright 2015 Jens Kuske jenskuske@gmail.com + */ + +#ifndef _SUNXI_DRAM_SUN8I_H3_H +#define _SUNXI_DRAM_SUN8I_H3_H + +#include <linux/bitops.h> + +struct sunxi_mctl_com_reg { + u32 cr; /* 0x000 control register */ + u32 cr_r1; /* 0x004 control register for 2nd rank */ + u32 unk_0x008; /* 0x008 */ + u32 tmr; /* 0x00c timer register */ + u8 reserved_0x010[4]; /* 0x010 */ + u32 unk_0x014; /* 0x014 */ + u8 reserved_0x018[8]; /* 0x018 */ + u32 maer0; /* 0x020 master enable register 0 */ + u32 maer1; /* 0x024 master enable register 1 */ + u32 maer2; /* 0x028 master enable register 2 */ + u8 reserved_0x02c[468]; /* 0x02c */ + u32 bwcr; /* 0x200 bandwidth control register */ + u8 reserved_0x204[12]; /* 0x204 */ + /* + * The last master configured by BSP libdram is at 0x49x, so the + * size of this struct array is set to 41 (0x29) now. + */ + struct { + u32 cfg0; /* 0x0 */ + u32 cfg1; /* 0x4 */ + u8 reserved_0x8[8]; /* 0x8 */ + } master[41]; /* 0x210 + index * 0x10 */ +}; +check_member(sunxi_mctl_com_reg, master[40].reserved_0x8, 0x498); + +#define MCTL_CR_BL8 (0x4 << 20) + +#define MCTL_CR_1T (0x1 << 19) +#define MCTL_CR_2T (0x0 << 19) + +#define MCTL_CR_LPDDR3 (0x7 << 16) +#define MCTL_CR_LPDDR2 (0x6 << 16) +#define MCTL_CR_DDR3 (0x3 << 16) +#define MCTL_CR_DDR2 (0x2 << 16) + +#define MCTL_CR_SEQUENTIAL (0x1 << 15) +#define MCTL_CR_INTERLEAVED (0x0 << 15) + +#define MCTL_CR_FULL_WIDTH (0x1 << 12) +#define MCTL_CR_HALF_WIDTH (0x0 << 12) +#define MCTL_CR_BUS_FULL_WIDTH(x) ((x) << 12) + +#define MCTL_CR_PAGE_SIZE(x) ((fls(x) - 4) << 8) +#define MCTL_CR_ROW_BITS(x) (((x) - 1) << 4) +#define MCTL_CR_EIGHT_BANKS (0x1 << 2) +#define MCTL_CR_FOUR_BANKS (0x0 << 2) +#define MCTL_CR_DUAL_RANK (0x1 << 0) +#define MCTL_CR_SINGLE_RANK (0x0 << 0) + +struct sunxi_mctl_ctl_reg { + u32 pir; /* 0x00 PHY initialization register */ + u32 pwrctl; /* 0x04 */ + u32 mrctrl; /* 0x08 */ + u32 clken; /* 0x0c */ + u32 pgsr[2]; /* 0x10 PHY general status registers */ + u32 statr; /* 0x18 */ + u8 res1[0x10]; /* 0x1c */ + u32 lp3mr11; /* 0x2c */ + u32 mr[4]; /* 0x30 mode registers */ + u32 pllgcr; /* 0x40 */ + u32 ptr[5]; /* 0x44 PHY timing registers */ + u32 dramtmg[9]; /* 0x58 DRAM timing registers */ + u32 odtcfg; /* 0x7c */ + u32 pitmg[2]; /* 0x80 PHY interface timing registers */ + u8 res2[0x4]; /* 0x88 */ + u32 rfshctl0; /* 0x8c */ + u32 rfshtmg[2]; /* 0x90 refresh timing */ + u32 pwrtmg; /* 0x98 */ + u8 res3[0x4]; /* 0x9c */ + u32 unk_0x0a0; /* 0xa0 */ + u8 res3_1[0x14]; /* 0xa4 */ + u32 vtfcr; /* 0xb8 (unused on H3) */ + u32 dqsgmr; /* 0xbc */ + u32 dtcr; /* 0xc0 */ + u32 dtar[4]; /* 0xc4 */ + u32 dtdr[2]; /* 0xd4 */ + u32 dtmr[2]; /* 0xdc */ + u32 dtbmr; /* 0xe4 */ + u32 catr[2]; /* 0xe8 */ + u32 dtedr[2]; /* 0xf0 */ + u8 res4[0x8]; /* 0xf8 */ + u32 pgcr[4]; /* 0x100 PHY general configuration registers */ + u32 iovcr[2]; /* 0x110 */ + u32 dqsdr; /* 0x118 */ + u32 dxccr; /* 0x11c */ + u32 odtmap; /* 0x120 */ + u32 zqctl[2]; /* 0x124 */ + u8 res6[0x14]; /* 0x12c */ + u32 zqcr; /* 0x140 ZQ control register */ + u32 zqsr; /* 0x144 ZQ status register */ + u32 zqdr[3]; /* 0x148 ZQ data registers */ + u8 res7[0x6c]; /* 0x154 */ + u32 sched; /* 0x1c0 */ + u32 perfhpr[2]; /* 0x1c4 */ + u32 perflpr[2]; /* 0x1cc */ + u32 perfwr[2]; /* 0x1d4 */ + u8 res8[0x24]; /* 0x1dc */ + u32 acmdlr; /* 0x200 AC master delay line register */ + u32 aclcdlr; /* 0x204 AC local calibrated delay line register */ + u32 aciocr; /* 0x208 AC I/O configuration register */ + u8 res9[0x4]; /* 0x20c */ + u32 acbdlr[31]; /* 0x210 AC bit delay line registers */ + u8 res10[0x74]; /* 0x28c */ + struct { /* 0x300 DATX8 modules*/ + u32 mdlr; /* 0x00 master delay line register */ + u32 lcdlr[3]; /* 0x04 local calibrated delay line registers */ + u32 bdlr[11]; /* 0x10 bit delay line registers */ + u32 sdlr; /* 0x3c output enable bit delay registers */ + u32 gtr; /* 0x40 general timing register */ + u32 gcr; /* 0x44 general configuration register */ + u32 gsr[3]; /* 0x48 general status registers */ + u8 res0[0x2c]; /* 0x54 */ + } dx[4]; + u8 res11[0x388]; /* 0x500 */ + u32 upd2; /* 0x888 */ +}; +check_member(sunxi_mctl_ctl_reg, upd2, 0x888); + +#define PTR3_TDINIT1(x) ((x) << 20) +#define PTR3_TDINIT0(x) ((x) << 0) + +#define PTR4_TDINIT3(x) ((x) << 20) +#define PTR4_TDINIT2(x) ((x) << 0) + +#define DRAMTMG0_TWTP(x) ((x) << 24) +#define DRAMTMG0_TFAW(x) ((x) << 16) +#define DRAMTMG0_TRAS_MAX(x) ((x) << 8) +#define DRAMTMG0_TRAS(x) ((x) << 0) + +#define DRAMTMG1_TXP(x) ((x) << 16) +#define DRAMTMG1_TRTP(x) ((x) << 8) +#define DRAMTMG1_TRC(x) ((x) << 0) + +#define DRAMTMG2_TCWL(x) ((x) << 24) +#define DRAMTMG2_TCL(x) ((x) << 16) +#define DRAMTMG2_TRD2WR(x) ((x) << 8) +#define DRAMTMG2_TWR2RD(x) ((x) << 0) + +#define DRAMTMG3_TMRW(x) ((x) << 16) +#define DRAMTMG3_TMRD(x) ((x) << 12) +#define DRAMTMG3_TMOD(x) ((x) << 0) + +#define DRAMTMG4_TRCD(x) ((x) << 24) +#define DRAMTMG4_TCCD(x) ((x) << 16) +#define DRAMTMG4_TRRD(x) ((x) << 8) +#define DRAMTMG4_TRP(x) ((x) << 0) + +#define DRAMTMG5_TCKSRX(x) ((x) << 24) +#define DRAMTMG5_TCKSRE(x) ((x) << 16) +#define DRAMTMG5_TCKESR(x) ((x) << 8) +#define DRAMTMG5_TCKE(x) ((x) << 0) + +#define RFSHTMG_TREFI(x) ((x) << 16) +#define RFSHTMG_TRFC(x) ((x) << 0) + +#define PIR_CLRSR (0x1 << 27) /* clear status registers */ +#define PIR_QSGATE (0x1 << 10) /* Read DQS gate training */ +#define PIR_DRAMINIT (0x1 << 8) /* DRAM initialization */ +#define PIR_DRAMRST (0x1 << 7) /* DRAM reset */ +#define PIR_PHYRST (0x1 << 6) /* PHY reset */ +#define PIR_DCAL (0x1 << 5) /* DDL calibration */ +#define PIR_PLLINIT (0x1 << 4) /* PLL initialization */ +#define PIR_ZCAL (0x1 << 1) /* ZQ calibration */ +#define PIR_INIT (0x1 << 0) /* PHY initialization trigger */ + +#define PGSR_INIT_DONE (0x1 << 0) /* PHY init done */ + +#define ZQCR_PWRDOWN (1U << 31) /* ZQ power down */ + +#define ACBDLR_WRITE_DELAY(x) ((x) << 8) + +#define DXBDLR_DQ(x) (x) /* DQ0-7 BDLR index */ +#define DXBDLR_DM 8 /* DM BDLR index */ +#define DXBDLR_DQS 9 /* DQS BDLR index */ +#define DXBDLR_DQSN 10 /* DQSN BDLR index */ + +#define DXBDLR_WRITE_DELAY(x) ((x) << 8) +#define DXBDLR_READ_DELAY(x) ((x) << 0) + +/* + * The delay parameters below allow to allegedly specify delay times of some + * unknown unit for each individual bit trace in each of the four data bytes + * the 32-bit wide access consists of. Also three control signals can be + * adjusted individually. + */ +#define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE) +/* The eight data lines (DQn) plus DM, DQS and DQSN */ +#define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) +struct dram_para { + u16 page_size; + u8 bus_full_width; + u8 dual_rank; + u8 row_bits; + u8 bank_bits; + const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; + const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; + const u8 ac_delays[31]; +}; + +static inline int ns_to_t(int nanoseconds) +{ + const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2; + + return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); +} + +void mctl_set_timing_params(uint16_t socid, struct dram_para *para); + +#endif /* _SUNXI_DRAM_SUN8I_H3_H */ diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 391a3dd9e5..c9bb47a8bd 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -54,6 +54,12 @@ config DRAM_SUN50I_H616 Select this dram controller driver for some sun50i platforms, like H616.
+config DRAM_SUN50I_R329 + bool + help + Select this dram controller driver for some sun50i platforms, + like R329. + if DRAM_SUN50I_H616 config DRAM_SUN50I_H616_WRITE_LEVELING bool "H616 DRAM write leveling" @@ -402,7 +408,7 @@ config ARM_BOOT_HOOK_RMR This allows both the SPL and the U-Boot proper to be entered in either mode and switch to AArch64 if needed.
-if SUNXI_DRAM_DW || DRAM_SUN50I_H6 +if SUNXI_DRAM_DW || DRAM_SUN50I_H6 || DRAM_SUN50I_R329 config SUNXI_DRAM_DDR3 bool
@@ -424,6 +430,14 @@ config SUNXI_DRAM_DDR3_1333 This option is the original only supported memory type, which suits many H3/H5/A64 boards available now.
+config SUNXI_DRAM_DDR3_R329 + bool "DDR3 found in R329 chip" + select SUNXI_DRAM_DDR3 + depends on DRAM_SUN50I_R329 + ---help--- + This option is only for the DDR3 memory chip which is co-packaged in + Allwinner R329 SoC. + config SUNXI_DRAM_LPDDR3_STOCK bool "LPDDR3 with Allwinner stock configuration" select SUNXI_DRAM_LPDDR3 diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 3f081d92f3..f90393cbbc 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -42,4 +42,6 @@ obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o obj-$(CONFIG_DRAM_SUN50I_H6) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_H616) += dram_sun50i_h616.o obj-$(CONFIG_DRAM_SUN50I_H616) += dram_timings/ +obj-$(CONFIG_DRAM_SUN50I_R329) += dram_sun50i_r329.o +obj-$(CONFIG_DRAM_SUN50I_R329) += dram_timings/ endif diff --git a/arch/arm/mach-sunxi/dram_sun50i_r329.c b/arch/arm/mach-sunxi/dram_sun50i_r329.c new file mode 100644 index 0000000000..730883999c --- /dev/null +++ b/arch/arm/mach-sunxi/dram_sun50i_r329.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sun50i R329 platform dram controller init + * + * (C) Copyright 2921 Sipeed + * + * Based on dram_sunxi_dw.c, which is: + * (C) Copyright 2007-2015 Allwinner Technology Co. + * Jerry Wang wangflord@allwinnertech.com + * (C) Copyright 2015 Vishnu Patekar vishnupatekar0510@gmail.com + * (C) Copyright 2015 Hans de Goede hdegoede@redhat.com + * (C) Copyright 2015 Jens Kuske jenskuske@gmail.com + */ +#include <common.h> +#include <init.h> +#include <log.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/dram.h> +#include <asm/arch/cpu.h> +#include <asm/arch/prcm.h> +#include <linux/delay.h> +#include <linux/kconfig.h> + +static void mctl_phy_init(u32 val) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + writel(val | PIR_INIT, &mctl_ctl->pir); + mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1); +} + +static void mctl_set_bit_delays(struct dram_para *para) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + int i, j; + + clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26); + + for (i = 0; i < NR_OF_BYTE_LANES; i++) + for (j = 0; j < LINES_PER_BYTE_LANE; j++) + writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) | + DXBDLR_READ_DELAY(para->dx_read_delays[i][j]), + &mctl_ctl->dx[i].bdlr[j]); + + for (i = 0; i < 31; i++) + writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]), + &mctl_ctl->acbdlr[i]); + + /* DQSn, DMn, DQn output enable bit delay */ + writel(0x4 << 24, &mctl_ctl->dx[0].sdlr); + writel(0x2 << 24, &mctl_ctl->dx[1].sdlr); + + setbits_le32(&mctl_ctl->pgcr[0], 1 << 26); +} + +static void mctl_apply_para(struct dram_para *para) +{ + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + clrsetbits_le32(&mctl_com->unk_0x008, 0x3f00, 0x2000); + + writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED | +#if defined CONFIG_SUNXI_DRAM_DDR2 + MCTL_CR_DDR2 | MCTL_CR_2T | +#elif defined CONFIG_SUNXI_DRAM_DDR3 + MCTL_CR_DDR3 | MCTL_CR_2T | +#else +#error Unsupported DRAM type! +#endif + (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) | + MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) | + (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | + MCTL_CR_PAGE_SIZE(para->page_size) | + MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr); + + if (para->dual_rank) + writel(0x00000303, &mctl_ctl->odtmap); + else + writel(0x00000201, &mctl_ctl->odtmap); + + if (!para->bus_full_width) + writel(0x0, &mctl_ctl->dx[1].gcr); + + /* TODO: asymmetric dual rank */ +} + +static uint32_t mctl_r329_round_dram_clk(void) +{ + const int base_clk[] = {1200000, 800000, 516096, 1548288}; + const int target_clk = CONFIG_DRAM_CLK * 2 * 1000; + int best_error = target_clk; + int best_mux = 0, best_n = 0, best_m = 0; + + for (int mux = 0; mux < 4; mux++) { + for (int n = 0; n < 4; n++) { + for (int m = 0; m < 4; m++) { + int clk = base_clk[mux] / (1 << n) / (m + 1); + int error = target_clk - clk; + + /* We shouldn't accept a higher result */ + if (clk > target_clk) + continue; + + if (error < best_error) { + best_error = error; + best_mux = mux; + best_n = n; + best_m = m; + } + } + } + } + + return (((uint32_t) best_mux) << 24) | + (((uint32_t) best_n) << 8) | + ((uint32_t) best_m); +} + +static void mctl_sys_init(struct dram_para *para) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + struct sunxi_prcm_reg * const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; + + /* + * These PLL2 values is the used by Allwinner BSP. + * + * The clock rate is 1548288 kHz according to BSP kernel. + */ + + /* Enable PLL */ + writel(0x09023f00, &prcm->pll2_cfg); + writel(0xc0070624, &prcm->pll2_pat0); + writel(0x0, &prcm->pll2_pat1); + udelay(5); + setbits_le32(&prcm->pll2_cfg, BIT(31) | BIT(29)); + mctl_await_completion(&prcm->pll2_cfg, BIT(28), BIT(28)); + + /* Put all DRAM-related blocks to reset state */ + clrbits_le32(&ccm->mbus_cfg, MBUS_ENABLE | MBUS_RESET); + clrbits_le32(&ccm->dram_gate_reset, BIT(0)); + udelay(5); + writel(0, &ccm->dram_gate_reset); + clrbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET); + udelay(5); + clrbits_le32(&ccm->dram_clk_cfg, BIT(31)); + udelay(5); + setbits_le32(&ccm->dram_clk_cfg, DRAM_CLK_UPDATE); + + /* Configure DRAM mod clock */ + writel(mctl_r329_round_dram_clk(), &ccm->dram_clk_cfg); + + /* Disable all masters */ + writel(1, &mctl_com->maer0); + writel(0, &mctl_com->maer1); + writel(0, &mctl_com->maer2); + + /* Configure MBUS and enable DRAM mod gate and reset */ + setbits_le32(&ccm->dram_gate_reset, BIT(RESET_SHIFT)); + setbits_le32(&ccm->mbus_cfg, MBUS_RESET); + setbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET); + setbits_le32(&ccm->dram_gate_reset, BIT(0)); + setbits_le32(&ccm->dram_clk_cfg, BIT(31)); + setbits_le32(&ccm->dram_clk_cfg, DRAM_CLK_UPDATE); + + /* Unknown hack from the BSP, which enables access of mctl_ctl regs */ + writel(0x8000, &mctl_ctl->clken); +} + +static void mctl_set_ddr3_magic(void) +{ + uint32_t magic_val_from_sid = (readl(SUNXI_SID_BASE + 0x20) >> 24) & 0xf; + if (magic_val_from_sid < 0xc) { + writel(0x08d08c40, SUNXI_DRAM_COM_BASE + 0x500); + writel(0x240030c5, SUNXI_DRAM_COM_BASE + 0x504); + writel(0x00000107, SUNXI_DRAM_COM_BASE + 0x508); + writel(0x2b4b4d60, SUNXI_DRAM_COM_BASE + 0x50c); + writel(0x08d08c41, SUNXI_DRAM_COM_BASE + 0x500); + } else if (magic_val_from_sid == 0xc) { + writel(0x02d20ca0, SUNXI_DRAM_COM_BASE + 0x500); + writel(0x24851cc2, SUNXI_DRAM_COM_BASE + 0x504); + writel(0x000031c9, SUNXI_DRAM_COM_BASE + 0x508); + writel(0x2b4b4573, SUNXI_DRAM_COM_BASE + 0x50c); + writel(0x02d20ca1, SUNXI_DRAM_COM_BASE + 0x500); + } +} + +/* These are more guessed based on some Allwinner code. */ +#define DX_GCR_ODT_DYNAMIC (0x0 << 4) +#define DX_GCR_ODT_ALWAYS_ON (0x1 << 4) +#define DX_GCR_ODT_OFF (0x2 << 4) + +static int mctl_channel_init(uint16_t socid, struct dram_para *para) +{ + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + unsigned int i; + + clrsetbits_le32(&mctl_ctl->iovcr[0], 0x7f7f7f7f, 0x48484848); + clrsetbits_le32(&mctl_ctl->iovcr[1], 0x7f, 0x48); + + mctl_apply_para(para); +#ifdef CONFIG_SUNXI_DRAM_DDR3 + mctl_set_ddr3_magic(); +#endif + mctl_set_timing_params(socid, para); + + clrsetbits_le32(&mctl_com->tmr, 0xfff, (CONFIG_DRAM_CLK / 2)); + + /* dphy & aphy phase select ? */ + clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), + (0x0 << 10) | (0x3 << 8)); + + /* set dramc odt */ + for (i = 0; i < 4; i++) { + u32 clearmask = 0xf61e; + u32 setmask = IS_ENABLED(CONFIG_DRAM_ODT_EN) ? + DX_GCR_ODT_DYNAMIC : DX_GCR_ODT_OFF; + if (CONFIG_DRAM_CLK > 672) + setmask |= 0x400; + + clrsetbits_le32(&mctl_ctl->dx[i].gcr, clearmask, setmask); + } + + /* AC PDR should always ON */ + clrsetbits_le32(&mctl_ctl->aciocr, 0, 0x1 << 1); + + mctl_set_bit_delays(para); + + /* set DQS auto gating PD mode */ + setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6); + + /* data training configuration */ + clrsetbits_le32(&mctl_ctl->dtcr, 0x0fffffff, + (para->dual_rank ? 0x3 : 0x1) << 24 | 1); + + udelay(50); + + clrsetbits_le32(&mctl_ctl->zqcr, 0x3ffffff, 0x2000000 | CONFIG_DRAM_ZQ); + + mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | + PIR_QSGATE | PIR_DRAMRST | PIR_DRAMINIT); + if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) + return 1; + + /* check the dramc status */ + mctl_await_completion(&mctl_ctl->statr, 0x1, 0x1); + + /* liuke added for refresh debug */ + setbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31); + udelay(10); + clrbits_le32(&mctl_ctl->rfshctl0, 0x1 << 31); + udelay(10); + + setbits_le32(&mctl_com->unk_0x014, BIT(31)); + + clrbits_le32(&mctl_ctl->pgcr[3], 0x06000000); + + return 0; +} + +static void mctl_auto_detect_dram_size(struct dram_para *para) +{ + /* detect row address bits */ + para->page_size = 512; + para->row_bits = 16; + para->bank_bits = 2; + mctl_apply_para(para); + + for (para->row_bits = 11; para->row_bits < 16; para->row_bits++) + if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size)) + break; + + /* detect bank address bits */ + para->bank_bits = 3; + mctl_apply_para(para); + + for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++) + if (mctl_mem_matches((1 << para->bank_bits) * para->page_size)) + break; + + /* detect page size */ + para->page_size = 8192; + mctl_apply_para(para); + + for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2) + if (mctl_mem_matches(para->page_size)) + break; +} + +#define SUN50I_R329_DX_READ_DELAYS \ + {{ 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0 }, \ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} +#define SUN50I_R329_DX_WRITE_DELAYS \ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} +#define SUN50I_R329_AC_DELAYS \ + { 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0 } + +unsigned long sunxi_dram_init(void) +{ + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + struct dram_para para = { + .dual_rank = 0, + .bus_full_width = 1, + .row_bits = 16, + .bank_bits = 3, + .page_size = 8192, + + .dx_read_delays = SUN50I_R329_DX_READ_DELAYS, + .dx_write_delays = SUN50I_R329_DX_WRITE_DELAYS, + .ac_delays = SUN50I_R329_AC_DELAYS, + }; + + /* Unknown magic */ + writel(0x10, 0x07010250); + writel(0x330000, 0x07010310); + writel(0x330003, 0x07010310); + +#if defined(CONFIG_MACH_SUN50I_R329) + uint16_t socid = SOCID_R329; +#endif + + mctl_sys_init(¶); + if (mctl_channel_init(socid, ¶)) + return 0; + + udelay(1); + + clrbits_le32(&mctl_ctl->unk_0x0a0, 0xffff); + clrbits_le32(&mctl_ctl->pwrctl, 0x1); + + /* HDR/DDR dynamic mode */ + clrbits_le32(&mctl_ctl->pgcr[0], 0xf000); + + /* power down zq calibration module for power save */ + setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN); + + /* DQ hold disable (tpr13[26] == 1) */ + clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13)); + + mctl_auto_detect_dram_size(¶); + mctl_apply_para(¶); + + /* enable master access */ + writel(0xffffffff, &mctl_com->maer0); + writel(0x7f, &mctl_com->maer1); + writel(0xffff, &mctl_com->maer2); + + return (1UL << (para.row_bits + para.bank_bits)) * para.page_size * + (para.dual_rank ? 2 : 1); +} diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile index 39a8756c29..32d5f15c61 100644 --- a/arch/arm/mach-sunxi/dram_timings/Makefile +++ b/arch/arm/mach-sunxi/dram_timings/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_SUNXI_DRAM_DDR3_1333) += ddr3_1333.o +obj-$(CONFIG_SUNXI_DRAM_DDR3_R329) += ddr3_r329.o obj-$(CONFIG_SUNXI_DRAM_LPDDR3_STOCK) += lpddr3_stock.o obj-$(CONFIG_SUNXI_DRAM_DDR2_V3S) += ddr2_v3s.o obj-$(CONFIG_SUNXI_DRAM_H6_LPDDR3) += h6_lpddr3.o diff --git a/arch/arm/mach-sunxi/dram_timings/ddr3_r329.c b/arch/arm/mach-sunxi/dram_timings/ddr3_r329.c new file mode 100644 index 0000000000..e8a34e7da3 --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/ddr3_r329.c @@ -0,0 +1,89 @@ +#include <common.h> +#include <asm/arch/dram.h> +#include <asm/arch/cpu.h> + +void mctl_set_timing_params(uint16_t socid, struct dram_para *para) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + u8 tccd = 2; + u8 tfaw = ns_to_t(50); + u8 trrd = max(ns_to_t(10), 2); + u8 trcd = ns_to_t(15); + u8 trc = ns_to_t(53); + u8 txp = max(ns_to_t(8), 2); + u8 twtr = max(ns_to_t(8), 2); + u8 trtp = max(ns_to_t(8), 2); + u8 twr = max(ns_to_t(15), 2); + u8 trp = ns_to_t(15); + u8 tras = ns_to_t(38); + u16 trefi = ns_to_t(7800) / 32 + 1; + u16 trfc = ns_to_t(350); + + u8 tmrw = 0; + u8 tmrd = 4; + u8 tmod = 12; + u8 tcke = 3; + u8 tcksrx = 5; + u8 tcksre = 5; + u8 tckesr = 4; + u8 trasmax = 25; + + u8 tcl = 6; /* CL 12 */ + u8 tcwl = 4; /* CWL 8 */ + u8 t_rdata_en = 4; + u8 wr_latency = 2; + + u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */ + u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */ + u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ + u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */ + + u8 twtp = tcwl + 2 + twr; /* WL + BL / 2 + tWR */ + u8 twr2rd = tcwl + 2 + twtr; /* WL + BL / 2 + tWTR */ + u8 trd2wr = 5; + + if (trtp < tcl + 2 - trp) + trtp = tcl + 2 - trp; + + /* set mode register */ + writel(0x1c70, &mctl_ctl->mr[0]); /* CL=11, WR=12 */ + writel(0x2, &mctl_ctl->mr[1]); + writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */ + writel(0x0, &mctl_ctl->mr[3]); + + /* set DRAM timing */ + writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) | + DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras), + &mctl_ctl->dramtmg[0]); + writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc), + &mctl_ctl->dramtmg[1]); + writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) | + DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd), + &mctl_ctl->dramtmg[2]); + writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod), + &mctl_ctl->dramtmg[3]); + writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) | + DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]); + writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) | + DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke), + &mctl_ctl->dramtmg[5]); + + /* set two rank timing */ + clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xf0 << 24) | (0xff << 8) | (0xff << 0), + (0xf0 << 24) | (0x66 << 8) | (0x10 << 0)); + + + /* set PHY interface timing, write latency and read latency configure */ + writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) | + (wr_latency << 0), &mctl_ctl->pitmg[0]); + + /* set PHY timing, PTR0-2 use default */ + writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]); + writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]); + + /* set refresh timing */ + writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg[0]); + writel((trefi / 2) << 16, &mctl_ctl->rfshtmg[1]); +}

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
R329 has a new DRAM controller, which looks like a combination of the H6/H616 MCTL_COM part and the SUNXI_DW MCTL_CTL part. This design has already got reused by Allwinner, and V831/V833 SoCs have similar memory controller.
Add support for it. To prepare for further support of other SoCs, routines with socid parameter are added, although not checked now.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
I cannot really review the DRAM init part. But it works, so that's probably good enough.
Tested-by: Samuel Holland samuel@sholland.org
There are a couple of magic values I happen to have an explanation for:
diff --git a/arch/arm/mach-sunxi/dram_sun50i_r329.c b/arch/arm/mach-sunxi/dram_sun50i_r329.c new file mode 100644 index 0000000000..730883999c --- /dev/null +++ b/arch/arm/mach-sunxi/dram_sun50i_r329.c ...> +unsigned long sunxi_dram_init(void) +{
- struct sunxi_mctl_com_reg * const mctl_com =
(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
- struct sunxi_mctl_ctl_reg * const mctl_ctl =
(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
- struct dram_para para = {
.dual_rank = 0,
.bus_full_width = 1,
.row_bits = 16,
.bank_bits = 3,
.page_size = 8192,
.dx_read_delays = SUN50I_R329_DX_READ_DELAYS,
.dx_write_delays = SUN50I_R329_DX_WRITE_DELAYS,
.ac_delays = SUN50I_R329_AC_DELAYS,
- };
- /* Unknown magic */
- writel(0x10, 0x07010250);
This is VDD_SYS_POWEROFF_GATING_REG, presumably disabling pad hold.
- writel(0x330000, 0x07010310);
- writel(0x330003, 0x07010310);
This is a resistor calibration process. See here:
https://github.com/smaeul/sun20i_d1_spl/blob/342cb1d8/include/arch/cpu_ncat.... https://github.com/smaeul/sun20i_d1_spl/blob/342cb1d8/board/sun20iw1p1/clock...
Some other BSP code has:
#define REG_CALIB_CONTROL_REG 0x0310 #define OHMS200_REG 0x0314 #define OHMS240_REG 0x0318 #define REG_CALIB_STATUS_REG 0x031c
So this suggests we are calibrating the termination resistors.
Regards, Samuel
+#if defined(CONFIG_MACH_SUN50I_R329)
- uint16_t socid = SOCID_R329;
+#endif
- mctl_sys_init(¶);
- if (mctl_channel_init(socid, ¶))
return 0;
- udelay(1);
- clrbits_le32(&mctl_ctl->unk_0x0a0, 0xffff);
- clrbits_le32(&mctl_ctl->pwrctl, 0x1);
- /* HDR/DDR dynamic mode */
- clrbits_le32(&mctl_ctl->pgcr[0], 0xf000);
- /* power down zq calibration module for power save */
- setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
- /* DQ hold disable (tpr13[26] == 1) */
- clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
- mctl_auto_detect_dram_size(¶);
- mctl_apply_para(¶);
- /* enable master access */
- writel(0xffffffff, &mctl_com->maer0);
- writel(0x7f, &mctl_com->maer1);
- writel(0xffff, &mctl_com->maer2);
- return (1UL << (para.row_bits + para.bank_bits)) * para.page_size *
(para.dual_rank ? 2 : 1);
+}

As most code are ready for basic R329 support, let's add a Kconfig option for it.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/mach-sunxi/Kconfig | 14 +++++++++++++- arch/arm/mach-sunxi/cpu_info.c | 2 ++ common/spl/Kconfig | 1 + 3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index c9bb47a8bd..9d3ec82497 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -128,6 +128,7 @@ config SUN8I_RSB config SUNXI_SRAM_ADDRESS hex default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5 + default 0x100000 if MACH_SUN50I_R329 default 0x20000 if SUN50I_GEN_H6 default 0x0 ---help--- @@ -371,6 +372,12 @@ config MACH_SUN50I_H616 select DRAM_SUN50I_H616 select SUN50I_GEN_H6
+config MACH_SUN50I_R329 + bool "sun50i (Allwinner R329)" + select ARM64 + select DRAM_SUN50I_R329 + select SUN50I_GEN_H6 + endchoice
# The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" @@ -420,7 +427,8 @@ config SUNXI_DRAM_LPDDR3
choice prompt "DRAM Type and Timing" - default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S + default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S && !MACH_SUN50I_R329 + default SUNXI_DRAM_DDR3_R329 if MACH_SUN50I_R329 default SUNXI_DRAM_DDR2_V3S if MACH_SUN8I_V3S
config SUNXI_DRAM_DDR3_1333 @@ -488,6 +496,7 @@ config DRAM_CLK MACH_SUN8I_V3S default 672 if MACH_SUN50I default 744 if MACH_SUN50I_H6 + default 775 if MACH_SUN50I_R329 default 720 if MACH_SUN50I_H616 ---help--- Set the dram clock speed, valid range 240 - 480 (prior to sun9i), @@ -510,6 +519,7 @@ config DRAM_ZQ MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_A83T default 127 if MACH_SUN7I default 14779 if MACH_SUN8I_V3S + default 3067 if MACH_SUN50I_R329 default 3881979 if MACH_SUNXI_H3_H5 || MACH_SUN8I_R40 || MACH_SUN50I_H6 default 4145117 if MACH_SUN9I default 3881915 if MACH_SUN50I @@ -616,6 +626,7 @@ config SYS_CLK_FREQ default 1008000000 if MACH_SUN9I default 888000000 if MACH_SUN50I_H6 default 1008000000 if MACH_SUN50I_H616 + default 1008000000 if MACH_SUN50I_R329
config SYS_CONFIG_NAME default "sun4i" if MACH_SUN4I @@ -627,6 +638,7 @@ config SYS_CONFIG_NAME default "sun50i" if MACH_SUN50I default "sun50i" if MACH_SUN50I_H6 default "sun50i" if MACH_SUN50I_H616 + default "sun50i" if MACH_SUN50I_R329
config SYS_BOARD default "sunxi" diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c index ba33ef2430..8021f4c307 100644 --- a/arch/arm/mach-sunxi/cpu_info.c +++ b/arch/arm/mach-sunxi/cpu_info.c @@ -101,6 +101,8 @@ int print_cpuinfo(void) puts("CPU: Allwinner H6 (SUN50I)\n"); #elif defined CONFIG_MACH_SUN50I_H616 puts("CPU: Allwinner H616 (SUN50I)\n"); +#elif defined CONFIG_MACH_SUN50I_R329 + puts("CPU: Allwinner R329 (SUN50I)\n"); #else #warning Please update cpu_info.c with correct CPU information puts("CPU: SUNXI Family\n"); diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 2df3e5d869..ed4477ff93 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -150,6 +150,7 @@ config SPL_TEXT_BASE hex "SPL Text Base" default ISW_ENTRY_ADDR if AM43XX || AM33XX || OMAP54XX || ARCH_KEYSTONE default 0x10060 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN9I + default 0x100060 if MACH_SUN50I_R329 default 0x20060 if SUN50I_GEN_H6 default 0x00060 if ARCH_SUNXI default 0xfffc0000 if ARCH_ZYNQMP

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
As most code are ready for basic R329 support, let's add a Kconfig option for it.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
Reviewed-by: Samuel Holland samuel@sholland.org
with one minor comment below.
arch/arm/mach-sunxi/Kconfig | 14 +++++++++++++- arch/arm/mach-sunxi/cpu_info.c | 2 ++ common/spl/Kconfig | 1 + 3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index c9bb47a8bd..9d3ec82497 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -128,6 +128,7 @@ config SUN8I_RSB config SUNXI_SRAM_ADDRESS hex default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
- default 0x100000 if MACH_SUN50I_R329 default 0x20000 if SUN50I_GEN_H6 default 0x0 ---help---
@@ -371,6 +372,12 @@ config MACH_SUN50I_H616 select DRAM_SUN50I_H616 select SUN50I_GEN_H6
+config MACH_SUN50I_R329
- bool "sun50i (Allwinner R329)"
- select ARM64
- select DRAM_SUN50I_R329
- select SUN50I_GEN_H6
endchoice
# The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" @@ -420,7 +427,8 @@ config SUNXI_DRAM_LPDDR3
choice prompt "DRAM Type and Timing"
- default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S
- default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S && !MACH_SUN50I_R329
- default SUNXI_DRAM_DDR3_R329 if MACH_SUN50I_R329 default SUNXI_DRAM_DDR2_V3S if MACH_SUN8I_V3S
The first matching line is used, so you can reorder these to remove the negations.
Regards, Samuel
config SUNXI_DRAM_DDR3_1333 @@ -488,6 +496,7 @@ config DRAM_CLK MACH_SUN8I_V3S default 672 if MACH_SUN50I default 744 if MACH_SUN50I_H6
- default 775 if MACH_SUN50I_R329 default 720 if MACH_SUN50I_H616 ---help--- Set the dram clock speed, valid range 240 - 480 (prior to sun9i),
@@ -510,6 +519,7 @@ config DRAM_ZQ MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_A83T default 127 if MACH_SUN7I default 14779 if MACH_SUN8I_V3S
- default 3067 if MACH_SUN50I_R329 default 3881979 if MACH_SUNXI_H3_H5 || MACH_SUN8I_R40 || MACH_SUN50I_H6 default 4145117 if MACH_SUN9I default 3881915 if MACH_SUN50I
@@ -616,6 +626,7 @@ config SYS_CLK_FREQ default 1008000000 if MACH_SUN9I default 888000000 if MACH_SUN50I_H6 default 1008000000 if MACH_SUN50I_H616
- default 1008000000 if MACH_SUN50I_R329
config SYS_CONFIG_NAME default "sun4i" if MACH_SUN4I @@ -627,6 +638,7 @@ config SYS_CONFIG_NAME default "sun50i" if MACH_SUN50I default "sun50i" if MACH_SUN50I_H6 default "sun50i" if MACH_SUN50I_H616
- default "sun50i" if MACH_SUN50I_R329
config SYS_BOARD default "sunxi" diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c index ba33ef2430..8021f4c307 100644 --- a/arch/arm/mach-sunxi/cpu_info.c +++ b/arch/arm/mach-sunxi/cpu_info.c @@ -101,6 +101,8 @@ int print_cpuinfo(void) puts("CPU: Allwinner H6 (SUN50I)\n"); #elif defined CONFIG_MACH_SUN50I_H616 puts("CPU: Allwinner H616 (SUN50I)\n"); +#elif defined CONFIG_MACH_SUN50I_R329
- puts("CPU: Allwinner R329 (SUN50I)\n");
#else #warning Please update cpu_info.c with correct CPU information puts("CPU: SUNXI Family\n"); diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 2df3e5d869..ed4477ff93 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -150,6 +150,7 @@ config SPL_TEXT_BASE hex "SPL Text Base" default ISW_ENTRY_ADDR if AM43XX || AM33XX || OMAP54XX || ARCH_KEYSTONE default 0x10060 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN9I
- default 0x100060 if MACH_SUN50I_R329 default 0x20060 if SUN50I_GEN_H6 default 0x00060 if ARCH_SUNXI default 0xfffc0000 if ARCH_ZYNQMP

Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- include/dt-bindings/clock/sun50i-r329-ccu.h | 73 +++++++++++++++++++ include/dt-bindings/clock/sun50i-r329-r-ccu.h | 32 ++++++++ include/dt-bindings/reset/sun50i-r329-ccu.h | 45 ++++++++++++ include/dt-bindings/reset/sun50i-r329-r-ccu.h | 23 ++++++ 4 files changed, 173 insertions(+) create mode 100644 include/dt-bindings/clock/sun50i-r329-ccu.h create mode 100644 include/dt-bindings/clock/sun50i-r329-r-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-r329-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-r329-r-ccu.h
diff --git a/include/dt-bindings/clock/sun50i-r329-ccu.h b/include/dt-bindings/clock/sun50i-r329-ccu.h new file mode 100644 index 0000000000..769a40a175 --- /dev/null +++ b/include/dt-bindings/clock/sun50i-r329-ccu.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Sipeed + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_R329_CCU_H_ +#define _DT_BINDINGS_CLK_SUN50I_R329_CCU_H_ + +#define CLK_CPUX 1 + +#define CLK_APB1 5 + +#define CLK_CE 7 +#define CLK_BUS_CE 8 +#define CLK_AIPU 9 +#define CLK_BUS_VE 10 +#define CLK_BUS_DMA 11 +#define CLK_BUS_MSGBOX 12 +#define CLK_BUS_SPINLOCK 13 +#define CLK_BUS_HSTIMER 14 +#define CLK_AVS 15 +#define CLK_BUS_DBG 16 +#define CLK_BUS_PWM 17 + +#define CLK_MBUS_DMA 19 +#define CLK_MBUS_CE 20 +#define CLK_MBUS_NAND 21 +#define CLK_MBUS_CSI 22 +#define CLK_MBUS_ISP 23 + +#define CLK_NAND0 25 +#define CLK_NAND1 26 +#define CLK_BUS_NAND 27 +#define CLK_MMC0 28 +#define CLK_MMC1 29 +#define CLK_BUS_MMC0 30 +#define CLK_BUS_MMC1 31 +#define CLK_BUS_UART0 32 +#define CLK_BUS_UART1 33 +#define CLK_BUS_UART2 34 +#define CLK_BUS_UART3 35 +#define CLK_BUS_I2C0 36 +#define CLK_BUS_I2C1 37 +#define CLK_BUS_SCR 38 +#define CLK_SPI0 39 +#define CLK_SPI1 40 +#define CLK_BUS_SPI0 41 +#define CLK_BUS_SPI1 42 +#define CLK_EMAC_25M_DIV 43 +#define CLK_EMAC_25M 44 +#define CLK_BUS_EMAC 45 +#define CLK_IR_RX 46 +#define CLK_BUS_IR_RX 47 +#define CLK_IR_TX 48 +#define CLK_BUS_IR_TX 49 +#define CLK_I2S0 50 +#define CLK_I2S1 51 +#define CLK_BUS_I2S0 52 +#define CLK_BUS_I2S1 53 +#define CLK_SPDIF 54 +#define CLK_BUS_SPDIF 55 +#define CLK_USB_OHCI0 56 +#define CLK_USB_PHY0 57 +#define CLK_USB_OHCI1 58 +#define CLK_USB_PHY1 59 +#define CLK_BUS_OHCI0 60 +#define CLK_BUS_OHCI1 61 +#define CLK_BUS_EHCI0 62 +#define CLK_BUS_OTG 63 +#define CLK_LEDC 64 +#define CLK_BUS_LEDC 65 + +#endif /* _DT_BINDINGS_CLK_SUN50I_R329_CCU_H_ */ diff --git a/include/dt-bindings/clock/sun50i-r329-r-ccu.h b/include/dt-bindings/clock/sun50i-r329-r-ccu.h new file mode 100644 index 0000000000..2044d25383 --- /dev/null +++ b/include/dt-bindings/clock/sun50i-r329-r-ccu.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Sipeed + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_R329_R_CCU_H_ +#define _DT_BINDINGS_CLK_SUN50I_R329_R_CCU_H_ + +#define CLK_R_APB1 12 + +#define CLK_R_BUS_GPADC 14 +#define CLK_R_BUS_THS 15 +#define CLK_R_PWM 16 +#define CLK_R_BUS_PWM 17 +#define CLK_R_CODEC_ADC 18 +#define CLK_R_CODEC_DAC 19 +#define CLK_R_BUS_CODEC 20 +#define CLK_R_DMIC 21 +#define CLK_R_BUS_DMIC 22 +#define CLK_R_BUS_LRADC 23 +#define CLK_R_I2S 24 +#define CLK_R_I2S_ASRC 25 +#define CLK_R_BUS_I2S 26 +#define CLK_R_BUS_UART 27 +#define CLK_R_BUS_I2C 28 +#define CLK_R_IR 29 +#define CLK_R_BUS_IR 30 +#define CLK_R_BUS_MSGBOX 31 +#define CLK_R_BUS_SPINLOCK 32 +#define CLK_R_BUS_RTC 33 + +#endif /* _DT_BINDINGS_CLK_SUN50I_R329_R_CCU_H_ */ diff --git a/include/dt-bindings/reset/sun50i-r329-ccu.h b/include/dt-bindings/reset/sun50i-r329-ccu.h new file mode 100644 index 0000000000..bb704a8244 --- /dev/null +++ b/include/dt-bindings/reset/sun50i-r329-ccu.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* + * Copyright (c) 2021 Sipeed + */ + +#ifndef _DT_BINDINGS_RST_SUN50I_R329_CCU_H_ +#define _DT_BINDINGS_RST_SUN50I_R329_CCU_H_ + +#define RST_MBUS 0 +#define RST_BUS_CE 1 +#define RST_BUS_AIPU 2 +#define RST_BUS_DMA 3 +#define RST_BUS_MSGBOX 4 +#define RST_BUS_SPINLOCK 5 +#define RST_BUS_HSTIMER 6 +#define RST_BUS_DBG 7 +#define RST_BUS_PWM 8 +#define RST_BUS_DRAM 9 +#define RST_BUS_NAND 10 +#define RST_BUS_MMC0 11 +#define RST_BUS_MMC1 12 +#define RST_BUS_UART0 13 +#define RST_BUS_UART1 14 +#define RST_BUS_UART2 15 +#define RST_BUS_UART3 16 +#define RST_BUS_I2C0 17 +#define RST_BUS_I2C1 18 +#define RST_BUS_SCR 19 +#define RST_BUS_SPI0 20 +#define RST_BUS_SPI1 21 +#define RST_BUS_EMAC 22 +#define RST_BUS_IR_RX 23 +#define RST_BUS_IR_TX 24 +#define RST_BUS_I2S0 25 +#define RST_BUS_I2S1 26 +#define RST_BUS_SPDIF 27 +#define RST_USB_PHY0 28 +#define RST_USB_PHY1 29 +#define RST_BUS_OHCI0 30 +#define RST_BUS_OHCI1 31 +#define RST_BUS_EHCI0 32 +#define RST_BUS_OTG 33 +#define RST_BUS_LEDC 34 + +#endif /* _DT_BINDINGS_RST_SUN50I_R329_CCU_H_ */ diff --git a/include/dt-bindings/reset/sun50i-r329-r-ccu.h b/include/dt-bindings/reset/sun50i-r329-r-ccu.h new file mode 100644 index 0000000000..e65a317afb --- /dev/null +++ b/include/dt-bindings/reset/sun50i-r329-r-ccu.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* + * Copyright (c) 2021 Sipeed + */ + +#ifndef _DT_BINDINGS_RST_SUN50I_R329_R_CCU_H_ +#define _DT_BINDINGS_RST_SUN50I_R329_R_CCU_H_ + +#define RST_R_BUS_GPADC 0 +#define RST_R_BUS_THS 1 +#define RST_R_BUS_PWM 2 +#define RST_R_BUS_CODEC 3 +#define RST_R_BUS_DMIC 4 +#define RST_R_BUS_LRADC 5 +#define RST_R_BUS_I2S 6 +#define RST_R_BUS_UART 7 +#define RST_R_BUS_I2C 8 +#define RST_R_BUS_IR 9 +#define RST_R_BUS_MSGBOX 10 +#define RST_R_BUS_SPINLOCK 11 +#define RST_R_BUS_RTC 12 + +#endif /* _DT_BINDINGS_RST_SUN50I_R329_R_CCU_H_ */

Currently only a subset of clocks/resets (similar to other SoCs) are supported.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- drivers/clk/sunxi/Kconfig | 7 +++ drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_r329.c | 94 ++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 drivers/clk/sunxi/clk_r329.c
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index bf084fa7a8..8dd3be4683 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -86,6 +86,13 @@ config CLK_SUN50I_H616 This enables common clock driver support for platforms based on Allwinner H616 SoC.
+config CLK_SUN50I_R329 + bool "Clock driver for Allwinner R329" + default MACH_SUN50I_R329 + help + This enables common clock driver support for platforms based + on Allwinner R329 SoC. + config CLK_SUN50I_A64 bool "Clock driver for Allwinner A64" default MACH_SUN50I diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 4f9282a8b9..050f7ecc46 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o +obj-$(CONFIG_CLK_SUN50I_R329) += clk_r329.o obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o diff --git a/drivers/clk/sunxi/clk_r329.c b/drivers/clk/sunxi/clk_r329.c new file mode 100644 index 0000000000..17157214b6 --- /dev/null +++ b/drivers/clk/sunxi/clk_r329.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2021 Sipeed + * Based on clk_h616.c, which is: + * Copyright (C) 2021 Jernej Skrabec jernej.skrabec@siol.net + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <asm/arch/ccu.h> +#include <dt-bindings/clock/sun50i-r329-ccu.h> +#include <dt-bindings/reset/sun50i-r329-ccu.h> +#include <linux/bitops.h> + +static struct ccu_clk_gate r329_gates[] = { + [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), + [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), + + [CLK_BUS_UART0] = GATE(0x90c, BIT(0)), + [CLK_BUS_UART1] = GATE(0x90c, BIT(1)), + [CLK_BUS_UART2] = GATE(0x90c, BIT(2)), + [CLK_BUS_UART3] = GATE(0x90c, BIT(3)), + + [CLK_SPI0] = GATE(0x940, BIT(31)), + [CLK_SPI1] = GATE(0x944, BIT(31)), + + [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)), + [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)), + + [CLK_BUS_EMAC] = GATE(0x97c, BIT(0)), + + [CLK_USB_PHY0] = GATE(0xa70, BIT(29)), + [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)), + + [CLK_USB_PHY1] = GATE(0xa74, BIT(29)), + [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)), + + [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)), + [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)), + [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)), + [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)), +}; + +static struct ccu_reset r329_resets[] = { + [RST_BUS_MMC0] = RESET(0x84c, BIT(16)), + [RST_BUS_MMC1] = RESET(0x84c, BIT(17)), + + [RST_BUS_UART0] = RESET(0x90c, BIT(16)), + [RST_BUS_UART1] = RESET(0x90c, BIT(17)), + [RST_BUS_UART2] = RESET(0x90c, BIT(18)), + [RST_BUS_UART3] = RESET(0x90c, BIT(19)), + + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), + [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), + + [RST_BUS_EMAC] = RESET(0x97c, BIT(16)), + + [RST_USB_PHY0] = RESET(0xa70, BIT(30)), + + [RST_USB_PHY1] = RESET(0xa74, BIT(30)), + + [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)), + [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)), + [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)), + [RST_BUS_OTG] = RESET(0xa8c, BIT(24)), +}; + +static const struct ccu_desc r329_ccu_desc = { + .gates = r329_gates, + .resets = r329_resets, +}; + +static int r329_clk_bind(struct udevice *dev) +{ + return sunxi_reset_bind(dev, ARRAY_SIZE(r329_resets)); +} + +static const struct udevice_id r329_ccu_ids[] = { + { .compatible = "allwinner,sun50i-r329-ccu", + .data = (ulong)&r329_ccu_desc }, + { } +}; + +U_BOOT_DRIVER(clk_sun50i_r329) = { + .name = "sun50i_r329_ccu", + .id = UCLASS_CLK, + .of_match = r329_ccu_ids, + .priv_auto = sizeof(struct ccu_priv), + .ops = &sunxi_clk_ops, + .probe = sunxi_clk_probe, + .bind = r329_clk_bind, +};

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
Currently only a subset of clocks/resets (similar to other SoCs) are supported.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
Reviewed-by: Samuel Holland samuel@sholland.org
drivers/clk/sunxi/Kconfig | 7 +++ drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_r329.c | 94 ++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 drivers/clk/sunxi/clk_r329.c
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index bf084fa7a8..8dd3be4683 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -86,6 +86,13 @@ config CLK_SUN50I_H616 This enables common clock driver support for platforms based on Allwinner H616 SoC.
+config CLK_SUN50I_R329
- bool "Clock driver for Allwinner R329"
- default MACH_SUN50I_R329
- help
This enables common clock driver support for platforms based
on Allwinner R329 SoC.
config CLK_SUN50I_A64 bool "Clock driver for Allwinner A64" default MACH_SUN50I diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 4f9282a8b9..050f7ecc46 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o +obj-$(CONFIG_CLK_SUN50I_R329) += clk_r329.o obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o diff --git a/drivers/clk/sunxi/clk_r329.c b/drivers/clk/sunxi/clk_r329.c new file mode 100644 index 0000000000..17157214b6 --- /dev/null +++ b/drivers/clk/sunxi/clk_r329.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/*
- Copyright (C) 2021 Sipeed
- Based on clk_h616.c, which is:
- Copyright (C) 2021 Jernej Skrabec jernej.skrabec@siol.net
- */
+#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <asm/arch/ccu.h>
This will need to be updated when you rebase:
#include <clk/sunxi.h>
Regards, Samuel
+#include <dt-bindings/clock/sun50i-r329-ccu.h> +#include <dt-bindings/reset/sun50i-r329-ccu.h> +#include <linux/bitops.h>
+static struct ccu_clk_gate r329_gates[] = {
- [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)),
- [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)),
- [CLK_BUS_UART0] = GATE(0x90c, BIT(0)),
- [CLK_BUS_UART1] = GATE(0x90c, BIT(1)),
- [CLK_BUS_UART2] = GATE(0x90c, BIT(2)),
- [CLK_BUS_UART3] = GATE(0x90c, BIT(3)),
- [CLK_SPI0] = GATE(0x940, BIT(31)),
- [CLK_SPI1] = GATE(0x944, BIT(31)),
- [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)),
- [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)),
- [CLK_BUS_EMAC] = GATE(0x97c, BIT(0)),
- [CLK_USB_PHY0] = GATE(0xa70, BIT(29)),
- [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)),
- [CLK_USB_PHY1] = GATE(0xa74, BIT(29)),
- [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)),
- [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
- [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)),
- [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
- [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
+};
+static struct ccu_reset r329_resets[] = {
- [RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
- [RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
- [RST_BUS_UART0] = RESET(0x90c, BIT(16)),
- [RST_BUS_UART1] = RESET(0x90c, BIT(17)),
- [RST_BUS_UART2] = RESET(0x90c, BIT(18)),
- [RST_BUS_UART3] = RESET(0x90c, BIT(19)),
- [RST_BUS_SPI0] = RESET(0x96c, BIT(16)),
- [RST_BUS_SPI1] = RESET(0x96c, BIT(17)),
- [RST_BUS_EMAC] = RESET(0x97c, BIT(16)),
- [RST_USB_PHY0] = RESET(0xa70, BIT(30)),
- [RST_USB_PHY1] = RESET(0xa74, BIT(30)),
- [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
- [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)),
- [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
- [RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
+};
+static const struct ccu_desc r329_ccu_desc = {
- .gates = r329_gates,
- .resets = r329_resets,
+};
+static int r329_clk_bind(struct udevice *dev) +{
- return sunxi_reset_bind(dev, ARRAY_SIZE(r329_resets));
+}
+static const struct udevice_id r329_ccu_ids[] = {
- { .compatible = "allwinner,sun50i-r329-ccu",
.data = (ulong)&r329_ccu_desc },
- { }
+};
+U_BOOT_DRIVER(clk_sun50i_r329) = {
- .name = "sun50i_r329_ccu",
- .id = UCLASS_CLK,
- .of_match = r329_ccu_ids,
- .priv_auto = sizeof(struct ccu_priv),
- .ops = &sunxi_clk_ops,
- .probe = sunxi_clk_probe,
- .bind = r329_clk_bind,
+};

R329 SoC has similar MMC controllers with previous Allwinner SoCs.
Add support for it by adding its compatible string.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- drivers/mmc/sunxi_mmc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 6b809c001f..59cc28794d 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -734,6 +734,7 @@ static const struct udevice_id sunxi_mmc_ids[] = { { .compatible = "allwinner,sun50i-h6-emmc" }, { .compatible = "allwinner,sun50i-a100-mmc" }, { .compatible = "allwinner,sun50i-a100-emmc" }, + { .compatible = "allwinner,sun50i-r329-mmc" }, { /* sentinel */ } };

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
R329 SoC has similar MMC controllers with previous Allwinner SoCs.
Add support for it by adding its compatible string.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
It really is that simple; as far as I can tell, the other checks are covered by CONFIG_SUN50I_GEN_H6.
Reviewed-by: Samuel Holland samuel@sholland.org
drivers/mmc/sunxi_mmc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 6b809c001f..59cc28794d 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -734,6 +734,7 @@ static const struct udevice_id sunxi_mmc_ids[] = { { .compatible = "allwinner,sun50i-h6-emmc" }, { .compatible = "allwinner,sun50i-a100-mmc" }, { .compatible = "allwinner,sun50i-a100-emmc" },
- { .compatible = "allwinner,sun50i-r329-mmc" }, { /* sentinel */ }
};

Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- arch/arm/dts/Makefile | 2 + arch/arm/dts/sun50i-r329-maix-iia-dock.dts | 36 ++++ arch/arm/dts/sun50i-r329-maix-iia.dtsi | 45 +++++ arch/arm/dts/sun50i-r329.dtsi | 225 +++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 arch/arm/dts/sun50i-r329-maix-iia-dock.dts create mode 100644 arch/arm/dts/sun50i-r329-maix-iia.dtsi create mode 100644 arch/arm/dts/sun50i-r329.dtsi
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 3941a08cf4..cfafb80a5f 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -643,6 +643,8 @@ dtb-$(CONFIG_MACH_SUN50I_H6) += \ sun50i-h6-tanix-tx6.dtb dtb-$(CONFIG_MACH_SUN50I_H616) += \ sun50i-h616-orangepi-zero2.dtb +dtb-$(CONFIG_MACH_SUN50I_R329) += \ + sun50i-r329-maix-iia-dock.dtb dtb-$(CONFIG_MACH_SUN50I) += \ sun50i-a64-amarula-relic.dtb \ sun50i-a64-bananapi-m64.dtb \ diff --git a/arch/arm/dts/sun50i-r329-maix-iia-dock.dts b/arch/arm/dts/sun50i-r329-maix-iia-dock.dts new file mode 100644 index 0000000000..2588eb6adb --- /dev/null +++ b/arch/arm/dts/sun50i-r329-maix-iia-dock.dts @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (c) 2021 Sipeed + +/dts-v1/; + +#include "sun50i-r329-maix-iia.dtsi" + +/ { + model = "Sipeed MAIX-II A Dock"; + compatible = "sipeed,maix-iia-dock", "sipeed,maix-iia", + "allwinner,sun50i-r329"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pf_pins>; + + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + status = "okay"; +}; diff --git a/arch/arm/dts/sun50i-r329-maix-iia.dtsi b/arch/arm/dts/sun50i-r329-maix-iia.dtsi new file mode 100644 index 0000000000..ac5c5a88d3 --- /dev/null +++ b/arch/arm/dts/sun50i-r329-maix-iia.dtsi @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (c) 2021 Sipeed + +#include "sun50i-r329.dtsi" + +#include <dt-bindings/gpio/gpio.h> + +/ { + ext_osc32k: ext_osc32k_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "ext_osc32k"; + }; + + reg_vcc3v3: vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&r_pio 1 0 GPIO_ACTIVE_LOW>; /* PM0 */ + post-power-on-delay-ms = <200>; + }; +}; + +&rtc { + clocks = <&ext_osc32k>; +}; + +&mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_clk_pg0>, <&mmc1_cmd_pg1>, <&mmc1_d0_pg2>, + <&mmc1_d1_pg3>, <&mmc1_d2_pg4>, <&mmc1_d3_pg5>; + + vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + non-removable; + status = "okay"; +}; diff --git a/arch/arm/dts/sun50i-r329.dtsi b/arch/arm/dts/sun50i-r329.dtsi new file mode 100644 index 0000000000..b4752020df --- /dev/null +++ b/arch/arm/dts/sun50i-r329.dtsi @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (c) 2021 Sipeed + +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/clock/sun50i-r329-ccu.h> +#include <dt-bindings/reset/sun50i-r329-ccu.h> +#include <dt-bindings/clock/sun50i-r329-r-ccu.h> +#include <dt-bindings/reset/sun50i-r329-r-ccu.h> + +/ { + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0>; + enable-method = "psci"; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <1>; + enable-method = "psci"; + }; + }; + + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + arm,no-tick-in-suspend; + interrupts = <GIC_PPI 13 + (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 14 + (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 11 + (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>, + <GIC_PPI 10 + (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pio: pinctrl@2000400 { + compatible = "allwinner,sun50i-r329-pinctrl"; + reg = <0x02000400 0x400>; + interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc 0>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + + uart0_pb_pins: uart0-pb-pins { + pins = "PB4", "PB5"; + function = "uart0"; + }; + + mmc0_pf_pins: mmc0-pf-pins { + pins = "PF0", "PF1", "PF2", + "PF3", "PF4", "PF5"; + function = "mmc0"; + }; + + mmc1_clk_pg0: mmc1-clk-pg0 { + pins = "PG0"; + function = "mmc1_clk"; + }; + + mmc1_cmd_pg1: mmc1-clk-pg1 { + pins = "PG1"; + function = "mmc1_cmd"; + }; + + mmc1_d0_pg2: mmc1-clk-pg2 { + pins = "PG2"; + function = "mmc1_d0"; + }; + + mmc1_d1_pg3: mmc1-clk-pg3 { + pins = "PG3"; + function = "mmc1_d1"; + }; + + mmc1_d2_pg4: mmc1-clk-pg4 { + pins = "PG4"; + function = "mmc1_d2"; + }; + + mmc1_d3_pg5: mmc1-clk-pg5 { + pins = "PG5"; + function = "mmc1_d3"; + }; + + spi1_cs_ph0: spi1-cs-ph0 { + pins = "PH0"; + function = "spi1"; + }; + + spi1_clk_ph1: spi1-clk-ph1 { + pins = "PH1"; + function = "spi1"; + }; + + spi1_mosi_ph2: spi1-mosi-ph2 { + pins = "PH2"; + function = "spi1"; + }; + }; + + ccu: clock@2001000 { + compatible = "allwinner,sun50i-r329-ccu"; + reg = <0x02001000 0x1000>; + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>; + clock-names = "hosc", "losc", "iosc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + uart0: serial@2500000 { + compatible = "snps,dw-apb-uart"; + reg = <0x02500000 0x400>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART0>; + resets = <&ccu RST_BUS_UART0>; + }; + + gic: interrupt-controller@3021000 { + compatible = "arm,gic-400"; + reg = <0x03021000 0x1000>, + <0x03022000 0x2000>, + <0x03024000 0x2000>, + <0x03026000 0x2000>; + interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + mmc0: mmc@4020000 { + compatible = "allwinner,sun50i-r329-mmc"; + reg = <0x04020000 0x1000>; + clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>; + clock-names = "ahb", "mmc"; + resets = <&ccu RST_BUS_MMC0>; + reset-names = "ahb"; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + max-frequency = <150000000>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc1: mmc@4021000 { + compatible = "allwinner,sun50i-r329-mmc"; + reg = <0x04021000 0x1000>; + clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>; + clock-names = "ahb", "mmc"; + resets = <&ccu RST_BUS_MMC1>; + reset-names = "ahb"; + interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + max-frequency = <150000000>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + r_ccu: clock@7010000 { + compatible = "allwinner,sun50i-r329-r-ccu"; + reg = <0x07010000 0x10000>; + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>; + clock-names = "hosc", "losc", "iosc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + r_pio: pinctrl@7022000 { + compatible = "allwinner,sun50i-r329-r-pinctrl"; + reg = <0x07022000 0x400>; + interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + rtc: rtc@7090000 { + compatible = "allwinner,sun50i-r329-rtc"; + reg = <0x07090000 0x400>; + interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; + clock-output-names = "osc32k", "osc32k-out", "iosc"; + #clock-cells = <1>; + }; + }; +};

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
Signed-off-by: Icenowy Zheng icenowy@sipeed.com
arch/arm/dts/Makefile | 2 + arch/arm/dts/sun50i-r329-maix-iia-dock.dts | 36 ++++ arch/arm/dts/sun50i-r329-maix-iia.dtsi | 45 +++++ arch/arm/dts/sun50i-r329.dtsi | 225 +++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 arch/arm/dts/sun50i-r329-maix-iia-dock.dts create mode 100644 arch/arm/dts/sun50i-r329-maix-iia.dtsi create mode 100644 arch/arm/dts/sun50i-r329.dtsi
One thing to note when you rebase: you will need to add the watchdog node for rebooting to work.
Regards, Samuel

Maix IIA is a SoM by Sipeed, and a official baseboard is sold with it.
Add support for this official baseboard with Maix IIA attached.
Signed-off-by: Icenowy Zheng icenowy@sipeed.com --- board/sunxi/MAINTAINERS | 5 +++++ configs/sipeed_maix_iia_dock_defconfig | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 configs/sipeed_maix_iia_dock_defconfig
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index 4fc26077b2..ae7c6a131a 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -493,6 +493,11 @@ M: VishnuPatekar vishnupatekar0510@gmail.com S: Maintained F: configs/Sinovoip_BPI_M3_defconfig
+SIPEED MAIX IIA DOCK BOARD +M: Icenowy Zheng icenowy@sipeed.com +S: Maintained +F: configs/sipeed_maix_iia_dock_defconfig + SOPINE BOARD M: Icenowy Zheng icenowy@aosc.io S: Maintained diff --git a/configs/sipeed_maix_iia_dock_defconfig b/configs/sipeed_maix_iia_dock_defconfig new file mode 100644 index 0000000000..a839f65e10 --- /dev/null +++ b/configs/sipeed_maix_iia_dock_defconfig @@ -0,0 +1,8 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="sun50i-r329-maix-iia-dock" +CONFIG_SPL=y +CONFIG_MACH_SUN50I_R329=y +CONFIG_MMC0_CD_PIN="PF6" +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_ENV_FAT_DEVICE_AND_PART="1:auto"

On 7/22/21 1:30 AM, Icenowy Zheng wrote:
This patchset adds Allwinner R329 support to U-Boot.
First, some code refactors happen for SoCs w/o SCP/MMC2.
Then the basical support for R329 come as several parts (memory map, clocks, pinmux, DRAM, final Kconfig option).
Then, as the RFC part of this patchset, some device tree related changes.
Finally it comes the defconfig file for a R329 board, Sipeed Maix IIA Dock.
I was able to boot into Linux on my MaixSense, but I also needed the top patch from your branch here:
https://github.com/sipeed/u-boot/commits/r329-wip
Otherwise, U-Boot complained that $kernel_addr_r overlapped reserved memory.
This patchset is RFC mainly because of the DT-related part, as no DT binding is mainlined in Linux now (it's still WIP). All other patches are ready for being reviewed and, if proper, merged.
Yes, I would like to have the Kconfig available so I can support R329 in my pinctrl series.
Regards, Samuel
participants (3)
-
Andre Przywara
-
Icenowy Zheng
-
Samuel Holland