Skip to content
Open
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
17 changes: 2 additions & 15 deletions sound/soc/sof/intel/cnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
bool ack_received = false;
bool ipc_irq = false;
u32 hipcida, hipctdr;

Expand All @@ -51,7 +50,6 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
cnl_ipc_dsp_done(sdev);

ipc_irq = true;
ack_received = true;
}

if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
Expand Down Expand Up @@ -98,13 +96,6 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
/* 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)
cnl_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
}

return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS(cnl_ipc4_irq_thread, "SND_SOC_SOF_INTEL_CNL");
Expand Down Expand Up @@ -259,12 +250,8 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;

if (hda_ipc4_tx_is_busy(sdev)) {
hdev->delayed_ipc_tx_msg = msg;
return 0;
}

hdev->delayed_ipc_tx_msg = NULL;
if (hda_ipc4_tx_is_busy(sdev))
return -EBUSY;

/* send the message via mailbox */
if (msg_data->data_size)
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/intel/hda-common-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = {
.unregister_ipc_clients = hda_unregister_clients,

/* DAI drivers */
.dai_link_hw_ready = hda_sdw_dai_hw_ready,
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
.is_chain_dma_supported = hda_is_chain_dma_supported,
Expand Down
17 changes: 2 additions & 15 deletions sound/soc/sof/intel/hda-ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,8 @@ 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;
struct sof_ipc4_msg *msg_data = msg->msg_data;

if (hda_ipc4_tx_is_busy(sdev)) {
hdev->delayed_ipc_tx_msg = msg;
return 0;
}

hdev->delayed_ipc_tx_msg = NULL;
if (hda_ipc4_tx_is_busy(sdev))
return -EBUSY;

/* send the message via mailbox */
if (msg_data->data_size)
Expand Down Expand Up @@ -168,7 +164,6 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
bool ack_received = false;
bool ipc_irq = false;
u32 hipcie, hipct;

Expand All @@ -182,7 +177,6 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
hda_dsp_ipc_dsp_done(sdev);

ipc_irq = true;
ack_received = true;
}

if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
Expand Down Expand Up @@ -233,13 +227,6 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
/* 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)
hda_dsp_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
}

return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS(hda_dsp_ipc4_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON");
Expand Down
44 changes: 44 additions & 0 deletions sound/soc/sof/intel/hda.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,50 @@ static void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev)
chip->process_mic_privacy(sdev, true, AZX_REG_ML_LEPTR_ID_SDW);
}

int hda_sdw_dai_hw_ready(struct snd_sof_dev *sdev, int dai_type)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sdw_peripherals *sdw_p;
long ret;
int idx;

if (dai_type != SOF_DAI_INTEL_ALH)
return 0;

if (!hdev || !hdev->sdw || !hdev->sdw->peripherals)
return 0;

sdw_p = hdev->sdw->peripherals;

for (idx = 0; idx < sdw_p->num_peripherals; idx++) {
struct sdw_slave *slave = sdw_p->array[idx];

if (!slave)
continue;

if (slave->status != SDW_SLAVE_ATTACHED)
continue;

ret = wait_for_completion_interruptible_timeout(
&slave->initialization_complete,
msecs_to_jiffies(2000));
if (ret == 0) {
dev_err(sdev->dev,
"timeout waiting for SoundWire slave %s initialization\n",
dev_name(&slave->dev));
return -ETIMEDOUT;
}
if (ret < 0) {
dev_dbg(sdev->dev,
"interrupted waiting for SoundWire slave %s initialization: %ld\n",
dev_name(&slave->dev), ret);
return ret;
}
}

return 0;
}

#else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
{
Expand Down
14 changes: 6 additions & 8 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,6 @@ struct sof_intel_hda_dev {

/* work queue for mic privacy state change notification sending */
struct sof_ace3_mic_privacy mic_privacy;

