mx6: ddr: pass mx6_ddr_sysinfo to calibration routines
authorEric Nelson <eric@nelint.com>
Sun, 30 Oct 2016 23:33:48 +0000 (16:33 -0700)
committerStefano Babic <sbabic@denx.de>
Tue, 29 Nov 2016 15:40:12 +0000 (16:40 +0100)
The DDR calibration routines have scattered support for bus
widths other than 64-bits:

-- The mmdc_do_write_level_calibration() routine assumes the
presence of PHY1, and
-- The mmdc_do_dqs_calibration() routine tries to determine
whether one or two DDR PHYs are active by reading MDCTL.

Since a caller of these routines must have a valid struct mx6_ddr_sysinfo
for use in calling mx6_dram_cfg(), and the bus width is available in the
"dsize" field, use this structure to inform the calibration routines which
PHYs are active.

This allows the use of the DDR calibration routines on CPU variants
like i.MX6SL that only have a single MMDC port.

Signed-off-by: Eric Nelson <eric@nelint.com>
Reviewed-by: Marek Vasut <marex@denx.de>
arch/arm/cpu/armv7/mx6/ddr.c
arch/arm/include/asm/arch-mx6/mx6-ddr.h
board/kosagi/novena/novena_spl.c

index b15f376da43587f5508d19e2587a07d39694f729..274a0ba357dd76962debb31545235d8072d8ff24 100644 (file)
@@ -86,14 +86,15 @@ static void modify_dg_result(u32 *reg_st0, u32 *reg_st1, u32 *reg_ctrl)
        writel(val_ctrl, reg_ctrl);
 }
 
-int mmdc_do_write_level_calibration(void)
+int mmdc_do_write_level_calibration(struct mx6_ddr_sysinfo const *sysinfo)
 {
        struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
        struct mmdc_p_regs *mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
        u32 esdmisc_val, zq_val;
        u32 errors = 0;
-       u32 ldectrl[4];
+       u32 ldectrl[4] = {0};
        u32 ddr_mr1 = 0x4;
+       u32 rwalat_max;
 
        /*
         * Stash old values in case calibration fails,
@@ -101,8 +102,10 @@ int mmdc_do_write_level_calibration(void)
         */
        ldectrl[0] = readl(&mmdc0->mpwldectrl0);
        ldectrl[1] = readl(&mmdc0->mpwldectrl1);
-       ldectrl[2] = readl(&mmdc1->mpwldectrl0);
-       ldectrl[3] = readl(&mmdc1->mpwldectrl1);
+       if (sysinfo->dsize == 2) {
+               ldectrl[2] = readl(&mmdc1->mpwldectrl0);
+               ldectrl[3] = readl(&mmdc1->mpwldectrl1);
+       }
 
        /* disable DDR logic power down timer */
        clrbits_le32(&mmdc0->mdpdc, 0xff00);
@@ -122,10 +125,10 @@ int mmdc_do_write_level_calibration(void)
        writel(zq_val & ~0x3, &mmdc0->mpzqhwctrl);
 
        /* 3. increase walat and ralat to maximum */
-       setbits_le32(&mmdc0->mdmisc,
-                    (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17));
-       setbits_le32(&mmdc1->mdmisc,
-                    (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17));
+       rwalat_max = (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17);
+       setbits_le32(&mmdc0->mdmisc, rwalat_max);
+       if (sysinfo->dsize == 2)
+               setbits_le32(&mmdc1->mdmisc, rwalat_max);
        /*
         * 4 & 5. Configure the external DDR device to enter write-leveling
         * mode through Load Mode Register command.
@@ -152,21 +155,25 @@ int mmdc_do_write_level_calibration(void)
         */
        if (readl(&mmdc0->mpwlgcr) & 0x00000F00)
                errors |= 1;
-       if (readl(&mmdc1->mpwlgcr) & 0x00000F00)
-               errors |= 2;
+       if (sysinfo->dsize == 2)
+               if (readl(&mmdc1->mpwlgcr) & 0x00000F00)
+                       errors |= 2;
 
        debug("Ending write leveling calibration. Error mask: 0x%x\n", errors);
 
        /* check to see if cal failed */
        if ((readl(&mmdc0->mpwldectrl0) == 0x001F001F) &&
            (readl(&mmdc0->mpwldectrl1) == 0x001F001F) &&
-           (readl(&mmdc1->mpwldectrl0) == 0x001F001F) &&
-           (readl(&mmdc1->mpwldectrl1) == 0x001F001F)) {
+           ((sysinfo->dsize < 2) ||
+            ((readl(&mmdc1->mpwldectrl0) == 0x001F001F) &&
+             (readl(&mmdc1->mpwldectrl1) == 0x001F001F)))) {
                debug("Cal seems to have soft-failed due to memory not supporting write leveling on all channels. Restoring original write leveling values.\n");
                writel(ldectrl[0], &mmdc0->mpwldectrl0);
                writel(ldectrl[1], &mmdc0->mpwldectrl1);
-               writel(ldectrl[2], &mmdc1->mpwldectrl0);
-               writel(ldectrl[3], &mmdc1->mpwldectrl1);
+               if (sysinfo->dsize == 2) {
+                       writel(ldectrl[2], &mmdc1->mpwldectrl0);
+                       writel(ldectrl[3], &mmdc1->mpwldectrl1);
+               }
                errors |= 4;
        }
 
@@ -189,16 +196,20 @@ int mmdc_do_write_level_calibration(void)
              readl(&mmdc0->mpwldectrl0));
        debug("\tMMDC_MPWLDECTRL1 after write level cal: 0x%08X\n",
              readl(&mmdc0->mpwldectrl1));
