blob: bf97dbbd2f9efcd40ce0bffe0fb7af5ef1ac8e21 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass47725112015-04-20 12:37:31 -06002/*
3 * Copyright (C) 2015 Google, Inc
Simon Glass47725112015-04-20 12:37:31 -06004 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <common.h>
Rasmus Villemoesc203ba42020-07-06 22:01:20 +02008#include <console.h>
Simon Glass47725112015-04-20 12:37:31 -06009#include <dm.h>
Simon Glass031a6502018-11-18 08:14:34 -070010#include <i2c.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Simon Glass47725112015-04-20 12:37:31 -060012#include <rtc.h>
13#include <asm/io.h>
Rasmus Villemoesbaed7792020-07-06 22:01:18 +020014#include <asm/rtc.h>
Simon Glass47725112015-04-20 12:37:31 -060015#include <asm/test.h>
Joe Hershbergere721b882015-05-20 14:27:27 -050016#include <dm/test.h>
Simon Glass0e1fad42020-07-19 10:15:37 -060017#include <test/test.h>
Joe Hershbergere721b882015-05-20 14:27:27 -050018#include <test/ut.h>
Simon Glass47725112015-04-20 12:37:31 -060019
20/* Simple RTC sanity check */
Joe Hershbergere721b882015-05-20 14:27:27 -050021static int dm_test_rtc_base(struct unit_test_state *uts)
Simon Glass47725112015-04-20 12:37:31 -060022{
23 struct udevice *dev;
24
25 ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_RTC, 2, &dev));
26 ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
27 ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev));
28
29 return 0;
30}
Simon Glasse180c2b2020-07-28 19:41:12 -060031DM_TEST(dm_test_rtc_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Simon Glass47725112015-04-20 12:37:31 -060032
33static void show_time(const char *msg, struct rtc_time *time)
34{
35 printf("%s: %02d/%02d/%04d %02d:%02d:%02d\n", msg,
36 time->tm_mday, time->tm_mon, time->tm_year,
37 time->tm_hour, time->tm_min, time->tm_sec);
38}
39
40static int cmp_times(struct rtc_time *expect, struct rtc_time *time, bool show)
41{
42 bool same;
43
44 same = expect->tm_sec == time->tm_sec;
45 same &= expect->tm_min == time->tm_min;
46 same &= expect->tm_hour == time->tm_hour;
47 same &= expect->tm_mday == time->tm_mday;
48 same &= expect->tm_mon == time->tm_mon;
49 same &= expect->tm_year == time->tm_year;
50 if (!same && show) {
51 show_time("expected", expect);
52 show_time("actual", time);
53 }
54
55 return same ? 0 : -EINVAL;
56}
57
58/* Set and get the time */
Joe Hershbergere721b882015-05-20 14:27:27 -050059static int dm_test_rtc_set_get(struct unit_test_state *uts)
Simon Glass47725112015-04-20 12:37:31 -060060{
61 struct rtc_time now, time, cmp;
62 struct udevice *dev, *emul;
Simon Glassfc7ceae2022-08-01 07:58:47 -060063 long offset, check_offset, old_offset, old_base_time;
64 int i;
Simon Glass47725112015-04-20 12:37:31 -060065
66 ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
Simon Glass47725112015-04-20 12:37:31 -060067
Simon Glass031a6502018-11-18 08:14:34 -070068 ut_assertok(i2c_emul_find(dev, &emul));
Simon Glasse033c182022-08-01 07:58:44 -060069 ut_assertnonnull(emul);
Simon Glass47725112015-04-20 12:37:31 -060070
Simon Glassfc7ceae2022-08-01 07:58:47 -060071 /* Get the offset, putting the RTC into manual mode */
72 i = 0;
73 do {
74 check_offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
75 ut_assertok(dm_rtc_get(dev, &now));
76
77 /* Tell the RTC to go into manual mode */
78 old_offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
79
80 /* If the times changed in that period, read it again */
81 } while (++i < 2 && check_offset != old_offset);
82 ut_asserteq(check_offset, old_offset);
83
Simon Glass47725112015-04-20 12:37:31 -060084 old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
85
86 memset(&time, '\0', sizeof(time));
Rasmus Villemoes9fb6a412020-07-06 22:01:16 +020087 time.tm_mday = 3;
88 time.tm_mon = 6;
89 time.tm_year = 2004;
90 time.tm_sec = 0;
91 time.tm_min = 18;
92 time.tm_hour = 18;
93 ut_assertok(dm_rtc_set(dev, &time));
94
95 memset(&cmp, '\0', sizeof(cmp));
96 ut_assertok(dm_rtc_get(dev, &cmp));
97 ut_assertok(cmp_times(&time, &cmp, true));
98
99 memset(&time, '\0', sizeof(time));
100 time.tm_mday = 31;
Simon Glass47725112015-04-20 12:37:31 -0600101 time.tm_mon = 8;
102 time.tm_year = 2004;
103 time.tm_sec = 0;
104 time.tm_min = 18;
105 time.tm_hour = 18;
106 ut_assertok(dm_rtc_set(dev, &time));
107
108 memset(&cmp, '\0', sizeof(cmp));
109 ut_assertok(dm_rtc_get(dev, &cmp));
110 ut_assertok(cmp_times(&time, &cmp, true));
111
112 /* Increment by 1 second */
113 offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
114 sandbox_i2c_rtc_set_offset(emul, false, offset + 1);
115
116 memset(&cmp, '\0', sizeof(cmp));
117 ut_assertok(dm_rtc_get(dev, &cmp));
118 ut_asserteq(1, cmp.tm_sec);
119
120 /* Check against original offset */
121 sandbox_i2c_rtc_set_offset(emul, false, old_offset);
122 ut_assertok(dm_rtc_get(dev, &cmp));
123 ut_assertok(cmp_times(&now, &cmp, true));
124
125 /* Back to the original offset */
126 sandbox_i2c_rtc_set_offset(emul, false, 0);
127 memset(&cmp, '\0', sizeof(cmp));
128 ut_assertok(dm_rtc_get(dev, &cmp));
129 ut_assertok(cmp_times(&now, &cmp, true));
130
131 /* Increment the base time by 1 emul */
132 sandbox_i2c_rtc_get_set_base_time(emul, old_base_time + 1);
133 memset(&cmp, '\0', sizeof(cmp));
134 ut_assertok(dm_rtc_get(dev, &cmp));
135 if (now.tm_sec == 59) {
136 ut_asserteq(0, cmp.tm_sec);
137 } else {
138 ut_asserteq(now.tm_sec + 1, cmp.tm_sec);
139 }
140
Simon Glassfc7ceae2022-08-01 07:58:47 -0600141 /* return RTC to normal mode */
142 sandbox_i2c_rtc_set_offset(emul, true, 0);
Simon Glass47725112015-04-20 12:37:31 -0600143
144 return 0;
145}
Simon Glasse180c2b2020-07-28 19:41:12 -0600146DM_TEST(dm_test_rtc_set_get, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Simon Glass47725112015-04-20 12:37:31 -0600147
Rasmus Villemoesbaed7792020-07-06 22:01:18 +0200148static int dm_test_rtc_read_write(struct unit_test_state *uts)
149{
150 struct rtc_time time;
151 struct udevice *dev, *emul;
152 long old_offset;
153 u8 buf[4], reg;
154
155 ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
156
157 memcpy(buf, "car", 4);
158 ut_assertok(dm_rtc_write(dev, REG_AUX0, buf, 4));
159 memset(buf, '\0', sizeof(buf));
160 ut_assertok(dm_rtc_read(dev, REG_AUX0, buf, 4));
161 ut_asserteq(memcmp(buf, "car", 4), 0);
162
163 reg = 'b';
164 ut_assertok(dm_rtc_write(dev, REG_AUX0, &reg, 1));
165 memset(buf, '\0', sizeof(buf));
166 ut_assertok(dm_rtc_read(dev, REG_AUX0, buf, 4));
167 ut_asserteq(memcmp(buf, "bar", 4), 0);
168
169 reg = 't';
170 ut_assertok(dm_rtc_write(dev, REG_AUX2, &reg, 1));
171 memset(buf, '\0', sizeof(buf));
172 ut_assertok(dm_rtc_read(dev, REG_AUX1, buf, 3));
173 ut_asserteq(memcmp(buf, "at", 3), 0);
174
175 ut_assertok(i2c_emul_find(dev, &emul));
Simon Glasse033c182022-08-01 07:58:44 -0600176 ut_assertnonnull(emul);
Rasmus Villemoesbaed7792020-07-06 22:01:18 +0200177
178 old_offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
179 ut_assertok(dm_rtc_get(dev, &time));
180
181 ut_assertok(dm_rtc_read(dev, REG_SEC, &reg, 1));
182 ut_asserteq(time.tm_sec, reg);
183 ut_assertok(dm_rtc_read(dev, REG_MDAY, &reg, 1));
184 ut_asserteq(time.tm_mday, reg);
185
186 sandbox_i2c_rtc_set_offset(emul, true, old_offset);
187
188 return 0;
189}
Simon Glasse180c2b2020-07-28 19:41:12 -0600190DM_TEST(dm_test_rtc_read_write, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Rasmus Villemoesbaed7792020-07-06 22:01:18 +0200191
Rasmus Villemoesc203ba42020-07-06 22:01:20 +0200192/* Test 'rtc list' command */
193static int dm_test_rtc_cmd_list(struct unit_test_state *uts)
194{
195 console_record_reset();
196
197 run_command("rtc list", 0);
198 ut_assert_nextline("RTC #0 - rtc@43");
199 ut_assert_nextline("RTC #1 - rtc@61");
200 ut_assert_console_end();
201
202 return 0;
203}
Simon Glasse180c2b2020-07-28 19:41:12 -0600204DM_TEST(dm_test_rtc_cmd_list, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Rasmus Villemoesc203ba42020-07-06 22:01:20 +0200205
206/* Test 'rtc read' and 'rtc write' commands */
207static int dm_test_rtc_cmd_rw(struct unit_test_state *uts)
208{
209 console_record_reset();
210
211 run_command("rtc dev 0", 0);
212 ut_assert_nextline("RTC #0 - rtc@43");
213 ut_assert_console_end();
214
215 run_command("rtc write 0x30 aabb", 0);
216 ut_assert_console_end();
217
218 run_command("rtc read 0x30 2", 0);
Simon Glassc7b16d82021-05-08 07:00:00 -0600219 ut_assert_nextline("00000030: aa bb ..");
Rasmus Villemoesc203ba42020-07-06 22:01:20 +0200220 ut_assert_console_end();
221
222 run_command("rtc dev 1", 0);
223 ut_assert_nextline("RTC #1 - rtc@61");
224 ut_assert_console_end();
225
226 run_command("rtc write 0x30 ccdd", 0);
227 ut_assert_console_end();
228
229 run_command("rtc read 0x30 2", 0);
Simon Glassc7b16d82021-05-08 07:00:00 -0600230 ut_assert_nextline("00000030: cc dd ..");
Rasmus Villemoesc203ba42020-07-06 22:01:20 +0200231 ut_assert_console_end();
232
233 /*
234 * Switch back to device #0, check that its aux registers
235 * still have the same values.
236 */
237 run_command("rtc dev 0", 0);
238 ut_assert_nextline("RTC #0 - rtc@43");
239 ut_assert_console_end();
240
241 run_command("rtc read 0x30 2", 0);
Simon Glassc7b16d82021-05-08 07:00:00 -0600242 ut_assert_nextline("00000030: aa bb ..");
Rasmus Villemoesc203ba42020-07-06 22:01:20 +0200243 ut_assert_console_end();
244
245 return 0;
246}
Simon Glasse180c2b2020-07-28 19:41:12 -0600247DM_TEST(dm_test_rtc_cmd_rw, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Rasmus Villemoesc203ba42020-07-06 22:01:20 +0200248
Simon Glass47725112015-04-20 12:37:31 -0600249/* Reset the time */
Joe Hershbergere721b882015-05-20 14:27:27 -0500250static int dm_test_rtc_reset(struct unit_test_state *uts)
Simon Glass47725112015-04-20 12:37:31 -0600251{
252 struct rtc_time now;
253 struct udevice *dev, *emul;
254 long old_base_time, base_time;
Simon Glass21ddac12022-08-01 07:58:48 -0600255 int i;
Simon Glass47725112015-04-20 12:37:31 -0600256
257 ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
258 ut_assertok(dm_rtc_get(dev, &now));
259
Simon Glass031a6502018-11-18 08:14:34 -0700260 ut_assertok(i2c_emul_find(dev, &emul));
Simon Glasse033c182022-08-01 07:58:44 -0600261 ut_assertnonnull(emul);
Simon Glass47725112015-04-20 12:37:31 -0600262
Simon Glass21ddac12022-08-01 07:58:48 -0600263 i = 0;
264 do {
265 old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
Simon Glass47725112015-04-20 12:37:31 -0600266
Simon Glass21ddac12022-08-01 07:58:48 -0600267 ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
Simon Glass47725112015-04-20 12:37:31 -0600268
Simon Glass21ddac12022-08-01 07:58:48 -0600269 ut_assertok(dm_rtc_reset(dev));
270 base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
271
272 /*
273 * Resetting the RTC should put the base time back to normal.
274 * Allow for a one-timeadjustment in case the time flips over
275 * while this test process is pre-empted (either by a second
276 * or a daylight-saving change), since reset_time() in
277 * i2c_rtc_emul.c reads the time from the OS.
278 */
279 } while (++i < 2 && base_time != old_base_time);
280 ut_asserteq(old_base_time, base_time);
Simon Glass47725112015-04-20 12:37:31 -0600281
282 return 0;
283}
Simon Glasse180c2b2020-07-28 19:41:12 -0600284DM_TEST(dm_test_rtc_reset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
Simon Glass47725112015-04-20 12:37:31 -0600285
286/* Check that two RTC devices can be used independently */
Joe Hershbergere721b882015-05-20 14:27:27 -0500287static int dm_test_rtc_dual(struct unit_test_state *uts)
Simon Glass47725112015-04-20 12:37:31 -0600288{
289 struct rtc_time now1, now2, cmp;
290 struct udevice *dev1, *dev2;
291 struct udevice *emul1, *emul2;
292 long offset;
293
294 ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev1));
295 ut_assertok(dm_rtc_get(dev1, &now1));
296 ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev2));
297 ut_assertok(dm_rtc_get(dev2, &now2));
298
Simon Glass031a6502018-11-18 08:14:34 -0700299 ut_assertok(i2c_emul_find(dev1, &emul1));
Simon Glasse033c182022-08-01 07:58:44 -0600300 ut_assertnonnull(emul1);
Simon Glass031a6502018-11-18 08:14:34 -0700301 ut_assertok(i2c_emul_find(dev2, &emul2));
Simon Glasse033c182022-08-01 07:58:44 -0600302 ut_assertnonnull(emul2);
Simon Glass47725112015-04-20 12:37:31 -0600303
304 offset = sandbox_i2c_rtc_set_offset(emul1, false, -1);
305 sandbox_i2c_rtc_set_offset(emul2, false, offset + 1);
306 memset(&cmp, '\0', sizeof(cmp));
307 ut_assertok(dm_rtc_get(dev2, &cmp));
308 ut_asserteq(-EINVAL, cmp_times(&now1, &cmp, false));
309
310 memset(&cmp, '\0', sizeof(cmp));
311 ut_assertok(dm_rtc_get(dev1, &cmp));
312 ut_assertok(cmp_times(&now1, &cmp, true));
313
314 return 0;
315}
Simon Glasse180c2b2020-07-28 19:41:12 -0600316DM_TEST(dm_test_rtc_dual, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);