[PATCH 13/21] ASoC: SOF: amd: Add support for SOF firmware authentication

Daniel Baluta daniel.baluta at oss.nxp.com
Wed Nov 17 01:37:26 PST 2021


From: Ajit Kumar Pandey <AjitKumar.Pandey at 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 at amd.com>
Signed-off-by: Ajit Kumar Pandey <AjitKumar.Pandey at amd.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
Reviewed-by: Curtis Malainey <curtis at malainey.com>
Signed-off-by: Daniel Baluta <daniel.baluta at 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




More information about the Linux-mediatek mailing list