|
@@ -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");
|
|
|
}
|