/*
* Pointing to the IPC message if immediate sending was not possible
* because the downlink communication channel was BUSY at the time.
* The message will be re-tried when the channel becomes free (the ACK
* is received from the DSP for the previous message)
*/
struct snd_sof_ipc_msg *delayed_ipc_tx_msg;
};

static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
Expand Down Expand Up @@ -841,6 +833,7 @@ bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev);
void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev);
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
int hda_sdw_dai_hw_ready(struct snd_sof_dev *sdev, int dai_type);

#else

Expand Down Expand Up @@ -890,6 +883,11 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
return false;
}

static inline int hda_sdw_dai_hw_ready(struct snd_sof_dev *sdev, int dai_type)
{
return 0;
}

#endif

int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
Expand Down
17 changes: 2 additions & 15 deletions sound/soc/sof/intel/mtl.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,8 @@ static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *ms
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;

if (hda_ipc4_tx_is_busy(sdev)) {
hdev->delayed_ipc_tx_msg = msg;
return 0;
}

hdev->delayed_ipc_tx_msg = NULL;
if (hda_ipc4_tx_is_busy(sdev))
return -EBUSY;

/* send the message via mailbox */
if (msg_data->data_size)
Expand Down Expand Up @@ -562,7 +558,6 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
bool ack_received = false;
bool ipc_irq = false;
u32 hipcida;
u32 hipctdr;
Expand All @@ -579,7 +574,6 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
mtl_ipc_dsp_done(sdev);

ipc_irq = true;
ack_received = true;
}

if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
Expand Down Expand Up @@ -628,13 +622,6 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
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);
}

return IRQ_HANDLED;
}

Expand Down
8 changes: 8 additions & 0 deletions sound/soc/sof/ipc4-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,14 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
{
/* Wait for DAI link hardware (e.g. SoundWire slaves) to be ready */
if (sdev->pdata->desc->ops->dai_link_hw_ready) {
ret = sdev->pdata->desc->ops->dai_link_hw_ready(
sdev, ipc4_copier->dai_type);
if (ret)
return ret;
}

/*
* Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
* That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt
Expand Down
17 changes: 15 additions & 2 deletions sound/soc/sof/ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,20 +367,33 @@ static int ipc4_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
return ret;
}

#define SOF_IPC4_TX_BUSY_RETRIES 50
#define SOF_IPC4_TX_BUSY_DELAY_US 100
#define SOF_IPC4_TX_BUSY_DELAY_MAX_US 200

static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes)
{
struct sof_ipc4_msg *ipc4_msg = msg_data;
struct snd_sof_dev *sdev = ipc->sdev;
int ret;
int ret, i;

if (msg_bytes > ipc->max_payload_size || reply_bytes > ipc->max_payload_size)
return -EINVAL;

sof_ipc4_log_header(sdev->dev, "ipc tx ", msg_data, true);

ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
for (i = 0; i < SOF_IPC4_TX_BUSY_RETRIES; i++) {
ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
if (ret != -EBUSY)
break;
usleep_range(SOF_IPC4_TX_BUSY_DELAY_US,
SOF_IPC4_TX_BUSY_DELAY_MAX_US);
}
if (i == SOF_IPC4_TX_BUSY_RETRIES)
dev_dbg(sdev->dev, "%s: TX still busy after %d retries\n",
__func__, i);
if (ret) {
dev_err_ratelimited(sdev->dev,
"%s: ipc message send for %#x|%#x failed: %d\n",
Expand Down
3 changes: 3 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,9 @@ struct snd_sof_dsp_ops {
int (*register_ipc_clients)(struct snd_sof_dev *sdev); /* optional */
void (*unregister_ipc_clients)(struct snd_sof_dev *sdev); /* optional */

/* optional: wait for DAI link hardware readiness (e.g. SoundWire slave init) */
int (*dai_link_hw_ready)(struct snd_sof_dev *sdev, int dai_type); /* optional */

/* DAI ops */
struct snd_soc_dai_driver *drv;
int num_drv;
Expand Down
Loading