[U-Boot] [PATCH 0/6] Allwinner DesignWare-like DRAM controllers refactor

Allwinner SoCs after H3 (including H3) seems to use similar DRAM controllers, which seems to originate from DesignWare.
This patchset did a series of refactors on it, which makes it possible to support more situations (Allwinner V3s' 16-bit controller and DDR2 DRAM, Pinebook early prototype's dual-rank DDR3, SoPine/Pinebook production batch's dual-rank LPDDR3). For extra DRAM types (DDR2/LPDDR3) additional patches are needed, but they are now much easier to write.
This patchset is only part of the original patchset by me which adds V3s DRAM support. It's taken out because supporting LPDDR3 needs this patchset. For V3s SPL support I will have another patchset, which depends on the not-yet-merged V3s support w/o SPL patchset.
Icenowy Zheng (6): sunxi: makes an invisible option for H3-like DRAM controllers sunxi: Rename bus-width related macros in H3 DRAM code sunxi: add option for 16-bit DW DRAM controller sunxi: add bank detection code to H3 DRAM initialization code sunxi: Add selective DRAM type and timing sunxi: enable dual rank detection in DesignWare-like DRAM code
arch/arm/include/asm/arch-sunxi/dram.h | 4 +- .../{dram_sun8i_h3.h => dram_sunxi_dw.h} | 36 ++++- arch/arm/mach-sunxi/Makefile | 3 +- .../{dram_sun8i_h3.c => dram_sunxi_dw.c} | 176 +++++++-------------- arch/arm/mach-sunxi/dram_timings/Makefile | 1 + arch/arm/mach-sunxi/dram_timings/ddr3_1333.c | 84 ++++++++++ board/sunxi/Kconfig | 43 +++++ 7 files changed, 219 insertions(+), 128 deletions(-) rename arch/arm/include/asm/arch-sunxi/{dram_sun8i_h3.h => dram_sunxi_dw.h} (85%) rename arch/arm/mach-sunxi/{dram_sun8i_h3.c => dram_sunxi_dw.c} (79%) create mode 100644 arch/arm/mach-sunxi/dram_timings/Makefile create mode 100644 arch/arm/mach-sunxi/dram_timings/ddr3_1333.c

Allwinner SoCs after H3 (e.g. A64, H5, R40, V3s) uses a H3-like DesignWare DRAM controller, which do not have official free DRAM initialization code, but can use modified dram_sun8i_h3.c.
Add a invisible option for easier DRAM initialization code reuse.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz Acked-by: Maxime Ripard maxime.ripard@free-electrons.com --- arch/arm/include/asm/arch-sunxi/dram.h | 4 ++-- .../include/asm/arch-sunxi/{dram_sun8i_h3.h => dram_sunxi_dw.h} | 0 arch/arm/mach-sunxi/Makefile | 2 +- arch/arm/mach-sunxi/{dram_sun8i_h3.c => dram_sunxi_dw.c} | 0 board/sunxi/Kconfig | 9 +++++++++ 5 files changed, 12 insertions(+), 3 deletions(-) rename arch/arm/include/asm/arch-sunxi/{dram_sun8i_h3.h => dram_sunxi_dw.h} (100%) rename arch/arm/mach-sunxi/{dram_sun8i_h3.c => dram_sunxi_dw.c} (100%)
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 53e6d471d2..80abac95b8 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -24,8 +24,8 @@ #include <asm/arch/dram_sun8i_a33.h> #elif defined(CONFIG_MACH_SUN8I_A83T) #include <asm/arch/dram_sun8i_a83t.h> -#elif defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I) -#include <asm/arch/dram_sun8i_h3.h> +#elif defined(CONFIG_SUNXI_DRAM_DW) +#include <asm/arch/dram_sunxi_dw.h> #elif defined(CONFIG_MACH_SUN9I) #include <asm/arch/dram_sun9i.h> #else diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h similarity index 100% rename from arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h rename to arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 7daba1169c..b8f01e3b61 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_MACH_SUN7I) += dram_sun4i.o obj-$(CONFIG_MACH_SUN8I_A23) += dram_sun8i_a23.o obj-$(CONFIG_MACH_SUN8I_A33) += dram_sun8i_a33.o obj-$(CONFIG_MACH_SUN8I_A83T) += dram_sun8i_a83t.o -obj-$(CONFIG_MACH_SUN8I_H3) += dram_sun8i_h3.o +obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_MACH_SUN9I) += dram_sun9i.o obj-$(CONFIG_MACH_SUN50I) += dram_sun8i_h3.o endif diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c similarity index 100% rename from arch/arm/mach-sunxi/dram_sun8i_h3.c rename to arch/arm/mach-sunxi/dram_sunxi_dw.c diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 56b7513fe3..e71fdaee86 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -42,6 +42,13 @@ config SUNXI_GEN_SUN6I separate ahb reset control registers, custom pmic bus, new style watchdog, etc.
+config SUNXI_DRAM_DW + bool + ---help--- + Select this for sunxi SoCs which uses a DRAM controller like the + DesignWare controller used in H3, mainly SoCs after H3, which do + not have official open-source DRAM initialization code, but can + use modified H3 DRAM initialization code.
choice prompt "Sunxi SoC Variant" @@ -113,6 +120,7 @@ config MACH_SUN8I_H3 select ARCH_SUPPORT_PSCI select SUNXI_GEN_SUN6I select SUPPORT_SPL + select SUNXI_DRAM_DW select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN8I_V3S @@ -135,6 +143,7 @@ config MACH_SUN50I select ARM64 select SUNXI_GEN_SUN6I select SUPPORT_SPL + select SUNXI_DRAM_DW
endchoice

On 13/03/17 17:50, Icenowy Zheng wrote:
Hi Icenowy,
as mentioned before, I like this patch. In general, can you rebase this series on top of sunxi/master? There are some rather easy conflicts due to the H5 support being merged in.
One minor thing below...
Allwinner SoCs after H3 (e.g. A64, H5, R40, V3s) uses a H3-like DesignWare DRAM controller, which do not have official free DRAM initialization code, but can use modified dram_sun8i_h3.c.
Add a invisible option for easier DRAM initialization code reuse.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
arch/arm/include/asm/arch-sunxi/dram.h | 4 ++-- .../include/asm/arch-sunxi/{dram_sun8i_h3.h => dram_sunxi_dw.h} | 0 arch/arm/mach-sunxi/Makefile | 2 +- arch/arm/mach-sunxi/{dram_sun8i_h3.c => dram_sunxi_dw.c} | 0 board/sunxi/Kconfig | 9 +++++++++ 5 files changed, 12 insertions(+), 3 deletions(-) rename arch/arm/include/asm/arch-sunxi/{dram_sun8i_h3.h => dram_sunxi_dw.h} (100%) rename arch/arm/mach-sunxi/{dram_sun8i_h3.c => dram_sunxi_dw.c} (100%)
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 53e6d471d2..80abac95b8 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -24,8 +24,8 @@ #include <asm/arch/dram_sun8i_a33.h> #elif defined(CONFIG_MACH_SUN8I_A83T) #include <asm/arch/dram_sun8i_a83t.h> -#elif defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I) -#include <asm/arch/dram_sun8i_h3.h> +#elif defined(CONFIG_SUNXI_DRAM_DW) +#include <asm/arch/dram_sunxi_dw.h> #elif defined(CONFIG_MACH_SUN9I) #include <asm/arch/dram_sun9i.h> #else diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h similarity index 100% rename from arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h rename to arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 7daba1169c..b8f01e3b61 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_MACH_SUN7I) += dram_sun4i.o obj-$(CONFIG_MACH_SUN8I_A23) += dram_sun8i_a23.o obj-$(CONFIG_MACH_SUN8I_A33) += dram_sun8i_a33.o obj-$(CONFIG_MACH_SUN8I_A83T) += dram_sun8i_a83t.o -obj-$(CONFIG_MACH_SUN8I_H3) += dram_sun8i_h3.o +obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o obj-$(CONFIG_MACH_SUN9I) += dram_sun9i.o obj-$(CONFIG_MACH_SUN50I) += dram_sun8i_h3.o
This line needs to be removed as well, otherwise you break the build for A64 boards.
Cheers, Andre.
endif diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c similarity index 100% rename from arch/arm/mach-sunxi/dram_sun8i_h3.c rename to arch/arm/mach-sunxi/dram_sunxi_dw.c diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 56b7513fe3..e71fdaee86 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -42,6 +42,13 @@ config SUNXI_GEN_SUN6I separate ahb reset control registers, custom pmic bus, new style watchdog, etc.
+config SUNXI_DRAM_DW
- bool
- ---help---
- Select this for sunxi SoCs which uses a DRAM controller like the
- DesignWare controller used in H3, mainly SoCs after H3, which do
- not have official open-source DRAM initialization code, but can
- use modified H3 DRAM initialization code.
choice prompt "Sunxi SoC Variant" @@ -113,6 +120,7 @@ config MACH_SUN8I_H3 select ARCH_SUPPORT_PSCI select SUNXI_GEN_SUN6I select SUPPORT_SPL
- select SUNXI_DRAM_DW select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN8I_V3S @@ -135,6 +143,7 @@ config MACH_SUN50I select ARM64 select SUNXI_GEN_SUN6I select SUPPORT_SPL
- select SUNXI_DRAM_DW
endchoice

The DesignWare DRAM controller used by H3 and newer SoCs use a bit to identify whether the DRAM is half-width.
As H3 itself come with 32-bit DRAM, the two modes of the bit used to be named "MCTL_CR_32BIT" and "MCTL_CR_16BIT", but for SoCs with 16-bit DRAM they're really 8-bit and 16-bit.
Rename the bit's macro, and also rename the variable name in dram_sun8i_h3.c.
This commit do not add 16-bit DRAM controller support, but the support will be introduced in next commit.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h | 6 +++--- arch/arm/mach-sunxi/dram_sunxi_dw.c | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h index 25d07d9863..48bd6f7c0f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h @@ -52,9 +52,9 @@ struct sunxi_mctl_com_reg { #define MCTL_CR_SEQUENTIAL (0x1 << 15) #define MCTL_CR_INTERLEAVED (0x0 << 15)
-#define MCTL_CR_32BIT (0x1 << 12) -#define MCTL_CR_16BIT (0x0 << 12) -#define MCTL_CR_BUS_WIDTH(x) ((x) == 32 ? MCTL_CR_32BIT : MCTL_CR_16BIT) +#define MCTL_CR_FULL_WIDTH (0x1 << 12) +#define MCTL_CR_HALF_WIDTH (0x0 << 12) +#define MCTL_CR_BUS_FULL_WIDTH(x) ((x) << 12)
#define MCTL_CR_PAGE_SIZE(x) ((fls(x) - 4) << 8) #define MCTL_CR_ROW_BITS(x) (((x) - 1) << 4) diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 9f7cc7fd4c..0c73a43075 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -28,7 +28,7 @@ #define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) struct dram_para { u16 page_size; - u8 bus_width; + u8 bus_full_width; u8 dual_rank; u8 row_bits; const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; @@ -358,7 +358,8 @@ static void mctl_set_cr(struct dram_para *para) (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED | - MCTL_CR_EIGHT_BANKS | MCTL_CR_BUS_WIDTH(para->bus_width) | + MCTL_CR_EIGHT_BANKS | + MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) | (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | MCTL_CR_PAGE_SIZE(para->page_size) | MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr); @@ -471,7 +472,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) }
/* set half DQ */ - if (para->bus_width != 32) { + if (!para->bus_full_width) { writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr); } @@ -509,7 +510,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) { writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr); - para->bus_width = 16; + para->bus_full_width = 0; }
mctl_set_cr(para); @@ -613,7 +614,7 @@ unsigned long sunxi_dram_init(void)
struct dram_para para = { .dual_rank = 0, - .bus_width = 32, + .bus_full_width = 1, .row_bits = 15, .page_size = 4096,

On 13/03/17 17:50, Icenowy Zheng wrote:
The DesignWare DRAM controller used by H3 and newer SoCs use a bit to identify whether the DRAM is half-width.
As H3 itself come with 32-bit DRAM, the two modes of the bit used to be named "MCTL_CR_32BIT" and "MCTL_CR_16BIT", but for SoCs with 16-bit DRAM they're really 8-bit and 16-bit.
Rename the bit's macro, and also rename the variable name in dram_sun8i_h3.c.
This commit do not add 16-bit DRAM controller support, but the support will be introduced in next commit.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz
arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h | 6 +++--- arch/arm/mach-sunxi/dram_sunxi_dw.c | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h index 25d07d9863..48bd6f7c0f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h @@ -52,9 +52,9 @@ struct sunxi_mctl_com_reg { #define MCTL_CR_SEQUENTIAL (0x1 << 15) #define MCTL_CR_INTERLEAVED (0x0 << 15)
-#define MCTL_CR_32BIT (0x1 << 12) -#define MCTL_CR_16BIT (0x0 << 12) -#define MCTL_CR_BUS_WIDTH(x) ((x) == 32 ? MCTL_CR_32BIT : MCTL_CR_16BIT) +#define MCTL_CR_FULL_WIDTH (0x1 << 12) +#define MCTL_CR_HALF_WIDTH (0x0 << 12) +#define MCTL_CR_BUS_FULL_WIDTH(x) ((x) << 12)
#define MCTL_CR_PAGE_SIZE(x) ((fls(x) - 4) << 8) #define MCTL_CR_ROW_BITS(x) (((x) - 1) << 4) diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 9f7cc7fd4c..0c73a43075 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -28,7 +28,7 @@ #define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) struct dram_para { u16 page_size;
- u8 bus_width;
- u8 bus_full_width;
So this could be a "bool" then? And wouldn't it be better to _add_ this variable and keep bus width, so it could be re-purposed as the actual bus width in the next patch?
The rest of the patch is fine.
Cheers, Andre.
u8 dual_rank; u8 row_bits; const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; @@ -358,7 +358,8 @@ static void mctl_set_cr(struct dram_para *para) (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED |
MCTL_CR_EIGHT_BANKS | MCTL_CR_BUS_WIDTH(para->bus_width) |
MCTL_CR_EIGHT_BANKS |
MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) | (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | MCTL_CR_PAGE_SIZE(para->page_size) | MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
@@ -471,7 +472,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) }
/* set half DQ */
- if (para->bus_width != 32) {
- if (!para->bus_full_width) { writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr); }
@@ -509,7 +510,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) { writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr);
para->bus_width = 16;
para->bus_full_width = 0;
}
mctl_set_cr(para);
@@ -613,7 +614,7 @@ unsigned long sunxi_dram_init(void)
struct dram_para para = { .dual_rank = 0,
.bus_width = 32,
.row_bits = 15, .page_size = 4096,.bus_full_width = 1,

Some Allwinner SoCs features a DesignWare-like controller with only 16 bit bus width.
Add support for them.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/mach-sunxi/dram_sunxi_dw.c | 34 +++++++++++++++++++++++++++++----- board/sunxi/Kconfig | 16 ++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 0c73a43075..b08998c0d1 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -298,6 +298,13 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para) { struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + int zq_count; + +#if defined CONFIG_SUNXI_DRAM_DW_16BIT + zq_count = 4; +#else + zq_count = 6; +#endif
if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 && (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) { @@ -326,7 +333,7 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
- for (i = 0; i < 6; i++) { + for (i = 0; i < zq_count; i++) { u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
writel((zq << 20) | (zq << 16) | (zq << 12) | @@ -348,7 +355,9 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]); writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]); - writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); + if (zq_count > 4) + writel((zq_val[5] << 16) | zq_val[4], + &mctl_ctl->zqdr[2]); } }
@@ -473,8 +482,14 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para)
/* set half DQ */ if (!para->bus_full_width) { +#if defined CONFIG_SUNXI_DRAM_DW_32BIT writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr); +#elif defined CONFIG_SUNXI_DRAM_DW_16BIT + writel(0x0, &mctl_ctl->dx[1].gcr); +#else +#error Unsupported DRAM bus width! +#endif }
/* data training configuration */ @@ -499,20 +514,29 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) /* detect ranks and bus width */ if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) { /* only one rank */ - if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) || - ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)) { + if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) +#if defined CONFIG_SUNXI_DRAM_DW_32BIT + || ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2) +#endif + ) { clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24); para->dual_rank = 0; }
/* only half DQ width */ +#if defined CONFIG_SUNXI_DRAM_DW_32BIT if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) || ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) { writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr); para->bus_full_width = 0; } - +#elif defined CONFIG_SUNXI_DRAM_DW_16BIT + if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) { + writel(0x0, &mctl_ctl->dx[1].gcr); + para->bus_full_width = 0; + } +#endif mctl_set_cr(para); udelay(20);
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index e71fdaee86..d8a1e341e8 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -50,6 +50,20 @@ config SUNXI_DRAM_DW not have official open-source DRAM initialization code, but can use modified H3 DRAM initialization code.
+if SUNXI_DRAM_DW +config SUNXI_DRAM_DW_16BIT + bool + ---help--- + Select this for sunxi SoCs with DesignWare DRAM controller and + have only 16-bit memory buswidth. + +config SUNXI_DRAM_DW_32BIT + bool + ---help--- + Select this for sunxi SoCs with DesignWare DRAM controller with + 32-bit memory buswidth. +endif + choice prompt "Sunxi SoC Variant" optional @@ -121,6 +135,7 @@ config MACH_SUN8I_H3 select SUNXI_GEN_SUN6I select SUPPORT_SPL select SUNXI_DRAM_DW + select SUNXI_DRAM_DW_32BIT select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN8I_V3S @@ -144,6 +159,7 @@ config MACH_SUN50I select SUNXI_GEN_SUN6I select SUPPORT_SPL select SUNXI_DRAM_DW + select SUNXI_DRAM_DW_32BIT
endchoice

