[U-Boot] [RFC PATCH 1/6] sunxi: makes an invisible option for H3-like DRAM controllers

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 --- arch/arm/include/asm/arch-sunxi/dram.h | 2 +- arch/arm/mach-sunxi/Makefile | 2 +- arch/arm/mach-sunxi/{dram_sun8i_h3.c => dram_sunxi_dw.c} | 0 board/sunxi/Kconfig | 9 +++++++++ 4 files changed, 11 insertions(+), 2 deletions(-) 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..1475a80196 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -24,7 +24,7 @@ #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) +#elif defined(CONFIG_SUNXI_DW_DRAM) #include <asm/arch/dram_sun8i_h3.h> #elif defined(CONFIG_MACH_SUN9I) #include <asm/arch/dram_sun9i.h> diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 7daba1169c..25d896a14e 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_DW_DRAM) += 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 018bdd12dd..d09ae6067e 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_DW_DRAM + 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_DW_DRAM select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN8I_V3S @@ -134,6 +142,7 @@ config MACH_SUN50I select ARM64 select SUNXI_GEN_SUN6I select SUPPORT_SPL + select SUNXI_DW_DRAM
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.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h index 25d07d9863..48bd6f7c0f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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,

Hi,
renaming is not quite enough, see the comments below.
On 11.02.2017 16:08, 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.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz
arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h index 25d07d9863..48bd6f7c0f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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);
This is not correct, it still disables byte 2 and 3, which don't even exist on 16bit bus devices. On a 16bit device dx[1] would have do be disabled for half width.
} @@ -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;
Same here, it only detects that byte 2 and 3 are missing, to detect half width on 16bit devices byte 1 would have to be checked in the if above. Also, the rank detection above must not check byte 1 on 16bit devices.
} 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,

12.02.2017, 01:00, "Jens Kuske" jenskuske@gmail.com:
Hi,
renaming is not quite enough, see the comments below.
On 11.02.2017 16:08, 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.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h index 25d07d9863..48bd6f7c0f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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);
This is not correct, it still disables byte 2 and 3, which don't even exist on 16bit bus devices. On a 16bit device dx[1] would have do be disabled for half width.
Yes, verified on dram_sun8i_a33.c .
} @@ -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;
Same here, it only detects that byte 2 and 3 are missing, to detect half width on 16bit devices byte 1 would have to be checked in the if above. Also, the rank detection above must not check byte 1 on 16bit devices.
}
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,
-- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

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 0c73a43075..f88c63058d 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]; @@ -358,7 +359,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) | @@ -551,10 +552,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 */ @@ -616,6 +626,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) @@ -665,6 +676,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_sun8i_h3.h | 30 ++++++ arch/arm/mach-sunxi/Makefile | 1 + arch/arm/mach-sunxi/dram_sunxi_dw.c | 127 +++--------------------- 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, 150 insertions(+), 111 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_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h index 48bd6f7c0f..61da150c14 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.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 25d896a14e..34124c4a90 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_DW_DRAM) += dram_sunxi_dw.o +obj-$(CONFIG_SUNXI_DW_DRAM) += 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 f88c63058d..fce8c76ea6 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] = { @@ -299,6 +190,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_DDR3 + zq_count = 6; +#else +#error Unsupported DRAM type! +#endif
if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 && (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) { @@ -327,7 +225,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) | @@ -349,7 +247,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]); +#if defined CONFIG_SUNXI_DRAM_DDR3 writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); +#endif } }
@@ -358,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_2T | MCTL_CR_INTERLEAVED | +#if defined CONFIG_SUNXI_DRAM_DDR3 + MCTL_CR_DDR3 | +#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 d09ae6067e..9ace29e4ac 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -175,6 +175,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_DW_DRAM +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

Hi.
On 11.02.2017 16:08, Icenowy Zheng wrote: [..]
@@ -299,6 +190,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_DDR3
- zq_count = 6;
This doesn't depend on DRAM type, but on how many ZQ calibration groups exist. H3 had three: AC, DX0/1 and DX2/3. Devices with only 16bit bus width most likely only have AC and DX0/1.
+#else +#error Unsupported DRAM type! +#endif
if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 && (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) { @@ -327,7 +225,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++) {
I think for (i = 0; i < (1 + (num_databyte_lanes / 2)) * 2; i++) would be the cleanest way of handling this, with num_databyte_lanes being chip-dependent.
But, as the name of this function already states, this is a quirk for a bug in H3, which always has 4 databyte lanes. Are you sure other chips need this quirk too? H5 and A64 for example work well with 'normal' ZQ calibration.
Jens
u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf; writel((zq << 20) | (zq << 16) | (zq << 12) |
@@ -349,7 +247,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]);
+#if defined CONFIG_SUNXI_DRAM_DDR3 writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); +#endif } }
@@ -358,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_2T | MCTL_CR_INTERLEAVED |
+#if defined CONFIG_SUNXI_DRAM_DDR3
MCTL_CR_DDR3 |
+#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) |

