Lines Matching +full:fiq +full:- +full:index
1 // SPDX-License-Identifier: GPL-2.0
7 #include <dt-bindings/power/xlnx-zynqmp-power.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/firmware/xlnx-zynqmp.h>
12 #include <linux/mailbox/zynqmp-ipi-message.h>
30 * reflects possible values of xlnx,cluster-mode dt-property
34 LOCKSTEP_MODE = 1, /* cores execute same code in lockstep,clk-for-clk */
39 * struct mem_bank_data - Memory Bank description
44 * @pm_domain_id: Power-domains id of memory bank for firmware to turn on/off
78 * accepted for system-dt specifications and upstreamed in linux kernel
132 * event_notified_idr_cb() - callback for vq_interrupt per notifyid
133 * @id: rproc->notify id
147 dev_dbg(&rproc->dev, "data not found for vqid=%d\n", id); in event_notified_idr_cb()
153 * handle_event_notified() - remoteproc notification work function
164 rproc = ipi->r5_core->rproc; in handle_event_notified()
173 idr_for_each(&rproc->notifyids, event_notified_idr_cb, rproc); in handle_event_notified()
177 * zynqmp_r5_mb_rx_cb() - receive channel mailbox callback
194 buf_msg = (struct zynqmp_ipi_message *)ipi->rx_mc_buf; in zynqmp_r5_mb_rx_cb()
195 len = ipi_msg->len; in zynqmp_r5_mb_rx_cb()
197 dev_warn(cl->dev, "msg size exceeded than %d\n", in zynqmp_r5_mb_rx_cb()
201 buf_msg->len = len; in zynqmp_r5_mb_rx_cb()
202 memcpy(buf_msg->data, ipi_msg->data, len); in zynqmp_r5_mb_rx_cb()
205 if (mbox_send_message(ipi->rx_chan, NULL) < 0) in zynqmp_r5_mb_rx_cb()
206 dev_err(cl->dev, "ack failed to mbox rx_chan\n"); in zynqmp_r5_mb_rx_cb()
208 schedule_work(&ipi->mbox_work); in zynqmp_r5_mb_rx_cb()
212 * zynqmp_r5_setup_mbox() - Setup mailboxes related properties
229 mbox_cl = &ipi->mbox_cl; in zynqmp_r5_setup_mbox()
230 mbox_cl->rx_callback = zynqmp_r5_mb_rx_cb; in zynqmp_r5_setup_mbox()
231 mbox_cl->tx_block = false; in zynqmp_r5_setup_mbox()
232 mbox_cl->knows_txdone = false; in zynqmp_r5_setup_mbox()
233 mbox_cl->tx_done = NULL; in zynqmp_r5_setup_mbox()
234 mbox_cl->dev = cdev; in zynqmp_r5_setup_mbox()
237 ipi->tx_chan = mbox_request_channel_byname(mbox_cl, "tx"); in zynqmp_r5_setup_mbox()
238 if (IS_ERR(ipi->tx_chan)) { in zynqmp_r5_setup_mbox()
239 ipi->tx_chan = NULL; in zynqmp_r5_setup_mbox()
245 ipi->rx_chan = mbox_request_channel_byname(mbox_cl, "rx"); in zynqmp_r5_setup_mbox()
246 if (IS_ERR(ipi->rx_chan)) { in zynqmp_r5_setup_mbox()
247 mbox_free_channel(ipi->tx_chan); in zynqmp_r5_setup_mbox()
248 ipi->rx_chan = NULL; in zynqmp_r5_setup_mbox()
249 ipi->tx_chan = NULL; in zynqmp_r5_setup_mbox()
255 INIT_WORK(&ipi->mbox_work, handle_event_notified); in zynqmp_r5_setup_mbox()
265 if (ipi->tx_chan) { in zynqmp_r5_free_mbox()
266 mbox_free_channel(ipi->tx_chan); in zynqmp_r5_free_mbox()
267 ipi->tx_chan = NULL; in zynqmp_r5_free_mbox()
270 if (ipi->rx_chan) { in zynqmp_r5_free_mbox()
271 mbox_free_channel(ipi->rx_chan); in zynqmp_r5_free_mbox()
272 ipi->rx_chan = NULL; in zynqmp_r5_free_mbox()
279 * zynqmp_r5_core_kick() - kick a firmware if mbox is provided
285 struct zynqmp_r5_core *r5_core = rproc->priv; in zynqmp_r5_rproc_kick()
286 struct device *dev = r5_core->dev; in zynqmp_r5_rproc_kick()
291 ipi = r5_core->ipi; in zynqmp_r5_rproc_kick()
295 mb_msg = (struct zynqmp_ipi_message *)ipi->tx_mc_buf; in zynqmp_r5_rproc_kick()
296 memcpy(mb_msg->data, &vqid, sizeof(vqid)); in zynqmp_r5_rproc_kick()
297 mb_msg->len = sizeof(vqid); in zynqmp_r5_rproc_kick()
298 ret = mbox_send_message(ipi->tx_chan, mb_msg); in zynqmp_r5_rproc_kick()
320 ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); in zynqmp_r5_set_mode()
322 dev_err(r5_core->dev, "failed to set RPU mode\n"); in zynqmp_r5_set_mode()
326 ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, tcm_mode); in zynqmp_r5_set_mode()
328 dev_err(r5_core->dev, "failed to configure TCM\n"); in zynqmp_r5_set_mode()
339 * return 0 on success, otherwise non-zero value on failure
343 struct zynqmp_r5_core *r5_core = rproc->priv; in zynqmp_r5_rproc_start()
348 * The exception vector pointers (EVP) refer to the base-address of in zynqmp_r5_rproc_start()
349 * exception vectors (for reset, IRQ, FIQ, etc). The reset-vector in zynqmp_r5_rproc_start()
350 * starts at the base-address and subsequent vectors are on 4-byte in zynqmp_r5_rproc_start()
354 * from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip Memory) in zynqmp_r5_rproc_start()
360 * and jitter. Also, if the OCM is secured and the Cortex-R5F processor in zynqmp_r5_rproc_start()
361 * is non-secured, then the Cortex-R5F processor cannot access the in zynqmp_r5_rproc_start()
364 bootmem = (rproc->bootaddr >= 0xFFFC0000) ? in zynqmp_r5_rproc_start()
367 dev_dbg(r5_core->dev, "RPU boot addr 0x%llx from %s.", rproc->bootaddr, in zynqmp_r5_rproc_start()
370 ret = zynqmp_pm_request_wake(r5_core->pm_domain_id, 1, in zynqmp_r5_rproc_start()
373 dev_err(r5_core->dev, in zynqmp_r5_rproc_start()
374 "failed to start RPU = 0x%x\n", r5_core->pm_domain_id); in zynqmp_r5_rproc_start()
384 * return 0 on success, otherwise non-zero value on failure
388 struct zynqmp_r5_core *r5_core = rproc->priv; in zynqmp_r5_rproc_stop()
391 ret = zynqmp_pm_force_pwrdwn(r5_core->pm_domain_id, in zynqmp_r5_rproc_stop()
394 dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret); in zynqmp_r5_rproc_stop()
402 * @mem: mem descriptor to map reserved memory-regions
404 * Callback to map va for memory-region's carveout.
406 * return 0 on success, otherwise non-zero value on failure
413 va = ioremap_wc(mem->dma, mem->len); in zynqmp_r5_mem_region_map()
415 return -ENOMEM; in zynqmp_r5_mem_region_map()
417 mem->va = (void *)va; in zynqmp_r5_mem_region_map()
427 * Unmap memory-region carveout
434 iounmap((void __iomem *)mem->va); in zynqmp_r5_mem_region_unmap()
442 * Construct rproc mem carveouts from memory-region property nodes
444 * return 0 on success, otherwise non-zero value on failure
454 r5_core = rproc->priv; in add_mem_regions_carveout()
457 of_phandle_iterator_init(&it, r5_core->np, "memory-region", NULL, 0); in add_mem_regions_carveout()
463 dev_err(&rproc->dev, "unable to acquire memory-region\n"); in add_mem_regions_carveout()
464 return -EINVAL; in add_mem_regions_carveout()
467 if (!strcmp(it.node->name, "vdev0buffer")) { in add_mem_regions_carveout()
469 rproc_mem = rproc_of_resm_mem_entry_init(&rproc->dev, i, in add_mem_regions_carveout()
470 rmem->size, in add_mem_regions_carveout()
471 rmem->base, in add_mem_regions_carveout()
472 it.node->name); in add_mem_regions_carveout()
475 rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL, in add_mem_regions_carveout()
476 (dma_addr_t)rmem->base, in add_mem_regions_carveout()
477 rmem->size, rmem->base, in add_mem_regions_carveout()
480 it.node->name); in add_mem_regions_carveout()
485 return -ENOMEM; in add_mem_regions_carveout()
490 dev_dbg(&rproc->dev, "reserved mem carveout %s addr=%llx, size=0x%llx", in add_mem_regions_carveout()
491 it.node->name, rmem->base, rmem->size); in add_mem_regions_carveout()
509 iounmap((void __iomem *)mem->va); in tcm_mem_unmap()
522 * return 0 on success, otherwise non-zero value on failure
529 va = ioremap_wc(mem->dma, mem->len); in tcm_mem_map()
531 return -ENOMEM; in tcm_mem_map()
534 mem->va = (void *)va; in tcm_mem_map()
537 memset_io(va, 0, mem->len); in tcm_mem_map()
548 * return 0 on success, otherwise non-zero value on failure
562 r5_core = rproc->priv; in add_tcm_carveout_split_mode()
563 dev = r5_core->dev; in add_tcm_carveout_split_mode()
564 num_banks = r5_core->tcm_bank_count; in add_tcm_carveout_split_mode()
567 * Power-on Each 64KB TCM, in add_tcm_carveout_split_mode()
572 bank_addr = r5_core->tcm_banks[i]->addr; in add_tcm_carveout_split_mode()
573 da = r5_core->tcm_banks[i]->da; in add_tcm_carveout_split_mode()
574 bank_name = r5_core->tcm_banks[i]->bank_name; in add_tcm_carveout_split_mode()
575 bank_size = r5_core->tcm_banks[i]->size; in add_tcm_carveout_split_mode()
576 pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; in add_tcm_carveout_split_mode()
594 ret = -ENOMEM; in add_tcm_carveout_split_mode()
606 for (i--; i >= 0; i--) { in add_tcm_carveout_split_mode()
607 pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; in add_tcm_carveout_split_mode()
619 * return 0 on success, otherwise non-zero value on failure
633 r5_core = rproc->priv; in add_tcm_carveout_lockstep_mode()
634 dev = r5_core->dev; in add_tcm_carveout_lockstep_mode()
637 num_banks = r5_core->tcm_bank_count; in add_tcm_carveout_lockstep_mode()
647 pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; in add_tcm_carveout_lockstep_mode()
658 bank_size = r5_core->tcm_banks[i]->size; in add_tcm_carveout_lockstep_mode()
662 bank_addr = r5_core->tcm_banks[i]->addr; in add_tcm_carveout_lockstep_mode()
663 da = r5_core->tcm_banks[i]->da; in add_tcm_carveout_lockstep_mode()
664 bank_name = r5_core->tcm_banks[i]->bank_name; in add_tcm_carveout_lockstep_mode()
672 ret = -ENOMEM; in add_tcm_carveout_lockstep_mode()
688 for (i--; i >= 0; i--) { in add_tcm_carveout_lockstep_mode()
689 pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; in add_tcm_carveout_lockstep_mode()
701 * return 0 on success, otherwise non-zero value on failure
709 r5_core = rproc->priv; in add_tcm_banks()
711 return -EINVAL; in add_tcm_banks()
713 dev = r5_core->dev; in add_tcm_banks()
715 cluster = dev_get_drvdata(dev->parent); in add_tcm_banks()
717 dev_err(dev->parent, "Invalid driver data\n"); in add_tcm_banks()
718 return -EINVAL; in add_tcm_banks()
726 if (cluster->mode == SPLIT_MODE) in add_tcm_banks()
728 else if (cluster->mode == LOCKSTEP_MODE) in add_tcm_banks()
731 return -EINVAL; in add_tcm_banks()
741 * return 0 on success, otherwise non-zero value on failure
748 if (ret == -EINVAL) { in zynqmp_r5_parse_fw()
755 dev_info(&rproc->dev, "no resource table found.\n"); in zynqmp_r5_parse_fw()
775 dev_err(&rproc->dev, "failed to get TCM banks, err %d\n", ret); in zynqmp_r5_rproc_prepare()
781 dev_err(&rproc->dev, "failed to get reserve mem regions %d\n", ret); in zynqmp_r5_rproc_prepare()
790 * Turns off TCM banks using power-domain id
802 r5_core = rproc->priv; in zynqmp_r5_rproc_unprepare()
804 for (i = 0; i < r5_core->tcm_bank_count; i++) { in zynqmp_r5_rproc_unprepare()
805 pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; in zynqmp_r5_rproc_unprepare()
807 dev_warn(r5_core->dev, in zynqmp_r5_rproc_unprepare()
853 return ERR_PTR(-ENOMEM); in zynqmp_r5_add_rproc_core()
856 r5_rproc->auto_boot = false; in zynqmp_r5_add_rproc_core()
857 r5_core = r5_rproc->priv; in zynqmp_r5_add_rproc_core()
858 r5_core->dev = cdev; in zynqmp_r5_add_rproc_core()
859 r5_core->np = dev_of_node(cdev); in zynqmp_r5_add_rproc_core()
860 if (!r5_core->np) { in zynqmp_r5_add_rproc_core()
862 ret = -EINVAL; in zynqmp_r5_add_rproc_core()
873 r5_core->rproc = r5_rproc; in zynqmp_r5_add_rproc_core()
885 * This approach is used as TCM bindings for system-dt is being developed
894 struct device *dev = cluster->dev; in zynqmp_r5_get_tcm_node()
899 if (cluster->mode == SPLIT_MODE) { in zynqmp_r5_get_tcm_node()
908 tcm_bank_count = tcm_bank_count / cluster->core_count; in zynqmp_r5_get_tcm_node()
916 for (i = 0; i < cluster->core_count; i++) { in zynqmp_r5_get_tcm_node()
917 r5_core = cluster->r5_cores[i]; in zynqmp_r5_get_tcm_node()
918 r5_core->tcm_banks = devm_kcalloc(dev, tcm_bank_count, in zynqmp_r5_get_tcm_node()
921 if (!r5_core->tcm_banks) in zynqmp_r5_get_tcm_node()
922 return -ENOMEM; in zynqmp_r5_get_tcm_node()
926 * Use pre-defined TCM reg values. in zynqmp_r5_get_tcm_node()
930 r5_core->tcm_banks[j] = in zynqmp_r5_get_tcm_node()
935 r5_core->tcm_bank_count = tcm_bank_count; in zynqmp_r5_get_tcm_node()
955 struct device *dev = cluster->dev; in zynqmp_r5_core_init()
965 for (i = 0; i < cluster->core_count; i++) { in zynqmp_r5_core_init()
966 r5_core = cluster->r5_cores[i]; in zynqmp_r5_core_init()
968 /* Initialize r5 cores with power-domains parsed from dts */ in zynqmp_r5_core_init()
969 ret = of_property_read_u32_index(r5_core->np, "power-domains", in zynqmp_r5_core_init()
970 1, &r5_core->pm_domain_id); in zynqmp_r5_core_init()
972 dev_err(dev, "failed to get power-domains property\n"); in zynqmp_r5_core_init()
979 cluster->mode, ret); in zynqmp_r5_core_init()
998 struct device *dev = cluster->dev; in zynqmp_r5_cluster_init()
1009 ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode); in zynqmp_r5_cluster_init()
1012 * on success returns 0, if not defined then returns -EINVAL, in zynqmp_r5_cluster_init()
1016 if (ret != -EINVAL && ret != 0) { in zynqmp_r5_cluster_init()
1017 dev_err(dev, "Invalid xlnx,cluster-mode property\n"); in zynqmp_r5_cluster_init()
1033 return -EINVAL; in zynqmp_r5_cluster_init()
1047 return -EINVAL; in zynqmp_r5_cluster_init()
1050 return -EINVAL; in zynqmp_r5_cluster_init()
1058 return -ENOMEM; in zynqmp_r5_cluster_init()
1064 return -ENOMEM; in zynqmp_r5_cluster_init()
1072 ret = -ENODEV; in zynqmp_r5_cluster_init()
1076 child_devs[i] = &child_pdev->dev; in zynqmp_r5_cluster_init()
1079 r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); in zynqmp_r5_cluster_init()
1091 ipi = zynqmp_r5_setup_mbox(&child_pdev->dev); in zynqmp_r5_cluster_init()
1093 r5_cores[i]->ipi = ipi; in zynqmp_r5_cluster_init()
1094 ipi->r5_core = r5_cores[i]; in zynqmp_r5_cluster_init()
1109 cluster->mode = cluster_mode; in zynqmp_r5_cluster_init()
1110 cluster->core_count = core_count; in zynqmp_r5_cluster_init()
1111 cluster->r5_cores = r5_cores; in zynqmp_r5_cluster_init()
1116 cluster->core_count = 0; in zynqmp_r5_cluster_init()
1117 cluster->r5_cores = NULL; in zynqmp_r5_cluster_init()
1121 * adjust index to free resources in reverse order in zynqmp_r5_cluster_init()
1123 i = core_count - 1; in zynqmp_r5_cluster_init()
1134 zynqmp_r5_free_mbox(r5_cores[i]->ipi); in zynqmp_r5_cluster_init()
1135 of_reserved_mem_device_release(r5_cores[i]->dev); in zynqmp_r5_cluster_init()
1136 rproc_del(r5_cores[i]->rproc); in zynqmp_r5_cluster_init()
1137 rproc_free(r5_cores[i]->rproc); in zynqmp_r5_cluster_init()
1139 i--; in zynqmp_r5_cluster_init()
1157 for (i = 0; i < cluster->core_count; i++) { in zynqmp_r5_cluster_exit()
1158 r5_core = cluster->r5_cores[i]; in zynqmp_r5_cluster_exit()
1159 zynqmp_r5_free_mbox(r5_core->ipi); in zynqmp_r5_cluster_exit()
1160 of_reserved_mem_device_release(r5_core->dev); in zynqmp_r5_cluster_exit()
1161 put_device(r5_core->dev); in zynqmp_r5_cluster_exit()
1162 rproc_del(r5_core->rproc); in zynqmp_r5_cluster_exit()
1163 rproc_free(r5_core->rproc); in zynqmp_r5_cluster_exit()
1166 kfree(cluster->r5_cores); in zynqmp_r5_cluster_exit()
1173 * parse device-tree, initialize hardware and allocate required resources
1183 struct device *dev = &pdev->dev; in zynqmp_r5_remoteproc_probe()
1188 return -ENOMEM; in zynqmp_r5_remoteproc_probe()
1190 cluster->dev = dev; in zynqmp_r5_remoteproc_probe()
1219 { .compatible = "xlnx,zynqmp-r5fss", },