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