]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
ad5bb451 WD |
2 | /* |
3 | * (C) Copyright 2002 | |
4 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
ad5bb451 WD |
5 | */ |
6 | ||
03de305e | 7 | #include <config.h> |
ad5bb451 WD |
8 | |
9 | /* | |
10 | * RTC test | |
11 | * | |
12 | * The Real Time Clock (RTC) operation is verified by this test. | |
13 | * The following features are verified: | |
b73a19e1 YT |
14 | * o) RTC Power Fault |
15 | * This is verified by analyzing the rtc_get() return status. | |
ad5bb451 WD |
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 | ||
ad5bb451 WD |
26 | #include <post.h> |
27 | #include <rtc.h> | |
28 | ||
1e019503 | 29 | #if CFG_POST & CFG_SYS_POST_RTC |
ad5bb451 WD |
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 | { | |
71420983 | 61 | time_t t = rtc_mktime(tm) + sec; |
ad5bb451 WD |
62 | struct rtc_time ntm; |
63 | ||
9f9276c3 | 64 | rtc_to_tm(t, &ntm); |
ad5bb451 WD |
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; | |
b73a19e1 YT |
81 | int reliable; |
82 | ||
83 | /* Time reliability */ | |
84 | reliable = rtc_get (&svtm); | |
ad5bb451 WD |
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++) { | |
71420983 | 117 | time_t t; |
ad5bb451 WD |
118 | struct rtc_time tm; |
119 | ||
71420983 SG |
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); | |
9f9276c3 | 127 | rtc_to_tm(t, &tm); |
ad5bb451 WD |
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++) { | |
71420983 | 148 | time_t t; |
ad5bb451 WD |
149 | struct rtc_time tm; |
150 | ||
71420983 SG |
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 | ||
9f9276c3 | 159 | rtc_to_tm(t, &tm); |
ad5bb451 WD |
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 | ||
b73a19e1 YT |
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 | ||
ad5bb451 WD |
189 | return 0; |
190 | } | |
191 | ||
1e019503 | 192 | #endif /* CFG_POST & CFG_SYS_POST_RTC */ |