xref: /linux/sound/soc/sof/intel/hda-loader.c (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018 Intel Corporation
7 //
8 // Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 //	    Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10 //	    Rander Wang <rander.wang@intel.com>
11 //          Keyon Jie <yang.jie@linux.intel.com>
12 //
13 
14 /*
15  * Hardware interface for HDA DSP code loader
16  */
17 
18 #include <linux/firmware.h>
19 #include <sound/hdaudio_ext.h>
20 #include <sound/hda_register.h>
21 #include <sound/sof.h>
22 #include <sound/sof/ipc4/header.h>
23 #include "ext_manifest.h"
24 #include "../ipc4-priv.h"
25 #include "../ops.h"
26 #include "../sof-priv.h"
27 #include "hda.h"
28 
29 static bool persistent_cl_buffer = true;
30 module_param(persistent_cl_buffer, bool, 0444);
31 MODULE_PARM_DESC(persistent_cl_buffer, "Persistent Code Loader DMA buffer "
32 		 "(default = Y, use N to force buffer re-allocation)");
33 
34 static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
35 {
36 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
37 	const struct sof_intel_dsp_desc *chip = hda->desc;
38 	int i;
39 
40 	/* DSP is powered up, set all SSPs to clock consumer/codec provider mode */
41 	for (i = 0; i < chip->ssp_count; i++) {
42 		snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
43 						 chip->ssp_base_offset
44 						 + i * SSP_DEV_MEM_SIZE
45 						 + SSP_SSC1_OFFSET,
46 						 SSP_SET_CBP_CFP,
47 						 SSP_SET_CBP_CFP);
48 	}
49 }
50 
51 struct hdac_ext_stream*
52 hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size,
53 	       struct snd_dma_buffer *dmab, bool persistent_buffer, int direction,
54 	       bool is_iccmax)
55 {
56 	return hda_data_stream_prepare(dev, format, size, dmab, persistent_buffer,
57 				       direction, is_iccmax, false);
58 }
59 EXPORT_SYMBOL_NS(hda_cl_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
60 
61 /*
62  * first boot sequence has some extra steps.
63  * power on all host managed cores and only unstall/run the boot core to boot the
64  * DSP then turn off all non boot cores (if any) is powered on.
65  */
66 int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
67 {
68 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
69 	const struct sof_intel_dsp_desc *chip = hda->desc;
70 	unsigned int status, target_status;
71 	u32 flags, ipc_hdr, j;
72 	unsigned long mask;
73 	char *dump_msg;
74 	int ret;
75 
76 	/* step 1: power up corex */
77 	ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
78 	if (ret < 0) {
79 		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
80 			dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
81 		goto err;
82 	}
83 
84 	hda_ssp_set_cbp_cfp(sdev);
85 
86 	/* step 2: Send ROM_CONTROL command (stream_tag is ignored for IMR boot) */
87 	ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL;
88 	if (!imr_boot)
89 		ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9);
90 
91 	snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
92 
93 	/* step 3: unset core 0 reset state & unstall/run core 0 */
94 	ret = hda_dsp_core_run(sdev, chip->init_core_mask);
95 	if (ret < 0) {
96 		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
97 			dev_err(sdev->dev,
98 				"error: dsp core start failed %d\n", ret);
99 		ret = -EIO;
100 		goto err;
101 	}
102 
103 	/* step 4: wait for IPC DONE bit from ROM */
104 	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
105 					    chip->ipc_ack, status,
106 					    ((status & chip->ipc_ack_mask)
107 						    == chip->ipc_ack_mask),
108 					    HDA_DSP_REG_POLL_INTERVAL_US,
109 					    HDA_DSP_INIT_TIMEOUT_US);
110 
111 	if (ret < 0) {
112 		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
113 			dev_err(sdev->dev,
114 				"error: %s: timeout for HIPCIE done\n",
115 				__func__);
116 		goto err;
117 	}
118 
119 	/* set DONE bit to clear the reply IPC message */
120 	snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
121 				       chip->ipc_ack,
122 				       chip->ipc_ack_mask,
123 				       chip->ipc_ack_mask);
124 
125 	/* step 5: power down cores that are no longer needed */
126 	ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask &
127 					   ~(chip->init_core_mask));
128 	if (ret < 0) {
129 		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
130 			dev_err(sdev->dev,
131 				"error: dsp core x power down failed\n");
132 		goto err;
133 	}
134 
135 	/* step 6: enable IPC interrupts */
136 	hda_dsp_ipc_int_enable(sdev);
137 
138 	/*
139 	 * step 7:
140 	 * - Cold/Full boot: wait for ROM init to proceed to download the firmware
141 	 * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR)
142 	 */
143 	if (imr_boot)
144 		target_status = FSR_STATE_FW_ENTERED;
145 	else
146 		target_status = FSR_STATE_INIT_DONE;
147 
148 	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
149 					chip->rom_status_reg, status,
150 					(FSR_TO_STATE_CODE(status) == target_status),
151 					HDA_DSP_REG_POLL_INTERVAL_US,
152 					chip->rom_init_timeout *
153 					USEC_PER_MSEC);
154 	if (!ret) {
155 		/* set enabled cores mask and increment ref count for cores in init_core_mask */
156 		sdev->enabled_cores_mask |= chip->init_core_mask;
157 		mask = sdev->enabled_cores_mask;
158 		for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES)
159 			sdev->dsp_core_ref_count[j]++;
160 		return 0;
161 	}
162 
163 	if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
164 		dev_err(sdev->dev,
165 			"%s: timeout with rom_status_reg (%#x) read\n",
166 			__func__, chip->rom_status_reg);
167 
168 err:
169 	flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
170 
171 	/* after max boot attempts make sure that the dump is printed */
172 	if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
173 		flags &= ~SOF_DBG_DUMP_OPTIONAL;
174 
175 	dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",
176 			     hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);
177 	snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);
178 	hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
179 
180 	kfree(dump_msg);
181 	return ret;
182 }
183 EXPORT_SYMBOL_NS(cl_dsp_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
184 
185 int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd)
186 {
187 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
188 	struct hdac_stream *hstream = &hext_stream->hstream;
189 	int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
190 	struct sof_intel_hda_stream *hda_stream;
191 
192 	/* code loader is special case that reuses stream ops */
193 	switch (cmd) {
194 	case SNDRV_PCM_TRIGGER_START:
195 		hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
196 					  hext_stream);
197 		reinit_completion(&hda_stream->ioc);
198 
199 		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
200 					1 << hstream->index,
201 					1 << hstream->index);
202 
203 		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
204 					sd_offset,
205 					SOF_HDA_SD_CTL_DMA_START |
206 					SOF_HDA_CL_DMA_SD_INT_MASK,
207 					SOF_HDA_SD_CTL_DMA_START |
208 					SOF_HDA_CL_DMA_SD_INT_MASK);
209 
210 		hstream->running = true;
211 		return 0;
212 	default:
213 		return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
214 	}
215 }
216 EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
217 
218 int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
219 		   bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax)
220 {
221 	return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream,
222 				       is_iccmax, false);
223 }
224 EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
225 
226 #define HDA_CL_DMA_IOC_TIMEOUT_MS 500
227 
228 int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
229 {
230 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
231 	const struct sof_intel_dsp_desc *chip = hda->desc;
232 	unsigned int reg;
233 	int ret, status;
234 
235 	dev_dbg(sdev->dev, "Code loader DMA starting\n");
236 
237 	ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
238 	if (ret < 0) {
239 		dev_err(sdev->dev, "error: DMA trigger start failed\n");
240 		return ret;
241 	}
242 
243 	dev_dbg(sdev->dev, "waiting for FW_ENTERED status\n");
244 
245 	status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
246 					chip->rom_status_reg, reg,
247 					(FSR_TO_STATE_CODE(reg) == FSR_STATE_FW_ENTERED),
248 					HDA_DSP_REG_POLL_INTERVAL_US,
249 					HDA_DSP_BASEFW_TIMEOUT_US);
250 
251 	/*
252 	 * even in case of errors we still need to stop the DMAs,
253 	 * but we return the initial error should the DMA stop also fail
254 	 */
255 
256 	if (status < 0) {
257 		dev_err(sdev->dev,
258 			"%s: timeout with rom_status_reg (%#x) read\n",
259 			__func__, chip->rom_status_reg);
260 	} else {
261 		dev_dbg(sdev->dev, "Code loader FW_ENTERED status\n");
262 	}
263 
264 	ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
265 	if (ret < 0) {
266 		dev_err(sdev->dev, "error: DMA trigger stop failed\n");
267 		if (!status)
268 			status = ret;
269 	} else {
270 		dev_dbg(sdev->dev, "Code loader DMA stopped\n");
271 	}
272 
273 	return status;
274 }
275 
276 int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
277 {
278 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
279 	struct hdac_ext_stream *iccmax_stream;
280 	int ret, ret1;
281 	u8 original_gb;
282 
283 	/* save the original LTRP guardband value */
284 	original_gb = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_LTRP) &
285 		HDA_VS_INTEL_LTRP_GB_MASK;
286 
287 	/*
288 	 * Prepare capture stream for ICCMAX. We do not need to store
289 	 * the data, so use a buffer of PAGE_SIZE for receiving.
290 	 */
291 	iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
292 				       &hda->iccmax_dmab, persistent_cl_buffer,
293 				       SNDRV_PCM_STREAM_CAPTURE, true);
294 	if (IS_ERR(iccmax_stream)) {
295 		dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
296 		return PTR_ERR(iccmax_stream);
297 	}
298 
299 	ret = hda_dsp_cl_boot_firmware(sdev);
300 
301 	/*
302 	 * Perform iccmax stream cleanup. This should be done even if firmware loading fails.
303 	 * If the cleanup also fails, we return the initial error
304 	 */
305 	ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab,
306 			      persistent_cl_buffer, iccmax_stream, true);
307 	if (ret1 < 0) {
308 		dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
309 
310 		/* set return value to indicate cleanup failure */
311 		if (!ret)
312 			ret = ret1;
313 	}
314 
315 	/* restore the original guardband value after FW boot */
316 	snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_LTRP,
317 			    HDA_VS_INTEL_LTRP_GB_MASK, original_gb);
318 
319 	return ret;
320 }
321 EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, "SND_SOC_SOF_INTEL_CNL");
322 
323 static int hda_dsp_boot_imr(struct snd_sof_dev *sdev)
324 {
325 	const struct sof_intel_dsp_desc *chip_info;
326 	int ret;
327 
328 	chip_info = get_chip_info(sdev->pdata);
329 	if (chip_info->cl_init)
330 		ret = chip_info->cl_init(sdev, 0, true);
331 	else
332 		ret = -EINVAL;
333 
334 	if (!ret)
335 		hda_sdw_process_wakeen(sdev);
336 
337 	return ret;
338 }
339 
340 int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
341 {
342 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
343 	struct snd_sof_pdata *plat_data = sdev->pdata;
344 	const struct sof_dev_desc *desc = plat_data->desc;
345 	const struct sof_intel_dsp_desc *chip_info;
346 	struct hdac_ext_stream *hext_stream;
347 	struct firmware stripped_firmware;
348 	int ret, ret1, i;
349 
350 	if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) {
351 		dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
352 		hda->boot_iteration = 0;
353 		ret = hda_dsp_boot_imr(sdev);
354 		if (!ret) {
355 			hda->booted_from_imr = true;
356 			return 0;
357 		}
358 
359 		dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n");
360 	}
361 
362 	hda->booted_from_imr = false;
363 
364 	chip_info = desc->chip_info;
365 
366 	if (sdev->basefw.fw->size <= sdev->basefw.payload_offset) {
367 		dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
368 		return -EINVAL;
369 	}
370 
371 	/* init for booting wait */
372 	init_waitqueue_head(&sdev->boot_wait);
373 
374 	/* prepare DMA for code loader stream */
375 	stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
376 	hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
377 				     stripped_firmware.size,
378 				     &hda->cl_dmab, persistent_cl_buffer,
379 				     SNDRV_PCM_STREAM_PLAYBACK, false);
380 	if (IS_ERR(hext_stream)) {
381 		dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
382 		return PTR_ERR(hext_stream);
383 	}
384 
385 	/*
386 	 * Copy the payload to the DMA buffer if it is temporary or if the
387 	 * buffer is  persistent but it does not have the basefw payload either
388 	 * because this is the first boot and the buffer needs to be initialized,
389 	 * or a library got loaded and it replaced the basefw.
390 	 */
391 	if (!persistent_cl_buffer || !hda->cl_dmab_contains_basefw) {
392 		stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
393 		memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size);
394 		hda->cl_dmab_contains_basefw = true;
395 	}
396 
397 	/* try ROM init a few times before giving up */
398 	for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) {
399 		dev_dbg(sdev->dev,
400 			"Attempting iteration %d of Core En/ROM load...\n", i);
401 
402 		hda->boot_iteration = i + 1;
403 		if (chip_info->cl_init)
404 			ret = chip_info->cl_init(sdev, hext_stream->hstream.stream_tag, false);
405 		else
406 			ret = -EINVAL;
407 
408 		/* don't retry anymore if successful */
409 		if (!ret)
410 			break;
411 	}
412 
413 	if (i == HDA_FW_BOOT_ATTEMPTS) {
414 		dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n",
415 			i, ret);
416 		goto cleanup;
417 	}
418 
419 	/*
420 	 * When a SoundWire link is in clock stop state, a Slave
421 	 * device may trigger in-band wakes for events such as jack
422 	 * insertion or acoustic event detection. This event will lead
423 	 * to a WAKEEN interrupt, handled by the PCI device and routed
424 	 * to PME if the PCI device is in D3. The resume function in
425 	 * audio PCI driver will be invoked by ACPI for PME event and
426 	 * initialize the device and process WAKEEN interrupt.
427 	 *
428 	 * The WAKEEN interrupt should be processed ASAP to prevent an
429 	 * interrupt flood, otherwise other interrupts, such IPC,
430 	 * cannot work normally.  The WAKEEN is handled after the ROM
431 	 * is initialized successfully, which ensures power rails are
432 	 * enabled before accessing the SoundWire SHIM registers
433 	 */
434 	if (!sdev->first_boot)
435 		hda_sdw_process_wakeen(sdev);
436 
437 	/*
438 	 * Set the boot_iteration to the last attempt, indicating that the
439 	 * DSP ROM has been initialized and from this point there will be no
440 	 * retry done to boot.
441 	 *
442 	 * Continue with code loading and firmware boot
443 	 */
444 	hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS;
445 	ret = hda_cl_copy_fw(sdev, hext_stream);
446 	if (!ret) {
447 		dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
448 		hda->skip_imr_boot = false;
449 	} else {
450 		snd_sof_dsp_dbg_dump(sdev, "Firmware download failed",
451 				     SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX);
452 		hda->skip_imr_boot = true;
453 	}
454 
455 cleanup:
456 	/*
457 	 * Perform codeloader stream cleanup.
458 	 * This should be done even if firmware loading fails.
459 	 * If the cleanup also fails, we return the initial error
460 	 */
461 	ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab,
462 			      persistent_cl_buffer, hext_stream, false);
463 	if (ret1 < 0) {
464 		dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
465 
466 		/* set return value to indicate cleanup failure */
467 		if (!ret)
468 			ret = ret1;
469 	}
470 
471 	/*
472 	 * return primary core id if both fw copy
473 	 * and stream clean up are successful
474 	 */
475 	if (!ret)
476 		return chip_info->init_core_mask;
477 
478 	/* disable DSP */
479 	hda_dsp_ctrl_ppcap_enable(sdev, false);
480 
481 	return ret;
482 }
483 EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, "SND_SOC_SOF_INTEL_HDA_COMMON");
484 
485 int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
486 			      struct sof_ipc4_fw_library *fw_lib, bool reload)
487 {
488 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
489 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
490 	struct hdac_ext_stream *hext_stream;
491 	struct firmware stripped_firmware;
492 	struct sof_ipc4_msg msg = {};
493 	int ret, ret1;
494 
495 	/*
496 	 * if IMR booting is enabled and libraries have been restored during fw
497 	 * boot, skip the loading
498 	 */
499 	if (reload && hda->booted_from_imr && ipc4_data->libraries_restored)
500 		return 0;
501 
502 	/* the fw_lib has been verified during loading, we can trust the validity here */
503 	stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset;
504 	stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;
505 
506 	/*
507 	 * force re-allocation of the cl_dmab if the preserved DMA buffer is
508 	 * smaller than what is needed for the library
509 	 */
510 	if (persistent_cl_buffer && stripped_firmware.size > hda->cl_dmab.bytes) {
511 		snd_dma_free_pages(&hda->cl_dmab);
512 		hda->cl_dmab.area = NULL;
513 		hda->cl_dmab.bytes = 0;
514 	}
515 
516 	/* prepare DMA for code loader stream */
517 	hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
518 				     stripped_firmware.size,
519 				     &hda->cl_dmab, persistent_cl_buffer,
520 				     SNDRV_PCM_STREAM_PLAYBACK, false);
521 	if (IS_ERR(hext_stream)) {
522 		dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
523 		return PTR_ERR(hext_stream);
524 	}
525 
526 	memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size);
527 	hda->cl_dmab_contains_basefw = false;
528 
529 	/*
530 	 * 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE
531 	 * Message includes the dma_id to be prepared for the library loading.
532 	 * If the firmware does not have support for the message, we will
533 	 * receive -EOPNOTSUPP. In this case we will use single step library
534 	 * loading and proceed to send the LOAD_LIBRARY message.
535 	 */
536 	msg.primary = hext_stream->hstream.stream_tag - 1;
537 	msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE);
538 	msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
539 	msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
540 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
541 	if (!ret) {
542 		int sd_offset = SOF_STREAM_SD_OFFSET(&hext_stream->hstream);
543 		unsigned int status;
544 
545 		/*
546 		 * Make sure that the FIFOS value is not 0 in SDxFIFOS register
547 		 * which indicates that the firmware set the GEN bit and we can
548 		 * continue to start the DMA
549 		 */
550 		ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR,
551 					sd_offset + SOF_HDA_ADSP_REG_SD_FIFOSIZE,
552 					status,
553 					status & SOF_HDA_SD_FIFOSIZE_FIFOS_MASK,
554 					HDA_DSP_REG_POLL_INTERVAL_US,
555 					HDA_DSP_BASEFW_TIMEOUT_US);
556 
557 		if (ret < 0)
558 			dev_warn(sdev->dev,
559 				 "%s: timeout waiting for FIFOS\n", __func__);
560 	} else if (ret != -EOPNOTSUPP) {
561 		goto cleanup;
562 	}
563 
564 	ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
565 	if (ret < 0) {
566 		dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
567 		goto cleanup;
568 	}
569 
570 	/*
571 	 * 2nd stage: LOAD_LIBRARY
572 	 * Message includes the dma_id and the lib_id, the dma_id must be
573 	 * identical to the one sent via LOAD_LIBRARY_PREPARE
574 	 */
575 	msg.primary &= ~SOF_IPC4_MSG_TYPE_MASK;
576 	msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY);
577 	msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id);
578 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
579 
580 	/* Stop the DMA channel */
581 	ret1 = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
582 	if (ret1 < 0) {
583 		dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);
584 		if (!ret)
585 			ret = ret1;
586 	}
587 
588 cleanup:
589 	/* clean up even in case of error and return the first error */
590 	ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer,
591 			      hext_stream, false);
592 	if (ret1 < 0) {
593 		dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
594 
595 		/* set return value to indicate cleanup failure */
596 		if (!ret)
597 			ret = ret1;
598 	}
599 
600 	return ret;
601 }
602 EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, "SND_SOC_SOF_INTEL_HDA_COMMON");
603 
604 int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
605 					 const struct sof_ext_man_elem_header *hdr)
606 {
607 	const struct sof_ext_man_cavs_config_data *config_data =
608 		container_of(hdr, struct sof_ext_man_cavs_config_data, hdr);
609 	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
610 	int i, elem_num;
611 
612 	/* calculate total number of config data elements */
613 	elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header))
614 		   / sizeof(struct sof_config_elem);
615 	if (elem_num <= 0) {
616 		dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num);
617 		return -EINVAL;
618 	}
619 
620 	for (i = 0; i < elem_num; i++)
621 		switch (config_data->elems[i].token) {
622 		case SOF_EXT_MAN_CAVS_CONFIG_EMPTY:
623 			/* skip empty token */
624 			break;
625 		case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO:
626 			hda->clk_config_lpro = config_data->elems[i].value;
627 			dev_dbg(sdev->dev, "FW clock config: %s\n",
628 				hda->clk_config_lpro ? "LPRO" : "HPRO");
629 			break;
630 		case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE:
631 		case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE:
632 			/* These elements are defined but not being used yet. No warn is required */
633 			break;
634 		default:
635 			dev_info(sdev->dev, "unsupported token type: %d\n",
636 				 config_data->elems[i].token);
637 		}
638 
639 	return 0;
640 }
641 EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, "SND_SOC_SOF_INTEL_HDA_COMMON");
642