I've looked at the code and byt_is_dsp_busy seems suspicious to me. Can you check if following change fixes problem for you:
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 74274bd38f7a..34746fd871b0 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -666,8 +666,8 @@ static bool byt_is_dsp_busy(struct sst_dsp *dsp) { u64 ipcx;
ipcx = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
return (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE));
ipcx = sst_dsp_shim_read64_unlocked(dsp, SST_IPCX);
return (ipcx & (SST_BYT_IPCX_BUSY | SST_BYT_IPCX_DONE));
}
int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
We seem to treat SST_IPCX as 32 bit register instead of 64 one, which may explain wrong behaviour. (Specification says it is 64 bit register).
Thanks, Amadeusz
Hi Amadeusz,
The patch does not work but I managed to create a workaround just for reference. Still don't know why first read in sst_byt_irq_thread returns incorrect value.
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 5bbaa667bec1..56c557cb722d 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -12,6 +12,7 @@ * more details. */
+#define DEBUG #include <linux/types.h> #include <linux/kernel.h> #include <linux/list.h> @@ -313,7 +314,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) struct sst_dsp *sst = (struct sst_dsp *) context; struct sst_byt *byt = sst_dsp_get_thread_context(sst); struct sst_generic_ipc *ipc = &byt->ipc; - u64 header; + u64 header, mask, old, new; unsigned long flags;
spin_lock_irqsave(&sst->spinlock, flags); @@ -332,10 +333,32 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) * processed the message and can accept new. Clear data part * of the header */ - sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD, - SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY | - IPC_HEADER_DATA(IPC_HEADER_DATA_MASK), - SST_BYT_IPCD_DONE); + /* inline the sst_dsp_shim_update_bits64_unlocked function */ + mask = SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY | + IPC_HEADER_DATA(IPC_HEADER_DATA_MASK); + old = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); + new = (old & (~mask)) | (SST_BYT_IPCD_DONE & mask); + + if (old != new) + sst_dsp_shim_write64_unlocked(sst, SST_IPCD, new); + + /* + * workaround, give it a second chance if the SST_IPCD + * changes + */ + if (old != header) { + dev_dbg(ipc->dev, "%s: header 0x%llx old 0x%llx\n", + __func__, header, old); + if (old & SST_BYT_IPCD_BUSY) { + if (old & IPC_NOTIFICATION) { + /* message from ADSP */ + sst_byt_process_notification(byt, &flags); + } else { + /* reply from ADSP */ + sst_byt_process_reply(byt, old); + } + } + } /* unmask message request interrupts */ sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX, SST_BYT_IMRX_REQUEST, 0);