// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2002 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. */ #include /* * 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 #include #if CFG_POST & CFG_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 = rtc_mktime(tm) + sec; struct rtc_time ntm; rtc_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; struct rtc_time tm; tm.tm_year = ynl; tm.tm_mon = i + 1; tm.tm_mday = daysnl[i]; tm.tm_hour = 23; tm.tm_min = 59; tm.tm_sec = 59; t = rtc_mktime(&tm); rtc_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; struct rtc_time tm; tm.tm_year = yl; tm.tm_mon = i + 1; tm.tm_mday = daysl[i]; tm.tm_hour = 23; tm.tm_min = 59; tm.tm_sec = 59; t = rtc_mktime(&tm); rtc_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 /* CFG_POST & CFG_SYS_POST_RTC */