12.02.2017, 01:00, "Jens Kuske" jenskuske@gmail.com:
Hi.
On 11.02.2017 16:08, Icenowy Zheng wrote: [..]
@@ -299,6 +190,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_DDR3 + zq_count = 6;
This doesn't depend on DRAM type, but on how many ZQ calibration groups exist. H3 had three: AC, DX0/1 and DX2/3. Devices with only 16bit bus width most likely only have AC and DX0/1.
Is ZQ even present on DDR2? What I read is that ZQ is a new feature introduced in DDR3...
+#else +#error Unsupported DRAM type! +#endif
if ((readl(SUNXI_SRAMC_BASE + 0x24) & 0xff) == 0 && (readl(SUNXI_SRAMC_BASE + 0xf0) & 0x1) == 0) { @@ -327,7 +225,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++) {
I think for (i = 0; i < (1 + (num_databyte_lanes / 2)) * 2; i++) would be the cleanest way of handling this, with num_databyte_lanes being chip-dependent.
But, as the name of this function already states, this is a quirk for a bug in H3, which always has 4 databyte lanes. Are you sure other chips need this quirk too? H5 and A64 for example work well with 'normal' ZQ calibration.
Jens
u8 zq = (CONFIG_DRAM_ZQ >> (i * 4)) & 0xf;
writel((zq << 20) | (zq << 16) | (zq << 12) | @@ -349,7 +247,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]); +#if defined CONFIG_SUNXI_DRAM_DDR3 writel((zq_val[5] << 16) | zq_val[4], &mctl_ctl->zqdr[2]); +#endif } }
@@ -358,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_2T | MCTL_CR_INTERLEAVED | +#if defined CONFIG_SUNXI_DRAM_DDR3 + MCTL_CR_DDR3 | +#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) |
-- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

