Lines Matching +full:imx8qxp +full:- +full:dsp
1 // SPDX-License-Identifier: GPL-2.0-only
4 #include <dt-bindings/firmware/imx/rsrc.h>
5 #include <linux/arm-smccc.h>
43 /* DSP own area */
45 /* DSP instruction area */
55 /* DSP audio mix registers */
77 * enum - Predefined Mailbox Messages
97 * struct imx_dsp_rproc - DSP remote processor state
133 * struct imx_dsp_rproc_dcfg - DSP remote processor configuration
184 /* Reset function for DSP on i.MX8MP */
190 /* Put DSP into reset and stall */ in imx8mp_dsp_reset()
198 reset_control_assert(priv->run_stall); in imx8mp_dsp_reset()
200 /* Take the DSP out of reset and keep stalled for FW loading */ in imx8mp_dsp_reset()
209 /* Reset function for DSP on i.MX8ULP */
214 /* Put DSP into reset and stall */ in imx8ulp_dsp_reset()
215 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
217 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
221 /* Configure resources of DSP through TFA */ in imx8ulp_dsp_reset()
224 /* Take the DSP out of reset and keep stalled for FW loading */ in imx8ulp_dsp_reset()
225 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
227 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
285 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_ready()
288 if (!priv->rxdb_ch) in imx_dsp_rproc_ready()
292 if (priv->flags & REMOTE_IS_READY) in imx_dsp_rproc_ready()
297 return -ETIMEDOUT; in imx_dsp_rproc_ready()
303 * There is a handshake for start procedure: when DSP starts, it
306 * a message to DSP.
310 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_start()
311 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_start()
312 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_start()
313 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_start()
316 switch (dcfg->method) { in imx_dsp_rproc_start()
318 ret = regmap_update_bits(priv->regmap, in imx_dsp_rproc_start()
319 dcfg->src_reg, in imx_dsp_rproc_start()
320 dcfg->src_mask, in imx_dsp_rproc_start()
321 dcfg->src_start); in imx_dsp_rproc_start()
324 ret = imx_sc_pm_cpu_start(priv->ipc_handle, in imx_dsp_rproc_start()
327 rproc->bootaddr); in imx_dsp_rproc_start()
330 ret = reset_control_deassert(priv->run_stall); in imx_dsp_rproc_start()
333 return -EOPNOTSUPP; in imx_dsp_rproc_start()
350 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_stop()
351 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_stop()
352 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_stop()
353 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_stop()
356 if (rproc->state == RPROC_CRASHED) { in imx_dsp_rproc_stop()
357 priv->flags &= ~REMOTE_IS_READY; in imx_dsp_rproc_stop()
361 switch (dcfg->method) { in imx_dsp_rproc_stop()
363 ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, in imx_dsp_rproc_stop()
364 dcfg->src_stop); in imx_dsp_rproc_stop()
367 ret = imx_sc_pm_cpu_start(priv->ipc_handle, in imx_dsp_rproc_stop()
370 rproc->bootaddr); in imx_dsp_rproc_stop()
373 ret = reset_control_assert(priv->run_stall); in imx_dsp_rproc_stop()
376 return -EOPNOTSUPP; in imx_dsp_rproc_stop()
382 priv->flags &= ~REMOTE_IS_READY; in imx_dsp_rproc_stop()
388 * imx_dsp_rproc_sys_to_da() - internal memory translation helper
394 * Convert system address (DDR address) to device address (DSP)
400 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_sys_to_da()
401 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_sys_to_da()
405 for (i = 0; i < dcfg->att_size; i++) { in imx_dsp_rproc_sys_to_da()
406 const struct imx_rproc_att *att = &dcfg->att[i]; in imx_dsp_rproc_sys_to_da()
408 if (sys >= att->sa && sys + len <= att->sa + att->size) { in imx_dsp_rproc_sys_to_da()
409 unsigned int offset = sys - att->sa; in imx_dsp_rproc_sys_to_da()
411 *da = att->da + offset; in imx_dsp_rproc_sys_to_da()
416 return -ENOENT; in imx_dsp_rproc_sys_to_da()
421 * This function is executed upon scheduling of the i.MX DSP remoteproc
441 struct rproc *rproc = priv->rproc; in imx_dsp_rproc_vq_work()
443 mutex_lock(&rproc->lock); in imx_dsp_rproc_vq_work()
445 if (rproc->state != RPROC_RUNNING) in imx_dsp_rproc_vq_work()
448 rproc_vq_interrupt(priv->rproc, 0); in imx_dsp_rproc_vq_work()
449 rproc_vq_interrupt(priv->rproc, 1); in imx_dsp_rproc_vq_work()
452 mutex_unlock(&rproc->lock); in imx_dsp_rproc_vq_work()
456 * imx_dsp_rproc_rx_tx_callback() - inbound mailbox message handler
466 struct rproc *rproc = dev_get_drvdata(cl->dev); in imx_dsp_rproc_rx_tx_callback()
467 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_rx_tx_callback()
468 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_rx_tx_callback()
475 complete(&priv->pm_comp); in imx_dsp_rproc_rx_tx_callback()
478 complete(&priv->pm_comp); in imx_dsp_rproc_rx_tx_callback()
481 schedule_work(&priv->rproc_work); in imx_dsp_rproc_rx_tx_callback()
487 * imx_dsp_rproc_rxdb_callback() - inbound mailbox message handler
496 struct rproc *rproc = dev_get_drvdata(cl->dev); in imx_dsp_rproc_rxdb_callback()
497 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_rxdb_callback()
500 priv->flags |= REMOTE_IS_READY; in imx_dsp_rproc_rxdb_callback()
504 * imx_dsp_rproc_mbox_alloc() - request mailbox channels
511 struct device *dev = priv->rproc->dev.parent; in imx_dsp_rproc_mbox_alloc()
515 if (!of_property_present(dev->of_node, "mbox-names")) in imx_dsp_rproc_mbox_alloc()
518 cl = &priv->cl; in imx_dsp_rproc_mbox_alloc()
519 cl->dev = dev; in imx_dsp_rproc_mbox_alloc()
520 cl->tx_block = true; in imx_dsp_rproc_mbox_alloc()
521 cl->tx_tout = 100; in imx_dsp_rproc_mbox_alloc()
522 cl->knows_txdone = false; in imx_dsp_rproc_mbox_alloc()
523 cl->rx_callback = imx_dsp_rproc_rx_tx_callback; in imx_dsp_rproc_mbox_alloc()
526 priv->tx_ch = mbox_request_channel_byname(cl, "tx"); in imx_dsp_rproc_mbox_alloc()
527 if (IS_ERR(priv->tx_ch)) { in imx_dsp_rproc_mbox_alloc()
528 ret = PTR_ERR(priv->tx_ch); in imx_dsp_rproc_mbox_alloc()
529 dev_dbg(cl->dev, "failed to request tx mailbox channel: %d\n", in imx_dsp_rproc_mbox_alloc()
535 priv->rx_ch = mbox_request_channel_byname(cl, "rx"); in imx_dsp_rproc_mbox_alloc()
536 if (IS_ERR(priv->rx_ch)) { in imx_dsp_rproc_mbox_alloc()
537 ret = PTR_ERR(priv->rx_ch); in imx_dsp_rproc_mbox_alloc()
538 dev_dbg(cl->dev, "failed to request rx mailbox channel: %d\n", in imx_dsp_rproc_mbox_alloc()
543 cl = &priv->cl_rxdb; in imx_dsp_rproc_mbox_alloc()
544 cl->dev = dev; in imx_dsp_rproc_mbox_alloc()
545 cl->rx_callback = imx_dsp_rproc_rxdb_callback; in imx_dsp_rproc_mbox_alloc()
551 priv->rxdb_ch = mbox_request_channel_byname(cl, "rxdb"); in imx_dsp_rproc_mbox_alloc()
552 if (IS_ERR(priv->rxdb_ch)) { in imx_dsp_rproc_mbox_alloc()
553 ret = PTR_ERR(priv->rxdb_ch); in imx_dsp_rproc_mbox_alloc()
554 dev_dbg(cl->dev, "failed to request mbox chan rxdb, ret %d\n", in imx_dsp_rproc_mbox_alloc()
562 mbox_free_channel(priv->rx_ch); in imx_dsp_rproc_mbox_alloc()
564 mbox_free_channel(priv->tx_ch); in imx_dsp_rproc_mbox_alloc()
582 mbox_free_channel(priv->tx_ch); in imx_dsp_rproc_free_mbox()
583 mbox_free_channel(priv->rx_ch); in imx_dsp_rproc_free_mbox()
584 mbox_free_channel(priv->rxdb_ch); in imx_dsp_rproc_free_mbox()
588 * imx_dsp_rproc_add_carveout() - request mailbox channels
592 * The carveouts can help to mapping the memory address for DSP.
596 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_add_carveout()
597 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_add_carveout()
598 struct rproc *rproc = priv->rproc; in imx_dsp_rproc_add_carveout()
599 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_add_carveout()
600 struct device_node *np = dev->of_node; in imx_dsp_rproc_add_carveout()
609 for (a = 0; a < dcfg->att_size; a++) { in imx_dsp_rproc_add_carveout()
610 const struct imx_rproc_att *att = &dcfg->att[a]; in imx_dsp_rproc_add_carveout()
612 if (!(att->flags & ATT_OWN)) in imx_dsp_rproc_add_carveout()
615 if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da)) in imx_dsp_rproc_add_carveout()
616 return -EINVAL; in imx_dsp_rproc_add_carveout()
618 cpu_addr = devm_ioremap_wc(dev, att->sa, att->size); in imx_dsp_rproc_add_carveout()
620 dev_err(dev, "failed to map memory %p\n", &att->sa); in imx_dsp_rproc_add_carveout()
621 return -ENOMEM; in imx_dsp_rproc_add_carveout()
625 mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa, in imx_dsp_rproc_add_carveout()
626 att->size, da, NULL, NULL, "dsp_mem"); in imx_dsp_rproc_add_carveout()
629 rproc_coredump_add_segment(rproc, da, att->size); in imx_dsp_rproc_add_carveout()
631 return -ENOMEM; in imx_dsp_rproc_add_carveout()
636 of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); in imx_dsp_rproc_add_carveout()
642 if (!strcmp(it.node->name, "vdev0buffer")) in imx_dsp_rproc_add_carveout()
648 dev_err(dev, "unable to acquire memory-region\n"); in imx_dsp_rproc_add_carveout()
649 return -EINVAL; in imx_dsp_rproc_add_carveout()
652 if (imx_dsp_rproc_sys_to_da(priv, rmem->base, rmem->size, &da)) { in imx_dsp_rproc_add_carveout()
654 return -EINVAL; in imx_dsp_rproc_add_carveout()
657 cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); in imx_dsp_rproc_add_carveout()
660 dev_err(dev, "failed to map memory %p\n", &rmem->base); in imx_dsp_rproc_add_carveout()
661 return -ENOMEM; in imx_dsp_rproc_add_carveout()
665 mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)rmem->base, in imx_dsp_rproc_add_carveout()
666 rmem->size, da, NULL, NULL, it.node->name); in imx_dsp_rproc_add_carveout()
669 rproc_coredump_add_segment(rproc, da, rmem->size); in imx_dsp_rproc_add_carveout()
672 return -ENOMEM; in imx_dsp_rproc_add_carveout()
684 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_prepare()
685 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_prepare()
701 list_for_each_entry(carveout, &rproc->carveouts, node) { in imx_dsp_rproc_prepare()
702 if (carveout->va) in imx_dsp_rproc_prepare()
703 memset(carveout->va, 0, carveout->len); in imx_dsp_rproc_prepare()
712 pm_runtime_put_sync(rproc->dev.parent); in imx_dsp_rproc_unprepare()
720 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_kick()
721 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_kick()
725 if (!priv->tx_ch) { in imx_dsp_rproc_kick()
736 err = mbox_send_message(priv->tx_ch, (void *)&mmsg); in imx_dsp_rproc_kick()
742 * Custom memory copy implementation for i.MX DSP Cores
744 * The IRAM is part of the HiFi DSP.
745 * According to hw specs only 32-bits writes are allowed.
758 return -EINVAL; in imx_dsp_rproc_memcpy()
789 * Custom memset implementation for i.MX DSP Cores
791 * The IRAM is part of the HiFi DSP.
792 * According to hw specs only 32-bits writes are allowed.
804 return -EINVAL; in imx_dsp_rproc_memset()
812 while (q--) in imx_dsp_rproc_memset()
834 * imx_dsp_rproc_elf_load_segments() - load firmware segments to memory
845 struct device *dev = &rproc->dev; in imx_dsp_rproc_elf_load_segments()
849 const u8 *elf_data = fw->data; in imx_dsp_rproc_elf_load_segments()
875 ret = -EINVAL; in imx_dsp_rproc_elf_load_segments()
879 if (offset + filesz > fw->size) { in imx_dsp_rproc_elf_load_segments()
881 offset + filesz, fw->size); in imx_dsp_rproc_elf_load_segments()
882 ret = -EINVAL; in imx_dsp_rproc_elf_load_segments()
889 ret = -EOVERFLOW; in imx_dsp_rproc_elf_load_segments()
898 ret = -EINVAL; in imx_dsp_rproc_elf_load_segments()
914 ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz); in imx_dsp_rproc_elf_load_segments()
929 dev_warn(&rproc->dev, "no resource table found for this firmware\n"); in imx_dsp_rproc_parse_fw()
948 * imx_dsp_attach_pm_domains() - attach the power domains
956 struct device *dev = priv->rproc->dev.parent; in imx_dsp_attach_pm_domains()
960 if (dev->pm_domain) in imx_dsp_attach_pm_domains()
963 ret = dev_pm_domain_attach_list(dev, NULL, &priv->pd_list); in imx_dsp_attach_pm_domains()
968 * imx_dsp_rproc_detect_mode() - detect DSP control mode
971 * Different platform has different control method for DSP, which depends
972 * on how the DSP is integrated in platform.
974 * For i.MX8QXP and i.MX8QM, DSP should be started and stopped by System
976 * For i.MX8MP and i.MX8ULP, DSP should be started and stopped by system
981 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_detect_mode()
982 struct device *dev = priv->rproc->dev.parent; in imx_dsp_rproc_detect_mode()
986 switch (dsp_dcfg->dcfg->method) { in imx_dsp_rproc_detect_mode()
988 ret = imx_scu_get_handle(&priv->ipc_handle); in imx_dsp_rproc_detect_mode()
993 regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,dsp-ctrl"); in imx_dsp_rproc_detect_mode()
999 priv->regmap = regmap; in imx_dsp_rproc_detect_mode()
1002 priv->run_stall = devm_reset_control_get_exclusive(dev, "runstall"); in imx_dsp_rproc_detect_mode()
1003 if (IS_ERR(priv->run_stall)) { in imx_dsp_rproc_detect_mode()
1004 dev_err(dev, "Failed to get DSP runstall reset control\n"); in imx_dsp_rproc_detect_mode()
1005 return PTR_ERR(priv->run_stall); in imx_dsp_rproc_detect_mode()
1009 ret = -EOPNOTSUPP; in imx_dsp_rproc_detect_mode()
1017 /* DSP clocks */
1023 struct device *dev = priv->rproc->dev.parent; in imx_dsp_rproc_clk_get()
1024 struct clk_bulk_data *clks = priv->clks; in imx_dsp_rproc_clk_get()
1036 struct device *dev = &pdev->dev; in imx_dsp_rproc_probe()
1044 return -ENODEV; in imx_dsp_rproc_probe()
1048 dev_err(dev, "failed to parse firmware-name property, ret = %d\n", in imx_dsp_rproc_probe()
1053 rproc = devm_rproc_alloc(dev, "imx-dsp-rproc", &imx_dsp_rproc_ops, in imx_dsp_rproc_probe()
1056 return -ENOMEM; in imx_dsp_rproc_probe()
1058 priv = rproc->priv; in imx_dsp_rproc_probe()
1059 priv->rproc = rproc; in imx_dsp_rproc_probe()
1060 priv->dsp_dcfg = dsp_dcfg; in imx_dsp_rproc_probe()
1069 INIT_WORK(&priv->rproc_work, imx_dsp_rproc_vq_work); in imx_dsp_rproc_probe()
1077 /* There are multiple power domains required by DSP on some platform */ in imx_dsp_rproc_probe()
1090 init_completion(&priv->pm_comp); in imx_dsp_rproc_probe()
1091 rproc->auto_boot = false; in imx_dsp_rproc_probe()
1103 dev_pm_domain_detach_list(priv->pd_list); in imx_dsp_rproc_probe()
1111 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_remove()
1113 pm_runtime_disable(&pdev->dev); in imx_dsp_rproc_remove()
1115 dev_pm_domain_detach_list(priv->pd_list); in imx_dsp_rproc_remove()
1122 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_runtime_resume()
1123 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_runtime_resume()
1138 ret = clk_bulk_prepare_enable(DSP_RPROC_CLK_MAX, priv->clks); in imx_dsp_runtime_resume()
1144 /* Reset DSP if needed */ in imx_dsp_runtime_resume()
1145 if (dsp_dcfg->reset) in imx_dsp_runtime_resume()
1146 dsp_dcfg->reset(priv); in imx_dsp_runtime_resume()
1154 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_runtime_suspend()
1156 clk_bulk_disable_unprepare(DSP_RPROC_CLK_MAX, priv->clks); in imx_dsp_runtime_suspend()
1177 ret = rproc->ops->start(rproc); in imx_dsp_load_firmware()
1181 rproc->ops->kick(rproc, 0); in imx_dsp_load_firmware()
1190 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_suspend()
1194 if (rproc->state != RPROC_RUNNING) in imx_dsp_suspend()
1197 reinit_completion(&priv->pm_comp); in imx_dsp_suspend()
1199 /* Tell DSP that suspend is happening */ in imx_dsp_suspend()
1200 ret = mbox_send_message(priv->tx_ch, (void *)&mmsg); in imx_dsp_suspend()
1207 * DSP need to save the context at suspend. in imx_dsp_suspend()
1208 * Here waiting the response for DSP, then power can be disabled. in imx_dsp_suspend()
1210 if (!wait_for_completion_timeout(&priv->pm_comp, msecs_to_jiffies(100))) in imx_dsp_suspend()
1211 return -EBUSY; in imx_dsp_suspend()
1215 * The power of DSP is disabled in suspend, so force pm runtime in imx_dsp_suspend()
1231 if (rproc->state != RPROC_RUNNING) in imx_dsp_resume()
1235 * The power of DSP is disabled at suspend, the memory of dsp in imx_dsp_resume()
1237 * firmware and restart the DSP if it is in running state. in imx_dsp_resume()
1240 rproc->firmware, dev, GFP_KERNEL, in imx_dsp_resume()
1261 { .compatible = "fsl,imx8qxp-hifi4", .data = &imx_dsp_rproc_cfg_imx8qxp },
1262 { .compatible = "fsl,imx8qm-hifi4", .data = &imx_dsp_rproc_cfg_imx8qm },
1263 { .compatible = "fsl,imx8mp-hifi4", .data = &imx_dsp_rproc_cfg_imx8mp },
1264 { .compatible = "fsl,imx8ulp-hifi4", .data = &imx_dsp_rproc_cfg_imx8ulp },
1273 .name = "imx-dsp-rproc",