3 * Texas Instruments Incorporated, <www.ti.com>
5 * Lokesh Vutla <lokeshvutla@ti.com>
7 * SPDX-License-Identifier: GPL-2.0+
11 #include <asm/utils.h>
12 #include <asm/arch/dra7xx_iodelay.h>
13 #include <asm/arch/omap.h>
14 #include <asm/arch/sys_proto.h>
15 #include <asm/arch/clock.h>
16 #include <asm/arch/mux_dra7xx.h>
17 #include <asm/omap_common.h>
19 static int isolate_io(u32 isolate
)
22 clrsetbits_le32((*ctrl
)->control_pbias
, SDCARD_PWRDNZ
,
24 clrsetbits_le32((*ctrl
)->control_pbias
, SDCARD_BIAS_PWRDNZ
,
28 /* Override control on ISOCLKIN signal to IO pad ring. */
29 clrsetbits_le32((*prcm
)->prm_io_pmctrl
, PMCTRL_ISOCLK_OVERRIDE_MASK
,
30 PMCTRL_ISOCLK_OVERRIDE_CTRL
);
31 if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK
, PMCTRL_ISOCLK_STATUS_MASK
,
32 (u32
*)(*prcm
)->prm_io_pmctrl
, LDELAY
))
33 return ERR_DEISOLATE_IO
<< isolate
;
35 /* Isolate/Deisolate IO */
36 clrsetbits_le32((*ctrl
)->ctrl_core_sma_sw_0
, CTRL_ISOLATE_MASK
,
37 isolate
<< CTRL_ISOLATE_SHIFT
);
38 /* Dummy read to add delay t > 10ns */
39 readl((*ctrl
)->ctrl_core_sma_sw_0
);
41 /* Return control on ISOCLKIN to hardware */
42 clrsetbits_le32((*prcm
)->prm_io_pmctrl
, PMCTRL_ISOCLK_OVERRIDE_MASK
,
43 PMCTRL_ISOCLK_NOT_OVERRIDE_CTRL
);
44 if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK
,
45 0 << PMCTRL_ISOCLK_STATUS_SHIFT
,
46 (u32
*)(*prcm
)->prm_io_pmctrl
, LDELAY
))
47 return ERR_DEISOLATE_IO
<< isolate
;
52 static int calibrate_iodelay(u32 base
)
56 /* Configure REFCLK period */
57 reg
= readl(base
+ CFG_REG_2_OFFSET
);
58 reg
&= ~CFG_REG_REFCLK_PERIOD_MASK
;
59 reg
|= CFG_REG_REFCLK_PERIOD
;
60 writel(reg
, base
+ CFG_REG_2_OFFSET
);
62 /* Initiate Calibration */
63 clrsetbits_le32(base
+ CFG_REG_0_OFFSET
, CFG_REG_CALIB_STRT_MASK
,
64 CFG_REG_CALIB_STRT
<< CFG_REG_CALIB_STRT_SHIFT
);
65 if (!wait_on_value(CFG_REG_CALIB_STRT_MASK
, CFG_REG_CALIB_END
,
66 (u32
*)(base
+ CFG_REG_0_OFFSET
), LDELAY
))
67 return ERR_CALIBRATE_IODELAY
;
72 static int update_delay_mechanism(u32 base
)
74 /* Initiate the reload of calibrated values. */
75 clrsetbits_le32(base
+ CFG_REG_0_OFFSET
, CFG_REG_ROM_READ_MASK
,
76 CFG_REG_ROM_READ_START
);
77 if (!wait_on_value(CFG_REG_ROM_READ_MASK
, CFG_REG_ROM_READ_END
,
78 (u32
*)(base
+ CFG_REG_0_OFFSET
), LDELAY
))
79 return ERR_UPDATE_DELAY
;
84 static u32
calculate_delay(u32 base
, u16 offset
, u16 den
)
86 u16 refclk_period
, dly_cnt
, ref_cnt
;
89 refclk_period
= readl(base
+ CFG_REG_2_OFFSET
) &
90 CFG_REG_REFCLK_PERIOD_MASK
;
92 reg
= readl(base
+ offset
);
93 dly_cnt
= (reg
& CFG_REG_DLY_CNT_MASK
) >> CFG_REG_DLY_CNT_SHIFT
;
94 ref_cnt
= (reg
& CFG_REG_REF_CNT_MASK
) >> CFG_REG_REF_CNT_SHIFT
;
100 * To avoid overflow and integer truncation, delay value
101 * is calculated as quotient + remainder.
103 q
= 5 * ((ref_cnt
* refclk_period
) / (dly_cnt
* den
));
104 r
= (10 * ((ref_cnt
* refclk_period
) % (dly_cnt
* den
))) /
110 static u32
get_cfg_reg(u16 a_delay
, u16 g_delay
, u32 cpde
, u32 fpde
)
112 u32 g_delay_coarse
, g_delay_fine
;
113 u32 a_delay_coarse
, a_delay_fine
;
114 u32 c_elements
, f_elements
;
115 u32 total_delay
, reg
= 0;
117 g_delay_coarse
= g_delay
/ 920;
118 g_delay_fine
= ((g_delay
% 920) * 10) / 60;
120 a_delay_coarse
= a_delay
/ cpde
;
121 a_delay_fine
= ((a_delay
% cpde
) * 10) / fpde
;
123 c_elements
= g_delay_coarse
+ a_delay_coarse
;
124 f_elements
= (g_delay_fine
+ a_delay_fine
) / 10;
126 if (f_elements
> 22) {
127 total_delay
= c_elements
* cpde
+ f_elements
* fpde
;
129 c_elements
= total_delay
/ cpde
;
130 f_elements
= (total_delay
% cpde
) / fpde
;
133 reg
= (c_elements
<< CFG_X_COARSE_DLY_SHIFT
) & CFG_X_COARSE_DLY_MASK
;
134 reg
|= (f_elements
<< CFG_X_FINE_DLY_SHIFT
) & CFG_X_FINE_DLY_MASK
;
135 reg
|= CFG_X_SIGNATURE
<< CFG_X_SIGNATURE_SHIFT
;
136 reg
|= CFG_X_LOCK
<< CFG_X_LOCK_SHIFT
;
141 int do_set_iodelay(u32 base
, struct iodelay_cfg_entry
const *array
,
144 struct iodelay_cfg_entry
*iodelay
= (struct iodelay_cfg_entry
*)array
;
145 u32 reg
, cpde
, fpde
, i
;
150 cpde
= calculate_delay((*ctrl
)->iodelay_config_base
, CFG_REG_3_OFFSET
,
155 fpde
= calculate_delay((*ctrl
)->iodelay_config_base
, CFG_REG_4_OFFSET
,
160 for (i
= 0; i
< niodelays
; i
++, iodelay
++) {
161 reg
= get_cfg_reg(iodelay
->a_delay
, iodelay
->g_delay
, cpde
,
163 writel(reg
, base
+ iodelay
->offset
);
169 int __recalibrate_iodelay_start(void)
173 /* IO recalibration should be done only from SRAM */
174 if (OMAP_INIT_CONTEXT_SPL
!= omap_hw_init_context()) {
175 puts("IODELAY recalibration called from invalid context - use only from SPL in SRAM\n");
179 /* unlock IODELAY CONFIG registers */
180 writel(CFG_IODELAY_UNLOCK_KEY
, (*ctrl
)->iodelay_config_base
+
183 ret
= calibrate_iodelay((*ctrl
)->iodelay_config_base
);
187 ret
= isolate_io(ISOLATE_IO
);
191 ret
= update_delay_mechanism((*ctrl
)->iodelay_config_base
);
197 void __recalibrate_iodelay_end(int ret
)
200 /* IO recalibration should be done only from SRAM */
201 if (OMAP_INIT_CONTEXT_SPL
!= omap_hw_init_context()) {
202 puts("IODELAY recalibration called from invalid context - use only from SPL in SRAM\n");
207 ret
= isolate_io(DEISOLATE_IO
);
209 /* lock IODELAY CONFIG registers */
210 writel(CFG_IODELAY_LOCK_KEY
, (*ctrl
)->iodelay_config_base
+
214 * UART cannot be used during IO recalibration sequence as IOs are in
215 * isolation. So error handling and debug prints are done after
216 * complete IO delay recalibration sequence
219 case ERR_CALIBRATE_IODELAY
:
220 puts("IODELAY: IO delay calibration sequence failed\n");
223 puts("IODELAY: Isolation of Device IOs failed\n");
225 case ERR_UPDATE_DELAY
:
226 puts("IODELAY: Delay mechanism update with new calibrated values failed\n");
228 case ERR_DEISOLATE_IO
:
229 puts("IODELAY: De-isolation of Device IOs failed\n");
232 puts("IODELAY: CPDE calculation failed\n");
235 puts("IODELAY: FPDE calculation failed\n");
238 puts("IODELAY: Wrong Context call?\n");
241 debug("IODELAY: IO delay recalibration successfully completed\n");
247 void __recalibrate_iodelay(struct pad_conf_entry
const *pad
, int npads
,
248 struct iodelay_cfg_entry
const *iodelay
,
253 /* IO recalibration should be done only from SRAM */
254 if (OMAP_INIT_CONTEXT_SPL
!= omap_hw_init_context()) {
255 puts("IODELAY recalibration called from invalid context - use only from SPL in SRAM\n");
259 ret
= __recalibrate_iodelay_start();
263 /* Configure Mux settings */
264 do_set_mux32((*ctrl
)->control_padconf_core_base
, pad
, npads
);
266 /* Configure Manual IO timing modes */
267 ret
= do_set_iodelay((*ctrl
)->iodelay_config_base
, iodelay
, niodelays
);
272 __recalibrate_iodelay_end(ret
);