diff options
40 files changed, 4094 insertions, 62 deletions
diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S index 6a7ec9a7ec1..ccddfaaf04c 100644 --- a/arch/arm/cpu/armv8/fel_utils.S +++ b/arch/arm/cpu/armv8/fel_utils.S @@ -41,10 +41,11 @@ ENTRY(return_to_fel) str w2, [x1] ldr w0, =0xfa50392f // CPU hotplug magic -#if defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_A133) +#if defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_A133) || \ + defined(CONFIG_MACH_SUN55I_A523) ldr w2, =(SUNXI_R_CPUCFG_BASE + 0x1c0) str w0, [x2], #0x4 -#elif CONFIG_MACH_SUN50I_H6 +#elif defined(CONFIG_MACH_SUN50I_H6) ldr w2, =(SUNXI_RTC_BASE + 0x1b8) // BOOT_CPU_HP_FLAG_REG str w0, [x2], #0x4 #else 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 575dff68804..45fa4ab6e57 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -13,6 +13,7 @@ #include <linux/bitops.h> #endif +/* Main CCU register offsets */ #define CCU_H6_PLL1_CFG 0x000 #define CCU_H6_PLL5_CFG 0x010 #define CCU_H6_PLL6_CFG 0x020 @@ -31,29 +32,39 @@ #define CCU_H6_UART_GATE_RESET 0x90c #define CCU_H6_I2C_GATE_RESET 0x91c -/* pll1 bit field */ -#define CCM_PLL1_CTRL_EN BIT(31) -#define CCM_PLL1_LDO_EN BIT(30) -#define CCM_PLL1_LOCK_EN BIT(29) -#define CCM_PLL1_LOCK BIT(28) -#define CCM_PLL1_OUT_EN BIT(27) -#define CCM_PLL1_CLOCK_TIME_2 (2 << 24) +/* A523 CPU PLL offsets */ +#define CPC_CPUA_PLL_CTRL 0x04 +#define CPC_DSU_PLL_CTRL 0x08 +#define CPC_CPUB_PLL_CTRL 0x0c +#define CPC_CPUA_CLK_REG 0x60 +#define CPC_CPUB_CLK_REG 0x64 +#define CPC_DSU_CLK_REG 0x6c + +/* PLL bit fields */ +#define CCM_PLL_CTRL_EN BIT(31) +#define CCM_PLL_LDO_EN BIT(30) +#define CCM_PLL_LOCK_EN BIT(29) +#define CCM_PLL_LOCK BIT(28) +#define CCM_PLL_OUT_EN BIT(27) +#define CCM_PLL1_UPDATE BIT(26) #define CCM_PLL1_CTRL_P(p) ((p) << 16) +#define CCM_PLL1_CTRL_N_MASK GENMASK(15, 8) #define CCM_PLL1_CTRL_N(n) (((n) - 1) << 8) +/* A523 CPU clock fields */ +#define CPU_CLK_SRC_HOSC (0 << 24) +#define CPU_CLK_SRC_CPUPLL (3 << 24) +#define CPU_CLK_CTRL_P(p) ((p) << 16) +#define CPU_CLK_APB_DIV(n) (((n) - 1) << 8) +#define CPU_CLK_PERI_DIV(m1) (((m1) - 1) << 2) +#define CPU_CLK_AXI_DIV(m) (((m) - 1) << 0) + /* pll5 bit field */ -#define CCM_PLL5_CTRL_EN BIT(31) -#define CCM_PLL5_LOCK_EN BIT(29) -#define CCM_PLL5_LOCK BIT(28) -#define CCM_PLL5_OUT_EN BIT(27) #define CCM_PLL5_CTRL_N(n) (((n) - 1) << 8) #define CCM_PLL5_CTRL_DIV1(div1) ((div1) << 0) #define CCM_PLL5_CTRL_DIV2(div0) ((div0) << 1) /* pll6 bit field */ -#define CCM_PLL6_CTRL_EN BIT(31) -#define CCM_PLL6_LOCK_EN BIT(29) -#define CCM_PLL6_LOCK BIT(28) #define CCM_PLL6_CTRL_P0_SHIFT 16 #define CCM_PLL6_CTRL_P0_MASK (0x7 << CCM_PLL6_CTRL_P0_SHIFT) #define CCM_PLL6_CTRL_N_SHIFT 8 @@ -97,6 +108,13 @@ #define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000002 #define CCM_AHB3_DEFAULT 0x03000002 #define CCM_APB1_DEFAULT 0x03000102 + +#elif CONFIG_MACH_SUN55I_A523 /* A523 */ + +#define CCM_PLL6_DEFAULT 0xe8216310 /* 1200 MHz */ +#define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000002 /* 200 MHz */ +#define CCM_APB1_DEFAULT 0x03000005 /* APB0 really */ +#define CCM_APB2_DEFAULT 0x03000005 /* APB1 really */ #endif /* apb2 bit field */ @@ -116,6 +134,7 @@ /* MBUS clock bit field */ #define MBUS_ENABLE BIT(31) #define MBUS_RESET BIT(30) +#define MBUS_UPDATE BIT(27) #define MBUS_CLK_SRC_MASK GENMASK(25, 24) #define MBUS_CLK_SRC_OSCM24 (0 << 24) #define MBUS_CLK_SRC_PLL6X2 (1 << 24) @@ -128,10 +147,12 @@ #define GATE_SHIFT (0) /* DRAM clock bit field */ +#define DRAM_CLK_ENABLE BIT(31) #define DRAM_MOD_RESET BIT(30) #define DRAM_CLK_UPDATE BIT(27) #define DRAM_CLK_SRC_MASK GENMASK(25, 24) #define DRAM_CLK_SRC_PLL5 (0 << 24) +#define DRAM_CLK_M_MASK (0x1f) #define DRAM_CLK_M(m) (((m)-1) << 0) /* MMC clock bit field */ diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h index 908a582ae0f..bcfdc0a41c5 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h @@ -21,14 +21,34 @@ #define SUNXI_SID_BASE 0x03006200 #define SUNXI_GIC400_BASE 0x03020000 +#ifdef CONFIG_MACH_SUN55I_A523 +#define SUNXI_DRAM_COM_BASE 0x03120000 +#define SUNXI_DRAM_CTL0_BASE 0x03130000 +#define SUNXI_DRAM_PHY0_BASE 0x03140000 +#endif + #define SUNXI_MMC0_BASE 0x04020000 #define SUNXI_MMC1_BASE 0x04021000 #define SUNXI_MMC2_BASE 0x04022000 +#ifndef CONFIG_MACH_SUN55I_A523 #define SUNXI_R_CPUCFG_BASE 0x07000400 +#endif #define SUNXI_PRCM_BASE 0x07010000 +#define SUNXI_R_WDOG_BASE 0x07020400 +#ifdef CONFIG_MACH_SUN55I_A523 +#define SUNXI_R_CPUCFG_BASE 0x07050000 +#endif +#define SUNXI_R_TWI_BASE 0x07081400 +#define SUNXI_RTC_BASE 0x07090000 +#ifdef CONFIG_MACH_SUN55I_A523 +#define SUNXI_CPUCFG_BASE 0x08815000 +#else #define SUNXI_CPUCFG_BASE 0x09010000 +#endif + +#define SUNXI_CPU_PLL_CFG_BASE 0x08817000 #ifndef __ASSEMBLY__ void sunxi_board_init(void); diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 0708ae3ee3b..0eccb1e6c28 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -35,6 +35,8 @@ #include <asm/arch/dram_sun50i_a133.h> #elif defined(CONFIG_MACH_SUNIV) #include <asm/arch/dram_suniv.h> +#elif defined(CONFIG_MACH_SUN55I_A523) +#include <asm/arch/dram_sun55i_a523.h> #else #include <asm/arch/dram_sun4i.h> #endif diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h b/arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h new file mode 100644 index 00000000000..08bfe462856 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/dram_sun55i_a523.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * t527 dram controller register and constant defines + * + * (C) Copyright 2024 Jernej Skrabec <jernej.skrabec@gmail.com> + */ + +#ifndef _SUNXI_DRAM_SUN55I_A523_H +#define _SUNXI_DRAM_SUN55I_A523_H + +#include <linux/bitops.h> + +enum sunxi_dram_type { + SUNXI_DRAM_TYPE_DDR3 = 3, + SUNXI_DRAM_TYPE_DDR4, + SUNXI_DRAM_TYPE_LPDDR3 = 7, + SUNXI_DRAM_TYPE_LPDDR4 +}; + +#define MCTL_COM_UNK_008 0x008 +#define MCTL_COM_MAER0 0x020 + +/* + * Controller registers seems to be the same or at least very similar + * to those in H6. + */ +struct sunxi_mctl_ctl_reg { + u32 mstr; /* 0x000 */ + u32 statr; /* 0x004 unused */ + u32 mstr1; /* 0x008 unused */ + u32 clken; /* 0x00c */ + u32 mrctrl0; /* 0x010 unused */ + u32 mrctrl1; /* 0x014 unused */ + u32 mrstatr; /* 0x018 unused */ + u32 mrctrl2; /* 0x01c unused */ + u32 derateen; /* 0x020 unused */ + u32 derateint; /* 0x024 unused */ + u8 reserved_0x028[8]; /* 0x028 */ + u32 pwrctl; /* 0x030 */ + u32 pwrtmg; /* 0x034 unused */ + u32 hwlpctl; /* 0x038 */ + u8 reserved_0x03c[20]; /* 0x03c */ + u32 rfshctl0; /* 0x050 unused */ + u32 rfshctl1; /* 0x054 unused */ + u8 reserved_0x058[8]; /* 0x058 */ + u32 rfshctl3; /* 0x060 */ + u32 rfshtmg; /* 0x064 */ + u8 reserved_0x068[104]; /* 0x068 */ + u32 init[8]; /* 0x0d0 */ + u32 dimmctl; /* 0x0f0 unused */ + u32 rankctl; /* 0x0f4 */ + u8 reserved_0x0f8[8]; /* 0x0f8 */ + u32 dramtmg[17]; /* 0x100 */ + u8 reserved_0x144[60]; /* 0x144 */ + u32 zqctl[3]; /* 0x180 */ + u32 zqstat; /* 0x18c unused */ + u32 dfitmg0; /* 0x190 */ + u32 dfitmg1; /* 0x194 */ + u32 dfilpcfg[2]; /* 0x198 unused */ + u32 dfiupd[3]; /* 0x1a0 */ + u32 reserved_0x1ac; /* 0x1ac */ + u32 dfimisc; /* 0x1b0 */ + u32 dfitmg2; /* 0x1b4 unused */ + u32 dfitmg3; /* 0x1b8 unused */ + u32 dfistat; /* 0x1bc */ + u32 dbictl; /* 0x1c0 */ + u8 reserved_0x1c4[60]; /* 0x1c4 */ + u32 addrmap[12]; /* 0x200 */ + u8 reserved_0x230[16]; /* 0x230 */ + u32 odtcfg; /* 0x240 */ + u32 odtmap; /* 0x244 */ + u8 reserved_0x248[8]; /* 0x248 */ + u32 sched[2]; /* 0x250 */ + u8 reserved_0x258[12]; /* 0x258 */ + u32 unk_0x264; /* 0x264 */ + u8 reserved_0x268[8]; /* 0x268 */ + u32 unk_0x270; /* 0x270 */ + u8 reserved_0x274[152]; /* 0x274 */ + u32 dbgcmd; /* 0x30c unused */ + u32 dbgstat; /* 0x310 unused */ + u8 reserved_0x314[12]; /* 0x314 */ + u32 swctl; /* 0x320 */ + u32 swstat; /* 0x324 */ + u8 reserved_0x328[7768];/* 0x328 */ + u32 unk_0x2180; /* 0x2180 */ + u8 reserved_0x2184[188];/* 0x2184 */ + u32 unk_0x2240; /* 0x2240 */ + u8 reserved_0x2244[3900];/* 0x2244 */ + u32 unk_0x3180; /* 0x3180 */ + u8 reserved_0x3184[188];/* 0x3184 */ + u32 unk_0x3240; /* 0x3240 */ + u8 reserved_0x3244[3900];/* 0x3244 */ + u32 unk_0x4180; /* 0x4180 */ + u8 reserved_0x4184[188];/* 0x4184 */ + u32 unk_0x4240; /* 0x4240 */ +}; +check_member(sunxi_mctl_ctl_reg, swstat, 0x324); +check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240); + +#define MSTR_DEVICETYPE_DDR3 BIT(0) +#define MSTR_DEVICETYPE_LPDDR2 BIT(2) +#define MSTR_DEVICETYPE_LPDDR3 BIT(3) +#define MSTR_DEVICETYPE_DDR4 BIT(4) +#define MSTR_DEVICETYPE_LPDDR4 BIT(5) +#define MSTR_DEVICETYPE_MASK GENMASK(5, 0) +#define MSTR_2TMODE BIT(10) +#define MSTR_BUSWIDTH_FULL (0 << 12) +#define MSTR_BUSWIDTH_HALF (1 << 12) +#define MSTR_ACTIVE_RANKS(x) ((((x) == 2) ? 3 : 1) << 24) +#define MSTR_BURST_LENGTH(x) (((x) >> 1) << 16) + +#define TPR10_CA_BIT_DELAY 0xffff0000 +#define TPR10_DX_BIT_DELAY0 BIT(17) +#define TPR10_DX_BIT_DELAY1 BIT(18) +#define TPR10_WRITE_LEVELING BIT(20) +#define TPR10_READ_CALIBRATION BIT(21) +#define TPR10_READ_TRAINING BIT(22) +#define TPR10_WRITE_TRAINING BIT(23) + +struct dram_para { + enum sunxi_dram_type type; + u32 dx_odt; + u32 dx_dri; + u32 ca_dri; + u32 tpr0; + u32 tpr1; + u32 tpr2; + u32 tpr6; + u32 tpr10; +}; + +struct dram_config { + u8 cols; + u8 rows; + u8 ranks; + u8 bus_full_width; + u32 clk; + u32 odt_en; + u32 tpr11; + u32 tpr12; + u32 tpr14; +}; + +static inline int ns_to_t(int nanoseconds, u32 clk) +{ + const unsigned int ctrl_freq = clk / 2; + + return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); +} + +void mctl_set_timing_params(u32 clk); + +#endif /* _SUNXI_DRAM_SUN55I_T527_H */ diff --git a/arch/arm/include/asm/arch-sunxi/watchdog.h b/arch/arm/include/asm/arch-sunxi/watchdog.h index 38e2ef2aca3..14a6e89ccfa 100644 --- a/arch/arm/include/asm/arch-sunxi/watchdog.h +++ b/arch/arm/include/asm/arch-sunxi/watchdog.h @@ -12,6 +12,8 @@ #define WDT_CTRL_RESTART (0x1 << 0) #define WDT_CTRL_KEY (0x0a57 << 1) +#define WDT_SRST_REG 0x08 + #if defined(CONFIG_MACH_SUN4I) || \ defined(CONFIG_MACH_SUN5I) || \ defined(CONFIG_MACH_SUN7I) || \ diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 0a7c029b15a..6a511c4fd39 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -57,7 +57,12 @@ config DRAM_SUN50I_A133 Select this dram controller driver for some sun50i platforms, like A133. -if DRAM_SUN50I_H616 || DRAM_SUN50I_A133 +config DRAM_SUN55I_A523 + bool + help + Select this DRAM controller driver for A523/T527 SoCs. + +if DRAM_SUN50I_H616 || DRAM_SUN50I_A133 || DRAM_SUN55I_A523 config DRAM_SUNXI_DX_ODT hex "DRAM DX ODT parameter" help @@ -170,8 +175,8 @@ config DRAM_SUNXI_TPR13 config DRAM_SUNXI_TPR14 hex "DRAM TPR14 parameter" - depends on DRAM_SUN50I_A133 - default 0x0 + depends on DRAM_SUN50I_A133 || MACH_SUN55I_A523 + default 0x48484848 help TPR14 value from vendor DRAM settings. @@ -209,6 +214,7 @@ config AXP_PMIC_BUS config SUNXI_SRAM_ADDRESS hex default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5 + default 0x44000 if MACH_SUN55I_A523 default 0x20000 if SUN50I_GEN_H6 || SUNXI_GEN_NCAT2 default 0x0 ---help--- @@ -221,6 +227,7 @@ config SUNXI_RVBAR_ADDRESS hex depends on ARM64 default 0x08100040 if MACH_SUN50I_A133 + default 0x08000040 if MACH_SUN55I_A523 default 0x09010040 if SUN50I_GEN_H6 default 0x017000a0 ---help--- @@ -249,6 +256,7 @@ config SUNXI_BL31_BASE default 0x00044000 if MACH_SUN50I || MACH_SUN50I_H5 default 0x40000000 if MACH_SUN50I_H616 default 0x00104000 if SUN50I_GEN_H6 + default 0x00054000 if MACH_SUN55I_A523 default 0x0 help Address where BL31 (TF-A) is loaded, or zero if BL31 is not used. @@ -330,7 +338,7 @@ config MACH_SUNXI_H3_H5 # TODO: try out A80's 8GiB DRAM space config SUNXI_DRAM_MAX_SIZE hex - default 0x100000000 if MACH_SUN50I_H616 || MACH_SUN50I_A133 + default 0x100000000 if MACH_SUN50I_H616 || MACH_SUN50I_A133 || MACH_SUN55I_A523 default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 default 0x80000000 @@ -532,6 +540,16 @@ config MACH_SUN50I_A133 select SUN50I_GEN_H6 imply OF_UPSTREAM +config MACH_SUN55I_A523 + bool "sun55i (Allwinner A523/A527/T527/H728)" + select ARM64 + select SUNXI_GEN_NCAT2 + select SUNXI_NEW_PINCTRL + select DRAM_SUN55I_A523 + select FIT + select SPL_LOAD_FIT if SPL + imply OF_UPSTREAM + endchoice # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" @@ -569,7 +587,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 || DRAM_SUN50I_H616 || DRAM_SUN50I_A133 +if SUNXI_DRAM_DW || DRAM_SUN50I_H6 || DRAM_SUN50I_H616 || DRAM_SUN50I_A133 || DRAM_SUN55I_A523 config SUNXI_DRAM_DDR3 bool @@ -587,6 +605,7 @@ config SUNXI_DRAM_DDR4 choice prompt "DRAM Type and Timing" + default SUNXI_DRAM_A523_LPDDR4 if MACH_SUN55I_A523 default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S default SUNXI_DRAM_DDR2_V3S if MACH_SUN8I_V3S @@ -670,6 +689,21 @@ config SUNXI_DRAM_DDR2_V3S This option is only for the DDR2 memory chip which is co-packaged in Allwinner V3s SoC. +config SUNXI_DRAM_A523_DDR3 + bool "DDR3 DRAM chips on the A523/T527 DRAM controller" + select SUNXI_DRAM_DDR3 + depends on DRAM_SUN55I_A523 + help + This option is the DDR3 timing used by the stock boot0 by + Allwinner. + +config SUNXI_DRAM_A523_LPDDR4 + bool "LPDDR4 DRAM chips on the A523/T527 DRAM controller" + select SUNXI_DRAM_LPDDR4 + depends on DRAM_SUN55I_A523 + help + This option is the LPDDR4 timing used by the stock boot0 by + Allwinner. endchoice endif @@ -690,6 +724,7 @@ config DRAM_CLK default 672 if MACH_SUN50I default 744 if MACH_SUN50I_H6 default 720 if MACH_SUN50I_H616 || MACH_SUN50I_A133 + default 1200 if MACH_SUN55I_A523 ---help--- Set the dram clock speed, valid range 240 - 480 (prior to sun9i), must be a multiple of 24. For the sun9i (A80), the tested values @@ -706,7 +741,9 @@ endif config DRAM_ZQ int "sunxi dram zq value" - depends on !MACH_SUN50I_H616 && !MACH_SUN50I_A133 + depends on !MACH_SUN50I_H616 + depends on !MACH_SUN50I_A133 + depends on !MACH_SUN55I_A523 default 123 if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || \ MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_A83T default 127 if MACH_SUN7I @@ -720,6 +757,7 @@ config DRAM_ZQ config DRAM_ODT_EN bool "sunxi dram odt enable" depends on !MACH_SUN50I_H616 + depends on !MACH_SUN55I_A523 default y if MACH_SUN8I_A23 default y if MACH_SUNXI_H3_H5 default y if MACH_SUN8I_R40 @@ -809,6 +847,7 @@ endif config SYS_CLK_FREQ default 408000000 if MACH_SUNIV + default 792000000 if MACH_SUN55I_A523 default 816000000 if MACH_SUN50I || MACH_SUN50I_H5 default 888000000 if MACH_SUN50I_H6 default 912000000 if MACH_SUN7I @@ -827,6 +866,7 @@ config SYS_CONFIG_NAME default "sun50i" if MACH_SUN50I_H6 default "sun50i" if MACH_SUN50I_H616 default "sun50i" if MACH_SUN50I_A133 + default "sun55i" if MACH_SUN55I_A523 config SYS_BOARD default "sunxi" @@ -893,7 +933,7 @@ config I2C1_ENABLE ---help--- See I2C0_ENABLE help text. -if SUNXI_GEN_SUN6I || SUN50I_GEN_H6 +if SUNXI_GEN_SUN6I || SUN50I_GEN_H6 || SUNXI_GEN_NCAT2 config R_I2C_ENABLE bool "Enable the PRCM I2C/TWI controller" # This is used for the pmic on H3 diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 8eff20b77bf..579530f27e3 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -47,4 +47,6 @@ obj-$(CONFIG_DRAM_SUN50I_H616) += dram_sun50i_h616.o dram_dw_helpers.o obj-$(CONFIG_DRAM_SUN50I_H616) += dram_timings/ obj-$(CONFIG_DRAM_SUN50I_A133) += dram_sun50i_a133.o obj-$(CONFIG_DRAM_SUN50I_A133) += dram_timings/ +obj-$(CONFIG_MACH_SUN55I_A523) += dram_sun55i_a523.o +obj-$(CONFIG_DRAM_SUN55I_A523) += dram_timings/ endif diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 08d55b3a0e3..fb4837c2082 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -141,6 +141,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_H616_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN50I_H616_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPB(10), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN55I_A523) + sunxi_gpio_set_cfgpin(SUNXI_GPB(9), 2); + sunxi_gpio_set_cfgpin(SUNXI_GPB(10), 2); + sunxi_gpio_set_pull(SUNXI_GPB(10), 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); @@ -197,6 +201,7 @@ static int gpio_init(void) if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUN50I_GEN_NCAT2)) { val = readl(SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL); + /* TODO: A523: keep only the lower two bits? */ writel(val, SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL); } if (IS_ENABLED(CONFIG_SUN50I_GEN_H6)) { @@ -502,6 +507,12 @@ void reset_cpu(void) /* sun5i sometimes gets stuck without this */ writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode); } +#elif defined(CONFIG_MACH_SUN55I_A523) + static const void *wdog = (void *)SUNXI_TIMER_BASE; + + writel(WDT_CTRL_KEY | WDT_CTRL_RESTART, wdog + WDT_SRST_REG); + while (1) + ; #elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2) #if defined(CONFIG_MACH_SUN50I_H6) /* WDOG is broken for some H6 rev. use the R_WDOG instead */ diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 3f375a51965..80004f13a1e 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -1,7 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ + #include <asm/io.h> #include <asm/arch/cpu.h> #include <asm/arch/clock.h> #include <asm/arch/prcm.h> +#include <linux/delay.h> + +#ifndef SUNXI_CPU_PLL_CFG_BASE +#define SUNXI_CPU_PLL_CFG_BASE 0 +#endif #ifdef CONFIG_XPL_BUILD void clock_init_safe(void) @@ -9,15 +16,22 @@ void clock_init_safe(void) void *const ccm = (void *)SUNXI_CCM_BASE; void *const prcm = (void *)SUNXI_PRCM_BASE; - if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) { - /* this seems to enable PLLs on H616 */ + if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) setbits_le32(prcm + CCU_PRCM_SYS_PWROFF_GATING, 0x10); + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + setbits_le32(prcm + CCU_PRCM_SYS_PWROFF_GATING, 0x200); + udelay(1); + + if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) || + IS_ENABLED(CONFIG_MACH_SUN55I_A523)) setbits_le32(prcm + CCU_PRCM_RES_CAL_CTRL, 2); - } + udelay(1); if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) || - IS_ENABLED(CONFIG_MACH_SUN50I_H6)) { + IS_ENABLED(CONFIG_MACH_SUN50I_H6) || + IS_ENABLED(CONFIG_MACH_SUN55I_A523)) { clrbits_le32(prcm + CCU_PRCM_RES_CAL_CTRL, 1); + udelay(1); setbits_le32(prcm + CCU_PRCM_RES_CAL_CTRL, 1); } @@ -31,12 +45,13 @@ void clock_init_safe(void) clock_set_pll1(408000000); writel(CCM_PLL6_DEFAULT, ccm + CCU_H6_PLL6_CFG); - while (!(readl(ccm + CCU_H6_PLL6_CFG) & CCM_PLL6_LOCK)) + while (!(readl(ccm + CCU_H6_PLL6_CFG) & CCM_PLL_LOCK)) ; - clrsetbits_le32(ccm + CCU_H6_CPU_AXI_CFG, - CCM_CPU_AXI_APB_MASK | CCM_CPU_AXI_AXI_MASK, - CCM_CPU_AXI_DEFAULT_FACTORS); + if (!IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + clrsetbits_le32(ccm + CCU_H6_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 + CCU_H6_PSI_AHB1_AHB2_CFG); #ifdef CCM_AHB3_DEFAULT @@ -48,7 +63,15 @@ void clock_init_safe(void) * 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 + CCU_H6_MBUS_CFG); + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) { + writel(MBUS_RESET, ccm + CCU_H6_MBUS_CFG); + udelay(1); + writel(MBUS_UPDATE | MBUS_CLK_SRC_OSCM24 | MBUS_CLK_M(4), + ccm + CCU_H6_MBUS_CFG); + } else { + writel(MBUS_CLK_SRC_PLL6X2 | MBUS_CLK_M(3), + ccm + CCU_H6_MBUS_CFG); + } } void clock_init_uart(void) @@ -70,38 +93,118 @@ void clock_init_uart(void) 1 << (RESET_SHIFT + CONFIG_CONS_INDEX - 1)); } -void clock_set_pll1(unsigned int clk) +static bool has_pll_output_gate(void) { - void *const ccm = (void *)SUNXI_CCM_BASE; + return (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2) || + IS_ENABLED(CONFIG_MACH_SUN50I_H616) || + IS_ENABLED(CONFIG_MACH_SUN50I_A133)); +} + +/* A shared routine to program the CPU PLLs for H6, H616, T113, A523 */ +static void clock_set_pll(u32 *reg, unsigned int n) +{ + u32 val = readl(reg); + + /* clear the lock enable bit */ + val &= ~CCM_PLL_LOCK_EN; + writel(val, reg); + + /* gate the output on the newer SoCs */ + if (has_pll_output_gate()) { + val &= ~CCM_PLL_OUT_EN; + writel(val, reg); + } + + val &= ~(CCM_PLL1_CTRL_N_MASK | GENMASK(3, 0) | GENMASK(21, 16)); + val |= CCM_PLL1_CTRL_N(n); + writel(val, reg); /* program parameter */ + + val |= CCM_PLL_CTRL_EN; + if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) + val |= CCM_PLL_LDO_EN; + writel(val, reg); /* enable PLL */ + + val |= CCM_PLL_LOCK_EN; + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + val |= CCM_PLL1_UPDATE; + writel(val, reg); /* start locking process */ + + while (!(readl(reg) & CCM_PLL_LOCK)) { /* wait for lock bit */ + } + udelay(20); /* wait as per manual */ + + /* un-gate the output on the newer SoCs */ + if (has_pll_output_gate()) { + val |= CCM_PLL_OUT_EN; + writel(val, reg); + } +} + +/* Program the PLLs for both clusters plus the DSU. */ +static void clock_a523_set_cpu_plls(unsigned int n_factor) +{ + void *const cpc = (void *)SUNXI_CPU_PLL_CFG_BASE; u32 val; - /* Do not support clocks < 288MHz as they need factor P */ - if (clk < 288000000) clk = 288000000; + val = CPU_CLK_SRC_HOSC | CPU_CLK_CTRL_P(0) | + CPU_CLK_APB_DIV(4) | CPU_CLK_PERI_DIV(2) | + CPU_CLK_AXI_DIV(2); + + /* Switch CPU clock source to 24MHz HOSC while changing the PLL */ + writel(val, cpc + CPC_CPUA_CLK_REG); + writel(val, cpc + CPC_CPUB_CLK_REG); + udelay(20); + writel(CPU_CLK_SRC_HOSC | CPU_CLK_CTRL_P(0), + cpc + CPC_DSU_CLK_REG); + udelay(20); - /* Switch to 24MHz clock while changing PLL1 */ + clock_set_pll(cpc + CPC_CPUA_PLL_CTRL, n_factor); + clock_set_pll(cpc + CPC_CPUB_PLL_CTRL, n_factor); + clock_set_pll(cpc + CPC_DSU_PLL_CTRL, n_factor); + + /* Switch CPU clock source to the CPU PLL */ + clrsetbits_le32(cpc + CPC_CPUA_CLK_REG, CPU_CLK_SRC_HOSC, + CPU_CLK_SRC_CPUPLL); + clrsetbits_le32(cpc + CPC_CPUB_CLK_REG, CPU_CLK_SRC_HOSC, + CPU_CLK_SRC_CPUPLL); + clrsetbits_le32(cpc + CPC_DSU_CLK_REG, CPU_CLK_SRC_HOSC, + CPU_CLK_SRC_CPUPLL); +} + +static void clock_h6_set_cpu_pll(unsigned int n_factor) +{ + void *const ccm = (void *)SUNXI_CCM_BASE; + u32 val; + + /* Switch CPU clock source to 24MHz HOSC while changing the PLL */ val = readl(ccm + CCU_H6_CPU_AXI_CFG); val &= ~CCM_CPU_AXI_MUX_MASK; val |= CCM_CPU_AXI_MUX_OSC24M; writel(val, ccm + CCU_H6_CPU_AXI_CFG); - /* clk = 24*n/p, p is ignored if clock is >288MHz */ - val = CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2; - val |= CCM_PLL1_CTRL_N(clk / 24000000); - if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) || - IS_ENABLED(CONFIG_MACH_SUN50I_A133)) - val |= CCM_PLL1_OUT_EN; - if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) - val |= CCM_PLL1_OUT_EN | CCM_PLL1_LDO_EN; - writel(val, ccm + CCU_H6_PLL1_CFG); - while (!(readl(ccm + CCU_H6_PLL1_CFG) & CCM_PLL1_LOCK)) {} + clock_set_pll(ccm + CCU_H6_PLL1_CFG, n_factor); - /* Switch CPU to PLL1 */ + /* Switch CPU clock source to the CPU PLL */ val = readl(ccm + CCU_H6_CPU_AXI_CFG); val &= ~CCM_CPU_AXI_MUX_MASK; val |= CCM_CPU_AXI_MUX_PLL_CPUX; writel(val, ccm + CCU_H6_CPU_AXI_CFG); } +void clock_set_pll1(unsigned int clk) +{ + /* Do not support clocks < 288MHz as they need factor P */ + if (clk < 288000000) + clk = 288000000; + + clk /= 24000000; + + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + clock_a523_set_cpu_plls(clk); + else + clock_h6_set_cpu_pll(clk); +} + int clock_twi_onoff(int port, int state) { void *const ccm = (void *)SUNXI_CCM_BASE; diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c index 3f4735d4717..c3a51d9956e 100644 --- a/arch/arm/mach-sunxi/cpu_info.c +++ b/arch/arm/mach-sunxi/cpu_info.c @@ -106,6 +106,8 @@ int print_cpuinfo(void) puts("CPU: Allwinner H616 (SUN50I)\n"); #elif defined CONFIG_MACH_SUN50I_A133 puts("CPU: Allwinner A133 (SUN50I)\n"); +#elif defined CONFIG_MACH_SUN55I_A523 + puts("CPU: Allwinner A523 (SUN55I)\n"); #else #warning Please update cpu_info.c with correct CPU information puts("CPU: SUNXI Family\n"); diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c index a0fca3738f4..3a231141168 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_a133.c +++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c @@ -78,19 +78,19 @@ static void mctl_clk_init(u32 clk) clrbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_RESET); clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(GATE_SHIFT)); clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(RESET_SHIFT)); - clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL5_CTRL_EN); + clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL_CTRL_EN); clrbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, DRAM_MOD_RESET); udelay(5); /* Set up PLL5 clock, used for DRAM */ clrsetbits_le32(ccm + CCU_H6_PLL5_CFG, 0xff03, - CCM_PLL5_CTRL_N((clk * 2) / 24) | CCM_PLL5_CTRL_EN); + CCM_PLL5_CTRL_N((clk * 2) / 24) | CCM_PLL_CTRL_EN); setbits_le32(ccm + CCU_H6_PLL5_CFG, BIT(24)); clrsetbits_le32(ccm + CCU_H6_PLL5_CFG, 0x3, - CCM_PLL5_LOCK_EN | CCM_PLL5_CTRL_EN | BIT(30)); - clrbits_le32(ccm + CCU_H6_PLL5_CFG, 0x3 | BIT(30)); + CCM_PLL_LOCK_EN | CCM_PLL_CTRL_EN | CCM_PLL_LDO_EN); + clrbits_le32(ccm + CCU_H6_PLL5_CFG, 0x3 | CCM_PLL_LDO_EN); mctl_await_completion(ccm + CCU_H6_PLL5_CFG, - CCM_PLL5_LOCK, CCM_PLL5_LOCK); + CCM_PLL_LOCK, CCM_PLL_LOCK); /* Enable DRAM clock and gate*/ clrbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, BIT(24) | BIT(25)); diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c index 84fd64a2bfc..ea26e6dd327 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h6.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c @@ -167,16 +167,16 @@ static void mctl_sys_init(u32 clk_rate) clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(0)); udelay(5); writel(0, ccm + CCU_H6_DRAM_GATE_RESET); - clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL5_CTRL_EN); + clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL_CTRL_EN); clrbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, DRAM_MOD_RESET); udelay(5); /* Set PLL5 rate to doubled DRAM clock rate */ - writel(CCM_PLL5_CTRL_EN | CCM_PLL5_LOCK_EN | + writel(CCM_PLL_CTRL_EN | CCM_PLL_LOCK_EN | CCM_PLL5_CTRL_N(clk_rate * 2 / 24), ccm + CCU_H6_PLL5_CFG); mctl_await_completion(ccm + CCU_H6_PLL5_CFG, - CCM_PLL5_LOCK, CCM_PLL5_LOCK); + CCM_PLL_LOCK, CCM_PLL_LOCK); /* Configure DRAM mod clock */ writel(DRAM_CLK_SRC_PLL5, ccm + CCU_H6_DRAM_CLK_CFG); diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 5a59f82d1ef..877181016f3 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -106,16 +106,16 @@ static void mctl_sys_init(u32 clk_rate) clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(GATE_SHIFT)); udelay(5); clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(RESET_SHIFT)); - clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL5_CTRL_EN); + clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL_CTRL_EN); clrbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, DRAM_MOD_RESET); udelay(5); /* Set PLL5 rate to doubled DRAM clock rate */ - writel(CCM_PLL5_CTRL_EN | CCM_PLL5_LOCK_EN | CCM_PLL5_OUT_EN | + writel(CCM_PLL_CTRL_EN | CCM_PLL_LOCK_EN | CCM_PLL_OUT_EN | CCM_PLL5_CTRL_N(clk_rate * 2 / 24), ccm + CCU_H6_PLL5_CFG); mctl_await_completion(ccm + CCU_H6_PLL5_CFG, - CCM_PLL5_LOCK, CCM_PLL5_LOCK); + CCM_PLL_LOCK, CCM_PLL_LOCK); /* Configure DRAM mod clock */ writel(DRAM_CLK_SRC_PLL5, ccm + CCU_H6_DRAM_CLK_CFG); diff --git a/arch/arm/mach-sunxi/dram_sun55i_a523.c b/arch/arm/mach-sunxi/dram_sun55i_a523.c new file mode 100644 index 00000000000..30bbeb40d0b --- /dev/null +++ b/arch/arm/mach-sunxi/dram_sun55i_a523.c @@ -0,0 +1,1590 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sun55i A523/A527/T527/H728 platform DRAM controller driver + * + * This driver supports DDR3 and LPDDR4 memory. + * + * (C) Copyright 2024 Jernej Skrabec <jernej.skrabec@gmail.com> + * + */ +#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/bitops.h> +#include <linux/delay.h> + +static void mctl_sys_init(u32 clk_rate) +{ + void * const ccm = (void *)SUNXI_CCM_BASE; + + /* Put all DRAM-related blocks to reset state */ + clrbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_ENABLE); + clrbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_RESET); + setbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_UPDATE); + clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(GATE_SHIFT)); + udelay(5); + clrbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(RESET_SHIFT)); + clrbits_le32(ccm + CCU_H6_PLL5_CFG, CCM_PLL_CTRL_EN); + clrsetbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, + DRAM_CLK_ENABLE, DRAM_CLK_UPDATE); + + udelay(5); + + /* Set PLL5 rate to doubled DRAM clock rate */ + writel(CCM_PLL_CTRL_EN | CCM_PLL_LDO_EN | CCM_PLL_LOCK_EN | + CCM_PLL_OUT_EN | CCM_PLL5_CTRL_N(clk_rate * 2 / 24), + ccm + CCU_H6_PLL5_CFG); + mctl_await_completion(ccm + CCU_H6_PLL5_CFG, + CCM_PLL_LOCK, CCM_PLL_LOCK); + + /* Configure DRAM mod clock */ + writel(DRAM_CLK_SRC_PLL5, ccm + CCU_H6_DRAM_CLK_CFG); + writel(BIT(RESET_SHIFT), ccm + CCU_H6_DRAM_GATE_RESET); + udelay(5); + setbits_le32(ccm + CCU_H6_DRAM_GATE_RESET, BIT(GATE_SHIFT)); + + /* Configure MBUS and enable DRAM clock */ + setbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_RESET | MBUS_UPDATE); + setbits_le32(ccm + CCU_H6_MBUS_CFG, MBUS_ENABLE | MBUS_UPDATE); + + clrsetbits_le32(ccm + CCU_H6_DRAM_CLK_CFG, DRAM_CLK_M_MASK, + DRAM_CLK_ENABLE | DRAM_CLK_UPDATE | DRAM_CLK_M(4)); + udelay(5); +} + +static void mctl_set_addrmap(const struct dram_config *config) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + u8 cols = config->cols; + u8 rows = config->rows; + u8 ranks = config->ranks; + + if (!config->bus_full_width) + cols -= 1; + + /* Ranks */ + if (ranks == 2) + mctl_ctl->addrmap[0] = 0x1F00 | (rows + cols - 3); + else + mctl_ctl->addrmap[0] = 0x1F1F; + + /* Banks, hardcoded to 8 banks now */ + mctl_ctl->addrmap[1] = (cols - 2) | (cols - 2) << 8 | (cols - 2) << 16; + + /* Columns */ + mctl_ctl->addrmap[2] = 0; + switch (cols) { + case 7: + mctl_ctl->addrmap[3] = 0x1F1F1F00; + mctl_ctl->addrmap[4] = 0x1F1F; + break; + case 8: + mctl_ctl->addrmap[3] = 0x1F1F0000; + mctl_ctl->addrmap[4] = 0x1F1F; + break; + case 9: + mctl_ctl->addrmap[3] = 0x1F000000; + mctl_ctl->addrmap[4] = 0x1F1F; + break; + case 10: + mctl_ctl->addrmap[3] = 0; + mctl_ctl->addrmap[4] = 0x1F1F; + break; + case 11: + mctl_ctl->addrmap[3] = 0; + mctl_ctl->addrmap[4] = 0x1F00; + break; + case 12: + mctl_ctl->addrmap[3] = 0; + mctl_ctl->addrmap[4] = 0; + break; + default: + panic("Unsupported DRAM configuration: column number invalid\n"); + } + + /* Rows */ + mctl_ctl->addrmap[5] = (cols - 3) | ((cols - 3) << 8) | + ((cols - 3) << 16) | ((cols - 3) << 24); + switch (rows) { + case 13: + mctl_ctl->addrmap[6] = (cols - 3) | 0x0F0F0F00; + mctl_ctl->addrmap[7] = 0x0F0F; + break; + case 14: + mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | + 0x0F0F0000; + mctl_ctl->addrmap[7] = 0x0F0F; + break; + case 15: + mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | + ((cols - 3) << 16) | 0x0F000000; + mctl_ctl->addrmap[7] = 0x0F0F; + break; + case 16: + mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | + ((cols - 3) << 16) | ((cols - 3) << 24); + mctl_ctl->addrmap[7] = 0x0F0F; + break; + case 17: + mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | + ((cols - 3) << 16) | ((cols - 3) << 24); + mctl_ctl->addrmap[7] = (cols - 3) | 0x0F00; + break; + case 18: + mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | + ((cols - 3) << 16) | ((cols - 3) << 24); + mctl_ctl->addrmap[7] = (cols - 3) | ((cols - 3) << 8); + break; + default: + panic("Unsupported DRAM configuration: row number invalid\n"); + } + + /* Bank groups, DDR4 only */ + mctl_ctl->addrmap[8] = 0x3F3F; +} + +#define MASK_BYTE(reg, nr) (((reg) >> ((nr) * 8)) & 0x1f) +static void mctl_phy_configure_odt(const struct dram_para *para) +{ + u32 val_lo, val_hi; + + val_hi = para->dx_dri; + val_lo = (para->type != SUNXI_DRAM_TYPE_LPDDR4) ? para->dx_dri : + (para->tpr1 & 0x1f1f1f1f) ? para->tpr1 : 0x04040404; + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x304, 0x1f1f0000, + (MASK_BYTE(val_hi, 0) << 24) | + (MASK_BYTE(val_lo, 0) << 16)); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x484, 0x1f1f0000, + (MASK_BYTE(val_hi, 1) << 24) | + (MASK_BYTE(val_lo, 1) << 16)); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x604, 0x1f1f0000, + (MASK_BYTE(val_hi, 2) << 24) | + (MASK_BYTE(val_lo, 2) << 16)); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x784, 0x1f1f0000, + (MASK_BYTE(val_hi, 3) << 24) | + (MASK_BYTE(val_lo, 3) << 16)); + + val_lo = para->ca_dri; + val_hi = para->ca_dri; + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xf4, 0x1f1f1f1f, + (MASK_BYTE(val_hi, 0) << 24) | + (MASK_BYTE(val_lo, 0) << 16) | + (MASK_BYTE(val_hi, 1) << 8) | + (MASK_BYTE(val_lo, 1))); + + val_hi = para->dx_odt; + val_lo = (para->type == SUNXI_DRAM_TYPE_LPDDR4) ? 0 : para->dx_odt; + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x304, 0x00001f1f, + (MASK_BYTE(val_hi, 0) << 8) | MASK_BYTE(val_lo, 0)); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x484, 0x00001f1f, + (MASK_BYTE(val_hi, 1) << 8) | MASK_BYTE(val_lo, 1)); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x604, 0x00001f1f, + (MASK_BYTE(val_hi, 2) << 8) | MASK_BYTE(val_lo, 2)); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x784, 0x00001f1f, + (MASK_BYTE(val_hi, 3) << 8) | MASK_BYTE(val_lo, 3)); +} + +static bool mctl_phy_write_leveling(const struct dram_para *para, + const struct dram_config *config) +{ + u32 mr2, low, high, val = 0; + bool result = true; + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0xf00, 0xe00); + + if (para->type == SUNXI_DRAM_TYPE_LPDDR4) { + if (config->clk <= 936) + mr2 = 0x1b; + else if (config->clk <= 1200) + mr2 = 0x2d; + else + mr2 = 0x36; + writeb(mr2, SUNXI_DRAM_PHY0_BASE + 3); + } + + low = readw(SUNXI_DRAM_PHY0_BASE + 2) | 4; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + + if (config->bus_full_width) + val = 0xf; + else + val = 3; + + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x62), val, val); + + low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xfffb; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + + val = readl(SUNXI_DRAM_PHY0_BASE + 0x96); + if (val == 0 || val == 0x3f) + result = false; + val = readl(SUNXI_DRAM_PHY0_BASE + 0x97); //TODO: ??? + if (val == 0 || val == 0x3f) + result = false; + val = readl(SUNXI_DRAM_PHY0_BASE + 0xc6); + if (val == 0 || val == 0x3f) + result = false; + val = readl(SUNXI_DRAM_PHY0_BASE + 0xc7); //TODO: ??? + if (val == 0 || val == 0x3f) + result = false; + + low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xff3f; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + + if (config->ranks == 2) { + low = (readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xff3f) | 0x40; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + + low = readw(SUNXI_DRAM_PHY0_BASE + 2) | 4; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + + if (config->bus_full_width) + val = 0xf; + else + val = 3; + + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x62), val, val); + + low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xfffb; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + } + + low = readw(SUNXI_DRAM_PHY0_BASE + 2) & 0xff3f; + high = readw(SUNXI_DRAM_PHY0_BASE + 4); + writew(low, SUNXI_DRAM_PHY0_BASE + 2); + writew(high, SUNXI_DRAM_PHY0_BASE + 4); + + return result; +} + +static bool mctl_phy_read_calibration(const struct dram_para *para, + const struct dram_config *config) +{ + bool result = true; + u32 val; + + if (para->type == SUNXI_DRAM_TYPE_LPDDR4) + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, 0x20000000); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c, 0x38); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1); + + if (config->bus_full_width) + val = 0xf; + else + val = 3; + + while ((readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & val) != val) { + if (readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & 0x20) { + result = false; + break; + } + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c); + + if (config->ranks == 2) { + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c, 0x34); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1); + + while ((readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & val) != val) { + if (readl(SUNXI_DRAM_PHY0_BASE + 0x20c) & 0x20) { + result = false; + break; + } + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 1); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x3c); + } + + return result; +} + +static bool mctl_phy_read_training(const struct dram_para *para, + const struct dram_config *config) +{ + u32 val1, val2, *ptr1, *ptr2; + bool result = true; + int i; + + if (para->type == SUNXI_DRAM_TYPE_LPDDR4) { + writel(0, SUNXI_DRAM_PHY0_BASE + 0x200); + writeb(0, SUNXI_DRAM_PHY0_BASE + 0x207); + writeb(0, SUNXI_DRAM_PHY0_BASE + 0x208); + writeb(0, SUNXI_DRAM_PHY0_BASE + 0x209); + writeb(0, SUNXI_DRAM_PHY0_BASE + 0x20a); + } + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x804, 0x3f, 0xf); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x808, 0x3f, 0xf); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa04, 0x3f, 0xf); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa08, 0x3f, 0xf); + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1); + + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); + if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) + result = false; + + if (config->bus_full_width) { + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); + if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) + result = false; + } + + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x898); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x850); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8bc); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x874); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + + if (config->bus_full_width) { + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa98); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa50); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xabc); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa74); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3); + + if (config->ranks == 2) { + /* maybe last parameter should be 1? */ + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2); + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1); + + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); + if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) + result = false; + + if (config->bus_full_width) { + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); + if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) + result = false; + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3); + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3); + + return result; +} + +static bool mctl_phy_write_training(const struct dram_config *config) +{ + u32 val1, val2, *ptr1, *ptr2; + bool result = true; + int i; + + writel(0, SUNXI_DRAM_PHY0_BASE + 0x134); + writel(0, SUNXI_DRAM_PHY0_BASE + 0x138); + writel(0, SUNXI_DRAM_PHY0_BASE + 0x19c); + writel(0, SUNXI_DRAM_PHY0_BASE + 0x1a0); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 8); + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20); + + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3); + if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc) + result = false; + + if (config->bus_full_width) { + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 3); + if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc) + result = false; + } + + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x938); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8f0); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x95c); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x914); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + + if (config->bus_full_width) { + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb38); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xaf0); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb5c); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb14); + for (i = 0; i < 9; i++) { + val1 = readl(&ptr1[i]); + val2 = readl(&ptr2[i]); + if (val1 - val2 <= 6) + result = false; + } + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60); + + if (config->ranks == 2) { + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 4); + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20); + + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3); + if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc) + result = false; + + if (config->bus_full_width) { + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 3); + if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc) + result = false; + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60); + } + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc); + + return result; +} + +static void mctl_phy_bit_delay_compensation(const struct dram_para *para, + const struct dram_config *config) +{ + u8 array0[32], array1[32]; + u32 tmp; + int i; + + for (i = 0; i < 32; i++) { + array0[i] = (config->tpr11 >> (i & 0xf8)) & 0xff; + array1[i] = (config->tpr12 >> (i & 0xf8)) & 0x7f; + } + + if (para->tpr10 & TPR10_DX_BIT_DELAY1) { + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa0, 3); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x80); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, BIT(28)); + + writel(array0[0], SUNXI_DRAM_PHY0_BASE + 0x320); + writel((array0[0] << 24) | (array0[1] << 16) | + (array0[2] << 8) | + array0[3], SUNXI_DRAM_PHY0_BASE + 0x324); + writel((array0[4] << 24) | (array0[5] << 16) | + (array0[6] << 8) | + array0[7], SUNXI_DRAM_PHY0_BASE + 0x328); + + writel(array0[0], SUNXI_DRAM_PHY0_BASE + 0x340); + writel((array0[0] << 24) | (array0[1] << 16) | + (array0[2] << 8) | + array0[3], SUNXI_DRAM_PHY0_BASE + 0x344); + writel((array0[4] << 24) | (array0[5] << 16) | + (array0[6] << 8) | + array0[7], SUNXI_DRAM_PHY0_BASE + 0x348); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x40c, 0xff00, + array0[0] << 8); + writel((array0[0] << 24) | (array0[1] << 16) | + (array0[2] << 8) | array0[3], + SUNXI_DRAM_PHY0_BASE + 0x400); + writel((array0[4] << 24) | (array0[5] << 16) | + (array0[6] << 8) | array0[7], + SUNXI_DRAM_PHY0_BASE + 0x404); + + writel(array0[0], SUNXI_DRAM_PHY0_BASE + 0x41c); + writel((array0[0] << 24) | (array0[1] << 16) | + (array0[2] << 8) | array0[3], + SUNXI_DRAM_PHY0_BASE + 0x420); + writel((array0[4] << 24) | (array0[5] << 16) | + (array0[6] << 8) | array0[7], + SUNXI_DRAM_PHY0_BASE + 0x424); + + tmp = config->odt_en & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x32c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x34c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x408); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x428); + + writel(array0[8], SUNXI_DRAM_PHY0_BASE + 0x4a0); + writel((array0[8] << 24) | (array0[9] << 16) | + (array0[10] << 8) | array0[11], + SUNXI_DRAM_PHY0_BASE + 0x4a4); + writel((array0[12] << 24) | (array0[13] << 16) | + (array0[14] << 8) | array0[15], + SUNXI_DRAM_PHY0_BASE + 0x4a8); + + writel(array0[8], SUNXI_DRAM_PHY0_BASE + 0x4c0); + writel((array0[8] << 24) | (array0[9] << 16) | + (array0[10] << 8) | array0[11], + SUNXI_DRAM_PHY0_BASE + 0x4c4); + writel((array0[12] << 24) | (array0[13] << 16) | + (array0[14] << 8) | array0[15], + SUNXI_DRAM_PHY0_BASE + 0x4c8); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x58c, 0xff00, + array0[8] << 8); + writel((array0[8] << 24) | (array0[9] << 16) | + (array0[10] << 8) | array0[11], + SUNXI_DRAM_PHY0_BASE + 0x580); + writel((array0[12] << 24) | (array0[13] << 16) | + (array0[14] << 8) | array0[15], + SUNXI_DRAM_PHY0_BASE + 0x584); + + writel(array0[8], SUNXI_DRAM_PHY0_BASE + 0x59c); + writel((array0[8] << 24) | (array0[9] << 16) | + (array0[10] << 8) | array0[11], + SUNXI_DRAM_PHY0_BASE + 0x5a0); + writel((array0[12] << 24) | (array0[13] << 16) | + (array0[14] << 8) | array0[15], + SUNXI_DRAM_PHY0_BASE + 0x5a4); + + tmp = (config->odt_en >> 8) & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4ac); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4cc); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x588); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x5a8); + + writel(array0[16], SUNXI_DRAM_PHY0_BASE + 0x620); + writel((array0[16] << 24) | (array0[17] << 16) | + (array0[18] << 8) | array0[19], + SUNXI_DRAM_PHY0_BASE + 0x624); + writel((array0[20] << 24) | (array0[21] << 16) | + (array0[22] << 8) | array0[23], + SUNXI_DRAM_PHY0_BASE + 0x628); + + writel(array0[16], SUNXI_DRAM_PHY0_BASE + 0x640); + writel((array0[16] << 24) | (array0[17] << 16) | + (array0[18] << 8) | array0[19], + SUNXI_DRAM_PHY0_BASE + 0x644); + writel((array0[20] << 24) | (array0[21] << 16) | + (array0[22] << 8) | array0[23], + SUNXI_DRAM_PHY0_BASE + 0x648); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x70c, + 0xff00, array0[16] << 8); + writel((array0[16] << 24) | (array0[17] << 16) | + (array0[18] << 8) | array0[19], + SUNXI_DRAM_PHY0_BASE + 0x700); + writel((array0[20] << 24) | (array0[21] << 16) | + (array0[22] << 8) | array0[23], + SUNXI_DRAM_PHY0_BASE + 0x704); + + writel(array0[16], SUNXI_DRAM_PHY0_BASE + 0x71c); + writel((array0[16] << 24) | (array0[17] << 16) | + (array0[18] << 8) | array0[19], + SUNXI_DRAM_PHY0_BASE + 0x720); + writel((array0[20] << 24) | (array0[21] << 16) | + (array0[22] << 8) | array0[23], SUNXI_DRAM_PHY0_BASE + 0x724); + + tmp = (config->odt_en >> 16) & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x62c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x64c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x708); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x728); + + writel(array0[24], SUNXI_DRAM_PHY0_BASE + 0x7a0); + writel((array0[24] << 24) | (array0[25] << 16) | + (array0[26] << 8) | array0[27], + SUNXI_DRAM_PHY0_BASE + 0x7a4); + writel((array0[28] << 24) | (array0[29] << 16) | + (array0[30] << 8) | array0[31], + SUNXI_DRAM_PHY0_BASE + 0x7a8); + + writel(array0[24], SUNXI_DRAM_PHY0_BASE + 0x7c0); + writel((array0[24] << 24) | (array0[25] << 16) | + (array0[26] << 8) | array0[27], + SUNXI_DRAM_PHY0_BASE + 0x7c4); + writel((array0[28] << 24) | (array0[29] << 16) | + (array0[30] << 8) | array0[31], + SUNXI_DRAM_PHY0_BASE + 0x7c8); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x88c, 0xff00, + array0[24] << 8); + writel((array0[24] << 24) | (array0[25] << 16) | + (array0[26] << 8) | array0[27], + SUNXI_DRAM_PHY0_BASE + 0x880); + writel((array0[28] << 24) | (array0[29] << 16) | + (array0[30] << 8) | array0[31], + SUNXI_DRAM_PHY0_BASE + 0x884); + + writel(array0[24], SUNXI_DRAM_PHY0_BASE + 0x89c); + writel((array0[24] << 24) | (array0[25] << 16) | + (array0[26] << 8) | array0[27], + SUNXI_DRAM_PHY0_BASE + 0x8a0); + writel((array0[28] << 24) | (array0[29] << 16) | + (array0[30] << 8) | array0[31], + SUNXI_DRAM_PHY0_BASE + 0x8a4); + + tmp = (config->odt_en >> 24) & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7ac); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7cc); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x888); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x8a8); + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, BIT(28)); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x44, BIT(28)); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); + } + + if (para->tpr10 & TPR10_DX_BIT_DELAY0) { + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); + + writel(array1[0] << 8, SUNXI_DRAM_PHY0_BASE + 0x330); + writel((array1[0] << 24) | (array1[1] << 16) | + (array1[2] << 8) | array1[3], + SUNXI_DRAM_PHY0_BASE + 0x334); + writel((array1[4] << 24) | (array1[5] << 16) | + (array1[6] << 8) | array1[7], + SUNXI_DRAM_PHY0_BASE + 0x338); + + writel(array1[0] << 8, SUNXI_DRAM_PHY0_BASE + 0x350); + writel((array1[0] << 24) | (array1[1] << 16) | + (array1[2] << 8) | array1[3], + SUNXI_DRAM_PHY0_BASE + 0x354); + writel((array1[4] << 24) | (array1[5] << 16) | + (array1[6] << 8) | array1[7], + SUNXI_DRAM_PHY0_BASE + 0x358); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x40c, 0xff, array1[0]); + writel((array1[0] << 24) | (array1[1] << 16) | + (array1[2] << 8) | array1[3], + SUNXI_DRAM_PHY0_BASE + 0x410); + writel((array1[4] << 24) | (array1[5] << 16) | + (array1[6] << 8) | array1[7], + SUNXI_DRAM_PHY0_BASE + 0x414); + + writel(array1[0] << 8, SUNXI_DRAM_PHY0_BASE + 0x42c); + writel((array1[0] << 24) | (array1[1] << 16) | + (array1[2] << 8) | array1[3], + SUNXI_DRAM_PHY0_BASE + 0x430); + writel((array1[4] << 24) | (array1[5] << 16) | + (array1[6] << 8) | array1[7], + SUNXI_DRAM_PHY0_BASE + 0x434); + + tmp = config->tpr14 & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x33c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x35c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x418); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x438); + + writel(array1[8] << 8, SUNXI_DRAM_PHY0_BASE + 0x4b0); + writel((array1[8] << 24) | (array1[9] << 16) | + (array1[10] << 8) | array1[11], + SUNXI_DRAM_PHY0_BASE + 0x4b4); + writel((array1[12] << 24) | (array1[13] << 16) | + (array1[14] << 8) | array1[15], + SUNXI_DRAM_PHY0_BASE + 0x4b8); + + writel(array1[8] << 8, SUNXI_DRAM_PHY0_BASE + 0x4d0); + writel((array1[8] << 24) | (array1[9] << 16) | + (array1[10] << 8) | array1[11], + SUNXI_DRAM_PHY0_BASE + 0x4d4); + writel((array1[12] << 24) | (array1[13] << 16) | + (array1[14] << 8) | array1[15], + SUNXI_DRAM_PHY0_BASE + 0x4d8); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x58c, 0xff, array1[8]); + writel((array1[8] << 24) | (array1[9] << 16) | + (array1[10] << 8) | array1[11], + SUNXI_DRAM_PHY0_BASE + 0x590); + writel((array1[12] << 24) | (array1[13] << 16) | + (array1[14] << 8) | array1[15], + SUNXI_DRAM_PHY0_BASE + 0x594); + + writel(array1[8] << 8, SUNXI_DRAM_PHY0_BASE + 0x5ac); + writel((array1[8] << 24) | (array1[9] << 16) | + (array1[10] << 8) | array1[11], + SUNXI_DRAM_PHY0_BASE + 0x5b0); + writel((array1[12] << 24) | (array1[13] << 16) | + (array1[14] << 8) | array1[15], + SUNXI_DRAM_PHY0_BASE + 0x5b4); + + tmp = (config->tpr14 >> 8) & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4bc); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x4dc); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x598); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x5b8); + + writel(array1[16] << 8, SUNXI_DRAM_PHY0_BASE + 0x630); + writel((array1[16] << 24) | (array1[17] << 16) | + (array1[18] << 8) | array1[19], + SUNXI_DRAM_PHY0_BASE + 0x634); + writel((array1[20] << 24) | (array1[21] << 16) | + (array1[22] << 8) | array1[23], + SUNXI_DRAM_PHY0_BASE + 0x638); + + writel(array1[16] << 8, SUNXI_DRAM_PHY0_BASE + 0x650); + writel((array1[16] << 24) | (array1[17] << 16) | + (array1[18] << 8) | array1[19], + SUNXI_DRAM_PHY0_BASE + 0x654); + writel((array1[20] << 24) | (array1[21] << 16) | + (array1[22] << 8) | array1[23], + SUNXI_DRAM_PHY0_BASE + 0x658); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x70c, 0xff, array1[16]); + writel((array1[16] << 24) | (array1[17] << 16) | + (array1[18] << 8) | array1[19], + SUNXI_DRAM_PHY0_BASE + 0x710); + writel((array1[20] << 24) | (array1[21] << 16) | + (array1[22] << 8) | array1[23], + SUNXI_DRAM_PHY0_BASE + 0x714); + + writel(array1[16] << 8, SUNXI_DRAM_PHY0_BASE + 0x72c); + writel((array1[16] << 24) | (array1[17] << 16) | + (array1[18] << 8) | array1[19], + SUNXI_DRAM_PHY0_BASE + 0x730); + writel((array1[20] << 24) | (array1[21] << 16) | + (array1[22] << 8) | array1[23], + SUNXI_DRAM_PHY0_BASE + 0x734); + + tmp = (config->tpr14 >> 16) & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x63c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x65c); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x718); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x738); + + writel(array1[24] << 8, SUNXI_DRAM_PHY0_BASE + 0x7b0); + writel((array1[24] << 24) | (array1[25] << 16) | + (array1[26] << 8) | array1[27], + SUNXI_DRAM_PHY0_BASE + 0x7b4); + writel((array1[28] << 24) | (array1[29] << 16) | + (array1[30] << 8) | array1[31], + SUNXI_DRAM_PHY0_BASE + 0x7b8); + + writel(array1[24] << 8, SUNXI_DRAM_PHY0_BASE + 0x7d0); + writel((array1[24] << 24) | (array1[25] << 16) | + (array1[26] << 8) | array1[27], + SUNXI_DRAM_PHY0_BASE + 0x7d4); + writel((array1[28] << 24) | (array1[29] << 16) | + (array1[30] << 8) | array1[31], + SUNXI_DRAM_PHY0_BASE + 0x7d8); + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x88c, 0xff, array1[24]); + writel((array1[24] << 24) | (array1[25] << 16) | + (array1[26] << 8) | array1[27], + SUNXI_DRAM_PHY0_BASE + 0x890); + writel((array1[28] << 24) | (array1[29] << 16) | + (array1[30] << 8) | array1[31], + SUNXI_DRAM_PHY0_BASE + 0x894); + + writel(array1[24] << 8, SUNXI_DRAM_PHY0_BASE + 0x8ac); + writel((array1[24] << 24) | (array1[25] << 16) | + (array1[26] << 8) | array1[27], + SUNXI_DRAM_PHY0_BASE + 0x8b0); + writel((array1[28] << 24) | (array1[29] << 16) | + (array1[30] << 8) | array1[31], + SUNXI_DRAM_PHY0_BASE + 0x8b4); + + tmp = (config->tpr14 >> 24) & 0xff; + tmp = (tmp << 24) | (tmp << 8); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7bc); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x7dc); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x898); + writel(tmp, SUNXI_DRAM_PHY0_BASE + 0x8b8); + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 4); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 4); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); + } +} + +static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para, + const struct dram_config *config) +{ + u32 val, low, high; + + if (para->tpr10 & BIT(31)) { + val = para->tpr0; + } else { + val = ((para->tpr10 & 0xf0) << 5) | ((para->tpr10 & 0xf) << 1); + if (para->tpr10 >> 29) + val <<= 1; + } + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0xac, 0x1000); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x48, 0xc0000000); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + case SUNXI_DRAM_TYPE_DDR4: + case SUNXI_DRAM_TYPE_LPDDR3: + low = val & 0xff; + high = (val >> 8) & 0xff; + + val = (high << 24) | (high << 16) | (high << 8) | high; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x104); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x108); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x10c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x114); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x118); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x11c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x120); + + val = (low << 24) | (low << 16) | (high << 8) | high; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x11c); + break; + case SUNXI_DRAM_TYPE_LPDDR4: + low = val & 0xff; + high = (val >> 8) & 0xff; + + val = (high << 24) | (high << 16) | (high << 8) | high; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x104); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x108); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x10c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x114); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x118); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x11c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x120); + + val = (high << 24) | (high << 16) | (low << 8) | low; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x110); + + val = (low << 24) | (high << 16) | (low << 8) | high; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x11c); + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x38, 1); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x38, 1); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); +} + +static bool mctl_phy_init(const struct dram_para *para, + const struct dram_config *config) +{ + void * const mctl_com = (void *)SUNXI_DRAM_COM_BASE; + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + void *const prcm = (void *)SUNXI_PRCM_BASE; + u32 val, val2, mr1, mr2; + int i; + + clrbits_le32(prcm + CCU_PRCM_SYS_PWROFF_GATING, 1); + udelay(1); + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x40000); + + if (config->bus_full_width) + val = 0xf00; + else + val = 0x300; + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, 0xf00, val); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + val = 9; + val2 = 13; + break; + case SUNXI_DRAM_TYPE_DDR4: + if (config->clk <= 936) { + val = 10; + val2 = 14; + } else if (config->clk <= 1200) { + val = 12; + val2 = 16; + } else { + val = 14; + val2 = 18; + } + break; + case SUNXI_DRAM_TYPE_LPDDR3: + val = 8; + val2 = 14; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + if (config->clk <= 936) { + val = 10; + val2 = 20; + } else if (config->clk <= 1200) { + val = 14; + val2 = 28; + } else { + val = 16; + val2 = 32; + } + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + + writel((val << 24) | (val << 16) | (val << 8) | val, SUNXI_DRAM_PHY0_BASE + 0x10); + writel((val2 << 24) | (val2 << 16) | (val2 << 8) | val2, SUNXI_DRAM_PHY0_BASE + 0x0c); + writel(0, SUNXI_DRAM_PHY0_BASE + 0x08); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + writel(0x150a0310, SUNXI_DRAM_PHY0_BASE + 0x54); + writel(0x13140816, SUNXI_DRAM_PHY0_BASE + 0x58); + writel(0x001c0d1b, SUNXI_DRAM_PHY0_BASE + 0x5c); + writel(0x050c1d1a, SUNXI_DRAM_PHY0_BASE + 0x60); + writel(0x0411060b, SUNXI_DRAM_PHY0_BASE + 0x64); + writel(0x09071217, SUNXI_DRAM_PHY0_BASE + 0x68); + writel(0x18190e01, SUNXI_DRAM_PHY0_BASE + 0x6c); + writel(0x020f1e00, SUNXI_DRAM_PHY0_BASE + 0x70); + break; + case SUNXI_DRAM_TYPE_DDR4: + writel(0x090c1c14, SUNXI_DRAM_PHY0_BASE + 0x54); + writel(0x1300060f, SUNXI_DRAM_PHY0_BASE + 0x58); + writel(0x12030807, SUNXI_DRAM_PHY0_BASE + 0x5c); + writel(0x0b100a02, SUNXI_DRAM_PHY0_BASE + 0x60); + writel(0x1a110e05, SUNXI_DRAM_PHY0_BASE + 0x64); + writel(0x0d041617, SUNXI_DRAM_PHY0_BASE + 0x68); + writel(0x1819011b, SUNXI_DRAM_PHY0_BASE + 0x6c); + writel(0x151d1e00, SUNXI_DRAM_PHY0_BASE + 0x70); + break; + case SUNXI_DRAM_TYPE_LPDDR3: + writel(0x010a1a0f, SUNXI_DRAM_PHY0_BASE + 0x54); + writel(0x10081b07, SUNXI_DRAM_PHY0_BASE + 0x58); + writel(0x11061c12, SUNXI_DRAM_PHY0_BASE + 0x5c); + writel(0x00131409, SUNXI_DRAM_PHY0_BASE + 0x60); + writel(0x15030e16, SUNXI_DRAM_PHY0_BASE + 0x64); + writel(0x0b0c0d17, SUNXI_DRAM_PHY0_BASE + 0x68); + writel(0x18190204, SUNXI_DRAM_PHY0_BASE + 0x6c); + writel(0x051d1e00, SUNXI_DRAM_PHY0_BASE + 0x70); + break; + case SUNXI_DRAM_TYPE_LPDDR4: + writel(0x00010203, SUNXI_DRAM_PHY0_BASE + 0x54); + writel(0x04050607, SUNXI_DRAM_PHY0_BASE + 0x58); + writel(0x08090a0b, SUNXI_DRAM_PHY0_BASE + 0x5c); + writel(0x0c0d0e0f, SUNXI_DRAM_PHY0_BASE + 0x60); + writel(0x10111213, SUNXI_DRAM_PHY0_BASE + 0x64); + writel(0x14151617, SUNXI_DRAM_PHY0_BASE + 0x68); + writel(0x18191a1b, SUNXI_DRAM_PHY0_BASE + 0x6c); + writel(0x1c1d1e00, SUNXI_DRAM_PHY0_BASE + 0x70); + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + + mctl_phy_configure_odt(para); + + if (para->tpr10 & TPR10_CA_BIT_DELAY) + mctl_phy_ca_bit_delay_compensation(para, config); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + val = 0x2bbd4900; + break; + case SUNXI_DRAM_TYPE_DDR4: + val = 0x3841b800; + break; + case SUNXI_DRAM_TYPE_LPDDR3: + val = 0x19016300; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + val = 0x18fd6300; + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa8, 0xffffff00, val); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, 0x70); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + val = 0x20; + break; + case SUNXI_DRAM_TYPE_DDR4: + val = 0x40; + break; + case SUNXI_DRAM_TYPE_LPDDR3: + val = 0x30; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + val = 0x50; + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, val); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x00, 0x80); + + // TODO: fix intervals + if (config->clk - 251 < 250) { + val = 0x18000000; + val2 = 0x18181818; + } else if (config->clk - 126 < 125) { + val = 0x28000000; + val2 = 0x28282828; + } else if (config->clk < 126) { + val = 0x38000000; + val2 = 0x38383838; + } else { + val = 0x18000000; + val2 = 0; + } + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xc0, 0x78000000, val); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xd0, 0x78787878, val2); + + clrbits_le32(mctl_com + MCTL_COM_UNK_008, BIT(9)); + udelay(10); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + val = para->tpr6 & 0xff; + break; + case SUNXI_DRAM_TYPE_DDR4: + val = para->tpr6 >> 8 & 0xff; + break; + case SUNXI_DRAM_TYPE_LPDDR3: + val = para->tpr6 >> 16 & 0xff; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + val = para->tpr6 >> 24; + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + val <<= 24; + + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x300, 0xff800060, val | 0x40); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x600, 0xff800060, val | 0x40); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x480, 0xff800060, val | 0x40); + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x780, 0xff800060, val | 0x40); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x8000000); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 0x80); + udelay(10); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x94, 0x80); + udelay(10); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x84, 0x8000000); + + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x308, 0x200); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x488, 0x200); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x608, 0x200); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x788, 0x200); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x908, 0x200); + if (para->type == SUNXI_DRAM_TYPE_LPDDR4) { + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x308, 0x200); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x488, 0x200); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x608, 0x200); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x788, 0x200); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x908, 0x200); + } + + if (config->clk < 936) + val = 0x1b000000; + else + val = 0xc000000; + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x14, 0x1f000000, val); + + setbits_le32(mctl_com + MCTL_COM_MAER0, BIT(8)); + + /* start DFI init */ + writel(0, &mctl_ctl->swctl); + setbits_le32(&mctl_ctl->dfimisc, 1); + setbits_le32(&mctl_ctl->dfimisc, 0x20); + writel(1, &mctl_ctl->swctl); + mctl_await_completion(&mctl_ctl->swstat, 1, 1); + mctl_await_completion(&mctl_ctl->dfistat, 1, 1); + + udelay(500); + setbits_le32(prcm + CCU_PRCM_SYS_PWROFF_GATING, 1); + udelay(1); + + writel(0, &mctl_ctl->swctl); + clrbits_le32(&mctl_ctl->dfimisc, 0x20); + writel(1, &mctl_ctl->swctl); + mctl_await_completion(&mctl_ctl->swstat, 1, 1); + + writel(0, &mctl_ctl->swctl); + clrbits_le32(&mctl_ctl->pwrctl, 0x20); + writel(1, &mctl_ctl->swctl); + mctl_await_completion(&mctl_ctl->swstat, 1, 1); + mctl_await_completion(&mctl_ctl->statr, 3, 1); + + udelay(500); + + writel(0, &mctl_ctl->swctl); + clrbits_le32(&mctl_ctl->dfimisc, 1); + writel(1, &mctl_ctl->swctl); + mctl_await_completion(&mctl_ctl->swstat, 1, 1); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + writel(0x1f14, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(4, &mctl_ctl->mrctrl1); + writel(0x800010f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x20, &mctl_ctl->mrctrl1); + writel(0x800020f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0, &mctl_ctl->mrctrl1); + writel(0x800030f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + break; + case SUNXI_DRAM_TYPE_LPDDR4: + if (config->clk <= 936) { + mr1 = 0x34; + mr2 = 0x1b; + } else if (config->clk <= 1200) { + mr1 = 0x54; + mr2 = 0x2d; + } else { + mr1 = 0x64; + mr2 = 0x36; + } + + writel(0x0, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x100 | mr1, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x200 | mr2, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x333, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x403, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0xb04, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0xc72, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0xd00, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0xe08, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x1626, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + + writel(0, &mctl_ctl->swctl); + clrbits_le32(&mctl_ctl->rfshctl3, 1); + writel(1, &mctl_ctl->swctl); + + if (para->tpr10 & TPR10_WRITE_LEVELING) { + for (i = 0; i < 5; i++) + if (mctl_phy_write_leveling(para, config)) + break; + if (i == 5) { + debug("write leveling failed!\n"); + return false; + } + } + + if (para->tpr10 & TPR10_READ_CALIBRATION) { + for (i = 0; i < 5; i++) + if (mctl_phy_read_calibration(para, config)) + break; + if (i == 5) { + debug("read calibration failed!\n"); + return false; + } + } + + if (para->tpr10 & TPR10_READ_TRAINING) { + for (i = 0; i < 5; i++) + if (mctl_phy_read_training(para, config)) + break; + if (i == 5) { + debug("read training failed!\n"); + return false; + } + } + + if (para->tpr10 & TPR10_WRITE_TRAINING) { + for (i = 0; i < 5; i++) + if (mctl_phy_write_training(config)) + break; + if (i == 5) { + debug("write training failed!\n"); + return false; + } + } + + mctl_phy_bit_delay_compensation(para, config); + + return true; +} + +static bool mctl_ctrl_init(const struct dram_para *para, + const struct dram_config *config) +{ + void * const mctl_com = (void *)SUNXI_DRAM_COM_BASE; + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + u32 reg_val; + + clrsetbits_le32(mctl_com + MCTL_COM_UNK_008, BIT(24), BIT(25) | BIT(9)); + setbits_le32(mctl_com + MCTL_COM_MAER0, BIT(15) | BIT(9)); + + if (para->type == SUNXI_DRAM_TYPE_LPDDR4) { + setbits_le32(0x02023ea8, 1); // NSI + setbits_le32(0x02071008, 1); // NSI_CPU + } + + clrsetbits_le32(&mctl_ctl->sched[0], 0xff08, 0x3000); + clrsetbits_le32(&mctl_ctl->sched[1], 0x77000000, 0x33000000); + clrsetbits_le32(&mctl_ctl->unk_0x270, 0xffff, 0x808); + clrsetbits_le32(&mctl_ctl->unk_0x264, 0xff00ffff, 0x1f000030); + + writel(0, &mctl_ctl->hwlpctl); + + reg_val = MSTR_ACTIVE_RANKS(config->ranks); + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + reg_val |= MSTR_BURST_LENGTH(8) | MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + reg_val |= MSTR_BURST_LENGTH(16) | MSTR_DEVICETYPE_LPDDR4; + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + if (config->bus_full_width) + reg_val |= MSTR_BUSWIDTH_FULL; + else + reg_val |= MSTR_BUSWIDTH_HALF; + writel(BIT(31) | BIT(30) | reg_val, &mctl_ctl->mstr); + + if (config->ranks == 2) + writel(0x0303, &mctl_ctl->odtmap); + else + writel(0x0201, &mctl_ctl->odtmap); + + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + reg_val = 0x06000400; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + reg_val = 0x04000400; + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + writel(reg_val, &mctl_ctl->odtcfg); + writel(reg_val, &mctl_ctl->unk_0x2240); + writel(reg_val, &mctl_ctl->unk_0x3240); + writel(reg_val, &mctl_ctl->unk_0x4240); + + mctl_set_addrmap(config); + + mctl_set_timing_params(config->clk); + + writel(0, &mctl_ctl->pwrctl); + + setbits_le32(&mctl_ctl->dfiupd[0], BIT(31) | BIT(30)); + setbits_le32(&mctl_ctl->zqctl[0], BIT(31) | BIT(30)); + setbits_le32(&mctl_ctl->unk_0x2180, BIT(31) | BIT(30)); + setbits_le32(&mctl_ctl->unk_0x3180, BIT(31) | BIT(30)); + setbits_le32(&mctl_ctl->unk_0x4180, BIT(31) | BIT(30)); + + if (para->type == SUNXI_DRAM_TYPE_LPDDR4) + setbits_le32(&mctl_ctl->dbictl, 0x1); + + setbits_le32(&mctl_ctl->rfshctl3, BIT(0)); + clrbits_le32(&mctl_ctl->dfimisc, BIT(0)); + + writel(0x20, &mctl_ctl->pwrctl); + setbits_le32(&mctl_ctl->clken, BIT(8)); + + clrsetbits_le32(mctl_com + MCTL_COM_UNK_008, BIT(24), BIT(9)); + udelay(1); + /* this write seems to enable PHY MMIO region */ + setbits_le32(mctl_com + MCTL_COM_UNK_008, BIT(24)); + + if (!mctl_phy_init(para, config)) + return false; + + writel(0, &mctl_ctl->swctl); + clrbits_le32(&mctl_ctl->rfshctl3, BIT(0)); + writel(1, &mctl_ctl->swctl); + mctl_await_completion(&mctl_ctl->swstat, 1, 1); + + return true; +} + +static bool mctl_core_init(const struct dram_para *para, + const struct dram_config *config) +{ + mctl_sys_init(config->clk); + + return mctl_ctrl_init(para, config); +} + +static void mctl_auto_detect_rank_width(const struct dram_para *para, + struct dram_config *config) +{ + /* this is minimum size that it's supported */ + config->cols = 8; + config->rows = 13; + + /* + * Strategy here is to test most demanding combination first and least + * demanding last, otherwise HW might not be fully utilized. For + * example, half bus width and rank = 1 combination would also work + * on HW with full bus width and rank = 2, but only 1/4 RAM would be + * visible. + */ + + debug("testing 32-bit width, rank = 2\n"); + config->bus_full_width = 1; + config->ranks = 2; + if (mctl_core_init(para, config)) + return; + + debug("testing 32-bit width, rank = 1\n"); + config->bus_full_width = 1; + config->ranks = 1; + if (mctl_core_init(para, config)) + return; + + debug("testing 16-bit width, rank = 2\n"); + config->bus_full_width = 0; + config->ranks = 2; + if (mctl_core_init(para, config)) + return; + + debug("testing 16-bit width, rank = 1\n"); + config->bus_full_width = 0; + config->ranks = 1; + if (mctl_core_init(para, config)) + return; + + panic("This DRAM setup is currently not supported.\n"); +} + +static void mctl_auto_detect_dram_size(const struct dram_para *para, + struct dram_config *config) +{ + /* detect row address bits */ + config->cols = 8; + config->rows = 16; + mctl_core_init(para, config); + + for (config->rows = 13; config->rows < 16; config->rows++) { + /* 8 banks, 8 bit per byte and 16/32 bit width */ + if (mctl_mem_matches((1 << (config->rows + config->cols + + 4 + config->bus_full_width)))) + break; + } + + /* detect column address bits */ + config->cols = 11; + mctl_core_init(para, config); + + for (config->cols = 8; config->cols < 11; config->cols++) { + /* 8 bits per byte and 16/32 bit width */ + if (mctl_mem_matches(1 << (config->cols + 1 + + config->bus_full_width))) + break; + } +} + +static unsigned long long mctl_calc_size(const struct dram_config *config) +{ + u8 width = config->bus_full_width ? 4 : 2; + + /* 8 banks */ + return (1ULL << (config->cols + config->rows + 3)) * width * config->ranks; +} + +static const struct dram_para para = { +#ifdef CONFIG_SUNXI_DRAM_A523_DDR3 + .type = SUNXI_DRAM_TYPE_DDR3, +#elif defined(CONFIG_SUNXI_DRAM_A523_LPDDR4) + .type = SUNXI_DRAM_TYPE_LPDDR4, +#endif + .dx_odt = CONFIG_DRAM_SUNXI_DX_ODT, + .dx_dri = CONFIG_DRAM_SUNXI_DX_DRI, + .ca_dri = CONFIG_DRAM_SUNXI_CA_DRI, + .tpr0 = CONFIG_DRAM_SUNXI_TPR0, + .tpr1 = CONFIG_DRAM_SUNXI_TPR1, + .tpr2 = CONFIG_DRAM_SUNXI_TPR2, + .tpr6 = CONFIG_DRAM_SUNXI_TPR6, + .tpr10 = CONFIG_DRAM_SUNXI_TPR10, +}; + +static void sunxi_nsi_init(void) +{ + /* IOMMU prio 3 */ + writel(0x1, 0x02021418); + writel(0xf, 0x02021414); + /* DE prio 2 */ + writel(0x1, 0x02021a18); + writel(0xa, 0x02021a14); + /* VE R prio 2 */ + writel(0x1, 0x02021618); + writel(0xa, 0x02021614); + /* VE RW prio 2 */ + writel(0x1, 0x02021818); + writel(0xa, 0x02021814); + /* ISP prio 2 */ + writel(0x1, 0x02020c18); + writel(0xa, 0x02020c14); + /* CSI prio 2 */ + writel(0x1, 0x02021c18); + writel(0xa, 0x02021c14); + /* NPU prio 2 */ + writel(0x1, 0x02020a18); + writel(0xa, 0x02020a14); + + /* close ra0 autogating */ + writel(0x0, 0x02023c00); + /* close ta autogating */ + writel(0x0, 0x02023e00); + /* close pcie autogating */ + writel(0x0, 0x02020600); +} + +static void init_something(void) + +{ + u32 *ptr = (u32 *)0x02000804; + + do { + *ptr++ = 0xffffffff; + } while (ptr != (u32 *)0x20008e4); + + writel(0, 0x07002400); + writel(0, 0x07002404); + writel(0, 0x07002408); + + writel(0xffffffff, 0x07002004); + writel(0xffffffff, 0x07002014); + writel(0xffffffff, 0x07002024); + setbits_le32(0x07010290, 7); + + writel(7, 0x02001f00); + writel(0xffff, 0x03002020); + writel(3, 0x020008e0); + writel(7, 0x07102008); +} + +unsigned long sunxi_dram_init(void) +{ + struct dram_config config; + unsigned long size; + + config.clk = 360; + switch (para.type) { + case SUNXI_DRAM_TYPE_DDR3: + config.odt_en = 0x90909090; + config.tpr11 = 0x8f919190; + config.tpr12 = 0x22222723; + config.tpr14 = 0x48484848; + break; + case SUNXI_DRAM_TYPE_LPDDR4: + config.odt_en = 0x84848484; + config.tpr11 = 0x9a9a9a9a; + config.tpr12 = 0x0e0f070a; + config.tpr14 = 0x48484848; + break; + default: + panic("This DRAM setup is currently not supported.\n"); + }; + + setbits_le32(0x03000160, BIT(8)); + clrbits_le32(0x03000168, 0x3f); + + mctl_auto_detect_rank_width(¶, &config); + mctl_auto_detect_dram_size(¶, &config); + + config.clk = CONFIG_DRAM_CLK; + config.odt_en = CONFIG_DRAM_SUNXI_ODT_EN; + config.tpr11 = CONFIG_DRAM_SUNXI_TPR11; + config.tpr12 = CONFIG_DRAM_SUNXI_TPR12; + config.tpr14 = CONFIG_DRAM_SUNXI_TPR14; + + mctl_core_init(¶, &config); + + size = mctl_calc_size(&config); + + sunxi_nsi_init(); + init_something(); + + return size; +}; diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile index 4dc1f29fc08..5de9fd5aab4 100644 --- a/arch/arm/mach-sunxi/dram_timings/Makefile +++ b/arch/arm/mach-sunxi/dram_timings/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR3) += h616_lpddr3.o obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR4) += h616_lpddr4_2133.o obj-$(CONFIG_SUNXI_DRAM_A133_DDR4) += a133_ddr4.o obj-$(CONFIG_SUNXI_DRAM_A133_LPDDR4) += a133_lpddr4.o +obj-$(CONFIG_SUNXI_DRAM_A523_DDR3) += a523_ddr3.o +obj-$(CONFIG_SUNXI_DRAM_A523_LPDDR4) += a523_lpddr4.o diff --git a/arch/arm/mach-sunxi/dram_timings/a523_ddr3.c b/arch/arm/mach-sunxi/dram_timings/a523_ddr3.c new file mode 100644 index 00000000000..6e140bb1454 --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/a523_ddr3.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sun55i A523 DDR3 timings, as programmed by Allwinner's boot0 on + * the X96QPro+ TV box. As usual very conservative timings, but probably + * the most compatible and reliable. + * + * (C) Copyright 2024 Mikhail Kalashnikov <iuncuim@gmail.com> + * Based on H616 DDR3 timings: + * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net> + */ + +#include <asm/arch/dram.h> +#include <asm/arch/cpu.h> + +void mctl_set_timing_params(u32 clk) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + /* + * formulas and constraints as of + * JEDEC DDR3 specification, for + * DDR3-1600, per JESD79-3F + */ + u8 tccd = 2; /* 4nCK */ + u8 tfaw = ns_to_t(50, clk); + u8 trrd = max(ns_to_t(6, clk), 4); /* max(6 ns, 4nCK) */ + u8 twtr = max(ns_to_t(8, clk), 4); /* max(7.5 ns, 4nCK) */ + u8 trcd = ns_to_t(15, clk); /* 13.5 ns */ + u8 trc = ns_to_t(53, clk); + u8 txp = max(ns_to_t(8, clk), 2); /* max(6 ns, 3nCK) */ + u8 trtp = max(ns_to_t(8, clk), 4); /* max(7.5 ns, 4nCK) */ + u8 trp = ns_to_t(15, clk); /* >= 13.75 ns */ + u8 tras = ns_to_t(38, clk); + u16 trefi = ns_to_t(11350, clk) / 32; + u16 trfc = ns_to_t(360, clk); /* 160 ns for 2Gb */ + u16 txsr = 4; + + u8 tmrw = 0; + u8 tmrd = 4; /* 4nCK */ + + u8 tmod = max(ns_to_t(15, clk), 12); /* max(15 ns, 12nCK) */ + u8 tcke = max(ns_to_t(6, clk), 4); /* max(5.625 ns, 3nCK)*/ + u8 tcksrx = max(ns_to_t(10, clk), 4); /* max(10 ns, 5nCK) */ + u8 tcksre = max(ns_to_t(10, clk), 4); /* max(10 ns, 5nCK) */ + u8 trasmax = (clk / 2) / 15; /* tREFI * 9 */ + + /* + * TODO: support multiple DDR3 speed grades, these values below match + * the worst case for DDR3-2133, so should be good for all frequencies, + * but use the most conversative timings. + * DDR3-1866 (DRAM_CLK=912) should also work, or tcl=6 and tcwl=4 with + * DRAM_CLK=792. Maybe even the combination of both, depending on the + * particular device. + */ + u8 tcl = 7; /* CAS latency: 14 */ + u8 tcwl = 5; /* CAS write latency: 10 */ + u8 t_rdata_en = 9; + u8 tphy_wrlat = 5; + u8 twr = 7; + + u8 tckesr = tcke + 1; /* tCKE(min) + 1nCK */ + + u8 twtp = twr + 2 + tcwl; + u8 twr2rd = twtr + 2 + tcwl; /* (WL + BL / 2 + tWTR) / 2 */ + u8 trd2wr = tcl + 3 - tcwl; + u8 txs = ns_to_t(360, clk) / 32; /* max(5nCK,tRFC+10ns)*/ + u8 txsdll = 512 / 32; /* 512 nCK */ + u8 txsabort = 4; + u8 txsfast = 4; + + /* set DRAM timing */ + writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras, + &mctl_ctl->dramtmg[0]); + writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]); + writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd, + &mctl_ctl->dramtmg[2]); + writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]); + writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp, + &mctl_ctl->dramtmg[4]); + writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke, + &mctl_ctl->dramtmg[5]); + /* Value suggested by ZynqMP manual and used by libdram */ + writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]); + writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs, + &mctl_ctl->dramtmg[8]); + writel(0x00020208, &mctl_ctl->dramtmg[9]); + writel(0xe0c05, &mctl_ctl->dramtmg[10]); + writel(0x440c021c, &mctl_ctl->dramtmg[11]); + writel(8, &mctl_ctl->dramtmg[12]); + writel(0xa100002, &mctl_ctl->dramtmg[13]); + writel(txsr, &mctl_ctl->dramtmg[14]); + + clrsetbits_le32(&mctl_ctl->init[0], 0xc0000fff, 0x156); + writel(0x01f20000, &mctl_ctl->init[1]); + writel(0x00001700, &mctl_ctl->init[2]); + writel(0, &mctl_ctl->dfimisc); + writel(0x1f140004, &mctl_ctl->init[3]); + writel(0x00200000, &mctl_ctl->init[4]); + writel(0, &mctl_ctl->init[6]); /* ? */ + writel(0, &mctl_ctl->init[7]); /* ? */ + + clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660); + + /* Configure DFI timing */ + writel(tphy_wrlat | 0x2000000 | (t_rdata_en << 16) | 0x808000, + &mctl_ctl->dfitmg0); + writel(0x100202, &mctl_ctl->dfitmg1); + + /* set refresh timing */ + trfc = 0; /* as written so by boot0 */ + writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg); +} diff --git a/arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c b/arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c new file mode 100644 index 00000000000..940a4d04d57 --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/a523_lpddr4.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sun55i A523 LPDDR4-2133 timings, as programmed by Allwinner's boot0 + * + * (C) Copyright 2024 Jernej Skrabec <jernej.skrabec@gmail.com> + * (C) Copyright 2023 Mikhail Kalashnikov <iuncuim@gmail.com> + * + */ + +#include <asm/arch/dram.h> +#include <asm/arch/cpu.h> + +void mctl_set_timing_params(u32 clk) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + u8 tcl, tcwl, t_rdata_en, trtp, twr, tphy_wrlat; + unsigned int mr1, mr2; + + u8 tccd = 4; + u8 tfaw = ns_to_t(40, clk); + u8 trrd = max(ns_to_t(10, clk), 2); + u8 twtr = max(ns_to_t(10, clk), 4); + u8 trcd = max(ns_to_t(18, clk), 2); + u8 trc = ns_to_t(65, clk); + u8 txp = max(ns_to_t(8, clk), 2); + u8 trp = ns_to_t(21, clk); + u8 tras = ns_to_t(42, clk); + u16 trefi = ns_to_t(3904, clk) / 32; + u16 trfc = ns_to_t(280, clk); + u16 txsr = ns_to_t(290, clk); + + u8 tmrw = max(ns_to_t(14, clk), 5); + u8 tmod = 12; + u8 tcke = max(ns_to_t(15, clk), 2); + u8 tcksrx = max(ns_to_t(2, clk), 2); + u8 tcksre = max(ns_to_t(5, clk), 2); + u8 trasmax = (trefi * 9) / 32; + + if (clk <= 936) { + mr1 = 0x34; + mr2 = 0x1b; + tcl = 10; + tcwl = 5; + t_rdata_en = 17; + trtp = 4; + tphy_wrlat = 5; + twr = 10; + } else if (clk <= 1200) { + mr1 = 0x54; + mr2 = 0x2d; + tcl = 14; + tcwl = 7; + t_rdata_en = 25; + trtp = 6; + tphy_wrlat = 9; + twr = 15; + } else { + mr1 = 0x64; + mr2 = 0x36; + tcl = 16; + tcwl = 8; + t_rdata_en = 29; + trtp = 7; + tphy_wrlat = 11; + twr = 17; + } + + u8 tmrd = tmrw; + u8 tckesr = tcke; + u8 twtp = twr + 9 + tcwl; + u8 twr2rd = twtr + 9 + tcwl; + u8 trd2wr = ns_to_t(4, clk) + 7 - ns_to_t(1, clk) + tcl; + u8 txs = 4; + u8 txsdll = 16; + u8 txsabort = 4; + u8 txsfast = 4; + + /* set DRAM timing */ + writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras, + &mctl_ctl->dramtmg[0]); + writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]); + writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd, + &mctl_ctl->dramtmg[2]); + writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]); + writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp, + &mctl_ctl->dramtmg[4]); + writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke, + &mctl_ctl->dramtmg[5]); + /* Value suggested by ZynqMP manual and used by libdram */ + writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]); + writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs, + &mctl_ctl->dramtmg[8]); + writel(0x00020208, &mctl_ctl->dramtmg[9]); + writel(0xE0C05, &mctl_ctl->dramtmg[10]); + writel(0x440C021C, &mctl_ctl->dramtmg[11]); + writel(8, &mctl_ctl->dramtmg[12]); + writel(0xA100002, &mctl_ctl->dramtmg[13]); + writel(txsr, &mctl_ctl->dramtmg[14]); + + clrsetbits_le32(&mctl_ctl->init[0], 0xC0000FFF, 0x558); + writel(0x01f20000, &mctl_ctl->init[1]); + writel(0x00001705, &mctl_ctl->init[2]); + writel(0, &mctl_ctl->dfimisc); + writel((mr1 << 16) | mr2, &mctl_ctl->init[3]); + writel(0x00330000, &mctl_ctl->init[4]); + writel(0x00040072, &mctl_ctl->init[6]); + writel(0x00260008, &mctl_ctl->init[7]); + + clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660); + + /* Configure DFI timing */ + writel(tphy_wrlat | 0x2000000 | (t_rdata_en << 16) | 0x808000, + &mctl_ctl->dfitmg0); + writel(0x100202, &mctl_ctl->dfitmg1); + + /* set refresh timing */ + writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg); +} diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index 1b4b7d87163..e00b54f4535 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -137,6 +137,11 @@ M: Chris Morgan <macromorgan@hotmail.com> S: Maintained F: configs/anbernic_rg35xx_h700_defconfig +AVAOTA A1 BOARD +M: Andre Przywara <andre.przywara@arm.com> +S: Maintained +F: configs/avaota-a1_defconfig + BANANAPI M1 PLUS M: Jagan Teki <jagan@amarulasolutions.com> S: Maintained @@ -531,6 +536,11 @@ M: Quentin Schulz <quentin.schulz@free-electrons.com> S: Maintained F: configs/parrot_r16_defconfig +RADXA CUBIE A5E BOARD +M: Andre Przywara <andre.przywara@arm.com> +S: Maintained +F: configs/radxa-cubie-a5e_defconfig + SINLINX SINA31s BOARD M: Chen-Yu Tsai <wens@csie.org> S: Maintained @@ -591,6 +601,11 @@ M: Andre Przywara <andre.przywara@arm.com> S: Maintained F: configs/x96_mate_defconfig +X96Q PRO+ TV BOX +M: Andre Przywara <andre.przywara@arm.com> +S: Maintained +F: configs/x96q_pro_plus_defconfig + YONES TOPTECH BD1078 BOARD M: Paul Kocialkowski <contact@paulk.fr> S: Maintained diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 943b6221b8a..2929bc17f08 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -118,6 +118,10 @@ void i2c_init_board(void) clock_twi_onoff(5, 1); sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN50I_H616_GPL_R_TWI); sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN50I_H616_GPL_R_TWI); +#elif CONFIG_MACH_SUN55I_A523 + clock_twi_onoff(5, 1); + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN50I_GPL_R_TWI); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN50I_GPL_R_TWI); #else clock_twi_onoff(5, 1); sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI); @@ -435,7 +439,8 @@ static void mmc_pinmux_setup(int sdc) sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); sunxi_gpio_set_drv(pin, 2); } -#elif defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_A133) +#elif defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_A133) || \ + defined(CONFIG_MACH_SUN55I_A523) /* SDC2: PC0-PC1, PC5-PC6, PC8-PC11, PC13-PC16 */ for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(16); pin++) { if (pin > SUNXI_GPC(1) && pin < SUNXI_GPC(5)) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index ac25fcea21d..ab05536bd02 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -80,7 +80,7 @@ config SPL_MAX_SIZE default 0x1b000 if AM33XX && !TI_SECURE_DEVICE default 0xec00 if OMAP34XX default 0x10000 if ARCH_MX6 && !MX6_OCRAM_256KB - default 0xbfa0 if MACH_SUN50I_H616 || MACH_SUN50I_A133 + default 0xbfa0 if MACH_SUN50I_H616 || MACH_SUN50I_A133 || MACH_SUN55I_A523 default 0x7000 if RCAR_GEN3 default 0x5fa0 if SUNXI_SRAM_ADDRESS = 0x0 default 0x7fa0 if ARCH_SUNXI @@ -278,6 +278,7 @@ config SPL_TEXT_BASE default 0x00912000 if ARCH_MX7 default 0x40301350 if OMAP54XX default 0x10060 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN9I + default 0x44060 if MACH_SUN55I_A523 default 0x20060 if SUN50I_GEN_H6 || SUNXI_GEN_NCAT2 default 0x00060 if ARCH_SUNXI default 0xfffc0000 if ARCH_ZYNQMP @@ -432,6 +433,7 @@ config SPL_STACK default 0x118000 if MACH_SUN50I_H6 default 0x52a00 if MACH_SUN50I_H616 default 0x40000 if MACH_SUN8I_R528 || MACH_SUN50I_A133 + default 0x44000 if MACH_SUN55I_A523 default 0x54000 if MACH_SUN50I || MACH_SUN50I_H5 default 0x18000 if MACH_SUN9I default 0x8000 if ARCH_SUNXI diff --git a/configs/avaota-a1_defconfig b/configs/avaota-a1_defconfig new file mode 100644 index 00000000000..55457edd3b3 --- /dev/null +++ b/configs/avaota-a1_defconfig @@ -0,0 +1,31 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun55i-t527-avaota-a1" +CONFIG_SPL=y +CONFIG_DRAM_SUNXI_DX_ODT=0x07070707 +CONFIG_DRAM_SUNXI_DX_DRI=0x0d0d0d0d +CONFIG_DRAM_SUNXI_CA_DRI=0x0e0e +CONFIG_DRAM_SUNXI_ODT_EN=0x84848484 +CONFIG_DRAM_SUNXI_TPR0=0x80808080 +CONFIG_DRAM_SUNXI_TPR1=0x06060606 +CONFIG_DRAM_SUNXI_TPR6=0x38000000 +CONFIG_DRAM_SUNXI_TPR10=0x802f3333 +CONFIG_DRAM_SUNXI_TPR11=0xc7c5c4c2 +CONFIG_DRAM_SUNXI_TPR12=0x3533302f +CONFIG_MACH_SUN55I_A523=y +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_R_I2C_ENABLE=y +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPL_I2C=y +CONFIG_SPL_SYS_I2C_LEGACY=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_SYS_I2C_SLAVE=0x7f +CONFIG_SYS_I2C_SPEED=400000 +CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_REGULATOR_AXP=y +CONFIG_AXP717_POWER=y +CONFIG_AXP_I2C_ADDRESS=0x35 +CONFIG_AXP_DCDC2_VOLT=920 +CONFIG_AXP_DCDC3_VOLT=1160 +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y diff --git a/configs/radxa-cubie-a5e_defconfig b/configs/radxa-cubie-a5e_defconfig new file mode 100644 index 00000000000..f5958629226 --- /dev/null +++ b/configs/radxa-cubie-a5e_defconfig @@ -0,0 +1,32 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun55i-a527-cubie-a5e" +CONFIG_SPL=y +CONFIG_DRAM_SUNXI_DX_ODT=0x07070707 +CONFIG_DRAM_SUNXI_DX_DRI=0x0d0d0d0d +CONFIG_DRAM_SUNXI_CA_DRI=0x0e0e +CONFIG_DRAM_SUNXI_ODT_EN=0x84848484 +CONFIG_DRAM_SUNXI_TPR0=0x80808080 +CONFIG_DRAM_SUNXI_TPR1=0x06060606 +CONFIG_DRAM_SUNXI_TPR6=0x38000000 +CONFIG_DRAM_SUNXI_TPR10=0x802f3333 +CONFIG_DRAM_SUNXI_TPR11=0xc7c5c4c2 +CONFIG_DRAM_SUNXI_TPR12=0x3533302f +# BSP value: CONFIG_DRAM_SUNXI_TPR11=0xc6c4c2c0 +# BSP value: CONFIG_DRAM_SUNXI_TPR12=0x3a373233 +CONFIG_MACH_SUN55I_A523=y +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_R_I2C_ENABLE=y +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPL_I2C=y +CONFIG_SPL_SYS_I2C_LEGACY=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_SYS_I2C_SLAVE=0x7f +CONFIG_SYS_I2C_SPEED=400000 +CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_REGULATOR_AXP=y +CONFIG_AXP717_POWER=y +CONFIG_AXP_DCDC2_VOLT=920 +CONFIG_AXP_DCDC3_VOLT=1100 +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y diff --git a/configs/x96q_pro_plus_defconfig b/configs/x96q_pro_plus_defconfig new file mode 100644 index 00000000000..07d3b078bef --- /dev/null +++ b/configs/x96q_pro_plus_defconfig @@ -0,0 +1,32 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="allwinner/sun55i-h728-x96qpro+" +CONFIG_SPL=y +CONFIG_DRAM_SUNXI_DX_ODT=0x07070707 +CONFIG_DRAM_SUNXI_DX_DRI=0x0c0c0c0c +CONFIG_DRAM_SUNXI_CA_DRI=0x0e0e +CONFIG_DRAM_SUNXI_ODT_EN=0x90909090 +CONFIG_DRAM_SUNXI_TPR0=0x80808080 +CONFIG_DRAM_SUNXI_TPR1=0x06060606 +CONFIG_DRAM_SUNXI_TPR6=0x3380807e +CONFIG_DRAM_SUNXI_TPR10=0x802f7788 +CONFIG_DRAM_SUNXI_TPR11=0x8f919190 +CONFIG_DRAM_SUNXI_TPR12=0x22222723 +CONFIG_MACH_SUN55I_A523=y +CONFIG_SUNXI_DRAM_A523_DDR3=y +CONFIG_DRAM_CLK=792 +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_R_I2C_ENABLE=y +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPL_I2C=y +CONFIG_SPL_SYS_I2C_LEGACY=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_SYS_I2C_SLAVE=0x7f +CONFIG_SYS_I2C_SPEED=400000 +CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_REGULATOR_AXP=y +CONFIG_AXP717_POWER=y +CONFIG_AXP_DCDC2_VOLT=920 +CONFIG_AXP_DCDC3_VOLT=1360 +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index f44db76c182..1c1cc82719c 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -129,4 +129,18 @@ config CLK_SUN50I_A100 This enables common clock driver support for platforms based on Allwinner A100/A133 SoCs. +config CLK_SUN55I_A523 + bool "Clock driver for Allwinner A523/T527" + default MACH_SUN55I_A523 + help + This enables common clock driver support for platforms based + on Allwinner A523/T527 SoC. + +config CLK_SUN55I_A523_R + bool "Clock driver for Allwinner A523 generation PRCM" + default MACH_SUN55I_A523 + help + This enables common clock driver support for the PRCM + in Allwinner A523/T527 SoCs. + endif # CLK_SUNXI diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 7ff71c756e0..93b542cebcd 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -25,3 +25,5 @@ obj-$(CONFIG_CLK_SUN50I_H6_R) += clk_h6_r.o obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o obj-$(CONFIG_CLK_SUN50I_A100) += clk_a100.o +obj-$(CONFIG_CLK_SUN55I_A523) += clk_a523.o +obj-$(CONFIG_CLK_SUN55I_A523_R) += clk_a523_r.o diff --git a/drivers/clk/sunxi/clk_a523.c b/drivers/clk/sunxi/clk_a523.c new file mode 100644 index 00000000000..1de95fbaf2f --- /dev/null +++ b/drivers/clk/sunxi/clk_a523.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2024 Arm Ltd. + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <clk/sunxi.h> +#include <linux/bitops.h> + +#include <dt-bindings/clock/sun55i-a523-ccu.h> +#include <dt-bindings/reset/sun55i-a523-ccu.h> + +static struct ccu_clk_gate a523_gates[] = { + [CLK_PLL_PERIPH0_200M] = GATE_DUMMY, + [CLK_APB1] = GATE_DUMMY, + + [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), + [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), + [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)), + [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_BUS_UART4] = GATE(0x90c, BIT(4)), + [CLK_BUS_UART5] = GATE(0x90c, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x91c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)), + [CLK_BUS_I2C3] = GATE(0x91c, 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_EMAC0_25M] = GATE(0x970, BIT(30) | BIT(31)), + [CLK_EMAC1_25M] = GATE(0x974, BIT(30) | BIT(31)), + [CLK_BUS_EMAC0] = GATE(0x97c, BIT(0)), + [CLK_BUS_EMAC1] = GATE(0x98c, BIT(0)), + + [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)), + [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_EHCI1] = GATE(0xa8c, BIT(5)), + [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)), +}; + +static struct ccu_reset a523_resets[] = { + [RST_BUS_MMC0] = RESET(0x84c, BIT(16)), + [RST_BUS_MMC1] = RESET(0x84c, BIT(17)), + [RST_BUS_MMC2] = RESET(0x84c, BIT(18)), + [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_UART4] = RESET(0x90c, BIT(20)), + [RST_BUS_UART5] = RESET(0x90c, BIT(21)), + [RST_BUS_I2C0] = RESET(0x91c, BIT(16)), + [RST_BUS_I2C1] = RESET(0x91c, BIT(17)), + [RST_BUS_I2C2] = RESET(0x91c, BIT(18)), + [RST_BUS_I2C3] = RESET(0x91c, BIT(19)), + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), + [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), + + [RST_BUS_EMAC0] = RESET(0x97c, BIT(16)), + [RST_BUS_EMAC1] = RESET(0x98c, BIT(16) | BIT(17)), + + [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_EHCI1] = RESET(0xa8c, BIT(21)), + [RST_BUS_OTG] = RESET(0xa8c, BIT(24)), +}; + +const struct ccu_desc a523_ccu_desc = { + .gates = a523_gates, + .resets = a523_resets, + .num_gates = ARRAY_SIZE(a523_gates), + .num_resets = ARRAY_SIZE(a523_resets), +}; diff --git a/drivers/clk/sunxi/clk_a523_r.c b/drivers/clk/sunxi/clk_a523_r.c new file mode 100644 index 00000000000..01e613d20aa --- /dev/null +++ b/drivers/clk/sunxi/clk_a523_r.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2024 Arm Ltd. + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <clk/sunxi.h> +#include <dt-bindings/clock/sun55i-a523-r-ccu.h> +#include <dt-bindings/reset/sun55i-a523-r-ccu.h> +#include <linux/bitops.h> + +static struct ccu_clk_gate a523_r_gates[] = { + [CLK_R_AHB] = GATE_DUMMY, + [CLK_R_APB0] = GATE_DUMMY, + [CLK_R_APB1] = GATE_DUMMY, + [CLK_BUS_R_TWD] = GATE(0x12c, BIT(0)), + [CLK_BUS_R_I2C0] = GATE(0x19c, BIT(0)), + [CLK_BUS_R_I2C1] = GATE(0x19c, BIT(1)), + [CLK_BUS_R_I2C2] = GATE(0x19c, BIT(2)), + [CLK_BUS_R_RTC] = GATE(0x20c, BIT(0)), +}; + +static struct ccu_reset a523_r_resets[] = { + [RST_BUS_R_TWD] = RESET(0x12c, BIT(16)), + [RST_BUS_R_UART0] = RESET(0x18c, BIT(16)), + [RST_BUS_R_I2C0] = RESET(0x19c, BIT(16)), + [RST_BUS_R_I2C1] = RESET(0x19c, BIT(17)), + [RST_BUS_R_I2C2] = RESET(0x19c, BIT(18)), + [RST_BUS_R_PPU1] = RESET(0x1ac, BIT(17)), + [RST_BUS_R_RTC] = RESET(0x20c, BIT(16)), +}; + +const struct ccu_desc a523_r_ccu_desc = { + .gates = a523_r_gates, + .resets = a523_r_resets, + .num_gates = ARRAY_SIZE(a523_r_gates), + .num_resets = ARRAY_SIZE(a523_r_resets), +}; diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c index e0765cbc6dc..842a0541bd6 100644 --- a/drivers/clk/sunxi/clk_sunxi.c +++ b/drivers/clk/sunxi/clk_sunxi.c @@ -126,6 +126,8 @@ extern const struct ccu_desc a100_ccu_desc; extern const struct ccu_desc h6_r_ccu_desc; extern const struct ccu_desc r40_ccu_desc; extern const struct ccu_desc v3s_ccu_desc; +extern const struct ccu_desc a523_ccu_desc; +extern const struct ccu_desc a523_r_ccu_desc; static const struct udevice_id sunxi_clk_ids[] = { #ifdef CONFIG_CLK_SUN4I_A10 @@ -224,6 +226,14 @@ static const struct udevice_id sunxi_clk_ids[] = { { .compatible = "allwinner,suniv-f1c100s-ccu", .data = (ulong)&f1c100s_ccu_desc }, #endif +#ifdef CONFIG_CLK_SUN55I_A523 + { .compatible = "allwinner,sun55i-a523-ccu", + .data = (ulong)&a523_ccu_desc }, +#endif +#ifdef CONFIG_CLK_SUN55I_A523_R + { .compatible = "allwinner,sun55i-a523-r-ccu", + .data = (ulong)&a523_r_ccu_desc }, +#endif { } }; diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 06c1e09bf26..e28c81afffe 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -99,6 +99,19 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) */ if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) pll_hz /= 2; + + /* + * The A523/T527 uses PERIPH0_400M as the MMC0/1 input clock, + * and PERIPH0_800M for MMC2. There is also the hidden divider + * of 2. The clock code reports 600 MHz for PERIPH0. + * Adjust the calculation accordingly: 600 * hidden2 / 3 for + * MMC0/1, and 600 * hidden2 / 3 * 2 for MMC2. + */ + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) { + pll_hz /= 3; + if (priv->mmc_no == 2) + pll_hz *= 2; + } } div = pll_hz / hz; @@ -153,6 +166,10 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) CCM_MMC_CTRL_SCLK_DLY(sclk_dly); } + /* The A523 has a second divider, not a shift. */ + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + n = (1U << n) - 1; + writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) | CCM_MMC_CTRL_M(div) | val, priv->mclkreg); @@ -559,7 +576,8 @@ struct mmc *sunxi_mmc_init(int sdc_no) cfg->host_caps = MMC_MODE_4BIT; if ((IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN8I) || - IS_ENABLED(CONFIG_SUN50I_GEN_H6)) && (sdc_no == 2)) + IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_MACH_SUN55I_A523)) && + (sdc_no == 2)) cfg->host_caps = MMC_MODE_8BIT; cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index 65e8192a99a..54314992299 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -139,4 +139,14 @@ config PINCTRL_SUN20I_D1 default MACH_SUN8I_R528 select PINCTRL_SUNXI +config PINCTRL_SUN55I_A523 + bool "Support for the Allwinner A523 PIO" + default MACH_SUN55I_A523 + select PINCTRL_SUNXI + +config PINCTRL_SUN55I_A523_R + bool "Support for the Allwinner A523 R-PIO" + default MACH_SUN55I_A523 + select PINCTRL_SUNXI + endif diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index c38edf7d4f5..03cfe23aaf8 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -759,6 +759,29 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = .num_banks = 9, }; +static const struct sunxi_pinctrl_function sun55i_a523_pinctrl_functions[] = { + { "emac0", 5 }, /* PI0-PI16 */ + { "gpio_in", 0 }, + { "gpio_out", 1 }, + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC0-PC16 */ + { "spi0", 4 }, /* PC0-PC7, PC15-PC16 */ +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PH0-PH1 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun55i_a523_pinctrl_desc = { + .functions = sun55i_a523_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun55i_a523_pinctrl_functions), + .first_bank = SUNXI_GPIO_A, + .num_banks = 11, +}; + static const struct sunxi_pinctrl_function sun50i_h616_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, @@ -809,6 +832,21 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a100_r_pinctrl_desc .num_banks = 1, }; +static const struct sunxi_pinctrl_function sun55i_a523_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, + { "r_i2c0", 2 }, /* PL0-PL1 */ + { "r_spi", 6 }, /* PL10-PL13 */ + { "r_uart", 2 }, /* PL2-PL3 */ +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun55i_a523_r_pinctrl_desc = { + .functions = sun55i_a523_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun55i_a523_r_pinctrl_functions), + .first_bank = SUNXI_GPIO_L, + .num_banks = 2, +}; + static const struct udevice_id sunxi_pinctrl_ids[] = { #ifdef CONFIG_PINCTRL_SUNIV_F1C100S { @@ -984,6 +1022,18 @@ static const struct udevice_id sunxi_pinctrl_ids[] = { .data = (ulong)&sun50i_a100_r_pinctrl_desc, }, #endif +#ifdef CONFIG_PINCTRL_SUN55I_A523 + { + .compatible = "allwinner,sun55i-a523-pinctrl", + .data = (ulong)&sun55i_a523_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN55I_A523_R + { + .compatible = "allwinner,sun55i-a523-r-pinctrl", + .data = (ulong)&sun55i_a523_r_pinctrl_desc, + }, +#endif {} }; diff --git a/drivers/power/pmic/axp.c b/drivers/power/pmic/axp.c index c300fd2bbc2..1204ec00f8d 100644 --- a/drivers/power/pmic/axp.c +++ b/drivers/power/pmic/axp.c @@ -89,6 +89,7 @@ static const struct udevice_id axp_pmic_ids[] = { { .compatible = "x-powers,axp221", .data = AXP221_ID }, { .compatible = "x-powers,axp223", .data = AXP223_ID }, { .compatible = "x-powers,axp313a", .data = AXP313_ID }, + { .compatible = "x-powers,axp323", .data = AXP323_ID }, { .compatible = "x-powers,axp717", .data = AXP717_ID }, { .compatible = "x-powers,axp803", .data = AXP803_ID }, { .compatible = "x-powers,axp806", .data = AXP806_ID }, diff --git a/drivers/power/regulator/axp_regulator.c b/drivers/power/regulator/axp_regulator.c index 75cdbca30f6..7794a4f5d92 100644 --- a/drivers/power/regulator/axp_regulator.c +++ b/drivers/power/regulator/axp_regulator.c @@ -318,6 +318,7 @@ static const struct axp_regulator_plat *const axp_regulators[] = { [AXP221_ID] = axp22x_regulators, [AXP223_ID] = axp22x_regulators, [AXP313_ID] = axp313_regulators, + [AXP323_ID] = axp313_regulators, [AXP717_ID] = axp717_regulators, [AXP803_ID] = axp803_regulators, [AXP806_ID] = axp806_regulators, diff --git a/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi b/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi new file mode 100644 index 00000000000..ee485899ba0 --- /dev/null +++ b/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +// Copyright (C) 2023-2024 Arm Ltd. + +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/clock/sun6i-rtc.h> +#include <dt-bindings/clock/sun55i-a523-ccu.h> +#include <dt-bindings/clock/sun55i-a523-r-ccu.h> +#include <dt-bindings/reset/sun55i-a523-ccu.h> +#include <dt-bindings/reset/sun55i-a523-r-ccu.h> + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x000>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x100>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x200>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x300>; + enable-method = "psci"; + }; + + cpu4: cpu@400 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x400>; + enable-method = "psci"; + }; + + cpu5: cpu@500 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x500>; + enable-method = "psci"; + }; + + cpu6: cpu@600 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x600>; + enable-method = "psci"; + }; + + cpu7: cpu@700 { + compatible = "arm,cortex-a55"; + device_type = "cpu"; + reg = <0x700>; + enable-method = "psci"; + }; + }; + + osc24M: osc24M-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + + pmu { + compatible = "arm,cortex-a55-pmu"; + interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + arm,no-tick-in-suspend; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>, + <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>, + <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>, + <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x40000000>; + + pio: pinctrl@2000000 { + compatible = "allwinner,sun55i-a523-pinctrl"; + reg = <0x2000000 0x800>; + interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc CLK_OSC32K>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + + mmc0_pins: mmc0-pins { + pins = "PF0" ,"PF1", "PF2", "PF3", "PF4", "PF5"; + allwinner,pinmux = <2>; + function = "mmc0"; + drive-strength = <30>; + bias-pull-up; + }; + + /omit-if-no-ref/ + mmc1_pins: mmc1-pins { + pins = "PG0" ,"PG1", "PG2", "PG3", "PG4", "PG5"; + allwinner,pinmux = <2>; + function = "mmc1"; + drive-strength = <30>; + bias-pull-up; + }; + + mmc2_pins: mmc2-pins { + pins = "PC0", "PC1" ,"PC5", "PC6", "PC8", + "PC9", "PC10", "PC11", "PC13", "PC14", + "PC15", "PC16"; + allwinner,pinmux = <3>; + function = "mmc2"; + drive-strength = <30>; + bias-pull-up; + }; + + uart0_pb_pins: uart0-pb-pins { + pins = "PB9", "PB10"; + allwinner,pinmux = <2>; + function = "uart0"; + }; + }; + + ccu: clock-controller@2001000 { + compatible = "allwinner,sun55i-a523-ccu"; + reg = <0x02001000 0x1000>; + clocks = <&osc24M>, <&rtc CLK_OSC32K>, + <&rtc CLK_IOSC>, <&rtc CLK_OSC32K_FANOUT>; + clock-names = "hosc", "losc", + "iosc", "losc-fanout"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + mmc0: mmc@4020000 { + compatible = "allwinner,sun55i-a523-mmc", + "allwinner,sun20i-d1-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>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins>; + status = "disabled"; + + max-frequency = <150000000>; + cap-sd-highspeed; + cap-mmc-highspeed; + cap-sdio-irq; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc1: mmc@4021000 { + compatible = "allwinner,sun55i-a523-mmc", + "allwinner,sun20i-d1-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>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + status = "disabled"; + + max-frequency = <150000000>; + cap-sd-highspeed; + cap-mmc-highspeed; + cap-sdio-irq; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc2: mmc@4022000 { + compatible = "allwinner,sun55i-a523-mmc", + "allwinner,sun20i-d1-mmc"; + reg = <0x04022000 0x1000>; + clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>; + clock-names = "ahb", "mmc"; + resets = <&ccu RST_BUS_MMC2>; + reset-names = "ahb"; + interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + status = "disabled"; + + max-frequency = <150000000>; + cap-sd-highspeed; + cap-mmc-highspeed; + cap-sdio-irq; + #address-cells = <1>; + #size-cells = <0>; + }; + + wdt: watchdog@2050000 { + compatible = "allwinner,sun55i-a523-wdt"; + reg = <0x2050000 0x20>; + interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc24M>, <&rtc CLK_OSC32K>; + clock-names = "hosc", "losc"; + status = "okay"; + }; + + 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>; + status = "disabled"; + }; + + uart1: serial@2500400 { + compatible = "snps,dw-apb-uart"; + reg = <0x02500400 0x400>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART1>; + resets = <&ccu RST_BUS_UART1>; + status = "disabled"; + }; + + uart2: serial@2500800 { + compatible = "snps,dw-apb-uart"; + reg = <0x02500800 0x400>; + interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART2>; + resets = <&ccu RST_BUS_UART2>; + status = "disabled"; + }; + + uart3: serial@2500c00 { + compatible = "snps,dw-apb-uart"; + reg = <0x02500c00 0x400>; + interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART3>; + resets = <&ccu RST_BUS_UART3>; + status = "disabled"; + }; + + uart4: serial@2501000 { + compatible = "snps,dw-apb-uart"; + reg = <0x02501000 0x400>; + interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART4>; + resets = <&ccu RST_BUS_UART4>; + status = "disabled"; + }; + + uart5: serial@2501400 { + compatible = "snps,dw-apb-uart"; + reg = <0x02501400 0x400>; + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART5>; + resets = <&ccu RST_BUS_UART5>; + status = "disabled"; + }; + + uart6: serial@2501800 { + compatible = "snps,dw-apb-uart"; + reg = <0x02501800 0x400>; + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART6>; + resets = <&ccu RST_BUS_UART6>; + status = "disabled"; + }; + + uart7: serial@2501c00 { + compatible = "snps,dw-apb-uart"; + reg = <0x02501c00 0x400>; + interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART7>; + resets = <&ccu RST_BUS_UART7>; + status = "disabled"; + }; + + i2c0: i2c@2502000 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x2502000 0x400>; + interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C0>; + resets = <&ccu RST_BUS_I2C0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@2502400 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x2502400 0x400>; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C1>; + resets = <&ccu RST_BUS_I2C1>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@2502800 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x2502800 0x400>; + interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C2>; + resets = <&ccu RST_BUS_I2C2>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c3: i2c@2502c00 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x2502c00 0x400>; + interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C3>; + resets = <&ccu RST_BUS_I2C3>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c4: i2c@2503000 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x2503000 0x400>; + interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C4>; + resets = <&ccu RST_BUS_I2C4>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c5: i2c@2503400 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x2503400 0x400>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_I2C5>; + resets = <&ccu RST_BUS_I2C5>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + gic: interrupt-controller@3400000 { + compatible = "arm,gic-v3"; + #address-cells = <1>; + #interrupt-cells = <3>; + #size-cells = <1>; + ranges; + interrupt-controller; + reg = <0x3400000 0x10000>, + <0x3460000 0x100000>; + interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>; + dma-noncoherent; + + its: msi-controller@3440000 { + compatible = "arm,gic-v3-its"; + reg = <0x3440000 0x20000>; + msi-controller; + #msi-cells = <1>; + dma-noncoherent; + }; + }; + + usb_otg: usb@4100000 { + compatible = "allwinner,sun55i-a523-musb", + "allwinner,sun8i-a33-musb"; + reg = <0x4100000 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "mc"; + clocks = <&ccu CLK_BUS_OTG>; + resets = <&ccu RST_BUS_OTG>; + extcon = <&usbphy 0>; + phys = <&usbphy 0>; + phy-names = "usb"; + status = "disabled"; + }; + + usbphy: phy@4100400 { + compatible = "allwinner,sun55i-a523-usb-phy", + "allwinner,sun20i-d1-usb-phy"; + reg = <0x4100400 0x100>, + <0x4101800 0x100>, + <0x4200800 0x100>; + reg-names = "phy_ctrl", + "pmu0", + "pmu1"; + clocks = <&osc24M>, + <&osc24M>; + clock-names = "usb0_phy", + "usb1_phy"; + resets = <&ccu RST_USB_PHY0>, + <&ccu RST_USB_PHY1>; + reset-names = "usb0_reset", + "usb1_reset"; + status = "disabled"; + #phy-cells = <1>; + }; + + ehci0: usb@4101000 { + compatible = "allwinner,sun55i-a523-ehci", + "generic-ehci"; + reg = <0x4101000 0x100>; + interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_OHCI0>, + <&ccu CLK_BUS_EHCI0>, + <&ccu CLK_USB_OHCI0>; + resets = <&ccu RST_BUS_OHCI0>, + <&ccu RST_BUS_EHCI0>; + phys = <&usbphy 0>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci0: usb@4101400 { + compatible = "allwinner,sun55i-a523-ohci", + "generic-ohci"; + reg = <0x4101400 0x100>; + interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_OHCI0>, + <&ccu CLK_USB_OHCI0>; + resets = <&ccu RST_BUS_OHCI0>; + phys = <&usbphy 0>; + phy-names = "usb"; + status = "disabled"; + }; + + ehci1: usb@4200000 { + compatible = "allwinner,sun55i-a523-ehci", + "generic-ehci"; + reg = <0x4200000 0x100>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_OHCI1>, + <&ccu CLK_BUS_EHCI1>, + <&ccu CLK_USB_OHCI1>; + resets = <&ccu RST_BUS_OHCI1>, + <&ccu RST_BUS_EHCI1>; + phys = <&usbphy 1>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci1: usb@4200400 { + compatible = "allwinner,sun55i-a523-ohci", + "generic-ohci"; + reg = <0x4200400 0x100>; + interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_OHCI1>, + <&ccu CLK_USB_OHCI1>; + resets = <&ccu RST_BUS_OHCI1>; + phys = <&usbphy 1>; + phy-names = "usb"; + status = "disabled"; + }; + + r_ccu: clock-controller@7010000 { + compatible = "allwinner,sun55i-a523-r-ccu"; + reg = <0x7010000 0x250>; + clocks = <&osc24M>, + <&rtc CLK_OSC32K>, + <&rtc CLK_IOSC>, + <&ccu CLK_PLL_PERIPH0_200M>, + <&ccu CLK_PLL_AUDIO0_4X>; + clock-names = "hosc", + "losc", + "iosc", + "pll-periph", + "pll-audio"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + nmi_intc: interrupt-controller@7010320 { + compatible = "allwinner,sun55i-a523-nmi"; + reg = <0x07010320 0xc>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + }; + + r_pio: pinctrl@7022000 { + compatible = "allwinner,sun55i-a523-r-pinctrl"; + reg = <0x7022000 0x800>; + interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_R_APB0>, + <&osc24M>, + <&rtc CLK_OSC32K>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + + r_i2c_pins: r-i2c-pins { + pins = "PL0" ,"PL1"; + allwinner,pinmux = <2>; + function = "r_i2c0"; + }; + }; + + r_i2c0: i2c@7081400 { + compatible = "allwinner,sun55i-a523-i2c", + "allwinner,sun8i-v536-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x07081400 0x400>; + interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_BUS_R_I2C0>; + resets = <&r_ccu RST_BUS_R_I2C0>; + pinctrl-names = "default"; + pinctrl-0 = <&r_i2c_pins>; + status = "disabled"; + + #address-cells = <1>; + #size-cells = <0>; + }; + + rtc: rtc@7090000 { + compatible = "allwinner,sun55i-a523-rtc", + "allwinner,sun50i-r329-rtc"; + reg = <0x7090000 0x400>; + interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_BUS_R_RTC>, + <&osc24M>, + <&r_ccu CLK_R_AHB>; + clock-names = "bus", "hosc", "ahb"; + #clock-cells = <1>; + }; + }; +}; diff --git a/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts b/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts new file mode 100644 index 00000000000..ad9bd6da424 --- /dev/null +++ b/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +// Copyright (C) 2025 Arm Ltd. + +/dts-v1/; + +#include "sun55i-a523.dtsi" + +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Radxa A5E"; + compatible = "radxa,cubie-a5e", "allwinner,sun55i-a527"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + ext_osc32k: ext-osc32k-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "ext_osc32k"; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply from the USB-C connector */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_usb_vbus: vbus { + compatible = "regulator-fixed"; + regulator-name = "usb-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_vcc5v>; + gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */ + enable-active-high; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&mmc0 { + vmmc-supply = <®_cldo3>; + cd-gpios = <&pio 5 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PF6 */ + bus-width = <4>; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&pio { + vcc-pb-supply = <®_cldo3>; /* via VCC-IO */ + vcc-pc-supply = <®_cldo1>; + vcc-pd-supply = <®_cldo3>; + vcc-pe-supply = <®_aldo2>; + vcc-pf-supply = <®_cldo3>; /* actually switchable */ + vcc-pg-supply = <®_bldo1>; + vcc-ph-supply = <®_cldo3>; /* via VCC-IO */ + vcc-pi-supply = <®_cldo3>; + vcc-pj-supply = <®_cldo4>; + vcc-pk-supply = <®_cldo1>; +}; + +&r_i2c0 { + status = "okay"; + + axp717: pmic@34 { + compatible = "x-powers,axp717"; + reg = <0x34>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + vin4-supply = <®_vcc5v>; + aldoin-supply = <®_vcc5v>; + bldoin-supply = <®_vcc5v>; + cldoin-supply = <®_vcc5v>; + + regulators { + /* Supplies the "little" cluster (1.4 GHz cores) */ + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-cpul"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <920000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-dram"; + }; + + reg_aldo1: aldo1 { + /* not connected */ + }; + + reg_aldo2: aldo2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pe"; + }; + + reg_aldo3: aldo3 { + /* supplies the I2C pins for this PMIC */ + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-pl-usb"; + }; + + reg_aldo4: aldo4 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pll-dxco-avcc"; + }; + + reg_bldo1: bldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pg-iowifi"; + }; + + reg_bldo2: bldo2 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pm-lpddr4"; + }; + + reg_bldo3: bldo3 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-mipi-cam"; + }; + + reg_bldo4: bldo4 { + /* not connected */ + }; + + reg_cldo1: cldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pc-and-their-dog"; + }; + + reg_cldo2: cldo2 { + /* not connected */ + }; + + reg_cldo3: cldo3 { + /* IO, USB-2, 3V3, card, NAND, sensor, PI */ + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-io-mmc-spi-ana"; + }; + + reg_cldo4: cldo4 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-pj-phy"; + }; + + reg_cpusldo: cpusldo { + /* supplies the management core */ + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdd-cpus"; + }; + }; + }; + + axp323: pmic@36 { + compatible = "x-powers,axp323"; + reg = <0x36>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + status = "okay"; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + + regulators { + aldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-mipi-dsi"; + }; + + dldo1 { + /* not connected */ + }; + + /* Supplies the "big" cluster (1.8 GHz cores) */ + reg_dcdc1_323: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-cpub"; + }; + + /* DCDC2 is polyphased with DCDC1 */ + + /* RISC-V management core supply */ + reg_dcdc3_323: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdd-dnr"; + }; + }; + }; +}; + +&r_pio { +/* + * Specifying the supply would create a circular dependency. + * + * vcc-pl-supply = <®_aldo3>; + */ + vcc-pm-supply = <®_aldo3>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&usb_otg { + /* + * The USB-C port is the primary power supply, so in this configuration + * relies on the other end of the USB cable to supply the VBUS power. + * So use this port in peripheral mode. + * It is possible to supply the board with the 5V pins on the GPIO + * header, and since the DCIN_5V line is hardwired to the USB-C VBUS + * pins, the port turns into a host port, unconditionally supplying + * power. The dr_mode property should be changed to "host" here, if + * users choose this setup. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +/* + * The schematic describes USB0_ID (PL10), measuring VBUS_5V, which looks to + * be always on. Also there is USB-VBUSDET (PL2), which is measuring the same + * VBUS_5V. There is also DCIN_DET, which measures DCIN_5V, so the power + * input rail. + * None of them seem to make any sense in relation to detecting USB devices + * or whether there is power provided via any USB pins: they would always + * report high, otherwise the system wouldn't be running. + * The AXP717C provides proper USB-C CC pin functionality, but the PMIC is + * not connected to those pins of the USB-C connector. + */ +&usbphy { + usb0_vbus-supply = <®_vcc5v>; + usb1_vbus-supply = <®_usb_vbus>; + status = "okay"; +}; diff --git a/dts/upstream/src/arm64/allwinner/sun55i-h728-x96qpro+.dts b/dts/upstream/src/arm64/allwinner/sun55i-h728-x96qpro+.dts new file mode 100644 index 00000000000..59db103546f --- /dev/null +++ b/dts/upstream/src/arm64/allwinner/sun55i-h728-x96qpro+.dts @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +// Copyright (C) 2024 Arm Ltd. + +/dts-v1/; + +#include "sun55i-a523.dtsi" + +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "X96Q Pro+"; + compatible = "amediatech,x96q-pro-plus", "allwinner,sun55i-h728"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + ext_osc32k: ext-osc32k-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "ext_osc32k"; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply from the barrel plug */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_vcc3v3: vcc3v3 { + /* 3.3V dummy supply for the SD card */ + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_vcc5v>; + regulator-always-on; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&mmc0 { + vmmc-supply = <®_vcc3v3>; + cd-gpios = <&pio 5 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PF6 */ + bus-width = <4>; + disable-wp; + status = "okay"; +}; + +&mmc2 { + vmmc-supply = <®_cldo3>; + vqmmc-supply = <®_cldo1>; + bus-width = <8>; + non-removable; + cap-mmc-hw-reset; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&pio { + vcc-pb-supply = <®_cldo3>; /* via VCC-IO */ + vcc-pc-supply = <®_cldo1>; + vcc-pd-supply = <®_dcdc4>; + vcc-pe-supply = <®_dcdc4>; + vcc-pf-supply = <®_cldo3>; /* actually switchable */ + vcc-pg-supply = <®_bldo1>; + vcc-ph-supply = <®_cldo3>; /* via VCC-IO */ + vcc-pi-supply = <®_dcdc4>; + vcc-pj-supply = <®_dcdc4>; + vcc-pk-supply = <®_bldo3>; +}; + +&r_i2c0 { + status = "okay"; + + axp717: pmic@34 { + compatible = "x-powers,axp717"; + reg = <0x34>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + vin4-supply = <®_vcc5v>; + aldoin-supply = <®_vcc5v>; + bldoin-supply = <®_vcc5v>; + cldoin-supply = <®_vcc5v>; + + regulators { + /* Supplies the "little" cluster (1.0(?) GHz cores) */ + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-cpul"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <920000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1360000>; + regulator-max-microvolt = <1360000>; + regulator-name = "vdd-dram"; + }; + + reg_dcdc4: dcdc4 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd-dcdc4"; + }; + + reg_aldo1: aldo1 { + /* not connected */ + }; + + reg_aldo2: aldo2 { + /* not connected */ + }; + + reg_aldo3: aldo3 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-aldo3"; + }; + + reg_aldo4: aldo4 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pll-dxco-avcc"; + }; + + reg_bldo1: bldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pg-wifi-lvds"; + }; + + reg_bldo2: bldo2 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-dram-1v8"; + }; + + reg_bldo3: bldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc-bldo3"; + }; + + reg_bldo4: bldo4 { + /* not connected */ + }; + + reg_cldo1: cldo1 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-codec-sd"; + }; + + reg_cldo2: cldo2 { + }; + + reg_cldo3: cldo3 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-codec-eth-sd"; + }; + + reg_cldo4: cldo4 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-eth-phy"; + }; + + reg_cpusldo: cpusldo { + /* supplies the management core */ + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdd-cpus"; + }; + }; + }; + + axp323: pmic@36 { + compatible = "x-powers,axp323"; + reg = <0x36>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + status = "okay"; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + + regulators { + aldo1 { + /* not connected */ + }; + + dldo1 { + /* not connected */ + }; + + /* Supplies the "big" cluster (1.8 GHz cores) */ + reg_dcdc1_323: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-cpub"; + }; + + /* DCDC2 is polyphased with DCDC1 */ + + reg_dcdc3_323: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-name = "vdd-dcdc3"; + }; + }; + }; +}; + +&r_pio { +/* + * Specifying the supply would create a circular dependency. + * + * vcc-pl-supply = <®_aldo3>; + */ + vcc-pm-supply = <®_aldo3>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&usb_otg { + /* USB0 is a USB-A receptacle, always powered, so force host mode. */ + dr_mode = "host"; + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; diff --git a/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts b/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts new file mode 100644 index 00000000000..dea2acc1849 --- /dev/null +++ b/dts/upstream/src/arm64/allwinner/sun55i-t527-avaota-a1.dts @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +// Copyright (C) 2024 Arm Ltd. + +/dts-v1/; + +#include "sun55i-a523.dtsi" + +#include <dt-bindings/gpio/gpio.h> + +/ { + model = "Avaota A1"; + compatible = "yuzukihd,avaota-a1", "allwinner,sun55i-t527"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + ext_osc32k: ext-osc32k-clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "ext_osc32k"; + }; + + reg_vcc12v: vcc12v { + /* DC input jack */ + compatible = "regulator-fixed"; + regulator-name = "vcc-12v"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply from the 12V->5V regulator */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_vcc12v>; + regulator-always-on; + }; + + reg_usb_vbus: vbus { + compatible = "regulator-fixed"; + regulator-name = "usb-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_vcc5v>; + gpio = <&pio 8 12 GPIO_ACTIVE_HIGH>; /* PI12 */ + enable-active-high; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&mmc0 { + vmmc-supply = <®_cldo3>; + cd-gpios = <&pio 5 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PF6 */ + bus-width = <4>; + status = "okay"; +}; + +&mmc2 { + bus-width = <8>; + cap-mmc-hw-reset; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + vmmc-supply = <®_cldo3>; + vqmmc-supply = <®_cldo1>; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&pio { + vcc-pb-supply = <®_cldo3>; /* via VCC-IO */ + vcc-pc-supply = <®_cldo1>; + vcc-pd-supply = <®_dcdc4>; + vcc-pe-supply = <®_dcdc4>; + vcc-pf-supply = <®_cldo3>; /* actually switchable */ + vcc-pg-supply = <®_bldo1>; + vcc-ph-supply = <®_cldo3>; /* via VCC-IO */ + vcc-pi-supply = <®_dcdc4>; + vcc-pj-supply = <®_dcdc4>; + vcc-pk-supply = <®_bldo3>; +}; + +&r_i2c0 { + status = "okay"; + + axp717: pmic@35 { + compatible = "x-powers,axp717"; + reg = <0x35>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + vin4-supply = <®_vcc5v>; + aldoin-supply = <®_vcc5v>; + bldoin-supply = <®_vcc5v>; + cldoin-supply = <®_vcc5v>; + + regulators { + /* Supplies the "little" cluster (1.4 GHz cores) */ + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-cpul"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <920000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1160000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-dram"; + }; + + reg_dcdc4: dcdc4 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vdd-io"; + }; + + reg_aldo1: aldo1 { + /* not connected */ + }; + + reg_aldo2: aldo2 { + /* not connected */ + }; + + reg_aldo3: aldo3 { + /* supplies the I2C pins for this PMIC */ + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-pl-pm"; + }; + + reg_aldo4: aldo4 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pll-dxco-avcc"; + }; + + reg_bldo1: bldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pg-wifi-lvds"; + }; + + reg_bldo2: bldo2 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-dram-1v8"; + }; + + reg_bldo3: bldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-cvp-pk-vid1v8"; + }; + + reg_bldo4: bldo4 { + /* not connected */ + }; + + reg_cldo1: cldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pc"; + }; + + reg_cldo2: cldo2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-efuse"; + }; + + reg_cldo3: cldo3 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-io-mmc-spi-ana"; + }; + + reg_cldo4: cldo4 { + /* not connected */ + }; + + reg_cpusldo: cpusldo { + /* supplies the management core */ + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdd-cpus"; + }; + }; + }; + + axp323: pmic@36 { + compatible = "x-powers,axp323"; + reg = <0x36>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + status = "okay"; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + + regulators { + aldo1 { + /* not connected */ + }; + + dldo1 { + /* not connected */ + }; + + /* Supplies the "big" cluster (1.8 GHz cores) */ + reg_dcdc1_323: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1160000>; + regulator-name = "vdd-cpub"; + }; + + /* DCDC2 is polyphased with DCDC1 */ + + /* Some RISC-V management core related voltage */ + reg_dcdc3_323: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdd-dnr"; + }; + }; + }; +}; + +&r_pio { +/* + * Specifying the supply would create a circular dependency. + * + * vcc-pl-supply = <®_aldo3>; + */ + vcc-pm-supply = <®_aldo3>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&usb_otg { + /* + * The CC pins of the USB-C port have two pull-down resistors + * connected to GND, which fixes this port to a peripheral role. + * There is a regulator, controlled by a GPIO, to provide VBUS power + * to the port, and a VBUSDET GPIO, to detect externally provided + * power, but without the CC pins there is no real way to do a + * runtime role detection. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + usb0_vbus-supply = <®_usb_vbus>; + usb0_vbus_det-gpios = <&pio 8 13 GPIO_ACTIVE_HIGH>; /* PI13 */ + status = "okay"; +}; diff --git a/include/axp_pmic.h b/include/axp_pmic.h index ae62ef0d76d..1806a7270a0 100644 --- a/include/axp_pmic.h +++ b/include/axp_pmic.h @@ -33,6 +33,7 @@ enum { AXP221_ID, AXP223_ID, AXP313_ID, + AXP323_ID, AXP717_ID, AXP803_ID, AXP806_ID, diff --git a/include/configs/sun55i.h b/include/configs/sun55i.h new file mode 100644 index 00000000000..70649366c1c --- /dev/null +++ b/include/configs/sun55i.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Placeholder wrapper to allow addressing Allwinner devices with Cortex-A55 + * cores separately. Please do not add anything in here. + */ +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <configs/sunxi-common.h> + +#endif /* __CONFIG_H */ |
