staticvoid mtl_ipc_host_done(struct snd_sof_dev *sdev)
{ /* * clear busy interrupt to tell dsp controller this interrupt has been accepted, * not trigger it again
*/
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR,
MTL_DSP_REG_HFIPCXTDR_BUSY, MTL_DSP_REG_HFIPCXTDR_BUSY); /* * clear busy bit to ack dsp the msg has been processed and send reply msg to dsp
*/
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA,
MTL_DSP_REG_HFIPCXTDA_BUSY, 0);
}
staticvoid mtl_ipc_dsp_done(struct snd_sof_dev *sdev)
{ /* * set DONE bit - tell DSP we have received the reply msg from DSP, and processed it, * don't send more reply to host
*/
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA,
MTL_DSP_REG_HFIPCXIDA_DONE, MTL_DSP_REG_HFIPCXIDA_DONE);
/* Set the DSP subsystem power on */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
MTL_HFDSSCS_SPA_MASK, MTL_HFDSSCS_SPA_MASK);
/* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
usleep_range(1000, 1010);
/* poll with timeout to check if operation successful */
cpa = MTL_HFDSSCS_CPA_MASK;
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,
(dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) {
dev_err(sdev->dev, "failed to enable DSP subsystem\n"); return ret;
}
/* Power up gated-DSP-0 domain in order to access the DSP shim register block. */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, dsppwrctl,
MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG);
usleep_range(1000, 1010);
/* poll with timeout to check if operation successful */
pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK;
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, dsppwrsts, dsphfpwrsts,
(dsphfpwrsts & pgs) == pgs,
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US); if (ret < 0)
dev_err(sdev->dev, "failed to power up gated DSP domain\n");
/* if SoundWire is used, make sure it is not power-gated */ if (hdev->info.handle && hdev->info.link_mask > 0)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
MTL_HfPWRCTL_WPIOXPG(1), MTL_HfPWRCTL_WPIOXPG(1));
return ret;
}
staticint mtl_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, "could not startup SoundWire links\n"); return ret;
}
/* Check if IMR boot is usable */ if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) {
hdev->imrboot_supported = true;
debugfs_create_bool("skip_imr_boot",
0644, sdev->debugfs_root,
&hdev->skip_imr_boot);
}
}
staticbool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)
{ int val;
val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE); if (val != U32_MAX && val & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) returntrue;
returnfalse;
}
staticint mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)
{ unsignedint cpa;
u32 dspcxctl; int ret;
/* Only the primary core can be powered up by the host */ if (core != SOF_DSP_PRIMARY_CORE || mtl_dsp_primary_core_is_enabled(sdev)) return 0;
/* Program the owner of the IP & shim registers (10: Host CPU) */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
MTL_DSP2CXCTL_PRIMARY_CORE_OSEL,
0x2 << MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT);
/* enable SPA bit */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK,
MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK);
/* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
usleep_range(1000, 1010);
/* poll with timeout to check if operation successful */
cpa = MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK;
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
(dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) {
dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
__func__); return ret;
}
/* set primary core mask and refcount to 1 */
sdev->enabled_cores_mask = BIT(SOF_DSP_PRIMARY_CORE);
sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 1;
return 0;
}
staticint mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
{
u32 dspcxctl; int ret;
/* Only the primary core can be powered down by the host */ if (core != SOF_DSP_PRIMARY_CORE || !mtl_dsp_primary_core_is_enabled(sdev)) return 0;
/* disable SPA bit */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0);
/* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
usleep_range(1000, 1010);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
!(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); if (ret < 0) {
dev_err(sdev->dev, "failed to power down primary core\n"); return ret;
}
int mtl_power_down_dsp(struct snd_sof_dev *sdev)
{
u32 dsphfdsscs, cpa; int ret;
/* first power down core */
ret = mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); if (ret) {
dev_err(sdev->dev, "mtl dsp power down error, %d\n", ret); return ret;
}
/* Set the DSP subsystem power down */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
MTL_HFDSSCS_SPA_MASK, 0);
/* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
usleep_range(1000, 1010);
/* step 2: power up primary core */
ret = mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE); if (ret < 0) { if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "dsp core 0/1 power up failed\n"); goto err;
}
dev_dbg(sdev->dev, "Primary core power up successful\n");
/* step 3: wait for IPC DONE bit from ROM */
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status,
((status & chip->ipc_ack_mask) == chip->ipc_ack_mask),
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "timeout waiting for purge IPC done\n"); goto err;
}
/* set DONE bit to clear the reply IPC message */
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask,
chip->ipc_ack_mask);
/* step 4: enable interrupts */
ret = mtl_enable_interrupts(sdev, true); if (ret < 0) { if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__); goto err;
}
mtl_enable_ipc_interrupts(sdev);
if (chip->rom_status_reg == MTL_DSP_ROM_STS) { /* * Workaround: when the ROM status register is pointing to * the SRAM window (MTL_DSP_ROM_STS) the platform cannot catch * ROM_INIT_DONE because of a very short timing window. * Follow the recommendations and skip target state waiting.
*/ return 0;
}
/* * 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 = FSR_STATE_FW_ENTERED; else
target_status = FSR_STATE_INIT_DONE;
/* reply message from DSP */ if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) { /* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,
MTL_DSP_REG_HFIPCXCTL_DONE, 0);
mtl_ipc_dsp_done(sdev);
ipc_irq = true;
ack_received = true;
}
if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) { /* Message from DSP (reply or notification) */
u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
u32 primary = hipctdr & MTL_DSP_REG_HFIPCXTDR_MSG_MASK;
/* * ACE fw sends a new fw ipc message to host to * notify the status of the last host ipc message
*/ if (primary & SOF_IPC4_MSG_DIR_MASK) { /* Reply received */ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
if (!ipc_irq) { /* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
}
if (ack_received) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
if (hdev->delayed_ipc_tx_msg)
mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.