diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h index 59cd014392c1b1..11805cf46affa3 100644 --- a/include/sound/sof/dai-amd.h +++ b/include/sound/sof/dai-amd.h @@ -18,6 +18,7 @@ struct sof_ipc_dai_acp_params { uint32_t fsync_rate; /* FSYNC frequency in Hz */ uint32_t tdm_slots; uint32_t tdm_mode; + u32 format; } __packed; /* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 0b6a6ba6489ab1..e3fe492e78f57c 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -91,6 +91,7 @@ enum sof_ipc_dai_type { SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */ SOF_DAI_AMD_SDW, /**< AMD ACP SDW */ SOF_DAI_INTEL_UAOL, /**< Intel UAOL */ + SOF_DAI_AMD_I2S, /**< AMD ACP I2S */ }; /* general purpose DAI configuration */ @@ -122,6 +123,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_mtk_afe_params afe; struct sof_ipc_dai_micfil_params micfil; struct sof_ipc_dai_acp_sdw_params acp_sdw; + struct sof_ipc_dai_acp_params acp_i2s; }; } __packed; diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index f4a7baadb44da0..cc694a3979870d 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -223,6 +223,7 @@ #define SOF_TKN_AMD_ACPI2S_RATE 1700 #define SOF_TKN_AMD_ACPI2S_CH 1701 #define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702 +#define SOF_TKN_AMD_ACPI2S_FORMAT 1703 /* MICFIL PDM */ #define SOF_TKN_IMX_MICFIL_RATE 2000 diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 309dc9ed6e0d2b..daa3859b61dddd 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -353,5 +353,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[] = { + { + .id = "AMDI1010", + .drv_name = "acp7x-dsp", + .pdata = &acp_quirk_data, + .fw_filename = "sof-acp7x.ri", + .sof_tplg_filename = "sof-acp7x.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp7x_sof_machines); + MODULE_DESCRIPTION("AMD ACP Machine Configuration Module"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 5b6362103ca0af..b602a983feb7f3 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -28,6 +28,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 05faf1c6d6fc3b..b3b8db3f47840e 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -103,5 +103,16 @@ config SND_SOC_SOF_AMD_ACP70 Select this option for SOF support on AMD ACP7.0/ACP7.1 version based platforms. Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms. +config SND_SOC_SOF_AMD_ACP7X + tristate "SOF support for ACP7.B/7.F platforms" + depends on SND_SOC_SOF_PCI + depends on AMD_NODE + select SND_SOC_SOF_AMD_COMMON + select SND_SOC_SOF_ACP_PROBES + help + Select this option for SOF support on AMD ACP7.B and ACP7.F PCI + revision based platforms. + Say Y if you want to enable SOF on ACP7.B/7.F based platforms. + If unsure select "N". endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 6ae39fd5a83622..bb1c0ddef69d77 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -11,6 +11,7 @@ snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o snd-sof-amd-acp63-y := pci-acp63.o acp63.o snd-sof-amd-acp70-y := pci-acp70.o acp70.o +snd-sof-amd-acp7x-y := pci-acp7x.o acp7x.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 @@ -18,3 +19,4 @@ obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o +obj-$(CONFIG_SND_SOC_SOF_AMD_ACP7X) += snd-sof-amd-acp7x.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 08583a91afbc47..c1696a83526f02 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -68,12 +68,14 @@ #define ACP5X_PGFSM_BASE 0x1424 #define ACP6X_PGFSM_BASE 0x1024 #define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE +#define ACP7X_PGFSM_BASE ACP6X_PGFSM_BASE #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 #define ACP5X_CLKMUX_SEL 0x142C #define ACP6X_CLKMUX_SEL 0x102C #define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL +#define ACP7X_CLKMUX_SEL ACP6X_CLKMUX_SEL /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 @@ -86,21 +88,31 @@ #define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL #define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT #define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1 +#define ACP7X_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB +#define ACP7X_EXTERNAL_INTR_CNTL 0x1A04 +#define ACP7X_EXT_INTR_STAT 0x1A1C +#define ACP7X_EXTERNAL_INTR_CNTL1 0x1A08 +#define ACP7X_EXT_INTR_STAT1 0x1A20 #define ACP3X_DSP_SW_INTR_BASE 0x1814 #define ACP5X_DSP_SW_INTR_BASE 0x1814 #define ACP6X_DSP_SW_INTR_BASE 0x1808 #define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE +#define ACP7X_DSP_SW_INTR_BASE 0x1860 #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 +#define ACP7X_DSP_SW_INTR_STAT (ACP7X_DSP_SW_INTR_BASE + DSP_SW_INTR_STAT_OFFSET) #define DSP_SW_INTR_TRIG_OFFSET 0x8 +#define ACP7X_DSP_SW_INTR_TRIG_OFFSET 0x30 #define ACP3X_ERROR_STATUS 0x18C4 #define ACP6X_ERROR_STATUS 0x1A4C #define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS +#define ACP7X_ERROR_STATUS 0x1A88 #define ACP3X_AXI2DAGB_SEM_0 0x1880 #define ACP5X_AXI2DAGB_SEM_0 0x1884 #define ACP6X_AXI2DAGB_SEM_0 0x1874 #define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0 +#define ACP7X_AXI2DAGB_SEM_0 0x18F4 /* ACP common registers to report errors related to I2S & SoundWire interfaces */ #define ACP3X_SW_I2S_ERROR_REASON 0x18C8 @@ -123,6 +135,7 @@ #define ACP_SCRATCH_REG_0 0x10000 #define ACP6X_DSP_FUSION_RUNSTALL 0x0644 #define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL +#define ACP7X_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL /* Cache window registers */ #define ACP_DSP0_CACHE_OFFSET0 0x0420 @@ -139,5 +152,9 @@ #define ACP70_SDW1_HOST_WAKE_STAT BIT(25) #define ACP70_SDW0_PME_STAT BIT(26) #define ACP70_SDW1_PME_STAT BIT(27) +#define ACP7X_DSP0_IDMA_ERROR_MASK 0x4B0 +#define ACP7X_IDMA_ERROR_MASK 0x1FF9FF +#define ACP_ZSC_DSP_CTRL 0x001014 +#define ACP_PME_EN 0x001400 #endif diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 3cd4674dd80075..479b2a0d768403 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -32,11 +32,20 @@ static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) struct snd_sof_dev *sdev = adata->dev; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); u32 swintr_trigger; - + unsigned int swintr_trigger_reg_offset; + + switch (adata->pci_rev) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + swintr_trigger_reg_offset = ACP7X_DSP_SW_INTR_TRIG_OFFSET; + break; + default: + swintr_trigger_reg_offset = DSP_SW_INTR_TRIG_OFFSET; + } swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base + - DSP_SW_INTR_TRIG_OFFSET); + swintr_trigger_reg_offset); swintr_trigger |= 0x01; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET, + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + swintr_trigger_reg_offset, swintr_trigger); } diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 059f152846209f..6e53e7ef2d4226 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "../ops.h" #include "acp-dsp-offset.h" @@ -173,10 +174,24 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) adata = sdev->pdata->hw_pdata; - if (adata->quirks && adata->quirks->signed_fw_image) + if (adata->pci_rev >= ACP7B_PCI_ID) { + if (adata->acp_sof_signed_firmware_image) { + if (adata->fw_bin_size <= ACP_IMAGE_HEADER_SIZE) { + dev_err(sdev->dev, "Invalid signed firmware size %u\n", + adata->fw_bin_size); + return -EINVAL; + } + size_fw = get_unaligned_le32(adata->bin_buf + + ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF); + size_fw += ACP_IMAGE_HEADER_SIZE; + } else { + size_fw = adata->fw_bin_size; + } + } else if (adata->quirks && adata->quirks->signed_fw_image) { size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; - else + } else { size_fw = adata->fw_bin_size; + } page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; adata->fw_bin_page_count = page_count; @@ -312,9 +327,14 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev, const char *fw_name) } kfree(fw_filename); - ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, - (void *)adata->fw_dbin->data, - adata->fw_dbin->size); + if (adata->pci_rev >= ACP7B_PCI_ID) + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_SRAM, 0, + (void *)adata->fw_dbin->data, + adata->fw_dbin->size); + else + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, + (void *)adata->fw_dbin->data, + adata->fw_dbin->size); return ret; } EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON"); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index f615b8d1c80208..7bac2c0d97ea6d 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -12,6 +12,7 @@ * Hardware interface for generic AMD ACP processor */ +#include #include #include #include @@ -60,6 +61,8 @@ static void init_dma_descriptor(struct acp_dev_data *adata) case ACP70_PCI_ID: case ACP71_PCI_ID: case ACP72_PCI_ID: + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR; acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR; break; @@ -101,6 +104,8 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch, case ACP70_PCI_ID: case ACP71_PCI_ID: case ACP72_PCI_ID: + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: acp_dma_cntl_0 = ACP70_DMA_CNTL_0; acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS; acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0; @@ -283,7 +288,8 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } - if (adata->quirks && adata->quirks->signed_fw_image) + if ((adata->quirks && adata->quirks->signed_fw_image) || + adata->acp_sof_signed_firmware_image) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); @@ -342,6 +348,8 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch) case ACP70_PCI_ID: case ACP71_PCI_ID: case ACP72_PCI_ID: + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: acp_dma_ch_sts = ACP70_DMA_CH_STS; break; default: @@ -506,8 +514,17 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0); /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */ - if (adata->pci_rev >= ACP_RMB_PCI_ID) + switch (adata->pci_rev) { + case ACP_RMB_PCI_ID: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: + case ACP72_PCI_ID: snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0); + break; + default: + break; + } snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); irq_flag = 1; } @@ -536,6 +553,35 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) return IRQ_NONE; } +static irqreturn_t acp7x_irq_handler(int irq, void *dev_id) +{ + struct snd_sof_dev *sdev = dev_id; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + unsigned int base = desc->dsp_intr_base; + unsigned int val; + unsigned int ext_intr_stat; + int irq_flag = 0; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); + if (val & ACP_DSP_TO_HOST_IRQ) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, + ACP_DSP_TO_HOST_IRQ); + return IRQ_WAKE_THREAD; + } + + ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); + if (ext_intr_stat & ACP_ERROR_IRQ_MASK) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); + irq_flag = 1; + } + + if (irq_flag) + return IRQ_HANDLED; + + return IRQ_NONE; +} + static int acp_power_on(struct snd_sof_dev *sdev) { const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); @@ -543,6 +589,7 @@ static int acp_power_on(struct snd_sof_dev *sdev) unsigned int base = desc->pgfsm_base; unsigned int val; unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask; + bool use_masked_status = false; int ret; val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET); @@ -567,6 +614,12 @@ static int acp_power_on(struct snd_sof_dev *sdev) acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK; acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK; break; + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + acp_pgfsm_status_mask = ACP7X_PGFSM_STATUS_MASK; + acp_pgfsm_cntl_mask = ACP7X_PGFSM_CNTL_POWER_ON_MASK; + use_masked_status = true; + break; default: return -EINVAL; } @@ -575,8 +628,17 @@ static int acp_power_on(struct snd_sof_dev *sdev) snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET, acp_pgfsm_cntl_mask); - ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val, - !val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (use_masked_status) + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, + base + PGFSM_STATUS_OFFSET, val, + !(val & acp_pgfsm_status_mask), + ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); + else + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, + base + PGFSM_STATUS_OFFSET, 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"); @@ -675,6 +737,13 @@ static int acp_init(struct snd_sof_dev *sdev) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1); break; + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_ZSC_DSP_CTRL, 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_PME_EN, 1); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK, + ACP7X_IDMA_ERROR_MASK); + break; } return 0; } @@ -721,6 +790,8 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) case ACP72_PCI_ID: enable = true; break; + default: + break; } snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); @@ -962,6 +1033,193 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON"); +int amd_sof_acp7x_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; + const union acpi_object *obj; + unsigned int addr; + unsigned int irqflags; + int ret; + + 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 = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->dev = sdev; + adata->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec", + PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(adata->dmic_dev)) { + dev_err(sdev->dev, "failed to register platform for dmic codec\n"); + return PTR_ERR(adata->dmic_dev); + } + + 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"); + ret = -ENXIO; + goto unregister_dev; + } + + pci_set_master(pci); + adata->addr = addr; + adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; + adata->pci_rev = pci->revision; + mutex_init(&adata->acp_lock); + sdev->pdata->hw_pdata = adata; + + ret = acp_init(sdev); + if (ret < 0) + goto unregister_dev; + + sdev->ipc_irq = pci->irq; + irqflags = IRQF_SHARED; + + ret = request_threaded_irq(pci->irq, acp7x_irq_handler, acp_irq_thread, + irqflags, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); + goto unregister_dev; + } + + if (!acpi_dev_get_property(ACPI_COMPANION(&pci->dev), "acp-sof-signed-firmware-image", + ACPI_TYPE_INTEGER, &obj)) + adata->acp_sof_signed_firmware_image = obj->integer.value; + + if (!acpi_dev_get_property(ACPI_COMPANION(&pci->dev), "acp-sof-skip_iram_dram_size_mod", + ACPI_TYPE_INTEGER, &obj)) + adata->acp_sof_skip_iram_dram_size_mod = obj->integer.value; + + sdev->dsp_box.offset = 0; + sdev->dsp_box.size = BOX_SIZE_512; + + sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; + sdev->host_box.size = BOX_SIZE_512; + + sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; + sdev->debug_box.size = BOX_SIZE_1024; + + if (adata->acp_sof_signed_firmware_image) { + adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-code.bin", chip->name); + if (!adata->fw_code_bin) { + ret = -ENOMEM; + goto free_ipc_irq; + } + adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-data.bin", chip->name); + if (!adata->fw_data_bin) { + ret = -ENOMEM; + goto free_ipc_irq; + } + } + + adata->enable_fw_debug = enable_fw_debug; + acp_memory_init(sdev); + acp_dsp_stream_init(sdev); + + return 0; + +free_ipc_irq: + free_irq(sdev->ipc_irq, sdev); +unregister_dev: + platform_device_unregister(adata->dmic_dev); + return ret; +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_probe, "SND_SOC_SOF_AMD_COMMON"); + +void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + + if (sdev->ipc_irq) + free_irq(sdev->ipc_irq, sdev); + + if (adata->dmic_dev) + platform_device_unregister(adata->dmic_dev); + + acp_reset(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + struct acp_dev_data *acp_data; + int ret; + bool enable = false; + + acp_data = sdev->pdata->hw_pdata; + + ret = acp_reset(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Reset failed\n"); + return ret; + } + switch (acp_data->pci_rev) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + enable = true; + break; + default: + break; + } + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_ZSC_DSP_CTRL, 1); + + return 0; +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_resume(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *acp_data; + int ret; + + acp_data = sdev->pdata->hw_pdata; + + ret = acp_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Init failed\n"); + return ret; + } + ret = acp_memory_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Memory init failed\n"); + return ret; + } + + switch (acp_data->pci_rev) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_PME_EN, 1); + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev) +{ + return amd_sof_acp7x_suspend(sdev, 0); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev) +{ + return amd_sof_acp7x_resume(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("AMD ACP sof driver"); MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 2799e34b235395..bd911cf89f15a6 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -76,6 +76,12 @@ #define ACP70_PCI_ID 0x70 #define ACP71_PCI_ID 0x71 #define ACP72_PCI_ID 0x72 +#define ACP7B_PCI_ID 0x7B +#define ACP7F_PCI_ID 0x7F + +#define ACP7X_PGFSM_CNTL_POWER_ON_MASK 0x7F +#define ACP7X_PGFSM_STATUS_MASK 0xFFF +#define ACP7X_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET #define HOST_BRIDGE_CZN 0x1630 #define HOST_BRIDGE_VGH 0x1645 @@ -107,6 +113,9 @@ #define PROBE_STATUS_BIT BIT(31) #define ACP_FIRMWARE_SIGNATURE 0x100 +#define ACP_IMAGE_HEADER_SIZE ACP_FIRMWARE_SIGNATURE +#define ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF 0x14 + #define ACP_ERROR_IRQ_MASK BIT(29) #define ACP_SDW0_IRQ_MASK BIT(21) #define ACP_SDW1_IRQ_MASK BIT(2) @@ -269,6 +278,8 @@ struct acp_dev_data { /* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */ bool acp70_sdw1_wake_event; unsigned int pci_rev; + int acp_sof_signed_firmware_image; + int acp_sof_skip_iram_dram_size_mod; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -342,6 +353,16 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_acp70_ops; int sof_acp70_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_acp7x_ops; +int sof_acp7x_ops_init(struct snd_sof_dev *sdev); + +int amd_sof_acp7x_probe(struct snd_sof_dev *sdev); +void amd_sof_acp7x_remove(struct snd_sof_dev *sdev); +int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state); +int amd_sof_acp7x_resume(struct snd_sof_dev *sdev); +int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev); +int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev); + struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c new file mode 100644 index 00000000000000..c35fd8fd805e56 --- /dev/null +++ b/sound/soc/sof/amd/acp7x.c @@ -0,0 +1,183 @@ +// 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) 2025 Advanced Micro Devices, Inc. +// +// Authors: Vijendar Mukunda + +/* + * Hardware interface for Audio DSP on ACP7.B/7.F platforms + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_TDM0_INSTANCE 0 +#define I2S_TDM1_INSTANCE 1 +#define I2S_TDM2_INSTANCE 2 +#define PDM0_DMIC_INSTANCE 3 +#define PDM1_DMIC_INSTANCE 4 + +static struct snd_soc_dai_driver acp7x_sof_dai[] = { + [I2S_TDM0_INSTANCE] = { + .id = I2S_TDM0_INSTANCE, + .name = "acp-sof-i2s0", + .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 HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_TDM1_INSTANCE] = { + .id = I2S_TDM1_INSTANCE, + .name = "acp-sof-i2s1", + .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, + }, + }, + + [I2S_TDM2_INSTANCE] = { + .id = I2S_TDM2_INSTANCE, + .name = "acp-sof-i2s2", + .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, + }, + }, + + [PDM0_DMIC_INSTANCE] = { + .id = PDM0_DMIC_INSTANCE, + .name = "acp-sof-dmic0", + .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, + }, + }, + + [PDM1_DMIC_INSTANCE] = { + .id = PDM1_DMIC_INSTANCE, + .name = "acp-sof-dmic1", + .capture = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 96000, + }, + }, +}; + +static int sof_acp7x_post_fw_run_delay(struct snd_sof_dev *sdev) +{ + /* + * Resuming from suspend in some cases may cause the DSP firmware + * to enter an unrecoverable faulty state. Delaying a bit any host + * to DSP transmission right after firmware boot completion seems + * to resolve the issue. + */ + if (!sdev->first_boot) + usleep_range(100, 150); + + return 0; +} + +struct snd_sof_dsp_ops sof_acp7x_ops; +EXPORT_SYMBOL_NS(sof_acp7x_ops, "SND_SOC_SOF_AMD_COMMON"); + +int sof_acp7x_ops_init(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + const union acpi_object *obj; + int acp_sof_signed_firmware_image = 0; + int acp_sof_post_fw_run_delay = 0; + + /* common defaults */ + memcpy(&sof_acp7x_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_acp7x_ops.drv = acp7x_sof_dai; + sof_acp7x_ops.num_drv = ARRAY_SIZE(acp7x_sof_dai); + sof_acp7x_ops.probe = amd_sof_acp7x_probe; + sof_acp7x_ops.remove = amd_sof_acp7x_remove; + + if (!acpi_dev_get_property(ACPI_COMPANION(&pci->dev), "acp-sof-signed-firmware-image", + ACPI_TYPE_INTEGER, &obj)) + acp_sof_signed_firmware_image = obj->integer.value; + + if (acp_sof_signed_firmware_image) + sof_acp7x_ops.load_firmware = acp_sof_load_signed_firmware; + + if (!acpi_dev_get_property(ACPI_COMPANION(&pci->dev), "acp-sof-post_fw_run_delay", + ACPI_TYPE_INTEGER, &obj)) + acp_sof_post_fw_run_delay = obj->integer.value; + + if (acp_sof_post_fw_run_delay) + sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay; + + sof_acp7x_ops.suspend = amd_sof_acp7x_suspend; + sof_acp7x_ops.resume = amd_sof_acp7x_resume; + sof_acp7x_ops.runtime_suspend = amd_sof_acp7x_suspend_runtime; + sof_acp7x_ops.runtime_resume = amd_sof_acp7x_resume_runtime; + + return 0; +} diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c new file mode 100644 index 00000000000000..4774cf710ec6db --- /dev/null +++ b/sound/soc/sof/amd/pci-acp7x.c @@ -0,0 +1,117 @@ +// 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) 2025 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vijendar Mukunda + +/* + * PCI interface for ACP7.B/7.F devices + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP7X_FUTURE_REG_ACLK_0 0x18e0 +#define ACP7X_REG_START 0x1240000 +#define ACP7X_REG_END 0x125C000 + +static const struct sof_amd_acp_desc acp7x_chip_info = { + .name = "acp7x", + .pgfsm_base = ACP7X_PGFSM_BASE, + .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB, + .ext_intr_cntl = ACP7X_EXTERNAL_INTR_CNTL, + .ext_intr_stat = ACP7X_EXT_INTR_STAT, + .ext_intr_stat1 = ACP7X_EXT_INTR_STAT1, + .dsp_intr_base = ACP7X_DSP_SW_INTR_BASE, + .acp_error_stat = ACP7X_ERROR_STATUS, + .sram_pte_offset = ACP7X_SRAM_PTE_OFFSET, + .hw_semaphore_offset = ACP7X_AXI2DAGB_SEM_0, + .fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0, + .reg_start_addr = ACP7X_REG_START, + .reg_end_addr = ACP7X_REG_END, +}; + +static const struct sof_dev_desc acp7x_desc = { + .machines = snd_soc_acpi_amd_acp7x_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &acp7x_chip_info, + .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), + .ipc_default = SOF_IPC_TYPE_3, + .default_fw_path = { + [SOF_IPC_TYPE_3] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC_TYPE_3] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC_TYPE_3] = "sof-acp7x.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_acp7x_ops, + .ops_init = sof_acp7x_ops_init, +}; + +static int acp7x_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + unsigned int flag; + + switch (pci->revision) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + break; + default: + return -ENODEV; + } + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + return sof_pci_probe(pci, pci_id); +} + +static void acp7x_pci_remove(struct pci_dev *pci) +{ + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id acp7x_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&acp7x_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, acp7x_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_acp7x_driver = { + .name = KBUILD_MODNAME, + .id_table = acp7x_pci_ids, + .probe = acp7x_pci_probe, + .remove = acp7x_pci_remove, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_amd_acp7x_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("ACP7X SOF Driver"); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 90ef5d99f626a9..143bf0fe8dd9da 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -421,6 +421,12 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_AMD_I2S: + rate->min = private->dai_config->acp_i2s.fsync_rate; + rate->max = private->dai_config->acp_i2s.fsync_rate; + channels->min = private->dai_config->acp_i2s.tdm_slots; + channels->max = private->dai_config->acp_i2s.tdm_slots; + break; default: dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type); break; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 4e066bbded9179..a3dc45302b530f 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -289,6 +289,8 @@ static const struct sof_topology_token acpi2s_tokens[] = { offsetof(struct sof_ipc_dai_acp_params, tdm_slots)}, {SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_dai_acp_params, tdm_mode)}, + {SOF_TKN_AMD_ACPI2S_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acp_params, format)}, }; /* MICFIL PDM */ @@ -1363,6 +1365,35 @@ static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof return 0; } +static int sof_link_acp_i2s_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acp_i2s, 0, sizeof(config->acp_i2s)); + config->hdr.size = size; + + ret = sof_update_ipc_object(scomp, &config->acp_i2s, SOF_ACPI2S_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { @@ -1692,6 +1723,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) case SOF_DAI_AMD_SDW: ret = sof_link_acp_sdw_load(scomp, slink, config, dai); break; + case SOF_DAI_AMD_I2S: + ret = sof_link_acp_i2s_load(scomp, slink, config, dai); + break; default: break; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8fc7726aec29d0..1e50cfb7469b1e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -309,7 +309,7 @@ static const struct sof_dai_types sof_dais[] = { {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL}, {"MICFIL", SOF_DAI_IMX_MICFIL}, {"ACP_SDW", SOF_DAI_AMD_SDW}, - + {"ACPTDM", SOF_DAI_AMD_I2S}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -1992,6 +1992,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ case SOF_DAI_AMD_HS: case SOF_DAI_AMD_SP_VIRTUAL: case SOF_DAI_AMD_HS_VIRTUAL: + case SOF_DAI_AMD_I2S: token_id = SOF_ACPI2S_TOKENS; num_tuples += token_list[SOF_ACPI2S_TOKENS].count; break;