for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) { if (!strncmp(ddata->mb[i].name, name, strlen(name))) return i;
}
dev_err(&rproc->dev, "mailbox %s not found\n", name);
return -EINVAL;
}
staticint stm32_rproc_prepare(struct rproc *rproc)
{ struct device *dev = rproc->dev.parent; struct device_node *np = dev->of_node; struct of_phandle_iterator it; struct rproc_mem_entry *mem; struct reserved_mem *rmem;
u64 da; int index = 0;
/* Register associated reserved memory regions */
of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); while (of_phandle_iterator_next(&it) == 0) {
rmem = of_reserved_mem_lookup(it.node); if (!rmem) {
of_node_put(it.node);
dev_err(dev, "unable to acquire memory-region\n"); return -EINVAL;
}
if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) {
of_node_put(it.node);
dev_err(dev, "memory region not valid %pa\n",
&rmem->base); return -EINVAL;
}
/* No need to map vdev buffer */ if (strcmp(it.node->name, "vdev0buffer")) { /* Register memory region */
mem = rproc_mem_entry_init(dev, NULL,
(dma_addr_t)rmem->base,
rmem->size, da,
stm32_rproc_mem_alloc,
stm32_rproc_mem_release,
it.node->name);
if (mem)
rproc_coredump_add_segment(rproc, da,
rmem->size);
} else { /* Register reserved memory for vdev buffer alloc */
mem = rproc_of_resm_mem_entry_init(dev, index,
rmem->size,
rmem->base,
it.node->name);
}
if (!mem) {
of_node_put(it.node); return -ENOMEM;
}
rproc_add_carveout(rproc, mem);
index++;
}
return 0;
}
staticint stm32_rproc_parse_fw(struct rproc *rproc, conststruct firmware *fw)
{ if (rproc_elf_load_rsc_table(rproc, fw))
dev_warn(&rproc->dev, "no resource table found for this firmware\n");
/* * 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 (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);
} elseif (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);
}
if (err)
dev_err(&rproc->dev, "failed to set hold boot\n");
/* request shutdown of the remote processor */ if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); if (idx >= 0 && ddata->mb[idx].chan) {
err = mbox_send_message(ddata->mb[idx].chan, "detach"); if (err < 0)
dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
}
}
err = stm32_rproc_set_hold_boot(rproc, true); if (err) return err;
err = reset_control_assert(ddata->rst); if (err) {
dev_err(&rproc->dev, "failed to assert the reset\n"); return err;
}
/* to allow platform Standby power mode, set remote proc Deep Sleep */ if (ddata->pdds.map) {
err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
ddata->pdds.mask, 1); if (err) {
dev_err(&rproc->dev, "failed to set pdds\n"); return err;
}
}
/* update coprocessor state to OFF if available */ if (ddata->m4_state.map) {
err = regmap_update_bits(ddata->m4_state.map,
ddata->m4_state.reg,
ddata->m4_state.mask,
M4_STATE_OFF); if (err) {
dev_err(&rproc->dev, "failed to set copro state\n"); return err;
}
}
return 0;
}
staticvoid stm32_rproc_kick(struct rproc *rproc, int vqid)
{ struct stm32_rproc *ddata = rproc->priv; unsignedint i; int err;
if (WARN_ON(vqid >= MBOX_NB_VQ)) return;
for (i = 0; i < MBOX_NB_MBX; i++) { if (vqid != ddata->mb[i].vq_id) continue; if (!ddata->mb[i].chan) return;
err = mbox_send_message(ddata->mb[i].chan, "kick"); if (err < 0)
dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
__func__, ddata->mb[i].name, err); return;
}
}
done: /* * Assuming the resource table fits in 1kB is fair. * Notice for the detach, that this 1 kB memory area has to be reserved in the coprocessor * firmware for the resource table. On detach, the remoteproc core re-initializes this * entire area by overwriting it with the initial values stored in rproc->clean_table.
*/
*table_sz = RSC_TBL_SIZE; return (__force struct resource_table *)ddata->rsc_va;
}
irq = platform_get_irq_optional(pdev, 0); if (irq == -EPROBE_DEFER) return irq;
if (irq > 0) {
err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
dev_name(dev), pdev); if (err) return dev_err_probe(dev, err, "failed to request wdg irq\n");
ddata->wdg_irq = irq;
if (of_property_read_bool(np, "wakeup-source")) {
device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, irq);
}
dev_info(dev, "wdg irq registered\n");
}
ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst"); if (!ddata->rst) { /* Try legacy fallback method: get it by index */
ddata->rst = devm_reset_control_get_by_index(dev, 0);
} if (IS_ERR(ddata->rst)) return dev_err_probe(dev, PTR_ERR(ddata->rst), "failed to get mcu_reset\n");
/* * 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
*/
ddata->hold_boot_rst = devm_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;
}
}
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;
}
}
err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); if (err)
dev_info(dev, "failed to get pdds\n");
/* * See if we can check the M4 status, i.e if it was started * from the boot loader or not.
*/
err = stm32_rproc_get_syscon(np, "st,syscfg-m4-state",
&ddata->m4_state); if (err) { /* remember this */
ddata->m4_state.map = NULL; /* no coprocessor state syscon (optional) */
dev_warn(dev, "m4 state not supported\n");
/* no need to go further */ return 0;
}
/* See if we can get the resource table */
err = stm32_rproc_get_syscon(np, "st,syscfg-rsc-tbl",
&ddata->rsctbl); if (err) { /* no rsc table syscon (optional) */
dev_warn(dev, "rsc tbl syscon not supported\n");
}
return 0;
}
staticint stm32_rproc_get_m4_status(struct stm32_rproc *ddata, unsignedint *state)
{ /* See stm32_rproc_parse_dt() */ if (!ddata->m4_state.map) { /* * We couldn't get the coprocessor's state, assume * it is not running.
*/
*state = M4_STATE_OFF; return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.