Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sound/soc/sof/intel/cnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR,
msg_data->primary | CNL_DSP_REG_HIPCIDR_BUSY);

hda_dsp_ipc4_schedule_d0i3_work(hdev, msg);

return 0;
}

Expand Down
46 changes: 35 additions & 11 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,19 +364,12 @@ static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev)

static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags)
{
struct sof_ipc_pm_gate pm_gate;
struct sof_ipc_reply reply;
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);

memset(&pm_gate, 0, sizeof(pm_gate));
if (pm_ops && pm_ops->set_pm_gate)
return pm_ops->set_pm_gate(sdev, flags);

/* configure pm_gate ipc message */
pm_gate.hdr.size = sizeof(pm_gate);
pm_gate.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE;
pm_gate.flags = flags;

/* send pm_gate ipc to dsp */
return sof_ipc_tx_message_no_pm(sdev->ipc, &pm_gate, sizeof(pm_gate),
&reply, sizeof(reply));
return 0;
}

static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value)
Expand Down Expand Up @@ -412,6 +405,34 @@ static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value)
return 0;
}

/*
* d0i3 streaming is enabled if all the active streams can
* work in d0i3 state and playback is enabled
*/
static bool hda_dsp_d0i3_streaming_applicable(struct snd_sof_dev *sdev)
{
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
bool playback_active = false;
int dir;

list_for_each_entry(spcm, &sdev->pcm_list, list) {
for_each_pcm_streams(dir) {
substream = spcm->stream[dir].substream;
if (!substream || !substream->runtime)
continue;

if (!spcm->stream[dir].d0i3_compatible)
return false;

if (dir == SNDRV_PCM_STREAM_PLAYBACK)
playback_active = true;
}
}

return playback_active;
}

static int hda_dsp_set_D0_state(struct snd_sof_dev *sdev,
const struct sof_dsp_power_state *target_state)
{
Expand Down Expand Up @@ -453,6 +474,9 @@ static int hda_dsp_set_D0_state(struct snd_sof_dev *sdev,
!hda_enable_trace_D0I3_S0 ||
sdev->system_suspend_target != SOF_SUSPEND_NONE)
flags = HDA_PM_NO_DMA_TRACE;

if (hda_dsp_d0i3_streaming_applicable(sdev))
flags |= HDA_PM_PG_STREAMING;
} else {
/* prevent power gating in D0I0 */
flags = HDA_PM_PPG;
Expand Down
28 changes: 28 additions & 0 deletions sound/soc/sof/intel/hda-ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,32 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}

static inline bool hda_dsp_ipc4_pm_msg(u32 primary)
{
/* pm setting is only supported by module msg */
if (SOF_IPC4_MSG_IS_MODULE_MSG(primary) != SOF_IPC4_MODULE_MSG)
return false;

if (SOF_IPC4_MSG_TYPE_GET(primary) == SOF_IPC4_MOD_SET_DX ||
SOF_IPC4_MSG_TYPE_GET(primary) == SOF_IPC4_MOD_SET_D0IX)
return true;

return false;
}

void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev,
struct snd_sof_ipc_msg *msg)
{
struct sof_ipc4_msg *msg_data = msg->msg_data;

/* Schedule a delayed work for d0i3 entry after sending non-pm ipc msg */
if (hda_dsp_ipc4_pm_msg(msg_data->primary))
return;

mod_delayed_work(system_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
}

int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
Expand All @@ -88,6 +114,8 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI,
msg_data->primary | HDA_DSP_REG_HIPCI_BUSY);

hda_dsp_ipc4_schedule_d0i3_work(hdev, msg);

return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,8 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context);
bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev);
void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev,
struct snd_sof_ipc_msg *msg);
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void hda_ipc4_dump(struct snd_sof_dev *sdev);
extern struct sdw_intel_ops sdw_callback;
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/intel/mtl.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *ms
snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR,
msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY);

hda_dsp_ipc4_schedule_d0i3_work(hdev, msg);

return 0;
}

Expand Down
18 changes: 18 additions & 0 deletions sound/soc/sof/ipc3.c
Original file line number Diff line number Diff line change
Expand Up @@ -1077,10 +1077,28 @@ static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
}

static int sof_ipc3_set_pm_gate(struct snd_sof_dev *sdev, u32 flags)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename to 'set_pm_gate_flags' - which seems to be a better definition of what the functions actually do.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does a bit more than setting flags, it sends the message to firmware to set the 'pm_gate' and the state is described by the 'flags' parameter.
It is more like 'pm_gate_params' if we want to be so generic.

{
struct sof_ipc_pm_gate pm_gate;
struct sof_ipc_reply reply;

memset(&pm_gate, 0, sizeof(pm_gate));

/* configure pm_gate ipc message */
pm_gate.hdr.size = sizeof(pm_gate);
pm_gate.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE;
pm_gate.flags = flags;

/* send pm_gate ipc to dsp */
return sof_ipc_tx_message_no_pm(sdev->ipc, &pm_gate, sizeof(pm_gate),
&reply, sizeof(reply));
}

static const struct sof_ipc_pm_ops ipc3_pm_ops = {
.ctx_save = sof_ipc3_ctx_save,
.ctx_restore = sof_ipc3_ctx_restore,
.set_core_state = sof_ipc3_set_core_state,
.set_pm_gate = sof_ipc3_set_pm_gate,
};

const struct sof_ipc_ops ipc3_ops = {
Expand Down
24 changes: 24 additions & 0 deletions sound/soc/sof/ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,17 @@ static int sof_ipc4_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_
if (!msg_data)
return -EINVAL;

if (!no_pm) {
const struct sof_dsp_power_state target_state = {
.state = SOF_DSP_PM_D0,
};

/* ensure the DSP is in D0i0 before sending a new IPC */
ret = snd_sof_dsp_set_power_state(sdev, &target_state);
if (ret < 0)
return ret;
}

/* Serialise IPC TX */
mutex_lock(&ipc->tx_mutex);

Expand Down Expand Up @@ -653,9 +664,22 @@ static int sof_ipc4_ctx_save(struct snd_sof_dev *sdev)
return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false);
}

static int sof_ipc4_set_pm_gate(struct snd_sof_dev *sdev, u32 flags)
{
struct sof_ipc4_msg msg = {{0}};

msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_D0IX);
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
msg.extension = flags;

return sof_ipc4_tx_msg(sdev, &msg, 0, NULL, 0, true);
}

static const struct sof_ipc_pm_ops ipc4_pm_ops = {
.ctx_save = sof_ipc4_ctx_save,
.set_core_state = sof_ipc4_set_core_state,
.set_pm_gate = sof_ipc4_set_pm_gate,
};

static int sof_ipc4_init(struct snd_sof_dev *sdev)
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,13 @@ struct sof_ipc_fw_tracing_ops {
* @ctx_save: Optional function pointer for context save
* @ctx_restore: Optional function pointer for context restore
* @set_core_state: Optional function pointer for turning on/off a DSP core
* @set_pm_gate: Optional function pointer for pm gate settings
*/
struct sof_ipc_pm_ops {
int (*ctx_save)(struct snd_sof_dev *sdev);
int (*ctx_restore)(struct snd_sof_dev *sdev);
int (*set_core_state)(struct snd_sof_dev *sdev, int core_idx, bool on);
int (*set_pm_gate)(struct snd_sof_dev *sdev, u32 flags);
};

/**
Expand Down