diff options
author | Tom Rini <trini@konsulko.com> | 2023-07-21 10:01:11 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-07-21 10:01:11 -0400 |
commit | 226ecf8be4c6a29caa86d1c9f33d5794c5732375 (patch) | |
tree | db9c1de1ba2419da90cb0984cdf9a2d7014c087f /arch | |
parent | e7f7e2e1e22fd719a8810ba488a9451635b13d1b (diff) | |
parent | ecb896cec75e98d6e5f9bcbf0a87976119443985 (diff) | |
download | u-boot-WIP/21Jul2023.zip u-boot-WIP/21Jul2023.tar.gz u-boot-WIP/21Jul2023.tar.bz2 |
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-sunxiWIP/21Jul2023
For once this adds USB support for two SoCs: the H616 and the F1C100s
series. The rest is support for LPDDR3 DRAM chips on H616 boards.
Gitlab CI passed, and I booted that briefly on an H616 and an F1C200s
board. I don't have an H616 board with LPDDR3 DRAM, but reportedly that
works for Mikhail, and doesn't regress on my DDR3 boards.
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/Kconfig | 29 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/dram_sun50i_h6.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/dram_sun50i_h616.c | 383 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/dram_sunxi_dw.c | 18 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/dram_timings/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c | 95 |
8 files changed, 370 insertions, 176 deletions
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index 6db869c..11774de 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -148,10 +148,6 @@ check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240); struct dram_para { u32 clk; enum sunxi_dram_type type; - u8 cols; - u8 rows; - u8 ranks; - u8 bus_full_width; u32 dx_odt; u32 dx_dri; u32 ca_dri; @@ -163,6 +159,12 @@ struct dram_para { u32 tpr12; }; +struct dram_config { + u8 cols; + u8 rows; + u8 ranks; + u8 bus_full_width; +}; static inline int ns_to_t(int nanoseconds) { @@ -171,6 +173,6 @@ static inline int ns_to_t(int nanoseconds) return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); } -void mctl_set_timing_params(struct dram_para *para); +void mctl_set_timing_params(const struct dram_para *para); #endif /* _SUNXI_DRAM_SUN50I_H616_H */ diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 6dcbb09..e20c3a3 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -207,7 +207,6 @@ endif config MACH_SUNXI_H3_H5 bool - select PHY_SUN4I_USB select SUNXI_DE2 select SUNXI_DRAM_DW select SUNXI_DRAM_DW_32BIT @@ -236,7 +235,6 @@ config MACH_SUNIV config MACH_SUN4I bool "sun4i (Allwinner A10)" select CPU_V7A - select PHY_SUN4I_USB select DRAM_SUN4I select SUNXI_GEN_SUN4I select SUPPORT_SPL @@ -247,7 +245,6 @@ config MACH_SUN5I bool "sun5i (Allwinner A13)" select CPU_V7A select DRAM_SUN4I - select PHY_SUN4I_USB select SUNXI_GEN_SUN4I select SUPPORT_SPL imply SPL_SYS_I2C_LEGACY @@ -261,7 +258,6 @@ config MACH_SUN6I select ARCH_SUPPORT_PSCI select SPL_ARMV7_SET_CORTEX_SMPEN select DRAM_SUN6I - select PHY_SUN4I_USB select SPL_I2C select SUN6I_PRCM select SUNXI_GEN_SUN6I @@ -277,7 +273,6 @@ config MACH_SUN7I select ARCH_SUPPORT_PSCI select SPL_ARMV7_SET_CORTEX_SMPEN select DRAM_SUN4I - select PHY_SUN4I_USB select SUNXI_GEN_SUN4I select SUPPORT_SPL select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT @@ -291,7 +286,6 @@ config MACH_SUN8I_A23 select CPU_V7_HAS_VIRT select ARCH_SUPPORT_PSCI select DRAM_SUN8I_A23 - select PHY_SUN4I_USB select SPL_I2C select SUNXI_GEN_SUN6I select SUPPORT_SPL @@ -305,7 +299,6 @@ config MACH_SUN8I_A33 select CPU_V7_HAS_VIRT select ARCH_SUPPORT_PSCI select DRAM_SUN8I_A33 - select PHY_SUN4I_USB select SPL_I2C select SUNXI_GEN_SUN6I select SUPPORT_SPL @@ -316,7 +309,6 @@ config MACH_SUN8I_A83T bool "sun8i (Allwinner A83T)" select CPU_V7A select DRAM_SUN8I_A83T - select PHY_SUN4I_USB select SPL_I2C select SUNXI_GEN_SUN6I select MMC_SUNXI_HAS_NEW_MODE @@ -344,7 +336,6 @@ config MACH_SUN8I_R40 select SUPPORT_SPL select SUNXI_DRAM_DW select SUNXI_DRAM_DW_32BIT - select PHY_SUN4I_USB imply SPL_SYS_I2C_LEGACY config MACH_SUN8I_V3S @@ -372,7 +363,6 @@ config MACH_SUN9I config MACH_SUN50I bool "sun50i (Allwinner A64)" select ARM64 - select PHY_SUN4I_USB select SUN6I_PRCM select SUNXI_DE2 select SUNXI_GEN_SUN6I @@ -395,7 +385,6 @@ config MACH_SUN50I_H5 config MACH_SUN50I_H6 bool "sun50i (Allwinner H6)" select ARM64 - select PHY_SUN4I_USB select DRAM_SUN50I_H6 select SUN50I_GEN_H6 @@ -442,7 +431,7 @@ config ARM_BOOT_HOOK_RMR This allows both the SPL and the U-Boot proper to be entered in either mode and switch to AArch64 if needed. -if SUNXI_DRAM_DW || DRAM_SUN50I_H6 +if SUNXI_DRAM_DW || DRAM_SUN50I_H6 || DRAM_SUN50I_H616 config SUNXI_DRAM_DDR3 bool @@ -487,6 +476,22 @@ config SUNXI_DRAM_H6_DDR3_1333 This option is the DDR3 timing used by the boot0 on H6 TV boxes which use a DDR3-1333 timing. +config SUNXI_DRAM_H616_LPDDR3 + bool "LPDDR3 DRAM chips on the H616 DRAM controller" + select SUNXI_DRAM_LPDDR3 + depends on DRAM_SUN50I_H616 + help + This option is the LPDDR3 timing used by the stock boot0 by + Allwinner. + +config SUNXI_DRAM_H616_DDR3_1333 + bool "DDR3-1333 boot0 timings on the H616 DRAM controller" + select SUNXI_DRAM_DDR3 + depends on DRAM_SUN50I_H616 + help + This option is the DDR3 timing used by the boot0 on H616 TV boxes + which use a DDR3-1333 timing. + config SUNXI_DRAM_DDR2_V3S bool "DDR2 found in V3s chip" select SUNXI_DRAM_DDR2 diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c index b332f3a..bff2e42 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h6.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c @@ -93,7 +93,8 @@ enum { MBUS_QOS_HIGH, MBUS_QOS_HIGHEST }; -inline void mbus_configure_port(u8 port, + +static void mbus_configure_port(u8 port, bool bwlimit, bool priority, u8 qos, diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 1f9416d..7e580b6 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -31,7 +31,7 @@ enum { MBUS_QOS_HIGHEST }; -inline void mbus_configure_port(u8 port, +static void mbus_configure_port(u8 port, bool bwlimit, bool priority, u8 qos, @@ -92,7 +92,7 @@ static void mctl_set_master_priority(void) dmb(); } -static void mctl_sys_init(struct dram_para *para) +static void mctl_sys_init(u32 clk_rate) { struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; @@ -114,7 +114,7 @@ static void mctl_sys_init(struct dram_para *para) /* Set PLL5 rate to doubled DRAM clock rate */ writel(CCM_PLL5_CTRL_EN | CCM_PLL5_LOCK_EN | CCM_PLL5_OUT_EN | - CCM_PLL5_CTRL_N(para->clk * 2 / 24), &ccm->pll5_cfg); + CCM_PLL5_CTRL_N(clk_rate * 2 / 24), &ccm->pll5_cfg); mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK, CCM_PLL5_LOCK); /* Configure DRAM mod clock */ @@ -141,15 +141,15 @@ static void mctl_sys_init(struct dram_para *para) writel(0x8000, &mctl_ctl->clken); } -static void mctl_set_addrmap(struct dram_para *para) +static void mctl_set_addrmap(const struct dram_config *config) { struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; - u8 cols = para->cols; - u8 rows = para->rows; - u8 ranks = para->ranks; + u8 cols = config->cols; + u8 rows = config->rows; + u8 ranks = config->ranks; - if (!para->bus_full_width) + if (!config->bus_full_width) cols -= 1; /* Ranks */ @@ -228,13 +228,20 @@ static void mctl_set_addrmap(struct dram_para *para) } static const u8 phy_init[] = { +#ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333 0x07, 0x0b, 0x02, 0x16, 0x0d, 0x0e, 0x14, 0x19, 0x0a, 0x15, 0x03, 0x13, 0x04, 0x0c, 0x10, 0x06, 0x0f, 0x11, 0x1a, 0x01, 0x12, 0x17, 0x00, 0x08, 0x09, 0x05, 0x18 +#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3) + 0x18, 0x06, 0x00, 0x05, 0x04, 0x03, 0x09, 0x02, + 0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x07, + 0x17, 0x19, 0x1a +#endif }; -static void mctl_phy_configure_odt(struct dram_para *para) +static void mctl_phy_configure_odt(const struct dram_para *para) { unsigned int val; @@ -263,25 +270,37 @@ static void mctl_phy_configure_odt(struct dram_para *para) writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x34c); val = para->dx_odt & 0x1f; - writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x380); + if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x380); + else + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x380); writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x384); val = (para->dx_odt >> 8) & 0x1f; - writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c0); + if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x3c0); + else + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c0); writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c4); val = (para->dx_odt >> 16) & 0x1f; - writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x400); + if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x400); + else + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x400); writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x404); val = (para->dx_odt >> 24) & 0x1f; - writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x440); + if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x440); + else + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x440); writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x444); dmb(); } -static bool mctl_phy_write_leveling(struct dram_para *para) +static bool mctl_phy_write_leveling(const struct dram_config *config) { bool result = true; u32 val; @@ -292,7 +311,7 @@ static bool mctl_phy_write_leveling(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4); - if (para->bus_full_width) + if (config->bus_full_width) val = 0xf; else val = 3; @@ -316,12 +335,12 @@ static bool mctl_phy_write_leveling(struct dram_para *para) clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0xc0); - if (para->ranks == 2) { + if (config->ranks == 2) { clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0xc0, 0x40); setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4); - if (para->bus_full_width) + if (config->bus_full_width) val = 0xf; else val = 3; @@ -336,7 +355,7 @@ static bool mctl_phy_write_leveling(struct dram_para *para) return result; } -static bool mctl_phy_read_calibration(struct dram_para *para) +static bool mctl_phy_read_calibration(const struct dram_config *config) { bool result = true; u32 val, tmp; @@ -345,7 +364,7 @@ static bool mctl_phy_read_calibration(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1); - if (para->bus_full_width) + if (config->bus_full_width) val = 0xf; else val = 3; @@ -361,7 +380,7 @@ static bool mctl_phy_read_calibration(struct dram_para *para) clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30); - if (para->ranks == 2) { + if (config->ranks == 2) { clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30, 0x10); setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1); @@ -395,7 +414,7 @@ static bool mctl_phy_read_calibration(struct dram_para *para) return result; } -static bool mctl_phy_read_training(struct dram_para *para) +static bool mctl_phy_read_training(const struct dram_config *config) { u32 val1, val2, *ptr1, *ptr2; bool result = true; @@ -414,7 +433,7 @@ static bool mctl_phy_read_training(struct dram_para *para) if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) result = false; - if (para->bus_full_width) { + if (config->bus_full_width) { mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) result = false; @@ -437,7 +456,7 @@ static bool mctl_phy_read_training(struct dram_para *para) result = false; } - if (para->bus_full_width) { + if (config->bus_full_width) { ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa98); ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa50); for (i = 0; i < 9; i++) { @@ -459,7 +478,7 @@ static bool mctl_phy_read_training(struct dram_para *para) clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3); - if (para->ranks == 2) { + if (config->ranks == 2) { /* maybe last parameter should be 1? */ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2); @@ -470,7 +489,7 @@ static bool mctl_phy_read_training(struct dram_para *para) if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) result = false; - if (para->bus_full_width) { + if (config->bus_full_width) { mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) result = false; @@ -484,7 +503,7 @@ static bool mctl_phy_read_training(struct dram_para *para) return result; } -static bool mctl_phy_write_training(struct dram_para *para) +static bool mctl_phy_write_training(const struct dram_config *config) { u32 val1, val2, *ptr1, *ptr2; bool result = true; @@ -504,7 +523,7 @@ static bool mctl_phy_write_training(struct dram_para *para) if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc) result = false; - if (para->bus_full_width) { + if (config->bus_full_width) { mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 3); if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc) result = false; @@ -527,7 +546,7 @@ static bool mctl_phy_write_training(struct dram_para *para) result = false; } - if (para->bus_full_width) { + if (config->bus_full_width) { ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xb38); ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xaf0); for (i = 0; i < 9; i++) { @@ -548,7 +567,7 @@ static bool mctl_phy_write_training(struct dram_para *para) clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60); - if (para->ranks == 2) { + if (config->ranks == 2) { clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 4); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); @@ -558,7 +577,7 @@ static bool mctl_phy_write_training(struct dram_para *para) if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc) result = false; - if (para->bus_full_width) { + if (config->bus_full_width) { mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 3); if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc) result = false; @@ -572,7 +591,7 @@ static bool mctl_phy_write_training(struct dram_para *para) return result; } -static void mctl_phy_bit_delay_compensation(struct dram_para *para) +static void mctl_phy_bit_delay_compensation(const struct dram_para *para) { u32 *ptr, val; int i; @@ -773,7 +792,8 @@ static void mctl_phy_bit_delay_compensation(struct dram_para *para) } } -static void mctl_phy_ca_bit_delay_compensation(struct dram_para *para) +static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para, + const struct dram_config *config) { u32 val, *ptr; int i; @@ -793,36 +813,53 @@ static void mctl_phy_ca_bit_delay_compensation(struct dram_para *para) writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e0); writel(val, SUNXI_DRAM_PHY0_BASE + 0x7f4); - /* following configuration is DDR3 specific */ - val = (para->tpr10 >> 7) & 0x1e; - if (para->tpr2 & 1) { - writel(val, SUNXI_DRAM_PHY0_BASE + 0x794); - if (para->ranks == 2) { - val = (para->tpr10 >> 11) & 0x1e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e4); - } - if (para->tpr0 & BIT(31)) { - val = (para->tpr0 << 1) & 0x3e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x790); - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7cc); - } - } else { - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d4); - if (para->ranks == 2) { - val = (para->tpr10 >> 11) & 0x1e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x79c); + if (para->type == SUNXI_DRAM_TYPE_DDR3) { + val = (para->tpr10 >> 7) & 0x1e; + if (para->tpr2 & 1) { + writel(val, SUNXI_DRAM_PHY0_BASE + 0x794); + if (config->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e4); + } + if (para->tpr0 & BIT(31)) { + val = (para->tpr0 << 1) & 0x3e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x790); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7cc); + } + } else { + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d4); + if (config->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x79c); + } + if (para->tpr0 & BIT(31)) { + val = (para->tpr0 << 1) & 0x3e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x78c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a4); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + } } - if (para->tpr0 & BIT(31)) { - val = (para->tpr0 << 1) & 0x3e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x78c); - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a4); - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) { + val = (para->tpr10 >> 7) & 0x1e; + if (para->tpr2 & 1) { + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a0); + if (config->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x79c); + } + } else { + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e8); + if (config->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7f8); + } } } } -static bool mctl_phy_init(struct dram_para *para) +static bool mctl_phy_init(const struct dram_para *para, + const struct dram_config *config) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; @@ -831,18 +868,29 @@ static bool mctl_phy_init(struct dram_para *para) u32 val, val2, *ptr, mr0, mr2; int i; - if (para->bus_full_width) + if (config->bus_full_width) val = 0xf; else val = 3; clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x3c, 0xf, val); if (para->tpr2 & 0x100) { - val = 9; - val2 = 7; + if (para->type == SUNXI_DRAM_TYPE_DDR3) { + val = 9; + val2 = 7; + } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) { + // untested setup: use some values for now + val = 14; + val2 = 8; + } } else { - val = 13; - val2 = 9; + if (para->type == SUNXI_DRAM_TYPE_DDR3) { + val = 13; + val2 = 9; + } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) { + val = 14; + val2 = 8; + } } writel(val, SUNXI_DRAM_PHY0_BASE + 0x14); @@ -865,14 +913,22 @@ static bool mctl_phy_init(struct dram_para *para) writel(phy_init[i], &ptr[i]); if (para->tpr10 & TPR10_CA_BIT_DELAY) - mctl_phy_ca_bit_delay_compensation(para); + mctl_phy_ca_bit_delay_compensation(para, config); - writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc); - writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x45c); + if (para->type == SUNXI_DRAM_TYPE_DDR3) + val = 0x80; + else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + val = 0xc0; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x3dc); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x45c); mctl_phy_configure_odt(para); - clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 7, 0xa); + if (para->type == SUNXI_DRAM_TYPE_DDR3) + val = 0x0a; + else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + val = 0x0b; + clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x7, val); if (para->clk <= 672) writel(0xf, SUNXI_DRAM_PHY0_BASE + 0x20); @@ -922,21 +978,39 @@ static bool mctl_phy_init(struct dram_para *para) mr2 = 0x20; } - writel(mr0, &mctl_ctl->mrctrl1); - writel(0x80000030, &mctl_ctl->mrctrl0); - mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); - - writel(4, &mctl_ctl->mrctrl1); - writel(0x80001030, &mctl_ctl->mrctrl0); - mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); - - writel(mr2, &mctl_ctl->mrctrl1); - writel(0x80002030, &mctl_ctl->mrctrl0); - mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); - - writel(0, &mctl_ctl->mrctrl1); - writel(0x80003030, &mctl_ctl->mrctrl0); - mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + if (para->type == SUNXI_DRAM_TYPE_DDR3) { + writel(mr0, &mctl_ctl->mrctrl1); + writel(0x80000030, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(4, &mctl_ctl->mrctrl1); + writel(0x80001030, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(mr2, &mctl_ctl->mrctrl1); + writel(0x80002030, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0, &mctl_ctl->mrctrl1); + writel(0x80003030, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) { + writel(mr0, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(4, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(mr2, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + + writel(0x301, &mctl_ctl->mrctrl1); + writel(0x800000f0, &mctl_ctl->mrctrl0); + mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0); + } writel(0, SUNXI_DRAM_PHY0_BASE + 0x54); @@ -946,7 +1020,7 @@ static bool mctl_phy_init(struct dram_para *para) if (para->tpr10 & TPR10_WRITE_LEVELING) { for (i = 0; i < 5; i++) - if (mctl_phy_write_leveling(para)) + if (mctl_phy_write_leveling(config)) break; if (i == 5) { debug("write leveling failed!\n"); @@ -956,7 +1030,7 @@ static bool mctl_phy_init(struct dram_para *para) if (para->tpr10 & TPR10_READ_CALIBRATION) { for (i = 0; i < 5; i++) - if (mctl_phy_read_calibration(para)) + if (mctl_phy_read_calibration(config)) break; if (i == 5) { debug("read calibration failed!\n"); @@ -966,7 +1040,7 @@ static bool mctl_phy_init(struct dram_para *para) if (para->tpr10 & TPR10_READ_TRAINING) { for (i = 0; i < 5; i++) - if (mctl_phy_read_training(para)) + if (mctl_phy_read_training(config)) break; if (i == 5) { debug("read training failed!\n"); @@ -976,7 +1050,7 @@ static bool mctl_phy_init(struct dram_para *para) if (para->tpr10 & TPR10_WRITE_TRAINING) { for (i = 0; i < 5; i++) - if (mctl_phy_write_training(para)) + if (mctl_phy_write_training(config)) break; if (i == 5) { debug("write training failed!\n"); @@ -991,7 +1065,8 @@ static bool mctl_phy_init(struct dram_para *para) return true; } -static bool mctl_ctrl_init(struct dram_para *para) +static bool mctl_ctrl_init(const struct dram_para *para, + const struct dram_config *config) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; @@ -1010,27 +1085,34 @@ static bool mctl_ctrl_init(struct dram_para *para) setbits_le32(&mctl_com->unk_0x008, 0xff00); - reg_val = MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para->ranks); - reg_val |= MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE; - if (para->bus_full_width) + reg_val = MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(config->ranks); + if (para->type == SUNXI_DRAM_TYPE_DDR3) + reg_val |= MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE; + else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + reg_val |= MSTR_DEVICETYPE_LPDDR3; + if (config->bus_full_width) reg_val |= MSTR_BUSWIDTH_FULL; else reg_val |= MSTR_BUSWIDTH_HALF; writel(BIT(31) | BIT(30) | reg_val, &mctl_ctl->mstr); - if (para->ranks == 2) + if (config->ranks == 2) writel(0x0303, &mctl_ctl->odtmap); else writel(0x0201, &mctl_ctl->odtmap); - writel(0x06000400, &mctl_ctl->odtcfg); - writel(0x06000400, &mctl_ctl->unk_0x2240); - writel(0x06000400, &mctl_ctl->unk_0x3240); - writel(0x06000400, &mctl_ctl->unk_0x4240); + if (para->type == SUNXI_DRAM_TYPE_DDR3) + reg_val = 0x06000400; + else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) + reg_val = 0x09020400; + writel(reg_val, &mctl_ctl->odtcfg); + writel(reg_val, &mctl_ctl->unk_0x2240); + writel(reg_val, &mctl_ctl->unk_0x3240); + writel(reg_val, &mctl_ctl->unk_0x4240); writel(BIT(31), &mctl_com->cr); - mctl_set_addrmap(para); + mctl_set_addrmap(config); mctl_set_timing_params(para); @@ -1056,7 +1138,7 @@ static bool mctl_ctrl_init(struct dram_para *para) /* this write seems to enable PHY MMIO region */ setbits_le32(&mctl_com->unk_0x500, BIT(24)); - if (!mctl_phy_init(para)) + if (!mctl_phy_init(para, config)) return false; writel(0, &mctl_ctl->swctl); @@ -1073,18 +1155,20 @@ static bool mctl_ctrl_init(struct dram_para *para) return true; } -static bool mctl_core_init(struct dram_para *para) +static bool mctl_core_init(const struct dram_para *para, + const struct dram_config *config) { - mctl_sys_init(para); + mctl_sys_init(para->clk); - return mctl_ctrl_init(para); + return mctl_ctrl_init(para, config); } -static void mctl_auto_detect_rank_width(struct dram_para *para) +static void mctl_auto_detect_rank_width(const struct dram_para *para, + struct dram_config *config) { /* this is minimum size that it's supported */ - para->cols = 8; - para->rows = 13; + config->cols = 8; + config->rows = 13; /* * Strategy here is to test most demanding combination first and least @@ -1095,94 +1179,101 @@ static void mctl_auto_detect_rank_width(struct dram_para *para) */ debug("testing 32-bit width, rank = 2\n"); - para->bus_full_width = 1; - para->ranks = 2; - if (mctl_core_init(para)) + config->bus_full_width = 1; + config->ranks = 2; + if (mctl_core_init(para, config)) return; debug("testing 32-bit width, rank = 1\n"); - para->bus_full_width = 1; - para->ranks = 1; - if (mctl_core_init(para)) + config->bus_full_width = 1; + config->ranks = 1; + if (mctl_core_init(para, config)) return; debug("testing 16-bit width, rank = 2\n"); - para->bus_full_width = 0; - para->ranks = 2; - if (mctl_core_init(para)) + config->bus_full_width = 0; + config->ranks = 2; + if (mctl_core_init(para, config)) return; debug("testing 16-bit width, rank = 1\n"); - para->bus_full_width = 0; - para->ranks = 1; - if (mctl_core_init(para)) + config->bus_full_width = 0; + config->ranks = 1; + if (mctl_core_init(para, config)) return; panic("This DRAM setup is currently not supported.\n"); } -static void mctl_auto_detect_dram_size(struct dram_para *para) +static void mctl_auto_detect_dram_size(const struct dram_para *para, + struct dram_config *config) { /* detect row address bits */ - para->cols = 8; - para->rows = 18; - mctl_core_init(para); + config->cols = 8; + config->rows = 18; + mctl_core_init(para, config); - for (para->rows = 13; para->rows < 18; para->rows++) { + for (config->rows = 13; config->rows < 18; config->rows++) { /* 8 banks, 8 bit per byte and 16/32 bit width */ - if (mctl_mem_matches((1 << (para->rows + para->cols + - 4 + para->bus_full_width)))) + if (mctl_mem_matches((1 << (config->rows + config->cols + + 4 + config->bus_full_width)))) break; } /* detect column address bits */ - para->cols = 11; - mctl_core_init(para); + config->cols = 11; + mctl_core_init(para, config); - for (para->cols = 8; para->cols < 11; para->cols++) { + for (config->cols = 8; config->cols < 11; config->cols++) { /* 8 bits per byte and 16/32 bit width */ - if (mctl_mem_matches(1 << (para->cols + 1 + - para->bus_full_width))) + if (mctl_mem_matches(1 << (config->cols + 1 + + config->bus_full_width))) break; } } -static unsigned long mctl_calc_size(struct dram_para *para) +static unsigned long mctl_calc_size(const struct dram_config *config) { - u8 width = para->bus_full_width ? 4 : 2; + u8 width = config->bus_full_width ? 4 : 2; /* 8 banks */ - return (1ULL << (para->cols + para->rows + 3)) * width * para->ranks; + return (1ULL << (config->cols + config->rows + 3)) * width * config->ranks; } +static const struct dram_para para = { + .clk = CONFIG_DRAM_CLK, +#ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333 + .type = SUNXI_DRAM_TYPE_DDR3, +#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3) + .type = SUNXI_DRAM_TYPE_LPDDR3, +#endif + .dx_odt = CONFIG_DRAM_SUN50I_H616_DX_ODT, + .dx_dri = CONFIG_DRAM_SUN50I_H616_DX_DRI, + .ca_dri = CONFIG_DRAM_SUN50I_H616_CA_DRI, + .odt_en = CONFIG_DRAM_SUN50I_H616_ODT_EN, + .tpr0 = CONFIG_DRAM_SUN50I_H616_TPR0, + .tpr2 = CONFIG_DRAM_SUN50I_H616_TPR2, + .tpr10 = CONFIG_DRAM_SUN50I_H616_TPR10, + .tpr11 = CONFIG_DRAM_SUN50I_H616_TPR11, + .tpr12 = CONFIG_DRAM_SUN50I_H616_TPR12, +}; + unsigned long sunxi_dram_init(void) { struct sunxi_prcm_reg *const prcm = (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; - struct dram_para para = { - .clk = CONFIG_DRAM_CLK, - .type = SUNXI_DRAM_TYPE_DDR3, - .dx_odt = CONFIG_DRAM_SUN50I_H616_DX_ODT, - .dx_dri = CONFIG_DRAM_SUN50I_H616_DX_DRI, - .ca_dri = CONFIG_DRAM_SUN50I_H616_CA_DRI, - .odt_en = CONFIG_DRAM_SUN50I_H616_ODT_EN, - .tpr0 = CONFIG_DRAM_SUN50I_H616_TPR0, - .tpr2 = CONFIG_DRAM_SUN50I_H616_TPR2, - .tpr10 = CONFIG_DRAM_SUN50I_H616_TPR10, - .tpr11 = CONFIG_DRAM_SUN50I_H616_TPR11, - .tpr12 = CONFIG_DRAM_SUN50I_H616_TPR12, - }; + struct dram_config config; unsigned long size; setbits_le32(&prcm->res_cal_ctrl, BIT(8)); clrbits_le32(&prcm->ohms240, 0x3f); - mctl_auto_detect_rank_width(¶); - mctl_auto_detect_dram_size(¶); + mctl_auto_detect_rank_width(¶, &config); + mctl_auto_detect_dram_size(¶, &config); - mctl_core_init(¶); + mctl_core_init(¶, &config); - size = mctl_calc_size(¶); + size = mctl_calc_size(&config); mctl_set_master_priority(); diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 4af5922..9382d3d 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -81,15 +81,15 @@ enum { MBUS_QOS_HIGHEST }; -static inline void mbus_configure_port(u8 port, - bool bwlimit, - bool priority, - u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */ - u8 waittime, /* 0 .. 0xf */ - u8 acs, /* 0 .. 0xff */ - u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */ - u16 bwl1, - u16 bwl2) +static void mbus_configure_port(u8 port, + bool bwlimit, + bool priority, + u8 qos, /* MBUS_QOS_LOWEST .. MBUS_QOS_HIGEST */ + u8 waittime, /* 0 .. 0xf */ + u8 acs, /* 0 .. 0xff */ + u16 bwl0, /* 0 .. 0xffff, bandwidth limit in MB/s */ + u16 bwl1, + u16 bwl2) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile index 39a8756..8bfd994 100644 --- a/arch/arm/mach-sunxi/dram_timings/Makefile +++ b/arch/arm/mach-sunxi/dram_timings/Makefile @@ -3,5 +3,5 @@ obj-$(CONFIG_SUNXI_DRAM_LPDDR3_STOCK) += lpddr3_stock.o obj-$(CONFIG_SUNXI_DRAM_DDR2_V3S) += ddr2_v3s.o obj-$(CONFIG_SUNXI_DRAM_H6_LPDDR3) += h6_lpddr3.o obj-$(CONFIG_SUNXI_DRAM_H6_DDR3_1333) += h6_ddr3_1333.o -# currently only DDR3 is supported on H616 -obj-$(CONFIG_MACH_SUN50I_H616) += h616_ddr3_1333.o +obj-$(CONFIG_SUNXI_DRAM_H616_DDR3_1333) += h616_ddr3_1333.o +obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR3) += h616_lpddr3.o diff --git a/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c index eea4d6a..232b4fe 100644 --- a/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c +++ b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c @@ -15,7 +15,7 @@ #include <asm/arch/dram.h> #include <asm/arch/cpu.h> -void mctl_set_timing_params(struct dram_para *para) +void mctl_set_timing_params(const struct dram_para *para) { struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; diff --git a/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c b/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c new file mode 100644 index 0000000..b6d6a68 --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c @@ -0,0 +1,95 @@ +/* + * sun50i H616 LPDDR3 timings, as programmed by Allwinner's boot0 + * + * The chips are probably able to be driven by a faster clock, but boot0 + * uses a more conservative timing (as usual). + * + * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net> + * Based on H6 DDR3 timings: + * (C) Copyright 2018,2019 Arm Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/dram.h> +#include <asm/arch/cpu.h> + +void mctl_set_timing_params(const 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(6), 4); + u8 trcd = ns_to_t(24); + u8 trc = ns_to_t(70); + u8 txp = max(ns_to_t(8), 3); + u8 trtp = max(ns_to_t(8), 2); + u8 trp = ns_to_t(27); + u8 tras = ns_to_t(41); + u16 trefi = ns_to_t(7800) / 64; + u16 trfc = ns_to_t(210); + u16 txsr = 88; + + u8 tmrw = 5; + u8 tmrd = 5; + u8 tmod = max(ns_to_t(15), 12); + u8 tcke = max(ns_to_t(6), 3); + u8 tcksrx = max(ns_to_t(12), 4); + u8 tcksre = max(ns_to_t(12), 4); + u8 tckesr = tcke + 2; + u8 trasmax = (para->clk / 2) / 16; + u8 txs = ns_to_t(360) / 32; + u8 txsdll = 16; + u8 txsabort = 4; + u8 txsfast = 4; + u8 tcl = 7; + u8 tcwl = 4; + u8 t_rdata_en = 12; + u8 t_wr_lat = 6; + + u8 twtp = 16; + u8 twr2rd = trtp + 9; + u8 trd2wr = 13; + + /* DRAM timing grabbed from tvbox with LPDDR3 memory */ + writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras, + &mctl_ctl->dramtmg[0]); + writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]); + writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd, + &mctl_ctl->dramtmg[2]); + writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]); + writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp, + &mctl_ctl->dramtmg[4]); + writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke, + &mctl_ctl->dramtmg[5]); + /* Value suggested by ZynqMP manual and used by libdram */ + writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]); + writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs, + &mctl_ctl->dramtmg[8]); + writel(0x00020208, &mctl_ctl->dramtmg[9]); + writel(0xE0C05, &mctl_ctl->dramtmg[10]); + writel(0x440C021C, &mctl_ctl->dramtmg[11]); + writel(8, &mctl_ctl->dramtmg[12]); + writel(0xA100002, &mctl_ctl->dramtmg[13]); + writel(txsr, &mctl_ctl->dramtmg[14]); + + writel(0x4f0112, &mctl_ctl->init[0]); + writel(0x420000, &mctl_ctl->init[1]); + writel(0xd05, &mctl_ctl->init[2]); + writel(0x83001c, &mctl_ctl->init[3]); + writel(0x00010000, &mctl_ctl->init[4]); + + writel(0, &mctl_ctl->dfimisc); + clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660); + + /* Configure DFI timing */ + writel(t_wr_lat | 0x2000000 | (t_rdata_en << 16) | 0x808000, + &mctl_ctl->dfitmg0); + writel(0x100202, &mctl_ctl->dfitmg1); + + /* set refresh timing */ + writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg); +} |