]> git.sur5r.net Git - u-boot/commitdiff
sunxi: A64: use H3 DRAM initialization code for A64 as well
authorJens Kuske <jenskuske@gmail.com>
Mon, 2 Jan 2017 11:48:42 +0000 (11:48 +0000)
committerJagan Teki <jagan@openedev.com>
Wed, 4 Jan 2017 15:37:42 +0000 (16:37 +0100)
The A64 DRAM controller is very similar to the H3 one,
so the code can be reused with some small changes.
This refactoring does not change the code size for the existing H3 part.

[Andre: rework from #ifdefs to using socid parameters in static
        functions, minor fixes, merging in fixes from Jens]

Signed-off-by: Jens Kuske <jenskuske@gmail.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Jagan Teki <jagan@openedev.com>
arch/arm/include/asm/arch-sunxi/clock_sun6i.h
arch/arm/include/asm/arch-sunxi/cpu.h
arch/arm/include/asm/arch-sunxi/dram.h
arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h
arch/arm/mach-sunxi/Makefile
arch/arm/mach-sunxi/clock_sun6i.c
arch/arm/mach-sunxi/dram_sun8i_h3.c

index be9fcfda0e35591c01c462ed3778d3d72a6bf165..3f87672c6253a7387ee8a4d95e471beafc1849f9 100644 (file)
@@ -322,6 +322,7 @@ struct sunxi_ccm_reg {
 #define CCM_DRAMCLK_CFG_DIV0_MASK      (0xf << 8)
 #define CCM_DRAMCLK_CFG_SRC_PLL5       (0x0 << 20)
 #define CCM_DRAMCLK_CFG_SRC_PLL6x2     (0x1 << 20)
+#define CCM_DRAMCLK_CFG_SRC_PLL11      (0x1 << 20) /* A64 only */
 #define CCM_DRAMCLK_CFG_SRC_MASK       (0x3 << 20)
 #define CCM_DRAMCLK_CFG_UPD            (0x1 << 16)
 #define CCM_DRAMCLK_CFG_RST            (0x1 << 31)
index 73583ed445a57bbdb3863e826056921e0cd25f9e..6f96a9715a91b71ed9d2ca49dd2c9b66ed92b9b1 100644 (file)
@@ -13,4 +13,7 @@
 #include <asm/arch/cpu_sun4i.h>
 #endif
 
+#define SOCID_A64      0x1689
+#define SOCID_H3       0x1680
+
 #endif /* _SUNXI_CPU_H */
index e0be744dba488275adc310d33063e37aeea89d87..53e6d471d2ec2ce4a79d4292adac06c2e5ecefd8 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/arch/dram_sun8i_a33.h>
 #elif defined(CONFIG_MACH_SUN8I_A83T)
 #include <asm/arch/dram_sun8i_a83t.h>
-#elif defined(CONFIG_MACH_SUN8I_H3)
+#elif defined(CONFIG_MACH_SUN8I_H3) || defined(CONFIG_MACH_SUN50I)
 #include <asm/arch/dram_sun8i_h3.h>
 #elif defined(CONFIG_MACH_SUN9I)
 #include <asm/arch/dram_sun9i.h>
index 346538c3a1a2a18850f38a57ca40a9ffc45814d2..25d07d9863c92b103b6b7a6dd6ce75810de888d6 100644 (file)
@@ -15,7 +15,8 @@
 
 struct sunxi_mctl_com_reg {
        u32 cr;                 /* 0x00 control register */
-       u8 res0[0xc];           /* 0x04 */
+       u8 res0[0x8];           /* 0x04 */
+       u32 tmr;                /* 0x0c (unused on H3) */
        u32 mcr[16][2];         /* 0x10 */
        u32 bwcr;               /* 0x90 bandwidth control register */
        u32 maer;               /* 0x94 master enable register */
@@ -32,7 +33,9 @@ struct sunxi_mctl_com_reg {
        u32 swoffr;             /* 0xc4 */
        u8 res2[0x8];           /* 0xc8 */
        u32 cccr;               /* 0xd0 */
-       u8 res3[0x72c];         /* 0xd4 */
+       u8 res3[0x54];          /* 0xd4 */
+       u32 mdfs_bwlr[3];       /* 0x128 (unused on H3) */
+       u8 res4[0x6cc];         /* 0x134 */
        u32 protect;            /* 0x800 */
 };
 
@@ -81,7 +84,8 @@ struct sunxi_mctl_ctl_reg {
        u32 rfshtmg;            /* 0x90 refresh timing */
        u32 rfshctl1;           /* 0x94 */
        u32 pwrtmg;             /* 0x98 */
-       u8  res3[0x20];         /* 0x9c */
+       u8 res3[0x1c];          /* 0x9c */
+       u32 vtfcr;              /* 0xb8 (unused on H3) */
        u32 dqsgmr;             /* 0xbc */
        u32 dtcr;               /* 0xc0 */
        u32 dtar[4];            /* 0xc4 */
index e73114ee642c22861e567e69eff12a676a56d82f..7daba1169c8f5062ceeb1b0f0a90bab1d41edd52 100644 (file)
@@ -50,4 +50,5 @@ obj-$(CONFIG_MACH_SUN8I_A33)  += dram_sun8i_a33.o
 obj-$(CONFIG_MACH_SUN8I_A83T)  += dram_sun8i_a83t.o
 obj-$(CONFIG_MACH_SUN8I_H3)    += dram_sun8i_h3.o
 obj-$(CONFIG_MACH_SUN9I)       += dram_sun9i.o
+obj-$(CONFIG_MACH_SUN50I)      += dram_sun8i_h3.o
 endif
index 8e39bbef82f65f98bbf751d046724fa1c047b527..d123b3acb2f1c8bd579637ef4509694878518baa 100644 (file)
@@ -217,7 +217,7 @@ done:
 }
 #endif
 
-#ifdef CONFIG_MACH_SUN8I_A33
+#if defined(CONFIG_MACH_SUN8I_A33) || defined(CONFIG_MACH_SUN50I)
 void clock_set_pll11(unsigned int clk, bool sigma_delta_enable)
 {
        struct sunxi_ccm_reg * const ccm =
index 4396754766734d1e8f3c56def91af09f9be11ddd..fe9cf9a181b392782a7a932c62b900e19c9865e6 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
 #include <linux/kconfig.h>
 
 /*
@@ -42,30 +43,6 @@ static inline int ns_to_t(int nanoseconds)
        return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
 }
 
-static u32 bin_to_mgray(int val)
-{
-       static const u8 lookup_table[32] = {
-               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
-               0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
-               0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
-               0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
-       };
-
-       return lookup_table[clamp(val, 0, 31)];
-}
-
-static int mgray_to_bin(u32 val)
-{
-       static const u8 lookup_table[32] = {
-               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
-               0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
-               0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
-               0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
-       };
-
-       return lookup_table[val & 0x1f];
-}
-
 static void mctl_phy_init(u32 val)
 {
        struct sunxi_mctl_ctl_reg * const mctl_ctl =
@@ -148,13 +125,13 @@ inline void mbus_configure_port(u8 port,
        mbus_configure_port(MBUS_PORT_ ## port, bwlimit, false, \
                            MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
 
-static void mctl_set_master_priority(void)
+static void mctl_set_master_priority_h3(void)
 {
        struct sunxi_mctl_com_reg * const mctl_com =
                        (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
 
        /* enable bandwidth limit windows and set windows size 1us */
-       writel(0x00010190, &mctl_com->bwcr);
+       writel((1 << 16) | (400 << 0), &mctl_com->bwcr);
 
        /* set cpu high priority */
        writel(0x00000001, &mctl_com->mapr);
@@ -173,7 +150,46 @@ static void mctl_set_master_priority(void)
        MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1024,  288,   64);
 }
 
-static void mctl_set_timing_params(struct dram_para *para)
+static void mctl_set_master_priority_a64(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+                       (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+       /* enable bandwidth limit windows and set windows size 1us */
+       writel(399, &mctl_com->tmr);
+       writel((1 << 16), &mctl_com->bwcr);
+
+       /* Port 2 is reserved per Allwinner's linux-3.10 source, yet they
+        * initialise it */
+       MBUS_CONF(   CPU,  true, HIGHEST, 0,  160,  100,   80);
+       MBUS_CONF(   GPU, false,    HIGH, 0, 1536, 1400,  256);
+       MBUS_CONF(UNUSED,  true, HIGHEST, 0,  512,  256,   96);
+       MBUS_CONF(   DMA,  true,    HIGH, 0,  256,   80,  100);
+       MBUS_CONF(    VE,  true,    HIGH, 0, 1792, 1600,  256);
+       MBUS_CONF(   CSI,  true,    HIGH, 0,  256,  128,    0);
+       MBUS_CONF(  NAND,  true,    HIGH, 0,  256,  128,   64);
+       MBUS_CONF(    SS,  true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    TS,  true, HIGHEST, 0,  256,  128,   64);
+       MBUS_CONF(    DI,  true,    HIGH, 0, 1024,  256,   64);
+       MBUS_CONF(    DE,  true,    HIGH, 2, 8192, 6144, 2048);
+       MBUS_CONF(DE_CFD,  true,    HIGH, 0, 1280,  144,   64);
+
+       writel(0x81000004, &mctl_com->mdfs_bwlr[2]);
+}
+
+static void mctl_set_master_priority(uint16_t socid)
+{
+       switch (socid) {
+       case SOCID_H3:
+               mctl_set_master_priority_h3();
+               return;
+       case SOCID_A64:
+               mctl_set_master_priority_a64();
+               return;
+       }
+}
+
+static void mctl_set_timing_params(uint16_t socid, struct dram_para *para)
 {
        struct sunxi_mctl_ctl_reg * const mctl_ctl =
                        (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
@@ -254,7 +270,31 @@ static void mctl_set_timing_params(struct dram_para *para)
        writel(RFSHTMG_TREFI(trefi) | RFSHTMG_TRFC(trfc), &mctl_ctl->rfshtmg);
 }
 
-static void mctl_zq_calibration(struct dram_para *para)
+static u32 bin_to_mgray(int val)
+{
+       static const u8 lookup_table[32] = {
+               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
+               0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09,
+               0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x1f, 0x1c, 0x1d,
+               0x14, 0x15, 0x16, 0x17, 0x12, 0x13, 0x10, 0x11,
+       };
+
+       return lookup_table[clamp(val, 0, 31)];
+}
+
+static int mgray_to_bin(u32 val)
+{
+       static const u8 lookup_table[32] = {
+               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05,
+               0x0e, 0x0f, 0x0c, 0x0d, 0x08, 0x09, 0x0a, 0x0b,
+               0x1e, 0x1f, 0x1c, 0x1d, 0x18, 0x19, 0x1a, 0x1b,
+               0x10, 0x11, 0x12, 0x13, 0x16, 0x17, 0x14, 0x15,
+       };
+
+       return lookup_table[val & 0x1f];
+}
+
+static void mctl_h3_zq_calibration_quirk(struct dram_para *para)
 {
        struct sunxi_mctl_ctl_reg * const mctl_ctl =
                        (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
@@ -324,7 +364,7 @@ static void mctl_set_cr(struct dram_para *para)
               MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr);
 }
 
-static void mctl_sys_init(struct dram_para *para)
+static void mctl_sys_init(uint16_t socid, struct dram_para *para)
 {
        struct sunxi_ccm_reg * const ccm =
                        (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -336,16 +376,30 @@ static void mctl_sys_init(struct dram_para *para)
        clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
        clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
        clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
+       if (socid == SOCID_A64)
+               clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN);
        udelay(10);
 
        clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
        udelay(1000);
 
-       clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
-       clrsetbits_le32(&ccm->dram_clk_cfg,
-                       CCM_DRAMCLK_CFG_DIV_MASK | CCM_DRAMCLK_CFG_SRC_MASK,
-                       CCM_DRAMCLK_CFG_DIV(1) | CCM_DRAMCLK_CFG_SRC_PLL5 |
-                       CCM_DRAMCLK_CFG_UPD);
+       if (socid == SOCID_A64) {
+               clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false);
+               clrsetbits_le32(&ccm->dram_clk_cfg,
+                               CCM_DRAMCLK_CFG_DIV_MASK |
+                               CCM_DRAMCLK_CFG_SRC_MASK,
+                               CCM_DRAMCLK_CFG_DIV(1) |
+                               CCM_DRAMCLK_CFG_SRC_PLL11 |
+                               CCM_DRAMCLK_CFG_UPD);
+       } else if (socid == SOCID_H3) {
+               clock_set_pll5(CONFIG_DRAM_CLK * 2 * 1000000, false);
+               clrsetbits_le32(&ccm->dram_clk_cfg,
+                               CCM_DRAMCLK_CFG_DIV_MASK |
+                               CCM_DRAMCLK_CFG_SRC_MASK,
+                               CCM_DRAMCLK_CFG_DIV(1) |
+                               CCM_DRAMCLK_CFG_SRC_PLL5 |
+                               CCM_DRAMCLK_CFG_UPD);
+       }
        mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
 
        setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
@@ -360,7 +414,7 @@ static void mctl_sys_init(struct dram_para *para)
        udelay(500);
 }
 
-static int mctl_channel_init(struct dram_para *para)
+static int mctl_channel_init(uint16_t socid, struct dram_para *para)
 {
        struct sunxi_mctl_com_reg * const mctl_com =
                        (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
@@ -370,8 +424,8 @@ static int mctl_channel_init(struct dram_para *para)
        unsigned int i;
 
        mctl_set_cr(para);
-       mctl_set_timing_params(para);
-       mctl_set_master_priority();
+       mctl_set_timing_params(socid, para);
+       mctl_set_master_priority(socid);
 
        /* setting VTC, default disable all VT */
        clrbits_le32(&mctl_ctl->pgcr[0], (1 << 30) | 0x3f);
@@ -397,12 +451,18 @@ static int mctl_channel_init(struct dram_para *para)
        /* set DQS auto gating PD mode */
        setbits_le32(&mctl_ctl->pgcr[2], 0x3 << 6);
 
-       /* dx ddr_clk & hdr_clk dynamic mode */
-       clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
-
-       /* dphy & aphy phase select 270 degree */
-       clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
-                       (0x1 << 10) | (0x2 << 8));
+       if (socid == SOCID_H3) {
+               /* dx ddr_clk & hdr_clk dynamic mode */
+               clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12));
+
+               /* dphy & aphy phase select 270 degree */
+               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
+                               (0x1 << 10) | (0x2 << 8));
+       } else if (socid == SOCID_A64) {
+               /* dphy & aphy phase select ? */
+               clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8),
+                               (0x0 << 10) | (0x3 << 8));
+       }
 
        /* set half DQ */
        if (para->bus_width != 32) {
@@ -417,10 +477,17 @@ static int mctl_channel_init(struct dram_para *para)
        mctl_set_bit_delays(para);
        udelay(50);
 
-       mctl_zq_calibration(para);
+       if (socid == SOCID_H3) {
+               mctl_h3_zq_calibration_quirk(para);
 
-       mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST |
-                     PIR_DRAMINIT | PIR_QSGATE);
+               mctl_phy_init(PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
+                             PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
+       } else if (socid == SOCID_A64) {
+               clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ);
+
+               mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST |
+                             PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE);
+       }
 
        /* detect ranks and bus width */
        if (readl(&mctl_ctl->pgsr[0]) & (0xfe << 20)) {
@@ -458,7 +525,10 @@ static int mctl_channel_init(struct dram_para *para)
        udelay(10);
 
        /* set PGCR3, CKE polarity */
-       writel(0x00aa0060, &mctl_ctl->pgcr[3]);
+       if (socid == SOCID_H3)
+               writel(0x00aa0060, &mctl_ctl->pgcr[3]);
+       else if (socid == SOCID_A64)
+               writel(0xc0aa0060, &mctl_ctl->pgcr[3]);
 
        /* power down zq calibration module for power save */
        setbits_le32(&mctl_ctl->zqcr, ZQCR_PWRDOWN);
@@ -512,6 +582,22 @@ static void mctl_auto_detect_dram_size(struct dram_para *para)
           0,  0,  0,  0,  0,  0,  0,  0,                       \
           0,  0,  0,  0,  0,  0,  0      }
 
