1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cpu/barrier.h>
18 #include <cpu/cpuMath.h>
19 #include <plat/rtc.h>
20 #include <plat/pwr.h>
21 #include <timer.h>
22 #include <platform.h>
23 #include <plat/exti.h>
24 #include <plat/cmsis.h>
25 #include <variant/variant.h>
26
27 #ifndef NS_PER_S
28 #define NS_PER_S UINT64_C(1000000000)
29 #endif
30
31
32 struct StmRtc
33 {
34 volatile uint32_t TR; /* 0x00 */
35 volatile uint32_t DR; /* 0x04 */
36 volatile uint32_t CR; /* 0x08 */
37 volatile uint32_t ISR; /* 0x0C */
38 volatile uint32_t PRER; /* 0x10 */
39 volatile uint32_t WUTR; /* 0x14 */
40 volatile uint32_t CALIBR; /* 0x18 */
41 volatile uint32_t ALRMAR; /* 0x1C */
42 volatile uint32_t ALRMBR; /* 0x20 */
43 volatile uint32_t WPR; /* 0x24 */
44 volatile uint32_t SSR; /* 0x28 */
45 volatile uint32_t SHIFTR; /* 0x2C */
46 volatile uint32_t TSTR; /* 0x30 */
47 volatile uint32_t TSDR; /* 0x34 */
48 volatile uint32_t TSSSR; /* 0x38 */
49 volatile uint32_t CALR; /* 0x3C */
50 volatile uint32_t TAFCR; /* 0x40 */
51 volatile uint32_t ALRMASSR; /* 0x44 */
52 volatile uint32_t ALRMBSSR; /* 0x48 */
53 uint8_t unused0[4]; /* 0x4C */
54 volatile uint32_t BKPR[20]; /* 0x50 - 0x9C */
55 };
56
57 #define RTC ((struct StmRtc*)RTC_BASE)
58
59 /* RTC bit defintions */
60 #define RTC_CR_WUCKSEL_MASK 0x00000007UL
61 #define RTC_CR_WUCKSEL_16DIV 0x00000000UL
62 #define RTC_CR_WUCKSEL_8DIV 0x00000001UL
63 #define RTC_CR_WUCKSEL_4DIV 0x00000002UL
64 #define RTC_CR_WUCKSEL_2DIV 0x00000003UL
65 #define RTC_CR_WUCKSEL_CK_SPRE 0x00000004UL
66 #define RTC_CR_WUCKSEL_CK_SPRE_2 0x00000006UL
67 #define RTC_CR_BYPSHAD 0x00000020UL
68 #define RTC_CR_FMT 0x00000040UL
69 #define RTC_CR_ALRAE 0x00000100UL
70 #define RTC_CR_WUTE 0x00000400UL
71 #define RTC_CR_ALRAIE 0x00001000UL
72 #define RTC_CR_WUTIE 0x00004000UL
73
74 #define RTC_ISR_ALRAWF 0x00000001UL
75 #define RTC_ISR_WUTWF 0x00000004UL
76 #define RTC_ISR_RSF 0x00000020UL
77 #define RTC_ISR_INITF 0x00000040UL
78 #define RTC_ISR_INIT 0x00000080UL
79 #define RTC_ISR_WUTF 0x00000400UL
80
81 /* RTC internal values */
82 #define RTC_FREQ_HZ 32768UL
83 #define RTC_WKUP_DOWNCOUNT_MAX 0x10000UL
84
85 /* TODO: Reset to crystal PPM once known */
86 #define RTC_PPM 50UL
87
88 /* Default prescalars of P[async] = 127 and P[sync] = 255 are appropriate
89 * produce a 1 Hz clock when using a 32.768kHZ clock source */
90 #ifndef RTC_PREDIV_A
91 #define RTC_PREDIV_A 31UL
92 #endif
93 #ifndef RTC_PREDIV_S
94 #define RTC_PREDIV_S 1023UL
95 #endif
96 #ifndef RTC_CALM
97 #define RTC_CALM 0
98 #endif
99 #ifndef RTC_CALP
100 #define RTC_CALP 0
101 #endif
102
103 /* Jitter = max wakeup timer resolution (61.035 us)
104 * + 2 RTC cycles for synchronization (61.035 us) */
105 #define RTC_DIV2_PERIOD_NS UINT64_C(61035)
106 #define RTC_DIV4_PERIOD_NS UINT64_C(122070)
107 #define RTC_DIV8_PERIOD_NS UINT64_C(244141)
108 #define RTC_DIV16_PERIOD_NS UINT64_C(488281)
109
110 #define RTC_VALID_DELAY_FOR_PERIOD(delay, period) \
111 (delay < (period * (RTC_WKUP_DOWNCOUNT_MAX + 1)))
112
rtcSetDefaultDateTimeAndPrescalar(void)113 static void rtcSetDefaultDateTimeAndPrescalar(void)
114 {
115 /* Enable writability of RTC registers */
116 RTC->WPR = 0xCA;
117 RTC->WPR = 0x53;
118
119 /* Enter RTC init mode */
120 RTC->ISR |= RTC_ISR_INIT;
121
122 mem_reorder_barrier();
123 /* Wait for initialization mode to be entered. */
124 while ((RTC->ISR & RTC_ISR_INITF) == 0);
125
126 /* Set prescalar rtc register. Two writes required. */
127 RTC->PRER = RTC_PREDIV_S;
128 RTC->PRER |= (RTC_PREDIV_A << 16);
129 RTC->CALR = (RTC_CALP << 15) | (RTC_CALM & 0x1FF);
130
131 /* 24 hour format */
132 RTC->CR &= ~RTC_CR_FMT;
133
134 /* disable shadow registers */
135 RTC->CR |= RTC_CR_BYPSHAD;
136
137 /* Set time and date registers to defaults */
138 /* Midnight */
139 RTC->TR = 0x0;
140 RTC->SSR = 0x0;
141 /* Sat Jan 1st, 2000 BCD */
142 RTC->DR = 0b1100000100000001;
143
144 /* Exit init mode for RTC */
145 RTC->ISR &= ~RTC_ISR_INIT;
146
147 /* Re-enable register write protection. RTC counting doesn't start for
148 * 4 RTC cycles after set - must poll RSF before read DR or TR */
149 RTC->WPR = 0xFF;
150
151 extiEnableIntLine(EXTI_LINE_RTC_WKUP, EXTI_TRIGGER_RISING);
152 NVIC_EnableIRQ(RTC_WKUP_IRQn);
153 }
154
rtcInit(void)155 void rtcInit(void)
156 {
157 pwrEnableAndClockRtc(RTC_CLK);
158 rtcSetDefaultDateTimeAndPrescalar();
159 }
160
161 /* Set calendar alarm to go off after delay has expired. uint64_t delay must
162 * be in valid uint64_t format */
rtcSetWakeupTimer(uint64_t delay)163 int rtcSetWakeupTimer(uint64_t delay)
164 {
165 uint64_t intState;
166 uint64_t periodNsRecip;
167 uint32_t wakeupClock;
168 uint32_t periodNs;
169
170 /* Minimum wakeup interrupt period is 122 us, max is 36.4 hours */
171 if (delay < (RTC_DIV2_PERIOD_NS * 2)) {
172 return RTC_ERR_TOO_SMALL;
173 } else if (delay > (NS_PER_S * 2 * RTC_WKUP_DOWNCOUNT_MAX)) {
174 delay = NS_PER_S * 2 * RTC_WKUP_DOWNCOUNT_MAX;
175 }
176
177 /* Get appropriate clock period for delay size. Wakeup clock = RTC/x. */
178 if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV2_PERIOD_NS)) {
179
180 wakeupClock = RTC_CR_WUCKSEL_2DIV;
181 periodNs = RTC_DIV2_PERIOD_NS;
182 periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV2_PERIOD_NS);
183 }
184 else if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV4_PERIOD_NS)) {
185
186 wakeupClock = RTC_CR_WUCKSEL_4DIV;
187 periodNs = RTC_DIV4_PERIOD_NS;
188 periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV4_PERIOD_NS);
189 }
190 else if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV8_PERIOD_NS)) {
191
192 wakeupClock = RTC_CR_WUCKSEL_8DIV;
193 periodNs = RTC_DIV8_PERIOD_NS;
194 periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV8_PERIOD_NS);
195 }
196 else if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV16_PERIOD_NS)) {
197
198 wakeupClock = RTC_CR_WUCKSEL_16DIV;
199 periodNs = RTC_DIV16_PERIOD_NS;
200 periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV16_PERIOD_NS);
201 }
202 else {
203
204 if (RTC_VALID_DELAY_FOR_PERIOD(delay, NS_PER_S))
205 wakeupClock = RTC_CR_WUCKSEL_CK_SPRE;
206 else
207 wakeupClock = RTC_CR_WUCKSEL_CK_SPRE_2;
208 periodNs = NS_PER_S;
209 periodNsRecip = U64_RECIPROCAL_CALCULATE(NS_PER_S);
210 }
211
212 intState = cpuIntsOff();
213
214 /* Enable RTC register write */
215 RTC->WPR = 0xCA;
216 RTC->WPR = 0x53;
217
218 /* Disable wakeup timer */
219 RTC->CR &= ~RTC_CR_WUTE;
220
221 /* Wait for access enabled for wakeup timer registers */
222 while ((RTC->ISR & RTC_ISR_WUTWF) == 0);
223
224 /* Clear wakeup clock source */
225 RTC->CR &= ~RTC_CR_WUCKSEL_MASK;
226
227 RTC->CR |= wakeupClock;
228 /* Downcounter value for wakeup clock. Wakeup flag is set every
229 * RTC->WUTR[15:0] + 1 cycles of the WUT clock. */
230 RTC->WUTR = cpuMathRecipAssistedUdiv64by32(delay, periodNs, periodNsRecip) - 1;
231
232 /* Enable wakeup interrupts */
233 RTC->CR |= RTC_CR_WUTIE;
234 extiClearPendingLine(EXTI_LINE_RTC_WKUP);
235
236 /* Enable wakeup timer */
237 RTC->CR |= RTC_CR_WUTE;
238
239 /* Clear overflow flag */
240 RTC->ISR &= ~RTC_ISR_WUTF;
241
242 /* Write-protect RTC registers */
243 RTC->WPR = 0xFF;
244
245 cpuIntsRestore(intState);
246
247 return 0;
248 }
249
rtcGetTime(void)250 uint64_t rtcGetTime(void)
251 {
252 int32_t time_s;
253 uint32_t dr, tr, ssr;
254 // cumulative adjustments from 32 day months (year 2000)
255 // 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
256 // 1, 3, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1
257 // 0 1, 4, 5, 7, 8, 10, 11, 12, 14, 15, 17
258 static const uint8_t adjust[] = { 0, 1, 4, 5, 7, 8, 10, 11, 12, 14, 15, 17 };
259 uint8_t month;
260
261 // need to loop incase an interrupt occurs in the middle or ssr
262 // decrements (which can propagate changes to tr and dr)
263 do {
264 ssr = RTC->SSR;
265 tr = RTC->TR;
266 dr = RTC->DR;
267 } while (ssr != RTC->SSR);
268
269 month = (((dr >> 12) & 0x1) * 10) + ((dr >> 8) & 0xf) - 1;
270 time_s = (((((dr >> 4) & 0x3) * 10) + (dr & 0xF) - 1) + (month << 5) - adjust[month]) * 86400ULL;
271 time_s += ((((tr >> 22) & 0x1) * 43200ULL) +
272 (((tr >> 20) & 0x3) * 36000ULL) +
273 (((tr >> 16) & 0xF) * 3600ULL) +
274 (((tr >> 12) & 0x7) * 600ULL) +
275 (((tr >> 8) & 0xF) * 60ULL) +
276 (((tr >> 4) & 0x7) * 10ULL) +
277 (((tr) & 0xF)));
278
279 return (time_s * NS_PER_S) + U64_DIV_BY_CONST_U16(((RTC_PREDIV_S - ssr) * NS_PER_S), (RTC_PREDIV_S + 1));
280 }
281
282 void EXTI22_RTC_WKUP_IRQHandler(void);
EXTI22_RTC_WKUP_IRQHandler(void)283 void EXTI22_RTC_WKUP_IRQHandler(void)
284 {
285 extiClearPendingLine(EXTI_LINE_RTC_WKUP);
286 timIntHandler();
287 }
288
rtcGetBackupStorage(void)289 uint32_t* rtcGetBackupStorage(void)
290 {
291 return (uint32_t*)RTC->BKPR;
292 }
293