Message ID | 20211117093734.17407-14-daniel.baluta@oss.nxp.com (mailing list archive) |
---|---|
State | Accepted |
Commit | f063eba3e7a6aeec8e2abb00469e70c51432453b |
Headers | show |
Series | ASoC: SOF: Platform updates for AMD and Mediatek | expand |
On Wed, Nov 17, 2021 at 1:38 AM Daniel Baluta <daniel.baluta@oss.nxp.com> wrote: > > From: Ajit Kumar Pandey <AjitKumar.Pandey@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@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> Sorry github must be attached to the wrong email, please use Reviewed-by: Curtis Malainey <cujomalainey@chromium.org> > Signed-off-by: Daniel Baluta <daniel.baluta@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 >
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",