Skip to content
Closed
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
135 changes: 51 additions & 84 deletions sound/soc/sof/intel/cnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
/*
* Hardware interface for audio DSP on Cannonlake.
*/

#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include "../ops.h"
#include "hda.h"

Expand All @@ -29,95 +30,61 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev);

static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
{
//irqreturn_t ret = IRQ_NONE;
struct snd_sof_dev *sdev = context;
u32 hipci;
u32 hipcctl;
u32 hipcida;
u32 hipctdr;
u32 hipctdd;
u32 msg;
u32 msg_ext;
irqreturn_t ret = IRQ_NONE;

hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL);
hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);

/* reenable IPC interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);

/* reply message from DSP */
if (hipcida & CNL_DSP_REG_HIPCIDA_DONE &&
hipcctl & CNL_DSP_REG_HIPCCTL_DONE) {
unsigned long flags;

hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCIDR);
msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK;
msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK;

dev_vdbg(sdev->dev,
"ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
msg, msg_ext);

/* mask Done interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0);

spin_lock_irqsave(&sdev->ipc_lock, flags);

/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);

if (sdev->code_loading) {
sdev->code_loading = 0;
wake_up(&sdev->waitq);
}

cnl_ipc_dsp_done(sdev);

spin_unlock_irqrestore(&sdev->ipc_lock, flags);

ret = IRQ_HANDLED;
struct hdac_bus *bus = sof_to_bus(sdev);
struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct hdac_stream *s;
u32 status;
u32 sd_status;

//status = sdev->intsts;
status = snd_hdac_chip_readl(bus, INTSTS);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* clear rirb int */
status = snd_hdac_chip_readb(bus, RIRBSTS);
if (status & RIRB_INT_MASK) {
if (status & RIRB_INT_RESPONSE)
snd_hdac_bus_update_rirb(bus);
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
}

/* new message from DSP */
if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCTDD);
msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK;
msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK;

dev_vdbg(sdev->dev,
"ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
msg, msg_ext);

/* handle messages from DSP */
if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) ==
SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext));
} else {
snd_sof_ipc_msgs_rx(sdev);
#endif
dev_err(sdev->dev, "in %s %d ylb, status: %#x\n", __func__, __LINE__, status);
status = snd_hdac_chip_readl(bus, INTSTS);
/* check streams */
list_for_each_entry(s, &bus->stream_list, list) {
if (status & (1 << s->index) && s->opened) {
sd_status = snd_hdac_stream_readb(s, SD_STS);

dev_vdbg(bus->dev, "stream %d status 0x%x\n",
s->index, sd_status);

snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK);

if (!s->substream ||
!s->running ||
(sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
continue;

/* Inform ALSA only in case not do that with IPC */
if (sof_hda->no_ipc_position)
snd_pcm_period_elapsed(s->substream);

}
}

/*
* 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,
CNL_DSP_REG_HIPCTDR,
CNL_DSP_REG_HIPCTDR_BUSY,
CNL_DSP_REG_HIPCTDR_BUSY);

cnl_ipc_host_done(sdev);
if (!sdev->wakeup)
return IRQ_HANDLED;
dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__);
snd_sof_ipc_reply(sdev, 0);

ret = IRQ_HANDLED;
if (sdev->code_loading) {
sdev->code_loading = 0;
wake_up(&sdev->waitq);
}

return ret;
sdev->wakeup = 0;
sdev->intsts = 0;
return IRQ_HANDLED;
}

static void cnl_ipc_host_done(struct snd_sof_dev *sdev)
Expand Down
115 changes: 110 additions & 5 deletions sound/soc/sof/intel/hda-ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,56 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
return ret;
}

static void cnl_ipc_dsp_done_1(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_unlocked(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCIDA,
CNL_DSP_REG_HIPCIDA_DONE,
CNL_DSP_REG_HIPCIDA_DONE);

/* unmask Done interrupt */
snd_sof_dsp_update_bits_unlock(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE,
CNL_DSP_REG_HIPCCTL_DONE);
}

static void cnl_ipc_host_done_1(struct snd_sof_dev *sdev)
{
/*
* set done bit to ack dsp the msg has been
* processed and send reply msg to dsp
*/
snd_sof_dsp_update_bits_forced_unlocked(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCTDA,
CNL_DSP_REG_HIPCTDA_DONE,
CNL_DSP_REG_HIPCTDA_DONE);
}

/* is this IRQ for ADSP ? - we only care about IPC here */
irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
int ret = IRQ_NONE;
u32 hipci;
u32 hipcctl;
u32 hipcida;
u32 hipctdr;
u32 hipctdd;
u32 msg;
u32 msg_ext;
u32 irq_status = 0;

spin_lock(&sdev->hw_lock);

hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL);
hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
sdev->irq_handled = 0;
/* store status */
irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status);
Expand All @@ -256,14 +297,78 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
goto out;

