From patchwork Sun Oct 30 17:19:01 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Nelson X-Patchwork-Id: 688980 X-Patchwork-Delegate: sbabic@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3t6PRw1n4Gz9t1b for ; Mon, 31 Oct 2016 04:21:48 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 48F204B98B; Sun, 30 Oct 2016 18:21:39 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id oOfF-D9BC8XI; Sun, 30 Oct 2016 18:21:39 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E8237A7550; Sun, 30 Oct 2016 18:21:28 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 44FC14B71E for ; Sun, 30 Oct 2016 18:21:22 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Ko02k0NlfGwo for ; Sun, 30 Oct 2016 18:21:22 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from fed1rmfepo103.cox.net (fed1rmfepo103.cox.net [68.230.241.145]) by theia.denx.de (Postfix) with ESMTP id 39B554B811 for ; Sun, 30 Oct 2016 18:21:17 +0100 (CET) Received: from fed1rmimpo210.cox.net ([68.230.241.161]) by fed1rmfepo103.cox.net (InterMail vM.8.01.05.28 201-2260-151-171-20160122) with ESMTP id <20161030172116.NUYE4001.fed1rmfepo103.cox.net@fed1rmimpo210.cox.net> for ; Sun, 30 Oct 2016 13:21:16 -0400 Received: from localhost.localdomain ([98.165.102.90]) by fed1rmimpo210.cox.net with cox id 1tME1u0011x1f0q01tMFf8; Sun, 30 Oct 2016 13:21:16 -0400 X-CT-Class: Clean X-CT-Score: 0.00 X-CT-RefID: str=0001.0A090203.58162C0C.001C, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 X-CT-Spam: 0 X-Authority-Analysis: v=2.1 cv=T9osN6+Q c=1 sm=1 tr=0 a=i7nT0dqFxmwB8XGI+JTv/g==:117 a=i7nT0dqFxmwB8XGI+JTv/g==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=9_1hYV8uAAAA:8 a=NVs_FsKcYCCwlgDNrJcA:9 a=FKwbt-OhbrkoYuZlCyy7:22 X-CM-Score: 0.00 Authentication-Results: cox.net; auth=pass (CRAM-MD5) smtp.auth=eric.a.nelson@cox.net From: Eric Nelson To: u-boot@lists.denx.de Date: Sun, 30 Oct 2016 10:19:01 -0700 Message-Id: <1477847942-20347-3-git-send-email-eric@nelint.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1477847942-20347-1-git-send-email-eric@nelint.com> References: <1477847942-20347-1-git-send-email-eric@nelint.com> Cc: marex@denx.de, albert.u.boot@aribaud.net, fabio.estevam@nxp.com Subject: [U-Boot] [PATCH 2/3] mx6: ddr: pass mx6_ddr_sysinfo to calibration routines X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 Reviewed-by: Marek Vasut --- arch/arm/cpu/armv7/mx6/ddr.c | 98 +++++++++++++++++++-------------- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 4 +- board/kosagi/novena/novena_spl.c | 4 +- 3 files changed, 60 insertions(+), 46 deletions(-) diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index b15f376..274a0ba 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -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); diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 53eb5fa..cd5bc97 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -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 */ diff --git a/board/kosagi/novena/novena_spl.c b/board/kosagi/novena/novena_spl.c index 92c61ae..b934d36 100644 --- a/board/kosagi/novena/novena_spl.c +++ b/board/kosagi/novena/novena_spl.c @@ -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);