aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/intel/hda-loader.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-05-25 16:55:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-05-25 16:55:16 -0700
commitd7227785e384d4422b3ca189aa5bf19f462337cc (patch)
treefbd117e5e3f31a8561f6b6d159413bc744f460e5 /sound/soc/sof/intel/hda-loader.c
parentMerge tag 'drm-next-2022-05-25' of git://anongit.freedesktop.org/drm/drm (diff)
parentALSA: hda/realtek - Add new type for ALC245 (diff)
downloadlinux-dev-d7227785e384d4422b3ca189aa5bf19f462337cc.tar.xz
linux-dev-d7227785e384d4422b3ca189aa5bf19f462337cc.zip
Merge tag 'sound-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "Not much dramatic changes at this time, but we've received quite a lot of changes for ASoC, while there are still a few fixes and quirks for usual HD- and USB-auido. Here are some highlights. ASoC: - Overhaul of endianness specification for data formats, avoiding needless restrictions due to CODECs - Initial stages of Intel AVS driver merge - Introduction of v4 IPC mechanism for SOF - TDM mode support for AK4613 - Support for Analog Devices ADAU1361, Cirrus Logic CS35L45, Maxim MAX98396, MediaTek MT8186, NXP i.MX8 micfil and SAI interfaces, nVidia Tegra186 ASRC, and Texas Instruments TAS2764 and TAS2780 Others: - A few regression fixes after the USB-audio endpoint management refactoring - More enhancements for Cirrus HD-audio codec support (still ongoing) - Addition of generic serial MIDI driver" * tag 'sound-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (504 commits) ALSA: hda/realtek - Add new type for ALC245 ALSA: usb-audio: Configure sync endpoints before data ALSA: ctxfi: fix typo in comment ALSA: cs5535audio: fix typo in comment ALSA: ctxfi: Add SB046x PCI ID ALSA: usb-audio: Add missing ep_idx in fixed EP quirks ALSA: usb-audio: Workaround for clock setup on TEAC devices ALSA: lola: Bounds check loop iterator against streams array size ASoC: max98090: Move check for invalid values before casting in max98090_put_enab_tlv() ASoC: rt1308-sdw: add the default value of register 0xc320 ASoC: rt9120: Use pm_runtime and regcache to optimize 'pwdnn' logic ASoC: rt9120: Fix 3byte read, valule offset typo ASoC: amd: acp: Set Speaker enable/disable pin through rt1019 codec driver. ASoC: amd: acp: Set Speaker enable/disable pin through rt1019 codec driver ASoC: wm2000: fix missing clk_disable_unprepare() on error in wm2000_anc_transition() ASoC: codecs: lpass: Fix passing zero to 'PTR_ERR' ASoC: SOF: sof-client-ipc-flood-test: use pm_runtime_resume_and_get() ASoC: SOF: mediatek: remove duplicate include in mt8195.c ASoC: SOF: mediatek: Add mt8195 debug dump ASoC: SOF: mediatek: Add mediatek common debug dump ...
Diffstat (limited to 'sound/soc/sof/intel/hda-loader.c')
-rw-r--r--sound/soc/sof/intel/hda-loader.c123
1 files changed, 63 insertions, 60 deletions
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 2ac5d9d0719b..64290125d7cd 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -24,8 +24,6 @@
#include "../sof-priv.h"
#include "hda.h"
-#define HDA_CL_STREAM_FORMAT 0x40
-
static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
@@ -43,9 +41,9 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
}
}
-static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
- unsigned int size, struct snd_dma_buffer *dmab,
- int direction)
+struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
+ unsigned int size, struct snd_dma_buffer *dmab,
+ int direction)
{
struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream;
@@ -101,14 +99,14 @@ out_put:
* 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 */
@@ -121,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));
@@ -171,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,
- HDA_DSP_SRAM_REG_ROM_STATUS, status,
+ 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);
@@ -190,8 +199,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev,
- "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n",
- __func__);
+ "%s: timeout with rom_status_reg (%#x) read\n",
+ __func__, chip->rom_status_reg);
err:
flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
@@ -236,8 +245,8 @@ static int cl_trigger(struct snd_sof_dev *sdev,
}
}
-static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
- struct hdac_ext_stream *hext_stream)
+int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
+ struct hdac_ext_stream *hext_stream)
{
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
@@ -268,8 +277,10 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
return ret;
}
-static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
+int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int reg;
int ret, status;
@@ -280,7 +291,7 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_str
}
status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
- HDA_DSP_SRAM_REG_ROM_STATUS, reg,
+ chip->rom_status_reg, reg,
((reg & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_FW_ENTERED),
HDA_DSP_REG_POLL_INTERVAL_US,
@@ -293,8 +304,8 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_str
if (status < 0) {
dev_err(sdev->dev,
- "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n",
- __func__);
+ "%s: timeout with rom_status_reg (%#x) read\n",
+ __func__, chip->rom_status_reg);
}
ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
@@ -313,6 +324,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
struct hdac_ext_stream *iccmax_stream;
struct hdac_bus *bus = sof_to_bus(sdev);
struct firmware stripped_firmware;
+ struct snd_dma_buffer dmab_bdl;
int ret, ret1;
u8 original_gb;
@@ -327,8 +339,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
/* prepare capture stream for ICCMAX */
- iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
- &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
+ iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
+ &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
return PTR_ERR(iccmax_stream);
@@ -340,7 +352,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Perform iccmax stream cleanup. This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
- ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream);
+ ret1 = hda_cl_cleanup(sdev, &dmab_bdl, iccmax_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@@ -357,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)
+ hda_sdw_process_wakeen(sdev);
return ret;
}
@@ -395,13 +386,17 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
const struct sof_intel_dsp_desc *chip_info;
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
+ 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)
+ return 0;
+
+ dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n");
}
chip_info = desc->chip_info;
@@ -418,14 +413,15 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
init_waitqueue_head(&sdev->boot_wait);
/* prepare DMA for code loader stream */
- hext_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
- &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK);
+ hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
+ stripped_firmware.size,
+ &dmab, SNDRV_PCM_STREAM_PLAYBACK);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
return PTR_ERR(hext_stream);
}
- memcpy(sdev->dmab.area, stripped_firmware.data,
+ memcpy(dmab.area, stripped_firmware.data,
stripped_firmware.size);
/* try ROM init a few times before giving up */
@@ -434,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)
@@ -473,7 +469,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
* Continue with code loading and firmware boot
*/
hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS;
- ret = cl_copy_fw(sdev, hext_stream);
+ ret = hda_cl_copy_fw(sdev, hext_stream);
if (!ret)
dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
else
@@ -486,7 +482,7 @@ cleanup:
* This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
- ret1 = cl_cleanup(sdev, &sdev->dmab, hext_stream);
+ ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@@ -522,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);