All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL)
@ 2018-06-25 10:37 Icenowy Zheng
  2018-06-25 10:37 ` [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS Icenowy Zheng
                   ` (13 more replies)
  0 siblings, 14 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

This patch trys to add support for Allwinner H6 SoC to U-Boot.

Allwinner H6 is a quite new Allwinner SoC, with several parts changed a
lot (memory map, DRAM controller, CCU, so on). The position which SPL
will be loaded (SRAM A1) also changed to 0x20000.

The Pine H64 board support comes with this patchset, as this is the
first H6 board that I can get (being early bird).

Icenowy Zheng (13):
  sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
  sunxi: add basical memory map definitions of H6 SoC
  sunxi: change RMR64's RVBAR address for H6
  sunxi: change ATF position for H6
  sunxi: add config for SPL at 0x20000 on H6
  sunxi: change GIC address on H6
  sunxi: add clock code for H6
  sunxi: use sun6i-style watchdog for H6
  sunxi: add UART0 setup for H6
  sunxi: add MMC support for H6
  sunxi: add DRAM support to H6
  sunxi: add support for Allwinner H6 SoC
  sunxi: add support for Pine H64 board

 arch/arm/dts/Makefile                         |   2 +
 arch/arm/dts/sun50i-h6-pine-h64.dts           |  64 ++
 arch/arm/dts/sun50i-h6.dtsi                   | 140 ++++
 arch/arm/include/asm/arch-sunxi/boot0.h       |   4 +
 arch/arm/include/asm/arch-sunxi/clock.h       |   2 +
 .../include/asm/arch-sunxi/clock_sun50i_h6.h  | 320 ++++++++
 arch/arm/include/asm/arch-sunxi/cpu.h         |   2 +
 .../include/asm/arch-sunxi/cpu_sun50i_h6.h    |  73 ++
 arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
 .../include/asm/arch-sunxi/dram_sun50i_h6.h   | 276 +++++++
 arch/arm/include/asm/arch-sunxi/gpio.h        |   1 +
 arch/arm/include/asm/arch-sunxi/mmc.h         |   2 +-
 arch/arm/include/asm/arch-sunxi/spl.h         |   6 +-
 arch/arm/include/asm/arch-sunxi/timer.h       |   2 +-
 arch/arm/mach-sunxi/Kconfig                   |  37 +-
 arch/arm/mach-sunxi/Makefile                  |   2 +
 arch/arm/mach-sunxi/board.c                   |   6 +-
 arch/arm/mach-sunxi/clock_sun50i_h6.c         |  94 +++
 arch/arm/mach-sunxi/cpu_info.c                |   2 +
 arch/arm/mach-sunxi/dram_sun50i_h6.c          | 708 ++++++++++++++++++
 arch/arm/mach-sunxi/rmr_switch.S              |   6 +
 board/sunxi/MAINTAINERS                       |   5 +
 board/sunxi/board.c                           |   7 +
 board/sunxi/mksunxi_fit_atf.sh                |  10 +-
 common/spl/Kconfig                            |   2 +-
 configs/pine_h64_defconfig                    |  15 +
 drivers/mmc/sunxi_mmc.c                       |  13 +-
 include/configs/sun50i.h                      |   5 +
 include/configs/sunxi-common.h                |  24 +-
 29 files changed, 1802 insertions(+), 30 deletions(-)
 create mode 100644 arch/arm/dts/sun50i-h6-pine-h64.dts
 create mode 100644 arch/arm/dts/sun50i-h6.dtsi
 create mode 100644 arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
 create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
 create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
 create mode 100644 arch/arm/mach-sunxi/clock_sun50i_h6.c
 create mode 100644 arch/arm/mach-sunxi/dram_sun50i_h6.c
 create mode 100644 configs/pine_h64_defconfig

-- 
2.17.1

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

* [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-25 12:30   ` Maxime Ripard
  2018-06-26 10:34   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC Icenowy Zheng
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The new Allwinner H6 SoC has its SRAM A1 at neither 0x0 nor 0x10000, but
it's at 0x20000. Thus the SUNXI_HIGH_SRAM option needs to be refactored
to support this new configuration.

Change it to SUNXI_SRAM_ADDRESS, which holds the real address of SRAM
A1 in the memory map.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/spl.h |  6 +-----
 arch/arm/mach-sunxi/Kconfig           | 14 +++++---------
 include/configs/sunxi-common.h        | 19 +++++++++++--------
 3 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
index a70b1797e5..e166568d11 100644
--- a/arch/arm/include/asm/arch-sunxi/spl.h
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -12,11 +12,7 @@
 #define SPL_SIGNATURE		"SPL" /* marks "sunxi" SPL header */
 #define SPL_HEADER_VERSION	2
 
-#ifdef CONFIG_SUNXI_HIGH_SRAM
-#define SPL_ADDR		0x10000
-#else
-#define SPL_ADDR		0x0
-#endif
+#define SPL_ADDR		CONFIG_SUNXI_SRAM_ADDRESS
 
 /* The low 8-bits of the 'boot_media' field in the SPL header */
 #define SUNXI_BOOTED_FROM_MMC0	0
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 0a7bd3086a..e3c19b7464 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -73,16 +73,15 @@ config SUN8I_RSB
 	  with various RSB based devices, such as AXP223, AXP8XX PMICs,
 	  and AC100/AC200 ICs.
 
-config SUNXI_HIGH_SRAM
-	bool
-	default n
+config SUNXI_SRAM_ADDRESS
+	hex
+	default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
+	default 0x0
 	---help---
 	Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
 	with the first SRAM region being located at address 0.
 	Some newer SoCs map the boot ROM at address 0 instead and move the
-	SRAM to 64KB, just behind the mask ROM.
-	Chips using the latter setup are supposed to select this option to
-	adjust the addresses accordingly.
+	SRAM to a different address.
 
 # Note only one of these may be selected at a time! But hidden choices are
 # not supported by Kconfig
@@ -252,7 +251,6 @@ config MACH_SUN9I
 	select CPU_V7
 	select DRAM_SUN9I
 	select SUN6I_PRCM
-	select SUNXI_HIGH_SRAM
 	select SUNXI_GEN_SUN6I
 	select SUN8I_RSB
 	select SUPPORT_SPL
@@ -264,7 +262,6 @@ config MACH_SUN50I
 	select PHY_SUN4I_USB
 	select SUNXI_DE2
 	select SUNXI_GEN_SUN6I
-	select SUNXI_HIGH_SRAM
 	select SUPPORT_SPL
 	select SUNXI_DRAM_DW
 	select SUNXI_DRAM_DW_32BIT
@@ -275,7 +272,6 @@ config MACH_SUN50I_H5
 	bool "sun50i (Allwinner H5)"
 	select ARM64
 	select MACH_SUNXI_H3_H5
-	select SUNXI_HIGH_SRAM
 	select FIT
 	select SPL_LOAD_FIT
 
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 9d9e9ce173..0196dd0431 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -83,20 +83,19 @@
 
 #define CONFIG_SPL_BSS_MAX_SIZE		0x00080000 /* 512 KiB */
 
-#ifdef CONFIG_SUNXI_HIGH_SRAM
 /*
  * The A80's A1 sram starts at 0x00010000 rather then at 0x00000000 and is
  * slightly bigger. Note that it is possible to map the first 32 KiB of the
  * A1 at 0x00000000 like with older SoCs by writing 0x16aa0001 to the
  * undocumented 0x008000e0 SYS_CTRL register. Where the 16aa is a key and
  * the 1 actually activates the mapping of the first 32 KiB to 0x00000000.
+ * A64 and H5 also has SRAM A1 at 0x00010000, but no magic remap register
+ * is known yet.
+ * H6 has SRAM A1 at 0x00020000.
  */
-#define CONFIG_SYS_INIT_RAM_ADDR	0x10000
-#define CONFIG_SYS_INIT_RAM_SIZE	0x08000	/* FIXME: 40 KiB ? */
-#else
-#define CONFIG_SYS_INIT_RAM_ADDR	0x0
-#define CONFIG_SYS_INIT_RAM_SIZE	0x8000	/* 32 KiB */
-#endif
+#define CONFIG_SYS_INIT_RAM_ADDR	CONFIG_SUNXI_SRAM_ADDRESS
+/* FIXME: this may be larger on some SoCs */
+#define CONFIG_SYS_INIT_RAM_SIZE	0x8000 /* 32 KiB */
 
 #define CONFIG_SYS_INIT_SP_OFFSET \
 	(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
@@ -188,7 +187,11 @@
 #define CONFIG_SPL_BOARD_LOAD_IMAGE
 #endif
 
-#ifdef CONFIG_SUNXI_HIGH_SRAM
+/*
+ * We cannot use expressions here, because expressions won't be evaluated in
+ * autoconf.mk.
+ */
+#if CONFIG_SUNXI_SRAM_ADDRESS == 0x10000
 #define CONFIG_SPL_TEXT_BASE		0x10060		/* sram start+header */
 #define CONFIG_SPL_MAX_SIZE		0x7fa0		/* 32 KiB */
 #ifdef CONFIG_ARM64
-- 
2.17.1

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

* [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
  2018-06-25 10:37 ` [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-25 12:33   ` Maxime Ripard
  2018-06-27  8:51   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 03/13] sunxi: change RMR64's RVBAR address for H6 Icenowy Zheng
                   ` (11 subsequent siblings)
  13 siblings, 2 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The Allwinner H6 SoC come with a totally new memory map.

Add basical definition of the new memory map into a header file, and let
the cpu.h header include it in the situation of H6.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
 .../include/asm/arch-sunxi/cpu_sun50i_h6.h    | 73 +++++++++++++++++++
 2 files changed, 75 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h

diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
index caec865264..08be963e8e 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu.h
@@ -9,6 +9,8 @@
 
 #if defined(CONFIG_MACH_SUN9I)
 #include <asm/arch/cpu_sun9i.h>
+#elif defined(CONFIG_MACH_SUN50I_H6)
+#include <asm/arch/cpu_sun50i_h6.h>
 #else
 #include <asm/arch/cpu_sun4i.h>
 #endif
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
new file mode 100644
index 0000000000..b12f2dd1a2
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
@@ -0,0 +1,73 @@
+/*
+ * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_CPU_SUN50I_H6_H
+#define _SUNXI_CPU_SUN50I_H6_H
+
+#define SUNXI_SRAM_A1_BASE		0x00020000
+#define SUNXI_SRAM_C_BASE		0x00028000
+#define SUNXI_SRAM_A2_BASE		0x00100000
+
+#define SUNXI_DE3_BASE			0x01000000
+#define SUNXI_SS_BASE			0x01904000
+#define SUNXI_EMCE_BASE			0x01905000
+
+#define SUNXI_SRAMC_BASE		0x03000000
+#define SUNXI_CCM_BASE			0x03001000
+#define SUNXI_DMA_BASE			0x03002000
+/* SID address space starts at 0x03006000, but e-fuse is at offset 0x200 */
+#define SUNXI_SIDC_BASE			0x03006000
+#define SNUXI_SID_BASE			0x03006200
+#define SUNXI_TIMER_BASE		0x03009000
+#define SUNXI_PIO_BASE			0x0300B000
+#define SUNXI_PSI_BASE			0x0300C000
+
+#define SUNXI_GIC400_BASE		0x03020000
+#define SUNXI_IOMMU_BASE		0x030F0000
+
+#define SUNXI_DRAM_COM_BASE		0x04002000
+#define SUNXI_DRAM_CTL0_BASE		0x04003000
+#define SUNXI_DRAM_PHY0_BASE		0x04005000
+#define SUNXI_NFC_BASE			0x04011000
+#define SUNXI_MMC0_BASE			0x04020000
+#define SUNXI_MMC1_BASE			0x04021000
+#define SUNXI_MMC2_BASE			0x04022000
+
+#define SUNXI_UART0_BASE		0x05000000
+#define SUNXI_UART1_BASE		0x05000400
+#define SUNXI_UART2_BASE		0x05000800
+#define SUNXI_UART3_BASE		0x05000C00
+#define SUNXI_TWI0_BASE			0x05002000
+#define SUNXI_TWI1_BASE			0x05002400
+#define SUNXI_TWI2_BASE			0x05002800
+#define SUNXI_TWI3_BASE			0x05002C00
+#define SUNXI_SPI0_BASE			0x05010000
+#define SUNXI_SPI1_BASE			0x05011000
+#define SUNXI_GMAC_BASE			0x05020000
+#define SUNXI_USB0_BASE			0x05100000
+#define SUNXI_XHCI_BASE			0x05200000
+#define SUNXI_USB3_BASE			0x05311000
+#define SUNXI_PCIE_BASE			0x05400000
+
+#define SUNXI_HDMI_BASE			0x06000000
+#define SUNXI_TCON_TOP_BASE		0x06510000
+#define SUNXI_TCON_LCD0_BASE		0x06511000
+#define SUNXI_TCON_TV0_BASE		0x06515000
+
+#define SUNXI_RTC_BASE			0x07000000
+#define SUNXI_R_CPUCFG_BASE		0x07000400
+#define SUNXI_PRCM_BASE			0x07010000
+#define SUNXI_R_PIO_BASE		0x07022000
+#define SUNXI_R_UART_BASE		0x07080000
+#define SUNXI_R_TWI_BASE		0x07081400
+
+#ifndef __ASSEMBLY__
+void sunxi_board_init(void);
+void sunxi_reset(void);
+int sunxi_get_sid(unsigned int *sid);
+#endif
+
+#endif /* _SUNXI_CPU_SUN9I_H */
-- 
2.17.1

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

* [U-Boot] [PATCH 03/13] sunxi: change RMR64's RVBAR address for H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
  2018-06-25 10:37 ` [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS Icenowy Zheng
  2018-06-25 10:37 ` [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-26 10:37   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 04/13] sunxi: change ATF position " Icenowy Zheng
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

Allwinner H6 has a different RVBAR address with A64/H5.

Add conditional RVBAR configuration into the code which does RMR switch.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/boot0.h | 4 ++++
 arch/arm/mach-sunxi/rmr_switch.S        | 6 ++++++
 2 files changed, 10 insertions(+)

diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
index 9c6d82dda1..5176fdcfdc 100644
--- a/arch/arm/include/asm/arch-sunxi/boot0.h
+++ b/arch/arm/include/asm/arch-sunxi/boot0.h
@@ -27,7 +27,11 @@
 	.word	0xf57ff06f	// isb     sy
 	.word	0xe320f003	// wfi
 	.word	0xeafffffd	// b       @wfi
+#ifndef CONFIG_MACH_SUN50I_H6
 	.word	0x017000a0	// writeable RVBAR mapping address
+#else
+	.word	0x09010040	// writeable RVBAR mapping address
+#endif
 #ifdef CONFIG_SPL_BUILD
 	.word	CONFIG_SPL_TEXT_BASE
 #else
diff --git a/arch/arm/mach-sunxi/rmr_switch.S b/arch/arm/mach-sunxi/rmr_switch.S
index cefa93001b..fafd306f95 100644
--- a/arch/arm/mach-sunxi/rmr_switch.S
+++ b/arch/arm/mach-sunxi/rmr_switch.S
@@ -26,9 +26,15 @@
 @ reference and to be able to regenerate a (probably fixed) version of this
 @ code found in encoded form in boot0.h.
 
+#include <config.h>
+
 .text
 
+#ifndef CONFIG_MACH_SUN50I_H6
 	ldr	r1, =0x017000a0		@ MMIO mapped RVBAR[0] register
+#else
+	ldr	r1, =0x09010040		@ MMIO mapped RVBAR[0] register
+#endif
 	ldr	r0, =0x57aA7add		@ start address, to be replaced
 	str	r0, [r1]
 	dsb	sy
-- 
2.17.1

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

* [U-Boot] [PATCH 04/13] sunxi: change ATF position for H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (2 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 03/13] sunxi: change RMR64's RVBAR address for H6 Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-26 10:56   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 05/13] sunxi: add config for SPL at 0x20000 on H6 Icenowy Zheng
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

H6 has different SRAM A2 address, so the ATF load address is also
different.

Add judgment code to sunxi 64-bit FIT generation script. It will judge
the SoC by the device tree's name.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 board/sunxi/mksunxi_fit_atf.sh | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/board/sunxi/mksunxi_fit_atf.sh b/board/sunxi/mksunxi_fit_atf.sh
index 36abe9efed..8540c3d88e 100755
--- a/board/sunxi/mksunxi_fit_atf.sh
+++ b/board/sunxi/mksunxi_fit_atf.sh
@@ -13,6 +13,12 @@ if [ ! -f $BL31 ]; then
 	BL31=/dev/null
 fi
 
+if [ "$(basename $1 .dtb | cut -d - -f 1-2)" = "sun50i-h6" ]; then
+	BL31_ADDR=0x104000
+else
+	BL31_ADDR=0x44000
+fi
+
 cat << __HEADER_EOF
 /dts-v1/;
 
@@ -35,8 +41,8 @@ cat << __HEADER_EOF
 			type = "firmware";
 			arch = "arm64";
 			compression = "none";
-			load = <0x44000>;
-			entry = <0x44000>;
+			load = <$BL31_ADDR>;
+			entry = <$BL31_ADDR>;
 		};
 __HEADER_EOF
 
-- 
2.17.1

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

* [U-Boot] [PATCH 05/13] sunxi: add config for SPL at 0x20000 on H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (3 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 04/13] sunxi: change ATF position " Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-26 10:56   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 06/13] sunxi: change GIC address " Icenowy Zheng
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

On the new Allwinner H6 SoC, the SRAM A2 address (SPL load address) is
at 0x20000, which is different with any old Allwinner SoCs.

Add SPL position and size configuration for this.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 include/configs/sunxi-common.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 0196dd0431..9e1c5fb2a6 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -200,6 +200,11 @@
 #else
 #define LOW_LEVEL_SRAM_STACK		0x00018000
 #endif /* !CONFIG_ARM64 */
+#elif CONFIG_SUNXI_SRAM_ADDRESS == 0x20000
+#define CONFIG_SPL_TEXT_BASE		0x20060		/* sram start+header */
+#define CONFIG_SPL_MAX_SIZE		0x7fa0		/* 32 KiB */
+/* end of SRAM A2 on H6 for now */
+#define LOW_LEVEL_SRAM_STACK		0x00118000
 #else
 #define CONFIG_SPL_TEXT_BASE		0x60		/* sram start+header */
 #define CONFIG_SPL_MAX_SIZE		0x5fa0		/* 24KB on sun4i/sun7i */
-- 
2.17.1

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

* [U-Boot] [PATCH 06/13] sunxi: change GIC address on H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (4 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 05/13] sunxi: add config for SPL at 0x20000 on H6 Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-26 10:56   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 07/13] sunxi: add clock code for H6 Icenowy Zheng
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

As the Allwinner H6 chip has a new memory map, its GIC MMIO address is
thus different.

Change the address on H6.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 include/configs/sun50i.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/configs/sun50i.h b/include/configs/sun50i.h
index b7b67a1ddc..1b3e84c4e9 100644
--- a/include/configs/sun50i.h
+++ b/include/configs/sun50i.h
@@ -18,8 +18,13 @@
 
 #define CONFIG_SUNXI_USB_PHYS	1
 
+#ifndef CONFIG_MACH_SUN50I_H6
 #define GICD_BASE		0x1c81000
 #define GICC_BASE		0x1c82000
+#else
+#define GICD_BASE		0x3021000
+#define GICC_BASE		0x3022000
+#endif
 
 /*
  * Include common sunxi configuration where most the settings are
-- 
2.17.1

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

* [U-Boot] [PATCH 07/13] sunxi: add clock code for H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (5 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 06/13] sunxi: change GIC address " Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-26 13:04   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 08/13] sunxi: use sun6i-style watchdog " Icenowy Zheng
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The new Allwinner H6 SoC has a brand new CCU layout.

Add clock code for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/clock.h       |   2 +
 .../include/asm/arch-sunxi/clock_sun50i_h6.h  | 320 ++++++++++++++++++
 arch/arm/mach-sunxi/Makefile                  |   1 +
 arch/arm/mach-sunxi/clock_sun50i_h6.c         |  94 +++++
 4 files changed, 417 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
 create mode 100644 arch/arm/mach-sunxi/clock_sun50i_h6.c

diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
index 3747f74d36..ecbef85f83 100644
--- a/arch/arm/include/asm/arch-sunxi/clock.h
+++ b/arch/arm/include/asm/arch-sunxi/clock.h
@@ -17,6 +17,8 @@
 /* clock control module regs definition */
 #if defined(CONFIG_MACH_SUN8I_A83T)
 #include <asm/arch/clock_sun8i_a83t.h>
+#elif defined(CONFIG_MACH_SUN50I_H6)
+#include <asm/arch/clock_sun50i_h6.h>
 #elif defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \
       defined(CONFIG_MACH_SUN50I)
 #include <asm/arch/clock_sun6i.h>
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
new file mode 100644
index 0000000000..e36937059b
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
@@ -0,0 +1,320 @@
+/*
+ * Allwinner H6 clock register definitions
+ *
+ * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_CLOCK_SUN50I_H6_H
+#define _SUNXI_CLOCK_SUN50I_H6_H
+
+struct sunxi_ccm_reg {
+	u32 pll1_cfg;		/* 0x000 pll1 (cpux) control */
+	u8 reserved_0x004[12];
+	u32 pll5_cfg;		/* 0x010 pll5 (ddr) control */
+	u8 reserved_0x014[12];
+	u32 pll6_cfg;		/* 0x020 pll6 (periph0) control */
+	u8 reserved_0x020[4];
+	u32 pll_periph1_cfg;	/* 0x028 pll periph1 control */
+	u8 reserved_0x028[4];
+	u32 pll7_cfg;		/* 0x030 pll7 (gpu) control */
+	u8 reserved_0x034[12];
+	u32 pll3_cfg;		/* 0x040 pll3 (video0) control */
+	u8 reserved_0x044[4];
+	u32 pll_video1_cfg;	/* 0x048 pll video1 control */
+	u8 reserved_0x04c[12];
+	u32 pll4_cfg;		/* 0x058 pll4 (ve) control */
+	u8 reserved_0x05c[4];
+	u32 pll10_cfg;		/* 0x060 pll10 (de) control */
+	u8 reserved_0x064[12];
+	u32 pll9_cfg;		/* 0x070 pll9 (hsic) control */
+	u8 reserved_0x074[4];
+	u32 pll2_cfg;		/* 0x078 pll2 (audio) control */
+	u8 reserved_0x07c[148];
+	u32 pll5_pat;		/* 0x110 pll5 (ddr) pattern */
+	u8 reserved_0x114[20];
+	u32 pll_periph1_pat0;	/* 0x128 pll periph1 pattern0 */
+	u32 pll_periph1_pat1;	/* 0x12c pll periph1 pattern1 */
+	u32 pll7_pat0;		/* 0x130 pll7 (gpu) pattern0 */
+	u32 pll7_pat1;		/* 0x134 pll7 (gpu) pattern1 */
+	u8 reserved_0x138[8];
+	u32 pll3_pat0;		/* 0x140 pll3 (video0) pattern0 */
+	u32 pll3_pat1;		/* 0x144 pll3 (video0) pattern1 */
+	u32 pll_video1_pat0;	/* 0x148 pll video1 pattern0 */
+	u32 pll_video1_pat1;	/* 0x14c pll video1 pattern1 */
+	u8 reserved_0x150[8];
+	u32 pll4_pat0;		/* 0x158 pll4 (ve) pattern0 */
+	u32 pll4_pat1;		/* 0x15c pll4 (ve) pattern1 */
+	u32 pll10_pat0;		/* 0x160 pll10 (de) pattern0 */
+	u32 pll10_pat1;		/* 0x164 pll10 (de) pattern1 */
+	u8 reserved_0x168[8];
+	u32 pll9_pat0;		/* 0x170 pll9 (hsic) pattern0 */
+	u32 pll9_pat1;		/* 0x174 pll9 (hsic) pattern1 */
+	u32 pll2_pat0;		/* 0x178 pll2 (audio) pattern0 */
+	u32 pll2_pat1;		/* 0x17c pll2 (audio) pattern1 */
+	u8 reserved_0x180[384];
+	u32 pll1_bias;		/* 0x300 pll1 (cpux) bias */
+	u8 reserved_0x304[12];
+	u32 pll5_bias;		/* 0x310 pll5 (ddr) bias */
+	u8 reserved_0x314[12];
+	u32 pll6_bias;		/* 0x320 pll6 (periph0) bias */
+	u8 reserved_0x324[4];
+	u32 pll_periph1_bias;	/* 0x328 pll periph1 bias */
+	u8 reserved_0x32c[4];
+	u32 pll7_bias;		/* 0x330 pll7 (gpu) bias */
+	u8 reserved_0x334[12];
+	u32 pll3_bias;		/* 0x340 pll3 (video0) bias */
+	u8 reserved_0x344[4];
+	u32 pll_video1_bias;	/* 0x348 pll video1 bias */
+	u8 reserved_0x34c[12];
+	u32 pll4_bias;		/* 0x358 pll4 (ve) bias */
+	u8 reserved_0x35c[4];
+	u32 pll10_bias;		/* 0x360 pll10 (de) bias */
+	u8 reserved_0x364[12];
+	u32 pll9_bias;		/* 0x370 pll9 (hsic) bias */
+	u8 reserved_0x374[4];
+	u32 pll2_bias;		/* 0x378 pll2 (audio) bias */
+	u8 reserved_0x37c[132];
+	u32 pll1_tun;		/* 0x400 pll1 (cpux) tunning */
+	u8 reserved_0x404[252];
+	u32 cpu_axi_cfg;	/* 0x500 CPUX/AXI clock control*/
+	u8 reserved_0x504[12];
+	u32 psi_ahb1_ahb2_cfg;	/* 0x510 PSI/AHB1/AHB2 clock control */
+	u8 reserved_0x514[8];
+	u32 ahb3_cfg;		/* 0x51c AHB3 clock control */
+	u32 apb1_cfg;		/* 0x520 APB1 clock control */
+	u32 apb2_cfg;		/* 0x524 APB2 clock control */
+	u8 reserved_0x528[24];
+	u32 mbus_cfg;		/* 0x540 MBUS clock control */
+	u8 reserved_0x544[188];
+	u32 de_clk_cfg;		/* 0x600 DE clock control */
+	u8 reserved_0x604[8];
+	u32 de_gate_reset;	/* 0x60c DE gate/reset control */
+	u8 reserved_0x610[16];
+	u32 di_clk_cfg;		/* 0x620 DI clock control */
+	u8 reserved_0x024[8];
+	u32 di_gate_reset;	/* 0x62c DI gate/reset control */
+	u8 reserved_0x630[64];
+	u32 gpu_clk_cfg;	/* 0x670 GPU clock control */
+	u8 reserved_0x674[8];
+	u32 gpu_gate_reset;	/* 0x67c GPU gate/reset control */
+	u32 ce_clk_cfg;		/* 0x680 CE clock control */
+	u8 reserved_0x684[8];
+	u32 ce_gate_reset;	/* 0x68c CE gate/reset control */
+	u32 ve_clk_cfg;		/* 0x690 VE clock control */
+	u8 reserved_0x694[8];
+	u32 ve_gate_reset;	/* 0x69c VE gate/reset control */
+	u8 reserved_0x6a0[16];
+	u32 emce_clk_cfg;	/* 0x6b0 EMCE clock control */
+	u8 reserved_0x6b4[8];
+	u32 emce_gate_reset;	/* 0x6bc EMCE gate/reset control */
+	u32 vp9_clk_cfg;	/* 0x6c0 VP9 clock control */
+	u8 reserved_0x6c4[8];
+	u32 vp9_gate_reset;	/* 0x6cc VP9 gate/reset control */
+	u8 reserved_0x6d0[60];
+	u32 dma_gate_reset;	/* 0x70c DMA gate/reset control */
+	u8 reserved_0x710[12];
+	u32 msgbox_gate_reset;	/* 0x71c Message Box gate/reset control */
+	u8 reserved_0x720[12];
+	u32 spinlock_gate_reset;/* 0x72c Spinlock gate/reset control */
+	u8 reserved_0x730[12];
+	u32 hstimer_gate_reset;	/* 0x73c HS Timer gate/reset control */
+	u32 avs_gate_reset;	/* 0x740 AVS gate/reset control */
+	u8 reserved_0x744[72];
+	u32 dbgsys_gate_reset;	/* 0x78c Debugging system gate/reset control */
+	u8 reserved_0x790[12];
+	u32 psi_gate_reset;	/* 0x79c PSI gate/reset control */
+	u8 reserved_0x7a0[12];
+	u32 pwm_gate_reset;	/* 0x7ac PWM gate/reset control */
+	u8 reserved_0x7b0[12];
+	u32 iommu_gate_reset;	/* 0x7bc IOMMU gate/reset control */
+	u8 reserved_0x7c0[64];
+	u32 dram_clk_cfg;		/* 0x800 DRAM clock control */
+	u32 mbus_gate;		/* 0x804 MBUS gate control */
+	u8 reserved_0x808[4];
+	u32 dram_gate_reset;	/* 0x80c DRAM gate/reset control */
+	u32 nand0_clk_cfg;	/* 0x810 NAND0 clock control */
+	u32 nand1_clk_cfg;	/* 0x814 NAND1 clock control */
+	u8 reserved_0x818[20];
+	u32 nand_gate_reset;	/* 0x82c NAND gate/reset control */
+	u32 sd0_clk_cfg;	/* 0x830 MMC0 clock control */
+	u32 sd1_clk_cfg;	/* 0x834 MMC1 clock control */
+	u32 sd2_clk_cfg;	/* 0x838 MMC2 clock control */
+	u8 reserved_0x83c[16];
+	u32 sd_gate_reset;	/* 0x84c MMC gate/reset control */
+	u8 reserved_0x850[188];
+	u32 uart_gate_reset;	/* 0x90c UART gate/reset control */
+	u8 reserved_0x910[12];
+	u32 twi_gate_reset;	/* 0x91c I2C gate/reset control */
+	u8 reserved_0x920[28];
+	u32 scr_gate_reset;	/* 0x93c SCR gate/reset control */
+	u32 spi0_clk_cfg;	/* 0x940 SPI0 clock control */
+	u32 spi1_clk_cfg;	/* 0x944 SPI1 clock control */
+	u8 reserved_0x948[36];
+	u32 spi_gate_reset;	/* 0x96c SPI gate/reset control */
+	u8 reserved_0x970[12];
+	u32 emac_gate_reset;	/* 0x97c EMAC gate/reset control */
+	u8 reserved_0x980[48];
+	u32 ts_clk_cfg;		/* 0x9b0 TS clock control */
+	u8 reserved_0x9b4[8];
+	u32 ts_gate_reset;	/* 0x9bc TS gate/reset control */
+	u32 irtx_clk_cfg;	/* 0x9c0 IR TX clock control */
+	u8 reserved_0x9c4[8];
+	u32 irtx_gate_reset;	/* 0x9cc IR TX gate/reset control */
+	u8 reserved_0x9d0[44];
+	u32 ths_gate_reset;	/* 0x9fc THS gate/reset control */
+	u8 reserved_0xa00[12];
+	u32 i2s3_clk_cfg;	/* 0xa0c I2S3 clock control */
+	u32 i2s0_clk_cfg;	/* 0xa10 I2S0 clock control */
+	u32 i2s1_clk_cfg;	/* 0xa14 I2S1 clock control */
+	u32 i2s2_clk_cfg;	/* 0xa18 I2S2 clock control */
+	u32 i2s_gate_reset;	/* 0xa1c I2S gate/reset control */
+	u32 spdif_clk_cfg;	/* 0xa20 SPDIF clock control */
+	u8 reserved_0xa24[8];
+	u32 spdif_gate_reset;	/* 0xa2c SPDIF gate/reset control */
+	u8 reserved_0xa30[16];
+	u32 dmic_clk_cfg;	/* 0xa40 DMIC clock control */
+	u8 reserved_0xa44[8];
+	u32 dmic_gate_reset;	/* 0xa4c DMIC gate/reset control */
+	u8 reserved_0xa50[16];
+	u32 ahub_clk_cfg;	/* 0xa60 Audio HUB clock control */
+	u8 reserved_0xa64[8];
+	u32 ahub_gate_reset;	/* 0xa6c Audio HUB gate/reset control */
+	u32 usb0_clk_cfg;	/* 0xa70 USB0(OTG) clock control */
+	u32 usb1_clk_cfg;	/* 0xa74 USB1(XHCI) clock control */
+	u8 reserved_0xa78[4];
+	u32 usb3_clk_cfg;	/* 0xa78 USB3 clock control */
+	u8 reserved_0xa80[12];
+	u32 usb_gate_reset;	/* 0xa8c USB gate/reset control */
+	u8 reserved_0xa90[32];
+	u32 pcie_ref_clk_cfg;	/* 0xab0 PCIE REF clock control */
+	u32 pcie_axi_clk_cfg;	/* 0xab4 PCIE AXI clock control */
+	u32 pcie_aux_clk_cfg;	/* 0xab8 PCIE AUX clock control */
+	u32 pcie_gate_reset;	/* 0xabc PCIE gate/reset control */
+	u8 reserved_0xac0[64];
+	u32 hdmi_clk_cfg;	/* 0xb00 HDMI clock control */
+	u32 hdmi_slow_clk_cfg;	/* 0xb04 HDMI slow clock control */
+	u8 reserved_0xb08[8];
+	u32 hdmi_cec_clk_cfg;	/* 0xb10 HDMI CEC clock control */
+	u8 reserved_0xb14[8];
+	u32 hdmi_gate_reset;	/* 0xb1c HDMI gate/reset control */
+	u8 reserved_0xb20[60];
+	u32 tcon_top_gate_reset;/* 0xb5c TCON TOP gate/reset control */
+	u32 tcon_lcd0_clk_cfg;	/* 0xb60 TCON LCD0 clock control */
+	u8 reserved_0xb64[24];
+	u32 tcon_lcd_gate_reset;/* 0xb7c TCON LCD gate/reset control */
+	u32 tcon_tv0_clk_cfg;	/* 0xb80 TCON TV0 clock control */
+	u8 reserved_0xb84[24];
+	u32 tcon_tv_gate_reset;	/* 0xb9c TCON TV gate/reset control */
+	u8 reserved_0xba0[96];
+	u32 csi_misc_clk_cfg;	/* 0xc00 CSI MISC clock control */
+	u32 csi_top_clk_cfg;	/* 0xc04 CSI TOP clock control */
+	u32 csi_mclk_cfg;	/* 0xc08 CSI Master clock control */
+	u8 reserved_0xc0c[32];
+	u32 csi_gate_reset;	/* 0xc2c CSI gate/reset control */
+	u8 reserved_0xc30[16];
+	u32 hdcp_clk_cfg;	/* 0xc40 HDCP clock control */
+	u8 reserved_0xc44[8];
+	u32 hdcp_gate_reset;	/* 0xc4c HDCP gate/reset control */
+	u8 reserved_0xc50[688];
+	u32 ccu_sec_switch;	/* 0xf00 CCU security switch */
+	u32 pll_lock_dbg_ctrl;	/* 0xf04 PLL lock debugging control */
+};
+
+/* pll1 bit field */
+#define CCM_PLL1_CTRL_EN		BIT(31)
+#define CCM_PLL1_LOCK_EN		BIT(29)
+#define CCM_PLL1_LOCK			BIT(28)
+#define CCM_PLL1_CLOCK_TIME_2		(2 << 24)
+#define CCM_PLL1_CTRL_P(p)		((p) << 16)
+#define CCM_PLL1_CTRL_N(n)		((n) << 8)
+
+/* 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_CTRL_N(n)		((n) << 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_N_SHIFT		8
+#define CCM_PLL6_CTRL_N_MASK		(0xff << CCM_PLL6_CTRL_N_SHIFT)
+#define CCM_PLL6_CTRL_DIV1_SHIFT	0
+#define CCM_PLL6_CTRL_DIV1_MASK		(0x1 << CCM_PLL6_CTRL_DIV1_SHIFT)
+#define CCM_PLL6_CTRL_DIV2_SHIFT	1
+#define CCM_PLL6_CTRL_DIV2_MASK		(0x1 << CCM_PLL6_CTRL_DIV2_SHIFT)
+#define CCM_PLL6_DEFAULT		0xa0006300
+
+/* cpu_axi bit field*/
+#define CCM_CPU_AXI_MUX_MASK		(0x3 << 24)
+#define CCM_CPU_AXI_MUX_OSC24M		(0x0 << 24)
+#define CCM_CPU_AXI_MUX_PLL_CPUX	(0x3 << 24)
+#define CCM_CPU_AXI_APB_MASK		0x300
+#define CCM_CPU_AXI_AXI_MASK		0x3
+#define CCM_CPU_AXI_DEFAULT_FACTORS	0x301
+
+/* psi_ahb1_ahb2 bit field */
+#define CCM_PSI_AHB1_AHB2_DEFAULT	0x03000102
+
+/* ahb3 bit field */
+#define CCM_AHB3_DEFAULT		0x03000002
+
+/* apb1 bit field */
+#define CCM_APB1_DEFAULT		0x03000102
+
+/* apb2 bit field */
+#define APB2_CLK_SRC_OSC24M		(0x0 << 24)
+#define APB2_CLK_SRC_OSC32K		(0x1 << 24)
+#define APB2_CLK_SRC_PSI		(0x2 << 24)
+#define APB2_CLK_SRC_PLL6		(0x3 << 24)
+#define APB2_CLK_SRC_MASK		(0x3 << 24)
+#define APB2_CLK_RATE_N_1		(0x0 << 8)
+#define APB2_CLK_RATE_N_2		(0x1 << 8)
+#define APB2_CLK_RATE_N_4		(0x2 << 8)
+#define APB2_CLK_RATE_N_8		(0x3 << 8)
+#define APB2_CLK_RATE_N_MASK		(3 << 8)
+#define APB2_CLK_RATE_M(m)		(((m)-1) << 0)
+#define APB2_CLK_RATE_M_MASK            (3 << 0)
+
+/* MBUS clock bit field */
+#define MBUS_ENABLE			BIT(31)
+#define MBUS_RESET			BIT(30)
+#define MBUS_CLK_SRC_MASK		GENMASK(25, 24)
+#define MBUS_CLK_SRC_OSCM24		(0 << 24)
+#define MBUS_CLK_SRC_PLL6X2		(1 << 24)
+#define MBUS_CLK_SRC_PLL5		(2 << 24)
+#define MBUS_CLK_SRC_PLL6X4		(3 << 24)
+#define MBUS_CLK_M(m)			(((m)-1) << 0)
+
+/* Module gate/reset shift*/
+#define RESET_SHIFT			(16)
+
+/* DRAM clock bit field */
+#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(m)			(((m)-1) << 0)
+
+/* MMC clock bit field */
+#define CCM_MMC_CTRL_M(x)		((x) - 1)
+#define CCM_MMC_CTRL_N(x)		((x) << 8)
+#define CCM_MMC_CTRL_OSCM24		(0x0 << 24)
+#define CCM_MMC_CTRL_PLL6X2		(0x1 << 24)
+#define CCM_MMC_CTRL_PLL_PERIPH2X2	(0x2 << 24)
+#define CCM_MMC_CTRL_ENABLE		(0x1 << 31)
+/* H6 doesn't have these delays */
+#define CCM_MMC_CTRL_OCLK_DLY(a)	((void) (a), 0)
+#define CCM_MMC_CTRL_SCLK_DLY(a)	((void) (a), 0)
+
+#ifndef __ASSEMBLY__
+void clock_set_pll1(unsigned int hz);
+unsigned int clock_get_pll6(void);
+#endif
+
+#endif /* _SUNXI_CLOCK_SUN50I_H6_H */
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 41f047f89e..bafeb59d64 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -28,6 +28,7 @@ else
 obj-$(CONFIG_MACH_SUN8I)	+= clock_sun6i.o
 endif
 obj-$(CONFIG_MACH_SUN9I)	+= clock_sun9i.o gtbus_sun9i.o
