summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/sof.h7
-rw-r--r--include/sound/sof/dai-imx.h55
-rw-r--r--include/sound/sof/dai.h3
-rw-r--r--include/uapi/sound/sof/abi.h2
-rw-r--r--include/uapi/sound/sof/tokens.h6
-rw-r--r--sound/soc/fsl/Kconfig8
-rw-r--r--sound/soc/fsl/Makefile2
-rw-r--r--sound/soc/fsl/fsl_dai.c276
-rw-r--r--sound/soc/soc-core.c2
-rw-r--r--sound/soc/sof/core.c132
-rw-r--r--sound/soc/sof/intel/apl.c5
-rw-r--r--sound/soc/sof/intel/bdw.c5
-rw-r--r--sound/soc/sof/intel/byt.c15
-rw-r--r--sound/soc/sof/intel/cnl.c5
-rw-r--r--sound/soc/sof/nocodec.c12
-rw-r--r--sound/soc/sof/ops.h26
-rw-r--r--sound/soc/sof/pcm.c29
-rw-r--r--sound/soc/sof/sof-acpi-dev.c11
-rw-r--r--sound/soc/sof/sof-of-dev.c20
-rw-r--r--sound/soc/sof/sof-pci-dev.c22
-rw-r--r--sound/soc/sof/sof-priv.h15
-rw-r--r--sound/soc/sof/topology.c152
-rw-r--r--sound/soc/sof/trace.c4
-rw-r--r--sound/soc/sof/utils.c60
24 files changed, 728 insertions, 146 deletions
diff --git a/include/sound/sof.h b/include/sound/sof.h
index 4640566b54fe..81889a859379 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -22,7 +22,6 @@ struct snd_sof_dsp_ops;
*/
struct snd_sof_pdata {
const struct firmware *fw;
- const char *drv_name;
const char *name;
const char *platform;
@@ -88,13 +87,13 @@ struct sof_dev_desc {
const char *default_fw_path;
const char *default_tplg_path;
+ /* default firmware name */
+ const char *default_fw_filename;
+
const struct snd_sof_dsp_ops *ops;
const struct sof_arch_ops *arch_ops;
};
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,
const struct snd_sof_dsp_ops *ops);
#endif
diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h
new file mode 100644
index 000000000000..8b286054b223
--- /dev/null
+++ b/include/sound/sof/dai-imx.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Copyright 2019 NXP
+ *
+ * Author: Daniel Baluta <daniel.baluta@nxp.com>
+ */
+
+#ifndef __INCLUDE_SOUND_SOF_DAI_IMX_H__
+#define __INCLUDE_SOUND_SOF_DAI_IMX_H__
+
+#include <sound/sof/header.h>
+
+/* ESAI Configuration Request - SOF_IPC_DAI_ESAI_CONFIG */
+struct sof_ipc_dai_esai_params {
+ struct sof_ipc_hdr hdr;
+
+ /* MCLK */
+ uint16_t reserved1;
+ uint16_t mclk_id;
+ uint32_t mclk_direction;
+
+ uint32_t mclk_rate; /* MCLK frequency in Hz */
+ uint32_t fsync_rate; /* FSYNC frequency in Hz */
+ uint32_t bclk_rate; /* BCLK frequency in Hz */
+
+ /* TDM */
+ uint32_t tdm_slots;
+ uint32_t rx_slots;
+ uint32_t tx_slots;
+ uint16_t tdm_slot_width;
+ uint16_t reserved2; /* alignment */
+} __packed;
+
+/* SAI Configuration Request - SOF_IPC_DAI_SAI_CONFIG */
+struct sof_ipc_dai_sai_params {
+ struct sof_ipc_hdr hdr;
+
+ /* MCLK */
+ uint16_t reserved1;
+ uint16_t mclk_id;
+ uint32_t mclk_direction;
+
+ uint32_t mclk_rate; /* MCLK frequency in Hz */
+ uint32_t fsync_rate; /* FSYNC frequency in Hz */
+ uint32_t bclk_rate; /* BCLK frequency in Hz */
+
+ /* TDM */
+ uint32_t tdm_slots;
+ uint32_t rx_slots;
+ uint32_t tx_slots;
+ uint16_t tdm_slot_width;
+ uint16_t reserved2; /* alignment */
+} __packed;
+#endif
+
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index 0f1235022146..2565edd336f1 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -11,6 +11,7 @@
#include <sound/sof/header.h>
#include <sound/sof/dai-intel.h>
+#include <sound/sof/dai-imx.h>
/*
* DAI Configuration.
@@ -73,6 +74,8 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_dmic_params dmic;
struct sof_ipc_dai_hda_params hda;
struct sof_ipc_dai_alh_params alh;
+ struct sof_ipc_dai_esai_params esai;
+ struct sof_ipc_dai_sai_params sai;
};
} __packed;
diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h
index a0fe0d4c4b66..ebfdc20ca081 100644
--- a/include/uapi/sound/sof/abi.h
+++ b/include/uapi/sound/sof/abi.h
@@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
-#define SOF_ABI_MINOR 10
+#define SOF_ABI_MINOR 11
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index 8f996857fb24..c66cfc0b451e 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -107,11 +107,9 @@
#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE
/* SAI */
-#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000
-/* TODO: Add SAI tokens */
+#define SOF_TKN_IMX_SAI_MCLK_ID 1000
/* ESAI */
-#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100
-/* TODO: Add ESAI tokens */
+#define SOF_TKN_IMX_ESAI_MCLK_ID 1100
#endif
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 0a887b373b6f..e3f94e95e746 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -65,6 +65,14 @@ config SND_SOC_FSL_ESAI
This option is only useful for out-of-tree drivers since
in-tree drivers select it automatically.
+config SND_SOC_FSL_DAI
+ tristate "Generic FSL DAI support for Sound Open Firmware"
+ help
+ Say Y if you want to enable generic FSL DAI support to be used
+ with Sound Open Firmware. This module takes care of enabling
+ clocks, power domain, pinctrl for FSL DAIs. The rest of DAI
+ control is taken care of by SOF firmware.
+
config SND_SOC_FSL_MICFIL
tristate "Pulse Density Modulation Microphone Interface (MICFIL) module support"
select REGMAP_MMIO
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8b40b170062b..630a39ae8eb0 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -22,6 +22,7 @@ snd-soc-fsl-ssi-y := fsl_ssi.o
snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
snd-soc-fsl-spdif-objs := fsl_spdif.o
snd-soc-fsl-esai-objs := fsl_esai.o
+snd-soc-fsl-dai-objs := fsl_dai.o
snd-soc-fsl-micfil-objs := fsl_micfil.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
+obj-$(CONFIG_SND_SOC_FSL_DAI) += snd-soc-fsl-dai.o
obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_FSL_HDMI) += snd-soc-fsl-hdmi.o
diff --git a/sound/soc/fsl/fsl_dai.c b/sound/soc/fsl/fsl_dai.c
new file mode 100644
index 000000000000..f70889939801
--- /dev/null
+++ b/sound/soc/fsl/fsl_dai.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale Generic DAI driver for DSP
+//
+// Copyright 2019 NXP
+// Author: Daniel Baluta <daniel.baluta@nxp.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+enum fsl_dai_type {
+ FSL_DAI_TYPE_NONE,
+ FSL_DAI_TYPE_SAI,
+ FSL_DAI_TYPE_ESAI,
+};
+
+#define FSL_DAI_ESAI_CLK_NUM 4
+static const char *esai_clks[FSL_DAI_ESAI_CLK_NUM] = {
+ "core",
+ "extal",
+ "fsys",
+ "spba",
+};
+
+#define FSL_DAI_SAI_CLK_NUM 5
+static const char *sai_clks[FSL_DAI_SAI_CLK_NUM] = {
+ "bus",
+ "mclk0",
+ "mclk1",
+ "mclk2",
+ "mclk3",
+};
+
+struct fsl_dai {
+ struct platform_device *pdev;
+
+ /* DAI clocks */
+ struct clk **clks;
+ const char **clk_names;
+ int num_clks;
+
+ /* Power Domain handling */
+ int num_domains;
+ struct device **pd_dev;
+ struct device_link **link;
+
+ /* DAIS */
+ struct snd_soc_dai_driver *dai_drv;
+ int num_drv;
+};
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+ .name = "esai0",
+};
+
+static struct snd_soc_dai_driver fsl_sai_dai = {
+ .name = "sai1",
+};
+
+static const struct snd_soc_component_driver fsl_dai_component = {
+ .name = "fsl-dai",
+};
+
+static int fsl_dai_init_clocks(struct fsl_dai *dai_priv)
+{
+ struct device *dev = &dai_priv->pdev->dev;
+ int i;
+
+ dai_priv->clks = devm_kcalloc(dev, dai_priv->num_clks,
+ sizeof(*dai_priv->clks), GFP_KERNEL);
+ if (!dai_priv->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < dai_priv->num_clks; i++) {
+ dai_priv->clks[i] = devm_clk_get(dev, dai_priv->clk_names[i]);
+ if (IS_ERR(dai_priv->clks[i])) {
+ dev_dbg(dev, "Failed to get clk %s\n",
+ dai_priv->clk_names[i]);
+ dai_priv->clks[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int fsl_get_dai_type(struct fsl_dai *dai_priv)
+{
+ struct device_node *np = dai_priv->pdev->dev.of_node;
+
+ if (of_device_is_compatible(np, "fsl,esai-dai"))
+ return FSL_DAI_TYPE_ESAI;
+
+ if (of_device_is_compatible(np, "fsl,sai-dai"))
+ return FSL_DAI_TYPE_SAI;
+
+ return FSL_DAI_TYPE_NONE;
+}
+
+static int fsl_dai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_dai *priv;
+ int dai_type;
+ int ret;
+ int i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ dai_type = fsl_get_dai_type(priv);
+ switch (dai_type) {
+ case FSL_DAI_TYPE_ESAI:
+ priv->clk_names = esai_clks;
+ priv->num_clks = FSL_DAI_ESAI_CLK_NUM;
+ priv->dai_drv = &fsl_esai_dai;
+ priv->num_drv = 1;
+ break;
+ case FSL_DAI_TYPE_SAI:
+ priv->clk_names = sai_clks;
+ priv->num_clks = FSL_DAI_SAI_CLK_NUM;
+ priv->dai_drv = &fsl_sai_dai;
+ priv->num_drv = 1;
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid DAI type %d\n", dai_type);
+ return -EINVAL;
+ }
+
+ ret = fsl_dai_init_clocks(priv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error at init clocks\n");
+ return ret;
+ }
+
+ priv->num_domains = of_count_phandle_with_args(np, "power-domains",
+ "#power-domain-cells");
+ if (priv->num_domains < 0) {
+ dev_err(&pdev->dev, "no power-domains property in %pOF\n", np);
+ return priv->num_domains;
+ }
+
+ priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains,
+ sizeof(*priv->pd_dev), GFP_KERNEL);
+ if (!priv->pd_dev)
+ return -ENOMEM;
+
+ priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains,
+ sizeof(*priv->link), GFP_KERNEL);
+ if (!priv->link)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->num_domains; i++) {
+ priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(priv->pd_dev[i])) {
+ ret = PTR_ERR(priv->pd_dev[i]);
+ goto unroll_pm;
+ }
+
+ priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i],
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!priv->link[i]) {
+ ret = -EINVAL;
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ goto unroll_pm;
+ }
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_dai_component,
+ priv->dai_drv, priv->num_drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register DAI ret = %d\n", ret);
+ return ret;
+ }
+ return 0;
+
+unroll_pm:
+ while (--i >= 0) {
+ device_link_del(priv->link[i]);
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ }
+ return ret;
+}
+
+static int fsl_dai_remove(struct platform_device *pdev)
+{
+ struct fsl_dai *priv = platform_get_drvdata(pdev);
+ int i;
+
+ pm_runtime_disable(&priv->pdev->dev);
+
+ for (i = 0; i < priv->num_domains; i++) {
+ device_link_del(priv->link[i]);
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id fsl_dai_dt_ids[] = {
+ { .compatible = "fsl,esai-dai", },
+ { .compatible = "fsl,sai-dai", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_dai_dt_ids);
+
+#ifdef CONFIG_PM
+static int fsl_dai_runtime_resume(struct device *dev)
+{
+ struct fsl_dai *priv = dev_get_drvdata(dev);
+ int i, ret;
+
+ for (i = 0; i < priv->num_clks; i++) {
+ ret = clk_prepare_enable(priv->clks[i]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable clk %s\n",
+ priv->clk_names[i]);
+ goto out;
+ }
+ }
+ return 0;
+out:
+ while (--i >= 0)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return ret;
+}
+
+static int fsl_dai_runtime_suspend(struct device *dev)
+{
+ struct fsl_dai *priv = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < priv->num_clks; i++)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops fsl_dai_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_dai_runtime_suspend,
+ fsl_dai_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_dai_driver = {
+ .probe = fsl_dai_probe,
+ .remove = fsl_dai_remove,
+ .driver = {
+ .name = "fsl-dai",
+ .pm = &fsl_dai_pm_ops,
+ .of_match_table = fsl_dai_dt_ids,
+ },
+};
+
+module_platform_driver(fsl_dai_driver);
+
+MODULE_ALIAS("platform:fsl-dai");
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
+MODULE_DESCRIPTION("FSL Generic DAI driver for DSP");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 88978a3036c4..9d3b546bae7b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1886,6 +1886,8 @@ match:
/* convert non BE into BE */
dai_link->no_pcm = 1;
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
/* override any BE fixups */
dai_link->be_hw_params_fixup =
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 81f28f7ff1a0..6a32eb8c0795 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -10,7 +10,6 @@
#include <linux/firmware.h>
#include <linux/module.h>
-#include <asm/unaligned.h>
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
@@ -196,67 +195,9 @@ out:
EXPORT_SYMBOL(snd_sof_get_status);
/*
- * Generic buffer page table creation.
- * Take the each physical page address and drop the least significant unused
- * bits from each (based on PAGE_SIZE). Then pack valid page address bits
- * into compressed page table.
- */
-
-int snd_sof_create_page_table(struct snd_sof_dev *sdev,
- struct snd_dma_buffer *dmab,
- unsigned char *page_table, size_t size)
-{
- int i, pages;
-
- pages = snd_sgbuf_aligned_pages(size);
-
- dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n",
- dmab->area, size, pages);
-
- for (i = 0; i < pages; i++) {
- /*
- * The number of valid address bits for each page is 20.
- * idx determines the byte position within page_table
- * where the current page's address is stored
- * in the compressed page_table.
- * This can be calculated by multiplying the page number by 2.5.
- */
- u32 idx = (5 * i) >> 1;
- u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
- u8 *pg_table;
-
- dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
-
- pg_table = (u8 *)(page_table + idx);
-
- /*
- * pagetable compression:
- * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
- * ___________pfn 0__________ __________pfn 1___________ _pfn 2...
- * .... .... .... .... .... .... .... .... .... .... ....
- * It is created by:
- * 1. set current location to 0, PFN index i to 0
- * 2. put pfn[i] at current location in Little Endian byte order
- * 3. calculate an intermediate value as
- * x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
- * 4. put x at offset (current location + 2) in LE byte order
- * 5. increment current location by 5 bytes, increment i by 2
- * 6. continue to (2)
- */
- if (i & 1)
- put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4,
- pg_table);
- else
- put_unaligned_le32(pfn, pg_table);
- }
-
- return pages;
-}
-
-/*
* SOF Driver enumeration.
*/
-static int sof_machine_check(struct snd_sof_dev *sdev)
+int sof_machine_check(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *plat_data = sdev->pdata;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
@@ -277,8 +218,10 @@ static int sof_machine_check(struct snd_sof_dev *sdev)
if (!machine)
return -ENOMEM;
- ret = sof_nocodec_setup(sdev->dev, plat_data, machine,
- plat_data->desc, plat_data->desc->ops);
+ machine->drv_name = "sof-nocodec";
+ plat_data->fw_filename = plat_data->desc->nocodec_fw_filename;
+ plat_data->tplg_filename = plat_data->desc->nocodec_tplg_filename;
+ ret = sof_nocodec_setup(sdev->dev, plat_data->desc->ops);
if (ret < 0)
return ret;
@@ -287,13 +230,45 @@ static int sof_machine_check(struct snd_sof_dev *sdev)
return 0;
#endif
}
+EXPORT_SYMBOL(sof_machine_check);
-static int sof_probe_continue(struct snd_sof_dev *sdev)
+int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata;
const char *drv_name;
const void *mach;
int size;
+
+ drv_name = plat_data->machine->drv_name;
+ mach = (const void *)plat_data->machine;
+ size = sizeof(*plat_data->machine);
+
+ /* register machine driver, pass machine info as pdata */
+ plat_data->pdev_mach =
+ platform_device_register_data(sdev->dev, drv_name,
+ PLATFORM_DEVID_NONE, mach, size);
+ if (IS_ERR(plat_data->pdev_mach))
+ return PTR_ERR(plat_data->pdev_mach);
+
+ dev_dbg(sdev->dev, "created machine %s\n",
+ dev_name(&plat_data->pdev_mach->dev));
+
+ return 0;
+}
+EXPORT_SYMBOL(sof_machine_register);
+
+void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata;
+
+ if (!IS_ERR_OR_NULL(plat_data->pdev_mach))
+ platform_device_unregister(plat_data->pdev_mach);
+}
+EXPORT_SYMBOL(sof_machine_unregister);
+
+static int sof_probe_continue(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
int ret;
/* probe the DSP hardware */
@@ -304,7 +279,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
}
/* check machine info */
- ret = sof_machine_check(sdev);
+ ret = snd_sof_machine_check(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to get machine info %d\n",
ret);
@@ -371,22 +346,17 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
goto fw_run_err;
}
- drv_name = plat_data->machine->drv_name;
- mach = (const void *)plat_data->machine;
- size = sizeof(*plat_data->machine);
-
- /* register machine driver, pass machine info as pdata */
- plat_data->pdev_mach =
- platform_device_register_data(sdev->dev, drv_name,
- PLATFORM_DEVID_NONE, mach, size);
-
- if (IS_ERR(plat_data->pdev_mach)) {
- ret = PTR_ERR(plat_data->pdev_mach);
+ ret = snd_sof_machine_register(sdev, plat_data);
+ if (ret < 0)
goto fw_run_err;
- }
- dev_dbg(sdev->dev, "created machine %s\n",
- dev_name(&plat_data->pdev_mach->dev));
+ /*
+ * Some platforms in SOF, ex: BYT, may not have their platform PM
+ * callbacks set. Increment the usage count so as to
+ * prevent the device from entering runtime suspend.
+ */
+ if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
+ pm_runtime_get_noresume(sdev->dev);
if (plat_data->sof_probe_complete)
plat_data->sof_probe_complete(sdev->dev);
@@ -504,9 +474,7 @@ int snd_sof_device_remove(struct device *dev)
* will remove the component driver and unload the topology
* before freeing the snd_card.
*/
- if (!IS_ERR_OR_NULL(pdata->pdev_mach))
- platform_device_unregister(pdata->pdev_mach);
-
+ snd_sof_machine_unregister(sdev, pdata);
/*
* Unregistering the machine driver results in unloading the topology.
* Some widgets, ex: scheduler, attempt to power down the core they are
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 8dc7a5558da4..1f46bfba0f1b 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -53,6 +53,11 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
+ /* machine driver */
+ .machine_check = sof_machine_check,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+
/* debug */
.debug_map = apl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs),
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index 663f45cbb03e..116174df4eec 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -557,6 +557,11 @@ const struct snd_sof_dsp_ops sof_bdw_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_check = sof_machine_check,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+
/* debug */
.debug_map = bdw_debugfs,
.debug_map_count = ARRAY_SIZE(bdw_debugfs),
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 89df246a0857..b55aecd6fe3f 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -493,6 +493,11 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_check = sof_machine_check,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+
/* debug */
.debug_map = byt_debugfs,
.debug_map_count = ARRAY_SIZE(byt_debugfs),
@@ -657,6 +662,11 @@ const struct snd_sof_dsp_ops sof_byt_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_check = sof_machine_check,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+
/* debug */
.debug_map = byt_debugfs,
.debug_map_count = ARRAY_SIZE(byt_debugfs),
@@ -716,6 +726,11 @@ const struct snd_sof_dsp_ops sof_cht_ops = {
.ipc_msg_data = intel_ipc_msg_data,
.ipc_pcm_params = intel_ipc_pcm_params,
+ /* machine driver */
+ .machine_check = sof_machine_check,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+
/* debug */
.debug_map = cht_debugfs,
.debug_map_count = ARRAY_SIZE(cht_debugfs),
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 4ddd73762d81..eba1bf4624a2 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -211,6 +211,11 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
+ /* machine driver */
+ .machine_check = sof_machine_check,
+ .machine_register = sof_machine_register,
+ .machine_unregister = sof_machine_unregister,
+
/* debug */
.debug_map = cnl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs),
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 3d128e5a132c..2233146386cc 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -63,23 +63,11 @@ static int sof_nocodec_bes_setup(struct device *dev,
}
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,
const struct snd_sof_dsp_ops *ops)
{
struct snd_soc_dai_link *links;
int ret;
- if (!mach)
- return -EINVAL;
-
- sof_pdata->drv_name = "sof-nocodec";
-
- mach->drv_name = "sof-nocodec";
- sof_pdata->fw_filename = desc->nocodec_fw_filename;
- sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
-
/* create dummy BE dai_links */
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
ops->num_drv, GFP_KERNEL);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index 824d36fe59fd..97f4feb73368 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -381,6 +381,32 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev,
return 0;
}
+/* machine driver */
+static inline int
+snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
+{
+ if (sof_ops(sdev) && sof_ops(sdev)->machine_register)
+ return sof_ops(sdev)->machine_register(sdev, pdata);
+
+ return 0;
+}
+
+static inline void
+snd_sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
+{
+ if (sof_ops(sdev) && sof_ops(sdev)->machine_unregister)
+ sof_ops(sdev)->machine_unregister(sdev, pdata);
+}
+
+static inline int
+snd_sof_machine_check(struct snd_sof_dev *sdev)
+{
+ if (sof_ops(sdev) && sof_ops(sdev)->machine_check)
+ return sof_ops(sdev)->machine_check(sdev);
+
+ return 0;
+}
+
static inline const struct snd_sof_dsp_ops
*sof_get_ops(const struct sof_dev_desc *d,
const struct sof_ops_table mach_ops[], int asize)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 2b876d497447..7fc5306b955d 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -34,7 +34,7 @@ static int create_page_table(struct snd_pcm_substream *substream,
if (!spcm)
return -EINVAL;
- return snd_sof_create_page_table(sdev, dmab,
+ return snd_sof_create_page_table(sdev->dev, dmab,
spcm->stream[stream].page_table.area, size);
}
@@ -691,6 +691,19 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
case SOF_DAI_INTEL_ALH:
/* do nothing for ALH dai_link */
break;
+ case SOF_DAI_IMX_ESAI:
+ channels->min = dai->dai_config->esai.tdm_slots;
+ channels->max = dai->dai_config->esai.tdm_slots;
+
+ break;
+ case SOF_DAI_IMX_SAI:
+ channels->min = dai->dai_config->sai.tdm_slots;
+ channels->max = dai->dai_config->sai.tdm_slots;
+
+ dev_dbg(sdev->dev,
+ "channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
default:
dev_err(sdev->dev, "error: invalid DAI type %d\n",
dai->dai_config->type);
@@ -724,14 +737,6 @@ static int sof_pcm_probe(struct snd_soc_component *component)
return ret;
}
- /*
- * Some platforms in SOF, ex: BYT, may not have their platform PM
- * callbacks set. Increment the usage count so as to
- * prevent the device from entering runtime suspend.
- */
- if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
- pm_runtime_get_noresume(sdev->dev);
-
return ret;
}
@@ -747,7 +752,11 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
struct snd_sof_pdata *plat_data = sdev->pdata;
const char *drv_name;
- drv_name = plat_data->machine->drv_name;
+
+ if (plat_data->machine)
+ drv_name = plat_data->machine->drv_name;
+ else
+ drv_name = "asoc-simple-card";
pd->name = "sof-audio-component";
pd->probe = sof_pcm_probe;
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index ea7b8b895412..9b77916d8aaf 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -39,6 +39,7 @@ static const struct sof_dev_desc sof_acpi_haswell_desc = {
.chip_info = &hsw_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-hsw.ri",
.nocodec_fw_filename = "sof-hsw.ri",
.nocodec_tplg_filename = "sof-hsw-nocodec.tplg",
.ops = &sof_hsw_ops,
@@ -56,6 +57,7 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = {
.chip_info = &bdw_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-bdw.ri",
.nocodec_fw_filename = "sof-bdw.ri",
.nocodec_tplg_filename = "sof-bdw-nocodec.tplg",
.ops = &sof_bdw_ops,
@@ -75,6 +77,7 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = {
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-byt.ri",
.nocodec_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
@@ -90,6 +93,7 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = {
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-byt.ri",
.nocodec_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
@@ -105,6 +109,7 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
.chip_info = &cht_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-cht.ri",
.nocodec_fw_filename = "sof-cht.ri",
.nocodec_tplg_filename = "sof-cht-nocodec.tplg",
.ops = &sof_cht_ops,
@@ -164,7 +169,11 @@ static int sof_acpi_probe(struct platform_device *pdev)
mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
if (!mach)
return -ENOMEM;
- ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
+
+ mach->drv_name = "sof-nocodec";
+ sof_pdata->fw_filename = desc->nocodec_fw_filename;
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+ ret = sof_nocodec_setup(dev, ops);
if (ret < 0)
return ret;
#else
diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c
index 28a9692974e5..ef5737f6918d 100644
--- a/sound/soc/sof/sof-of-dev.c
+++ b/sound/soc/sof/sof-of-dev.c
@@ -19,6 +19,7 @@ extern struct snd_sof_dsp_ops sof_imx8_ops;
static struct sof_dev_desc sof_of_imx8qxp_desc = {
.default_fw_path = "imx/sof",
.default_tplg_path = "imx/sof-tplg",
+ .default_fw_filename = "sof-imx8.ri",
.nocodec_fw_filename = "sof-imx8.ri",
.nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8_ops,
@@ -72,18 +73,17 @@ static int sof_of_probe(struct platform_device *pdev)
mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
if (!mach)
return -ENOMEM;
- ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
+
+ mach->drv_name = "sof-nocodec";
+ sof_pdata->fw_filename = desc->nocodec_fw_filename;
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+ ret = sof_nocodec_setup(dev, ops);
if (ret < 0)
return ret;
-#else
- /* TODO: implement case where we actually have a codec */
- return -ENODEV;
#endif
- if (mach)
- mach->mach_params.platform = dev_name(dev);
-
- sof_pdata->machine = mach;
+ /* TODO: replace machine with info from DT */
+ sof_pdata->machine = NULL;
sof_pdata->desc = desc;
sof_pdata->dev = &pdev->dev;
sof_pdata->platform = dev_name(dev);
@@ -92,6 +92,10 @@ static int sof_of_probe(struct platform_device *pdev)
sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path;
sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path;
+ sof_pdata->fw_filename = desc->default_fw_filename;
+ /* FIXME: Add proper value for tplg_filename */
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
/* set callback to enable runtime_pm */
sof_pdata->sof_probe_complete = sof_of_probe_complete;
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index d66412a77873..a42f43b40042 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -40,6 +40,7 @@ static const struct sof_dev_desc bxt_desc = {
.chip_info = &apl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-apl.ri",
.nocodec_fw_filename = "sof-apl.ri",
.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
.ops = &sof_apl_ops,
@@ -58,6 +59,7 @@ static const struct sof_dev_desc glk_desc = {
.chip_info = &apl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-glk.ri",
.nocodec_fw_filename = "sof-glk.ri",
.nocodec_tplg_filename = "sof-glk-nocodec.tplg",
.ops = &sof_apl_ops,
@@ -86,6 +88,7 @@ static const struct sof_dev_desc tng_desc = {
.chip_info = &tng_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-byt.ri",
.nocodec_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt.tplg",
.ops = &sof_tng_ops,
@@ -104,6 +107,7 @@ static const struct sof_dev_desc cnl_desc = {
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-cnl.ri",
.nocodec_fw_filename = "sof-cnl.ri",
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -113,7 +117,7 @@ static const struct sof_dev_desc cnl_desc = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
static const struct sof_dev_desc cfl_desc = {
- .machines = snd_soc_acpi_intel_cnl_machines,
+ .machines = snd_soc_acpi_intel_cfl_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
@@ -122,7 +126,8 @@ static const struct sof_dev_desc cfl_desc = {
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-cnl.ri",
+ .default_fw_filename = "sof-cfl.ri",
+ .nocodec_fw_filename = "sof-cfl.ri",
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
.arch_ops = &sof_xtensa_arch_ops
@@ -133,7 +138,7 @@ static const struct sof_dev_desc cfl_desc = {
IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
static const struct sof_dev_desc cml_desc = {
- .machines = snd_soc_acpi_intel_cnl_machines,
+ .machines = snd_soc_acpi_intel_cml_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
@@ -142,7 +147,8 @@ static const struct sof_dev_desc cml_desc = {
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
- .nocodec_fw_filename = "sof-cnl.ri",
+ .default_fw_filename = "sof-cml.ri",
+ .nocodec_fw_filename = "sof-cml.ri",
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
.arch_ops = &sof_xtensa_arch_ops
@@ -160,6 +166,7 @@ static const struct sof_dev_desc icl_desc = {
.chip_info = &icl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-icl.ri",
.nocodec_fw_filename = "sof-icl.ri",
.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -214,6 +221,7 @@ static const struct sof_dev_desc tgl_desc = {
.chip_info = &tgl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-tgl.ri",
.nocodec_fw_filename = "sof-tgl.ri",
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -232,6 +240,7 @@ static const struct sof_dev_desc ehl_desc = {
.chip_info = &ehl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
+ .default_fw_filename = "sof-ehl.ri",
.nocodec_fw_filename = "sof-ehl.ri",
.nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -306,7 +315,10 @@ static int sof_pci_probe(struct pci_dev *pci,
ret = -ENOMEM;
goto release_regions;
}
- ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
+ mach->drv_name = "sof-nocodec";
+ sof_pdata->fw_filename = desc->nocodec_fw_filename;
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+ ret = sof_nocodec_setup(dev, ops);
if (ret < 0)
goto release_regions;
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 730f3259dd02..8ee185bbf6f0 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -202,6 +202,13 @@ struct snd_sof_dsp_ops {
int (*get_window_offset)(struct snd_sof_dev *sdev,
u32 id);/* mandatory for common loader code */
+ /* machine driver ops */
+ int (*machine_register)(struct snd_sof_dev *sdev,
+ void *pdata); /* optional */
+ void (*machine_unregister)(struct snd_sof_dev *sdev,
+ void *pdata); /* optional */
+ int (*machine_check)(struct snd_sof_dev *sdev); /* optional */
+
/* DAI ops */
struct snd_soc_dai_driver *drv;
int num_drv;
@@ -458,10 +465,14 @@ int snd_sof_suspend(struct device *dev);
void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
-int snd_sof_create_page_table(struct snd_sof_dev *sdev,
+int snd_sof_create_page_table(struct device *dev,
struct snd_dma_buffer *dmab,
unsigned char *page_table, size_t size);
+int sof_machine_register(struct snd_sof_dev *sdev, void *pdata);
+void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata);
+int sof_machine_check(struct snd_sof_dev *sdev);
+
/*
* Firmware loading.
*/
@@ -542,8 +553,6 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
* There is no snd_sof_free_topology since topology components will
* be freed by snd_soc_unregister_component,
*/
-int snd_sof_init_topology(struct snd_sof_dev *sdev,
- struct snd_soc_tplg_ops *ops);
int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file);
int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget);
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 4452594c2e17..d424413dc531 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -799,6 +799,21 @@ static const struct sof_topology_token dmic_tokens[] = {
};
+/* ESAI */
+static const struct sof_topology_token esai_tokens[] = {
+ {SOF_TKN_IMX_ESAI_MCLK_ID,
+ SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
+ offsetof(struct sof_ipc_dai_esai_params, mclk_id), 0},
+};
+
+/* SAI */
+static const struct sof_topology_token sai_tokens[] = {
+ {SOF_TKN_IMX_SAI_MCLK_ID,
+ SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
+ offsetof(struct sof_ipc_dai_sai_params, mclk_id), 0},
+};
+
+
/*
* DMIC PDM Tokens
* SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
@@ -2526,8 +2541,66 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_hw_config *hw_config,
struct sof_ipc_dai_config *config)
{
- /*TODO: Add implementation */
- return 0;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_soc_tplg_private *private = &cfg->priv;
+ struct sof_ipc_reply reply;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ /* init IPC */
+ memset(&config->sai, 0, sizeof(struct sof_ipc_dai_sai_params));
+ config->hdr.size = size;
+
+ ret = sof_parse_tokens(scomp, &config->sai, sai_tokens,
+ ARRAY_SIZE(sai_tokens), private->array,
+ le32_to_cpu(private->size));
+ if (ret != 0) {
+ dev_err(sdev->dev, "error: parse sai tokens failed %d\n",
+ le32_to_cpu(private->size));
+ return ret;
+ }
+
+ config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
+ config->sai.mclk_direction = hw_config->mclk_direction;
+
+ config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
+ config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
+ config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
+
+ dev_info(sdev->dev,
+ "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
+ config->dai_index, config->format,
+ config->sai.mclk_rate, config->sai.tdm_slot_width,
+ config->sai.tdm_slots, config->sai.mclk_id);
+
+ if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
+ dev_err(sdev->dev, "error: invalid channel count for SAI%d\n",
+ config->dai_index);
+ return -EINVAL;
+ }
+
+ /* send message to DSP */
+ ret = sof_ipc_tx_message(sdev->ipc,
+ config->hdr.cmd, config, size, &reply,
+ sizeof(reply));
+
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: failed to set DAI config for SAI%d\n",
+ config->dai_index);
+ return ret;
+ }
+
+ /* set config for all DAI's with name matching the link name */
+ ret = sof_set_dai_config(sdev, size, link, config);
+ if (ret < 0)
+ dev_err(sdev->dev, "error: failed to save DAI config for SAI%d\n",
+ config->dai_index);
+
+ return ret;
}
static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
@@ -2536,8 +2609,66 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_hw_config *hw_config,
struct sof_ipc_dai_config *config)
{
- /*TODO: Add implementation */
- return 0;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_soc_tplg_private *private = &cfg->priv;
+ struct sof_ipc_reply reply;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ /* init IPC */
+ memset(&config->esai, 0, sizeof(struct sof_ipc_dai_esai_params));
+ config->hdr.size = size;
+
+ ret = sof_parse_tokens(scomp, &config->esai, esai_tokens,
+ ARRAY_SIZE(esai_tokens), private->array,
+ le32_to_cpu(private->size));
+ if (ret != 0) {
+ dev_err(sdev->dev, "error: parse esai tokens failed %d\n",
+ le32_to_cpu(private->size));
+ return ret;
+ }
+
+ config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
+ config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
+ config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
+ config->esai.mclk_direction = hw_config->mclk_direction;
+ config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
+ config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
+ config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
+
+ dev_info(sdev->dev,
+ "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
+ config->dai_index, config->format,
+ config->esai.mclk_rate, config->esai.tdm_slot_width,
+ config->esai.tdm_slots, config->esai.mclk_id);
+
+ if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
+ dev_err(sdev->dev, "error: invalid channel count for ESAI%d\n",
+ config->dai_index);
+ return -EINVAL;
+ }
+
+ /* send message to DSP */
+ ret = sof_ipc_tx_message(sdev->ipc,
+ config->hdr.cmd, config, size, &reply,
+ sizeof(reply));
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: failed to set DAI config for ESAI%d\n",
+ config->dai_index);
+ return ret;
+ }
+
+ /* set config for all DAI's with name matching the link name */
+ ret = sof_set_dai_config(sdev, size, link, config);
+ if (ret < 0)
+ dev_err(sdev->dev, "error: failed to save DAI config for ESAI%d\n",
+ config->dai_index);
+
+ return ret;
}
static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
@@ -2968,7 +3099,9 @@ found:
case SOF_DAI_INTEL_SSP:
case SOF_DAI_INTEL_DMIC:
case SOF_DAI_INTEL_ALH:
- /* no resource needs to be released for SSP, DMIC and ALH */
+ case SOF_DAI_IMX_SAI:
+ case SOF_DAI_IMX_ESAI:
+ /* no resource needs to be released for all cases above */
break;
case SOF_DAI_INTEL_HDA:
ret = sof_link_hda_unload(sdev, link);
@@ -3299,15 +3432,6 @@ static struct snd_soc_tplg_ops sof_tplg_ops = {
.bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops),
};
-int snd_sof_init_topology(struct snd_sof_dev *sdev,
- struct snd_soc_tplg_ops *ops)
-{
- /* TODO: support linked list of topologies */
- sdev->tplg_ops = ops;
- return 0;
-}
-EXPORT_SYMBOL(snd_sof_init_topology);
-
int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file)
{
const struct firmware *fw;
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index 4c3cff031fd6..17453d2da45d 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -244,8 +244,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev)
}
/* create compressed page table for audio firmware */
- ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area,
- sdev->dmatb.bytes);
+ ret = snd_sof_create_page_table(sdev->dev, &sdev->dmatb,
+ sdev->dmatp.area, sdev->dmatb.bytes);
if (ret < 0)
goto table_err;
diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c
index 2ac4c3da0320..9831eb57df6c 100644
--- a/sound/soc/sof/utils.c
+++ b/sound/soc/sof/utils.c
@@ -10,6 +10,7 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/platform_device.h>
+#include <asm/unaligned.h>
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
@@ -110,3 +111,62 @@ void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest,
memcpy_fromio(dest, src, size);
}
EXPORT_SYMBOL(sof_block_read);
+
+/*
+ * Generic buffer page table creation.
+ * Take the each physical page address and drop the least significant unused
+ * bits from each (based on PAGE_SIZE). Then pack valid page address bits
+ * into compressed page table.
+ */
+
+int snd_sof_create_page_table(struct device *dev,
+ struct snd_dma_buffer *dmab,
+ unsigned char *page_table, size_t size)
+{
+ int i, pages;
+
+ pages = snd_sgbuf_aligned_pages(size);
+
+ dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n",
+ dmab->area, size, pages);
+
+ for (i = 0; i < pages; i++) {
+ /*
+ * The number of valid address bits for each page is 20.
+ * idx determines the byte position within page_table
+ * where the current page's address is stored
+ * in the compressed page_table.
+ * This can be calculated by multiplying the page number by 2.5.
+ */
+ u32 idx = (5 * i) >> 1;
+ u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
+ u8 *pg_table;
+
+ dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
+
+ pg_table = (u8 *)(page_table + idx);
+
+ /*
+ * pagetable compression:
+ * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
+ * ___________pfn 0__________ __________pfn 1___________ _pfn 2...
+ * .... .... .... .... .... .... .... .... .... .... ....
+ * It is created by:
+ * 1. set current location to 0, PFN index i to 0
+ * 2. put pfn[i] at current location in Little Endian byte order
+ * 3. calculate an intermediate value as
+ * x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
+ * 4. put x at offset (current location + 2) in LE byte order
+ * 5. increment current location by 5 bytes, increment i by 2
+ * 6. continue to (2)
+ */
+ if (i & 1)
+ put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4,
+ pg_table);
+ else
+ put_unaligned_le32(pfn, pg_table);
+ }
+
+ return pages;
+}
+EXPORT_SYMBOL(snd_sof_create_page_table);