[PATCH 1/1] sunxi: h616: add GPIO-selected DRAM profiles
James Hilliard
james.hilliard1 at gmail.com
Thu Mar 12 21:49:06 CET 2026
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 <james.hilliard1 at gmail.com>
---
.../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 at 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 at 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
More information about the U-Boot
mailing list