]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_R5_UltraScale_MPSoC/RTOSDemo_R5_bsp/psu_cortexr5_0/libsrc/rtcpsu_v1_3/src/xrtcpsu.c
Update BSP source files for UltraScale Cortex-A53 and Cortex-R5 and Microblaze to...
[freertos] / FreeRTOS / Demo / CORTEX_R5_UltraScale_MPSoC / RTOSDemo_R5_bsp / psu_cortexr5_0 / libsrc / rtcpsu_v1_3 / src / xrtcpsu.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2015 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xrtcpsu.c
36 * @addtogroup rtcpsu_v1_0
37 * @{
38 *
39 * Functions in this file are the minimum required functions for the XRtcPsu
40 * driver. See xrtcpsu.h for a detailed description of the driver.
41 *
42 * @note         None.
43 *
44 *
45 * <pre>
46 * MODIFICATION HISTORY:
47 *
48 * Ver   Who    Date     Changes
49 * ----- -----  -------- -----------------------------------------------
50 * 1.00  kvn    04/21/15 First release
51 * 1.1   kvn    09/25/15 Modify control register to enable battery
52 *                       switching when vcc_psaux is not available.
53 * 1.2          02/15/16 Corrected Calibration mask and Fractional
54 *                       mask in CalculateCalibration API.
55 * 1.3   vak    04/25/16 Corrected the RTC read and write time logic(cr#948833).
56 * </pre>
57 *
58 ******************************************************************************/
59
60 /***************************** Include Files *********************************/
61
62 #include "xrtcpsu.h"
63 #include "xrtcpsu_hw.h"
64
65 /************************** Constant Definitions *****************************/
66
67 /**************************** Type Definitions *******************************/
68
69 /***************** Macros (Inline Functions) Definitions *********************/
70
71 /************************** Variable Definitions *****************************/
72
73 static const u32 DaysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
74
75 /************************** Function Prototypes ******************************/
76
77 static void XRtcPsu_StubHandler(void *CallBackRef, u32 Event);
78
79 /*****************************************************************************/
80 /*
81 *
82 * This function initializes a XRtcPsu instance/driver.
83 *
84 * The initialization entails:
85 * - Initialize all members of the XRtcPsu structure.
86 *
87 * @param        InstancePtr is a pointer to the XRtcPsu instance.
88 * @param        ConfigPtr points to the XRtcPsu device configuration structure.
89 * @param        EffectiveAddr is the device base address in the virtual memory
90 *               address space. If the address translation is not used then the
91 *               physical address is passed.
92 *               Unexpected errors may occur if the address mapping is changed
93 *               after this function is invoked.
94 *
95 * @return       XST_SUCCESS always.
96 *
97 * @note         None.
98 *
99 ******************************************************************************/
100 s32 XRtcPsu_CfgInitialize(XRtcPsu *InstancePtr, XRtcPsu_Config *ConfigPtr,
101                                 u32 EffectiveAddr)
102 {
103         s32 Status;
104         u32 ControlRegister;
105         Xil_AssertNonvoid(InstancePtr != NULL);
106         Xil_AssertNonvoid(ConfigPtr != NULL);
107
108         /*
109          * Set some default values for instance data, don't indicate the device
110          * is ready to use until everything has been initialized successfully.
111          */
112         InstancePtr->IsReady = 0U;
113         InstancePtr->RtcConfig.BaseAddr = EffectiveAddr;
114         InstancePtr->RtcConfig.DeviceId = ConfigPtr->DeviceId;
115
116         if(InstancePtr->OscillatorFreq == 0U) {
117                 InstancePtr->CalibrationValue = XRTC_CALIBRATION_VALUE;
118                 InstancePtr->OscillatorFreq = XRTC_TYPICAL_OSC_FREQ;
119         }
120
121         /* Set all handlers to stub values, let user configure this data later. */
122         InstancePtr->Handler = XRtcPsu_StubHandler;
123
124         InstancePtr->IsPeriodicAlarm = 0U;
125
126         /* Set the calibration value in calibration register. */
127         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CALIB_WR_OFFSET,
128                                 InstancePtr->CalibrationValue);
129
130         /* Set the Oscillator crystal and Battery switch enable in control register. */
131         ControlRegister = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CTL_OFFSET);
132         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CTL_OFFSET,
133                         (ControlRegister | (u32)XRTCPSU_CRYSTAL_OSC_EN | (u32)XRTC_CTL_BATTERY_EN_MASK));
134
135         /* Clear the Interrupt Status and Disable the interrupts. */
136         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET,
137                         ((u32)XRTC_INT_STS_ALRM_MASK | (u32)XRTC_INT_STS_SECS_MASK));
138         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_DIS_OFFSET,
139                         ((u32)XRTC_INT_DIS_ALRM_MASK | (u32)XRTC_INT_DIS_SECS_MASK));
140
141         /* Indicate the component is now ready to use. */
142         InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
143
144         /* Clear TimeUpdated and CurrTimeUpdated */
145         InstancePtr->TimeUpdated = 0;
146         InstancePtr->CurrTimeUpdated = 0;
147
148         Status = XST_SUCCESS;
149         return Status;
150 }
151
152 /****************************************************************************/
153 /**
154 *
155 * This function is a stub handler that is the default handler such that if the
156 * application has not set the handler when interrupts are enabled, this
157 * function will be called.
158 *
159 * @param        CallBackRef is unused by this function.
160 * @param        Event is unused by this function.
161 *
162 * @return       None.
163 *
164 * @note         None.
165 *
166 *****************************************************************************/
167 static void XRtcPsu_StubHandler(void *CallBackRef, u32 Event)
168 {
169         (void *) CallBackRef;
170         (void) Event;
171         /* Assert occurs always since this is a stub and should never be called */
172         Xil_AssertVoidAlways();
173 }
174
175 /****************************************************************************/
176 /**
177 *
178 * This function sets the RTC time by writing into rtc write register.
179 *
180 * @param        InstancePtr is a pointer to the XRtcPsu instance.
181 * @param        Time that should be updated into RTC write register.
182 *
183 * @return       None.
184 *
185 * @note         None.
186 *
187 *****************************************************************************/
188 void XRtcPsu_SetTime(XRtcPsu *InstancePtr,u32 Time)
189 {
190         /* Set the calibration value in calibration register, so that
191          * next Second is triggered exactly at 1 sec period
192          */
193         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CALIB_WR_OFFSET,
194                                                         InstancePtr->CalibrationValue);
195         /* clear the RTC secs interrupt from status register */
196         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET,
197                                                                 XRTC_INT_STS_SECS_MASK);
198         InstancePtr->CurrTimeUpdated = 0;
199         /* Update the flag before setting the time */
200         InstancePtr->TimeUpdated = 1;
201         /* Since RTC takes 1 sec to update the time into current time register, write
202          * load time + 1sec into the set time register.
203          */
204         XRtcPsu_WriteSetTime(InstancePtr, Time + 1);
205 }
206
207 /****************************************************************************/
208 /**
209 *
210 * This function gets the current RTC time.
211 *
212 * @param        InstancePtr is a pointer to the XRtcPsu instance.
213 *
214 * @return       RTC Current time.
215 *
216 * @note         None.
217 *
218 *****************************************************************************/
219 u32 XRtcPsu_GetCurrentTime(XRtcPsu *InstancePtr)
220 {
221         u32 Status, IntMask, CurrTime;
222
223         IntMask = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_MSK_OFFSET);
224
225         if((IntMask & XRTC_INT_STS_SECS_MASK) != (u32)0) {
226                 /* We come here if interrupts are disabled */
227                 Status = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET);
228                 if((InstancePtr->TimeUpdated == (u32)1) &&
229                         (Status & XRTC_INT_STS_SECS_MASK) == (u32)0) {
230                         /* Give the previous written time */
231                         CurrTime = XRtcPsu_GetLastSetTime(InstancePtr) - 1;
232                 } else {
233                         /* Clear TimeUpdated */
234                         if((InstancePtr->TimeUpdated == (u32)1) &&
235                                 ((Status & XRTC_INT_STS_SECS_MASK) == (u32)1)) {
236                                 InstancePtr->TimeUpdated = (u32)0;
237                         }
238
239                         /* RTC time got updated */
240                         CurrTime = XRtcPsu_ReadCurrentTime(InstancePtr);
241                 }
242         } else {
243                 /* We come here if interrupts are enabled */
244                 if((InstancePtr->TimeUpdated == (u32)1) &&
245                         (InstancePtr->CurrTimeUpdated == (u32)0)) {
246                         /* Give the previous written time -1 sec */
247                         CurrTime = XRtcPsu_GetLastSetTime(InstancePtr) - 1;
248                 } else {
249                         /* Clear TimeUpdated */
250                         if(InstancePtr->TimeUpdated == (u32)1)
251                                 InstancePtr->TimeUpdated = (u32)0;
252                         /* RTC time got updated */
253                         CurrTime = XRtcPsu_ReadCurrentTime(InstancePtr);
254                 }
255         }
256         return CurrTime;
257 }
258
259 /****************************************************************************/
260 /**
261 *
262 * This function sets the alarm value of RTC device.
263 *
264 * @param        InstancePtr is a pointer to the XRtcPsu instance
265 * @param        Alarm is the desired alarm time for RTC.
266 * @param        Periodic says whether the alarm need to set at periodic
267 *                       Intervals or a one-time alarm.
268 *
269 * @return       None.
270 *
271 * @note         None.
272 *
273 *****************************************************************************/
274 void XRtcPsu_SetAlarm(XRtcPsu *InstancePtr, u32 Alarm, u32 Periodic)
275 {
276         Xil_AssertVoid(InstancePtr != NULL);
277         Xil_AssertVoid(Alarm != 0U);
278         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
279         Xil_AssertVoid((Alarm - XRtcPsu_GetCurrentTime(InstancePtr)) > (u32)0);
280
281         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr+XRTC_ALRM_OFFSET, Alarm);
282         if(Periodic != 0U) {
283                 InstancePtr->IsPeriodicAlarm = 1U;
284                 InstancePtr->PeriodicAlarmTime =
285                                 Alarm - XRtcPsu_GetCurrentTime(InstancePtr);
286         }
287 }
288
289
290 /****************************************************************************/
291 /**
292 *
293 * This function translates time in seconds to a YEAR:MON:DAY HR:MIN:SEC
294 * format and saves it in the DT structure variable. It also reports the weekday.
295 *
296 * @param        Seconds is the time value that has to be shown in DateTime
297 *                       format.
298 * @param        dt is the DateTime format variable that stores the translated
299 *                       time.
300 *
301 * @return       None.
302 *
303 * @note         This API supports this century i.e., 2000 - 2099 years only.
304 *
305 *****************************************************************************/
306 void XRtcPsu_SecToDateTime(u32 Seconds, XRtcPsu_DT *dt)
307 {
308         u32 CurrentTime, TempDays, Leap, DaysPerMonth;
309
310         CurrentTime = Seconds;
311         dt->Sec = CurrentTime % 60U;
312         CurrentTime /= 60U;
313         dt->Min = CurrentTime % 60U;
314         CurrentTime /= 60U;
315         dt->Hour = CurrentTime % 24U;
316         TempDays = CurrentTime / 24U;
317
318         if (TempDays == 0U) {
319                 TempDays = 1U;
320         }
321         dt->WeekDay = TempDays % 7U;
322
323         for (dt->Year = 0U; dt->Year <= 99U; ++(dt->Year)) {
324                 if ((dt->Year % 4U) == 0U ) {
325                         Leap = 1U;
326                 }
327                 else {
328                         Leap = 0U;
329                 }
330                 if (TempDays < (365U + Leap)) {
331                         break;
332                 }
333                 TempDays -= (365U + Leap);
334         }
335
336         for (dt->Month = 1U; dt->Month >= 1U; ++(dt->Month)) {
337                 DaysPerMonth = DaysInMonth[dt->Month - 1];
338                 if ((Leap == 1U) && (dt->Month == 2U)) {
339                         DaysPerMonth++;
340                 }
341                 if (TempDays < DaysPerMonth) {
342                         break;
343                 }
344                 TempDays -= DaysPerMonth;
345         }
346
347         dt->Day = TempDays;
348         dt->Year += 2000U;
349 }
350
351 /****************************************************************************/
352 /**
353 *
354 * This function translates time in YEAR:MON:DAY HR:MIN:SEC format to
355 * seconds.
356 *
357 * @param        dt is a pointer to a DatetTime format structure variable
358 *                       of time that has to be shown in seconds.
359 *
360 * @return       Seconds value of provided in dt time.
361 *
362 * @note         None.
363 *
364 *****************************************************************************/
365 u32 XRtcPsu_DateTimeToSec(XRtcPsu_DT *dt)
366 {
367         u32 i, Days;
368         u32 Seconds;
369         Xil_AssertNonvoid(dt != NULL);
370
371         if (dt->Year >= 2000U) {
372                 dt->Year -= 2000U;
373         }
374
375         for (i = 1U; i < dt->Month; i++) {
376                 dt->Day += (u32)DaysInMonth[i-1];
377         }
378
379         if ((dt->Month > 2U) && ((dt->Year % 4U) == 0U)) {
380                 dt->Day++;
381         }
382         Days = dt->Day + (365U * dt->Year) + ((dt->Year + 3U) / 4U);
383         Seconds = (((((Days * 24U) + dt->Hour) * 60U) + dt->Min) * 60U) + dt->Sec;
384         return Seconds;
385 }
386
387 /****************************************************************************/
388 /**
389 *
390 * This function calculates the calibration value depending on the actual
391 * realworld time and also helps in deriving new calibration value if
392 * the user wishes to change his oscillator frequency.TimeReal is generally the
393 * internet time with EPOCH time as reference i.e.,1/1/1970 1st second.
394 * But this RTC driver assumes start time from 1/1/2000 1st second. Hence,if
395 * the user maps the internet time InternetTimeInSecs, then he has to use
396 *       XRtcPsu_SecToDateTime(InternetTimeInSecs,&InternetTime),
397 *       TimeReal = XRtcPsu_DateTimeToSec(InternetTime)
398 *       consecutively to arrive at TimeReal value.
399 *
400 * @param        InstancePtr is a pointer to the XRtcPsu instance.
401 * @param        TimeReal is the actual realworld time generally an
402 *               network time / Internet time in seconds.
403 *
404 * @param        CrystalOscFreq is the Oscillator new frequency. Say, If the user
405 *               is going with the typical 32768Hz, then he inputs the same
406 *               frequency value.
407 *
408 * @return       None.
409 *
410 * @note         After Calculating the calibration register, user / application has to
411 *                       call again CfgInitialize API to bring the new calibration into effect.
412 *
413 *****************************************************************************/
414 void XRtcPsu_CalculateCalibration(XRtcPsu *InstancePtr,u32 TimeReal,
415                 u32 CrystalOscFreq)
416 {
417         u32 ReadTime, SetTime;
418         u32 Cprev,Fprev,Cnew,Fnew,Xf,Calibration;
419         Xil_AssertVoid(TimeReal != 0U);
420         Xil_AssertVoid(CrystalOscFreq != 0U);
421
422         ReadTime = XRtcPsu_GetCurrentTime(InstancePtr);
423         SetTime = XRtcPsu_GetLastSetTime(InstancePtr);
424         Calibration = XRtcPsu_GetCalibration(InstancePtr);
425         /*
426          * When board gets reseted, Calibration value is zero
427          * and Last setTime will be marked as 1st  second. This implies
428          * CurrentTime to be in few seconds say something in tens. TimeReal will
429          * be huge, say something in thousands. So to prevent such reset case, Cnew
430          * and Fnew will not be calculated.
431          */
432         if((Calibration == 0U) || (CrystalOscFreq != InstancePtr->OscillatorFreq)) {
433                 Cnew = CrystalOscFreq - (u32)1;
434                 Fnew = 0U;
435         } else {
436                 Cprev = Calibration & XRTC_CALIB_RD_MAX_TCK_MASK;
437                 Fprev = Calibration & XRTC_CALIB_RD_FRACTN_DATA_MASK;
438
439                 Xf = ((ReadTime - SetTime) * ((Cprev+1U) + ((Fprev+1U)/16U))) / (TimeReal - SetTime);
440                 Cnew = (u32)(Xf) - (u32)1;
441                 Fnew = XRtcPsu_RoundOff((Xf - Cnew) * 16U) - (u32)1;
442         }
443
444         Calibration = (Fnew << XRTC_CALIB_RD_FRACTN_DATA_SHIFT) + Cnew;
445         Calibration |= XRTC_CALIB_RD_FRACTN_EN_MASK;
446
447         InstancePtr->CalibrationValue = Calibration;
448         InstancePtr->OscillatorFreq = CrystalOscFreq;
449 }
450
451 /****************************************************************************/
452 /**
453 *
454 * This function returns the seconds event status by reading
455 * interrupt status register.
456 *
457 * @param        InstancePtr is a pointer to the XRtcPsu instance.
458 *
459 * @return       Returns 1 if a new second event is generated.Else 0..
460 *
461 * @note         This API is used in polled mode operation of RTC.
462 *                       This also clears interrupt status seconds bit.
463 *
464 *****************************************************************************/
465 u32 XRtcPsu_IsSecondsEventGenerated(XRtcPsu *InstancePtr)
466 {
467         u32 Status;
468
469         /* Loop the interrupt status register for Seconds Event */
470         if ((XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr +
471                         XRTC_INT_STS_OFFSET) & (XRTC_INT_STS_SECS_MASK)) == 0U) {
472                 Status = 0U;
473         } else {
474                 /* Clear the interrupt status register */
475                 XRtcPsu_WriteReg((InstancePtr)->RtcConfig.BaseAddr +
476                                 XRTC_INT_STS_OFFSET, XRTC_INT_STS_SECS_MASK);
477                 Status = 1U;
478         }
479         return Status;
480 }
481
482 /****************************************************************************/
483 /**
484 *
485 * This function returns the alarm event status by reading
486 * interrupt status register.
487 *
488 * @param        InstancePtr is a pointer to the XRtcPsu instance.
489 *
490 * @return       Returns 1 if the alarm event is generated.Else 0.
491 *
492 * @note         This API is used in polled mode operation of RTC.
493 *                       This also clears interrupt status alarm bit.
494 *
495 *****************************************************************************/
496 u32 XRtcPsu_IsAlarmEventGenerated(XRtcPsu *InstancePtr)
497 {
498         u32 Status;
499
500         /* Loop the interrupt status register for Alarm Event */
501         if ((XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr +
502                         XRTC_INT_STS_OFFSET) & (XRTC_INT_STS_ALRM_MASK)) == 0U) {
503                 Status = 0U;
504         } else {
505                 /* Clear the interrupt status register */
506                 XRtcPsu_WriteReg((InstancePtr)->RtcConfig.BaseAddr +
507                                 XRTC_INT_STS_OFFSET, XRTC_INT_STS_ALRM_MASK);
508                 Status = 1U;
509         }
510         return Status;
511 }
512 /** @} */