core: add ofnode_get_by_phandle() api
[people/ms/u-boot.git] / post / drivers / rtc.c
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 */