[PATCH 00/21] ASoC: SOF: Platform updates for AMD and Mediatek
From: Daniel Baluta daniel.baluta@nxp.com
This patchseries adds Renoir ACP HW support and Mediatek MT8195 platform.
Notes: - I first send the meditatek support in a previous emails but it failed to apply because there are some dependencies on AMD patches related to DAI ids.
Ajit Kumar Pandey (12): ASoC: SOF: amd: Add Renoir ACP HW support ASoC: SOF: amd: Add helper callbacks for ACP's DMA configuration ASoC: SOF: amd: Add fw loader and renoir dsp ops to load firmware ASoC: SOF: amd: Add IPC support for ACP IP block ASoC: SOF: amd: Add dai driver dsp ops callback for Renoir ASoC: SOF: amd: Add PCM stream callback for Renoir dai's ASoC: amd: Add module to determine ACP configuration ASoC: SOF: amd: Add machine driver dsp ops for Renoir platform ASoC: SOF: amd: Add Renoir PCI driver interface ASoC: amd: acp-config: Remove legacy acpi based machine struct ASoC: SOF: topology: Add support for AMD ACP DAIs ASoC: SOF: amd: Add support for SOF firmware authentication
V sujith kumar Reddy (1): ASoC: SOF: amd: Add trace logger support
YC Hung (8): ASoC: SOF: mediatek: Add mt8195 hardware support ASoC: SOF: tokens: add token for Mediatek AFE ASoC: SOF: topology: Add support for Mediatek AFE DAI ASoC: SOF: mediatek: Add fw loader and mt8195 dsp ops to load firmware ASoC: SOF: Add mt8195 device descriptor ASoC: SOF: mediatek: Add dai driver dsp ops callback for mt8195 ASoC: SOF: mediatek: Add mt8195 dsp clock support ASoC: SOF: mediatek: Add DSP system PM callback for mt8195
include/sound/sof/dai-amd.h | 21 + include/sound/sof/dai-mediatek.h | 23 + include/sound/sof/dai.h | 10 + include/uapi/sound/sof/tokens.h | 5 + sound/soc/amd/Kconfig | 6 + sound/soc/amd/Makefile | 2 + sound/soc/amd/acp-config.c | 71 +++ sound/soc/amd/mach-config.h | 28 ++ sound/soc/sof/Kconfig | 4 +- sound/soc/sof/Makefile | 2 + sound/soc/sof/amd/Kconfig | 33 ++ sound/soc/sof/amd/Makefile | 11 + sound/soc/sof/amd/acp-dsp-offset.h | 78 +++ sound/soc/sof/amd/acp-ipc.c | 187 ++++++++ sound/soc/sof/amd/acp-loader.c | 199 ++++++++ sound/soc/sof/amd/acp-pcm.c | 82 ++++ sound/soc/sof/amd/acp-stream.c | 181 +++++++ sound/soc/sof/amd/acp-trace.c | 84 ++++ sound/soc/sof/amd/acp.c | 446 ++++++++++++++++++ sound/soc/sof/amd/acp.h | 226 +++++++++ sound/soc/sof/amd/pci-rn.c | 165 +++++++ sound/soc/sof/amd/renoir.c | 185 ++++++++ sound/soc/sof/mediatek/Kconfig | 33 ++ sound/soc/sof/mediatek/Makefile | 2 + sound/soc/sof/mediatek/adsp_helper.h | 49 ++ sound/soc/sof/mediatek/mediatek-ops.h | 8 + sound/soc/sof/mediatek/mt8195/Makefile | 3 + sound/soc/sof/mediatek/mt8195/mt8195-clk.c | 158 +++++++ sound/soc/sof/mediatek/mt8195/mt8195-clk.h | 28 ++ sound/soc/sof/mediatek/mt8195/mt8195-loader.c | 56 +++ sound/soc/sof/mediatek/mt8195/mt8195.c | 437 +++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.h | 158 +++++++ sound/soc/sof/pcm.c | 48 ++ sound/soc/sof/sof-of-dev.c | 13 + sound/soc/sof/topology.c | 168 +++++++ 35 files changed, 3209 insertions(+), 1 deletion(-) create mode 100644 include/sound/sof/dai-amd.h create mode 100644 include/sound/sof/dai-mediatek.h create mode 100644 sound/soc/amd/acp-config.c create mode 100644 sound/soc/amd/mach-config.h create mode 100644 sound/soc/sof/amd/Kconfig create mode 100644 sound/soc/sof/amd/Makefile create mode 100644 sound/soc/sof/amd/acp-dsp-offset.h create mode 100644 sound/soc/sof/amd/acp-ipc.c create mode 100644 sound/soc/sof/amd/acp-loader.c create mode 100644 sound/soc/sof/amd/acp-pcm.c create mode 100644 sound/soc/sof/amd/acp-stream.c create mode 100644 sound/soc/sof/amd/acp-trace.c create mode 100644 sound/soc/sof/amd/acp.c create mode 100644 sound/soc/sof/amd/acp.h create mode 100644 sound/soc/sof/amd/pci-rn.c create mode 100644 sound/soc/sof/amd/renoir.c create mode 100644 sound/soc/sof/mediatek/Kconfig create mode 100644 sound/soc/sof/mediatek/Makefile create mode 100644 sound/soc/sof/mediatek/adsp_helper.h create mode 100644 sound/soc/sof/mediatek/mediatek-ops.h create mode 100644 sound/soc/sof/mediatek/mt8195/Makefile create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-clk.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-clk.h create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-loader.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195.h
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
This patch initializes ACP HW block to support SOF on AMD Renoir platform.
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/amd/Kconfig | 30 ++++++++ sound/soc/sof/amd/Makefile | 11 +++ sound/soc/sof/amd/acp-dsp-offset.h | 20 +++++ sound/soc/sof/amd/acp.c | 118 +++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 36 +++++++++ sound/soc/sof/amd/renoir.c | 34 +++++++++ 8 files changed, 251 insertions(+) create mode 100644 sound/soc/sof/amd/Kconfig create mode 100644 sound/soc/sof/amd/Makefile create mode 100644 sound/soc/sof/amd/acp-dsp-offset.h create mode 100644 sound/soc/sof/amd/acp.c create mode 100644 sound/soc/sof/amd/acp.h create mode 100644 sound/soc/sof/amd/renoir.c
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 041c54639c4d..68571bf2585e 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -223,6 +223,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe.
+source "sound/soc/sof/amd/Kconfig" source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 06e5f49f7ee8..011abfa0fd82 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -22,4 +22,5 @@ obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ +obj-$(CONFIG_SND_SOC_SOF_AMD_TOPLEVEL) += amd/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig new file mode 100644 index 000000000000..400dd5a24ae6 --- /dev/null +++ b/sound/soc/sof/amd/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + +config SND_SOC_SOF_AMD_TOPLEVEL + tristate "SOF support for AMD audio DSPs" + depends on X86 || COMPILE_TEST + help + This adds support for Sound Open Firmware for AMD platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_AMD_TOPLEVEL + +config SND_SOC_SOF_AMD_COMMON + tristate + select SND_SOC_SOF + help + This option is not user-selectable but automatically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_AMD_RENOIR + tristate "SOF support for RENOIR" + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support on AMD Renoir platform + +endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile new file mode 100644 index 000000000000..ac2ecd21be5f --- /dev/null +++ b/sound/soc/sof/amd/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + +snd-sof-amd-acp-objs := acp.o +snd-sof-amd-renoir-objs := renoir.o + +obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o +obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h new file mode 100644 index 000000000000..2cc2a9a842c5 --- /dev/null +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + */ + +#ifndef _ACP_DSP_IP_OFFSET_H +#define _ACP_DSP_IP_OFFSET_H + +#define ACP_SOFT_RESET 0x1000 + +/* Registers from ACP_PGFSM block */ +#define ACP_PGFSM_CONTROL 0x141C +#define ACP_PGFSM_STATUS 0x1420 + +#endif diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c new file mode 100644 index 000000000000..687a67419335 --- /dev/null +++ b/sound/soc/sof/amd/acp.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vijendar Mukunda Vijendar.Mukunda@amd.com +// Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* + * Hardware interface for generic AMD ACP processor + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +static int acp_power_on(struct snd_sof_dev *sdev) +{ + unsigned int val; + int ret; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS); + + if (val == ACP_POWERED_ON) + return 0; + + if (val & ACP_PGFSM_STATUS_MASK) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_PGFSM_CONTROL, + ACP_PGFSM_CNTL_POWER_ON_MASK); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS, val, !val, + ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n"); + + return ret; +} + +static int acp_reset(struct snd_sof_dev *sdev) +{ + unsigned int val; + int ret; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_ASSERT_RESET); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val, + val & ACP_SOFT_RESET_DONE_MASK, + ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "timeout asserting reset\n"); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_RELEASE_RESET); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val, !val, + ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "timeout in releasing reset\n"); + + return ret; +} + +static int acp_init(struct snd_sof_dev *sdev) +{ + int ret; + + /* power on */ + ret = acp_power_on(sdev); + if (ret) { + dev_err(sdev->dev, "ACP power on failed\n"); + return ret; + } + /* Reset */ + return acp_reset(sdev); +} + +int amd_sof_acp_probe(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct acp_dev_data *adata; + unsigned int addr; + + adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), + GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->dev = sdev; + addr = pci_resource_start(pci, ACP_DSP_BAR); + sdev->bar[ACP_DSP_BAR] = devm_ioremap(sdev->dev, addr, pci_resource_len(pci, ACP_DSP_BAR)); + if (!sdev->bar[ACP_DSP_BAR]) { + dev_err(sdev->dev, "ioremap error\n"); + return -ENXIO; + } + + pci_set_master(pci); + + sdev->pdata->hw_pdata = adata; + + return acp_init(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); + +int amd_sof_acp_remove(struct snd_sof_dev *sdev) +{ + return acp_reset(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON); + +MODULE_DESCRIPTION("AMD ACP sof driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h new file mode 100644 index 000000000000..c7ac8f9941d5 --- /dev/null +++ b/sound/soc/sof/amd/acp.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + */ + +#ifndef __SOF_AMD_ACP_H +#define __SOF_AMD_ACP_H + +#define ACP_DSP_BAR 0 + +#define ACP_REG_POLL_INTERVAL 500 +#define ACP_REG_POLL_TIMEOUT_US 2000 + +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_ASSERT_RESET 0x01 +#define ACP_RELEASE_RESET 0x00 +#define ACP_SOFT_RESET_DONE_MASK 0x00010001 + +/* Common device data struct for ACP devices */ +struct acp_dev_data { + struct snd_sof_dev *dev; +}; + +/* ACP device probe/remove */ +int amd_sof_acp_probe(struct snd_sof_dev *sdev); +int amd_sof_acp_remove(struct snd_sof_dev *sdev); + +extern const struct snd_sof_dsp_ops sof_renoir_ops; +#endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c new file mode 100644 index 000000000000..3d1dc6c2fa9b --- /dev/null +++ b/sound/soc/sof/amd/renoir.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* + * Hardware interface for Audio DSP on Renoir platform + */ + +#include <linux/platform_device.h> +#include <linux/module.h> + +#include "../ops.h" +#include "acp.h" + +/* AMD Renoir DSP ops */ +const struct snd_sof_dsp_ops sof_renoir_ops = { + /* probe and remove */ + .probe = amd_sof_acp_probe, + .remove = amd_sof_acp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, +}; +EXPORT_SYMBOL(sof_renoir_ops); + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("RENOIR SOF Driver"); +MODULE_LICENSE("Dual BSD/GPL");
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
ACP DMA is used for loading SOF firmware into DSP memory and data transfer from system memory to DSP memory. Add helper callbacks to initialize and configure ACP DMA block for fw loading.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/acp-dsp-offset.h | 47 ++++++ sound/soc/sof/amd/acp.c | 222 ++++++++++++++++++++++++++++- sound/soc/sof/amd/acp.h | 91 ++++++++++++ 3 files changed, 359 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 2cc2a9a842c5..bfb02390b414 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -11,10 +11,57 @@ #ifndef _ACP_DSP_IP_OFFSET_H #define _ACP_DSP_IP_OFFSET_H
+/* Registers from ACP_DMA_0 block */ +#define ACP_DMA_CNTL_0 0x00 +#define ACP_DMA_DSCR_STRT_IDX_0 0x20 +#define ACP_DMA_DSCR_CNT_0 0x40 +#define ACP_DMA_PRIO_0 0x60 +#define ACP_DMA_CUR_DSCR_0 0x80 +#define ACP_DMA_ERR_STS_0 0xC0 +#define ACP_DMA_DESC_BASE_ADDR 0xE0 +#define ACP_DMA_DESC_MAX_NUM_DSCR 0xE4 +#define ACP_DMA_CH_STS 0xE8 +#define ACP_DMA_CH_GROUP 0xEC +#define ACP_DMA_CH_RST_STS 0xF0 + +/* Registers from ACP_AXI2AXIATU block */ +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0xC08 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0xC0C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0xC10 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0xC14 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0xC18 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0xC1C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0xC28 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0xC2C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0xC30 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0xC34 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0xC38 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C +#define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACP_SOFT_RESET 0x1000
/* Registers from ACP_PGFSM block */ #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420
+/* Registers from ACP_INTR block */ +#define ACP_DSP_SW_INTR_CNTL 0x1814 +#define ACP_ERROR_STATUS 0x18C4 + +/* Registers from ACP_SHA block */ +#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70 +#define ACP_SHA_DMA_CMD 0x1CB0 +#define ACP_SHA_MSG_LENGTH 0x1CB4 +#define ACP_SHA_DMA_STRT_ADDR 0x1CB8 +#define ACP_SHA_DMA_DESTINATION_ADDR 0x1CBC +#define ACP_SHA_DMA_CMD_STS 0x1CC0 +#define ACP_SHA_DMA_ERR_STATUS 0x1CC4 +#define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 + +#define ACP_SCRATCH_REG_0 0x10000 + #endif diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 687a67419335..3778f781f16a 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,219 @@ #include "acp.h" #include "acp-dsp-offset.h"
+static void configure_acp_groupregisters(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + + /* Group Enable */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1, + ACP_SRAM_PTE_OFFSET | BIT(31)); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1, + PAGE_SIZE_4K_ENABLE); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID); +} + +static void init_dma_descriptor(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int addr; + + addr = ACP_SRAM_PTE_OFFSET + offsetof(struct scratch_reg_conf, dma_desc); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_BASE_ADDR, addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_MAX_NUM_DSCR, ACP_MAX_DESC_CNT); +} + +static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short idx, + struct dma_descriptor *dscr_info) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int offset; + + offset = ACP_SCRATCH_REG_0 + offsetof(struct scratch_reg_conf, dma_desc) + + idx * sizeof(struct dma_descriptor); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset, dscr_info->src_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset + 0x4, dscr_info->dest_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset + 0x8, dscr_info->tx_cnt.u32_all); +} + +static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch, + unsigned int idx, unsigned int dscr_count) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int val, status; + int ret; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), + ACP_DMA_CH_RST | ACP_DMA_CH_GRACEFUL_RST_EN); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_RST_STS, val, + val & (1 << ch), ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) { + status = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_ERROR_STATUS); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_ERR_STS_0 + ch * sizeof(u32)); + + dev_err(sdev->dev, "ACP_DMA_ERR_STS :0x%x ACP_ERROR_STATUS :0x%x\n", val, status); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, (ACP_DMA_CNTL_0 + ch * sizeof(u32)), 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_CNT_0 + ch * sizeof(u32), dscr_count); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_STRT_IDX_0 + ch * sizeof(u32), idx); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_PRIO_0 + ch * sizeof(u32), 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), ACP_DMA_CH_RUN); + + return ret; +} + +static int acpbus_dma_start(struct acp_dev_data *adata, unsigned int ch, + unsigned int dscr_count, struct dma_descriptor *dscr_info) +{ + struct snd_sof_dev *sdev = adata->dev; + int ret; + u16 dscr; + + if (!dscr_info || !dscr_count) + return -EINVAL; + + for (dscr = 0; dscr < dscr_count; dscr++) + configure_dma_descriptor(adata, dscr, dscr_info++); + + ret = config_dma_channel(adata, ch, 0, dscr_count); + if (ret < 0) + dev_err(sdev->dev, "config dma ch failed:%d\n", ret); + + return ret; +} + +int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, + unsigned int dest_addr, int dsp_data_size) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int desc_count, index; + int ret; + + for (desc_count = 0; desc_count < ACP_MAX_DESC && dsp_data_size >= 0; + desc_count++, dsp_data_size -= ACP_PAGE_SIZE) { + adata->dscr_info[desc_count].src_addr = src_addr + desc_count * ACP_PAGE_SIZE; + adata->dscr_info[desc_count].dest_addr = dest_addr + desc_count * ACP_PAGE_SIZE; + adata->dscr_info[desc_count].tx_cnt.bits.count = ACP_PAGE_SIZE; + if (dsp_data_size < ACP_PAGE_SIZE) + adata->dscr_info[desc_count].tx_cnt.bits.count = dsp_data_size; + } + + ret = acpbus_dma_start(adata, 0, desc_count, adata->dscr_info); + if (ret) + dev_err(sdev->dev, "acpbus_dma_start failed\n"); + + /* Clear descriptor array */ + for (index = 0; index < desc_count; index++) + memset(&adata->dscr_info[index], 0x00, sizeof(struct dma_descriptor)); + + return ret; +} + +int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, + unsigned int start_addr, unsigned int dest_addr, + unsigned int image_length) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int tx_count, fw_qualifier, val; + int ret; + + if (!image_addr) { + dev_err(sdev->dev, "SHA DMA image address is NULL\n"); + return -EINVAL; + } + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD); + if (val & ACP_SHA_RUN) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RESET); + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD_STS, + val, val & ACP_SHA_RESET, + ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "SHA DMA Failed to Reset\n"); + return ret; + } + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RUN); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_TRANSFER_BYTE_CNT, + tx_count, tx_count == image_length, + ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "SHA DMA Failed to Transfer Length %x\n", tx_count); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, DSP_FW_RUN_ENABLE); + + fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER); + if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) { + dev_err(sdev->dev, "PSP validation failed\n"); + return -EINVAL; + } + + return ret; +} + +int acp_dma_status(struct acp_dev_data *adata, unsigned char ch) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int val; + int ret = 0; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32)); + if (val & ACP_DMA_CH_RUN) { + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_STS, val, !val, + ACP_REG_POLL_INTERVAL, + ACP_DMA_COMPLETE_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "DMA_CHANNEL %d status timeout\n", ch); + } + + return ret; +} + +void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes) +{ + unsigned int reg_offset = offset + ACP_SCRATCH_REG_0; + int i, j; + + for (i = 0, j = 0; i < bytes; i = i + 4, j++) + dst[j] = snd_sof_dsp_read(sdev, ACP_DSP_BAR, reg_offset + i); +} + +void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes) +{ + unsigned int reg_offset = offset + ACP_SCRATCH_REG_0; + int i, j; + + for (i = 0, j = 0; i < bytes; i = i + 4, j++) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, reg_offset + i, src[j]); +} + +static int acp_memory_init(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + + snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_CNTL, + ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); + configure_acp_groupregisters(adata); + init_dma_descriptor(adata); + + return 0; +} + static int acp_power_on(struct snd_sof_dev *sdev) { unsigned int val; @@ -86,6 +299,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) struct pci_dev *pci = to_pci_dev(sdev->dev); struct acp_dev_data *adata; unsigned int addr; + int ret;
adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL); @@ -104,7 +318,13 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->pdata->hw_pdata = adata;
- return acp_init(sdev); + ret = acp_init(sdev); + if (ret < 0) + return ret; + + acp_memory_init(sdev); + + return 0; } EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index c7ac8f9941d5..ff01d0ef67ef 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -15,6 +15,7 @@
#define ACP_REG_POLL_INTERVAL 500 #define ACP_REG_POLL_TIMEOUT_US 2000 +#define ACP_DMA_COMPLETE_TIMEOUT_US 5000
#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 #define ACP_PGFSM_STATUS_MASK 0x03 @@ -23,11 +24,101 @@ #define ACP_RELEASE_RESET 0x00 #define ACP_SOFT_RESET_DONE_MASK 0x00010001
+#define ACP_DSP_INTR_EN_MASK 0x00000001 +#define ACP_SRAM_PTE_OFFSET 0x02050000 +#define PAGE_SIZE_4K_ENABLE 0x2 +#define ACP_PAGE_SIZE 0x1000 +#define ACP_DMA_CH_RUN 0x02 +#define ACP_MAX_DESC_CNT 0x02 +#define DSP_FW_RUN_ENABLE 0x01 +#define ACP_SHA_RUN 0x01 +#define ACP_SHA_RESET 0x02 +#define ACP_DMA_CH_RST 0x01 +#define ACP_DMA_CH_GRACEFUL_RST_EN 0x10 +#define ACP_ATU_CACHE_INVALID 0x01 +#define ACP_MAX_DESC 128 +#define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0 + +struct acp_atu_grp_pte { + u32 low; + u32 high; +}; + +union dma_tx_cnt { + struct { + unsigned int count : 19; + unsigned int reserved : 12; + unsigned ioc : 1; + } bitfields, bits; + unsigned int u32_all; + signed int i32_all; +}; + +struct dma_descriptor { + unsigned int src_addr; + unsigned int dest_addr; + union dma_tx_cnt tx_cnt; + unsigned int reserved; +}; + +/* Scratch memory structure for communication b/w host and dsp */ +struct scratch_ipc_conf { + /* DSP mailbox */ + u8 sof_out_box[512]; + /* Host mailbox */ + u8 sof_in_box[512]; + /* Debug memory */ + u8 sof_debug_box[1024]; + /* Exception memory*/ + u8 sof_except_box[1024]; + /* Stream buffer */ + u8 sof_stream_box[1024]; + /* Trace buffer */ + u8 sof_trace_box[1024]; + /* Host msg flag */ + u32 sof_host_msg_write; + /* Host ack flag*/ + u32 sof_host_ack_write; + /* DSP msg flag */ + u32 sof_dsp_msg_write; + /* Dsp ack flag */ + u32 sof_dsp_ack_write; +}; + +struct scratch_reg_conf { + struct scratch_ipc_conf info; + struct acp_atu_grp_pte grp1_pte[16]; + struct acp_atu_grp_pte grp2_pte[16]; + struct acp_atu_grp_pte grp3_pte[16]; + struct acp_atu_grp_pte grp4_pte[16]; + struct acp_atu_grp_pte grp5_pte[16]; + struct acp_atu_grp_pte grp6_pte[16]; + struct acp_atu_grp_pte grp7_pte[16]; + struct acp_atu_grp_pte grp8_pte[16]; + struct dma_descriptor dma_desc[64]; + unsigned int reg_offset[8]; + unsigned int buf_size[8]; + u8 acp_tx_fifo_buf[256]; + u8 acp_rx_fifo_buf[256]; + unsigned int reserve[]; +}; + /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + struct dma_descriptor dscr_info[ACP_MAX_DESC]; };
+void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); +void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes); + +int acp_dma_status(struct acp_dev_data *adata, unsigned char ch); +int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, + unsigned int dest_addr, int dsp_data_size); +int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, + unsigned int start_addr, unsigned int dest_addr, + unsigned int image_length); + /* ACP device probe/remove */ int amd_sof_acp_probe(struct snd_sof_dev *sdev); int amd_sof_acp_remove(struct snd_sof_dev *sdev);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add acp-loader module with ops callback to load and run firmware on ACP DSP block on Renoir platform.
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-dsp-offset.h | 3 + sound/soc/sof/amd/acp-loader.c | 199 +++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 27 ++++ sound/soc/sof/amd/renoir.c | 15 +++ 5 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/acp-loader.c
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index ac2ecd21be5f..031fb9493876 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
-snd-sof-amd-acp-objs := acp.o +snd-sof-amd-acp-objs := acp.o acp-loader.o snd-sof-amd-renoir-objs := renoir.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index bfb02390b414..f4bc7e9abafb 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -24,6 +24,9 @@ #define ACP_DMA_CH_GROUP 0xEC #define ACP_DMA_CH_RST_STS 0xF0
+/* Registers from ACP_DSP_0 block */ +#define ACP_DSP0_RUNSTALL 0x414 + /* Registers from ACP_AXI2AXIATU block */ #define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00 #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04 diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c new file mode 100644 index 000000000000..2dc15ae38155 --- /dev/null +++ b/sound/soc/sof/amd/acp-loader.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* + * Hardware interface for ACP DSP Firmware binaries loader + */ + +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include "../ops.h" +#include "acp-dsp-offset.h" +#include "acp.h" + +#define FW_BIN 0 +#define FW_DATA_BIN 1 + +#define FW_BIN_PTE_OFFSET 0x00 +#define FW_DATA_BIN_PTE_OFFSET 0x08 + +#define ACP_DSP_RUN 0x00 + +int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size) +{ + switch (blk_type) { + case SOF_FW_BLK_TYPE_SRAM: + offset = offset - ACP_SCRATCH_MEMORY_ADDRESS; + memcpy_from_scratch(sdev, offset, dest, size); + break; + default: + dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON); + +int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t size) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct acp_dev_data *adata; + void *dest; + u32 dma_size, page_count; + unsigned int size_fw; + + adata = sdev->pdata->hw_pdata; + + switch (blk_type) { + case SOF_FW_BLK_TYPE_IRAM: + if (!adata->bin_buf) { + size_fw = plat_data->fw->size; + page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; + dma_size = page_count * ACP_PAGE_SIZE; + adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size, + &adata->sha_dma_addr, + GFP_ATOMIC); + if (!adata->bin_buf) + return -ENOMEM; + } + adata->fw_bin_size = size + offset; + dest = adata->bin_buf + offset; + break; + case SOF_FW_BLK_TYPE_DRAM: + if (!adata->data_buf) { + adata->data_buf = dma_alloc_coherent(&pci->dev, + ACP_DEFAULT_DRAM_LENGTH, + &adata->dma_addr, + GFP_ATOMIC); + if (!adata->data_buf) + return -ENOMEM; + } + dest = adata->data_buf + offset; + adata->fw_data_bin_size = size + offset; + break; + case SOF_FW_BLK_TYPE_SRAM: + offset = offset - ACP_SCRATCH_MEMORY_ADDRESS; + memcpy_to_scratch(sdev, offset, src, size); + return 0; + default: + dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type); + return -EINVAL; + } + + memcpy(dest, src, size); + return 0; +} +EXPORT_SYMBOL_NS(acp_dsp_block_write, SND_SOC_SOF_AMD_COMMON); + +int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} +EXPORT_SYMBOL_NS(acp_get_bar_index, SND_SOC_SOF_AMD_COMMON); + +static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev; + unsigned int low, high; + dma_addr_t addr; + u16 page_idx; + u32 offset; + + sdev = adata->dev; + + switch (type) { + case FW_BIN: + offset = FW_BIN_PTE_OFFSET; + addr = adata->sha_dma_addr; + break; + case FW_DATA_BIN: + offset = adata->fw_bin_page_count * 8; + addr = adata->dma_addr; + break; + default: + dev_err(sdev->dev, "Invalid data type %x\n", type); + return; + } + + for (page_idx = 0; page_idx < num_pages; page_idx++) { + low = lower_32_bits(addr); + high = upper_32_bits(addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low); + high |= BIT(31); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high); + offset += 8; + addr += PAGE_SIZE; + } +} + +/* pre fw run operations */ +int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata; + unsigned int src_addr, size_fw; + u32 page_count, dma_size; + int ret; + + adata = sdev->pdata->hw_pdata; + size_fw = adata->fw_bin_size; + + page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; + adata->fw_bin_page_count = page_count; + + configure_pte_for_fw_loading(FW_BIN, page_count, adata); + ret = configure_and_run_sha_dma(adata, adata->bin_buf, ACP_SYSTEM_MEMORY_WINDOW, + ACP_IRAM_BASE_ADDRESS, size_fw); + if (ret < 0) { + dev_err(sdev->dev, "SHA DMA transfer failed status: %d\n", ret); + return ret; + } + configure_pte_for_fw_loading(FW_DATA_BIN, ACP_DRAM_PAGE_COUNT, adata); + + src_addr = ACP_SYSTEM_MEMORY_WINDOW + page_count * ACP_PAGE_SIZE; + ret = configure_and_run_dma(adata, src_addr, ACP_DATA_RAM_BASE_ADDRESS, + adata->fw_data_bin_size); + if (ret < 0) { + dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret); + return ret; + } + + ret = acp_dma_status(adata, 0); + if (ret < 0) + dev_err(sdev->dev, "acp dma transfer status: %d\n", ret); + + /* Free memory once DMA is complete */ + dma_size = (PAGE_ALIGN(plat_data->fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE; + dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr); + dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr); + adata->bin_buf = NULL; + adata->data_buf = NULL; + + return ret; +} +EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_dsp_run(struct snd_sof_dev *sdev) +{ + int val; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL, ACP_DSP_RUN); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL); + dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val); + + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index ff01d0ef67ef..e755a31374c6 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -11,6 +11,8 @@ #ifndef __SOF_AMD_ACP_H #define __SOF_AMD_ACP_H
+#include "../sof-priv.h" + #define ACP_DSP_BAR 0
#define ACP_REG_POLL_INTERVAL 500 @@ -39,6 +41,13 @@ #define ACP_MAX_DESC 128 #define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0
+#define ACP_DEFAULT_DRAM_LENGTH 0x00080000 +#define ACP_SCRATCH_MEMORY_ADDRESS 0x02050000 +#define ACP_SYSTEM_MEMORY_WINDOW 0x4000000 +#define ACP_IRAM_BASE_ADDRESS 0x000000 +#define ACP_DATA_RAM_BASE_ADDRESS 0x01000000 +#define ACP_DRAM_PAGE_COUNT 128 + struct acp_atu_grp_pte { u32 low; u32 high; @@ -106,6 +115,13 @@ struct scratch_reg_conf { /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + unsigned int fw_bin_size; + unsigned int fw_data_bin_size; + u32 fw_bin_page_count; + dma_addr_t sha_dma_addr; + u8 *bin_buf; + dma_addr_t dma_addr; + u8 *data_buf; struct dma_descriptor dscr_info[ACP_MAX_DESC]; };
@@ -123,5 +139,16 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, int amd_sof_acp_probe(struct snd_sof_dev *sdev); int amd_sof_acp_remove(struct snd_sof_dev *sdev);
+/* DSP Loader callbacks */ +int acp_sof_dsp_run(struct snd_sof_dev *sdev); +int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type); + +/* Block IO callbacks */ +int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t size); +int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size); + extern const struct snd_sof_dsp_ops sof_renoir_ops; #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 3d1dc6c2fa9b..bca80784b322 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -26,6 +26,21 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { /* Register IO */ .write = sof_io_write, .read = sof_io_read, + + /* Block IO */ + .block_read = acp_dsp_block_read, + .block_write = acp_dsp_block_write, + + /* Module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + .pre_fw_run = acp_dsp_pre_fw_run, + .get_bar_index = acp_get_bar_index, + + /* DSP core boot */ + .run = acp_sof_dsp_run, }; EXPORT_SYMBOL(sof_renoir_ops);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add IPC module for generic ACP block and exposed ops callback for to synchronize SOF IPC message between host and DSP
Signed-off-by: Balakishore Pati Balakishore.pati@amd.com Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-dsp-offset.h | 2 + sound/soc/sof/amd/acp-ipc.c | 187 +++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.c | 44 ++++++- sound/soc/sof/amd/acp.h | 15 +++ sound/soc/sof/amd/renoir.c | 8 ++ 6 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/amd/acp-ipc.c
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 031fb9493876..29928b16002f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
-snd-sof-amd-acp-objs := acp.o acp-loader.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o snd-sof-amd-renoir-objs := renoir.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index f4bc7e9abafb..3a1c848020ca 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -53,6 +53,8 @@
/* Registers from ACP_INTR block */ #define ACP_DSP_SW_INTR_CNTL 0x1814 +#define ACP_DSP_SW_INTR_STAT 0x1818 +#define ACP_SW_INTR_TRIG 0x181C #define ACP_ERROR_STATUS 0x18C4
/* Registers from ACP_SHA block */ diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c new file mode 100644 index 000000000000..e132223b4c66 --- /dev/null +++ b/sound/soc/sof/amd/acp-ipc.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Balakishore Pati Balakishore.pati@amd.com +// Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* ACP-specific SOF IPC code */ + +#include <linux/module.h> +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) +{ + memcpy_to_scratch(sdev, offset, message, bytes); +} +EXPORT_SYMBOL_NS(acp_mailbox_write, SND_SOC_SOF_AMD_COMMON); + +void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) +{ + memcpy_from_scratch(sdev, offset, message, bytes); +} +EXPORT_SYMBOL_NS(acp_mailbox_read, SND_SOC_SOF_AMD_COMMON); + +static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + u32 swintr_trigger; + + swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG); + swintr_trigger |= 0x01; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG, swintr_trigger); +} + +static void acp_ipc_host_msg_set(struct snd_sof_dev *sdev) +{ + unsigned int host_msg = offsetof(struct scratch_ipc_conf, sof_host_msg_write); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg, 1); +} + +static void acp_dsp_ipc_host_done(struct snd_sof_dev *sdev) +{ + unsigned int dsp_msg = offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg, 0); +} + +static void acp_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + unsigned int dsp_ack = offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack, 0); +} + +int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box); + + acp_mailbox_write(sdev, offset, msg->msg_data, msg->msg_size); + acp_ipc_host_msg_set(sdev); + + /* Trigger host to dsp interrupt for the msg */ + acpbus_trigger_host_to_dsp_swintr(adata); + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, SND_SOC_SOF_AMD_COMMON); + +static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + struct sof_ipc_cmd_hdr *hdr; + unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box); + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + hdr = msg->msg_data; + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || + hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { + /* + * memory windows are powered off before sending IPC reply, + * so we can't read the mailbox for CTX_SAVE and PM_GATE + * replies. + */ + reply.error = 0; + reply.hdr.cmd = SOF_IPC_GLB_REPLY; + reply.hdr.size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); + goto out; + } + /* get IPC reply from DSP in the mailbox */ + acp_mailbox_read(sdev, offset, &reply, sizeof(reply)); + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size && + !(reply.hdr.cmd & SOF_IPC_GLB_PROBE)) { + dev_err(sdev->dev, "reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + /* read the message */ + if (msg->reply_size > 0) + acp_mailbox_read(sdev, offset, msg->reply_data, msg->reply_size); + } +out: + msg->reply_error = ret; +} + +irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + unsigned int dsp_msg_write = offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); + unsigned int dsp_ack_write = offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); + bool ipc_irq = false; + int dsp_msg, dsp_ack; + + dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); + if (dsp_msg) { + snd_sof_ipc_msgs_rx(sdev); + acp_dsp_ipc_host_done(sdev); + ipc_irq = true; + } + + dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); + if (dsp_ack) { + spin_lock_irq(&sdev->ipc_lock); + /* handle immediate reply from DSP core */ + acp_dsp_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, 0); + /* set the done bit */ + acp_dsp_ipc_dsp_done(sdev); + spin_unlock_irq(&sdev->ipc_lock); + ipc_irq = true; + } + + if (!ipc_irq) + dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + unsigned int offset = offsetof(struct scratch_ipc_conf, sof_out_box); + + if (!substream || !sdev->stream_box.size) + acp_mailbox_read(sdev, offset, p, sz); + + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + /* TODO: Implement stream hw params to validate stream offset */ + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_pcm_params, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return ACP_SCRATCH_MEMORY_ADDRESS; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON); + +MODULE_DESCRIPTION("AMD ACP sof-ipc driver"); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 3778f781f16a..43a57d15e3ca 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -233,6 +233,34 @@ static int acp_memory_init(struct snd_sof_dev *sdev) return 0; }
+static irqreturn_t acp_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); + if (val & ACP_DSP_TO_HOST_IRQ) { + sof_ops(sdev)->irq_thread(irq, sdev); + val |= ACP_DSP_TO_HOST_IRQ; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT, val); + return IRQ_HANDLED; + } + + return IRQ_NONE; +}; + +static irqreturn_t acp_irq_handler(int irq, void *dev_id) +{ + struct snd_sof_dev *sdev = dev_id; + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); + if (val) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + static int acp_power_on(struct snd_sof_dev *sdev) { unsigned int val; @@ -318,9 +346,20 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->pdata->hw_pdata = adata;
+ sdev->ipc_irq = pci->irq; + ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, + IRQF_SHARED, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to register IRQ %d\n", + sdev->ipc_irq); + return ret; + } + ret = acp_init(sdev); - if (ret < 0) + if (ret < 0) { + free_irq(sdev->ipc_irq, sdev); return ret; + }
acp_memory_init(sdev);
@@ -330,6 +369,9 @@ EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_remove(struct snd_sof_dev *sdev) { + if (sdev->ipc_irq) + free_irq(sdev->ipc_irq, sdev); + return acp_reset(sdev); } EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index e755a31374c6..ac8340119125 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -48,6 +48,8 @@ #define ACP_DATA_RAM_BASE_ADDRESS 0x01000000 #define ACP_DRAM_PAGE_COUNT 128
+#define ACP_DSP_TO_HOST_IRQ 0x04 + struct acp_atu_grp_pte { u32 low; u32 high; @@ -150,5 +152,18 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, u32 offset, void *dest, size_t size);
+/* IPC callbacks */ +irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context); +int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + void *p, size_t sz); +int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); +int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int acp_sof_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); +int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); +void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); +void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); + extern const struct snd_sof_dsp_ops sof_renoir_ops; #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index bca80784b322..9d95ea66f867 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -41,6 +41,14 @@ const struct snd_sof_dsp_ops sof_renoir_ops = {
/* DSP core boot */ .run = acp_sof_dsp_run, + + /*IPC */ + .send_msg = acp_sof_ipc_send_msg, + .ipc_msg_data = acp_sof_ipc_msg_data, + .ipc_pcm_params = acp_sof_ipc_pcm_params, + .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, + .irq_thread = acp_sof_ipc_irq_thread, + .fw_ready = sof_fw_ready, }; EXPORT_SYMBOL(sof_renoir_ops);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add dsp ops callback to register I2S and DMIC sof dai's with ALSA
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/acp-dsp-offset.h | 2 + sound/soc/sof/amd/renoir.c | 91 ++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+)
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 3a1c848020ca..1d11e9d69dce 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -47,6 +47,8 @@ #define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACP_SOFT_RESET 0x1000
+#define ACP_I2S_PIN_CONFIG 0x1400 + /* Registers from ACP_PGFSM block */ #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420 diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 9d95ea66f867..ca5582b3f82d 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -15,7 +15,94 @@ #include <linux/module.h>
#include "../ops.h" +#include "../sof-audio.h" #include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_BT_INSTANCE 0 +#define I2S_SP_INSTANCE 1 +#define PDM_DMIC_INSTANCE 2 + +#define I2S_MODE 0x04 + +static int renoir_dai_probe(struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_I2S_PIN_CONFIG); + if (val != I2S_MODE) { + dev_err(sdev->dev, "I2S Mode is not supported (I2S_PIN_CONFIG: %#x)\n", val); + return -EINVAL; + } + + return 0; +} + +static struct snd_soc_dai_driver renoir_sof_dai[] = { + [I2S_BT_INSTANCE] = { + .id = I2S_BT_INSTANCE, + .name = "acp-sof-bt", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .probe = &renoir_dai_probe, + }, + + [I2S_SP_INSTANCE] = { + .id = I2S_SP_INSTANCE, + .name = "acp-sof-sp", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .probe = &renoir_dai_probe, + }, + + [PDM_DMIC_INSTANCE] = { + .id = PDM_DMIC_INSTANCE, + .name = "acp-sof-dmic", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, +};
/* AMD Renoir DSP ops */ const struct snd_sof_dsp_ops sof_renoir_ops = { @@ -49,6 +136,10 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, .irq_thread = acp_sof_ipc_irq_thread, .fw_ready = sof_fw_ready, + + /* DAI drivers */ + .drv = renoir_sof_dai, + .num_drv = ARRAY_SIZE(renoir_sof_dai), }; EXPORT_SYMBOL(sof_renoir_ops);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add module to support ALSA pcm stream configurations for ACP I2S and DMIC endpoints
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-pcm.c | 82 +++++++++++++++ sound/soc/sof/amd/acp-stream.c | 181 +++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.c | 2 + sound/soc/sof/amd/acp.h | 28 +++++ sound/soc/sof/amd/renoir.c | 11 ++ 6 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/acp-pcm.c create mode 100644 sound/soc/sof/amd/acp-stream.c
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 29928b16002f..7b88db9c5fb7 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
-snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o snd-sof-amd-renoir-objs := renoir.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c new file mode 100644 index 000000000000..5b23830cb1f3 --- /dev/null +++ b/sound/soc/sof/amd/acp-pcm.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* + * PCM interface for generic AMD audio ACP DSP block + */ +#include <sound/pcm_params.h> + +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params) +{ + struct acp_dsp_stream *stream = substream->runtime->private_data; + unsigned int buf_offset, index; + u32 size; + int ret; + + size = ipc_params->buffer.size; + stream->num_pages = ipc_params->buffer.pages; + stream->dmab = substream->runtime->dma_buffer_p; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "stream configuration failed\n"); + return ret; + } + + ipc_params->buffer.phy_addr = stream->reg_offset; + ipc_params->stream_tag = stream->stream_tag; + + /* write buffer size of stream in scratch memory */ + + buf_offset = offsetof(struct scratch_reg_conf, buf_size); + index = stream->stream_tag - 1; + buf_offset = buf_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size); + + return 0; +} +EXPORT_SYMBOL_NS(acp_pcm_hw_params, SND_SOC_SOF_AMD_COMMON); + +int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +{ + struct acp_dsp_stream *stream; + + stream = acp_dsp_stream_get(sdev, 0); + if (!stream) + return -ENODEV; + + substream->runtime->private_data = stream; + stream->substream = substream; + + return 0; +} +EXPORT_SYMBOL_NS(acp_pcm_open, SND_SOC_SOF_AMD_COMMON); + +int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +{ + struct acp_dsp_stream *stream; + + stream = substream->runtime->private_data; + if (!stream) { + dev_err(sdev->dev, "No open stream\n"); + return -EINVAL; + } + + stream->substream = NULL; + substream->runtime->private_data = NULL; + + return acp_dsp_stream_put(sdev, stream); +} +EXPORT_SYMBOL_NS(acp_pcm_close, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-stream.c b/sound/soc/sof/amd/acp-stream.c new file mode 100644 index 000000000000..f2837bfbdb20 --- /dev/null +++ b/sound/soc/sof/amd/acp-stream.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* + * Hardware interface for generic AMD audio DSP ACP IP + */ + +#include "../ops.h" +#include "acp-dsp-offset.h" +#include "acp.h" + +#define PTE_GRP1_OFFSET 0x00000000 +#define PTE_GRP2_OFFSET 0x00800000 +#define PTE_GRP3_OFFSET 0x01000000 +#define PTE_GRP4_OFFSET 0x01800000 +#define PTE_GRP5_OFFSET 0x02000000 +#define PTE_GRP6_OFFSET 0x02800000 +#define PTE_GRP7_OFFSET 0x03000000 +#define PTE_GRP8_OFFSET 0x03800000 + +int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream) +{ + unsigned int pte_reg, pte_size, phy_addr_offset, index; + int stream_tag = stream->stream_tag; + u32 low, high, offset, reg_val; + dma_addr_t addr; + int page_idx; + + switch (stream_tag) { + case 1: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_1; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1; + offset = offsetof(struct scratch_reg_conf, grp1_pte); + stream->reg_offset = PTE_GRP1_OFFSET; + break; + case 2: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_2; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2; + offset = offsetof(struct scratch_reg_conf, grp2_pte); + stream->reg_offset = PTE_GRP2_OFFSET; + break; + case 3: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_3; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3; + offset = offsetof(struct scratch_reg_conf, grp3_pte); + stream->reg_offset = PTE_GRP3_OFFSET; + break; + case 4: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_4; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4; + offset = offsetof(struct scratch_reg_conf, grp4_pte); + stream->reg_offset = PTE_GRP4_OFFSET; + break; + case 5: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5; + offset = offsetof(struct scratch_reg_conf, grp5_pte); + stream->reg_offset = PTE_GRP5_OFFSET; + break; + case 6: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_6; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6; + offset = offsetof(struct scratch_reg_conf, grp6_pte); + stream->reg_offset = PTE_GRP6_OFFSET; + break; + case 7: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_7; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7; + offset = offsetof(struct scratch_reg_conf, grp7_pte); + stream->reg_offset = PTE_GRP7_OFFSET; + break; + case 8: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_8; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8; + offset = offsetof(struct scratch_reg_conf, grp8_pte); + stream->reg_offset = PTE_GRP8_OFFSET; + break; + default: + dev_err(sdev->dev, "Invalid stream tag %d\n", stream_tag); + return -EINVAL; + } + + /* write phy_addr in scratch memory */ + + phy_addr_offset = offsetof(struct scratch_reg_conf, reg_offset); + index = stream_tag - 1; + phy_addr_offset = phy_addr_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + + phy_addr_offset, stream->reg_offset); + + /* Group Enable */ + reg_val = ACP_SRAM_PTE_OFFSET + offset; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_reg, reg_val | BIT(31)); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_size, PAGE_SIZE_4K_ENABLE); + + for (page_idx = 0; page_idx < stream->num_pages; page_idx++) { + addr = snd_sgbuf_get_addr(stream->dmab, page_idx * PAGE_SIZE); + + /* Load the low address of page int ACP SRAM through SRBM */ + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low); + + high |= BIT(31); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high); + /* Move to next physically contiguous page */ + offset += 8; + } + + return 0; +} + +struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + struct acp_dsp_stream *stream = adata->stream_buf; + int i; + + for (i = 0; i < ACP_MAX_STREAM; i++, stream++) { + if (stream->active) + continue; + + /* return stream if tag not specified*/ + if (!tag) { + stream->active = 1; + return stream; + } + + /* check if this is the requested stream tag */ + if (stream->stream_tag == tag) { + stream->active = 1; + return stream; + } + } + + dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag); + return NULL; +} +EXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON); + +int acp_dsp_stream_put(struct snd_sof_dev *sdev, + struct acp_dsp_stream *acp_stream) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + struct acp_dsp_stream *stream = adata->stream_buf; + int i; + + /* Free an active stream */ + for (i = 0; i < ACP_MAX_STREAM; i++, stream++) { + if (stream == acp_stream) { + stream->active = 0; + return 0; + } + } + + dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag); + return -EINVAL; +} +EXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON); + +int acp_dsp_stream_init(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + int i; + + for (i = 0; i < ACP_MAX_STREAM; i++) { + adata->stream_buf[i].sdev = sdev; + adata->stream_buf[i].active = 0; + adata->stream_buf[i].stream_tag = i + 1; + } + return 0; +} +EXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 43a57d15e3ca..74ede28aa8d8 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -363,6 +363,8 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
acp_memory_init(sdev);
+ acp_dsp_stream_init(sdev); + return 0; } EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index ac8340119125..36d000c3f792 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -13,6 +13,8 @@
#include "../sof-priv.h"
+#define ACP_MAX_STREAM 8 + #define ACP_DSP_BAR 0
#define ACP_REG_POLL_INTERVAL 500 @@ -114,6 +116,17 @@ struct scratch_reg_conf { unsigned int reserve[]; };
+struct acp_dsp_stream { + struct list_head list; + struct snd_sof_dev *sdev; + struct snd_pcm_substream *substream; + struct snd_dma_buffer *dmab; + int num_pages; + int stream_tag; + int active; + unsigned int reg_offset; +}; + /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; @@ -125,6 +138,7 @@ struct acp_dev_data { dma_addr_t dma_addr; u8 *data_buf; struct dma_descriptor dscr_info[ACP_MAX_DESC]; + struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; };
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -165,5 +179,19 @@ int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *s void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes);
+/* ACP - DSP stream callbacks */ +int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream); +int acp_dsp_stream_init(struct snd_sof_dev *sdev); +struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag); +int acp_dsp_stream_put(struct snd_sof_dev *sdev, struct acp_dsp_stream *acp_stream); + +/* + * DSP PCM Operations. + */ +int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params); + extern const struct snd_sof_dsp_ops sof_renoir_ops; #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index ca5582b3f82d..0241c5dce156 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -140,6 +140,17 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { /* DAI drivers */ .drv = renoir_sof_dai, .num_drv = ARRAY_SIZE(renoir_sof_dai), + + /* stream callbacks */ + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + + .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, }; EXPORT_SYMBOL(sof_renoir_ops);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
ACP hw block configuration differs across various distributions and hence it's required to register different drivers module for distributions. For now we support three ACP drivers:
* ACP without SOF use case * ACP with SOF use case * ACP with SOF use case for DMIC and non SOF for I2S endpoints
As all above driver registers with common PCI ID for ACP hw block we need code to determine ACP configuration and auto select driver module. This patch expose function that return configuration flag based on dmi checks for a system. ACP driver module probe register platform device based on such configuration flag to avoid conflict with other ACP drivers probed for same PCI ID.
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/amd/Kconfig | 6 +++ sound/soc/amd/Makefile | 2 + sound/soc/amd/acp-config.c | 81 +++++++++++++++++++++++++++++++++++++ sound/soc/amd/mach-config.h | 29 +++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 sound/soc/amd/acp-config.c create mode 100644 sound/soc/amd/mach-config.h
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 2c6af3f8f296..092966ff5ea7 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -96,4 +96,10 @@ config SND_SOC_AMD_YC_MACH Say m if you have such a device. If unsure select "N".
+config SND_AMD_ACP_CONFIG + tristate "AMD ACP configuration selection" + help + This option adds an auto detection to determine which ACP + driver modules to use + source "sound/soc/amd/acp/Kconfig" diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index f1d42bbda709..4b1f77930a4a 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -3,6 +3,7 @@ acp_audio_dma-objs := acp-pcm-dma.o snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o snd-soc-acp-rt5645-mach-objs := acp-rt5645.o snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o +snd-acp-config-objs := acp-config.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o @@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/ obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/ obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/ +obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c new file mode 100644 index 000000000000..c9abbb46b6f5 --- /dev/null +++ b/sound/soc/amd/acp-config.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com +// + +/* ACP machine configuration module */ + +#include <linux/acpi.h> +#include <linux/bits.h> +#include <linux/dmi.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include "../sof/amd/acp.h" +#include "mach-config.h" + +static int acp_quirk_data; + +static const struct config_entry config_table[] = { + { + .flags = FLAG_AMD_SOF, + .device = ACP_PCI_DEV_ID, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AMD"), + DMI_MATCH(DMI_PRODUCT_NAME, "Majolica-CZN"), + }, + }, + {} + }, + }, +}; + +int snd_amd_acp_find_config(struct pci_dev *pci) +{ + const struct config_entry *table = config_table; + u16 device = pci->device; + int i; + + for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) { + if (table->device != device) + continue; + if (table->dmi_table && !dmi_check_system(table->dmi_table)) + continue; + acp_quirk_data = table->flags; + return table->flags; + } + + return 0; +} +EXPORT_SYMBOL(snd_amd_acp_find_config); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { + { + .id = "AMDI1019", + .drv_name = "renoir-dsp", + .pdata = (void *)&acp_quirk_data, + .fw_filename = "sof-rn.ri", + .sof_tplg_filename = "sof-acp.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { + { + .id = "AMDI1019", + .drv_name = "renoir-acp", + .pdata = (void *)&acp_quirk_data, + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp_machines); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h new file mode 100644 index 000000000000..608f1e199775 --- /dev/null +++ b/sound/soc/amd/mach-config.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + */ +#ifndef __AMD_MACH_CONFIG_H +#define __AMD_MACH_CONFIG_H + +#include <sound/soc-acpi.h> + +#define FLAG_AMD_SOF BIT(1) +#define FLAG_AMD_SOF_ONLY_DMIC BIT(2) + +#define ACP_PCI_DEV_ID 0x15E2 + +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[]; + +struct config_entry { + u32 flags; + u16 device; + const struct dmi_system_id *dmi_table; +}; + +#endif
Hi Daniel,
On Wed, Nov 17, 2021 at 12:39 PM Daniel Baluta daniel.baluta@oss.nxp.com wrote:
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
ACP hw block configuration differs across various distributions and hence it's required to register different drivers module for distributions. For now we support three ACP drivers:
- ACP without SOF use case
- ACP with SOF use case
- ACP with SOF use case for DMIC and non SOF for I2S endpoints
As all above driver registers with common PCI ID for ACP hw block we need code to determine ACP configuration and auto select driver module. This patch expose function that return configuration flag based on dmi checks for a system. ACP driver module probe register platform device based on such configuration flag to avoid conflict with other ACP drivers probed for same PCI ID.
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com
Thanks for your patch, which is now commit f1bdd8d385a80356 ("ASoC: amd: Add module to determine ACP configuration") in sound-asoc/for-next.
--- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -96,4 +96,10 @@ config SND_SOC_AMD_YC_MACH Say m if you have such a device. If unsure select "N".
+config SND_AMD_ACP_CONFIG
tristate "AMD ACP configuration selection"
This definitely needs proper dependencies, to prevent asking the user about this when configuring a kernel without AMD Audio ACP support.
I would have sent a patch, but...
help
This option adds an auto detection to determine which ACP
driver modules to use
source "sound/soc/amd/acp/Kconfig"
--- /dev/null +++ b/sound/soc/amd/acp-config.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com +//
+/* ACP machine configuration module */
+#include <linux/acpi.h> +#include <linux/bits.h> +#include <linux/dmi.h> +#include <linux/module.h> +#include <linux/pci.h>
+#include "../sof/amd/acp.h"
This doesn't seem to use anything from this header file?
+#include "mach-config.h"
+static int acp_quirk_data;
+static const struct config_entry config_table[] = {
{
.flags = FLAG_AMD_SOF,
.device = ACP_PCI_DEV_ID,
.dmi_table = (const struct dmi_system_id []) {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AMD"),
DMI_MATCH(DMI_PRODUCT_NAME, "Majolica-CZN"),
},
},
{}
},
},
+};
+int snd_amd_acp_find_config(struct pci_dev *pci) +{
const struct config_entry *table = config_table;
u16 device = pci->device;
int i;
for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) {
if (table->device != device)
continue;
if (table->dmi_table && !dmi_check_system(table->dmi_table))
continue;
acp_quirk_data = table->flags;
return table->flags;
}
return 0;
+} +EXPORT_SYMBOL(snd_amd_acp_find_config);
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = {
{
.id = "AMDI1019",
.drv_name = "renoir-acp",
.pdata = (void *)&acp_quirk_data,
},
{},
+}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp_machines);
These symbols are only used from sound/soc/sof/amd/pci-rn.c.
Why is this code living under sound/soc/amd/, while the ACP code is under sound/soc/amd/acp/?
Gr{oetje,eeting}s,
Geert
-- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
--- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -96,4 +96,10 @@ config SND_SOC_AMD_YC_MACH Say m if you have such a device. If unsure select "N".
+config SND_AMD_ACP_CONFIG
tristate "AMD ACP configuration selection"
This definitely needs proper dependencies, to prevent asking the user about this when configuring a kernel without AMD Audio ACP support.
I would have sent a patch, but...
There's indeed a missing dependency that was fixed in https://github.com/thesofproject/linux/pull/3284
Daniel, you may want to squash it in an update?
To Geert's point, there may be an additional need to add a
depends on SND_SOC_AMD_ACP
There are also a set of
SND_SOC_AMD_ACPyx options, not sure if any applies as a dependency here?
On Tue, Nov 30, 2021 at 10:49:30AM -0600, Pierre-Louis Bossart wrote:
To Geert's point, there may be an additional need to add a
depends on SND_SOC_AMD_ACP
There are also a set of
SND_SOC_AMD_ACPyx options, not sure if any applies as a dependency here?
Or put them in an if block (IIRC I thought they were which was why the dependency wasn't needed but I don't know what I was looking at if I did check that).
On Tue, Nov 30, 2021 at 7:05 PM Mark Brown broonie@kernel.org wrote:
On Tue, Nov 30, 2021 at 10:49:30AM -0600, Pierre-Louis Bossart wrote:
To Geert's point, there may be an additional need to add a
depends on SND_SOC_AMD_ACP
There are also a set of
SND_SOC_AMD_ACPyx options, not sure if any applies as a dependency here?
Or put them in an if block (IIRC I thought they were which was why the dependency wasn't needed but I don't know what I was looking at if I did check that).
There will be some delays in handling this as I'm in vacation until next Monday.
Hi Mark,
On Tue, Nov 30, 2021 at 6:05 PM Mark Brown broonie@kernel.org wrote:
On Tue, Nov 30, 2021 at 10:49:30AM -0600, Pierre-Louis Bossart wrote:
To Geert's point, there may be an additional need to add a
depends on SND_SOC_AMD_ACP
There are also a set of
SND_SOC_AMD_ACPyx options, not sure if any applies as a dependency here?
Or put them in an if block (IIRC I thought they were which was why the dependency wasn't needed but I don't know what I was looking at if I did check that).
Probably you were looking at sound/soc/amd/acp/Kconfig, where all the other ACP options live, and where you had applied my earlier patch to wrap everything in a big "if".
Gr{oetje,eeting}s,
Geert
-- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add dsp ops callback to select and register machine driver.
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/renoir.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 0241c5dce156..3cd269bfe75d 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -104,6 +104,23 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { }, };
+static void amd_sof_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(sdev->dev, "No matching ASoC machine driver found\n"); + return; + } + + sof_pdata->tplg_filename = mach->sof_tplg_filename; + sof_pdata->fw_filename = mach->fw_filename; + sof_pdata->machine = mach; +} + /* AMD Renoir DSP ops */ const struct snd_sof_dsp_ops sof_renoir_ops = { /* probe and remove */ @@ -151,6 +168,11 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + + /* Machine driver callbacks */ + .machine_select = amd_sof_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, }; EXPORT_SYMBOL(sof_renoir_ops);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add PCI driver module to enable sof pci device support for Renoir. If machine flag set to FLAG_SOF_ONLY_DMIC this pci driver register platform device for non dsp based I2S platform device. If machine flag is not enabled for SOF pci probe will return without invoking sof device probe and registration
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/Kconfig | 5 +- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp.h | 3 + sound/soc/sof/amd/pci-rn.c | 160 +++++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/amd/pci-rn.c
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 400dd5a24ae6..085232e04582 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -17,14 +17,17 @@ if SND_SOC_SOF_AMD_TOPLEVEL config SND_SOC_SOF_AMD_COMMON tristate select SND_SOC_SOF + select SND_SOC_SOF_PCI_DEV + select SND_AMD_ACP_CONFIG + select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by 'select' statements at a higher level
config SND_SOC_SOF_AMD_RENOIR tristate "SOF support for RENOIR" + depends on SND_SOC_SOF_PCI select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support on AMD Renoir platform - endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 7b88db9c5fb7..b27ce50014b8 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -5,7 +5,7 @@ # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o -snd-sof-amd-renoir-objs := renoir.o +snd-sof-amd-renoir-objs := pci-rn.o renoir.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 36d000c3f792..5f6e9eff116a 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -194,4 +194,7 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params);
extern const struct snd_sof_dsp_ops sof_renoir_ops; + +/* Machine configuration */ +int snd_amd_acp_find_config(struct pci_dev *pci); #endif diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c new file mode 100644 index 000000000000..3c379a5ef231 --- /dev/null +++ b/sound/soc/sof/amd/pci-rn.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Ajit Kumar Pandey AjitKumar.Pandey@amd.com + +/* + * PCI interface for Renoir ACP device + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <sound/sof.h> +#include <sound/soc-acpi.h> + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" + +#define ACP3x_REG_START 0x1240000 +#define ACP3x_REG_END 0x125C000 + +static struct platform_device *dmic_dev; +static struct platform_device *pdev; + +static const struct resource renoir_res[] = { + { + .start = 0, + .end = ACP3x_REG_END - ACP3x_REG_START, + .name = "acp_mem", + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .name = "acp_dai_irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct sof_dev_desc renoir_desc = { + .machines = snd_soc_acpi_amd_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .default_fw_path = "amd/sof", + .default_tplg_path = "amd/sof-tplg", + .default_fw_filename = "sof-rn.ri", + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_renoir_ops, +}; + +static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + struct platform_device_info pdevinfo; + struct device *dev = &pci->dev; + const struct resource *res_i2s; + struct resource *res; + unsigned int flag, i, addr; + int ret; + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + ret = sof_pci_probe(pci, pci_id); + if (ret != 0) + return ret; + + dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(dmic_dev)) { + dev_err(dev, "failed to create DMIC device\n"); + sof_pci_remove(pci); + return PTR_ERR(dmic_dev); + } + + /* Register platform device only if flag set to FLAG_AMD_SOF_ONLY_DMIC */ + if (flag != FLAG_AMD_SOF_ONLY_DMIC) + return 0; + + addr = pci_resource_start(pci, 0); + res = devm_kzalloc(&pci->dev, sizeof(struct resource) * ARRAY_SIZE(renoir_res), GFP_KERNEL); + if (!res) { + sof_pci_remove(pci); + return -ENOMEM; + } + + res_i2s = renoir_res; + for (i = 0; i < ARRAY_SIZE(renoir_res); i++, res_i2s++) { + res[i].name = res_i2s->name; + res[i].flags = res_i2s->flags; + res[i].start = addr + res_i2s->start; + res[i].end = addr + res_i2s->end; + if (res_i2s->flags == IORESOURCE_IRQ) { + res[i].start = pci->irq; + res[i].end = res[i].start; + } + } + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + + /* + * We have common PCI driver probe for ACP device but we have to support I2S without SOF + * for some distributions. Register platform device that will be used to support non dsp + * ACP's audio ends points on some machines. + */ + + pdevinfo.name = "acp_asoc_renoir"; + pdevinfo.id = 0; + pdevinfo.parent = &pci->dev; + pdevinfo.num_res = ARRAY_SIZE(renoir_res); + pdevinfo.res = &res[0]; + + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) { + dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); + sof_pci_remove(pci); + platform_device_unregister(dmic_dev); + ret = PTR_ERR(pdev); + } + + return ret; +}; + +static void acp_pci_rn_remove(struct pci_dev *pci) +{ + if (dmic_dev) + platform_device_unregister(dmic_dev); + if (pdev) + platform_device_unregister(pdev); + + return sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id rn_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&renoir_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, rn_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_rn_driver = { + .name = KBUILD_MODNAME, + .id_table = rn_pci_ids, + .probe = acp_pci_rn_probe, + .remove = acp_pci_rn_remove, +}; +module_pci_driver(snd_sof_pci_amd_rn_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
We have moved legacy based machine struct into platform driver to resolve module dependency with non-SOF ALSA build, hence removed it from acp-config driver module.
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/amd/acp-config.c | 10 ---------- sound/soc/amd/mach-config.h | 1 - 2 files changed, 11 deletions(-)
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index c9abbb46b6f5..1493d52c9290 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -68,14 +68,4 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines);
-struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { - { - .id = "AMDI1019", - .drv_name = "renoir-acp", - .pdata = (void *)&acp_quirk_data, - }, - {}, -}; -EXPORT_SYMBOL(snd_soc_acpi_amd_acp_machines); - MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 608f1e199775..feb3756d9ac4 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -18,7 +18,6 @@ #define ACP_PCI_DEV_ID 0x15E2
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[];
struct config_entry { u32 flags;
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add new sof dais and config to pass topology file configuration to SOF firmware running on ACP's DSP core. ACP firmware support I2S_BT, I2S_SP and DMIC controller hence add three new dais to the list of supported sof_dais
Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- include/sound/sof/dai-amd.h | 21 +++++++ include/sound/sof/dai.h | 7 +++ sound/soc/sof/pcm.c | 36 ++++++++++++ sound/soc/sof/topology.c | 109 ++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 include/sound/sof/dai-amd.h
diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h new file mode 100644 index 000000000000..90d09dbdd709 --- /dev/null +++ b/include/sound/sof/dai-amd.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc.. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_AMD_H__ +#define __INCLUDE_SOUND_SOF_DAI_AMD_H__ + +#include <sound/sof/header.h> + +/* ACP Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ +struct sof_ipc_dai_acp_params { + struct sof_ipc_hdr hdr; + + uint32_t fsync_rate; /* FSYNC frequency in Hz */ + uint32_t tdm_slots; +} __packed; +#endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 9625f47557b8..3782127a7095 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -12,6 +12,7 @@ #include <sound/sof/header.h> #include <sound/sof/dai-intel.h> #include <sound/sof/dai-imx.h> +#include <sound/sof/dai-amd.h>
/* * DAI Configuration. @@ -66,6 +67,9 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_ALH, /**< Intel ALH */ SOF_DAI_IMX_SAI, /**< i.MX SAI */ SOF_DAI_IMX_ESAI, /**< i.MX ESAI */ + SOF_DAI_AMD_BT, /**< AMD ACP BT*/ + SOF_DAI_AMD_SP, /**< AMD ACP SP */ + SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */ };
/* general purpose DAI configuration */ @@ -90,6 +94,9 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_alh_params alh; struct sof_ipc_dai_esai_params esai; struct sof_ipc_dai_sai_params sai; + struct sof_ipc_dai_acp_params acpbt; + struct sof_ipc_dai_acp_params acpsp; + struct sof_ipc_dai_acp_params acpdmic; }; } __packed;
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index fa0bfcd2474e..8d313c9862cb 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -826,6 +826,42 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa "channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_AMD_BT: + rate->min = dai->dai_config->acpbt.fsync_rate; + rate->max = dai->dai_config->acpbt.fsync_rate; + channels->min = dai->dai_config->acpbt.tdm_slots; + channels->max = dai->dai_config->acpbt.tdm_slots; + + dev_dbg(component->dev, + "AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "AMD_BT channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_AMD_SP: + rate->min = dai->dai_config->acpsp.fsync_rate; + rate->max = dai->dai_config->acpsp.fsync_rate; + channels->min = dai->dai_config->acpsp.tdm_slots; + channels->max = dai->dai_config->acpsp.tdm_slots; + + dev_dbg(component->dev, + "AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "AMD_SP channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_AMD_DMIC: + rate->min = dai->dai_config->acpdmic.fsync_rate; + rate->max = dai->dai_config->acpdmic.fsync_rate; + channels->min = dai->dai_config->acpdmic.tdm_slots; + channels->max = dai->dai_config->acpdmic.tdm_slots; + + dev_dbg(component->dev, + "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "AMD_DMIC channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; default: dev_err(component->dev, "error: invalid DAI type %d\n", dai->dai_config->type); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bb9e62bbe5db..72e671c15a34 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -376,6 +376,9 @@ static const struct sof_dai_types sof_dais[] = { {"ALH", SOF_DAI_INTEL_ALH}, {"SAI", SOF_DAI_IMX_SAI}, {"ESAI", SOF_DAI_IMX_ESAI}, + {"ACP", SOF_DAI_AMD_BT}, + {"ACPSP", SOF_DAI_AMD_SP}, + {"ACPDMIC", SOF_DAI_AMD_DMIC}, };
static enum sof_ipc_dai_type find_dai(const char *name) @@ -2992,6 +2995,102 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, return ret; }
+static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpdmic, 0, sizeof(struct sof_ipc_dai_acp_params)); + config->hdr.size = size; + + config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n", + config->dai_index, config->acpdmic.tdm_slots, + config->acpdmic.fsync_rate); + + /* 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(scomp->dev, "ACP_DMIC failed to save DAI config for ACP%d\n", + config->dai_index); + return ret; +} + +static int sof_link_acp_bt_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpbt, 0, sizeof(struct sof_ipc_dai_acp_params)); + config->hdr.size = size; + + config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n", + config->dai_index, config->acpbt.tdm_slots, + config->acpbt.fsync_rate); + + /* 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(scomp->dev, "ACP_BT failed to save DAI config for ACP%d\n", + config->dai_index); + return ret; +} + +static int sof_link_acp_sp_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpsp, 0, sizeof(struct sof_ipc_dai_acp_params)); + config->hdr.size = size; + + config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n", + config->dai_index, config->acpsp.tdm_slots, + config->acpsp.fsync_rate); + + /* 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(scomp->dev, "ACP_SP failed to save DAI config for ACP%d\n", + config->dai_index); + return ret; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -3277,6 +3376,16 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, case SOF_DAI_IMX_ESAI: ret = sof_link_esai_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; + case SOF_DAI_AMD_BT: + ret = sof_link_acp_bt_load(scomp, index, link, cfg, hw_config + curr_conf, config); + break; + case SOF_DAI_AMD_SP: + ret = sof_link_acp_sp_load(scomp, index, link, cfg, hw_config + curr_conf, config); + break; + case SOF_DAI_AMD_DMIC: + ret = sof_link_acp_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, + config); + break; default: dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type); ret = -EINVAL;
From: V sujith kumar Reddy vsreddy@amd.com
Add trace support and configure trace stream for ACP firmware.
Signed-off-by: Vishnuvardhanrao Ravuapati vishnuvardhanrao.ravulapati@amd.com Signed-off-by: V sujith kumar Reddy vsreddy@amd.com Reviewed-by: Bard Liao bard.liao@intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-trace.c | 84 +++++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 5 +++ sound/soc/sof/amd/renoir.c | 4 ++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/acp-trace.c
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index b27ce50014b8..7b9f1a0af3c8 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
-snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-trace.c b/sound/soc/sof/amd/acp-trace.c new file mode 100644 index 000000000000..fa4da8947186 --- /dev/null +++ b/sound/soc/sof/amd/acp-trace.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vishnuvardhanrao Ravuapati vishnuvardhanrao.ravulapati@amd.com +// V Sujith Kumar Reddy Vsujithkumar.Reddy@amd.com + +/*This file support Host TRACE Logger driver callback for SOF FW */ + +#include "acp.h" + +#define ACP_LOGGER_STREAM 8 +#define NUM_PAGES 16 + +int acp_sof_trace_release(struct snd_sof_dev *sdev) +{ + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + int ret; + + adata = sdev->pdata->hw_pdata; + stream = adata->dtrace_stream; + ret = acp_dsp_stream_put(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to release trace stream\n"); + return ret; + } + + adata->dtrace_stream = NULL; + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_trace_release, SND_SOC_SOF_AMD_COMMON); + +static int acp_sof_trace_prepare(struct snd_sof_dev *sdev, + struct sof_ipc_dma_trace_params_ext *params) +{ + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + int ret; + + adata = sdev->pdata->hw_pdata; + stream = adata->dtrace_stream; + stream->dmab = &sdev->dmatb; + stream->num_pages = NUM_PAGES; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to configure trace stream\n"); + return ret; + } + + params->buffer.phy_addr = stream->reg_offset; + params->stream_tag = stream->stream_tag; + + return 0; +} + +int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) +{ + struct sof_ipc_dma_trace_params_ext *params; + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + int ret; + + adata = sdev->pdata->hw_pdata; + stream = acp_dsp_stream_get(sdev, ACP_LOGGER_STREAM); + if (!stream) + return -ENODEV; + + adata->dtrace_stream = stream; + params = container_of(stream_tag, struct sof_ipc_dma_trace_params_ext, stream_tag); + ret = acp_sof_trace_prepare(sdev, params); + if (ret < 0) { + acp_dsp_stream_put(sdev, stream); + return ret; + } + + *stream_tag = stream->stream_tag; + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_trace_init, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 5f6e9eff116a..fd923f72a01a 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -139,6 +139,7 @@ struct acp_dev_data { u8 *data_buf; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; + struct acp_dsp_stream *dtrace_stream; };
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -197,4 +198,8 @@ extern const struct snd_sof_dsp_ops sof_renoir_ops;
/* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); + +/* Trace */ +int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); +int acp_sof_trace_release(struct snd_sof_dev *sdev); #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 3cd269bfe75d..43037109e130 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -173,6 +173,10 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { .machine_select = amd_sof_machine_select, .machine_register = sof_machine_register, .machine_unregister = sof_machine_unregister, + + /* Trace Logger */ + .trace_init = acp_sof_trace_init, + .trace_release = acp_sof_trace_release, }; EXPORT_SYMBOL(sof_renoir_ops);
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add callback to notify PSP after loading firmware on DSP. PSP will validate the loaded firmware and set qualifier bit to run firmware on secured AMD systems.
Signed-off-by: Julian Schroeder Julian.Schroeder@amd.com Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Curtis Malainey curtis@malainey.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/amd/acp-dsp-offset.h | 4 ++ sound/soc/sof/amd/acp.c | 66 +++++++++++++++++++++++++++++- sound/soc/sof/amd/acp.h | 21 ++++++++++ sound/soc/sof/amd/pci-rn.c | 5 +++ 4 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 1d11e9d69dce..63f13c111b24 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -54,6 +54,9 @@ #define ACP_PGFSM_STATUS 0x1420
/* Registers from ACP_INTR block */ +#define ACP_EXTERNAL_INTR_ENB 0x1800 +#define ACP_EXTERNAL_INTR_CNTL 0x1804 +#define ACP_EXTERNAL_INTR_STAT 0x1808 #define ACP_DSP_SW_INTR_CNTL 0x1814 #define ACP_DSP_SW_INTR_STAT 0x1818 #define ACP_SW_INTR_TRIG 0x181C @@ -68,6 +71,7 @@ #define ACP_SHA_DMA_CMD_STS 0x1CC0 #define ACP_SHA_DMA_ERR_STATUS 0x1CC4 #define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 +#define ACP_SHA_PSP_ACK 0x1C74
#define ACP_SCRATCH_REG_0 0x10000
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 74ede28aa8d8..4c5550e8d364 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,22 @@ #include "acp.h" #include "acp-dsp-offset.h"
+static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) +{ + pci_write_config_dword(dev, 0x60, smn_addr); + pci_write_config_dword(dev, 0x64, data); + + return 0; +} + +static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data) +{ + pci_write_config_dword(dev, 0x60, smn_addr); + pci_read_config_dword(dev, 0x64, data); + + return 0; +} + static void configure_acp_groupregisters(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; @@ -135,6 +151,25 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, return ret; }
+static int psp_fw_validate(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + int timeout; + u32 data; + + smn_write(adata->smn_dev, MP0_C2PMSG_26_REG, MBOX_ACP_SHA_DMA_COMMAND); + + for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) { + msleep(20); + smn_read(adata->smn_dev, MP0_C2PMSG_26_REG, &data); + if (data & MBOX_READY_MASK) + return 0; + } + + dev_err(sdev->dev, "FW validation timedout: status %x\n", data & MBOX_STATUS_MASK); + return -ETIMEDOUT; +} + int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, unsigned int start_addr, unsigned int dest_addr, unsigned int image_length) @@ -174,7 +209,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, return ret; }
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, DSP_FW_RUN_ENABLE); + ret = psp_fw_validate(adata); + if (ret) + return ret;
fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER); if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) { @@ -238,6 +275,13 @@ static irqreturn_t acp_irq_thread(int irq, void *context) struct snd_sof_dev *sdev = context; unsigned int val;
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT); + if (val & ACP_SHA_STAT) { + /* Clear SHA interrupt raised by PSP */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT, val); + return IRQ_HANDLED; + } + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); if (val & ACP_DSP_TO_HOST_IRQ) { sof_ops(sdev)->irq_thread(irq, sdev); @@ -326,6 +370,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); struct acp_dev_data *adata; + const struct sof_amd_acp_desc *chip; unsigned int addr; int ret;
@@ -346,18 +391,32 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->pdata->hw_pdata = adata;
+ chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device); + return -EIO; + } + + adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL); + if (!adata->smn_dev) { + dev_err(sdev->dev, "Failed to get host bridge device\n"); + return -ENODEV; + } + sdev->ipc_irq = pci->irq; ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); + pci_dev_put(adata->smn_dev); return ret; }
ret = acp_init(sdev); if (ret < 0) { free_irq(sdev->ipc_irq, sdev); + pci_dev_put(adata->smn_dev); return ret; }
@@ -371,6 +430,11 @@ EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_remove(struct snd_sof_dev *sdev) { + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + + if (adata->smn_dev) + pci_dev_put(adata->smn_dev); + if (sdev->ipc_irq) free_irq(sdev->ipc_irq, sdev);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index fd923f72a01a..a2f8e4219066 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -52,6 +52,15 @@
#define ACP_DSP_TO_HOST_IRQ 0x04
+#define HOST_BRIDGE_CZN 0x1630 +#define ACP_SHA_STAT 0x8000 +#define ACP_PSP_TIMEOUT_COUNTER 5 +#define ACP_EXT_INTR_ERROR_STAT 0x20000000 +#define MP0_C2PMSG_26_REG 0x03810570 +#define MBOX_ACP_SHA_DMA_COMMAND 0x330000 +#define MBOX_READY_MASK 0x80000000 +#define MBOX_STATUS_MASK 0xFFFF + struct acp_atu_grp_pte { u32 low; u32 high; @@ -140,6 +149,7 @@ struct acp_dev_data { struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; + struct pci_dev *smn_dev; };
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -202,4 +212,15 @@ int snd_amd_acp_find_config(struct pci_dev *pci); /* Trace */ int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); int acp_sof_trace_release(struct snd_sof_dev *sdev); + +struct sof_amd_acp_desc { + unsigned int host_bridge_id; +}; + +static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata *pdata) +{ + const struct sof_dev_desc *desc = pdata->desc; + + return desc->chip_info; +} #endif diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 3c379a5ef231..392ffbdf6417 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -43,12 +43,17 @@ static const struct resource renoir_res[] = { }, };
+static const struct sof_amd_acp_desc renoir_chip_info = { + .host_bridge_id = HOST_BRIDGE_CZN, +}; + static const struct sof_dev_desc renoir_desc = { .machines = snd_soc_acpi_amd_sof_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, + .chip_info = &renoir_chip_info, .default_fw_path = "amd/sof", .default_tplg_path = "amd/sof-tplg", .default_fw_filename = "sof-rn.ri",
On Wed, Nov 17, 2021 at 1:38 AM Daniel Baluta daniel.baluta@oss.nxp.com wrote:
From: Ajit Kumar Pandey AjitKumar.Pandey@amd.com
Add callback to notify PSP after loading firmware on DSP. PSP will validate the loaded firmware and set qualifier bit to run firmware on secured AMD systems.
Signed-off-by: Julian Schroeder Julian.Schroeder@amd.com Signed-off-by: Ajit Kumar Pandey AjitKumar.Pandey@amd.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Curtis Malainey curtis@malainey.com
Sorry github must be attached to the wrong email, please use
Reviewed-by: Curtis Malainey cujomalainey@chromium.org
Signed-off-by: Daniel Baluta daniel.baluta@nxp.com
sound/soc/sof/amd/acp-dsp-offset.h | 4 ++ sound/soc/sof/amd/acp.c | 66 +++++++++++++++++++++++++++++- sound/soc/sof/amd/acp.h | 21 ++++++++++ sound/soc/sof/amd/pci-rn.c | 5 +++ 4 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 1d11e9d69dce..63f13c111b24 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -54,6 +54,9 @@ #define ACP_PGFSM_STATUS 0x1420
/* Registers from ACP_INTR block */ +#define ACP_EXTERNAL_INTR_ENB 0x1800 +#define ACP_EXTERNAL_INTR_CNTL 0x1804 +#define ACP_EXTERNAL_INTR_STAT 0x1808 #define ACP_DSP_SW_INTR_CNTL 0x1814 #define ACP_DSP_SW_INTR_STAT 0x1818 #define ACP_SW_INTR_TRIG 0x181C @@ -68,6 +71,7 @@ #define ACP_SHA_DMA_CMD_STS 0x1CC0 #define ACP_SHA_DMA_ERR_STATUS 0x1CC4 #define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 +#define ACP_SHA_PSP_ACK 0x1C74
#define ACP_SCRATCH_REG_0 0x10000
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 74ede28aa8d8..4c5550e8d364 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,22 @@ #include "acp.h" #include "acp-dsp-offset.h"
+static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) +{
pci_write_config_dword(dev, 0x60, smn_addr);
pci_write_config_dword(dev, 0x64, data);
return 0;
+}
+static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data) +{
pci_write_config_dword(dev, 0x60, smn_addr);
pci_read_config_dword(dev, 0x64, data);
return 0;
+}
static void configure_acp_groupregisters(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; @@ -135,6 +151,25 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, return ret; }
+static int psp_fw_validate(struct acp_dev_data *adata) +{
struct snd_sof_dev *sdev = adata->dev;
int timeout;
u32 data;
smn_write(adata->smn_dev, MP0_C2PMSG_26_REG, MBOX_ACP_SHA_DMA_COMMAND);
for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
msleep(20);
smn_read(adata->smn_dev, MP0_C2PMSG_26_REG, &data);
if (data & MBOX_READY_MASK)
return 0;
}
dev_err(sdev->dev, "FW validation timedout: status %x\n", data & MBOX_STATUS_MASK);
return -ETIMEDOUT;
+}
int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, unsigned int start_addr, unsigned int dest_addr, unsigned int image_length) @@ -174,7 +209,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, return ret; }
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, DSP_FW_RUN_ENABLE);
ret = psp_fw_validate(adata);
if (ret)
return ret; fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER); if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) {
@@ -238,6 +275,13 @@ static irqreturn_t acp_irq_thread(int irq, void *context) struct snd_sof_dev *sdev = context; unsigned int val;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT);
if (val & ACP_SHA_STAT) {
/* Clear SHA interrupt raised by PSP */
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT, val);
return IRQ_HANDLED;
}
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); if (val & ACP_DSP_TO_HOST_IRQ) { sof_ops(sdev)->irq_thread(irq, sdev);
@@ -326,6 +370,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); struct acp_dev_data *adata;
const struct sof_amd_acp_desc *chip; unsigned int addr; int ret;
@@ -346,18 +391,32 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->pdata->hw_pdata = adata;
chip = get_chip_info(sdev->pdata);
if (!chip) {
dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device);
return -EIO;
}
adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL);
if (!adata->smn_dev) {
dev_err(sdev->dev, "Failed to get host bridge device\n");
return -ENODEV;
}
sdev->ipc_irq = pci->irq; ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq);
pci_dev_put(adata->smn_dev); return ret; } ret = acp_init(sdev); if (ret < 0) { free_irq(sdev->ipc_irq, sdev);
pci_dev_put(adata->smn_dev); return ret; }
@@ -371,6 +430,11 @@ EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_remove(struct snd_sof_dev *sdev) {
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
if (adata->smn_dev)
pci_dev_put(adata->smn_dev);
if (sdev->ipc_irq) free_irq(sdev->ipc_irq, sdev);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index fd923f72a01a..a2f8e4219066 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -52,6 +52,15 @@
#define ACP_DSP_TO_HOST_IRQ 0x04
+#define HOST_BRIDGE_CZN 0x1630 +#define ACP_SHA_STAT 0x8000 +#define ACP_PSP_TIMEOUT_COUNTER 5 +#define ACP_EXT_INTR_ERROR_STAT 0x20000000 +#define MP0_C2PMSG_26_REG 0x03810570 +#define MBOX_ACP_SHA_DMA_COMMAND 0x330000 +#define MBOX_READY_MASK 0x80000000 +#define MBOX_STATUS_MASK 0xFFFF
struct acp_atu_grp_pte { u32 low; u32 high; @@ -140,6 +149,7 @@ struct acp_dev_data { struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream;
struct pci_dev *smn_dev;
};
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -202,4 +212,15 @@ int snd_amd_acp_find_config(struct pci_dev *pci); /* Trace */ int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); int acp_sof_trace_release(struct snd_sof_dev *sdev);
+struct sof_amd_acp_desc {
unsigned int host_bridge_id;
+};
+static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata *pdata) +{
const struct sof_dev_desc *desc = pdata->desc;
return desc->chip_info;
+} #endif diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 3c379a5ef231..392ffbdf6417 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -43,12 +43,17 @@ static const struct resource renoir_res[] = { }, };
+static const struct sof_amd_acp_desc renoir_chip_info = {
.host_bridge_id = HOST_BRIDGE_CZN,
+};
static const struct sof_dev_desc renoir_desc = { .machines = snd_soc_acpi_amd_sof_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1,
.chip_info = &renoir_chip_info, .default_fw_path = "amd/sof", .default_tplg_path = "amd/sof-tplg", .default_fw_filename = "sof-rn.ri",
-- 2.27.0
From: YC Hung yc.hung@mediatek.com
This patch initialize to support SOF on Mediatek mt8195 platform. MT8195 has four Cortex A78 cores paired with four Cortex A55 cores. It also has Cadence HiFi-4 DSP single core. There are shared DRAM and mailbox interrupt between AP and DSP to use for IPC communication.
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/mediatek/Kconfig | 33 +++ sound/soc/sof/mediatek/Makefile | 2 + sound/soc/sof/mediatek/adsp_helper.h | 49 ++++ sound/soc/sof/mediatek/mediatek-ops.h | 8 + sound/soc/sof/mediatek/mt8195/Makefile | 3 + sound/soc/sof/mediatek/mt8195/mt8195.c | 334 +++++++++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.h | 155 ++++++++++++ 9 files changed, 586 insertions(+) create mode 100644 sound/soc/sof/mediatek/Kconfig create mode 100644 sound/soc/sof/mediatek/Makefile create mode 100644 sound/soc/sof/mediatek/adsp_helper.h create mode 100644 sound/soc/sof/mediatek/mediatek-ops.h create mode 100644 sound/soc/sof/mediatek/mt8195/Makefile create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195.h
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 68571bf2585e..41f97c6cb4c1 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -226,6 +226,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE source "sound/soc/sof/amd/Kconfig" source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" +source "sound/soc/sof/mediatek/Kconfig" source "sound/soc/sof/xtensa/Kconfig"
endif diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 011abfa0fd82..43a983376976 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_AMD_TOPLEVEL) += amd/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ +obj-$(CONFIG_SND_SOC_SOF_MTK_TOPLEVEL) += mediatek/ diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig new file mode 100644 index 000000000000..aeacf0e5bfbb --- /dev/null +++ b/sound/soc/sof/mediatek/Kconfig @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) + +config SND_SOC_SOF_MTK_TOPLEVEL + bool "SOF support for MTK audio DSPs" + depends on ARM64 || COMPILE_TEST + depends on SND_SOC_SOF_OF + help + This adds support for Sound Open Firmware for Mediatek platforms. + It is top level for all mediatek platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_MTK_TOPLEVEL +config SND_SOC_SOF_MTK_COMMON + tristate + select SND_SOC_SOF_OF_DEV + select SND_SOC_SOF + select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_COMPRESS + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_MT8195 + tristate "SOF support for MT8195 audio DSP" + select SND_SOC_SOF_MTK_COMMON + help + This adds support for Sound Open Firmware for Mediatek platforms + using the mt8195 processors. + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_MTK_TOPLEVEL diff --git a/sound/soc/sof/mediatek/Makefile b/sound/soc/sof/mediatek/Makefile new file mode 100644 index 000000000000..e8ec6da981de --- /dev/null +++ b/sound/soc/sof/mediatek/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +obj-$(CONFIG_SND_SOC_SOF_MT8195) += mt8195/ diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h new file mode 100644 index 000000000000..346953dd22db --- /dev/null +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2021 MediaTek Corporation. All rights reserved. + */ + +#ifndef __MTK_ADSP_HELPER_H__ +#define __MTK_ADSP_HELPER_H__ + +/* + * Global important adsp data structure. + */ +#define DSP_MBOX_NUM 3 + +struct mtk_adsp_chip_info { + phys_addr_t pa_sram; + phys_addr_t pa_dram; /* adsp dram physical base */ + phys_addr_t pa_shared_dram; /* adsp dram physical base */ + phys_addr_t pa_cfgreg; + phys_addr_t pa_mboxreg[DSP_MBOX_NUM]; + u32 sramsize; + u32 dramsize; + u32 cfgregsize; + void __iomem *va_sram; /* corresponding to pa_sram */ + void __iomem *va_dram; /* corresponding to pa_dram */ + void __iomem *va_cfgreg; + void __iomem *va_mboxreg[DSP_MBOX_NUM]; + void __iomem *shared_sram; /* part of va_sram */ + void __iomem *shared_dram; /* part of va_dram */ + phys_addr_t adsp_bootup_addr; + int dram_offset; /*dram offset between system and dsp view*/ +}; + +struct adsp_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct mbox_controller *adsp_mbox; + + struct mtk_adsp_chip_info *adsp; + + u32 (*ap2adsp_addr)(u32 addr, void *data); + u32 (*adsp2ap_addr)(u32 addr, void *data); + + void *private_data; +}; + +#endif diff --git a/sound/soc/sof/mediatek/mediatek-ops.h b/sound/soc/sof/mediatek/mediatek-ops.h new file mode 100644 index 000000000000..e0ffa69ecb0c --- /dev/null +++ b/sound/soc/sof/mediatek/mediatek-ops.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ + +#ifndef __MEDIATEK_OPS_H__ +#define __MEDIATEK_OPS_H__ + +extern const struct snd_sof_dsp_ops sof_mt8195_ops; + +#endif diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile new file mode 100644 index 000000000000..dd2b6e4affc9 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +snd-sof-mt8195-objs := mt8195.o +obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c new file mode 100644 index 000000000000..945601a0dc37 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2021 Mediatek Inc. All rights reserved. +// +// Author: YC Hung yc.hung@mediatek.com +// + +/* + * Hardware interface for audio DSP on mt8195 + */ + +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/of_reserved_mem.h> +#include <linux/module.h> + +#include <sound/sof.h> +#include <sound/sof/xtensa.h> +#include "../../ops.h" +#include "../../sof-audio.h" +#include "../adsp_helper.h" +#include "../mediatek-ops.h" +#include "mt8195.h" + +static int platform_parse_resource(struct platform_device *pdev, void *data) +{ + struct resource *mmio; + struct resource res; + struct device_node *mem_region; + struct device *dev = &pdev->dev; + struct mtk_adsp_chip_info *adsp = data; + int ret; + + mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!mem_region) { + dev_err(dev, "no dma memory-region phandle\n"); + return -ENODEV; + } + + ret = of_address_to_resource(mem_region, 0, &res); + if (ret) { + dev_err(dev, "of_address_to_resource dma failed\n"); + return ret; + } + + dev_dbg(dev, "DMA pbase=0x%llx, size=0x%llx\n", + (phys_addr_t)res.start, resource_size(&res)); + + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_err(dev, "of_reserved_mem_device_init failed\n"); + return ret; + } + + mem_region = of_parse_phandle(dev->of_node, "memory-region", 1); + if (!mem_region) { + dev_err(dev, "no memory-region sysmem phandle\n"); + return -ENODEV; + } + + ret = of_address_to_resource(mem_region, 0, &res); + if (ret) { + dev_err(dev, "of_address_to_resource sysmem failed\n"); + return ret; + } + + adsp->pa_dram = (phys_addr_t)res.start; + adsp->dramsize = resource_size(&res); + if (adsp->pa_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_dram); + return -EINVAL; + } + + if (adsp->dramsize < TOTAL_SIZE_SHARED_DRAM_FROM_TAIL) { + dev_err(dev, "adsp memory(%#x) is not enough for share\n", + adsp->dramsize); + return -EINVAL; + } + + dev_dbg(dev, "dram pbase=%pa, dramsize=%#x\n", + &adsp->pa_dram, adsp->dramsize); + + /* Parse CFG base */ + mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); + if (!mmio) { + dev_err(dev, "no ADSP-CFG register resource\n"); + return -ENXIO; + } + /* remap for DSP register accessing */ + adsp->va_cfgreg = devm_ioremap_resource(dev, mmio); + if (IS_ERR(adsp->va_cfgreg)) + return PTR_ERR(adsp->va_cfgreg); + + adsp->pa_cfgreg = (phys_addr_t)mmio->start; + adsp->cfgregsize = resource_size(mmio); + + dev_dbg(dev, "cfgreg-vbase=%p, cfgregsize=%#x\n", + adsp->va_cfgreg, adsp->cfgregsize); + + /* Parse SRAM */ + mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (!mmio) { + dev_err(dev, "no SRAM resource\n"); + return -ENXIO; + } + + adsp->pa_sram = (phys_addr_t)mmio->start; + adsp->sramsize = resource_size(mmio); + if (adsp->sramsize < TOTAL_SIZE_SHARED_SRAM_FROM_TAIL) { + dev_err(dev, "adsp SRAM(%#x) is not enough for share\n", + adsp->sramsize); + return -EINVAL; + } + + dev_dbg(dev, "sram pbase=%pa,%#x\n", &adsp->pa_sram, adsp->sramsize); + + return ret; +} + +static int adsp_sram_power_on(struct device *dev, bool on) +{ + void __iomem *va_dspsysreg; + u32 srampool_con; + + va_dspsysreg = ioremap(ADSP_SRAM_POOL_CON, 0x4); + if (!va_dspsysreg) { + dev_err(dev, "failed to ioremap sram pool base %#x\n", + ADSP_SRAM_POOL_CON); + return -ENOMEM; + } + + srampool_con = readl(va_dspsysreg); + if (on) + writel(srampool_con & ~DSP_SRAM_POOL_PD_MASK, va_dspsysreg); + else + writel(srampool_con | DSP_SRAM_POOL_PD_MASK, va_dspsysreg); + + iounmap(va_dspsysreg); + return 0; +} + +/* Init the basic DSP DRAM address */ +static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info *adsp) +{ + void __iomem *vaddr_emi_map; + int offset; + + if (!adsp) + return -ENXIO; + + vaddr_emi_map = devm_ioremap(dev, DSP_EMI_MAP_ADDR, 0x4); + if (!vaddr_emi_map) { + dev_err(dev, "failed to ioremap emi map base %#x\n", + DSP_EMI_MAP_ADDR); + return -ENOMEM; + } + + offset = adsp->pa_dram - DRAM_PHYS_BASE_FROM_DSP_VIEW; + adsp->dram_offset = offset; + offset >>= DRAM_REMAP_SHIFT; + dev_dbg(dev, "adsp->pa_dram %llx, offset %#x\n", adsp->pa_dram, offset); + writel(offset, vaddr_emi_map); + if (offset != readl(vaddr_emi_map)) { + dev_err(dev, "write emi map fail : %#x\n", readl(vaddr_emi_map)); + return -EIO; + } + + return 0; +} + +static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) +{ + struct device *dev = &pdev->dev; + struct mtk_adsp_chip_info *adsp = data; + u32 shared_size; + + /* remap shared-dram base to be non-cachable */ + shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; + adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; + if (adsp->va_dram) { + adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; + } else { + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "ioremap failed for shared DRAM\n"); + return -ENOMEM; + } + } + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%llx, size=%#x\n", + adsp->shared_dram, adsp->pa_shared_dram, shared_size); + + return 0; +} + +static int mt8195_run(struct snd_sof_dev *sdev) +{ + u32 adsp_bootup_addr; + + adsp_bootup_addr = SRAM_PHYS_BASE_FROM_DSP_VIEW; + dev_dbg(sdev->dev, "HIFIxDSP boot from base : 0x%08X\n", adsp_bootup_addr); + sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr); + + return 0; +} + +static int mt8195_dsp_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + struct adsp_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sdev->pdata->hw_pdata = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + priv->adsp = devm_kzalloc(&pdev->dev, sizeof(struct mtk_adsp_chip_info), GFP_KERNEL); + if (!priv->adsp) + return -ENOMEM; + + ret = platform_parse_resource(pdev, priv->adsp); + if (ret) + return ret; + + ret = adsp_sram_power_on(sdev->dev, true); + if (ret) { + dev_err(sdev->dev, "adsp_sram_power_on fail!\n"); + return ret; + } + + ret = adsp_memory_remap_init(&pdev->dev, priv->adsp); + if (ret) { + dev_err(sdev->dev, "adsp_memory_remap_init fail!\n"); + goto err_adsp_sram_power_off; + } + + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_sram, + priv->adsp->sramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { + dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", + &priv->adsp->pa_sram, priv->adsp->sramsize); + ret = -EINVAL; + goto err_adsp_sram_power_off; + } + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { + dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", + &priv->adsp->pa_dram, priv->adsp->dramsize); + ret = -EINVAL; + goto err_adsp_sram_power_off; + } + priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; + + ret = adsp_shared_base_ioremap(pdev, priv->adsp); + if (ret) { + dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); + goto err_adsp_sram_power_off; + } + + sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; + sdev->bar[DSP_MBOX0_BAR] = priv->adsp->va_mboxreg[0]; + sdev->bar[DSP_MBOX1_BAR] = priv->adsp->va_mboxreg[1]; + sdev->bar[DSP_MBOX2_BAR] = priv->adsp->va_mboxreg[2]; + + sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM; + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + + return 0; + +err_adsp_sram_power_off: + adsp_sram_power_on(&pdev->dev, false); + + return ret; +} + +static int mt8195_dsp_remove(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + + return adsp_sram_power_on(&pdev->dev, false); +} + +/* on mt8195 there is 1 to 1 match between type and BAR idx */ +static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} + +/* mt8195 ops */ +const struct snd_sof_dsp_ops sof_mt8195_ops = { + /* probe and remove */ + .probe = mt8195_dsp_probe, + .remove = mt8195_dsp_remove, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* misc */ + .get_bar_index = mt8195_get_bar_index, + + /* Firmware ops */ + .dsp_arch_ops = &sof_xtensa_arch_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, +}; +EXPORT_SYMBOL(sof_mt8195_ops); + +MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h new file mode 100644 index 000000000000..48cbbb5aacb5 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2021 MediaTek Corporation. All rights reserved. + * + * Header file for the mt8195 DSP register definition + */ + +#ifndef __MT8195_H +#define __MT8195_H + +struct mtk_adsp_chip_info; + +#define DSP_REG_BASE 0x10803000 +#define SCP_CFGREG_BASE 0x10724000 +#define DSP_SYSAO_BASE 0x1080C000 + +/***************************************************************************** + * R E G I S T E R TABLE + *****************************************************************************/ +#define DSP_JTAGMUX 0x0000 +#define DSP_ALTRESETVEC 0x0004 +#define DSP_PDEBUGDATA 0x0008 +#define DSP_PDEBUGBUS0 0x000c +#define PDEBUG_ENABLE BIT(0) +#define DSP_PDEBUGBUS1 0x0010 +#define DSP_PDEBUGINST 0x0014 +#define DSP_PDEBUGLS0STAT 0x0018 +#define DSP_PDEBUGLS1STAT 0x001c +#define DSP_PDEBUGPC 0x0020 +#define DSP_RESET_SW 0x0024 /*reset sw*/ +#define ADSP_BRESET_SW BIT(0) +#define ADSP_DRESET_SW BIT(1) +#define ADSP_RUNSTALL BIT(3) +#define STATVECTOR_SEL BIT(4) +#define DSP_PFAULTBUS 0x0028 +#define DSP_PFAULTINFO 0x002c +#define DSP_GPR00 0x0030 +#define DSP_GPR01 0x0034 +#define DSP_GPR02 0x0038 +#define DSP_GPR03 0x003c +#define DSP_GPR04 0x0040 +#define DSP_GPR05 0x0044 +#define DSP_GPR06 0x0048 +#define DSP_GPR07 0x004c +#define DSP_GPR08 0x0050 +#define DSP_GPR09 0x0054 +#define DSP_GPR0A 0x0058 +#define DSP_GPR0B 0x005c +#define DSP_GPR0C 0x0060 +#define DSP_GPR0D 0x0064 +#define DSP_GPR0E 0x0068 +#define DSP_GPR0F 0x006c +#define DSP_GPR10 0x0070 +#define DSP_GPR11 0x0074 +#define DSP_GPR12 0x0078 +#define DSP_GPR13 0x007c +#define DSP_GPR14 0x0080 +#define DSP_GPR15 0x0084 +#define DSP_GPR16 0x0088 +#define DSP_GPR17 0x008c +#define DSP_GPR18 0x0090 +#define DSP_GPR19 0x0094 +#define DSP_GPR1A 0x0098 +#define DSP_GPR1B 0x009c +#define DSP_GPR1C 0x00a0 +#define DSP_GPR1D 0x00a4 +#define DSP_GPR1E 0x00a8 +#define DSP_GPR1F 0x00ac +#define DSP_TCM_OFFSET 0x00b0 /* not used */ +#define DSP_DDR_OFFSET 0x00b4 /* not used */ +#define DSP_INTFDSP 0x00d0 +#define DSP_INTFDSP_CLR 0x00d4 +#define DSP_SRAM_PD_SW1 0x00d8 +#define DSP_SRAM_PD_SW2 0x00dc +#define DSP_OCD 0x00e0 +#define DSP_RG_DSP_IRQ_POL 0x00f0 /* not used */ +#define DSP_DSP_IRQ_EN 0x00f4 /* not used */ +#define DSP_DSP_IRQ_LEVEL 0x00f8 /* not used */ +#define DSP_DSP_IRQ_STATUS 0x00fc /* not used */ +#define DSP_RG_INT2CIRQ 0x0114 +#define DSP_RG_INT_POL_CTL0 0x0120 +#define DSP_RG_INT_EN_CTL0 0x0130 +#define DSP_RG_INT_LV_CTL0 0x0140 +#define DSP_RG_INT_STATUS0 0x0150 +#define DSP_PDEBUGSTATUS0 0x0200 +#define DSP_PDEBUGSTATUS1 0x0204 +#define DSP_PDEBUGSTATUS2 0x0208 +#define DSP_PDEBUGSTATUS3 0x020c +#define DSP_PDEBUGSTATUS4 0x0210 +#define DSP_PDEBUGSTATUS5 0x0214 +#define DSP_PDEBUGSTATUS6 0x0218 +#define DSP_PDEBUGSTATUS7 0x021c +#define DSP_DSP2PSRAM_PRIORITY 0x0220 /* not used */ +#define DSP_AUDIO_DSP2SPM_INT 0x0224 +#define DSP_AUDIO_DSP2SPM_INT_ACK 0x0228 +#define DSP_AUDIO_DSP_DEBUG_SEL 0x022C +#define DSP_AUDIO_DSP_EMI_BASE_ADDR 0x02E0 /* not used */ +#define DSP_AUDIO_DSP_SHARED_IRAM 0x02E4 +#define DSP_AUDIO_DSP_CKCTRL_P2P_CK_CON 0x02F0 +#define DSP_RG_SEMAPHORE00 0x0300 +#define DSP_RG_SEMAPHORE01 0x0304 +#define DSP_RG_SEMAPHORE02 0x0308 +#define DSP_RG_SEMAPHORE03 0x030C +#define DSP_RG_SEMAPHORE04 0x0310 +#define DSP_RG_SEMAPHORE05 0x0314 +#define DSP_RG_SEMAPHORE06 0x0318 +#define DSP_RG_SEMAPHORE07 0x031C +#define DSP_RESERVED_0 0x03F0 +#define DSP_RESERVED_1 0x03F4 + +/* dsp wdt */ +#define DSP_WDT_MODE 0x0400 + +/* dsp mbox */ +#define DSP_MBOX_IN_CMD 0x00 +#define DSP_MBOX_IN_CMD_CLR 0x04 +#define DSP_MBOX_OUT_CMD 0x1c +#define DSP_MBOX_OUT_CMD_CLR 0x20 +#define DSP_MBOX_IN_MSG0 0x08 +#define DSP_MBOX_IN_MSG1 0x0C +#define DSP_MBOX_OUT_MSG0 0x24 +#define DSP_MBOX_OUT_MSG1 0x28 + +/*dsp sys ao*/ +#define ADSP_SRAM_POOL_CON (DSP_SYSAO_BASE + 0x30) +#define DSP_SRAM_POOL_PD_MASK 0xf +#define DSP_EMI_MAP_ADDR (DSP_SYSAO_BASE + 0x81c) + +/* DSP memories */ +#define MBOX_OFFSET 0x800000 /* DRAM */ +#define MBOX_SIZE 0x1000 /* consistent with which in memory.h of sof fw */ +#define DSP_DRAM_SIZE 0x1000000 /* 16M */ + +#define DSP_REG_BAR 4 +#define DSP_MBOX0_BAR 5 +#define DSP_MBOX1_BAR 6 +#define DSP_MBOX2_BAR 7 + +#define TOTAL_SIZE_SHARED_SRAM_FROM_TAIL 0x0 + +#define SIZE_SHARED_DRAM_DL 0x40000 /*Shared buffer for Downlink*/ +#define SIZE_SHARED_DRAM_UL 0x40000 /*Shared buffer for Uplink*/ + +#define TOTAL_SIZE_SHARED_DRAM_FROM_TAIL \ + (SIZE_SHARED_DRAM_DL + SIZE_SHARED_DRAM_UL) + +#define SRAM_PHYS_BASE_FROM_DSP_VIEW 0x40000000 /* MT8195 DSP view */ +#define DRAM_PHYS_BASE_FROM_DSP_VIEW 0x60000000 /* MT8195 DSP view */ + +/*remap dram between AP and DSP view, 4KB aligned*/ +#define DRAM_REMAP_SHIFT 12 +#define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1) + +#endif
From: YC Hung yc.hung@mediatek.com
Add the definition for Mediatek audio front end(AFE) tokens,include AFE sampling rate, channels, and format.
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- include/uapi/sound/sof/tokens.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 02b71a8deea4..b72fa385bebf 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -140,4 +140,9 @@ #define SOF_TKN_INTEL_HDA_RATE 1500 #define SOF_TKN_INTEL_HDA_CH 1501
+/* AFE */ +#define SOF_TKN_MEDIATEK_AFE_RATE 1600 +#define SOF_TKN_MEDIATEK_AFE_CH 1601 +#define SOF_TKN_MEDIATEK_AFE_FORMAT 1602 + #endif
From: YC Hung yc.hung@mediatek.com
Add new sof dai and config to pass topology file configuration to SOF firmware running on Mediatek platform DSP core. Add mediatek audio front end(AFE) to the list of supported sof_dais
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- include/sound/sof/dai-mediatek.h | 23 +++++++++++++ include/sound/sof/dai.h | 3 ++ sound/soc/sof/pcm.c | 12 +++++++ sound/soc/sof/topology.c | 59 ++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 include/sound/sof/dai-mediatek.h
diff --git a/include/sound/sof/dai-mediatek.h b/include/sound/sof/dai-mediatek.h new file mode 100644 index 000000000000..62dd4720558d --- /dev/null +++ b/include/sound/sof/dai-mediatek.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * Copyright(c) 2021 Mediatek Corporation. All rights reserved. + * + * Author: Bo Pan bo.pan@mediatek.com + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_MEDIATEK_H__ +#define __INCLUDE_SOUND_SOF_DAI_MEDIATEK_H__ + +#include <sound/sof/header.h> + +struct sof_ipc_dai_mtk_afe_params { + struct sof_ipc_hdr hdr; + u32 channels; + u32 rate; + u32 format; + u32 stream_id; + u32 reserved[4]; /* reserve for future */ +} __packed; + +#endif + diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 3782127a7095..5132bc60f54b 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -13,6 +13,7 @@ #include <sound/sof/dai-intel.h> #include <sound/sof/dai-imx.h> #include <sound/sof/dai-amd.h> +#include <sound/sof/dai-mediatek.h>
/* * DAI Configuration. @@ -70,6 +71,7 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_BT, /**< AMD ACP BT*/ SOF_DAI_AMD_SP, /**< AMD ACP SP */ SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */ + SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */ };
/* general purpose DAI configuration */ @@ -97,6 +99,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_acp_params acpbt; struct sof_ipc_dai_acp_params acpsp; struct sof_ipc_dai_acp_params acpdmic; + struct sof_ipc_dai_mtk_afe_params afe; }; } __packed;
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8d313c9862cb..31dd79b794f1 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -808,6 +808,18 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa channels->min = dai->dai_config->esai.tdm_slots; channels->max = dai->dai_config->esai.tdm_slots;
+ dev_dbg(component->dev, + "rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_MEDIATEK_AFE: + rate->min = dai->dai_config->afe.rate; + rate->max = dai->dai_config->afe.rate; + channels->min = dai->dai_config->afe.channels; + channels->max = dai->dai_config->afe.channels; + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); dev_dbg(component->dev, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 72e671c15a34..10caf2b1a33c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -379,6 +379,7 @@ static const struct sof_dai_types sof_dais[] = { {"ACP", SOF_DAI_AMD_BT}, {"ACPSP", SOF_DAI_AMD_SP}, {"ACPDMIC", SOF_DAI_AMD_DMIC}, + {"AFE", SOF_DAI_MEDIATEK_AFE}, };
static enum sof_ipc_dai_type find_dai(const char *name) @@ -806,6 +807,19 @@ static const struct sof_topology_token led_tokens[] = { get_token_u32, offsetof(struct snd_sof_led_control, direction), 0}, };
+/* AFE */ +static const struct sof_topology_token afe_tokens[] = { + {SOF_TKN_MEDIATEK_AFE_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_mtk_afe_params, rate), 0}, + {SOF_TKN_MEDIATEK_AFE_CH, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_mtk_afe_params, channels), 0}, + {SOF_TKN_MEDIATEK_AFE_FORMAT, + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_dai_mtk_afe_params, format), 0}, +}; + static int sof_parse_uuid_tokens(struct snd_soc_component *scomp, void *object, const struct sof_topology_token *tokens, @@ -3091,6 +3105,48 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, int index, return ret; }
+static int sof_link_afe_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct snd_soc_dai *dai; + u32 size = sizeof(*config); + int ret; + + config->hdr.size = size; + + /* get any bespoke DAI tokens */ + ret = sof_parse_tokens(scomp, &config->afe, afe_tokens, + ARRAY_SIZE(afe_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(scomp->dev, "parse afe tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n", + config->afe.rate, config->afe.channels, config->afe.format); + + dai = snd_soc_find_dai(link->cpus); + if (!dai) { + dev_err(scomp->dev, "%s: failed to find dai %s", __func__, link->cpus->dai_name); + return -EINVAL; + } + + config->afe.stream_id = DMA_CHAN_INVALID; + + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(scomp->dev, "failed to process afe dai link %s", link->name); + + return ret; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -3386,6 +3442,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_acp_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; + case SOF_DAI_MEDIATEK_AFE: + ret = sof_link_afe_load(scomp, index, link, cfg, hw_config + curr_conf, config); + break; default: dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type); ret = -EINVAL;
On Wed, Nov 17, 2021 at 11:37:29AM +0200, Daniel Baluta wrote:
From: YC Hung yc.hung@mediatek.com
Add new sof dai and config to pass topology file configuration to SOF firmware running on Mediatek platform DSP core. Add mediatek audio front end(AFE) to the list of supported sof_dais
This breaks an x86 allmodconfig build:
/mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c: In function 'mt8195_run': /mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c:207:2: error: implicit declaration of function 'sof_hifixdsp_boot_sequence' [-Werror=implicit-function-declaration] 207 | sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ At top level: /mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c:201:12: error: 'mt8195_run' defined but not used [-Werror=unused-function] 201 | static int mt8195_run(struct snd_sof_dev *sdev) | ^~~~~~~~~~ cc1: all warnings being treated as errors
_boot_sequence is added in "ASoC: SOF: mediatek: Add fw loader and mt8195 dsp ops to load firmware" which is later in the series.
mt8195_run should be either global, a static inline or not declared in the header at all.
On 11/17/21 7:29 PM, Mark Brown wrote:
On Wed, Nov 17, 2021 at 11:37:29AM +0200, Daniel Baluta wrote:
From: YC Hung yc.hung@mediatek.com
Add new sof dai and config to pass topology file configuration to SOF firmware running on Mediatek platform DSP core. Add mediatek audio front end(AFE) to the list of supported sof_dais
This breaks an x86 allmodconfig build:
/mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c: In function 'mt8195_run': /mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c:207:2: error: implicit declaration of function 'sof_hifixdsp_boot_sequence' [-Werror=implicit-function-declaration] 207 | sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ At top level: /mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c:201:12: error: 'mt8195_run' defined but not used [-Werror=unused-function] 201 | static int mt8195_run(struct snd_sof_dev *sdev) | ^~~~~~~~~~ cc1: all warnings being treated as errors
_boot_sequence is added in "ASoC: SOF: mediatek: Add fw loader and mt8195 dsp ops to load firmware" which is later in the series.
mt8195_run should be either global, a static inline or not declared in the header at all.
YC,
Please send a fix for this on top of topic/sof-dev. I will take care of the squash and resend.
Hi Mark,
I noticed that you already applied this. Should I resend the entire series or just a fixup?
On Wed, Nov 17, 2021 at 7:32 PM Daniel Baluta daniel.baluta@nxp.com wrote:
On 11/17/21 7:29 PM, Mark Brown wrote:
On Wed, Nov 17, 2021 at 11:37:29AM +0200, Daniel Baluta wrote:
From: YC Hung yc.hung@mediatek.com
Add new sof dai and config to pass topology file configuration to SOF firmware running on Mediatek platform DSP core. Add mediatek audio front end(AFE) to the list of supported sof_dais
This breaks an x86 allmodconfig build:
/mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c: In function 'mt8195_run': /mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c:207:2: error: implicit declaration of function 'sof_hifixdsp_boot_sequence' [-Werror=implicit-function-declaration] 207 | sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ At top level: /mnt/kernel/sound/soc/sof/mediatek/mt8195/mt8195.c:201:12: error: 'mt8195_run' defined but not used [-Werror=unused-function] 201 | static int mt8195_run(struct snd_sof_dev *sdev) | ^~~~~~~~~~ cc1: all warnings being treated as errors
_boot_sequence is added in "ASoC: SOF: mediatek: Add fw loader and mt8195 dsp ops to load firmware" which is later in the series.
mt8195_run should be either global, a static inline or not declared in the header at all.
YC,
Please send a fix for this on top of topic/sof-dev. I will take care of the squash and resend.
On Thu, Nov 18, 2021 at 11:34 AM Daniel Baluta daniel.baluta@gmail.com wrote:
Hi Mark,
I noticed that you already applied this. Should I resend the entire series or just a fixup?
Later edit: All good. You applied only the AMD patches. Sorry for the noise.
Will fix and resend the MTK patches.
From: YC Hung yc.hung@mediatek.com
Add mt8195-loader module with ops callback to load and run firmware on mt8195 platform.
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/mediatek/mt8195/Makefile | 2 +- sound/soc/sof/mediatek/mt8195/mt8195-loader.c | 56 +++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.c | 8 +++ sound/soc/sof/mediatek/mt8195/mt8195.h | 3 + 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-loader.c
diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile index dd2b6e4affc9..66cdc0e7bf3c 100644 --- a/sound/soc/sof/mediatek/mt8195/Makefile +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-mt8195-objs := mt8195.o +snd-sof-mt8195-objs := mt8195.o mt8195-loader.o obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-loader.c b/sound/soc/sof/mediatek/mt8195/mt8195-loader.c new file mode 100644 index 000000000000..ed18d6379e92 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195-loader.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright (c) 2021 Mediatek Corporation. All rights reserved. +// +// Author: YC Hung yc.hung@mediatek.com +// +// Hardware interface for mt8195 DSP code loader + +#include <sound/sof.h> +#include "mt8195.h" +#include "../../ops.h" + +void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr) +{ + /* ADSP bootup base */ + snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_ALTRESETVEC, boot_addr); + + /* pull high RunStall (set bit3 to 1) */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_RUNSTALL, ADSP_RUNSTALL); + + /* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + DSP_RESET_SW, DSP_RESET_SW); + + /* toggle DReset & BReset */ + /* pull high DReset & BReset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW); + + /* pull low DReset & BReset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW, + 0); + + /* Enable PDebug */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_PDEBUGBUS0, + PDEBUG_ENABLE, + PDEBUG_ENABLE); + + /* release RunStall (set bit3 to 0) */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_RUNSTALL, 0); +} + +void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev) +{ + /* Clear to 0 firstly */ + snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_RESET_SW, 0x0); + + /* RUN_STALL pull high again to reset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_RUNSTALL, ADSP_RUNSTALL); +} + diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 945601a0dc37..88da6c2de070 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -305,6 +305,9 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { .probe = mt8195_dsp_probe, .remove = mt8195_dsp_remove,
+ /* DSP core boot */ + .run = mt8195_run, + /* Block IO */ .block_read = sof_block_read, .block_write = sof_block_write, @@ -318,6 +321,11 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { /* misc */ .get_bar_index = mt8195_get_bar_index,
+ /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops,
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h index 48cbbb5aacb5..929424182357 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.h +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -10,6 +10,7 @@ #define __MT8195_H
struct mtk_adsp_chip_info; +struct snd_sof_dev;
#define DSP_REG_BASE 0x10803000 #define SCP_CFGREG_BASE 0x10724000 @@ -152,4 +153,6 @@ struct mtk_adsp_chip_info; #define DRAM_REMAP_SHIFT 12 #define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1)
+void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr); +void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev); #endif
From: YC Hung yc.hung@mediatek.com
Add SOF device and DT descriptor for Mediatek mt8195 platform.
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/Kconfig | 2 +- sound/soc/sof/sof-of-dev.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 41f97c6cb4c1..977835f9b987 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -43,7 +43,7 @@ config SND_SOC_SOF_OF select SND_SOC_SOF help This adds support for Device Tree enumeration. This option is - required to enable i.MX8 devices. + required to enable i.MX8 or Mediatek devices. Say Y if you need this option. If unsure select "N".
config SND_SOC_SOF_COMPRESS diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 885430a42226..412cbb824b84 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -13,6 +13,7 @@
#include "ops.h" #include "imx/imx-ops.h" +#include "mediatek/mediatek-ops.h"
static char *fw_path; module_param(fw_path, charp, 0444); @@ -50,6 +51,15 @@ static struct sof_dev_desc sof_of_imx8mp_desc = { .ops = &sof_imx8m_ops, }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MT8195) +static const struct sof_dev_desc sof_of_mt8195_desc = { + .default_fw_path = "mediatek/sof", + .default_tplg_path = "mediatek/sof-tplg", + .default_fw_filename = "sof-mt8195.ri", + .nocodec_tplg_filename = "sof-mt8195-nocodec.tplg", + .ops = &sof_mt8195_ops, +}; +#endif
static const struct dev_pm_ops sof_of_pm = { .prepare = snd_sof_prepare, @@ -130,6 +140,9 @@ static const struct of_device_id sof_of_ids[] = { #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M) { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MT8195) + { .compatible = "mediatek,mt8195-dsp", .data = &sof_of_mt8195_desc}, #endif { } };
From: YC Hung yc.hung@mediatek.com
Add dsp ops callback to register AFE DL2/DL3/UL4/UL5 sof dai's with ALSA
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Guennadi Liakhovetski guennadi.liakhovetski@linux.intel.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/mediatek/mt8195/mt8195.c | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 88da6c2de070..99075598a35a 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -299,6 +299,37 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; }
+static struct snd_soc_dai_driver mt8195_dai[] = { +{ + .name = "SOF_DL2", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_DL3", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL4", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL5", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +}; + /* mt8195 ops */ const struct snd_sof_dsp_ops sof_mt8195_ops = { /* probe and remove */ @@ -329,6 +360,10 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops,
+ /* DAI drivers */ + .drv = mt8195_dai, + .num_drv = ARRAY_SIZE(mt8195_dai), + /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
From: YC Hung yc.hung@mediatek.com
Add adsp clock on/off support on mt8195 platform.
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/mediatek/adsp_helper.h | 2 +- sound/soc/sof/mediatek/mt8195/Makefile | 2 +- sound/soc/sof/mediatek/mt8195/mt8195-clk.c | 158 +++++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195-clk.h | 28 ++++ sound/soc/sof/mediatek/mt8195/mt8195.c | 22 ++- 5 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-clk.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-clk.h
diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index 346953dd22db..6734e2c0c6b1 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -39,7 +39,7 @@ struct adsp_priv { struct mbox_controller *adsp_mbox;
struct mtk_adsp_chip_info *adsp; - + struct clk **clk; u32 (*ap2adsp_addr)(u32 addr, void *data); u32 (*adsp2ap_addr)(u32 addr, void *data);
diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile index 66cdc0e7bf3c..afc4f21fccc5 100644 --- a/sound/soc/sof/mediatek/mt8195/Makefile +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-mt8195-objs := mt8195.o mt8195-loader.o +snd-sof-mt8195-objs := mt8195.o mt8195-clk.o mt8195-loader.o obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c new file mode 100644 index 000000000000..6bcb4b9b00fb --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2021 Mediatek Corporation. All rights reserved. +// +// Author: YC Hung yc.hung@mediatek.com +// +// Hardware interface for mt8195 DSP clock + +#include <linux/clk.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> +#include "mt8195.h" +#include "mt8195-clk.h" +#include "../adsp_helper.h" +#include "../../sof-audio.h" + +static const char *adsp_clks[ADSP_CLK_MAX] = { + [CLK_TOP_ADSP] = "adsp_sel", + [CLK_TOP_CLK26M] = "clk26m_ck", + [CLK_TOP_AUDIO_LOCAL_BUS] = "audio_local_bus", + [CLK_TOP_MAINPLL_D7_D2] = "mainpll_d7_d2", + [CLK_SCP_ADSP_AUDIODSP] = "scp_adsp_audiodsp", + [CLK_TOP_AUDIO_H] = "audio_h", +}; + +int mt8195_adsp_init_clock(struct snd_sof_dev *sdev) +{ + struct device *dev = sdev->dev; + struct adsp_priv *priv = sdev->pdata->hw_pdata; + int i; + + priv->clk = devm_kcalloc(dev, ADSP_CLK_MAX, sizeof(*priv->clk), GFP_KERNEL); + + if (!priv->clk) + return -ENOMEM; + + for (i = 0; i < ADSP_CLK_MAX; i++) { + priv->clk[i] = devm_clk_get(dev, adsp_clks[i]); + if (IS_ERR(priv->clk[i])) + return PTR_ERR(priv->clk[i]); + } + + return 0; +} + +static int adsp_enable_all_clock(struct snd_sof_dev *sdev) +{ + struct device *dev = sdev->dev; + struct adsp_priv *priv = sdev->pdata->hw_pdata; + int ret; + + ret = clk_prepare_enable(priv->clk[CLK_TOP_MAINPLL_D7_D2]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(mainpll_d7_d2) fail %d\n", + __func__, ret); + return ret; + } + + ret = clk_prepare_enable(priv->clk[CLK_TOP_ADSP]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(adsp_sel) fail %d\n", + __func__, ret); + goto disable_mainpll_d7_d2_clk; + } + + ret = clk_prepare_enable(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(audio_local_bus) fail %d\n", + __func__, ret); + goto disable_dsp_sel_clk; + } + + ret = clk_prepare_enable(priv->clk[CLK_SCP_ADSP_AUDIODSP]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(scp_adsp_audiodsp) fail %d\n", + __func__, ret); + goto disable_audio_local_bus_clk; + } + + ret = clk_prepare_enable(priv->clk[CLK_TOP_AUDIO_H]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(audio_h) fail %d\n", + __func__, ret); + goto disable_scp_adsp_audiodsp_clk; + } + + return 0; + +disable_scp_adsp_audiodsp_clk: + clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]); +disable_audio_local_bus_clk: + clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); +disable_dsp_sel_clk: + clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]); +disable_mainpll_d7_d2_clk: + clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]); + + return ret; +} + +static void adsp_disable_all_clock(struct snd_sof_dev *sdev) +{ + struct adsp_priv *priv = sdev->pdata->hw_pdata; + + clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_H]); + clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]); + clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); + clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]); + clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]); +} + +static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable) +{ + struct device *dev = sdev->dev; + struct adsp_priv *priv = sdev->pdata->hw_pdata; + int ret; + + dev_dbg(dev, "%s: %s\n", __func__, enable ? "on" : "off"); + + if (enable) { + ret = clk_set_parent(priv->clk[CLK_TOP_ADSP], + priv->clk[CLK_TOP_CLK26M]); + if (ret) { + dev_err(dev, "failed to set dsp_sel to clk26m: %d\n", ret); + return ret; + } + + ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS], + priv->clk[CLK_TOP_MAINPLL_D7_D2]); + if (ret) { + dev_err(dev, "set audio_local_bus failed %d\n", ret); + return ret; + } + + ret = adsp_enable_all_clock(sdev); + if (ret) { + dev_err(dev, "failed to adsp_enable_clock: %d\n", ret); + return ret; + } + } else { + adsp_disable_all_clock(sdev); + } + + return 0; +} + +int adsp_clock_on(struct snd_sof_dev *sdev) +{ + /* Open ADSP clock */ + return adsp_default_clk_init(sdev, 1); +} + +int adsp_clock_off(struct snd_sof_dev *sdev) +{ + /* Close ADSP clock */ + return adsp_default_clk_init(sdev, 0); +} + diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.h b/sound/soc/sof/mediatek/mt8195/mt8195-clk.h new file mode 100644 index 000000000000..9cc0573d5cd2 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2021 MediaTek Corporation. All rights reserved. + * + * Header file for the mt8195 DSP clock definition + */ + +#ifndef __MT8195_CLK_H +#define __MT8195_CLK_H + +struct snd_sof_dev; + +/*DSP clock*/ +enum adsp_clk_id { + CLK_TOP_ADSP, + CLK_TOP_CLK26M, + CLK_TOP_AUDIO_LOCAL_BUS, + CLK_TOP_MAINPLL_D7_D2, + CLK_SCP_ADSP_AUDIODSP, + CLK_TOP_AUDIO_H, + ADSP_CLK_MAX +}; + +int mt8195_adsp_init_clock(struct snd_sof_dev *sdev); +int adsp_clock_on(struct snd_sof_dev *sdev); +int adsp_clock_off(struct snd_sof_dev *sdev); +#endif diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 99075598a35a..5bfae9379ac8 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -25,6 +25,7 @@ #include "../adsp_helper.h" #include "../mediatek-ops.h" #include "mt8195.h" +#include "mt8195-clk.h"
static int platform_parse_resource(struct platform_device *pdev, void *data) { @@ -231,10 +232,22 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) if (ret) return ret;
+ ret = mt8195_adsp_init_clock(sdev); + if (ret) { + dev_err(sdev->dev, "mt8195_adsp_init_clock failed\n"); + return -EINVAL; + } + + ret = adsp_clock_on(sdev); + if (ret) { + dev_err(sdev->dev, "adsp_clock_on fail!\n"); + return -EINVAL; + } + ret = adsp_sram_power_on(sdev->dev, true); if (ret) { dev_err(sdev->dev, "adsp_sram_power_on fail!\n"); - return ret; + goto exit_clk_disable; }
ret = adsp_memory_remap_init(&pdev->dev, priv->adsp); @@ -282,6 +295,8 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
err_adsp_sram_power_off: adsp_sram_power_on(&pdev->dev, false); +exit_clk_disable: + adsp_clock_off(sdev);
return ret; } @@ -290,7 +305,10 @@ static int mt8195_dsp_remove(struct snd_sof_dev *sdev) { struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
- return adsp_sram_power_on(&pdev->dev, false); + adsp_sram_power_on(&pdev->dev, false); + adsp_clock_off(sdev); + + return 0; }
/* on mt8195 there is 1 to 1 match between type and BAR idx */
From: YC Hung yc.hung@mediatek.com
Add DSP system PM callback for suspend and resume
Signed-off-by: YC Hung yc.hung@mediatek.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Daniel Baluta daniel.baluta@nxp.com Signed-off-by: Daniel Baluta daniel.baluta@nxp.com --- sound/soc/sof/mediatek/mt8195/mt8195.c | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 5bfae9379ac8..40e5a25875a6 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -311,6 +311,44 @@ static int mt8195_dsp_remove(struct snd_sof_dev *sdev) return 0; }
+static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + int ret; + + /* stall and reset dsp */ + sof_hifixdsp_shutdown(sdev); + + /* power down adsp sram */ + ret = adsp_sram_power_on(&pdev->dev, false); + if (ret) { + dev_err(sdev->dev, "adsp_sram_power_off fail!\n"); + return ret; + } + + /* turn off adsp clock */ + return adsp_clock_off(sdev); +} + +static int mt8195_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + /* turn on adsp clock */ + ret = adsp_clock_on(sdev); + if (ret) { + dev_err(sdev->dev, "adsp_clock_on fail!\n"); + return ret; + } + + /* power on adsp sram */ + ret = adsp_sram_power_on(sdev->dev, true); + if (ret) + dev_err(sdev->dev, "adsp_sram_power_on fail!\n"); + + return ret; +} + /* on mt8195 there is 1 to 1 match between type and BAR idx */ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) { @@ -382,6 +420,10 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { .drv = mt8195_dai, .num_drv = ARRAY_SIZE(mt8195_dai),
+ /* PM */ + .suspend = mt8195_dsp_suspend, + .resume = mt8195_dsp_resume, + /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
On Wed, 17 Nov 2021 11:37:13 +0200, Daniel Baluta wrote:
From: Daniel Baluta daniel.baluta@nxp.com
This patchseries adds Renoir ACP HW support and Mediatek MT8195 platform.
Notes:
- I first send the meditatek support in a previous emails but it failed to apply because there are some dependencies on AMD patches related to DAI ids.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[01/21] ASoC: SOF: amd: Add Renoir ACP HW support commit: 846aef1d7cc05651e27c17c3b4e2b5ce5cdec97b [02/21] ASoC: SOF: amd: Add helper callbacks for ACP's DMA configuration commit: 0e44572a28a49109eae23af1545c658b86c4bf00 [03/21] ASoC: SOF: amd: Add fw loader and renoir dsp ops to load firmware commit: 7e51a9e38ab204eba2844b8773486392d7444435 [04/21] ASoC: SOF: amd: Add IPC support for ACP IP block commit: 738a2b5e2cc9fd63d48faac11c8d60a5a2313a9d [05/21] ASoC: SOF: amd: Add dai driver dsp ops callback for Renoir commit: bda93076d184ad80a8cab09bf29ace7692de18f7 [06/21] ASoC: SOF: amd: Add PCM stream callback for Renoir dai's commit: e8afccf8fb75bae9c3292a0e51593af92839415e [07/21] ASoC: amd: Add module to determine ACP configuration commit: f1bdd8d385a803565024c8feeedc17bf86aac4f5 [08/21] ASoC: SOF: amd: Add machine driver dsp ops for Renoir platform commit: 11ddd4e371810017faf7ff7cb2349f321e50d1d3 [09/21] ASoC: SOF: amd: Add Renoir PCI driver interface commit: ec25a3b14261fcb05568a1fec15ca68152e9d208 [10/21] ASoC: amd: acp-config: Remove legacy acpi based machine struct commit: 63fba90fc88b6cee9f8bead761a419169ecda6cc [11/21] ASoC: SOF: topology: Add support for AMD ACP DAIs commit: efb931cdc4b94a0f7ed17a76844f08cef1bdffe5 [12/21] ASoC: SOF: amd: Add trace logger support commit: 4627421fb883928af5220c66a304bed1f9b77e8d [13/21] ASoC: SOF: amd: Add support for SOF firmware authentication commit: f063eba3e7a6aeec8e2abb00469e70c51432453b [14/21] ASoC: SOF: mediatek: Add mt8195 hardware support (no commit info) [15/21] ASoC: SOF: tokens: add token for Mediatek AFE (no commit info) [16/21] ASoC: SOF: topology: Add support for Mediatek AFE DAI (no commit info) [17/21] ASoC: SOF: mediatek: Add fw loader and mt8195 dsp ops to load firmware (no commit info) [18/21] ASoC: SOF: Add mt8195 device descriptor (no commit info) [19/21] ASoC: SOF: mediatek: Add dai driver dsp ops callback for mt8195 (no commit info) [20/21] ASoC: SOF: mediatek: Add mt8195 dsp clock support (no commit info) [21/21] ASoC: SOF: mediatek: Add DSP system PM callback for mt8195 (no commit info)
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (7)
-
Curtis Malainey
-
Daniel Baluta
-
Daniel Baluta
-
Daniel Baluta
-
Geert Uytterhoeven
-
Mark Brown
-
Pierre-Louis Bossart