summaryrefslogtreecommitdiffstats
path: root/sound/soc/sof
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof')
-rw-r--r--sound/soc/sof/Kconfig42
-rw-r--r--sound/soc/sof/control.c42
-rw-r--r--sound/soc/sof/debug.c119
-rw-r--r--sound/soc/sof/imx/Kconfig10
-rw-r--r--sound/soc/sof/imx/imx-common.c2
-rw-r--r--sound/soc/sof/intel/Kconfig110
-rw-r--r--sound/soc/sof/intel/Makefile2
-rw-r--r--sound/soc/sof/intel/apl.c3
-rw-r--r--sound/soc/sof/intel/byt.c2
-rw-r--r--sound/soc/sof/intel/cnl.c19
-rw-r--r--sound/soc/sof/intel/ext_manifest.h35
-rw-r--r--sound/soc/sof/intel/hda-dsp.c2
-rw-r--r--sound/soc/sof/intel/hda-loader.c119
-rw-r--r--sound/soc/sof/intel/hda-pcm.c7
-rw-r--r--sound/soc/sof/intel/hda.c10
-rw-r--r--sound/soc/sof/intel/hda.h12
-rw-r--r--sound/soc/sof/intel/icl.c145
-rw-r--r--sound/soc/sof/intel/intel-ipc.c7
-rw-r--r--sound/soc/sof/intel/tgl.c19
-rw-r--r--sound/soc/sof/ipc.c9
-rw-r--r--sound/soc/sof/loader.c62
-rw-r--r--sound/soc/sof/nocodec.c18
-rw-r--r--sound/soc/sof/ops.c2
-rw-r--r--sound/soc/sof/ops.h14
-rw-r--r--sound/soc/sof/pcm.c14
-rw-r--r--sound/soc/sof/sof-acpi-dev.c14
-rw-r--r--sound/soc/sof/sof-audio.c12
-rw-r--r--sound/soc/sof/sof-audio.h5
-rw-r--r--sound/soc/sof/sof-pci-dev.c24
-rw-r--r--sound/soc/sof/sof-priv.h22
-rw-r--r--sound/soc/sof/topology.c33
-rw-r--r--sound/soc/sof/trace.c224
32 files changed, 995 insertions, 165 deletions
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 8c1f0829de40..031dad5fc4c7 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -2,7 +2,7 @@
config SND_SOC_SOF_TOPLEVEL
bool "Sound Open Firmware Support"
help
- This adds support for Sound Open Firmware (SOF). SOF is a free and
+ This adds support for Sound Open Firmware (SOF). SOF is free and
generic open source audio DSP firmware for multiple devices.
Say Y if you have such a device that is supported by SOF.
If unsure select "N".
@@ -16,8 +16,8 @@ config SND_SOC_SOF_PCI
select SND_SOC_ACPI if ACPI
help
This adds support for PCI enumeration. This option is
- required to enable Intel Skylake+ devices
- Say Y if you need this option
+ required to enable Intel Skylake+ devices.
+ Say Y if you need this option.
If unsure select "N".
config SND_SOC_SOF_ACPI
@@ -28,8 +28,8 @@ config SND_SOC_SOF_ACPI
select IOSF_MBI if X86 && PCI
help
This adds support for ACPI enumeration. This option is required
- to enable Intel Broadwell/Baytrail/Cherrytrail devices
- Say Y if you need this option
+ to enable Intel Broadwell/Baytrail/Cherrytrail devices.
+ Say Y if you need this option.
If unsure select "N".
config SND_SOC_SOF_OF
@@ -54,12 +54,12 @@ config SND_SOC_SOF_DEVELOPER_SUPPORT
bool "SOF developer options support"
depends on EXPERT
help
- This option unlock SOF developer options for debug/performance/
+ This option unlocks SOF developer options for debug/performance/
code hardening.
Distributions should not select this option, only SOF development
teams should select it.
- Say Y if you are involved in SOF development and need this option
- If not, select N
+ Say Y if you are involved in SOF development and need this option.
+ If not, select N.
if SND_SOC_SOF_DEVELOPER_SUPPORT
@@ -72,13 +72,13 @@ config SND_SOC_SOF_NOCODEC_SUPPORT
This adds support for a dummy/nocodec machine driver fallback
option if no known codec is detected. This is typically only
enabled for developers or devices where the sound card is
- controlled externally
- This option is mutually exclusive with the Intel HDAudio support,
- selecting it may have negative impacts and prevent e.g. microphone
+ controlled externally.
+ This option is mutually exclusive with the Intel HDAudio support.
+ Selecting it may have negative impacts and prevent e.g. microphone
functionality from being enabled on Intel CoffeeLake and later
platforms.
Distributions should not select this option!
- Say Y if you need this nocodec fallback option
+ Say Y if you need this nocodec fallback option.
If unsure select "N".
config SND_SOC_SOF_STRICT_ABI_CHECKS
@@ -92,8 +92,8 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS
is invoked.
This option will stop topology creation and firmware load upfront.
It is intended for SOF CI/releases and not for users or distros.
- Say Y if you want strict ABI checks for an SOF release
- If you are not involved in SOF releases and CI development
+ Say Y if you want strict ABI checks for an SOF release.
+ If you are not involved in SOF releases and CI development,
select "N".
config SND_SOC_SOF_DEBUG
@@ -114,8 +114,8 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE
though there is a codec detected on the real platform. This is
typically only enabled for developers for debug purposes, before
codec/machine driver is ready, or to exclude the impact of those
- drivers
- Say Y if you need this force nocodec mode option
+ drivers.
+ Say Y if you need this force nocodec mode option.
If unsure select "N".
config SND_SOC_SOF_DEBUG_XRUN_STOP
@@ -137,12 +137,12 @@ config SND_SOC_SOF_DEBUG_VERBOSE_IPC
config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION
bool "SOF force to use IPC for position update on SKL+"
help
- This option force to handle stream position update IPCs and run pcm
+ This option forces to handle stream position update IPCs and run PCM
elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that
with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM.
On platforms (e.g. Intel SKL-) where position update IPC is the only
one choice, this setting won't impact anything.
- if you are trying to debug pointer update with position IPCs or where
+ If you are trying to debug pointer update with position IPCs or where
DPIB/posbuf is not ready, select "Y".
If unsure select "N".
@@ -161,7 +161,7 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE
help
The firmware trace can be enabled either at build-time with
this option, or dynamically by setting flags in the SOF core
- module parameter (similar to dynamic debug)
+ module parameter (similar to dynamic debug).
If unsure, select "N".
config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST
@@ -190,7 +190,7 @@ config SND_SOC_SOF
select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
The selection is made at the top level and does not exactly follow
module dependencies but since the module or built-in type is decided
at the top level it doesn't matter.
@@ -199,7 +199,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE
bool
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
When selected, the probe is handled in two steps, for example to
avoid lockdeps if request_module is used in the probe.
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 0352d2b61358..a5dd728c580a 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -114,6 +114,28 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
+int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_sof_control *scontrol = sm->dobj.private;
+ unsigned int channels = scontrol->num_channels;
+ int platform_max;
+
+ if (!sm->platform_max)
+ sm->platform_max = sm->max;
+ platform_max = sm->platform_max;
+
+ if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+ uinfo->count = channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = platform_max - sm->min;
+ return 0;
+}
+
int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -309,7 +331,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
* the length (as bytes) is needed to know the correct copy
* length of data from tlvd->tlv.
*/
- if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
+ if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
return -EFAULT;
/* make sure TLV info is consistent */
@@ -351,7 +373,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
}
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
- if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+ if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n");
return -EINVAL;
}
@@ -405,15 +427,15 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
goto out;
/* check data size doesn't exceed max coming from topology */
- if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+ if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n",
cdata->data->size,
- be->max - sizeof(const struct sof_abi_hdr));
+ be->max - sizeof(struct sof_abi_hdr));
ret = -EINVAL;
goto out;
}
- data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
+ data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
/* make sure we don't exceed size provided by user space for data */
if (data_size > size) {
@@ -423,7 +445,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
header.numid = scontrol->cmd;
header.length = data_size;
- if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
+ if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) {
ret = -EFAULT;
goto out;
}
@@ -466,14 +488,14 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
cdata->data->abi = SOF_ABI_VERSION;
/* check data size doesn't exceed max coming from topology */
- if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) {
+ if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) {
dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n",
cdata->data->size,
- be->max - sizeof(const struct sof_abi_hdr));
+ be->max - sizeof(struct sof_abi_hdr));
return -EINVAL;
}
- data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
+ data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
/* make sure we don't exceed size provided by user space for data */
if (data_size > size)
@@ -481,7 +503,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
header.numid = scontrol->cmd;
header.length = data_size;
- if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv)))
+ if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
return -EFAULT;
if (copy_to_user(tlvd->tlv, cdata->data, data_size))
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index 9419a99bab53..30213a1beaaa 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -14,6 +14,8 @@
#include <linux/debugfs.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
+#include <sound/sof/ext_manifest.h>
+#include <sound/sof/debug.h>
#include "sof-priv.h"
#include "ops.h"
@@ -626,6 +628,121 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item);
+static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size)
+{
+ struct sof_ipc_cmd_hdr msg = {
+ .size = sizeof(struct sof_ipc_cmd_hdr),
+ .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE,
+ };
+ struct sof_ipc_dbg_mem_usage *reply;
+ int len;
+ int ret;
+ int i;
+
+ reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
+ if (!reply)
+ return -ENOMEM;
+
+ ret = pm_runtime_get_sync(sdev->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(sdev->dev);
+ dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
+ goto error;
+ }
+
+ ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
+ pm_runtime_mark_last_busy(sdev->dev);
+ pm_runtime_put_autosuspend(sdev->dev);
+ if (ret < 0 || reply->rhdr.error < 0) {
+ ret = min(ret, reply->rhdr.error);
+ dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret);
+ goto error;
+ }
+
+ if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) {
+ dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n",
+ reply->rhdr.hdr.size);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ for (i = 0, len = 0; i < reply->num_elems; i++) {
+ ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
+ reply->elems[i].zone, reply->elems[i].id,
+ reply->elems[i].used, reply->elems[i].free);
+ if (ret < 0)
+ goto error;
+ len += ret;
+ }
+
+ ret = len;
+error:
+ kfree(reply);
+ return ret;
+}
+
+static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+ struct snd_sof_dfsentry *dfse = file->private_data;
+ struct snd_sof_dev *sdev = dfse->sdev;
+ int data_length;
+
+ /* read memory info from FW only once for each file read */
+ if (!*ppos) {
+ dfse->buf_data_size = 0;
+ data_length = memory_info_update(sdev, dfse->buf, dfse->size);
+ if (data_length < 0)
+ return data_length;
+ dfse->buf_data_size = data_length;
+ }
+
+ return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size);
+}
+
+static int memory_info_open(struct inode *inode, struct file *file)
+{
+ struct snd_sof_dfsentry *dfse = inode->i_private;
+ struct snd_sof_dev *sdev = dfse->sdev;
+
+ file->private_data = dfse;
+
+ /* allocate buffer memory only in first open run, to save memory when unused */
+ if (!dfse->buf) {
+ dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL);
+ if (!dfse->buf)
+ return -ENOMEM;
+ dfse->size = PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static const struct file_operations memory_info_fops = {
+ .open = memory_info_open,
+ .read = memory_info_read,
+ .llseek = default_llseek,
+};
+
+int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_dfsentry *dfse;
+
+ dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+ if (!dfse)
+ return -ENOMEM;
+
+ /* don't allocate buffer before first usage, to save memory when unused */
+ dfse->type = SOF_DFSENTRY_TYPE_BUF;
+ dfse->sdev = sdev;
+
+ debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops);
+
+ /* add to dfsentry list */
+ list_add(&dfse->list, &sdev->dfsentry_list);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
+
int snd_sof_dbg_init(struct snd_sof_dev *sdev)
{
const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
@@ -700,7 +817,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
}
/* dump vital information to the logs */
- snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+ snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
snd_sof_ipc_dump(sdev);
snd_sof_trace_notify_for_error(sdev);
}
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index 48f998a19ddb..49d605cb09a5 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -17,7 +17,7 @@ config SND_SOC_SOF_IMX_OF
select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_IMX_COMMON
tristate
@@ -30,7 +30,7 @@ config SND_SOC_SOF_IMX8_SUPPORT
depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF
depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_IMX_OF
help
- This adds support for Sound Open Firmware for NXP i.MX8 platforms
+ This adds support for Sound Open Firmware for NXP i.MX8 platforms.
Say Y if you have such a device.
If unsure select "N".
@@ -40,13 +40,13 @@ config SND_SOC_SOF_IMX8
select SND_SOC_SOF_XTENSA
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_IMX8M_SUPPORT
bool "SOF support for i.MX8M"
depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_OF
help
- This adds support for Sound Open Firmware for NXP i.MX8M platforms
+ This adds support for Sound Open Firmware for NXP i.MX8M platforms.
Say Y if you have such a device.
If unsure select "N".
@@ -56,6 +56,6 @@ config SND_SOC_SOF_IMX8M
select SND_SOC_SOF_XTENSA
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL
diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c
index 5fee637834c2..8826ef94f04a 100644
--- a/sound/soc/sof/imx/imx-common.c
+++ b/sound/soc/sof/imx/imx-common.c
@@ -47,6 +47,8 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
/**
* imx8_dump() - This function is called when a panic message is
* received from the firmware.
+ * @sdev: SOF device
+ * @flags: parameter not used but required by ops prototype
*/
void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
{
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index a066e08860cb..d306c370e5d1 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -15,7 +15,7 @@ config SND_SOC_SOF_INTEL_ACPI
select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_INTEL_PCI
def_tristate SND_SOC_SOF_PCI
@@ -29,15 +29,16 @@ config SND_SOC_SOF_INTEL_PCI
select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT
select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT
select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT
+ select SND_SOC_SOF_ALDERLAKE if SND_SOC_SOF_ALDERLAKE_SUPPORT
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_INTEL_HIFI_EP_IPC
tristate
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
tristate
@@ -45,7 +46,7 @@ config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
select SND_SOC_SOF_INTEL_HIFI_EP_IPC
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_INTEL_COMMON
tristate
@@ -55,47 +56,48 @@ config SND_SOC_SOF_INTEL_COMMON
select SND_SOC_ACPI if ACPI
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
if SND_SOC_SOF_INTEL_ACPI
config SND_SOC_SOF_BAYTRAIL_SUPPORT
bool "SOF support for Baytrail, Braswell and Cherrytrail"
- depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n
help
This adds support for Sound Open Firmware for Intel(R) platforms
using the Baytrail, Braswell or Cherrytrail processors.
- This option is mutually exclusive with the Atom/SST and Baytrail
- legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail,
- you need to deselect those options first.
- SOF does not support Baytrail-CR for now, so this option is not
- recommended for distros. At some point all legacy drivers will be
- deprecated but not before all userspace firmware/topology/UCM files
- are made available to downstream distros.
- Say Y if you want to enable SOF on Baytrail/Cherrytrail
+ This option can coexist in the same build with the Atom legacy
+ drivers, currently the default but which will be deprecated
+ at some point.
+ Existing firmware/topology binaries and UCM configurations
+ typically located in the root file system are already
+ compatible with both SOF or Atom/SST legacy drivers.
+ This is a recommended option for distributions.
+ Say Y if you want to enable SOF on Baytrail/Cherrytrail.
If unsure select "N".
config SND_SOC_SOF_BAYTRAIL
tristate
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
+ select SND_INTEL_DSP_CONFIG
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_BROADWELL_SUPPORT
bool "SOF support for Broadwell"
- depends on SND_SOC_INTEL_HASWELL=n
+ select SND_INTEL_DSP_CONFIG
help
This adds support for Sound Open Firmware for Intel(R) platforms
using the Broadwell processors.
- This option is mutually exclusive with the Haswell/Broadwell legacy
- driver. If you want to enable SOF on Broadwell you need to deselect
- the legacy driver first.
- SOF does fully support Broadwell yet, so this option is not
- recommended for distros. At some point all legacy drivers will be
- deprecated but not before all userspace firmware/topology/UCM files
- are made available to downstream distros.
- Say Y if you want to enable SOF on Broadwell
+ This option can coexist in the same build with the default 'catpt'
+ driver.
+ Existing firmware/topology binaries and UCM configurations typically
+ located in the root file system are already compatible with both SOF
+ or catpt drivers.
+ SOF does not fully support Broadwell and has limitations related to
+ DMA and suspend-resume, this is not a recommended option for
+ distributions.
+ Say Y if you want to enable SOF on Broadwell.
If unsure select "N".
config SND_SOC_SOF_BROADWELL
@@ -104,7 +106,7 @@ config SND_SOC_SOF_BROADWELL
select SND_SOC_SOF_INTEL_HIFI_EP_IPC
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
endif ## SND_SOC_SOF_INTEL_ACPI
@@ -123,7 +125,7 @@ config SND_SOC_SOF_MERRIFIELD
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_APOLLOLAKE_SUPPORT
bool "SOF support for Apollolake"
@@ -138,7 +140,7 @@ config SND_SOC_SOF_APOLLOLAKE
select SND_SOC_SOF_HDA_COMMON
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_GEMINILAKE_SUPPORT
bool "SOF support for GeminiLake"
@@ -153,7 +155,7 @@ config SND_SOC_SOF_GEMINILAKE
select SND_SOC_SOF_HDA_COMMON
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_CANNONLAKE_SUPPORT
bool "SOF support for Cannonlake"
@@ -169,7 +171,7 @@ config SND_SOC_SOF_CANNONLAKE
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_COFFEELAKE_SUPPORT
bool "SOF support for CoffeeLake"
@@ -185,7 +187,7 @@ config SND_SOC_SOF_COFFEELAKE
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_ICELAKE_SUPPORT
bool "SOF support for Icelake"
@@ -201,7 +203,7 @@ config SND_SOC_SOF_ICELAKE
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_COMETLAKE
tristate
@@ -209,7 +211,7 @@ config SND_SOC_SOF_COMETLAKE
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_COMETLAKE_SUPPORT
bool
@@ -236,7 +238,7 @@ config SND_SOC_SOF_TIGERLAKE
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_ELKHARTLAKE_SUPPORT
bool "SOF support for ElkhartLake"
@@ -252,7 +254,7 @@ config SND_SOC_SOF_ELKHARTLAKE
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_JASPERLAKE_SUPPORT
bool "SOF support for JasperLake"
@@ -267,15 +269,32 @@ config SND_SOC_SOF_JASPERLAKE
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_ALDERLAKE_SUPPORT
+ bool "SOF support for Alderlake"
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Alderlake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_ALDERLAKE
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ 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_INTEL_DSP_CONFIG
select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_HDA_LINK_BASELINE
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
if SND_SOC_SOF_HDA_COMMON
@@ -285,7 +304,7 @@ config SND_SOC_SOF_HDA_LINK
select SND_SOC_SOF_PROBE_WORK_QUEUE
help
This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
- for Intel(R) platforms.
+ for Intel(R) platforms.
Say Y if you want to enable HDA links with SOF.
If unsure select "N".
@@ -294,7 +313,7 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
depends on SND_SOC_SOF_HDA_LINK
help
This adds support for HDAudio codecs with Sound Open Firmware
- for Intel(R) platforms.
+ for Intel(R) platforms.
Say Y if you want to enable HDAudio codecs with SOF.
If unsure select "N".
@@ -302,8 +321,8 @@ config SND_SOC_SOF_HDA_PROBES
bool "SOF enable probes over HDA"
depends on SND_SOC_SOF_DEBUG_PROBES
help
- This option enables the data probing for Intel(R).
- Intel(R) Skylake and newer platforms.
+ This option enables the data probing for Intel(R)
+ Skylake and newer platforms.
Say Y if you want to enable probes.
If unsure, select "N".
@@ -314,7 +333,7 @@ config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1
and disables known workarounds for specific HDAudio platforms.
Only use to look into power optimizations on platforms not
affected by DMI L1 issues. This option is not recommended.
- Say Y if you want to enable DMI Link L1
+ Say Y if you want to enable DMI Link L1.
If unsure, select "N".
endif ## SND_SOC_SOF_HDA_COMMON
@@ -324,23 +343,22 @@ config SND_SOC_SOF_HDA_LINK_BASELINE
select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
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_DSP_CONFIG
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
bool "SOF support for SoundWire"
depends on SOUNDWIRE && ACPI
help
This adds support for SoundWire with Sound Open Firmware
- for Intel(R) platforms.
+ for Intel(R) platforms.
Say Y if you want to enable SoundWire links with SOF.
If unsure select "N".
@@ -349,14 +367,14 @@ config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
config SND_SOC_SOF_INTEL_SOUNDWIRE
tristate
select SOUNDWIRE_INTEL
help
This option is not user-selectable but automagically handled by
- 'select' statements at a higher level
+ 'select' statements at a higher level.
endif ## SND_SOC_SOF_INTEL_PCI
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index 72d85b25df7d..2589111c2fae 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o
snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
hda-dai.o hda-bus.o \
- apl.o cnl.o tgl.o
+ apl.o cnl.o tgl.o icl.o
snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o
snd-sof-intel-hda-objs := hda-codec.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 4eeade2e77f7..fc29b91b8932 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -92,6 +92,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
+ /* parse platform specific extended manifest */
+ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
/* dsp core power up/down */
.core_power_up = hda_dsp_enable_core,
.core_power_down = hda_dsp_core_reset_power_down,
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 186736ee5fc2..19260dbecac5 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -336,7 +336,7 @@ static int byt_run(struct snd_sof_dev *sdev)
}
if (tries < 0) {
dev_err(sdev->dev, "error: unable to run DSP firmware\n");
- byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+ byt_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
return -ENODEV;
}
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index a5d3258104c0..e38db519f38d 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -294,6 +294,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
+ /* parse platform specific extended manifest */
+ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
/* dsp core power up/down */
.core_power_up = hda_dsp_enable_core,
.core_power_down = hda_dsp_core_reset_power_down,
@@ -346,22 +349,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
};
EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
-const struct sof_intel_dsp_desc icl_chip_info = {
- /* Icelake */
- .cores_num = 4,
- .init_core_mask = 1,
- .host_managed_cores_mask = GENMASK(3, 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_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
-
const struct sof_intel_dsp_desc ehl_chip_info = {
/* Elkhartlake */
.cores_num = 4,
diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h
new file mode 100644
index 000000000000..2dfae9285d3c
--- /dev/null
+++ b/sound/soc/sof/intel/ext_manifest.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ */
+
+/*
+ * Intel extended manifest is a extra place to store Intel cavs specific
+ * metadata about firmware, for example LPRO/HPRO configuration is
+ * Intel cavs specific. This part of output binary is not signed.
+ */
+
+#ifndef __INTEL_CAVS_EXT_MANIFEST_H__
+#define __INTEL_CAVS_EXT_MANIFEST_H__
+
+#include <sound/sof/ext_manifest.h>
+
+/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements identificators */
+enum sof_cavs_config_elem_type {
+ SOF_EXT_MAN_CAVS_CONFIG_EMPTY = 0,
+ SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO = 1,
+ SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE = 2,
+ SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE = 3,
+};
+
+/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements */
+struct sof_ext_man_cavs_config_data {
+ struct sof_ext_man_elem_header hdr;
+
+ struct sof_config_elem elems[];
+} __packed;
+
+#endif /* __INTEL_CAVS_EXT_MANIFEST_H__ */
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 18ff1c2f5376..2b001151fe37 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -44,7 +44,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask)
reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS,
- reset, reset),
+ reset, reset);
/* poll with timeout to check if operation successful */
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 2707a16c6a4d..ed773696b495 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -19,6 +19,7 @@
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
+#include "ext_manifest.h"
#include "../ops.h"
#include "hda.h"
@@ -87,6 +88,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int status;
+ u32 flags;
int ret;
int i;
@@ -174,7 +176,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
__func__);
err:
- hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
+ flags = SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX;
+
+ /* force error log level after max boot attempts */
+ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+ flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL;
+
+ hda_dsp_dump(sdev, flags);
hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
return ret;
@@ -407,10 +415,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
* should be ready for code loading and firmware boot
*/
ret = cl_copy_fw(sdev, stream);
- if (!ret)
+ if (!ret) {
dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
- else
+ } else {
+ hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX |
+ SOF_DBG_DUMP_FORCE_ERR_LEVEL);
dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret);
+ }
cleanup:
/*
@@ -434,9 +445,6 @@ cleanup:
if (!ret)
return chip_info->init_core_mask;
- /* dump dsp registers and disable DSP upon error */
- hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
-
/* disable DSP */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
SOF_HDA_REG_PP_PPCTL,
@@ -470,3 +478,102 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
/* re-enable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, true);
}
+
+/*
+ * post fw run operations for ICL,
+ * Core 3 will be powered up and in stall when HPRO is enabled
+ */
+int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ int ret;
+
+ if (sdev->first_boot) {
+ ret = hda_sdw_startup(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "error: could not startup SoundWire links\n");
+ return ret;
+ }
+ }
+
+ hda_sdw_int_enable(sdev, true);
+
+ /*
+ * The recommended HW programming sequence for ICL is to
+ * power up core 3 and keep it in stall if HPRO is enabled.
+ * Major difference between ICL and TGL, on ICL core 3 is managed by
+ * the host whereas on TGL it is handled by the firmware.
+ */
+ if (!hda->clk_config_lpro) {
+ ret = snd_sof_dsp_core_power_up(sdev, BIT(3));
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: dsp core power up failed on core 3\n");
+ return ret;
+ }
+
+ snd_sof_dsp_stall(sdev, BIT(3));
+ }
+
+ /* re-enable clock gating and power gating */
+ return hda_dsp_ctrl_clock_power_gating(sdev, true);
+}
+
+int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
+ const struct sof_ext_man_elem_header *hdr)
+{
+ const struct sof_ext_man_cavs_config_data *config_data =
+ container_of(hdr, struct sof_ext_man_cavs_config_data, hdr);
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ int i, elem_num;
+
+ /* calculate total number of config data elements */
+ elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header))
+ / sizeof(struct sof_config_elem);
+ if (elem_num <= 0) {
+ dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < elem_num; i++)
+ switch (config_data->elems[i].token) {
+ case SOF_EXT_MAN_CAVS_CONFIG_EMPTY:
+ /* skip empty token */
+ break;
+ case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO:
+ hda->clk_config_lpro = config_data->elems[i].value;
+ dev_dbg(sdev->dev, "FW clock config: %s\n",
+ hda->clk_config_lpro ? "LPRO" : "HPRO");
+ break;
+ case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE:
+ case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE:
+ /* These elements are defined but not being used yet. No warn is required */
+ break;
+ default:
+ dev_info(sdev->dev, "unsupported token type: %d\n",
+ config_data->elems[i].token);
+ }
+
+ return 0;
+}
+
+int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+
+ /* make sure core_mask in host managed cores */
+ core_mask &= chip->host_managed_cores_mask;
+ if (!core_mask) {
+ dev_err(sdev->dev, "error: core_mask is not in host managed cores\n");
+ return -EINVAL;
+ }
+
+ /* stall core */
+ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
+ HDA_DSP_REG_ADSPCS,
+ HDA_DSP_ADSPCS_CSTALL_MASK(core_mask),
+ HDA_DSP_ADSPCS_CSTALL_MASK(core_mask));
+
+ return 0;
+}
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index b527d5958ae5..5d35bb18660a 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -225,6 +225,13 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
return -ENODEV;
}
+ /* minimum as per HDA spec */
+ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
+
+ /* avoid circular buffer wrap in middle of period */
+ snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
/* binding pcm substream to hda stream */
substream->runtime->private_data = &dsp_stream->hstream;
return 0;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index bb4128a72a42..509a9b256423 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -416,9 +416,8 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
}
/* dump the first 8 dwords representing the extended ROM status */
-static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev)
+static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags)
{
- struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
char msg[128];
int len = 0;
u32 value;
@@ -429,14 +428,13 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev)
len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
}
- sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS,
+ sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL,
"extended rom status: %s", msg);
}
void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
- struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct sof_ipc_dsp_oops_xtensa xoops;
struct sof_ipc_panic_info panic_info;
u32 stack[HDA_DSP_STACK_DUMP_SIZE];
@@ -456,11 +454,11 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
stack, HDA_DSP_STACK_DUMP_SIZE);
} else {
- sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS,
+ sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL,
"status = 0x%8.8x panic = 0x%8.8x\n",
status, panic);
- hda_dsp_dump_ext_rom_status(sdev);
+ hda_dsp_dump_ext_rom_status(sdev, flags);
hda_dsp_get_status(sdev);
}
}
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 1bc4dabdd394..9ec8ae0fd649 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -447,6 +447,9 @@ struct sof_intel_hda_dev {
/* sdw context allocated by SoundWire driver */
struct sdw_intel_ctx *sdw;
+
+ /* FW clock config, 0:HPRO, 1:LPRO */
+ bool clk_config_lpro;
};
static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@@ -612,11 +615,18 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
*/
int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev);
+int hda_dsp_cl_boot_firmware_iccmax_icl(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev);
/* pre and post fw run ops */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev);
int hda_dsp_post_fw_run(struct snd_sof_dev *sdev);
+int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev);
+int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask);
+
+/* parse platform specific ext manifest ops */
+int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
+ const struct sof_ext_man_elem_header *hdr);
/*
* HDA Controller Operations.
@@ -733,6 +743,7 @@ extern struct snd_soc_dai_driver skl_dai[];
extern const struct snd_sof_dsp_ops sof_apl_ops;
extern const struct snd_sof_dsp_ops sof_cnl_ops;
extern const struct snd_sof_dsp_ops sof_tgl_ops;
+extern const struct snd_sof_dsp_ops sof_icl_ops;
extern const struct sof_intel_dsp_desc apl_chip_info;
extern const struct sof_intel_dsp_desc cnl_chip_info;
@@ -742,6 +753,7 @@ extern const struct sof_intel_dsp_desc tgl_chip_info;
extern const struct sof_intel_dsp_desc tglh_chip_info;
extern const struct sof_intel_dsp_desc ehl_chip_info;
extern const struct sof_intel_dsp_desc jsl_chip_info;
+extern const struct sof_intel_dsp_desc adls_chip_info;
/* machine driver select */
void hda_machine_select(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
new file mode 100644
index 000000000000..e9d5a0a58504
--- /dev/null
+++ b/sound/soc/sof/intel/icl.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Fred Oh <fred.oh@linux.intel.com>
+//
+
+/*
+ * Hardware interface for audio DSP on IceLake.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kconfig.h>
+#include <linux/export.h>
+#include <linux/bits.h>
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+
+static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = {
+ {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
+/* Icelake ops */
+const struct snd_sof_dsp_ops sof_icl_ops = {
+ /* probe and remove */
+ .probe = hda_dsp_probe,
+ .remove = hda_dsp_remove,
+
+ /* Register IO */
+ .write = sof_io_write,
+ .read = sof_io_read,
+ .write64 = sof_io_write64,
+ .read64 = sof_io_read64,
+
+ /* Block IO */
+ .block_read = sof_block_read,
+ .block_write = sof_block_write,
+
+ /* doorbell */
+ .irq_thread = cnl_ipc_irq_thread,
+
+ /* ipc */
+ .send_msg = cnl_ipc_send_msg,
+ .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,
+
+ /* machine driver */
+ .machine_select = hda_machine_select,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+ .set_mach_params = hda_set_mach_params,
+
+ /* debug */
+ .debug_map = icl_dsp_debugfs,
+ .debug_map_count = ARRAY_SIZE(icl_dsp_debugfs),
+ .dbg_dump = hda_dsp_dump,
+ .ipc_dump = cnl_ipc_dump,
+
+ /* stream callbacks */
+ .pcm_open = hda_dsp_pcm_open,
+ .pcm_close = hda_dsp_pcm_close,
+ .pcm_hw_params = hda_dsp_pcm_hw_params,
+ .pcm_hw_free = hda_dsp_stream_hw_free,
+ .pcm_trigger = hda_dsp_pcm_trigger,
+ .pcm_pointer = hda_dsp_pcm_pointer,
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
+ /* probe callbacks */
+ .probe_assign = hda_probe_compr_assign,
+ .probe_free = hda_probe_compr_free,
+ .probe_set_params = hda_probe_compr_set_params,
+ .probe_trigger = hda_probe_compr_trigger,
+ .probe_pointer = hda_probe_compr_pointer,
+#endif
+
+ /* firmware loading */
+ .load_firmware = snd_sof_load_firmware_raw,
+
+ /* pre/post fw run */
+ .pre_fw_run = hda_dsp_pre_fw_run,
+ .post_fw_run = hda_dsp_post_fw_run_icl,
+
+ /* parse platform specific extended manifest */
+ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
+ /* dsp core power up/down */
+ .core_power_up = hda_dsp_enable_core,
+ .core_power_down = hda_dsp_core_reset_power_down,
+
+ /* firmware run */
+ .run = hda_dsp_cl_boot_firmware_iccmax,
+ .stall = hda_dsp_core_stall_icl,
+
+ /* trace callback */
+ .trace_init = hda_dsp_trace_init,
+ .trace_release = hda_dsp_trace_release,
+ .trace_trigger = hda_dsp_trace_trigger,
+
+ /* DAI drivers */
+ .drv = skl_dai,
+ .num_drv = SOF_SKL_NUM_DAIS,
+
+ /* PM */
+ .suspend = hda_dsp_suspend,
+ .resume = hda_dsp_resume,
+ .runtime_suspend = hda_dsp_runtime_suspend,
+ .runtime_resume = hda_dsp_runtime_resume,
+ .runtime_idle = hda_dsp_runtime_idle,
+ .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
+ .set_power_state = hda_dsp_set_power_state,
+
+ /* ALSA HW info flags */
+ .hw_info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+
+ .arch_ops = &sof_xtensa_arch_ops,
+};
+EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc icl_chip_info = {
+ /* Icelake */
+ .cores_num = 4,
+ .init_core_mask = 1,
+ .host_managed_cores_mask = GENMASK(3, 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_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c
index 310f9168c124..de66f8a82a07 100644
--- a/sound/soc/sof/intel/intel-ipc.c
+++ b/sound/soc/sof/intel/intel-ipc.c
@@ -73,6 +73,13 @@ int intel_pcm_open(struct snd_sof_dev *sdev,
/* binding pcm substream to hda stream */
substream->runtime->private_data = stream;
+ /* align to DMA minimum transfer size */
+ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
+
+ /* avoid circular buffer wrap in middle of period */
+ snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
return 0;
}
EXPORT_SYMBOL_NS(intel_pcm_open, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 0278b67de1ec..2252ca38ff4b 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -84,6 +84,9 @@ const struct snd_sof_dsp_ops sof_tgl_ops = {
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
+ /* parse platform specific extended manifest */
+ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
+
/* dsp core power up/down */
.core_power_up = hda_dsp_enable_core,
.core_power_down = hda_dsp_core_reset_power_down,
@@ -151,3 +154,19 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc adls_chip_info = {
+ /* Alderlake-S */
+ .cores_num = 2,
+ .init_core_mask = BIT(0),
+ .host_managed_cores_mask = BIT(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_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index fd2b96ae4943..fc13bb06dbf3 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -181,6 +181,15 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
str2 = "unknown type"; break;
}
break;
+ case SOF_IPC_GLB_DEBUG:
+ str = "GLB_DEBUG";
+ switch (type) {
+ case SOF_IPC_DEBUG_MEM_USAGE:
+ str2 = "MEM_USAGE"; break;
+ default:
+ str2 = "unknown type"; break;
+ }
+ break;
default:
str = "unknown GLB command"; break;
}
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index ba9ed66f98bc..08a17abb63ff 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -124,7 +124,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
/* They are supported but we don't do anything here */
break;
default:
- dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
+ dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
ext_hdr->type, ext_hdr->hdr.size);
ret = 0;
break;
@@ -197,6 +197,54 @@ static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev,
return 0;
}
+static int ext_man_get_config_data(struct snd_sof_dev *sdev,
+ const struct sof_ext_man_elem_header *hdr)
+{
+ const struct sof_ext_man_config_data *config =
+ container_of(hdr, struct sof_ext_man_config_data, hdr);
+ const struct sof_config_elem *elem;
+ int elems_counter;
+ int elems_size;
+ int ret = 0;
+ int i;
+
+ /* calculate elements counter */
+ elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header);
+ elems_counter = elems_size / sizeof(struct sof_config_elem);
+
+ dev_dbg(sdev->dev, "%s can hold up to %d config elements\n",
+ __func__, elems_counter);
+
+ for (i = 0; i < elems_counter; ++i) {
+ elem = &config->elems[i];
+ dev_dbg(sdev->dev, "%s get index %d token %d val %d\n",
+ __func__, i, elem->token, elem->value);
+ switch (elem->token) {
+ case SOF_EXT_MAN_CONFIG_EMPTY:
+ /* unused memory space is zero filled - mapped to EMPTY elements */
+ break;
+ case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE:
+ /* TODO: use ipc msg size from config data */
+ break;
+ case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN:
+ if (sdev->first_boot && elem->value)
+ ret = snd_sof_dbg_memory_info_init(sdev);
+ break;
+ default:
+ dev_info(sdev->dev, "Unknown firmware configuration token %d value %d",
+ elem->token, elem->value);
+ break;
+ }
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n",
+ elem->token, elem->value, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
{
const struct sof_ext_man_header *head;
@@ -279,8 +327,14 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
case SOF_EXT_MAN_ELEM_DBG_ABI:
ret = ext_man_get_dbg_abi_info(sdev, elem_hdr);
break;
+ case SOF_EXT_MAN_ELEM_CONFIG_DATA:
+ ret = ext_man_get_config_data(sdev, elem_hdr);
+ break;
+ case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA:
+ ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr);
+ break;
default:
- dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
+ dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n",
elem_hdr->type, elem_hdr->size);
break;
}
@@ -802,8 +856,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
msecs_to_jiffies(sdev->boot_timeout));
if (ret == 0) {
dev_err(sdev->dev, "error: firmware boot failure\n");
- snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
- SOF_DBG_TEXT | SOF_DBG_PCI);
+ snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX |
+ SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_FORCE_ERR_LEVEL);
sdev->fw_state = SOF_FW_BOOT_FAILED;
return -EIO;
}
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 9e922df6a710..3b9bb2e83a86 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -10,17 +10,21 @@
#include <linux/module.h>
#include <sound/sof.h>
+#include "sof-audio.h"
#include "sof-priv.h"
static struct snd_soc_card sof_nocodec_card = {
.name = "nocodec", /* the sof- prefix is added by the core */
+ .topology_shortname = "sof-nocodec",
.owner = THIS_MODULE
};
static int sof_nocodec_bes_setup(struct device *dev,
const struct snd_sof_dsp_ops *ops,
struct snd_soc_dai_link *links,
- int link_num, struct snd_soc_card *card)
+ int link_num, struct snd_soc_card *card,
+ int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params))
{
struct snd_soc_dai_link_component *dlc;
int i;
@@ -39,6 +43,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
if (!links[i].name)
return -ENOMEM;
+ links[i].stream_name = links[i].name;
+
links[i].cpus = &dlc[0];
links[i].codecs = &dlc[1];
links[i].platforms = &dlc[2];
@@ -57,6 +63,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
links[i].dpcm_playback = 1;
if (ops->drv[i].capture.channels_min)
links[i].dpcm_capture = 1;
+
+ links[i].be_hw_params_fixup = pcm_dai_link_fixup;
}
card->dai_link = links;
@@ -65,8 +73,9 @@ static int sof_nocodec_bes_setup(struct device *dev,
return 0;
}
-int sof_nocodec_setup(struct device *dev,
- const struct snd_sof_dsp_ops *ops)
+int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops,
+ int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params))
{
struct snd_soc_dai_link *links;
@@ -77,7 +86,7 @@ int sof_nocodec_setup(struct device *dev,
return -ENOMEM;
return sof_nocodec_bes_setup(dev, ops, links, ops->num_drv,
- &sof_nocodec_card);
+ &sof_nocodec_card, pcm_dai_link_fixup);
}
EXPORT_SYMBOL(sof_nocodec_setup);
@@ -86,6 +95,7 @@ static int sof_nocodec_probe(struct platform_device *pdev)
struct snd_soc_card *card = &sof_nocodec_card;
card->dev = &pdev->dev;
+ card->topology_shortname_created = true;
return devm_snd_soc_register_card(&pdev->dev, card);
}
diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c
index 1a394b4c6a2f..11ecebd07907 100644
--- a/sound/soc/sof/ops.c
+++ b/sound/soc/sof/ops.c
@@ -157,7 +157,7 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n",
sdev->dsp_oops_offset, offset);
- snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+ snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
snd_sof_trace_notify_for_error(sdev);
}
EXPORT_SYMBOL(snd_sof_dsp_panic);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index b21632f5511a..95e748b36903 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -48,10 +48,10 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev)
return sof_ops(sdev)->run(sdev);
}
-static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev, unsigned int core_mask)
{
if (sof_ops(sdev)->stall)
- return sof_ops(sdev)->stall(sdev);
+ return sof_ops(sdev)->stall(sdev, core_mask);
return 0;
}
@@ -100,6 +100,16 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev)
return 0;
}
+/* parse platform specific extended manifest */
+static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev,
+ const struct sof_ext_man_elem_header *hdr)
+{
+ if (sof_ops(sdev)->parse_platform_ext_manifest)
+ return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr);
+
+ return 0;
+}
+
/* misc */
/**
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index cbac6f17c52f..0dc39fbcd81d 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -478,17 +478,10 @@ static int sof_pcm_open(struct snd_soc_component *component,
caps = &spcm->pcm.caps[substream->stream];
- /* set any runtime constraints based on topology */
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- le32_to_cpu(caps->period_size_min));
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- le32_to_cpu(caps->period_size_min));
-
/* set runtime config */
runtime->hw.info = ops->hw_info; /* platform-specific */
+ /* set any runtime constraints based on topology */
runtime->hw.formats = le64_to_cpu(caps->formats);
runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
@@ -627,8 +620,7 @@ capture:
}
/* fixup the BE DAI link to match any values from topology */
-static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
+int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
@@ -780,7 +772,7 @@ static int sof_pcm_probe(struct snd_soc_component *component)
static void sof_pcm_remove(struct snd_soc_component *component)
{
/* remove topology */
- snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+ snd_soc_tplg_component_remove(component);
}
void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index a78b76ef37b2..2a369c2c6551 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -12,6 +12,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include <sound/sof.h>
@@ -120,12 +121,23 @@ static void sof_acpi_probe_complete(struct device *dev)
static int sof_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ const struct acpi_device_id *id;
const struct sof_dev_desc *desc;
struct snd_sof_pdata *sof_pdata;
const struct snd_sof_dsp_ops *ops;
int ret;
- dev_dbg(&pdev->dev, "ACPI DSP detected");
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return -ENODEV;
+
+ ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+ if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
+ dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(dev, "ACPI DSP detected");
sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
if (!sof_pdata)
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index afe7e503bf66..3277489fee5e 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -443,11 +443,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
struct snd_soc_acpi_mach *mach;
int ret;
- /* force nocodec mode */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
- dev_warn(sdev->dev, "Force to use nocodec mode\n");
- goto nocodec;
-#endif
+#if !IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
/* find machine */
snd_sof_machine_select(sdev);
@@ -460,8 +456,8 @@ int sof_machine_check(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
return -ENODEV;
#endif
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
-nocodec:
+#else
+ dev_warn(sdev->dev, "Force to use nocodec mode\n");
#endif
/* select nocodec mode */
dev_warn(sdev->dev, "Using nocodec machine driver\n");
@@ -472,7 +468,7 @@ nocodec:
mach->drv_name = "sof-nocodec";
sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
- ret = sof_nocodec_setup(sdev->dev, desc->ops);
+ ret = sof_nocodec_setup(sdev->dev, desc->ops, sof_pcm_dai_link_fixup);
if (ret < 0)
return ret;
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 9f645a2e5a6c..dc930fc2f4b5 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -124,6 +124,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+int snd_sof_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
@@ -212,6 +214,9 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
enum sof_ipc_ctrl_cmd ctrl_cmd,
bool send);
+/* DAI link fixup */
+int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
+
/* PM */
int sof_restore_pipelines(struct device *dev);
int sof_set_hw_params_upon_resume(struct device *dev);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 8f62e3487dc1..63b989e3ec40 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -209,7 +209,7 @@ static const struct sof_dev_desc icl_desc = {
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-icl.ri",
.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
- .ops = &sof_cnl_ops,
+ .ops = &sof_icl_ops,
};
#endif
@@ -284,6 +284,24 @@ static const struct sof_dev_desc jsl_desc = {
};
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+static const struct sof_dev_desc adls_desc = {
+ .machines = snd_soc_acpi_intel_adl_machines,
+ .alt_machines = snd_soc_acpi_intel_adl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .resindex_dma_base = -1,
+ .chip_info = &adls_chip_info,
+ .default_fw_path = "intel/sof",
+ .default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-adl-s.ri",
+ .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
+ .ops = &sof_tgl_ops,
+};
+#endif
+
static const struct dev_pm_ops sof_pci_pm = {
.prepare = snd_sof_prepare,
.complete = snd_sof_complete,
@@ -491,6 +509,10 @@ static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x4b58),
.driver_data = (unsigned long)&ehl_desc},
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
+ { PCI_DEVICE(0x8086, 0x7ad0),
+ .driver_data = (unsigned long)&adls_desc},
+#endif
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 0aed2a7ab858..68da8f797403 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -18,14 +18,18 @@
#include <sound/sof/pm.h>
#include <sound/sof/trace.h>
#include <uapi/sound/sof/fw.h>
+#include <sound/sof/ext_manifest.h>
/* debug flags */
#define SOF_DBG_ENABLE_TRACE BIT(0)
-#define SOF_DBG_REGS BIT(1)
-#define SOF_DBG_MBOX BIT(2)
-#define SOF_DBG_TEXT BIT(3)
-#define SOF_DBG_PCI BIT(4)
-#define SOF_DBG_RETAIN_CTX BIT(5) /* prevent DSP D3 on FW exception */
+#define SOF_DBG_RETAIN_CTX BIT(1) /* prevent DSP D3 on FW exception */
+
+#define SOF_DBG_DUMP_REGS BIT(0)
+#define SOF_DBG_DUMP_MBOX BIT(1)
+#define SOF_DBG_DUMP_TEXT BIT(2)
+#define SOF_DBG_DUMP_PCI BIT(3)
+#define SOF_DBG_DUMP_FORCE_ERR_LEVEL BIT(4) /* used to dump dsp status with error log level */
+
/* global debug state set by SOF_DBG_ flags */
extern int sof_core_debug;
@@ -100,7 +104,7 @@ struct snd_sof_dsp_ops {
/* DSP core boot / reset */
int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */
- int (*stall)(struct snd_sof_dev *sof_dev); /* optional */
+ int (*stall)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */
int (*reset)(struct snd_sof_dev *sof_dev); /* optional */
int (*core_power_up)(struct snd_sof_dev *sof_dev,
unsigned int core_mask); /* optional */
@@ -208,6 +212,10 @@ struct snd_sof_dsp_ops {
int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
+ /* parse platform specific extended manifest, optional */
+ int (*parse_platform_ext_manifest)(struct snd_sof_dev *sof_dev,
+ const struct sof_ext_man_elem_header *hdr);
+
/* DSP PM */
int (*suspend)(struct snd_sof_dev *sof_dev,
u32 target_state); /* optional */
@@ -290,6 +298,7 @@ enum sof_debugfs_access_type {
/* FS entry for debug files that can expose DSP memories, registers */
struct snd_sof_dfsentry {
size_t size;
+ size_t buf_data_size; /* length of buffered data for file read operation */
enum sof_dfsentry_type type;
/*
* access_type specifies if the
@@ -523,6 +532,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
void *stack, size_t stack_words);
int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev);
void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
+int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev);
/*
* Platform specific ops.
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 69313fbdb636..b6b32a7a91f8 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1041,6 +1041,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
goto out;
}
+ /*
+ * If control has more than 2 channels we need to override the info. This is because even if
+ * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
+ * pre-defined dapm control types (and related functions) creating the actual control
+ * restrict the channels only to mono or stereo.
+ */
+ if (le32_to_cpu(mc->num_channels) > 2)
+ kc->info = snd_sof_volume_info;
+
/* init the volume get/put data */
scontrol->size = struct_size(scontrol->control_data, chanv,
le32_to_cpu(mc->num_channels));
@@ -1201,7 +1210,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp,
ret = -EINVAL;
goto out_free;
}
- if (cdata->data->size + sizeof(const struct sof_abi_hdr) !=
+ if (cdata->data->size + sizeof(struct sof_abi_hdr) !=
le32_to_cpu(control->priv.size)) {
dev_err(scomp->dev,
"error: Conflict in bytes vs. priv size.\n");
@@ -2777,18 +2786,18 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
struct sof_ipc_dai_config *config)
{
/* clock directions wrt codec */
- if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) {
- /* codec is bclk master */
- if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
- config->format |= SOF_DAI_FMT_CBM_CFM;
+ if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
+ /* codec is bclk provider */
+ if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
+ config->format |= SOF_DAI_FMT_CBP_CFP;
else
- config->format |= SOF_DAI_FMT_CBM_CFS;
+ config->format |= SOF_DAI_FMT_CBP_CFC;
} else {
- /* codec is bclk slave */
- if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
- config->format |= SOF_DAI_FMT_CBS_CFM;
+ /* codec is bclk consumer */
+ if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
+ config->format |= SOF_DAI_FMT_CBC_CFP;
else
- config->format |= SOF_DAI_FMT_CBS_CFS;
+ config->format |= SOF_DAI_FMT_CBC_CFC;
}
/* inverted clocks ? */
@@ -3734,9 +3743,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
return ret;
}
- ret = snd_soc_tplg_component_load(scomp,
- &sof_tplg_ops, fw,
- SND_SOC_TPLG_INDEX_ALL);
+ ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
if (ret < 0) {
dev_err(scomp->dev, "error: tplg component load failed %d\n",
ret);
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index 69889241a092..f72a6e83e6af 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -13,6 +13,225 @@
#include "sof-priv.h"
#include "ops.h"
+#define TRACE_FILTER_ELEMENTS_PER_ENTRY 4
+#define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024
+
+static int trace_filter_append_elem(struct snd_sof_dev *sdev, uint32_t key, uint32_t value,
+ struct sof_ipc_trace_filter_elem *elem_list,
+ int capacity, int *counter)
+{
+ if (*counter >= capacity)
+ return -ENOMEM;
+
+ elem_list[*counter].key = key;
+ elem_list[*counter].value = value;
+ ++*counter;
+
+ return 0;
+}
+
+static int trace_filter_parse_entry(struct snd_sof_dev *sdev, const char *line,
+ struct sof_ipc_trace_filter_elem *elem,
+ int capacity, int *counter)
+{
+ int len = strlen(line);
+ int cnt = *counter;
+ uint32_t uuid_id;
+ int log_level;
+ int pipe_id;
+ int comp_id;
+ int read;
+ int ret;
+
+ /* ignore empty content */
+ ret = sscanf(line, " %n", &read);
+ if (!ret && read == len)
+ return len;
+
+ ret = sscanf(line, " %d %x %d %d %n", &log_level, &uuid_id, &pipe_id, &comp_id, &read);
+ if (ret != TRACE_FILTER_ELEMENTS_PER_ENTRY || read != len) {
+ dev_err(sdev->dev, "error: invalid trace filter entry '%s'\n", line);
+ return -EINVAL;
+ }
+
+ if (uuid_id > 0) {
+ ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_UUID,
+ uuid_id, elem, capacity, &cnt);
+ if (ret)
+ return ret;
+ }
+ if (pipe_id >= 0) {
+ ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE,
+ pipe_id, elem, capacity, &cnt);
+ if (ret)
+ return ret;
+ }
+ if (comp_id >= 0) {
+ ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_COMP,
+ comp_id, elem, capacity, &cnt);
+ if (ret)
+ return ret;
+ }
+
+ ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL |
+ SOF_IPC_TRACE_FILTER_ELEM_FIN,
+ log_level, elem, capacity, &cnt);
+ if (ret)
+ return ret;
+
+ /* update counter only when parsing whole entry passed */
+ *counter = cnt;
+
+ return len;
+}
+
+static int trace_filter_parse(struct snd_sof_dev *sdev, char *string,
+ int *out_elem_cnt,
+ struct sof_ipc_trace_filter_elem **out)
+{
+ static const char entry_delimiter[] = ";";
+ char *entry = string;
+ int capacity = 0;
+ int entry_len;
+ int cnt = 0;
+
+ /*
+ * Each entry contains at least 1, up to TRACE_FILTER_ELEMENTS_PER_ENTRY
+ * IPC elements, depending on content. Calculate IPC elements capacity
+ * for the input string where each element is set.
+ */
+ while (entry) {
+ capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY;
+ entry = strchr(entry + 1, entry_delimiter[0]);
+ }
+ *out = kmalloc(capacity * sizeof(**out), GFP_KERNEL);
+ if (!*out)
+ return -ENOMEM;
+
+ /* split input string by ';', and parse each entry separately in trace_filter_parse_entry */
+ while ((entry = strsep(&string, entry_delimiter))) {
+ entry_len = trace_filter_parse_entry(sdev, entry, *out, capacity, &cnt);
+ if (entry_len < 0) {
+ dev_err(sdev->dev, "error: %s failed for '%s', %d\n", __func__, entry,
+ entry_len);
+ return -EINVAL;
+ }
+ }
+
+ *out_elem_cnt = cnt;
+
+ return 0;
+}
+
+static int sof_ipc_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
+ struct sof_ipc_trace_filter_elem *elems)
+{
+ struct sof_ipc_trace_filter *msg;
+ struct sof_ipc_reply reply;
+ size_t size;
+ int ret;
+
+ size = struct_size(msg, elems, num_elems);
+ if (size > SOF_IPC_MSG_MAX_SIZE)
+ return -EINVAL;
+
+ msg = kmalloc(size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->hdr.size = size;
+ msg->hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_FILTER_UPDATE;
+ msg->elem_cnt = num_elems;
+ memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems));
+
+ ret = pm_runtime_get_sync(sdev->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(sdev->dev);
+ dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
+ goto error;
+ }
+ ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
+ &reply, sizeof(reply));
+ pm_runtime_mark_last_busy(sdev->dev);
+ pm_runtime_put_autosuspend(sdev->dev);
+
+error:
+ kfree(msg);
+ return ret ? ret : reply.error;
+}
+
+static ssize_t sof_dfsentry_trace_filter_write(struct file *file, const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct snd_sof_dfsentry *dfse = file->private_data;
+ struct sof_ipc_trace_filter_elem *elems = NULL;
+ struct snd_sof_dev *sdev = dfse->sdev;
+ loff_t pos = 0;
+ int num_elems;
+ char *string;
+ int ret;
+
+ if (count > TRACE_FILTER_MAX_CONFIG_STRING_LENGTH) {
+ dev_err(sdev->dev, "%s too long input, %zu > %d\n", __func__, count,
+ TRACE_FILTER_MAX_CONFIG_STRING_LENGTH);
+ return -EINVAL;
+ }
+
+ string = kmalloc(count + 1, GFP_KERNEL);
+ if (!string)
+ return -ENOMEM;
+
+ /* assert null termination */
+ string[count] = 0;
+ ret = simple_write_to_buffer(string, count, &pos, from, count);
+ if (ret < 0)
+ goto error;
+
+ ret = trace_filter_parse(sdev, string, &num_elems, &elems);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: fail in trace_filter_parse, %d\n", ret);
+ goto error;
+ }
+
+ if (num_elems) {
+ ret = sof_ipc_trace_update_filter(sdev, num_elems, elems);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: fail in sof_ipc_trace_update_filter %d\n", ret);
+ goto error;
+ }
+ }
+ ret = count;
+error:
+ kfree(string);
+ kfree(elems);
+ return ret;
+}
+
+static const struct file_operations sof_dfs_trace_filter_fops = {
+ .open = simple_open,
+ .write = sof_dfsentry_trace_filter_write,
+ .llseek = default_llseek,
+};
+
+static int trace_debugfs_filter_create(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_dfsentry *dfse;
+
+ dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+ if (!dfse)
+ return -ENOMEM;
+
+ dfse->sdev = sdev;
+ dfse->type = SOF_DFSENTRY_TYPE_BUF;
+
+ debugfs_create_file("filter", 0200, sdev->debugfs_root, dfse,
+ &sof_dfs_trace_filter_fops);
+ /* add to dfsentry list */
+ list_add(&dfse->list, &sdev->dfsentry_list);
+
+ return 0;
+}
+
static size_t sof_trace_avail(struct snd_sof_dev *sdev,
loff_t pos, size_t buffer_size)
{
@@ -135,10 +354,15 @@ static const struct file_operations sof_dfs_trace_fops = {
static int trace_debugfs_create(struct snd_sof_dev *sdev)
{
struct snd_sof_dfsentry *dfse;
+ int ret;
if (!sdev)
return -EINVAL;
+ ret = trace_debugfs_filter_create(sdev);
+ if (ret < 0)
+ dev_err(sdev->dev, "error: fail in %s, %d", __func__, ret);
+
dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
if (!dfse)
return -ENOMEM;