+obj-$(CONFIG_MACH_SUN50I_H6)	+= clock_sun50i_h6.o
 
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_DRAM_SUN4I)	+= dram_sun4i.o
diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
new file mode 100644
index 0000000000..84bc469b2a
--- /dev/null
+++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
@@ -0,0 +1,94 @@
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clock.h>
+
+#ifdef CONFIG_SPL_BUILD
+void clock_init_safe(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	clock_set_pll1(408000000);
+
+	writel(CCM_PLL6_DEFAULT, &ccm->pll6_cfg);
+	while (!(readl(&ccm->pll6_cfg) & CCM_PLL6_LOCK))
+		;
+
+	clrsetbits_le32(&ccm->cpu_axi_cfg, CCM_CPU_AXI_APB_MASK | CCM_CPU_AXI_AXI_MASK,
+			CCM_CPU_AXI_DEFAULT_FACTORS);
+
+	writel(CCM_PSI_AHB1_AHB2_DEFAULT, &ccm->psi_ahb1_ahb2_cfg);
+	writel(CCM_AHB3_DEFAULT, &ccm->ahb3_cfg);
+	writel(CCM_APB1_DEFAULT, &ccm->apb1_cfg);
+
+	/*
+	 * The mux and factor are set, but the clock will be enabled in
+	 * DRAM initialization code.
+	 */
+	writel(MBUS_CLK_SRC_PLL6X2 | MBUS_CLK_M(3), &ccm->mbus_cfg);
+}
+#endif
+
+void clock_init_uart(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* uart clock source is apb2 */
+	writel(APB2_CLK_SRC_OSC24M|
+	       APB2_CLK_RATE_N_1|
+	       APB2_CLK_RATE_M(1),
+	       &ccm->apb2_cfg);
+
+	/* open the clock for uart */
+	setbits_le32(&ccm->uart_gate_reset,
+		     1 << (CONFIG_CONS_INDEX - 1));
+
+	/* deassert uart reset */
+	setbits_le32(&ccm->uart_gate_reset,
+		     1 << (RESET_SHIFT + CONFIG_CONS_INDEX - 1));
+}
+
+#ifdef CONFIG_SPL_BUILD
+void clock_set_pll1(unsigned int clk)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	u32 val;
+
+	/* Do not support clocks < 288MHz as they need factor P */
+	if (clk < 288000000) clk = 288000000;
+
+	/* Switch to 24MHz clock while changing PLL1 */
+	val = readl(&ccm->cpu_axi_cfg);
+	val &= ~CCM_CPU_AXI_MUX_MASK;
+	val |= CCM_CPU_AXI_MUX_OSC24M;
+	writel(val, &ccm->cpu_axi_cfg);
+
+	/* clk = 24*n/p, p is ignored if clock is >288MHz */
+	writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 |
+	       CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg);
+	while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
+
+	/* Switch CPU to PLL1 */
+	val = readl(&ccm->cpu_axi_cfg);
+	val &= ~CCM_CPU_AXI_MUX_MASK;
+	val |= CCM_CPU_AXI_MUX_PLL_CPUX;
+	writel(val, &ccm->cpu_axi_cfg);
+}
+#endif
+
+unsigned int clock_get_pll6(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	uint32_t rval = readl(&ccm->pll6_cfg);
+	int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT);
+	int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
+			CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
+	int div2 = ((rval & CCM_PLL6_CTRL_DIV2_MASK) >>
+			CCM_PLL6_CTRL_DIV2_SHIFT) + 1;
+	/* The register defines PLL6-4X, not plain PLL6 */
+	return 24000000 * n / div1 / div2 / 4;
+}
-- 
2.17.1

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

* [U-Boot] [PATCH 08/13] sunxi: use sun6i-style watchdog for H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (6 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 07/13] sunxi: add clock code for H6 Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-25 10:37 ` [U-Boot] [PATCH 09/13] sunxi: add UART0 setup " Icenowy Zheng
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The H6 SoC has a sun6i-style watchdog in its timer part.

Enable the usage of it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/timer.h | 2 +-
 arch/arm/mach-sunxi/board.c             | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h
index ccdf942534..938067924e 100644
--- a/arch/arm/include/asm/arch-sunxi/timer.h
+++ b/arch/arm/include/asm/arch-sunxi/timer.h
@@ -77,7 +77,7 @@ struct sunxi_timer_reg {
 	struct sunxi_tgp tgp[4];
 	u8 res5[8];
 	u32 cpu_cfg;
-#elif defined(CONFIG_SUNXI_GEN_SUN6I)
+#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6)
 	u8 res3[16];
 	struct sunxi_wdog wdog[5];	/* We have 5 watchdogs */
 #endif
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 1753faec1d..8105a7dbfc 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -287,7 +287,7 @@ void reset_cpu(ulong addr)
 		/* sun5i sometimes gets stuck without this */
 		writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
 	}
-#elif defined(CONFIG_SUNXI_GEN_SUN6I)
+#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6)
 	static const struct sunxi_wdog *wdog =
 		 ((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog;
 
-- 
2.17.1

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

* [U-Boot] [PATCH 09/13] sunxi: add UART0 setup for H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (7 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 08/13] sunxi: use sun6i-style watchdog " Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-26 11:01   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 10/13] sunxi: add MMC support " Icenowy Zheng
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The UART0 on H6 is available at PH bank (and PF bank, but the PF one is
muxed with SD card).

Add pinmux configuration.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/gpio.h | 1 +
 arch/arm/mach-sunxi/board.c            | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 24f85206c8..5acc3033f5 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -198,6 +198,7 @@ enum sunxi_gpio_number {
 #define SUN6I_GPH_TWI2		2
 #define SUN6I_GPH_UART0		2
 #define SUN9I_GPH_UART0		2
+#define SUN50I_H6_GPH_UART0	2
 
 #define SUNXI_GPI_SDC3		2
 #define SUN7I_GPI_TWI3		3
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 8105a7dbfc..b04a005efc 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -108,6 +108,10 @@ static int gpio_init(void)
 	sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN50I_GPB_UART0);
 	sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_GPB_UART0);
 	sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP);
+#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I_H6)
+	sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H6_GPH_UART0);
+	sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H6_GPH_UART0);
+	sunxi_gpio_set_pull(SUNXI_GPH(1), 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);
-- 
2.17.1

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

* [U-Boot] [PATCH 10/13] sunxi: add MMC support for H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (8 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 09/13] sunxi: add UART0 setup " Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-25 10:37 ` [U-Boot] [PATCH 11/13] sunxi: add DRAM support to H6 Icenowy Zheng
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The Allwinner H6 SoC has 3 MMC controllers like the ones in A64, with
the MMC2 come with the capability to do crypto by EMCE.

