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