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