Add MMC support for H6. EMCE support is not added yet.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/mmc.h |  2 +-
 board/sunxi/board.c                   |  7 +++++++
 drivers/mmc/sunxi_mmc.c               | 13 ++++++++++++-
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
index 69f737f3bf..4fce9218ff 100644
--- a/arch/arm/include/asm/arch-sunxi/mmc.h
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
@@ -46,7 +46,7 @@ struct sunxi_mmc {
 	u32 chda;		/* 0x90 */
 	u32 cbda;		/* 0x94 */
 	u32 res2[26];
-#ifdef CONFIG_SUNXI_GEN_SUN6I
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6)
 	u32 res3[64];
 #endif
 	u32 fifo;		/* 0x100 / 0x200 FIFO access address */
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index a5789090c0..4853fe7e00 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -444,6 +444,13 @@ 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_H6)
+		/* SDC2: PC4-PC14 */
+		for (pin = SUNXI_GPC(4); pin <= SUNXI_GPC(14); pin++) {
+			sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
+			sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
+			sunxi_gpio_set_drv(pin, 2);
+		}
 #elif defined(CONFIG_MACH_SUN9I)
 		/* SDC2: PC6-PC16 */
 		for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(16); pin++) {
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 5292f2d3cc..2f6e9058d1 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -71,10 +71,12 @@ static int mmc_resource_init(int sdc_no)
 		priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
 		priv->mclkreg = &ccm->sd2_clk_cfg;
 		break;
+#ifdef SUNXI_MMC3_BASE
 	case 3:
 		priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
 		priv->mclkreg = &ccm->sd3_clk_cfg;
 		break;
+#endif
 	default:
 		printf("Wrong mmc number %d\n", sdc_no);
 		return -1;
@@ -117,6 +119,9 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
 #ifdef CONFIG_MACH_SUN9I
 		pll = CCM_MMC_CTRL_PLL_PERIPH0;
 		pll_hz = clock_get_pll4_periph0();
+#elif defined(CONFIG_MACH_SUN50I_H6)
+		pll = CCM_MMC_CTRL_PLL6X2;
+		pll_hz = clock_get_pll6() * 2;
 #else
 		pll = CCM_MMC_CTRL_PLL6;
 		pll_hz = clock_get_pll6();
@@ -495,7 +500,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
 
 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
 	cfg->host_caps = MMC_MODE_4BIT;
-#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I)
+#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I_H6)
 	if (sdc_no == 2)
 		cfg->host_caps = MMC_MODE_8BIT;
 #endif
@@ -510,6 +515,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
 
 	/* config ahb clock */
 	debug("init mmc %d clock and io\n", sdc_no);
+#if !defined(CONFIG_MACH_SUN50I_H6)
 	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
 
 #ifdef CONFIG_SUNXI_GEN_SUN6I
@@ -520,6 +526,11 @@ struct mmc *sunxi_mmc_init(int sdc_no)
 	/* sun9i has a mmc-common module, also set the gate and reset there */
 	writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
 	       SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
+#endif
+#else /* CONFIG_MACH_SUN50I_H6 */
+	setbits_le32(&ccm->sd_gate_reset, 1 << sdc_no);
+	/* unassert reset */
+	setbits_le32(&ccm->sd_gate_reset, 1 << (RESET_SHIFT + sdc_no));
 #endif
 	ret = mmc_set_mod_clk(priv, 24000000);
 	if (ret)
-- 
2.17.1

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

* [U-Boot] [PATCH 11/13] sunxi: add DRAM support to H6
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (9 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 10/13] sunxi: add MMC support " Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-27  9:46   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC Icenowy Zheng
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

The Allwinner H6 SoC comes with a set of new DRAM controller+PHY combo.
Both the controller and the PHY seem to be originate from DesignWare,
and are similar to the ones in ZynqMP SoCs.

This commit introduces an initial DRAM driver for H6, which contains
only LPDDR3 support. The currently known SBCs with H6 all come with
LPDDR3 memory, including Pine H64 and several Orange Pi's.

The BSP DRAM initialization code is closed source and violates GPL. Code
in this commit is written by experimenting, referring the code/document
of other users of the IPs (mainly the ZynqMP, as it's the only found PHY
reference) and disassebling the BSP blob.

Thanks for Jernej Skrabec for review and fix some issues in this driver
(including the most critical one which made it to work), and rewrite
some code from register dump!

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
 .../include/asm/arch-sunxi/dram_sun50i_h6.h   | 276 +++++++
 arch/arm/mach-sunxi/Kconfig                   |   6 +
 arch/arm/mach-sunxi/Makefile                  |   1 +
 arch/arm/mach-sunxi/dram_sun50i_h6.c          | 708 ++++++++++++++++++
 5 files changed, 993 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
 create mode 100644 arch/arm/mach-sunxi/dram_sun50i_h6.c

diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
index 80abac95b8..cc11fca8ef 100644
--- a/arch/arm/include/asm/arch-sunxi/dram.h
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -28,6 +28,8 @@
 #include <asm/arch/dram_sunxi_dw.h>
 #elif defined(CONFIG_MACH_SUN9I)
 #include <asm/arch/dram_sun9i.h>
+#elif defined(CONFIG_MACH_SUN50I_H6)
+#include <asm/arch/dram_sun50i_h6.h>
 #else
 #include <asm/arch/dram_sun4i.h>
 #endif
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
new file mode 100644
index 0000000000..fe138b8cc0
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
@@ -0,0 +1,276 @@
+/*
+ * H6 dram controller register and constant defines
+ *
+ * (C) Copyright 2017  Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN50I_H6_H
+#define _SUNXI_DRAM_SUN50I_H6_H
+
+enum sunxi_dram_type {
+	SUNXI_DRAM_TYPE_DDR3 = 3,
+	SUNXI_DRAM_TYPE_DDR4,
+	SUNXI_DRAM_TYPE_LPDDR2 = 6,
+	SUNXI_DRAM_TYPE_LPDDR3,
+};
+
+/*
+ * The following information is mainly retrieved by disassembly and some FPGA
+ * test code of sun50iw3 platform.
+ */
+struct sunxi_mctl_com_reg {
+	u32 cr;			/* 0x000 control register */
+	u8 reserved_0x004[4];	/* 0x004 */
+	u32 unk_0x008;		/* 0x008 */
+	u32 tmr;		/* 0x00c timer register */
+	u8 reserved_0x010[4];	/* 0x010 */
+	u32 unk_0x014;		/* 0x014 */
+	u8 reserved_0x018[8];	/* 0x018 */
+	u32 maer0;		/* 0x020 master enable register 0 */
+	u32 maer1;		/* 0x024 master enable register 1 */
+	u32 maer2;		/* 0x028 master enable register 2 */
+	u8 reserved_0x02c[468];	/* 0x02c */
+	u32 bwcr;		/* 0x200 bandwidth control register */
+	u8 reserved_0x204[12];	/* 0x204 */
+	/*
+	 * The last master configured by BSP libdram is at 0x49x, so the
+	 * size of this struct array is set to 41 (0x29) now.
+	 */
+	struct {
+		u32 cfg0;		/* 0x0 */
+		u32 cfg1;		/* 0x4 */
+		u8 reserved_0x8[8];	/* 0x8 */
+	} master[41];		/* 0x210 + index * 0x10 */
+};
+check_member(sunxi_mctl_com_reg, master[40].reserved_0x8, 0x498);
+
+/*
+ * The following register information are retrieved from some similar DRAM
+ * controllers, including the DRAM controllers in Allwinner A23/A80 SoCs,
+ * Rockchip RK3328 SoC, NXP i.MX7 SoCs and Xilinx Zynq UltraScale+ SoCs.
+ *
+ * The DRAM controller in Allwinner A23/A80 SoCs and NXP i.MX7 SoCs seems
+ * to be older than the one in Allwinner H6, as the DRAMTMG9 register
+ * is missing in these SoCs. (From the product specifications of these
+ * SoCs they're not capable of DDR4)
+ *
+ * Information sources:
+ * - dram_sun9i.h and dram_sun8i_a23.h in the same directory.
+ * - sdram_rk3328.h from the RK3328 TPL DRAM patchset
+ * - i.MX 7Solo Applications Processor Reference Manual (IMX7SRM)
+ * - Zynq UltraScale+ MPSoC Register Reference (UG1087)
+ */
+struct sunxi_mctl_ctl_reg {
+	u32 mstr;		/* 0x000 */
+	u32 statr;		/* 0x004 unused */
+	u32 mstr1;		/* 0x008 unused */
+	u32 unk_0x00c;		/* 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 unused */
+	u32 pwrtmg;		/* 0x034 unused */
+	u32 hwlpctl;		/* 0x038 unused */
+	u8 reserved_0x03c[20];	/* 0x03c */
+	u32 rfshctl0;		/* 0x050 unused */
+	u32 rfshctl1;		/* 0x054 unused */
+	u8 reserved_0x058[8];	/* 0x05c */
+	u32 rfshctl3;		/* 0x060 */
+	u32 rfshtmg;		/* 0x064 */
+	u8 reserved_0x068[104];	/* 0x068 reserved for ECC&CRC (from ZynqMP) */
+	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, may not exist */
+	u8 reserved_0x1b8[8];	/* 0x1b8 */
+	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[180];	/* 0x258 */
+	u32 dbgcmd;		/* 0x30c unused */
+	u32 dbgstat;		/* 0x310 unused */
+	u8 reserved_0x314[12];	/* 0x314 */
+	u32 swctl;		/* 0x320 */
+	u32 swstat;		/* 0x324 */
+};
+check_member(sunxi_mctl_ctl_reg, swstat, 0x324);
+
+#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_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)
+
+/*
+ * The following register information is based on Zynq UltraScale+
+ * MPSoC Register Reference, as it's the currently only known
+ * DDR PHY similar to the one used in H6; however although the
+ * map is similar, the bit fields definitions are different.
+ *
+ * Other DesignWare DDR PHY's have similar register names, but the
+ * offset and definitions are both different.
+ */
+struct sunxi_mctl_phy_reg {
+	u32 ver;		/* 0x000 guess based on similar PHYs */
+	u32 pir;		/* 0x004 */
+	u8 reserved_0x008[8];	/* 0x008 */
+	/*
+	 * The ZynqMP manual didn't document PGCR1, however this register
+	 * exists on H6 and referenced by libdram.
+	 */
+	u32 pgcr[8];		/* 0x010 */
+	/*
+	 * By comparing the hardware and the ZynqMP manual, the PGSR seems
+	 * to start at 0x34 on H6.
+	 */
+	u8 reserved_0x030[4];	/* 0x030 */
+	u32 pgsr[3];		/* 0x034 */
+	u32 ptr[7];		/* 0x040 */
+	/*
+	 * According to ZynqMP reference there's PLLCR0~6 in this area,
+	 * but they're tagged "Type B PLL Only" and H6 seems to have
+	 * no them.
+	 * 0x080 is not present in ZynqMP reference but it seems to be
+	 * present on H6.
+	 */
+	u8 reserved_0x05c[36];	/* 0x05c */
+	u32 unk_0x080;		/* 0x080 */
+	u8 reserved_0x084[4];	/* 0x084 */
+	u32 dxccr;		/* 0x088 */
+	u8 reserved_0x08c[4];	/* 0x08c */
+	u32 dsgcr;		/* 0x090 */
+	u8 reserved_0x094[4];	/* 0x094 */
+	u32 odtcr;		/* 0x098 */
+	u8 reserved_0x09c[4];	/* 0x09c */
+	u32 aacr;		/* 0x0a0 */
+	u8 reserved_0x0a4[32];	/* 0x0a4 */
+	u32 gpr1;		/* 0x0c4 */
+	u8 reserved_0x0c8[56];	/* 0x0c8 */
+	u32 dcr;		/* 0x100 */
+	u8 reserved_0x104[12];	/* 0x104 */
+	u32 dtpr[7];		/* 0x110 */
+	u8 reserved_0x12c[20];	/* 0x12c */
+	u32 rdimmgcr[3];	/* 0x140 */
+	u8 reserved_0x14c[4];	/* 0x14c */
+	u32 rdimmcr[5];		/* 0x150 */
+	u8 reserved_0x164[4];	/* 0x164 */
+	u32 schcr[2];		/* 0x168 */
+	u8 reserved_0x170[16];	/* 0x170 */
+	/*
+	 * The ZynqMP manual documents MR0~7, 11~14 and 22.
+	 */
+	u32 mr[23];		/* 0x180 */
+	u8 reserved_0x1dc[36];	/* 0x1dc */
+	u32 dtcr[2];		/* 0x200 */
+	u32 dtar[3];		/* 0x208 */
+	u8 reserved_0x214[4];	/* 0x214 */
+	u32 dtdr[2];		/* 0x218 */
+	u8 reserved_0x220[16];	/* 0x220 */
+	u32 dtedr0;		/* 0x230 */
+	u32 dtedr1;		/* 0x234 */
+	u32 dtedr2;		/* 0x238 */
+	u32 vtdr;		/* 0x23c */
+	u32 catr[2];		/* 0x240 */
+	u8 reserved_0x248[8];
+	u32 dqsdr[3];		/* 0x250 */
+	u32 dtedr3;		/* 0x25c */
+	u8 reserved_0x260[160];	/* 0x260 */
+	u32 dcuar;		/* 0x300 */
+	u32 dcudr;		/* 0x304 */
+	u32 dcurr;		/* 0x308 */
+	u32 dculr;		/* 0x30c */
+	u32 dcugcr;		/* 0x310 */
+	u32 dcutpr;		/* 0x314 */
+	u32 dcusr[2];		/* 0x318 */
+	u8 reserved_0x320[444];	/* 0x320 */
+	u32 rankidr;		/* 0x4dc */
+	u32 riocr[6];		/* 0x4e0 */
+	u8 reserved_0x4f8[8];	/* 0x4f8 */
+	u32 aciocr[6];		/* 0x500 */
+	u8 reserved_0x518[8];	/* 0x518 */
+	u32 iovcr[2];		/* 0x520 */
+	u32 vtcr[2];		/* 0x528 */
+	u8 reserved_0x530[16];	/* 0x530 */
+	u32 acbdlr[17];		/* 0x540 */
+	u32 aclcdlr;		/* 0x584 */
+	u8 reserved_0x588[24];	/* 0x588 */
+	u32 acmdlr[2];		/* 0x5a0 */
+	u8 reserved_0x5a8[216];	/* 0x5a8 */
+	struct {
+		u32 zqcr;	/* 0x00 only the first one valid */
+		u32 zqpr[2];	/* 0x04 */
+		u32 zqdr[2];	/* 0x0c */
+		u32 zqor[2];	/* 0x14 */
+		u32 zqsr;	/* 0x1c */
+	} zq[2];		/* 0x680, 0x6a0 */
+	u8 reserved_0x6c0[64];	/* 0x6c0 */
+	struct {
+		u32 gcr[7];		/* 0x00 */
+		u8 reserved_0x1c[36];	/* 0x1c */
+		u32 bdlr0;		/* 0x40 */
+		u32 bdlr1;		/* 0x44 */
+		u32 bdlr2;		/* 0x48 */
+		u8 reserved_0x4c[4];	/* 0x4c */
+		u32 bdlr3;		/* 0x50 */
+		u32 bdlr4;		/* 0x54 */
+		u32 bdlr5;		/* 0x58 */
+		u8 reserved_0x5c[4];	/* 0x5c */
+		u32 bdlr6;		/* 0x60 */
+		u8 reserved_0x64[28];	/* 0x64 */
+		u32 lcdlr[6];		/* 0x80 */
+		u8 reserved_0x98[8];	/* 0x98 */
+		u32 mdlr[2];		/* 0xa0 */
+		u8 reserved_0xa8[24];	/* 0xa8 */
+		u32 gtr0;		/* 0xc0 */
+		u8 reserved_0xc4[12];	/* 0xc4 */
+		/*
+		 * DXnRSR0 is not documented in ZynqMP manual but
+		 * it's used in libdram.
+		 */
+		u32 rsr[4];		/* 0xd0 */
+		u32 gsr[4];		/* 0xe0 */
+		u8 reserved_0xf0[16];	/* 0xf0 */
+	} dx[4];		/* 0x700, 0x800, 0x900, 0xa00 */
+};
+check_member(sunxi_mctl_phy_reg, dx[3].reserved_0xf0, 0xaf0);
+
+#define DCR_LPDDR3	(1 << 0)
+#define DCR_DDR3	(3 << 0)
+#define DCR_DDR4	(4 << 0)
+#define DCR_DDR8BANK	BIT(3)
+
+static inline int ns_to_t(int nanoseconds)
+{
+	const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
+
+	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
+}
+
+#endif /* _SUNXI_DRAM_SUN50I_H6_H */
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index e3c19b7464..c2fa0533e7 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -42,6 +42,12 @@ config DRAM_SUN9I
 	  Select this dram controller driver for Sun9i platforms,
 	  like A80.
 
+config DRAM_SUN50I_H6
+	bool
+	help
+	  Select this dram controller driver for some sun50i platforms,
+	  like H6.
+
 config SUN6I_P2WI
 	bool "Allwinner sun6i internal P2WI controller"
 	help
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index bafeb59d64..a00d4b335d 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -40,4 +40,5 @@ obj-$(CONFIG_DRAM_SUN9I)	+= dram_sun9i.o
 obj-$(CONFIG_SPL_SPI_SUNXI)	+= spl_spi_sunxi.o
 obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_sunxi_dw.o
 obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_timings/
+obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_sun50i_h6.o
 endif
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c
new file mode 100644
index 0000000000..c7c4ea9ba7
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
@@ -0,0 +1,708 @@
+/*
+ * sun50i H6 platform dram controller init
+ *
+ * (C) Copyright 2017      Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
+#include <linux/bitops.h>
+#include <linux/kconfig.h>
+
+/*
+ * The delay parameters below allow to allegedly specify delay times of some
+ * unknown unit for each individual bit trace in each of the four data bytes
+ * the 32-bit wide access consists of. Also three control signals can be
+ * adjusted individually.
+ */
+#define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
+/* The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable and DQSN */
+#define WR_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 4)
+/*
+ * The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable, DQSN,
+ * Termination and Power down
+ */
+#define RD_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 6)
+struct dram_para {
+	u32 clk;
+	enum sunxi_dram_type type;
+	u8 cols;
+	u8 rows;
+	u8 ranks;
+	const u8 dx_read_delays[NR_OF_BYTE_LANES][RD_LINES_PER_BYTE_LANE];
+	const u8 dx_write_delays[NR_OF_BYTE_LANES][WR_LINES_PER_BYTE_LANE];
+};
+
+static void mctl_sys_init(struct dram_para *para);
+static void mctl_com_init(struct dram_para *para);
+static void mctl_set_timing_lpddr3(struct dram_para *para);
+static void mctl_channel_init(struct dram_para *para);
+
+static void mctl_core_init(struct dram_para *para)
+{
+	mctl_sys_init(para);
+	mctl_com_init(para);
+	switch (para->type) {
+	case SUNXI_DRAM_TYPE_LPDDR3:
+		mctl_set_timing_lpddr3(para);
+		break;
+	default:
+		panic("Unsupported DRAM type!");
+	};
+	mctl_channel_init(para);
+}
+
+static void mctl_phy_pir_init(u32 val)
+{
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+
+	writel(val | BIT(0), &mctl_phy->pir);
+	mctl_await_completion(&mctl_phy->pgsr[0], BIT(0), BIT(0));
+}
+
+enum {
+	MBUS_PORT_CPU           = 0,
+	MBUS_PORT_GPU           = 1,
+	MBUS_PORT_MAHB          = 2,
+	MBUS_PORT_DMA           = 3,
+	MBUS_PORT_VE            = 4,
+	MBUS_PORT_CE            = 5,
+	MBUS_PORT_TSC0          = 6,
+	MBUS_PORT_NDFC0         = 8,
+	MBUS_PORT_CSI0          = 11,
+	MBUS_PORT_DI0           = 14,
+	MBUS_PORT_DI1           = 15,
+	MBUS_PORT_DE300         = 16,
+	MBUS_PORT_IOMMU         = 25,
+	MBUS_PORT_VE2           = 26,
+	MBUS_PORT_USB3        = 37,
+	MBUS_PORT_PCIE          = 38,
+	MBUS_PORT_VP9           = 39,
+	MBUS_PORT_HDCP2       = 40,
+};
+
+enum {
+	MBUS_QOS_LOWEST = 0,
+	MBUS_QOS_LOW,
+	MBUS_QOS_HIGH,
+	MBUS_QOS_HIGHEST
+};
+inline void mbus_configure_port(u8 port,
+				bool bwlimit,
+				bool priority,
+				u8 qos,
+				u8 waittime,
+				u8 acs,
+				u16 bwl0,
+				u16 bwl1,
+				u16 bwl2)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+	const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
+			   | (priority ? (1 << 1) : 0)
+			   | ((qos & 0x3) << 2)
+			   | ((waittime & 0xf) << 4)
+			   | ((acs & 0xff) << 8)
+			   | (bwl0 << 16) );
+	const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
+
+	debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
+	writel(cfg0, &mctl_com->master[port].cfg0);
+	writel(cfg1, &mctl_com->master[port].cfg1);
+}
+
+#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)	\
+	mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
+			    MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
+
+static void mctl_set_master_priority(void)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+	/* enable bandwidth limit windows and set windows size 1us */
+	writel(399, &mctl_com->tmr);
+	writel(BIT(16), &mctl_com->bwcr);
+
+	MBUS_CONF(  CPU,  true, HIGHEST, 0,  256,  128,  100);
+	MBUS_CONF(  GPU,  true,    HIGH, 0, 1536, 1400,  256);
+	MBUS_CONF( MAHB,  true, HIGHEST, 0,  512,  256,   96);
+	MBUS_CONF(  DMA,  true,    HIGH, 0,  256,  100,   80);
+	MBUS_CONF(   VE,  true,    HIGH, 2, 8192, 5500, 5000);
+	MBUS_CONF(   CE,  true,    HIGH, 2,  100,   64,   32);
+	MBUS_CONF( TSC0,  true,    HIGH, 2,  100,   64,   32);
+	MBUS_CONF(NDFC0,  true,    HIGH, 0,  256,  128,   64);
+	MBUS_CONF( CSI0,  true,    HIGH, 0,  256,  128,  100);
+	MBUS_CONF(  DI0,  true,    HIGH, 0, 1024,  256,   64);
+	MBUS_CONF(DE300,  true, HIGHEST, 6, 8192, 2800, 2400);
+	MBUS_CONF(IOMMU,  true, HIGHEST, 0,  100,   64,   32);
+	MBUS_CONF(  VE2,  true,    HIGH, 2, 8192, 5500, 5000);
+	MBUS_CONF( USB3,  true,    HIGH, 0,  256,  128,   64);
+	MBUS_CONF( PCIE,  true,    HIGH, 2,  100,   64,   32);
+	MBUS_CONF(  VP9,  true,    HIGH, 2, 8192, 5500, 5000);
+	MBUS_CONF(HDCP2,  true,    HIGH, 2,  100,   64,   32);
+}
+
+static u32 mr_lpddr3[12] = {
+	0x00000000, 0x00000043, 0x0000001a, 0x00000001,
+	0x00000000, 0x00000000, 0x00000048, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000003,
+};
+
+/* TODO: flexible timing */
+static void mctl_set_timing_lpddr3(struct dram_para *para)
+{
+	struct sunxi_mctl_ctl_reg * const mctl_ctl =
+			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+
+	u8 tccd		= 2;
+	u8 tfaw		= max(ns_to_t(50), 4);
+	u8 trrd		= max(ns_to_t(10), 2);
+	u8 trcd		= max(ns_to_t(24), 2);
+	u8 trc		= ns_to_t(70);
+	u8 txp		= max(ns_to_t(8), 2);
+	u8 twtr		= max(ns_to_t(8), 2);
+	u8 trtp		= max(ns_to_t(8), 2);
+	u8 twr		= max(ns_to_t(15), 2);
+	u8 trp		= ns_to_t(18);
+	u8 tras		= ns_to_t(42);
+	u8 twtr_sa	= ns_to_t(5);
+	u8 tcksrea	= ns_to_t(11);
+	u16 trefi	= ns_to_t(3900) / 32;
+	u16 trfc	= ns_to_t(210);
+	u16 txsr	= ns_to_t(220);
+
+	if (CONFIG_DRAM_CLK % 400 == 0) {
+		/* Round up these parameters */
+		twtr_sa++;
+		tcksrea++;
+	}
+
+	u8 tmrw		= 5;
+	u8 tmrd		= 5;
+	u8 tmod		= 12;
+	u8 tcke		= 3;
+	u8 tcksrx	= 5;
+	u8 tcksre	= 5;
+	u8 tckesr	= 5;
+	u8 trasmax	= CONFIG_DRAM_CLK / 60;
+	u8 txs		= 4;
+	u8 txsdll	= 4;
+	u8 txsabort	= 4;
+	u8 txsfast	= 4;
+
+	u8 tcl		= 5; /* CL 10 */
+	u8 tcwl		= 3; /* CWL 6 */
+	u8 t_rdata_en	= twtr_sa + 8;
+
+	u32 tdinit0	= (200 * CONFIG_DRAM_CLK) + 1;		/* 200us */
+	u32 tdinit1	= (100 * CONFIG_DRAM_CLK) / 1000 + 1;	/* 100ns */
+	u32 tdinit2	= (11 * CONFIG_DRAM_CLK) + 1;		/* 11us */
+	u32 tdinit3	= (1 * CONFIG_DRAM_CLK) + 1;		/* 1us */
+
+	u8 twtp		= tcwl + 4 + twr + 1;
+	/*
+	 * The code below for twr2rd and trd2wr follows the IP core's
+	 * document from ZynqMP and i.MX7. The BSP has both number
+	 * substracted by 2.
+	 */
+	u8 twr2rd	= tcwl + 4 + 1 + twtr;
+	u8 trd2wr	= tcl + 4 + (tcksrea >> 1) - tcwl + 1;
+
+	/* set mode register */
+	memcpy(mctl_phy->mr, mr_lpddr3, sizeof(mr_lpddr3));
+
+	/* 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(txsr, &mctl_ctl->dramtmg[14]);
+
+	clrsetbits_le32(&mctl_ctl->init[0], (3 << 30), (1 << 30));
+	writel(0, &mctl_ctl->dfimisc);
+	clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
+
+	/*
+	 * Set timing registers of the PHY.
+	 * Note: the PHY is clocked 2x from the DRAM frequency.
+	 */
+	writel((trrd << 25) | (tras << 17) | (trp << 9) | (trtp << 1),
+	       &mctl_phy->dtpr[0]);
+	writel((tfaw << 17) | 0x28000400 | (tmrd << 1), &mctl_phy->dtpr[1]);
+	writel(((txs << 6) - 1) | (tcke << 17), &mctl_phy->dtpr[2]);
+	writel(((txsdll << 22) - (0x1 << 16)) | twtr_sa | (tcksrea << 8),
+	       &mctl_phy->dtpr[3]);
+	writel((txp << 1) | (trfc << 17) | 0x800, &mctl_phy->dtpr[4]);
+	writel((trc << 17) | (trcd << 9) | (twtr << 1), &mctl_phy->dtpr[5]);
+	writel(0x0505, &mctl_phy->dtpr[6]);
+
+	/* Configure DFI timing */
+	writel(tcl | 0x2000200 | (t_rdata_en << 16) | 0x808000,
+	       &mctl_ctl->dfitmg0);
+	writel(0x040201, &mctl_ctl->dfitmg1);
+
+	/* Configure PHY timing */
+	writel(tdinit0 | (tdinit1 << 20), &mctl_phy->ptr[3]);
+	writel(tdinit2 | (tdinit3 << 18), &mctl_phy->ptr[4]);
+
+	/* set refresh timing */
+	writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
+}
+
+static void mctl_sys_init(struct dram_para *para)
+{
+	struct sunxi_ccm_reg * const ccm =
+			(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	struct sunxi_mctl_com_reg * const mctl_com =
+			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	struct sunxi_mctl_ctl_reg * const mctl_ctl =
+			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+	/* Put all DRAM-related blocks to reset state */
+	clrbits_le32(&ccm->mbus_cfg, MBUS_ENABLE | MBUS_RESET);
+	writel(0, &ccm->dram_gate_reset);
+	clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
+	clrbits_le32(&ccm->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_CTRL_N(para->clk * 2 / 24 - 1), &ccm->pll5_cfg);
+	mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK, CCM_PLL5_LOCK);
+
+	/* Configure DRAM mod clock */
+	writel(DRAM_CLK_SRC_PLL5, &ccm->dram_clk_cfg);
+	setbits_le32(&ccm->dram_clk_cfg, DRAM_CLK_UPDATE);
+	writel(BIT(0) | BIT(RESET_SHIFT), &ccm->dram_gate_reset);
+
+	/* Disable all channels */
+	writel(0, &mctl_com->maer0);
+	writel(0, &mctl_com->maer1);
+	writel(0, &mctl_com->maer2);
+
+	/* Configure MBUS and enable DRAM mod reset */
+	setbits_le32(&ccm->mbus_cfg, MBUS_RESET);
+	setbits_le32(&ccm->mbus_cfg, MBUS_ENABLE);
+	setbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET);
+	udelay(5);
+
+	/* Unknown hack from the BSP, which enables access of mctl_ctl regs */
+	writel(0x8000, &mctl_ctl->unk_0x00c);
+}
+
+static void mctl_set_addrmap(struct dram_para *para)
+{
+	struct sunxi_mctl_ctl_reg * const mctl_ctl =
+			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+	u8 cols = para->cols;
+	u8 rows = para->rows;
+	u8 ranks = para->ranks;
+
+	/* Ranks */
+	if (ranks == 2)
+		mctl_ctl->addrmap[0] = rows + cols - 3;
+	else
+		mctl_ctl->addrmap[0] = 0x0F;
+
+	/* 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 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;
+}
+
+static void mctl_com_init(struct dram_para *para)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	struct sunxi_mctl_ctl_reg * const mctl_ctl =
+			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	u32 reg_val, tmp;
+
+	mctl_set_addrmap(para);
+
+	setbits_le32(&mctl_com->cr, BIT(31));
+	/*
+	 * This address is magic; it's in SID memory area, but there's no
+	 * known definition of it.
+	 * On my Pine H64 board it has content 7.
+	 */
+	if (readl(0x03006100) == 7)
+		clrbits_le32(&mctl_com->cr, BIT(27));
+	else if (readl(0x03006100) == 3)
+		setbits_le32(&mctl_com->cr, BIT(27));
+
+	if (para->clk > 408)
+		reg_val = 0xf00;
+	else if (para->clk > 246)
+		reg_val = 0x1f00;
+	else
+		reg_val = 0x3f00;
+	clrsetbits_le32(&mctl_com->unk_0x008, 0x3f00, reg_val);
+
+	/* TODO: half DQ, non-LPDDR3 types */
+	writel(MSTR_DEVICETYPE_LPDDR3 | MSTR_BUSWIDTH_FULL |
+	       MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para->ranks) |
+	       0x80000000, &mctl_ctl->mstr);
+	writel(DCR_LPDDR3 | DCR_DDR8BANK | 0x400, &mctl_phy->dcr);
+
+	if (para->ranks == 2)
+		writel(0x0303, &mctl_ctl->odtmap);
+	else
+		writel(0x0201, &mctl_ctl->odtmap);
+
+	/* TODO: non-LPDDR3 types */
+	tmp = para->clk * 7 / 2000;
+	reg_val = 0x0400;
+	reg_val |= (tmp + 7) << 24;
+	reg_val |= (((para->clk < 400) ? 3 : 4) - tmp) << 16;
+	writel(reg_val, &mctl_ctl->odtcfg);
+
+	/* TODO: half DQ */
+}
+
+static void mctl_bit_delay_set(struct dram_para *para)
+{
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	int i, j;
+	u32 val;
+
+	for (i = 0; i < 4; i++) {
+		val = readl(&mctl_phy->dx[i].bdlr0);
+		for (j = 0; j < 4; j++)
+			val += para->dx_write_delays[i][j] << (j * 8);
+		writel(val, &mctl_phy->dx[i].bdlr0);
+
+		val = readl(&mctl_phy->dx[i].bdlr1);
+		for (j = 0; j < 4; j++)
+			val += para->dx_write_delays[i][j + 4] << (j * 8);
+		writel(val, &mctl_phy->dx[i].bdlr1);
+
+		val = readl(&mctl_phy->dx[i].bdlr2);
+		for (j = 0; j < 4; j++)
+			val += para->dx_write_delays[i][j + 8] << (j * 8);
+		writel(val, &mctl_phy->dx[i].bdlr2);
+	}
+	clrbits_le32(&mctl_phy->pgcr[0], BIT(26));
+
+	for (i = 0; i < 4; i++) {
+		val = readl(&mctl_phy->dx[i].bdlr3);
+		for (j = 0; j < 4; j++)
+			val += para->dx_read_delays[i][j] << (j * 8);
+		writel(val, &mctl_phy->dx[i].bdlr3);
+
+		val = readl(&mctl_phy->dx[i].bdlr4);
+		for (j = 0; j < 4; j++)
+			val += para->dx_read_delays[i][j + 4] << (j * 8);
+		writel(val, &mctl_phy->dx[i].bdlr4);
+
+		val = readl(&mctl_phy->dx[i].bdlr5);
+		for (j = 0; j < 4; j++)
+			val += para->dx_read_delays[i][j + 8] << (j * 8);
+		writel(val, &mctl_phy->dx[i].bdlr5);
+
+		val = readl(&mctl_phy->dx[i].bdlr6);
+		val += (para->dx_read_delays[i][12] << 8) |
+		       (para->dx_read_delays[i][13] << 16);
+		writel(val, &mctl_phy->dx[i].bdlr6);
+	}
+	setbits_le32(&mctl_phy->pgcr[0], BIT(26));
+	udelay(1);
+
+	for (i = 1; i < 14; i++) {
+		val = readl(&mctl_phy->acbdlr[i]);
+		val += 0x0a0a0a0a;
+		writel(val, &mctl_phy->acbdlr[i]);
+	}
+}
+
+static void mctl_channel_init(struct dram_para *para)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	struct sunxi_mctl_ctl_reg * const mctl_ctl =
+			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	int i;
+	u32 val;
+
+	setbits_le32(&mctl_ctl->dfiupd[0], BIT(31) | BIT(30));
+	setbits_le32(&mctl_ctl->zqctl[0], BIT(31) | BIT(30));
+	writel(0x2f05, &mctl_ctl->sched[0]);
+	setbits_le32(&mctl_ctl->rfshctl3, BIT(0));
+	setbits_le32(&mctl_ctl->dfimisc, BIT(0));
+	setbits_le32(&mctl_ctl->unk_0x00c, BIT(8));
+	clrsetbits_le32(&mctl_phy->pgcr[1], 0x180, 0xc0);
+	/* TODO: non-LPDDR3 types */
+	clrsetbits_le32(&mctl_phy->pgcr[2], GENMASK(17, 0), ns_to_t(7800));
+	clrbits_le32(&mctl_phy->pgcr[6], BIT(0));
+	clrsetbits_le32(&mctl_phy->dxccr, 0xee0, 0x220);
+	/* TODO: VT compensation */
+	clrsetbits_le32(&mctl_phy->dsgcr, BIT(0), 0x440060);
+	clrbits_le32(&mctl_phy->vtcr[1], BIT(1));
+
+	for (i = 0; i < 4; i++)
+		clrsetbits_le32(&mctl_phy->dx[i].gcr[0], 0xe00, 0x800);
+	for (i = 0; i < 4; i++)
+		clrsetbits_le32(&mctl_phy->dx[i].gcr[2], 0xffff, 0x5555);
+	for (i = 0; i < 4; i++)
+		clrsetbits_le32(&mctl_phy->dx[i].gcr[3], 0x3030, 0x1010);
+
+	udelay(100);
+
+	if (para->ranks == 2)
+		setbits_le32(&mctl_phy->dtcr[1], 0x30000);
+	else
+		clrsetbits_le32(&mctl_phy->dtcr[1], 0x30000, 0x10000);
+
+	clrbits_le32(&mctl_phy->dtcr[1], BIT(1));
+	if (para->ranks == 2) {
+		writel(0x00010001, &mctl_phy->rankidr);
+		writel(0x20000, &mctl_phy->odtcr);
+	} else {
+		writel(0x0, &mctl_phy->rankidr);
+		writel(0x10000, &mctl_phy->odtcr);
+	}
+
+	/* TODO: non-LPDDR3 types */
+	clrsetbits_le32(&mctl_phy->dtcr[0], 0xF0000000, 0x10000040);
+	if (para->clk <= 792) {
+		if (para->clk <= 672) {
+			if (para->clk <= 600)
+				val = 0x300;
+			else
+				val = 0x400;
+		} else {
+			val = 0x500;
+		}
+	} else {
+		val = 0x600;
+	}
+	/* FIXME: NOT REVIEWED YET */
+	clrsetbits_le32(&mctl_phy->zq[0].zqcr, 0x700, val);
+	clrsetbits_le32(&mctl_phy->zq[0].zqpr[0], 0xff,
+			CONFIG_DRAM_ZQ & 0xff);
+	clrbits_le32(&mctl_phy->zq[0].zqor[0], 0xfffff);
+	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ >> 8) & 0xff);
+	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ & 0xf00) - 0x100);
+	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ & 0xff00) << 4);
+	clrbits_le32(&mctl_phy->zq[1].zqpr[0], 0xfffff);
+	setbits_le32(&mctl_phy->zq[1].zqpr[0], (CONFIG_DRAM_ZQ >> 16) & 0xff);
+	setbits_le32(&mctl_phy->zq[1].zqpr[0], ((CONFIG_DRAM_ZQ >> 8) & 0xf00) - 0x100);
+	setbits_le32(&mctl_phy->zq[1].zqpr[0], (CONFIG_DRAM_ZQ & 0xff0000) >> 4);
+	if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
+		for (i = 1; i < 14; i++)
+			writel(0x06060606, &mctl_phy->acbdlr[i]);
+	}
+
+	/* TODO: non-LPDDR3 types */
+	mctl_phy_pir_init(0xf562 | BIT(10));
+
+	/* TODO: non-LPDDR3 types */
+	for (i = 0; i < 4; i++)
+		writel(0x00000909, &mctl_phy->dx[i].gcr[5]);
+
+	for (i = 0; i < 4; i++) {
+		if (IS_ENABLED(CONFIG_DRAM_ODT_EN))
+			val = 0x0;
+		else
+			val = 0xaaaa;
+		clrsetbits_le32(&mctl_phy->dx[i].gcr[2], 0xffff, val);
+
+		if (IS_ENABLED(CONFIG_DRAM_ODT_EN))
+			val = 0x0;
+		else
+			val = 0x2020;
+		clrsetbits_le32(&mctl_phy->dx[i].gcr[3], 0x3030, val);
+	}
+
+	mctl_bit_delay_set(para);
+	udelay(1);
+
+	setbits_le32(&mctl_phy->pgcr[6], BIT(0));
+	clrbits_le32(&mctl_phy->pgcr[6], 0xfff8);
+	for (i = 0; i < 4; i++)
+		clrbits_le32(&mctl_phy->dx[i].gcr[3], ~0x3ffff);
+	udelay(10);
+
+	if (readl(&mctl_phy->pgsr[0]) & 0xff00000) {
+		/* Oops! There's something wrong! */
+		debug("PLL = %x\n", readl(0x3001010));
+		debug("DRAM PHY PGSR0 = %x\n", readl(&mctl_phy->pgsr[0]));
+		for (i = 0; i < 4; i++)
+			debug("DRAM PHY DX%dRSR0 = %x\n", i, readl(&mctl_phy->dx[i].rsr[0]));
+		panic("Error while initializing DRAM PHY!\n");
+	}
+
+	clrsetbits_le32(&mctl_phy->dsgcr, 0xc0, 0x40);
+	clrbits_le32(&mctl_phy->pgcr[1], 0x40);
+	clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
+	writel(1, &mctl_ctl->swctl);
+	mctl_await_completion(&mctl_ctl->swstat, 1, 1);
+	clrbits_le32(&mctl_ctl->rfshctl3, BIT(0));
+
+	setbits_le32(&mctl_com->unk_0x014, BIT(31));
+	writel(0xffffffff, &mctl_com->maer0);
+	writel(0x7ff, &mctl_com->maer1);
+	writel(0xffff, &mctl_com->maer2);
+}
+
+static void mctl_auto_detect_dram_size(struct dram_para *para)
+{
+	/* TODO: non-LPDDR3, half DQ */
+	/* detect row address bits */
+	para->cols = 8;
+	para->rows = 18;
+	mctl_core_init(para);
+
+	for (para->rows = 13; para->rows < 18; para->rows++) {
+		/* 8 banks, 8 bit per byte and 32 bit width */
+		if (mctl_mem_matches((1 << (para->rows + para->cols + 5))))
+			break;
+	}
+
+	/* detect column address bits */
+	para->cols = 11;
+	mctl_core_init(para);
+
+	for (para->cols = 8; para->cols < 11; para->cols++) {
+		/* 8 bits per byte and 32 bit width */
+		if (mctl_mem_matches(1 << (para->cols + 2)))
+			break;
+	}
+}
+
+unsigned long mctl_calc_size(struct dram_para *para)
+{
+	/* TODO: non-LPDDR3, half DQ */
+
+	/* 8 banks, 32-bit (4 byte) data width */
+	return (1ULL << (para->cols + para->rows + 3)) * 4 * para->ranks;
+}
+
+#define SUN50I_H6_DX_WRITE_DELAYS				\
+	{{  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },	\
+	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },	\
+	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0 },	\
+	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }}
+#define SUN50I_H6_DX_READ_DELAYS					\
+	{{  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 },	\
+	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 },	\
+	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 },	\
+	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 }}
+
+unsigned long sunxi_dram_init(void)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	struct dram_para para = {
+		.clk = CONFIG_DRAM_CLK,
+		.type = SUNXI_DRAM_TYPE_LPDDR3,
+		.ranks = 2,
+		.cols = 11,
+		.rows = 14,
+		.dx_read_delays  = SUN50I_H6_DX_READ_DELAYS,
+		.dx_write_delays = SUN50I_H6_DX_WRITE_DELAYS,
+	};
+
+	unsigned long size;
+
+	/* RES_CAL_CTRL_REG in BSP U-boot*/
+	setbits_le32(0x7010310, BIT(8));
+	clrbits_le32(0x7010318, 0x3f);
+
+	mctl_auto_detect_dram_size(&para);
+
+	mctl_core_init(&para);
+
+	size = mctl_calc_size(&para);
+
+	clrsetbits_le32(&mctl_com->cr, 0xf0, (size / 1024 / 1024) & 0xf0);
+
+	mctl_set_master_priority();
+
+	return size;
+};
-- 
2.17.1

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

