From 13f05a2f651ea755aa238614dd5b11c60a458863 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 31 Oct 2019 16:57:54 +0800 Subject: [PATCH] ASoC: SOF: merge ipc and sdw irq So we can use single irq to handle both ipc and sdw interrupts. Signed-off-by: Bard Liao --- drivers/soundwire/intel_init.c | 27 ++------------------------- include/linux/soundwire/sdw_intel.h | 14 ++++++++++++++ sound/soc/sof/intel/hda-ipc.c | 26 +++++++++++++++++++++++++- sound/soc/sof/intel/hda.c | 2 +- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-priv.h | 5 +++++ 6 files changed, 48 insertions(+), 27 deletions(-) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index ed2a83989c72ff..c6c422c8a5817d 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -163,21 +163,7 @@ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) } EXPORT_SYMBOL(sdw_intel_enable_irq); -static irqreturn_t sdw_intel_irq(int irq, void *dev_id) -{ - struct sdw_intel_ctx *ctx = dev_id; - u32 int_status; - - int_status = readl(ctx->mmio_base + HDA_DSP_REG_ADSPIS2); - if (int_status & HDA_DSP_REG_ADSPIC2_SNDW) { - sdw_intel_enable_irq(ctx->mmio_base, false); - return IRQ_WAKE_THREAD; - } - - return IRQ_NONE; -} - -static irqreturn_t sdw_intel_thread(int irq, void *dev_id) +irqreturn_t sdw_intel_thread(int irq, void *dev_id) { struct sdw_intel_ctx *ctx = dev_id; struct sdw_intel_link_res *link; @@ -188,6 +174,7 @@ static irqreturn_t sdw_intel_thread(int irq, void *dev_id) sdw_intel_enable_irq(ctx->mmio_base, true); return IRQ_HANDLED; } +EXPORT_SYMBOL(sdw_intel_thread); static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) @@ -199,7 +186,6 @@ static struct sdw_intel_ctx u32 link_mask; int count; int i; - int ret; if (!res) return NULL; @@ -261,15 +247,6 @@ static struct sdw_intel_ctx list_add_tail(&link->list, &ctx->link_list); } - ret = request_threaded_irq(ctx->irq, - sdw_intel_irq, sdw_intel_thread, - IRQF_SHARED, KBUILD_MODNAME, ctx); - if (ret < 0) { - dev_err(&adev->dev, "unable to grab IRQ %d, disabling device\n", - res->irq); - goto err; - } - return ctx; err: diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 373947003cea01..6556b7a089644f 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -123,4 +123,18 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx); void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable); +irqreturn_t sdw_intel_thread(int irq, void *dev_id); + +static inline +bool is_sdw_intel_irq(struct sdw_intel_ctx *ctx) +{ + u32 int_status; + + int_status = readl(ctx->mmio_base + 0x14); + if (int_status & BIT(5)) + return true; + + return false; +} + #endif diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 0fd2153c176953..620fed2a1eb1ce 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -237,15 +237,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -/* is this IRQ for ADSP ? - we only care about IPC here */ +/* is this IRQ for ADSP or SDW? - we only care about IPC and SDW here */ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; int ret = IRQ_NONE; u32 irq_status; spin_lock(&sdev->hw_lock); + sdev->irq_event = 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); @@ -260,6 +263,13 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, HDA_DSP_ADSPIC_IPC, 0); + sdev->irq_event |= SOF_IRQ_IPC; + ret = IRQ_WAKE_THREAD; + } + /* SDW message */ + if (hdev->sdw && is_sdw_intel_irq(hdev->sdw)) { + hda_sdw_int_enable(sdev, false); + sdev->irq_event |= SOF_IRQ_SDW; ret = IRQ_WAKE_THREAD; } @@ -268,6 +278,20 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) return ret; } +irqreturn_t hda_dsp_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + if (sdev->irq_event & SOF_IRQ_IPC) + sof_ops(sdev)->irq_thread(irq, context); + + if (sdev->irq_event & SOF_IRQ_SDW) + sdw_intel_thread(irq, hdev->sdw); + + return IRQ_HANDLED; +} + int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return HDA_DSP_MBOX_UPLINK_OFFSET; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 91bd88fddac7aa..adf5ee206c7b43 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -632,7 +632,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, - sof_ops(sdev)->irq_thread, IRQF_SHARED, + hda_dsp_irq_thread, IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 18d7e72bf9b722..c988e1b509b8ce 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -542,6 +542,7 @@ int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); +irqreturn_t hda_dsp_irq_thread(int irq, void *context); int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); /* diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6408ac88a3e582..de9f37f023eba3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -36,6 +36,10 @@ #define SOF_DBG_PCI BIT(4) #define SOF_DBG_RETAIN_CTX BIT(5) /* prevent DSP D3 on FW exception */ +/* interrupt event flags */ +#define SOF_IRQ_IPC BIT(0) +#define SOF_IRQ_SDW BIT(1) + /* global debug state set by SOF_DBG_ flags */ extern int sof_core_debug; @@ -424,6 +428,7 @@ struct snd_sof_dev { struct snd_sof_mailbox stream_box; /* Stream position update */ struct snd_sof_ipc_msg *msg; int ipc_irq; + u32 irq_event; /* Which interrupt are triggered*/ u32 next_comp_id; /* monotonic - reset during S3 */ /* memory bases for mmaped DSPs - set by dsp_init() */