ARM: DRA7: Add support for IO delay configuration
authorLokesh Vutla <lokeshvutla@ti.com>
Thu, 4 Jun 2015 11:12:36 +0000 (16:42 +0530)
committerTom Rini <trini@konsulko.com>
Fri, 12 Jun 2015 17:02:05 +0000 (13:02 -0400)
On DRA7, in addition to the regular muxing of pins, an additional
hardware module called IODelay which is also expected to be
configured. This "IODelay" module has it's own register space that is
independent of the control module.

It is advocated strongly in TI's official documentation considering
the existing design of the DRA7 family of processors during mux or
IODelay recalibration, there is a potential for a significant glitch
which may cause functional impairment to certain hardware. It is
hence recommended to do muxing as part of IOdelay recalibration.

IODELAY recalibration sequence:
- Complete AVS voltage change on VDD_CORE_L
- Unlock IODLAY config registers.
- Perform IO delay calibration with predefined values.
- Isolate all the IOs
- Update the delay mechanism for each IO with new calibrated values.
- Configure PAD configuration registers
- De-isolate all the IOs.
- Relock IODELAY config registers.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
arch/arm/cpu/armv7/omap-common/clocks-common.c
arch/arm/cpu/armv7/omap5/Makefile
arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c [new file with mode: 0644]
arch/arm/cpu/armv7/omap5/prcm-regs.c
arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h [new file with mode: 0644]
arch/arm/include/asm/omap_common.h

index 03674e609ffce42c28eea7ee88539308a65b5c73..fa04bbedf9ea780841f7b96fc37d79f2351581ee 100644 (file)
@@ -508,6 +508,12 @@ static u32 optimize_vcore_voltage(struct volts const *v)
        return val;
 }
 
+#ifdef CONFIG_IODELAY_RECALIBRATION
+void __weak recalibrate_iodelay(void)
+{
+}
+#endif
+
 /*
  * Setup the voltages for the main SoC core power domains.
  * We start with the maximum voltages allowed here, as set in the corresponding
@@ -561,6 +567,16 @@ void scale_vcores(struct vcores_data const *vcores)
 
        debug("cor: %d\n", vcores->core.value);
        do_scale_vcore(vcores->core.addr, vcores->core.value, vcores->core.pmic);
+       /*
+        * IO delay recalibration should be done immediately after
+        * adjusting AVS voltages for VDD_CORE_L.
+        * Respective boards should call __recalibrate_iodelay()
+        * with proper mux, virtual and manual mode configurations.
+        */
+#ifdef CONFIG_IODELAY_RECALIBRATION
+       recalibrate_iodelay();
+#endif
+
        debug("mpu: %d\n", vcores->mpu.value);
        do_scale_vcore(vcores->mpu.addr, vcores->mpu.value, vcores->mpu.pmic);
        /* Configure MPU ABB LDO after scale */
@@ -587,6 +603,16 @@ void scale_vcores(struct vcores_data const *vcores)
        val = optimize_vcore_voltage(&vcores->core);
        do_scale_vcore(vcores->core.addr, val, vcores->core.pmic);
 
+       /*
+        * IO delay recalibration should be done immediately after
+        * adjusting AVS voltages for VDD_CORE_L.
+        * Respective boards should call __recalibrate_iodelay()
+        * with proper mux, virtual and manual mode configurations.
+        */
+#ifdef CONFIG_IODELAY_RECALIBRATION
+       recalibrate_iodelay();
+#endif
+
        val = optimize_vcore_voltage(&vcores->mpu);
        do_scale_vcore(vcores->mpu.addr, val, vcores->mpu.pmic);
 
index 64c68791f18e3405d3aba11d39a3e6557c2f5f7b..e709f14a921bb24c22a56ab5f600cca50fb6f99d 100644 (file)
@@ -11,3 +11,4 @@ obj-y += sdram.o
 obj-y  += prcm-regs.o
 obj-y  += hw_data.o
 obj-y  += abb.o