* [U-Boot] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (10 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 11/13] sunxi: add DRAM support to H6 Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-27 14:04   ` [U-Boot] [linux-sunxi] " Andre Przywara
  2018-06-25 10:37 ` [U-Boot] [PATCH 13/13] sunxi: add support for Pine H64 board Icenowy Zheng
  2018-06-25 12:40 ` [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL) Jagan Teki
  13 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

Allwinner H6 is a new SoC from Allwinner features USB3 and PCIe
interfaces.

This patch adds support for it.

As this is a new SoC supported by mainline U-Boot, the MMC env support
is dropped and only FAT env is available.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/dts/sun50i-h6.dtsi    | 140 +++++++++++++++++++++++++++++++++
 arch/arm/mach-sunxi/Kconfig    |  17 +++-
 arch/arm/mach-sunxi/cpu_info.c |   2 +
 common/spl/Kconfig             |   2 +-
 4 files changed, 159 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/dts/sun50i-h6.dtsi

diff --git a/arch/arm/dts/sun50i-h6.dtsi b/arch/arm/dts/sun50i-h6.dtsi
new file mode 100644
index 0000000000..50f9146318
--- /dev/null
+++ b/arch/arm/dts/sun50i-h6.dtsi
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			compatible = "arm,cortex-a53", "arm,armv8";
+			device_type = "cpu";
+			reg = <0>;
+		};
+
+		cpu1: cpu at 1 {
+			compatible = "arm,cortex-a53", "arm,armv8";
+			device_type = "cpu";
+			reg = <1>;
+		};
+
+		cpu2: cpu at 2 {
+			compatible = "arm,cortex-a53", "arm,armv8";
+			device_type = "cpu";
+			reg = <2>;
+		};
+
+		cpu3: cpu at 3 {
+			compatible = "arm,cortex-a53", "arm,armv8";
+			device_type = "cpu";
+			reg = <3>;
+		};
+	};
+
+	osc24M: osc24M_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <24000000>;
+		clock-output-names = "osc24M";
+	};
+
+	osc32k: osc32k_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+		clock-output-names = "osc32k";
+	};
+
+	iosc: internal-osc-clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <16000000>;
+		clock-accuracy = <300000000>;
+		clock-output-names = "iosc";
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13
+			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 14
+			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 11
+			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 10
+			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gic: interrupt-controller at 3021000 {
+			compatible = "arm,gic-400";
+			reg = <0x03021000 0x1000>,
+			      <0x03022000 0x2000>,
+			      <0x03024000 0x2000>,
+			      <0x03026000 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+		};
+
+		uart0: serial at 5000000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x05000000 0x400>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&osc24M>; /* placeholder */
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index c2fa0533e7..cb4a9af6bf 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -82,6 +82,7 @@ config SUN8I_RSB
 config SUNXI_SRAM_ADDRESS
 	hex
 	default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
+	default 0x20000 if MACH_SUN50I_H6
 	default 0x0
 	---help---
 	Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
@@ -281,6 +282,14 @@ config MACH_SUN50I_H5
 	select FIT
 	select SPL_LOAD_FIT
 
+config MACH_SUN50I_H6
+	bool "sun50i (Allwinner H6)"
+	select ARM64
+	select SUPPORT_SPL
+	select FIT
+	select SPL_LOAD_FIT
+	select DRAM_SUN50I_H6
+
 endchoice
 
 # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33"
@@ -374,6 +383,7 @@ config DRAM_CLK
 	default 360 if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || \
 		       MACH_SUN8I_V3S
 	default 672 if MACH_SUN50I
+	default 744 if MACH_SUN50I_H6
 	---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
@@ -393,7 +403,7 @@ config DRAM_ZQ
 	default 123 if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || MACH_SUN8I
 	default 127 if MACH_SUN7I
 	default 14779 if MACH_SUN8I_V3S
-	default 3881979 if MACH_SUN8I_R40
+	default 3881979 if MACH_SUN8I_R40 || MACH_SUN50I_H6
 	default 4145117 if MACH_SUN9I
 	default 3881915 if MACH_SUN50I
 	---help---
@@ -405,6 +415,7 @@ config DRAM_ODT_EN
 	default y if MACH_SUN8I_A23
 	default y if MACH_SUN8I_R40
 	default y if MACH_SUN50I
+	default y if MACH_SUN50I_H6
 	---help---
 	Select this to enable dram odt (on die termination).
 
@@ -495,6 +506,7 @@ config SYS_CLK_FREQ
 	default 816000000 if MACH_SUN50I || MACH_SUN50I_H5
 	default 1008000000 if MACH_SUN8I
 	default 1008000000 if MACH_SUN9I
+	default 888000000 if MACH_SUN50I_H6
 
 config SYS_CONFIG_NAME
 	default "sun4i" if MACH_SUN4I
@@ -504,6 +516,7 @@ config SYS_CONFIG_NAME
 	default "sun8i" if MACH_SUN8I
 	default "sun9i" if MACH_SUN9I
 	default "sun50i" if MACH_SUN50I
+	default "sun50i" if MACH_SUN50I_H6
 
 config SYS_BOARD
 	default "sunxi"
@@ -709,6 +722,7 @@ config VIDEO_SUNXI
 	depends on !MACH_SUN8I_V3S
 	depends on !MACH_SUN9I
 	depends on !MACH_SUN50I
+	depends on !MACH_SUN50I_H6
 	select VIDEO
 	imply VIDEO_DT_SIMPLEFB
 	default y
@@ -941,6 +955,7 @@ config SPL_STACK_R_ADDR
 	default 0x4fe00000 if MACH_SUN8I
 	default 0x2fe00000 if MACH_SUN9I
 	default 0x4fe00000 if MACH_SUN50I
+	default 0x4fe00000 if MACH_SUN50I_H6
 
 config SPL_SPI_SUNXI
 	bool "Support for SPI Flash on Allwinner SoCs in SPL"
diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c
index 25a5ec26a0..90aff395dc 100644
--- a/arch/arm/mach-sunxi/cpu_info.c
+++ b/arch/arm/mach-sunxi/cpu_info.c
@@ -97,6 +97,8 @@ int print_cpuinfo(void)
 	puts("CPU:   Allwinner A64 (SUN50I)\n");
 #elif defined CONFIG_MACH_SUN50I_H5
 	puts("CPU:   Allwinner H5 (SUN50I)\n");
+#elif defined CONFIG_MACH_SUN50I_H6
+	puts("CPU:   Allwinner H6 (SUN50I)\n");
 #else
 #warning Please update cpu_info.c with correct CPU information
 	puts("CPU:   SUNXI Family\n");
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 4d27565566..e761bda6f1 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -246,7 +246,7 @@ config SPL_SHA256_SUPPORT
 config SPL_FIT_IMAGE_TINY
 	bool "Remove functionality from SPL FIT loading to reduce size"
 	depends on SPL_FIT
-	default y if MACH_SUN50I || MACH_SUN50I_H5
+	default y if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6
 	help
 	  Enable this to reduce the size of the FIT image loading code
 	  in SPL, if space for the SPL binary is very tight.
-- 
2.17.1

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

* [U-Boot] [PATCH 13/13] sunxi: add support for Pine H64 board
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (11 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC Icenowy Zheng
@ 2018-06-25 10:37 ` Icenowy Zheng
  2018-06-25 12:40 ` [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL) Jagan Teki
  13 siblings, 0 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 10:37 UTC (permalink / raw)
  To: u-boot

Pine H64 is a SBC with Allwinner H6 SoC produced by Pine64. It features
1GiB/2GiB/4GiB(3GiB usable) DRAM, two USB 2.0 ports, one USB 3.0 port
and a mPCIE slot.

Add support for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/dts/Makefile               |  2 +
 arch/arm/dts/sun50i-h6-pine-h64.dts | 64 +++++++++++++++++++++++++++++
 board/sunxi/MAINTAINERS             |  5 +++
 configs/pine_h64_defconfig          | 15 +++++++
 4 files changed, 86 insertions(+)
 create mode 100644 arch/arm/dts/sun50i-h6-pine-h64.dts
 create mode 100644 configs/pine_h64_defconfig

diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index ab0b2568ea..0ef2165e3c 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -376,6 +376,8 @@ dtb-$(CONFIG_MACH_SUN50I_H5) += \
 	sun50i-h5-orangepi-pc2.dtb \
 	sun50i-h5-orangepi-prime.dtb \
 	sun50i-h5-orangepi-zero-plus2.dtb
+dtb-$(CONFIG_MACH_SUN50I_H6) += \
+	sun50i-h6-pine-h64.dtb
 dtb-$(CONFIG_MACH_SUN50I) += \
 	sun50i-a64-bananapi-m64.dtb \
 	sun50i-a64-nanopi-a64.dtb \
diff --git a/arch/arm/dts/sun50i-h6-pine-h64.dts b/arch/arm/dts/sun50i-h6-pine-h64.dts
new file mode 100644
index 0000000000..8e4f3b38fe
--- /dev/null
+++ b/arch/arm/dts/sun50i-h6-pine-h64.dts
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "sun50i-h6.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Pine H64";
+	compatible = "pine64,pine-h64", "allwinner,sun50i-h6";
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index 5d31bcbdcd..59fc5c372c 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -352,6 +352,11 @@ M:	Andre Przywara <andre.przywara@arm.com>
 S:	Maintained
 F:	configs/pine64_plus_defconfig
 
+PINE H64 BOARD
+M:	Icenowy Zheng <icenowy@aosc.io>
+S:	Maintained
+F:	configs/pine_h64_defconfig
+
 R16 EVB PARROT BOARD
 M:	Quentin Schulz <quentin.schulz@free-electrons.com>
 S:	Maintained
diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig
new file mode 100644
index 0000000000..e9596c0284
--- /dev/null
+++ b/configs/pine_h64_defconfig
@@ -0,0 +1,15 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_MACH_SUN50I_H6=y
+CONFIG_DRAM_ODT_EN=y
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+# CONFIG_PSCI_RESET is not set
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-pine-h64"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SPL=y
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_SPL_ISO_PARTITION is not set
+# CONFIG_SPL_EFI_PARTITION is not set
-- 
2.17.1

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

* [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
  2018-06-25 10:37 ` [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS Icenowy Zheng
@ 2018-06-25 12:30   ` Maxime Ripard
  2018-06-26 10:34   ` [U-Boot] [linux-sunxi] " Andre Przywara
  1 sibling, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2018-06-25 12:30 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 06:37:11PM +0800, Icenowy Zheng wrote:
> The new Allwinner H6 SoC has its SRAM A1 at neither 0x0 nor 0x10000, but
> it's at 0x20000. Thus the SUNXI_HIGH_SRAM option needs to be refactored
> to support this new configuration.
> 
> Change it to SUNXI_SRAM_ADDRESS, which holds the real address of SRAM
> A1 in the memory map.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180625/6563fe88/attachment.sig>

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

* [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC
  2018-06-25 10:37 ` [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC Icenowy Zheng
@ 2018-06-25 12:33   ` Maxime Ripard
  2018-06-25 12:50     ` Icenowy Zheng
  2018-06-27  8:51   ` [U-Boot] [linux-sunxi] " Andre Przywara
  1 sibling, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2018-06-25 12:33 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 06:37:12PM +0800, Icenowy Zheng wrote:
> The Allwinner H6 SoC come with a totally new memory map.
> 
> Add basical definition of the new memory map into a header file, and let
> the cpu.h header include it in the situation of H6.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
>  .../include/asm/arch-sunxi/cpu_sun50i_h6.h    | 73 +++++++++++++++++++
>  2 files changed, 75 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
> index caec865264..08be963e8e 100644
> --- a/arch/arm/include/asm/arch-sunxi/cpu.h
> +++ b/arch/arm/include/asm/arch-sunxi/cpu.h
> @@ -9,6 +9,8 @@
>  
>  #if defined(CONFIG_MACH_SUN9I)
>  #include <asm/arch/cpu_sun9i.h>
> +#elif defined(CONFIG_MACH_SUN50I_H6)
> +#include <asm/arch/cpu_sun50i_h6.h>
>  #else
>  #include <asm/arch/cpu_sun4i.h>
>  #endif
> diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> new file mode 100644
> index 0000000000..b12f2dd1a2
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> @@ -0,0 +1,73 @@
> +/*
> + * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _SUNXI_CPU_SUN50I_H6_H
> +#define _SUNXI_CPU_SUN50I_H6_H
> +
> +#define SUNXI_SRAM_A1_BASE		0x00020000

Isn't that the same thing than SUNXI_SRAM_ADDRESS? Having it defined
twice and expecting the value to be matching seems a bit weird.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180625/c6223caf/attachment.sig>

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

* [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL)
  2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
                   ` (12 preceding siblings ...)
  2018-06-25 10:37 ` [U-Boot] [PATCH 13/13] sunxi: add support for Pine H64 board Icenowy Zheng
@ 2018-06-25 12:40 ` Jagan Teki
  2018-06-25 12:49   ` Icenowy Zheng
  13 siblings, 1 reply; 36+ messages in thread
From: Jagan Teki @ 2018-06-25 12:40 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 4:07 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> This patch trys to add support for Allwinner H6 SoC to U-Boot.
>
> Allwinner H6 is a quite new Allwinner SoC, with several parts changed a
> lot (memory map, DRAM controller, CCU, so on). The position which SPL
> will be loaded (SRAM A1) also changed to 0x20000.
>
> The Pine H64 board support comes with this patchset, as this is the
> first H6 board that I can get (being early bird).
>
> Icenowy Zheng (13):
>   sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
>   sunxi: add basical memory map definitions of H6 SoC
>   sunxi: change RMR64's RVBAR address for H6
>   sunxi: change ATF position for H6
>   sunxi: add config for SPL at 0x20000 on H6
>   sunxi: change GIC address on H6
>   sunxi: add clock code for H6
>   sunxi: use sun6i-style watchdog for H6
>   sunxi: add UART0 setup for H6
>   sunxi: add MMC support for H6
>   sunxi: add DRAM support to H6
>   sunxi: add support for Allwinner H6 SoC
>   sunxi: add support for Pine H64 board

is it on top of master? unable to apply for testing on master, point
me the branch would help.

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

* [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL)
  2018-06-25 12:40 ` [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL) Jagan Teki
@ 2018-06-25 12:49   ` Icenowy Zheng
  2018-06-25 13:02     ` Jagan Teki
  0 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 12:49 UTC (permalink / raw)
  To: u-boot



于 2018年6月25日 GMT+08:00 下午8:40:21, Jagan Teki <jagan@amarulasolutions.com> 写到:
>On Mon, Jun 25, 2018 at 4:07 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>> This patch trys to add support for Allwinner H6 SoC to U-Boot.
>>
>> Allwinner H6 is a quite new Allwinner SoC, with several parts changed
>a
>> lot (memory map, DRAM controller, CCU, so on). The position which SPL
>> will be loaded (SRAM A1) also changed to 0x20000.
>>
>> The Pine H64 board support comes with this patchset, as this is the
>> first H6 board that I can get (being early bird).
>>
>> Icenowy Zheng (13):
>>   sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
>>   sunxi: add basical memory map definitions of H6 SoC
>>   sunxi: change RMR64's RVBAR address for H6
>>   sunxi: change ATF position for H6
>>   sunxi: add config for SPL at 0x20000 on H6
>>   sunxi: change GIC address on H6
>>   sunxi: add clock code for H6
>>   sunxi: use sun6i-style watchdog for H6
>>   sunxi: add UART0 setup for H6
>>   sunxi: add MMC support for H6
>>   sunxi: add DRAM support to H6
>>   sunxi: add support for Allwinner H6 SoC
>>   sunxi: add support for Pine H64 board
>
>is it on top of master? unable to apply for testing on master, point
>me the branch would help.

sunxi/next.

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

* [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC
  2018-06-25 12:33   ` Maxime Ripard
@ 2018-06-25 12:50     ` Icenowy Zheng
  2018-06-25 17:07       ` Maxime Ripard
  2018-06-26 10:35       ` [U-Boot] [linux-sunxi] " Andre Przywara
  0 siblings, 2 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-25 12:50 UTC (permalink / raw)
  To: u-boot



于 2018年6月25日 GMT+08:00 下午8:33:34, Maxime Ripard <maxime.ripard@bootlin.com> 写到:
>On Mon, Jun 25, 2018 at 06:37:12PM +0800, Icenowy Zheng wrote:
>> The Allwinner H6 SoC come with a totally new memory map.
>> 
>> Add basical definition of the new memory map into a header file, and
>let
>> the cpu.h header include it in the situation of H6.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>>  arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
>>  .../include/asm/arch-sunxi/cpu_sun50i_h6.h    | 73
>+++++++++++++++++++
>>  2 files changed, 75 insertions(+)
>>  create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>> 
>> diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h
>b/arch/arm/include/asm/arch-sunxi/cpu.h
>> index caec865264..08be963e8e 100644
>> --- a/arch/arm/include/asm/arch-sunxi/cpu.h
>> +++ b/arch/arm/include/asm/arch-sunxi/cpu.h
>> @@ -9,6 +9,8 @@
>>  
>>  #if defined(CONFIG_MACH_SUN9I)
>>  #include <asm/arch/cpu_sun9i.h>
>> +#elif defined(CONFIG_MACH_SUN50I_H6)
>> +#include <asm/arch/cpu_sun50i_h6.h>
>>  #else
>>  #include <asm/arch/cpu_sun4i.h>
>>  #endif
>> diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>> new file mode 100644
>> index 0000000000..b12f2dd1a2
>> --- /dev/null
>> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>> @@ -0,0 +1,73 @@
>> +/*
>> + * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * SPDX-License-Identifier:	GPL-2.0+
>> + */
>> +
>> +#ifndef _SUNXI_CPU_SUN50I_H6_H
>> +#define _SUNXI_CPU_SUN50I_H6_H
>> +
>> +#define SUNXI_SRAM_A1_BASE		0x00020000
>
>Isn't that the same thing than SUNXI_SRAM_ADDRESS? Having it defined
>twice and expecting the value to be matching seems a bit weird.

This assumes SPL will be in SRAM A1, which may change.

>
>Maxime

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

* [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL)
  2018-06-25 12:49   ` Icenowy Zheng
@ 2018-06-25 13:02     ` Jagan Teki
  2018-07-19 18:14       ` Jagan Teki
  0 siblings, 1 reply; 36+ messages in thread
From: Jagan Teki @ 2018-06-25 13:02 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 6:19 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>
>
> 于 2018年6月25日 GMT+08:00 下午8:40:21, Jagan Teki <jagan@amarulasolutions.com> 写到:
>>On Mon, Jun 25, 2018 at 4:07 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>>> This patch trys to add support for Allwinner H6 SoC to U-Boot.
>>>
>>> Allwinner H6 is a quite new Allwinner SoC, with several parts changed
>>a
>>> lot (memory map, DRAM controller, CCU, so on). The position which SPL
>>> will be loaded (SRAM A1) also changed to 0x20000.
>>>
>>> The Pine H64 board support comes with this patchset, as this is the
>>> first H6 board that I can get (being early bird).
>>>
>>> Icenowy Zheng (13):
>>>   sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
>>>   sunxi: add basical memory map definitions of H6 SoC
>>>   sunxi: change RMR64's RVBAR address for H6
>>>   sunxi: change ATF position for H6
>>>   sunxi: add config for SPL at 0x20000 on H6
>>>   sunxi: change GIC address on H6
>>>   sunxi: add clock code for H6
>>>   sunxi: use sun6i-style watchdog for H6
>>>   sunxi: add UART0 setup for H6
>>>   sunxi: add MMC support for H6
>>>   sunxi: add DRAM support to H6
>>>   sunxi: add support for Allwinner H6 SoC
>>>   sunxi: add support for Pine H64 board
>>
>>is it on top of master? unable to apply for testing on master, point
>>me the branch would help.
>
> sunxi/next.

please send it, on top of master

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

* [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC
  2018-06-25 12:50     ` Icenowy Zheng
@ 2018-06-25 17:07       ` Maxime Ripard
  2018-06-26 10:35       ` [U-Boot] [linux-sunxi] " Andre Przywara
  1 sibling, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2018-06-25 17:07 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 08:50:08PM +0800, Icenowy Zheng wrote:
> 
> 
> 于 2018年6月25日 GMT+08:00 下午8:33:34, Maxime Ripard <maxime.ripard@bootlin.com> 写到:
> >On Mon, Jun 25, 2018 at 06:37:12PM +0800, Icenowy Zheng wrote:
> >> The Allwinner H6 SoC come with a totally new memory map.
> >> 
> >> Add basical definition of the new memory map into a header file, and
> >let
> >> the cpu.h header include it in the situation of H6.
> >> 
> >> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> >> ---
> >>  arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
> >>  .../include/asm/arch-sunxi/cpu_sun50i_h6.h    | 73
> >+++++++++++++++++++
> >>  2 files changed, 75 insertions(+)
> >>  create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> >> 
> >> diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h
> >b/arch/arm/include/asm/arch-sunxi/cpu.h
> >> index caec865264..08be963e8e 100644
> >> --- a/arch/arm/include/asm/arch-sunxi/cpu.h
> >> +++ b/arch/arm/include/asm/arch-sunxi/cpu.h
> >> @@ -9,6 +9,8 @@
> >>  
> >>  #if defined(CONFIG_MACH_SUN9I)
> >>  #include <asm/arch/cpu_sun9i.h>
> >> +#elif defined(CONFIG_MACH_SUN50I_H6)
> >> +#include <asm/arch/cpu_sun50i_h6.h>
> >>  #else
> >>  #include <asm/arch/cpu_sun4i.h>
> >>  #endif
> >> diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> >b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> >> new file mode 100644
> >> index 0000000000..b12f2dd1a2
> >> --- /dev/null
> >> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> >> @@ -0,0 +1,73 @@
> >> +/*
> >> + * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
> >> + *
> >> + * SPDX-License-Identifier:	GPL-2.0+
> >> + */
> >> +
> >> +#ifndef _SUNXI_CPU_SUN50I_H6_H
> >> +#define _SUNXI_CPU_SUN50I_H6_H
> >> +
> >> +#define SUNXI_SRAM_A1_BASE		0x00020000
> >
> >Isn't that the same thing than SUNXI_SRAM_ADDRESS? Having it defined
> >twice and expecting the value to be matching seems a bit weird.
> 
> This assumes SPL will be in SRAM A1, which may change.

Then let's deal with this when it will change.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180625/a220f5ab/attachment.sig>

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

* [U-Boot] [linux-sunxi] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
  2018-06-25 10:37 ` [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS Icenowy Zheng
  2018-06-25 12:30   ` Maxime Ripard
@ 2018-06-26 10:34   ` Andre Przywara
  1 sibling, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 10:34 UTC (permalink / raw)
  To: u-boot

(resend from proper address)
Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> The new Allwinner H6 SoC has its SRAM A1 at neither 0x0 nor 0x10000, but
> it's at 0x20000. Thus the SUNXI_HIGH_SRAM option needs to be refactored
> to support this new configuration.
> 
> Change it to SUNXI_SRAM_ADDRESS, which holds the real address of SRAM
> A1 in the memory map.

Nice rework, thanks for that!

> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> ---
>  arch/arm/include/asm/arch-sunxi/spl.h |  6 +-----
>  arch/arm/mach-sunxi/Kconfig           | 14 +++++---------
>  include/configs/sunxi-common.h        | 19 +++++++++++--------
>  3 files changed, 17 insertions(+), 22 deletions(-)
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
> index a70b1797e5..e166568d11 100644
> --- a/arch/arm/include/asm/arch-sunxi/spl.h
> +++ b/arch/arm/include/asm/arch-sunxi/spl.h
> @@ -12,11 +12,7 @@
>  #define SPL_SIGNATURE		"SPL" /* marks "sunxi" SPL header */
>  #define SPL_HEADER_VERSION	2
>  
> -#ifdef CONFIG_SUNXI_HIGH_SRAM
> -#define SPL_ADDR		0x10000
> -#else
> -#define SPL_ADDR		0x0
> -#endif
> +#define SPL_ADDR		CONFIG_SUNXI_SRAM_ADDRESS
>  
>  /* The low 8-bits of the 'boot_media' field in the SPL header */
>  #define SUNXI_BOOTED_FROM_MMC0	0
> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
> index 0a7bd3086a..e3c19b7464 100644
> --- a/arch/arm/mach-sunxi/Kconfig
> +++ b/arch/arm/mach-sunxi/Kconfig
> @@ -73,16 +73,15 @@ config SUN8I_RSB
>  	  with various RSB based devices, such as AXP223, AXP8XX PMICs,
>  	  and AC100/AC200 ICs.
>  
> -config SUNXI_HIGH_SRAM
> -	bool
> -	default n
> +config SUNXI_SRAM_ADDRESS
> +	hex
> +	default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
> +	default 0x0
>  	---help---
>  	Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
>  	with the first SRAM region being located at address 0.
>  	Some newer SoCs map the boot ROM at address 0 instead and move the
> -	SRAM to 64KB, just behind the mask ROM.
> -	Chips using the latter setup are supposed to select this option to
> -	adjust the addresses accordingly.
> +	SRAM to a different address.
>  
>  # Note only one of these may be selected at a time! But hidden choices are
>  # not supported by Kconfig
> @@ -252,7 +251,6 @@ config MACH_SUN9I
>  	select CPU_V7
>  	select DRAM_SUN9I
>  	select SUN6I_PRCM
> -	select SUNXI_HIGH_SRAM
>  	select SUNXI_GEN_SUN6I
>  	select SUN8I_RSB
>  	select SUPPORT_SPL
> @@ -264,7 +262,6 @@ config MACH_SUN50I
>  	select PHY_SUN4I_USB
>  	select SUNXI_DE2
>  	select SUNXI_GEN_SUN6I
> -	select SUNXI_HIGH_SRAM
>  	select SUPPORT_SPL
>  	select SUNXI_DRAM_DW
>  	select SUNXI_DRAM_DW_32BIT
> @@ -275,7 +272,6 @@ config MACH_SUN50I_H5
>  	bool "sun50i (Allwinner H5)"
>  	select ARM64
>  	select MACH_SUNXI_H3_H5
> -	select SUNXI_HIGH_SRAM
>  	select FIT
>  	select SPL_LOAD_FIT
>  
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 9d9e9ce173..0196dd0431 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -83,20 +83,19 @@
>  
>  #define CONFIG_SPL_BSS_MAX_SIZE		0x00080000 /* 512 KiB */
>  
> -#ifdef CONFIG_SUNXI_HIGH_SRAM
>  /*
>   * The A80's A1 sram starts at 0x00010000 rather then at 0x00000000 and is
>   * slightly bigger. Note that it is possible to map the first 32 KiB of the
>   * A1 at 0x00000000 like with older SoCs by writing 0x16aa0001 to the
>   * undocumented 0x008000e0 SYS_CTRL register. Where the 16aa is a key and
>   * the 1 actually activates the mapping of the first 32 KiB to 0x00000000.
> + * A64 and H5 also has SRAM A1 at 0x00010000, but no magic remap register
> + * is known yet.
> + * H6 has SRAM A1 at 0x00020000.
>   */
> -#define CONFIG_SYS_INIT_RAM_ADDR	0x10000
> -#define CONFIG_SYS_INIT_RAM_SIZE	0x08000	/* FIXME: 40 KiB ? */
> -#else
> -#define CONFIG_SYS_INIT_RAM_ADDR	0x0
> -#define CONFIG_SYS_INIT_RAM_SIZE	0x8000	/* 32 KiB */
> -#endif
> +#define CONFIG_SYS_INIT_RAM_ADDR	CONFIG_SUNXI_SRAM_ADDRESS
> +/* FIXME: this may be larger on some SoCs */
> +#define CONFIG_SYS_INIT_RAM_SIZE	0x8000 /* 32 KiB */
>  
>  #define CONFIG_SYS_INIT_SP_OFFSET \
>  	(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
> @@ -188,7 +187,11 @@
>  #define CONFIG_SPL_BOARD_LOAD_IMAGE
>  #endif
>  
> -#ifdef CONFIG_SUNXI_HIGH_SRAM
> +/*
> + * We cannot use expressions here, because expressions won't be evaluated in
> + * autoconf.mk.
> + */
> +#if CONFIG_SUNXI_SRAM_ADDRESS == 0x10000
>  #define CONFIG_SPL_TEXT_BASE		0x10060		/* sram start+header */
>  #define CONFIG_SPL_MAX_SIZE		0x7fa0		/* 32 KiB */
>  #ifdef CONFIG_ARM64
> 

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

* [U-Boot] [linux-sunxi] Re: [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC
  2018-06-25 12:50     ` Icenowy Zheng
  2018-06-25 17:07       ` Maxime Ripard
@ 2018-06-26 10:35       ` Andre Przywara
  1 sibling, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 10:35 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 13:50, Icenowy Zheng wrote:
> 
> 
> 于 2018年6月25日 GMT+08:00 下午8:33:34, Maxime Ripard <maxime.ripard@bootlin.com> 写到:
>> On Mon, Jun 25, 2018 at 06:37:12PM +0800, Icenowy Zheng wrote:
>>> The Allwinner H6 SoC come with a totally new memory map.
>>>
>>> Add basical definition of the new memory map into a header file, and
>> let
>>> the cpu.h header include it in the situation of H6.
>>>
>>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>>> ---
>>>  arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
>>>  .../include/asm/arch-sunxi/cpu_sun50i_h6.h    | 73
>> +++++++++++++++++++
>>>  2 files changed, 75 insertions(+)
>>>  create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>>>
>>> diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h
>> b/arch/arm/include/asm/arch-sunxi/cpu.h
>>> index caec865264..08be963e8e 100644
>>> --- a/arch/arm/include/asm/arch-sunxi/cpu.h
>>> +++ b/arch/arm/include/asm/arch-sunxi/cpu.h
>>> @@ -9,6 +9,8 @@
>>>  
>>>  #if defined(CONFIG_MACH_SUN9I)
>>>  #include <asm/arch/cpu_sun9i.h>
>>> +#elif defined(CONFIG_MACH_SUN50I_H6)
>>> +#include <asm/arch/cpu_sun50i_h6.h>
>>>  #else
>>>  #include <asm/arch/cpu_sun4i.h>
>>>  #endif
>>> diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>> b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>>> new file mode 100644
>>> index 0000000000..b12f2dd1a2
>>> --- /dev/null
>>> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
>>> @@ -0,0 +1,73 @@
>>> +/*
>>> + * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
>>> + *
>>> + * SPDX-License-Identifier:	GPL-2.0+
>>> + */
>>> +
>>> +#ifndef _SUNXI_CPU_SUN50I_H6_H
>>> +#define _SUNXI_CPU_SUN50I_H6_H
>>> +
>>> +#define SUNXI_SRAM_A1_BASE		0x00020000
>>
>> Isn't that the same thing than SUNXI_SRAM_ADDRESS? Having it defined
>> twice and expecting the value to be matching seems a bit weird.
> 
> This assumes SPL will be in SRAM A1, which may change.

Can it? I believe this part is fixed, because this is where the BootROM
loads the initial code to. And for the boot flow we support the SPL is
the first one to execute. Not sure if a TPL would change that, but as
Maxime said, we can address that when we really need to.

I guess we can't use that symbol in Kconfig, can we? So that we could
say: "default SUNXI_SRAM_A1_BASE if MACH_SUN50I_H6" in patch 12/13 ...

Cheers,
Andre

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

* [U-Boot] [linux-sunxi] [PATCH 03/13] sunxi: change RMR64's RVBAR address for H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 03/13] sunxi: change RMR64's RVBAR address for H6 Icenowy Zheng
@ 2018-06-26 10:37   ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 10:37 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> Allwinner H6 has a different RVBAR address with A64/H5.
> 
> Add conditional RVBAR configuration into the code which does RMR switch.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

And thanks for amending the assembly stub too!

Cheers,
Andre.

> ---
>  arch/arm/include/asm/arch-sunxi/boot0.h | 4 ++++
>  arch/arm/mach-sunxi/rmr_switch.S        | 6 ++++++
>  2 files changed, 10 insertions(+)
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
> index 9c6d82dda1..5176fdcfdc 100644
> --- a/arch/arm/include/asm/arch-sunxi/boot0.h
> +++ b/arch/arm/include/asm/arch-sunxi/boot0.h
> @@ -27,7 +27,11 @@
>  	.word	0xf57ff06f	// isb     sy
>  	.word	0xe320f003	// wfi
>  	.word	0xeafffffd	// b       @wfi
> +#ifndef CONFIG_MACH_SUN50I_H6
>  	.word	0x017000a0	// writeable RVBAR mapping address
> +#else
> +	.word	0x09010040	// writeable RVBAR mapping address
> +#endif
>  #ifdef CONFIG_SPL_BUILD
>  	.word	CONFIG_SPL_TEXT_BASE
>  #else
> diff --git a/arch/arm/mach-sunxi/rmr_switch.S b/arch/arm/mach-sunxi/rmr_switch.S
> index cefa93001b..fafd306f95 100644
> --- a/arch/arm/mach-sunxi/rmr_switch.S
> +++ b/arch/arm/mach-sunxi/rmr_switch.S
> @@ -26,9 +26,15 @@
>  @ reference and to be able to regenerate a (probably fixed) version of this
>  @ code found in encoded form in boot0.h.
>  
> +#include <config.h>
> +
>  .text
>  
> +#ifndef CONFIG_MACH_SUN50I_H6
>  	ldr	r1, =0x017000a0		@ MMIO mapped RVBAR[0] register
> +#else
> +	ldr	r1, =0x09010040		@ MMIO mapped RVBAR[0] register
> +#endif
>  	ldr	r0, =0x57aA7add		@ start address, to be replaced
>  	str	r0, [r1]
>  	dsb	sy
> 

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

* [U-Boot] [linux-sunxi] [PATCH 04/13] sunxi: change ATF position for H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 04/13] sunxi: change ATF position " Icenowy Zheng
@ 2018-06-26 10:56   ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 10:56 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> H6 has different SRAM A2 address, so the ATF load address is also
> different.
> 
> Add judgment code to sunxi 64-bit FIT generation script. It will judge
> the SoC by the device tree's name.

Mmh, would it be better to check for some config symbol to derive the
ATF load address?
Like:
if grep -q "^CONFIG_MACH_SUN50I_H6=y" .config; then
...

Relying on a certain wording of the *first* .dtb name sounds a bit more
fragile.

Or maybe we could even have an explicit config symbol, which is just
used by that script?

BL31_ADDR=$(grep "^CONFIG_ATF_LOAD_ADDR=" .config | cut -d= -f2)

Cheers,
Andre.

> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  board/sunxi/mksunxi_fit_atf.sh | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/board/sunxi/mksunxi_fit_atf.sh b/board/sunxi/mksunxi_fit_atf.sh
> index 36abe9efed..8540c3d88e 100755
> --- a/board/sunxi/mksunxi_fit_atf.sh
> +++ b/board/sunxi/mksunxi_fit_atf.sh
> @@ -13,6 +13,12 @@ if [ ! -f $BL31 ]; then
>  	BL31=/dev/null
>  fi
>  
> +if [ "$(basename $1 .dtb | cut -d - -f 1-2)" = "sun50i-h6" ]; then
> +	BL31_ADDR=0x104000
> +else
> +	BL31_ADDR=0x44000
> +fi
> +
>  cat << __HEADER_EOF
>  /dts-v1/;
>  
> @@ -35,8 +41,8 @@ cat << __HEADER_EOF
>  			type = "firmware";
>  			arch = "arm64";
>  			compression = "none";
> -			load = <0x44000>;
> -			entry = <0x44000>;
> +			load = <$BL31_ADDR>;
> +			entry = <$BL31_ADDR>;
>  		};
>  __HEADER_EOF
>  
> 

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

* [U-Boot] [linux-sunxi] [PATCH 05/13] sunxi: add config for SPL at 0x20000 on H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 05/13] sunxi: add config for SPL at 0x20000 on H6 Icenowy Zheng
@ 2018-06-26 10:56   ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 10:56 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> On the new Allwinner H6 SoC, the SRAM A2 address (SPL load address) is
> at 0x20000, which is different with any old Allwinner SoCs.
> 
> Add SPL position and size configuration for this.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre

> ---
>  include/configs/sunxi-common.h | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 0196dd0431..9e1c5fb2a6 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -200,6 +200,11 @@
>  #else
>  #define LOW_LEVEL_SRAM_STACK		0x00018000
>  #endif /* !CONFIG_ARM64 */
> +#elif CONFIG_SUNXI_SRAM_ADDRESS == 0x20000
> +#define CONFIG_SPL_TEXT_BASE		0x20060		/* sram start+header */
> +#define CONFIG_SPL_MAX_SIZE		0x7fa0		/* 32 KiB */
> +/* end of SRAM A2 on H6 for now */
> +#define LOW_LEVEL_SRAM_STACK		0x00118000
>  #else
>  #define CONFIG_SPL_TEXT_BASE		0x60		/* sram start+header */
>  #define CONFIG_SPL_MAX_SIZE		0x5fa0		/* 24KB on sun4i/sun7i */
> 

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

* [U-Boot] [linux-sunxi] [PATCH 06/13] sunxi: change GIC address on H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 06/13] sunxi: change GIC address " Icenowy Zheng
@ 2018-06-26 10:56   ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 10:56 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> As the Allwinner H6 chip has a new memory map, its GIC MMIO address is
> thus different.
> 
> Change the address on H6.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> ---
>  include/configs/sun50i.h | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/include/configs/sun50i.h b/include/configs/sun50i.h
> index b7b67a1ddc..1b3e84c4e9 100644
> --- a/include/configs/sun50i.h
> +++ b/include/configs/sun50i.h
> @@ -18,8 +18,13 @@
>  
>  #define CONFIG_SUNXI_USB_PHYS	1
>  
> +#ifndef CONFIG_MACH_SUN50I_H6
>  #define GICD_BASE		0x1c81000
>  #define GICC_BASE		0x1c82000
> +#else
> +#define GICD_BASE		0x3021000
> +#define GICC_BASE		0x3022000
> +#endif
>  
>  /*
>   * Include common sunxi configuration where most the settings are
> 

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

* [U-Boot] [linux-sunxi] [PATCH 09/13] sunxi: add UART0 setup for H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 09/13] sunxi: add UART0 setup " Icenowy Zheng
@ 2018-06-26 11:01   ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 11:01 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> The UART0 on H6 is available at PH bank (and PF bank, but the PF one is
> muxed with SD card).
> 
> Add pinmux configuration.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

> ---
>  arch/arm/include/asm/arch-sunxi/gpio.h | 1 +
>  arch/arm/mach-sunxi/board.c            | 4 ++++
>  2 files changed, 5 insertions(+)
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
> index 24f85206c8..5acc3033f5 100644
> --- a/arch/arm/include/asm/arch-sunxi/gpio.h
> +++ b/arch/arm/include/asm/arch-sunxi/gpio.h
> @@ -198,6 +198,7 @@ enum sunxi_gpio_number {
>  #define SUN6I_GPH_TWI2		2
>  #define SUN6I_GPH_UART0		2
>  #define SUN9I_GPH_UART0		2
> +#define SUN50I_H6_GPH_UART0	2
>  
>  #define SUNXI_GPI_SDC3		2
>  #define SUN7I_GPI_TWI3		3
> diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
> index 8105a7dbfc..b04a005efc 100644
> --- a/arch/arm/mach-sunxi/board.c
> +++ b/arch/arm/mach-sunxi/board.c
> @@ -108,6 +108,10 @@ static int gpio_init(void)
>  	sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN50I_GPB_UART0);
>  	sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_GPB_UART0);
>  	sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP);
> +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I_H6)
> +	sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H6_GPH_UART0);
> +	sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H6_GPH_UART0);
> +	sunxi_gpio_set_pull(SUNXI_GPH(1), 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);
> 

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

* [U-Boot] [linux-sunxi] [PATCH 07/13] sunxi: add clock code for H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 07/13] sunxi: add clock code for H6 Icenowy Zheng
@ 2018-06-26 13:04   ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-26 13:04 UTC (permalink / raw)
  To: u-boot

Hi,

I will compare the code against the manual later, just one thing that
popped up:

On 25/06/18 11:37, Icenowy Zheng wrote:
> The new Allwinner H6 SoC has a brand new CCU layout.
> 
> Add clock code for it.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  arch/arm/include/asm/arch-sunxi/clock.h       |   2 +
>  .../include/asm/arch-sunxi/clock_sun50i_h6.h  | 320 ++++++++++++++++++
>  arch/arm/mach-sunxi/Makefile                  |   1 +
>  arch/arm/mach-sunxi/clock_sun50i_h6.c         |  94 +++++
>  4 files changed, 417 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
>  create mode 100644 arch/arm/mach-sunxi/clock_sun50i_h6.c
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
> new file mode 100644
> index 0000000000..e36937059b
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
> @@ -0,0 +1,320 @@

...

> +unsigned int clock_get_pll6(void)
> +{
> +	struct sunxi_ccm_reg *const ccm =
> +		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +
> +	uint32_t rval = readl(&ccm->pll6_cfg);
> +	int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT);
> +	int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
> +			CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
> +	int div2 = ((rval & CCM_PLL6_CTRL_DIV2_MASK) >>
> +			CCM_PLL6_CTRL_DIV2_SHIFT) + 1;
> +	/* The register defines PLL6-4X, not plain PLL6 */
> +	return 24000000 * n / div1 / div2 / 4;

