From patchwork Thu Jun 4 11:12:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lokesh Vutla X-Patchwork-Id: 480643 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id B0F31140081 for ; Thu, 4 Jun 2015 21:16:00 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8D42D4B65F; Thu, 4 Jun 2015 13:15:53 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 8e7mzMLYrA5D; Thu, 4 Jun 2015 13:15:53 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 311AB4B69A; Thu, 4 Jun 2015 13:15:36 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1C29F4B660 for ; Thu, 4 Jun 2015 13:15:29 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id q6SSafd5Zhjc for ; Thu, 4 Jun 2015 13:15:29 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from bear.ext.ti.com (bear.ext.ti.com [192.94.94.41]) by theia.denx.de (Postfix) with ESMTPS id 166134B64D for ; Thu, 4 Jun 2015 13:15:21 +0200 (CEST) Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id t54BFIIb007594; Thu, 4 Jun 2015 06:15:18 -0500 Received: from DLEE70.ent.ti.com (dlemailx.itg.ti.com [157.170.170.113]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id t54BFIGD016464; Thu, 4 Jun 2015 06:15:18 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.224.2; Thu, 4 Jun 2015 06:15:18 -0500 Received: from a0131933.apr.dhcp.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id t54BF5gB009164; Thu, 4 Jun 2015 06:15:16 -0500 From: Lokesh Vutla To: , Date: Thu, 4 Jun 2015 16:42:37 +0530 Message-ID: <1433416362-7708-6-git-send-email-lokeshvutla@ti.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1433416362-7708-1-git-send-email-lokeshvutla@ti.com> References: <1433416362-7708-1-git-send-email-lokeshvutla@ti.com> MIME-Version: 1.0 Cc: t-kristo@ti.com, nsekhar@ti.com Subject: [U-Boot] [PATCH 05/10] ARM: DRA7: Add support for manual mode configuration X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" In addition to the regular mux configuration, certain pins of DRA7 require to have "manual mode" also programmed, when predefined delay characteristics cannot be used for the interface. struct iodelay_cfg_entry is introduced for populating manual mode IO timings. For configuring manual mode, along with the normal pad configuration do the following steps: - Select MODESELECT field of each assocaited PAD. CTRL_CORE_PAD_XXX[8]:MODESELECT = 1(Enable MANUAL_MODE macro along with mux) - Populate A_DELAY, G_DELAY values that are specified in DATA MANUAL. And pass the offset of the CFG_XXX register in iodelay_cfg_entry. Signed-off-by: Lokesh Vutla Signed-off-by: Nishanth Menon --- arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c | 101 ++++++++++++++++++++++- arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h | 27 +++++- arch/arm/include/asm/arch-omap5/mux_dra7xx.h | 2 + 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 4b8ba26..9fa6e69 100644 --- a/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c +++ b/arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c @@ -13,6 +13,7 @@ #include #include #include +#include #include 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 a924629..2f53d85 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 13c288b..2115abb 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 b41bf15..6da8297 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;