-       debug("\tMMDC_MPWLDECTRL0 after write level cal: 0x%08X\n",
-             readl(&mmdc1->mpwldectrl0));
-       debug("\tMMDC_MPWLDECTRL1 after write level cal: 0x%08X\n",
-             readl(&mmdc1->mpwldectrl1));
+       if (sysinfo->dsize == 2) {
+               debug("\tMMDC_MPWLDECTRL0 after write level cal: 0x%08X\n",
+                     readl(&mmdc1->mpwldectrl0));
+               debug("\tMMDC_MPWLDECTRL1 after write level cal: 0x%08X\n",
+                     readl(&mmdc1->mpwldectrl1));
+       }
 
        /* We must force a readback of these values, to get them to stick */
        readl(&mmdc0->mpwldectrl0);
        readl(&mmdc0->mpwldectrl1);
-       readl(&mmdc1->mpwldectrl0);
-       readl(&mmdc1->mpwldectrl1);
+       if (sysinfo->dsize == 2) {
+               readl(&mmdc1->mpwldectrl0);
+               readl(&mmdc1->mpwldectrl1);
+       }
 
        /* enable DDR logic power down timer: */
        setbits_le32(&mmdc0->mdpdc, 0x00005500);
@@ -212,7 +223,7 @@ int mmdc_do_write_level_calibration(void)
        return errors;
 }
 
-int mmdc_do_dqs_calibration(void)
+int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo)
 {
        struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
        struct mmdc_p_regs *mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR;
@@ -223,7 +234,6 @@ int mmdc_do_dqs_calibration(void)
        bool cs0_enable_initial;
        bool cs1_enable_initial;
        u32 esdmisc_val;
-       u32 bus_size;
        u32 temp_ref;
        u32 pddword = 0x00ffff00; /* best so far, place into MPPDCMPR1 */
        u32 errors = 0;
@@ -292,10 +302,6 @@ int mmdc_do_dqs_calibration(void)
        cs0_enable = readl(&mmdc0->mdctl) & 0x80000000;
        cs1_enable = readl(&mmdc0->mdctl) & 0x40000000;
 
-       /* Check to see what the data bus size is */
-       bus_size = (readl(&mmdc0->mdctl) & 0x30000) >> 16;
-       debug("Data bus size: %d (%d bits)\n", bus_size, 1 << (bus_size + 4));
-
        precharge_all(cs0_enable, cs1_enable);
 
        /* Write the pre-defined value into MPPDCMPR1 */
@@ -314,11 +320,11 @@ int mmdc_do_dqs_calibration(void)
         * Both PHYs for x64 configuration, if x32, do only PHY0.
         */
        writel(initdelay, &mmdc0->mprddlctl);
-       if (bus_size == 0x2)
+       if (sysinfo->dsize == 0x2)
                writel(initdelay, &mmdc1->mprddlctl);
 
        /* Force a measurment, for previous delay setup to take effect. */
-       force_delay_measurement(bus_size);
+       force_delay_measurement(sysinfo->dsize);
 
        /*
         * ***************************
@@ -364,7 +370,7 @@ int mmdc_do_dqs_calibration(void)
        if (readl(&mmdc0->mpdgctrl0) & 0x00001000)
                errors |= 1;
 
-       if ((bus_size == 0x2) && (readl(&mmdc1->mpdgctrl0) & 0x00001000))
+       if ((sysinfo->dsize == 0x2) && (readl(&mmdc1->mpdgctrl0) & 0x00001000))
                errors |= 2;
 
        /* now disable mpdgctrl0[DG_CMP_CYC] */
@@ -381,7 +387,7 @@ int mmdc_do_dqs_calibration(void)
                         &mmdc0->mpdgctrl0);
        modify_dg_result(&mmdc0->mpdghwst2, &mmdc0->mpdghwst3,
                         &mmdc0->mpdgctrl1);