I understand that this is copied from the other SoC's clock drivers, but
the return line looks prone to overflows:
If n > 178, then the result will be wrong.
We probably won't go that high, but this can be easily fixed by moving
the "/ 4" upfront, right after the 24000000.

Cheers,
Andre.

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

* [U-Boot] [linux-sunxi] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC
  2018-06-25 10:37 ` [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC Icenowy Zheng
  2018-06-25 12:33   ` Maxime Ripard
@ 2018-06-27  8:51   ` Andre Przywara
  1 sibling, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-27  8:51 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> The Allwinner H6 SoC come with a totally new memory map.
> 
> Add basical definition of the new memory map into a header file, and let
> the cpu.h header include it in the situation of H6.

I checked all addresses against the manual and found no issues.

> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!
Andre

P.S. I don't believe "basical" is an English word, it's just "basic".

> ---
>  arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
>  .../include/asm/arch-sunxi/cpu_sun50i_h6.h    | 73 +++++++++++++++++++
>  2 files changed, 75 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
> index caec865264..08be963e8e 100644
> --- a/arch/arm/include/asm/arch-sunxi/cpu.h
> +++ b/arch/arm/include/asm/arch-sunxi/cpu.h
> @@ -9,6 +9,8 @@
>  
>  #if defined(CONFIG_MACH_SUN9I)
>  #include <asm/arch/cpu_sun9i.h>
> +#elif defined(CONFIG_MACH_SUN50I_H6)
> +#include <asm/arch/cpu_sun50i_h6.h>
>  #else
>  #include <asm/arch/cpu_sun4i.h>
>  #endif
> diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> new file mode 100644
> index 0000000000..b12f2dd1a2
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> @@ -0,0 +1,73 @@
> +/*
> + * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _SUNXI_CPU_SUN50I_H6_H
> +#define _SUNXI_CPU_SUN50I_H6_H
> +
> +#define SUNXI_SRAM_A1_BASE		0x00020000
> +#define SUNXI_SRAM_C_BASE		0x00028000
> +#define SUNXI_SRAM_A2_BASE		0x00100000
> +
> +#define SUNXI_DE3_BASE			0x01000000
> +#define SUNXI_SS_BASE			0x01904000
> +#define SUNXI_EMCE_BASE			0x01905000
> +
> +#define SUNXI_SRAMC_BASE		0x03000000
> +#define SUNXI_CCM_BASE			0x03001000
> +#define SUNXI_DMA_BASE			0x03002000
> +/* SID address space starts at 0x03006000, but e-fuse is at offset 0x200 */
> +#define SUNXI_SIDC_BASE			0x03006000
> +#define SNUXI_SID_BASE			0x03006200
> +#define SUNXI_TIMER_BASE		0x03009000
> +#define SUNXI_PIO_BASE			0x0300B000
> +#define SUNXI_PSI_BASE			0x0300C000
> +
> +#define SUNXI_GIC400_BASE		0x03020000
> +#define SUNXI_IOMMU_BASE		0x030F0000
> +
> +#define SUNXI_DRAM_COM_BASE		0x04002000
> +#define SUNXI_DRAM_CTL0_BASE		0x04003000
> +#define SUNXI_DRAM_PHY0_BASE		0x04005000
> +#define SUNXI_NFC_BASE			0x04011000
> +#define SUNXI_MMC0_BASE			0x04020000
> +#define SUNXI_MMC1_BASE			0x04021000
> +#define SUNXI_MMC2_BASE			0x04022000
> +
> +#define SUNXI_UART0_BASE		0x05000000
> +#define SUNXI_UART1_BASE		0x05000400
> +#define SUNXI_UART2_BASE		0x05000800
> +#define SUNXI_UART3_BASE		0x05000C00
> +#define SUNXI_TWI0_BASE			0x05002000
> +#define SUNXI_TWI1_BASE			0x05002400
> +#define SUNXI_TWI2_BASE			0x05002800
> +#define SUNXI_TWI3_BASE			0x05002C00
> +#define SUNXI_SPI0_BASE			0x05010000
> +#define SUNXI_SPI1_BASE			0x05011000
> +#define SUNXI_GMAC_BASE			0x05020000
> +#define SUNXI_USB0_BASE			0x05100000
> +#define SUNXI_XHCI_BASE			0x05200000
> +#define SUNXI_USB3_BASE			0x05311000
> +#define SUNXI_PCIE_BASE			0x05400000
> +
> +#define SUNXI_HDMI_BASE			0x06000000
> +#define SUNXI_TCON_TOP_BASE		0x06510000
> +#define SUNXI_TCON_LCD0_BASE		0x06511000
> +#define SUNXI_TCON_TV0_BASE		0x06515000
> +
> +#define SUNXI_RTC_BASE			0x07000000
> +#define SUNXI_R_CPUCFG_BASE		0x07000400
> +#define SUNXI_PRCM_BASE			0x07010000
> +#define SUNXI_R_PIO_BASE		0x07022000
> +#define SUNXI_R_UART_BASE		0x07080000
> +#define SUNXI_R_TWI_BASE		0x07081400
> +
> +#ifndef __ASSEMBLY__
> +void sunxi_board_init(void);
> +void sunxi_reset(void);
> +int sunxi_get_sid(unsigned int *sid);
> +#endif
> +
> +#endif /* _SUNXI_CPU_SUN9I_H */
> 

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

* [U-Boot] [linux-sunxi] [PATCH 11/13] sunxi: add DRAM support to H6
  2018-06-25 10:37 ` [U-Boot] [PATCH 11/13] sunxi: add DRAM support to H6 Icenowy Zheng
@ 2018-06-27  9:46   ` Andre Przywara
  2018-06-27 10:49     ` Icenowy Zheng
  0 siblings, 1 reply; 36+ messages in thread
From: Andre Przywara @ 2018-06-27  9:46 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> The Allwinner H6 SoC comes with a set of new DRAM controller+PHY combo.
> Both the controller and the PHY seem to be originate from DesignWare,
> and are similar to the ones in ZynqMP SoCs.
> 
> This commit introduces an initial DRAM driver for H6, which contains
> only LPDDR3 support. The currently known SBCs with H6 all come with
> LPDDR3 memory, including Pine H64 and several Orange Pi's.
> 
> The BSP DRAM initialization code is closed source and violates GPL. Code
> in this commit is written by experimenting, referring the code/document
> of other users of the IPs (mainly the ZynqMP, as it's the only found PHY
> reference) and disassebling the BSP blob.
> 
> Thanks for Jernej Skrabec for review and fix some issues in this driver
> (including the most critical one which made it to work), and rewrite
> some code from register dump!

It seems that you guys really spent a lot of time and work into this,
thanks a lot for that!
Just skimming over the code, that looks vaguely similar to the existing
dram_sunxi_dw.c driver. I guess you considered and dismissed that idea
already, but can you briefly comment on how much effort it would be to
integrate H6 support into that driver?
I guess it would be beneficial for all SoCs to have one driver to rule
them all.

Cheers,
Andre.

> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
>  .../include/asm/arch-sunxi/dram_sun50i_h6.h   | 276 +++++++
>  arch/arm/mach-sunxi/Kconfig                   |   6 +
>  arch/arm/mach-sunxi/Makefile                  |   1 +
>  arch/arm/mach-sunxi/dram_sun50i_h6.c          | 708 ++++++++++++++++++
>  5 files changed, 993 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
>  create mode 100644 arch/arm/mach-sunxi/dram_sun50i_h6.c
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
> index 80abac95b8..cc11fca8ef 100644
> --- a/arch/arm/include/asm/arch-sunxi/dram.h
> +++ b/arch/arm/include/asm/arch-sunxi/dram.h
> @@ -28,6 +28,8 @@
>  #include <asm/arch/dram_sunxi_dw.h>
>  #elif defined(CONFIG_MACH_SUN9I)
>  #include <asm/arch/dram_sun9i.h>
> +#elif defined(CONFIG_MACH_SUN50I_H6)
> +#include <asm/arch/dram_sun50i_h6.h>
>  #else
>  #include <asm/arch/dram_sun4i.h>
>  #endif
> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
> new file mode 100644
> index 0000000000..fe138b8cc0
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
> @@ -0,0 +1,276 @@
> +/*
> + * H6 dram controller register and constant defines
> + *
> + * (C) Copyright 2017  Icenowy Zheng <icenowy@aosc.io>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _SUNXI_DRAM_SUN50I_H6_H
> +#define _SUNXI_DRAM_SUN50I_H6_H
> +
> +enum sunxi_dram_type {
> +	SUNXI_DRAM_TYPE_DDR3 = 3,
> +	SUNXI_DRAM_TYPE_DDR4,
> +	SUNXI_DRAM_TYPE_LPDDR2 = 6,
> +	SUNXI_DRAM_TYPE_LPDDR3,
> +};
> +
> +/*
> + * The following information is mainly retrieved by disassembly and some FPGA
> + * test code of sun50iw3 platform.
> + */
> +struct sunxi_mctl_com_reg {
> +	u32 cr;			/* 0x000 control register */
> +	u8 reserved_0x004[4];	/* 0x004 */
> +	u32 unk_0x008;		/* 0x008 */
> +	u32 tmr;		/* 0x00c timer register */
> +	u8 reserved_0x010[4];	/* 0x010 */
> +	u32 unk_0x014;		/* 0x014 */
> +	u8 reserved_0x018[8];	/* 0x018 */
> +	u32 maer0;		/* 0x020 master enable register 0 */
> +	u32 maer1;		/* 0x024 master enable register 1 */
> +	u32 maer2;		/* 0x028 master enable register 2 */
> +	u8 reserved_0x02c[468];	/* 0x02c */
> +	u32 bwcr;		/* 0x200 bandwidth control register */
> +	u8 reserved_0x204[12];	/* 0x204 */
> +	/*
> +	 * The last master configured by BSP libdram is at 0x49x, so the
> +	 * size of this struct array is set to 41 (0x29) now.
> +	 */
> +	struct {
> +		u32 cfg0;		/* 0x0 */
> +		u32 cfg1;		/* 0x4 */
> +		u8 reserved_0x8[8];	/* 0x8 */
> +	} master[41];		/* 0x210 + index * 0x10 */
> +};
> +check_member(sunxi_mctl_com_reg, master[40].reserved_0x8, 0x498);
> +
> +/*
> + * The following register information are retrieved from some similar DRAM
> + * controllers, including the DRAM controllers in Allwinner A23/A80 SoCs,
> + * Rockchip RK3328 SoC, NXP i.MX7 SoCs and Xilinx Zynq UltraScale+ SoCs.
> + *
> + * The DRAM controller in Allwinner A23/A80 SoCs and NXP i.MX7 SoCs seems
> + * to be older than the one in Allwinner H6, as the DRAMTMG9 register
> + * is missing in these SoCs. (From the product specifications of these
> + * SoCs they're not capable of DDR4)
> + *
> + * Information sources:
> + * - dram_sun9i.h and dram_sun8i_a23.h in the same directory.
> + * - sdram_rk3328.h from the RK3328 TPL DRAM patchset
> + * - i.MX 7Solo Applications Processor Reference Manual (IMX7SRM)
> + * - Zynq UltraScale+ MPSoC Register Reference (UG1087)
> + */
> +struct sunxi_mctl_ctl_reg {
> +	u32 mstr;		/* 0x000 */
> +	u32 statr;		/* 0x004 unused */
> +	u32 mstr1;		/* 0x008 unused */
> +	u32 unk_0x00c;		/* 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 unused */
> +	u32 pwrtmg;		/* 0x034 unused */
> +	u32 hwlpctl;		/* 0x038 unused */
> +	u8 reserved_0x03c[20];	/* 0x03c */
> +	u32 rfshctl0;		/* 0x050 unused */
> +	u32 rfshctl1;		/* 0x054 unused */
> +	u8 reserved_0x058[8];	/* 0x05c */
> +	u32 rfshctl3;		/* 0x060 */
> +	u32 rfshtmg;		/* 0x064 */
> +	u8 reserved_0x068[104];	/* 0x068 reserved for ECC&CRC (from ZynqMP) */
> +	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, may not exist */
> +	u8 reserved_0x1b8[8];	/* 0x1b8 */
> +	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[180];	/* 0x258 */
> +	u32 dbgcmd;		/* 0x30c unused */
> +	u32 dbgstat;		/* 0x310 unused */
> +	u8 reserved_0x314[12];	/* 0x314 */
> +	u32 swctl;		/* 0x320 */
> +	u32 swstat;		/* 0x324 */
> +};
> +check_member(sunxi_mctl_ctl_reg, swstat, 0x324);
> +
> +#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_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)
> +
> +/*
> + * The following register information is based on Zynq UltraScale+
> + * MPSoC Register Reference, as it's the currently only known
> + * DDR PHY similar to the one used in H6; however although the
> + * map is similar, the bit fields definitions are different.
> + *
> + * Other DesignWare DDR PHY's have similar register names, but the
> + * offset and definitions are both different.
> + */
> +struct sunxi_mctl_phy_reg {
> +	u32 ver;		/* 0x000 guess based on similar PHYs */
> +	u32 pir;		/* 0x004 */
> +	u8 reserved_0x008[8];	/* 0x008 */
> +	/*
> +	 * The ZynqMP manual didn't document PGCR1, however this register
> +	 * exists on H6 and referenced by libdram.
> +	 */
> +	u32 pgcr[8];		/* 0x010 */
> +	/*
> +	 * By comparing the hardware and the ZynqMP manual, the PGSR seems
> +	 * to start at 0x34 on H6.
> +	 */
> +	u8 reserved_0x030[4];	/* 0x030 */
> +	u32 pgsr[3];		/* 0x034 */
> +	u32 ptr[7];		/* 0x040 */
> +	/*
> +	 * According to ZynqMP reference there's PLLCR0~6 in this area,
> +	 * but they're tagged "Type B PLL Only" and H6 seems to have
> +	 * no them.
> +	 * 0x080 is not present in ZynqMP reference but it seems to be
> +	 * present on H6.
> +	 */
> +	u8 reserved_0x05c[36];	/* 0x05c */
> +	u32 unk_0x080;		/* 0x080 */
> +	u8 reserved_0x084[4];	/* 0x084 */
> +	u32 dxccr;		/* 0x088 */
> +	u8 reserved_0x08c[4];	/* 0x08c */
> +	u32 dsgcr;		/* 0x090 */
> +	u8 reserved_0x094[4];	/* 0x094 */
> +	u32 odtcr;		/* 0x098 */
> +	u8 reserved_0x09c[4];	/* 0x09c */
> +	u32 aacr;		/* 0x0a0 */
> +	u8 reserved_0x0a4[32];	/* 0x0a4 */
> +	u32 gpr1;		/* 0x0c4 */
> +	u8 reserved_0x0c8[56];	/* 0x0c8 */
> +	u32 dcr;		/* 0x100 */
> +	u8 reserved_0x104[12];	/* 0x104 */
> +	u32 dtpr[7];		/* 0x110 */
> +	u8 reserved_0x12c[20];	/* 0x12c */
> +	u32 rdimmgcr[3];	/* 0x140 */
> +	u8 reserved_0x14c[4];	/* 0x14c */
> +	u32 rdimmcr[5];		/* 0x150 */
> +	u8 reserved_0x164[4];	/* 0x164 */
> +	u32 schcr[2];		/* 0x168 */
> +	u8 reserved_0x170[16];	/* 0x170 */
> +	/*
> +	 * The ZynqMP manual documents MR0~7, 11~14 and 22.
> +	 */
> +	u32 mr[23];		/* 0x180 */
> +	u8 reserved_0x1dc[36];	/* 0x1dc */
> +	u32 dtcr[2];		/* 0x200 */
> +	u32 dtar[3];		/* 0x208 */
> +	u8 reserved_0x214[4];	/* 0x214 */
> +	u32 dtdr[2];		/* 0x218 */
> +	u8 reserved_0x220[16];	/* 0x220 */
> +	u32 dtedr0;		/* 0x230 */
> +	u32 dtedr1;		/* 0x234 */
> +	u32 dtedr2;		/* 0x238 */
> +	u32 vtdr;		/* 0x23c */
> +	u32 catr[2];		/* 0x240 */
> +	u8 reserved_0x248[8];
> +	u32 dqsdr[3];		/* 0x250 */
> +	u32 dtedr3;		/* 0x25c */
> +	u8 reserved_0x260[160];	/* 0x260 */
> +	u32 dcuar;		/* 0x300 */
> +	u32 dcudr;		/* 0x304 */
> +	u32 dcurr;		/* 0x308 */
> +	u32 dculr;		/* 0x30c */
> +	u32 dcugcr;		/* 0x310 */
> +	u32 dcutpr;		/* 0x314 */
> +	u32 dcusr[2];		/* 0x318 */
> +	u8 reserved_0x320[444];	/* 0x320 */
> +	u32 rankidr;		/* 0x4dc */
> +	u32 riocr[6];		/* 0x4e0 */
> +	u8 reserved_0x4f8[8];	/* 0x4f8 */
> +	u32 aciocr[6];		/* 0x500 */
> +	u8 reserved_0x518[8];	/* 0x518 */
> +	u32 iovcr[2];		/* 0x520 */
> +	u32 vtcr[2];		/* 0x528 */
> +	u8 reserved_0x530[16];	/* 0x530 */
> +	u32 acbdlr[17];		/* 0x540 */
> +	u32 aclcdlr;		/* 0x584 */
> +	u8 reserved_0x588[24];	/* 0x588 */
> +	u32 acmdlr[2];		/* 0x5a0 */
> +	u8 reserved_0x5a8[216];	/* 0x5a8 */
> +	struct {
> +		u32 zqcr;	/* 0x00 only the first one valid */
> +		u32 zqpr[2];	/* 0x04 */
> +		u32 zqdr[2];	/* 0x0c */
> +		u32 zqor[2];	/* 0x14 */
> +		u32 zqsr;	/* 0x1c */
> +	} zq[2];		/* 0x680, 0x6a0 */
> +	u8 reserved_0x6c0[64];	/* 0x6c0 */
> +	struct {
> +		u32 gcr[7];		/* 0x00 */
> +		u8 reserved_0x1c[36];	/* 0x1c */
> +		u32 bdlr0;		/* 0x40 */
> +		u32 bdlr1;		/* 0x44 */
> +		u32 bdlr2;		/* 0x48 */
> +		u8 reserved_0x4c[4];	/* 0x4c */
> +		u32 bdlr3;		/* 0x50 */
> +		u32 bdlr4;		/* 0x54 */
> +		u32 bdlr5;		/* 0x58 */
> +		u8 reserved_0x5c[4];	/* 0x5c */
> +		u32 bdlr6;		/* 0x60 */
> +		u8 reserved_0x64[28];	/* 0x64 */
> +		u32 lcdlr[6];		/* 0x80 */
> +		u8 reserved_0x98[8];	/* 0x98 */
> +		u32 mdlr[2];		/* 0xa0 */
> +		u8 reserved_0xa8[24];	/* 0xa8 */
> +		u32 gtr0;		/* 0xc0 */
> +		u8 reserved_0xc4[12];	/* 0xc4 */
> +		/*
> +		 * DXnRSR0 is not documented in ZynqMP manual but
> +		 * it's used in libdram.
> +		 */
> +		u32 rsr[4];		/* 0xd0 */
> +		u32 gsr[4];		/* 0xe0 */
> +		u8 reserved_0xf0[16];	/* 0xf0 */
> +	} dx[4];		/* 0x700, 0x800, 0x900, 0xa00 */
> +};
> +check_member(sunxi_mctl_phy_reg, dx[3].reserved_0xf0, 0xaf0);
> +
> +#define DCR_LPDDR3	(1 << 0)
> +#define DCR_DDR3	(3 << 0)
> +#define DCR_DDR4	(4 << 0)
> +#define DCR_DDR8BANK	BIT(3)
> +
> +static inline int ns_to_t(int nanoseconds)
> +{
> +	const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
> +
> +	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
> +}
> +
> +#endif /* _SUNXI_DRAM_SUN50I_H6_H */
> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
> index e3c19b7464..c2fa0533e7 100644
> --- a/arch/arm/mach-sunxi/Kconfig
> +++ b/arch/arm/mach-sunxi/Kconfig
> @@ -42,6 +42,12 @@ config DRAM_SUN9I
>  	  Select this dram controller driver for Sun9i platforms,
>  	  like A80.
>  
> +config DRAM_SUN50I_H6
> +	bool
> +	help
> +	  Select this dram controller driver for some sun50i platforms,
> +	  like H6.
> +
>  config SUN6I_P2WI
>  	bool "Allwinner sun6i internal P2WI controller"
>  	help
> diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
> index bafeb59d64..a00d4b335d 100644
> --- a/arch/arm/mach-sunxi/Makefile
> +++ b/arch/arm/mach-sunxi/Makefile
> @@ -40,4 +40,5 @@ obj-$(CONFIG_DRAM_SUN9I)	+= dram_sun9i.o
>  obj-$(CONFIG_SPL_SPI_SUNXI)	+= spl_spi_sunxi.o
>  obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_sunxi_dw.o
>  obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_timings/
> +obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_sun50i_h6.o
>  endif
> diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c
> new file mode 100644
> index 0000000000..c7c4ea9ba7
> --- /dev/null
> +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
> @@ -0,0 +1,708 @@
> +/*
> + * sun50i H6 platform dram controller init
> + *
> + * (C) Copyright 2017      Icenowy Zheng <icenowy@aosc.io>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/dram.h>
> +#include <asm/arch/cpu.h>
> +#include <linux/bitops.h>
> +#include <linux/kconfig.h>
> +
> +/*
> + * The delay parameters below allow to allegedly specify delay times of some
> + * unknown unit for each individual bit trace in each of the four data bytes
> + * the 32-bit wide access consists of. Also three control signals can be
> + * adjusted individually.
> + */
> +#define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
> +/* The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable and DQSN */
> +#define WR_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 4)
> +/*
> + * The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable, DQSN,
> + * Termination and Power down
> + */
> +#define RD_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 6)
> +struct dram_para {
> +	u32 clk;
> +	enum sunxi_dram_type type;
> +	u8 cols;
> +	u8 rows;
> +	u8 ranks;
> +	const u8 dx_read_delays[NR_OF_BYTE_LANES][RD_LINES_PER_BYTE_LANE];
> +	const u8 dx_write_delays[NR_OF_BYTE_LANES][WR_LINES_PER_BYTE_LANE];
> +};
> +
> +static void mctl_sys_init(struct dram_para *para);
> +static void mctl_com_init(struct dram_para *para);
> +static void mctl_set_timing_lpddr3(struct dram_para *para);
> +static void mctl_channel_init(struct dram_para *para);
> +
> +static void mctl_core_init(struct dram_para *para)
> +{
> +	mctl_sys_init(para);
> +	mctl_com_init(para);
> +	switch (para->type) {
> +	case SUNXI_DRAM_TYPE_LPDDR3:
> +		mctl_set_timing_lpddr3(para);
> +		break;
> +	default:
> +		panic("Unsupported DRAM type!");
> +	};
> +	mctl_channel_init(para);
> +}
> +
> +static void mctl_phy_pir_init(u32 val)
> +{
> +	struct sunxi_mctl_phy_reg * const mctl_phy =
> +			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +
> +	writel(val | BIT(0), &mctl_phy->pir);
> +	mctl_await_completion(&mctl_phy->pgsr[0], BIT(0), BIT(0));
> +}
> +
> +enum {
> +	MBUS_PORT_CPU           = 0,
> +	MBUS_PORT_GPU           = 1,
> +	MBUS_PORT_MAHB          = 2,
> +	MBUS_PORT_DMA           = 3,
> +	MBUS_PORT_VE            = 4,
> +	MBUS_PORT_CE            = 5,
> +	MBUS_PORT_TSC0          = 6,
> +	MBUS_PORT_NDFC0         = 8,
> +	MBUS_PORT_CSI0          = 11,
> +	MBUS_PORT_DI0           = 14,
> +	MBUS_PORT_DI1           = 15,
> +	MBUS_PORT_DE300         = 16,
> +	MBUS_PORT_IOMMU         = 25,
> +	MBUS_PORT_VE2           = 26,
> +	MBUS_PORT_USB3        = 37,
> +	MBUS_PORT_PCIE          = 38,
> +	MBUS_PORT_VP9           = 39,
> +	MBUS_PORT_HDCP2       = 40,
> +};
> +
> +enum {
> +	MBUS_QOS_LOWEST = 0,
> +	MBUS_QOS_LOW,
> +	MBUS_QOS_HIGH,
> +	MBUS_QOS_HIGHEST
> +};
> +inline void mbus_configure_port(u8 port,
> +				bool bwlimit,
> +				bool priority,
> +				u8 qos,
> +				u8 waittime,
> +				u8 acs,
> +				u16 bwl0,
> +				u16 bwl1,
> +				u16 bwl2)
> +{
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +
> +	const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
> +			   | (priority ? (1 << 1) : 0)
> +			   | ((qos & 0x3) << 2)
> +			   | ((waittime & 0xf) << 4)
> +			   | ((acs & 0xff) << 8)
> +			   | (bwl0 << 16) );
> +	const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
> +
> +	debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
> +	writel(cfg0, &mctl_com->master[port].cfg0);
> +	writel(cfg1, &mctl_com->master[port].cfg1);
> +}
> +
> +#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)	\
> +	mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
> +			    MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
> +
> +static void mctl_set_master_priority(void)
> +{
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +
> +	/* enable bandwidth limit windows and set windows size 1us */
> +	writel(399, &mctl_com->tmr);
> +	writel(BIT(16), &mctl_com->bwcr);
> +
> +	MBUS_CONF(  CPU,  true, HIGHEST, 0,  256,  128,  100);
> +	MBUS_CONF(  GPU,  true,    HIGH, 0, 1536, 1400,  256);
> +	MBUS_CONF( MAHB,  true, HIGHEST, 0,  512,  256,   96);
> +	MBUS_CONF(  DMA,  true,    HIGH, 0,  256,  100,   80);
> +	MBUS_CONF(   VE,  true,    HIGH, 2, 8192, 5500, 5000);
> +	MBUS_CONF(   CE,  true,    HIGH, 2,  100,   64,   32);
> +	MBUS_CONF( TSC0,  true,    HIGH, 2,  100,   64,   32);
> +	MBUS_CONF(NDFC0,  true,    HIGH, 0,  256,  128,   64);
> +	MBUS_CONF( CSI0,  true,    HIGH, 0,  256,  128,  100);
> +	MBUS_CONF(  DI0,  true,    HIGH, 0, 1024,  256,   64);
> +	MBUS_CONF(DE300,  true, HIGHEST, 6, 8192, 2800, 2400);
> +	MBUS_CONF(IOMMU,  true, HIGHEST, 0,  100,   64,   32);
> +	MBUS_CONF(  VE2,  true,    HIGH, 2, 8192, 5500, 5000);
> +	MBUS_CONF( USB3,  true,    HIGH, 0,  256,  128,   64);
> +	MBUS_CONF( PCIE,  true,    HIGH, 2,  100,   64,   32);
> +	MBUS_CONF(  VP9,  true,    HIGH, 2, 8192, 5500, 5000);
> +	MBUS_CONF(HDCP2,  true,    HIGH, 2,  100,   64,   32);
> +}
> +
> +static u32 mr_lpddr3[12] = {
> +	0x00000000, 0x00000043, 0x0000001a, 0x00000001,
> +	0x00000000, 0x00000000, 0x00000048, 0x00000000,
> +	0x00000000, 0x00000000, 0x00000000, 0x00000003,
> +};
> +
> +/* TODO: flexible timing */
> +static void mctl_set_timing_lpddr3(struct dram_para *para)
> +{
> +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +	struct sunxi_mctl_phy_reg * const mctl_phy =
> +			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +
> +	u8 tccd		= 2;
> +	u8 tfaw		= max(ns_to_t(50), 4);
> +	u8 trrd		= max(ns_to_t(10), 2);
> +	u8 trcd		= max(ns_to_t(24), 2);
> +	u8 trc		= ns_to_t(70);
> +	u8 txp		= max(ns_to_t(8), 2);
> +	u8 twtr		= max(ns_to_t(8), 2);
> +	u8 trtp		= max(ns_to_t(8), 2);
> +	u8 twr		= max(ns_to_t(15), 2);
> +	u8 trp		= ns_to_t(18);
> +	u8 tras		= ns_to_t(42);
> +	u8 twtr_sa	= ns_to_t(5);
> +	u8 tcksrea	= ns_to_t(11);
> +	u16 trefi	= ns_to_t(3900) / 32;
> +	u16 trfc	= ns_to_t(210);
> +	u16 txsr	= ns_to_t(220);
> +
> +	if (CONFIG_DRAM_CLK % 400 == 0) {
> +		/* Round up these parameters */
> +		twtr_sa++;
> +		tcksrea++;
> +	}
> +
> +	u8 tmrw		= 5;
> +	u8 tmrd		= 5;
> +	u8 tmod		= 12;
> +	u8 tcke		= 3;
> +	u8 tcksrx	= 5;
> +	u8 tcksre	= 5;
> +	u8 tckesr	= 5;
> +	u8 trasmax	= CONFIG_DRAM_CLK / 60;
> +	u8 txs		= 4;
> +	u8 txsdll	= 4;
> +	u8 txsabort	= 4;
> +	u8 txsfast	= 4;
> +
> +	u8 tcl		= 5; /* CL 10 */
> +	u8 tcwl		= 3; /* CWL 6 */
> +	u8 t_rdata_en	= twtr_sa + 8;
> +
> +	u32 tdinit0	= (200 * CONFIG_DRAM_CLK) + 1;		/* 200us */
> +	u32 tdinit1	= (100 * CONFIG_DRAM_CLK) / 1000 + 1;	/* 100ns */
> +	u32 tdinit2	= (11 * CONFIG_DRAM_CLK) + 1;		/* 11us */
> +	u32 tdinit3	= (1 * CONFIG_DRAM_CLK) + 1;		/* 1us */
> +
> +	u8 twtp		= tcwl + 4 + twr + 1;
> +	/*
> +	 * The code below for twr2rd and trd2wr follows the IP core's
> +	 * document from ZynqMP and i.MX7. The BSP has both number
> +	 * substracted by 2.
> +	 */
> +	u8 twr2rd	= tcwl + 4 + 1 + twtr;
> +	u8 trd2wr	= tcl + 4 + (tcksrea >> 1) - tcwl + 1;
> +
> +	/* set mode register */
> +	memcpy(mctl_phy->mr, mr_lpddr3, sizeof(mr_lpddr3));
> +
> +	/* 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(txsr, &mctl_ctl->dramtmg[14]);
> +
> +	clrsetbits_le32(&mctl_ctl->init[0], (3 << 30), (1 << 30));
> +	writel(0, &mctl_ctl->dfimisc);
> +	clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
> +
> +	/*
> +	 * Set timing registers of the PHY.
> +	 * Note: the PHY is clocked 2x from the DRAM frequency.
> +	 */
> +	writel((trrd << 25) | (tras << 17) | (trp << 9) | (trtp << 1),
> +	       &mctl_phy->dtpr[0]);
> +	writel((tfaw << 17) | 0x28000400 | (tmrd << 1), &mctl_phy->dtpr[1]);
> +	writel(((txs << 6) - 1) | (tcke << 17), &mctl_phy->dtpr[2]);
> +	writel(((txsdll << 22) - (0x1 << 16)) | twtr_sa | (tcksrea << 8),
> +	       &mctl_phy->dtpr[3]);
> +	writel((txp << 1) | (trfc << 17) | 0x800, &mctl_phy->dtpr[4]);
> +	writel((trc << 17) | (trcd << 9) | (twtr << 1), &mctl_phy->dtpr[5]);
> +	writel(0x0505, &mctl_phy->dtpr[6]);
> +
> +	/* Configure DFI timing */
> +	writel(tcl | 0x2000200 | (t_rdata_en << 16) | 0x808000,
> +	       &mctl_ctl->dfitmg0);
> +	writel(0x040201, &mctl_ctl->dfitmg1);
> +
> +	/* Configure PHY timing */
> +	writel(tdinit0 | (tdinit1 << 20), &mctl_phy->ptr[3]);
> +	writel(tdinit2 | (tdinit3 << 18), &mctl_phy->ptr[4]);
> +
> +	/* set refresh timing */
> +	writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
> +}
> +
> +static void mctl_sys_init(struct dram_para *para)
> +{
> +	struct sunxi_ccm_reg * const ccm =
> +			(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +
> +	/* Put all DRAM-related blocks to reset state */
> +	clrbits_le32(&ccm->mbus_cfg, MBUS_ENABLE | MBUS_RESET);
> +	writel(0, &ccm->dram_gate_reset);
> +	clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
> +	clrbits_le32(&ccm->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_CTRL_N(para->clk * 2 / 24 - 1), &ccm->pll5_cfg);
> +	mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK, CCM_PLL5_LOCK);
> +
> +	/* Configure DRAM mod clock */
> +	writel(DRAM_CLK_SRC_PLL5, &ccm->dram_clk_cfg);
> +	setbits_le32(&ccm->dram_clk_cfg, DRAM_CLK_UPDATE);
> +	writel(BIT(0) | BIT(RESET_SHIFT), &ccm->dram_gate_reset);
> +
> +	/* Disable all channels */
> +	writel(0, &mctl_com->maer0);
> +	writel(0, &mctl_com->maer1);
> +	writel(0, &mctl_com->maer2);
> +
> +	/* Configure MBUS and enable DRAM mod reset */
> +	setbits_le32(&ccm->mbus_cfg, MBUS_RESET);
> +	setbits_le32(&ccm->mbus_cfg, MBUS_ENABLE);
> +	setbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET);
> +	udelay(5);
> +
> +	/* Unknown hack from the BSP, which enables access of mctl_ctl regs */
> +	writel(0x8000, &mctl_ctl->unk_0x00c);
> +}
> +
> +static void mctl_set_addrmap(struct dram_para *para)
> +{
> +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +	u8 cols = para->cols;
> +	u8 rows = para->rows;
> +	u8 ranks = para->ranks;
> +
> +	/* Ranks */
> +	if (ranks == 2)
> +		mctl_ctl->addrmap[0] = rows + cols - 3;
> +	else
> +		mctl_ctl->addrmap[0] = 0x0F;
> +
> +	/* 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 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;
> +}
> +
> +static void mctl_com_init(struct dram_para *para)
> +{
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +	struct sunxi_mctl_phy_reg * const mctl_phy =
> +			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +	u32 reg_val, tmp;
> +
> +	mctl_set_addrmap(para);
> +
> +	setbits_le32(&mctl_com->cr, BIT(31));
> +	/*
> +	 * This address is magic; it's in SID memory area, but there's no
> +	 * known definition of it.
> +	 * On my Pine H64 board it has content 7.
> +	 */
> +	if (readl(0x03006100) == 7)
> +		clrbits_le32(&mctl_com->cr, BIT(27));
> +	else if (readl(0x03006100) == 3)
> +		setbits_le32(&mctl_com->cr, BIT(27));
> +
> +	if (para->clk > 408)
> +		reg_val = 0xf00;
> +	else if (para->clk > 246)
> +		reg_val = 0x1f00;
> +	else
> +		reg_val = 0x3f00;
> +	clrsetbits_le32(&mctl_com->unk_0x008, 0x3f00, reg_val);
> +
> +	/* TODO: half DQ, non-LPDDR3 types */
> +	writel(MSTR_DEVICETYPE_LPDDR3 | MSTR_BUSWIDTH_FULL |
> +	       MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para->ranks) |
> +	       0x80000000, &mctl_ctl->mstr);
> +	writel(DCR_LPDDR3 | DCR_DDR8BANK | 0x400, &mctl_phy->dcr);
> +
> +	if (para->ranks == 2)
> +		writel(0x0303, &mctl_ctl->odtmap);
> +	else
> +		writel(0x0201, &mctl_ctl->odtmap);
> +
> +	/* TODO: non-LPDDR3 types */
> +	tmp = para->clk * 7 / 2000;
> +	reg_val = 0x0400;
> +	reg_val |= (tmp + 7) << 24;
> +	reg_val |= (((para->clk < 400) ? 3 : 4) - tmp) << 16;
> +	writel(reg_val, &mctl_ctl->odtcfg);
> +
> +	/* TODO: half DQ */
> +}
> +
> +static void mctl_bit_delay_set(struct dram_para *para)
> +{
> +	struct sunxi_mctl_phy_reg * const mctl_phy =
> +			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +	int i, j;
> +	u32 val;
> +
> +	for (i = 0; i < 4; i++) {
> +		val = readl(&mctl_phy->dx[i].bdlr0);
> +		for (j = 0; j < 4; j++)
> +			val += para->dx_write_delays[i][j] << (j * 8);
> +		writel(val, &mctl_phy->dx[i].bdlr0);
> +
> +		val = readl(&mctl_phy->dx[i].bdlr1);
> +		for (j = 0; j < 4; j++)
> +			val += para->dx_write_delays[i][j + 4] << (j * 8);
> +		writel(val, &mctl_phy->dx[i].bdlr1);
> +
> +		val = readl(&mctl_phy->dx[i].bdlr2);
> +		for (j = 0; j < 4; j++)
> +			val += para->dx_write_delays[i][j + 8] << (j * 8);
> +		writel(val, &mctl_phy->dx[i].bdlr2);
> +	}
> +	clrbits_le32(&mctl_phy->pgcr[0], BIT(26));
> +
> +	for (i = 0; i < 4; i++) {
> +		val = readl(&mctl_phy->dx[i].bdlr3);
> +		for (j = 0; j < 4; j++)
> +			val += para->dx_read_delays[i][j] << (j * 8);
> +		writel(val, &mctl_phy->dx[i].bdlr3);
> +
> +		val = readl(&mctl_phy->dx[i].bdlr4);
> +		for (j = 0; j < 4; j++)
> +			val += para->dx_read_delays[i][j + 4] << (j * 8);
> +		writel(val, &mctl_phy->dx[i].bdlr4);
> +
> +		val = readl(&mctl_phy->dx[i].bdlr5);
> +		for (j = 0; j < 4; j++)
> +			val += para->dx_read_delays[i][j + 8] << (j * 8);
> +		writel(val, &mctl_phy->dx[i].bdlr5);
> +
> +		val = readl(&mctl_phy->dx[i].bdlr6);
> +		val += (para->dx_read_delays[i][12] << 8) |
> +		       (para->dx_read_delays[i][13] << 16);
> +		writel(val, &mctl_phy->dx[i].bdlr6);
> +	}
> +	setbits_le32(&mctl_phy->pgcr[0], BIT(26));
> +	udelay(1);
> +
> +	for (i = 1; i < 14; i++) {
> +		val = readl(&mctl_phy->acbdlr[i]);
> +		val += 0x0a0a0a0a;
> +		writel(val, &mctl_phy->acbdlr[i]);
> +	}
> +}
> +
> +static void mctl_channel_init(struct dram_para *para)
> +{
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +	struct sunxi_mctl_phy_reg * const mctl_phy =
> +			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
> +	int i;
> +	u32 val;
> +
> +	setbits_le32(&mctl_ctl->dfiupd[0], BIT(31) | BIT(30));
> +	setbits_le32(&mctl_ctl->zqctl[0], BIT(31) | BIT(30));
> +	writel(0x2f05, &mctl_ctl->sched[0]);
> +	setbits_le32(&mctl_ctl->rfshctl3, BIT(0));
> +	setbits_le32(&mctl_ctl->dfimisc, BIT(0));
> +	setbits_le32(&mctl_ctl->unk_0x00c, BIT(8));
> +	clrsetbits_le32(&mctl_phy->pgcr[1], 0x180, 0xc0);
> +	/* TODO: non-LPDDR3 types */
> +	clrsetbits_le32(&mctl_phy->pgcr[2], GENMASK(17, 0), ns_to_t(7800));
> +	clrbits_le32(&mctl_phy->pgcr[6], BIT(0));
> +	clrsetbits_le32(&mctl_phy->dxccr, 0xee0, 0x220);
> +	/* TODO: VT compensation */
> +	clrsetbits_le32(&mctl_phy->dsgcr, BIT(0), 0x440060);
> +	clrbits_le32(&mctl_phy->vtcr[1], BIT(1));
> +
> +	for (i = 0; i < 4; i++)
> +		clrsetbits_le32(&mctl_phy->dx[i].gcr[0], 0xe00, 0x800);
> +	for (i = 0; i < 4; i++)
> +		clrsetbits_le32(&mctl_phy->dx[i].gcr[2], 0xffff, 0x5555);
> +	for (i = 0; i < 4; i++)
> +		clrsetbits_le32(&mctl_phy->dx[i].gcr[3], 0x3030, 0x1010);
> +
> +	udelay(100);
> +
> +	if (para->ranks == 2)
> +		setbits_le32(&mctl_phy->dtcr[1], 0x30000);
> +	else
> +		clrsetbits_le32(&mctl_phy->dtcr[1], 0x30000, 0x10000);
> +
> +	clrbits_le32(&mctl_phy->dtcr[1], BIT(1));
> +	if (para->ranks == 2) {
> +		writel(0x00010001, &mctl_phy->rankidr);
> +		writel(0x20000, &mctl_phy->odtcr);
> +	} else {
> +		writel(0x0, &mctl_phy->rankidr);
> +		writel(0x10000, &mctl_phy->odtcr);
> +	}
> +
> +	/* TODO: non-LPDDR3 types */
> +	clrsetbits_le32(&mctl_phy->dtcr[0], 0xF0000000, 0x10000040);
> +	if (para->clk <= 792) {
> +		if (para->clk <= 672) {
> +			if (para->clk <= 600)
> +				val = 0x300;
> +			else
> +				val = 0x400;
> +		} else {
> +			val = 0x500;
> +		}
> +	} else {
> +		val = 0x600;
> +	}
> +	/* FIXME: NOT REVIEWED YET */
> +	clrsetbits_le32(&mctl_phy->zq[0].zqcr, 0x700, val);
> +	clrsetbits_le32(&mctl_phy->zq[0].zqpr[0], 0xff,
> +			CONFIG_DRAM_ZQ & 0xff);
> +	clrbits_le32(&mctl_phy->zq[0].zqor[0], 0xfffff);
> +	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ >> 8) & 0xff);
> +	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ & 0xf00) - 0x100);
> +	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ & 0xff00) << 4);
> +	clrbits_le32(&mctl_phy->zq[1].zqpr[0], 0xfffff);
> +	setbits_le32(&mctl_phy->zq[1].zqpr[0], (CONFIG_DRAM_ZQ >> 16) & 0xff);
> +	setbits_le32(&mctl_phy->zq[1].zqpr[0], ((CONFIG_DRAM_ZQ >> 8) & 0xf00) - 0x100);
> +	setbits_le32(&mctl_phy->zq[1].zqpr[0], (CONFIG_DRAM_ZQ & 0xff0000) >> 4);
> +	if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
> +		for (i = 1; i < 14; i++)
> +			writel(0x06060606, &mctl_phy->acbdlr[i]);
> +	}
> +
> +	/* TODO: non-LPDDR3 types */
> +	mctl_phy_pir_init(0xf562 | BIT(10));
> +
> +	/* TODO: non-LPDDR3 types */
> +	for (i = 0; i < 4; i++)
> +		writel(0x00000909, &mctl_phy->dx[i].gcr[5]);
> +
> +	for (i = 0; i < 4; i++) {
> +		if (IS_ENABLED(CONFIG_DRAM_ODT_EN))
> +			val = 0x0;
> +		else
> +			val = 0xaaaa;
> +		clrsetbits_le32(&mctl_phy->dx[i].gcr[2], 0xffff, val);
> +
> +		if (IS_ENABLED(CONFIG_DRAM_ODT_EN))
> +			val = 0x0;
> +		else
> +			val = 0x2020;
> +		clrsetbits_le32(&mctl_phy->dx[i].gcr[3], 0x3030, val);
> +	}
> +
> +	mctl_bit_delay_set(para);
> +	udelay(1);
> +
> +	setbits_le32(&mctl_phy->pgcr[6], BIT(0));
> +	clrbits_le32(&mctl_phy->pgcr[6], 0xfff8);
> +	for (i = 0; i < 4; i++)
> +		clrbits_le32(&mctl_phy->dx[i].gcr[3], ~0x3ffff);
> +	udelay(10);
> +
> +	if (readl(&mctl_phy->pgsr[0]) & 0xff00000) {
> +		/* Oops! There's something wrong! */
> +		debug("PLL = %x\n", readl(0x3001010));
> +		debug("DRAM PHY PGSR0 = %x\n", readl(&mctl_phy->pgsr[0]));
> +		for (i = 0; i < 4; i++)
> +			debug("DRAM PHY DX%dRSR0 = %x\n", i, readl(&mctl_phy->dx[i].rsr[0]));
> +		panic("Error while initializing DRAM PHY!\n");
> +	}
> +
> +	clrsetbits_le32(&mctl_phy->dsgcr, 0xc0, 0x40);
> +	clrbits_le32(&mctl_phy->pgcr[1], 0x40);
> +	clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
> +	writel(1, &mctl_ctl->swctl);
> +	mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> +	clrbits_le32(&mctl_ctl->rfshctl3, BIT(0));
> +
> +	setbits_le32(&mctl_com->unk_0x014, BIT(31));
> +	writel(0xffffffff, &mctl_com->maer0);
> +	writel(0x7ff, &mctl_com->maer1);
> +	writel(0xffff, &mctl_com->maer2);
> +}
> +
> +static void mctl_auto_detect_dram_size(struct dram_para *para)
> +{
> +	/* TODO: non-LPDDR3, half DQ */
> +	/* detect row address bits */
> +	para->cols = 8;
> +	para->rows = 18;
> +	mctl_core_init(para);
> +
> +	for (para->rows = 13; para->rows < 18; para->rows++) {
> +		/* 8 banks, 8 bit per byte and 32 bit width */
> +		if (mctl_mem_matches((1 << (para->rows + para->cols + 5))))
> +			break;
> +	}
> +
> +	/* detect column address bits */
> +	para->cols = 11;
> +	mctl_core_init(para);
> +
> +	for (para->cols = 8; para->cols < 11; para->cols++) {
> +		/* 8 bits per byte and 32 bit width */
> +		if (mctl_mem_matches(1 << (para->cols + 2)))
> +			break;
> +	}
> +}
> +
> +unsigned long mctl_calc_size(struct dram_para *para)
> +{
> +	/* TODO: non-LPDDR3, half DQ */
> +
> +	/* 8 banks, 32-bit (4 byte) data width */
> +	return (1ULL << (para->cols + para->rows + 3)) * 4 * para->ranks;
> +}
> +
> +#define SUN50I_H6_DX_WRITE_DELAYS				\
> +	{{  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },	\
> +	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },	\
> +	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0 },	\
> +	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }}
> +#define SUN50I_H6_DX_READ_DELAYS					\
> +	{{  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 },	\
> +	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 },	\
> +	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 },	\
> +	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0 }}
> +
> +unsigned long sunxi_dram_init(void)
> +{
> +	struct sunxi_mctl_com_reg * const mctl_com =
> +			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
> +	struct dram_para para = {
> +		.clk = CONFIG_DRAM_CLK,
> +		.type = SUNXI_DRAM_TYPE_LPDDR3,
> +		.ranks = 2,
> +		.cols = 11,
> +		.rows = 14,
> +		.dx_read_delays  = SUN50I_H6_DX_READ_DELAYS,
> +		.dx_write_delays = SUN50I_H6_DX_WRITE_DELAYS,
> +	};
> +
> +	unsigned long size;
> +
> +	/* RES_CAL_CTRL_REG in BSP U-boot*/
> +	setbits_le32(0x7010310, BIT(8));
> +	clrbits_le32(0x7010318, 0x3f);
> +
> +	mctl_auto_detect_dram_size(&para);
> +
> +	mctl_core_init(&para);
> +
> +	size = mctl_calc_size(&para);
> +
> +	clrsetbits_le32(&mctl_com->cr, 0xf0, (size / 1024 / 1024) & 0xf0);
> +
> +	mctl_set_master_priority();
> +
> +	return size;
> +};
> 

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

