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