On 13/03/17 17:50, Icenowy Zheng wrote:
Hi Icenowy,
Some Allwinner SoCs features a DesignWare-like controller with only 16 bit bus width.
Add support for them.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz
arch/arm/mach-sunxi/dram_sunxi_dw.c | 34 +++++++++++++++++++++++++++++----- board/sunxi/Kconfig | 16 ++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 0c73a43075..b08998c0d1 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -298,6 +298,13 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
So can you confirm that this quirk is still needed for the V3s?
{ struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
- int zq_count;
+#if defined CONFIG_SUNXI_DRAM_DW_16BIT
Can we have a proper variable here, probably as a member of struct dram_para? This should work similar to the socid: the compiler would optimize out the not-needed code path.
- zq_count = 4;
And can you explain the 4 and 6 here? Either by using Jens' formula or by adding a comment?
Cheers, Andre.
+#else
- zq_count = 6;
+#endif
if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 && (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) { @@ -326,7 +333,7 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
writel(0x0a0a0a0a, &mctl_ctl->zqdr[2]);
for (i = 0; i < 6; i++) {
for (i = 0; i < zq_count; i++) { u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf; writel((zq << 20) | (zq << 16) | (zq << 12) |
@@ -348,7 +355,9 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
writel((zq_val[1] << 16) | zq_val[0], &mctl_ctl->zqdr[0]); writel((zq_val[3] << 16) | zq_val[2], &mctl_ctl->zqdr[1]);
writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]);
if (zq_count > 4)
writel((zq_val[5] << 16) | zq_val[4],
}&mctl_ctl->zqdr[2]);
}
@@ -473,8 +482,14 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para)
/* set half DQ */ if (!para->bus_full_width) { +#if defined CONFIG_SUNXI_DRAM_DW_32BIT
writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr);
+#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
writel(0x0, &mctl_ctl->dx[1].gcr);
+#else +#error Unsupported DRAM bus width! +#endif }
/* data training configuration */ @@ -499,20 +514,29 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) /* detect ranks and bus width */ if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) { /* only one rank */
if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2) ||
((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)) {
if (((readl(&mctl_ctl->dx[0].gsr[0]) >> 24) & 0x2)
+#if defined CONFIG_SUNXI_DRAM_DW_32BIT
|| ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x2)
+#endif
) { clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24); para->dual_rank = 0;
}
/* only half DQ width */
+#if defined CONFIG_SUNXI_DRAM_DW_32BIT if (((readl(&mctl_ctl->dx[2].gsr[0]) >> 24) & 0x1) || ((readl(&mctl_ctl->dx[3].gsr[0]) >> 24) & 0x1)) { writel(0x0, &mctl_ctl->dx[2].gcr); writel(0x0, &mctl_ctl->dx[3].gcr); para->bus_full_width = 0; }
+#elif defined CONFIG_SUNXI_DRAM_DW_16BIT
if ((readl(&mctl_ctl->dx[1].gsr[0]) >> 24) & 0x1) {
writel(0x0, &mctl_ctl->dx[1].gcr);
para->bus_full_width = 0;
}
+#endif mctl_set_cr(para); udelay(20);
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index e71fdaee86..d8a1e341e8 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -50,6 +50,20 @@ config SUNXI_DRAM_DW not have official open-source DRAM initialization code, but can use modified H3 DRAM initialization code.
+if SUNXI_DRAM_DW +config SUNXI_DRAM_DW_16BIT
- bool
- ---help---
- Select this for sunxi SoCs with DesignWare DRAM controller and
- have only 16-bit memory buswidth.
+config SUNXI_DRAM_DW_32BIT
- bool
- ---help---
- Select this for sunxi SoCs with DesignWare DRAM controller with
- 32-bit memory buswidth.
+endif
choice prompt "Sunxi SoC Variant" optional @@ -121,6 +135,7 @@ config MACH_SUN8I_H3 select SUNXI_GEN_SUN6I select SUPPORT_SPL select SUNXI_DRAM_DW
- select SUNXI_DRAM_DW_32BIT select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN8I_V3S @@ -144,6 +159,7 @@ config MACH_SUN50I select SUNXI_GEN_SUN6I select SUPPORT_SPL select SUNXI_DRAM_DW
- select SUNXI_DRAM_DW_32BIT
endchoice