* [U-Boot] [linux-sunxi] [PATCH 11/13] sunxi: add DRAM support to H6
  2018-06-27  9:46   ` [U-Boot] [linux-sunxi] " Andre Przywara
@ 2018-06-27 10:49     ` Icenowy Zheng
  2018-06-27 17:29       ` Andre Przywara
  0 siblings, 1 reply; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-27 10:49 UTC (permalink / raw)
  To: u-boot

在 2018-06-27三的 10:46 +0100,Andre Przywara写道:
> Hi,
> 
> On 25/06/18 11:37, Icenowy Zheng wrote:
> > The Allwinner H6 SoC comes with a set of new DRAM controller+PHY
> > combo.
> > Both the controller and the PHY seem to be originate from
> > DesignWare,
> > and are similar to the ones in ZynqMP SoCs.
> > 
> > This commit introduces an initial DRAM driver for H6, which
> > contains
> > only LPDDR3 support. The currently known SBCs with H6 all come with
> > LPDDR3 memory, including Pine H64 and several Orange Pi's.
> > 
> > The BSP DRAM initialization code is closed source and violates GPL.
> > Code
> > in this commit is written by experimenting, referring the
> > code/document
> > of other users of the IPs (mainly the ZynqMP, as it's the only
> > found PHY
> > reference) and disassebling the BSP blob.
> > 
> > Thanks for Jernej Skrabec for review and fix some issues in this
> > driver
> > (including the most critical one which made it to work), and
> > rewrite
> > some code from register dump!
> 
> It seems that you guys really spent a lot of time and work into this,
> thanks a lot for that!
> Just skimming over the code, that looks vaguely similar to the
> existing
> dram_sunxi_dw.c driver. I guess you considered and dismissed that 

They're quite different. The "sunxi_dw" memory controller is a
controller+PHY combo, and address translation happen on the "mctl_com"
part, with just address feed; the H6 memory controller have dedicated
controller and PHY parts, like A23/A80, with a similar but enhanced
controller and a quite different PHY (both the controller and the PHY
are similar to the ones on ZynqMP), and address translation is also
dropped from mctl_com, instead done by the memory controller (the
ADDRMAPx registers).

The main part that should seem similar on all SoCs is the mctl_com
priority code, which is not only similar with sunxi_dw but also with
A23/A33/A83T/A80 (although I think A33/A83T are also similar with
sunxi_dw).

Other similar parts are similar because they all originate from
Allwinner's code, but with different controller (different offsets,
different bit definition, etc).

Maybe I should add a comment somewhere to describe the different?

> idea
> already, but can you briefly comment on how much effort it would be
> to
> integrate H6 support into that driver?
> I guess it would be beneficial for all SoCs to have one driver to
> rule
> them all.
> 
> Cheers,
> Andre.
> 
> > 
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> > ---
> >  arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
> >  .../include/asm/arch-sunxi/dram_sun50i_h6.h   | 276 +++++++
> >  arch/arm/mach-sunxi/Kconfig                   |   6 +
> >  arch/arm/mach-sunxi/Makefile                  |   1 +
> >  arch/arm/mach-sunxi/dram_sun50i_h6.c          | 708
> > ++++++++++++++++++
> >  5 files changed, 993 insertions(+)
> >  create mode 100644 arch/arm/include/asm/arch-
> > sunxi/dram_sun50i_h6.h
> >  create mode 100644 arch/arm/mach-sunxi/dram_sun50i_h6.c
> > 
> > diff --git a/arch/arm/include/asm/arch-sunxi/dram.h
> > b/arch/arm/include/asm/arch-sunxi/dram.h
> > index 80abac95b8..cc11fca8ef 100644
> > --- a/arch/arm/include/asm/arch-sunxi/dram.h
> > +++ b/arch/arm/include/asm/arch-sunxi/dram.h
> > @@ -28,6 +28,8 @@
> >  #include <asm/arch/dram_sunxi_dw.h>
> >  #elif defined(CONFIG_MACH_SUN9I)
> >  #include <asm/arch/dram_sun9i.h>
> > +#elif defined(CONFIG_MACH_SUN50I_H6)
> > +#include <asm/arch/dram_sun50i_h6.h>
> >  #else
> >  #include <asm/arch/dram_sun4i.h>
> >  #endif
> > diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
> > b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
> > new file mode 100644
> > index 0000000000..fe138b8cc0
> > --- /dev/null
> > +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
> > @@ -0,0 +1,276 @@
> > +/*
> > + * H6 dram controller register and constant defines
> > + *
> > + * (C) Copyright 2017  Icenowy Zheng <icenowy@aosc.io>
> > + *
> > + * SPDX-License-Identifier:	GPL-2.0+
> > + */
> > +
> > +#ifndef _SUNXI_DRAM_SUN50I_H6_H
> > +#define _SUNXI_DRAM_SUN50I_H6_H
> > +
> > +enum sunxi_dram_type {
> > +	SUNXI_DRAM_TYPE_DDR3 = 3,
> > +	SUNXI_DRAM_TYPE_DDR4,
> > +	SUNXI_DRAM_TYPE_LPDDR2 = 6,
> > +	SUNXI_DRAM_TYPE_LPDDR3,
> > +};
> > +
> > +/*
> > + * The following information is mainly retrieved by disassembly
> > and some FPGA
> > + * test code of sun50iw3 platform.
> > + */
> > +struct sunxi_mctl_com_reg {
> > +	u32 cr;			/* 0x000 control register
> > */
> > +	u8 reserved_0x004[4];	/* 0x004 */
> > +	u32 unk_0x008;		/* 0x008 */
> > +	u32 tmr;		/* 0x00c timer register */
> > +	u8 reserved_0x010[4];	/* 0x010 */
> > +	u32 unk_0x014;		/* 0x014 */
> > +	u8 reserved_0x018[8];	/* 0x018 */
> > +	u32 maer0;		/* 0x020 master enable register
> > 0 */
> > +	u32 maer1;		/* 0x024 master enable register
> > 1 */
> > +	u32 maer2;		/* 0x028 master enable register
> > 2 */
> > +	u8 reserved_0x02c[468];	/* 0x02c */
> > +	u32 bwcr;		/* 0x200 bandwidth control
> > register */
> > +	u8 reserved_0x204[12];	/* 0x204 */
> > +	/*
> > +	 * The last master configured by BSP libdram is at 0x49x,
> > so the
> > +	 * size of this struct array is set to 41 (0x29) now.
> > +	 */
> > +	struct {
> > +		u32 cfg0;		/* 0x0 */
> > +		u32 cfg1;		/* 0x4 */
> > +		u8 reserved_0x8[8];	/* 0x8 */
> > +	} master[41];		/* 0x210 + index * 0x10 */
> > +};
> > +check_member(sunxi_mctl_com_reg, master[40].reserved_0x8, 0x498);
> > +
> > +/*
> > + * The following register information are retrieved from some
> > similar DRAM
> > + * controllers, including the DRAM controllers in Allwinner
> > A23/A80 SoCs,
> > + * Rockchip RK3328 SoC, NXP i.MX7 SoCs and Xilinx Zynq UltraScale+
> > SoCs.
> > + *
> > + * The DRAM controller in Allwinner A23/A80 SoCs and NXP i.MX7
> > SoCs seems
> > + * to be older than the one in Allwinner H6, as the DRAMTMG9
> > register
> > + * is missing in these SoCs. (From the product specifications of
> > these
> > + * SoCs they're not capable of DDR4)
> > + *
> > + * Information sources:
> > + * - dram_sun9i.h and dram_sun8i_a23.h in the same directory.
> > + * - sdram_rk3328.h from the RK3328 TPL DRAM patchset
> > + * - i.MX 7Solo Applications Processor Reference Manual (IMX7SRM)
> > + * - Zynq UltraScale+ MPSoC Register Reference (UG1087)
> > + */
> > +struct sunxi_mctl_ctl_reg {
> > +	u32 mstr;		/* 0x000 */
> > +	u32 statr;		/* 0x004 unused */
> > +	u32 mstr1;		/* 0x008 unused */
> > +	u32 unk_0x00c;		/* 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 unused */
> > +	u32 pwrtmg;		/* 0x034 unused */
> > +	u32 hwlpctl;		/* 0x038 unused */
> > +	u8 reserved_0x03c[20];	/* 0x03c */
> > +	u32 rfshctl0;		/* 0x050 unused */
> > +	u32 rfshctl1;		/* 0x054 unused */
> > +	u8 reserved_0x058[8];	/* 0x05c */
> > +	u32 rfshctl3;		/* 0x060 */
> > +	u32 rfshtmg;		/* 0x064 */
> > +	u8 reserved_0x068[104];	/* 0x068 reserved for
> > ECC&CRC (from ZynqMP) */
> > +	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, may not exist
> > */
> > +	u8 reserved_0x1b8[8];	/* 0x1b8 */
> > +	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[180];	/* 0x258 */
> > +	u32 dbgcmd;		/* 0x30c unused */
> > +	u32 dbgstat;		/* 0x310 unused */
> > +	u8 reserved_0x314[12];	/* 0x314 */
> > +	u32 swctl;		/* 0x320 */
> > +	u32 swstat;		/* 0x324 */
> > +};
> > +check_member(sunxi_mctl_ctl_reg, swstat, 0x324);
> > +
> > +#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_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)
> > +
> > +/*
> > + * The following register information is based on Zynq UltraScale+
> > + * MPSoC Register Reference, as it's the currently only known
> > + * DDR PHY similar to the one used in H6; however although the
> > + * map is similar, the bit fields definitions are different.
> > + *
> > + * Other DesignWare DDR PHY's have similar register names, but the
> > + * offset and definitions are both different.
> > + */
> > +struct sunxi_mctl_phy_reg {
> > +	u32 ver;		/* 0x000 guess based on similar
> > PHYs */
> > +	u32 pir;		/* 0x004 */
> > +	u8 reserved_0x008[8];	/* 0x008 */
> > +	/*
> > +	 * The ZynqMP manual didn't document PGCR1, however this
> > register
> > +	 * exists on H6 and referenced by libdram.
> > +	 */
> > +	u32 pgcr[8];		/* 0x010 */
> > +	/*
> > +	 * By comparing the hardware and the ZynqMP manual, the
> > PGSR seems
> > +	 * to start at 0x34 on H6.
> > +	 */
> > +	u8 reserved_0x030[4];	/* 0x030 */
> > +	u32 pgsr[3];		/* 0x034 */
> > +	u32 ptr[7];		/* 0x040 */
> > +	/*
> > +	 * According to ZynqMP reference there's PLLCR0~6 in this
> > area,
> > +	 * but they're tagged "Type B PLL Only" and H6 seems to
> > have
> > +	 * no them.
> > +	 * 0x080 is not present in ZynqMP reference but it seems
> > to be
> > +	 * present on H6.
> > +	 */
> > +	u8 reserved_0x05c[36];	/* 0x05c */
> > +	u32 unk_0x080;		/* 0x080 */
> > +	u8 reserved_0x084[4];	/* 0x084 */
> > +	u32 dxccr;		/* 0x088 */
> > +	u8 reserved_0x08c[4];	/* 0x08c */
> > +	u32 dsgcr;		/* 0x090 */
> > +	u8 reserved_0x094[4];	/* 0x094 */
> > +	u32 odtcr;		/* 0x098 */
> > +	u8 reserved_0x09c[4];	/* 0x09c */
> > +	u32 aacr;		/* 0x0a0 */
> > +	u8 reserved_0x0a4[32];	/* 0x0a4 */
> > +	u32 gpr1;		/* 0x0c4 */
> > +	u8 reserved_0x0c8[56];	/* 0x0c8 */
> > +	u32 dcr;		/* 0x100 */
> > +	u8 reserved_0x104[12];	/* 0x104 */
> > +	u32 dtpr[7];		/* 0x110 */
> > +	u8 reserved_0x12c[20];	/* 0x12c */
> > +	u32 rdimmgcr[3];	/* 0x140 */
> > +	u8 reserved_0x14c[4];	/* 0x14c */
> > +	u32 rdimmcr[5];		/* 0x150 */
> > +	u8 reserved_0x164[4];	/* 0x164 */
> > +	u32 schcr[2];		/* 0x168 */
> > +	u8 reserved_0x170[16];	/* 0x170 */
> > +	/*
> > +	 * The ZynqMP manual documents MR0~7, 11~14 and 22.
> > +	 */
> > +	u32 mr[23];		/* 0x180 */
> > +	u8 reserved_0x1dc[36];	/* 0x1dc */
> > +	u32 dtcr[2];		/* 0x200 */
> > +	u32 dtar[3];		/* 0x208 */
> > +	u8 reserved_0x214[4];	/* 0x214 */
> > +	u32 dtdr[2];		/* 0x218 */
> > +	u8 reserved_0x220[16];	/* 0x220 */
> > +	u32 dtedr0;		/* 0x230 */
> > +	u32 dtedr1;		/* 0x234 */
> > +	u32 dtedr2;		/* 0x238 */
> > +	u32 vtdr;		/* 0x23c */
> > +	u32 catr[2];		/* 0x240 */
> > +	u8 reserved_0x248[8];
> > +	u32 dqsdr[3];		/* 0x250 */
> > +	u32 dtedr3;		/* 0x25c */
> > +	u8 reserved_0x260[160];	/* 0x260 */
> > +	u32 dcuar;		/* 0x300 */
> > +	u32 dcudr;		/* 0x304 */
> > +	u32 dcurr;		/* 0x308 */
> > +	u32 dculr;		/* 0x30c */
> > +	u32 dcugcr;		/* 0x310 */
> > +	u32 dcutpr;		/* 0x314 */
> > +	u32 dcusr[2];		/* 0x318 */
> > +	u8 reserved_0x320[444];	/* 0x320 */
> > +	u32 rankidr;		/* 0x4dc */
> > +	u32 riocr[6];		/* 0x4e0 */
> > +	u8 reserved_0x4f8[8];	/* 0x4f8 */
> > +	u32 aciocr[6];		/* 0x500 */
> > +	u8 reserved_0x518[8];	/* 0x518 */
> > +	u32 iovcr[2];		/* 0x520 */
> > +	u32 vtcr[2];		/* 0x528 */
> > +	u8 reserved_0x530[16];	/* 0x530 */
> > +	u32 acbdlr[17];		/* 0x540 */
> > +	u32 aclcdlr;		/* 0x584 */
> > +	u8 reserved_0x588[24];	/* 0x588 */
> > +	u32 acmdlr[2];		/* 0x5a0 */
> > +	u8 reserved_0x5a8[216];	/* 0x5a8 */
> > +	struct {
> > +		u32 zqcr;	/* 0x00 only the first one valid
> > */
> > +		u32 zqpr[2];	/* 0x04 */
> > +		u32 zqdr[2];	/* 0x0c */
> > +		u32 zqor[2];	/* 0x14 */
> > +		u32 zqsr;	/* 0x1c */
> > +	} zq[2];		/* 0x680, 0x6a0 */
> > +	u8 reserved_0x6c0[64];	/* 0x6c0 */
> > +	struct {
> > +		u32 gcr[7];		/* 0x00 */
> > +		u8 reserved_0x1c[36];	/* 0x1c */
> > +		u32 bdlr0;		/* 0x40 */
> > +		u32 bdlr1;		/* 0x44 */
> > +		u32 bdlr2;		/* 0x48 */
> > +		u8 reserved_0x4c[4];	/* 0x4c */
> > +		u32 bdlr3;		/* 0x50 */
> > +		u32 bdlr4;		/* 0x54 */
> > +		u32 bdlr5;		/* 0x58 */
> > +		u8 reserved_0x5c[4];	/* 0x5c */
> > +		u32 bdlr6;		/* 0x60 */
> > +		u8 reserved_0x64[28];	/* 0x64 */
> > +		u32 lcdlr[6];		/* 0x80 */
> > +		u8 reserved_0x98[8];	/* 0x98 */
> > +		u32 mdlr[2];		/* 0xa0 */
> > +		u8 reserved_0xa8[24];	/* 0xa8 */
> > +		u32 gtr0;		/* 0xc0 */
> > +		u8 reserved_0xc4[12];	/* 0xc4 */
> > +		/*
> > +		 * DXnRSR0 is not documented in ZynqMP manual but
> > +		 * it's used in libdram.
> > +		 */
> > +		u32 rsr[4];		/* 0xd0 */
> > +		u32 gsr[4];		/* 0xe0 */
> > +		u8 reserved_0xf0[16];	/* 0xf0 */
> > +	} dx[4];		/* 0x700, 0x800, 0x900, 0xa00 */
> > +};
> > +check_member(sunxi_mctl_phy_reg, dx[3].reserved_0xf0, 0xaf0);
> > +
> > +#define DCR_LPDDR3	(1 << 0)
> > +#define DCR_DDR3	(3 << 0)
> > +#define DCR_DDR4	(4 << 0)
> > +#define DCR_DDR8BANK	BIT(3)
> > +
> > +static inline int ns_to_t(int nanoseconds)
> > +{
> > +	const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
> > +
> > +	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
> > +}
> > +
> > +#endif /* _SUNXI_DRAM_SUN50I_H6_H */
> > diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-
> > sunxi/Kconfig
> > index e3c19b7464..c2fa0533e7 100644
> > --- a/arch/arm/mach-sunxi/Kconfig
> > +++ b/arch/arm/mach-sunxi/Kconfig
> > @@ -42,6 +42,12 @@ config DRAM_SUN9I
> >  	  Select this dram controller driver for Sun9i platforms,
> >  	  like A80.
> >  
> > +config DRAM_SUN50I_H6
> > +	bool
> > +	help
> > +	  Select this dram controller driver for some sun50i
> > platforms,
> > +	  like H6.
> > +
> >  config SUN6I_P2WI
> >  	bool "Allwinner sun6i internal P2WI controller"
> >  	help
> > diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-
> > sunxi/Makefile
> > index bafeb59d64..a00d4b335d 100644
> > --- a/arch/arm/mach-sunxi/Makefile
> > +++ b/arch/arm/mach-sunxi/Makefile
> > @@ -40,4 +40,5 @@ obj-$(CONFIG_DRAM_SUN9I)	+= dram_sun9i.o
> >  obj-$(CONFIG_SPL_SPI_SUNXI)	+= spl_spi_sunxi.o
> >  obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_sunxi_dw.o
> >  obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_timings/
> > +obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_sun50i_h6.o
> >  endif
> > diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-
> > sunxi/dram_sun50i_h6.c
> > new file mode 100644
> > index 0000000000..c7c4ea9ba7
> > --- /dev/null
> > +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
> > @@ -0,0 +1,708 @@
> > +/*
> > + * sun50i H6 platform dram controller init
> > + *
> > + * (C) Copyright 2017      Icenowy Zheng <icenowy@aosc.io>
> > + *
> > + * SPDX-License-Identifier:	GPL-2.0+
> > + */
> > +#include <common.h>
> > +#include <asm/io.h>
> > +#include <asm/arch/clock.h>
> > +#include <asm/arch/dram.h>
> > +#include <asm/arch/cpu.h>
> > +#include <linux/bitops.h>
> > +#include <linux/kconfig.h>
> > +
> > +/*
> > + * The delay parameters below allow to allegedly specify delay
> > times of some
> > + * unknown unit for each individual bit trace in each of the four
> > data bytes
> > + * the 32-bit wide access consists of. Also three control signals
> > can be
> > + * adjusted individually.
> > + */
> > +#define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
> > +/* The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output
> > Enable and DQSN */
> > +#define WR_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 4)
> > +/*
> > + * The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output
> > Enable, DQSN,
> > + * Termination and Power down
> > + */
> > +#define RD_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 6)
> > +struct dram_para {
> > +	u32 clk;
> > +	enum sunxi_dram_type type;
> > +	u8 cols;
> > +	u8 rows;
> > +	u8 ranks;
> > +	const u8
> > dx_read_delays[NR_OF_BYTE_LANES][RD_LINES_PER_BYTE_LANE];
> > +	const u8
> > dx_write_delays[NR_OF_BYTE_LANES][WR_LINES_PER_BYTE_LANE];
> > +};
> > +
> > +static void mctl_sys_init(struct dram_para *para);
> > +static void mctl_com_init(struct dram_para *para);
> > +static void mctl_set_timing_lpddr3(struct dram_para *para);
> > +static void mctl_channel_init(struct dram_para *para);
> > +
> > +static void mctl_core_init(struct dram_para *para)
> > +{
> > +	mctl_sys_init(para);
> > +	mctl_com_init(para);
> > +	switch (para->type) {
> > +	case SUNXI_DRAM_TYPE_LPDDR3:
> > +		mctl_set_timing_lpddr3(para);
> > +		break;
> > +	default:
> > +		panic("Unsupported DRAM type!");
> > +	};
> > +	mctl_channel_init(para);
> > +}
> > +
> > +static void mctl_phy_pir_init(u32 val)
> > +{
> > +	struct sunxi_mctl_phy_reg * const mctl_phy =
> > +			(struct sunxi_mctl_phy_reg
> > *)SUNXI_DRAM_PHY0_BASE;
> > +
> > +	writel(val | BIT(0), &mctl_phy->pir);
> > +	mctl_await_completion(&mctl_phy->pgsr[0], BIT(0), BIT(0));
> > +}
> > +
> > +enum {
> > +	MBUS_PORT_CPU           = 0,
> > +	MBUS_PORT_GPU           = 1,
> > +	MBUS_PORT_MAHB          = 2,
> > +	MBUS_PORT_DMA           = 3,
> > +	MBUS_PORT_VE            = 4,
> > +	MBUS_PORT_CE            = 5,
> > +	MBUS_PORT_TSC0          = 6,
> > +	MBUS_PORT_NDFC0         = 8,
> > +	MBUS_PORT_CSI0          = 11,
> > +	MBUS_PORT_DI0           = 14,
> > +	MBUS_PORT_DI1           = 15,
> > +	MBUS_PORT_DE300         = 16,
> > +	MBUS_PORT_IOMMU         = 25,
> > +	MBUS_PORT_VE2           = 26,
> > +	MBUS_PORT_USB3        = 37,
> > +	MBUS_PORT_PCIE          = 38,
> > +	MBUS_PORT_VP9           = 39,
> > +	MBUS_PORT_HDCP2       = 40,
> > +};
> > +
> > +enum {
> > +	MBUS_QOS_LOWEST = 0,
> > +	MBUS_QOS_LOW,
> > +	MBUS_QOS_HIGH,
> > +	MBUS_QOS_HIGHEST
> > +};
> > +inline void mbus_configure_port(u8 port,
> > +				bool bwlimit,
> > +				bool priority,
> > +				u8 qos,
> > +				u8 waittime,
> > +				u8 acs,
> > +				u16 bwl0,
> > +				u16 bwl1,
> > +				u16 bwl2)
> > +{
> > +	struct sunxi_mctl_com_reg * const mctl_com =
> > +			(struct sunxi_mctl_com_reg
> > *)SUNXI_DRAM_COM_BASE;
> > +
> > +	const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
> > +			   | (priority ? (1 << 1) : 0)
> > +			   | ((qos & 0x3) << 2)
> > +			   | ((waittime & 0xf) << 4)
> > +			   | ((acs & 0xff) << 8)
> > +			   | (bwl0 << 16) );
> > +	const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
> > +
> > +	debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0,
> > cfg1);
> > +	writel(cfg0, &mctl_com->master[port].cfg0);
> > +	writel(cfg1, &mctl_com->master[port].cfg1);
> > +}
> > +
> > +#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2)	
> > \
> > +	mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
> > +			    MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1,
> > bwl2)
> > +
> > +static void mctl_set_master_priority(void)
> > +{
> > +	struct sunxi_mctl_com_reg * const mctl_com =
> > +			(struct sunxi_mctl_com_reg
> > *)SUNXI_DRAM_COM_BASE;
> > +
> > +	/* enable bandwidth limit windows and set windows size 1us
> > */
> > +	writel(399, &mctl_com->tmr);
> > +	writel(BIT(16), &mctl_com->bwcr);
> > +
> > +	MBUS_CONF(  CPU,  true, HIGHEST, 0,  256,  128,  100);
> > +	MBUS_CONF(  GPU,  true,    HIGH, 0, 1536, 1400,  256);
> > +	MBUS_CONF( MAHB,  true, HIGHEST, 0,  512,  256,   96);
> > +	MBUS_CONF(  DMA,  true,    HIGH, 0,  256,  100,   80);
> > +	MBUS_CONF(   VE,  true,    HIGH, 2, 8192, 5500, 5000);
> > +	MBUS_CONF(   CE,  true,    HIGH, 2,  100,   64,   32);
> > +	MBUS_CONF( TSC0,  true,    HIGH, 2,  100,   64,   32);
> > +	MBUS_CONF(NDFC0,  true,    HIGH, 0,  256,  128,   64);
> > +	MBUS_CONF( CSI0,  true,    HIGH, 0,  256,  128,  100);
> > +	MBUS_CONF(  DI0,  true,    HIGH, 0, 1024,  256,   64);
> > +	MBUS_CONF(DE300,  true, HIGHEST, 6, 8192, 2800, 2400);
> > +	MBUS_CONF(IOMMU,  true, HIGHEST, 0,  100,   64,   32);
> > +	MBUS_CONF(  VE2,  true,    HIGH, 2, 8192, 5500, 5000);
> > +	MBUS_CONF( USB3,  true,    HIGH, 0,  256,  128,   64);
> > +	MBUS_CONF( PCIE,  true,    HIGH, 2,  100,   64,   32);
> > +	MBUS_CONF(  VP9,  true,    HIGH, 2, 8192, 5500, 5000);
> > +	MBUS_CONF(HDCP2,  true,    HIGH, 2,  100,   64,   32);
> > +}
> > +
> > +static u32 mr_lpddr3[12] = {
> > +	0x00000000, 0x00000043, 0x0000001a, 0x00000001,
> > +	0x00000000, 0x00000000, 0x00000048, 0x00000000,
> > +	0x00000000, 0x00000000, 0x00000000, 0x00000003,
> > +};
> > +
> > +/* TODO: flexible timing */
> > +static void mctl_set_timing_lpddr3(struct dram_para *para)
> > +{
> > +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> > +			(struct sunxi_mctl_ctl_reg
> > *)SUNXI_DRAM_CTL0_BASE;
> > +	struct sunxi_mctl_phy_reg * const mctl_phy =
> > +			(struct sunxi_mctl_phy_reg
> > *)SUNXI_DRAM_PHY0_BASE;
> > +
> > +	u8 tccd		= 2;
> > +	u8 tfaw		= max(ns_to_t(50), 4);
> > +	u8 trrd		= max(ns_to_t(10), 2);
> > +	u8 trcd		= max(ns_to_t(24), 2);
> > +	u8 trc		= ns_to_t(70);
> > +	u8 txp		= max(ns_to_t(8), 2);
> > +	u8 twtr		= max(ns_to_t(8), 2);
> > +	u8 trtp		= max(ns_to_t(8), 2);
> > +	u8 twr		= max(ns_to_t(15), 2);
> > +	u8 trp		= ns_to_t(18);
> > +	u8 tras		= ns_to_t(42);
> > +	u8 twtr_sa	= ns_to_t(5);
> > +	u8 tcksrea	= ns_to_t(11);
> > +	u16 trefi	= ns_to_t(3900) / 32;
> > +	u16 trfc	= ns_to_t(210);
> > +	u16 txsr	= ns_to_t(220);
> > +
> > +	if (CONFIG_DRAM_CLK % 400 == 0) {
> > +		/* Round up these parameters */
> > +		twtr_sa++;
> > +		tcksrea++;
> > +	}
> > +
> > +	u8 tmrw		= 5;
> > +	u8 tmrd		= 5;
> > +	u8 tmod		= 12;
> > +	u8 tcke		= 3;
> > +	u8 tcksrx	= 5;
> > +	u8 tcksre	= 5;
> > +	u8 tckesr	= 5;
> > +	u8 trasmax	= CONFIG_DRAM_CLK / 60;
> > +	u8 txs		= 4;
> > +	u8 txsdll	= 4;
> > +	u8 txsabort	= 4;
> > +	u8 txsfast	= 4;
> > +
> > +	u8 tcl		= 5; /* CL 10 */
> > +	u8 tcwl		= 3; /* CWL 6 */
> > +	u8 t_rdata_en	= twtr_sa + 8;
> > +
> > +	u32 tdinit0	= (200 * CONFIG_DRAM_CLK) + 1;		
> > /* 200us */
> > +	u32 tdinit1	= (100 * CONFIG_DRAM_CLK) / 1000 + 1;	
> > /* 100ns */
> > +	u32 tdinit2	= (11 * CONFIG_DRAM_CLK) + 1;		
> > /* 11us */
> > +	u32 tdinit3	= (1 * CONFIG_DRAM_CLK) + 1;		
> > /* 1us */
> > +
> > +	u8 twtp		= tcwl + 4 + twr + 1;
> > +	/*
> > +	 * The code below for twr2rd and trd2wr follows the IP
> > core's
> > +	 * document from ZynqMP and i.MX7. The BSP has both number
> > +	 * substracted by 2.
> > +	 */
> > +	u8 twr2rd	= tcwl + 4 + 1 + twtr;
> > +	u8 trd2wr	= tcl + 4 + (tcksrea >> 1) - tcwl + 1;
> > +
> > +	/* set mode register */
> > +	memcpy(mctl_phy->mr, mr_lpddr3, sizeof(mr_lpddr3));
> > +
> > +	/* 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(txsr, &mctl_ctl->dramtmg[14]);
> > +
> > +	clrsetbits_le32(&mctl_ctl->init[0], (3 << 30), (1 << 30));
> > +	writel(0, &mctl_ctl->dfimisc);
> > +	clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
> > +
> > +	/*
> > +	 * Set timing registers of the PHY.
> > +	 * Note: the PHY is clocked 2x from the DRAM frequency.
> > +	 */
> > +	writel((trrd << 25) | (tras << 17) | (trp << 9) | (trtp <<
> > 1),
> > +	       &mctl_phy->dtpr[0]);
> > +	writel((tfaw << 17) | 0x28000400 | (tmrd << 1), &mctl_phy-
> > >dtpr[1]);
> > +	writel(((txs << 6) - 1) | (tcke << 17), &mctl_phy-
> > >dtpr[2]);
> > +	writel(((txsdll << 22) - (0x1 << 16)) | twtr_sa | (tcksrea
> > << 8),
> > +	       &mctl_phy->dtpr[3]);
> > +	writel((txp << 1) | (trfc << 17) | 0x800, &mctl_phy-
> > >dtpr[4]);
> > +	writel((trc << 17) | (trcd << 9) | (twtr << 1), &mctl_phy-
> > >dtpr[5]);
> > +	writel(0x0505, &mctl_phy->dtpr[6]);
> > +
> > +	/* Configure DFI timing */
> > +	writel(tcl | 0x2000200 | (t_rdata_en << 16) | 0x808000,
> > +	       &mctl_ctl->dfitmg0);
> > +	writel(0x040201, &mctl_ctl->dfitmg1);
> > +
> > +	/* Configure PHY timing */
> > +	writel(tdinit0 | (tdinit1 << 20), &mctl_phy->ptr[3]);
> > +	writel(tdinit2 | (tdinit3 << 18), &mctl_phy->ptr[4]);
> > +
> > +	/* set refresh timing */
> > +	writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
> > +}
> > +
> > +static void mctl_sys_init(struct dram_para *para)
> > +{
> > +	struct sunxi_ccm_reg * const ccm =
> > +			(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> > +	struct sunxi_mctl_com_reg * const mctl_com =
> > +			(struct sunxi_mctl_com_reg
> > *)SUNXI_DRAM_COM_BASE;
> > +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> > +			(struct sunxi_mctl_ctl_reg
> > *)SUNXI_DRAM_CTL0_BASE;
> > +
> > +	/* Put all DRAM-related blocks to reset state */
> > +	clrbits_le32(&ccm->mbus_cfg, MBUS_ENABLE | MBUS_RESET);
> > +	writel(0, &ccm->dram_gate_reset);
> > +	clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
> > +	clrbits_le32(&ccm->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_CTRL_N(para->clk * 2 / 24 - 1), &ccm-
> > >pll5_cfg);
> > +	mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK,
> > CCM_PLL5_LOCK);
> > +
> > +	/* Configure DRAM mod clock */
> > +	writel(DRAM_CLK_SRC_PLL5, &ccm->dram_clk_cfg);
> > +	setbits_le32(&ccm->dram_clk_cfg, DRAM_CLK_UPDATE);
> > +	writel(BIT(0) | BIT(RESET_SHIFT), &ccm->dram_gate_reset);
> > +
> > +	/* Disable all channels */
> > +	writel(0, &mctl_com->maer0);
> > +	writel(0, &mctl_com->maer1);
> > +	writel(0, &mctl_com->maer2);
> > +
> > +	/* Configure MBUS and enable DRAM mod reset */
> > +	setbits_le32(&ccm->mbus_cfg, MBUS_RESET);
> > +	setbits_le32(&ccm->mbus_cfg, MBUS_ENABLE);
> > +	setbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET);
> > +	udelay(5);
> > +
> > +	/* Unknown hack from the BSP, which enables access of
> > mctl_ctl regs */
> > +	writel(0x8000, &mctl_ctl->unk_0x00c);
> > +}
> > +
> > +static void mctl_set_addrmap(struct dram_para *para)
> > +{
> > +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> > +			(struct sunxi_mctl_ctl_reg
> > *)SUNXI_DRAM_CTL0_BASE;
> > +	u8 cols = para->cols;
> > +	u8 rows = para->rows;
> > +	u8 ranks = para->ranks;
> > +
> > +	/* Ranks */
> > +	if (ranks == 2)
> > +		mctl_ctl->addrmap[0] = rows + cols - 3;
> > +	else
> > +		mctl_ctl->addrmap[0] = 0x0F;
> > +
> > +	/* 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 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;
> > +}
> > +
> > +static void mctl_com_init(struct dram_para *para)
> > +{
> > +	struct sunxi_mctl_com_reg * const mctl_com =
> > +			(struct sunxi_mctl_com_reg
> > *)SUNXI_DRAM_COM_BASE;
> > +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> > +			(struct sunxi_mctl_ctl_reg
> > *)SUNXI_DRAM_CTL0_BASE;
> > +	struct sunxi_mctl_phy_reg * const mctl_phy =
> > +			(struct sunxi_mctl_phy_reg
> > *)SUNXI_DRAM_PHY0_BASE;
> > +	u32 reg_val, tmp;
> > +
> > +	mctl_set_addrmap(para);
> > +
> > +	setbits_le32(&mctl_com->cr, BIT(31));
> > +	/*
> > +	 * This address is magic; it's in SID memory area, but
> > there's no
> > +	 * known definition of it.
> > +	 * On my Pine H64 board it has content 7.
> > +	 */
> > +	if (readl(0x03006100) == 7)
> > +		clrbits_le32(&mctl_com->cr, BIT(27));
> > +	else if (readl(0x03006100) == 3)
> > +		setbits_le32(&mctl_com->cr, BIT(27));
> > +
> > +	if (para->clk > 408)
> > +		reg_val = 0xf00;
> > +	else if (para->clk > 246)
> > +		reg_val = 0x1f00;
> > +	else
> > +		reg_val = 0x3f00;
> > +	clrsetbits_le32(&mctl_com->unk_0x008, 0x3f00, reg_val);
> > +
> > +	/* TODO: half DQ, non-LPDDR3 types */
> > +	writel(MSTR_DEVICETYPE_LPDDR3 | MSTR_BUSWIDTH_FULL |
> > +	       MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para-
> > >ranks) |
> > +	       0x80000000, &mctl_ctl->mstr);
> > +	writel(DCR_LPDDR3 | DCR_DDR8BANK | 0x400, &mctl_phy->dcr);
> > +
> > +	if (para->ranks == 2)
> > +		writel(0x0303, &mctl_ctl->odtmap);
> > +	else
> > +		writel(0x0201, &mctl_ctl->odtmap);
> > +
> > +	/* TODO: non-LPDDR3 types */
> > +	tmp = para->clk * 7 / 2000;
> > +	reg_val = 0x0400;
> > +	reg_val |= (tmp + 7) << 24;
> > +	reg_val |= (((para->clk < 400) ? 3 : 4) - tmp) << 16;
> > +	writel(reg_val, &mctl_ctl->odtcfg);
> > +
> > +	/* TODO: half DQ */
> > +}
> > +
> > +static void mctl_bit_delay_set(struct dram_para *para)
> > +{
> > +	struct sunxi_mctl_phy_reg * const mctl_phy =
> > +			(struct sunxi_mctl_phy_reg
> > *)SUNXI_DRAM_PHY0_BASE;
> > +	int i, j;
> > +	u32 val;
> > +
> > +	for (i = 0; i < 4; i++) {
> > +		val = readl(&mctl_phy->dx[i].bdlr0);
> > +		for (j = 0; j < 4; j++)
> > +			val += para->dx_write_delays[i][j] << (j *
> > 8);
> > +		writel(val, &mctl_phy->dx[i].bdlr0);
> > +
> > +		val = readl(&mctl_phy->dx[i].bdlr1);
> > +		for (j = 0; j < 4; j++)
> > +			val += para->dx_write_delays[i][j + 4] <<
> > (j * 8);
> > +		writel(val, &mctl_phy->dx[i].bdlr1);
> > +
> > +		val = readl(&mctl_phy->dx[i].bdlr2);
> > +		for (j = 0; j < 4; j++)
> > +			val += para->dx_write_delays[i][j + 8] <<
> > (j * 8);
> > +		writel(val, &mctl_phy->dx[i].bdlr2);
> > +	}
> > +	clrbits_le32(&mctl_phy->pgcr[0], BIT(26));
> > +
> > +	for (i = 0; i < 4; i++) {
> > +		val = readl(&mctl_phy->dx[i].bdlr3);
> > +		for (j = 0; j < 4; j++)
> > +			val += para->dx_read_delays[i][j] << (j *
> > 8);
> > +		writel(val, &mctl_phy->dx[i].bdlr3);
> > +
> > +		val = readl(&mctl_phy->dx[i].bdlr4);
> > +		for (j = 0; j < 4; j++)
> > +			val += para->dx_read_delays[i][j + 4] <<
> > (j * 8);
> > +		writel(val, &mctl_phy->dx[i].bdlr4);
> > +
> > +		val = readl(&mctl_phy->dx[i].bdlr5);
> > +		for (j = 0; j < 4; j++)
> > +			val += para->dx_read_delays[i][j + 8] <<
> > (j * 8);
> > +		writel(val, &mctl_phy->dx[i].bdlr5);
> > +
> > +		val = readl(&mctl_phy->dx[i].bdlr6);
> > +		val += (para->dx_read_delays[i][12] << 8) |
> > +		       (para->dx_read_delays[i][13] << 16);
> > +		writel(val, &mctl_phy->dx[i].bdlr6);
> > +	}
> > +	setbits_le32(&mctl_phy->pgcr[0], BIT(26));
> > +	udelay(1);
> > +
> > +	for (i = 1; i < 14; i++) {
> > +		val = readl(&mctl_phy->acbdlr[i]);
> > +		val += 0x0a0a0a0a;
> > +		writel(val, &mctl_phy->acbdlr[i]);
> > +	}
> > +}
> > +
> > +static void mctl_channel_init(struct dram_para *para)
> > +{
> > +	struct sunxi_mctl_com_reg * const mctl_com =
> > +			(struct sunxi_mctl_com_reg
> > *)SUNXI_DRAM_COM_BASE;
> > +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> > +			(struct sunxi_mctl_ctl_reg
> > *)SUNXI_DRAM_CTL0_BASE;
> > +	struct sunxi_mctl_phy_reg * const mctl_phy =
> > +			(struct sunxi_mctl_phy_reg
> > *)SUNXI_DRAM_PHY0_BASE;
> > +	int i;
> > +	u32 val;
> > +
> > +	setbits_le32(&mctl_ctl->dfiupd[0], BIT(31) | BIT(30));
> > +	setbits_le32(&mctl_ctl->zqctl[0], BIT(31) | BIT(30));
> > +	writel(0x2f05, &mctl_ctl->sched[0]);
> > +	setbits_le32(&mctl_ctl->rfshctl3, BIT(0));
> > +	setbits_le32(&mctl_ctl->dfimisc, BIT(0));
> > +	setbits_le32(&mctl_ctl->unk_0x00c, BIT(8));
> > +	clrsetbits_le32(&mctl_phy->pgcr[1], 0x180, 0xc0);
> > +	/* TODO: non-LPDDR3 types */
> > +	clrsetbits_le32(&mctl_phy->pgcr[2], GENMASK(17, 0),
> > ns_to_t(7800));
> > +	clrbits_le32(&mctl_phy->pgcr[6], BIT(0));
> > +	clrsetbits_le32(&mctl_phy->dxccr, 0xee0, 0x220);
> > +	/* TODO: VT compensation */
> > +	clrsetbits_le32(&mctl_phy->dsgcr, BIT(0), 0x440060);
> > +	clrbits_le32(&mctl_phy->vtcr[1], BIT(1));
> > +
> > +	for (i = 0; i < 4; i++)
> > +		clrsetbits_le32(&mctl_phy->dx[i].gcr[0], 0xe00,
> > 0x800);
> > +	for (i = 0; i < 4; i++)
> > +		clrsetbits_le32(&mctl_phy->dx[i].gcr[2], 0xffff,
> > 0x5555);
> > +	for (i = 0; i < 4; i++)
> > +		clrsetbits_le32(&mctl_phy->dx[i].gcr[3], 0x3030,
> > 0x1010);
> > +
> > +	udelay(100);
> > +
> > +	if (para->ranks == 2)
> > +		setbits_le32(&mctl_phy->dtcr[1], 0x30000);
> > +	else
> > +		clrsetbits_le32(&mctl_phy->dtcr[1], 0x30000,
> > 0x10000);
> > +
> > +	clrbits_le32(&mctl_phy->dtcr[1], BIT(1));
> > +	if (para->ranks == 2) {
> > +		writel(0x00010001, &mctl_phy->rankidr);
> > +		writel(0x20000, &mctl_phy->odtcr);
> > +	} else {
> > +		writel(0x0, &mctl_phy->rankidr);
> > +		writel(0x10000, &mctl_phy->odtcr);
> > +	}
> > +
> > +	/* TODO: non-LPDDR3 types */
> > +	clrsetbits_le32(&mctl_phy->dtcr[0], 0xF0000000,
> > 0x10000040);
> > +	if (para->clk <= 792) {
> > +		if (para->clk <= 672) {
> > +			if (para->clk <= 600)
> > +				val = 0x300;
> > +			else
> > +				val = 0x400;
> > +		} else {
> > +			val = 0x500;
> > +		}
> > +	} else {
> > +		val = 0x600;
> > +	}
> > +	/* FIXME: NOT REVIEWED YET */
> > +	clrsetbits_le32(&mctl_phy->zq[0].zqcr, 0x700, val);
> > +	clrsetbits_le32(&mctl_phy->zq[0].zqpr[0], 0xff,
> > +			CONFIG_DRAM_ZQ & 0xff);
> > +	clrbits_le32(&mctl_phy->zq[0].zqor[0], 0xfffff);
> > +	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ >>
> > 8) & 0xff);
> > +	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ &
> > 0xf00) - 0x100);
> > +	setbits_le32(&mctl_phy->zq[0].zqor[0], (CONFIG_DRAM_ZQ &
> > 0xff00) << 4);
> > +	clrbits_le32(&mctl_phy->zq[1].zqpr[0], 0xfffff);
> > +	setbits_le32(&mctl_phy->zq[1].zqpr[0], (CONFIG_DRAM_ZQ >>
> > 16) & 0xff);
> > +	setbits_le32(&mctl_phy->zq[1].zqpr[0], ((CONFIG_DRAM_ZQ >>
> > 8) & 0xf00) - 0x100);
> > +	setbits_le32(&mctl_phy->zq[1].zqpr[0], (CONFIG_DRAM_ZQ &
> > 0xff0000) >> 4);
> > +	if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
> > +		for (i = 1; i < 14; i++)
> > +			writel(0x06060606, &mctl_phy->acbdlr[i]);
> > +	}
> > +
> > +	/* TODO: non-LPDDR3 types */
> > +	mctl_phy_pir_init(0xf562 | BIT(10));
> > +
> > +	/* TODO: non-LPDDR3 types */
> > +	for (i = 0; i < 4; i++)
> > +		writel(0x00000909, &mctl_phy->dx[i].gcr[5]);
> > +
> > +	for (i = 0; i < 4; i++) {
> > +		if (IS_ENABLED(CONFIG_DRAM_ODT_EN))
> > +			val = 0x0;
> > +		else
> > +			val = 0xaaaa;
> > +		clrsetbits_le32(&mctl_phy->dx[i].gcr[2], 0xffff,
> > val);
> > +
> > +		if (IS_ENABLED(CONFIG_DRAM_ODT_EN))
> > +			val = 0x0;
> > +		else
> > +			val = 0x2020;
> > +		clrsetbits_le32(&mctl_phy->dx[i].gcr[3], 0x3030,
> > val);
> > +	}
> > +
> > +	mctl_bit_delay_set(para);
> > +	udelay(1);
> > +
> > +	setbits_le32(&mctl_phy->pgcr[6], BIT(0));
> > +	clrbits_le32(&mctl_phy->pgcr[6], 0xfff8);
> > +	for (i = 0; i < 4; i++)
> > +		clrbits_le32(&mctl_phy->dx[i].gcr[3], ~0x3ffff);
> > +	udelay(10);
> > +
> > +	if (readl(&mctl_phy->pgsr[0]) & 0xff00000) {
> > +		/* Oops! There's something wrong! */
> > +		debug("PLL = %x\n", readl(0x3001010));
> > +		debug("DRAM PHY PGSR0 = %x\n", readl(&mctl_phy-
> > >pgsr[0]));
> > +		for (i = 0; i < 4; i++)
> > +			debug("DRAM PHY DX%dRSR0 = %x\n", i,
> > readl(&mctl_phy->dx[i].rsr[0]));
> > +		panic("Error while initializing DRAM PHY!\n");
> > +	}
> > +
> > +	clrsetbits_le32(&mctl_phy->dsgcr, 0xc0, 0x40);
> > +	clrbits_le32(&mctl_phy->pgcr[1], 0x40);
> > +	clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
> > +	writel(1, &mctl_ctl->swctl);
> > +	mctl_await_completion(&mctl_ctl->swstat, 1, 1);
> > +	clrbits_le32(&mctl_ctl->rfshctl3, BIT(0));
> > +
> > +	setbits_le32(&mctl_com->unk_0x014, BIT(31));
> > +	writel(0xffffffff, &mctl_com->maer0);
> > +	writel(0x7ff, &mctl_com->maer1);
> > +	writel(0xffff, &mctl_com->maer2);
> > +}
> > +
> > +static void mctl_auto_detect_dram_size(struct dram_para *para)
> > +{
> > +	/* TODO: non-LPDDR3, half DQ */
> > +	/* detect row address bits */
> > +	para->cols = 8;
> > +	para->rows = 18;
> > +	mctl_core_init(para);
> > +
> > +	for (para->rows = 13; para->rows < 18; para->rows++) {
> > +		/* 8 banks, 8 bit per byte and 32 bit width */
> > +		if (mctl_mem_matches((1 << (para->rows + para-
> > >cols + 5))))
> > +			break;
> > +	}
> > +
> > +	/* detect column address bits */
> > +	para->cols = 11;
> > +	mctl_core_init(para);
> > +
> > +	for (para->cols = 8; para->cols < 11; para->cols++) {
> > +		/* 8 bits per byte and 32 bit width */
> > +		if (mctl_mem_matches(1 << (para->cols + 2)))
> > +			break;
> > +	}
> > +}
> > +
> > +unsigned long mctl_calc_size(struct dram_para *para)
> > +{
> > +	/* TODO: non-LPDDR3, half DQ */
> > +
> > +	/* 8 banks, 32-bit (4 byte) data width */
> > +	return (1ULL << (para->cols + para->rows + 3)) * 4 * para-
> > >ranks;
> > +}
> > +
> > +#define SUN50I_H6_DX_WRITE_DELAYS				\
> > +	{{  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },	
> > \
> > +	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },	
> > \
> > +	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0 },	
> > \
> > +	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }}
> > +#define SUN50I_H6_DX_READ_DELAYS					
> > \
> > +	{{  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0
> > },	\
> > +	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0
> > },	\
> > +	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0
> > },	\
> > +	 {  4,  4,  4,  4,  4,  4,  4,  4,  4,  0,  0,  0,  0,  0
> > }}
> > +
> > +unsigned long sunxi_dram_init(void)
> > +{
> > +	struct sunxi_mctl_com_reg * const mctl_com =
> > +			(struct sunxi_mctl_com_reg
> > *)SUNXI_DRAM_COM_BASE;
> > +	struct dram_para para = {
> > +		.clk = CONFIG_DRAM_CLK,
> > +		.type = SUNXI_DRAM_TYPE_LPDDR3,
> > +		.ranks = 2,
> > +		.cols = 11,
> > +		.rows = 14,
> > +		.dx_read_delays  = SUN50I_H6_DX_READ_DELAYS,
> > +		.dx_write_delays = SUN50I_H6_DX_WRITE_DELAYS,
> > +	};
> > +
> > +	unsigned long size;
> > +
> > +	/* RES_CAL_CTRL_REG in BSP U-boot*/
> > +	setbits_le32(0x7010310, BIT(8));
> > +	clrbits_le32(0x7010318, 0x3f);
> > +
> > +	mctl_auto_detect_dram_size(&para);
> > +
> > +	mctl_core_init(&para);
> > +
> > +	size = mctl_calc_size(&para);
> > +
> > +	clrsetbits_le32(&mctl_com->cr, 0xf0, (size / 1024 / 1024)
> > & 0xf0);
> > +
> > +	mctl_set_master_priority();
> > +
> > +	return size;
> > +};
> > 
> 
> 

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

* [U-Boot] [linux-sunxi] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC
  2018-06-25 10:37 ` [U-Boot] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC Icenowy Zheng
