[PATCH] ASoC: SOF: Intel: hda: Revisit IMR boot sequence
From: Peter Ujfalusi peter.ujfalusi@linux.intel.com
The sequence for IMR boot is essentially the same as normal boot with the difference that instead of DMA from host the firmware is loaded from IMR.
Re-structure the code to use the existing sequence and also add fallback handling in case the IMR boot fails.
Introduce a new flag to make the IMR boot support check simpler.
Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Signed-off-by: Peter Ujfalusi peter.ujfalusi@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- sound/soc/sof/intel/hda-loader.c | 76 ++++++++++++++++---------------- sound/soc/sof/intel/hda.h | 6 ++- sound/soc/sof/intel/icl.c | 7 +++ 3 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 78ceb5a2cbc0c..7d4436f079c65 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -99,14 +99,14 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned * status on core 1, so power up core 1 also momentarily, keep it in * reset/stall and then turn it off */ -static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) +static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; - unsigned int status; + unsigned int status, target_status; + u32 flags, ipc_hdr, j; unsigned long mask; char *dump_msg; - u32 flags, j; int ret;
/* step 1: power up corex */ @@ -119,10 +119,12 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
hda_ssp_set_cbp_cfp(sdev);
- /* step 2: purge FW request */ - snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, - chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | - ((stream_tag - 1) << 9))); + /* step 2: Send ROM_CONTROL command (stream_tag is ignored for IMR boot) */ + ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL; + if (!imr_boot) + ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
/* step 3: unset core 0 reset state & unstall/run core 0 */ ret = hda_dsp_core_run(sdev, BIT(0)); @@ -169,11 +171,20 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) /* step 6: enable IPC interrupts */ hda_dsp_ipc_int_enable(sdev);
- /* step 7: wait for ROM init */ + /* + * step 7: + * - Cold/Full boot: wait for ROM init to proceed to download the firmware + * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR) + */ + if (imr_boot) + target_status = HDA_DSP_ROM_FW_ENTERED; + else + target_status = HDA_DSP_ROM_INIT; + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->rom_status_reg, status, ((status & HDA_DSP_ROM_STS_MASK) - == HDA_DSP_ROM_INIT), + == target_status), HDA_DSP_REG_POLL_INTERVAL_US, chip->rom_init_timeout * USEC_PER_MSEC); @@ -358,32 +369,11 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
static int hda_dsp_boot_imr(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - const struct sof_intel_dsp_desc *chip = hda->desc; - unsigned long mask; - u32 j; int ret;
- /* power up & unstall/run the cores to run the firmware */ - ret = hda_dsp_enable_core(sdev, chip->init_core_mask); - if (ret < 0) { - dev_err(sdev->dev, "dsp core start failed %d\n", ret); - return -EIO; - } - - /* set enabled cores mask and increment ref count for cores in init_core_mask */ - sdev->enabled_cores_mask |= chip->init_core_mask; - mask = sdev->enabled_cores_mask; - for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES) - sdev->dsp_core_ref_count[j]++; - - hda_ssp_set_cbp_cfp(sdev); - - /* enable IPC interrupts */ - hda_dsp_ipc_int_enable(sdev); - - /* process wakes */ - hda_sdw_process_wakeen(sdev); + ret = cl_dsp_init(sdev, 0, true); + if (ret >= 0) + hda_sdw_process_wakeen(sdev);
return ret; } @@ -399,11 +389,14 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) struct snd_dma_buffer dmab; int ret, ret1, i;
- if ((sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT) && - !(sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) && - !sdev->first_boot) { + if (hda->imrboot_supported && !sdev->first_boot) { dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n"); - return hda_dsp_boot_imr(sdev); + hda->boot_iteration = 0; + ret = hda_dsp_boot_imr(sdev); + if (ret >= 0) + return ret; + + dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n"); }
chip_info = desc->chip_info; @@ -437,7 +430,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) "Attempting iteration %d of Core En/ROM load...\n", i);
hda->boot_iteration = i + 1; - ret = cl_dsp_init(sdev, hext_stream->hstream.stream_tag); + ret = cl_dsp_init(sdev, hext_stream->hstream.stream_tag, false);
/* don't retry anymore if successful */ if (!ret) @@ -525,12 +518,19 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) int ret;
if (sdev->first_boot) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + ret = hda_sdw_startup(sdev); if (ret < 0) { dev_err(sdev->dev, "error: could not startup SoundWire links\n"); return ret; } + + /* Check if IMR boot is usable */ + if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) && + sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT) + hdev->imrboot_supported = true; }
hda_sdw_int_enable(sdev, true); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7827ea4fdacb3..6e05c77594809 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -210,7 +210,9 @@ #define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000 #define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000 #define HDA_DSP_ROM_NULL_FW_ENTRY 0x4c4c4e55 -#define HDA_DSP_IPC_PURGE_FW 0x01004000 + +#define HDA_DSP_ROM_IPC_CONTROL 0x01000000 +#define HDA_DSP_ROM_IPC_PURGE_FW 0x00004000
/* various timeout values */ #define HDA_DSP_PU_TIMEOUT 50 @@ -416,6 +418,8 @@ enum sof_hda_D0_substate {
/* represents DSP HDA controller frontend - i.e. host facing control */ struct sof_intel_hda_dev { + bool imrboot_supported; + int boot_iteration;
struct hda_bus hbus; diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 8dd5626969344..f845064c3589a 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -56,11 +56,18 @@ static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev) int ret;
if (sdev->first_boot) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + ret = hda_sdw_startup(sdev); if (ret < 0) { dev_err(sdev->dev, "error: could not startup SoundWire links\n"); return ret; } + + /* Check if IMR boot is usable */ + if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) && + sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT) + hdev->imrboot_supported = true; }
hda_sdw_int_enable(sdev, true);
On Thu, 21 Apr 2022 15:20:31 -0500, Pierre-Louis Bossart wrote:
From: Peter Ujfalusi peter.ujfalusi@linux.intel.com
The sequence for IMR boot is essentially the same as normal boot with the difference that instead of DMA from host the firmware is loaded from IMR.
Re-structure the code to use the existing sequence and also add fallback handling in case the IMR boot fails.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/1] ASoC: SOF: Intel: hda: Revisit IMR boot sequence commit: 2a68ff846164922196c38718ad8dc216819ccd38
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (2)
-
Mark Brown
-
Pierre-Louis Bossart