709 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2021-2022 Intel Corporation4//5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>7//8 9#include <linux/firmware.h>10#include <linux/module.h>11#include <linux/slab.h>12#include <sound/hdaudio.h>13#include <sound/hdaudio_ext.h>14#include "avs.h"15#include "cldma.h"16#include "messages.h"17#include "registers.h"18#include "topology.h"19 20#define AVS_ROM_STS_MASK 0xFF21#define AVS_ROM_INIT_DONE 0x122#define SKL_ROM_BASEFW_ENTERED 0xF23#define APL_ROM_FW_ENTERED 0x524#define AVS_ROM_INIT_POLLING_US 525#define SKL_ROM_INIT_TIMEOUT_US 100000026#define APL_ROM_INIT_TIMEOUT_US 30000027#define APL_ROM_INIT_RETRIES 328 29#define AVS_FW_INIT_POLLING_US 50030#define AVS_FW_INIT_TIMEOUT_MS 300031#define AVS_FW_INIT_TIMEOUT_US (AVS_FW_INIT_TIMEOUT_MS * 1000)32 33#define AVS_CLDMA_START_DELAY_MS 10034 35#define AVS_ROOT_DIR "intel/avs"36#define AVS_BASEFW_FILENAME "dsp_basefw.bin"37#define AVS_EXT_MANIFEST_MAGIC 0x3145412438#define SKL_MANIFEST_MAGIC 0x0000000639#define SKL_ADSPFW_OFFSET 0x28440#define APL_MANIFEST_MAGIC 0x4450432441#define APL_ADSPFW_OFFSET 0x200042 43/* Occasionally, engineering (release candidate) firmware is provided for testing. */44static bool debug_ignore_fw_version;45module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444);46MODULE_PARM_DESC(ignore_fw_version, "Ignore firmware version check 0=no (default), 1=yes");47 48#define AVS_LIB_NAME_SIZE 849 50struct avs_fw_manifest {51 u32 id;52 u32 len;53 char name[AVS_LIB_NAME_SIZE];54 u32 preload_page_count;55 u32 img_flags;56 u32 feature_mask;57 struct avs_fw_version version;58} __packed;59static_assert(sizeof(struct avs_fw_manifest) == 36);60 61struct avs_fw_ext_manifest {62 u32 id;63 u32 len;64 u16 version_major;65 u16 version_minor;66 u32 entries;67} __packed;68static_assert(sizeof(struct avs_fw_ext_manifest) == 16);69 70static int avs_fw_ext_manifest_strip(struct firmware *fw)71{72 struct avs_fw_ext_manifest *man;73 74 if (fw->size < sizeof(*man))75 return -EINVAL;76 77 man = (struct avs_fw_ext_manifest *)fw->data;78 if (man->id == AVS_EXT_MANIFEST_MAGIC) {79 fw->data += man->len;80 fw->size -= man->len;81 }82 83 return 0;84}85 86static int avs_fw_manifest_offset(struct firmware *fw)87{88 /* Header type found in first DWORD of fw binary. */89 u32 magic = *(u32 *)fw->data;90 91 switch (magic) {92 case SKL_MANIFEST_MAGIC:93 return SKL_ADSPFW_OFFSET;94 case APL_MANIFEST_MAGIC:95 return APL_ADSPFW_OFFSET;96 default:97 return -EINVAL;98 }99}100 101static int avs_fw_manifest_strip_verify(struct avs_dev *adev, struct firmware *fw,102 const struct avs_fw_version *min)103{104 struct avs_fw_manifest *man;105 int offset, ret;106 107 ret = avs_fw_ext_manifest_strip(fw);108 if (ret)109 return ret;110 111 offset = avs_fw_manifest_offset(fw);112 if (offset < 0)113 return offset;114 115 if (fw->size < offset + sizeof(*man))116 return -EINVAL;117 if (!min)118 return 0;119 120 man = (struct avs_fw_manifest *)(fw->data + offset);121 if (man->version.major != min->major ||122 man->version.minor != min->minor ||123 man->version.hotfix != min->hotfix ||124 man->version.build < min->build) {125 dev_warn(adev->dev, "bad FW version %d.%d.%d.%d, expected %d.%d.%d.%d or newer\n",126 man->version.major, man->version.minor,127 man->version.hotfix, man->version.build,128 min->major, min->minor, min->hotfix, min->build);129 130 if (!debug_ignore_fw_version)131 return -EINVAL;132 }133 134 return 0;135}136 137int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw)138{139 struct hda_cldma *cl = &code_loader;140 unsigned int reg;141 int ret;142 143 ret = avs_dsp_op(adev, power, AVS_MAIN_CORE_MASK, true);144 if (ret < 0)145 return ret;146 147 ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);148 if (ret < 0)149 return ret;150 151 ret = hda_cldma_reset(cl);152 if (ret < 0) {153 dev_err(adev->dev, "cldma reset failed: %d\n", ret);154 return ret;155 }156 hda_cldma_setup(cl);157 158 ret = avs_dsp_op(adev, stall, AVS_MAIN_CORE_MASK, false);159 if (ret < 0)160 return ret;161 162 reinit_completion(&adev->fw_ready);163 avs_dsp_op(adev, int_control, true);164 165 /* await ROM init */166 ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg,167 (reg & AVS_ROM_INIT_DONE) == AVS_ROM_INIT_DONE,168 AVS_ROM_INIT_POLLING_US, SKL_ROM_INIT_TIMEOUT_US);169 if (ret < 0) {170 dev_err(adev->dev, "rom init timeout: %d\n", ret);171 avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);172 return ret;173 }174 175 hda_cldma_set_data(cl, (void *)fw->data, fw->size);176 /* transfer firmware */177 hda_cldma_transfer(cl, 0);178 ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg,179 (reg & AVS_ROM_STS_MASK) == SKL_ROM_BASEFW_ENTERED,180 AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US);181 hda_cldma_stop(cl);182 if (ret < 0) {183 dev_err(adev->dev, "transfer fw failed: %d\n", ret);184 avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);185 return ret;186 }187 188 return 0;189}190 191int avs_cldma_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)192{193 struct hda_cldma *cl = &code_loader;194 int ret;195 196 hda_cldma_set_data(cl, (void *)lib->data, lib->size);197 /* transfer modules manifest */198 hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));199 200 /* DMA id ignored as there is only ever one code-loader DMA */201 ret = avs_ipc_load_library(adev, 0, id);202 hda_cldma_stop(cl);203 204 if (ret) {205 ret = AVS_IPC_RET(ret);206 dev_err(adev->dev, "transfer lib %d failed: %d\n", id, ret);207 }208 209 return ret;210}211 212static int avs_cldma_load_module(struct avs_dev *adev, struct avs_module_entry *mentry)213{214 struct hda_cldma *cl = &code_loader;215 const struct firmware *mod;216 char *mod_name;217 int ret;218 219 mod_name = kasprintf(GFP_KERNEL, "%s/%s/dsp_mod_%pUL.bin", AVS_ROOT_DIR,220 adev->spec->name, mentry->uuid.b);221 if (!mod_name)222 return -ENOMEM;223 224 ret = avs_request_firmware(adev, &mod, mod_name);225 kfree(mod_name);226 if (ret < 0)227 return ret;228 229 avs_hda_power_gating_enable(adev, false);230 avs_hda_clock_gating_enable(adev, false);231 avs_hda_l1sen_enable(adev, false);232 233 hda_cldma_set_data(cl, (void *)mod->data, mod->size);234 hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));235 ret = avs_ipc_load_modules(adev, &mentry->module_id, 1);236 hda_cldma_stop(cl);237 238 avs_hda_l1sen_enable(adev, true);239 avs_hda_clock_gating_enable(adev, true);240 avs_hda_power_gating_enable(adev, true);241 242 if (ret) {243 dev_err(adev->dev, "load module %d failed: %d\n", mentry->module_id, ret);244 avs_release_last_firmware(adev);245 return AVS_IPC_RET(ret);246 }247 248 return 0;249}250 251int avs_cldma_transfer_modules(struct avs_dev *adev, bool load,252 struct avs_module_entry *mods, u32 num_mods)253{254 u16 *mod_ids;255 int ret, i;256 257 /* Either load to DSP or unload them to free space. */258 if (load) {259 for (i = 0; i < num_mods; i++) {260 ret = avs_cldma_load_module(adev, &mods[i]);261 if (ret)262 return ret;263 }264 265 return 0;266 }267 268 mod_ids = kcalloc(num_mods, sizeof(u16), GFP_KERNEL);269 if (!mod_ids)270 return -ENOMEM;271 272 for (i = 0; i < num_mods; i++)273 mod_ids[i] = mods[i].module_id;274 275 ret = avs_ipc_unload_modules(adev, mod_ids, num_mods);276 kfree(mod_ids);277 if (ret)278 return AVS_IPC_RET(ret);279 280 return 0;281}282 283static int284avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge)285{286 const struct avs_spec *const spec = adev->spec;287 unsigned int corex_mask, reg;288 int ret;289 290 corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK;291 292 ret = avs_dsp_op(adev, power, spec->core_init_mask, true);293 if (ret < 0)294 goto err;295 296 ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);297 if (ret < 0)298 goto err;299 300 reinit_completion(&adev->fw_ready);301 avs_dsp_op(adev, int_control, true);302 303 /* set boot config */304 ret = avs_ipc_set_boot_config(adev, dma_id, purge);305 if (ret) {306 ret = AVS_IPC_RET(ret);307 goto err;308 }309 310 /* await ROM init */311 ret = snd_hdac_adsp_readq_poll(adev, spec->sram->rom_status_offset, reg,312 (reg & 0xF) == AVS_ROM_INIT_DONE ||313 (reg & 0xF) == APL_ROM_FW_ENTERED,314 AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US);315 if (ret < 0) {316 dev_err(adev->dev, "rom init timeout: %d\n", ret);317 goto err;318 }319 320 /* power down non-main cores */321 if (corex_mask) {322 ret = avs_dsp_op(adev, power, corex_mask, false);323 if (ret < 0)324 goto err;325 }326 327 return 0;328 329err:330 avs_dsp_core_disable(adev, spec->core_init_mask);331 return ret;332}333 334static int avs_imr_load_basefw(struct avs_dev *adev)335{336 int ret;337 338 /* DMA id ignored when flashing from IMR as no transfer occurs. */339 ret = avs_hda_init_rom(adev, 0, false);340 if (ret < 0) {341 dev_err(adev->dev, "rom init failed: %d\n", ret);342 return ret;343 }344 345 ret = wait_for_completion_timeout(&adev->fw_ready,346 msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));347 if (!ret) {348 dev_err(adev->dev, "firmware ready timeout\n");349 avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);350 return -ETIMEDOUT;351 }352 353 return 0;354}355 356int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)357{358 struct snd_pcm_substream substream;359 struct snd_dma_buffer dmab;360 struct hdac_ext_stream *estream;361 struct hdac_stream *hstream;362 struct hdac_bus *bus = &adev->base.core;363 unsigned int sdfmt, reg;364 int ret, i;365 366 /* configure hda dma */367 memset(&substream, 0, sizeof(substream));368 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;369 estream = snd_hdac_ext_stream_assign(bus, &substream,370 HDAC_EXT_STREAM_TYPE_HOST);371 if (!estream)372 return -ENODEV;373 hstream = hdac_stream(estream);374 375 /* code loading performed with default format */376 sdfmt = snd_hdac_stream_format(1, 32, 48000);377 ret = snd_hdac_dsp_prepare(hstream, sdfmt, fw->size, &dmab);378 if (ret < 0)379 goto release_stream;380 381 /* enable SPIB for hda stream */382 snd_hdac_stream_spbcap_enable(bus, true, hstream->index);383 ret = snd_hdac_stream_set_spib(bus, hstream, fw->size);384 if (ret)385 goto cleanup_resources;386 387 memcpy(dmab.area, fw->data, fw->size);388 389 for (i = 0; i < APL_ROM_INIT_RETRIES; i++) {390 unsigned int dma_id = hstream->stream_tag - 1;391 392 ret = avs_hda_init_rom(adev, dma_id, true);393 if (!ret)394 break;395 dev_info(adev->dev, "#%d rom init fail: %d\n", i + 1, ret);396 }397 if (ret < 0)398 goto cleanup_resources;399 400 /* transfer firmware */401 snd_hdac_dsp_trigger(hstream, true);402 ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg,403 (reg & AVS_ROM_STS_MASK) == APL_ROM_FW_ENTERED,404 AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US);405 snd_hdac_dsp_trigger(hstream, false);406 if (ret < 0) {407 dev_err(adev->dev, "transfer fw failed: %d\n", ret);408 avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);409 }410 411cleanup_resources:412 /* disable SPIB for hda stream */413 snd_hdac_stream_spbcap_enable(bus, false, hstream->index);414 snd_hdac_stream_set_spib(bus, hstream, 0);415 416 snd_hdac_dsp_cleanup(hstream, &dmab);417release_stream:418 snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST);419 420 return ret;421}422 423int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)424{425 struct snd_pcm_substream substream;426 struct snd_dma_buffer dmab;427 struct hdac_ext_stream *estream;428 struct hdac_stream *stream;429 struct hdac_bus *bus = &adev->base.core;430 unsigned int sdfmt;431 int ret;432 433 /* configure hda dma */434 memset(&substream, 0, sizeof(substream));435 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;436 estream = snd_hdac_ext_stream_assign(bus, &substream,437 HDAC_EXT_STREAM_TYPE_HOST);438 if (!estream)439 return -ENODEV;440 stream = hdac_stream(estream);441 442 /* code loading performed with default format */443 sdfmt = snd_hdac_stream_format(1, 32, 48000);444 ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab);445 if (ret < 0)446 goto release_stream;447 448 /* enable SPIB for hda stream */449 snd_hdac_stream_spbcap_enable(bus, true, stream->index);450 snd_hdac_stream_set_spib(bus, stream, lib->size);451 452 memcpy(dmab.area, lib->data, lib->size);453 454 /* transfer firmware */455 snd_hdac_dsp_trigger(stream, true);456 ret = avs_ipc_load_library(adev, stream->stream_tag - 1, id);457 snd_hdac_dsp_trigger(stream, false);458 if (ret) {459 dev_err(adev->dev, "transfer lib %d failed: %d\n", id, ret);460 ret = AVS_IPC_RET(ret);461 }462 463 /* disable SPIB for hda stream */464 snd_hdac_stream_spbcap_enable(bus, false, stream->index);465 snd_hdac_stream_set_spib(bus, stream, 0);466 467 snd_hdac_dsp_cleanup(stream, &dmab);468release_stream:469 snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST);470 471 return ret;472}473 474int avs_hda_transfer_modules(struct avs_dev *adev, bool load,475 struct avs_module_entry *mods, u32 num_mods)476{477 /*478 * All platforms without CLDMA are equipped with IMR,479 * and thus the module transferring is offloaded to DSP.480 */481 return 0;482}483 484int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, u32 num_libs)485{486 int start, id, i = 0;487 int ret;488 489 /* Calculate the id to assign for the next lib. */490 for (id = 0; id < adev->fw_cfg.max_libs_count; id++)491 if (adev->lib_names[id][0] == '\0')492 break;493 if (id + num_libs >= adev->fw_cfg.max_libs_count)494 return -EINVAL;495 496 start = id;497 while (i < num_libs) {498 struct avs_fw_manifest *man;499 const struct firmware *fw;500 struct firmware stripped_fw;501 char *filename;502 int j;503 504 filename = kasprintf(GFP_KERNEL, "%s/%s/%s", AVS_ROOT_DIR, adev->spec->name,505 libs[i].name);506 if (!filename)507 return -ENOMEM;508 509 /*510 * If any call after this one fails, requested firmware is not released with511 * avs_release_last_firmware() as failing to load code results in need for reload512 * of entire driver module. And then avs_release_firmwares() is in place already.513 */514 ret = avs_request_firmware(adev, &fw, filename);515 kfree(filename);516 if (ret < 0)517 return ret;518 519 stripped_fw = *fw;520 ret = avs_fw_manifest_strip_verify(adev, &stripped_fw, NULL);521 if (ret) {522 dev_err(adev->dev, "invalid library data: %d\n", ret);523 return ret;524 }525 526 ret = avs_fw_manifest_offset(&stripped_fw);527 if (ret < 0)528 return ret;529 man = (struct avs_fw_manifest *)(stripped_fw.data + ret);530 531 /* Don't load anything that's already in DSP memory. */532 for (j = 0; j < id; j++)533 if (!strncmp(adev->lib_names[j], man->name, AVS_LIB_NAME_SIZE))534 goto next_lib;535 536 ret = avs_dsp_op(adev, load_lib, &stripped_fw, id);537 if (ret)538 return ret;539 540 strscpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE);541 id++;542next_lib:543 i++;544 }545 546 return start == id ? 1 : 0;547}548 549static int avs_dsp_load_basefw(struct avs_dev *adev)550{551 const struct avs_fw_version *min_req;552 const struct avs_spec *const spec = adev->spec;553 const struct firmware *fw;554 struct firmware stripped_fw;555 char *filename;556 int ret;557 558 filename = kasprintf(GFP_KERNEL, "%s/%s/%s", AVS_ROOT_DIR, spec->name, AVS_BASEFW_FILENAME);559 if (!filename)560 return -ENOMEM;561 562 ret = avs_request_firmware(adev, &fw, filename);563 kfree(filename);564 if (ret < 0) {565 dev_err(adev->dev, "request firmware failed: %d\n", ret);566 return ret;567 }568 569 stripped_fw = *fw;570 min_req = &adev->spec->min_fw_version;571 572 ret = avs_fw_manifest_strip_verify(adev, &stripped_fw, min_req);573 if (ret < 0) {574 dev_err(adev->dev, "invalid firmware data: %d\n", ret);575 goto release_fw;576 }577 578 ret = avs_dsp_op(adev, load_basefw, &stripped_fw);579 if (ret < 0) {580 dev_err(adev->dev, "basefw load failed: %d\n", ret);581 goto release_fw;582 }583 584 ret = wait_for_completion_timeout(&adev->fw_ready,585 msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));586 if (!ret) {587 dev_err(adev->dev, "firmware ready timeout\n");588 avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);589 ret = -ETIMEDOUT;590 goto release_fw;591 }592 593 return 0;594 595release_fw:596 avs_release_last_firmware(adev);597 return ret;598}599 600int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)601{602 struct avs_soc_component *acomp;603 int ret, i;604 605 /* Forgo full boot if flash from IMR succeeds. */606 if (!purge && avs_platattr_test(adev, IMR)) {607 ret = avs_imr_load_basefw(adev);608 if (!ret)609 return 0;610 611 dev_dbg(adev->dev, "firmware flash from imr failed: %d\n", ret);612 }613 614 /* Full boot, clear cached data except for basefw (slot 0). */615 for (i = 1; i < adev->fw_cfg.max_libs_count; i++)616 memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);617 618 avs_hda_power_gating_enable(adev, false);619 avs_hda_clock_gating_enable(adev, false);620 avs_hda_l1sen_enable(adev, false);621 622 ret = avs_dsp_load_basefw(adev);623 if (ret)624 goto reenable_gating;625 626 mutex_lock(&adev->comp_list_mutex);627 list_for_each_entry(acomp, &adev->comp_list, node) {628 struct avs_tplg *tplg = acomp->tplg;629 630 ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);631 if (ret < 0)632 break;633 }634 mutex_unlock(&adev->comp_list_mutex);635 636reenable_gating:637 avs_hda_l1sen_enable(adev, true);638 avs_hda_clock_gating_enable(adev, true);639 avs_hda_power_gating_enable(adev, true);640 641 if (ret < 0)642 return ret;643 644 /* With all code loaded, refresh module information. */645 ret = avs_module_info_init(adev, true);646 if (ret) {647 dev_err(adev->dev, "init module info failed: %d\n", ret);648 return ret;649 }650 651 return 0;652}653 654int avs_dsp_first_boot_firmware(struct avs_dev *adev)655{656 int ret, i;657 658 if (avs_platattr_test(adev, CLDMA)) {659 ret = hda_cldma_init(&code_loader, &adev->base.core,660 adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE);661 if (ret < 0) {662 dev_err(adev->dev, "cldma init failed: %d\n", ret);663 return ret;664 }665 }666 667 ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);668 if (ret < 0)669 return ret;670 671 ret = avs_dsp_boot_firmware(adev, true);672 if (ret < 0) {673 dev_err(adev->dev, "firmware boot failed: %d\n", ret);674 return ret;675 }676 677 ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg);678 if (ret) {679 dev_err(adev->dev, "get hw cfg failed: %d\n", ret);680 return AVS_IPC_RET(ret);681 }682 683 ret = avs_ipc_get_fw_config(adev, &adev->fw_cfg);684 if (ret) {685 dev_err(adev->dev, "get fw cfg failed: %d\n", ret);686 return AVS_IPC_RET(ret);687 }688 689 adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores,690 sizeof(*adev->core_refs), GFP_KERNEL);691 adev->lib_names = devm_kcalloc(adev->dev, adev->fw_cfg.max_libs_count,692 sizeof(*adev->lib_names), GFP_KERNEL);693 if (!adev->core_refs || !adev->lib_names)694 return -ENOMEM;695 696 for (i = 0; i < adev->fw_cfg.max_libs_count; i++) {697 adev->lib_names[i] = devm_kzalloc(adev->dev, AVS_LIB_NAME_SIZE, GFP_KERNEL);698 if (!adev->lib_names[i])699 return -ENOMEM;700 }701 702 /* basefw always occupies slot 0 */703 strscpy(adev->lib_names[0], "BASEFW", AVS_LIB_NAME_SIZE);704 705 ida_init(&adev->ppl_ida);706 707 return 0;708}709