Lines Matching +full:pruss +full:- +full:intc
1 // SPDX-License-Identifier: GPL-2.0-only
3 * PRU-ICSS remoteproc driver for various TI SoCs
5 * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/
8 * Suman Anna <s-anna@ti.com>
37 /* CTRL register bit-fields */
67 * enum pru_iomem - PRU core memory/register range identifiers
82 * enum pru_type - PRU core type identifier
84 * @PRU_TYPE_PRU: Programmable Real-time Unit
85 * @PRU_TYPE_RTU: Auxiliary Programmable Real-Time Unit
86 * @PRU_TYPE_TX_PRU: Transmit Programmable Real-Time Unit
97 * struct pru_private_data - device data for a PRU core
107 * struct pru_rproc - PRU remoteproc structure
108 * @id: id of the PRU core within the PRUSS
110 * @pruss: back-reference to parent PRUSS structure
125 struct pruss *pruss; member
140 return readl_relaxed(pru->mem_regions[PRU_IOMEM_CTRL].va + reg); in pru_control_read_reg()
146 writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); in pru_control_write_reg()
151 return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg); in pru_debug_read_reg()
156 struct rproc *rproc = s->private; in regs_show()
157 struct pru_rproc *pru = rproc->priv; in regs_show()
191 seq_printf(s, "GPREG%-2d := 0x%08x\tCT_REG%-2d := 0x%08x\n", in regs_show()
201 * Control PRU single-step mode
203 * This is a debug helper function used for controlling the single-step
207 * Writing a non-zero value sets the PRU into single-step mode irrespective
209 * a single-step mode. Writing a zero value will restore the PRU into its
215 struct pru_rproc *pru = rproc->priv; in pru_rproc_debug_ss_set()
219 if (!val && !pru->dbg_single_step) in pru_rproc_debug_ss_set()
224 if (val && !pru->dbg_single_step) in pru_rproc_debug_ss_set()
225 pru->dbg_continuous = reg_val; in pru_rproc_debug_ss_set()
230 reg_val = pru->dbg_continuous; in pru_rproc_debug_ss_set()
232 pru->dbg_single_step = val; in pru_rproc_debug_ss_set()
241 struct pru_rproc *pru = rproc->priv; in pru_rproc_debug_ss_get()
243 *val = pru->dbg_single_step; in pru_rproc_debug_ss_get()
251 * Create PRU-specific debugfs entries
258 if (!rproc->dbg_dir) in pru_rproc_create_debug_entries()
261 debugfs_create_file("regs", 0400, rproc->dbg_dir, in pru_rproc_create_debug_entries()
263 debugfs_create_file("single_step", 0600, rproc->dbg_dir, in pru_rproc_create_debug_entries()
269 if (!pru->mapped_irq) in pru_dispose_irq_mapping()
272 while (pru->evt_count) { in pru_dispose_irq_mapping()
273 pru->evt_count--; in pru_dispose_irq_mapping()
274 if (pru->mapped_irq[pru->evt_count] > 0) in pru_dispose_irq_mapping()
275 irq_dispose_mapping(pru->mapped_irq[pru->evt_count]); in pru_dispose_irq_mapping()
278 kfree(pru->mapped_irq); in pru_dispose_irq_mapping()
279 pru->mapped_irq = NULL; in pru_dispose_irq_mapping()
283 * Parse the custom PRU interrupt map resource and configure the INTC
288 struct device *dev = rproc->dev.parent; in pru_handle_intrmap()
289 struct pru_rproc *pru = rproc->priv; in pru_handle_intrmap()
290 struct pru_irq_rsc *rsc = pru->pru_interrupt_map; in pru_handle_intrmap()
300 if (rsc->type != 0) { in pru_handle_intrmap()
301 dev_err(dev, "unsupported rsc type: %d\n", rsc->type); in pru_handle_intrmap()
302 return -EINVAL; in pru_handle_intrmap()
305 if (rsc->num_evts > MAX_PRU_SYS_EVENTS) in pru_handle_intrmap()
306 return -EINVAL; in pru_handle_intrmap()
308 if (sizeof(*rsc) + rsc->num_evts * sizeof(struct pruss_int_map) != in pru_handle_intrmap()
309 pru->pru_interrupt_map_sz) in pru_handle_intrmap()
310 return -EINVAL; in pru_handle_intrmap()
312 pru->evt_count = rsc->num_evts; in pru_handle_intrmap()
313 pru->mapped_irq = kcalloc(pru->evt_count, sizeof(unsigned int), in pru_handle_intrmap()
315 if (!pru->mapped_irq) { in pru_handle_intrmap()
316 pru->evt_count = 0; in pru_handle_intrmap()
317 return -ENOMEM; in pru_handle_intrmap()
322 * channel-to-host mapping. The interrupt controller to be used in pru_handle_intrmap()
324 * corresponding sibling PRUSS INTC node. in pru_handle_intrmap()
326 parent = of_get_parent(dev_of_node(pru->dev)); in pru_handle_intrmap()
328 kfree(pru->mapped_irq); in pru_handle_intrmap()
329 pru->mapped_irq = NULL; in pru_handle_intrmap()
330 pru->evt_count = 0; in pru_handle_intrmap()
331 return -ENODEV; in pru_handle_intrmap()
334 irq_parent = of_get_child_by_name(parent, "interrupt-controller"); in pru_handle_intrmap()
337 kfree(pru->mapped_irq); in pru_handle_intrmap()
338 pru->mapped_irq = NULL; in pru_handle_intrmap()
339 pru->evt_count = 0; in pru_handle_intrmap()
340 return -ENODEV; in pru_handle_intrmap()
345 for (i = 0; i < pru->evt_count; i++) { in pru_handle_intrmap()
346 fwspec.param[0] = rsc->pru_intc_map[i].event; in pru_handle_intrmap()
347 fwspec.param[1] = rsc->pru_intc_map[i].chnl; in pru_handle_intrmap()
348 fwspec.param[2] = rsc->pru_intc_map[i].host; in pru_handle_intrmap()
353 pru->mapped_irq[i] = irq_create_fwspec_mapping(&fwspec); in pru_handle_intrmap()
354 if (!pru->mapped_irq[i]) { in pru_handle_intrmap()
358 ret = -EINVAL; in pru_handle_intrmap()
375 struct device *dev = &rproc->dev; in pru_rproc_start()
376 struct pru_rproc *pru = rproc->priv; in pru_rproc_start()
381 dev_dbg(dev, "starting %s%d: entry-point = 0x%llx\n", in pru_rproc_start()
382 names[pru->data->type], pru->id, (rproc->bootaddr >> 2)); in pru_rproc_start()
386 * reset references to pru interrupt map - they will stop being valid in pru_rproc_start()
389 pru->pru_interrupt_map = NULL; in pru_rproc_start()
390 pru->pru_interrupt_map_sz = 0; in pru_rproc_start()
394 val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16); in pru_rproc_start()
402 struct device *dev = &rproc->dev; in pru_rproc_stop()
403 struct pru_rproc *pru = rproc->priv; in pru_rproc_stop()
407 dev_dbg(dev, "stopping %s%d\n", names[pru->data->type], pru->id); in pru_rproc_stop()
413 /* dispose irq mapping - new firmware can provide new mapping */ in pru_rproc_stop()
422 * Each PRU has access to all data memories within the PRUSS, accessible at
431 struct pruss *pruss = pru->pruss; in pru_d_da_to_va() local
438 dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0]; in pru_d_da_to_va()
439 dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1]; in pru_d_da_to_va()
441 if (pru->id == 1) in pru_d_da_to_va()
443 shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2]; in pru_d_da_to_va()
446 offset = da - PRU_PDRAM_DA; in pru_d_da_to_va()
450 offset = da - PRU_SDRAM_DA; in pru_d_da_to_va()
454 offset = da - PRU_SHRDRAM_DA; in pru_d_da_to_va()
484 * bits anyway. PRU architecture limits the program counter to 16-bit in pru_i_da_to_va()
485 * word-address range. This in turn corresponds to 18-bit IRAM in pru_i_da_to_va()
486 * byte-address range for ELF. in pru_i_da_to_va()
488 * Two more bits are added just in case to make the final 20-bit mask. in pru_i_da_to_va()
495 da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) { in pru_i_da_to_va()
496 offset = da - PRU_IRAM_DA; in pru_i_da_to_va()
497 va = (__force void *)(pru->mem_regions[PRU_IOMEM_IRAM].va + in pru_i_da_to_va()
511 struct pru_rproc *pru = rproc->priv; in pru_rproc_da_to_va()
516 /* PRU-specific address translator used by PRU loader. */
519 struct pru_rproc *pru = rproc->priv; in pru_da_to_va()
541 * properly in the IRAM memories only for integer (4-byte) copies. Any unaligned
542 * copies result in all the other pre-existing bytes zeroed out within that
543 * 4-byte boundary, thereby resulting in wrong text/code in the IRAMs. Also, the
544 * IRAM memory port interface does not allow any 8-byte copies (as commonly used
556 * TODO: relax limitation of 4-byte aligned dest addresses and copy in pru_rproc_memcpy()
560 return -EINVAL; in pru_rproc_memcpy()
562 /* src offsets in ELF firmware image can be non-aligned */ in pru_rproc_memcpy()
566 return -ENOMEM; in pru_rproc_memcpy()
570 while (size--) in pru_rproc_memcpy()
581 struct pru_rproc *pru = rproc->priv; in pru_rproc_load_elf_segments()
582 struct device *dev = &rproc->dev; in pru_rproc_load_elf_segments()
586 const u8 *elf_data = fw->data; in pru_rproc_load_elf_segments()
589 phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); in pru_rproc_load_elf_segments()
592 for (i = 0; i < ehdr->e_phnum; i++, phdr++) { in pru_rproc_load_elf_segments()
593 u32 da = phdr->p_paddr; in pru_rproc_load_elf_segments()
594 u32 memsz = phdr->p_memsz; in pru_rproc_load_elf_segments()
595 u32 filesz = phdr->p_filesz; in pru_rproc_load_elf_segments()
596 u32 offset = phdr->p_offset; in pru_rproc_load_elf_segments()
600 if (phdr->p_type != PT_LOAD || !filesz) in pru_rproc_load_elf_segments()
604 phdr->p_type, da, memsz, filesz); in pru_rproc_load_elf_segments()
609 ret = -EINVAL; in pru_rproc_load_elf_segments()
613 if (offset + filesz > fw->size) { in pru_rproc_load_elf_segments()
615 offset + filesz, fw->size); in pru_rproc_load_elf_segments()
616 ret = -EINVAL; in pru_rproc_load_elf_segments()
621 is_iram = phdr->p_flags & PF_X; in pru_rproc_load_elf_segments()
625 ret = -EINVAL; in pru_rproc_load_elf_segments()
629 if (pru->data->is_k3) { in pru_rproc_load_elf_segments()
630 ret = pru_rproc_memcpy(ptr, elf_data + phdr->p_offset, in pru_rproc_load_elf_segments()
638 memcpy(ptr, elf_data + phdr->p_offset, filesz); in pru_rproc_load_elf_segments()
652 const u8 *elf_data = fw->data; in pru_rproc_find_interrupt_map()
654 u16 shnum = ehdr->e_shnum; in pru_rproc_find_interrupt_map()
655 u16 shstrndx = ehdr->e_shstrndx; in pru_rproc_find_interrupt_map()
659 shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); in pru_rproc_find_interrupt_map()
663 name_table = elf_data + name_table_shdr->sh_offset; in pru_rproc_find_interrupt_map()
666 u32 size = shdr->sh_size; in pru_rproc_find_interrupt_map()
667 u32 offset = shdr->sh_offset; in pru_rproc_find_interrupt_map()
668 u32 name = shdr->sh_name; in pru_rproc_find_interrupt_map()
674 if (offset + size > fw->size || offset + size < size) { in pru_rproc_find_interrupt_map()
676 return ERR_PTR(-EINVAL); in pru_rproc_find_interrupt_map()
681 dev_err(dev, "header-less .pru_irq_map section\n"); in pru_rproc_find_interrupt_map()
682 return ERR_PTR(-EINVAL); in pru_rproc_find_interrupt_map()
698 * and .pru_irq_map one. The second one contains the PRUSS interrupt mapping
705 struct device *dev = &rproc->dev; in pru_rproc_parse_fw()
706 struct pru_rproc *pru = rproc->priv; in pru_rproc_parse_fw()
707 const u8 *elf_data = fw->data; in pru_rproc_parse_fw()
715 if (ret == -EINVAL) in pru_rproc_parse_fw()
716 dev_dbg(&rproc->dev, "no resource table found for this fw\n"); in pru_rproc_parse_fw()
730 pru->pru_interrupt_map = (struct pru_irq_rsc *)(elf_data + sh_offset); in pru_rproc_parse_fw()
731 pru->pru_interrupt_map_sz = elf_shdr_get_sh_size(class, shdr); in pru_rproc_parse_fw()
738 * always at a particular offset within the PRUSS address space.
744 switch (pru->mem_regions[PRU_IOMEM_IRAM].pa & PRU_IRAM_ADDR_MASK) { in pru_rproc_set_id()
750 pru->id = 0; in pru_rproc_set_id()
757 pru->id = 1; in pru_rproc_set_id()
760 ret = -EINVAL; in pru_rproc_set_id()
768 struct device *dev = &pdev->dev; in pru_rproc_probe()
769 struct device_node *np = dev->of_node; in pru_rproc_probe()
770 struct platform_device *ppdev = to_platform_device(dev->parent); in pru_rproc_probe()
779 data = of_device_get_match_data(&pdev->dev); in pru_rproc_probe()
781 return -ENODEV; in pru_rproc_probe()
783 ret = of_property_read_string(np, "firmware-name", &fw_name); in pru_rproc_probe()
785 dev_err(dev, "unable to retrieve firmware-name %d\n", ret); in pru_rproc_probe()
789 rproc = devm_rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name, in pru_rproc_probe()
793 return -ENOMEM; in pru_rproc_probe()
795 /* use a custom load function to deal with PRU-specific quirks */ in pru_rproc_probe()
796 rproc->ops->load = pru_rproc_load_elf_segments; in pru_rproc_probe()
798 /* use a custom parse function to deal with PRU-specific resources */ in pru_rproc_probe()
799 rproc->ops->parse_fw = pru_rproc_parse_fw; in pru_rproc_probe()
802 rproc->recovery_disabled = true; in pru_rproc_probe()
805 * rproc_add will auto-boot the processor normally, but this is not in pru_rproc_probe()
806 * desired with PRU client driven boot-flow methodology. A PRU in pru_rproc_probe()
808 * remote-processor as part of its state machine either through the in pru_rproc_probe()
811 rproc->auto_boot = false; in pru_rproc_probe()
813 pru = rproc->priv; in pru_rproc_probe()
814 pru->dev = dev; in pru_rproc_probe()
815 pru->data = data; in pru_rproc_probe()
816 pru->pruss = platform_get_drvdata(ppdev); in pru_rproc_probe()
817 pru->rproc = rproc; in pru_rproc_probe()
818 pru->fw_name = fw_name; in pru_rproc_probe()
823 pru->mem_regions[i].va = devm_ioremap_resource(dev, res); in pru_rproc_probe()
824 if (IS_ERR(pru->mem_regions[i].va)) { in pru_rproc_probe()
827 ret = PTR_ERR(pru->mem_regions[i].va); in pru_rproc_probe()
830 pru->mem_regions[i].pa = res->start; in pru_rproc_probe()
831 pru->mem_regions[i].size = resource_size(res); in pru_rproc_probe()
834 mem_names[i], &pru->mem_regions[i].pa, in pru_rproc_probe()
835 pru->mem_regions[i].size, pru->mem_regions[i].va); in pru_rproc_probe()
844 ret = devm_rproc_add(dev, pru->rproc); in pru_rproc_probe()
859 struct device *dev = &pdev->dev; in pru_rproc_remove()
862 dev_dbg(dev, "%s: removing rproc %s\n", __func__, rproc->name); in pru_rproc_remove()
887 { .compatible = "ti,am3356-pru", .data = &pru_data },
888 { .compatible = "ti,am4376-pru", .data = &pru_data },
889 { .compatible = "ti,am5728-pru", .data = &pru_data },
890 { .compatible = "ti,am642-pru", .data = &k3_pru_data },
891 { .compatible = "ti,am642-rtu", .data = &k3_rtu_data },
892 { .compatible = "ti,am642-tx-pru", .data = &k3_tx_pru_data },
893 { .compatible = "ti,k2g-pru", .data = &pru_data },
894 { .compatible = "ti,am654-pru", .data = &k3_pru_data },
895 { .compatible = "ti,am654-rtu", .data = &k3_rtu_data },
896 { .compatible = "ti,am654-tx-pru", .data = &k3_tx_pru_data },
897 { .compatible = "ti,j721e-pru", .data = &k3_pru_data },
898 { .compatible = "ti,j721e-rtu", .data = &k3_rtu_data },
899 { .compatible = "ti,j721e-tx-pru", .data = &k3_tx_pru_data },
900 { .compatible = "ti,am625-pru", .data = &k3_pru_data },
907 .name = "pru-rproc",
916 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
919 MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver");