0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/firmware.h>
0014 #include "sof-priv.h"
0015 #include "ops.h"
0016
0017 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
0018 {
0019 struct snd_sof_pdata *plat_data = sdev->pdata;
0020 const char *fw_filename;
0021 ssize_t ext_man_size;
0022 int ret;
0023
0024
0025 if (plat_data->fw)
0026 return 0;
0027
0028 fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
0029 plat_data->fw_filename_prefix,
0030 plat_data->fw_filename);
0031 if (!fw_filename)
0032 return -ENOMEM;
0033
0034 ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
0035
0036 if (ret < 0) {
0037 dev_err(sdev->dev,
0038 "error: sof firmware file is missing, you might need to\n");
0039 dev_err(sdev->dev,
0040 " download it from https://github.com/thesofproject/sof-bin/\n");
0041 goto err;
0042 } else {
0043 dev_dbg(sdev->dev, "request_firmware %s successful\n",
0044 fw_filename);
0045 }
0046
0047
0048 ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
0049 if (ext_man_size > 0) {
0050
0051 plat_data->fw_offset = ext_man_size;
0052 } else if (!ext_man_size) {
0053
0054 dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
0055 } else {
0056 ret = ext_man_size;
0057 dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
0058 fw_filename, ret);
0059 }
0060
0061 err:
0062 kfree(fw_filename);
0063
0064 return ret;
0065 }
0066 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
0067
0068 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
0069 {
0070 struct snd_sof_pdata *plat_data = sdev->pdata;
0071 int ret;
0072
0073 ret = snd_sof_load_firmware_raw(sdev);
0074 if (ret < 0)
0075 return ret;
0076
0077
0078 ret = sdev->ipc->ops->fw_loader->validate(sdev);
0079 if (ret < 0) {
0080 dev_err(sdev->dev, "error: invalid FW header\n");
0081 goto error;
0082 }
0083
0084
0085 ret = snd_sof_dsp_reset(sdev);
0086 if (ret < 0) {
0087 dev_err(sdev->dev, "error: failed to reset DSP\n");
0088 goto error;
0089 }
0090
0091
0092 if (sdev->ipc->ops->fw_loader->load_fw_to_dsp) {
0093 ret = sdev->ipc->ops->fw_loader->load_fw_to_dsp(sdev);
0094 if (ret < 0) {
0095 dev_err(sdev->dev, "Firmware loading failed\n");
0096 goto error;
0097 }
0098 }
0099
0100 return 0;
0101
0102 error:
0103 release_firmware(plat_data->fw);
0104 plat_data->fw = NULL;
0105 return ret;
0106
0107 }
0108 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
0109
0110 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
0111 {
0112 int ret;
0113
0114 init_waitqueue_head(&sdev->boot_wait);
0115
0116
0117 sdev->dbg_dump_printed = false;
0118 sdev->ipc_dump_printed = false;
0119
0120
0121 if (sdev->first_boot) {
0122 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
0123 sizeof(sdev->fw_version),
0124 "fw_version", 0444);
0125
0126 if (ret < 0) {
0127 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
0128 return ret;
0129 }
0130 }
0131
0132
0133 ret = snd_sof_dsp_pre_fw_run(sdev);
0134 if (ret < 0) {
0135 dev_err(sdev->dev, "error: failed pre fw run op\n");
0136 return ret;
0137 }
0138
0139 dev_dbg(sdev->dev, "booting DSP firmware\n");
0140
0141
0142 ret = snd_sof_dsp_run(sdev);
0143 if (ret < 0) {
0144 snd_sof_dsp_dbg_dump(sdev, "Failed to start DSP",
0145 SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_PCI);
0146 return ret;
0147 }
0148
0149
0150
0151
0152
0153
0154
0155 ret = wait_event_timeout(sdev->boot_wait,
0156 sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
0157 msecs_to_jiffies(sdev->boot_timeout));
0158 if (ret == 0) {
0159 snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout",
0160 SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX |
0161 SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI);
0162 return -EIO;
0163 }
0164
0165 if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED)
0166 return -EIO;
0167
0168
0169 ret = snd_sof_dsp_post_fw_run(sdev);
0170 if (ret < 0) {
0171 dev_err(sdev->dev, "error: failed post fw run op\n");
0172 return ret;
0173 }
0174
0175 dev_dbg(sdev->dev, "firmware boot complete\n");
0176 sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
0177
0178 if (sdev->first_boot && sdev->ipc->ops->fw_loader->query_fw_configuration)
0179 return sdev->ipc->ops->fw_loader->query_fw_configuration(sdev);
0180
0181 return 0;
0182 }
0183 EXPORT_SYMBOL(snd_sof_run_firmware);
0184
0185 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
0186 {
0187
0188 release_firmware(sdev->pdata->fw);
0189 sdev->pdata->fw = NULL;
0190 }
0191 EXPORT_SYMBOL(snd_sof_fw_unload);