When matching the "psp" platform_device, the register offsets are determined at runtime from the ASP ACPI table. The structure containing the offset is passed through the platform data field provided before registering the platform device. To support this scenario, dynamically allocate vdata structs and fill those in with offsets provided by the platform. Due to the fields of the structs being const, it was necessary to use temporary structs and memcpy, as any assignment of the whole struct fails with an 'read-only location' compiler error. Signed-off-by: Jeremi Piotrowski <jpiotrowski@xxxxxxxxxxxxxxxxxxx> --- drivers/crypto/ccp/sp-platform.c | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c index 5dcc834deb72..2e57ec15046b 100644 --- a/drivers/crypto/ccp/sp-platform.c +++ b/drivers/crypto/ccp/sp-platform.c @@ -22,6 +22,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/acpi.h> +#include <linux/platform_data/psp.h> #include "ccp-dev.h" @@ -86,6 +87,60 @@ static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev) return NULL; } +static void sp_platform_fill_vdata(struct sp_dev_vdata *vdata, struct psp_vdata *psp, + struct sev_vdata *sev, const struct psp_platform_data *pdata) +{ + struct sev_vdata sevtmp = { + .cmdresp_reg = pdata->sev_cmd_resp_reg, + .cmdbuff_addr_lo_reg = pdata->sev_cmd_buf_lo_reg, + .cmdbuff_addr_hi_reg = pdata->sev_cmd_buf_hi_reg, + }; + struct psp_vdata psptmp = { + .sev = sev, + .feature_reg = pdata->feature_reg, + .inten_reg = pdata->irq_en_reg, + .intsts_reg = pdata->irq_st_reg, + }; + + memcpy(sev, &sevtmp, sizeof(*sev)); + memcpy(psp, &psptmp, sizeof(*psp)); + vdata->psp_vdata = psp; +} + +static struct sp_dev_vdata *sp_get_platform_version(struct sp_device *sp) +{ + struct psp_platform_data *pdata; + struct device *dev = sp->dev; + struct sp_dev_vdata *vdata; + struct psp_vdata *psp; + struct sev_vdata *sev; + + pdata = dev_get_platdata(dev); + if (!pdata) { + dev_err(dev, "missing platform data\n"); + return NULL; + } + + vdata = devm_kzalloc(dev, sizeof(*vdata) + sizeof(*psp) + sizeof(*sev), GFP_KERNEL); + if (!vdata) + return NULL; + + psp = (void *)vdata + sizeof(*vdata); + sev = (void *)psp + sizeof(*psp); + sp_platform_fill_vdata(vdata, psp, sev, pdata); + + dev_dbg(dev, "PSP feature register:\t%x\n", psp->feature_reg); + dev_dbg(dev, "PSP IRQ enable register:\t%x\n", psp->inten_reg); + dev_dbg(dev, "PSP IRQ status register:\t%x\n", psp->intsts_reg); + dev_dbg(dev, "SEV cmdresp register:\t%x\n", sev->cmdresp_reg); + dev_dbg(dev, "SEV cmdbuf lo register:\t%x\n", sev->cmdbuff_addr_lo_reg); + dev_dbg(dev, "SEV cmdbuf hi register:\t%x\n", sev->cmdbuff_addr_hi_reg); + dev_dbg(dev, "SEV cmdresp IRQ:\t%x\n", pdata->mbox_irq_id); + dev_dbg(dev, "ACPI cmdresp register:\t%x\n", pdata->acpi_cmd_resp_reg); + + return vdata; +} + static int sp_get_irqs(struct sp_device *sp) { struct sp_platform *sp_platform = sp->dev_specific; @@ -137,6 +192,8 @@ static int sp_platform_probe(struct platform_device *pdev) sp->dev_specific = sp_platform; sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev) : sp_get_acpi_version(pdev); + if (!sp->dev_vdata) + sp->dev_vdata = sp_get_platform_version(sp); if (!sp->dev_vdata) { ret = -ENODEV; dev_err(dev, "missing driver data\n"); -- 2.25.1