@ 2018-06-27 14:04   ` Andre Przywara
  2018-06-27 14:26     ` Icenowy Zheng
  0 siblings, 1 reply; 36+ messages in thread
From: Andre Przywara @ 2018-06-27 14:04 UTC (permalink / raw)
  To: u-boot

Hi,

On 25/06/18 11:37, Icenowy Zheng wrote:
> Allwinner H6 is a new SoC from Allwinner features USB3 and PCIe
> interfaces.
> 
> This patch adds support for it.

Can you please mention in the commit message or subject line that this
includes the SoC .dtsi? Or maybe even split this out into a separate patch?

And is there any reason you didn't copy the official Linux DT version?
Or is that one here just an older copy of that?
Anyway, please use the most recent version of the .dtsi, so we can use
that directly to pass on to the kernel.

Thanks!
Andre.

> As this is a new SoC supported by mainline U-Boot, the MMC env support
> is dropped and only FAT env is available.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  arch/arm/dts/sun50i-h6.dtsi    | 140 +++++++++++++++++++++++++++++++++
>  arch/arm/mach-sunxi/Kconfig    |  17 +++-
>  arch/arm/mach-sunxi/cpu_info.c |   2 +
>  common/spl/Kconfig             |   2 +-
>  4 files changed, 159 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/dts/sun50i-h6.dtsi
> 
> diff --git a/arch/arm/dts/sun50i-h6.dtsi b/arch/arm/dts/sun50i-h6.dtsi
> new file mode 100644
> index 0000000000..50f9146318
> --- /dev/null
> +++ b/arch/arm/dts/sun50i-h6.dtsi
> @@ -0,0 +1,140 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + *  a) This file is free software; you can redistribute it and/or
> + *     modify it under the terms of the GNU General Public License as
> + *     published by the Free Software Foundation; either version 2 of the
> + *     License, or (at your option) any later version.
> + *
> + *     This file is distributed in the hope that it will be useful,
> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *     GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + *  b) Permission is hereby granted, free of charge, to any person
> + *     obtaining a copy of this software and associated documentation
> + *     files (the "Software"), to deal in the Software without
> + *     restriction, including without limitation the rights to use,
> + *     copy, modify, merge, publish, distribute, sublicense, and/or
> + *     sell copies of the Software, and to permit persons to whom the
> + *     Software is furnished to do so, subject to the following
> + *     conditions:
> + *
> + *     The above copyright notice and this permission notice shall be
> + *     included in all copies or substantial portions of the Software.
> + *
> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + *     OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +/ {
> +	interrupt-parent = <&gic>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		cpu0: cpu at 0 {
> +			compatible = "arm,cortex-a53", "arm,armv8";
> +			device_type = "cpu";
> +			reg = <0>;
> +		};
> +
> +		cpu1: cpu at 1 {
> +			compatible = "arm,cortex-a53", "arm,armv8";
> +			device_type = "cpu";
> +			reg = <1>;
> +		};
> +
> +		cpu2: cpu at 2 {
> +			compatible = "arm,cortex-a53", "arm,armv8";
> +			device_type = "cpu";
> +			reg = <2>;
> +		};
> +
> +		cpu3: cpu at 3 {
> +			compatible = "arm,cortex-a53", "arm,armv8";
> +			device_type = "cpu";
> +			reg = <3>;
> +		};
> +	};
> +
> +	osc24M: osc24M_clk {
> +		#clock-cells = <0>;
> +		compatible = "fixed-clock";
> +		clock-frequency = <24000000>;
> +		clock-output-names = "osc24M";
> +	};
> +
> +	osc32k: osc32k_clk {
> +		#clock-cells = <0>;
> +		compatible = "fixed-clock";
> +		clock-frequency = <32768>;
> +		clock-output-names = "osc32k";
> +	};
> +
> +	iosc: internal-osc-clk {
> +		#clock-cells = <0>;
> +		compatible = "fixed-clock";
> +		clock-frequency = <16000000>;
> +		clock-accuracy = <300000000>;
> +		clock-output-names = "iosc";
> +	};
> +
> +	timer {
> +		compatible = "arm,armv8-timer";
> +		interrupts = <GIC_PPI 13
> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
> +			     <GIC_PPI 14
> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
> +			     <GIC_PPI 11
> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
> +			     <GIC_PPI 10
> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
> +	};
> +
> +	soc {
> +		compatible = "simple-bus";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		gic: interrupt-controller at 3021000 {
> +			compatible = "arm,gic-400";
> +			reg = <0x03021000 0x1000>,
> +			      <0x03022000 0x2000>,
> +			      <0x03024000 0x2000>,
> +			      <0x03026000 0x2000>;
> +			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
> +			interrupt-controller;
> +			#interrupt-cells = <3>;
> +		};
> +
> +		uart0: serial at 5000000 {
> +			compatible = "snps,dw-apb-uart";
> +			reg = <0x05000000 0x400>;
> +			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> +			reg-shift = <2>;
> +			reg-io-width = <4>;
> +			clocks = <&osc24M>; /* placeholder */
> +			status = "disabled";
> +		};
> +	};
> +};
> diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
> index c2fa0533e7..cb4a9af6bf 100644
> --- a/arch/arm/mach-sunxi/Kconfig
> +++ b/arch/arm/mach-sunxi/Kconfig
> @@ -82,6 +82,7 @@ config SUN8I_RSB
>  config SUNXI_SRAM_ADDRESS
>  	hex
>  	default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
> +	default 0x20000 if MACH_SUN50I_H6
>  	default 0x0
>  	---help---
>  	Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
> @@ -281,6 +282,14 @@ config MACH_SUN50I_H5
>  	select FIT
>  	select SPL_LOAD_FIT
>  
> +config MACH_SUN50I_H6
> +	bool "sun50i (Allwinner H6)"
> +	select ARM64
> +	select SUPPORT_SPL
> +	select FIT
> +	select SPL_LOAD_FIT
> +	select DRAM_SUN50I_H6
> +
>  endchoice
>  
>  # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33"
> @@ -374,6 +383,7 @@ config DRAM_CLK
>  	default 360 if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || \
>  		       MACH_SUN8I_V3S
>  	default 672 if MACH_SUN50I
> +	default 744 if MACH_SUN50I_H6
>  	---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
> @@ -393,7 +403,7 @@ config DRAM_ZQ
>  	default 123 if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || MACH_SUN8I
>  	default 127 if MACH_SUN7I
>  	default 14779 if MACH_SUN8I_V3S
> -	default 3881979 if MACH_SUN8I_R40
> +	default 3881979 if MACH_SUN8I_R40 || MACH_SUN50I_H6
>  	default 4145117 if MACH_SUN9I
>  	default 3881915 if MACH_SUN50I
>  	---help---
> @@ -405,6 +415,7 @@ config DRAM_ODT_EN
>  	default y if MACH_SUN8I_A23
>  	default y if MACH_SUN8I_R40
>  	default y if MACH_SUN50I
> +	default y if MACH_SUN50I_H6
>  	---help---
>  	Select this to enable dram odt (on die termination).
>  
> @@ -495,6 +506,7 @@ config SYS_CLK_FREQ
>  	default 816000000 if MACH_SUN50I || MACH_SUN50I_H5
>  	default 1008000000 if MACH_SUN8I
>  	default 1008000000 if MACH_SUN9I
> +	default 888000000 if MACH_SUN50I_H6
>  
>  config SYS_CONFIG_NAME
>  	default "sun4i" if MACH_SUN4I
> @@ -504,6 +516,7 @@ config SYS_CONFIG_NAME
>  	default "sun8i" if MACH_SUN8I
>  	default "sun9i" if MACH_SUN9I
>  	default "sun50i" if MACH_SUN50I
> +	default "sun50i" if MACH_SUN50I_H6
>  
>  config SYS_BOARD
>  	default "sunxi"
> @@ -709,6 +722,7 @@ config VIDEO_SUNXI
>  	depends on !MACH_SUN8I_V3S
>  	depends on !MACH_SUN9I
>  	depends on !MACH_SUN50I
> +	depends on !MACH_SUN50I_H6
>  	select VIDEO
>  	imply VIDEO_DT_SIMPLEFB
>  	default y
> @@ -941,6 +955,7 @@ config SPL_STACK_R_ADDR
>  	default 0x4fe00000 if MACH_SUN8I
>  	default 0x2fe00000 if MACH_SUN9I
>  	default 0x4fe00000 if MACH_SUN50I
> +	default 0x4fe00000 if MACH_SUN50I_H6
>  
>  config SPL_SPI_SUNXI
>  	bool "Support for SPI Flash on Allwinner SoCs in SPL"
> diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c
> index 25a5ec26a0..90aff395dc 100644
> --- a/arch/arm/mach-sunxi/cpu_info.c
> +++ b/arch/arm/mach-sunxi/cpu_info.c
> @@ -97,6 +97,8 @@ int print_cpuinfo(void)
>  	puts("CPU:   Allwinner A64 (SUN50I)\n");
>  #elif defined CONFIG_MACH_SUN50I_H5
>  	puts("CPU:   Allwinner H5 (SUN50I)\n");
> +#elif defined CONFIG_MACH_SUN50I_H6
> +	puts("CPU:   Allwinner H6 (SUN50I)\n");
>  #else
>  #warning Please update cpu_info.c with correct CPU information
>  	puts("CPU:   SUNXI Family\n");
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index 4d27565566..e761bda6f1 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -246,7 +246,7 @@ config SPL_SHA256_SUPPORT
>  config SPL_FIT_IMAGE_TINY
>  	bool "Remove functionality from SPL FIT loading to reduce size"
>  	depends on SPL_FIT
> -	default y if MACH_SUN50I || MACH_SUN50I_H5
> +	default y if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6
>  	help
>  	  Enable this to reduce the size of the FIT image loading code
>  	  in SPL, if space for the SPL binary is very tight.
> 

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

