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", &para->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", &para->dx_odt))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,dx-dri", &para->dx_dri))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,ca-dri", &para->ca_dri))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,odt-en", &para->odt_en))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,tpr0", &para->tpr0))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,tpr2", &para->tpr2))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,tpr6", &para->tpr6))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,tpr10", &para->tpr10))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,tpr11", &para->tpr11))
+               return -EINVAL;
+       if (h616_fdt_read_u32(blob, node, "allwinner,tpr12", &para->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", &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(&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

Reply via email to