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>
9 * Andrew F. Davis <afd@ti.com>
10 * Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments
13 #include <linux/bitops.h>
14 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/pruss_driver.h>
17 #include <linux/remoteproc.h>
19 #include "remoteproc_internal.h"
20 #include "remoteproc_elf_helpers.h"
22 /* PRU_ICSS_PRU_CTRL registers */
23 #define PRU_CTRL_CTRL 0x0000
24 #define PRU_CTRL_STS 0x0004
26 /* CTRL register bit-fields */
27 #define CTRL_CTRL_SOFT_RST_N BIT(0)
28 #define CTRL_CTRL_EN BIT(1)
29 #define CTRL_CTRL_SLEEPING BIT(2)
30 #define CTRL_CTRL_CTR_EN BIT(3)
31 #define CTRL_CTRL_SINGLE_STEP BIT(8)
32 #define CTRL_CTRL_RUNSTATE BIT(15)
34 /* PRU Core IRAM address masks */
35 #define PRU_IRAM_ADDR_MASK 0x3ffff
36 #define PRU0_IRAM_ADDR_MASK 0x34000
37 #define PRU1_IRAM_ADDR_MASK 0x38000
39 /* PRU device addresses for various type of PRU RAMs */
40 #define PRU_IRAM_DA 0 /* Instruction RAM */
41 #define PRU_PDRAM_DA 0 /* Primary Data RAM */
42 #define PRU_SDRAM_DA 0x2000 /* Secondary Data RAM */
43 #define PRU_SHRDRAM_DA 0x10000 /* Shared Data RAM */
46 * enum pru_iomem - PRU core memory/register range identifiers
48 * @PRU_IOMEM_IRAM: PRU Instruction RAM range
49 * @PRU_IOMEM_CTRL: PRU Control register range
50 * @PRU_IOMEM_DEBUG: PRU Debug register range
51 * @PRU_IOMEM_MAX: just keep this one at the end
61 * struct pru_rproc - PRU remoteproc structure
62 * @id: id of the PRU core within the PRUSS
63 * @dev: PRU core device pointer
64 * @pruss: back-reference to parent PRUSS structure
65 * @rproc: remoteproc pointer for this PRU core
66 * @mem_regions: data for each of the PRU memory regions
67 * @fw_name: name of firmware image used during loading
74 struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
78 static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg)
80 return readl_relaxed(pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
84 void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val)
86 writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
89 static int pru_rproc_start(struct rproc *rproc)
91 struct device *dev = &rproc->dev;
92 struct pru_rproc *pru = rproc->priv;
95 dev_dbg(dev, "starting PRU%d: entry-point = 0x%llx\n",
96 pru->id, (rproc->bootaddr >> 2));
98 val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16);
99 pru_control_write_reg(pru, PRU_CTRL_CTRL, val);
104 static int pru_rproc_stop(struct rproc *rproc)
106 struct device *dev = &rproc->dev;
107 struct pru_rproc *pru = rproc->priv;
110 dev_dbg(dev, "stopping PRU%d\n", pru->id);
112 val = pru_control_read_reg(pru, PRU_CTRL_CTRL);
113 val &= ~CTRL_CTRL_EN;
114 pru_control_write_reg(pru, PRU_CTRL_CTRL, val);
120 * Convert PRU device address (data spaces only) to kernel virtual address.
122 * Each PRU has access to all data memories within the PRUSS, accessible at
123 * different ranges. So, look through both its primary and secondary Data
124 * RAMs as well as any shared Data RAM to convert a PRU device address to
125 * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data
126 * RAM1 is primary Data RAM for PRU1.
128 static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
130 struct pruss_mem_region dram0, dram1, shrd_ram;
131 struct pruss *pruss = pru->pruss;
138 dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0];
139 dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1];
140 /* PRU1 has its local RAM addresses reversed */
143 shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2];
145 if (da >= PRU_PDRAM_DA && da + len <= PRU_PDRAM_DA + dram0.size) {
146 offset = da - PRU_PDRAM_DA;
147 va = (__force void *)(dram0.va + offset);
148 } else if (da >= PRU_SDRAM_DA &&
149 da + len <= PRU_SDRAM_DA + dram1.size) {
150 offset = da - PRU_SDRAM_DA;
151 va = (__force void *)(dram1.va + offset);
152 } else if (da >= PRU_SHRDRAM_DA &&
153 da + len <= PRU_SHRDRAM_DA + shrd_ram.size) {
154 offset = da - PRU_SHRDRAM_DA;
155 va = (__force void *)(shrd_ram.va + offset);
162 * Convert PRU device address (instruction space) to kernel virtual address.
164 * A PRU does not have an unified address space. Each PRU has its very own
165 * private Instruction RAM, and its device address is identical to that of
166 * its primary Data RAM device address.
168 static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
176 if (da >= PRU_IRAM_DA &&
177 da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) {
178 offset = da - PRU_IRAM_DA;
179 va = (__force void *)(pru->mem_regions[PRU_IOMEM_IRAM].va +
187 * Provide address translations for only PRU Data RAMs through the remoteproc
188 * core for any PRU client drivers. The PRU Instruction RAM access is restricted
189 * only to the PRU loader code.
191 static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
193 struct pru_rproc *pru = rproc->priv;
195 return pru_d_da_to_va(pru, da, len);
198 /* PRU-specific address translator used by PRU loader. */
199 static void *pru_da_to_va(struct rproc *rproc, u64 da, size_t len, bool is_iram)
201 struct pru_rproc *pru = rproc->priv;
205 va = pru_i_da_to_va(pru, da, len);
207 va = pru_d_da_to_va(pru, da, len);
212 static struct rproc_ops pru_rproc_ops = {
213 .start = pru_rproc_start,
214 .stop = pru_rproc_stop,
215 .da_to_va = pru_rproc_da_to_va,
219 pru_rproc_load_elf_segments(struct rproc *rproc, const struct firmware *fw)
221 struct device *dev = &rproc->dev;
222 struct elf32_hdr *ehdr;
223 struct elf32_phdr *phdr;
225 const u8 *elf_data = fw->data;
227 ehdr = (struct elf32_hdr *)elf_data;
228 phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
230 /* go through the available ELF segments */
231 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
232 u32 da = phdr->p_paddr;
233 u32 memsz = phdr->p_memsz;
234 u32 filesz = phdr->p_filesz;
235 u32 offset = phdr->p_offset;
239 if (phdr->p_type != PT_LOAD || !filesz)
242 dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
243 phdr->p_type, da, memsz, filesz);
245 if (filesz > memsz) {
246 dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
252 if (offset + filesz > fw->size) {
253 dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
254 offset + filesz, fw->size);
259 /* grab the kernel address for this device address */
260 is_iram = phdr->p_flags & PF_X;
261 ptr = pru_da_to_va(rproc, da, memsz, is_iram);
263 dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
268 memcpy(ptr, elf_data + phdr->p_offset, filesz);
270 /* skip the memzero logic performed by remoteproc ELF loader */
277 * Use a custom parse_fw callback function for dealing with PRU firmware
280 static int pru_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
284 /* load optional rsc table */
285 ret = rproc_elf_load_rsc_table(rproc, fw);
287 dev_dbg(&rproc->dev, "no resource table found for this fw\n");
295 * Compute PRU id based on the IRAM addresses. The PRU IRAMs are
296 * always at a particular offset within the PRUSS address space.
298 static int pru_rproc_set_id(struct pru_rproc *pru)
302 switch (pru->mem_regions[PRU_IOMEM_IRAM].pa & PRU_IRAM_ADDR_MASK) {
303 case PRU0_IRAM_ADDR_MASK:
306 case PRU1_IRAM_ADDR_MASK:
316 static int pru_rproc_probe(struct platform_device *pdev)
318 struct device *dev = &pdev->dev;
319 struct device_node *np = dev->of_node;
320 struct platform_device *ppdev = to_platform_device(dev->parent);
321 struct pru_rproc *pru;
323 struct rproc *rproc = NULL;
324 struct resource *res;
326 const char *mem_names[PRU_IOMEM_MAX] = { "iram", "control", "debug" };
328 ret = of_property_read_string(np, "firmware-name", &fw_name);
330 dev_err(dev, "unable to retrieve firmware-name %d\n", ret);
334 rproc = devm_rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name,
337 dev_err(dev, "rproc_alloc failed\n");
340 /* use a custom load function to deal with PRU-specific quirks */
341 rproc->ops->load = pru_rproc_load_elf_segments;
343 /* use a custom parse function to deal with PRU-specific resources */
344 rproc->ops->parse_fw = pru_rproc_parse_fw;
346 /* error recovery is not supported for PRUs */
347 rproc->recovery_disabled = true;
350 * rproc_add will auto-boot the processor normally, but this is not
351 * desired with PRU client driven boot-flow methodology. A PRU
352 * application/client driver will boot the corresponding PRU
353 * remote-processor as part of its state machine either through the
354 * remoteproc sysfs interface or through the equivalent kernel API.
356 rproc->auto_boot = false;
360 pru->pruss = platform_get_drvdata(ppdev);
362 pru->fw_name = fw_name;
364 for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
365 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
367 pru->mem_regions[i].va = devm_ioremap_resource(dev, res);
368 if (IS_ERR(pru->mem_regions[i].va)) {
369 dev_err(dev, "failed to parse and map memory resource %d %s\n",
371 ret = PTR_ERR(pru->mem_regions[i].va);
374 pru->mem_regions[i].pa = res->start;
375 pru->mem_regions[i].size = resource_size(res);
377 dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
378 mem_names[i], &pru->mem_regions[i].pa,
379 pru->mem_regions[i].size, pru->mem_regions[i].va);
382 ret = pru_rproc_set_id(pru);
386 platform_set_drvdata(pdev, rproc);
388 ret = devm_rproc_add(dev, pru->rproc);
390 dev_err(dev, "rproc_add failed: %d\n", ret);
394 dev_dbg(dev, "PRU rproc node %pOF probed successfully\n", np);
399 static int pru_rproc_remove(struct platform_device *pdev)
401 struct device *dev = &pdev->dev;
402 struct rproc *rproc = platform_get_drvdata(pdev);
404 dev_dbg(dev, "%s: removing rproc %s\n", __func__, rproc->name);
409 static const struct of_device_id pru_rproc_match[] = {
410 { .compatible = "ti,am3356-pru", },
411 { .compatible = "ti,am4376-pru", },
412 { .compatible = "ti,am5728-pru", },
413 { .compatible = "ti,k2g-pru", },
416 MODULE_DEVICE_TABLE(of, pru_rproc_match);
418 static struct platform_driver pru_rproc_driver = {
421 .of_match_table = pru_rproc_match,
422 .suppress_bind_attrs = true,
424 .probe = pru_rproc_probe,
425 .remove = pru_rproc_remove,
427 module_platform_driver(pru_rproc_driver);
429 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
430 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
431 MODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>");
432 MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver");
433 MODULE_LICENSE("GPL v2");