^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // This file is provided under a dual BSD/GPLv2 license. When using or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // redistributing this file, you may do so under either license.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // Copyright(c) 2018 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) // Generic firmware loader.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/sof.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/sof/ext_manifest.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static int get_ext_windows(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) const struct sof_ipc_ext_data_hdr *ext_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) const struct sof_ipc_window *w =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) if (sdev->info_window) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) dev_err(sdev->dev, "error: mismatch between window descriptor from extended manifest and mailbox");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* keep a local copy of the data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!sdev->info_window)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int get_cc_info(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const struct sof_ipc_ext_data_hdr *ext_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) const struct sof_ipc_cc_version *cc =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (sdev->cc_version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) dev_err(sdev->dev, "error: receive diverged cc_version descriptions");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) cc->name, cc->major, cc->minor, cc->micro, cc->desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) cc->optim);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* create read-only cc_version debugfs to store compiler version info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* use local copy of the cc_version to prevent data corruption */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (sdev->first_boot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (!sdev->cc_version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) cc->ext_hdr.hdr.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) "cc_version", 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* errors are only due to memory allocation, not debugfs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* parse the extended FW boot data structures from FW boot message */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct sof_ipc_ext_data_hdr *ext_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void *ext_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!ext_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* get first header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) sizeof(*ext_hdr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) ext_hdr = ext_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* read in ext structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ext_hdr->hdr.size - sizeof(*ext_hdr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) ext_hdr->type, ext_hdr->hdr.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* process structure data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) switch (ext_hdr->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) case SOF_IPC_EXT_WINDOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) ret = get_ext_windows(sdev, ext_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case SOF_IPC_EXT_CC_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ret = get_cc_info(sdev, ext_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) case SOF_IPC_EXT_UNUSED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) case SOF_IPC_EXT_PROBE_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) case SOF_IPC_EXT_USER_ABI_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* They are supported but we don't do anything here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ext_hdr->type, ext_hdr->hdr.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ext_hdr->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* move to next header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) offset += ext_hdr->hdr.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) sizeof(*ext_hdr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ext_hdr = ext_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) kfree(ext_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int ext_man_get_fw_version(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) const struct sof_ext_man_elem_header *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) const struct sof_ext_man_fw_version *v =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) container_of(hdr, struct sof_ext_man_fw_version, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) memcpy(&sdev->fw_ready.version, &v->version, sizeof(v->version));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) sdev->fw_ready.flags = v->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* log ABI versions and check FW compatibility */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return snd_sof_ipc_valid(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int ext_man_get_windows(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) const struct sof_ext_man_elem_header *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) const struct sof_ext_man_window *w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) w = container_of(hdr, struct sof_ext_man_window, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return get_ext_windows(sdev, &w->ipc_window.ext_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int ext_man_get_cc_info(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) const struct sof_ext_man_elem_header *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) const struct sof_ext_man_cc_version *cc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) cc = container_of(hdr, struct sof_ext_man_cc_version, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return get_cc_info(sdev, &cc->cc_version.ext_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) const struct sof_ext_man_elem_header *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) const struct ext_man_dbg_abi *dbg_abi =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) container_of(hdr, struct ext_man_dbg_abi, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (sdev->first_boot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) dev_dbg(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) "Firmware: DBG_ABI %d:%d:%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) SOF_ABI_VERSION_MAJOR(dbg_abi->dbg_abi.abi_dbg_version),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) SOF_ABI_VERSION_MINOR(dbg_abi->dbg_abi.abi_dbg_version),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) SOF_ABI_VERSION_PATCH(dbg_abi->dbg_abi.abi_dbg_version));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) const struct sof_ext_man_header *head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) head = (struct sof_ext_man_header *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * assert fw size is big enough to contain extended manifest header,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * it prevents from reading unallocated memory from `head` in following
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * step.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (fw->size < sizeof(*head))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * When fw points to extended manifest,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * then first u32 must be equal SOF_EXT_MAN_MAGIC_NUMBER.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return head->full_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /* otherwise given fw don't have an extended manifest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* parse extended FW manifest data structures */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) const struct sof_ext_man_elem_header *elem_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) const struct sof_ext_man_header *head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) ssize_t ext_man_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) ssize_t remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) uintptr_t iptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) head = (struct sof_ext_man_header *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) remaining = head->full_size - head->header_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ext_man_size = snd_sof_ext_man_size(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /* Assert firmware starts with extended manifest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (ext_man_size <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return ext_man_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* incompatible version */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (SOF_EXT_MAN_VERSION_INCOMPATIBLE(SOF_EXT_MAN_VERSION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) head->header_version)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) dev_err(sdev->dev, "error: extended manifest version 0x%X differ from used 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) head->header_version, SOF_EXT_MAN_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* get first extended manifest element header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) iptr = (uintptr_t)fw->data + head->header_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) while (remaining > sizeof(*elem_hdr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) elem_hdr = (struct sof_ext_man_elem_header *)iptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) dev_dbg(sdev->dev, "found sof_ext_man header type %d size 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) elem_hdr->type, elem_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (elem_hdr->size < sizeof(*elem_hdr) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) elem_hdr->size > remaining) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) dev_err(sdev->dev, "error: invalid sof_ext_man header size, type %d size 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) elem_hdr->type, elem_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* process structure data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) switch (elem_hdr->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) case SOF_EXT_MAN_ELEM_FW_VERSION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) ret = ext_man_get_fw_version(sdev, elem_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) case SOF_EXT_MAN_ELEM_WINDOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) ret = ext_man_get_windows(sdev, elem_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case SOF_EXT_MAN_ELEM_CC_VERSION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ret = ext_man_get_cc_info(sdev, elem_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) case SOF_EXT_MAN_ELEM_DBG_ABI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) ret = ext_man_get_dbg_abi_info(sdev, elem_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) elem_hdr->type, elem_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) dev_err(sdev->dev, "error: failed to parse sof_ext_man header type %d size 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) elem_hdr->type, elem_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) remaining -= elem_hdr->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) iptr += elem_hdr->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (remaining) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) dev_err(sdev->dev, "error: sof_ext_man header is inconsistent\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return ext_man_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * IPC Firmware ready.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static void sof_get_windows(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct sof_ipc_window_elem *elem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) u32 outbox_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) u32 stream_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) u32 inbox_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) u32 outbox_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) u32 stream_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) u32 inbox_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) u32 debug_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) u32 debug_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) int window_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) int bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (!sdev->info_window) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) dev_err(sdev->dev, "error: have no window info\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (bar < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) dev_err(sdev->dev, "error: have no bar mapping\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) for (i = 0; i < sdev->info_window->num_windows; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) elem = &sdev->info_window->window[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (window_offset < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) dev_warn(sdev->dev, "warn: no offset for window %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) elem->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) switch (elem->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) case SOF_IPC_REGION_UPBOX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) inbox_offset = window_offset + elem->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) inbox_size = elem->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) inbox_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) elem->size, "inbox",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) case SOF_IPC_REGION_DOWNBOX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) outbox_offset = window_offset + elem->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) outbox_size = elem->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) outbox_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) elem->size, "outbox",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) case SOF_IPC_REGION_TRACE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) window_offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) elem->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) elem->size, "etrace",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) case SOF_IPC_REGION_DEBUG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) debug_offset = window_offset + elem->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) debug_size = elem->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) window_offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) elem->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) elem->size, "debug",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) case SOF_IPC_REGION_STREAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) stream_offset = window_offset + elem->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) stream_size = elem->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) stream_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) elem->size, "stream",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) case SOF_IPC_REGION_REGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) window_offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) elem->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) elem->size, "regs",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) case SOF_IPC_REGION_EXCEPTION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) sdev->dsp_oops_offset = window_offset + elem->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) snd_sof_debugfs_io_item(sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) sdev->bar[bar] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) window_offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) elem->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) elem->size, "exception",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) SOF_DEBUGFS_ACCESS_D0_ONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) dev_err(sdev->dev, "error: get illegal window info\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (outbox_size == 0 || inbox_size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) dev_err(sdev->dev, "error: get illegal mailbox window\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) outbox_offset, outbox_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) sdev->stream_box.offset = stream_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) sdev->stream_box.size = stream_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) sdev->debug_box.offset = debug_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) sdev->debug_box.size = debug_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) inbox_offset, inbox_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) outbox_offset, outbox_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) stream_offset, stream_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) debug_offset, debug_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /* check for ABI compatibility and create memory windows on first boot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) int bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* mailbox must be on 4k boundary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) offset = snd_sof_dsp_get_mailbox_offset(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (offset < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) dev_err(sdev->dev, "error: have no mailbox offset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (bar < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) dev_err(sdev->dev, "error: have no bar mapping\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) msg_id, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) /* no need to re-check version/ABI for subsequent boots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (!sdev->first_boot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* copy data from the DSP FW ready offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* make sure ABI version is compatible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) ret = snd_sof_ipc_valid(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) /* now check for extended data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) snd_sof_fw_parse_ext_data(sdev, bar, offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) sizeof(struct sof_ipc_fw_ready));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) sof_get_windows(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) EXPORT_SYMBOL(sof_fw_ready);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /* generic module parser for mmaped DSPs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct snd_sof_mod_hdr *module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct snd_sof_blk_hdr *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int count, bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) u32 offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) size_t remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) module->size, module->num_blocks, module->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) /* module->size doesn't include header size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) remaining = module->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) for (count = 0; count < module->num_blocks; count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) /* check for wrap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (remaining < sizeof(*block)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) dev_err(sdev->dev, "error: not enough data remaining\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* minus header size of block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) remaining -= sizeof(*block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (block->size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dev_warn(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "warning: block %d size zero\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) block->type, block->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) switch (block->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) case SOF_FW_BLK_TYPE_RSRVD0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) continue; /* not handled atm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) case SOF_FW_BLK_TYPE_IRAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) case SOF_FW_BLK_TYPE_DRAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) case SOF_FW_BLK_TYPE_SRAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) offset = block->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) bar = snd_sof_dsp_get_bar_index(sdev, block->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (bar < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) dev_err(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) "error: no BAR mapping for block type 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) block->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) return bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) block->type, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) dev_dbg(sdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) "block %d type 0x%x size 0x%x ==> offset 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) count, block->type, block->size, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) /* checking block->size to avoid unaligned access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (block->size % sizeof(u32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) dev_err(sdev->dev, "error: invalid block size 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) block->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) snd_sof_dsp_block_write(sdev, bar, offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) block + 1, block->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (remaining < block->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) dev_err(sdev->dev, "error: not enough data remaining\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) /* minus body size of block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) remaining -= block->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* next block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) + block->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) size_t fw_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct snd_sof_fw_header *header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) size_t fw_size = fw->size - fw_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (fw->size <= fw_offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /* Read the header information from the data pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /* verify FW sig */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) dev_err(sdev->dev, "error: invalid firmware signature\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) /* check size is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (fw_size != header->file_size + sizeof(*header)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) fw_size, header->file_size + sizeof(*header));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) header->file_size, header->num_modules,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) header->abi, sizeof(*header));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) size_t fw_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct snd_sof_fw_header *header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct snd_sof_mod_hdr *module;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) int (*load_module)(struct snd_sof_dev *sof_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct snd_sof_mod_hdr *hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) int ret, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) size_t remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) load_module = sof_ops(sdev)->load_module;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (!load_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) /* parse each module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) sizeof(*header));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) remaining = fw->size - sizeof(*header) - fw_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /* check for wrap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (remaining > fw->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) dev_err(sdev->dev, "error: fw size smaller than header size\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) for (count = 0; count < header->num_modules; count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /* check for wrap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (remaining < sizeof(*module)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) dev_err(sdev->dev, "error: not enough data remaining\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* minus header size of module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) remaining -= sizeof(*module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) ret = load_module(sdev, module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) dev_err(sdev->dev, "error: invalid module %d\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (remaining < module->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) dev_err(sdev->dev, "error: not enough data remaining\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) /* minus body size of module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) remaining -= module->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) module = (struct snd_sof_mod_hdr *)((u8 *)module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) + sizeof(*module) + module->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) struct snd_sof_pdata *plat_data = sdev->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) const char *fw_filename;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) ssize_t ext_man_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) /* Don't request firmware again if firmware is already requested */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) if (plat_data->fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) plat_data->fw_filename_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) plat_data->fw_filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (!fw_filename)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) fw_filename, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) dev_dbg(sdev->dev, "request_firmware %s successful\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) fw_filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) /* check for extended manifest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (ext_man_size > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /* when no error occurred, drop extended manifest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) plat_data->fw_offset = ext_man_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) } else if (!ext_man_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) /* No extended manifest, so nothing to skip during FW load */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) ret = ext_man_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) fw_filename, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) kfree(fw_filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) EXPORT_SYMBOL(snd_sof_load_firmware_raw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) struct snd_sof_pdata *plat_data = sdev->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) ret = snd_sof_load_firmware_raw(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) /* make sure the FW header and file is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) ret = check_header(sdev, plat_data->fw, plat_data->fw_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) dev_err(sdev->dev, "error: invalid FW header\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /* prepare the DSP for FW loading */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) ret = snd_sof_dsp_reset(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) dev_err(sdev->dev, "error: failed to reset DSP\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) /* parse and load firmware modules to DSP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) dev_err(sdev->dev, "error: invalid FW modules\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) release_firmware(plat_data->fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) plat_data->fw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) int snd_sof_load_firmware(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) dev_dbg(sdev->dev, "loading firmware\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (sof_ops(sdev)->load_firmware)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return sof_ops(sdev)->load_firmware(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) EXPORT_SYMBOL(snd_sof_load_firmware);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) int snd_sof_run_firmware(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) int init_core_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) init_waitqueue_head(&sdev->boot_wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) /* create read-only fw_version debugfs to store boot version info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (sdev->first_boot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) sizeof(sdev->fw_version),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) "fw_version", 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) /* errors are only due to memory allocation, not debugfs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) /* perform pre fw run operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) ret = snd_sof_dsp_pre_fw_run(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) dev_err(sdev->dev, "error: failed pre fw run op\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) dev_dbg(sdev->dev, "booting DSP firmware\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) /* boot the firmware on the DSP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) ret = snd_sof_dsp_run(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) dev_err(sdev->dev, "error: failed to reset DSP\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) init_core_mask = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) * now wait for the DSP to boot. There are 3 possible outcomes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) * 1. Boot wait times out indicating FW boot failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) * 2. FW boots successfully and fw_ready op succeeds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) * 3. FW boots but fw_ready op fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) ret = wait_event_timeout(sdev->boot_wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) msecs_to_jiffies(sdev->boot_timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) dev_err(sdev->dev, "error: firmware boot failure\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) SOF_DBG_TEXT | SOF_DBG_PCI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) sdev->fw_state = SOF_FW_BOOT_FAILED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) dev_dbg(sdev->dev, "firmware boot complete\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) return -EIO; /* FW boots but fw_ready op failed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) /* perform post fw run operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) ret = snd_sof_dsp_post_fw_run(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) dev_err(sdev->dev, "error: failed post fw run op\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) /* fw boot is complete. Update the active cores mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) sdev->enabled_cores_mask = init_core_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) EXPORT_SYMBOL(snd_sof_run_firmware);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) void snd_sof_fw_unload(struct snd_sof_dev *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) /* TODO: support module unloading at runtime */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) release_firmware(sdev->pdata->fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) sdev->pdata->fw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) EXPORT_SYMBOL(snd_sof_fw_unload);