+obj-$(CONFIG_IODELAY_RECALIBRATION) += dra7xx_iodelay.o
diff --git a/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c b/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c
new file mode 100644 (file)
index 0000000..4b8ba26
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/utils.h>
+#include <asm/arch/dra7xx_iodelay.h>
+#include <asm/arch/omap.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clock.h>
+#include <asm/omap_common.h>
+
+static int isolate_io(u32 isolate)
+{
+       if (isolate) {
+               clrsetbits_le32((*ctrl)->control_pbias, SDCARD_PWRDNZ,
+                               SDCARD_PWRDNZ);
+               clrsetbits_le32((*ctrl)->control_pbias, SDCARD_BIAS_PWRDNZ,
+                               SDCARD_BIAS_PWRDNZ);
+       }
+
+       /* Override control on ISOCLKIN signal to IO pad ring. */
+       clrsetbits_le32((*prcm)->prm_io_pmctrl, PMCTRL_ISOCLK_OVERRIDE_MASK,
+                       PMCTRL_ISOCLK_OVERRIDE_CTRL);
+       if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK, PMCTRL_ISOCLK_STATUS_MASK,
+                          (u32 *)(*prcm)->prm_io_pmctrl, LDELAY))
+               return ERR_DEISOLATE_IO << isolate;
+
+       /* Isolate/Deisolate IO */
+       clrsetbits_le32((*ctrl)->ctrl_core_sma_sw_0, CTRL_ISOLATE_MASK,
+                       isolate << CTRL_ISOLATE_SHIFT);
+       /* Dummy read to add delay t > 10ns */
+       readl((*ctrl)->ctrl_core_sma_sw_0);
+
+       /* Return control on ISOCLKIN to hardware */
+       clrsetbits_le32((*prcm)->prm_io_pmctrl, PMCTRL_ISOCLK_OVERRIDE_MASK,
+                       PMCTRL_ISOCLK_NOT_OVERRIDE_CTRL);
+       if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK,
+                          0 << PMCTRL_ISOCLK_STATUS_SHIFT,
+                          (u32 *)(*prcm)->prm_io_pmctrl, LDELAY))
+               return ERR_DEISOLATE_IO << isolate;
+
+       return 0;
+}
+
+static int calibrate_iodelay(u32 base)
+{
+       u32 reg;
+
+       /* Configure REFCLK period */
+       reg = readl(base + CFG_REG_2_OFFSET);
+       reg &= ~CFG_REG_REFCLK_PERIOD_MASK;
+       reg |= CFG_REG_REFCLK_PERIOD;
+       writel(reg, base + CFG_REG_2_OFFSET);
+
+       /* Initiate Calibration */
+       clrsetbits_le32(base + CFG_REG_0_OFFSET, CFG_REG_CALIB_STRT_MASK,
+                       CFG_REG_CALIB_STRT << CFG_REG_CALIB_STRT_SHIFT);
+       if (!wait_on_value(CFG_REG_CALIB_STRT_MASK, CFG_REG_CALIB_END,
+                          (u32 *)(base + CFG_REG_0_OFFSET), LDELAY))
+               return ERR_CALIBRATE_IODELAY;
+
+       return 0;
+}
+
+static int update_delay_mechanism(u32 base)
+{
+       /* Initiate the reload of calibrated values. */
+       clrsetbits_le32(base + CFG_REG_0_OFFSET, CFG_REG_ROM_READ_MASK,
+                       CFG_REG_ROM_READ_START);
+       if (!wait_on_value(CFG_REG_ROM_READ_MASK, CFG_REG_ROM_READ_END,
+                          (u32 *)(base + CFG_REG_0_OFFSET), LDELAY))
+               return ERR_UPDATE_DELAY;
+
+       return 0;
+}
+
+void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads)
+{
+       int ret = 0;
+
+       /* IO recalibration should be done only from SRAM */
+       if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context()) {
+               puts("IODELAY recalibration called from invalid context - use only from SPL in SRAM\n");
+               return;
+       }
+
+       /* unlock IODELAY CONFIG registers */
+       writel(CFG_IODELAY_UNLOCK_KEY, (*ctrl)->iodelay_config_base +
+              CFG_REG_8_OFFSET);
+
+       ret = calibrate_iodelay((*ctrl)->iodelay_config_base);
+       if (ret)
+               goto err;
+
+       ret = isolate_io(ISOLATE_IO);
+       if (ret)
+               goto err;
+
+       ret = update_delay_mechanism((*ctrl)->iodelay_config_base);
+       if (ret)
+               goto err;
+
+       /* Configure Mux settings */
+       do_set_mux32((*ctrl)->control_padconf_core_base, pad, npads);
+
+       ret = isolate_io(DEISOLATE_IO);
+
+err:
+       /* lock IODELAY CONFIG registers */
+       writel(CFG_IODELAY_LOCK_KEY, (*ctrl)->iodelay_config_base +
+              CFG_REG_8_OFFSET);
+       /*
+        * UART cannot be used during IO recalibration sequence as IOs are in
+        * isolation. So error handling and debug prints are done after
+        * complete IO delay recalibration sequence
+        */
+       switch (ret) {
+       case ERR_CALIBRATE_IODELAY:
+               puts("IODELAY: IO delay calibration sequence failed\n");
+               break;
+       case ERR_ISOLATE_IO:
+               puts("IODELAY: Isolation of Device IOs failed\n");
+               break;
+       case ERR_UPDATE_DELAY:
+               puts("IODELAY: Delay mechanism update with new calibrated values failed\n");
+               break;
+       case ERR_DEISOLATE_IO:
+               puts("IODELAY: De-isolation of Device IOs failed\n");
+               break;
+       default:
+               debug("IODELAY: IO delay recalibration successfully completed\n");
+       }
+}
index f80d36dc3cf161512687aa4bb396e303f9a9b902..0547037ff8fc8e79f341c5420cf45fa188884418 100644 (file)
@@ -378,6 +378,7 @@ struct omap_sys_ctrl_regs const dra7xx_ctrl = {
        .control_status                         = 0x4A002134,
        .control_phy_power_usb                  = 0x4A002370,
        .control_phy_power_sata                 = 0x4A002374,
+       .ctrl_core_sma_sw_0                     = 0x4A0023FC,
        .control_core_mac_id_0_lo               = 0x4A002514,
        .control_core_mac_id_0_hi               = 0x4A002518,
        .control_core_mac_id_1_lo               = 0x4A00251C,
@@ -457,6 +458,7 @@ struct omap_sys_ctrl_regs const dra7xx_ctrl = {
        .control_efuse_3                        = 0x4AE0C5D0,
        .control_efuse_4                        = 0x4AE0C5D4,
        .control_efuse_13                       = 0x4AE0C5F0,
+       .iodelay_config_base                    = 0x4844A000,
 };
 
 struct prcm_regs const omap5_es2_prcm = {
@@ -976,6 +978,7 @@ struct prcm_regs const dra7xx_prcm = {
        .prm_rstctrl                            = 0x4ae07d00,
        .prm_rstst                              = 0x4ae07d04,
        .prm_rsttime                            = 0x4ae07d08,
+       .prm_io_pmctrl                          = 0x4ae07d20,
        .prm_vc_val_bypass                      = 0x4ae07da0,
        .prm_vc_cfg_i2c_mode                    = 0x4ae07db4,
        .prm_vc_cfg_i2c_clk                     = 0x4ae07db8,
diff --git a/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h b/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h
new file mode 100644 (file)
index 0000000..a924629
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated
+ *
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _DRA7_IODELAY_H_
+#define _DRA7_IODELAY_H_
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+
+/* CONFIG_REG_0 */
+#define CFG_REG_0_OFFSET               0xC
+#define CFG_REG_ROM_READ_SHIFT         1
+#define CFG_REG_ROM_READ_MASK          (1 << 1)
+#define CFG_REG_CALIB_STRT_SHIFT       0
+#define CFG_REG_CALIB_STRT_MASK                (1 << 0)
+#define CFG_REG_CALIB_STRT             1
+#define CFG_REG_CALIB_END              0
+#define CFG_REG_ROM_READ_START         (1 << 1)
+#define CFG_REG_ROM_READ_END           (0 << 1)
+
+/* CONFIG_REG_2 */
+#define CFG_REG_2_OFFSET               0x14
+#define CFG_REG_REFCLK_PERIOD_SHIFT    0
+#define CFG_REG_REFCLK_PERIOD_MASK     (0xFFFF << 0)
+#define CFG_REG_REFCLK_PERIOD          0x2EF
+
+/* CONFIG_REG_8 */
+#define CFG_REG_8_OFFSET               0x2C
+#define CFG_IODELAY_UNLOCK_KEY         0x0000AAAA
+#define CFG_IODELAY_LOCK_KEY           0x0000AAAB
+
+/* CTRL_CORE_SMA_SW_0 */
+#define CTRL_ISOLATE_SHIFT             2
+#define CTRL_ISOLATE_MASK              (1 << 2)
+#define ISOLATE_IO                     1
+#define DEISOLATE_IO                   0
+
+/* PRM_IO_PMCTRL */
+#define PMCTRL_ISOCLK_OVERRIDE_SHIFT   0
+#define PMCTRL_ISOCLK_OVERRIDE_MASK    (1 << 0)
+#define PMCTRL_ISOCLK_STATUS_SHIFT     1
+#define PMCTRL_ISOCLK_STATUS_MASK      (1 << 1)
+#define PMCTRL_ISOCLK_OVERRIDE_CTRL    1
+#define PMCTRL_ISOCLK_NOT_OVERRIDE_CTRL        0
+
+#define ERR_CALIBRATE_IODELAY          0x1
+#define ERR_DEISOLATE_IO               0x2
+#define ERR_ISOLATE_IO                 0x4
+#define ERR_UPDATE_DELAY               0x8
+
+void __recalibrate_iodelay(struct pad_conf_entry const *array, int npads);
+#endif
index 50f178bd58b7dc01bcf44b3111ca21fe030d544b..12c2207c275a2567c0702990d7b78da8224f06f4 100644 (file)
@@ -313,6 +313,7 @@ struct prcm_regs {
        u32 prm_rstctrl;
        u32 prm_rstst;
        u32 prm_rsttime;
+       u32 prm_io_pmctrl;
        u32 prm_vc_val_bypass;
        u32 prm_vc_cfg_i2c_mode;
        u32 prm_vc_cfg_i2c_clk;
@@ -455,6 +456,8 @@ struct omap_sys_ctrl_regs {
        u32 control_efuse_12;
        u32 control_efuse_13;
        u32 control_padconf_wkup_base;
+       u32 iodelay_config_base;
+       u32 ctrl_core_sma_sw_0;
 };
 
 struct dpll_params {
@@ -583,6 +586,7 @@ s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb);
 
 void usb_fake_mac_from_die_id(u32 *id);
 void usb_set_serial_num_from_die_id(u32 *id);
+void recalibrate_iodelay(void);
 
 void omap_smc1(u32 service, u32 val);