]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/omap5/dra7xx_iodelay.c
ARM: DRA7: Add support for IO delay configuration
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / omap5 / dra7xx_iodelay.c
1 /*
2  * (C) Copyright 2015
3  * Texas Instruments Incorporated, <www.ti.com>
4  *
5  * Lokesh Vutla <lokeshvutla@ti.com>
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
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/omap_common.h>
17
18 static int isolate_io(u32 isolate)
19 {
20         if (isolate) {
21                 clrsetbits_le32((*ctrl)->control_pbias, SDCARD_PWRDNZ,
22                                 SDCARD_PWRDNZ);
23                 clrsetbits_le32((*ctrl)->control_pbias, SDCARD_BIAS_PWRDNZ,
24                                 SDCARD_BIAS_PWRDNZ);
25         }
26
27         /* Override control on ISOCLKIN signal to IO pad ring. */
28         clrsetbits_le32((*prcm)->prm_io_pmctrl, PMCTRL_ISOCLK_OVERRIDE_MASK,
29                         PMCTRL_ISOCLK_OVERRIDE_CTRL);
30         if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK, PMCTRL_ISOCLK_STATUS_MASK,
31                            (u32 *)(*prcm)->prm_io_pmctrl, LDELAY))
32                 return ERR_DEISOLATE_IO << isolate;
33
34         /* Isolate/Deisolate IO */
35         clrsetbits_le32((*ctrl)->ctrl_core_sma_sw_0, CTRL_ISOLATE_MASK,
36                         isolate << CTRL_ISOLATE_SHIFT);
37         /* Dummy read to add delay t > 10ns */
38         readl((*ctrl)->ctrl_core_sma_sw_0);
39
40         /* Return control on ISOCLKIN to hardware */
41         clrsetbits_le32((*prcm)->prm_io_pmctrl, PMCTRL_ISOCLK_OVERRIDE_MASK,
42                         PMCTRL_ISOCLK_NOT_OVERRIDE_CTRL);
43         if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK,
44                            0 << PMCTRL_ISOCLK_STATUS_SHIFT,
45                            (u32 *)(*prcm)->prm_io_pmctrl, LDELAY))
46                 return ERR_DEISOLATE_IO << isolate;
47
48         return 0;
49 }
50
51 static int calibrate_iodelay(u32 base)
52 {
53         u32 reg;
54
55         /* Configure REFCLK period */
56         reg = readl(base + CFG_REG_2_OFFSET);
57         reg &= ~CFG_REG_REFCLK_PERIOD_MASK;
58         reg |= CFG_REG_REFCLK_PERIOD;
59         writel(reg, base + CFG_REG_2_OFFSET);
60
61         /* Initiate Calibration */
62         clrsetbits_le32(base + CFG_REG_0_OFFSET, CFG_REG_CALIB_STRT_MASK,
63                         CFG_REG_CALIB_STRT << CFG_REG_CALIB_STRT_SHIFT);
64         if (!wait_on_value(CFG_REG_CALIB_STRT_MASK, CFG_REG_CALIB_END,
65                            (u32 *)(base + CFG_REG_0_OFFSET), LDELAY))
66                 return ERR_CALIBRATE_IODELAY;
67
68         return 0;
69 }
70
71 static int update_delay_mechanism(u32 base)
72 {
73         /* Initiate the reload of calibrated values. */
74         clrsetbits_le32(base + CFG_REG_0_OFFSET, CFG_REG_ROM_READ_MASK,
75                         CFG_REG_ROM_READ_START);
76         if (!wait_on_value(CFG_REG_ROM_READ_MASK, CFG_REG_ROM_READ_END,
77                            (u32 *)(base + CFG_REG_0_OFFSET), LDELAY))
78                 return ERR_UPDATE_DELAY;
79
80         return 0;
81 }
82
83 void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads)
84 {
85         int ret = 0;
86
87         /* IO recalibration should be done only from SRAM */
88         if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context()) {
89                 puts("IODELAY recalibration called from invalid context - use only from SPL in SRAM\n");
90                 return;
91         }
92
93         /* unlock IODELAY CONFIG registers */
94         writel(CFG_IODELAY_UNLOCK_KEY, (*ctrl)->iodelay_config_base +
95                CFG_REG_8_OFFSET);
96
97         ret = calibrate_iodelay((*ctrl)->iodelay_config_base);
98         if (ret)
99                 goto err;
100
101         ret = isolate_io(ISOLATE_IO);
102         if (ret)
103                 goto err;
104
105         ret = update_delay_mechanism((*ctrl)->iodelay_config_base);
106         if (ret)
107                 goto err;
108
109         /* Configure Mux settings */
110         do_set_mux32((*ctrl)->control_padconf_core_base, pad, npads);
111
112         ret = isolate_io(DEISOLATE_IO);
113
114 err:
115         /* lock IODELAY CONFIG registers */
116         writel(CFG_IODELAY_LOCK_KEY, (*ctrl)->iodelay_config_base +
117                CFG_REG_8_OFFSET);
118         /*
119          * UART cannot be used during IO recalibration sequence as IOs are in
120          * isolation. So error handling and debug prints are done after
121          * complete IO delay recalibration sequence
122          */
123         switch (ret) {
124         case ERR_CALIBRATE_IODELAY:
125                 puts("IODELAY: IO delay calibration sequence failed\n");
126                 break;
127         case ERR_ISOLATE_IO:
128                 puts("IODELAY: Isolation of Device IOs failed\n");
129                 break;
130         case ERR_UPDATE_DELAY:
131                 puts("IODELAY: Delay mechanism update with new calibrated values failed\n");
132                 break;
133         case ERR_DEISOLATE_IO:
134                 puts("IODELAY: De-isolation of Device IOs failed\n");
135                 break;
136         default:
137                 debug("IODELAY: IO delay recalibration successfully completed\n");
138         }
139 }