Some DDR2 DRAM have only four banks, not eight.
Add code to detect this situation.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/mach-sunxi/dram_sunxi_dw.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index b08998c0d1..bb4457d2b8 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -31,6 +31,7 @@ struct dram_para { u8 bus_full_width; u8 dual_rank; u8 row_bits; + u8 bank_bits; const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; const u8 ac_delays[31]; @@ -367,7 +368,7 @@ static void mctl_set_cr(struct dram_para *para) (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED | - MCTL_CR_EIGHT_BANKS | + (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) | MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) | (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | MCTL_CR_PAGE_SIZE(para->page_size) | @@ -575,10 +576,19 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) /* detect row address bits */ para->page_size = 512; para->row_bits = 16; + para->bank_bits = 2; mctl_set_cr(para);
for (para->row_bits = 11; para->row_bits < 16; para->row_bits++) - if (mctl_mem_matches((1 << (para->row_bits + 3)) * para->page_size)) + if (mctl_mem_matches((1 << (para->row_bits + para->bank_bits)) * para->page_size)) + break; + + /* detect bank address bits */ + para->bank_bits = 3; + mctl_set_cr(para); + + for (para->bank_bits = 2; para->bank_bits < 3; para->bank_bits++) + if (mctl_mem_matches((1 << para->bank_bits) * para->page_size)) break;
/* detect page size */ @@ -640,6 +650,7 @@ unsigned long sunxi_dram_init(void) .dual_rank = 0, .bus_full_width = 1, .row_bits = 15, + .bank_bits = 3, .page_size = 4096,
#if defined(CONFIG_MACH_SUN8I_H3) @@ -689,6 +700,6 @@ unsigned long sunxi_dram_init(void) mctl_auto_detect_dram_size(¶); mctl_set_cr(¶);
- return (1UL << (para.row_bits + 3)) * para.page_size * - (para.dual_rank ? 2 : 1); + return (1UL << (para.row_bits + para.bank_bits)) * para.page_size * + (para.dual_rank ? 2 : 1); }

