aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam Girdwood <liam.r.girdwood@linux.intel.com>2018-07-09 11:09:54 +0100
committerLiam Girdwood <liam.r.girdwood@linux.intel.com>2018-07-09 11:09:54 +0100
commit9b685810e82dddf05915b50f5d38088a243fe13d (patch)
treebb6d3e036d7818595f386777297dde85a6b95b1d
parentdcc8b997601eb210989f7cec96d6608f0ab32838 (diff)
downloadasoc-topic/sof-upstream-core.tar.gz
[FOR FIX] Rebase WiPtopic/sof-upstream-core
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
-rw-r--r--include/sound/sof.h10
-rw-r--r--include/uapi/sound/sof-ipc.h4
-rw-r--r--include/uapi/sound/sof-topology.h3
-rw-r--r--sound/soc/sof/Kconfig30
-rw-r--r--sound/soc/sof/Makefile20
-rw-r--r--sound/soc/sof/control.c54
-rw-r--r--sound/soc/sof/core.c76
-rw-r--r--sound/soc/sof/debug.c12
-rw-r--r--sound/soc/sof/ipc.c360
-rw-r--r--sound/soc/sof/ops.c22
-rw-r--r--sound/soc/sof/ops.h32
-rw-r--r--sound/soc/sof/pcm.c35
-rw-r--r--sound/soc/sof/sof-priv.h92
-rw-r--r--sound/soc/sof/topology.c335
-rw-r--r--sound/soc/sof/trace.c6
-rw-r--r--sound/soc/sof/utils.c57
16 files changed, 708 insertions, 440 deletions
diff --git a/include/sound/sof.h b/include/sound/sof.h
index 7767ec8ce188d6..e522e13e7a18d7 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -17,6 +17,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
+#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <uapi/sound/sof-ipc.h>
@@ -73,4 +74,13 @@ struct sof_dev_desc {
const char *nocodec_tplg_filename;
};
+int sof_nocodec_setup(struct device *dev,
+ struct snd_sof_pdata *sof_pdata,
+ struct snd_soc_acpi_mach *mach,
+ const struct sof_dev_desc *desc,
+ struct snd_sof_dsp_ops *ops);
+
+int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops,
+ struct snd_soc_dai_link *links, int link_num,
+ struct snd_soc_card *card);
#endif
diff --git a/include/uapi/sound/sof-ipc.h b/include/uapi/sound/sof-ipc.h
index 7bd9d64a9c50b1..e1df5c0a86a162 100644
--- a/include/uapi/sound/sof-ipc.h
+++ b/include/uapi/sound/sof-ipc.h
@@ -99,7 +99,7 @@
#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002)
/* Get message component id */
-#define SOF_IPC_MESSAGE_ID(x) (x & 0xffff)
+#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff)
/* maximum message size for mailbox Tx/Rx */
#define SOF_IPC_MSG_MAX_SIZE 128
@@ -209,7 +209,7 @@ enum sof_ipc_dai_type {
/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */
struct sof_ipc_dai_ssp_params {
uint16_t mode; // FIXME: do we need this?
- uint16_t clk_id; // FIXME: do we need this?
+ uint16_t mclk_id;
uint32_t mclk_rate; /* mclk frequency in Hz */
uint32_t fsync_rate; /* fsync frequency in Hz */
diff --git a/include/uapi/sound/sof-topology.h b/include/uapi/sound/sof-topology.h
index 1a4957b7fd049d..096aaed4333059 100644
--- a/include/uapi/sound/sof-topology.h
+++ b/include/uapi/sound/sof-topology.h
@@ -37,7 +37,6 @@
#define SOF_TKN_DAI_DMAC_CONFIG 153
#define SOF_TKN_DAI_TYPE 154
#define SOF_TKN_DAI_INDEX 155
-#define SOF_TKN_DAI_SAMPLE_BITS 156
/* scheduling */
#define SOF_TKN_SCHED_DEADLINE 200
@@ -68,6 +67,8 @@
#define SOF_TKN_INTEL_SSP_MCLK_KEEP_ACTIVE 500
#define SOF_TKN_INTEL_SSP_BCLK_KEEP_ACTIVE 501
#define SOF_TKN_INTEL_SSP_FS_KEEP_ACTIVE 502
+#define SOF_TKN_INTEL_SSP_MCLK_ID 503
+#define SOF_TKN_INTEL_SSP_SAMPLE_BITS 504
/* DMIC */
#define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 0e2a262c4daa9a..20ff0389c180b4 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -7,11 +7,9 @@ config SND_SOC_SOF_ACPI
config SND_SOC_SOF_PLATFORM
tristate
-
config SND_SOC_SOF
tristate "Sound Open Firmware Support"
default m
- depends on SND_DMA_SGBUF
select SND_SOC_TOPOLOGY
select SND_SOC_COMPRESS
help
@@ -19,27 +17,21 @@ config SND_SOC_SOF
Say Y if you have such a device.
If unsure select "N".
-config SND_SOC_SOF_NOCODEC
- tristate "SOF nocodec mode Support"
+config SND_SOC_SOF_DEBUG
+ bool "SOF debugging features"
depends on SND_SOC_SOF
help
- 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
- Say Y if you need this nocodec fallback option
+ This option can be used to enable or disable individual SOF firmware
+ and driver debugging options.
+ Say Y if you are debugging SOF FW or drivers.
If unsure select "N".
-config SND_SOC_SOF_FORCE_NOCODEC_MODE
- tristate "SOF force nocodec Mode"
- depends on SND_SOC_SOF_NOCODEC
+config SND_SOC_SOF_DEBUG_XRUN_STOP
+ bool "SOF stop on XRUN"
+ depends on SND_SOC_SOF_DEBUG
help
- This forces SOF to use dummy/nocodec as machine driver, even
- 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
+ This option forces PCMs to stop on any XRUN event. This is useful to
+ preserve any trace data ond pipeline status prior to the XRUN.
+ Say Y if you are debugging SOF FW pipeline XRUNs.
If unsure select "N".
-source "sound/soc/sof/intel/Kconfig"
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index ece93000a1974d..aad44d2f669756 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -1,22 +1,6 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
-snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
- control.o trace.o compressed.o
-snd-sof-spi-objs := hw-spi.o
-
-snd-sof-pci-objs := sof-pci-dev.o
-snd-sof-acpi-objs := sof-acpi-dev.o
-snd-sof-platform-objs := sof-platform-dev.o
-snd-sof-nocodec-objs := nocodec.o
+snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o debug.o topology.o\
+ control.o trace.o
obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o
-obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o
-
-obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o
-obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o
-obj-$(CONFIG_SND_SOC_SOF_SPI) += sof-spi-dev.o
-obj-$(SND_SOC_SOF_PLATFORM) += sof-platform-dev.o
-
-obj-$(CONFIG_SND_SOC_SOF_SPIDSP) += snd-sof-spi.o
-
-obj-$(CONFIG_SND_SOC_SOF_INTEL) += intel/
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 1c88596e70ba3a..e65340a8f704d9 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -20,57 +20,19 @@
#include <uapi/sound/sof-ipc.h>
#include "sof-priv.h"
-/* simple volume table TODO: to be replaced by coefficients from topology */
-/* -52 dB to +12 dB in 2 dB steps, 33 values */
-static const u32 volume_map[] = {
- 165,
- 207,
- 261,
- 328,
- 414,
- 521,
- 655,
- 825,
- 1039,
- 1308,
- 1646,
- 2072,
- 2609,
- 3285,
- 4135,
- 5206,
- 6554,
- 8250,
- 10387,
- 13076,
- 16462,
- 20724,
- 26090,
- 32846,
- 41350,
- 52057,
- 65536, /* 0 dB for Qx.16 gain value */
- 82505,
- 103868,
- 130762,
- 164619,
- 207243,
- 260904
-};
-
-static inline u32 mixer_to_ipc(unsigned int value)
+static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
{
- if (value >= ARRAY_SIZE(volume_map))
- return volume_map[0];
+ if (value >= size)
+ return volume_map[size - 1];
else
return volume_map[value];
}
-static inline u32 ipc_to_mixer(u32 value)
+static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
{
int i;
- for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
+ for (i = 0; i < size; i++) {
if (volume_map[i] >= value)
return i;
}
@@ -98,7 +60,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
/* read back each channel */
for (i = 0; i < channels; i++)
ucontrol->value.integer.value[i] =
- ipc_to_mixer(cdata->chanv[i].value);
+ ipc_to_mixer(cdata->chanv[i].value,
+ scontrol->volume_table, sm->max + 1);
pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
@@ -120,7 +83,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
/* update each channel */
for (i = 0; i < channels; i++) {
cdata->chanv[i].value =
- mixer_to_ipc(ucontrol->value.integer.value[i]);
+ mixer_to_ipc(ucontrol->value.integer.value[i],
+ scontrol->volume_table, sm->max + 1);
cdata->chanv[i].channel = i;
}
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 3bbcc34a72bbdd..5b178b62972736 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -8,6 +8,7 @@
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -33,7 +34,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm = NULL;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
- if (spcm->pcm.dai_id == rtd->dai_link->id)
+ if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id)
return spcm;
}
@@ -86,7 +87,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm = NULL;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
- if (spcm->pcm.pcm_id == pcm_id)
+ if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
return spcm;
}
@@ -122,6 +123,11 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
return NULL;
}
+static inline unsigned int sof_get_pages(size_t size)
+{
+ return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
/*
* FW Panic/fault handling.
*/
@@ -145,62 +151,6 @@ static const struct sof_panic_msg panic_msg[] = {
{SOF_IPC_PANIC_IDLE, "can't enter idle"},
};
-/* only need xtensa atm */
-static void sof_arch_dsp_oops(struct snd_sof_dev *sdev, void *oops)
-{
- struct sof_ipc_dsp_oops_xtensa *xoops = oops;
-
- dev_err(sdev->dev, "error: DSP Firmware Oops\n");
- dev_err(sdev->dev, "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n",
- xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar);
- dev_err(sdev->dev, "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x",
- xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4);
- dev_err(sdev->dev, "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x",
- xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc);
- dev_err(sdev->dev, "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x",
- xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5);
- dev_err(sdev->dev, "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x",
- xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt);
-}
-
-static void sof_dsp_dump_stack(struct snd_sof_dev *sdev, void *oops,
- u32 *stack, u32 stack_words)
-{
- struct sof_ipc_dsp_oops_xtensa *xoops = oops;
- u32 stack_ptr = xoops->stack;
- int i;
-
- dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr);
-
- for (i = 0; i <= stack_words - 4; i += 4) {
- dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
- stack_ptr + i, stack[i], stack[i + 1], stack[i + 2],
- stack[i + 3]);
- }
-
- /* deal with any remaining words */
- switch (stack_words - i) {
- case 0:
- break;
- case 1:
- dev_err(sdev->dev, "0x%8.8x: 0x%8.8x\n",
- stack_ptr + stack_words - 1, stack[stack_words - 1]);
- break;
- case 2:
- dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x\n",
- stack_ptr + stack_words - 2, stack[stack_words - 2],
- stack[stack_words - 1]);
- break;
- case 3:
- dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x 0x%8.8x\n",
- stack_ptr + stack_words - 3, stack[stack_words - 3],
- stack[stack_words - 2], stack[stack_words - 1]);
- break;
- default:
- break;
- }
-}
-
int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
u32 tracep_code, void *oops, void *stack,
size_t stack_words)
@@ -232,8 +182,8 @@ int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code);
out:
- sof_arch_dsp_oops(sdev, oops);
- sof_dsp_dump_stack(sdev, oops, stack, stack_words);
+ sof_oops(sdev, oops);
+ sof_stack(sdev, oops, stack, stack_words);
return -EFAULT;
}
EXPORT_SYMBOL(snd_sof_get_status);
@@ -407,6 +357,12 @@ static int sof_remove(struct platform_device *pdev)
return 0;
}
+void snd_sof_shutdown(struct device *dev)
+{
+}
+EXPORT_SYMBOL(snd_sof_shutdown);
+
+
static struct platform_driver sof_driver = {
.driver = {
.name = "sof-audio",
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index 6f9abbd240d9a9..bee43dbd7e640a 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -35,7 +35,7 @@ static int sof_dfsentry_open(struct inode *inode, struct file *file)
static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
- struct snd_sof_dfsentry *dfse = file->private_data;
+ struct snd_sof_dfsentry_io *dfse = file->private_data;
struct snd_sof_dev *sdev = dfse->sdev;
int size;
u32 *buf;
@@ -86,7 +86,7 @@ int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev,
void __iomem *base, size_t size,
const char *name)
{
- struct snd_sof_dfsentry *dfse;
+ struct snd_sof_dfsentry_io *dfse;
if (!sdev)
return -EINVAL;
@@ -102,8 +102,7 @@ int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev,
dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root,
dfse, &sof_dfs_fops);
if (!dfse->dfsentry) {
- dev_err(sdev->dev, "error: cannot create debugfs entry %s\n",
- name);
+ dev_err(sdev->dev, "cannot create debugfs entry.\n");
kfree(dfse);
return -ENODEV;
}
@@ -129,11 +128,12 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
for (i = 0; i < ops->debug_map_count; i++) {
map = &ops->debug_map[i];
- err = snd_sof_debugfs_create_item(sdev, sdev->bar[map->bar] +
+ err = snd_sof_debugfs_create_item(sdev,
+ sdev->bar[map->bar] +
map->offset, map->size,
map->name);
if (err < 0)
- dev_err(sdev->dev, "error: cannot create debugfs for %s\n",
+ dev_err(sdev->dev, "cannot create debugfs for %s\n",
map->name);
}
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index bd646c23cf9fd2..a08529a111c7e3 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -6,6 +6,9 @@
* Copyright(c) 2017 Intel Corporation. All rights reserved.
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+ *
+ * Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided
+ * by platform driver code.
*/
#include <linux/types.h>
@@ -31,11 +34,21 @@
#include "sof-priv.h"
#include "ops.h"
-/* IPC message timeout (msecs) */
+/*
+ * IPC message default size and timeout (msecs).
+ * TODO: allow platforms to set size and timeout.
+ */
#define IPC_TIMEOUT_MSECS 300
#define IPC_EMPTY_LIST_SIZE 8
+static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id);
+static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd);
+
+/*
+ * IPC message Tx/Rx message handling.
+ */
+
/* SOF generic IPC data */
struct snd_sof_ipc {
struct snd_sof_dev *sdev;
@@ -59,6 +72,7 @@ static struct snd_sof_ipc_msg *msg_get_empty(struct snd_sof_ipc *ipc)
{
struct snd_sof_ipc_msg *msg = NULL;
+ /* get first empty message in the list */
if (!list_empty(&ipc->empty_list)) {
msg = list_first_entry(&ipc->empty_list, struct snd_sof_ipc_msg,
list);
@@ -68,6 +82,7 @@ static struct snd_sof_ipc_msg *msg_get_empty(struct snd_sof_ipc *ipc)
return msg;
}
+/* wait for IPC message reply */
static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg,
void *reply_data)
{
@@ -111,6 +126,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg,
return ret;
}
+/* send IPC message from host to DSP */
int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
void *msg_data, size_t msg_bytes, void *reply_data,
size_t reply_bytes)
@@ -121,6 +137,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
spin_lock_irqsave(&sdev->ipc_lock, flags);
+ /* get an empty message */
msg = msg_get_empty(ipc);
if (!msg) {
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
@@ -132,9 +149,11 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
msg->reply_size = reply_bytes;
msg->complete = false;
+ /* attach any data */
if (msg_bytes)
memcpy(msg->msg_data, msg_data, msg_bytes);
+ /* add message to transmit list */
list_add_tail(&msg->list, &ipc->tx_list);
/* schedule the messgae if not busy */
@@ -143,10 +162,12 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
+ /* now wait for completion */
return tx_wait_done(ipc, msg, reply_data);
}
EXPORT_SYMBOL(sof_ipc_tx_message);
+/* send next IPC message in list */
static void ipc_tx_next_msg(struct work_struct *work)
{
struct snd_sof_ipc *ipc =
@@ -156,13 +177,15 @@ static void ipc_tx_next_msg(struct work_struct *work)
spin_lock_irq(&sdev->ipc_lock);
+ /* send message if HW read and message in TX list */
if (list_empty(&ipc->tx_list))
goto out;
+ /* sned first message in TX list */
msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list);
list_move(&msg->list, &ipc->reply_list);
-
snd_sof_dsp_send_msg(sdev, msg);
+
dev_dbg(sdev->dev, "ipc: send 0x%x\n", msg->header);
out:
@@ -200,6 +223,7 @@ void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc,
wake_up(&msg->waitq);
}
+/* drop all IPC messages in preparation for DSP stall/reset */
void sof_ipc_drop_all(struct snd_sof_ipc *ipc)
{
struct snd_sof_dev *sdev = ipc->sdev;
@@ -223,6 +247,7 @@ void sof_ipc_drop_all(struct snd_sof_ipc *ipc)
}
EXPORT_SYMBOL(sof_ipc_drop_all);
+/* handle reply message from DSP */
void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
{
struct snd_sof_ipc_msg *msg;
@@ -239,17 +264,105 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
}
EXPORT_SYMBOL(snd_sof_ipc_reply);
-int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox,
- size_t dspbox_size, u32 hostbox,
- size_t hostbox_size)
+/* DSP firmware has sent host a message */
+static void ipc_msgs_rx(struct work_struct *work)
{
- sdev->dsp_box.offset = dspbox;
- sdev->dsp_box.size = dspbox_size;
- sdev->host_box.offset = hostbox;
- sdev->host_box.size = hostbox_size;
- return 0;
+ struct snd_sof_ipc *ipc =
+ container_of(work, struct snd_sof_ipc, rx_kwork);
+ struct snd_sof_dev *sdev = ipc->sdev;
+ struct sof_ipc_hdr hdr;
+ u32 cmd, type;
+ int err = -EINVAL;
+
+ /* read back header */
+ snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr));
+
+ cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
+ type = hdr.cmd & SOF_CMD_TYPE_MASK;
+
+ /* check message type */
+ switch (cmd) {
+ case SOF_IPC_GLB_REPLY:
+ dev_err(sdev->dev, "error: ipc reply unknown\n");
+ break;
+ case SOF_IPC_FW_READY:
+ /* check for FW boot completion */
+ if (!sdev->boot_complete) {
+ if (sdev->ops->fw_ready)
+ err = sdev->ops->fw_ready(sdev, cmd);
+ if (err < 0) {
+ dev_err(sdev->dev, "DSP firmware boot timeout %d\n",
+ err);
+ } else {
+ /* firmware boot completed OK */
+ sdev->boot_complete = true;
+ dev_dbg(sdev->dev, "booting DSP firmware completed\n");
+ wake_up(&sdev->boot_wait);
+ }
+ }
+ break;
+ case SOF_IPC_GLB_COMPOUND:
+ case SOF_IPC_GLB_TPLG_MSG:
+ case SOF_IPC_GLB_PM_MSG:
+ case SOF_IPC_GLB_COMP_MSG:
+ break;
+ case SOF_IPC_GLB_STREAM_MSG:
+ /* need to pass msg id into the function */
+ ipc_stream_message(sdev, hdr.cmd);
+ break;
+ case SOF_IPC_GLB_TRACE_MSG:
+ ipc_trace_message(sdev, type);
+ break;
+ default:
+ dev_err(sdev->dev, "unknown DSP message 0x%x\n", cmd);
+ break;
+ }
+
+ dev_dbg(sdev->dev, "ipc rx: 0x%x done\n", hdr.cmd);
+
+ /* tell DSP we are done */
+ snd_sof_dsp_cmd_done(sdev);
}
-EXPORT_SYMBOL(snd_sof_dsp_mailbox_init);
+
+/* schedule work to transmit any IPC in queue */
+void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev)
+{
+ schedule_work(&sdev->ipc->tx_kwork);
+}
+EXPORT_SYMBOL(snd_sof_ipc_msgs_tx);
+
+/* schedule work to handle IPC from DSP */
+void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
+{
+ schedule_work(&sdev->ipc->rx_kwork);
+}
+EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);
+
+/*
+ * IPC trace mechanism.
+ */
+
+static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
+{
+ struct sof_ipc_dma_trace_posn posn;
+
+ switch (msg_id) {
+ case SOF_IPC_TRACE_DMA_POSITION:
+ /* read back full message */
+ snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn,
+ sizeof(posn));
+ snd_sof_trace_update_pos(sdev, &posn);
+ break;
+ default:
+ dev_err(sdev->dev, "error: unhandled trace message %x\n",
+ msg_id);
+ break;
+ }
+}
+
+/*
+ * IPC stream position.
+ */
static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
{
@@ -293,6 +406,7 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
snd_pcm_period_elapsed(spcm->stream[direction].substream);
}
+/* DSP notifies host of an XRUN within FW */
static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
{
struct sof_ipc_stream_posn posn;
@@ -300,7 +414,7 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
u32 posn_offset;
int direction;
- /* check if we have stream box */
+ /* check if we have stream MMIO on this platform */
if (sdev->stream_box.size == 0) {
/* read back full message */
snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn,
@@ -330,12 +444,14 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n",
posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
- return; /* TODO: don't do anything yet until preload is working */
-
+#if defined(CONFIG_SOC_SOF_DEBUG_XRUN_STOP)
+ /* stop PCM on XRUN - used for pipeline debug */
memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn));
snd_pcm_stop_xrun(spcm->stream[direction].substream);
+#endif
}
+/* stream notifications from DSP FW */
static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
{
/* get msg cmd type and msd id */
@@ -356,148 +472,7 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
}
}
-static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
-{
- struct sof_ipc_dma_trace_posn posn;
-
- switch (msg_id) {
- case SOF_IPC_TRACE_DMA_POSITION:
- /* read back full message */
- snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn,
- sizeof(posn));
- snd_sof_trace_update_pos(sdev, &posn);
- break;
- default:
- dev_err(sdev->dev, "error: unhandled trace message %x\n",
- msg_id);
- break;
- }
-}
-
-/* DSP firmware has sent host a message */
-static void ipc_msgs_rx(struct work_struct *work)
-{
- struct snd_sof_ipc *ipc =
- container_of(work, struct snd_sof_ipc, rx_kwork);
- struct snd_sof_dev *sdev = ipc->sdev;
- struct sof_ipc_hdr hdr;
- u32 cmd, type;
- int err = -EINVAL;
-
- /* read back header */
- snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr));
-
- cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
- type = hdr.cmd & SOF_CMD_TYPE_MASK;
-
- switch (cmd) {
- case SOF_IPC_GLB_REPLY:
- dev_err(sdev->dev, "error: ipc reply unknown\n");
- break;
- case SOF_IPC_FW_READY:
- /* check for FW boot completion */
- if (!sdev->boot_complete) {
- if (sdev->ops->fw_ready)
- err = sdev->ops->fw_ready(sdev, cmd);
- if (err < 0) {
- dev_err(sdev->dev, "DSP firmware boot timeout %d\n",
- err);
- } else {
- /* firmware boot completed OK */
- sdev->boot_complete = true;
- dev_dbg(sdev->dev, "booting DSP firmware completed\n");
- wake_up(&sdev->boot_wait);
- }
- }
- break;
- case SOF_IPC_GLB_COMPOUND:
- case SOF_IPC_GLB_TPLG_MSG:
- case SOF_IPC_GLB_PM_MSG:
- case SOF_IPC_GLB_COMP_MSG:
- break;
- case SOF_IPC_GLB_STREAM_MSG:
- /* need to pass msg id into the function */
- ipc_stream_message(sdev, hdr.cmd);
- break;
- case SOF_IPC_GLB_TRACE_MSG:
- ipc_trace_message(sdev, type);
- break;
- default:
- dev_err(sdev->dev, "unknown DSP message 0x%x\n", cmd);
- break;
- }
-
- dev_dbg(sdev->dev, "ipc rx: 0x%x done\n", hdr.cmd);
-
- snd_sof_dsp_cmd_done(sdev);
-}
-
-void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev)
-{
- schedule_work(&sdev->ipc->tx_kwork);
-}
-EXPORT_SYMBOL(snd_sof_ipc_msgs_tx);
-
-void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
-{
- schedule_work(&sdev->ipc->rx_kwork);
-}
-EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);
-
-struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
-{
- struct snd_sof_ipc *ipc;
- struct snd_sof_ipc_msg *msg;
- int i;
-
- ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
- if (!ipc)
- return NULL;
-
- INIT_LIST_HEAD(&ipc->tx_list);
- INIT_LIST_HEAD(&ipc->reply_list);
- INIT_LIST_HEAD(&ipc->empty_list);
- init_waitqueue_head(&ipc->wait_txq);
- INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg);
- INIT_WORK(&ipc->rx_kwork, ipc_msgs_rx);
- ipc->sdev = sdev;
-
- /* pre-allocate messages */
- dev_dbg(sdev->dev, "pre-allocate %d IPC messages\n",
- IPC_EMPTY_LIST_SIZE);
- msg = devm_kzalloc(sdev->dev, sizeof(struct snd_sof_ipc_msg) *
- IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
- if (!msg)
- return NULL;
-
- /* pre-allocate message data */
- for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
- msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL);
- if (!msg->msg_data)
- return NULL;
-
- msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE,
- GFP_KERNEL);
- if (!msg->reply_data)
- return NULL;
-
- init_waitqueue_head(&msg->waitq);
- list_add(&msg->list, &ipc->empty_list);
- msg++;
- }
-
- return ipc;
-}
-EXPORT_SYMBOL(snd_sof_ipc_init);
-
-void snd_sof_ipc_free(struct snd_sof_dev *sdev)
-{
- /* TODO: send IPC to prepare DSP for shutdown */
- cancel_work_sync(&sdev->ipc->tx_kwork);
- cancel_work_sync(&sdev->ipc->rx_kwork);
-}
-EXPORT_SYMBOL(snd_sof_ipc_free);
-
+/* get stream position IPC - use faster MMIO method if available on platform */
int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm, int direction,
struct sof_ipc_stream_posn *posn)
@@ -524,6 +499,10 @@ int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL(snd_sof_ipc_stream_posn);
+/*
+ * IPC get()/set() for kcontrols.
+ */
+
int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc,
struct snd_sof_control *scontrol, u32 ipc_cmd,
enum sof_ipc_ctrl_type ctrl_type,
@@ -607,3 +586,72 @@ int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc,
return 0;
}
EXPORT_SYMBOL(snd_sof_ipc_get_comp_data);
+
+/*
+ * IPC layer enumeration.
+ */
+
+int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox,
+ size_t dspbox_size, u32 hostbox,
+ size_t hostbox_size)
+{
+ sdev->dsp_box.offset = dspbox;
+ sdev->dsp_box.size = dspbox_size;
+ sdev->host_box.offset = hostbox;
+ sdev->host_box.size = hostbox_size;
+ return 0;
+}
+EXPORT_SYMBOL(snd_sof_dsp_mailbox_init);
+
+struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_ipc *ipc;
+ struct snd_sof_ipc_msg *msg;
+ int i;
+
+ ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
+ if (!ipc)
+ return NULL;
+
+ INIT_LIST_HEAD(&ipc->tx_list);
+ INIT_LIST_HEAD(&ipc->reply_list);
+ INIT_LIST_HEAD(&ipc->empty_list);
+ init_waitqueue_head(&ipc->wait_txq);
+ INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg);
+ INIT_WORK(&ipc->rx_kwork, ipc_msgs_rx);
+ ipc->sdev = sdev;
+
+ /* pre-allocate messages */
+ dev_dbg(sdev->dev, "pre-allocate %d IPC messages\n",
+ IPC_EMPTY_LIST_SIZE);
+ msg = devm_kzalloc(sdev->dev, sizeof(struct snd_sof_ipc_msg) *
+ IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+ if (!msg)
+ return NULL;
+
+ /* pre-allocate message data */
+ for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+ msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL);
+ if (!msg->msg_data)
+ return NULL;
+
+ msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE,
+ GFP_KERNEL);
+ if (!msg->reply_data)
+ return NULL;
+
+ init_waitqueue_head(&msg->waitq);
+ list_add(&msg->list, &ipc->empty_list);
+ msg++;
+ }
+
+ return ipc;
+}
+EXPORT_SYMBOL(snd_sof_ipc_init);
+
+void snd_sof_ipc_free(struct snd_sof_dev *sdev)
+{
+ cancel_work_sync(&sdev->ipc->tx_kwork);
+ cancel_work_sync(&sdev->ipc->rx_kwork);
+}
+EXPORT_SYMBOL(snd_sof_ipc_free);
diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c
index 9ac69e83a584a3..0668f64e1ef672 100644
--- a/sound/soc/sof/ops.c
+++ b/sound/soc/sof/ops.c
@@ -23,7 +23,7 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
{
bool change;
unsigned int old, new;
- u32 ret;
+ u32 ret = ~0; /* explicit init to remove uninitialized use warnings */
pci_read_config_dword(sdev->pci, offset, &ret);
dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n",
@@ -188,3 +188,23 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset,
return ret;
}
EXPORT_SYMBOL(snd_sof_dsp_register_poll);
+
+void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
+{
+ dev_err(sdev->dev, "error : DSP panic!\n");
+
+ /* check if DSP is not ready and did not set the dsp_oops_offset.
+ * if the dsp_oops_offset is not set, set it from the panic message.
+ * Also add a check to memory window setting with panic message.
+ */
+ if (!sdev->dsp_oops_offset)
+ sdev->dsp_oops_offset = offset;
+ else
+ 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_trace_notify_for_error(sdev);
+ snd_sof_dsp_cmd_done(sdev);
+}
+EXPORT_SYMBOL(snd_sof_dsp_panic);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index e49ac67becfae3..828a49f7bb2c60 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -220,8 +220,9 @@ static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd)
}
/* host PCM ops */
-static inline int snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream)
+static inline int
+snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
{
if (sdev->ops && sdev->ops->pcm_open)
return sdev->ops->pcm_open(sdev, substream);
@@ -229,9 +230,10 @@ static inline int snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,
return 0;
}
- /* disconnect pcm substream to a host stream */
-static inline int snd_sof_pcm_platform_close(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream)
+/* disconnect pcm substream to a host stream */
+static inline int
+snd_sof_pcm_platform_close(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
{
if (sdev->ops && sdev->ops->pcm_close)
return sdev->ops->pcm_close(sdev, substream);
@@ -239,10 +241,11 @@ static inline int snd_sof_pcm_platform_close(struct snd_sof_dev *sdev,
return 0;
}
- /* host stream hw params */
-static inline int snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+/* host stream hw params */
+static inline int
+snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
if (sdev->ops && sdev->ops->pcm_hw_params)
return sdev->ops->pcm_hw_params(sdev, substream, params);
@@ -250,6 +253,17 @@ static inline int snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
return 0;
}
+/* host stream trigger */
+static inline int
+snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ if (sdev->ops && sdev->ops->pcm_trigger)
+ return sdev->ops->pcm_trigger(sdev, substream, cmd);
+ else
+ return 0;
+}
+
int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
u32 offset, u32 mask, u32 value);
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 63c99165ae193b..23c3a88ca592b9 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -243,6 +243,8 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return -EINVAL;
}
+ snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+
/* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
sizeof(stream), &reply, sizeof(reply));
@@ -302,10 +304,10 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
/* set any runtime constraints based on topology */
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- caps->period_size_min);
+ le32_to_cpu(caps->period_size_min));
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- caps->period_size_min);
+ le32_to_cpu(caps->period_size_min));
/* set runtime config */
runtime->hw.info = SNDRV_PCM_INFO_MMAP |
@@ -314,12 +316,12 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
- runtime->hw.formats = caps->formats;
- runtime->hw.period_bytes_min = caps->period_size_min;
- runtime->hw.period_bytes_max = caps->period_size_max;
- runtime->hw.periods_min = caps->periods_min;
- runtime->hw.periods_max = caps->periods_max;
- runtime->hw.buffer_bytes_max = caps->buffer_size_max;
+ 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);
+ runtime->hw.periods_min = le32_to_cpu(caps->periods_min);
+ runtime->hw.periods_max = le32_to_cpu(caps->periods_max);
+ runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
dev_dbg(sdev->dev, "period min %zd max %zd bytes\n",
runtime->hw.period_bytes_min,
@@ -413,8 +415,8 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd)
ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
SNDRV_DMA_TYPE_DEV_SG, sdev->parent,
- caps->buffer_size_min,
- caps->buffer_size_max);
+ le32_to_cpu(caps->buffer_size_min),
+ le32_to_cpu(caps->buffer_size_max));
if (ret) {
dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n",
caps->buffer_size_min, caps->buffer_size_max,
@@ -446,8 +448,8 @@ capture:
ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
SNDRV_DMA_TYPE_DEV_SG, sdev->parent,
- caps->buffer_size_min,
- caps->buffer_size_max);
+ le32_to_cpu(caps->buffer_size_min),
+ le32_to_cpu(caps->buffer_size_max));
if (ret) {
dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n",
caps->buffer_size_min, caps->buffer_size_max,
@@ -525,7 +527,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->max = 2;
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
@@ -535,13 +537,13 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
switch (dai->comp_dai.config.frame_fmt) {
case SOF_IPC_FRAME_S16_LE:
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S16_LE);
break;
case SOF_IPC_FRAME_S24_4LE:
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S24_LE);
break;
case SOF_IPC_FRAME_S32_LE:
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE);
+ snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S32_LE);
break;
default:
dev_err(sdev->dev, "No available DAI format!\n");
@@ -629,7 +631,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
pd->probe = sof_pcm_probe;
pd->remove = sof_pcm_remove;
pd->ops = &sof_pcm_ops;
- pd->compr_ops = &sof_compressed_ops;
pd->pcm_new = sof_pcm_new;
pd->pcm_free = sof_pcm_free;
pd->ignore_machine = plat_data->machine->drv_name;
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 8fe495182acfa1..da2daf7ad82ba0 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -57,7 +57,14 @@ struct snd_sof_ipc;
struct snd_sof_debugfs_map;
struct snd_soc_tplg_ops;
struct snd_soc_component;
+struct sof_intel_hda_dev;
+struct snd_sof_pdata;
+/*
+ * SOF DSP HW abstraction operations.
+ * Used to abstract DSP HW architecture and any IO busses between host CPU
+ * and DSP device(s).
+ */
struct snd_sof_dsp_ops {
/* probe and remove */
int (*remove)(struct snd_sof_dev *sof_dev);
@@ -95,9 +102,9 @@ struct snd_sof_dsp_ops {
/* mailbox */
void (*mailbox_read)(struct snd_sof_dev *sof_dev, u32 offset,
- void __iomem *addr, size_t bytes);
+ void *addr, size_t bytes);
void (*mailbox_write)(struct snd_sof_dev *sof_dev, u32 offset,
- void __iomem *addr, size_t bytes);
+ void *addr, size_t bytes);
/* ipc */
int (*send_msg)(struct snd_sof_dev *sof_dev,
@@ -124,6 +131,10 @@ struct snd_sof_dsp_ops {
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
+ /* host stream trigger */
+ int (*pcm_trigger)(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream, int cmd);
+
/* FW loading */
int (*load_firmware)(struct snd_sof_dev *sof_dev,
const struct firmware *fw);
@@ -141,21 +152,36 @@ struct snd_sof_dsp_ops {
int num_drv;
};
-struct snd_sof_pdata;
+/* DSP architecture specific callbacks for oops and stack dumps */
+struct sof_arch_ops {
+ void (*dsp_oops)(struct snd_sof_dev *sdev, void *oops);
+ void (*dsp_stack)(struct snd_sof_dev *sdev, void *oops,
+ u32 *stack, u32 stack_words);
+};
+/* DSP device HW descriptor mapping between bus ID and ops */
struct sof_ops_table {
const struct sof_dev_desc *desc;
struct snd_sof_dsp_ops *ops;
struct platform_device *(*new_data)(struct snd_sof_pdata *pdata);
};
-struct snd_sof_dfsentry {
+/* FS entry for debug files that can expose DSP memories, registers */
+struct snd_sof_dfsentry_io {
+ struct dentry *dfsentry;
+ size_t size;
+ void __iomem *buf;
+ struct snd_sof_dev *sdev;
+};
+
+struct snd_sof_dfsentry_buf {
struct dentry *dfsentry;
size_t size;
void *buf;
struct snd_sof_dev *sdev;
};
+/* Debug mapping for any DSP memory or registers that can used for debug */
struct snd_sof_debugfs_map {
const char *name;
u32 bar;
@@ -163,11 +189,28 @@ struct snd_sof_debugfs_map {
u32 size;
};
+/* mailbox descriptor, used for host <-> DSP IPC */
struct snd_sof_mailbox {
u32 offset;
size_t size;
};
+/* IPC message descriptor for host <-> DSP IO */
+struct snd_sof_ipc_msg {
+ struct list_head list;
+
+ /* message data */
+ u32 header;
+ void *msg_data;
+ void *reply_data;
+ size_t msg_size;
+ size_t reply_size;
+
+ wait_queue_head_t waitq;
+ bool complete;
+};
+
+/* PCM stream, mapped to FW component */
struct snd_sof_pcm_stream {
u32 comp_id;
struct snd_dma_buffer page_table;
@@ -175,6 +218,7 @@ struct snd_sof_pcm_stream {
struct snd_pcm_substream *substream;
};
+/* ASLA SOF PCM device */
struct snd_sof_pcm {
struct snd_sof_dev *sdev;
struct snd_soc_tplg_pcm pcm;
@@ -184,6 +228,7 @@ struct snd_sof_pcm {
struct list_head list; /* list in sdev pcm list */
};
+/* ALSA SOF Kcontrol device */
struct snd_sof_control {
struct snd_sof_dev *sdev;
int comp_id;
@@ -198,6 +243,7 @@ struct snd_sof_control {
struct list_head list; /* list in sdev control list */
};
+/* ASoC SOF DAPM widget */
struct snd_sof_widget {
struct snd_sof_dev *sdev;
int comp_id;
@@ -209,9 +255,10 @@ struct snd_sof_widget {
struct mutex mutex;
struct list_head list; /* list in sdev widget list */
- void *private; /* core does not touch this */
+ void *private; /* core does not touch this */
};
+/* ASoC DAI device */
struct snd_sof_dai {
struct snd_sof_dev *sdev;
const char *name;
@@ -221,22 +268,6 @@ struct snd_sof_dai {
struct list_head list; /* list in sdev dai list */
};
-struct snd_sof_ipc_msg {
- struct list_head list;
-
- /* message data */
- u32 header;
- void *msg_data;
- void *reply_data;
- size_t msg_size;
- size_t reply_size;
-
- wait_queue_head_t waitq;
- bool complete;
-};
-
-struct sof_intel_hda_dev;
-
/*
* SOF Device Level.
*/
@@ -258,6 +289,7 @@ struct snd_sof_dev {
struct snd_sof_pdata *pdata;
const struct snd_sof_dsp_ops *ops;
struct sof_intel_hda_dev *hda; /* for HDA based DSP HW */
+ const struct sof_arch_ops *arch_ops;
/* IPC */
struct snd_sof_ipc *ipc;
@@ -371,6 +403,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
int *direction);
struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
unsigned int pcm_id);
+void sof_ipc_drop_all(struct snd_sof_ipc *ipc);
/*
* Stream IPC
@@ -438,4 +471,21 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+/*
+ * DSP Architectures.
+ */
+static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
+ u32 stack_words)
+{
+ if (sdev->arch_ops->dsp_stack)
+ sdev->arch_ops->dsp_stack(sdev, oops, stack, stack_words);
+}
+
+static inline void sof_oops(struct snd_sof_dev *sdev, void *oops)
+{
+ if (sdev->arch_ops->dsp_oops)
+ sdev->arch_ops->dsp_oops(sdev, oops);
+}
+
+extern const struct sof_arch_ops sof_xtensa_arch_ops;
#endif
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 03b054b2492612..9d5b575760f9c5 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -20,15 +20,166 @@
#include <linux/string.h>
#include <sound/soc-topology.h>
#include <sound/soc.h>
+#include <uapi/sound/tlv.h>
+#include <sound/tlv.h>
#include <uapi/sound/sof-ipc.h>
#include <uapi/sound/sof-topology.h>
#include "sof-priv.h"
#define COMP_ID_UNASSIGNED 0xffffffff
+/* Constants used in the computation of linear volume gain from dB gain */
+/* 20th root of 10 in Q1.16 fixed-point notation*/
+#define VOL_TWENTIETH_ROOT_OF_TEN 73533
+/* 40th root of 10 in Q1.16 fixed-point notation*/
+#define VOL_FORTIETH_ROOT_OF_TEN 69419
+/* Volume fractional word length */
+#define VOLUME_FWL 16
+/* 0.5 dB step value in topology TLV */
+#define VOL_HALF_DB_STEP 50
+
+/* TLV data items */
+#define TLV_ITEMS 3
+#define TLV_MIN 0
+#define TLV_STEP 1
+#define TLV_MUTE 2
+
+static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS])
+{
+ /* we only support dB scale TLV type at the moment */
+ if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE)
+ return -EINVAL;
-/*
- * Supported DAI types and lookup, add new ones to end of list .
+ /* min value in topology tlv data is multiplied by 100 */
+ tlv[TLV_MIN] = (int)p[SNDRV_CTL_TLVO_DB_SCALE_MIN] / 100;
+
+ /* volume steps */
+ tlv[TLV_STEP] = (int)(p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
+ TLV_DB_SCALE_MASK);
+
+ /* mute ON/OFF */
+ if ((p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
+ TLV_DB_SCALE_MUTE) == 0)
+ tlv[TLV_MUTE] = 0;
+ else
+ tlv[TLV_MUTE] = 1;
+
+ return 0;
+}
+
+/* Function to truncate an unsigned 64-bit number
+ * by x bits and return 32-bit unsigned number
+ * This function also takes care of rounding while truncating
+ */
+static inline u32 vol_shift_64(u64 i, u32 x)
+{
+ /* do not truncate more than 32 bits */
+ if (x > 32)
+ x = 32;
+
+ if (x == 0)
+ return (u32)i;
+
+ return (u32)(((i >> (x - 1)) + 1) >> 1);
+}
+
+/* Function to compute a ^ exp where,
+ * a is a fractional number represented by a fixed-point integer
+ * with a fractional world length of "fwl"
+ * exp is an integer
+ * fwl is the fractional word length
+ * Return value is a fractional number represented by a fixed-point
+ * integer with a fractional word length of "fwl"
+ */
+static u32 vol_pow32(u32 a, int exp, u32 fwl)
+{
+ int i, iter;
+ u32 power = 1 << fwl;
+ u64 numerator;
+
+ /* if exponent is 0, return 1 */
+ if (exp == 0)
+ return power;
+
+ /* determine the number of iterations based on the exponent */
+ if (exp < 0)
+ iter = exp * -1;
+ else
+ iter = exp;
+
+ /* mutiply a "iter" times to compute power */
+ for (i = 0; i < iter; i++) {
+ /* Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl
+ * Truncate product back to fwl fractional bits with rounding
+ */
+ power = vol_shift_64((u64)power * a, fwl);
+ }
+
+ if (exp > 0) {
+ /* if exp is positive, return the result */
+ return power;
+ }
+
+ /* if exp is negative, return the multiplicative inverse */
+ numerator = (u64)1 << (fwl << 1);
+ do_div(numerator, power);
+
+ return (u32)numerator;
+}
+
+/* Function to calculate volume gain from TLV data
+ * This function can only handle gain steps that are multiples of 0.5 dB
+ */
+static u32 vol_compute_gain(u32 value, int *tlv)
+{
+ int dB_gain;
+ u32 linear_gain;
+ int f_step;
+
+ /* mute volume */
+ if (value == 0 && tlv[TLV_MUTE])
+ return 0;
+
+ /* compute dB gain from tlv
+ * tlv_step in topology is multiplied by 100
+ */
+ dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100;
+
+ /* compute linear gain
+ * represented by fixed-point int with VOLUME_FWL fractional bits
+ */
+ linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL);
+
+ /* extract the fractional part of volume step */
+ f_step = tlv[TLV_STEP] - (tlv[TLV_STEP] / 100);
+
+ /* if volume step is an odd multiple of 0.5 dB */
+ if (f_step == VOL_HALF_DB_STEP && (value & 1))
+ linear_gain = vol_shift_64((u64)linear_gain *
+ VOL_FORTIETH_ROOT_OF_TEN,
+ VOLUME_FWL);
+
+ return linear_gain;
+}
+
+/* Set up volume table for kcontrols from tlv data
+ * "size" specifies the number of entries in the table
*/
+static int set_up_volume_table(struct snd_sof_control *scontrol,
+ int tlv[TLV_ITEMS], int size)
+{
+ int j;
+
+ /* init the volume table */
+ scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
+ if (!scontrol->volume_table)
+ return -ENOMEM;
+
+ /* populate the volume table */
+ for (j = 0; j < size ; j++)
+ scontrol->volume_table[j] = vol_compute_gain(j, tlv);
+
+ return 0;
+}
struct sof_dai_types {
const char *name;
@@ -69,7 +220,7 @@ static const struct sof_frame_types sof_frames[] = {
{"float", SOF_IPC_FRAME_FLOAT},
};
-static enum sof_ipc_dai_type find_format(const char *name)
+static enum sof_ipc_frame find_format(const char *name)
{
int i;
@@ -97,19 +248,20 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
struct sof_ipc_ctrl_data *cdata;
/* validate topology data */
- if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN)
+ if (le32_to_cpu(mc->num_channels) >= SND_SOC_TPLG_MAX_CHAN)
return -EINVAL;
/* init the volume get/put data */
scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
- sizeof(struct sof_ipc_ctrl_value_chan) * mc->num_channels;
+ sizeof(struct sof_ipc_ctrl_value_chan) *
+ le32_to_cpu(mc->num_channels);
scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
cdata = scontrol->control_data;
if (!scontrol->control_data)
return -ENOMEM;
scontrol->comp_id = sdev->next_comp_id;
- scontrol->num_channels = mc->num_channels;
+ scontrol->num_channels = le32_to_cpu(mc->num_channels);
dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n",
scontrol->comp_id, scontrol->num_channels);
@@ -135,7 +287,7 @@ static int get_token_u32(void *elem, void *object, u32 offset, u32 size)
struct snd_soc_tplg_vendor_value_elem *velem = elem;
u32 *val = object + offset;
- *val = velem->value;
+ *val = le32_to_cpu(velem->value);
return 0;
}
@@ -190,11 +342,6 @@ static const struct sof_topology_token dai_link_tokens[] = {
offsetof(struct sof_ipc_dai_config, type), 0},
};
-static const struct sof_topology_token dai_ssp_link_tokens[] = {
- {SOF_TKN_DAI_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits), 0},
-};
-
/* scheduling */
static const struct sof_topology_token sched_tokens[] = {
{SOF_TKN_SCHED_DEADLINE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -265,6 +412,12 @@ static const struct sof_topology_token ssp_tokens[] = {
{SOF_TKN_INTEL_SSP_FS_KEEP_ACTIVE,
SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u32,
offsetof(struct sof_ipc_dai_ssp_params, fs_keep_active), 0},
+ {SOF_TKN_INTEL_SSP_MCLK_ID,
+ SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
+ offsetof(struct sof_ipc_dai_ssp_params, mclk_id), 0},
+ {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32,
+ offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits), 0},
};
/* DMIC */
@@ -348,7 +501,7 @@ static void sof_parse_uuid_tokens(struct snd_soc_component *scomp,
int i, j;
/* parse element by element */
- for (i = 0; i < array->num_elems; i++) {
+ for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
elem = &array->uuid[i];
/* search for token */
@@ -358,7 +511,7 @@ static void sof_parse_uuid_tokens(struct snd_soc_component *scomp,
continue;
/* match token id */
- if (tokens[j].token != elem->token)
+ if (tokens[j].token != le32_to_cpu(elem->token))
continue;
/* matched - now load token */
@@ -378,7 +531,7 @@ static void sof_parse_string_tokens(struct snd_soc_component *scomp,
int i, j;
/* parse element by element */
- for (i = 0; i < array->num_elems; i++) {
+ for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
elem = &array->string[i];
/* search for token */
@@ -388,7 +541,7 @@ static void sof_parse_string_tokens(struct snd_soc_component *scomp,
continue;
/* match token id */
- if (tokens[j].token != elem->token)
+ if (tokens[j].token != le32_to_cpu(elem->token))
continue;
/* matched - now load token */
@@ -412,7 +565,7 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
u32 *index = NULL;
/* parse element by element */
- for (i = 0; i < array->num_elems; i++) {
+ for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
elem = &array->value[i];
/* search for token */
@@ -423,7 +576,7 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
continue;
/* match token id */
- if (tokens[j].token != elem->token)
+ if (tokens[j].token != le32_to_cpu(elem->token))
continue;
/* pdm config array index */
@@ -436,7 +589,8 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
/* inc number of pdm array index */
if (index)
- ++(*index);
+ (*index)++;
+ /* fallthrough */
case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable:
case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable:
case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A:
@@ -478,7 +632,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
int asize;
while (priv_size > 0) {
- asize = array->size;
+ asize = le32_to_cpu(array->size);
/* validate asize */
if (asize < 0) { /* FIXME: A zero-size array makes no sense */
@@ -496,7 +650,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
}
/* call correct parser depending on type */
- switch (array->type) {
+ switch (le32_to_cpu(array->type)) {
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
sof_parse_uuid_tokens(scomp, object, tokens, count,
array);
@@ -555,7 +709,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index,
scontrol->sdev = sdev;
mutex_init(&scontrol->mutex);
- switch (hdr->ops.info) {
+ switch (le32_to_cpu(hdr->ops.info)) {
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_VOLSW_SX:
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
@@ -678,16 +832,16 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens,
ARRAY_SIZE(dai_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse dai tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
ret = sof_parse_tokens(scomp, &comp_dai.config, comp_tokens,
ARRAY_SIZE(comp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse dai.cfg tokens failed %d\n",
private->size);
@@ -733,7 +887,7 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &buffer, buffer_tokens,
ARRAY_SIZE(buffer_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse buffer tokens failed %d\n",
private->size);
@@ -774,7 +928,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &host, pcm_tokens,
ARRAY_SIZE(pcm_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse host tokens failed %d\n",
private->size);
@@ -783,10 +937,10 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &host.config, comp_tokens,
ARRAY_SIZE(comp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse host.cfg tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -835,7 +989,7 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp,
ret = sof_parse_tokens(scomp, &pipeline, sched_tokens,
ARRAY_SIZE(sched_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse pipeline tokens failed %d\n",
private->size);
@@ -875,7 +1029,7 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &mixer.config, comp_tokens,
ARRAY_SIZE(comp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse mixer.cfg tokens failed %d\n",
private->size);
@@ -900,14 +1054,41 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &tw->priv;
struct sof_ipc_comp_volume volume;
- int ret;
+ struct snd_soc_dapm_widget *widget = swidget->widget;
+ const struct snd_kcontrol_new *kc = NULL;
+ struct soc_mixer_control *sm;
+ struct snd_sof_control *scontrol;
+ const unsigned int *p;
+ int ret, tlv[TLV_ITEMS];
- if (tw->num_kcontrols != 1) {
+ if (le32_to_cpu(tw->num_kcontrols) != 1) {
dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n",
tw->num_kcontrols);
return -EINVAL;
}
+ /* set up volume gain tables for kcontrol */
+ kc = &widget->kcontrol_news[0];
+ sm = (struct soc_mixer_control *)kc->private_value;
+
+ /* get volume control */
+ scontrol = sm->dobj.private;
+
+ /* get topology tlv data */
+ p = kc->tlv.p;
+
+ /* extract tlv data */
+ if (get_tlv_data(p, tlv) < 0) {
+ dev_err(sdev->dev, "error: invalid TLV data\n");
+ return -EINVAL;
+ }
+
+ /* set up volume table */
+ if (set_up_volume_table(scontrol, tlv, sm->max + 1) < 0) {
+ dev_err(sdev->dev, "error: setting up volume table\n");
+ return -ENOMEM;
+ }
+
/* configure dai IPC message */
memset(&volume, 0, sizeof(volume));
volume.comp.hdr.size = sizeof(volume);
@@ -918,7 +1099,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &volume, volume_tokens,
ARRAY_SIZE(volume_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse volume tokens failed %d\n",
private->size);
@@ -926,10 +1107,10 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
}
ret = sof_parse_tokens(scomp, &volume.config, comp_tokens,
ARRAY_SIZE(comp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse volume.cfg tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -964,7 +1145,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &src, src_tokens,
ARRAY_SIZE(src_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse src tokens failed %d\n",
private->size);
@@ -973,10 +1154,10 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &src.config, comp_tokens,
ARRAY_SIZE(comp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse src.cfg tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -1013,19 +1194,19 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index,
ret = sof_parse_tokens(scomp, &tone, tone_tokens,
ARRAY_SIZE(tone_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse tone tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
ret = sof_parse_tokens(scomp, &tone.config, comp_tokens,
ARRAY_SIZE(comp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse tone.cfg tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -1076,7 +1257,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
memset(&reply, 0, sizeof(reply));
dev_dbg(sdev->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
- swidget->comp_id, index, tw->id, tw->name,
+ swidget->comp_id, index, swidget->id, tw->name,
tw->sname ? tw->sname : "none");
/* handle any special case widgets */
@@ -1139,7 +1320,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
case snd_soc_dapm_effect:
default:
dev_warn(sdev->dev, "warning: widget type %d name %s not handled\n",
- tw->id, tw->name);
+ swidget->id, tw->name);
break;
}
@@ -1147,7 +1328,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
if (ret < 0 || reply.rhdr.error < 0) {
dev_err(sdev->dev,
"error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n",
- tw->shift, tw->id, tw->name,
+ tw->shift, swidget->id, tw->name,
tw->sname ? tw->sname : "none", reply.rhdr.error);
return ret;
}
@@ -1302,39 +1483,29 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
memset(&config->ssp, 0, sizeof(struct sof_ipc_dai_ssp_params));
config->hdr.size = size;
- /* get any bespoke DAI tokens */
- ret = sof_parse_tokens(scomp, &config->ssp, dai_ssp_link_tokens,
- ARRAY_SIZE(dai_ssp_link_tokens),
- private->array, private->size);
- if (ret != 0) {
- dev_err(sdev->dev, "error: parse ssp link tokens failed %d\n",
- private->size);
- return ret;
- }
-
- ret = sof_parse_tokens(scomp, config, ssp_tokens,
+ ret = sof_parse_tokens(scomp, &config->ssp, ssp_tokens,
ARRAY_SIZE(ssp_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse ssp tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
- config->ssp.mclk_rate = hw_config->mclk_rate;
- config->ssp.bclk_rate = hw_config->bclk_rate;
- config->ssp.fsync_rate = hw_config->fsync_rate;
- config->ssp.tdm_slots = hw_config->tdm_slots;
- config->ssp.tdm_slot_width = hw_config->tdm_slot_width;
+ config->ssp.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
+ config->ssp.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
+ config->ssp.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
+ config->ssp.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ config->ssp.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
config->ssp.mclk_direction = hw_config->mclk_direction;
- config->ssp.rx_slots = hw_config->rx_slots;
- config->ssp.tx_slots = hw_config->tx_slots;
+ config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots);
+ config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots);
- dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d\n",
+ dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d\n",
config->id, config->format,
config->ssp.mclk_rate, config->ssp.bclk_rate,
config->ssp.fsync_rate, config->ssp.sample_valid_bits,
- config->ssp.tdm_slot_width, config->ssp.tdm_slots);
+ config->ssp.tdm_slot_width, config->ssp.tdm_slots, config->ssp.mclk_id);
/* send message to DSP */
ret = sof_ipc_tx_message(sdev->ipc,
@@ -1366,10 +1537,10 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
/* get DMIC tokens */
ret = sof_parse_tokens(scomp, &config->dmic, dmic_tokens,
ARRAY_SIZE(dmic_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse dmic tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -1398,10 +1569,10 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
/* get DMIC PDM tokens */
ret = sof_parse_tokens(scomp, &ipc_config->dmic.pdm[0], dmic_pdm_tokens,
ARRAY_SIZE(dmic_pdm_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
kfree(ipc_config);
return ret;
}
@@ -1474,10 +1645,10 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
/* get any bespoke DAI tokens */
ret = sof_parse_tokens(scomp, config, hda_tokens,
ARRAY_SIZE(hda_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse hda tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -1516,14 +1687,14 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
return 0;
/* only support 1 config atm */
- if (cfg->num_hw_configs != 1) {
+ if (le32_to_cpu(cfg->num_hw_configs) != 1) {
dev_err(sdev->dev, "error: unexpected DAI config count %d\n",
- cfg->num_hw_configs);
+ le32_to_cpu(cfg->num_hw_configs));
return -EINVAL;
}
/* check we have some tokens - we need at least DAI type */
- if (private->size == 0) {
+ if (le32_to_cpu(private->size) == 0) {
dev_err(sdev->dev, "error: expected tokens for DAI, none found\n");
return -EINVAL;
}
@@ -1533,10 +1704,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
/* get any common DAI tokens */
ret = sof_parse_tokens(scomp, &config, dai_link_tokens,
ARRAY_SIZE(dai_link_tokens), private->array,
- private->size);
+ le32_to_cpu(private->size));
if (ret != 0) {
dev_err(sdev->dev, "error: parse link tokens failed %d\n",
- private->size);
+ le32_to_cpu(private->size));
return ret;
}
@@ -1544,8 +1715,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
hw_config = &cfg->hw_config[0];
config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
- config.id = hw_config->id;
- config.format = hw_config->fmt;
+ config.id = le32_to_cpu(hw_config->id);
+ config.format = le32_to_cpu(hw_config->fmt);
/* now load DAI specific data and send IPC - type comes from token */
switch (config.type) {
@@ -1703,7 +1874,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
static int sof_route_unload(struct snd_soc_component *scomp,
struct snd_soc_dobj *dobj)
{
- /* TODO: unload routes when yopology is changed */
+ /* TODO: unload routes when topology is changed */
return 0;
}
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index 5991967d8099d6..a27edb9f4a7ea9 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -68,7 +68,7 @@ out:
static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
- struct snd_sof_dfsentry *dfse = file->private_data;
+ struct snd_sof_dfsentry_buf *dfse = file->private_data;
struct snd_sof_dev *sdev = dfse->sdev;
unsigned long rem;
loff_t lpos = *ppos;
@@ -118,7 +118,7 @@ static const struct file_operations sof_dfs_trace_fops = {
static int trace_debugfs_create(struct snd_sof_dev *sdev)
{
- struct snd_sof_dfsentry *dfse;
+ struct snd_sof_dfsentry_buf *dfse;
if (!sdev)
return -EINVAL;
@@ -131,7 +131,7 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev)
dfse->size = sdev->dmatb.bytes;
dfse->sdev = sdev;
- dfse->dfsentry = debugfs_create_file("trace", 0644, sdev->debugfs_root,
+ dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root,
dfse, &sof_dfs_trace_fops);
if (!dfse->dfsentry) {
dev_err(sdev->dev,
diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c
new file mode 100644
index 00000000000000..9636ed48d1644c
--- /dev/null
+++ b/sound/soc/sof/utils.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved.
+ *
+ * Author: Keyon Jie <yang.jie@linux.intel.com>
+ */
+
+#include <linux/device.h>
+#include <sound/soc.h>
+#include <sound/sof.h>
+#include "sof-priv.h"
+
+int sof_bes_setup(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops,
+ struct snd_soc_dai_link *links, int link_num,
+ struct snd_soc_card *card)
+{
+ char name[32];
+ int i;
+
+ if (!ops || !links || !card) {
+ dev_err(sdev->dev, "error: no link, card or ops for BEs\n");
+ return -EINVAL;
+ }
+
+ /* set up BE dai_links */
+ for (i = 0; i < link_num; i++) {
+ snprintf(name, 32, "NoCodec-%d", i);
+ links[i].name = kmemdup(name, sizeof(name), GFP_KERNEL);
+ if (!links[i].name)
+ goto no_mem;
+
+ links[i].id = i;
+ links[i].no_pcm = 1;
+ links[i].cpu_dai_name = ops->dai_drv->drv[i].name;
+ links[i].platform_name = "sof-audio";
+ links[i].codec_dai_name = "snd-soc-dummy-dai";
+ links[i].codec_name = "snd-soc-dummy";
+ links[i].dpcm_playback = 1;
+ links[i].dpcm_capture = 1;
+ }
+
+ card->dai_link = links;
+ card->num_links = link_num;
+
+ return 0;
+no_mem:
+ /* free allocated memories and return error */
+ for (; i > 0; i--)
+ kfree(links[i - 1].name);
+
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(sof_bes_setup);
+