Allwinner V3s SoC features a co-packaged DDR2 DRAM chip, which needs its timing param.
Add support for it.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/mach-sunxi/dram_sunxi_dw.c | 4 ++ arch/arm/mach-sunxi/dram_timings/Makefile | 1 + arch/arm/mach-sunxi/dram_timings/ddr2_v3s.c | 84 +++++++++++++++++++++++++++++ board/sunxi/Kconfig | 10 ++++ 4 files changed, 99 insertions(+) create mode 100644 arch/arm/mach-sunxi/dram_timings/ddr2_v3s.c
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index fce8c76ea6..5e304d1915 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -194,6 +194,8 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
#if defined CONFIG_SUNXI_DRAM_DDR3 zq_count = 6; +#elif defined CONFIG_SUNXI_DRAM_DDR2 + zq_count = 4; #else #error Unsupported DRAM type! #endif @@ -261,6 +263,8 @@ static void mctl_set_cr(struct dram_para *para) writel(MCTL_CR_BL8 | MCTL_CR_2T | MCTL_CR_INTERLEAVED | #if defined CONFIG_SUNXI_DRAM_DDR3 MCTL_CR_DDR3 | +#elif defined CONFIG_SUNXI_DRAM_DDR2 + MCTL_CR_DDR2 | #else #error Unsupported DRAM type! #endif diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile index 7e71c76a5c..a4c9dc556c 100644 --- a/arch/arm/mach-sunxi/dram_timings/Makefile +++ b/arch/arm/mach-sunxi/dram_timings/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_SUNXI_DRAM_DDR3_1333) += ddr3_1333.o +obj-$(CONFIG_SUNXI_DRAM_DDR2_V3S) += ddr2_v3s.o diff --git a/arch/arm/mach-sunxi/dram_timings/ddr2_v3s.c b/arch/arm/mach-sunxi/dram_timings/ddr2_v3s.c new file mode 100644 index 0000000000..9077f86a8b --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/ddr2_v3s.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 = 1; + u8 tfaw = ns_to_t(50); + u8 trrd = max(ns_to_t(10), 2); + u8 trcd = ns_to_t(20); + u8 trc = ns_to_t(65); + u8 txp = 2; + u8 twtr = max(ns_to_t(8), 2); + u8 trtp = max(ns_to_t(8), 2); + u8 twr = max(ns_to_t(15), 3); + u8 trp = ns_to_t(15); + u8 tras = ns_to_t(45); + u16 trefi = ns_to_t(7800) / 32; + u16 trfc = ns_to_t(328); + + u8 tmrw = 0; + u8 tmrd = 2; + u8 tmod = 12; + u8 tcke = 3; + u8 tcksrx = 5; + u8 tcksre = 5; + u8 tckesr = 4; + u8 trasmax = 27; + + u8 tcl = 3; /* CL 6 */ + u8 tcwl = 3; /* CWL 6 */ + u8 t_rdata_en = 1; + u8 wr_latency = 1; + + u32 tdinit0 = (400 * CONFIG_DRAM_CLK) + 1; /* 400us */ + u32 tdinit1 = (500 * CONFIG_DRAM_CLK) / 1000 + 1; /* 500ns */ + 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(0x263, &mctl_ctl->mr[0]); + writel(0x4, &mctl_ctl->mr[1]); + writel(0x0, &mctl_ctl->mr[2]); + 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 9ace29e4ac..020371c455 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -179,6 +179,9 @@ if SUNXI_DW_DRAM config SUNXI_DRAM_DDR3 bool
+config SUNXI_DRAM_DDR2 + bool + choice prompt "DRAM Type and Timing" default SUNXI_DRAM_DDR3_1333 @@ -190,6 +193,13 @@ config SUNXI_DRAM_DDR3_1333 This option is the original only supported memory type, which suits many H3/H5/A64 boards available now.
+config SUNXI_DRAM_DDR2_V3S + bool "DDR2 found in V3s chip" + select SUNXI_DRAM_DDR2 + ---help--- + This option is only for the DDR2 memory chip which is co-packaged in + Allwinner V3s SoC. + endchoice endif

Allwinner V3s features a DRAM controller like the on in H3, but with a DDR2 DRAM.
Add support for it.
Signed-off-by: Icenowy Zheng icenowy@aosc.xyz --- arch/arm/mach-sunxi/dram_sunxi_dw.c | 3 +++ board/sunxi/Kconfig | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 5e304d1915..8d7f1df27f 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -555,6 +555,9 @@ unsigned long sunxi_dram_init(void) */ #if defined(CONFIG_MACH_SUN8I_H3) uint16_t socid = SOCID_H3; +#elif defined(CONFIG_MACH_SUN8I_V3S) + /* TODO: set delays and mbus priority for V3s */ + uint16_t socid = SOCID_H3; #elif defined(CONFIG_MACH_SUN50I) uint16_t socid = SOCID_A64; #endif diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 020371c455..0bf0579d9e 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -129,6 +129,9 @@ config MACH_SUN8I_V3S select CPU_V7_HAS_NONSEC select CPU_V7_HAS_VIRT select SUNXI_GEN_SUN6I + select SUPPORT_SPL + select SUNXI_DW_DRAM + select SUNXI_DRAM_DDR2_V3S select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
config MACH_SUN9I @@ -184,11 +187,13 @@ config SUNXI_DRAM_DDR2
choice prompt "DRAM Type and Timing" - default SUNXI_DRAM_DDR3_1333 + default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S + default SUNXI_DRAM_DDR2_V3s if MACH_SUN8I_V3S
config SUNXI_DRAM_DDR3_1333 bool "DDR3 1333" select SUNXI_DRAM_DDR3 + depends on !MACH_SUN8I_V3S ---help--- This option is the original only supported memory type, which suits many H3/H5/A64 boards available now. @@ -196,6 +201,7 @@ config SUNXI_DRAM_DDR3_1333 config SUNXI_DRAM_DDR2_V3S bool "DDR2 found in V3s chip" select SUNXI_DRAM_DDR2 + depends on MACH_SUN8I_V3S ---help--- This option is only for the DDR2 memory chip which is co-packaged in Allwinner V3s SoC.

On Sat, Feb 11, 2017 at 11:08:38PM +0800, Icenowy Zheng wrote:
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
Thanks, Maxime
participants (3)
-
Icenowy Zheng
-
Jens Kuske
-
Maxime Ripard