summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2025-02-10 13:06:19 +0000
committerMark Brown <broonie@kernel.org>2025-02-10 13:06:19 +0000
commit3c331bdeececb629669961a80c0f929301c088d2 (patch)
tree15f2886b58b6c42ca046f0f941477f0e27fb00db
parent005859a2cf7aa349fbbfe433ab1769b15c535b72 (diff)
parent6cf5df1040ba0694aea6a5edc6f31811a442ea36 (diff)
Refactor imx drivers and introduce support for
Merge series from Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>: A rather aggressive but arguably much needed refactorization of the SOF imx drivers. The refactorization is meant to address the code duplication in the imx drivers and decrease the coding effort required for introducing a new imx platform. After refactorization and imx95 introduction, only two drivers remain: imx8 (meant for the imx8 series: imx8 (imx8qm), imx8x (imx8qxp), imx8m, and imx8ulp) and imx9 (meant for the imx9 series: imx95 (for now)). The series also includes the introduction of the imx95 driver.
-rw-r--r--sound/soc/sof/imx/Kconfig17
-rw-r--r--sound/soc/sof/imx/Makefile6
-rw-r--r--sound/soc/sof/imx/imx-common.c431
-rw-r--r--sound/soc/sof/imx/imx-common.h151
-rw-r--r--sound/soc/sof/imx/imx8.c753
-rw-r--r--sound/soc/sof/imx/imx8m.c567
-rw-r--r--sound/soc/sof/imx/imx8ulp.c520
-rw-r--r--sound/soc/sof/imx/imx9.c137
8 files changed, 988 insertions, 1594 deletions
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index 4751b04d5e6f..327e2df94a58 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -32,22 +32,13 @@ config SND_SOC_SOF_IMX8
Say Y if you have such a device.
If unsure select "N".
-config SND_SOC_SOF_IMX8M
- tristate "SOF support for i.MX8M"
+config SND_SOC_SOF_IMX9
+ tristate "SOF support for i.MX9"
depends on IMX_DSP
select SND_SOC_SOF_IMX_COMMON
help
- This adds support for Sound Open Firmware for NXP i.MX8M platforms.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_SOF_IMX8ULP
- tristate "SOF support for i.MX8ULP"
- depends on IMX_DSP
- select SND_SOC_SOF_IMX_COMMON
- help
- This adds support for Sound Open Firmware for NXP i.MX8ULP platforms.
- Say Y if you have such a device.
+ This adds support for Sound Open Firmware for NXP i.MX9 platforms.
+ Say Y if you need such a device.
If unsure select "N".
endif ## SND_SOC_SOF_IMX_TOPLEVEL
diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile
index be0bf0736dfa..74b5ecad8fe8 100644
--- a/sound/soc/sof/imx/Makefile
+++ b/sound/soc/sof/imx/Makefile
@@ -1,11 +1,9 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-imx8-y := imx8.o
-snd-sof-imx8m-y := imx8m.o
-snd-sof-imx8ulp-y := imx8ulp.o
+snd-sof-imx9-y := imx9.o
snd-sof-imx-common-y := imx-common.o
obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o
-obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o
-obj-$(CONFIG_SND_SOC_SOF_IMX8ULP) += snd-sof-imx8ulp.o
+obj-$(CONFIG_SND_SOC_SOF_IMX9) += snd-sof-imx9.o
obj-$(CONFIG_SND_SOC_SOF_IMX_COMMON) += imx-common.o
diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c
index fce6d9cf6a6b..82057af1436c 100644
--- a/sound/soc/sof/imx/imx-common.c
+++ b/sound/soc/sof/imx/imx-common.c
@@ -1,11 +1,16 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright 2020 NXP
+// Copyright 2020-2025 NXP
//
// Common helpers for the audio DSP on i.MX8
+#include <linux/firmware/imx/dsp.h>
#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_domain.h>
#include <sound/sof/xtensa.h>
+
#include "../ops.h"
#include "imx-common.h"
@@ -74,5 +79,429 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
}
EXPORT_SYMBOL(imx8_dump);
+static void imx_handle_reply(struct imx_dsp_ipc *ipc)
+{
+ struct snd_sof_dev *sdev;
+ unsigned long flags;
+
+ sdev = imx_dsp_get_data(ipc);
+
+ spin_lock_irqsave(&sdev->ipc_lock, flags);
+ snd_sof_ipc_process_reply(sdev, 0);
+ spin_unlock_irqrestore(&sdev->ipc_lock, flags);
+}
+
+static void imx_handle_request(struct imx_dsp_ipc *ipc)
+{
+ struct snd_sof_dev *sdev;
+ u32 panic_code;
+
+ sdev = imx_dsp_get_data(ipc);
+
+ if (get_chip_info(sdev)->ipc_info.has_panic_code) {
+ sof_mailbox_read(sdev, sdev->debug_box.offset + 0x4,
+ &panic_code,
+ sizeof(panic_code));
+
+ if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+ snd_sof_dsp_panic(sdev, panic_code, true);
+ return;
+ }
+ }
+
+ snd_sof_ipc_msgs_rx(sdev);
+}
+
+static struct imx_dsp_ops imx_ipc_ops = {
+ .handle_reply = imx_handle_reply,
+ .handle_request = imx_handle_request,
+};
+
+static int imx_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+{
+ struct imx_common_data *common = sdev->pdata->hw_pdata;
+
+ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size);
+ imx_dsp_ring_doorbell(common->ipc_handle, 0x0);
+
+ return 0;
+}
+
+static int imx_get_bar_index(struct snd_sof_dev *sdev, u32 type)
+{
+ switch (type) {
+ case SOF_FW_BLK_TYPE_IRAM:
+ case SOF_FW_BLK_TYPE_SRAM:
+ return type;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+ return get_chip_info(sdev)->ipc_info.boot_mbox_offset;
+}
+
+static int imx_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+ return get_chip_info(sdev)->ipc_info.window_offset;
+}
+
+static int imx_set_power_state(struct snd_sof_dev *sdev,
+ const struct sof_dsp_power_state *target)
+{
+ sdev->dsp_power_state = *target;
+
+ return 0;
+}
+
+static int imx_common_resume(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ int ret, i;
+
+ common = sdev->pdata->hw_pdata;
+
+ ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
+ if (ret)
+ dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
+
+ for (i = 0; i < DSP_MU_CHAN_NUM; i++)
+ imx_dsp_request_channel(common->ipc_handle, i);
+
+ /* done. If need be, core will be started by SOF core immediately after */
+ return 0;
+}
+
+static int imx_common_suspend(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ int i, ret;
+
+ common = sdev->pdata->hw_pdata;
+
+ ret = imx_chip_core_shutdown(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to shutdown core: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < DSP_MU_CHAN_NUM; i++)
+ imx_dsp_free_channel(common->ipc_handle, i);
+
+ clk_bulk_disable_unprepare(common->clk_num, common->clks);
+
+ return 0;
+}
+
+static int imx_runtime_resume(struct snd_sof_dev *sdev)
+{
+ const struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D0,
+ };
+ int ret;
+
+ ret = imx_common_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to runtime common resume: %d\n", ret);
+ return ret;
+ }
+
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int imx_resume(struct snd_sof_dev *sdev)
+{
+ const struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D0,
+ };
+ int ret;
+
+ ret = imx_common_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to common resume: %d\n", ret);
+ return ret;
+ }
+
+ if (pm_runtime_suspended(sdev->dev)) {
+ pm_runtime_disable(sdev->dev);
+ pm_runtime_set_active(sdev->dev);
+ pm_runtime_mark_last_busy(sdev->dev);
+ pm_runtime_enable(sdev->dev);
+ pm_runtime_idle(sdev->dev);
+ }
+
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int imx_runtime_suspend(struct snd_sof_dev *sdev)
+{
+ const struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D3,
+ };
+ int ret;
+
+ ret = imx_common_suspend(sdev);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to runtime common suspend: %d\n", ret);
+
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int imx_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
+{
+ const struct sof_dsp_power_state target_power_state = {
+ .state = target_state,
+ };
+ int ret;
+
+ if (!pm_runtime_suspended(sdev->dev)) {
+ ret = imx_common_suspend(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to common suspend: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return snd_sof_dsp_set_power_state(sdev, &target_power_state);
+}
+
+static int imx_region_name_to_blk_type(const char *region_name)
+{
+ if (!strcmp(region_name, "iram"))
+ return SOF_FW_BLK_TYPE_IRAM;
+ else if (!strcmp(region_name, "dram"))
+ return SOF_FW_BLK_TYPE_DRAM;
+ else if (!strcmp(region_name, "sram"))
+ return SOF_FW_BLK_TYPE_SRAM;
+ else
+ return -EINVAL;
+}
+
+static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_info *chip_info;
+ struct reserved_mem *reserved;
+ struct platform_device *pdev;
+ struct device_node *res_np;
+ phys_addr_t base, size;
+ struct resource *res;
+ int i, blk_type, ret;
+
+ pdev = to_platform_device(sdev->dev);
+ chip_info = get_chip_info(sdev);
+
+ for (i = 0; chip_info->memory[i].name; i++) {
+ blk_type = imx_region_name_to_blk_type(chip_info->memory[i].name);
+ if (blk_type < 0)
+ return dev_err_probe(sdev->dev, blk_type,
+ "no blk type for region %s\n",
+ chip_info->memory[i].name);
+
+ if (!chip_info->memory[i].reserved) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ chip_info->memory[i].name);
+ if (!res)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to fetch %s resource\n",
+ chip_info->memory[i].name);
+
+ base = res->start;
+ size = resource_size(res);
+ } else {
+ ret = of_property_match_string(pdev->dev.of_node,
+ "memory-region-names",
+ chip_info->memory[i].name);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "no valid index for %s\n",
+ chip_info->memory[i].name);
+
+ res_np = of_parse_phandle(pdev->dev.of_node,
+ "memory-region",
+ ret);
+ if (!res_np)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to parse phandle %s\n",
+ chip_info->memory[i].name);
+
+ reserved = of_reserved_mem_lookup(res_np);
+ of_node_put(res_np);
+ if (!reserved)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to get %s reserved\n",
+ chip_info->memory[i].name);
+
+ base = reserved->base;
+ size = reserved->size;
+ }
+
+ sdev->bar[blk_type] = devm_ioremap(sdev->dev, base, size);
+ if (IS_ERR(sdev->bar[blk_type]))
+ return dev_err_probe(sdev->dev,
+ PTR_ERR(sdev->bar[blk_type]),
+ "failed to ioremap %s region\n",
+ chip_info->memory[i].name);
+ }
+
+ return 0;
+}
+
+static void imx_unregister_action(void *data)
+{
+ struct imx_common_data *common;
+ struct snd_sof_dev *sdev;
+
+ sdev = data;
+ common = sdev->pdata->hw_pdata;
+
+ if (get_chip_info(sdev)->has_dma_reserved)
+ of_reserved_mem_device_release(sdev->dev);
+
+ platform_device_unregister(common->ipc_dev);
+}
+
+static int imx_probe(struct snd_sof_dev *sdev)
+{
+ struct dev_pm_domain_attach_data domain_data = {
+ .pd_names = NULL, /* no filtering */
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ };
+ struct imx_common_data *common;
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = to_platform_device(sdev->dev);
+
+ common = devm_kzalloc(sdev->dev, sizeof(*common), GFP_KERNEL);
+ if (!common)
+ return dev_err_probe(sdev->dev, -ENOMEM,
+ "failed to allocate common data\n");
+
+ common->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
+ PLATFORM_DEVID_NONE,
+ pdev, sizeof(*pdev));
+ if (IS_ERR(common->ipc_dev))
+ return dev_err_probe(sdev->dev, PTR_ERR(common->ipc_dev),
+ "failed to create IPC device\n");
+
+ if (get_chip_info(sdev)->has_dma_reserved) {
+ ret = of_reserved_mem_device_init_by_name(sdev->dev,
+ pdev->dev.of_node,
+ "dma");
+ if (ret) {
+ platform_device_unregister(common->ipc_dev);
+
+ return dev_err_probe(sdev->dev, ret,
+ "failed to bind DMA region\n");
+ }
+ }
+
+ /* let the devres API take care of the cleanup */
+ ret = devm_add_action_or_reset(sdev->dev,
+ imx_unregister_action,
+ sdev);
+ if (ret)
+ return dev_err_probe(sdev->dev, ret, "failed to add devm action\n");
+
+ common->ipc_handle = dev_get_drvdata(&common->ipc_dev->dev);
+ if (!common->ipc_handle)
+ return dev_err_probe(sdev->dev, -EPROBE_DEFER,
+ "failed to fetch IPC handle\n");
+
+ ret = imx_parse_ioremap_memory(sdev);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "failed to parse/ioremap memory regions\n");
+
+ if (!sdev->dev->pm_domain) {
+ ret = devm_pm_domain_attach_list(sdev->dev,
+ &domain_data, &common->pd_list);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret, "failed to attach PDs\n");
+ }
+
+ ret = devm_clk_bulk_get_all(sdev->dev, &common->clks);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, common->clk_num,
+ "failed to fetch clocks\n");
+ common->clk_num = ret;
+
+ ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret, "failed to enable clocks\n");
+
+ common->ipc_handle->ops = &imx_ipc_ops;
+ imx_dsp_set_data(common->ipc_handle, sdev);
+
+ sdev->num_cores = 1;
+ sdev->pdata->hw_pdata = common;
+ sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
+ sdev->dsp_box.offset = get_chip_info(sdev)->ipc_info.boot_mbox_offset;
+
+ return imx_chip_probe(sdev);
+}
+
+static void imx_remove(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ int ret;
+
+ common = sdev->pdata->hw_pdata;
+
+ if (!pm_runtime_suspended(sdev->dev)) {
+ ret = imx_chip_core_shutdown(sdev);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to shutdown core: %d\n", ret);
+
+ clk_bulk_disable_unprepare(common->clk_num, common->clks);
+ }
+}
+
+const struct snd_sof_dsp_ops sof_imx_ops = {
+ .probe = imx_probe,
+ .remove = imx_remove,
+
+ .run = imx_chip_core_kick,
+ .reset = imx_chip_core_reset,
+
+ .block_read = sof_block_read,
+ .block_write = sof_block_write,
+
+ .mailbox_read = sof_mailbox_read,
+ .mailbox_write = sof_mailbox_write,
+
+ .send_msg = imx_send_msg,
+ .get_mailbox_offset = imx_get_mailbox_offset,
+ .get_window_offset = imx_get_window_offset,
+
+ .ipc_msg_data = sof_ipc_msg_data,
+ .set_stream_data_offset = sof_set_stream_data_offset,
+
+ .get_bar_index = imx_get_bar_index,
+ .load_firmware = snd_sof_load_firmware_memcpy,
+
+ .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+
+ .pcm_open = sof_stream_pcm_open,
+ .pcm_close = sof_stream_pcm_close,
+
+ .runtime_suspend = imx_runtime_suspend,
+ .runtime_resume = imx_runtime_resume,
+ .suspend = imx_suspend,
+ .resume = imx_resume,
+
+ .set_power_state = imx_set_power_state,
+
+ .hw_info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+};
+EXPORT_SYMBOL(sof_imx_ops);
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF helpers for IMX platforms");
diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h
index 13d7f3ef675e..9bd711dbb5d0 100644
--- a/sound/soc/sof/imx/imx-common.h
+++ b/sound/soc/sof/imx/imx-common.h
@@ -4,10 +4,159 @@
#define __IMX_COMMON_H__
#include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <sound/sof/xtensa.h>
+
+#include "../sof-of-dev.h"
+#include "../ops.h"
#define EXCEPT_MAX_HDR_SIZE 0x400
#define IMX8_STACK_DUMP_SIZE 32
+/* chip_info refers to the data stored in struct sof_dev_desc's chip_info */
+#define get_chip_info(sdev)\
+ ((const struct imx_chip_info *)((sdev)->pdata->desc->chip_info))
+
+/* chip_pdata refers to the data stored in struct imx_common_data's chip_pdata */
+#define get_chip_pdata(sdev)\
+ (((struct imx_common_data *)((sdev)->pdata->hw_pdata))->chip_pdata)
+
+/* can be used if:
+ * 1) The only supported IPC version is IPC3.
+ * 2) The default paths/FW name match values below.
+ *
+ * otherwise, just explicitly declare the structure
+ */
+#define IMX_SOF_DEV_DESC(mach_name, of_machs, \
+ mach_chip_info, mach_ops, mach_ops_init) \
+static struct sof_dev_desc sof_of_##mach_name##_desc = { \
+ .of_machines = of_machs, \
+ .chip_info = mach_chip_info, \
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), \
+ .ipc_default = SOF_IPC_TYPE_3, \
+ .default_fw_path = { \
+ [SOF_IPC_TYPE_3] = "imx/sof", \
+ }, \
+ .default_tplg_path = { \
+ [SOF_IPC_TYPE_3] = "imx/sof-tplg", \
+ }, \
+ .default_fw_filename = { \
+ [SOF_IPC_TYPE_3] = "sof-" #mach_name ".ri", \
+ }, \
+ .ops = mach_ops, \
+ .ops_init = mach_ops_init, \
+}
+
+/* to be used alongside IMX_SOF_DEV_DESC() */
+#define IMX_SOF_DEV_DESC_NAME(mach_name) sof_of_##mach_name##_desc
+
+/* dai driver entry w/ playback and capture caps. If one direction is missing
+ * then set the channels to 0.
+ */
+#define IMX_SOF_DAI_DRV_ENTRY(dai_name, pb_cmin, pb_cmax, cap_cmin, cap_cmax) \
+{ \
+ .name = dai_name, \
+ .playback = { \
+ .channels_min = pb_cmin, \
+ .channels_max = pb_cmax, \
+ }, \
+ .capture = { \
+ .channels_min = cap_cmin, \
+ .channels_max = cap_cmax, \
+ }, \
+}
+
+/* use if playback and capture have the same min/max channel count */
+#define IMX_SOF_DAI_DRV_ENTRY_BIDIR(dai_name, cmin, cmax)\
+ IMX_SOF_DAI_DRV_ENTRY(dai_name, cmin, cmax, cmin, cmax)
+
+struct imx_ipc_info {
+ /* true if core is able to write a panic code to the debug box */
+ bool has_panic_code;
+ /* offset to mailbox in which firmware initially writes FW_READY */
+ int boot_mbox_offset;
+ /* offset to region at which the mailboxes start */
+ int window_offset;
+};
+
+struct imx_chip_ops {
+ /* called after clocks and PDs are enabled */
+ int (*probe)(struct snd_sof_dev *sdev);
+ /* used directly by the SOF core */
+ int (*core_kick)(struct snd_sof_dev *sdev);
+ /* called during suspend()/remove() before clocks are disabled */
+ int (*core_shutdown)(struct snd_sof_dev *sdev);
+ /* used directly by the SOF core */
+ int (*core_reset)(struct snd_sof_dev *sdev);
+};
+
+struct imx_memory_info {
+ const char *name;
+ bool reserved;
+};
+
+struct imx_chip_info {
+ struct imx_ipc_info ipc_info;
+ /* does the chip have a reserved memory region for DMA? */
+ bool has_dma_reserved;
+ struct imx_memory_info *memory;
+ struct snd_soc_dai_driver *drv;
+ int num_drv;
+ /* optional */
+ const struct imx_chip_ops *ops;
+};
+
+struct imx_common_data {
+ struct platform_device *ipc_dev;
+ struct imx_dsp_ipc *ipc_handle;
+ /* core may have no clocks */
+ struct clk_bulk_data *clks;
+ int clk_num;
+ /* core may have no PDs */
+ struct dev_pm_domain_list *pd_list;
+ void *chip_pdata;
+};
+
+static inline int imx_chip_core_kick(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->core_kick)
+ return ops->core_kick(sdev);
+
+ return 0;
+}
+
+static inline int imx_chip_core_shutdown(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->core_shutdown)
+ return ops->core_shutdown(sdev);
+
+ return 0;
+}
+
+static inline int imx_chip_core_reset(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->core_reset)
+ return ops->core_reset(sdev);
+
+ return 0;
+}
+
+static inline int imx_chip_probe(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->probe)
+ return ops->probe(sdev);
+
+ return 0;
+}
+
void imx8_get_registers(struct snd_sof_dev *sdev,
struct sof_ipc_dsp_oops_xtensa *xoops,
struct sof_ipc_panic_info *panic_info,
@@ -15,4 +164,6 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
void imx8_dump(struct snd_sof_dev *sdev, u32 flags);
+extern const struct snd_sof_dsp_ops sof_imx_ops;
+
#endif
diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c
index 1e7bf00d7c46..4be4c569b583 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -1,140 +1,72 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright 2019 NXP
+// Copyright 2019-2025 NXP
//
// Author: Daniel Baluta <daniel.baluta@nxp.com>
//
// Hardware interface for audio DSP on i.MX8
-#include <linux/firmware.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/pm_domain.h>
-
-#include <linux/module.h>
-#include <sound/sof.h>
-#include <sound/sof/xtensa.h>
-#include <linux/firmware/imx/ipc.h>
-#include <linux/firmware/imx/dsp.h>
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/arm-smccc.h>
#include <linux/firmware/imx/svc/misc.h>
-#include <dt-bindings/firmware/imx/rsrc.h>
-#include "../ops.h"
-#include "../sof-of-dev.h"
-#include "imx-common.h"
+#include <linux/mfd/syscon.h>
-/* DSP memories */
-#define IRAM_OFFSET 0x10000
-#define IRAM_SIZE (2 * 1024)
-#define DRAM0_OFFSET 0x0
-#define DRAM0_SIZE (32 * 1024)
-#define DRAM1_OFFSET 0x8000
-#define DRAM1_SIZE (32 * 1024)
-#define SYSRAM_OFFSET 0x18000
-#define SYSRAM_SIZE (256 * 1024)
-#define SYSROM_OFFSET 0x58000
-#define SYSROM_SIZE (192 * 1024)
+#include "imx-common.h"
+/* imx8/imx8x macros */
#define RESET_VECTOR_VADDR 0x596f8000
-#define MBOX_OFFSET 0x800000
-#define MBOX_SIZE 0x1000
-
-struct imx8_priv {
- struct device *dev;
- struct snd_sof_dev *sdev;
-
- /* DSP IPC handler */
- struct imx_dsp_ipc *dsp_ipc;
- struct platform_device *ipc_dev;
-
- /* System Controller IPC handler */
- struct imx_sc_ipc *sc_ipc;
-
- /* Power domain handling */
- int num_domains;
- struct device **pd_dev;
- struct device_link **link;
-
- struct clk_bulk_data *clks;
- int clk_num;
-};
-
-static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev)
-{
- return MBOX_OFFSET;
-}
-
-static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id)
-{
- return MBOX_OFFSET;
-}
-
-static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc)
-{
- struct imx8_priv *priv = imx_dsp_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- snd_sof_ipc_process_reply(priv->sdev, 0);
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc)
-{
- struct imx8_priv *priv = imx_dsp_get_data(ipc);
- u32 p; /* panic code */
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
-
- /* Check to see if the message is a panic code (0x0dead***) */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
- snd_sof_dsp_panic(priv->sdev, p, true);
- else
- snd_sof_ipc_msgs_rx(priv->sdev);
-}
-
-static struct imx_dsp_ops dsp_ops = {
- .handle_reply = imx8_dsp_handle_reply,
- .handle_request = imx8_dsp_handle_request,
+/* imx8m macros */
+#define IMX8M_DAP_DEBUG 0x28800000
+#define IMX8M_DAP_DEBUG_SIZE (64 * 1024)
+#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020)
+#define IMX8M_PWRCTL_CORERESET BIT(16)
+
+#define AudioDSP_REG0 0x100
+#define AudioDSP_REG1 0x104
+#define AudioDSP_REG2 0x108
+#define AudioDSP_REG3 0x10c
+
+#define AudioDSP_REG2_RUNSTALL BIT(5)
+
+/* imx8ulp macros */
+#define FSL_SIP_HIFI_XRDC 0xc200000e
+#define SYSCTRL0 0x8
+#define EXECUTE_BIT BIT(13)
+#define RESET_BIT BIT(16)
+#define HIFI4_CLK_BIT BIT(17)
+#define PB_CLK_BIT BIT(18)
+#define PLAT_CLK_BIT BIT(19)
+#define DEBUG_LOGIC_BIT BIT(25)
+
+struct imx8m_chip_data {
+ void __iomem *dap;
+ struct regmap *regmap;
};
-static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
-{
- struct imx8_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
- imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
-
- return 0;
-}
-
/*
* DSP control.
*/
static int imx8x_run(struct snd_sof_dev *sdev)
{
- struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata;
int ret;
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_SEL, 1);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset source select\n");
return ret;
}
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_AUDIO, 0x80);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset of AUDIO\n");
return ret;
}
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_PERIPH, 0x5A);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset of PERIPH %d\n",
@@ -142,14 +74,14 @@ static int imx8x_run(struct snd_sof_dev *sdev)
return ret;
}
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_IRQ, 0x51);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset of IRQ\n");
return ret;
}
- imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true,
+ imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
RESET_VECTOR_VADDR);
return 0;
@@ -157,17 +89,16 @@ static int imx8x_run(struct snd_sof_dev *sdev)
static int imx8_run(struct snd_sof_dev *sdev)
{
- struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata;
int ret;
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_SEL, 0);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset source select\n");
return ret;
}
- imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true,
+ imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
RESET_VECTOR_VADDR);
return 0;
@@ -175,428 +106,273 @@ static int imx8_run(struct snd_sof_dev *sdev)
static int imx8_probe(struct snd_sof_dev *sdev)
{
- struct platform_device *pdev = to_platform_device(sdev->dev);
- struct device_node *np = pdev->dev.of_node;
- struct device_node *res_node;
- struct resource *mmio;
- struct imx8_priv *priv;
- struct resource res;
- u32 base, size;
- int ret = 0;
- int i;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- sdev->num_cores = 1;
- sdev->pdata->hw_pdata = priv;
- priv->dev = sdev->dev;
- priv->sdev = sdev;
-
- /* power up device associated power domains */
- priv->num_domains = of_count_phandle_with_args(np, "power-domains",
- "#power-domain-cells");
- if (priv->num_domains < 0) {
- dev_err(sdev->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 exit_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 = -ENOMEM;
- dev_pm_domain_detach(priv->pd_dev[i], false);
- goto exit_unroll_pm;
- }
- }
-
- ret = imx_scu_get_handle(&priv->sc_ipc);
- if (ret) {
- dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n",
- ret);
- goto exit_unroll_pm;
- }
+ struct imx_sc_ipc *sc_ipc_handle;
+ struct imx_common_data *common;
+ int ret;
- priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
- PLATFORM_DEVID_NONE,
- pdev, sizeof(*pdev));
- if (IS_ERR(priv->ipc_dev)) {
- ret = PTR_ERR(priv->ipc_dev);
- goto exit_unroll_pm;
- }
+ common = sdev->pdata->hw_pdata;
- priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
- if (!priv->dsp_ipc) {
- /* DSP IPC driver not probed yet, try later */
- ret = -EPROBE_DEFER;
- dev_err(sdev->dev, "Failed to get drvdata\n");
- goto exit_pdev_unregister;
- }
+ ret = imx_scu_get_handle(&sc_ipc_handle);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "failed to fetch SC IPC handle\n");
- imx_dsp_set_data(priv->dsp_ipc, priv);
- priv->dsp_ipc->ops = &dsp_ops;
-
- /* DSP base */
- mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mmio) {
- base = mmio->start;
- size = resource_size(mmio);
- } else {
- dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
- ret = -EINVAL;
- goto exit_pdev_unregister;
- }
+ common->chip_pdata = sc_ipc_handle;
- sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
- if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
- dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
- base, size);
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
- sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
+ return 0;
+}
- res_node = of_parse_phandle(np, "memory-region", 0);
- if (!res_node) {
- dev_err(&pdev->dev, "failed to get memory region node\n");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
+static int imx8m_reset(struct snd_sof_dev *sdev)
+{
+ struct imx8m_chip_data *chip;
+ u32 pwrctl;
- ret = of_address_to_resource(res_node, 0, &res);
- of_node_put(res_node);
- if (ret) {
- dev_err(&pdev->dev, "failed to get reserved region address\n");
- goto exit_pdev_unregister;
- }
+ chip = get_chip_pdata(sdev);
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- resource_size(&res));
- if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
- dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
- base, size);
- ret = -ENOMEM;
- goto exit_pdev_unregister;
- }
- sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
+ /* put DSP into reset and stall */
+ pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL);
+ pwrctl |= IMX8M_PWRCTL_CORERESET;
+ writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL);
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
+ /* keep reset asserted for 10 cycles */
+ usleep_range(1, 2);
- ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
- priv->clk_num = ret;
+ regmap_update_bits(chip->regmap, AudioDSP_REG2,
+ AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL);
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
+ /* take the DSP out of reset and keep stalled for FW loading */
+ pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL);
+ pwrctl &= ~IMX8M_PWRCTL_CORERESET;
+ writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL);
return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
-exit_unroll_pm:
- while (--i >= 0) {
- device_link_del(priv->link[i]);
- dev_pm_domain_detach(priv->pd_dev[i], false);
- }
-
- return ret;
}
-static void imx8_remove(struct snd_sof_dev *sdev)
+static int imx8m_run(struct snd_sof_dev *sdev)
{
- struct imx8_priv *priv = sdev->pdata->hw_pdata;
- int i;
+ struct imx8m_chip_data *chip = get_chip_pdata(sdev);
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
- platform_device_unregister(priv->ipc_dev);
+ regmap_update_bits(chip->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0);
- 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;
}
-/* on i.MX8 there is 1 to 1 match between type and BAR idx */
-static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type)
+static int imx8m_probe(struct snd_sof_dev *sdev)
{
- /* Only IRAM and SRAM bars are valid */
- switch (type) {
- case SOF_FW_BLK_TYPE_IRAM:
- case SOF_FW_BLK_TYPE_SRAM:
- return type;
- default:
- return -EINVAL;
- }
-}
+ struct imx_common_data *common;
+ struct imx8m_chip_data *chip;
-static void imx8_suspend(struct snd_sof_dev *sdev)
-{
- int i;
- struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
+ common = sdev->pdata->hw_pdata;
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
+ chip = devm_kzalloc(sdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return dev_err_probe(sdev->dev, -ENOMEM,
+ "failed to allocate chip data\n");
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
-}
+ chip->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE);
+ if (!chip->dap)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to ioremap DAP\n");
-static int imx8_resume(struct snd_sof_dev *sdev)
-{
- struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
- int ret;
- int i;
+ chip->regmap = syscon_regmap_lookup_by_phandle(sdev->dev->of_node, "fsl,dsp-ctrl");
+ if (IS_ERR(chip->regmap))
+ return dev_err_probe(sdev->dev, PTR_ERR(chip->regmap),
+ "failed to fetch dsp ctrl regmap\n");
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_request_channel(priv->dsp_ipc, i);
+ common->chip_pdata = chip;
return 0;
}
-static int imx8_dsp_runtime_resume(struct snd_sof_dev *sdev)
+static int imx8ulp_run(struct snd_sof_dev *sdev)
{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
+ struct regmap *regmap = get_chip_pdata(sdev);
- ret = imx8_resume(sdev);
- if (ret < 0)
- return ret;
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
+ /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */
+ regmap_update_bits(regmap, SYSCTRL0, RESET_BIT, 0);
-static int imx8_dsp_runtime_suspend(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D3,
- };
+ /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/
+ regmap_update_bits(regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0);
- imx8_suspend(sdev);
+ /* Stall HIFI4 DSP Execution: 1 stall, 0 run */
+ regmap_update_bits(regmap, SYSCTRL0, EXECUTE_BIT, 0);
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
+ return 0;
}
-static int imx8_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
+static int imx8ulp_reset(struct snd_sof_dev *sdev)
{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = target_state,
- };
+ struct arm_smccc_res smc_res;
+ struct regmap *regmap;
- if (!pm_runtime_suspended(sdev->dev))
- imx8_suspend(sdev);
+ regmap = get_chip_pdata(sdev);
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
+ /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */
+ regmap_update_bits(regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT);
-static int imx8_dsp_resume(struct snd_sof_dev *sdev)
-{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
+ /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */
+ regmap_update_bits(regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT);
- ret = imx8_resume(sdev);
- if (ret < 0)
- return ret;
+ /* HiFi4 Clock Enable: 1 enabled, 0 disabled */
+ regmap_update_bits(regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT);
- if (pm_runtime_suspended(sdev->dev)) {
- pm_runtime_disable(sdev->dev);
- pm_runtime_set_active(sdev->dev);
- pm_runtime_mark_last_busy(sdev->dev);
- pm_runtime_enable(sdev->dev);
- pm_runtime_idle(sdev->dev);
- }
+ regmap_update_bits(regmap, SYSCTRL0, RESET_BIT, RESET_BIT);
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
+ usleep_range(1, 2);
-static struct snd_soc_dai_driver imx8_dai[] = {
-{
- .name = "esai0",
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- },
-},
-{
- .name = "sai1",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-};
+ /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */
+ regmap_update_bits(regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT);
+ usleep_range(1, 2);
-static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev,
- const struct sof_dsp_power_state *target_state)
-{
- sdev->dsp_power_state = *target_state;
+ arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_res);
- return 0;
+ return smc_res.a0;
}
-/* i.MX8 ops */
-static const struct snd_sof_dsp_ops sof_imx8_ops = {
- /* probe and remove */
- .probe = imx8_probe,
- .remove = imx8_remove,
- /* DSP core boot */
- .run = imx8_run,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
+static int imx8ulp_probe(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ struct regmap *regmap;
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
+ common = sdev->pdata->hw_pdata;
- /* ipc */
- .send_msg = imx8_send_msg,
- .get_mailbox_offset = imx8_get_mailbox_offset,
- .get_window_offset = imx8_get_window_offset,
+ regmap = syscon_regmap_lookup_by_phandle(sdev->dev->of_node, "fsl,dsp-ctrl");
+ if (IS_ERR(regmap))
+ return dev_err_probe(sdev->dev, PTR_ERR(regmap),
+ "failed to fetch dsp ctrl regmap\n");
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
+ common->chip_pdata = regmap;
- .get_bar_index = imx8_get_bar_index,
+ return 0;
+}
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
+static struct snd_soc_dai_driver imx8_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("esai0", 1, 8),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32),
+};
- /* Debug information */
- .dbg_dump = imx8_dump,
- .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+static struct snd_soc_dai_driver imx8m_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai2", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai5", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai7", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY("micfil", 0, 0, 1, 8),
+};
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
+static struct snd_soc_dai_driver imx8ulp_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai5", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32),
+};
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
+static struct snd_sof_dsp_ops sof_imx8_ops;
- /* DAI drivers */
- .drv = imx8_dai,
- .num_drv = ARRAY_SIZE(imx8_dai),
+static int imx8_ops_init(struct snd_sof_dev *sdev)
+{
+ /* first copy from template */
+ memcpy(&sof_imx8_ops, &sof_imx_ops, sizeof(sof_imx_ops));
- /* ALSA HW info flags */
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ /* then set common imx8 ops */
+ sof_imx8_ops.dbg_dump = imx8_dump;
+ sof_imx8_ops.dsp_arch_ops = &sof_xtensa_arch_ops;
+ sof_imx8_ops.debugfs_add_region_item =
+ snd_sof_debugfs_add_region_item_iomem;
- /* PM */
- .runtime_suspend = imx8_dsp_runtime_suspend,
- .runtime_resume = imx8_dsp_runtime_resume,
+ /* ... and finally set DAI driver */
+ sof_imx8_ops.drv = get_chip_info(sdev)->drv;
+ sof_imx8_ops.num_drv = get_chip_info(sdev)->num_drv;
- .suspend = imx8_dsp_suspend,
- .resume = imx8_dsp_resume,
+ return 0;
+}
- .set_power_state = imx8_dsp_set_power_state,
+static const struct imx_chip_ops imx8_chip_ops = {
+ .probe = imx8_probe,
+ .core_kick = imx8_run,
};
-/* i.MX8X ops */
-static const struct snd_sof_dsp_ops sof_imx8x_ops = {
- /* probe and remove */
- .probe = imx8_probe,
- .remove = imx8_remove,
- /* DSP core boot */
- .run = imx8x_run,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
-
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
-
- /* ipc */
- .send_msg = imx8_send_msg,
- .get_mailbox_offset = imx8_get_mailbox_offset,
- .get_window_offset = imx8_get_window_offset,
-
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
+static const struct imx_chip_ops imx8x_chip_ops = {
+ .probe = imx8_probe,
+ .core_kick = imx8x_run,
+};
- .get_bar_index = imx8_get_bar_index,
+static const struct imx_chip_ops imx8m_chip_ops = {
+ .probe = imx8m_probe,
+ .core_kick = imx8m_run,
+ .core_reset = imx8m_reset,
+};
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
+static const struct imx_chip_ops imx8ulp_chip_ops = {
+ .probe = imx8ulp_probe,
+ .core_kick = imx8ulp_run,
+ .core_reset = imx8ulp_reset,
+};
- /* Debug information */
- .dbg_dump = imx8_dump,
- .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+static struct imx_memory_info imx8_memory_regions[] = {
+ { .name = "iram", .reserved = false },
+ { .name = "sram", .reserved = true },
+ { }
+};
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
+static struct imx_memory_info imx8m_memory_regions[] = {
+ { .name = "iram", .reserved = false },
+ { .name = "sram", .reserved = true },
+ { }
+};
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
+static struct imx_memory_info imx8ulp_memory_regions[] = {
+ { .name = "iram", .reserved = false },
+ { .name = "sram", .reserved = true },
+ { }
+};
- /* DAI drivers */
+static const struct imx_chip_info imx8_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .memory = imx8_memory_regions,
.drv = imx8_dai,
.num_drv = ARRAY_SIZE(imx8_dai),
+ .ops = &imx8_chip_ops,
+};
- /* PM */
- .runtime_suspend = imx8_dsp_runtime_suspend,
- .runtime_resume = imx8_dsp_runtime_resume,
-
- .suspend = imx8_dsp_suspend,
- .resume = imx8_dsp_resume,
+static const struct imx_chip_info imx8x_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .memory = imx8_memory_regions,
+ .drv = imx8_dai,
+ .num_drv = ARRAY_SIZE(imx8_dai),
+ .ops = &imx8x_chip_ops,
+};
- .set_power_state = imx8_dsp_set_power_state,
+static const struct imx_chip_info imx8m_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .memory = imx8m_memory_regions,
+ .drv = imx8m_dai,
+ .num_drv = ARRAY_SIZE(imx8m_dai),
+ .ops = &imx8m_chip_ops,
+};
- /* ALSA HW info flags */
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
+static const struct imx_chip_info imx8ulp_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .has_dma_reserved = true,
+ .memory = imx8ulp_memory_regions,
+ .drv = imx8ulp_dai,
+ .num_drv = ARRAY_SIZE(imx8ulp_dai),
+ .ops = &imx8ulp_chip_ops,
};
static struct snd_sof_of_mach sof_imx8_machs[] = {
@@ -630,47 +406,46 @@ static struct snd_sof_of_mach sof_imx8_machs[] = {
.sof_tplg_filename = "sof-imx8-cs42888.tplg",
.drv_name = "asoc-audio-graph-card2",
},
-
- {}
-};
-
-static struct sof_dev_desc sof_of_imx8qxp_desc = {
- .of_machines = sof_imx8_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
+ {
+ .compatible = "fsl,imx8mp-evk",
+ .sof_tplg_filename = "sof-imx8mp-wm8960.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
+ {
+ .compatible = "fsl,imx8mp-evk-revb4",
+ .sof_tplg_filename = "sof-imx8mp-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8x.ri",
+ {
+ .compatible = "fsl,imx8ulp-evk",
+ .sof_tplg_filename = "sof-imx8ulp-btsco.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8x_ops,
+ {}
};
-static struct sof_dev_desc sof_of_imx8qm_desc = {
- .of_machines = sof_imx8_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
+IMX_SOF_DEV_DESC(imx8, sof_imx8_machs, &imx8_chip_info, &sof_imx8_ops, imx8_ops_init);
+IMX_SOF_DEV_DESC(imx8x, sof_imx8_machs, &imx8x_chip_info, &sof_imx8_ops, imx8_ops_init);
+IMX_SOF_DEV_DESC(imx8m, sof_imx8_machs, &imx8m_chip_info, &sof_imx8_ops, imx8_ops_init);
+IMX_SOF_DEV_DESC(imx8ulp, sof_imx8_machs, &imx8ulp_chip_info, &sof_imx8_ops, imx8_ops_init);
+
+static const struct of_device_id sof_of_imx8_ids[] = {
+ {
+ .compatible = "fsl,imx8qxp-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8x),
},
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
+ {
+ .compatible = "fsl,imx8qm-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8),
},
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8.ri",
+ {
+ .compatible = "fsl,imx8mp-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8m),
+ },
+ {
+ .compatible = "fsl,imx8ulp-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8ulp),
},
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8_ops,
-};
-
-static const struct of_device_id sof_of_imx8_ids[] = {
- { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc},
- { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc},
{ }
};
MODULE_DEVICE_TABLE(of, sof_of_imx8_ids);
diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c
deleted file mode 100644
index 3cabdebac558..000000000000
--- a/sound/soc/sof/imx/imx8m.c
+++ /dev/null
@@ -1,567 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-//
-// Copyright 2020 NXP
-//
-// Author: Daniel Baluta <daniel.baluta@nxp.com>
-//
-// Hardware interface for audio DSP on i.MX8M
-
-#include <linux/bits.h>
-#include <linux/firmware.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/regmap.h>
-
-#include <linux/module.h>
-#include <sound/sof.h>
-#include <sound/sof/xtensa.h>
-#include <linux/firmware/imx/dsp.h>
-
-#include "../ops.h"
-#include "../sof-of-dev.h"
-#include "imx-common.h"
-
-#define MBOX_OFFSET 0x800000
-#define MBOX_SIZE 0x1000
-
-/* DAP registers */
-#define IMX8M_DAP_DEBUG 0x28800000
-#define IMX8M_DAP_DEBUG_SIZE (64 * 1024)
-#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020)
-#define IMX8M_PWRCTL_CORERESET BIT(16)
-
-/* DSP audio mix registers */
-#define AudioDSP_REG0 0x100
-#define AudioDSP_REG1 0x104
-#define AudioDSP_REG2 0x108
-#define AudioDSP_REG3 0x10c
-
-#define AudioDSP_REG2_RUNSTALL BIT(5)
-
-struct imx8m_priv {
- struct device *dev;
- struct snd_sof_dev *sdev;
-
- /* DSP IPC handler */
- struct imx_dsp_ipc *dsp_ipc;
- struct platform_device *ipc_dev;
-
- struct clk_bulk_data *clks;
- int clk_num;
-
- void __iomem *dap;
- struct regmap *regmap;
-};
-
-static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev)
-{
- return MBOX_OFFSET;
-}
-
-static int imx8m_get_window_offset(struct snd_sof_dev *sdev, u32 id)
-{
- return MBOX_OFFSET;
-}
-
-static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc)
-{
- struct imx8m_priv *priv = imx_dsp_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- snd_sof_ipc_process_reply(priv->sdev, 0);
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc)
-{
- struct imx8m_priv *priv = imx_dsp_get_data(ipc);
- u32 p; /* Panic code */
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
-
- /* Check to see if the message is a panic code (0x0dead***) */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
- snd_sof_dsp_panic(priv->sdev, p, true);
- else
- snd_sof_ipc_msgs_rx(priv->sdev);
-}
-
-static struct imx_dsp_ops imx8m_dsp_ops = {
- .handle_reply = imx8m_dsp_handle_reply,
- .handle_request = imx8m_dsp_handle_request,
-};
-
-static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
-{
- struct imx8m_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
- imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
-
- return 0;
-}
-
-/*
- * DSP control.
- */
-static int imx8m_run(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
-
- regmap_update_bits(priv->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0);
-
- return 0;
-}
-
-static int imx8m_reset(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
- u32 pwrctl;
-
- /* put DSP into reset and stall */
- pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL);
- pwrctl |= IMX8M_PWRCTL_CORERESET;
- writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL);
-
- /* keep reset asserted for 10 cycles */
- usleep_range(1, 2);
-
- regmap_update_bits(priv->regmap, AudioDSP_REG2,
- AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL);
-
- /* take the DSP out of reset and keep stalled for FW loading */
- pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL);
- pwrctl &= ~IMX8M_PWRCTL_CORERESET;
- writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL);
-
- return 0;
-}
-
-static int imx8m_probe(struct snd_sof_dev *sdev)
-{
- struct platform_device *pdev = to_platform_device(sdev->dev);
- struct device_node *np = pdev->dev.of_node;
- struct device_node *res_node;
- struct resource *mmio;
- struct imx8m_priv *priv;
- struct resource res;
- u32 base, size;
- int ret = 0;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- sdev->num_cores = 1;
- sdev->pdata->hw_pdata = priv;
- priv->dev = sdev->dev;
- priv->sdev = sdev;
-
- priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
- PLATFORM_DEVID_NONE,
- pdev, sizeof(*pdev));
- if (IS_ERR(priv->ipc_dev))
- return PTR_ERR(priv->ipc_dev);
-
- priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
- if (!priv->dsp_ipc) {
- /* DSP IPC driver not probed yet, try later */
- ret = -EPROBE_DEFER;
- dev_err(sdev->dev, "Failed to get drvdata\n");
- goto exit_pdev_unregister;
- }
-
- imx_dsp_set_data(priv->dsp_ipc, priv);
- priv->dsp_ipc->ops = &imx8m_dsp_ops;
-
- /* DSP base */
- mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mmio) {
- base = mmio->start;
- size = resource_size(mmio);
- } else {
- dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
- ret = -EINVAL;
- goto exit_pdev_unregister;
- }
-
- priv->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE);
- if (!priv->dap) {
- dev_err(sdev->dev, "error: failed to map DAP debug memory area");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
- if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
- dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
- base, size);
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
- sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
-
- res_node = of_parse_phandle(np, "memory-region", 0);
- if (!res_node) {
- dev_err(&pdev->dev, "failed to get memory region node\n");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
-
- ret = of_address_to_resource(res_node, 0, &res);
- of_node_put(res_node);
- if (ret) {
- dev_err(&pdev->dev, "failed to get reserved region address\n");
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- resource_size(&res));
- if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
- dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
- base, size);
- ret = -ENOMEM;
- goto exit_pdev_unregister;
- }
- sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
-
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
-
- priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl");
- if (IS_ERR(priv->regmap)) {
- dev_err(sdev->dev, "cannot find dsp-ctrl registers");
- ret = PTR_ERR(priv->regmap);
- goto exit_pdev_unregister;
- }
-
- ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
- priv->clk_num = ret;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
-
- return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
- return ret;
-}
-
-static void imx8m_remove(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = sdev->pdata->hw_pdata;
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-}
-
-/* on i.MX8 there is 1 to 1 match between type and BAR idx */
-static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- /* Only IRAM and SRAM bars are valid */
- switch (type) {
- case SOF_FW_BLK_TYPE_IRAM:
- case SOF_FW_BLK_TYPE_SRAM:
- return type;
- default:
- return -EINVAL;
- }
-}
-
-static struct snd_soc_dai_driver imx8m_dai[] = {
-{
- .name = "sai1",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "sai2",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "sai3",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "sai5",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "sai6",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "sai7",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "micfil",
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- },
-},
-};
-
-static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev,
- const struct sof_dsp_power_state *target_state)
-{
- sdev->dsp_power_state = *target_state;
-
- return 0;
-}
-
-static int imx8m_resume(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
- int ret;
- int i;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_request_channel(priv->dsp_ipc, i);
-
- return 0;
-}
-
-static void imx8m_suspend(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
- int i;
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
-}
-
-static int imx8m_dsp_runtime_resume(struct snd_sof_dev *sdev)
-{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
-
- ret = imx8m_resume(sdev);
- if (ret < 0)
- return ret;
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8m_dsp_runtime_suspend(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D3,
- };
-
- imx8m_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8m_dsp_resume(struct snd_sof_dev *sdev)
-{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
-
- ret = imx8m_resume(sdev);
- if (ret < 0)
- return ret;
-
- if (pm_runtime_suspended(sdev->dev)) {
- pm_runtime_disable(sdev->dev);
- pm_runtime_set_active(sdev->dev);
- pm_runtime_mark_last_busy(sdev->dev);
- pm_runtime_enable(sdev->dev);
- pm_runtime_idle(sdev->dev);
- }
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = target_state,
- };
-
- if (!pm_runtime_suspended(sdev->dev))
- imx8m_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-/* i.MX8 ops */
-static const struct snd_sof_dsp_ops sof_imx8m_ops = {
- /* probe and remove */
- .probe = imx8m_probe,
- .remove = imx8m_remove,
- /* DSP core boot */
- .run = imx8m_run,
- .reset = imx8m_reset,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
-
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
-
- /* ipc */
- .send_msg = imx8m_send_msg,
- .get_mailbox_offset = imx8m_get_mailbox_offset,
- .get_window_offset = imx8m_get_window_offset,
-
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
-
- .get_bar_index = imx8m_get_bar_index,
-
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
-
- /* Debug information */
- .dbg_dump = imx8_dump,
- .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
-
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
-
- /* DAI drivers */
- .drv = imx8m_dai,
- .num_drv = ARRAY_SIZE(imx8m_dai),
-
- .suspend = imx8m_dsp_suspend,
- .resume = imx8m_dsp_resume,
-
- .runtime_suspend = imx8m_dsp_runtime_suspend,
- .runtime_resume = imx8m_dsp_runtime_resume,
-
- .set_power_state = imx8m_dsp_set_power_state,
-
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
-};
-
-static struct snd_sof_of_mach sof_imx8mp_machs[] = {
- {
- .compatible = "fsl,imx8mp-evk-revb4",
- .sof_tplg_filename = "sof-imx8mp-wm8962.tplg",
- .drv_name = "asoc-audio-graph-card2",
- },
- {
- .compatible = "fsl,imx8mp-evk",
- .sof_tplg_filename = "sof-imx8mp-wm8960.tplg",
- .drv_name = "asoc-audio-graph-card2",
- },
- {}
-};
-
-static struct sof_dev_desc sof_of_imx8mp_desc = {
- .of_machines = sof_imx8mp_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
- },
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
- },
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8m.ri",
- },
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8m_ops,
-};
-
-static const struct of_device_id sof_of_imx8m_ids[] = {
- { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc},
- { }
-};
-MODULE_DEVICE_TABLE(of, sof_of_imx8m_ids);
-
-/* DT driver definition */
-static struct platform_driver snd_sof_of_imx8m_driver = {
- .probe = sof_of_probe,
- .remove = sof_of_remove,
- .driver = {
- .name = "sof-audio-of-imx8m",
- .pm = &sof_of_pm,
- .of_match_table = sof_of_imx8m_ids,
- },
-};
-module_platform_driver(snd_sof_of_imx8m_driver);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("SOF support for IMX8M platforms");
-MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c
deleted file mode 100644
index 0704da27e69d..000000000000
--- a/sound/soc/sof/imx/imx8ulp.c
+++ /dev/null
@@ -1,520 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-//
-// Copyright 2021-2022 NXP
-//
-// Author: Peng Zhang <peng.zhang_8@nxp.com>
-//
-// Hardware interface for audio DSP on i.MX8ULP
-
-#include <linux/arm-smccc.h>
-#include <linux/clk.h>
-#include <linux/firmware.h>
-#include <linux/firmware/imx/dsp.h>
-#include <linux/firmware/imx/ipc.h>
-#include <linux/firmware/imx/svc/misc.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/of_reserved_mem.h>
-
-#include <sound/sof.h>
-#include <sound/sof/xtensa.h>
-
-#include "../ops.h"
-#include "../sof-of-dev.h"
-#include "imx-common.h"
-
-#define FSL_SIP_HIFI_XRDC 0xc200000e
-
-/* SIM Domain register */
-#define SYSCTRL0 0x8
-#define EXECUTE_BIT BIT(13)
-#define RESET_BIT BIT(16)
-#define HIFI4_CLK_BIT BIT(17)
-#define PB_CLK_BIT BIT(18)
-#define PLAT_CLK_BIT BIT(19)
-#define DEBUG_LOGIC_BIT BIT(25)
-
-#define MBOX_OFFSET 0x800000
-#define MBOX_SIZE 0x1000
-
-struct imx8ulp_priv {
- struct device *dev;
- struct snd_sof_dev *sdev;
-
- /* DSP IPC handler */
- struct imx_dsp_ipc *dsp_ipc;
- struct platform_device *ipc_dev;
-
- struct regmap *regmap;
- struct clk_bulk_data *clks;
- int clk_num;
-};
-
-static void imx8ulp_sim_lpav_start(struct imx8ulp_priv *priv)
-{
- /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */
- regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, 0);
-
- /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/
- regmap_update_bits(priv->regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0);
-
- /* Stall HIFI4 DSP Execution: 1 stall, 0 run */
- regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, 0);
-}
-
-static int imx8ulp_get_mailbox_offset(struct snd_sof_dev *sdev)
-{
- return MBOX_OFFSET;
-}
-
-static int imx8ulp_get_window_offset(struct snd_sof_dev *sdev, u32 id)
-{
- return MBOX_OFFSET;
-}
-
-static void imx8ulp_dsp_handle_reply(struct imx_dsp_ipc *ipc)
-{
- struct imx8ulp_priv *priv = imx_dsp_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
-
- snd_sof_ipc_process_reply(priv->sdev, 0);
-
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void imx8ulp_dsp_handle_request(struct imx_dsp_ipc *ipc)
-{
- struct imx8ulp_priv *priv = imx_dsp_get_data(ipc);
- u32 p; /* panic code */
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
-
- /* Check to see if the message is a panic code (0x0dead***) */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
- snd_sof_dsp_panic(priv->sdev, p, true);
- else
- snd_sof_ipc_msgs_rx(priv->sdev);
-}
-
-static struct imx_dsp_ops dsp_ops = {
- .handle_reply = imx8ulp_dsp_handle_reply,
- .handle_request = imx8ulp_dsp_handle_request,
-};
-
-static int imx8ulp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
- imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
-
- return 0;
-}
-
-static int imx8ulp_run(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- imx8ulp_sim_lpav_start(priv);
-
- return 0;
-}
-
-static int imx8ulp_reset(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
- struct arm_smccc_res smc_resource;
-
- /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */
- regmap_update_bits(priv->regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT);
-
- /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */
- regmap_update_bits(priv->regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT);
-
- /* HiFi4 Clock Enable: 1 enabled, 0 disabled */
- regmap_update_bits(priv->regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT);
-
- regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, RESET_BIT);
- usleep_range(1, 2);
-
- /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */
- regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT);
- usleep_range(1, 2);
-
- arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_resource);
-
- return 0;
-}
-
-static int imx8ulp_probe(struct snd_sof_dev *sdev)
-{
- struct platform_device *pdev = to_platform_device(sdev->dev);
- struct device_node *np = pdev->dev.of_node;
- struct device_node *res_node;
- struct resource *mmio;
- struct imx8ulp_priv *priv;
- struct resource res;
- u32 base, size;
- int ret = 0;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- sdev->num_cores = 1;
- sdev->pdata->hw_pdata = priv;
- priv->dev = sdev->dev;
- priv->sdev = sdev;
-
- /* System integration module(SIM) control dsp configuration */
- priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl");
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
-
- priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
- PLATFORM_DEVID_NONE,
- pdev, sizeof(*pdev));
- if (IS_ERR(priv->ipc_dev))
- return PTR_ERR(priv->ipc_dev);
-
- priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
- if (!priv->dsp_ipc) {
- /* DSP IPC driver not probed yet, try later */
- ret = -EPROBE_DEFER;
- dev_err(sdev->dev, "Failed to get drvdata\n");
- goto exit_pdev_unregister;
- }
-
- imx_dsp_set_data(priv->dsp_ipc, priv);
- priv->dsp_ipc->ops = &dsp_ops;
-
- /* DSP base */
- mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mmio) {
- base = mmio->start;
- size = resource_size(mmio);
- } else {
- dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
- ret = -EINVAL;
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
- if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
- dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
- base, size);
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
- sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
-
- res_node = of_parse_phandle(np, "memory-reserved", 0);
- if (!res_node) {
- dev_err(&pdev->dev, "failed to get memory region node\n");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
-
- ret = of_address_to_resource(res_node, 0, &res);
- of_node_put(res_node);
- if (ret) {
- dev_err(&pdev->dev, "failed to get reserved region address\n");
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- resource_size(&res));
- if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
- dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
- base, size);
- ret = -ENOMEM;
- goto exit_pdev_unregister;
- }
- sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
-
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
-
- ret = of_reserved_mem_device_init(sdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to init reserved memory region %d\n", ret);
- goto exit_pdev_unregister;
- }
-
- ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
- priv->clk_num = ret;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
-
- return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
-
- return ret;
-}
-
-static void imx8ulp_remove(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-}
-
-/* on i.MX8 there is 1 to 1 match between type and BAR idx */
-static int imx8ulp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- return type;
-}
-
-static int imx8ulp_suspend(struct snd_sof_dev *sdev)
-{
- int i;
- struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata;
-
- /*Stall DSP, release in .run() */
- regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT);
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
-
- return 0;
-}
-
-static int imx8ulp_resume(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata;
- int i, ret;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_request_channel(priv->dsp_ipc, i);
-
- return 0;
-}
-
-static int imx8ulp_dsp_runtime_resume(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- .substate = 0,
- };
-
- imx8ulp_resume(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8ulp_dsp_runtime_suspend(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D3,
- .substate = 0,
- };
-
- imx8ulp_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8ulp_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = target_state,
- .substate = 0,
- };
-
- if (!pm_runtime_suspended(sdev->dev))
- imx8ulp_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8ulp_dsp_resume(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- .substate = 0,
- };
-
- imx8ulp_resume(sdev);
-
- if (pm_runtime_suspended(sdev->dev)) {
- pm_runtime_disable(sdev->dev);
- pm_runtime_set_active(sdev->dev);
- pm_runtime_mark_last_busy(sdev->dev);
- pm_runtime_enable(sdev->dev);
- pm_runtime_idle(sdev->dev);
- }
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static struct snd_soc_dai_driver imx8ulp_dai[] = {
- {
- .name = "sai5",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
- },
- {
- .name = "sai6",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
- },
-};
-
-static int imx8ulp_dsp_set_power_state(struct snd_sof_dev *sdev,
- const struct sof_dsp_power_state *target_state)
-{
- sdev->dsp_power_state = *target_state;
-
- return 0;
-}
-
-/* i.MX8 ops */
-static const struct snd_sof_dsp_ops sof_imx8ulp_ops = {
- /* probe and remove */
- .probe = imx8ulp_probe,
- .remove = imx8ulp_remove,
- /* DSP core boot */
- .run = imx8ulp_run,
- .reset = imx8ulp_reset,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
-
- /* Module IO */
- .read64 = sof_io_read64,
-
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
-
- /* ipc */
- .send_msg = imx8ulp_send_msg,
- .get_mailbox_offset = imx8ulp_get_mailbox_offset,
- .get_window_offset = imx8ulp_get_window_offset,
-
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
-
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
-
- /* module loading */
- .get_bar_index = imx8ulp_get_bar_index,
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
-
- /* Debug information */
- .dbg_dump = imx8_dump,
-
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
-
- /* DAI drivers */
- .drv = imx8ulp_dai,
- .num_drv = ARRAY_SIZE(imx8ulp_dai),
-
- /* ALSA HW info flags */
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
-
- /* PM */
- .runtime_suspend = imx8ulp_dsp_runtime_suspend,
- .runtime_resume = imx8ulp_dsp_runtime_resume,
-
- .suspend = imx8ulp_dsp_suspend,
- .resume = imx8ulp_dsp_resume,
-
- .set_power_state = imx8ulp_dsp_set_power_state,
-};
-
-static struct snd_sof_of_mach sof_imx8ulp_machs[] = {
- {
- .compatible = "fsl,imx8ulp-evk",
- .sof_tplg_filename = "sof-imx8ulp-btsco.tplg",
- .drv_name = "asoc-audio-graph-card2",
- },
- {}
-};
-
-static struct sof_dev_desc sof_of_imx8ulp_desc = {
- .of_machines = sof_imx8ulp_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
- },
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
- },
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8ulp.ri",
- },
- .nocodec_tplg_filename = "sof-imx8ulp-nocodec.tplg",
- .ops = &sof_imx8ulp_ops,
-};
-
-static const struct of_device_id sof_of_imx8ulp_ids[] = {
- { .compatible = "fsl,imx8ulp-dsp", .data = &sof_of_imx8ulp_desc},
- { }
-};
-MODULE_DEVICE_TABLE(of, sof_of_imx8ulp_ids);
-
-/* DT driver definition */
-static struct platform_driver snd_sof_of_imx8ulp_driver = {
- .probe = sof_of_probe,
- .remove = sof_of_remove,
- .driver = {
- .name = "sof-audio-of-imx8ulp",
- .pm = &sof_of_pm,
- .of_match_table = sof_of_imx8ulp_ids,
- },
-};
-module_platform_driver(snd_sof_of_imx8ulp_driver);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("SOF support for IMX8ULP platforms");
-MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
diff --git a/sound/soc/sof/imx/imx9.c b/sound/soc/sof/imx/imx9.c
new file mode 100644
index 000000000000..598675d4350a
--- /dev/null
+++ b/sound/soc/sof/imx/imx9.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/arm-smccc.h>
+
+#include "imx-common.h"
+
+#define IMX_SIP_SRC 0xC2000005
+#define IMX_SIP_SRC_M_RESET_ADDR_SET 0x03
+
+#define IMX95_CPU_VEC_FLAGS_BOOT BIT(29)
+
+#define IMX_SIP_LMM 0xC200000F
+#define IMX_SIP_LMM_BOOT 0x0
+#define IMX_SIP_LMM_SHUTDOWN 0x1
+
+#define IMX95_M7_LM_ID 0x1
+
+static struct snd_soc_dai_driver imx95_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32),
+};
+
+static struct snd_sof_dsp_ops sof_imx9_ops;
+
+static int imx95_ops_init(struct snd_sof_dev *sdev)
+{
+ /* first copy from template */
+ memcpy(&sof_imx9_ops, &sof_imx_ops, sizeof(sof_imx_ops));
+
+ /* ... and finally set DAI driver */
+ sof_imx9_ops.drv = get_chip_info(sdev)->drv;
+ sof_imx9_ops.num_drv = get_chip_info(sdev)->num_drv;
+
+ return 0;
+}
+
+static int imx95_chip_probe(struct snd_sof_dev *sdev)
+{
+ struct arm_smccc_res smc_res;
+ struct platform_device *pdev;
+ struct resource *res;
+
+ pdev = to_platform_device(sdev->dev);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
+ if (!res)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to fetch SRAM region\n");
+
+ /* set core boot reset address */
+ arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M_RESET_ADDR_SET, res->start,
+ IMX95_CPU_VEC_FLAGS_BOOT, 0, 0, 0, 0, &smc_res);
+
+ return smc_res.a0;
+}
+
+static int imx95_core_kick(struct snd_sof_dev *sdev)
+{
+ struct arm_smccc_res smc_res;
+
+ arm_smccc_smc(IMX_SIP_LMM, IMX_SIP_LMM_BOOT,
+ IMX95_M7_LM_ID, 0, 0, 0, 0, 0, &smc_res);
+
+ return smc_res.a0;
+}
+
+static int imx95_core_shutdown(struct snd_sof_dev *sdev)
+{
+ struct arm_smccc_res smc_res;
+
+ arm_smccc_smc(IMX_SIP_LMM, IMX_SIP_LMM_SHUTDOWN,
+ IMX95_M7_LM_ID, 0, 0, 0, 0, 0, &smc_res);
+
+ return smc_res.a0;
+}
+
+static const struct imx_chip_ops imx95_chip_ops = {
+ .probe = imx95_chip_probe,
+ .core_kick = imx95_core_kick,
+ .core_shutdown = imx95_core_shutdown,
+};
+
+static struct imx_memory_info imx95_memory_regions[] = {
+ { .name = "sram", .reserved = false },
+ { }
+};
+
+static const struct imx_chip_info imx95_chip_info = {
+ .ipc_info = {
+ .boot_mbox_offset = 0x6001000,
+ .window_offset = 0x6000000,
+ },
+ .has_dma_reserved = true,
+ .memory = imx95_memory_regions,
+ .drv = imx95_dai,
+ .num_drv = ARRAY_SIZE(imx95_dai),
+ .ops = &imx95_chip_ops,
+};
+
+static struct snd_sof_of_mach sof_imx9_machs[] = {
+ {
+ .compatible = "fsl,imx95-19x19-evk",
+ .sof_tplg_filename = "sof-imx95-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
+ },
+ {
+ }
+};
+
+IMX_SOF_DEV_DESC(imx95, sof_imx9_machs, &imx95_chip_info, &sof_imx9_ops, imx95_ops_init);
+
+static const struct of_device_id sof_of_imx9_ids[] = {
+ {
+ .compatible = "fsl,imx95-cm7-sof",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx95),
+ },
+ {
+ },
+};
+MODULE_DEVICE_TABLE(of, sof_of_imx9_ids);
+
+static struct platform_driver snd_sof_of_imx9_driver = {
+ .probe = sof_of_probe,
+ .remove = sof_of_remove,
+ .driver = {
+ .name = "sof-audio-of-imx9",
+ .pm = &sof_of_pm,
+ .of_match_table = sof_of_imx9_ids,
+ },
+};
+module_platform_driver(snd_sof_of_imx9_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF driver for imx9 platforms");
+MODULE_AUTHOR("Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>");