blob: cc7a49847ccdc1c0a051d98a211954f5d0cb8837 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Wolfgang Denkad5bb452007-03-06 18:08:43 +01002/*
3 * (C) Copyright 2002
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Wolfgang Denkad5bb452007-03-06 18:08:43 +01005 */
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:
Yuri Tikhonovb73a19e2008-03-20 17:56:04 +030014 * o) RTC Power Fault
15 * This is verified by analyzing the rtc_get() return status.
Wolfgang Denkad5bb452007-03-06 18:08:43 +010016 * 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
Wolfgang Denkad5bb452007-03-06 18:08:43 +010026#include <post.h>
27#include <rtc.h>
28
Tom Rini1e019502022-12-04 10:14:17 -050029#if CFG_POST & CFG_SYS_POST_RTC
Wolfgang Denkad5bb452007-03-06 18:08:43 +010030
31static 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
59static void rtc_post_restore (struct rtc_time *tm, unsigned int sec)
60{
Simon Glass71420982015-04-20 12:37:19 -060061 time_t t = rtc_mktime(tm) + sec;
Wolfgang Denkad5bb452007-03-06 18:08:43 +010062 struct rtc_time ntm;
63
Simon Glass9f9276c2015-04-20 12:37:18 -060064 rtc_to_tm(t, &ntm);
Wolfgang Denkad5bb452007-03-06 18:08:43 +010065
66 rtc_set (&ntm);
67}
68
69int 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;
Yuri Tikhonovb73a19e2008-03-20 17:56:04 +030081 int reliable;
82
83 /* Time reliability */
84 reliable = rtc_get (&svtm);
Wolfgang Denkad5bb452007-03-06 18:08:43 +010085
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++) {
Simon Glass71420982015-04-20 12:37:19 -0600117 time_t t;
Wolfgang Denkad5bb452007-03-06 18:08:43 +0100118 struct rtc_time tm;
119
Simon Glass71420982015-04-20 12:37:19 -0600120 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);
Simon Glass9f9276c2015-04-20 12:37:18 -0600127 rtc_to_tm(t, &tm);
Wolfgang Denkad5bb452007-03-06 18:08:43 +0100128 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++) {
Simon Glass71420982015-04-20 12:37:19 -0600148 time_t t;
Wolfgang Denkad5bb452007-03-06 18:08:43 +0100149 struct rtc_time tm;
150
Simon Glass71420982015-04-20 12:37:19 -0600151 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
Simon Glass9f9276c2015-04-20 12:37:18 -0600159 rtc_to_tm(t, &tm);
Wolfgang Denkad5bb452007-03-06 18:08:43 +0100160 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
Yuri Tikhonovb73a19e2008-03-20 17:56:04 +0300180 /* 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
Wolfgang Denkad5bb452007-03-06 18:08:43 +0100189 return 0;
190}
191
Tom Rini1e019502022-12-04 10:14:17 -0500192#endif /* CFG_POST & CFG_SYS_POST_RTC */