1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
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.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
10 // Generic firmware loader.
13 #include <linux/firmware.h>
17 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
19 struct snd_sof_pdata *plat_data = sdev->pdata;
20 const char *fw_filename;
24 /* Don't request firmware again if firmware is already requested */
28 fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
29 plat_data->fw_filename_prefix,
30 plat_data->fw_filename);
34 ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
38 "error: sof firmware file is missing, you might need to\n");
40 " download it from https://github.com/thesofproject/sof-bin/\n");
43 dev_dbg(sdev->dev, "request_firmware %s successful\n",
47 /* check for extended manifest */
48 ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
49 if (ext_man_size > 0) {
50 /* when no error occurred, drop extended manifest */
51 sdev->basefw.payload_offset = ext_man_size;
52 } else if (!ext_man_size) {
53 /* No extended manifest, so nothing to skip during FW load */
54 dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
57 dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
62 * Until the platform code is switched to use the new container the fw
63 * and payload offset must be set in plat_data
65 plat_data->fw = sdev->basefw.fw;
66 plat_data->fw_offset = sdev->basefw.payload_offset;
72 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
74 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
76 struct snd_sof_pdata *plat_data = sdev->pdata;
79 ret = snd_sof_load_firmware_raw(sdev);
83 /* make sure the FW header and file is valid */
84 ret = sdev->ipc->ops->fw_loader->validate(sdev);
86 dev_err(sdev->dev, "error: invalid FW header\n");
90 /* prepare the DSP for FW loading */
91 ret = snd_sof_dsp_reset(sdev);
93 dev_err(sdev->dev, "error: failed to reset DSP\n");
97 /* parse and load firmware modules to DSP */
98 if (sdev->ipc->ops->fw_loader->load_fw_to_dsp) {
99 ret = sdev->ipc->ops->fw_loader->load_fw_to_dsp(sdev);
101 dev_err(sdev->dev, "Firmware loading failed\n");
109 release_firmware(sdev->basefw.fw);
110 sdev->basefw.fw = NULL;
111 plat_data->fw = NULL;
115 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
117 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
121 init_waitqueue_head(&sdev->boot_wait);
123 /* (re-)enable dsp dump */
124 sdev->dbg_dump_printed = false;
125 sdev->ipc_dump_printed = false;
127 /* create read-only fw_version debugfs to store boot version info */
128 if (sdev->first_boot) {
129 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
130 sizeof(sdev->fw_version),
132 /* errors are only due to memory allocation, not debugfs */
134 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
139 /* perform pre fw run operations */
140 ret = snd_sof_dsp_pre_fw_run(sdev);
142 dev_err(sdev->dev, "error: failed pre fw run op\n");
146 dev_dbg(sdev->dev, "booting DSP firmware\n");
148 /* boot the firmware on the DSP */
149 ret = snd_sof_dsp_run(sdev);
151 snd_sof_dsp_dbg_dump(sdev, "Failed to start DSP",
152 SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_PCI);
157 * now wait for the DSP to boot. There are 3 possible outcomes:
158 * 1. Boot wait times out indicating FW boot failure.
159 * 2. FW boots successfully and fw_ready op succeeds.
160 * 3. FW boots but fw_ready op fails.
162 ret = wait_event_timeout(sdev->boot_wait,
163 sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
164 msecs_to_jiffies(sdev->boot_timeout));
166 snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout",
167 SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX |
168 SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI);
172 if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED)
173 return -EIO; /* FW boots but fw_ready op failed */
175 /* perform post fw run operations */
176 ret = snd_sof_dsp_post_fw_run(sdev);
178 dev_err(sdev->dev, "error: failed post fw run op\n");
182 dev_dbg(sdev->dev, "firmware boot complete\n");
183 sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
185 if (sdev->first_boot && sdev->ipc->ops->fw_loader->query_fw_configuration)
186 return sdev->ipc->ops->fw_loader->query_fw_configuration(sdev);
190 EXPORT_SYMBOL(snd_sof_run_firmware);
192 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
194 /* TODO: support module unloading at runtime */
195 release_firmware(sdev->basefw.fw);
196 sdev->basefw.fw = NULL;
197 sdev->pdata->fw = NULL;
199 EXPORT_SYMBOL(snd_sof_fw_unload);