DRAM chip varies, and one code cannot satisfy all DRAMs.
Add options to select a timing set.
Currently only DDR3-1333 (the original set) is added into it.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h | 30 ++++++ arch/arm/mach-sunxi/Makefile | 1 + arch/arm/mach-sunxi/dram_sunxi_dw.c | 116 ++---------------------- arch/arm/mach-sunxi/dram_timings/Makefile | 1 + arch/arm/mach-sunxi/dram_timings/ddr3_1333.c | 84 +++++++++++++++++ board/sunxi/Kconfig | 18 ++++ 6 files changed, 140 insertions(+), 110 deletions(-) create mode 100644 arch/arm/mach-sunxi/dram_timings/Makefile create mode 100644 arch/arm/mach-sunxi/dram_timings/ddr3_1333.c
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h index 48bd6f7c0f..61da150c14 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h @@ -191,4 +191,34 @@ struct sunxi_mctl_ctl_reg { #define DXBDLR_WRITE_DELAY(x) ((x) << 8) #define DXBDLR_READ_DELAY(x) ((x) << 0)
+/* + * The delay parameters below allow to allegedly specify delay times of some + * unknown unit for each individual bit trace in each of the four data bytes + * the 32-bit wide access consists of. Also three control signals can be + * adjusted individually. + */ +#define BITS_PER_BYTE 8 +#define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE) +/* The eight data lines (DQn) plus DM, DQS and DQSN */ +#define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) +struct dram_para { + u16 page_size; + u8 bus_full_width; + u8 dual_rank; + u8 row_bits; + u8 bank_bits; + const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; + const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; + const u8 ac_delays[31]; +}; + +static inline int ns_to_t(int nanoseconds) +{ + const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2; + + return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); +} + +void mctl_set_timing_params(uint16_t socid, struct dram_para *para); + #endif /* _SUNXI_DRAM_SUN8I_H3_H */ diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index b8f01e3b61..e1b6fe8d5c 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MACH_SUN8I_A23) += dram_sun8i_a23.o obj-$(CONFIG_MACH_SUN8I_A33) += dram_sun8i_a33.o obj-$(CONFIG_MACH_SUN8I_A83T) += dram_sun8i_a83t.o obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o +obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/ obj-$(CONFIG_MACH_SUN9I) += dram_sun9i.o obj-$(CONFIG_MACH_SUN50I) += dram_sun8i_h3.o endif diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index bb4457d2b8..3629d34f71 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -16,34 +16,6 @@ #include <asm/arch/cpu.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 BITS_PER_BYTE 8 -#define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE) -/* The eight data lines (DQn) plus DM, DQS and DQSN */ -#define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) -struct dram_para { - u16 page_size; - u8 bus_full_width; - u8 dual_rank; - u8 row_bits; - u8 bank_bits; - const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; - const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE]; - const u8 ac_delays[31]; -}; - -static inline int ns_to_t(int nanoseconds) -{ - const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2; - - return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); -} - static void mctl_phy_init(u32 val) { struct sunxi_mctl_ctl_reg * const mctl_ctl = @@ -190,87 +162,6 @@ static void mctl_set_master_priority(uint16_t socid) } }
-static void mctl_set_timing_params(uint16_t socid, struct dram_para *para) -{ - struct sunxi_mctl_ctl_reg * const mctl_ctl = - (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; - - u8 tccd = 2; - u8 tfaw = ns_to_t(50); - u8 trrd = max(ns_to_t(10), 4); - u8 trcd = ns_to_t(15); - u8 trc = ns_to_t(53); - u8 txp = max(ns_to_t(8), 3); - u8 twtr = max(ns_to_t(8), 4); - u8 trtp = max(ns_to_t(8), 4); - u8 twr = max(ns_to_t(15), 3); - u8 trp = ns_to_t(15); - u8 tras = ns_to_t(38); - u16 trefi = ns_to_t(7800) / 32; - u16 trfc = ns_to_t(350); - - u8 tmrw = 0; - u8 tmrd = 4; - u8 tmod = 12; - u8 tcke = 3; - u8 tcksrx = 5; - u8 tcksre = 5; - u8 tckesr = 4; - u8 trasmax = 24; - - u8 tcl = 6; /* CL 12 */ - u8 tcwl = 4; /* CWL 8 */ - u8 t_rdata_en = 4; - u8 wr_latency = 2; - - u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */ - u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */ - u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ - u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */ - - u8 twtp = tcwl + 2 + twr; /* WL + BL / 2 + tWR */ - u8 twr2rd = tcwl + 2 + twtr; /* WL + BL / 2 + tWTR */ - u8 trd2wr = tcl + 2 + 1 - tcwl; /* RL + BL / 2 + 2 - WL */ - - /* set mode register */ - writel(0x1c70, &mctl_ctl->mr[0]); /* CL=11, WR=12 */ - writel(0x40, &mctl_ctl->mr[1]); - writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */ - writel(0x0, &mctl_ctl->mr[3]); - - /* set DRAM timing */ - writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) | - DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras), - &mctl_ctl->dramtmg[0]); - writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc), - &mctl_ctl->dramtmg[1]); - writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) | - DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd), - &mctl_ctl->dramtmg[2]); - writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod), - &mctl_ctl->dramtmg[3]); - writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) | - DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]); - writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) | - DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke), - &mctl_ctl->dramtmg[5]); - - /* set two rank timing */ - clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xff << 8) | (0xff << 0), - (0x66 << 8) | (0x10 << 0)); - - /* set PHY interface timing, write latency and read latency configure */ - writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) | - (wr_latency << 0), &mctl_ctl->pitmg[0]); - - /* set PHY timing, PTR0-2 use default */ - writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]); - writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]); - - /* set refresh timing */ - writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg); -} - static u32 bin_to_mgray(int val) { static const u8 lookup_table[32] = { @@ -367,7 +258,12 @@ static void mctl_set_cr(struct dram_para *para) struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
- writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_DDR3 | MCTL_CR_INTERLEAVED | + writel(MCTL_CR_BL8 | MCTL_CR_INTERLEAVED | +#if defined CONFIG_SUNXI_DRAM_DDR3 + MCTL_CR_DDR3 | MCTL_CR_2T | +#else +#error Unsupported DRAM type! +#endif (para->bank_bits == 3 ? MCTL_CR_EIGHT_BANKS : MCTL_CR_FOUR_BANKS) | MCTL_CR_BUS_FULL_WIDTH(para->bus_full_width) | (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile new file mode 100644 index 0000000000..7e71c76a5c --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SUNXI_DRAM_DDR3_1333) += ddr3_1333.o diff --git a/arch/arm/mach-sunxi/dram_timings/ddr3_1333.c b/arch/arm/mach-sunxi/dram_timings/ddr3_1333.c new file mode 100644 index 0000000000..8e082c735a --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/ddr3_1333.c @@ -0,0 +1,84 @@ +#include <common.h> +#include <asm/arch/dram.h> +#include <asm/arch/cpu.h> + +void mctl_set_timing_params(uint16_t socid, struct dram_para *para) +{ + struct sunxi_mctl_ctl_reg * const mctl_ctl = + (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + + u8 tccd = 2; + u8 tfaw = ns_to_t(50); + u8 trrd = max(ns_to_t(10), 4); + u8 trcd = ns_to_t(15); + u8 trc = ns_to_t(53); + u8 txp = max(ns_to_t(8), 3); + u8 twtr = max(ns_to_t(8), 4); + u8 trtp = max(ns_to_t(8), 4); + u8 twr = max(ns_to_t(15), 3); + u8 trp = ns_to_t(15); + u8 tras = ns_to_t(38); + u16 trefi = ns_to_t(7800) / 32; + u16 trfc = ns_to_t(350); + + u8 tmrw = 0; + u8 tmrd = 4; + u8 tmod = 12; + u8 tcke = 3; + u8 tcksrx = 5; + u8 tcksre = 5; + u8 tckesr = 4; + u8 trasmax = 24; + + u8 tcl = 6; /* CL 12 */ + u8 tcwl = 4; /* CWL 8 */ + u8 t_rdata_en = 4; + u8 wr_latency = 2; + + u32 tdinit0 = (500 * CONFIG_DRAM_CLK) + 1; /* 500us */ + u32 tdinit1 = (360 * CONFIG_DRAM_CLK) / 1000 + 1; /* 360ns */ + u32 tdinit2 = (200 * CONFIG_DRAM_CLK) + 1; /* 200us */ + u32 tdinit3 = (1 * CONFIG_DRAM_CLK) + 1; /* 1us */ + + u8 twtp = tcwl + 2 + twr; /* WL + BL / 2 + tWR */ + u8 twr2rd = tcwl + 2 + twtr; /* WL + BL / 2 + tWTR */ + u8 trd2wr = tcl + 2 + 1 - tcwl; /* RL + BL / 2 + 2 - WL */ + + /* set mode register */ + writel(0x1c70, &mctl_ctl->mr[0]); /* CL=11, WR=12 */ + writel(0x40, &mctl_ctl->mr[1]); + writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */ + writel(0x0, &mctl_ctl->mr[3]); + + /* set DRAM timing */ + writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) | + DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras), + &mctl_ctl->dramtmg[0]); + writel(DRAMTMG1_TXP(txp) | DRAMTMG1_TRTP(trtp) | DRAMTMG1_TRC(trc), + &mctl_ctl->dramtmg[1]); + writel(DRAMTMG2_TCWL(tcwl) | DRAMTMG2_TCL(tcl) | + DRAMTMG2_TRD2WR(trd2wr) | DRAMTMG2_TWR2RD(twr2rd), + &mctl_ctl->dramtmg[2]); + writel(DRAMTMG3_TMRW(tmrw) | DRAMTMG3_TMRD(tmrd) | DRAMTMG3_TMOD(tmod), + &mctl_ctl->dramtmg[3]); + writel(DRAMTMG4_TRCD(trcd) | DRAMTMG4_TCCD(tccd) | DRAMTMG4_TRRD(trrd) | + DRAMTMG4_TRP(trp), &mctl_ctl->dramtmg[4]); + writel(DRAMTMG5_TCKSRX(tcksrx) | DRAMTMG5_TCKSRE(tcksre) | + DRAMTMG5_TCKESR(tckesr) | DRAMTMG5_TCKE(tcke), + &mctl_ctl->dramtmg[5]); + + /* set two rank timing */ + clrsetbits_le32(&mctl_ctl->dramtmg[8], (0xff << 8) | (0xff << 0), + (0x66 << 8) | (0x10 << 0)); + + /* set PHY interface timing, write latency and read latency configure */ + writel((0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) | + (wr_latency << 0), &mctl_ctl->pitmg[0]); + + /* set PHY timing, PTR0-2 use default */ + writel(PTR3_TDINIT0(tdinit0) | PTR3_TDINIT1(tdinit1), &mctl_ctl->ptr[3]); + writel(PTR4_TDINIT2(tdinit2) | PTR4_TDINIT3(tdinit3), &mctl_ctl->ptr[4]); + + /* set refresh timing */ + writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg); +} diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index d8a1e341e8..7e03ee8b36 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -192,6 +192,24 @@ config ARM_BOOT_HOOK_RMR This allows both the SPL and the U-Boot proper to be entered in either mode and switch to AArch64 if needed.
+if SUNXI_DRAM_DW +config SUNXI_DRAM_DDR3 + bool + +choice + prompt "DRAM Type and Timing" + default SUNXI_DRAM_DDR3_1333 + +config SUNXI_DRAM_DDR3_1333 + bool "DDR3 1333" + select SUNXI_DRAM_DDR3 + ---help--- + This option is the original only supported memory type, which suits + many H3/H5/A64 boards available now. + +endchoice +endif + config DRAM_TYPE int "sunxi dram type" depends on MACH_SUN8I_A83T

The DesignWare-like DRAM code used to set the controller defaultly to single rank mode, which makes it not able to detect the second rank.
Set the default value to dual rank, thus the rank detection code can work and finally the rank setting will be the correct value.
This change is tested on a Orange Pi One (H3, single rank), a Pine64+ 2GiB version (A64, single rank) , a Pinebook early prototype with DDR3 (A64, dual rank) and a SoPine with some LPDDR3 patch (A64, dual CS pins on one chip).
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/mach-sunxi/dram_sunxi_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 3629d34f71..e1ea6845df 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -543,7 +543,7 @@ unsigned long sunxi_dram_init(void) (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
struct dram_para para = { - .dual_rank = 0, + .dual_rank = 1, .bus_full_width = 1, .row_bits = 15, .bank_bits = 3,

On 13/03/17 17:50, Icenowy Zheng wrote:
The DesignWare-like DRAM code used to set the controller defaultly to single rank mode, which makes it not able to detect the second rank.
Set the default value to dual rank, thus the rank detection code can work and finally the rank setting will be the correct value.
This change is tested on a Orange Pi One (H3, single rank), a Pine64+ 2GiB version (A64, single rank) , a Pinebook early prototype with DDR3 (A64, dual rank) and a SoPine with some LPDDR3 patch (A64, dual CS pins on one chip).
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre.
arch/arm/mach-sunxi/dram_sunxi_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 3629d34f71..e1ea6845df 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -543,7 +543,7 @@ unsigned long sunxi_dram_init(void) (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
struct dram_para para = {
.dual_rank = 0,
.bus_full_width = 1, .row_bits = 15, .bank_bits = 3,.dual_rank = 1,
participants (2)
-
André Przywara
-
Icenowy Zheng