From f063eba3e7a6aeec8e2abb00469e70c51432453b Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:26 +0200 Subject: [PATCH] ASoC: SOF: amd: Add support for SOF firmware authentication 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 Signed-off-by: Ajit Kumar Pandey Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Curtis Malainey Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-14-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- 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",