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
rtc_post_skip(ulong * diff)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
rtc_post_restore(struct rtc_time * tm,unsigned int sec)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
rtc_post_test(int flags)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 */
193