xref: /linux/sound/soc/codecs/cs-amp-lib-test.c (revision 09b1704f5b02c18dd02b21343530463fcfc92c54)
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/test-bug.h>
11 #include <kunit/static_stub.h>
12 #include <linux/device/faux.h>
13 #include <linux/firmware/cirrus/cs_dsp.h>
14 #include <linux/firmware/cirrus/wmfw.h>
15 #include <linux/gpio/driver.h>
16 #include <linux/list.h>
17 #include <linux/module.h>
18 #include <linux/overflow.h>
19 #include <linux/platform_device.h>
20 #include <linux/random.h>
21 #include <sound/cs-amp-lib.h>
22 
23 #define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker"
24 #define LENOVO_SPEAKER_ID_EFI_GUID \
25 	EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82)
26 
27 #define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID"
28 #define HP_SPEAKER_ID_EFI_GUID \
29 	EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e)
30 
31 KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
32 			    struct faux_device *)
33 
34 struct cs_amp_lib_test_priv {
35 	struct faux_device *amp_dev;
36 
37 	struct cirrus_amp_efi_data *cal_blob;
38 	struct list_head ctl_write_list;
39 };
40 
41 struct cs_amp_lib_test_ctl_write_entry {
42 	struct list_head list;
43 	unsigned int value;
44 	char name[16];
45 };
46 
47 struct cs_amp_lib_test_param {
48 	int num_amps;
49 	int amp_index;
50 };
51 
52 static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps)
53 {
54 	struct cs_amp_lib_test_priv *priv = test->priv;
55 	unsigned int blob_size;
56 	int i;
57 
58 	blob_size = struct_size(priv->cal_blob, data, num_amps);
59 
60 	priv->cal_blob = kunit_kzalloc(test, blob_size, GFP_KERNEL);
61 	KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
62 
63 	priv->cal_blob->size = blob_size;
64 	priv->cal_blob->count = num_amps;
65 
66 	get_random_bytes(priv->cal_blob->data, flex_array_size(priv->cal_blob, data, num_amps));
67 
68 	/* Ensure all timestamps are non-zero to mark the entry valid. */
69 	for (i = 0; i < num_amps; i++)
70 		priv->cal_blob->data[i].calTime[0] |= 1;
71 
72 	/* Ensure that all UIDs are non-zero and unique. */
73 	for (i = 0; i < num_amps; i++)
74 		*(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1;
75 }
76 
77 static u64 cs_amp_lib_test_get_target_uid(struct kunit *test)
78 {
79 	struct cs_amp_lib_test_priv *priv = test->priv;
80 	const struct cs_amp_lib_test_param *param = test->param_value;
81 	u64 uid;
82 
83 	uid = priv->cal_blob->data[param->amp_index].calTarget[1];
84 	uid <<= 32;
85 	uid |= priv->cal_blob->data[param->amp_index].calTarget[0];
86 
87 	return uid;
88 }
89 
90 /* Redirected get_efi_variable to simulate that the file is too short */
91 static efi_status_t cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t *name,
92 							    efi_guid_t *guid,
93 							    unsigned long *size,
94 							    void *buf)
95 {
96 	if (!buf) {
97 		*size = offsetof(struct cirrus_amp_efi_data, data) - 1;
98 		return EFI_BUFFER_TOO_SMALL;
99 	}
100 
101 	return EFI_NOT_FOUND;
102 }
103 
104 /* Should return -EOVERFLOW if the header is larger than the EFI data */
105 static void cs_amp_lib_test_cal_data_too_short_test(struct kunit *test)
106 {
107 	struct cs_amp_lib_test_priv *priv = test->priv;
108 	struct cirrus_amp_cal_data result_data;
109 	int ret;
110 
111 	/* Redirect calls to get EFI data */
112 	kunit_activate_static_stub(test,
113 				   cs_amp_test_hooks->get_efi_variable,
114 				   cs_amp_lib_test_get_efi_variable_nohead);
115 
116 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
117 	KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
118 
119 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
120 }
121 
122 /* Redirected get_efi_variable to simulate that the count is larger than the file */
123 static efi_status_t cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t *name,
124 							       efi_guid_t *guid,
125 							       unsigned long *size,
126 							       void *buf)
127 {
128 	struct kunit *test = kunit_get_current_test();
129 	struct cs_amp_lib_test_priv *priv = test->priv;
130 
131 	if (!buf) {
132 		/*
133 		 * Return a size that is shorter than required for the
134 		 * declared number of entries.
135 		 */
136 		*size = priv->cal_blob->size - 1;
137 		return EFI_BUFFER_TOO_SMALL;
138 	}
139 
140 	memcpy(buf, priv->cal_blob, priv->cal_blob->size - 1);
141 
142 	return EFI_SUCCESS;
143 }
144 
145 /* Should return -EOVERFLOW if the entry count is larger than the EFI data */
146 static void cs_amp_lib_test_cal_count_too_big_test(struct kunit *test)
147 {
148 	struct cs_amp_lib_test_priv *priv = test->priv;
149 	struct cirrus_amp_cal_data result_data;
150 	int ret;
151 
152 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
153 
154 	/* Redirect calls to get EFI data */
155 	kunit_activate_static_stub(test,
156 				   cs_amp_test_hooks->get_efi_variable,
157 				   cs_amp_lib_test_get_efi_variable_bad_count);
158 
159 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
160 	KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
161 
162 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
163 }
164 
165 /* Redirected get_efi_variable to simulate that the variable not found */
166 static efi_status_t cs_amp_lib_test_get_efi_variable_none(efi_char16_t *name,
167 							  efi_guid_t *guid,
168 							  unsigned long *size,
169 							  void *buf)
170 {
171 	return EFI_NOT_FOUND;
172 }
173 
174 /* If EFI doesn't contain a cal data variable the result should be -ENOENT */
175 static void cs_amp_lib_test_no_cal_data_test(struct kunit *test)
176 {
177 	struct cs_amp_lib_test_priv *priv = test->priv;
178 	struct cirrus_amp_cal_data result_data;
179 	int ret;
180 
181 	/* Redirect calls to get EFI data */
182 	kunit_activate_static_stub(test,
183 				   cs_amp_test_hooks->get_efi_variable,
184 				   cs_amp_lib_test_get_efi_variable_none);
185 
186 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
187 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
188 
189 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
190 }
191 
192 /* Redirected get_efi_variable to simulate reading a cal data blob */
193 static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
194 						     efi_guid_t *guid,
195 						     unsigned long *size,
196 						     void *buf)
197 {
198 	static const efi_char16_t expected_name[] = L"CirrusSmartAmpCalibrationData";
199 	static const efi_guid_t expected_guid =
200 		EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
201 	struct kunit *test = kunit_get_current_test();
202 	struct cs_amp_lib_test_priv *priv = test->priv;
203 
204 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
205 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
206 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
207 
208 	if (memcmp(name, expected_name, sizeof(expected_name)) ||
209 	    efi_guidcmp(*guid, expected_guid))
210 		return -EFI_NOT_FOUND;
211 
212 	if (!buf) {
213 		*size = priv->cal_blob->size;
214 		return EFI_BUFFER_TOO_SMALL;
215 	}
216 
217 	KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
218 
219 	memcpy(buf, priv->cal_blob, priv->cal_blob->size);
220 
221 	return EFI_SUCCESS;
222 }
223 
224 static efi_status_t cs_amp_lib_test_get_hp_cal_efi_variable(efi_char16_t *name,
225 							    efi_guid_t *guid,
226 							    unsigned long *size,
227 							    void *buf)
228 {
229 	static const efi_char16_t expected_name[] = L"SmartAmpCalibrationData";
230 	static const efi_guid_t expected_guid =
231 		EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93);
232 	struct kunit *test = kunit_get_current_test();
233 	struct cs_amp_lib_test_priv *priv = test->priv;
234 
235 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
236 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
237 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
238 
239 	if (memcmp(name, expected_name, sizeof(expected_name)) ||
240 	    efi_guidcmp(*guid, expected_guid))
241 		return -EFI_NOT_FOUND;
242 
243 	if (!buf) {
244 		*size = priv->cal_blob->size;
245 		return EFI_BUFFER_TOO_SMALL;
246 	}
247 
248 	KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
249 
250 	memcpy(buf, priv->cal_blob, priv->cal_blob->size);
251 
252 	return EFI_SUCCESS;
253 }
254 
255 /* Get cal data block from HP variable. */
256 static void cs_amp_lib_test_get_hp_efi_cal(struct kunit *test)
257 {
258 	struct cs_amp_lib_test_priv *priv = test->priv;
259 	struct cirrus_amp_cal_data result_data;
260 	int ret;
261 
262 	cs_amp_lib_test_init_dummy_cal_blob(test, 2);
263 
264 	kunit_activate_static_stub(test,
265 				   cs_amp_test_hooks->get_efi_variable,
266 				   cs_amp_lib_test_get_hp_cal_efi_variable);
267 
268 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
269 	KUNIT_EXPECT_EQ(test, ret, 0);
270 
271 	KUNIT_EXPECT_MEMEQ(test, &result_data, &priv->cal_blob->data[0], sizeof(result_data));
272 }
273 
274 /* Get cal data block for a given amp, matched by target UID. */
275 static void cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit *test)
276 {
277 	struct cs_amp_lib_test_priv *priv = test->priv;
278 	const struct cs_amp_lib_test_param *param = test->param_value;
279 	struct cirrus_amp_cal_data result_data;
280 	u64 target_uid;
281 	int ret;
282 
283 	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
284 
285 	/* Redirect calls to get EFI data */
286 	kunit_activate_static_stub(test,
287 				   cs_amp_test_hooks->get_efi_variable,
288 				   cs_amp_lib_test_get_efi_variable);
289 
290 	target_uid = cs_amp_lib_test_get_target_uid(test);
291 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid, -1, &result_data);
292 	KUNIT_EXPECT_EQ(test, ret, 0);
293 
294 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
295 
296 	KUNIT_EXPECT_EQ(test, result_data.calTarget[0], target_uid & 0xFFFFFFFFULL);
297 	KUNIT_EXPECT_EQ(test, result_data.calTarget[1], target_uid >> 32);
298 	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
299 			      priv->cal_blob->data[param->amp_index].calTime[0]);
300 	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
301 			      priv->cal_blob->data[param->amp_index].calTime[1]);
302 	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
303 			      priv->cal_blob->data[param->amp_index].calAmbient);
304 	KUNIT_EXPECT_EQ(test, result_data.calStatus,
305 			      priv->cal_blob->data[param->amp_index].calStatus);
306 	KUNIT_EXPECT_EQ(test, result_data.calR,
307 			      priv->cal_blob->data[param->amp_index].calR);
308 }
309 
310 /* Get cal data block for a given amp index without checking target UID. */
311 static void cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit *test)
312 {
313 	struct cs_amp_lib_test_priv *priv = test->priv;
314 	const struct cs_amp_lib_test_param *param = test->param_value;
315 	struct cirrus_amp_cal_data result_data;
316 	int ret;
317 
318 	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
319 
320 	/* Redirect calls to get EFI data */
321 	kunit_activate_static_stub(test,
322 				   cs_amp_test_hooks->get_efi_variable,
323 				   cs_amp_lib_test_get_efi_variable);
324 
325 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0,
326 					      param->amp_index, &result_data);
327 	KUNIT_EXPECT_EQ(test, ret, 0);
328 
329 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
330 
331 	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
332 			      priv->cal_blob->data[param->amp_index].calTime[0]);
333 	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
334 			      priv->cal_blob->data[param->amp_index].calTime[1]);
335 	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
336 			      priv->cal_blob->data[param->amp_index].calAmbient);
337 	KUNIT_EXPECT_EQ(test, result_data.calStatus,
338 			      priv->cal_blob->data[param->amp_index].calStatus);
339 	KUNIT_EXPECT_EQ(test, result_data.calR,
340 			      priv->cal_blob->data[param->amp_index].calR);
341 }
342 
343 /* Get cal data block for a given amp index with checked target UID. */
344 static void cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit *test)
345 {
346 	struct cs_amp_lib_test_priv *priv = test->priv;
347 	const struct cs_amp_lib_test_param *param = test->param_value;
348 	struct cirrus_amp_cal_data result_data;
349 	u64 target_uid;
350 	int ret;
351 
352 	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
353 
354 	/* Redirect calls to get EFI data */
355 	kunit_activate_static_stub(test,
356 				   cs_amp_test_hooks->get_efi_variable,
357 				   cs_amp_lib_test_get_efi_variable);
358 
359 	target_uid = cs_amp_lib_test_get_target_uid(test);
360 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid,
361 					      param->amp_index, &result_data);
362 	KUNIT_EXPECT_EQ(test, ret, 0);
363 
364 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
365 
366 	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
367 			      priv->cal_blob->data[param->amp_index].calTime[0]);
368 	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
369 			      priv->cal_blob->data[param->amp_index].calTime[1]);
370 	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
371 			      priv->cal_blob->data[param->amp_index].calAmbient);
372 	KUNIT_EXPECT_EQ(test, result_data.calStatus,
373 			      priv->cal_blob->data[param->amp_index].calStatus);
374 	KUNIT_EXPECT_EQ(test, result_data.calR,
375 			      priv->cal_blob->data[param->amp_index].calR);
376 }
377 
378 /*
379  * Get cal data block for a given amp index with checked target UID.
380  * The UID does not match so the result should be -ENOENT.
381  */
382 static void cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit *test)
383 {
384 	struct cs_amp_lib_test_priv *priv = test->priv;
385 	const struct cs_amp_lib_test_param *param = test->param_value;
386 	struct cirrus_amp_cal_data result_data;
387 	u64 target_uid;
388 	int ret;
389 
390 	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
391 
392 	/* Redirect calls to get EFI data */
393 	kunit_activate_static_stub(test,
394 				   cs_amp_test_hooks->get_efi_variable,
395 				   cs_amp_lib_test_get_efi_variable);
396 
397 	/* Get a target UID that won't match the entry */
398 	target_uid = ~cs_amp_lib_test_get_target_uid(test);
399 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid,
400 					      param->amp_index, &result_data);
401 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
402 
403 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
404 }
405 
406 /*
407  * Get cal data block for a given amp, where the cal data does not
408  * specify calTarget so the lookup falls back to using the index
409  */
410 static void cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit *test)
411 {
412 	struct cs_amp_lib_test_priv *priv = test->priv;
413 	const struct cs_amp_lib_test_param *param = test->param_value;
414 	struct cirrus_amp_cal_data result_data;
415 	static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
416 	int i, ret;
417 
418 	cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
419 
420 	/* Make all the target values zero so they are ignored */
421 	for (i = 0; i < priv->cal_blob->count; ++i) {
422 		priv->cal_blob->data[i].calTarget[0] = 0;
423 		priv->cal_blob->data[i].calTarget[1] = 0;
424 	}
425 
426 	/* Redirect calls to get EFI data */
427 	kunit_activate_static_stub(test,
428 				   cs_amp_test_hooks->get_efi_variable,
429 				   cs_amp_lib_test_get_efi_variable);
430 
431 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid,
432 					      param->amp_index, &result_data);
433 	KUNIT_EXPECT_EQ(test, ret, 0);
434 
435 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
436 
437 	KUNIT_EXPECT_EQ(test, result_data.calTime[0],
438 			      priv->cal_blob->data[param->amp_index].calTime[0]);
439 	KUNIT_EXPECT_EQ(test, result_data.calTime[1],
440 			      priv->cal_blob->data[param->amp_index].calTime[1]);
441 	KUNIT_EXPECT_EQ(test, result_data.calAmbient,
442 			      priv->cal_blob->data[param->amp_index].calAmbient);
443 	KUNIT_EXPECT_EQ(test, result_data.calStatus,
444 			      priv->cal_blob->data[param->amp_index].calStatus);
445 	KUNIT_EXPECT_EQ(test, result_data.calR,
446 			      priv->cal_blob->data[param->amp_index].calR);
447 }
448 
449 /*
450  * If the target UID isn't present in the cal data, and there isn't an
451  * index to fall back do, the result should be -ENOENT.
452  */
453 static void cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit *test)
454 {
455 	struct cs_amp_lib_test_priv *priv = test->priv;
456 	struct cirrus_amp_cal_data result_data;
457 	static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
458 	int i, ret;
459 
460 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
461 
462 	/* Make all the target values != bad_target_uid */
463 	for (i = 0; i < priv->cal_blob->count; ++i) {
464 		priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
465 		priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
466 	}
467 
468 	/* Redirect calls to get EFI data */
469 	kunit_activate_static_stub(test,
470 				   cs_amp_test_hooks->get_efi_variable,
471 				   cs_amp_lib_test_get_efi_variable);
472 
473 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, -1,
474 					      &result_data);
475 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
476 
477 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
478 }
479 
480 /*
481  * If the target UID isn't present in the cal data, and the index is
482  * out of range, the result should be -ENOENT.
483  */
484 static void cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit *test)
485 {
486 	struct cs_amp_lib_test_priv *priv = test->priv;
487 	struct cirrus_amp_cal_data result_data;
488 	static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
489 	int i, ret;
490 
491 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
492 
493 	/* Make all the target values != bad_target_uid */
494 	for (i = 0; i < priv->cal_blob->count; ++i) {
495 		priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
496 		priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
497 	}
498 
499 	/* Redirect calls to get EFI data */
500 	kunit_activate_static_stub(test,
501 				   cs_amp_test_hooks->get_efi_variable,
502 				   cs_amp_lib_test_get_efi_variable);
503 
504 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, 99,
505 					      &result_data);
506 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
507 
508 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
509 }
510 
511 /*
512  * If the target UID isn't given, and the index is out of range, the
513  * result should be -ENOENT.
514  */
515 static void cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit *test)
516 {
517 	struct cs_amp_lib_test_priv *priv = test->priv;
518 	struct cirrus_amp_cal_data result_data;
519 	int ret;
520 
521 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
522 
523 	/* Redirect calls to get EFI data */
524 	kunit_activate_static_stub(test,
525 				   cs_amp_test_hooks->get_efi_variable,
526 				   cs_amp_lib_test_get_efi_variable);
527 
528 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 99, &result_data);
529 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
530 
531 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
532 }
533 
534 /* If neither the target UID or the index is given the result should be -ENOENT. */
535 static void cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit *test)
536 {
537 	struct cs_amp_lib_test_priv *priv = test->priv;
538 	struct cirrus_amp_cal_data result_data;
539 	int ret;
540 
541 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
542 
543 	/* Redirect calls to get EFI data */
544 	kunit_activate_static_stub(test,
545 				   cs_amp_test_hooks->get_efi_variable,
546 				   cs_amp_lib_test_get_efi_variable);
547 
548 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data);
549 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
550 
551 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
552 }
553 
554 /*
555  * If the UID is passed as 0 this must not match an entry with an
556  * unpopulated calTarget
557  */
558 static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test)
559 {
560 	struct cs_amp_lib_test_priv *priv = test->priv;
561 	struct cirrus_amp_cal_data result_data;
562 	int i, ret;
563 
564 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
565 
566 	/* Make all the target values zero so they are ignored */
567 	for (i = 0; i < priv->cal_blob->count; ++i) {
568 		priv->cal_blob->data[i].calTarget[0] = 0;
569 		priv->cal_blob->data[i].calTarget[1] = 0;
570 	}
571 
572 	/* Redirect calls to get EFI data */
573 	kunit_activate_static_stub(test,
574 				   cs_amp_test_hooks->get_efi_variable,
575 				   cs_amp_lib_test_get_efi_variable);
576 
577 	ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data);
578 	KUNIT_EXPECT_EQ(test, ret, -ENOENT);
579 
580 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
581 }
582 
583 /*
584  * If an entry has a timestamp of 0 it should be ignored even if it has
585  * a matching target UID.
586  */
587 static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test)
588 {
589 	struct cs_amp_lib_test_priv *priv = test->priv;
590 	struct cirrus_amp_cal_data result_data;
591 	u64 uid;
592 
593 	cs_amp_lib_test_init_dummy_cal_blob(test, 8);
594 
595 	/* Mark the 3rd entry invalid by zeroing calTime */
596 	priv->cal_blob->data[2].calTime[0] = 0;
597 	priv->cal_blob->data[2].calTime[1] = 0;
598 
599 	/* Get the UID value of the 3rd entry */
600 	uid = priv->cal_blob->data[2].calTarget[1];
601 	uid <<= 32;
602 	uid |= priv->cal_blob->data[2].calTarget[0];
603 
604 	/* Redirect calls to get EFI data */
605 	kunit_activate_static_stub(test,
606 				   cs_amp_test_hooks->get_efi_variable,
607 				   cs_amp_lib_test_get_efi_variable);
608 
609 	/* Lookup by UID should not find it */
610 	KUNIT_EXPECT_EQ(test,
611 			cs_amp_get_efi_calibration_data(&priv->amp_dev->dev,
612 							uid, -1,
613 							&result_data),
614 			-ENOENT);
615 
616 	/* Get by index should ignore it */
617 	KUNIT_EXPECT_EQ(test,
618 			cs_amp_get_efi_calibration_data(&priv->amp_dev->dev,
619 							0, 2,
620 							&result_data),
621 			-ENOENT);
622 
623 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable);
624 }
625 
626 static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = {
627 	.alg_id =	0x9f210,
628 	.mem_region =	WMFW_ADSP2_YM,
629 	.ambient =	"CAL_AMBIENT",
630 	.calr =		"CAL_R",
631 	.status =	"CAL_STATUS",
632 	.checksum =	"CAL_CHECKSUM",
633 };
634 
635 static int cs_amp_lib_test_write_cal_coeff(struct cs_dsp *dsp,
636 					   const struct cirrus_amp_cal_controls *controls,
637 					   const char *ctl_name, u32 val)
638 {
639 	struct kunit *test = kunit_get_current_test();
640 	struct cs_amp_lib_test_priv *priv = test->priv;
641 	struct cs_amp_lib_test_ctl_write_entry *entry;
642 
643 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name);
644 	KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls);
645 
646 	entry = kunit_kzalloc(test, sizeof(*entry), GFP_KERNEL);
647 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, entry);
648 
649 	INIT_LIST_HEAD(&entry->list);
650 	strscpy(entry->name, ctl_name, sizeof(entry->name));
651 	entry->value = val;
652 
653 	list_add_tail(&entry->list, &priv->ctl_write_list);
654 
655 	return 0;
656 }
657 
658 static void cs_amp_lib_test_write_cal_data_test(struct kunit *test)
659 {
660 	struct cs_amp_lib_test_priv *priv = test->priv;
661 	struct cs_amp_lib_test_ctl_write_entry *entry;
662 	struct cirrus_amp_cal_data data;
663 	struct cs_dsp *dsp;
664 	int ret;
665 
666 	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
667 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
668 	dsp->dev = &priv->amp_dev->dev;
669 
670 	get_random_bytes(&data, sizeof(data));
671 
672 	/* Redirect calls to write firmware controls */
673 	kunit_activate_static_stub(test,
674 				   cs_amp_test_hooks->write_cal_coeff,
675 				   cs_amp_lib_test_write_cal_coeff);
676 
677 	ret = cs_amp_write_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data);
678 	KUNIT_EXPECT_EQ(test, ret, 0);
679 
680 	kunit_deactivate_static_stub(test, cs_amp_test_hooks->write_cal_coeff);
681 
682 	KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 4);
683 
684 	/* Checksum control must be written last */
685 	entry = list_last_entry(&priv->ctl_write_list, typeof(*entry), list);
686 	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.checksum);
687 	KUNIT_EXPECT_EQ(test, entry->value, data.calR + 1);
688 	list_del(&entry->list);
689 
690 	entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
691 	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient);
692 	KUNIT_EXPECT_EQ(test, entry->value, data.calAmbient);
693 	list_del(&entry->list);
694 
695 	entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
696 	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.calr);
697 	KUNIT_EXPECT_EQ(test, entry->value, data.calR);
698 	list_del(&entry->list);
699 
700 	entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
701 	KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.status);
702 	KUNIT_EXPECT_EQ(test, entry->value, data.calStatus);
703 }
704 
705 static void cs_amp_lib_test_spkid_lenovo_not_present(struct kunit *test)
706 {
707 	struct cs_amp_lib_test_priv *priv = test->priv;
708 	struct device *dev = &priv->amp_dev->dev;
709 
710 	kunit_activate_static_stub(test,
711 				   cs_amp_test_hooks->get_efi_variable,
712 				   cs_amp_lib_test_get_efi_variable_none);
713 
714 	KUNIT_EXPECT_EQ(test, -ENOENT, cs_amp_get_vendor_spkid(dev));
715 }
716 
717 static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_d0(efi_char16_t *name,
718 							       efi_guid_t *guid,
719 							       unsigned long *size,
720 							       void *buf)
721 {
722 	struct kunit *test = kunit_get_current_test();
723 
724 	if (efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID) ||
725 	    memcmp(name, LENOVO_SPEAKER_ID_EFI_NAME, sizeof(LENOVO_SPEAKER_ID_EFI_NAME)))
726 		return EFI_NOT_FOUND;
727 
728 	KUNIT_ASSERT_EQ(test, *size, 1);
729 	*size = 1;
730 	*(u8 *)buf = 0xd0;
731 
732 	return EFI_SUCCESS;
733 }
734 
735 static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_d1(efi_char16_t *name,
736 							       efi_guid_t *guid,
737 							       unsigned long *size,
738 							       void *buf)
739 {
740 	struct kunit *test = kunit_get_current_test();
741 
742 	if (efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID) ||
743 	    memcmp(name, LENOVO_SPEAKER_ID_EFI_NAME, sizeof(LENOVO_SPEAKER_ID_EFI_NAME)))
744 		return EFI_NOT_FOUND;
745 
746 	KUNIT_ASSERT_EQ(test, *size, 1);
747 	*size = 1;
748 	*(u8 *)buf = 0xd1;
749 
750 	return EFI_SUCCESS;
751 }
752 
753 static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_00(efi_char16_t *name,
754 							       efi_guid_t *guid,
755 							       unsigned long *size,
756 							       void *buf)
757 {
758 	struct kunit *test = kunit_get_current_test();
759 
760 	KUNIT_ASSERT_EQ(test, 0, efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID));
761 	KUNIT_ASSERT_EQ(test, *size, 1);
762 	*size = 1;
763 	*(u8 *)buf = 0;
764 
765 	return EFI_SUCCESS;
766 }
767 
768 static void cs_amp_lib_test_spkid_lenovo_d0(struct kunit *test)
769 {
770 	struct cs_amp_lib_test_priv *priv = test->priv;
771 	struct device *dev = &priv->amp_dev->dev;
772 
773 	kunit_activate_static_stub(test,
774 				   cs_amp_test_hooks->get_efi_variable,
775 				   cs_amp_lib_test_get_efi_variable_lenovo_d0);
776 
777 	KUNIT_EXPECT_EQ(test, 0, cs_amp_get_vendor_spkid(dev));
778 }
779 
780 static void cs_amp_lib_test_spkid_lenovo_d1(struct kunit *test)
781 {
782 	struct cs_amp_lib_test_priv *priv = test->priv;
783 	struct device *dev = &priv->amp_dev->dev;
784 
785 	kunit_activate_static_stub(test,
786 				   cs_amp_test_hooks->get_efi_variable,
787 				   cs_amp_lib_test_get_efi_variable_lenovo_d1);
788 
789 	KUNIT_EXPECT_EQ(test, 1, cs_amp_get_vendor_spkid(dev));
790 }
791 
792 static void cs_amp_lib_test_spkid_lenovo_illegal(struct kunit *test)
793 {
794 	struct cs_amp_lib_test_priv *priv = test->priv;
795 	struct device *dev = &priv->amp_dev->dev;
796 
797 	kunit_activate_static_stub(test,
798 				   cs_amp_test_hooks->get_efi_variable,
799 				   cs_amp_lib_test_get_efi_variable_lenovo_00);
800 
801 	KUNIT_EXPECT_LT(test, cs_amp_get_vendor_spkid(dev), 0);
802 }
803 
804 static efi_status_t cs_amp_lib_test_get_efi_variable_buf_too_small(efi_char16_t *name,
805 								   efi_guid_t *guid,
806 								   unsigned long *size,
807 								   void *buf)
808 {
809 	return EFI_BUFFER_TOO_SMALL;
810 }
811 
812 static void cs_amp_lib_test_spkid_lenovo_oversize(struct kunit *test)
813 {
814 	struct cs_amp_lib_test_priv *priv = test->priv;
815 	struct device *dev = &priv->amp_dev->dev;
816 
817 	kunit_activate_static_stub(test,
818 				   cs_amp_test_hooks->get_efi_variable,
819 				   cs_amp_lib_test_get_efi_variable_buf_too_small);
820 
821 	KUNIT_EXPECT_LT(test, cs_amp_get_vendor_spkid(dev), 0);
822 }
823 
824 static efi_status_t cs_amp_lib_test_get_efi_variable_hp_30(efi_char16_t *name,
825 							   efi_guid_t *guid,
826 							   unsigned long *size,
827 							   void *buf)
828 {
829 	struct kunit *test = kunit_get_current_test();
830 
831 	if (efi_guidcmp(*guid, HP_SPEAKER_ID_EFI_GUID) ||
832 	    memcmp(name, HP_SPEAKER_ID_EFI_NAME, sizeof(HP_SPEAKER_ID_EFI_NAME)))
833 		return EFI_NOT_FOUND;
834 
835 	KUNIT_ASSERT_EQ(test, *size, 1);
836 	*size = 1;
837 	*(u8 *)buf = 0x30;
838 
839 	return EFI_SUCCESS;
840 }
841 
842 static efi_status_t cs_amp_lib_test_get_efi_variable_hp_31(efi_char16_t *name,
843 							   efi_guid_t *guid,
844 							   unsigned long *size,
845 							   void *buf)
846 {
847 	struct kunit *test = kunit_get_current_test();
848 
849 	if (efi_guidcmp(*guid, HP_SPEAKER_ID_EFI_GUID) ||
850 	    memcmp(name, HP_SPEAKER_ID_EFI_NAME, sizeof(HP_SPEAKER_ID_EFI_NAME)))
851 		return EFI_NOT_FOUND;
852 
853 	KUNIT_ASSERT_EQ(test, *size, 1);
854 	*size = 1;
855 	*(u8 *)buf = 0x31;
856 
857 	return EFI_SUCCESS;
858 }
859 
860 static void cs_amp_lib_test_spkid_hp_30(struct kunit *test)
861 {
862 	struct cs_amp_lib_test_priv *priv = test->priv;
863 	struct device *dev = &priv->amp_dev->dev;
864 
865 	kunit_activate_static_stub(test,
866 				   cs_amp_test_hooks->get_efi_variable,
867 				   cs_amp_lib_test_get_efi_variable_hp_30);
868 
869 	KUNIT_EXPECT_EQ(test, 0, cs_amp_get_vendor_spkid(dev));
870 }
871 
872 static void cs_amp_lib_test_spkid_hp_31(struct kunit *test)
873 {
874 	struct cs_amp_lib_test_priv *priv = test->priv;
875 	struct device *dev = &priv->amp_dev->dev;
876 
877 	kunit_activate_static_stub(test,
878 				   cs_amp_test_hooks->get_efi_variable,
879 				   cs_amp_lib_test_get_efi_variable_hp_31);
880 
881 	KUNIT_EXPECT_EQ(test, 1, cs_amp_get_vendor_spkid(dev));
882 }
883 
884 static int cs_amp_lib_test_case_init(struct kunit *test)
885 {
886 	struct cs_amp_lib_test_priv *priv;
887 
888 	KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks);
889 
890 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
891 	if (!priv)
892 		return -ENOMEM;
893 
894 	test->priv = priv;
895 	INIT_LIST_HEAD(&priv->ctl_write_list);
896 
897 	/* Create dummy amp driver dev */
898 	priv->amp_dev = faux_device_create("cs_amp_lib_test_drv", NULL, NULL);
899 	KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
900 	KUNIT_ASSERT_EQ(test, 0,
901 			kunit_add_action_or_reset(test,
902 						  faux_device_destroy_wrapper,
903 						  priv->amp_dev));
904 
905 	return 0;
906 }
907 
908 static const struct cs_amp_lib_test_param cs_amp_lib_test_get_cal_param_cases[] = {
909 	{ .num_amps = 2, .amp_index = 0 },
910 	{ .num_amps = 2, .amp_index = 1 },
911 
912 	{ .num_amps = 3, .amp_index = 0 },
913 	{ .num_amps = 3, .amp_index = 1 },
914 	{ .num_amps = 3, .amp_index = 2 },
915 
916 	{ .num_amps = 4, .amp_index = 0 },
917 	{ .num_amps = 4, .amp_index = 1 },
918 	{ .num_amps = 4, .amp_index = 2 },
919 	{ .num_amps = 4, .amp_index = 3 },
920 
921 	{ .num_amps = 5, .amp_index = 0 },
922 	{ .num_amps = 5, .amp_index = 1 },
923 	{ .num_amps = 5, .amp_index = 2 },
924 	{ .num_amps = 5, .amp_index = 3 },
925 	{ .num_amps = 5, .amp_index = 4 },
926 
927 	{ .num_amps = 6, .amp_index = 0 },
928 	{ .num_amps = 6, .amp_index = 1 },
929 	{ .num_amps = 6, .amp_index = 2 },
930 	{ .num_amps = 6, .amp_index = 3 },
931 	{ .num_amps = 6, .amp_index = 4 },
932 	{ .num_amps = 6, .amp_index = 5 },
933 
934 	{ .num_amps = 8, .amp_index = 0 },
935 	{ .num_amps = 8, .amp_index = 1 },
936 	{ .num_amps = 8, .amp_index = 2 },
937 	{ .num_amps = 8, .amp_index = 3 },
938 	{ .num_amps = 8, .amp_index = 4 },
939 	{ .num_amps = 8, .amp_index = 5 },
940 	{ .num_amps = 8, .amp_index = 6 },
941 	{ .num_amps = 8, .amp_index = 7 },
942 };
943 
944 static void cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param *param,
945 					       char *desc)
946 {
947 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "num_amps:%d amp_index:%d",
948 		 param->num_amps, param->amp_index);
949 }
950 
951 KUNIT_ARRAY_PARAM(cs_amp_lib_test_get_cal, cs_amp_lib_test_get_cal_param_cases,
952 		  cs_amp_lib_test_get_cal_param_desc);
953 
954 static struct kunit_case cs_amp_lib_test_cases[] = {
955 	/* Tests for getting calibration data from EFI */
956 	KUNIT_CASE(cs_amp_lib_test_cal_data_too_short_test),
957 	KUNIT_CASE(cs_amp_lib_test_cal_count_too_big_test),
958 	KUNIT_CASE(cs_amp_lib_test_no_cal_data_test),
959 	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test),
960 	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test),
961 	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test),
962 	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_no_index_test),
963 	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_zero_not_matched_test),
964 	KUNIT_CASE(cs_amp_lib_test_get_hp_efi_cal),
965 	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_uid_test,
966 			 cs_amp_lib_test_get_cal_gen_params),
967 	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_unchecked_test,
968 			 cs_amp_lib_test_get_cal_gen_params),
969 	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_checked_test,
970 			 cs_amp_lib_test_get_cal_gen_params),
971 	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test,
972 			 cs_amp_lib_test_get_cal_gen_params),
973 	KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test,
974 			 cs_amp_lib_test_get_cal_gen_params),
975 	KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test),
976 
977 	/* Tests for writing calibration data */
978 	KUNIT_CASE(cs_amp_lib_test_write_cal_data_test),
979 
980 	/* Test cases for speaker ID */
981 	KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_not_present),
982 	KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d0),
983 	KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d1),
984 	KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_illegal),
985 	KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_oversize),
986 	KUNIT_CASE(cs_amp_lib_test_spkid_hp_30),
987 	KUNIT_CASE(cs_amp_lib_test_spkid_hp_31),
988 
989 	{ } /* terminator */
990 };
991 
992 static struct kunit_suite cs_amp_lib_test_suite = {
993 	.name = "snd-soc-cs-amp-lib-test",
994 	.init = cs_amp_lib_test_case_init,
995 	.test_cases = cs_amp_lib_test_cases,
996 };
997 
998 kunit_test_suite(cs_amp_lib_test_suite);
999 
1000 MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
1001 MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library");
1002 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
1003 MODULE_LICENSE("GPL");
1004