| /* |
| * (C) Copyright 2002 |
| * Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| |
| /* |
| * RTC test |
| * |
| * The Real Time Clock (RTC) operation is verified by this test. |
| * The following features are verified: |
| * o) RTC Power Fault |
| * This is verified by analyzing the rtc_get() return status. |
| * o) Time uniformity |
| * This is verified by reading RTC in polling within |
| * a short period of time. |
| * o) Passing month boundaries |
| * This is checked by setting RTC to a second before |
| * a month boundary and reading it after its passing the |
| * boundary. The test is performed for both leap- and |
| * nonleap-years. |
| */ |
| |
| #include <post.h> |
| #include <rtc.h> |
| |
| #if CONFIG_POST & CONFIG_SYS_POST_RTC |
| |
| static int rtc_post_skip (ulong * diff) |
| { |
| struct rtc_time tm1; |
| struct rtc_time tm2; |
| ulong start1; |
| ulong start2; |
| |
| rtc_get (&tm1); |
| start1 = get_timer (0); |
| |
| while (1) { |
| rtc_get (&tm2); |
| start2 = get_timer (0); |
| if (tm1.tm_sec != tm2.tm_sec) |
| break; |
| if (start2 - start1 > 1500) |
| break; |
| } |
| |
| if (tm1.tm_sec != tm2.tm_sec) { |
| *diff = start2 - start1; |
| |
| return 0; |
| } else { |
| return -1; |
| } |
| } |
| |
| static void rtc_post_restore (struct rtc_time *tm, unsigned int sec) |
| { |
| time_t t = mktime (tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, |
| tm->tm_min, tm->tm_sec) + sec; |
| struct rtc_time ntm; |
| |
| to_tm (t, &ntm); |
| |
| rtc_set (&ntm); |
| } |
| |
| int rtc_post_test (int flags) |
| { |
| ulong diff; |
| unsigned int i; |
| struct rtc_time svtm; |
| static unsigned int daysnl[] = |
| { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| static unsigned int daysl[] = |
| { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| unsigned int ynl = 1999; |
| unsigned int yl = 2000; |
| unsigned int skipped = 0; |
| int reliable; |
| |
| /* Time reliability */ |
| reliable = rtc_get (&svtm); |
| |
| /* Time uniformity */ |
| if (rtc_post_skip (&diff) != 0) { |
| post_log ("Timeout while waiting for a new second !\n"); |
| |
| return -1; |
| } |
| |
| for (i = 0; i < 5; i++) { |
| if (rtc_post_skip (&diff) != 0) { |
| post_log ("Timeout while waiting for a new second !\n"); |
| |
| return -1; |
| } |
| |
| if (diff < 950 || diff > 1050) { |
| post_log ("Invalid second duration !\n"); |
| |
| return -1; |
| } |
| } |
| |
| /* Passing month boundaries */ |
| |
| if (rtc_post_skip (&diff) != 0) { |
| post_log ("Timeout while waiting for a new second !\n"); |
| |
| return -1; |
| } |
| rtc_get (&svtm); |
| |
| for (i = 0; i < 12; i++) { |
| time_t t = mktime (ynl, i + 1, daysnl[i], 23, 59, 59); |
| struct rtc_time tm; |
| |
| to_tm (t, &tm); |
| rtc_set (&tm); |
| |
| skipped++; |
| if (rtc_post_skip (&diff) != 0) { |
| rtc_post_restore (&svtm, skipped); |
| post_log ("Timeout while waiting for a new second !\n"); |
| |
| return -1; |
| } |
| |
| rtc_get (&tm); |
| if (tm.tm_mon == i + 1) { |
| rtc_post_restore (&svtm, skipped); |
| post_log ("Month %d boundary is not passed !\n", i + 1); |
| |
| return -1; |
| } |
| } |
| |
| for (i = 0; i < 12; i++) { |
| time_t t = mktime (yl, i + 1, daysl[i], 23, 59, 59); |
| struct rtc_time tm; |
| |
| to_tm (t, &tm); |
| rtc_set (&tm); |
| |
| skipped++; |
| if (rtc_post_skip (&diff) != 0) { |
| rtc_post_restore (&svtm, skipped); |
| post_log ("Timeout while waiting for a new second !\n"); |
| |
| return -1; |
| } |
| |
| rtc_get (&tm); |
| if (tm.tm_mon == i + 1) { |
| rtc_post_restore (&svtm, skipped); |
| post_log ("Month %d boundary is not passed !\n", i + 1); |
| |
| return -1; |
| } |
| } |
| rtc_post_restore (&svtm, skipped); |
| |
| /* If come here, then RTC operates correcty, check the correctness |
| * of the time it reports. |
| */ |
| if (reliable < 0) { |
| post_log ("RTC Time is not reliable! Power fault? \n"); |
| |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| #endif /* CONFIG_POST & CONFIG_SYS_POST_RTC */ |