1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // KUnit test for the Cirrus common amplifier library.
4 //
5 // Copyright (C) 2024 Cirrus Logic, Inc. and
6 // Cirrus Logic International Semiconductor Ltd.
7
8 #include <kunit/test.h>
9 #include <kunit/static_stub.h>
10 #include <linux/firmware/cirrus/cs_dsp.h>
11 #include <linux/firmware/cirrus/wmfw.h>
12 #include <linux/gpio/driver.h>
13 #include <linux/list.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/random.h>
17 #include <sound/cs-amp-lib.h>
18
19 struct cs_amp_lib_test_priv {
20 struct platform_device amp_pdev;
21
22 struct cirrus_amp_efi_data *cal_blob;
23 struct list_head ctl_write_list;
24 };
25
26 struct cs_amp_lib_test_ctl_write_entry {
27 struct list_head list;
28 unsigned int value;
29 char name[16];
30 };
31
32 struct cs_amp_lib_test_param {
33 int num_amps;
34 int amp_index;
35 };
36
cs_amp_lib_test_init_dummy_cal_blob(struct kunit * test,int num_amps)37 static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps)
38 {
39 struct cs_amp_lib_test_priv *priv = test->priv;
40 unsigned int blob_size;
41 int i;
42
43 blob_size = offsetof(struct cirrus_amp_efi_data, data) +
44 sizeof(struct cirrus_amp_cal_data) * num_amps;
45
46 priv->cal_blob = kunit_kzalloc(test, blob_size, GFP_KERNEL);
47 KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
48
49 priv->cal_blob->size = blob_size;
50 priv->cal_blob->count = num_amps;
51
52 get_random_bytes(priv->cal_blob->data, sizeof(struct cirrus_amp_cal_data) * num_amps);
53
54 /* Ensure all timestamps are non-zero to mark the entry valid. */
55 for (i = 0; i < num_amps; i++)
56 priv->cal_blob->data[i].calTime[0] |= 1;
57
58 /* Ensure that all UIDs are non-zero and unique. */
59 for (i = 0; i < num_amps; i++)
60 *(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1;
61 }
62
cs_amp_lib_test_get_target_uid(struct kunit * test)63 static u64 cs_amp_lib_test_get_target_uid(struct kunit *test)
64 {
65 struct cs_amp_lib_test_priv *priv = test->priv;
66 const struct cs_amp_lib_test_param *param = test->param_value;
67 u64 uid;
68
69 uid = priv->cal_blob->data[param->amp_index].calTarget[1];
70 uid <<= 32;
71 uid |= priv->cal_blob->data[param->amp_index].calTarget[0];
72
73 return uid;
74 }
75
76 /* Redirected get_efi_variable to simulate that the file is too short */
cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)77 static efi_status_t cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t *name,
78 efi_guid_t *guid,
79 unsigned long *size,
80 void *buf)
81 {
82 if (!buf) {
83 *size = offsetof(struct cirrus_amp_efi_data, data) - 1;
84 return EFI_BUFFER_TOO_SMALL;
85 }
86
87 return EFI_NOT_FOUND;
88 }
89
90 /* Should return -EOVERFLOW if the header is larger than the EFI data */
cs_amp_lib_test_cal_data_too_short_test(struct kunit * test)91 static void cs_amp_lib_test_cal_data_too_short_test(struct kunit *test)
92 {
93 struct cs_amp_lib_test_priv *priv = test->priv;
94 struct cirrus_amp_cal_data result_data;
95 int ret;
96
97 /* Redirect calls to get EFI data */
98 kunit_activate_static_stub(test,
99 cs_amp_test_hooks->get_efi_variable,
100 cs_amp_lib_test_get_efi_variable_nohead);
101
102 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 0, &result_data);
103 KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
104
105 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
106 }
107
108 /* Redirected get_efi_variable to simulate that the count is larger than the file */
cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)109 static efi_status_t cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t *name,
110 efi_guid_t *guid,
111 unsigned long *size,
112 void *buf)
113 {
114 struct kunit *test = kunit_get_current_test();
115 struct cs_amp_lib_test_priv *priv = test->priv;
116
117 if (!buf) {
118 /*
119 * Return a size that is shorter than required for the
120 * declared number of entries.
121 */
122 *size = priv->cal_blob->size - 1;
123 return EFI_BUFFER_TOO_SMALL;
124 }
125
126 memcpy(buf, priv->cal_blob, priv->cal_blob->size - 1);
127
128 return EFI_SUCCESS;
129 }
130
131 /* Should return -EOVERFLOW if the entry count is larger than the EFI data */
cs_amp_lib_test_cal_count_too_big_test(struct kunit * test)132 static void cs_amp_lib_test_cal_count_too_big_test(struct kunit *test)
133 {
134 struct cs_amp_lib_test_priv *priv = test->priv;
135 struct cirrus_amp_cal_data result_data;
136 int ret;
137
138 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
139
140 /* Redirect calls to get EFI data */
141 kunit_activate_static_stub(test,
142 cs_amp_test_hooks->get_efi_variable,
143 cs_amp_lib_test_get_efi_variable_bad_count);
144
145 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 0, &result_data);
146 KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
147
148 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
149 }
150
151 /* Redirected get_efi_variable to simulate that the variable not found */
cs_amp_lib_test_get_efi_variable_none(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)152 static efi_status_t cs_amp_lib_test_get_efi_variable_none(efi_char16_t *name,
153 efi_guid_t *guid,
154 unsigned long *size,
155 void *buf)
156 {
157 return EFI_NOT_FOUND;
158 }
159
160 /* If EFI doesn't contain a cal data variable the result should be -ENOENT */
cs_amp_lib_test_no_cal_data_test(struct kunit * test)161 static void cs_amp_lib_test_no_cal_data_test(struct kunit *test)
162 {
163 struct cs_amp_lib_test_priv *priv = test->priv;
164 struct cirrus_amp_cal_data result_data;
165 int ret;
166
167 /* Redirect calls to get EFI data */
168 kunit_activate_static_stub(test,
169 cs_amp_test_hooks->get_efi_variable,
170 cs_amp_lib_test_get_efi_variable_none);
171
172 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 0, &result_data);
173 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
174
175 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
176 }
177
178 /* Redirected get_efi_variable to simulate reading a cal data blob */
cs_amp_lib_test_get_efi_variable(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,void * buf)179 static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
180 efi_guid_t *guid,
181 unsigned long *size,
182 void *buf)
183 {
184 static const efi_char16_t expected_name[] = L"CirrusSmartAmpCalibrationData";
185 static const efi_guid_t expected_guid =
186 EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
187 struct kunit *test = kunit_get_current_test();
188 struct cs_amp_lib_test_priv *priv = test->priv;
189
190 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
191 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
192 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
193
194 KUNIT_EXPECT_MEMEQ(test, name, expected_name, sizeof(expected_name));
195 KUNIT_EXPECT_MEMEQ(test, guid, &expected_guid, sizeof(expected_guid));
196
197 if (!buf) {
198 *size = priv->cal_blob->size;
199 return EFI_BUFFER_TOO_SMALL;
200 }
201
202 KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
203
204 memcpy(buf, priv->cal_blob, priv->cal_blob->size);
205
206 return EFI_SUCCESS;
207 }
208
209 /* Get cal data block for a given amp, matched by target UID. */
cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit * test)210 static void cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit *test)
211 {
212 struct cs_amp_lib_test_priv *priv = test->priv;
213 const struct cs_amp_lib_test_param *param = test->param_value;
214 struct cirrus_amp_cal_data result_data;
215 u64 target_uid;
216 int ret;
217
218 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
219
220 /* Redirect calls to get EFI data */
221 kunit_activate_static_stub(test,
222 cs_amp_test_hooks->get_efi_variable,
223 cs_amp_lib_test_get_efi_variable);
224
225 target_uid = cs_amp_lib_test_get_target_uid(test);
226 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, target_uid, -1, &result_data);
227 KUNIT_EXPECT_EQ(test, ret, 0);
228
229 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
230
231 KUNIT_EXPECT_EQ(test, result_data.calTarget[0], target_uid & 0xFFFFFFFFULL);
232 KUNIT_EXPECT_EQ(test, result_data.calTarget[1], target_uid >> 32);
233 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
234 priv->cal_blob->data[param->amp_index].calTime[0]);
235 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
236 priv->cal_blob->data[param->amp_index].calTime[1]);
237 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
238 priv->cal_blob->data[param->amp_index].calAmbient);
239 KUNIT_EXPECT_EQ(test, result_data.calStatus,
240 priv->cal_blob->data[param->amp_index].calStatus);
241 KUNIT_EXPECT_EQ(test, result_data.calR,
242 priv->cal_blob->data[param->amp_index].calR);
243 }
244
245 /* Get cal data block for a given amp index without checking target UID. */
cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit * test)246 static void cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit *test)
247 {
248 struct cs_amp_lib_test_priv *priv = test->priv;
249 const struct cs_amp_lib_test_param *param = test->param_value;
250 struct cirrus_amp_cal_data result_data;
251 int ret;
252
253 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
254
255 /* Redirect calls to get EFI data */
256 kunit_activate_static_stub(test,
257 cs_amp_test_hooks->get_efi_variable,
258 cs_amp_lib_test_get_efi_variable);
259
260 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0,
261 param->amp_index, &result_data);
262 KUNIT_EXPECT_EQ(test, ret, 0);
263
264 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
265
266 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
267 priv->cal_blob->data[param->amp_index].calTime[0]);
268 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
269 priv->cal_blob->data[param->amp_index].calTime[1]);
270 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
271 priv->cal_blob->data[param->amp_index].calAmbient);
272 KUNIT_EXPECT_EQ(test, result_data.calStatus,
273 priv->cal_blob->data[param->amp_index].calStatus);
274 KUNIT_EXPECT_EQ(test, result_data.calR,
275 priv->cal_blob->data[param->amp_index].calR);
276 }
277
278 /* Get cal data block for a given amp index with checked target UID. */
cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit * test)279 static void cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit *test)
280 {
281 struct cs_amp_lib_test_priv *priv = test->priv;
282 const struct cs_amp_lib_test_param *param = test->param_value;
283 struct cirrus_amp_cal_data result_data;
284 u64 target_uid;
285 int ret;
286
287 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
288
289 /* Redirect calls to get EFI data */
290 kunit_activate_static_stub(test,
291 cs_amp_test_hooks->get_efi_variable,
292 cs_amp_lib_test_get_efi_variable);
293
294 target_uid = cs_amp_lib_test_get_target_uid(test);
295 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, target_uid,
296 param->amp_index, &result_data);
297 KUNIT_EXPECT_EQ(test, ret, 0);
298
299 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
300
301 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
302 priv->cal_blob->data[param->amp_index].calTime[0]);
303 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
304 priv->cal_blob->data[param->amp_index].calTime[1]);
305 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
306 priv->cal_blob->data[param->amp_index].calAmbient);
307 KUNIT_EXPECT_EQ(test, result_data.calStatus,
308 priv->cal_blob->data[param->amp_index].calStatus);
309 KUNIT_EXPECT_EQ(test, result_data.calR,
310 priv->cal_blob->data[param->amp_index].calR);
311 }
312
313 /*
314 * Get cal data block for a given amp index with checked target UID.
315 * The UID does not match so the result should be -ENOENT.
316 */
cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit * test)317 static void cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit *test)
318 {
319 struct cs_amp_lib_test_priv *priv = test->priv;
320 const struct cs_amp_lib_test_param *param = test->param_value;
321 struct cirrus_amp_cal_data result_data;
322 u64 target_uid;
323 int ret;
324
325 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
326
327 /* Redirect calls to get EFI data */
328 kunit_activate_static_stub(test,
329 cs_amp_test_hooks->get_efi_variable,
330 cs_amp_lib_test_get_efi_variable);
331
332 /* Get a target UID that won't match the entry */
333 target_uid = ~cs_amp_lib_test_get_target_uid(test);
334 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, target_uid,
335 param->amp_index, &result_data);
336 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
337
338 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
339 }
340
341 /*
342 * Get cal data block for a given amp, where the cal data does not
343 * specify calTarget so the lookup falls back to using the index
344 */
cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit * test)345 static void cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit *test)
346 {
347 struct cs_amp_lib_test_priv *priv = test->priv;
348 const struct cs_amp_lib_test_param *param = test->param_value;
349 struct cirrus_amp_cal_data result_data;
350 static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
351 int i, ret;
352
353 cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
354
355 /* Make all the target values zero so they are ignored */
356 for (i = 0; i < priv->cal_blob->count; ++i) {
357 priv->cal_blob->data[i].calTarget[0] = 0;
358 priv->cal_blob->data[i].calTarget[1] = 0;
359 }
360
361 /* Redirect calls to get EFI data */
362 kunit_activate_static_stub(test,
363 cs_amp_test_hooks->get_efi_variable,
364 cs_amp_lib_test_get_efi_variable);
365
366 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, bad_target_uid,
367 param->amp_index, &result_data);
368 KUNIT_EXPECT_EQ(test, ret, 0);
369
370 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
371
372 KUNIT_EXPECT_EQ(test, result_data.calTime[0],
373 priv->cal_blob->data[param->amp_index].calTime[0]);
374 KUNIT_EXPECT_EQ(test, result_data.calTime[1],
375 priv->cal_blob->data[param->amp_index].calTime[1]);
376 KUNIT_EXPECT_EQ(test, result_data.calAmbient,
377 priv->cal_blob->data[param->amp_index].calAmbient);
378 KUNIT_EXPECT_EQ(test, result_data.calStatus,
379 priv->cal_blob->data[param->amp_index].calStatus);
380 KUNIT_EXPECT_EQ(test, result_data.calR,
381 priv->cal_blob->data[param->amp_index].calR);
382 }
383
384 /*
385 * If the target UID isn't present in the cal data, and there isn't an
386 * index to fall back do, the result should be -ENOENT.
387 */
cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit * test)388 static void cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit *test)
389 {
390 struct cs_amp_lib_test_priv *priv = test->priv;
391 struct cirrus_amp_cal_data result_data;
392 static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
393 int i, ret;
394
395 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
396
397 /* Make all the target values != bad_target_uid */
398 for (i = 0; i < priv->cal_blob->count; ++i) {
399 priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
400 priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
401 }
402
403 /* Redirect calls to get EFI data */
404 kunit_activate_static_stub(test,
405 cs_amp_test_hooks->get_efi_variable,
406 cs_amp_lib_test_get_efi_variable);
407
408 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, bad_target_uid, -1,
409 &result_data);
410 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
411
412 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
413 }
414
415 /*
416 * If the target UID isn't present in the cal data, and the index is
417 * out of range, the result should be -ENOENT.
418 */
cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit * test)419 static void cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit *test)
420 {
421 struct cs_amp_lib_test_priv *priv = test->priv;
422 struct cirrus_amp_cal_data result_data;
423 static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
424 int i, ret;
425
426 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
427
428 /* Make all the target values != bad_target_uid */
429 for (i = 0; i < priv->cal_blob->count; ++i) {
430 priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
431 priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
432 }
433
434 /* Redirect calls to get EFI data */
435 kunit_activate_static_stub(test,
436 cs_amp_test_hooks->get_efi_variable,
437 cs_amp_lib_test_get_efi_variable);
438
439 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, bad_target_uid, 99,
440 &result_data);
441 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
442
443 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
444 }
445
446 /*
447 * If the target UID isn't given, and the index is out of range, the
448 * result should be -ENOENT.
449 */
cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit * test)450 static void cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit *test)
451 {
452 struct cs_amp_lib_test_priv *priv = test->priv;
453 struct cirrus_amp_cal_data result_data;
454 int ret;
455
456 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
457
458 /* Redirect calls to get EFI data */
459 kunit_activate_static_stub(test,
460 cs_amp_test_hooks->get_efi_variable,
461 cs_amp_lib_test_get_efi_variable);
462
463 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, 99, &result_data);
464 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
465
466 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
467 }
468
469 /* If neither the target UID or the index is given the result should be -ENOENT. */
cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit * test)470 static void cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit *test)
471 {
472 struct cs_amp_lib_test_priv *priv = test->priv;
473 struct cirrus_amp_cal_data result_data;
474 int ret;
475
476 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
477
478 /* Redirect calls to get EFI data */
479 kunit_activate_static_stub(test,
480 cs_amp_test_hooks->get_efi_variable,
481 cs_amp_lib_test_get_efi_variable);
482
483 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, -1, &result_data);
484 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
485
486 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
487 }
488
489 /*
490 * If the UID is passed as 0 this must not match an entry with an
491 * unpopulated calTarget
492 */
cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit * test)493 static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test)
494 {
495 struct cs_amp_lib_test_priv *priv = test->priv;
496 struct cirrus_amp_cal_data result_data;
497 int i, ret;
498
499 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
500
501 /* Make all the target values zero so they are ignored */
502 for (i = 0; i < priv->cal_blob->count; ++i) {
503 priv->cal_blob->data[i].calTarget[0] = 0;
504 priv->cal_blob->data[i].calTarget[1] = 0;
505 }
506
507 /* Redirect calls to get EFI data */
508 kunit_activate_static_stub(test,
509 cs_amp_test_hooks->get_efi_variable,
510 cs_amp_lib_test_get_efi_variable);
511
512 ret = cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, 0, -1, &result_data);
513 KUNIT_EXPECT_EQ(test, ret, -ENOENT);
514
515 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
516 }
517
518 /*
519 * If an entry has a timestamp of 0 it should be ignored even if it has
520 * a matching target UID.
521 */
cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit * test)522 static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test)
523 {
524 struct cs_amp_lib_test_priv *priv = test->priv;
525 struct cirrus_amp_cal_data result_data;
526 u64 uid;
527
528 cs_amp_lib_test_init_dummy_cal_blob(test, 8);
529
530 /* Mark the 3rd entry invalid by zeroing calTime */
531 priv->cal_blob->data[2].calTime[0] = 0;
532 priv->cal_blob->data[2].calTime[1] = 0;
533
534 /* Get the UID value of the 3rd entry */
535 uid = priv->cal_blob->data[2].calTarget[1];
536 uid <<= 32;
537 uid |= priv->cal_blob->data[2].calTarget[0];
538
539 /* Redirect calls to get EFI data */
540 kunit_activate_static_stub(test,
541 cs_amp_test_hooks->get_efi_variable,
542 cs_amp_lib_test_get_efi_variable);
543
544 /* Lookup by UID should not find it */
545 KUNIT_EXPECT_EQ(test,
546 cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev,
547 uid, -1,
548 &result_data),
549 -ENOENT);
550
551 /* Get by index should ignore it */
552 KUNIT_EXPECT_EQ(test,
553 cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev,
554 0, 2,
555 &result_data),
556 -ENOENT);
557
558 kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
559 }
560
561 static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = {
562 .alg_id = 0x9f210,
563 .mem_region = WMFW_ADSP2_YM,
564 .ambient = "CAL_AMBIENT",
565 .calr = "CAL_R",
566 .status = "CAL_STATUS",
567 .checksum = "CAL_CHECKSUM",
568 };
569
cs_amp_lib_test_write_cal_coeff(struct cs_dsp * dsp,const struct cirrus_amp_cal_controls * controls,const char * ctl_name,u32 val)570 static int cs_amp_lib_test_write_cal_coeff(struct cs_dsp *dsp,
571 const struct cirrus_amp_cal_controls *controls,
572 const char *ctl_name, u32 val)
573 {
574 struct kunit *test = kunit_get_current_test();
575 struct cs_amp_lib_test_priv *priv = test->priv;
576 struct cs_amp_lib_test_ctl_write_entry *entry;
577
578 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name);
579 KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls);
580
581 entry = kunit_kzalloc(test, sizeof(*entry), GFP_KERNEL);
582 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, entry);
583
584 INIT_LIST_HEAD(&entry->list);
585 strscpy(entry->name, ctl_name, sizeof(entry->name));
586 entry->value = val;
587
588 list_add_tail(&entry->list, &priv->ctl_write_list);
589
590 return 0;
591 }
592
cs_amp_lib_test_write_cal_data_test(struct kunit * test)593 static void cs_amp_lib_test_write_cal_data_test(struct kunit *test)
594 {
595 struct cs_amp_lib_test_priv *priv = test->priv;
596 struct cs_amp_lib_test_ctl_write_entry *entry;
597 struct cirrus_amp_cal_data data;
598 struct cs_dsp *dsp;
599 int ret;
600
601 dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
602 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
603 dsp->dev = &priv->amp_pdev.dev;
604
605 get_random_bytes(&data, sizeof(data));
606
607 /* Redirect calls to write firmware controls */
608 kunit_activate_static_stub(test,
609 cs_amp_test_hooks->write_cal_coeff,
610 cs_amp_lib_test_write_cal_coeff);
611
612 ret = cs_amp_write_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data);
613 KUNIT_EXPECT_EQ(test, ret, 0);
614
615 kunit_deactivate_static_stub(test, cs_amp_test_hooks->write_cal_coeff);
616
617 KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 4);
618
619 /* Checksum control must be written last */
620 entry = list_last_entry(&priv->ctl_write_list, typeof(*entry), list);
621 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.checksum);
622 KUNIT_EXPECT_EQ(test, entry->value, data.calR + 1);
623 list_del(&entry->list);
624
625 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
626 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient);
627 KUNIT_EXPECT_EQ(test, entry->value, data.calAmbient);
628 list_del(&entry->list);
629
630 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
631 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.calr);
632 KUNIT_EXPECT_EQ(test, entry->value, data.calR);
633 list_del(&entry->list);
634
635 entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
636 KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.status);
637 KUNIT_EXPECT_EQ(test, entry->value, data.calStatus);
638 }
639
cs_amp_lib_test_dev_release(struct device * dev)640 static void cs_amp_lib_test_dev_release(struct device *dev)
641 {
642 }
643
cs_amp_lib_test_case_init(struct kunit * test)644 static int cs_amp_lib_test_case_init(struct kunit *test)
645 {
646 struct cs_amp_lib_test_priv *priv;
647 int ret;
648
649 KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks);
650
651 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
652 if (!priv)
653 return -ENOMEM;
654
655 test->priv = priv;
656 INIT_LIST_HEAD(&priv->ctl_write_list);
657
658 /* Create dummy amp driver dev */
659 priv->amp_pdev.name = "cs_amp_lib_test_drv";
660 priv->amp_pdev.id = -1;
661 priv->amp_pdev.dev.release = cs_amp_lib_test_dev_release;
662 ret = platform_device_register(&priv->amp_pdev);
663 KUNIT_ASSERT_GE_MSG(test, ret, 0, "Failed to register amp platform device\n");
664
665 return 0;
666 }
667
cs_amp_lib_test_case_exit(struct kunit * test)668 static void cs_amp_lib_test_case_exit(struct kunit *test)
669 {
670 struct cs_amp_lib_test_priv *priv = test->priv;
671
672 if (priv->amp_pdev.name)
673 platform_device_unregister(&priv->amp_pdev);
674 }
675
676 static const struct cs_amp_lib_test_param cs_amp_lib_test_get_cal_param_cases[] = {
677 { .num_amps = 2, .amp_index = 0 },
678 { .num_amps = 2, .amp_index = 1 },
679
680 { .num_amps = 3, .amp_index = 0 },
681 { .num_amps = 3, .amp_index = 1 },
682 { .num_amps = 3, .amp_index = 2 },
683
684 { .num_amps = 4, .amp_index = 0 },
685 { .num_amps = 4, .amp_index = 1 },
686 { .num_amps = 4, .amp_index = 2 },
687 { .num_amps = 4, .amp_index = 3 },
688
689 { .num_amps = 5, .amp_index = 0 },
690 { .num_amps = 5, .amp_index = 1 },
691 { .num_amps = 5, .amp_index = 2 },
692 { .num_amps = 5, .amp_index = 3 },
693 { .num_amps = 5, .amp_index = 4 },
694
695 { .num_amps = 6, .amp_index = 0 },
696 { .num_amps = 6, .amp_index = 1 },
697 { .num_amps = 6, .amp_index = 2 },
698 { .num_amps = 6, .amp_index = 3 },
699 { .num_amps = 6, .amp_index = 4 },
700 { .num_amps = 6, .amp_index = 5 },
701
702 { .num_amps = 8, .amp_index = 0 },
703 { .num_amps = 8, .amp_index = 1 },
704 { .num_amps = 8, .amp_index = 2 },
705 { .num_amps = 8, .amp_index = 3 },
706 { .num_amps = 8, .amp_index = 4 },
707 { .num_amps = 8, .amp_index = 5 },
708 { .num_amps = 8, .amp_index = 6 },
709 { .num_amps = 8, .amp_index = 7 },
710 };
711
cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param * param,char * desc)712 static void cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param *param,
713 char *desc)
714 {
715 snprintf(desc, KUNIT_PARAM_DESC_SIZE, "num_amps:%d amp_index:%d",
716 param->num_amps, param->amp_index);
717 }
718
719 KUNIT_ARRAY_PARAM(cs_amp_lib_test_get_cal, cs_amp_lib_test_get_cal_param_cases,
720 cs_amp_lib_test_get_cal_param_desc);
721
722 static struct kunit_case cs_amp_lib_test_cases[] = {
723 /* Tests for getting calibration data from EFI */
724 KUNIT_CASE(cs_amp_lib_test_cal_data_too_short_test),
725 KUNIT_CASE(cs_amp_lib_test_cal_count_too_big_test),
726 KUNIT_CASE(cs_amp_lib_test_no_cal_data_test),
727 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test),
728 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test),
729 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test),
730 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_no_index_test),
731 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_zero_not_matched_test),
732 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_uid_test,
733 cs_amp_lib_test_get_cal_gen_params),
734 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_unchecked_test,
735 cs_amp_lib_test_get_cal_gen_params),
736 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_checked_test,
737 cs_amp_lib_test_get_cal_gen_params),
738 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test,
739 cs_amp_lib_test_get_cal_gen_params),
740 KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test,
741 cs_amp_lib_test_get_cal_gen_params),
742 KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test),
743
744 /* Tests for writing calibration data */
745 KUNIT_CASE(cs_amp_lib_test_write_cal_data_test),
746
747 { } /* terminator */
748 };
749
750 static struct kunit_suite cs_amp_lib_test_suite = {
751 .name = "snd-soc-cs-amp-lib-test",
752 .init = cs_amp_lib_test_case_init,
753 .exit = cs_amp_lib_test_case_exit,
754 .test_cases = cs_amp_lib_test_cases,
755 };
756
757 kunit_test_suite(cs_amp_lib_test_suite);
758
759 MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB);
760 MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library");
761 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
762 MODULE_LICENSE("GPL");
763