summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/intel')
-rw-r--r--sound/soc/sof/intel/Kconfig33
-rw-r--r--sound/soc/sof/intel/apl.c4
-rw-r--r--sound/soc/sof/intel/bdw.c166
-rw-r--r--sound/soc/sof/intel/byt.c174
-rw-r--r--sound/soc/sof/intel/cnl.c40
-rw-r--r--sound/soc/sof/intel/hda-bus.c86
-rw-r--r--sound/soc/sof/intel/hda-codec.c50
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c21
-rw-r--r--sound/soc/sof/intel/hda-dai.c38
-rw-r--r--sound/soc/sof/intel/hda-dsp.c100
-rw-r--r--sound/soc/sof/intel/hda-ipc.c154
-rw-r--r--sound/soc/sof/intel/hda.c132
-rw-r--r--sound/soc/sof/intel/hda.h18
13 files changed, 342 insertions, 674 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index dd14ce92fe10..479ba249e219 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -27,6 +27,8 @@ config SND_SOC_SOF_INTEL_PCI
select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT
select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT
select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT
+ select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT
+ select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level
@@ -212,6 +214,36 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_SOF_TIGERLAKE_SUPPORT
+ bool "SOF support for Tigerlake"
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Tigerlake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_TIGERLAKE
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
+
+config SND_SOC_SOF_ELKHARTLAKE_SUPPORT
+ bool "SOF support for ElkhartLake"
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the ElkhartLake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_ELKHARTLAKE
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
+
config SND_SOC_SOF_HDA_COMMON
tristate
select SND_SOC_SOF_INTEL_COMMON
@@ -254,6 +286,7 @@ config SND_SOC_SOF_HDA
tristate
select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
+ select SND_INTEL_NHLT if ACPI
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index fd2e26d79796..8dc7a5558da4 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -46,7 +46,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
/* ipc */
.send_msg = hda_dsp_ipc_send_msg,
- .fw_ready = hda_dsp_ipc_fw_ready,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
+ .get_window_offset = hda_dsp_ipc_get_window_offset,
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index 70d524ef9bc0..e282179263e8 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -328,153 +328,6 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
}
/*
- * IPC Firmware ready.
- */
-static void bdw_get_windows(struct snd_sof_dev *sdev)
-{
- struct sof_ipc_window_elem *elem;
- u32 outbox_offset = 0;
- u32 stream_offset = 0;
- u32 inbox_offset = 0;
- u32 outbox_size = 0;
- u32 stream_size = 0;
- u32 inbox_size = 0;
- int i;
-
- if (!sdev->info_window) {
- dev_err(sdev->dev, "error: have no window info\n");
- return;
- }
-
- for (i = 0; i < sdev->info_window->num_windows; i++) {
- elem = &sdev->info_window->window[i];
-
- switch (elem->type) {
- case SOF_IPC_REGION_UPBOX:
- inbox_offset = elem->offset + MBOX_OFFSET;
- inbox_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- inbox_offset,
- elem->size, "inbox",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_DOWNBOX:
- outbox_offset = elem->offset + MBOX_OFFSET;
- outbox_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- outbox_offset,
- elem->size, "outbox",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_TRACE:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "etrace",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_DEBUG:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "debug",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_STREAM:
- stream_offset = elem->offset + MBOX_OFFSET;
- stream_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- stream_offset,
- elem->size, "stream",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_REGS:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "regs",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_EXCEPTION:
- sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BDW_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "exception",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- default:
- dev_err(sdev->dev, "error: get illegal window info\n");
- return;
- }
- }
-
- if (outbox_size == 0 || inbox_size == 0) {
- dev_err(sdev->dev, "error: get illegal mailbox window\n");
- return;
- }
-
- snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
- outbox_offset, outbox_size);
- sdev->stream_box.offset = stream_offset;
- sdev->stream_box.size = stream_size;
-
- dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
- inbox_offset, inbox_size);
- dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
- outbox_offset, outbox_size);
- dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
- stream_offset, stream_size);
-}
-
-/* check for ABI compatibility and create memory windows on first boot */
-static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
-{
- struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
- u32 offset;
- int ret;
-
- /* mailbox must be on 4k boundary */
- offset = MBOX_OFFSET;
-
- dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
- msg_id, offset);
-
- /* no need to re-check version/ABI for subsequent boots */
- if (!sdev->first_boot)
- return 0;
-
- /* copy data from the DSP FW ready offset */
- sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready,
- sizeof(*fw_ready));
-
- snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset,
- fw_ready->dspbox_size,
- fw_ready->hostbox_offset,
- fw_ready->hostbox_size);
-
- /* make sure ABI version is compatible */
- ret = snd_sof_ipc_valid(sdev);
- if (ret < 0)
- return ret;
-
- /* now check for extended data */
- snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET +
- sizeof(struct sof_ipc_fw_ready));
-
- bdw_get_windows(sdev);
-
- return 0;
-}
-
-/*
* IPC Mailbox IO
*/
@@ -527,6 +380,16 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
msg->reply_error = ret;
}
+static int bdw_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+ return MBOX_OFFSET;
+}
+
+static int bdw_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+ return MBOX_OFFSET;
+}
+
static void bdw_host_done(struct snd_sof_dev *sdev)
{
/* clear BUSY bit and set DONE bit - accept new messages */
@@ -613,11 +476,8 @@ static int bdw_probe(struct snd_sof_dev *sdev)
/* register our IRQ */
sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
- if (sdev->ipc_irq < 0) {
- dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
- desc->irqindex_host_ipc);
+ if (sdev->ipc_irq < 0)
return sdev->ipc_irq;
- }
dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
@@ -680,7 +540,9 @@ const struct snd_sof_dsp_ops sof_bdw_ops = {
/* ipc */
.send_msg = bdw_send_msg,
- .fw_ready = bdw_fw_ready,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = bdw_get_mailbox_offset,
+ .get_window_offset = bdw_get_window_offset,
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 107d711efc3f..5e7a6aaa627a 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -110,153 +110,6 @@ static void byt_dsp_done(struct snd_sof_dev *sdev);
static void byt_get_reply(struct snd_sof_dev *sdev);
/*
- * IPC Firmware ready.
- */
-static void byt_get_windows(struct snd_sof_dev *sdev)
-{
- struct sof_ipc_window_elem *elem;
- u32 outbox_offset = 0;
- u32 stream_offset = 0;
- u32 inbox_offset = 0;
- u32 outbox_size = 0;
- u32 stream_size = 0;
- u32 inbox_size = 0;
- int i;
-
- if (!sdev->info_window) {
- dev_err(sdev->dev, "error: have no window info\n");
- return;
- }
-
- for (i = 0; i < sdev->info_window->num_windows; i++) {
- elem = &sdev->info_window->window[i];
-
- switch (elem->type) {
- case SOF_IPC_REGION_UPBOX:
- inbox_offset = elem->offset + MBOX_OFFSET;
- inbox_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- inbox_offset,
- elem->size, "inbox",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_DOWNBOX:
- outbox_offset = elem->offset + MBOX_OFFSET;
- outbox_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- outbox_offset,
- elem->size, "outbox",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_TRACE:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "etrace",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_DEBUG:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "debug",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_STREAM:
- stream_offset = elem->offset + MBOX_OFFSET;
- stream_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- stream_offset,
- elem->size, "stream",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_REGS:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "regs",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_EXCEPTION:
- sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[BYT_DSP_BAR] +
- elem->offset +
- MBOX_OFFSET,
- elem->size, "exception",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- default:
- dev_err(sdev->dev, "error: get illegal window info\n");
- return;
- }
- }
-
- if (outbox_size == 0 || inbox_size == 0) {
- dev_err(sdev->dev, "error: get illegal mailbox window\n");
- return;
- }
-
- snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
- outbox_offset, outbox_size);
- sdev->stream_box.offset = stream_offset;
- sdev->stream_box.size = stream_size;
-
- dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
- inbox_offset, inbox_size);
- dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
- outbox_offset, outbox_size);
- dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
- stream_offset, stream_size);
-}
-
-/* check for ABI compatibility and create memory windows on first boot */
-static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
-{
- struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
- u32 offset;
- int ret;
-
- /* mailbox must be on 4k boundary */
- offset = MBOX_OFFSET;
-
- dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
- msg_id, offset);
-
- /* no need to re-check version/ABI for subsequent boots */
- if (!sdev->first_boot)
- return 0;
-
- /* copy data from the DSP FW ready offset */
- sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready,
- sizeof(*fw_ready));
-
- snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset,
- fw_ready->dspbox_size,
- fw_ready->hostbox_offset,
- fw_ready->hostbox_size);
-
- /* make sure ABI version is compatible */
- ret = snd_sof_ipc_valid(sdev);
- if (ret < 0)
- return ret;
-
- /* now check for extended data */
- snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET +
- sizeof(struct sof_ipc_fw_ready));
-
- byt_get_windows(sdev);
-
- return 0;
-}
-
-/*
* Debug
*/
@@ -423,6 +276,16 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
msg->reply_error = ret;
}
+static int byt_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+ return MBOX_OFFSET;
+}
+
+static int byt_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+ return MBOX_OFFSET;
+}
+
static void byt_host_done(struct snd_sof_dev *sdev)
{
/* clear BUSY bit and set DONE bit - accept new messages */
@@ -617,7 +480,9 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
/* ipc */
.send_msg = byt_send_msg,
- .fw_ready = byt_fw_ready,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = byt_get_mailbox_offset,
+ .get_window_offset = byt_get_window_offset,
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
@@ -728,11 +593,8 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev)
irq:
/* register our IRQ */
sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
- if (sdev->ipc_irq < 0) {
- dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
- desc->irqindex_host_ipc);
+ if (sdev->ipc_irq < 0)
return sdev->ipc_irq;
- }
dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
@@ -779,7 +641,9 @@ const struct snd_sof_dsp_ops sof_byt_ops = {
/* ipc */
.send_msg = byt_send_msg,
- .fw_ready = byt_fw_ready,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = byt_get_mailbox_offset,
+ .get_window_offset = byt_get_window_offset,
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
@@ -836,7 +700,9 @@ const struct snd_sof_dsp_ops sof_cht_ops = {
/* ipc */
.send_msg = byt_send_msg,
- .fw_ready = byt_fw_ready,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = byt_get_mailbox_offset,
+ .get_window_offset = byt_get_window_offset,
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index f2b392998f20..4ddd73762d81 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -101,8 +101,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
/*
* This interrupt is not shared so no need to return IRQ_NONE.
*/
- dev_err_ratelimited(sdev->dev,
- "error: nothing to do in IRQ thread\n");
+ dev_dbg_ratelimited(sdev->dev,
+ "nothing to do in IPC IRQ thread\n");
}
/* re-enable IPC interrupt */
@@ -204,7 +204,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
/* ipc */
.send_msg = cnl_ipc_send_msg,
- .fw_ready = hda_dsp_ipc_fw_ready,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
+ .get_window_offset = hda_dsp_ipc_get_window_offset,
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
@@ -293,3 +295,35 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
EXPORT_SYMBOL(icl_chip_info);
+
+const struct sof_intel_dsp_desc tgl_chip_info = {
+ /* Tigerlake */
+ .cores_num = 4,
+ .init_core_mask = 1,
+ .cores_mask = HDA_DSP_CORE_MASK(0),
+ .ipc_req = CNL_DSP_REG_HIPCIDR,
+ .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+ .ipc_ack = CNL_DSP_REG_HIPCIDA,
+ .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+ .ipc_ctl = CNL_DSP_REG_HIPCCTL,
+ .rom_init_timeout = 300,
+ .ssp_count = ICL_SSP_COUNT,
+ .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL(tgl_chip_info);
+
+const struct sof_intel_dsp_desc ehl_chip_info = {
+ /* Elkhartlake */
+ .cores_num = 4,
+ .init_core_mask = 1,
+ .cores_mask = HDA_DSP_CORE_MASK(0),
+ .ipc_req = CNL_DSP_REG_HIPCIDR,
+ .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
+ .ipc_ack = CNL_DSP_REG_HIPCIDA,
+ .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
+ .ipc_ctl = CNL_DSP_REG_HIPCCTL,
+ .rom_init_timeout = 300,
+ .ssp_count = ICL_SSP_COUNT,
+ .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+};
+EXPORT_SYMBOL(ehl_chip_info);
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index a7e6d8227df6..1d2babdda9dd 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -12,82 +12,27 @@
#include "../sof-priv.h"
#include "hda.h"
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-
-static const struct hdac_bus_ops bus_ops = {
- .command = snd_hdac_bus_send_cmd,
- .get_response = snd_hdac_bus_get_response,
-};
-
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+#include "../../codecs/hdac_hda.h"
+#define sof_hda_ext_ops snd_soc_hdac_hda_get_ops()
+#else
+#define sof_hda_ext_ops NULL
#endif
-static void sof_hda_writel(u32 value, u32 __iomem *addr)
-{
- writel(value, addr);
-}
-
-static u32 sof_hda_readl(u32 __iomem *addr)
-{
- return readl(addr);
-}
-
-static void sof_hda_writew(u16 value, u16 __iomem *addr)
-{
- writew(value, addr);
-}
-
-static u16 sof_hda_readw(u16 __iomem *addr)
-{
- return readw(addr);
-}
-
-static void sof_hda_writeb(u8 value, u8 __iomem *addr)
-{
- writeb(value, addr);
-}
-
-static u8 sof_hda_readb(u8 __iomem *addr)
-{
- return readb(addr);
-}
-
-static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type,
- size_t size, struct snd_dma_buffer *buf)
-{
- return snd_dma_alloc_pages(type, bus->dev, size, buf);
-}
-
-static void sof_hda_dma_free_pages(struct hdac_bus *bus,
- struct snd_dma_buffer *buf)
-{
- snd_dma_free_pages(buf);
-}
-
-static const struct hdac_io_ops io_ops = {
- .reg_writel = sof_hda_writel,
- .reg_readl = sof_hda_readl,
- .reg_writew = sof_hda_writew,
- .reg_readw = sof_hda_readw,
- .reg_writeb = sof_hda_writeb,
- .reg_readb = sof_hda_readb,
- .dma_alloc_pages = sof_hda_dma_alloc_pages,
- .dma_free_pages = sof_hda_dma_free_pages,
-};
-
/*
* This can be used for both with/without hda link support.
*/
-void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev,
- const struct hdac_ext_bus_ops *ext_ops)
+void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev)
{
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ snd_hdac_ext_bus_init(bus, dev, NULL, sof_hda_ext_ops);
+#else /* CONFIG_SND_SOC_SOF_HDA */
memset(bus, 0, sizeof(*bus));
bus->dev = dev;
- bus->io_ops = &io_ops;
INIT_LIST_HEAD(&bus->stream_list);
bus->irq = -1;
- bus->ext_ops = ext_ops;
/*
* There is only one HDA bus atm. keep the index as 0.
@@ -96,16 +41,5 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev,
bus->idx = 0;
spin_lock_init(&bus->reg_lock);
-
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
- INIT_LIST_HEAD(&bus->codec_list);
- INIT_LIST_HEAD(&bus->hlink_list);
-
- mutex_init(&bus->cmd_mutex);
- mutex_init(&bus->lock);
- bus->ops = &bus_ops;
- INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
- bus->cmd_dma_state = true;
-#endif
-
+#endif /* CONFIG_SND_SOC_SOF_HDA */
}
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index b8b37f082309..3ca6795a89ba 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <sound/hdaudio_ext.h>
+#include <sound/hda_register.h>
#include <sound/hda_codec.h>
#include <sound/hda_i915.h>
#include <sound/sof.h>
@@ -37,16 +38,55 @@ static void hda_codec_load_module(struct hda_codec *codec)
static void hda_codec_load_module(struct hda_codec *codec) {}
#endif
+/* enable controller wake up event for all codecs with jack connectors */
+void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev)
+{
+ struct hda_bus *hbus = sof_to_hbus(sdev);
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct hda_codec *codec;
+ unsigned int mask = 0;
+
+ list_for_each_codec(codec, hbus)
+ if (codec->jacktbl.used)
+ mask |= BIT(codec->core.addr);
+
+ snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
+}
+
+/* check jack status after resuming from suspend mode */
+void hda_codec_jack_check(struct snd_sof_dev *sdev)
+{
+ struct hda_bus *hbus = sof_to_hbus(sdev);
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct hda_codec *codec;
+
+ /* disable controller Wake Up event*/
+ snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
+
+ list_for_each_codec(codec, hbus)
+ /*
+ * Wake up all jack-detecting codecs regardless whether an event
+ * has been recorded in STATESTS
+ */
+ if (codec->jacktbl.used)
+ schedule_delayed_work(&codec->jackpoll_work,
+ codec->jackpoll_interval);
+}
+#else
+void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {}
+void hda_codec_jack_check(struct snd_sof_dev *sdev) {}
#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
+EXPORT_SYMBOL(hda_codec_jack_wake_enable);
+EXPORT_SYMBOL(hda_codec_jack_check);
/* probe individual codec */
static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
{
- struct hda_bus *hbus = sof_to_hbus(sdev);
- struct hdac_device *hdev;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
struct hdac_hda_priv *hda_priv;
#endif
+ struct hda_bus *hbus = sof_to_hbus(sdev);
+ struct hdac_device *hdev;
u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
u32 resp = -1;
@@ -62,8 +102,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
address, resp);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
- /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */
- hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL);
+ hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL);
if (!hda_priv)
return -ENOMEM;
@@ -82,8 +121,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
return 0;
#else
- /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */
- hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
+ hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
if (!hdev)
return -ENOMEM;
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index ea63f83a509b..bc41028a7a01 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -164,6 +164,9 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ struct hdac_ext_link *hlink;
+#endif
struct hdac_stream *stream;
int sd_offset, ret = 0;
@@ -173,11 +176,6 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
hda_dsp_ctrl_misc_clock_gating(sdev, false);
if (full_reset) {
- /* clear WAKESTS */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
- SOF_HDA_WAKESTS_INT_MASK,
- SOF_HDA_WAKESTS_INT_MASK);
-
/* reset HDA controller */
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
@@ -245,13 +243,18 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* program the position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
- snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
- snd_hdac_chip_writel(bus, DPUBASE,
- upper_32_bits(bus->posbuf.addr));
+ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE,
+ (u32)bus->posbuf.addr);
+ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE,
+ upper_32_bits(bus->posbuf.addr));
}
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ /* Reset stream-to-link mapping */
+ list_for_each_entry(hlink, &bus->hlink_list, list)
+ writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
#endif
bus->chip_init = true;
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index a514f9cf5c9a..8796f385be76 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -210,9 +210,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
int stream_tag;
int ret;
- link_dev = hda_link_stream_assign(bus, substream);
- if (!link_dev)
- return -EBUSY;
+ /* get stored dma data if resuming from system suspend */
+ link_dev = snd_soc_dai_get_dma_data(dai, substream);
+ if (!link_dev) {
+ link_dev = hda_link_stream_assign(bus, substream);
+ if (!link_dev)
+ return -EBUSY;
+ }
stream_tag = hdac_stream(link_dev)->stream_tag;
@@ -226,8 +230,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- hda_stream->hw_params_upon_resume = 0;
-
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -267,8 +269,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream,
hda_stream = hstream_to_sof_hda_stream(link_dev);
- /* setup hw_params again only if resuming from system suspend */
- if (!hda_stream->hw_params_upon_resume)
+ if (link_dev->link_prepared)
return 0;
dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
@@ -317,22 +318,25 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
snd_hdac_ext_link_stream_start(link_dev);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
/*
- * clear and release link DMA channel. It will be assigned when
+ * clear link DMA channel. It will be assigned when
* hw_params is set up again after resume.
*/
ret = hda_link_config_ipc(hda_stream, dai->name,
DMA_CHAN_INVALID, substream->stream);
if (ret < 0)
return ret;
- stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
- snd_hdac_ext_stream_release(link_dev,
- HDAC_EXT_STREAM_TYPE_LINK);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ stream_tag = hdac_stream(link_dev)->stream_tag;
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ }
+
+ link_dev->link_prepared = 0;
/* fallthrough */
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(link_dev);
break;
default:
@@ -369,8 +373,12 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
if (!link)
return -EINVAL;
- stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ stream_tag = hdac_stream(link_dev)->stream_tag;
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ }
+
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
link_dev->link_prepared = 0;
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 91de4785b6a3..fb55a3c5afd0 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -282,7 +282,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0);
}
-static int hda_suspend(struct snd_sof_dev *sdev, int state)
+static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
@@ -295,6 +295,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state)
hda_dsp_ipc_int_disable(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ if (runtime_suspend)
+ hda_codec_jack_wake_enable(sdev);
+
/* power down all hda link */
snd_hdac_ext_bus_link_power_down_all(bus);
#endif
@@ -329,7 +332,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state)
return 0;
}
-static int hda_resume(struct snd_sof_dev *sdev)
+static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_bus *bus = sof_to_bus(sdev);
@@ -343,7 +346,6 @@ static int hda_resume(struct snd_sof_dev *sdev)
*/
snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* reset and start hda controller */
ret = hda_dsp_ctrl_init_chip(sdev, true);
if (ret < 0) {
@@ -352,46 +354,11 @@ static int hda_resume(struct snd_sof_dev *sdev)
return ret;
}
- hda_dsp_ctrl_misc_clock_gating(sdev, false);
-
- /* Reset stream-to-link mapping */
- list_for_each_entry(hlink, &bus->hlink_list, list)
- bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
-
- hda_dsp_ctrl_misc_clock_gating(sdev, true);
-#else
-
- hda_dsp_ctrl_misc_clock_gating(sdev, false);
-
- /* reset controller */
- ret = hda_dsp_ctrl_link_reset(sdev, true);
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to reset controller during resume\n");
- return ret;
- }
-
- /* take controller out of reset */
- ret = hda_dsp_ctrl_link_reset(sdev, false);
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to ready controller during resume\n");
- return ret;
- }
-
- /* enable hda bus irq */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
- SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
- SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
-
- hda_dsp_ctrl_misc_clock_gating(sdev, true);
-#endif
-
- /* enable ppcap interrupt */
- hda_dsp_ctrl_ppcap_enable(sdev, true);
- hda_dsp_ctrl_ppcap_int_enable(sdev, true);
-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ /* check jack status */
+ if (runtime_resume)
+ hda_codec_jack_check(sdev);
+
/* turn off the links that were off before suspend */
list_for_each_entry(hlink, &bus->hlink_list, list) {
if (!hlink->ref_count)
@@ -403,19 +370,23 @@ static int hda_resume(struct snd_sof_dev *sdev)
snd_hdac_bus_stop_cmd_io(bus);
#endif
+ /* enable ppcap interrupt */
+ hda_dsp_ctrl_ppcap_enable(sdev, true);
+ hda_dsp_ctrl_ppcap_int_enable(sdev, true);
+
return 0;
}
int hda_dsp_resume(struct snd_sof_dev *sdev)
{
/* init hda controller. DSP cores will be powered up during fw boot */
- return hda_resume(sdev);
+ return hda_resume(sdev, false);
}
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
{
/* init hda controller. DSP cores will be powered up during fw boot */
- return hda_resume(sdev);
+ return hda_resume(sdev, true);
}
int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
@@ -431,19 +402,19 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
return 0;
}
-int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state)
+int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
{
/* stop hda controller and power dsp off */
- return hda_suspend(sdev, state);
+ return hda_suspend(sdev, true);
}
-int hda_dsp_suspend(struct snd_sof_dev *sdev, int state)
+int hda_dsp_suspend(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
int ret;
/* stop hda controller and power dsp off */
- ret = hda_suspend(sdev, state);
+ ret = hda_suspend(sdev, false);
if (ret < 0) {
dev_err(bus->dev, "error: suspending dsp\n");
return ret;
@@ -454,30 +425,24 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state)
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
- struct sof_intel_hda_stream *hda_stream;
- struct hdac_ext_stream *stream;
- struct hdac_stream *s;
-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_soc_pcm_runtime *rtd;
+ struct hdac_ext_stream *stream;
struct hdac_ext_link *link;
+ struct hdac_stream *s;
const char *name;
int stream_tag;
-#endif
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s);
- hda_stream = container_of(stream, struct sof_intel_hda_stream,
- hda_stream);
- hda_stream->hw_params_upon_resume = 1;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+
/*
- * clear and release stream. This should already be taken care
- * for running streams when the SUSPEND trigger is called.
- * But paused streams do not get suspended, so this needs to be
- * done explicitly during suspend.
+ * clear stream. This should already be taken care for running
+ * streams when the SUSPEND trigger is called. But paused
+ * streams do not get suspended, so this needs to be done
+ * explicitly during suspend.
*/
if (stream->link_substream) {
rtd = snd_pcm_substream_chip(stream->link_substream);
@@ -485,12 +450,17 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
link = snd_hdac_ext_bus_get_link(bus, name);
if (!link)
return -EINVAL;
+
+ stream->link_prepared = 0;
+
+ if (hdac_stream(stream)->direction ==
+ SNDRV_PCM_STREAM_CAPTURE)
+ continue;
+
stream_tag = hdac_stream(stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
- snd_hdac_ext_stream_release(stream,
- HDAC_EXT_STREAM_TYPE_LINK);
}
-#endif
}
+#endif
return 0;
}
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index 50244b82600c..6aae6f18b3dc 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -224,8 +224,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
/*
* This interrupt is not shared so no need to return IRQ_NONE.
*/
- dev_err_ratelimited(sdev->dev,
- "error: nothing to do in IRQ thread\n");
+ dev_dbg_ratelimited(sdev->dev,
+ "nothing to do in IPC IRQ thread\n");
}
/* re-enable IPC interrupt */
@@ -266,156 +266,14 @@ out:
return ret;
}
-/* IPC Firmware ready */
-
-static void ipc_get_windows(struct snd_sof_dev *sdev)
+int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
- struct sof_ipc_window_elem *elem;
- u32 outbox_offset = 0;
- u32 stream_offset = 0;
- u32 inbox_offset = 0;
- u32 outbox_size = 0;
- u32 stream_size = 0;
- u32 inbox_size = 0;
- int i;
-
- if (!sdev->info_window) {
- dev_err(sdev->dev, "error: have no window info\n");
- return;
- }
-
- for (i = 0; i < sdev->info_window->num_windows; i++) {
- elem = &sdev->info_window->window[i];
-
- switch (elem->type) {
- case SOF_IPC_REGION_UPBOX:
- inbox_offset =
- elem->offset + SRAM_WINDOW_OFFSET(elem->id);
- inbox_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- inbox_offset,
- elem->size, "inbox",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_DOWNBOX:
- outbox_offset =
- elem->offset + SRAM_WINDOW_OFFSET(elem->id);
- outbox_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- outbox_offset,
- elem->size, "outbox",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_TRACE:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- elem->offset +
- SRAM_WINDOW_OFFSET
- (elem->id),
- elem->size, "etrace",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_DEBUG:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- elem->offset +
- SRAM_WINDOW_OFFSET
- (elem->id),
- elem->size, "debug",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_STREAM:
- stream_offset =
- elem->offset + SRAM_WINDOW_OFFSET(elem->id);
- stream_size = elem->size;
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- elem->offset +
- SRAM_WINDOW_OFFSET
- (elem->id),
- elem->size, "stream",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_REGS:
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- elem->offset +
- SRAM_WINDOW_OFFSET
- (elem->id),
- elem->size, "regs",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- case SOF_IPC_REGION_EXCEPTION:
- sdev->dsp_oops_offset = elem->offset +
- SRAM_WINDOW_OFFSET(elem->id);
- snd_sof_debugfs_io_item(sdev,
- sdev->bar[HDA_DSP_BAR] +
- elem->offset +
- SRAM_WINDOW_OFFSET
- (elem->id),
- elem->size, "exception",
- SOF_DEBUGFS_ACCESS_D0_ONLY);
- break;
- default:
- dev_err(sdev->dev, "error: get illegal window info\n");
- return;
- }
- }
-
- if (outbox_size == 0 || inbox_size == 0) {
- dev_err(sdev->dev, "error: get illegal mailbox window\n");
- return;
- }
-
- snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
- outbox_offset, outbox_size);
- sdev->stream_box.offset = stream_offset;
- sdev->stream_box.size = stream_size;
-
- dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
- inbox_offset, inbox_size);
- dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
- outbox_offset, outbox_size);
- dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
- stream_offset, stream_size);
+ return HDA_DSP_MBOX_UPLINK_OFFSET;
}
-/* check for ABI compatibility and create memory windows on first boot */
-int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
+int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
- struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
- u32 offset;
- int ret;
-
- /* mailbox must be on 4k boundary */
- offset = HDA_DSP_MBOX_UPLINK_OFFSET;
-
- dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
- msg_id, offset);
-
- /* no need to re-check version/ABI for subsequent boots */
- if (!sdev->first_boot)
- return 0;
-
- /* copy data from the DSP FW ready offset */
- sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready,
- sizeof(*fw_ready));
-
- /* make sure ABI version is compatible */
- ret = snd_sof_ipc_valid(sdev);
- if (ret < 0)
- return ret;
-
- /* now check for extended data */
- snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar,
- HDA_DSP_MBOX_UPLINK_OFFSET +
- sizeof(struct sof_ipc_fw_ready));
-
- ipc_get_windows(sdev);
-
- return 0;
+ return SRAM_WINDOW_OFFSET(id);
}
void hda_ipc_msg_data(struct snd_sof_dev *sdev,
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 7f665392618f..c72e9a09eee1 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -19,13 +19,11 @@
#include <sound/hda_register.h>
#include <linux/module.h>
+#include <sound/intel-nhlt.h>
#include <sound/sof.h>
#include <sound/sof/xtensa.h>
#include "../ops.h"
#include "hda.h"
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
-#include "../../codecs/hdac_hda.h"
-#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
#include <sound/soc-acpi-intel-match.h>
@@ -46,6 +44,18 @@ struct hda_dsp_msg_code {
const char *msg;
};
+static bool hda_use_msi = IS_ENABLED(CONFIG_PCI);
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
+module_param_named(use_msi, hda_use_msi, bool, 0444);
+MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode");
+#endif
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+static int hda_dmic_num = -1;
+module_param_named(dmic_num, hda_dmic_num, int, 0444);
+MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
+#endif
+
static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
{HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"},
{HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"},
@@ -236,7 +246,6 @@ static int hda_init(struct snd_sof_dev *sdev)
{
struct hda_bus *hbus;
struct hdac_bus *bus;
- struct hdac_ext_bus_ops *ext_ops = NULL;
struct pci_dev *pci = to_pci_dev(sdev->dev);
int ret;
@@ -244,10 +253,7 @@ static int hda_init(struct snd_sof_dev *sdev)
bus = sof_to_bus(sdev);
/* HDA bus init */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
- ext_ops = snd_soc_hdac_hda_get_ops();
-#endif
- sof_hda_bus_init(bus, &pci->dev, ext_ops);
+ sof_hda_bus_init(bus, &pci->dev);
/* Workaround for a communication error on CFL (bko#199007) and CNL */
if (IS_CFL(pci) || IS_CNL(pci))
@@ -284,8 +290,26 @@ static int hda_init(struct snd_sof_dev *sdev)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+static int check_nhlt_dmic(struct snd_sof_dev *sdev)
+{
+ struct nhlt_acpi_table *nhlt;
+ int dmic_num;
+
+ nhlt = intel_nhlt_init(sdev->dev);
+ if (nhlt) {
+ dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
+ intel_nhlt_free(nhlt);
+ if (dmic_num == 2 || dmic_num == 4)
+ return dmic_num;
+ }
+
+ return 0;
+}
+
static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
- const char *sof_tplg_filename)
+ const char *sof_tplg_filename,
+ const char *idisp_str,
+ const char *dmic_str)
{
const char *tplg_filename = NULL;
char *filename;
@@ -299,7 +323,8 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
split_ext = strsep(&filename, ".");
if (split_ext) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
- "%s-idisp.tplg", split_ext);
+ "%s%s%s.tplg",
+ split_ext, idisp_str, dmic_str);
if (!tplg_filename)
return NULL;
}
@@ -318,6 +343,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
struct snd_sof_pdata *pdata = sdev->pdata;
struct snd_soc_acpi_mach *mach;
const char *tplg_filename;
+ const char *idisp_str;
+ const char *dmic_str;
+ int dmic_num;
int codec_num = 0;
int i;
#endif
@@ -329,10 +357,23 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (bus->ppcap)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ /* init i915 and HDMI codecs */
+ ret = hda_codec_i915_init(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: init i915 and HDMI codec failed\n");
+ return ret;
+ }
+#endif
+
+ /* Init HDA controller after i915 init */
ret = hda_dsp_ctrl_init_chip(sdev, true);
if (ret < 0) {
dev_err(bus->dev, "error: init chip failed with ret: %d\n",
ret);
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ hda_codec_i915_exit(sdev);
+#endif
return ret;
}
@@ -340,13 +381,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
- /* init i915 and HDMI codecs */
- ret = hda_codec_i915_init(sdev);
- if (ret < 0) {
- dev_err(sdev->dev, "error: no HDMI audio devices found\n");
- return ret;
- }
-
/* codec detection */
if (!bus->codec_mask) {
dev_info(bus->dev, "no hda codecs found!\n");
@@ -382,17 +416,39 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
dev_info(bus->dev, "using HDA machine driver %s now\n",
hda_mach->drv_name);
- /* fixup topology file for HDMI only platforms */
- if (codec_num == 1) {
- /* use local variable for readability */
- tplg_filename = pdata->tplg_filename;
- tplg_filename = fixup_tplg_name(sdev, tplg_filename);
- if (!tplg_filename) {
- hda_codec_i915_exit(sdev);
- return ret;
- }
- pdata->tplg_filename = tplg_filename;
+ if (codec_num == 1)
+ idisp_str = "-idisp";
+ else
+ idisp_str = "";
+
+ /* first check NHLT for DMICs */
+ dmic_num = check_nhlt_dmic(sdev);
+
+ /* allow for module parameter override */
+ if (hda_dmic_num != -1)
+ dmic_num = hda_dmic_num;
+
+ switch (dmic_num) {
+ case 2:
+ dmic_str = "-2ch";
+ break;
+ case 4:
+ dmic_str = "-4ch";
+ break;
+ default:
+ dmic_num = 0;
+ dmic_str = "";
+ break;
+ }
+
+ tplg_filename = pdata->tplg_filename;
+ tplg_filename = fixup_tplg_name(sdev, tplg_filename,
+ idisp_str, dmic_str);
+ if (!tplg_filename) {
+ hda_codec_i915_exit(sdev);
+ return ret;
}
+ pdata->tplg_filename = tplg_filename;
}
}
@@ -529,11 +585,18 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
* register our IRQ
* let's try to enable msi firstly
* if it fails, use legacy interrupt mode
- * TODO: support interrupt mode selection with kernel parameter
- * support msi multiple vectors
+ * TODO: support msi multiple vectors
*/
- ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI);
- if (ret < 0) {
+ if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) {
+ dev_info(sdev->dev, "use msi interrupt mode\n");
+ hdev->irq = pci_irq_vector(pci, 0);
+ /* ipc irq number is the same of hda irq */
+ sdev->ipc_irq = hdev->irq;
+ /* initialised to "false" by kzalloc() */
+ sdev->msi_enabled = true;
+ }
+
+ if (!sdev->msi_enabled) {
dev_info(sdev->dev, "use legacy interrupt mode\n");
/*
* in IO-APIC mode, hda->irq and ipc_irq are using the same
@@ -541,13 +604,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
*/
hdev->irq = pci->irq;
sdev->ipc_irq = pci->irq;
- sdev->msi_enabled = 0;
- } else {
- dev_info(sdev->dev, "use msi interrupt mode\n");
- hdev->irq = pci_irq_vector(pci, 0);
- /* ipc irq number is the same of hda irq */
- sdev->ipc_irq = hdev->irq;
- sdev->msi_enabled = 1;
}
dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq);
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index d9c17146200b..5591841a1b6f 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -175,7 +175,7 @@
#define HDA_DSP_STACK_DUMP_SIZE 32
/* ROM status/error values */
-#define HDA_DSP_ROM_STS_MASK 0xf
+#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0)
#define HDA_DSP_ROM_INIT 0x1
#define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3
#define HDA_DSP_ROM_FW_FW_LOADED 0x4
@@ -418,7 +418,6 @@ struct sof_intel_hda_stream {
struct snd_sof_dev *sdev;
struct hdac_ext_stream hda_stream;
struct sof_intel_stream stream;
- int hw_params_upon_resume; /* set up hw_params upon resume */
int host_reserved; /* reserve host DMA channel */
};
@@ -453,9 +452,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev);
void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev);
-int hda_dsp_suspend(struct snd_sof_dev *sdev, int state);
+int hda_dsp_suspend(struct snd_sof_dev *sdev);
int hda_dsp_resume(struct snd_sof_dev *sdev);
-int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
+int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev);
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
int hda_dsp_runtime_idle(struct snd_sof_dev *sdev);
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
@@ -520,7 +519,9 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev,
int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev,
struct snd_sof_ipc_msg *msg);
void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev);
-int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id);
+int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
+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);
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
@@ -549,14 +550,15 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev);
/*
* HDA bus operations.
*/
-void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev,
- const struct hdac_ext_bus_ops *ext_ops);
+void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/*
* HDA Codec operations.
*/
int hda_codec_probe_bus(struct snd_sof_dev *sdev);
+void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev);
+void hda_codec_jack_check(struct snd_sof_dev *sdev);
#endif /* CONFIG_SND_SOC_SOF_HDA */
@@ -597,5 +599,7 @@ extern const struct sof_intel_dsp_desc apl_chip_info;
extern const struct sof_intel_dsp_desc cnl_chip_info;
extern const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc icl_chip_info;
+extern const struct sof_intel_dsp_desc tgl_chip_info;
+extern const struct sof_intel_dsp_desc ehl_chip_info;
#endif