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