1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <common.h>
8 #include <console.h>
9 #include <dm.h>
10 #include <i2c.h>
11 #include <log.h>
12 #include <rtc.h>
13 #include <asm/io.h>
14 #include <asm/rtc.h>
15 #include <asm/test.h>
16 #include <dm/test.h>
17 #include <test/test.h>
18 #include <test/ut.h>
19 
20 /* Simple RTC sanity check */
dm_test_rtc_base(struct unit_test_state * uts)21 static int dm_test_rtc_base(struct unit_test_state *uts)
22 {
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 }
31 DM_TEST(dm_test_rtc_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
32 
show_time(const char * msg,struct rtc_time * time)33 static 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 
cmp_times(struct rtc_time * expect,struct rtc_time * time,bool show)40 static 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 */
dm_test_rtc_set_get(struct unit_test_state * uts)59 static int dm_test_rtc_set_get(struct unit_test_state *uts)
60 {
61 	struct rtc_time now, time, cmp;
62 	struct udevice *dev, *emul;
63 	long offset, check_offset, old_offset, old_base_time;
64 	int i;
65 
66 	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
67 
68 	ut_assertok(i2c_emul_find(dev, &emul));
69 	ut_assertnonnull(emul);
70 
71 	/* 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 
84 	old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
85 
86 	memset(&time, '\0', sizeof(time));
87 	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;
101 	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 
141 	/* return RTC to normal mode */
142 	sandbox_i2c_rtc_set_offset(emul, true, 0);
143 
144 	return 0;
145 }
146 DM_TEST(dm_test_rtc_set_get, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
147 
dm_test_rtc_read_write(struct unit_test_state * uts)148 static 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));
176 	ut_assertnonnull(emul);
177 
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 }
190 DM_TEST(dm_test_rtc_read_write, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
191 
192 /* Test 'rtc list' command */
dm_test_rtc_cmd_list(struct unit_test_state * uts)193 static 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 }
204 DM_TEST(dm_test_rtc_cmd_list, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
205 
206 /* Test 'rtc read' and 'rtc write' commands */
dm_test_rtc_cmd_rw(struct unit_test_state * uts)207 static 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);
219 	ut_assert_nextline("00000030: aa bb                                            ..");
220 	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);
230 	ut_assert_nextline("00000030: cc dd                                            ..");
231 	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);
242 	ut_assert_nextline("00000030: aa bb                                            ..");
243 	ut_assert_console_end();
244 
245 	return 0;
246 }
247 DM_TEST(dm_test_rtc_cmd_rw, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
248 
249 /* Reset the time */
dm_test_rtc_reset(struct unit_test_state * uts)250 static int dm_test_rtc_reset(struct unit_test_state *uts)
251 {
252 	struct rtc_time now;
253 	struct udevice *dev, *emul;
254 	long old_base_time, base_time;
255 	int i;
256 
257 	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
258 	ut_assertok(dm_rtc_get(dev, &now));
259 
260 	ut_assertok(i2c_emul_find(dev, &emul));
261 	ut_assertnonnull(emul);
262 
263 	i = 0;
264 	do {
265 		old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
266 
267 		ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
268 
269 		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);
281 
282 	return 0;
283 }
284 DM_TEST(dm_test_rtc_reset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
285 
286 /* Check that two RTC devices can be used independently */
dm_test_rtc_dual(struct unit_test_state * uts)287 static int dm_test_rtc_dual(struct unit_test_state *uts)
288 {
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 
299 	ut_assertok(i2c_emul_find(dev1, &emul1));
300 	ut_assertnonnull(emul1);
301 	ut_assertok(i2c_emul_find(dev2, &emul2));
302 	ut_assertnonnull(emul2);
303 
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 }
316 DM_TEST(dm_test_rtc_dual, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
317