Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license.  When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2018 Intel Corporation. All rights reserved.
0007 //
0008 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
0009 //
0010 // Generic firmware loader.
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     /* Don't request firmware again if firmware is already requested */
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     /* check for extended manifest */
0048     ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
0049     if (ext_man_size > 0) {
0050         /* when no error occurred, drop extended manifest */
0051         plat_data->fw_offset = ext_man_size;
0052     } else if (!ext_man_size) {
0053         /* No extended manifest, so nothing to skip during FW load */
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     /* make sure the FW header and file is valid */
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     /* prepare the DSP for FW loading */
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     /* parse and load firmware modules to DSP */
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     /* (re-)enable dsp dump */
0117     sdev->dbg_dump_printed = false;
0118     sdev->ipc_dump_printed = false;
0119 
0120     /* create read-only fw_version debugfs to store boot version info */
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         /* errors are only due to memory allocation, not debugfs */
0126         if (ret < 0) {
0127             dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
0128             return ret;
0129         }
0130     }
0131 
0132     /* perform pre fw run operations */
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     /* boot the firmware on the DSP */
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      * now wait for the DSP to boot. There are 3 possible outcomes:
0151      * 1. Boot wait times out indicating FW boot failure.
0152      * 2. FW boots successfully and fw_ready op succeeds.
0153      * 3. FW boots but fw_ready op fails.
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; /* FW boots but fw_ready op failed */
0167 
0168     /* perform post fw run operations */
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     /* TODO: support module unloading at runtime */
0188     release_firmware(sdev->pdata->fw);
0189     sdev->pdata->fw = NULL;
0190 }
0191 EXPORT_SYMBOL(snd_sof_fw_unload);