diff options
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/clocks-common.c | 26 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap5/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c | 139 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap5/prcm-regs.c | 3 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h | 58 | ||||
-rw-r--r-- | arch/arm/include/asm/omap_common.h | 4 |
6 files changed, 231 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/omap-common/clocks-common.c b/arch/arm/cpu/armv7/omap-common/clocks-common.c index 03674e609f..fa04bbedf9 100644 --- a/arch/arm/cpu/armv7/omap-common/clocks-common.c +++ b/arch/arm/cpu/armv7/omap-common/clocks-common.c @@ -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); diff --git a/arch/arm/cpu/armv7/omap5/Makefile b/arch/arm/cpu/armv7/omap5/Makefile index 64c68791f1..e709f14a92 100644 --- a/arch/arm/cpu/armv7/omap5/Makefile +++ b/arch/arm/cpu/armv7/omap5/Makefile @@ -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 index 0000000000..4b8ba26fd6 --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c @@ -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"); + } +} diff --git a/arch/arm/cpu/armv7/omap5/prcm-regs.c b/arch/arm/cpu/armv7/omap5/prcm-regs.c index f80d36dc3c..0547037ff8 100644 --- a/arch/arm/cpu/armv7/omap5/prcm-regs.c +++ b/arch/arm/cpu/armv7/omap5/prcm-regs.c @@ -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 index 0000000000..a924629a35 --- /dev/null +++ b/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h @@ -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 diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h index 50f178bd58..12c2207c27 100644 --- a/arch/arm/include/asm/omap_common.h +++ b/arch/arm/include/asm/omap_common.h @@ -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); |