Merge branch '2020-05-18-reduce-size-of-common.h'
[oweals/u-boot.git] / post / drivers / rtc.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2002
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 #include <common.h>
8
9 /*
10  * RTC test
11  *
12  * The Real Time Clock (RTC) operation is verified by this test.
13  * The following features are verified:
14  *   o) RTC Power Fault
15  *      This is verified by analyzing the rtc_get() return status.
16  *   o) Time uniformity
17  *      This is verified by reading RTC in polling within
18  *      a short period of time.
19  *   o) Passing month boundaries
20  *      This is checked by setting RTC to a second before
21  *      a month boundary and reading it after its passing the
22  *      boundary. The test is performed for both leap- and
23  *      nonleap-years.
24  */
25
26 #include <post.h>
27 #include <rtc.h>
28
29 #if CONFIG_POST & CONFIG_SYS_POST_RTC
30
31 static int rtc_post_skip (ulong * diff)
32 {
33         struct rtc_time tm1;
34         struct rtc_time tm2;
35         ulong start1;
36         ulong start2;
37
38         rtc_get (&tm1);
39         start1 = get_timer (0);
40
41         while (1) {
42                 rtc_get (&tm2);
43                 start2 = get_timer (0);
44                 if (tm1.tm_sec != tm2.tm_sec)
45                         break;
46                 if (start2 - start1 > 1500)
47                         break;
48         }
49
50         if (tm1.tm_sec != tm2.tm_sec) {
51                 *diff = start2 - start1;
52
53                 return 0;
54         } else {
55                 return -1;
56         }
57 }
58
59 static void rtc_post_restore (struct rtc_time *tm, unsigned int sec)
60 {
61         time_t t = rtc_mktime(tm) + sec;
62         struct rtc_time ntm;
63
64         rtc_to_tm(t, &ntm);
65
66         rtc_set (&ntm);
67 }
68
69 int rtc_post_test (int flags)
70 {
71         ulong diff;
72         unsigned int i;
73         struct rtc_time svtm;
74         static unsigned int daysnl[] =
75                         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
76         static unsigned int daysl[] =
77                         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
78         unsigned int ynl = 1999;
79         unsigned int yl = 2000;
80         unsigned int skipped = 0;
81         int reliable;
82
83         /* Time reliability */
84         reliable = rtc_get (&svtm);
85
86         /* Time uniformity */
87         if (rtc_post_skip (&diff) != 0) {
88                 post_log ("Timeout while waiting for a new second !\n");
89
90                 return -1;
91         }
92
93         for (i = 0; i < 5; i++) {
94                 if (rtc_post_skip (&diff) != 0) {
95                         post_log ("Timeout while waiting for a new second !\n");
96
97                         return -1;
98                 }
99
100                 if (diff < 950 || diff > 1050) {
101                         post_log ("Invalid second duration !\n");
102
103                         return -1;
104                 }
105         }
106
107         /* Passing month boundaries */
108
109         if (rtc_post_skip (&diff) != 0) {
110                 post_log ("Timeout while waiting for a new second !\n");
111
112                 return -1;
113         }
114         rtc_get (&svtm);
115
116         for (i = 0; i < 12; i++) {
117                 time_t t;
118                 struct rtc_time tm;
119
120                 tm.tm_year = ynl;
121                 tm.tm_mon = i + 1;
122                 tm.tm_mday = daysnl[i];
123                 tm.tm_hour = 23;
124                 tm.tm_min = 59;
125                 tm.tm_sec = 59;
126                 t = rtc_mktime(&tm);
127                 rtc_to_tm(t, &tm);
128                 rtc_set (&tm);
129
130                 skipped++;
131                 if (rtc_post_skip (&diff) != 0) {
132                         rtc_post_restore (&svtm, skipped);
133                         post_log ("Timeout while waiting for a new second !\n");
134
135                         return -1;
136                 }
137
138                 rtc_get (&tm);
139                 if (tm.tm_mon == i + 1) {
140                         rtc_post_restore (&svtm, skipped);
141                         post_log ("Month %d boundary is not passed !\n", i + 1);
142
143                         return -1;
144                 }
145         }
146
147         for (i = 0; i < 12; i++) {
148                 time_t t;
149                 struct rtc_time tm;
150
151                 tm.tm_year = yl;
152                 tm.tm_mon = i + 1;
153                 tm.tm_mday = daysl[i];
154                 tm.tm_hour = 23;
155                 tm.tm_min = 59;
156                 tm.tm_sec = 59;
157                 t = rtc_mktime(&tm);
158
159                 rtc_to_tm(t, &tm);
160                 rtc_set (&tm);
161
162                 skipped++;
163                 if (rtc_post_skip (&diff) != 0) {
164                         rtc_post_restore (&svtm, skipped);
165                         post_log ("Timeout while waiting for a new second !\n");
166
167                         return -1;
168                 }
169
170                 rtc_get (&tm);
171                 if (tm.tm_mon == i + 1) {
172                         rtc_post_restore (&svtm, skipped);
173                         post_log ("Month %d boundary is not passed !\n", i + 1);
174
175                         return -1;
176                 }
177         }
178         rtc_post_restore (&svtm, skipped);
179
180         /* If come here, then RTC operates correcty, check the correctness
181          * of the time it reports.
182          */
183         if (reliable < 0) {
184                 post_log ("RTC Time is not reliable! Power fault? \n");
185
186                 return -1;
187         }
188
189         return 0;
190 }
191
192 #endif /* CONFIG_POST & CONFIG_SYS_POST_RTC */