diff options
-rw-r--r-- | arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c | 101 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h | 27 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-omap5/mux_dra7xx.h | 2 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-omap5/sys_proto.h | 12 |
4 files changed, 140 insertions, 2 deletions
diff --git a/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c b/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c index 4b8ba26fd6..9fa6e6991f 100644 --- a/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c +++ b/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c @@ -13,6 +13,7 @@ #include <asm/arch/omap.h> #include <asm/arch/sys_proto.h> #include <asm/arch/clock.h> +#include <asm/arch/mux_dra7xx.h> #include <asm/omap_common.h> static int isolate_io(u32 isolate) @@ -80,7 +81,94 @@ static int update_delay_mechanism(u32 base) return 0; } -void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads) +static u32 calculate_delay(u32 base, u16 offset, u16 den) +{ + u16 refclk_period, dly_cnt, ref_cnt; + u32 reg, q, r; + + refclk_period = readl(base + CFG_REG_2_OFFSET) & + CFG_REG_REFCLK_PERIOD_MASK; + + reg = readl(base + offset); + dly_cnt = (reg & CFG_REG_DLY_CNT_MASK) >> CFG_REG_DLY_CNT_SHIFT; + ref_cnt = (reg & CFG_REG_REF_CNT_MASK) >> CFG_REG_REF_CNT_SHIFT; + + if (!dly_cnt || !den) + return 0; + + /* + * To avoid overflow and integer truncation, delay value + * is calculated as quotient + remainder. + */ + q = 5 * ((ref_cnt * refclk_period) / (dly_cnt * den)); + r = (10 * ((ref_cnt * refclk_period) % (dly_cnt * den))) / + (2 * dly_cnt * den); + + return q + r; +} + +static u32 get_cfg_reg(u16 a_delay, u16 g_delay, u32 cpde, u32 fpde) +{ + u32 g_delay_coarse, g_delay_fine; + u32 a_delay_coarse, a_delay_fine; + u32 c_elements, f_elements; + u32 total_delay, reg = 0; + + g_delay_coarse = g_delay / 920; + g_delay_fine = ((g_delay % 920) * 10) / 60; + + a_delay_coarse = a_delay / cpde; + a_delay_fine = ((a_delay % cpde) * 10) / fpde; + + c_elements = g_delay_coarse + a_delay_coarse; + f_elements = (g_delay_fine + a_delay_fine) / 10; + + if (f_elements > 22) { + total_delay = c_elements * cpde + f_elements * fpde; + + c_elements = total_delay / cpde; + f_elements = (total_delay % cpde) / fpde; + } + + reg = (c_elements << CFG_X_COARSE_DLY_SHIFT) & CFG_X_COARSE_DLY_MASK; + reg |= (f_elements << CFG_X_FINE_DLY_SHIFT) & CFG_X_FINE_DLY_MASK; + reg |= CFG_X_SIGNATURE << CFG_X_SIGNATURE_SHIFT; + reg |= CFG_X_LOCK << CFG_X_LOCK_SHIFT; + + return reg; +} + +static int do_set_iodelay(u32 base, struct iodelay_cfg_entry const *array, + int niodelays) +{ + struct iodelay_cfg_entry *iodelay = (struct iodelay_cfg_entry *)array; + u32 reg, cpde, fpde, i; + + if (!niodelays) + return 0; + + cpde = calculate_delay((*ctrl)->iodelay_config_base, CFG_REG_3_OFFSET, + 88); + if (!cpde) + return ERR_CPDE; + + fpde = calculate_delay((*ctrl)->iodelay_config_base, CFG_REG_4_OFFSET, + 264); + if (!fpde) + return ERR_FPDE; + + for (i = 0; i < niodelays; i++, iodelay++) { + reg = get_cfg_reg(iodelay->a_delay, iodelay->g_delay, cpde, + fpde); + writel(reg, base + iodelay->offset); + } + + return 0; +} + +void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads, + struct iodelay_cfg_entry const *iodelay, + int niodelays) { int ret = 0; @@ -109,6 +197,11 @@ void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads) /* Configure Mux settings */ do_set_mux32((*ctrl)->control_padconf_core_base, pad, npads); + /* Configure Manual IO timing modes */ + ret = do_set_iodelay((*ctrl)->iodelay_config_base, iodelay, niodelays); + if (ret) + goto err; + ret = isolate_io(DEISOLATE_IO); err: @@ -133,6 +226,12 @@ err: case ERR_DEISOLATE_IO: puts("IODELAY: De-isolation of Device IOs failed\n"); break; + case ERR_CPDE: + puts("IODELAY: CPDE calculation failed\n"); + break; + case ERR_FPDE: + puts("IODELAY: FPDE calculation failed\n"); + break; default: debug("IODELAY: IO delay recalibration successfully completed\n"); } diff --git a/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h b/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h index a924629a35..2f53d85283 100644 --- a/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h +++ b/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h @@ -35,6 +35,14 @@ #define CFG_IODELAY_UNLOCK_KEY 0x0000AAAA #define CFG_IODELAY_LOCK_KEY 0x0000AAAB +/* CONFIG_REG_3/4 */ +#define CFG_REG_3_OFFSET 0x18 +#define CFG_REG_4_OFFSET 0x1C +#define CFG_REG_DLY_CNT_SHIFT 16 +#define CFG_REG_DLY_CNT_MASK (0xFFFF << 16) +#define CFG_REG_REF_CNT_SHIFT 0 +#define CFG_REG_REF_CNT_MASK (0xFFFF << 0) + /* CTRL_CORE_SMA_SW_0 */ #define CTRL_ISOLATE_SHIFT 2 #define CTRL_ISOLATE_MASK (1 << 2) @@ -53,6 +61,23 @@ #define ERR_DEISOLATE_IO 0x2 #define ERR_ISOLATE_IO 0x4 #define ERR_UPDATE_DELAY 0x8 +#define ERR_CPDE 0x3 +#define ERR_FPDE 0x5 + +/* CFG_XXX */ +#define CFG_X_SIGNATURE_SHIFT 12 +#define CFG_X_SIGNATURE_MASK (0x3F << 12) +#define CFG_X_LOCK_SHIFT 10 +#define CFG_X_LOCK_MASK (0x1 << 10) +#define CFG_X_COARSE_DLY_SHIFT 5 +#define CFG_X_COARSE_DLY_MASK (0x1F << 5) +#define CFG_X_FINE_DLY_SHIFT 0 +#define CFG_X_FINE_DLY_MASK (0x1F << 0) +#define CFG_X_SIGNATURE 0x29 +#define CFG_X_LOCK 1 + +void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads, + struct iodelay_cfg_entry const *iodelay, + int niodelays); -void __recalibrate_iodelay(struct pad_conf_entry const *array, int npads); #endif diff --git a/arch/arm/include/asm/arch-omap5/mux_dra7xx.h b/arch/arm/include/asm/arch-omap5/mux_dra7xx.h index 13c288b5d3..2115abb555 100644 --- a/arch/arm/include/asm/arch-omap5/mux_dra7xx.h +++ b/arch/arm/include/asm/arch-omap5/mux_dra7xx.h @@ -61,6 +61,8 @@ #define MODE_SELECT (1 << 8) #define DELAYMODE_SHIFT 4 +#define MANUAL_MODE MODE_SELECT + #define VIRTUAL_MODE0 (MODE_SELECT | (0x0 << DELAYMODE_SHIFT)) #define VIRTUAL_MODE1 (MODE_SELECT | (0x1 << DELAYMODE_SHIFT)) #define VIRTUAL_MODE2 (MODE_SELECT | (0x2 << DELAYMODE_SHIFT)) diff --git a/arch/arm/include/asm/arch-omap5/sys_proto.h b/arch/arm/include/asm/arch-omap5/sys_proto.h index b41bf15a08..6da8297c72 100644 --- a/arch/arm/include/asm/arch-omap5/sys_proto.h +++ b/arch/arm/include/asm/arch-omap5/sys_proto.h @@ -18,6 +18,18 @@ DECLARE_GLOBAL_DATA_PTR; +/* + * Structure for Iodelay configuration registers. + * Theoretical max for g_delay is 21560 ps. + * Theoretical max for a_delay is 1/3rd of g_delay max. + * So using u16 for both a/g_delay. + */ +struct iodelay_cfg_entry { + u16 offset; + u16 a_delay; + u16 g_delay; +}; + struct pad_conf_entry { u32 offset; u32 val; |