ASoC: SOF: amd: Add support for Rembrandt plaform.
authorV sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Tue, 13 Sep 2022 14:43:16 +0000 (20:13 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 20 Sep 2022 18:38:02 +0000 (19:38 +0100)
Add pci driver and platform driver to enable SOF support on ACP6x
architecture based Rembrandt platform.

Signed-off-by: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
Signed-off-by: V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20220913144319.1055302-3-Vsujithkumar.Reddy@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/amd/Kconfig
sound/soc/sof/amd/Makefile
sound/soc/sof/amd/acp-dsp-offset.h
sound/soc/sof/amd/acp-loader.c
sound/soc/sof/amd/acp.h
sound/soc/sof/amd/pci-rmb.c [new file with mode: 0644]
sound/soc/sof/amd/rembrandt.c [new file with mode: 0644]

index 190c85d..a305ea6 100644 (file)
@@ -31,4 +31,14 @@ config SND_SOC_SOF_AMD_RENOIR
        select SND_SOC_SOF_AMD_COMMON
        help
          Select this option for SOF support on AMD Renoir platform
+
+config SND_SOC_SOF_AMD_REMBRANDT
+       tristate "SOF support for REMBRANDT"
+       depends on SND_SOC_SOF_PCI
+       select SND_SOC_SOF_AMD_COMMON
+       help
+         Select this option for SOF support on AMD Rembrandt platform
+         Say Y if you want to enable SOF on Rembrandt.
+         If unsure select "N".
+
 endif
index efea92f..5626d13 100644 (file)
@@ -6,6 +6,8 @@
 
 snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o
 snd-sof-amd-renoir-objs := pci-rn.o renoir.o
+snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.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
+obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o
index 47151a8..de57262 100644 (file)
 #define ACP_CONTROL                            0x1004
 
 #define ACP3X_I2S_PIN_CONFIG                   0x1400
+#define ACP6X_I2S_PIN_CONFIG                   0x1440
 
 /* Registers offsets from ACP_PGFSM block */
 #define ACP3X_PGFSM_BASE                       0x141C
+#define ACP6X_PGFSM_BASE                        0x1024
 #define PGFSM_CONTROL_OFFSET                   0x0
 #define PGFSM_STATUS_OFFSET                    0x4
 #define ACP3X_CLKMUX_SEL                       0x1424
+#define ACP6X_CLKMUX_SEL                       0x102C
 
 /* Registers from ACP_INTR block */
 #define ACP3X_EXT_INTR_STAT                    0x1808
+#define ACP6X_EXT_INTR_STAT                     0x1A0C
 
 #define ACP3X_DSP_SW_INTR_BASE                 0x1814
+#define ACP6X_DSP_SW_INTR_BASE                  0x1808
 #define DSP_SW_INTR_CNTL_OFFSET                        0x0
 #define DSP_SW_INTR_STAT_OFFSET                        0x4
 #define DSP_SW_INTR_TRIG_OFFSET                        0x8
 #define ACP_ERROR_STATUS                       0x18C4
 #define ACP3X_AXI2DAGB_SEM_0                   0x1880
+#define ACP6X_AXI2DAGB_SEM_0                   0x1874
 
 /* Registers from ACP_SHA block */
 #define ACP_SHA_DSP_FW_QUALIFIER               0x1C70
@@ -78,5 +84,5 @@
 #define ACP_SHA_PSP_ACK                         0x1C74
 
 #define ACP_SCRATCH_REG_0                      0x10000
-
+#define ACP6X_DSP_FUSION_RUNSTALL              0x0644
 #endif
index f372f93..d1e74ba 100644 (file)
@@ -198,12 +198,19 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON);
 
 int acp_sof_dsp_run(struct snd_sof_dev *sdev)
 {
+       const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
        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);
 
+       /* Some platforms won't support fusion DSP,keep offset zero for no support */
+       if (desc->fusion_dsp_offset) {
+               snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN);
+               val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset);
+               dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val);
+       }
        return 0;
 }
 EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON);
index bc024be..e59a865 100644 (file)
@@ -31,6 +31,7 @@
 
 #define ACP_DSP_INTR_EN_MASK                   0x00000001
 #define ACP3X_SRAM_PTE_OFFSET                  0x02050000
+#define ACP6X_SRAM_PTE_OFFSET                  0x03800000
 #define PAGE_SIZE_4K_ENABLE                    0x2
 #define ACP_PAGE_SIZE                          0x1000
 #define ACP_DMA_CH_RUN                         0x02
@@ -54,6 +55,7 @@
 #define ACP_DSP_TO_HOST_IRQ                    0x04
 
 #define HOST_BRIDGE_CZN                                0x1630
+#define HOST_BRIDGE_RMB                                0x14B5
 #define ACP_SHA_STAT                           0x8000
 #define ACP_PSP_TIMEOUT_COUNTER                        5
 #define ACP_EXT_INTR_ERROR_STAT                        0x20000000
@@ -150,6 +152,7 @@ struct sof_amd_acp_desc {
        u32 i2s_pin_config_offset;
        u32 hw_semaphore_offset;
        u32 acp_clkmux_sel;
+       u32 fusion_dsp_offset;
 };
 
 /* Common device data struct for ACP devices */
@@ -223,6 +226,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops;
 
 extern struct snd_sof_dsp_ops sof_renoir_ops;
 int sof_renoir_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_rembrandt_ops;
+int sof_rembrandt_ops_init(struct snd_sof_dev *sdev);
 
 int acp_dai_probe(struct snd_soc_dai *dai);
 struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c
