summaryrefslogtreecommitdiff
path: root/arch/arm/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r--arch/arm/cpu/armv7/mx6/Kconfig20
-rw-r--r--arch/arm/cpu/armv7/mx6/clock.c19
-rw-r--r--arch/arm/cpu/armv7/mx6/ddr.c131
-rw-r--r--arch/arm/cpu/armv7/mx6/soc.c31
4 files changed, 152 insertions, 49 deletions
diff --git a/arch/arm/cpu/armv7/mx6/Kconfig b/arch/arm/cpu/armv7/mx6/Kconfig
index 762a5814d7..8c96ba37c3 100644
--- a/arch/arm/cpu/armv7/mx6/Kconfig
+++ b/arch/arm/cpu/armv7/mx6/Kconfig
@@ -35,6 +35,14 @@ config MX6ULL
bool
select MX6UL
+config MX6_DDRCAL
+ bool "Include dynamic DDR calibration routines"
+ depends on SPL
+ default n
+ help
+ Say "Y" if your board uses dynamic (per-boot) DDR calibration.
+ If unsure, say N.
+
choice
prompt "MX6 board select"
optional
@@ -192,6 +200,16 @@ config TARGET_UDOO
bool "udoo"
select SUPPORT_SPL
+config TARGET_UDOO_NEO
+ bool "UDOO Neo"
+ select SUPPORT_SPL
+
+config TARGET_SAMTEC_VINING_2000
+ bool "samtec VIN|ING 2000"
+ select MX6SX
+ select DM
+ select DM_THERMAL
+
config TARGET_WANDBOARD
bool "wandboard"
select SUPPORT_SPL
@@ -247,12 +265,14 @@ source "board/freescale/mx6ullevk/Kconfig"
source "board/phytec/pcm058/Kconfig"
source "board/gateworks/gw_ventana/Kconfig"
source "board/kosagi/novena/Kconfig"
+source "board/samtec/vining_2000/Kconfig"
source "board/seco/Kconfig"
source "board/solidrun/mx6cuboxi/Kconfig"
source "board/technexion/pico-imx6ul/Kconfig"
source "board/tbs/tbs2910/Kconfig"
source "board/tqc/tqma6/Kconfig"
source "board/udoo/Kconfig"
+source "board/udoo/neo/Kconfig"
source "board/wandboard/Kconfig"
source "board/warp/Kconfig"
diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
index ae3143c760..299562884a 100644
--- a/arch/arm/cpu/armv7/mx6/clock.c
+++ b/arch/arm/cpu/armv7/mx6/clock.c
@@ -881,6 +881,11 @@ int enable_fec_anatop_clock(int fec_id, enum enet_freq freq)
writel(reg, &anatop->pll_enet);
#ifdef CONFIG_MX6SX
+ /* Disable enet system clcok before switching clock parent */
+ reg = readl(&imx_ccm->CCGR3);
+ reg &= ~MXC_CCM_CCGR3_ENET_MASK;
+ writel(reg, &imx_ccm->CCGR3);
+
/*
* Set enet ahb clock to 200MHz
* pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
@@ -1379,6 +1384,20 @@ void select_ldb_di_clock_source(enum ldb_di_clock clk)
}
#endif
+#ifndef CONFIG_SYS_NO_FLASH
+void enable_eim_clk(unsigned char enable)
+{
+ u32 reg;
+
+ reg = __raw_readl(&imx_ccm->CCGR6);
+ if (enable)
+ reg |= MXC_CCM_CCGR6_EMI_SLOW_MASK;
+ else
+ reg &= ~MXC_CCM_CCGR6_EMI_SLOW_MASK;
+ __raw_writel(reg, &imx_ccm->CCGR6);
+}
+#endif
+
/***************************************************/
U_BOOT_CMD(
diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c
index 7beb7eabf7..0cf391eb9c 100644
--- a/arch/arm/cpu/armv7/mx6/ddr.c
+++ b/arch/arm/cpu/armv7/mx6/ddr.c
@@ -14,8 +14,7 @@
#include <asm/types.h>
#include <wait_bit.h>
-#if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) || defined(CONFIG_MX6D)
-
+#if defined(CONFIG_MX6_DDRCAL)
static void reset_read_data_fifos(void)
{
struct mmdc_p_regs *mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR;
@@ -86,14 +85,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 +101,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 +124,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 +154,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 +195,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 +222,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 +233,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 +301,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 +319,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);
/*
* ***************************
@@ -347,6 +352,8 @@ int mmdc_do_dqs_calibration(void)
* 16 before comparing read data.
*/
setbits_le32(&mmdc0->mpdgctrl0, 1 << 30);
+ if (sysinfo->dsize == 2)
+ setbits_le32(&mmdc1->mpdgctrl0, 1 << 30);
/* Set bit 28 to start automatic read DQS gating calibration */
setbits_le32(&mmdc0->mpdgctrl0, 5 << 28);
@@ -362,9 +369,14 @@ 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] */
+ clrbits_le32(&mmdc0->mpdgctrl0, 1 << 30);
+ if (sysinfo->dsize == 2)
+ clrbits_le32(&mmdc1->mpdgctrl0, 1 << 30);
+
/*
* DQS gating absolute offset should be modified from
* reflecting (HW_DG_LOWx + HW_DG_UPx)/2 to
@@ -374,7 +386,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,
@@ -417,7 +429,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);
@@ -443,14 +456,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
@@ -470,7 +483,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);
@@ -522,14 +536,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
@@ -541,10 +559,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);
@@ -1480,6 +1500,29 @@ void mx6_ddr3_cfg(const struct mx6_ddr_sysinfo *sysinfo,
mdelay(1);
}
+void mmdc_read_calibration(struct mx6_ddr_sysinfo const *sysinfo,
+ struct mx6_mmdc_calibration *calib)
+{
+ 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;
+
+ calib->p0_mpwldectrl0 = readl(&mmdc0->mpwldectrl0);
+ calib->p0_mpwldectrl1 = readl(&mmdc0->mpwldectrl1);
+ calib->p0_mpdgctrl0 = readl(&mmdc0->mpdgctrl0);
+ calib->p0_mpdgctrl1 = readl(&mmdc0->mpdgctrl1);
+ calib->p0_mprddlctl = readl(&mmdc0->mprddlctl);
+ calib->p0_mpwrdlctl = readl(&mmdc0->mpwrdlctl);
+
+ if (sysinfo->dsize == 2) {
+ calib->p1_mpwldectrl0 = readl(&mmdc1->mpwldectrl0);
+ calib->p1_mpwldectrl1 = readl(&mmdc1->mpwldectrl1);
+ calib->p1_mpdgctrl0 = readl(&mmdc1->mpdgctrl0);
+ calib->p1_mpdgctrl1 = readl(&mmdc1->mpdgctrl1);
+ calib->p1_mprddlctl = readl(&mmdc1->mprddlctl);
+ calib->p1_mpwrdlctl = readl(&mmdc1->mpwrdlctl);
+ }
+}
+
void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo,
const struct mx6_mmdc_calibration *calib,
const void *ddr_cfg)
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c
index 7b53bfdeb4..dd94797514 100644
--- a/arch/arm/cpu/armv7/mx6/soc.c
+++ b/arch/arm/cpu/armv7/mx6/soc.c
@@ -300,9 +300,17 @@ static void clear_mmdc_ch_mask(void)
writel(reg, &mxc_ccm->ccdr);
}
+#define OCOTP_MEM0_REFTOP_TRIM_SHIFT 8
+
static void init_bandgap(void)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
+ struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
+ struct fuse_bank *bank = &ocotp->bank[1];
+ struct fuse_bank1_regs *fuse =
+ (struct fuse_bank1_regs *)bank->fuse_regs;
+ uint32_t val;
+
/*
* Ensure the bandgap has stabilized.
*/
@@ -315,13 +323,26 @@ static void init_bandgap(void)
*/
writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
/*
- * On i.MX6ULL, the LDO 1.2V bandgap voltage is 30mV higher. so set
- * VBGADJ bits to 2b'110 to adjust it.
+ * On i.MX6ULL,we need to set VBGADJ bits according to the
+ * REFTOP_TRIM[3:0] in fuse table
+ * 000 - set REFTOP_VBGADJ[2:0] to 3b'110,
+ * 110 - set REFTOP_VBGADJ[2:0] to 3b'000,
+ * 001 - set REFTOP_VBGADJ[2:0] to 3b'001,
+ * 010 - set REFTOP_VBGADJ[2:0] to 3b'010,
+ * 011 - set REFTOP_VBGADJ[2:0] to 3b'011,
+ * 100 - set REFTOP_VBGADJ[2:0] to 3b'100,
+ * 101 - set REFTOP_VBGADJ[2:0] to 3b'101,
+ * 111 - set REFTOP_VBGADJ[2:0] to 3b'111,
*/
- if (is_mx6ull())
- writel(BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ, &anatop->ana_misc0_set);
-}
+ if (is_mx6ull()) {
+ val = readl(&fuse->mem0);
+ val >>= OCOTP_MEM0_REFTOP_TRIM_SHIFT;
+ val &= 0x7;
+ writel(val << BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ_SHIFT,
+ &anatop->ana_misc0_set);
+ }
+}
#ifdef CONFIG_MX6SL
static void set_preclk_from_osc(void)