-       if (bus_size == 0x2) {
+       if (sysinfo->dsize == 0x2) {
                modify_dg_result(&mmdc1->mpdghwst0, &mmdc1->mpdghwst1,
                                 &mmdc1->mpdgctrl0);
                modify_dg_result(&mmdc1->mpdghwst2, &mmdc1->mpdghwst3,
@@ -424,7 +430,8 @@ int mmdc_do_dqs_calibration(void)
        if (readl(&mmdc0->mprddlhwctl) & 0x0000000f)
                errors |= 4;
 
-       if ((bus_size == 0x2) && (readl(&mmdc1->mprddlhwctl) & 0x0000000f))
+       if ((sysinfo->dsize == 0x2) &&
+           (readl(&mmdc1->mprddlhwctl) & 0x0000000f))
                errors |= 8;
 
        debug("Ending Read Delay calibration. Error mask: 0x%x\n", errors);
@@ -450,14 +457,14 @@ int mmdc_do_dqs_calibration(void)
         * Both PHYs for x64 configuration, if x32, do only PHY0.
         */
        writel(initdelay, &mmdc0->mpwrdlctl);
-       if (bus_size == 0x2)
+       if (sysinfo->dsize == 0x2)
                writel(initdelay, &mmdc1->mpwrdlctl);
 
        /*
         * XXX This isn't in the manual. Force a measurement,
         * for previous delay setup to effect.
         */
-       force_delay_measurement(bus_size);
+       force_delay_measurement(sysinfo->dsize);
 
        /*
         * 9. 10. Start the automatic write calibration process
@@ -477,7 +484,8 @@ int mmdc_do_dqs_calibration(void)
        if (readl(&mmdc0->mpwrdlhwctl) & 0x0000000f)
                errors |= 16;
 
-       if ((bus_size == 0x2) && (readl(&mmdc1->mpwrdlhwctl) & 0x0000000f))
+       if ((sysinfo->dsize == 0x2) &&
+           (readl(&mmdc1->mpwrdlhwctl) & 0x0000000f))
                errors |= 32;
 
        debug("Ending Write Delay calibration. Error mask: 0x%x\n", errors);
@@ -529,14 +537,18 @@ int mmdc_do_dqs_calibration(void)
        debug("Read DQS gating calibration:\n");
        debug("\tMPDGCTRL0 PHY0 = 0x%08X\n", readl(&mmdc0->mpdgctrl0));
        debug("\tMPDGCTRL1 PHY0 = 0x%08X\n", readl(&mmdc0->mpdgctrl1));
-       debug("\tMPDGCTRL0 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl0));
-       debug("\tMPDGCTRL1 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl1));
+       if (sysinfo->dsize == 2) {
+               debug("\tMPDGCTRL0 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl0));
+               debug("\tMPDGCTRL1 PHY1 = 0x%08X\n", readl(&mmdc1->mpdgctrl1));
+       }
        debug("Read calibration:\n");
        debug("\tMPRDDLCTL PHY0 = 0x%08X\n", readl(&mmdc0->mprddlctl));
-       debug("\tMPRDDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mprddlctl));
+       if (sysinfo->dsize == 2)
+               debug("\tMPRDDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mprddlctl));
        debug("Write calibration:\n");
        debug("\tMPWRDLCTL PHY0 = 0x%08X\n", readl(&mmdc0->mpwrdlctl));
-       debug("\tMPWRDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mpwrdlctl));
+       if (sysinfo->dsize == 2)
+               debug("\tMPWRDLCTL PHY1 = 0x%08X\n", readl(&mmdc1->mpwrdlctl));
 
        /*
         * Registers below are for debugging purposes.  These print out
@@ -548,10 +560,12 @@ int mmdc_do_dqs_calibration(void)
        debug("\tMPDGHWST1 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst1));
        debug("\tMPDGHWST2 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst2));
        debug("\tMPDGHWST3 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst3));
-       debug("\tMPDGHWST0 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst0));
-       debug("\tMPDGHWST1 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst1));
-       debug("\tMPDGHWST2 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst2));
-       debug("\tMPDGHWST3 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst3));
+       if (sysinfo->dsize == 2) {
+               debug("\tMPDGHWST0 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst0));
+               debug("\tMPDGHWST1 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst1));
+               debug("\tMPDGHWST2 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst2));
+               debug("\tMPDGHWST3 PHY1 = 0x%08x\n", readl(&mmdc1->mpdghwst3));
+       }
 
        debug("Final do_dqs_calibration error mask: 0x%x\n", errors);
 
index 53eb5fa9b08d1858ee0c454b07a261b17f5372e8..cd5bc9768e48e1061c2b17d7ea9a3e0f5e42b1de 100644 (file)
@@ -459,8 +459,8 @@ void mx6sl_dram_iocfg(unsigned width,
                      const struct mx6sl_iomux_grp_regs *);
 
 #if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D)
-int mmdc_do_write_level_calibration(void);
-int mmdc_do_dqs_calibration(void);
+int mmdc_do_write_level_calibration(struct mx6_ddr_sysinfo const *sysinfo);
+int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo);
 #endif
 
 /* configure mx6 mmdc registers */
index 92c61aebb109442b19da7a269ce4c85bd46fe8e8..b934d3678814661a2eb06873232bccf0b0b4d75f 100644 (file)
@@ -605,8 +605,8 @@ void board_init_f(ulong dummy)
 
        /* Perform DDR DRAM calibration */
        udelay(100);
-       mmdc_do_write_level_calibration();
-       mmdc_do_dqs_calibration();
+       mmdc_do_write_level_calibration(&novena_ddr_info);
+       mmdc_do_dqs_calibration(&novena_ddr_info);
 
        /* Clear the BSS. */
        memset(__bss_start, 0, __bss_end - __bss_start);