new file mode 100644 (file)
index 0000000..4e1de46
--- /dev/null
@@ -0,0 +1,186 @@
+// 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) 2022 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+
+/*.
+ * PCI interface for Rembrandt 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"
+#include "acp-dsp-offset.h"
+
+#define ACP6x_REG_START                0x1240000
+#define ACP6x_REG_END          0x125C000
+
+static struct platform_device *dmic_dev;
+static struct platform_device *pdev;
+
+static const struct resource rembrandt_res[] = {
+       {
+               .start = 0,
+               .end = ACP6x_REG_END - ACP6x_REG_START,
+               .name = "acp_mem",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = 0,
+               .end = 0,
+               .name = "acp_dai_irq",
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static const struct sof_amd_acp_desc rembrandt_chip_info = {
+       .rev            = 6,
+       .host_bridge_id = HOST_BRIDGE_RMB,
+       .i2s_mode       = 0x0a,
+       .pgfsm_base     = ACP6X_PGFSM_BASE,
+       .ext_intr_stat  = ACP6X_EXT_INTR_STAT,
+       .dsp_intr_base  = ACP6X_DSP_SW_INTR_BASE,
+       .sram_pte_offset = ACP6X_SRAM_PTE_OFFSET,
+       .i2s_pin_config_offset = ACP6X_I2S_PIN_CONFIG,
+       .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
+       .acp_clkmux_sel = ACP6X_CLKMUX_SEL,
+       .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
+};
+
+static const struct sof_dev_desc rembrandt_desc = {
+       .machines               = snd_soc_acpi_amd_rmb_sof_machines,
+       .resindex_lpe_base      = 0,
+       .resindex_pcicfg_base   = -1,
+       .resindex_imr_base      = -1,
+       .irqindex_host_ipc      = -1,
+       .chip_info              = &rembrandt_chip_info,
+       .ipc_supported_mask     = BIT(SOF_IPC),
+       .ipc_default            = SOF_IPC,
+       .default_fw_path        = {
+               [SOF_IPC] = "amd/sof",
+       },
+       .default_tplg_path      = {
+               [SOF_IPC] = "amd/sof-tplg",
+       },
+       .default_fw_filename    = {
+               [SOF_IPC] = "sof-rmb.ri",
+       },
+       .nocodec_tplg_filename  = "sof-acp.tplg",
+       .ops                    = &sof_rembrandt_ops,
+       .ops_init               = sof_rembrandt_ops_init,
+};
+
+static int acp_pci_rmb_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(rembrandt_res),
+                          GFP_KERNEL);
+       if (!res) {
+               platform_device_unregister(dmic_dev);
+               sof_pci_remove(pci);
+               return -ENOMEM;
+       }
+
+       res_i2s = rembrandt_res;
+       for (i = 0; i < ARRAY_SIZE(rembrandt_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_rembrandt";
+       pdevinfo.id = 0;
+       pdevinfo.parent = &pci->dev;
+       pdevinfo.num_res = ARRAY_SIZE(rembrandt_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);
+               platform_device_unregister(dmic_dev);
+               sof_pci_remove(pci);
+               ret = PTR_ERR(pdev);
+       }
+
+       return ret;
+};
+
+static void acp_pci_rmb_remove(struct pci_dev *pci)
+{
+       if (dmic_dev)
+               platform_device_unregister(dmic_dev);
+       if (pdev)
+               platform_device_unregister(pdev);
+
+       sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id rmb_pci_ids[] = {
+               { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+               .driver_data = (unsigned long)&rembrandt_desc},
+               { 0, }
+};
+MODULE_DEVICE_TABLE(pci, rmb_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_rmb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = rmb_pci_ids,
+       .probe = acp_pci_rmb_probe,
+       .remove = acp_pci_rmb_remove,
+};
+module_pci_driver(snd_sof_pci_amd_rmb_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c
new file mode 100644 (file)
index 0000000..dcb64a2
--- /dev/null
@@ -0,0 +1,134 @@
+// 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) 2022 Advanced Micro Devices, Inc.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on Rembrandt platform
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include "../ops.h"
+#include "../sof-audio.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define I2S_HS_INSTANCE                0
+#define I2S_BT_INSTANCE                1
+#define I2S_SP_INSTANCE                2
+#define PDM_DMIC_INSTANCE      3
+
+static struct snd_soc_dai_driver rembrandt_sof_dai[] = {
+       [I2S_HS_INSTANCE] = {
+               .id = I2S_HS_INSTANCE,
+               .name = "acp-sof-hs",
+               .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,
+               },
+               .probe = &acp_dai_probe,
+       },
+
+       [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 = &acp_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 = &acp_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,
+               },
+       },
+};
+
+/* Rembrandt ops */
+struct snd_sof_dsp_ops sof_rembrandt_ops;
+EXPORT_SYMBOL_NS(sof_rembrandt_ops, SND_SOC_SOF_AMD_COMMON);
+
+int sof_rembrandt_ops_init(struct snd_sof_dev *sdev)
+{
+       /* common defaults */
+       memcpy(&sof_rembrandt_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+       sof_rembrandt_ops.drv = rembrandt_sof_dai;
+       sof_rembrandt_ops.num_drv = ARRAY_SIZE(rembrandt_sof_dai);
+
+       return 0;
+}
+
+MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_DESCRIPTION("REMBRANDT SOF Driver");
+MODULE_LICENSE("Dual BSD/GPL");