]> git.sur5r.net Git - u-boot/blob - drivers/rtc/imxdi.c
dm: core: Update of_read_fmap_entry() for livetree
[u-boot] / drivers / rtc / imxdi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2009-2012 ADVANSEE
4  * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
5  *
6  * Based on the Linux rtc-imxdi.c driver, which is:
7  * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
8  * Copyright 2010 Orex Computed Radiography
9  */
10
11 /*
12  * Date & Time support for Freescale i.MX DryIce RTC
13  */
14
15 #include <common.h>
16 #include <command.h>
17 #include <linux/compat.h>
18 #include <rtc.h>
19
20 #if defined(CONFIG_CMD_DATE)
21
22 #include <asm/io.h>
23 #include <asm/arch/imx-regs.h>
24
25 /* DryIce Register Definitions */
26
27 struct imxdi_regs {
28         u32 dtcmr;                      /* Time Counter MSB Reg */
29         u32 dtclr;                      /* Time Counter LSB Reg */
30         u32 dcamr;                      /* Clock Alarm MSB Reg */
31         u32 dcalr;                      /* Clock Alarm LSB Reg */
32         u32 dcr;                        /* Control Reg */
33         u32 dsr;                        /* Status Reg */
34         u32 dier;                       /* Interrupt Enable Reg */
35 };
36
37 #define DCAMR_UNSET     0xFFFFFFFF      /* doomsday - 1 sec */
38
39 #define DCR_TCE         (1 << 3)        /* Time Counter Enable */
40
41 #define DSR_WBF         (1 << 10)       /* Write Busy Flag */
42 #define DSR_WNF         (1 << 9)        /* Write Next Flag */
43 #define DSR_WCF         (1 << 8)        /* Write Complete Flag */
44 #define DSR_WEF         (1 << 7)        /* Write Error Flag */
45 #define DSR_CAF         (1 << 4)        /* Clock Alarm Flag */
46 #define DSR_NVF         (1 << 1)        /* Non-Valid Flag */
47 #define DSR_SVF         (1 << 0)        /* Security Violation Flag */
48
49 #define DIER_WNIE       (1 << 9)        /* Write Next Interrupt Enable */
50 #define DIER_WCIE       (1 << 8)        /* Write Complete Interrupt Enable */
51 #define DIER_WEIE       (1 << 7)        /* Write Error Interrupt Enable */
52 #define DIER_CAIE       (1 << 4)        /* Clock Alarm Interrupt Enable */
53
54 /* Driver Private Data */
55
56 struct imxdi_data {
57         struct imxdi_regs __iomem       *regs;
58         int                             init_done;
59 };
60
61 static struct imxdi_data data;
62
63 /*
64  * This function attempts to clear the dryice write-error flag.
65  *
66  * A dryice write error is similar to a bus fault and should not occur in
67  * normal operation.  Clearing the flag requires another write, so the root
68  * cause of the problem may need to be fixed before the flag can be cleared.
69  */
70 static void clear_write_error(void)
71 {
72         int cnt;
73
74         puts("### Warning: RTC - Register write error!\n");
75
76         /* clear the write error flag */
77         __raw_writel(DSR_WEF, &data.regs->dsr);
78
79         /* wait for it to take effect */
80         for (cnt = 0; cnt < 1000; cnt++) {
81                 if ((__raw_readl(&data.regs->dsr) & DSR_WEF) == 0)
82                         return;
83                 udelay(10);
84         }
85         puts("### Error: RTC - Cannot clear write-error flag!\n");
86 }
87
88 /*
89  * Write a dryice register and wait until it completes.
90  *
91  * Use interrupt flags to determine when the write has completed.
92  */
93 #define DI_WRITE_WAIT(val, reg)                                         \
94 (                                                                       \
95         /* do the register write */                                     \
96         __raw_writel((val), &data.regs->reg),                           \
97                                                                         \
98         di_write_wait((val), #reg)                                      \
99 )
100 static int di_write_wait(u32 val, const char *reg)
101 {
102         int cnt;
103         int ret = 0;
104         int rc = 0;
105
106         /* wait for the write to finish */
107         for (cnt = 0; cnt < 100; cnt++) {
108                 if ((__raw_readl(&data.regs->dsr) & (DSR_WCF | DSR_WEF)) != 0) {
109                         ret = 1;
110                         break;
111                 }
112                 udelay(10);
113         }
114         if (ret == 0)
115                 printf("### Warning: RTC - Write-wait timeout "
116                                 "val = 0x%.8x reg = %s\n", val, reg);
117
118         /* check for write error */
119         if (__raw_readl(&data.regs->dsr) & DSR_WEF) {
120                 clear_write_error();
121                 rc = -1;
122         }
123
124         return rc;
125 }
126
127 /*
128  * Initialize dryice hardware
129  */
130 static int di_init(void)
131 {
132         int rc = 0;
133
134         data.regs = (struct imxdi_regs __iomem *)IMX_DRYICE_BASE;
135
136         /* mask all interrupts */
137         __raw_writel(0, &data.regs->dier);
138
139         /* put dryice into valid state */
140         if (__raw_readl(&data.regs->dsr) & DSR_NVF) {
141                 rc = DI_WRITE_WAIT(DSR_NVF | DSR_SVF, dsr);
142                 if (rc)
143                         goto err;
144         }
145
146         /* initialize alarm */
147         rc = DI_WRITE_WAIT(DCAMR_UNSET, dcamr);
148         if (rc)
149                 goto err;
150         rc = DI_WRITE_WAIT(0, dcalr);
151         if (rc)
152                 goto err;
153
154         /* clear alarm flag */
155         if (__raw_readl(&data.regs->dsr) & DSR_CAF) {
156                 rc = DI_WRITE_WAIT(DSR_CAF, dsr);
157                 if (rc)
158                         goto err;
159         }
160
161         /* the timer won't count if it has never been written to */
162         if (__raw_readl(&data.regs->dtcmr) == 0) {
163                 rc = DI_WRITE_WAIT(0, dtcmr);
164                 if (rc)
165                         goto err;
166         }
167
168         /* start keeping time */
169         if (!(__raw_readl(&data.regs->dcr) & DCR_TCE)) {
170                 rc = DI_WRITE_WAIT(__raw_readl(&data.regs->dcr) | DCR_TCE, dcr);
171                 if (rc)
172                         goto err;
173         }
174
175         data.init_done = 1;
176         return 0;
177
178 err:
179         return rc;
180 }
181
182 int rtc_get(struct rtc_time *tmp)
183 {
184         unsigned long now;
185         int rc = 0;
186
187         if (!data.init_done) {
188                 rc = di_init();
189                 if (rc)
190                         goto err;
191         }
192
193         now = __raw_readl(&data.regs->dtcmr);
194         rtc_to_tm(now, tmp);
195
196 err:
197         return rc;
198 }
199
200 int rtc_set(struct rtc_time *tmp)
201 {
202         unsigned long now;
203         int rc;
204
205         if (!data.init_done) {
206                 rc = di_init();
207                 if (rc)
208                         goto err;
209         }
210
211         now = rtc_mktime(tmp);
212         /* zero the fractional part first */
213         rc = DI_WRITE_WAIT(0, dtclr);
214         if (rc == 0)
215                 rc = DI_WRITE_WAIT(now, dtcmr);
216
217 err:
218         return rc;
219 }
220
221 void rtc_reset(void)
222 {
223         di_init();
224 }
225
226 #endif