Add an H616 profile-source choice so SPL can either use the existing fixed Kconfig profile or load a DRAM profile selected by GPIO straps from the U-Boot device tree. The GPIO-selected path decodes up to four allwinner,dram-coding-gpios bits and loads the matching profile from /dram-profiles.
Refactor the H616 DRAM code so the PHY init tables and timing backend are selected at runtime from para->type, and switch the H616 timing helpers to use para->clk instead of CONFIG_DRAM_CLK. This allows a single SPL build to support multiple H616 DRAM types selected at boot while keeping fixed-profile mode as the default. Hide the fixed H616 Kconfig timing and parameter prompts when GPIO-based selection is enabled, since those settings are not used in that mode. The selector name stays H616-specific because this only models the BSP GPIO strap flow, not the GPADC-based variants. Signed-off-by: James Hilliard <[email protected]> --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 7 +- arch/arm/mach-sunxi/Kconfig | 47 ++- arch/arm/mach-sunxi/dram_sun50i_h616.c | 367 ++++++++++++++++-- arch/arm/mach-sunxi/dram_timings/Makefile | 5 +- arch/arm/mach-sunxi/dram_timings/h616.c | 27 ++ .../mach-sunxi/dram_timings/h616_ddr3_1333.c | 32 +- .../arm/mach-sunxi/dram_timings/h616_lpddr3.c | 32 +- .../dram_timings/h616_lpddr4_2133.c | 32 +- 8 files changed, 463 insertions(+), 86 deletions(-) create mode 100644 arch/arm/mach-sunxi/dram_timings/h616.c 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 a8fdda124a0..ea64f997fbf 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -168,13 +168,16 @@ struct dram_config { u8 bus_full_width; }; -static inline int ns_to_t(int nanoseconds) +static inline int h616_ns_to_t(const struct dram_para *para, int nanoseconds) { - const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2; + const unsigned int ctrl_freq = para->clk / 2; return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000); } +void h616_ddr3_set_timing_params(const struct dram_para *para); +void h616_lpddr3_set_timing_params(const struct dram_para *para); +void h616_lpddr4_set_timing_params(const 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 e979ee4a2cc..f8cb0a96182 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -62,7 +62,41 @@ config DRAM_SUN55I_A523 help Select this DRAM controller driver for A523/T527 SoCs. -if DRAM_SUN50I_H616 || DRAM_SUN50I_A133 || DRAM_SUN55I_A523 +if DRAM_SUN50I_H616 +choice + prompt "H616 DRAM profile source" + default SUNXI_DRAM_H616_FIXED_PROFILE + help + Select whether SPL uses the fixed H616 Kconfig DRAM settings or + loads an H616 DRAM profile from the device tree at boot. + +config SUNXI_DRAM_H616_FIXED_PROFILE + bool "Fixed build-time DRAM profile" + help + Use a single H616 DRAM profile selected at build time. + This keeps the existing Kconfig-based timing selection flow. + +config SUNXI_DRAM_H616_GPIO_SELECT + bool "GPIO-selected DRAM profile" + select GPIO + select OF_CONTROL + select SPL_OF_CONTROL + select SPL_GPIO + help + Enable runtime H616 DRAM profile selection using GPIO strap bits + described in the U-Boot device tree. + + SPL reads the allwinner,dram-coding-gpios property from the + /dram-profiles node, decodes up to four strap bits into a profile + ID, and loads the matching profile from /dram-profiles instead of + using a fixed build-time H616 DRAM profile. + + Each profile must provide the H616 DRAM parameters used by the + driver. Supported dram-type values are DDR3, LPDDR3, and LPDDR4. +endchoice +endif + +if (DRAM_SUN50I_H616 && SUNXI_DRAM_H616_FIXED_PROFILE) || DRAM_SUN50I_A133 || DRAM_SUN55I_A523 config DRAM_SUNXI_DX_ODT hex "DRAM DX ODT parameter" help @@ -608,6 +642,7 @@ config SUNXI_DRAM_DDR4 choice prompt "DRAM Type and Timing" + depends on !DRAM_SUN50I_H616 || SUNXI_DRAM_H616_FIXED_PROFILE default SUNXI_DRAM_A523_LPDDR4 if MACH_SUN55I_A523 default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S default SUNXI_DRAM_DDR2_V3S if MACH_SUN8I_V3S @@ -647,7 +682,8 @@ config SUNXI_DRAM_H6_DDR3_1333 config SUNXI_DRAM_H616_LPDDR3 bool "LPDDR3 DRAM chips on the H616 DRAM controller" select SUNXI_DRAM_LPDDR3 - depends on DRAM_SUN50I_H616 || DRAM_SUN50I_A133 + depends on (DRAM_SUN50I_H616 && SUNXI_DRAM_H616_FIXED_PROFILE) || \ + DRAM_SUN50I_A133 help This option is the LPDDR3 timing used by the stock boot0 by Allwinner. @@ -655,7 +691,8 @@ config SUNXI_DRAM_H616_LPDDR3 config SUNXI_DRAM_H616_LPDDR4 bool "LPDDR4 DRAM chips on the H616 DRAM controller" select SUNXI_DRAM_LPDDR4 - depends on DRAM_SUN50I_H616 || DRAM_SUN50I_A133 + depends on (DRAM_SUN50I_H616 && SUNXI_DRAM_H616_FIXED_PROFILE) || \ + DRAM_SUN50I_A133 help This option is the LPDDR4 timing used by the stock boot0 by Allwinner. @@ -663,7 +700,8 @@ config SUNXI_DRAM_H616_LPDDR4 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 || DRAM_SUN50I_A133 + depends on (DRAM_SUN50I_H616 && SUNXI_DRAM_H616_FIXED_PROFILE) || \ + DRAM_SUN50I_A133 help This option is the DDR3 timing used by the boot0 on H616 TV boxes which use a DDR3-1333 timing. @@ -719,6 +757,7 @@ config DRAM_TYPE config DRAM_CLK int "sunxi dram clock speed" + depends on !DRAM_SUN50I_H616 || SUNXI_DRAM_H616_FIXED_PROFILE default 792 if MACH_SUN9I default 648 if MACH_SUN8I_R40 default 360 if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || \ diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 3345c9b8e82..f72c1e0f38c 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -15,6 +15,17 @@ #include <init.h> #include <log.h> #include <asm/io.h> + +#define H616_GPIO_SELECT_ENABLED IS_ENABLED(CONFIG_SUNXI_DRAM_H616_GPIO_SELECT) + +#if H616_GPIO_SELECT_ENABLED +#include <asm-generic/gpio.h> +#include <asm/global_data.h> +#include <errno.h> +#include <sunxi_gpio.h> +#include <linux/libfdt.h> +#include <linux/string.h> +#endif #include <asm/arch/clock.h> #include <asm/arch/dram.h> #include <asm/arch/dram_dw_helpers.h> @@ -23,6 +34,12 @@ #include <linux/bitops.h> #include <linux/delay.h> +#define H616_DRAM_STRAP_GPIO_COUNT 4 + +#if H616_GPIO_SELECT_ENABLED +DECLARE_GLOBAL_DATA_PTR; +#endif + enum { MBUS_QOS_LOWEST = 0, MBUS_QOS_LOW, @@ -227,45 +244,67 @@ static void mctl_set_addrmap(const struct dram_config *config) mctl_ctl->addrmap[8] = 0x3F3F; } +#define H616_PHY_INIT_LEN 27 + #ifdef CONFIG_DRAM_SUNXI_PHY_ADDR_MAP_1 -static const u8 phy_init[] = { -#ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333 +static const u8 phy_init_ddr3[H616_PHY_INIT_LEN] = { 0x08, 0x02, 0x12, 0x05, 0x15, 0x17, 0x18, 0x0b, 0x14, 0x07, 0x04, 0x13, 0x0c, 0x00, 0x16, 0x1a, 0x0a, 0x11, 0x03, 0x10, 0x0e, 0x01, 0x0d, 0x19, 0x06, 0x09, 0x0f -#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3) +}; + +static const u8 phy_init_lpddr3[H616_PHY_INIT_LEN] = { 0x18, 0x00, 0x04, 0x09, 0x06, 0x05, 0x02, 0x19, 0x17, 0x03, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x07, 0x08, 0x01, 0x1a -#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR4) +}; + +static const u8 phy_init_lpddr4[H616_PHY_INIT_LEN] = { 0x03, 0x00, 0x17, 0x05, 0x02, 0x19, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x01, 0x18, 0x04, 0x1a -#endif }; -#else /* CONFIG_DRAM_SUNXI_PHY_ADDR_MAP_0 */ -static const u8 phy_init[] = { -#ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333 +#else +static const u8 phy_init_ddr3[H616_PHY_INIT_LEN] = { 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) +}; + +static const u8 phy_init_lpddr3[H616_PHY_INIT_LEN] = { 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 -#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR4) +}; + +static const u8 phy_init_lpddr4[H616_PHY_INIT_LEN] = { 0x02, 0x00, 0x17, 0x05, 0x04, 0x19, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x01, 0x18, 0x03, 0x1a -#endif }; -#endif /* CONFIG_DRAM_SUNXI_PHY_ADDR_MAP_0 */ +#endif + +static const u8 *h616_get_phy_init(const struct dram_para *para) +{ + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + return phy_init_ddr3; + case SUNXI_DRAM_TYPE_LPDDR3: + return phy_init_lpddr3; + case SUNXI_DRAM_TYPE_LPDDR4: + return phy_init_lpddr4; + case SUNXI_DRAM_TYPE_DDR4: + default: + panic("Unsupported H616 DRAM type: %u\n", para->type); + } +} + #define MASK_BYTE(reg, nr) (((reg) >> ((nr) * 8)) & 0x1f) static void mctl_phy_configure_odt(const struct dram_para *para) { @@ -908,6 +947,7 @@ static bool mctl_phy_init(const struct dram_para *para, (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; + const u8 *phy_init = h616_get_phy_init(para); u32 val, val2, *ptr, mr0, mr2; int i; @@ -964,7 +1004,7 @@ static bool mctl_phy_init(const struct dram_para *para, writel(val2, SUNXI_DRAM_PHY0_BASE + 0x37c); ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xc0); - for (i = 0; i < ARRAY_SIZE(phy_init); i++) + for (i = 0; i < H616_PHY_INIT_LEN; i++) writel(phy_init[i], &ptr[i]); if (para->tpr10 & TPR10_CA_BIT_DELAY) @@ -1319,33 +1359,302 @@ bool mctl_core_init(const struct dram_para *para, return mctl_ctrl_init(para, config); } -static const struct dram_para para = { - .clk = CONFIG_DRAM_CLK, +#if H616_GPIO_SELECT_ENABLED +static int h616_fdt_read_u32(const void *blob, int node, const char *prop_name, + u32 *val) +{ + const fdt32_t *prop; + int len; + + prop = fdt_getprop(blob, node, prop_name, &len); + if (!prop || len != sizeof(*prop)) + return -EINVAL; + + *val = fdt32_to_cpu(*prop); + + return 0; +} + +static int h616_fdt_read_dram_type(const void *blob, int node, u32 *val) +{ + const char *prop; + int len; + + prop = fdt_getprop(blob, node, "allwinner,dram-type", &len); + if (!prop) + return -EINVAL; + + if (len == sizeof(fdt32_t)) { + *val = fdt32_to_cpu(*(const fdt32_t *)prop); + return 0; + } + + if (len <= 0 || prop[len - 1] != '\0') + return -EINVAL; + + if (!strcmp(prop, "ddr3")) { + *val = SUNXI_DRAM_TYPE_DDR3; + return 0; + } + if (!strcmp(prop, "ddr4")) { + *val = SUNXI_DRAM_TYPE_DDR4; + return 0; + } + if (!strcmp(prop, "lpddr3")) { + *val = SUNXI_DRAM_TYPE_LPDDR3; + return 0; + } + if (!strcmp(prop, "lpddr4")) { + *val = SUNXI_DRAM_TYPE_LPDDR4; + return 0; + } + + return -EINVAL; +} + +static int h616_get_strap_gpio(u32 bank, u32 pin) +{ + if (pin >= SUNXI_GPIOS_PER_BANK) + return -EINVAL; + + switch (bank) { + case SUNXI_GPIO_A: + return SUNXI_GPA(pin); + case SUNXI_GPIO_B: + return SUNXI_GPB(pin); + case SUNXI_GPIO_C: + return SUNXI_GPC(pin); + case SUNXI_GPIO_D: + return SUNXI_GPD(pin); + case SUNXI_GPIO_E: + return SUNXI_GPE(pin); + case SUNXI_GPIO_F: + return SUNXI_GPF(pin); + case SUNXI_GPIO_G: + return SUNXI_GPG(pin); + case SUNXI_GPIO_H: + return SUNXI_GPH(pin); + case SUNXI_GPIO_I: + return SUNXI_GPI(pin); + case SUNXI_GPIO_L: + return SUNXI_GPL(pin); + case SUNXI_GPIO_M: + return SUNXI_GPM(pin); + case SUNXI_GPIO_N: + return SUNXI_GPN(pin); + default: + return -EINVAL; + } +} + +static int h616_fdt_get_gpio_spec(const void *blob, int node, + const char *prop_name, int index, + u32 *bank, u32 *pin) +{ + const fdt32_t *prop; + int entries, gpio_node, i, len, pos; + u32 cells, phandle; + + prop = fdt_getprop(blob, node, prop_name, &len); + if (!prop) + return -ENOENT; + if (len % sizeof(*prop)) + return -EINVAL; + + entries = len / sizeof(*prop); + for (i = 0, pos = 0; pos < entries; i++) { + phandle = fdt32_to_cpu(prop[pos++]); + if (!phandle) + break; + + gpio_node = fdt_node_offset_by_phandle(blob, phandle); + if (gpio_node < 0) + return gpio_node; + if (h616_fdt_read_u32(blob, gpio_node, "#gpio-cells", &cells)) + return -EINVAL; + if (cells < 2 || pos + cells > entries) + return -EINVAL; + + if (i == index) { + *bank = fdt32_to_cpu(prop[pos]); + *pin = fdt32_to_cpu(prop[pos + 1]); + return 0; + } + + pos += cells; + } + + return -ENOENT; +} + +static int h616_parse_dram_para(const void *blob, int node, + struct dram_para *para) +{ + u32 val; + + if (h616_fdt_read_u32(blob, node, "allwinner,dram-clk", ¶->clk)) + return -EINVAL; + if (h616_fdt_read_dram_type(blob, node, &val)) + return -EINVAL; + + switch (val) { + case SUNXI_DRAM_TYPE_DDR3: + case SUNXI_DRAM_TYPE_LPDDR3: + case SUNXI_DRAM_TYPE_LPDDR4: + para->type = val; + break; + default: + return -EINVAL; + } + + if (h616_fdt_read_u32(blob, node, "allwinner,dx-odt", ¶->dx_odt)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,dx-dri", ¶->dx_dri)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,ca-dri", ¶->ca_dri)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,odt-en", ¶->odt_en)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,tpr0", ¶->tpr0)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,tpr2", ¶->tpr2)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,tpr6", ¶->tpr6)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,tpr10", ¶->tpr10)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,tpr11", ¶->tpr11)) + return -EINVAL; + if (h616_fdt_read_u32(blob, node, "allwinner,tpr12", ¶->tpr12)) + return -EINVAL; + + return 0; +} + +static int h616_load_dram_profile(u32 profile_id, struct dram_para *para) +{ + const void *blob = gd->fdt_blob; + int node, profiles; + u32 reg; + + profiles = fdt_path_offset(blob, "/dram-profiles"); + if (profiles < 0) + return profiles; + + for (node = fdt_first_subnode(blob, profiles); + node >= 0; + node = fdt_next_subnode(blob, node)) { + if (h616_fdt_read_u32(blob, node, "reg", ®)) + continue; + if (reg != profile_id) + continue; + + return h616_parse_dram_para(blob, node, para); + } + + return -ENOENT; +} + +static int h616_get_dram_profile_id(u32 *profile_id) +{ + const void *blob = gd->fdt_blob; + int gpio, i, profiles, ret, value; + u32 bank, pin; + + profiles = fdt_path_offset(blob, "/dram-profiles"); + if (profiles < 0) + return profiles; + + *profile_id = 0; + for (i = 0; i < H616_DRAM_STRAP_GPIO_COUNT; i++) { + ret = h616_fdt_get_gpio_spec(blob, profiles, + "allwinner,dram-coding-gpios", + i, &bank, &pin); + if (ret == -ENOENT) + return i ? 0 : -ENOENT; + if (ret) + return ret; + + gpio = h616_get_strap_gpio(bank, pin); + if (gpio < 0) + return gpio; + + ret = gpio_request(gpio, "h616_dram_sel"); + if (ret) + return ret; + + ret = gpio_direction_input(gpio); + if (ret) { + gpio_free(gpio); + return ret; + } + + value = gpio_get_value(gpio); + gpio_free(gpio); + if (value < 0) + return value; + + *profile_id |= !!value << i; + } + + return 0; +} + +static void h616_get_dram_para(struct dram_para *para) +{ + u32 profile_id; + int ret; + + ret = h616_get_dram_profile_id(&profile_id); + if (ret) + panic("H616 GPIO DRAM profile selection could not determine a profile\n"); + + ret = h616_load_dram_profile(profile_id, para); + if (ret) + panic("H616 GPIO DRAM profile selection failed to load profile %u\n", + profile_id); +} +#else +static enum sunxi_dram_type h616_get_fixed_dram_type(void) +{ #ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333 - .type = SUNXI_DRAM_TYPE_DDR3, + return SUNXI_DRAM_TYPE_DDR3; #elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3) - .type = SUNXI_DRAM_TYPE_LPDDR3, + return SUNXI_DRAM_TYPE_LPDDR3; #elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR4) - .type = SUNXI_DRAM_TYPE_LPDDR4, + return SUNXI_DRAM_TYPE_LPDDR4; +#endif + panic("No fixed H616 DRAM type selected\n"); +} + +static void h616_get_dram_para(struct dram_para *para) +{ + *para = (struct dram_para) { + .clk = CONFIG_DRAM_CLK, + .type = h616_get_fixed_dram_type(), + .dx_odt = CONFIG_DRAM_SUNXI_DX_ODT, + .dx_dri = CONFIG_DRAM_SUNXI_DX_DRI, + .ca_dri = CONFIG_DRAM_SUNXI_CA_DRI, + .odt_en = CONFIG_DRAM_SUNXI_ODT_EN, + .tpr0 = CONFIG_DRAM_SUNXI_TPR0, + .tpr2 = CONFIG_DRAM_SUNXI_TPR2, + .tpr6 = CONFIG_DRAM_SUNXI_TPR6, + .tpr10 = CONFIG_DRAM_SUNXI_TPR10, + .tpr11 = CONFIG_DRAM_SUNXI_TPR11, + .tpr12 = CONFIG_DRAM_SUNXI_TPR12, + }; +} #endif - .dx_odt = CONFIG_DRAM_SUNXI_DX_ODT, - .dx_dri = CONFIG_DRAM_SUNXI_DX_DRI, - .ca_dri = CONFIG_DRAM_SUNXI_CA_DRI, - .odt_en = CONFIG_DRAM_SUNXI_ODT_EN, - .tpr0 = CONFIG_DRAM_SUNXI_TPR0, - .tpr2 = CONFIG_DRAM_SUNXI_TPR2, - .tpr6 = CONFIG_DRAM_SUNXI_TPR6, - .tpr10 = CONFIG_DRAM_SUNXI_TPR10, - .tpr11 = CONFIG_DRAM_SUNXI_TPR11, - .tpr12 = CONFIG_DRAM_SUNXI_TPR12, -}; unsigned long sunxi_dram_init(void) { void *const prcm = (void *)SUNXI_PRCM_BASE; + struct dram_para para; struct dram_config config; unsigned long size; + h616_get_dram_para(¶); + setbits_le32(prcm + CCU_PRCM_RES_CAL_CTRL, BIT(8)); clrbits_le32(prcm + CCU_PRCM_OHMS240, 0x3f); diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile index 5de9fd5aab4..34d46f2864a 100644 --- a/arch/arm/mach-sunxi/dram_timings/Makefile +++ b/arch/arm/mach-sunxi/dram_timings/Makefile @@ -3,9 +3,8 @@ 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 -obj-$(CONFIG_SUNXI_DRAM_H616_DDR3_1333) += h616_ddr3_1333.o -obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR3) += h616_lpddr3.o -obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR4) += h616_lpddr4_2133.o +obj-$(CONFIG_DRAM_SUN50I_H616) += h616.o h616_ddr3_1333.o +obj-$(CONFIG_DRAM_SUN50I_H616) += h616_lpddr3.o h616_lpddr4_2133.o obj-$(CONFIG_SUNXI_DRAM_A133_DDR4) += a133_ddr4.o obj-$(CONFIG_SUNXI_DRAM_A133_LPDDR4) += a133_lpddr4.o obj-$(CONFIG_SUNXI_DRAM_A523_DDR3) += a523_ddr3.o diff --git a/arch/arm/mach-sunxi/dram_timings/h616.c b/arch/arm/mach-sunxi/dram_timings/h616.c new file mode 100644 index 00000000000..d05d528cc57 --- /dev/null +++ b/arch/arm/mach-sunxi/dram_timings/h616.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sun50i H616 DRAM timing dispatcher + * + * Build all H616 timing backends and select the appropriate one at runtime. + */ + +#include <asm/arch/dram.h> +#include <vsprintf.h> + +void mctl_set_timing_params(const struct dram_para *para) +{ + switch (para->type) { + case SUNXI_DRAM_TYPE_DDR3: + h616_ddr3_set_timing_params(para); + break; + case SUNXI_DRAM_TYPE_LPDDR3: + h616_lpddr3_set_timing_params(para); + break; + case SUNXI_DRAM_TYPE_LPDDR4: + h616_lpddr4_set_timing_params(para); + break; + case SUNXI_DRAM_TYPE_DDR4: + default: + panic("Unsupported H616 DRAM type: %u\n", para->type); + } +} 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 3faf8d5bd97..4fde0a81a0a 100644 --- a/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c +++ b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c @@ -14,33 +14,33 @@ #include <asm/arch/dram.h> #include <asm/arch/cpu.h> -void mctl_set_timing_params(const struct dram_para *para) +void h616_ddr3_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; /* JEDEC: 4nCK */ - u8 tfaw = ns_to_t(50); /* JEDEC: 30 ns w/ 1K pages */ - u8 trrd = max(ns_to_t(6), 4); /* JEDEC: max(6 ns, 4nCK) */ - u8 trcd = ns_to_t(15); /* JEDEC: 13.5 ns */ - u8 trc = ns_to_t(53); /* JEDEC: 49.5 ns */ - u8 txp = max(ns_to_t(6), 3); /* JEDEC: max(6 ns, 3nCK) */ - u8 trtp = max(ns_to_t(8), 2); /* JEDEC: max(7.5 ns, 4nCK) */ - u8 trp = ns_to_t(15); /* JEDEC: >= 13.75 ns */ - u8 tras = ns_to_t(38); /* JEDEC >= 36 ns, <= 9*trefi */ - u16 trefi = ns_to_t(7800) / 32; /* JEDEC: 7.8us@Tcase <= 85C */ - u16 trfc = ns_to_t(350); /* JEDEC: 160 ns for 2Gb */ + u8 tfaw = h616_ns_to_t(para, 50); /* JEDEC: 30 ns w/ 1K pages */ + u8 trrd = max(h616_ns_to_t(para, 6), 4); /* JEDEC: max(6 ns, 4nCK) */ + u8 trcd = h616_ns_to_t(para, 15); /* JEDEC: 13.5 ns */ + u8 trc = h616_ns_to_t(para, 53); /* JEDEC: 49.5 ns */ + u8 txp = max(h616_ns_to_t(para, 6), 3); /* JEDEC: max(6 ns, 3nCK) */ + u8 trtp = max(h616_ns_to_t(para, 8), 2); /* JEDEC: max(7.5 ns, 4nCK) */ + u8 trp = h616_ns_to_t(para, 15); /* JEDEC: >= 13.75 ns */ + u8 tras = h616_ns_to_t(para, 38); /* JEDEC >= 36 ns, <= 9*trefi */ + u16 trefi = h616_ns_to_t(para, 7800) / 32; /* JEDEC: 7.8us@Tcase <= 85C */ + u16 trfc = h616_ns_to_t(para, 350); /* JEDEC: 160 ns for 2Gb */ u16 txsr = 4; /* ? */ u8 tmrw = 0; /* ? */ u8 tmrd = 4; /* JEDEC: 4nCK */ - u8 tmod = max(ns_to_t(15), 12); /* JEDEC: max(15 ns, 12nCK) */ - u8 tcke = max(ns_to_t(6), 3); /* JEDEC: max(5.625 ns, 3nCK) */ - u8 tcksrx = max(ns_to_t(10), 4); /* JEDEC: max(10 ns, 5nCK) */ - u8 tcksre = max(ns_to_t(10), 4); /* JEDEC: max(10 ns, 5nCK) */ + u8 tmod = max(h616_ns_to_t(para, 15), 12); /* JEDEC: max(15 ns, 12nCK) */ + u8 tcke = max(h616_ns_to_t(para, 6), 3); /* JEDEC: max(5.625 ns, 3nCK) */ + u8 tcksrx = max(h616_ns_to_t(para, 10), 4); /* JEDEC: max(10 ns, 5nCK) */ + u8 tcksre = max(h616_ns_to_t(para, 10), 4); /* JEDEC: max(10 ns, 5nCK) */ u8 tckesr = tcke + 1; /* JEDEC: tCKE(min) + 1nCK */ u8 trasmax = (para->clk / 2) / 15; /* JEDEC: tREFI * 9 */ - u8 txs = ns_to_t(360) / 32; /* JEDEC: max(5nCK,tRFC+10ns) */ + u8 txs = h616_ns_to_t(para, 360) / 32; /* JEDEC: max(5nCK,tRFC+10ns) */ u8 txsdll = 16; /* JEDEC: 512 nCK */ u8 txsabort = 4; /* ? */ u8 txsfast = 4; /* ? */ diff --git a/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c b/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c index ce2ffa7a020..d5106765b05 100644 --- a/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c +++ b/arch/arm/mach-sunxi/dram_timings/h616_lpddr3.c @@ -14,33 +14,33 @@ #include <asm/arch/dram.h> #include <asm/arch/cpu.h> -void mctl_set_timing_params(const struct dram_para *para) +void h616_lpddr3_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); + u8 tfaw = h616_ns_to_t(para, 50); + u8 trrd = max(h616_ns_to_t(para, 6), 4); + u8 trcd = h616_ns_to_t(para, 24); + u8 trc = h616_ns_to_t(para, 70); + u8 txp = max(h616_ns_to_t(para, 8), 3); + u8 trtp = max(h616_ns_to_t(para, 8), 2); + u8 trp = h616_ns_to_t(para, 27); + u8 tras = h616_ns_to_t(para, 41); + u16 trefi = h616_ns_to_t(para, 7800) / 64; + u16 trfc = h616_ns_to_t(para, 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 tmod = max(h616_ns_to_t(para, 15), 12); + u8 tcke = max(h616_ns_to_t(para, 6), 3); + u8 tcksrx = max(h616_ns_to_t(para, 12), 4); + u8 tcksre = max(h616_ns_to_t(para, 12), 4); u8 tckesr = tcke + 2; u8 trasmax = (para->clk / 2) / 16; - u8 txs = ns_to_t(360) / 32; + u8 txs = h616_ns_to_t(para, 360) / 32; u8 txsdll = 16; u8 txsabort = 4; u8 txsfast = 4; diff --git a/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c b/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c index 6f5c4acbd62..e1ea41f7a3e 100644 --- a/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c +++ b/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c @@ -12,30 +12,30 @@ #include <asm/arch/dram.h> #include <asm/arch/cpu.h> -void mctl_set_timing_params(const struct dram_para *para) +void h616_lpddr4_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 = 4; - u8 tfaw = ns_to_t(40); - u8 trrd = max(ns_to_t(10), 2); - u8 trcd = max(ns_to_t(18), 2); - u8 trc = ns_to_t(65); - u8 txp = max(ns_to_t(8), 2); + u8 tfaw = h616_ns_to_t(para, 40); + u8 trrd = max(h616_ns_to_t(para, 10), 2); + u8 trcd = max(h616_ns_to_t(para, 18), 2); + u8 trc = h616_ns_to_t(para, 65); + u8 txp = max(h616_ns_to_t(para, 8), 2); u8 trtp = 4; - u8 trp = ns_to_t(21); - u8 tras = ns_to_t(42); - u16 trefi = ns_to_t(3904) / 32; - u16 trfc = ns_to_t(280); - u16 txsr = ns_to_t(190); + u8 trp = h616_ns_to_t(para, 21); + u8 tras = h616_ns_to_t(para, 42); + u16 trefi = h616_ns_to_t(para, 3904) / 32; + u16 trfc = h616_ns_to_t(para, 280); + u16 txsr = h616_ns_to_t(para, 190); - u8 tmrw = max(ns_to_t(14), 5); + u8 tmrw = max(h616_ns_to_t(para, 14), 5); u8 tmrd = tmrw; u8 tmod = 12; - u8 tcke = max(ns_to_t(15), 2); - u8 tcksrx = max(ns_to_t(2), 2); - u8 tcksre = max(ns_to_t(5), 2); + u8 tcke = max(h616_ns_to_t(para, 15), 2); + u8 tcksrx = max(h616_ns_to_t(para, 2), 2); + u8 tcksre = max(h616_ns_to_t(para, 5), 2); u8 tckesr = tcke; u8 trasmax = (trefi * 9) / 32; u8 txs = 4; @@ -49,7 +49,7 @@ void mctl_set_timing_params(const struct dram_para *para) u8 twtp = 24; u8 twr2rd = max(trrd, (u8)4) + 14; - u8 trd2wr = (ns_to_t(4) + 17) - ns_to_t(1); + u8 trd2wr = (h616_ns_to_t(para, 4) + 17) - h616_ns_to_t(para, 1); /* set DRAM timing */ writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras, -- 2.43.0

