summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/configs/imx5_defconfig2
-rw-r--r--arch/arm/plat-mxc/zq_calib.c68
2 files changed, 60 insertions, 10 deletions
diff --git a/arch/arm/configs/imx5_defconfig b/arch/arm/configs/imx5_defconfig
index 63abbc522970..fc5c3171f05d 100644
--- a/arch/arm/configs/imx5_defconfig
+++ b/arch/arm/configs/imx5_defconfig
@@ -274,7 +274,7 @@ CONFIG_MXC_PWM=y
CONFIG_ARCH_HAS_RNGC=y
CONFIG_ARCH_MXC_IOMUX_V3=y
CONFIG_MXC_DVFS_PER=y
-# CONFIG_MXC_ZQ_CALIBRATION is not set
+CONFIG_MXC_ZQ_CALIBRATION=y
#
# Processor Type
diff --git a/arch/arm/plat-mxc/zq_calib.c b/arch/arm/plat-mxc/zq_calib.c
index 469acaf6527e..33e744cfbdaa 100644
--- a/arch/arm/plat-mxc/zq_calib.c
+++ b/arch/arm/plat-mxc/zq_calib.c
@@ -48,6 +48,15 @@ extern void __iomem *databahn_base;
#define DATABAHN_REG_ZQ_SW_CFG2 DATABAHN_CTL_REG75
#define DATABAHN_REG_ZQ_STATUS DATABAHN_CTL_REG83
+#define DDR_TYPE_LPDDR2 (0x5 << 8)
+static inline bool is_lpddr2(void)
+{
+ u32 v;
+ v = __raw_readl(databahn_base);
+
+ return (v & DDR_TYPE_LPDDR2) == DDR_TYPE_LPDDR2;
+}
+
/*!
* MXC ZQ interface - Compare PU vs the External Resistor (240/300 ohm)
*
@@ -189,27 +198,36 @@ static s32 mxc_zq_pd_calib(u32 start, u32 pu)
* @param pu u32
* @param pd u32
*/
-static void mxc_zq_hw_load(u32 pu, u32 pd)
+static void mxc_zq_hw_load(u32 pu, u32 pd, u32 pu_pd_sel)
{
u32 data;
+ u32 pu_plus_1, pd_plus_1;
+
+ pu_plus_1 = (pu == 0x1F) ? 0x1F : pu + 1;
+ pd_plus_1 = (pd == 0x0F) ? 0x0F : pd + 1;
+
/*
* The PU/PD values stored in register
* DATABAHN_REG_ZQ_SW_CFG1/2 would be loaded
*/
- data = (pd << 24) | (pu << 16);
- __raw_writel(data, databahn_base + DATABAHN_REG_ZQ_SW_CFG1);
- data = ((pd + 1) << 8) | (pu + 1);
+ data = (pd << 8) | pu;
__raw_writel(data, databahn_base + DATABAHN_REG_ZQ_SW_CFG2);
+ data = (pd_plus_1 << 24) | (pu_plus_1 << 16); /* load PD */
+ if (pu_pd_sel)
+ data |= (1 << 4); /* load PU */
+ __raw_writel(data, databahn_base + DATABAHN_REG_ZQ_SW_CFG1);
+
/*
* bit[0]: enable hardware load
* bit[4]: trigger a hardware load.
*
* When the posedge of bit[4] detected, hardware trigger a load.
*/
- __raw_writel(0x11, databahn_base + DATABAHN_REG_ZQ_HW_CFG);
- /* clear bit[4] for next load */
- __raw_writel(0x01, databahn_base + DATABAHN_REG_ZQ_HW_CFG);
+ __raw_writel(0x10011, databahn_base + DATABAHN_REG_ZQ_HW_CFG);
+ __raw_writel(0x10001, databahn_base + DATABAHN_REG_ZQ_HW_CFG);
+ ndelay(300);
+ __raw_writel(0x1, databahn_base + DATABAHN_REG_ZQ_HW_CFG);
}
/*!
@@ -252,6 +270,33 @@ static void mxc_zq_sw_load(u32 pu, u32 pd)
__raw_writel(0x1 << 21, databahn_base + DATABAHN_REG_ZQ_HW_CFG);
}
+/*
+ * This function is for ZQ pu calibration
+ */
+static u32 pu_calib_based_on_pd(u32 start, u32 pd)
+{
+ u32 i;
+ u32 data;
+ u32 zq_pu_val = 0;
+
+ /*
+ * compare PU from 0 to 0x1F
+ * data is the result of the comparator
+ * the result sequence looks like:
+ * 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ * Pleae take the First "1" in the sequence for PU
+ */
+ for (i = start; i < 32; i++) {
+ data = mxc_zq_pd_compare(i, pd);
+ if (data) {
+ zq_pu_val = i;
+ break;
+ }
+ }
+
+ return zq_pu_val;
+}
+
/*!
* MXC ZQ interface - PU/PD calib function
* This function Do a complete PU/PD calib and loading process.
@@ -264,9 +309,14 @@ static void mxc_zq_main(struct work_struct *dummy)
/* Search pu value start from 0 */
pu = mxc_zq_pu_calib(0);
/* Search pd value start from 0 */
- pd = mxc_zq_pd_calib(0, pu);
+ if (is_lpddr2()) {
+ pd = mxc_zq_pd_calib(0, pu) + 3;
+ pu = pu_calib_based_on_pd(0, pd);
+ } else
+ pd = mxc_zq_pd_calib(0, pu);
dev_dbg(zq_calib_dev, "za_calib: pu = %d, pd = %d\n", pu, pd);
- mxc_zq_hw_load(pu, pd);
+ mxc_zq_hw_load(pu, pd, 1); /* Load Pu */
+ mxc_zq_hw_load(pu, pd, 0); /* Load Pd */
/* or do software load alternatively */
/* zq_sw_load(pu, pd); */
spin_unlock(&zq_lock);