OSDN Git Service

ASoC: SOF: amd: Add support for SOF firmware authentication
authorAjit Kumar Pandey <AjitKumar.Pandey@amd.com>
Wed, 17 Nov 2021 09:37:26 +0000 (11:37 +0200)
committerMark Brown <broonie@kernel.org>
Wed, 17 Nov 2021 17:35:56 +0000 (17:35 +0000)
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>
Link: https://lore.kernel.org/r/20211117093734.17407-14-daniel.baluta@oss.nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/amd/acp-dsp-offset.h
sound/soc/sof/amd/acp.c
sound/soc/sof/amd/acp.h
sound/soc/sof/amd/pci-rn.c

index 1d11e9d..63f13c1 100644 (file)
@@ -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
 
index 74ede28..4c5550e 100644 (file)
 #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);
 
index fd923f7..a2f8e42 100644 (file)
 
 #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
index 3c379a5..392ffbd 100644 (file)
@@ -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",