/* IPC message ? */
if (irq_status & HDA_DSP_ADSPIS_IPC) {
/* disable IPC interrupt */
snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_IPC, 0);
if (!(irq_status & HDA_DSP_ADSPIS_IPC))
goto out;

if (hipcida & CNL_DSP_REG_HIPCIDA_DONE &&
hipcctl & CNL_DSP_REG_HIPCCTL_DONE) {
hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCIDR);
msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK;
msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK;

dev_vdbg(sdev->dev,
"ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
msg, msg_ext);

/* mask Done interrupt */
snd_sof_dsp_update_bits_unlock(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0);

/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
sdev->wakeup = 1;
/* snd_sof_ipc_reply(sdev, msg); */

/* if (sdev->code_loading) { */
/* sdev->code_loading = 0; */
/* wake_up(&sdev->waitq); */
/* } */

cnl_ipc_dsp_done_1(sdev);
sdev->irq_handled = 1;

ret = IRQ_WAKE_THREAD;
}

/* new message from DSP */
if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCTDD);
msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK;
msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK;

dev_vdbg(sdev->dev,
"ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
msg, msg_ext);

/* handle messages from DSP */
if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) ==
SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext));
} else {
snd_sof_ipc_msgs_rx(sdev);
}

/*
* clear busy interrupt to tell dsp controller this
* interrupt has been accepted, not trigger it again
*/
snd_sof_dsp_update_bits_forced_unlocked(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCTDR,
CNL_DSP_REG_HIPCTDR_BUSY,
CNL_DSP_REG_HIPCTDR_BUSY);

cnl_ipc_host_done_1(sdev);
sdev->irq_handled = 1;

if (ret == IRQ_NONE)
ret = IRQ_HANDLED;
}
/* /\* reenable IPC interrupt *\/ */
/* snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, */
/* HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); */
out:
spin_unlock(&sdev->hw_lock);
return ret;
Expand Down
42 changes: 38 additions & 4 deletions sound/soc/sof/intel/hda-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,22 +460,26 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,

irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
{
struct hdac_bus *bus = context;
struct snd_sof_dev *sdev = context;
struct hdac_bus *bus = sof_to_bus(sdev);
struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
u32 stream_mask;
u32 status;
struct hdac_stream *s;
u32 sd_status;

dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n",
snd_hdac_chip_readl(bus, INTSTS));

sdev->irq_handled = 0;
if (!pm_runtime_active(bus->dev))
return IRQ_NONE;

spin_lock(&bus->reg_lock);

status = snd_hdac_chip_readl(bus, INTSTS);
stream_mask = GENMASK(sof_hda->stream_max - 1, 0) | AZX_INT_CTRL_EN;

dev_err(sdev->dev, "in %s %d ylb status: %#x, intsts: %#x\n", __func__, __LINE__, status, sdev->intsts);
/* Not stream interrupt or register inaccessible, ignore it.*/
if (!(status & stream_mask) || status == 0xffffffff) {
spin_unlock(&bus->reg_lock);
Expand All @@ -491,10 +495,40 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
}
#endif
dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__);
status = snd_hdac_chip_readl(bus, INTSTS);
dev_err(sdev->dev, "in %s %d ylb status: %#x, intsts: %#x\n", __func__, __LINE__, status, sdev->intsts);
sdev->irq_handled = 1;
if (!sdev->intsts)
sdev->intsts = status;

spin_unlock(&bus->reg_lock);

/* /\* check streams *\/ */
/* list_for_each_entry(s, &bus->stream_list, list) { */
/* if (status & (1 << s->index) && s->opened) { */
/* sd_status = snd_hdac_stream_readb(s, SD_STS); */

/* dev_vdbg(bus->dev, "stream %d status 0x%x\n", */
/* s->index, sd_status); */

return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
/* snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); */

/* if (!s->substream || */
/* !s->running || */
/* (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) */
/* continue; */

/* /\* Inform ALSA only in case not do that with IPC *\/ */
/* if (sof_hda->no_ipc_position) */
/* snd_pcm_period_elapsed(s->substream); */

/* } */
/* } */


spin_unlock(&bus->reg_lock);

return IRQ_HANDLED;
}

irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
Expand Down
Loading