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