Lines Matching +full:am4376 +full:- +full:pru

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 */
49 /* PRU/RTU/Tx_PRU Core IRAM address masks */
58 /* PRU device addresses for various type of PRU RAMs */
67 * enum pru_iomem - PRU core memory/register range identifiers
69 * @PRU_IOMEM_IRAM: PRU Instruction RAM range
70 * @PRU_IOMEM_CTRL: PRU Control register range
71 * @PRU_IOMEM_DEBUG: PRU Debug register range
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
98 * @type: type of the PRU core (PRU, RTU, Tx_PRU)
107 * struct pru_rproc - PRU remoteproc structure
108 * @id: id of the PRU core within the PRUSS
109 * @dev: PRU core device pointer
110 * @pruss: back-reference to parent PRUSS structure
111 * @rproc: remoteproc pointer for this PRU core
112 * @data: PRU core specific data
113 * @mem_regions: data for each of the PRU memory regions
118 * @dbg_single_step: debug state variable to set PRU into single step mode
119 * @dbg_continuous: debug state variable to restore PRU execution mode
138 static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg) in pru_control_read_reg() argument
140 return readl_relaxed(pru->mem_regions[PRU_IOMEM_CTRL].va + reg); in pru_control_read_reg()
144 void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) in pru_control_write_reg() argument
146 writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); in pru_control_write_reg()
149 static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg) in pru_debug_read_reg() argument
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() local
164 pru_control_read_reg(pru, PRU_CTRL_CTRL)); in regs_show()
165 pru_sts = pru_control_read_reg(pru, PRU_CTRL_STS); in regs_show()
168 pru_control_read_reg(pru, PRU_CTRL_WAKEUP_EN)); in regs_show()
170 pru_control_read_reg(pru, PRU_CTRL_CYCLE)); in regs_show()
172 pru_control_read_reg(pru, PRU_CTRL_STALL)); in regs_show()
174 pru_control_read_reg(pru, PRU_CTRL_CTBIR0)); in regs_show()
176 pru_control_read_reg(pru, PRU_CTRL_CTBIR1)); in regs_show()
178 pru_control_read_reg(pru, PRU_CTRL_CTPPR0)); in regs_show()
180 pru_control_read_reg(pru, PRU_CTRL_CTPPR1)); in regs_show()
183 pru_is_running = pru_control_read_reg(pru, PRU_CTRL_CTRL) & in regs_show()
186 seq_puts(s, "PRU is executing, cannot print/access debug registers.\n"); in regs_show()
191 seq_printf(s, "GPREG%-2d := 0x%08x\tCT_REG%-2d := 0x%08x\n", in regs_show()
192 i, pru_debug_read_reg(pru, PRU_DEBUG_GPREG(i)), in regs_show()
193 i, pru_debug_read_reg(pru, PRU_DEBUG_CT_REG(i))); in regs_show()
201 * Control PRU single-step mode
203 * This is a debug helper function used for controlling the single-step
204 * mode of the PRU. The PRU Debug registers are not accessible when the
205 * PRU is in RUNNING state.
207 * Writing a non-zero value sets the PRU into single-step mode irrespective
208 * of its previous state. The PRU mode is saved only on the first set into
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() local
219 if (!val && !pru->dbg_single_step) in pru_rproc_debug_ss_set()
222 reg_val = pru_control_read_reg(pru, PRU_CTRL_CTRL); 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()
233 pru_control_write_reg(pru, PRU_CTRL_CTRL, reg_val); in pru_rproc_debug_ss_set()
241 struct pru_rproc *pru = rproc->priv; in pru_rproc_debug_ss_get() local
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()
267 static void pru_dispose_irq_mapping(struct pru_rproc *pru) in pru_dispose_irq_mapping() argument
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() local
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()
323 * for these mappings for a given PRU remoteproc is always its 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()
367 pru_dispose_irq_mapping(pru); 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() local
377 const char *names[PRU_TYPE_MAX] = { "PRU", "RTU", "Tx_PRU" }; 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()
395 pru_control_write_reg(pru, PRU_CTRL_CTRL, val); 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() local
404 const char *names[PRU_TYPE_MAX] = { "PRU", "RTU", "Tx_PRU" }; in pru_rproc_stop()
407 dev_dbg(dev, "stopping %s%d\n", names[pru->data->type], pru->id); in pru_rproc_stop()
409 val = pru_control_read_reg(pru, PRU_CTRL_CTRL); in pru_rproc_stop()
411 pru_control_write_reg(pru, PRU_CTRL_CTRL, val); in pru_rproc_stop()
413 /* dispose irq mapping - new firmware can provide new mapping */ in pru_rproc_stop()
414 pru_dispose_irq_mapping(pru); in pru_rproc_stop()
420 * Convert PRU device address (data spaces only) to kernel virtual address.
422 * Each PRU has access to all data memories within the PRUSS, accessible at
424 * RAMs as well as any shared Data RAM to convert a PRU device address to
428 static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len) in pru_d_da_to_va() argument
431 struct pruss *pruss = pru->pruss; in pru_d_da_to_va()
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()
462 * Convert PRU device address (instruction space) to kernel virtual address.
464 * A PRU does not have an unified address space. Each PRU has its very own
468 static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len) in pru_i_da_to_va() argument
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()
505 * Provide address translations for only PRU Data RAMs through the remoteproc
506 * core for any PRU client drivers. The PRU Instruction RAM access is restricted
507 * only to the PRU loader code.
511 struct pru_rproc *pru = rproc->priv; in pru_rproc_da_to_va() local
513 return pru_d_da_to_va(pru, da, len); 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() local
523 va = pru_i_da_to_va(pru, da, len); in pru_da_to_va()
525 va = pru_d_da_to_va(pru, da, len); in pru_da_to_va()
537 * Custom memory copy implementation for ICSSG PRU/RTU/Tx_PRU Cores
539 * The ICSSG PRU/RTU/Tx_PRU cores have a memory copying issue with IRAM
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() local
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()
633 dev_err(dev, "PRU memory copy failed for da 0x%x memsz 0x%x\n", 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()
694 * Use a custom parse_fw callback function for dealing with PRU firmware
699 * description, which needs to be setup before powering on the PRU core. To
701 * firmware linker) and therefore is not loaded to PRU memory.
705 struct device *dev = &rproc->dev; in pru_rproc_parse_fw()
706 struct pru_rproc *pru = rproc->priv; in pru_rproc_parse_fw() local
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()
728 /* preserve pointer to PRU interrupt map together with it size */ 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()
737 * Compute PRU id based on the IRAM addresses. The PRU IRAMs are
740 static int pru_rproc_set_id(struct pru_rproc *pru) in pru_rproc_set_id() argument
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()
771 struct pru_rproc *pru; in pru_rproc_probe() local
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()
790 sizeof(*pru)); 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()
807 * application/client driver will boot the corresponding 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()
838 ret = pru_rproc_set_id(pru); in pru_rproc_probe()
844 ret = devm_rproc_add(dev, pru->rproc); in pru_rproc_probe()
852 dev_dbg(dev, "PRU rproc node %pOF probed successfully\n", np); 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");