diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/cpu/armv7/mx6/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx6/clock.c | 8 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx6/ddr.c | 559 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx6/soc.c | 64 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx7/soc.c | 21 | ||||
-rw-r--r-- | arch/arm/dts/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/dts/pcm052.dts | 22 | ||||
-rw-r--r-- | arch/arm/dts/vf-colibri.dtsi | 15 | ||||
-rw-r--r-- | arch/arm/dts/vf.dtsi | 48 | ||||
-rw-r--r-- | arch/arm/dts/vf500-colibri.dts | 5 | ||||
-rw-r--r-- | arch/arm/dts/vf610-colibri.dts | 5 | ||||
-rw-r--r-- | arch/arm/dts/vf610-twr.dts | 22 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-mx6/imx-regs.h | 23 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-mx6/mx6-ddr.h | 5 |
14 files changed, 751 insertions, 56 deletions
diff --git a/arch/arm/cpu/armv7/mx6/Kconfig b/arch/arm/cpu/armv7/mx6/Kconfig index 8489182651..c72a150875 100644 --- a/arch/arm/cpu/armv7/mx6/Kconfig +++ b/arch/arm/cpu/armv7/mx6/Kconfig @@ -96,6 +96,11 @@ config TARGET_MX6SXSABRESD select DM select DM_THERMAL +config TARGET_MX6SXSABREAUTO + bool "mx6sxsabreauto" + select DM + select DM_THERMAL + config TARGET_MX6UL_9X9_EVK bool "mx6ul_9x9_evk" select MX6UL @@ -166,6 +171,7 @@ source "board/freescale/mx6qsabreauto/Kconfig" source "board/freescale/mx6sabresd/Kconfig" source "board/freescale/mx6slevk/Kconfig" source "board/freescale/mx6sxsabresd/Kconfig" +source "board/freescale/mx6sxsabreauto/Kconfig" source "board/freescale/mx6ul_14x14_evk/Kconfig" source "board/gateworks/gw_ventana/Kconfig" source "board/kosagi/novena/Kconfig" diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 27a3f2f4e6..88380a6cd9 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -638,10 +638,6 @@ void mxs_set_lcdclk(u32 base_addr, u32 freq) } temp = freq * max_pred * max_postd; - if (temp > max) { - puts("Please decrease freq, too large!\n"); - return; - } if (temp < min) { /* * Register: PLL_VIDEO @@ -742,8 +738,8 @@ int enable_lcdif_clock(u32 base_addr) u32 lcdif_clk_sel_mask, lcdif_ccgr3_mask; if (is_cpu_type(MXC_CPU_MX6SX)) { - if ((base_addr == LCDIF1_BASE_ADDR) || - (base_addr == LCDIF2_BASE_ADDR)) { + if ((base_addr != LCDIF1_BASE_ADDR) && + (base_addr != LCDIF2_BASE_ADDR)) { puts("Wrong LCD interface!\n"); return -EINVAL; } diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index 567ddc4bdd..e457febf67 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -13,6 +13,565 @@ #include <asm/io.h> #include <asm/types.h> +#if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D) + +static int wait_for_bit(void *reg, const uint32_t mask, bool set) +{ + unsigned int timeout = 1000; + u32 val; + + while (--timeout) { + val = readl(reg); + if (!set) + val = ~val; + + if ((val & mask) == mask) + return 0; + + udelay(1); + } + + printf("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n", + __func__, reg, mask, set); + hang(); /* DRAM couldn't be calibrated, game over :-( */ +} + +static void reset_read_data_fifos(void) +{ + struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR; + + /* Reset data FIFOs twice. */ + setbits_le32(&mmdc0->mpdgctrl0, 1 << 31); + wait_for_bit(&mmdc0->mpdgctrl0, 1 << 31, 0); + + setbits_le32(&mmdc0->mpdgctrl0, 1 << 31); + wait_for_bit(&mmdc0->mpdgctrl0, 1 << 31, 0); +} + +static void precharge_all(const bool cs0_enable, const bool cs1_enable) +{ + struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR; + + /* + * Issue the Precharge-All command to the DDR device for both + * chip selects. Note, CON_REQ bit should also remain set. If + * only using one chip select, then precharge only the desired + * chip select. + */ + if (cs0_enable) { /* CS0 */ + writel(0x04008050, &mmdc0->mdscr); + wait_for_bit(&mmdc0->mdscr, 1 << 14, 1); + } + + if (cs1_enable) { /* CS1 */ + writel(0x04008058, &mmdc0->mdscr); + wait_for_bit(&mmdc0->mdscr, 1 << 14, 1); + } +} + +static void force_delay_measurement(int bus_size) +{ + 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; + + writel(0x800, &mmdc0->mpmur0); + if (bus_size == 0x2) + writel(0x800, &mmdc1->mpmur0); +} + +static void modify_dg_result(u32 *reg_st0, u32 *reg_st1, u32 *reg_ctrl) +{ + u32 dg_tmp_val, dg_dl_abs_offset, dg_hc_del, val_ctrl; + + /* + * DQS gating absolute offset should be modified from reflecting + * (HW_DG_LOWx + HW_DG_UPx)/2 to reflecting (HW_DG_UPx - 0x80) + */ + + val_ctrl = readl(reg_ctrl); + val_ctrl &= 0xf0000000; + + dg_tmp_val = ((readl(reg_st0) & 0x07ff0000) >> 16) - 0xc0; + dg_dl_abs_offset = dg_tmp_val & 0x7f; + dg_hc_del = (dg_tmp_val & 0x780) << 1; + + val_ctrl |= dg_dl_abs_offset + dg_hc_del; + + dg_tmp_val = ((readl(reg_st1) & 0x07ff0000) >> 16) - 0xc0; + dg_dl_abs_offset = dg_tmp_val & 0x7f; + dg_hc_del = (dg_tmp_val & 0x780) << 1; + + val_ctrl |= (dg_dl_abs_offset + dg_hc_del) << 16; + + writel(val_ctrl, reg_ctrl); +} + +int mmdc_do_write_level_calibration(void) +{ + 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 ddr_mr1 = 0x4; + + /* + * Stash old values in case calibration fails, + * we need to restore them + */ + ldectrl[0] = readl(&mmdc0->mpwldectrl0); + ldectrl[1] = readl(&mmdc0->mpwldectrl1); + ldectrl[2] = readl(&mmdc1->mpwldectrl0); + ldectrl[3] = readl(&mmdc1->mpwldectrl1); + + /* disable DDR logic power down timer */ + clrbits_le32(&mmdc0->mdpdc, 0xff00); + + /* disable Adopt power down timer */ + setbits_le32(&mmdc0->mapsr, 0x1); + + debug("Starting write leveling calibration.\n"); + + /* + * 2. disable auto refresh and ZQ calibration + * before proceeding with Write Leveling calibration + */ + esdmisc_val = readl(&mmdc0->mdref); + writel(0x0000C000, &mmdc0->mdref); + zq_val = readl(&mmdc0->mpzqhwctrl); + 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)); + /* + * 4 & 5. Configure the external DDR device to enter write-leveling + * mode through Load Mode Register command. + * Register setting: + * Bits[31:16] MR1 value (0x0080 write leveling enable) + * Bit[9] set WL_EN to enable MMDC DQS output + * Bits[6:4] set CMD bits for Load Mode Register programming + * Bits[2:0] set CMD_BA to 0x1 for DDR MR1 programming + */ + writel(0x00808231, &mmdc0->mdscr); + + /* 6. Activate automatic calibration by setting MPWLGCR[HW_WL_EN] */ + writel(0x00000001, &mmdc0->mpwlgcr); + + /* + * 7. Upon completion of this process the MMDC de-asserts + * the MPWLGCR[HW_WL_EN] + */ + wait_for_bit(&mmdc0->mpwlgcr, 1 << 0, 0); + + /* + * 8. check for any errors: check both PHYs for x64 configuration, + * if x32, check only PHY0 + */ + if (readl(&mmdc0->mpwlgcr) & 0x00000F00) + errors |= 1; + 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)) { + 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); + errors |= 4; + } + + /* + * User should issue MRS command to exit write leveling mode + * through Load Mode Register command + * Register setting: + * Bits[31:16] MR1 value "ddr_mr1" value from initialization + * Bit[9] clear WL_EN to disable MMDC DQS output + * Bits[6:4] set CMD bits for Load Mode Register programming + * Bits[2:0] set CMD_BA to 0x1 for DDR MR1 programming + */ + writel((ddr_mr1 << 16) + 0x8031, &mmdc0->mdscr); + + /* re-enable auto refresh and zq cal */ + writel(esdmisc_val, &mmdc0->mdref); + writel(zq_val, &mmdc0->mpzqhwctrl); + + debug("\tMMDC_MPWLDECTRL0 after write level cal: 0x%08X\n", + 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)); + + /* 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); + + /* enable DDR logic power down timer: */ + setbits_le32(&mmdc0->mdpdc, 0x00005500); + + /* Enable Adopt power down timer: */ + clrbits_le32(&mmdc0->mapsr, 0x1); + + /* Clear CON_REQ */ + writel(0, &mmdc0->mdscr); + + return errors; +} + +int mmdc_do_dqs_calibration(void) +{ + 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; + struct mx6dq_iomux_ddr_regs *mx6_ddr_iomux = + (struct mx6dq_iomux_ddr_regs *)MX6DQ_IOM_DDR_BASE; + bool cs0_enable; + bool cs1_enable; + 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; + u32 initdelay = 0x40404040; + + /* check to see which chip selects are enabled */ + cs0_enable_initial = readl(&mmdc0->mdctl) & 0x80000000; + cs1_enable_initial = readl(&mmdc0->mdctl) & 0x40000000; + + /* disable DDR logic power down timer: */ + clrbits_le32(&mmdc0->mdpdc, 0xff00); + + /* disable Adopt power down timer: */ + setbits_le32(&mmdc0->mapsr, 0x1); + + /* set DQS pull ups */ + setbits_le32(&mx6_ddr_iomux->dram_sdqs0, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs1, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs2, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs3, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs4, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs5, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs6, 0x7000); + setbits_le32(&mx6_ddr_iomux->dram_sdqs7, 0x7000); + + /* Save old RALAT and WALAT values */ + esdmisc_val = readl(&mmdc0->mdmisc); + + setbits_le32(&mmdc0->mdmisc, + (1 << 6) | (1 << 7) | (1 << 8) | (1 << 16) | (1 << 17)); + + /* Disable auto refresh before proceeding with calibration */ + temp_ref = readl(&mmdc0->mdref); + writel(0x0000c000, &mmdc0->mdref); + + /* + * Per the ref manual, issue one refresh cycle MDSCR[CMD]= 0x2, + * this also sets the CON_REQ bit. + */ + if (cs0_enable_initial) + writel(0x00008020, &mmdc0->mdscr); + if (cs1_enable_initial) + writel(0x00008028, &mmdc0->mdscr); + + /* poll to make sure the con_ack bit was asserted */ + wait_for_bit(&mmdc0->mdscr, 1 << 14, 1); + + /* + * Check MDMISC register CALIB_PER_CS to see which CS calibration + * is targeted to (under normal cases, it should be cleared + * as this is the default value, indicating calibration is directed + * to CS0). + * Disable the other chip select not being target for calibration + * to avoid any potential issues. This will get re-enabled at end + * of calibration. + */ + if ((readl(&mmdc0->mdmisc) & 0x00100000) == 0) + clrbits_le32(&mmdc0->mdctl, 1 << 30); /* clear SDE_1 */ + else + clrbits_le32(&mmdc0->mdctl, 1 << 31); /* clear SDE_0 */ + + /* + * Check to see which chip selects are now enabled for + * the remainder of the calibration. + */ + 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 */ + writel(pddword, &mmdc0->mppdcmpr1); + + /* + * Issue a write access to the external DDR device by setting + * the bit SW_DUMMY_WR (bit 0) in the MPSWDAR0 and then poll + * this bit until it clears to indicate completion of the write access. + */ + setbits_le32(&mmdc0->mpswdar0, 1); + wait_for_bit(&mmdc0->mpswdar0, 1 << 0, 0); + + /* Set the RD_DL_ABS# bits to their default values + * (will be calibrated later in the read delay-line calibration). + * Both PHYs for x64 configuration, if x32, do only PHY0. + */ + writel(initdelay, &mmdc0->mprddlctl); + if (bus_size == 0x2) + writel(initdelay, &mmdc1->mprddlctl); + + /* Force a measurment, for previous delay setup to take effect. */ + force_delay_measurement(bus_size); + + /* + * *************************** + * Read DQS Gating calibration + * *************************** + */ + debug("Starting Read DQS Gating calibration.\n"); + + /* + * Reset the read data FIFOs (two resets); only need to issue reset + * to PHY0 since in x64 mode, the reset will also go to PHY1. + */ + reset_read_data_fifos(); + + /* + * Start the automatic read DQS gating calibration process by + * asserting MPDGCTRL0[HW_DG_EN] and MPDGCTRL0[DG_CMP_CYC] + * and then poll MPDGCTRL0[HW_DG_EN]] until this bit clears + * to indicate completion. + * Also, ensure that MPDGCTRL0[HW_DG_ERR] is clear to indicate + * no errors were seen during calibration. + */ + + /* + * Set bit 30: chooses option to wait 32 cycles instead of + * 16 before comparing read data. + */ + setbits_le32(&mmdc0->mpdgctrl0, 1 << 30); + + /* Set bit 28 to start automatic read DQS gating calibration */ + setbits_le32(&mmdc0->mpdgctrl0, 5 << 28); + + /* Poll for completion. MPDGCTRL0[HW_DG_EN] should be 0 */ + wait_for_bit(&mmdc0->mpdgctrl0, 1 << 28, 0); + + /* + * Check to see if any errors were encountered during calibration + * (check MPDGCTRL0[HW_DG_ERR]). + * Check both PHYs for x64 configuration, if x32, check only PHY0. + */ + if (readl(&mmdc0->mpdgctrl0) & 0x00001000) + errors |= 1; + + if ((bus_size == 0x2) && (readl(&mmdc1->mpdgctrl0) & 0x00001000)) + errors |= 2; + + /* + * DQS gating absolute offset should be modified from + * reflecting (HW_DG_LOWx + HW_DG_UPx)/2 to + * reflecting (HW_DG_UPx - 0x80) + */ + modify_dg_result(&mmdc0->mpdghwst0, &mmdc0->mpdghwst1, + &mmdc0->mpdgctrl0); + modify_dg_result(&mmdc0->mpdghwst2, &mmdc0->mpdghwst3, + &mmdc0->mpdgctrl1); + if (bus_size == 0x2) { + modify_dg_result(&mmdc1->mpdghwst0, &mmdc1->mpdghwst1, + &mmdc1->mpdgctrl0); + modify_dg_result(&mmdc1->mpdghwst2, &mmdc1->mpdghwst3, + &mmdc1->mpdgctrl1); + } + debug("Ending Read DQS Gating calibration. Error mask: 0x%x\n", errors); + + /* + * ********************** + * Read Delay calibration + * ********************** + */ + debug("Starting Read Delay calibration.\n"); + + reset_read_data_fifos(); + + /* + * 4. Issue the Precharge-All command to the DDR device for both + * chip selects. If only using one chip select, then precharge + * only the desired chip select. + */ + precharge_all(cs0_enable, cs1_enable); + + /* + * 9. Read delay-line calibration + * Start the automatic read calibration process by asserting + * MPRDDLHWCTL[HW_RD_DL_EN]. + */ + writel(0x00000030, &mmdc0->mprddlhwctl); + + /* + * 10. poll for completion + * MMDC indicates that the write data calibration had finished by + * setting MPRDDLHWCTL[HW_RD_DL_EN] = 0. Also, ensure that + * no error bits were set. + */ + wait_for_bit(&mmdc0->mprddlhwctl, 1 << 4, 0); + + /* check both PHYs for x64 configuration, if x32, check only PHY0 */ + if (readl(&mmdc0->mprddlhwctl) & 0x0000000f) + errors |= 4; + + if ((bus_size == 0x2) && (readl(&mmdc1->mprddlhwctl) & 0x0000000f)) + errors |= 8; + + debug("Ending Read Delay calibration. Error mask: 0x%x\n", errors); + + /* + * *********************** + * Write Delay Calibration + * *********************** + */ + debug("Starting Write Delay calibration.\n"); + + reset_read_data_fifos(); + + /* + * 4. Issue the Precharge-All command to the DDR device for both + * chip selects. If only using one chip select, then precharge + * only the desired chip select. + */ + precharge_all(cs0_enable, cs1_enable); + + /* + * 8. Set the WR_DL_ABS# bits to their default values. + * Both PHYs for x64 configuration, if x32, do only PHY0. + */ + writel(initdelay, &mmdc0->mpwrdlctl); + if (bus_size == 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); + + /* + * 9. 10. Start the automatic write calibration process + * by asserting MPWRDLHWCTL0[HW_WR_DL_EN]. + */ + writel(0x00000030, &mmdc0->mpwrdlhwctl); + + /* + * Poll for completion. + * MMDC indicates that the write data calibration had finished + * by setting MPWRDLHWCTL[HW_WR_DL_EN] = 0. + * Also, ensure that no error bits were set. + */ + wait_for_bit(&mmdc0->mpwrdlhwctl, 1 << 4, 0); + + /* Check both PHYs for x64 configuration, if x32, check only PHY0 */ + if (readl(&mmdc0->mpwrdlhwctl) & 0x0000000f) + errors |= 16; + + if ((bus_size == 0x2) && (readl(&mmdc1->mpwrdlhwctl) & 0x0000000f)) + errors |= 32; + + debug("Ending Write Delay calibration. Error mask: 0x%x\n", errors); + + reset_read_data_fifos(); + + /* Enable DDR logic power down timer */ + setbits_le32(&mmdc0->mdpdc, 0x00005500); + + /* Enable Adopt power down timer */ + clrbits_le32(&mmdc0->mapsr, 0x1); + + /* Restore MDMISC value (RALAT, WALAT) to MMDCP1 */ + writel(esdmisc_val, &mmdc0->mdmisc); + + /* Clear DQS pull ups */ + clrbits_le32(&mx6_ddr_iomux->dram_sdqs0, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs1, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs2, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs3, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs4, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs5, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs6, 0x7000); + clrbits_le32(&mx6_ddr_iomux->dram_sdqs7, 0x7000); + + /* Re-enable SDE (chip selects) if they were set initially */ + if (cs1_enable_initial) + /* Set SDE_1 */ + setbits_le32(&mmdc0->mdctl, 1 << 30); + + if (cs0_enable_initial) + /* Set SDE_0 */ + setbits_le32(&mmdc0->mdctl, 1 << 31); + + /* Re-enable to auto refresh */ + writel(temp_ref, &mmdc0->mdref); + + /* Clear the MDSCR (including the con_req bit) */ + writel(0x0, &mmdc0->mdscr); /* CS0 */ + + /* Poll to make sure the con_ack bit is clear */ + wait_for_bit(&mmdc0->mdscr, 1 << 14, 0); + + /* + * Print out the registers that were updated as a result + * of the calibration process. + */ + debug("MMDC registers updated from calibration\n"); + 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)); + debug("Read calibration:\n"); + debug("\tMPRDDLCTL PHY0 = 0x%08X\n", readl(&mmdc0->mprddlctl)); + 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)); + + /* + * Registers below are for debugging purposes. These print out + * the upper and lower boundaries captured during + * read DQS gating calibration. + */ + debug("Status registers bounds for read DQS gating:\n"); + debug("\tMPDGHWST0 PHY0 = 0x%08x\n", readl(&mmdc0->mpdghwst0)); + 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)); + + debug("Final do_dqs_calibration error mask: 0x%x\n", errors); + + return errors; +} +#endif + #if defined(CONFIG_MX6SX) /* Configure MX6SX mmdc iomux */ void mx6sx_dram_iocfg(unsigned width, diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index bf5ae8cdff..8aeeaecfd2 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -349,6 +349,38 @@ int arch_cpu_init(void) return 0; } +#ifdef CONFIG_ENV_IS_IN_MMC +__weak int board_mmc_get_env_dev(int devno) +{ + return CONFIG_SYS_MMC_ENV_DEV; +} + +int mmc_get_env_dev(void) +{ + struct src *src_regs = (struct src *)SRC_BASE_ADDR; + u32 soc_sbmr = readl(&src_regs->sbmr1); + u32 bootsel; + int devno; + + /* + * Refer to + * "i.MX 6Dual/6Quad Applications Processor Reference Manual" + * Chapter "8.5.3.1 Expansion Device eFUSE Configuration" + * i.MX6SL/SX/UL has same layout. + */ + bootsel = (soc_sbmr & 0x000000FF) >> 6; + + /* If not boot from sd/mmc, use default value */ + if (bootsel != 1) + return CONFIG_SYS_MMC_ENV_DEV; + + /* BOOT_CFG2[3] and BOOT_CFG2[4] */ + devno = (soc_sbmr & 0x00001800) >> 11; + + return board_mmc_get_env_dev(devno); +} +#endif + int board_postclk_init(void) { set_ldo_voltage(LDO_SOC, 1175); /* Set VDDSOC to 1.175V */ @@ -364,15 +396,29 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) struct fuse_bank4_regs *fuse = (struct fuse_bank4_regs *)bank->fuse_regs; - u32 value = readl(&fuse->mac_addr_high); - mac[0] = (value >> 8); - mac[1] = value ; - - value = readl(&fuse->mac_addr_low); - mac[2] = value >> 24 ; - mac[3] = value >> 16 ; - mac[4] = value >> 8 ; - mac[5] = value ; + if ((is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL)) && + dev_id == 1) { + u32 value = readl(&fuse->mac_addr2); + mac[0] = value >> 24 ; + mac[1] = value >> 16 ; + mac[2] = value >> 8 ; + mac[3] = value ; + + value = readl(&fuse->mac_addr1); + mac[4] = value >> 24 ; + mac[5] = value >> 16 ; + + } else { + u32 value = readl(&fuse->mac_addr1); + mac[0] = (value >> 8); + mac[1] = value ; + + value = readl(&fuse->mac_addr0); + mac[2] = value >> 24 ; + mac[3] = value >> 16 ; + mac[4] = value >> 8 ; + mac[5] = value ; + } } #endif diff --git a/arch/arm/cpu/armv7/mx7/soc.c b/arch/arm/cpu/armv7/mx7/soc.c index 1d8e470971..a6ab551a4a 100644 --- a/arch/arm/cpu/armv7/mx7/soc.c +++ b/arch/arm/cpu/armv7/mx7/soc.c @@ -288,6 +288,27 @@ enum boot_device get_boot_device(void) return boot_dev; } +#ifdef CONFIG_ENV_IS_IN_MMC +__weak int board_mmc_get_env_dev(int devno) +{ + return CONFIG_SYS_MMC_ENV_DEV; +} + +int mmc_get_env_dev(void) +{ + struct bootrom_sw_info **p = + (struct bootrom_sw_info **)ROM_SW_INFO_ADDR; + int devno = (*p)->boot_dev_instance; + u8 boot_type = (*p)->boot_dev_type; + + /* If not boot from sd/mmc, use default value */ + if ((boot_type != BOOT_TYPE_SD) && (boot_type != BOOT_TYPE_MMC)) + return CONFIG_SYS_MMC_ENV_DEV; + + return board_mmc_get_env_dev(devno); +} +#endif + void s_init(void) { #if !defined CONFIG_SPL_BUILD diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 77efb292da..0fa5796946 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -195,7 +195,9 @@ dtb-$(CONFIG_MACH_SUN9I) += \ sun9i-a80-cubieboard4.dtb dtb-$(CONFIG_VF610) += vf500-colibri.dtb \ - vf610-colibri.dtb + vf610-colibri.dtb \ + vf610-twr.dtb \ + pcm052.dtb dtb-$(CONFIG_SOC_KEYSTONE) += k2hk-evm.dtb \ k2l-evm.dtb \ diff --git a/arch/arm/dts/pcm052.dts b/arch/arm/dts/pcm052.dts new file mode 100644 index 0000000000..0475f1f5ee --- /dev/null +++ b/arch/arm/dts/pcm052.dts @@ -0,0 +1,22 @@ +/* + * Copyright 2016 Toradex AG + * + * SPDX-License-Identifier: GPL-2.0+ or X11 + */ + +/dts-v1/; +#include "vf.dtsi" + +/ { + model = "Phytec phyCORE-Vybrid"; + compatible = "phytec,pcm052", "fsl,vf610"; + + choosen { + stdout-path = &uart1; + }; + +}; + +&uart1 { + status = "okay"; +}; diff --git a/arch/arm/dts/vf-colibri.dtsi b/arch/arm/dts/vf-colibri.dtsi index 7a8e9bee33..dc52748c09 100644 --- a/arch/arm/dts/vf-colibri.dtsi +++ b/arch/arm/dts/vf-colibri.dtsi @@ -2,14 +2,15 @@ * Copyright 2014 Toradex AG * * SPDX-License-Identifier: GPL-2.0+ or X11 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include "vf.dtsi" +/ { + chosen { + stdout-path = &uart0; + }; +}; + &dspi1 { status = "okay"; bus-num = <1>; @@ -19,3 +20,7 @@ spi-max-frequency = <50000000>; }; }; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm/dts/vf.dtsi b/arch/arm/dts/vf.dtsi index 78706e118e..1530d2fc87 100644 --- a/arch/arm/dts/vf.dtsi +++ b/arch/arm/dts/vf.dtsi @@ -2,11 +2,6 @@ * Copyright 2013 Freescale Semiconductor, Inc. * * SPDX-License-Identifier: GPL-2.0+ or X11 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ /include/ "skeleton.dtsi" @@ -17,6 +12,12 @@ gpio2 = &gpio2; gpio3 = &gpio3; gpio4 = &gpio4; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; spi0 = &dspi0; spi1 = &dspi1; }; @@ -33,6 +34,30 @@ #size-cells = <1>; ranges; + uart0: serial@40027000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x40027000 0x1000>; + status = "disabled"; + }; + + uart1: serial@40028000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x40028000 0x1000>; + status = "disabled"; + }; + + uart2: serial@40029000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x40029000 0x1000>; + status = "disabled"; + }; + + uart3: serial@4002a000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x4002a000 0x1000>; + status = "disabled"; + }; + dspi0: dspi0@4002c000 { #address-cells = <1>; #size-cells = <0>; @@ -95,6 +120,19 @@ #address-cells = <1>; #size-cells = <1>; ranges; + + uart4: serial@400a9000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x400a9000 0x1000>; + status = "disabled"; + }; + + uart5: serial@400aa000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x400aa000 0x1000>; + status = "disabled"; + }; + }; }; }; diff --git a/arch/arm/dts/vf500-colibri.dts b/arch/arm/dts/vf500-colibri.dts index e3833064d2..02d0ce8653 100644 --- a/arch/arm/dts/vf500-colibri.dts +++ b/arch/arm/dts/vf500-colibri.dts @@ -2,11 +2,6 @@ * Copyright 2014 Toradex AG * * SPDX-License-Identifier: GPL-2.0+ or X11 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ /dts-v1/; diff --git a/arch/arm/dts/vf610-colibri.dts b/arch/arm/dts/vf610-colibri.dts index 63bb3f4ee7..24dfcbe0fc 100644 --- a/arch/arm/dts/vf610-colibri.dts +++ b/arch/arm/dts/vf610-colibri.dts @@ -2,11 +2,6 @@ * Copyright 2014 Toradex AG * * SPDX-License-Identifier: GPL-2.0+ or X11 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ /dts-v1/; diff --git a/arch/arm/dts/vf610-twr.dts b/arch/arm/dts/vf610-twr.dts new file mode 100644 index 0000000000..a4ccbcbde1 --- /dev/null +++ b/arch/arm/dts/vf610-twr.dts @@ -0,0 +1,22 @@ +/* + * Copyright 2016 Toradex AG + * + * SPDX-License-Identifier: GPL-2.0+ or X11 + */ + +/dts-v1/; +#include "vf.dtsi" + +/ { + model = "VF610 Tower Board"; + compatible = "fsl,vf610-twr", "fsl,vf610"; + + choosen { + stdout-path = &uart1; + }; + +}; + +&uart1 { + status = "okay"; +}; diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index f24525e7af..5c45bf6d6e 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -715,39 +715,22 @@ struct fuse_bank1_regs { u32 rsvd7[3]; }; -#if (defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL)) struct fuse_bank4_regs { u32 sjc_resp_low; u32 rsvd0[3]; u32 sjc_resp_high; u32 rsvd1[3]; - u32 mac_addr_low; + u32 mac_addr0; u32 rsvd2[3]; - u32 mac_addr_high; + u32 mac_addr1; u32 rsvd3[3]; - u32 mac_addr2; + u32 mac_addr2; /*For i.MX6SX and i.MX6UL*/ u32 rsvd4[7]; u32 gp1; u32 rsvd5[3]; u32 gp2; u32 rsvd6[3]; }; -#else -struct fuse_bank4_regs { - u32 sjc_resp_low; - u32 rsvd0[3]; - u32 sjc_resp_high; - u32 rsvd1[3]; - u32 mac_addr_low; - u32 rsvd2[3]; - u32 mac_addr_high; - u32 rsvd3[0xb]; - u32 gp1; - u32 rsvd4[3]; - u32 gp2; - u32 rsvd5[3]; -}; -#endif struct aipstz_regs { u32 mprot0; diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 68d9bda2c5..12c30d274f 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -456,6 +456,11 @@ void mx6sl_dram_iocfg(unsigned width, const struct mx6sl_iomux_ddr_regs *, 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); +#endif + /* configure mx6 mmdc registers */ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *, const struct mx6_mmdc_calibration *, |