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>
42 /* DSP own area */
44 /* DSP instruction area */
54 /* DSP audio mix registers */
76 * enum - Predefined Mailbox Messages
96 * struct imx_dsp_rproc - DSP remote processor state
134 * struct imx_dsp_rproc_dcfg - DSP remote processor configuration
185 /* Reset function for DSP on i.MX8MP */
191 /* Put DSP into reset and stall */ in imx8mp_dsp_reset()
199 regmap_update_bits(priv->regmap, IMX8M_AudioDSP_REG2, in imx8mp_dsp_reset()
203 /* Take the DSP out of reset and keep stalled for FW loading */ in imx8mp_dsp_reset()
212 /* Reset function for DSP on i.MX8ULP */
217 /* Put DSP into reset and stall */ in imx8ulp_dsp_reset()
218 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
220 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
224 /* Configure resources of DSP through TFA */ in imx8ulp_dsp_reset()
227 /* Take the DSP out of reset and keep stalled for FW loading */ in imx8ulp_dsp_reset()
228 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
230 regmap_update_bits(priv->regmap, IMX8ULP_SIM_LPAV_REG_SYSCTRL0, in imx8ulp_dsp_reset()
292 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_ready()
295 if (!priv->rxdb_ch) in imx_dsp_rproc_ready()
299 if (priv->flags & REMOTE_IS_READY) in imx_dsp_rproc_ready()
304 return -ETIMEDOUT; in imx_dsp_rproc_ready()
310 * There is a handshake for start procedure: when DSP starts, it
313 * a message to DSP.
317 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_start()
318 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_start()
319 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_start()
320 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_start()
323 switch (dcfg->method) { in imx_dsp_rproc_start()
325 ret = regmap_update_bits(priv->regmap, in imx_dsp_rproc_start()
326 dcfg->src_reg, in imx_dsp_rproc_start()
327 dcfg->src_mask, in imx_dsp_rproc_start()
328 dcfg->src_start); in imx_dsp_rproc_start()
331 ret = imx_sc_pm_cpu_start(priv->ipc_handle, in imx_dsp_rproc_start()
334 rproc->bootaddr); in imx_dsp_rproc_start()
337 return -EOPNOTSUPP; in imx_dsp_rproc_start()
354 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_stop()
355 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_stop()
356 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_stop()
357 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_stop()
360 if (rproc->state == RPROC_CRASHED) { in imx_dsp_rproc_stop()
361 priv->flags &= ~REMOTE_IS_READY; in imx_dsp_rproc_stop()
365 switch (dcfg->method) { in imx_dsp_rproc_stop()
367 ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, in imx_dsp_rproc_stop()
368 dcfg->src_stop); in imx_dsp_rproc_stop()
371 ret = imx_sc_pm_cpu_start(priv->ipc_handle, in imx_dsp_rproc_stop()
374 rproc->bootaddr); in imx_dsp_rproc_stop()
377 return -EOPNOTSUPP; in imx_dsp_rproc_stop()
383 priv->flags &= ~REMOTE_IS_READY; in imx_dsp_rproc_stop()
389 * imx_dsp_rproc_sys_to_da() - internal memory translation helper
395 * Convert system address (DDR address) to device address (DSP)
401 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_sys_to_da()
402 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_sys_to_da()
406 for (i = 0; i < dcfg->att_size; i++) { in imx_dsp_rproc_sys_to_da()
407 const struct imx_rproc_att *att = &dcfg->att[i]; in imx_dsp_rproc_sys_to_da()
409 if (sys >= att->sa && sys + len <= att->sa + att->size) { in imx_dsp_rproc_sys_to_da()
410 unsigned int offset = sys - att->sa; in imx_dsp_rproc_sys_to_da()
412 *da = att->da + offset; in imx_dsp_rproc_sys_to_da()
417 return -ENOENT; in imx_dsp_rproc_sys_to_da()
422 * This function is executed upon scheduling of the i.MX DSP remoteproc
442 struct rproc *rproc = priv->rproc; in imx_dsp_rproc_vq_work()
444 mutex_lock(&rproc->lock); in imx_dsp_rproc_vq_work()
446 if (rproc->state != RPROC_RUNNING) in imx_dsp_rproc_vq_work()
449 rproc_vq_interrupt(priv->rproc, 0); in imx_dsp_rproc_vq_work()
450 rproc_vq_interrupt(priv->rproc, 1); in imx_dsp_rproc_vq_work()
453 mutex_unlock(&rproc->lock); in imx_dsp_rproc_vq_work()
457 * imx_dsp_rproc_rx_tx_callback() - inbound mailbox message handler
467 struct rproc *rproc = dev_get_drvdata(cl->dev); in imx_dsp_rproc_rx_tx_callback()
468 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_rx_tx_callback()
469 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_rx_tx_callback()
476 complete(&priv->pm_comp); in imx_dsp_rproc_rx_tx_callback()
479 complete(&priv->pm_comp); in imx_dsp_rproc_rx_tx_callback()
482 schedule_work(&priv->rproc_work); in imx_dsp_rproc_rx_tx_callback()
488 * imx_dsp_rproc_rxdb_callback() - inbound mailbox message handler
497 struct rproc *rproc = dev_get_drvdata(cl->dev); in imx_dsp_rproc_rxdb_callback()
498 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_rxdb_callback()
501 priv->flags |= REMOTE_IS_READY; in imx_dsp_rproc_rxdb_callback()
505 * imx_dsp_rproc_mbox_alloc() - request mailbox channels
512 struct device *dev = priv->rproc->dev.parent; in imx_dsp_rproc_mbox_alloc()
516 if (!of_get_property(dev->of_node, "mbox-names", NULL)) in imx_dsp_rproc_mbox_alloc()
519 cl = &priv->cl; in imx_dsp_rproc_mbox_alloc()
520 cl->dev = dev; in imx_dsp_rproc_mbox_alloc()
521 cl->tx_block = true; in imx_dsp_rproc_mbox_alloc()
522 cl->tx_tout = 100; in imx_dsp_rproc_mbox_alloc()
523 cl->knows_txdone = false; in imx_dsp_rproc_mbox_alloc()
524 cl->rx_callback = imx_dsp_rproc_rx_tx_callback; in imx_dsp_rproc_mbox_alloc()
527 priv->tx_ch = mbox_request_channel_byname(cl, "tx"); in imx_dsp_rproc_mbox_alloc()
528 if (IS_ERR(priv->tx_ch)) { in imx_dsp_rproc_mbox_alloc()
529 ret = PTR_ERR(priv->tx_ch); in imx_dsp_rproc_mbox_alloc()
530 dev_dbg(cl->dev, "failed to request tx mailbox channel: %d\n", in imx_dsp_rproc_mbox_alloc()
536 priv->rx_ch = mbox_request_channel_byname(cl, "rx"); in imx_dsp_rproc_mbox_alloc()
537 if (IS_ERR(priv->rx_ch)) { in imx_dsp_rproc_mbox_alloc()
538 ret = PTR_ERR(priv->rx_ch); in imx_dsp_rproc_mbox_alloc()
539 dev_dbg(cl->dev, "failed to request rx mailbox channel: %d\n", in imx_dsp_rproc_mbox_alloc()
544 cl = &priv->cl_rxdb; in imx_dsp_rproc_mbox_alloc()
545 cl->dev = dev; in imx_dsp_rproc_mbox_alloc()
546 cl->rx_callback = imx_dsp_rproc_rxdb_callback; in imx_dsp_rproc_mbox_alloc()
552 priv->rxdb_ch = mbox_request_channel_byname(cl, "rxdb"); in imx_dsp_rproc_mbox_alloc()
553 if (IS_ERR(priv->rxdb_ch)) { in imx_dsp_rproc_mbox_alloc()
554 ret = PTR_ERR(priv->rxdb_ch); in imx_dsp_rproc_mbox_alloc()
555 dev_dbg(cl->dev, "failed to request mbox chan rxdb, ret %d\n", in imx_dsp_rproc_mbox_alloc()
563 mbox_free_channel(priv->rx_ch); in imx_dsp_rproc_mbox_alloc()
565 mbox_free_channel(priv->tx_ch); in imx_dsp_rproc_mbox_alloc()
583 mbox_free_channel(priv->tx_ch); in imx_dsp_rproc_free_mbox()
584 mbox_free_channel(priv->rx_ch); in imx_dsp_rproc_free_mbox()
585 mbox_free_channel(priv->rxdb_ch); in imx_dsp_rproc_free_mbox()
589 * imx_dsp_rproc_add_carveout() - request mailbox channels
593 * The carveouts can help to mapping the memory address for DSP.
597 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_add_carveout()
598 const struct imx_rproc_dcfg *dcfg = dsp_dcfg->dcfg; in imx_dsp_rproc_add_carveout()
599 struct rproc *rproc = priv->rproc; in imx_dsp_rproc_add_carveout()
600 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_add_carveout()
601 struct device_node *np = dev->of_node; in imx_dsp_rproc_add_carveout()
610 for (a = 0; a < dcfg->att_size; a++) { in imx_dsp_rproc_add_carveout()
611 const struct imx_rproc_att *att = &dcfg->att[a]; in imx_dsp_rproc_add_carveout()
613 if (!(att->flags & ATT_OWN)) in imx_dsp_rproc_add_carveout()
616 if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da)) in imx_dsp_rproc_add_carveout()
617 return -EINVAL; in imx_dsp_rproc_add_carveout()
619 cpu_addr = devm_ioremap_wc(dev, att->sa, att->size); in imx_dsp_rproc_add_carveout()
621 dev_err(dev, "failed to map memory %p\n", &att->sa); in imx_dsp_rproc_add_carveout()
622 return -ENOMEM; in imx_dsp_rproc_add_carveout()
626 mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa, in imx_dsp_rproc_add_carveout()
627 att->size, da, NULL, NULL, "dsp_mem"); in imx_dsp_rproc_add_carveout()
630 rproc_coredump_add_segment(rproc, da, att->size); in imx_dsp_rproc_add_carveout()
632 return -ENOMEM; in imx_dsp_rproc_add_carveout()
637 of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); in imx_dsp_rproc_add_carveout()
643 if (!strcmp(it.node->name, "vdev0buffer")) in imx_dsp_rproc_add_carveout()
649 dev_err(dev, "unable to acquire memory-region\n"); in imx_dsp_rproc_add_carveout()
650 return -EINVAL; in imx_dsp_rproc_add_carveout()
653 if (imx_dsp_rproc_sys_to_da(priv, rmem->base, rmem->size, &da)) { in imx_dsp_rproc_add_carveout()
655 return -EINVAL; in imx_dsp_rproc_add_carveout()
658 cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); in imx_dsp_rproc_add_carveout()
661 dev_err(dev, "failed to map memory %p\n", &rmem->base); in imx_dsp_rproc_add_carveout()
662 return -ENOMEM; in imx_dsp_rproc_add_carveout()
666 mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)rmem->base, in imx_dsp_rproc_add_carveout()
667 rmem->size, da, NULL, NULL, it.node->name); in imx_dsp_rproc_add_carveout()
670 rproc_coredump_add_segment(rproc, da, rmem->size); in imx_dsp_rproc_add_carveout()
673 return -ENOMEM; in imx_dsp_rproc_add_carveout()
685 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_prepare()
686 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_prepare()
702 list_for_each_entry(carveout, &rproc->carveouts, node) { in imx_dsp_rproc_prepare()
703 if (carveout->va) in imx_dsp_rproc_prepare()
704 memset(carveout->va, 0, carveout->len); in imx_dsp_rproc_prepare()
713 pm_runtime_put_sync(rproc->dev.parent); in imx_dsp_rproc_unprepare()
721 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_kick()
722 struct device *dev = rproc->dev.parent; in imx_dsp_rproc_kick()
726 if (!priv->tx_ch) { in imx_dsp_rproc_kick()
737 err = mbox_send_message(priv->tx_ch, (void *)&mmsg); in imx_dsp_rproc_kick()
743 * Custom memory copy implementation for i.MX DSP Cores
745 * The IRAM is part of the HiFi DSP.
746 * According to hw specs only 32-bits writes are allowed.
759 return -EINVAL; in imx_dsp_rproc_memcpy()
790 * Custom memset implementation for i.MX DSP Cores
792 * The IRAM is part of the HiFi DSP.
793 * According to hw specs only 32-bits writes are allowed.
805 return -EINVAL; in imx_dsp_rproc_memset()
813 while (q--) in imx_dsp_rproc_memset()
835 * imx_dsp_rproc_elf_load_segments() - load firmware segments to memory
846 struct device *dev = &rproc->dev; in imx_dsp_rproc_elf_load_segments()
850 const u8 *elf_data = fw->data; in imx_dsp_rproc_elf_load_segments()
876 ret = -EINVAL; in imx_dsp_rproc_elf_load_segments()
880 if (offset + filesz > fw->size) { in imx_dsp_rproc_elf_load_segments()
882 offset + filesz, fw->size); in imx_dsp_rproc_elf_load_segments()
883 ret = -EINVAL; in imx_dsp_rproc_elf_load_segments()
890 ret = -EOVERFLOW; in imx_dsp_rproc_elf_load_segments()
899 ret = -EINVAL; in imx_dsp_rproc_elf_load_segments()
915 ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz); in imx_dsp_rproc_elf_load_segments()
930 dev_warn(&rproc->dev, "no resource table found for this firmware\n"); in imx_dsp_rproc_parse_fw()
949 * imx_dsp_attach_pm_domains() - attach the power domains
957 struct device *dev = priv->rproc->dev.parent; in imx_dsp_attach_pm_domains()
960 priv->num_domains = of_count_phandle_with_args(dev->of_node, in imx_dsp_attach_pm_domains()
961 "power-domains", in imx_dsp_attach_pm_domains()
962 "#power-domain-cells"); in imx_dsp_attach_pm_domains()
965 if (priv->num_domains <= 1) in imx_dsp_attach_pm_domains()
968 priv->pd_dev = devm_kmalloc_array(dev, priv->num_domains, in imx_dsp_attach_pm_domains()
969 sizeof(*priv->pd_dev), in imx_dsp_attach_pm_domains()
971 if (!priv->pd_dev) in imx_dsp_attach_pm_domains()
972 return -ENOMEM; in imx_dsp_attach_pm_domains()
974 priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_domains, in imx_dsp_attach_pm_domains()
975 sizeof(*priv->pd_dev_link), in imx_dsp_attach_pm_domains()
977 if (!priv->pd_dev_link) in imx_dsp_attach_pm_domains()
978 return -ENOMEM; in imx_dsp_attach_pm_domains()
980 for (i = 0; i < priv->num_domains; i++) { in imx_dsp_attach_pm_domains()
981 priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); in imx_dsp_attach_pm_domains()
982 if (IS_ERR(priv->pd_dev[i])) { in imx_dsp_attach_pm_domains()
983 ret = PTR_ERR(priv->pd_dev[i]); in imx_dsp_attach_pm_domains()
988 * device_link_add will check priv->pd_dev[i], if it is in imx_dsp_attach_pm_domains()
991 priv->pd_dev_link[i] = device_link_add(dev, in imx_dsp_attach_pm_domains()
992 priv->pd_dev[i], in imx_dsp_attach_pm_domains()
995 if (!priv->pd_dev_link[i]) { in imx_dsp_attach_pm_domains()
996 dev_pm_domain_detach(priv->pd_dev[i], false); in imx_dsp_attach_pm_domains()
997 ret = -EINVAL; in imx_dsp_attach_pm_domains()
1005 while (--i >= 0) { in imx_dsp_attach_pm_domains()
1006 device_link_del(priv->pd_dev_link[i]); in imx_dsp_attach_pm_domains()
1007 dev_pm_domain_detach(priv->pd_dev[i], false); in imx_dsp_attach_pm_domains()
1017 if (priv->num_domains <= 1) in imx_dsp_detach_pm_domains()
1020 for (i = 0; i < priv->num_domains; i++) { in imx_dsp_detach_pm_domains()
1021 device_link_del(priv->pd_dev_link[i]); in imx_dsp_detach_pm_domains()
1022 dev_pm_domain_detach(priv->pd_dev[i], false); in imx_dsp_detach_pm_domains()
1029 * imx_dsp_rproc_detect_mode() - detect DSP control mode
1032 * Different platform has different control method for DSP, which depends
1033 * on how the DSP is integrated in platform.
1035 * For i.MX8QXP and i.MX8QM, DSP should be started and stopped by System
1037 * For i.MX8MP and i.MX8ULP, DSP should be started and stopped by system
1042 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_rproc_detect_mode()
1043 struct device *dev = priv->rproc->dev.parent; in imx_dsp_rproc_detect_mode()
1047 switch (dsp_dcfg->dcfg->method) { in imx_dsp_rproc_detect_mode()
1049 ret = imx_scu_get_handle(&priv->ipc_handle); in imx_dsp_rproc_detect_mode()
1054 regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,dsp-ctrl"); in imx_dsp_rproc_detect_mode()
1060 priv->regmap = regmap; in imx_dsp_rproc_detect_mode()
1063 ret = -EOPNOTSUPP; in imx_dsp_rproc_detect_mode()
1071 /* DSP clocks */
1077 struct device *dev = priv->rproc->dev.parent; in imx_dsp_rproc_clk_get()
1078 struct clk_bulk_data *clks = priv->clks; in imx_dsp_rproc_clk_get()
1090 struct device *dev = &pdev->dev; in imx_dsp_rproc_probe()
1098 return -ENODEV; in imx_dsp_rproc_probe()
1102 dev_err(dev, "failed to parse firmware-name property, ret = %d\n", in imx_dsp_rproc_probe()
1107 rproc = rproc_alloc(dev, "imx-dsp-rproc", &imx_dsp_rproc_ops, fw_name, in imx_dsp_rproc_probe()
1110 return -ENOMEM; in imx_dsp_rproc_probe()
1112 priv = rproc->priv; in imx_dsp_rproc_probe()
1113 priv->rproc = rproc; in imx_dsp_rproc_probe()
1114 priv->dsp_dcfg = dsp_dcfg; in imx_dsp_rproc_probe()
1123 INIT_WORK(&priv->rproc_work, imx_dsp_rproc_vq_work); in imx_dsp_rproc_probe()
1131 /* There are multiple power domains required by DSP on some platform */ in imx_dsp_rproc_probe()
1144 init_completion(&priv->pm_comp); in imx_dsp_rproc_probe()
1145 rproc->auto_boot = false; in imx_dsp_rproc_probe()
1167 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_rproc_remove()
1169 pm_runtime_disable(&pdev->dev); in imx_dsp_rproc_remove()
1179 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_runtime_resume()
1180 const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; in imx_dsp_runtime_resume()
1195 ret = clk_bulk_prepare_enable(DSP_RPROC_CLK_MAX, priv->clks); in imx_dsp_runtime_resume()
1201 /* Reset DSP if needed */ in imx_dsp_runtime_resume()
1202 if (dsp_dcfg->reset) in imx_dsp_runtime_resume()
1203 dsp_dcfg->reset(priv); in imx_dsp_runtime_resume()
1211 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_runtime_suspend()
1213 clk_bulk_disable_unprepare(DSP_RPROC_CLK_MAX, priv->clks); in imx_dsp_runtime_suspend()
1234 ret = rproc->ops->start(rproc); in imx_dsp_load_firmware()
1238 rproc->ops->kick(rproc, 0); in imx_dsp_load_firmware()
1247 struct imx_dsp_rproc *priv = rproc->priv; in imx_dsp_suspend()
1251 if (rproc->state != RPROC_RUNNING) in imx_dsp_suspend()
1254 reinit_completion(&priv->pm_comp); in imx_dsp_suspend()
1256 /* Tell DSP that suspend is happening */ in imx_dsp_suspend()
1257 ret = mbox_send_message(priv->tx_ch, (void *)&mmsg); in imx_dsp_suspend()
1264 * DSP need to save the context at suspend. in imx_dsp_suspend()
1265 * Here waiting the response for DSP, then power can be disabled. in imx_dsp_suspend()
1267 if (!wait_for_completion_timeout(&priv->pm_comp, msecs_to_jiffies(100))) in imx_dsp_suspend()
1268 return -EBUSY; in imx_dsp_suspend()
1272 * The power of DSP is disabled in suspend, so force pm runtime in imx_dsp_suspend()
1288 if (rproc->state != RPROC_RUNNING) in imx_dsp_resume()
1292 * The power of DSP is disabled at suspend, the memory of dsp in imx_dsp_resume()
1294 * firmware and restart the DSP if it is in running state. in imx_dsp_resume()
1297 rproc->firmware, dev, GFP_KERNEL, in imx_dsp_resume()
1318 { .compatible = "fsl,imx8qxp-hifi4", .data = &imx_dsp_rproc_cfg_imx8qxp },
1319 { .compatible = "fsl,imx8qm-hifi4", .data = &imx_dsp_rproc_cfg_imx8qm },
1320 { .compatible = "fsl,imx8mp-hifi4", .data = &imx_dsp_rproc_cfg_imx8mp },
1321 { .compatible = "fsl,imx8ulp-hifi4", .data = &imx_dsp_rproc_cfg_imx8ulp },
1330 .name = "imx-dsp-rproc",