* [U-Boot] [linux-sunxi] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC
  2018-06-27 14:04   ` [U-Boot] [linux-sunxi] " Andre Przywara
@ 2018-06-27 14:26     ` Icenowy Zheng
  0 siblings, 0 replies; 36+ messages in thread
From: Icenowy Zheng @ 2018-06-27 14:26 UTC (permalink / raw)
  To: u-boot



于 2018年6月27日 GMT+08:00 下午10:04:53, Andre Przywara <andre.przywara@arm.com> 写到:
>Hi,
>
>On 25/06/18 11:37, Icenowy Zheng wrote:
>> Allwinner H6 is a new SoC from Allwinner features USB3 and PCIe
>> interfaces.
>> 
>> This patch adds support for it.
>
>Can you please mention in the commit message or subject line that this
>includes the SoC .dtsi? Or maybe even split this out into a separate
>patch?
>
>And is there any reason you didn't copy the official Linux DT version?
>Or is that one here just an older copy of that?
>Anyway, please use the most recent version of the .dtsi, so we can use
>that directly to pass on to the kernel.

Okay.

P.S. it's "oldest", not "older".

>
>Thanks!
>Andre.
>
>> As this is a new SoC supported by mainline U-Boot, the MMC env
>support
>> is dropped and only FAT env is available.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>>  arch/arm/dts/sun50i-h6.dtsi    | 140
>+++++++++++++++++++++++++++++++++
>>  arch/arm/mach-sunxi/Kconfig    |  17 +++-
>>  arch/arm/mach-sunxi/cpu_info.c |   2 +
>>  common/spl/Kconfig             |   2 +-
>>  4 files changed, 159 insertions(+), 2 deletions(-)
>>  create mode 100644 arch/arm/dts/sun50i-h6.dtsi
>> 
>> diff --git a/arch/arm/dts/sun50i-h6.dtsi
>b/arch/arm/dts/sun50i-h6.dtsi
>> new file mode 100644
>> index 0000000000..50f9146318
>> --- /dev/null
>> +++ b/arch/arm/dts/sun50i-h6.dtsi
>> @@ -0,0 +1,140 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * This file is dual-licensed: you can use it either under the terms
>> + * of the GPL or the X11 license, at your option. Note that this
>dual
>> + * licensing only applies to this file, and not this project as a
>> + * whole.
>> + *
>> + *  a) This file is free software; you can redistribute it and/or
>> + *     modify it under the terms of the GNU General Public License
>as
>> + *     published by the Free Software Foundation; either version 2
>of the
>> + *     License, or (at your option) any later version.
>> + *
>> + *     This file is distributed in the hope that it will be useful,
>> + *     but WITHOUT ANY WARRANTY; without even the implied warranty
>of
>> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *     GNU General Public License for more details.
>> + *
>> + * Or, alternatively,
>> + *
>> + *  b) Permission is hereby granted, free of charge, to any person
>> + *     obtaining a copy of this software and associated
>documentation
>> + *     files (the "Software"), to deal in the Software without
>> + *     restriction, including without limitation the rights to use,
>> + *     copy, modify, merge, publish, distribute, sublicense, and/or
>> + *     sell copies of the Software, and to permit persons to whom
>the
>> + *     Software is furnished to do so, subject to the following
>> + *     conditions:
>> + *
>> + *     The above copyright notice and this permission notice shall
>be
>> + *     included in all copies or substantial portions of the
>Software.
>> + *
>> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
>KIND,
>> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
>WARRANTIES
>> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
>> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + *     OTHER DEALINGS IN THE SOFTWARE.
>> + */
>> +
>> +#include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> +/ {
>> +	interrupt-parent = <&gic>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +
>> +	cpus {
>> +		#address-cells = <1>;
>> +		#size-cells = <0>;
>> +
>> +		cpu0: cpu at 0 {
>> +			compatible = "arm,cortex-a53", "arm,armv8";
>> +			device_type = "cpu";
>> +			reg = <0>;
>> +		};
>> +
>> +		cpu1: cpu at 1 {
>> +			compatible = "arm,cortex-a53", "arm,armv8";
>> +			device_type = "cpu";
>> +			reg = <1>;
>> +		};
>> +
>> +		cpu2: cpu at 2 {
>> +			compatible = "arm,cortex-a53", "arm,armv8";
>> +			device_type = "cpu";
>> +			reg = <2>;
>> +		};
>> +
>> +		cpu3: cpu at 3 {
>> +			compatible = "arm,cortex-a53", "arm,armv8";
>> +			device_type = "cpu";
>> +			reg = <3>;
>> +		};
>> +	};
>> +
>> +	osc24M: osc24M_clk {
>> +		#clock-cells = <0>;
>> +		compatible = "fixed-clock";
>> +		clock-frequency = <24000000>;
>> +		clock-output-names = "osc24M";
>> +	};
>> +
>> +	osc32k: osc32k_clk {
>> +		#clock-cells = <0>;
>> +		compatible = "fixed-clock";
>> +		clock-frequency = <32768>;
>> +		clock-output-names = "osc32k";
>> +	};
>> +
>> +	iosc: internal-osc-clk {
>> +		#clock-cells = <0>;
>> +		compatible = "fixed-clock";
>> +		clock-frequency = <16000000>;
>> +		clock-accuracy = <300000000>;
>> +		clock-output-names = "iosc";
>> +	};
>> +
>> +	timer {
>> +		compatible = "arm,armv8-timer";
>> +		interrupts = <GIC_PPI 13
>> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
>> +			     <GIC_PPI 14
>> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
>> +			     <GIC_PPI 11
>> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
>> +			     <GIC_PPI 10
>> +			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
>> +	};
>> +
>> +	soc {
>> +		compatible = "simple-bus";
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		ranges;
>> +
>> +		gic: interrupt-controller at 3021000 {
>> +			compatible = "arm,gic-400";
>> +			reg = <0x03021000 0x1000>,
>> +			      <0x03022000 0x2000>,
>> +			      <0x03024000 0x2000>,
>> +			      <0x03026000 0x2000>;
>> +			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
>IRQ_TYPE_LEVEL_HIGH)>;
>> +			interrupt-controller;
>> +			#interrupt-cells = <3>;
>> +		};
>> +
>> +		uart0: serial at 5000000 {
>> +			compatible = "snps,dw-apb-uart";
>> +			reg = <0x05000000 0x400>;
>> +			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
>> +			reg-shift = <2>;
>> +			reg-io-width = <4>;
>> +			clocks = <&osc24M>; /* placeholder */
>> +			status = "disabled";
>> +		};
>> +	};
>> +};
>> diff --git a/arch/arm/mach-sunxi/Kconfig
>b/arch/arm/mach-sunxi/Kconfig
>> index c2fa0533e7..cb4a9af6bf 100644
>> --- a/arch/arm/mach-sunxi/Kconfig
>> +++ b/arch/arm/mach-sunxi/Kconfig
>> @@ -82,6 +82,7 @@ config SUN8I_RSB
>>  config SUNXI_SRAM_ADDRESS
>>  	hex
>>  	default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
>> +	default 0x20000 if MACH_SUN50I_H6
>>  	default 0x0
>>  	---help---
>>  	Older Allwinner SoCs have their mask boot ROM mapped just below
>4GB,
>> @@ -281,6 +282,14 @@ config MACH_SUN50I_H5
>>  	select FIT
>>  	select SPL_LOAD_FIT
>>  
>> +config MACH_SUN50I_H6
>> +	bool "sun50i (Allwinner H6)"
>> +	select ARM64
>> +	select SUPPORT_SPL
>> +	select FIT
>> +	select SPL_LOAD_FIT
>> +	select DRAM_SUN50I_H6
>> +
>>  endchoice
>>  
>>  # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23
>|| A33"
>> @@ -374,6 +383,7 @@ config DRAM_CLK
>>  	default 360 if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || \
>>  		       MACH_SUN8I_V3S
>>  	default 672 if MACH_SUN50I
>> +	default 744 if MACH_SUN50I_H6
>>  	---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
>> @@ -393,7 +403,7 @@ config DRAM_ZQ
>>  	default 123 if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || MACH_SUN8I
>>  	default 127 if MACH_SUN7I
>>  	default 14779 if MACH_SUN8I_V3S
>> -	default 3881979 if MACH_SUN8I_R40
>> +	default 3881979 if MACH_SUN8I_R40 || MACH_SUN50I_H6
>>  	default 4145117 if MACH_SUN9I
>>  	default 3881915 if MACH_SUN50I
>>  	---help---
>> @@ -405,6 +415,7 @@ config DRAM_ODT_EN
>>  	default y if MACH_SUN8I_A23
>>  	default y if MACH_SUN8I_R40
>>  	default y if MACH_SUN50I
>> +	default y if MACH_SUN50I_H6
>>  	---help---
>>  	Select this to enable dram odt (on die termination).
>>  
>> @@ -495,6 +506,7 @@ config SYS_CLK_FREQ
>>  	default 816000000 if MACH_SUN50I || MACH_SUN50I_H5
>>  	default 1008000000 if MACH_SUN8I
>>  	default 1008000000 if MACH_SUN9I
>> +	default 888000000 if MACH_SUN50I_H6
>>  
>>  config SYS_CONFIG_NAME
>>  	default "sun4i" if MACH_SUN4I
>> @@ -504,6 +516,7 @@ config SYS_CONFIG_NAME
>>  	default "sun8i" if MACH_SUN8I
>>  	default "sun9i" if MACH_SUN9I
>>  	default "sun50i" if MACH_SUN50I
>> +	default "sun50i" if MACH_SUN50I_H6
>>  
>>  config SYS_BOARD
>>  	default "sunxi"
>> @@ -709,6 +722,7 @@ config VIDEO_SUNXI
>>  	depends on !MACH_SUN8I_V3S
>>  	depends on !MACH_SUN9I
>>  	depends on !MACH_SUN50I
>> +	depends on !MACH_SUN50I_H6
>>  	select VIDEO
>>  	imply VIDEO_DT_SIMPLEFB
>>  	default y
>> @@ -941,6 +955,7 @@ config SPL_STACK_R_ADDR
>>  	default 0x4fe00000 if MACH_SUN8I
>>  	default 0x2fe00000 if MACH_SUN9I
>>  	default 0x4fe00000 if MACH_SUN50I
>> +	default 0x4fe00000 if MACH_SUN50I_H6
>>  
>>  config SPL_SPI_SUNXI
>>  	bool "Support for SPI Flash on Allwinner SoCs in SPL"
>> diff --git a/arch/arm/mach-sunxi/cpu_info.c
>b/arch/arm/mach-sunxi/cpu_info.c
>> index 25a5ec26a0..90aff395dc 100644
>> --- a/arch/arm/mach-sunxi/cpu_info.c
>> +++ b/arch/arm/mach-sunxi/cpu_info.c
>> @@ -97,6 +97,8 @@ int print_cpuinfo(void)
>>  	puts("CPU:   Allwinner A64 (SUN50I)\n");
>>  #elif defined CONFIG_MACH_SUN50I_H5
>>  	puts("CPU:   Allwinner H5 (SUN50I)\n");
>> +#elif defined CONFIG_MACH_SUN50I_H6
>> +	puts("CPU:   Allwinner H6 (SUN50I)\n");
>>  #else
>>  #warning Please update cpu_info.c with correct CPU information
>>  	puts("CPU:   SUNXI Family\n");
>> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
>> index 4d27565566..e761bda6f1 100644
>> --- a/common/spl/Kconfig
>> +++ b/common/spl/Kconfig
>> @@ -246,7 +246,7 @@ config SPL_SHA256_SUPPORT
>>  config SPL_FIT_IMAGE_TINY
>>  	bool "Remove functionality from SPL FIT loading to reduce size"
>>  	depends on SPL_FIT
>> -	default y if MACH_SUN50I || MACH_SUN50I_H5
>> +	default y if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6
>>  	help
>>  	  Enable this to reduce the size of the FIT image loading code
>>  	  in SPL, if space for the SPL binary is very tight.
>> 

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

* [U-Boot] [linux-sunxi] [PATCH 11/13] sunxi: add DRAM support to H6
  2018-06-27 10:49     ` Icenowy Zheng
@ 2018-06-27 17:29       ` Andre Przywara
  0 siblings, 0 replies; 36+ messages in thread
From: Andre Przywara @ 2018-06-27 17:29 UTC (permalink / raw)
  To: u-boot

Hi,

On 27/06/18 11:49, Icenowy Zheng wrote:
> 在 2018-06-27三的 10:46 +0100,Andre Przywara写道:
>> Hi,
>>
>> On 25/06/18 11:37, Icenowy Zheng wrote:
>>> The Allwinner H6 SoC comes with a set of new DRAM controller+PHY
>>> combo.
>>> Both the controller and the PHY seem to be originate from
>>> DesignWare,
>>> and are similar to the ones in ZynqMP SoCs.
>>>
>>> This commit introduces an initial DRAM driver for H6, which
>>> contains
>>> only LPDDR3 support. The currently known SBCs with H6 all come with
>>> LPDDR3 memory, including Pine H64 and several Orange Pi's.
>>>
>>> The BSP DRAM initialization code is closed source and violates GPL.
>>> Code
>>> in this commit is written by experimenting, referring the
>>> code/document
>>> of other users of the IPs (mainly the ZynqMP, as it's the only
>>> found PHY
>>> reference) and disassebling the BSP blob.
>>>
>>> Thanks for Jernej Skrabec for review and fix some issues in this
>>> driver
>>> (including the most critical one which made it to work), and
>>> rewrite
>>> some code from register dump!
>>
>> It seems that you guys really spent a lot of time and work into this,
>> thanks a lot for that!
>> Just skimming over the code, that looks vaguely similar to the
>> existing
>> dram_sunxi_dw.c driver. I guess you considered and dismissed that 
> 
> They're quite different. The "sunxi_dw" memory controller is a
> controller+PHY combo, and address translation happen on the "mctl_com"
> part, with just address feed; the H6 memory controller have dedicated
> controller and PHY parts, like A23/A80, with a similar but enhanced
> controller and a quite different PHY (both the controller and the PHY
> are similar to the ones on ZynqMP), and address translation is also
> dropped from mctl_com, instead done by the memory controller (the
> ADDRMAPx registers).
> 
> The main part that should seem similar on all SoCs is the mctl_com
> priority code, which is not only similar with sunxi_dw but also with
> A23/A33/A83T/A80 (although I think A33/A83T are also similar with
> sunxi_dw).
> 
> Other similar parts are similar because they all originate from
> Allwinner's code, but with different controller (different offsets,
> different bit definition, etc).

Thanks a lot for that comprehensive answer, and I was afraid of
something like that :-)

> Maybe I should add a comment somewhere to describe the different?

Yeah, it would be helpful to not loose this information.
I was always wondering if we should try to unify DRAM controller
drivers, starting with the other Allwinner SoCs, but also looking at
other platforms. I see that this is quite some work, but this research
of yours above would be quite beneficial for that task.

Cheers,
Andre.

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

* [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL)
  2018-06-25 13:02     ` Jagan Teki
@ 2018-07-19 18:14       ` Jagan Teki
  0 siblings, 0 replies; 36+ messages in thread
From: Jagan Teki @ 2018-07-19 18:14 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 25, 2018 at 6:32 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> On Mon, Jun 25, 2018 at 6:19 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>>
>>
>> 于 2018年6月25日 GMT+08:00 下午8:40:21, Jagan Teki <jagan@amarulasolutions.com> 写到:
>>>On Mon, Jun 25, 2018 at 4:07 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>>>> This patch trys to add support for Allwinner H6 SoC to U-Boot.
>>>>
>>>> Allwinner H6 is a quite new Allwinner SoC, with several parts changed
>>>a
>>>> lot (memory map, DRAM controller, CCU, so on). The position which SPL
>>>> will be loaded (SRAM A1) also changed to 0x20000.
>>>>
>>>> The Pine H64 board support comes with this patchset, as this is the
>>>> first H6 board that I can get (being early bird).
>>>>
>>>> Icenowy Zheng (13):
>>>>   sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS
>>>>   sunxi: add basical memory map definitions of H6 SoC
>>>>   sunxi: change RMR64's RVBAR address for H6
>>>>   sunxi: change ATF position for H6
>>>>   sunxi: add config for SPL at 0x20000 on H6
>>>>   sunxi: change GIC address on H6
>>>>   sunxi: add clock code for H6
>>>>   sunxi: use sun6i-style watchdog for H6
>>>>   sunxi: add UART0 setup for H6
>>>>   sunxi: add MMC support for H6
>>>>   sunxi: add DRAM support to H6
>>>>   sunxi: add support for Allwinner H6 SoC
>>>>   sunxi: add support for Pine H64 board
>>>
>>>is it on top of master? unable to apply for testing on master, point
>>>me the branch would help.
>>
>> sunxi/next.
>
> please send it, on top of master

Are you planning to send v2, if so please rebase it on master.

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

end of thread, other threads:[~2018-07-19 18:14 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-25 10:37 [U-Boot] [PATCH 00/13] Allwinner H6 support (w/ SPL) Icenowy Zheng
2018-06-25 10:37 ` [U-Boot] [PATCH 01/13] sunxi: change SUNXI_HIGH_SRAM option to SUNXI_SRAM_ADDRESS Icenowy Zheng
2018-06-25 12:30   ` Maxime Ripard
2018-06-26 10:34   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 02/13] sunxi: add basical memory map definitions of H6 SoC Icenowy Zheng
2018-06-25 12:33   ` Maxime Ripard
2018-06-25 12:50     ` Icenowy Zheng
2018-06-25 17:07       ` Maxime Ripard
2018-06-26 10:35       ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-27  8:51   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 03/13] sunxi: change RMR64's RVBAR address for H6 Icenowy Zheng
2018-06-26 10:37   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 04/13] sunxi: change ATF position " Icenowy Zheng
2018-06-26 10:56   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 05/13] sunxi: add config for SPL at 0x20000 on H6 Icenowy Zheng
2018-06-26 10:56   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 06/13] sunxi: change GIC address " Icenowy Zheng
2018-06-26 10:56   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 07/13] sunxi: add clock code for H6 Icenowy Zheng
2018-06-26 13:04   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 08/13] sunxi: use sun6i-style watchdog " Icenowy Zheng
2018-06-25 10:37 ` [U-Boot] [PATCH 09/13] sunxi: add UART0 setup " Icenowy Zheng
2018-06-26 11:01   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 10/13] sunxi: add MMC support " Icenowy Zheng
2018-06-25 10:37 ` [U-Boot] [PATCH 11/13] sunxi: add DRAM support to H6 Icenowy Zheng
2018-06-27  9:46   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-27 10:49     ` Icenowy Zheng
2018-06-27 17:29       ` Andre Przywara
2018-06-25 10:37 ` [U-Boot] [PATCH 12/13] sunxi: add support for Allwinner H6 SoC Icenowy Zheng
2018-06-27 14:04   ` [U-Boot] [linux-sunxi] " Andre Przywara
2018-06-27 14:26     ` Icenowy Zheng
2018-06-25 10:37 ` [U-Boot] [PATCH 13/13] sunxi: add support for Pine H64 board Icenowy Zheng
2018-06-25 12:40 ` [U-Boot] [linux-sunxi] [PATCH 00/13] Allwinner H6 support (w/ SPL) Jagan Teki
2018-06-25 12:49   ` Icenowy Zheng
2018-06-25 13:02     ` Jagan Teki
2018-07-19 18:14       ` Jagan Teki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.