diff options
author | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:00:44 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:00:44 +0800 |
commit | b7f8883066ed37854ab4d87ca6df8f628dfa0126 (patch) | |
tree | 743e498f7c6bdcb866b051bbed55ab0ffa0882ba | |
parent | 2a635fc846224d82fcfa73cfdab969d2a2cfb484 (diff) | |
parent | 9c3a087b1db3807400723f5c6e9a13e4429cfc3f (diff) |
Merge remote-tracking branch 'origin/audio/sof' into audio/next
* origin/audio/sof: (21 commits)
ASoC: SOF: Read tplg filename from board descriptor
ASoC: SOF: Update fw_filename from board description
ASoC: SOF: Allow probe to continue when we have an actual codec
ASoC: SOF: Hardcode ignore_machine
ASoC: fsl: Add generic DAI driver
...
-rw-r--r-- | include/sound/sof.h | 7 | ||||
-rw-r--r-- | include/sound/sof/dai-imx.h | 55 | ||||
-rw-r--r-- | include/sound/sof/dai.h | 3 | ||||
-rw-r--r-- | include/uapi/sound/sof/abi.h | 2 | ||||
-rw-r--r-- | include/uapi/sound/sof/tokens.h | 6 | ||||
-rw-r--r-- | sound/soc/fsl/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dai.c | 276 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 2 | ||||
-rw-r--r-- | sound/soc/sof/core.c | 132 | ||||
-rw-r--r-- | sound/soc/sof/intel/apl.c | 5 | ||||
-rw-r--r-- | sound/soc/sof/intel/bdw.c | 5 | ||||
-rw-r--r-- | sound/soc/sof/intel/byt.c | 15 | ||||
-rw-r--r-- | sound/soc/sof/intel/cnl.c | 5 | ||||
-rw-r--r-- | sound/soc/sof/nocodec.c | 12 | ||||
-rw-r--r-- | sound/soc/sof/ops.h | 26 | ||||
-rw-r--r-- | sound/soc/sof/pcm.c | 29 | ||||
-rw-r--r-- | sound/soc/sof/sof-acpi-dev.c | 11 | ||||
-rw-r--r-- | sound/soc/sof/sof-of-dev.c | 20 | ||||
-rw-r--r-- | sound/soc/sof/sof-pci-dev.c | 22 | ||||
-rw-r--r-- | sound/soc/sof/sof-priv.h | 15 | ||||
-rw-r--r-- | sound/soc/sof/topology.c | 152 | ||||
-rw-r--r-- | sound/soc/sof/trace.c | 4 | ||||
-rw-r--r-- | sound/soc/sof/utils.c | 60 |
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); |