1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. |
4 | // |
5 | // Authors: Cezary Rojewski <cezary.rojewski@intel.com> |
6 | // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> |
7 | // |
8 | |
9 | #include <linux/firmware.h> |
10 | #include <linux/module.h> |
11 | #include <linux/slab.h> |
12 | #include <sound/hdaudio.h> |
13 | #include <sound/hdaudio_ext.h> |
14 | #include "avs.h" |
15 | #include "cldma.h" |
16 | #include "messages.h" |
17 | #include "registers.h" |
18 | #include "topology.h" |
19 | |
20 | #define AVS_ROM_STS_MASK 0xFF |
21 | #define AVS_ROM_INIT_DONE 0x1 |
22 | #define SKL_ROM_BASEFW_ENTERED 0xF |
23 | #define APL_ROM_FW_ENTERED 0x5 |
24 | #define AVS_ROM_INIT_POLLING_US 5 |
25 | #define SKL_ROM_INIT_TIMEOUT_US 1000000 |
26 | #define APL_ROM_INIT_TIMEOUT_US 300000 |
27 | #define APL_ROM_INIT_RETRIES 3 |
28 | |
29 | #define AVS_FW_INIT_POLLING_US 500 |
30 | #define AVS_FW_INIT_TIMEOUT_MS 3000 |
31 | #define AVS_FW_INIT_TIMEOUT_US (AVS_FW_INIT_TIMEOUT_MS * 1000) |
32 | |
33 | #define AVS_CLDMA_START_DELAY_MS 100 |
34 | |
35 | #define AVS_ROOT_DIR "intel/avs" |
36 | #define AVS_BASEFW_FILENAME "dsp_basefw.bin" |
37 | #define AVS_EXT_MANIFEST_MAGIC 0x31454124 |
38 | #define SKL_MANIFEST_MAGIC 0x00000006 |
39 | #define SKL_ADSPFW_OFFSET 0x284 |
40 | #define APL_MANIFEST_MAGIC 0x44504324 |
41 | #define APL_ADSPFW_OFFSET 0x2000 |
42 | |
43 | /* Occasionally, engineering (release candidate) firmware is provided for testing. */ |
44 | static bool debug_ignore_fw_version; |
45 | module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444); |
46 | MODULE_PARM_DESC(ignore_fw_version, "Ignore firmware version check 0=no (default), 1=yes" ); |
47 | |
48 | #define AVS_LIB_NAME_SIZE 8 |
49 | |
50 | struct avs_fw_manifest { |
51 | u32 id; |
52 | u32 len; |
53 | char name[AVS_LIB_NAME_SIZE]; |
54 | u32 preload_page_count; |
55 | u32 img_flags; |
56 | u32 feature_mask; |
57 | struct avs_fw_version version; |
58 | } __packed; |
59 | |
60 | struct avs_fw_ext_manifest { |
61 | u32 id; |
62 | u32 len; |
63 | u16 version_major; |
64 | u16 version_minor; |
65 | u32 entries; |
66 | } __packed; |
67 | |
68 | static int avs_fw_ext_manifest_strip(struct firmware *fw) |
69 | { |
70 | struct avs_fw_ext_manifest *man; |
71 | |
72 | if (fw->size < sizeof(*man)) |
73 | return -EINVAL; |
74 | |
75 | man = (struct avs_fw_ext_manifest *)fw->data; |
76 | if (man->id == AVS_EXT_MANIFEST_MAGIC) { |
77 | fw->data += man->len; |
78 | fw->size -= man->len; |
79 | } |
80 | |
81 | return 0; |
82 | } |
83 | |
84 | static int avs_fw_manifest_offset(struct firmware *fw) |
85 | { |
86 | /* Header type found in first DWORD of fw binary. */ |
87 | u32 magic = *(u32 *)fw->data; |
88 | |
89 | switch (magic) { |
90 | case SKL_MANIFEST_MAGIC: |
91 | return SKL_ADSPFW_OFFSET; |
92 | case APL_MANIFEST_MAGIC: |
93 | return APL_ADSPFW_OFFSET; |
94 | default: |
95 | return -EINVAL; |
96 | } |
97 | } |
98 | |
99 | static int avs_fw_manifest_strip_verify(struct avs_dev *adev, struct firmware *fw, |
100 | const struct avs_fw_version *min) |
101 | { |
102 | struct avs_fw_manifest *man; |
103 | int offset, ret; |
104 | |
105 | ret = avs_fw_ext_manifest_strip(fw); |
106 | if (ret) |
107 | return ret; |
108 | |
109 | offset = avs_fw_manifest_offset(fw); |
110 | if (offset < 0) |
111 | return offset; |
112 | |
113 | if (fw->size < offset + sizeof(*man)) |
114 | return -EINVAL; |
115 | if (!min) |
116 | return 0; |
117 | |
118 | man = (struct avs_fw_manifest *)(fw->data + offset); |
119 | if (man->version.major != min->major || |
120 | man->version.minor != min->minor || |
121 | man->version.hotfix != min->hotfix || |
122 | man->version.build < min->build) { |
123 | dev_warn(adev->dev, "bad FW version %d.%d.%d.%d, expected %d.%d.%d.%d or newer\n" , |
124 | man->version.major, man->version.minor, |
125 | man->version.hotfix, man->version.build, |
126 | min->major, min->minor, min->hotfix, min->build); |
127 | |
128 | if (!debug_ignore_fw_version) |
129 | return -EINVAL; |
130 | } |
131 | |
132 | return 0; |
133 | } |
134 | |
135 | int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw) |
136 | { |
137 | struct hda_cldma *cl = &code_loader; |
138 | unsigned int reg; |
139 | int ret; |
140 | |
141 | ret = avs_dsp_op(adev, power, AVS_MAIN_CORE_MASK, true); |
142 | if (ret < 0) |
143 | return ret; |
144 | |
145 | ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false); |
146 | if (ret < 0) |
147 | return ret; |
148 | |
149 | ret = hda_cldma_reset(cl); |
150 | if (ret < 0) { |
151 | dev_err(adev->dev, "cldma reset failed: %d\n" , ret); |
152 | return ret; |
153 | } |
154 | hda_cldma_setup(cl); |
155 | |
156 | ret = avs_dsp_op(adev, stall, AVS_MAIN_CORE_MASK, false); |
157 | if (ret < 0) |
158 | return ret; |
159 | |
160 | reinit_completion(x: &adev->fw_ready); |
161 | avs_dsp_op(adev, int_control, true); |
162 | |
163 | /* await ROM init */ |
164 | ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg, |
165 | (reg & AVS_ROM_INIT_DONE) == AVS_ROM_INIT_DONE, |
166 | AVS_ROM_INIT_POLLING_US, SKL_ROM_INIT_TIMEOUT_US); |
167 | if (ret < 0) { |
168 | dev_err(adev->dev, "rom init timeout: %d\n" , ret); |
169 | avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); |
170 | return ret; |
171 | } |
172 | |
173 | hda_cldma_set_data(cl, data: (void *)fw->data, size: fw->size); |
174 | /* transfer firmware */ |
175 | hda_cldma_transfer(cl, start_delay: 0); |
176 | ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg, |
177 | (reg & AVS_ROM_STS_MASK) == SKL_ROM_BASEFW_ENTERED, |
178 | AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US); |
179 | hda_cldma_stop(cl); |
180 | if (ret < 0) { |
181 | dev_err(adev->dev, "transfer fw failed: %d\n" , ret); |
182 | avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); |
183 | return ret; |
184 | } |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | int avs_cldma_load_library(struct avs_dev *adev, struct firmware *lib, u32 id) |
190 | { |
191 | struct hda_cldma *cl = &code_loader; |
192 | int ret; |
193 | |
194 | hda_cldma_set_data(cl, data: (void *)lib->data, size: lib->size); |
195 | /* transfer modules manifest */ |
196 | hda_cldma_transfer(cl, start_delay: msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS)); |
197 | |
198 | /* DMA id ignored as there is only ever one code-loader DMA */ |
199 | ret = avs_ipc_load_library(adev, dma_id: 0, lib_id: id); |
200 | hda_cldma_stop(cl); |
201 | |
202 | if (ret) { |
203 | ret = AVS_IPC_RET(ret); |
204 | dev_err(adev->dev, "transfer lib %d failed: %d\n" , id, ret); |
205 | } |
206 | |
207 | return ret; |
208 | } |
209 | |
210 | static int avs_cldma_load_module(struct avs_dev *adev, struct avs_module_entry *mentry) |
211 | { |
212 | struct hda_cldma *cl = &code_loader; |
213 | const struct firmware *mod; |
214 | char *mod_name; |
215 | int ret; |
216 | |
217 | mod_name = kasprintf(GFP_KERNEL, fmt: "%s/%s/dsp_mod_%pUL.bin" , AVS_ROOT_DIR, |
218 | adev->spec->name, mentry->uuid.b); |
219 | if (!mod_name) |
220 | return -ENOMEM; |
221 | |
222 | ret = avs_request_firmware(adev, fw_p: &mod, name: mod_name); |
223 | kfree(objp: mod_name); |
224 | if (ret < 0) |
225 | return ret; |
226 | |
227 | avs_hda_power_gating_enable(adev, enable: false); |
228 | avs_hda_clock_gating_enable(adev, enable: false); |
229 | avs_hda_l1sen_enable(adev, enable: false); |
230 | |
231 | hda_cldma_set_data(cl, data: (void *)mod->data, size: mod->size); |
232 | hda_cldma_transfer(cl, start_delay: msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS)); |
233 | ret = avs_ipc_load_modules(adev, mod_ids: &mentry->module_id, num_mod_ids: 1); |
234 | hda_cldma_stop(cl); |
235 | |
236 | avs_hda_l1sen_enable(adev, enable: true); |
237 | avs_hda_clock_gating_enable(adev, enable: true); |
238 | avs_hda_power_gating_enable(adev, enable: true); |
239 | |
240 | if (ret) { |
241 | dev_err(adev->dev, "load module %d failed: %d\n" , mentry->module_id, ret); |
242 | avs_release_last_firmware(adev); |
243 | return AVS_IPC_RET(ret); |
244 | } |
245 | |
246 | return 0; |
247 | } |
248 | |
249 | int avs_cldma_transfer_modules(struct avs_dev *adev, bool load, |
250 | struct avs_module_entry *mods, u32 num_mods) |
251 | { |
252 | u16 *mod_ids; |
253 | int ret, i; |
254 | |
255 | /* Either load to DSP or unload them to free space. */ |
256 | if (load) { |
257 | for (i = 0; i < num_mods; i++) { |
258 | ret = avs_cldma_load_module(adev, mentry: &mods[i]); |
259 | if (ret) |
260 | return ret; |
261 | } |
262 | |
263 | return 0; |
264 | } |
265 | |
266 | mod_ids = kcalloc(n: num_mods, size: sizeof(u16), GFP_KERNEL); |
267 | if (!mod_ids) |
268 | return -ENOMEM; |
269 | |
270 | for (i = 0; i < num_mods; i++) |
271 | mod_ids[i] = mods[i].module_id; |
272 | |
273 | ret = avs_ipc_unload_modules(adev, mod_ids, num_mod_ids: num_mods); |
274 | kfree(objp: mod_ids); |
275 | if (ret) |
276 | return AVS_IPC_RET(ret); |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static int |
282 | avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge) |
283 | { |
284 | const struct avs_spec *const spec = adev->spec; |
285 | unsigned int corex_mask, reg; |
286 | int ret; |
287 | |
288 | corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK; |
289 | |
290 | ret = avs_dsp_op(adev, power, spec->core_init_mask, true); |
291 | if (ret < 0) |
292 | goto err; |
293 | |
294 | ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false); |
295 | if (ret < 0) |
296 | goto err; |
297 | |
298 | reinit_completion(x: &adev->fw_ready); |
299 | avs_dsp_op(adev, int_control, true); |
300 | |
301 | /* set boot config */ |
302 | ret = avs_ipc_set_boot_config(adev, dma_id, purge); |
303 | if (ret) { |
304 | ret = AVS_IPC_RET(ret); |
305 | goto err; |
306 | } |
307 | |
308 | /* await ROM init */ |
309 | ret = snd_hdac_adsp_readq_poll(adev, spec->sram->rom_status_offset, reg, |
310 | (reg & 0xF) == AVS_ROM_INIT_DONE || |
311 | (reg & 0xF) == APL_ROM_FW_ENTERED, |
312 | AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US); |
313 | if (ret < 0) { |
314 | dev_err(adev->dev, "rom init timeout: %d\n" , ret); |
315 | goto err; |
316 | } |
317 | |
318 | /* power down non-main cores */ |
319 | if (corex_mask) { |
320 | ret = avs_dsp_op(adev, power, corex_mask, false); |
321 | if (ret < 0) |
322 | goto err; |
323 | } |
324 | |
325 | return 0; |
326 | |
327 | err: |
328 | avs_dsp_core_disable(adev, core_mask: spec->core_init_mask); |
329 | return ret; |
330 | } |
331 | |
332 | static int avs_imr_load_basefw(struct avs_dev *adev) |
333 | { |
334 | int ret; |
335 | |
336 | /* DMA id ignored when flashing from IMR as no transfer occurs. */ |
337 | ret = avs_hda_init_rom(adev, dma_id: 0, purge: false); |
338 | if (ret < 0) { |
339 | dev_err(adev->dev, "rom init failed: %d\n" , ret); |
340 | return ret; |
341 | } |
342 | |
343 | ret = wait_for_completion_timeout(x: &adev->fw_ready, |
344 | timeout: msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS)); |
345 | if (!ret) { |
346 | dev_err(adev->dev, "firmware ready timeout\n" ); |
347 | avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); |
348 | return -ETIMEDOUT; |
349 | } |
350 | |
351 | return 0; |
352 | } |
353 | |
354 | int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw) |
355 | { |
356 | struct snd_pcm_substream substream; |
357 | struct snd_dma_buffer dmab; |
358 | struct hdac_ext_stream *estream; |
359 | struct hdac_stream *hstream; |
360 | struct hdac_bus *bus = &adev->base.core; |
361 | unsigned int sdfmt, reg; |
362 | int ret, i; |
363 | |
364 | /* configure hda dma */ |
365 | memset(&substream, 0, sizeof(substream)); |
366 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; |
367 | estream = snd_hdac_ext_stream_assign(bus, substream: &substream, |
368 | type: HDAC_EXT_STREAM_TYPE_HOST); |
369 | if (!estream) |
370 | return -ENODEV; |
371 | hstream = hdac_stream(estream); |
372 | |
373 | /* code loading performed with default format */ |
374 | sdfmt = snd_hdac_stream_format(channels: 1, bits: 32, rate: 48000); |
375 | ret = snd_hdac_dsp_prepare(azx_dev: hstream, format: sdfmt, byte_size: fw->size, bufp: &dmab); |
376 | if (ret < 0) |
377 | goto release_stream; |
378 | |
379 | /* enable SPIB for hda stream */ |
380 | snd_hdac_stream_spbcap_enable(chip: bus, enable: true, index: hstream->index); |
381 | ret = snd_hdac_stream_set_spib(bus, azx_dev: hstream, value: fw->size); |
382 | if (ret) |
383 | goto cleanup_resources; |
384 | |
385 | memcpy(dmab.area, fw->data, fw->size); |
386 | |
387 | for (i = 0; i < APL_ROM_INIT_RETRIES; i++) { |
388 | unsigned int dma_id = hstream->stream_tag - 1; |
389 | |
390 | ret = avs_hda_init_rom(adev, dma_id, purge: true); |
391 | if (!ret) |
392 | break; |
393 | dev_info(adev->dev, "#%d rom init fail: %d\n" , i + 1, ret); |
394 | } |
395 | if (ret < 0) |
396 | goto cleanup_resources; |
397 | |
398 | /* transfer firmware */ |
399 | snd_hdac_dsp_trigger(azx_dev: hstream, start: true); |
400 | ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg, |
401 | (reg & AVS_ROM_STS_MASK) == APL_ROM_FW_ENTERED, |
402 | AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US); |
403 | snd_hdac_dsp_trigger(azx_dev: hstream, start: false); |
404 | if (ret < 0) { |
405 | dev_err(adev->dev, "transfer fw failed: %d\n" , ret); |
406 | avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); |
407 | } |
408 | |
409 | cleanup_resources: |
410 | /* disable SPIB for hda stream */ |
411 | snd_hdac_stream_spbcap_enable(chip: bus, enable: false, index: hstream->index); |
412 | snd_hdac_stream_set_spib(bus, azx_dev: hstream, value: 0); |
413 | |
414 | snd_hdac_dsp_cleanup(azx_dev: hstream, dmab: &dmab); |
415 | release_stream: |
416 | snd_hdac_ext_stream_release(hext_stream: estream, type: HDAC_EXT_STREAM_TYPE_HOST); |
417 | |
418 | return ret; |
419 | } |
420 | |
421 | int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id) |
422 | { |
423 | struct snd_pcm_substream substream; |
424 | struct snd_dma_buffer dmab; |
425 | struct hdac_ext_stream *estream; |
426 | struct hdac_stream *stream; |
427 | struct hdac_bus *bus = &adev->base.core; |
428 | unsigned int sdfmt; |
429 | int ret; |
430 | |
431 | /* configure hda dma */ |
432 | memset(&substream, 0, sizeof(substream)); |
433 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; |
434 | estream = snd_hdac_ext_stream_assign(bus, substream: &substream, |
435 | type: HDAC_EXT_STREAM_TYPE_HOST); |
436 | if (!estream) |
437 | return -ENODEV; |
438 | stream = hdac_stream(estream); |
439 | |
440 | /* code loading performed with default format */ |
441 | sdfmt = snd_hdac_stream_format(channels: 1, bits: 32, rate: 48000); |
442 | ret = snd_hdac_dsp_prepare(azx_dev: stream, format: sdfmt, byte_size: lib->size, bufp: &dmab); |
443 | if (ret < 0) |
444 | goto release_stream; |
445 | |
446 | /* enable SPIB for hda stream */ |
447 | snd_hdac_stream_spbcap_enable(chip: bus, enable: true, index: stream->index); |
448 | snd_hdac_stream_set_spib(bus, azx_dev: stream, value: lib->size); |
449 | |
450 | memcpy(dmab.area, lib->data, lib->size); |
451 | |
452 | /* transfer firmware */ |
453 | snd_hdac_dsp_trigger(azx_dev: stream, start: true); |
454 | ret = avs_ipc_load_library(adev, dma_id: stream->stream_tag - 1, lib_id: id); |
455 | snd_hdac_dsp_trigger(azx_dev: stream, start: false); |
456 | if (ret) { |
457 | dev_err(adev->dev, "transfer lib %d failed: %d\n" , id, ret); |
458 | ret = AVS_IPC_RET(ret); |
459 | } |
460 | |
461 | /* disable SPIB for hda stream */ |
462 | snd_hdac_stream_spbcap_enable(chip: bus, enable: false, index: stream->index); |
463 | snd_hdac_stream_set_spib(bus, azx_dev: stream, value: 0); |
464 | |
465 | snd_hdac_dsp_cleanup(azx_dev: stream, dmab: &dmab); |
466 | release_stream: |
467 | snd_hdac_ext_stream_release(hext_stream: estream, type: HDAC_EXT_STREAM_TYPE_HOST); |
468 | |
469 | return ret; |
470 | } |
471 | |
472 | int avs_hda_transfer_modules(struct avs_dev *adev, bool load, |
473 | struct avs_module_entry *mods, u32 num_mods) |
474 | { |
475 | /* |
476 | * All platforms without CLDMA are equipped with IMR, |
477 | * and thus the module transferring is offloaded to DSP. |
478 | */ |
479 | return 0; |
480 | } |
481 | |
482 | int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, u32 num_libs) |
483 | { |
484 | int start, id, i = 0; |
485 | int ret; |
486 | |
487 | /* Calculate the id to assign for the next lib. */ |
488 | for (id = 0; id < adev->fw_cfg.max_libs_count; id++) |
489 | if (adev->lib_names[id][0] == '\0') |
490 | break; |
491 | if (id + num_libs >= adev->fw_cfg.max_libs_count) |
492 | return -EINVAL; |
493 | |
494 | start = id; |
495 | while (i < num_libs) { |
496 | struct avs_fw_manifest *man; |
497 | const struct firmware *fw; |
498 | struct firmware stripped_fw; |
499 | char *filename; |
500 | int j; |
501 | |
502 | filename = kasprintf(GFP_KERNEL, fmt: "%s/%s/%s" , AVS_ROOT_DIR, adev->spec->name, |
503 | libs[i].name); |
504 | if (!filename) |
505 | return -ENOMEM; |
506 | |
507 | /* |
508 | * If any call after this one fails, requested firmware is not released with |
509 | * avs_release_last_firmware() as failing to load code results in need for reload |
510 | * of entire driver module. And then avs_release_firmwares() is in place already. |
511 | */ |
512 | ret = avs_request_firmware(adev, fw_p: &fw, name: filename); |
513 | kfree(objp: filename); |
514 | if (ret < 0) |
515 | return ret; |
516 | |
517 | stripped_fw = *fw; |
518 | ret = avs_fw_manifest_strip_verify(adev, fw: &stripped_fw, NULL); |
519 | if (ret) { |
520 | dev_err(adev->dev, "invalid library data: %d\n" , ret); |
521 | return ret; |
522 | } |
523 | |
524 | ret = avs_fw_manifest_offset(fw: &stripped_fw); |
525 | if (ret < 0) |
526 | return ret; |
527 | man = (struct avs_fw_manifest *)(stripped_fw.data + ret); |
528 | |
529 | /* Don't load anything that's already in DSP memory. */ |
530 | for (j = 0; j < id; j++) |
531 | if (!strncmp(adev->lib_names[j], man->name, AVS_LIB_NAME_SIZE)) |
532 | goto next_lib; |
533 | |
534 | ret = avs_dsp_op(adev, load_lib, &stripped_fw, id); |
535 | if (ret) |
536 | return ret; |
537 | |
538 | strncpy(p: adev->lib_names[id], q: man->name, AVS_LIB_NAME_SIZE); |
539 | id++; |
540 | next_lib: |
541 | i++; |
542 | } |
543 | |
544 | return start == id ? 1 : 0; |
545 | } |
546 | |
547 | static int avs_dsp_load_basefw(struct avs_dev *adev) |
548 | { |
549 | const struct avs_fw_version *min_req; |
550 | const struct avs_spec *const spec = adev->spec; |
551 | const struct firmware *fw; |
552 | struct firmware stripped_fw; |
553 | char *filename; |
554 | int ret; |
555 | |
556 | filename = kasprintf(GFP_KERNEL, fmt: "%s/%s/%s" , AVS_ROOT_DIR, spec->name, AVS_BASEFW_FILENAME); |
557 | if (!filename) |
558 | return -ENOMEM; |
559 | |
560 | ret = avs_request_firmware(adev, fw_p: &fw, name: filename); |
561 | kfree(objp: filename); |
562 | if (ret < 0) { |
563 | dev_err(adev->dev, "request firmware failed: %d\n" , ret); |
564 | return ret; |
565 | } |
566 | |
567 | stripped_fw = *fw; |
568 | min_req = &adev->spec->min_fw_version; |
569 | |
570 | ret = avs_fw_manifest_strip_verify(adev, fw: &stripped_fw, min: min_req); |
571 | if (ret < 0) { |
572 | dev_err(adev->dev, "invalid firmware data: %d\n" , ret); |
573 | goto release_fw; |
574 | } |
575 | |
576 | ret = avs_dsp_op(adev, load_basefw, &stripped_fw); |
577 | if (ret < 0) { |
578 | dev_err(adev->dev, "basefw load failed: %d\n" , ret); |
579 | goto release_fw; |
580 | } |
581 | |
582 | ret = wait_for_completion_timeout(x: &adev->fw_ready, |
583 | timeout: msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS)); |
584 | if (!ret) { |
585 | dev_err(adev->dev, "firmware ready timeout\n" ); |
586 | avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); |
587 | ret = -ETIMEDOUT; |
588 | goto release_fw; |
589 | } |
590 | |
591 | return 0; |
592 | |
593 | release_fw: |
594 | avs_release_last_firmware(adev); |
595 | return ret; |
596 | } |
597 | |
598 | int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) |
599 | { |
600 | struct avs_soc_component *acomp; |
601 | int ret, i; |
602 | |
603 | /* Forgo full boot if flash from IMR succeeds. */ |
604 | if (!purge && avs_platattr_test(adev, IMR)) { |
605 | ret = avs_imr_load_basefw(adev); |
606 | if (!ret) |
607 | return 0; |
608 | |
609 | dev_dbg(adev->dev, "firmware flash from imr failed: %d\n" , ret); |
610 | } |
611 | |
612 | /* Full boot, clear cached data except for basefw (slot 0). */ |
613 | for (i = 1; i < adev->fw_cfg.max_libs_count; i++) |
614 | memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE); |
615 | |
616 | avs_hda_power_gating_enable(adev, enable: false); |
617 | avs_hda_clock_gating_enable(adev, enable: false); |
618 | avs_hda_l1sen_enable(adev, enable: false); |
619 | |
620 | ret = avs_dsp_load_basefw(adev); |
621 | if (ret) |
622 | goto reenable_gating; |
623 | |
624 | mutex_lock(&adev->comp_list_mutex); |
625 | list_for_each_entry(acomp, &adev->comp_list, node) { |
626 | struct avs_tplg *tplg = acomp->tplg; |
627 | |
628 | ret = avs_dsp_load_libraries(adev, libs: tplg->libs, num_libs: tplg->num_libs); |
629 | if (ret < 0) |
630 | break; |
631 | } |
632 | mutex_unlock(lock: &adev->comp_list_mutex); |
633 | |
634 | reenable_gating: |
635 | avs_hda_l1sen_enable(adev, enable: true); |
636 | avs_hda_clock_gating_enable(adev, enable: true); |
637 | avs_hda_power_gating_enable(adev, enable: true); |
638 | |
639 | if (ret < 0) |
640 | return ret; |
641 | |
642 | /* With all code loaded, refresh module information. */ |
643 | ret = avs_module_info_init(adev, purge: true); |
644 | if (ret) { |
645 | dev_err(adev->dev, "init module info failed: %d\n" , ret); |
646 | return ret; |
647 | } |
648 | |
649 | return 0; |
650 | } |
651 | |
652 | int avs_dsp_first_boot_firmware(struct avs_dev *adev) |
653 | { |
654 | int ret, i; |
655 | |
656 | if (avs_platattr_test(adev, CLDMA)) { |
657 | ret = hda_cldma_init(cl: &code_loader, bus: &adev->base.core, |
658 | dsp_ba: adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE); |
659 | if (ret < 0) { |
660 | dev_err(adev->dev, "cldma init failed: %d\n" , ret); |
661 | return ret; |
662 | } |
663 | } |
664 | |
665 | ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); |
666 | if (ret < 0) |
667 | return ret; |
668 | |
669 | ret = avs_dsp_boot_firmware(adev, purge: true); |
670 | if (ret < 0) { |
671 | dev_err(adev->dev, "firmware boot failed: %d\n" , ret); |
672 | return ret; |
673 | } |
674 | |
675 | ret = avs_ipc_get_hw_config(adev, cfg: &adev->hw_cfg); |
676 | if (ret) { |
677 | dev_err(adev->dev, "get hw cfg failed: %d\n" , ret); |
678 | return AVS_IPC_RET(ret); |
679 | } |
680 | |
681 | ret = avs_ipc_get_fw_config(adev, cfg: &adev->fw_cfg); |
682 | if (ret) { |
683 | dev_err(adev->dev, "get fw cfg failed: %d\n" , ret); |
684 | return AVS_IPC_RET(ret); |
685 | } |
686 | |
687 | adev->core_refs = devm_kcalloc(dev: adev->dev, n: adev->hw_cfg.dsp_cores, |
688 | size: sizeof(*adev->core_refs), GFP_KERNEL); |
689 | adev->lib_names = devm_kcalloc(dev: adev->dev, n: adev->fw_cfg.max_libs_count, |
690 | size: sizeof(*adev->lib_names), GFP_KERNEL); |
691 | if (!adev->core_refs || !adev->lib_names) |
692 | return -ENOMEM; |
693 | |
694 | for (i = 0; i < adev->fw_cfg.max_libs_count; i++) { |
695 | adev->lib_names[i] = devm_kzalloc(dev: adev->dev, AVS_LIB_NAME_SIZE, GFP_KERNEL); |
696 | if (!adev->lib_names[i]) |
697 | return -ENOMEM; |
698 | } |
699 | |
700 | /* basefw always occupies slot 0 */ |
701 | strcpy(p: &adev->lib_names[0][0], q: "BASEFW" ); |
702 | |
703 | ida_init(ida: &adev->ppl_ida); |
704 | |
705 | return 0; |
706 | } |
707 | |