+#define SUN50I_A64_DX_READ_DELAYS                              \
+       {{ 16, 16, 16, 16, 17, 16, 16, 17, 16,  1,  0 },        \
+        { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 },        \
+        { 16, 17, 17, 16, 16, 16, 16, 16, 16,  0,  0 },        \
+        { 17, 17, 17, 17, 17, 17, 17, 17, 17,  1,  0 }}
+#define SUN50I_A64_DX_WRITE_DELAYS                             \
+       {{  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15 },        \
+        {  0,  0,  0,  0,  1,  1,  1,  1,  0, 10, 10 },        \
+        {  1,  0,  1,  1,  1,  1,  1,  1,  0, 11, 11 },        \
+        {  1,  0,  0,  1,  1,  1,  1,  1,  0, 12, 12 }}
+#define SUN50I_A64_AC_DELAYS                                   \
+       {  5,  5, 13, 10,  2,  5,  3,  3,                       \
+          0,  3,  3,  3,  1,  0,  0,  0,                       \
+          3,  4,  0,  3,  4,  1,  4,  0,                       \
+          1,  1,  0,  1, 13,  5,  4      }
+
 unsigned long sunxi_dram_init(void)
 {
        struct sunxi_mctl_com_reg * const mctl_com =
@@ -524,13 +610,30 @@ unsigned long sunxi_dram_init(void)
                .bus_width = 32,
                .row_bits = 15,
                .page_size = 4096,
+
+#if defined(CONFIG_MACH_SUN8I_H3)
                .dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
                .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
                .ac_delays       = SUN8I_H3_AC_DELAYS,
+#elif defined(CONFIG_MACH_SUN50I)
+               .dx_read_delays  = SUN50I_A64_DX_READ_DELAYS,
+               .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS,
+               .ac_delays       = SUN50I_A64_AC_DELAYS,
+#endif
        };
-
-       mctl_sys_init(&para);
-       if (mctl_channel_init(&para))
+/*
+ * Let the compiler optimize alternatives away by passing this value into
+ * the static functions. This saves us #ifdefs, but still keeps the binary
+ * small.
+ */
+#if defined(CONFIG_MACH_SUN8I_H3)
+       uint16_t socid = SOCID_H3;
+#elif defined(CONFIG_MACH_SUN50I)
+       uint16_t socid = SOCID_A64;
+#endif
+
+       mctl_sys_init(socid, &para);
+       if (mctl_channel_init(socid, &para))
                return 0;
 
        if (para.dual_rank)
@@ -540,7 +643,13 @@ unsigned long sunxi_dram_init(void)
        udelay(1);
 
        /* odt delay */
-       writel(0x0c000400, &mctl_ctl->odtcfg);
+       if (socid == SOCID_H3)
+               writel(0x0c000400, &mctl_ctl->odtcfg);
+
+       if (socid == SOCID_A64) {
+               setbits_le32(&mctl_ctl->vtfcr, 2 << 8);
+               clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13));
+       }
 
        /* clear credit value */
        setbits_le32(&mctl_com->cccr, 1 << 31);