diff options
Diffstat (limited to 'drivers/remoteproc/stm32_rproc.c')
-rw-r--r-- | drivers/remoteproc/stm32_rproc.c | 89 |
1 files changed, 60 insertions, 29 deletions
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index bfd4d59768..4dd1634a47 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) STMicroelectronics 2018 - All Rights Reserved * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. @@ -10,10 +10,10 @@ #include <driver.h> #include <init.h> #include <io.h> -#include <mach/smc.h> +#include <mach/stm32mp/smc.h> #include <mfd/syscon.h> #include <of_address.h> -#include <regmap.h> +#include <linux/regmap.h> #include <linux/remoteproc.h> #include <linux/reset.h> @@ -30,17 +30,18 @@ struct stm32_syscon { struct stm32_rproc { struct reset_control *rst; + struct reset_control *hold_boot_rst; struct stm32_syscon hold_boot; - bool secured_soc; + bool hold_boot_smc; }; static void *stm32_rproc_da_to_va(struct rproc *rproc, u64 da, int len) { __be32 in_addr = cpu_to_be32(da); - struct device_d *dev = &rproc->dev; + struct device *dev = &rproc->dev; u64 paddr; - paddr = of_translate_dma_address(dev->parent->device_node, &in_addr); + paddr = of_translate_dma_address(dev->parent->of_node, &in_addr); if (paddr == OF_BAD_ADDR) return NULL; @@ -54,13 +55,28 @@ static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) struct arm_smccc_res smc_res; int val, err; + /* + * Three ways to manage the hold boot + * - using SCMI: the hold boot is managed as a reset, + * - using Linux(no SCMI): the hold boot is managed as a syscon register + * - using SMC call (deprecated): use SMC reset interface + */ + val = hold ? HOLD_BOOT : RELEASE_BOOT; - if (IS_ENABLED(CONFIG_ARM_SMCC) && ddata->secured_soc) { + if (ddata->hold_boot_rst) { + /* Use the SCMI reset controller */ + if (!hold) + err = reset_control_deassert(ddata->hold_boot_rst); + else + err = reset_control_assert(ddata->hold_boot_rst); + } else if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && ddata->hold_boot_smc) { + /* Use the SMC call */ arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE, hold_boot->reg, val, 0, 0, 0, 0, &smc_res); err = smc_res.a0; } else { + /* Use syscon */ err = regmap_update_bits(hold_boot->map, hold_boot->reg, hold_boot->mask, val); } @@ -128,9 +144,9 @@ out: return err; } -static int stm32_rproc_parse_dt(struct device_d *dev, struct stm32_rproc *ddata) +static int stm32_rproc_parse_dt(struct device *dev, struct stm32_rproc *ddata) { - struct device_node *np = dev->device_node; + struct device_node *np = dev->of_node; struct stm32_syscon tz; unsigned int tzen; int err; @@ -142,34 +158,48 @@ static int stm32_rproc_parse_dt(struct device_d *dev, struct stm32_rproc *ddata) } /* - * if platform is secured the hold boot bit must be written by - * smc call and read normally. - * if not secure the hold boot bit could be read/write normally + * Three ways to manage the hold boot + * - using SCMI: the hold boot is managed as a reset + * The DT "reset-mames" property should be defined with 2 items: + * reset-names = "mcu_rst", "hold_boot"; + * - using SMC call (deprecated): use SMC reset interface + * The DT "reset-mames" property is optional, "st,syscfg-tz" is required + * - default(no SCMI, no SMC): the hold boot is managed as a syscon register + * The DT "reset-mames" property is optional, "st,syscfg-holdboot" is required */ - err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz); - if (err) { - dev_err(dev, "failed to get tz syscfg\n"); - return err; - } - err = regmap_read(tz.map, tz.reg, &tzen); - if (err) { - dev_err(dev, "failed to read tzen\n"); - return err; + ddata->hold_boot_rst = reset_control_get_optional(dev, "hold_boot"); + if (IS_ERR(ddata->hold_boot_rst)) + return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst), + "failed to get hold_boot reset\n"); + + if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) { + /* Manage the MCU_BOOT using SMC call */ + err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz); + if (!err) { + err = regmap_read(tz.map, tz.reg, &tzen); + if (err) { + dev_err(dev, "failed to read tzen\n"); + return err; + } + ddata->hold_boot_smc = tzen & tz.mask; + } } - ddata->secured_soc = tzen & tz.mask; - err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", - &ddata->hold_boot); - if (err) { - dev_err(dev, "failed to get hold boot\n"); - return err; + if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) { + /* Default: hold boot manage it through the syscon controller */ + err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", + &ddata->hold_boot); + if (err) { + dev_err(dev, "failed to get hold boot\n"); + return err; + } } return 0; } -static int stm32_rproc_probe(struct device_d *dev) +static int stm32_rproc_probe(struct device *dev) { struct rproc *rproc; int ret; @@ -190,8 +220,9 @@ static const struct of_device_id stm32_rproc_of_match[] = { { .compatible = "st,stm32mp1-m4" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, stm32_rproc_of_match); -static struct driver_d stm32_rproc_driver = { +static struct driver stm32_rproc_driver = { .name = "stm32-rproc", .probe = stm32_rproc_probe, .of_compatible = DRV_OF_COMPAT(stm32_rproc_of_match), |