Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * PRU-ICSS remoteproc driver for various TI SoCs
0004  *
0005  * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/
0006  *
0007  * Author(s):
0008  *  Suman Anna <s-anna@ti.com>
0009  *  Andrew F. Davis <afd@ti.com>
0010  *  Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments
0011  */
0012 
0013 #include <linux/bitops.h>
0014 #include <linux/debugfs.h>
0015 #include <linux/irqdomain.h>
0016 #include <linux/module.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/pruss_driver.h>
0020 #include <linux/remoteproc.h>
0021 
0022 #include "remoteproc_internal.h"
0023 #include "remoteproc_elf_helpers.h"
0024 #include "pru_rproc.h"
0025 
0026 /* PRU_ICSS_PRU_CTRL registers */
0027 #define PRU_CTRL_CTRL       0x0000
0028 #define PRU_CTRL_STS        0x0004
0029 #define PRU_CTRL_WAKEUP_EN  0x0008
0030 #define PRU_CTRL_CYCLE      0x000C
0031 #define PRU_CTRL_STALL      0x0010
0032 #define PRU_CTRL_CTBIR0     0x0020
0033 #define PRU_CTRL_CTBIR1     0x0024
0034 #define PRU_CTRL_CTPPR0     0x0028
0035 #define PRU_CTRL_CTPPR1     0x002C
0036 
0037 /* CTRL register bit-fields */
0038 #define CTRL_CTRL_SOFT_RST_N    BIT(0)
0039 #define CTRL_CTRL_EN        BIT(1)
0040 #define CTRL_CTRL_SLEEPING  BIT(2)
0041 #define CTRL_CTRL_CTR_EN    BIT(3)
0042 #define CTRL_CTRL_SINGLE_STEP   BIT(8)
0043 #define CTRL_CTRL_RUNSTATE  BIT(15)
0044 
0045 /* PRU_ICSS_PRU_DEBUG registers */
0046 #define PRU_DEBUG_GPREG(x)  (0x0000 + (x) * 4)
0047 #define PRU_DEBUG_CT_REG(x) (0x0080 + (x) * 4)
0048 
0049 /* PRU/RTU/Tx_PRU Core IRAM address masks */
0050 #define PRU_IRAM_ADDR_MASK  0x3ffff
0051 #define PRU0_IRAM_ADDR_MASK 0x34000
0052 #define PRU1_IRAM_ADDR_MASK 0x38000
0053 #define RTU0_IRAM_ADDR_MASK 0x4000
0054 #define RTU1_IRAM_ADDR_MASK 0x6000
0055 #define TX_PRU0_IRAM_ADDR_MASK  0xa000
0056 #define TX_PRU1_IRAM_ADDR_MASK  0xc000
0057 
0058 /* PRU device addresses for various type of PRU RAMs */
0059 #define PRU_IRAM_DA 0   /* Instruction RAM */
0060 #define PRU_PDRAM_DA    0   /* Primary Data RAM */
0061 #define PRU_SDRAM_DA    0x2000  /* Secondary Data RAM */
0062 #define PRU_SHRDRAM_DA  0x10000 /* Shared Data RAM */
0063 
0064 #define MAX_PRU_SYS_EVENTS 160
0065 
0066 /**
0067  * enum pru_iomem - PRU core memory/register range identifiers
0068  *
0069  * @PRU_IOMEM_IRAM: PRU Instruction RAM range
0070  * @PRU_IOMEM_CTRL: PRU Control register range
0071  * @PRU_IOMEM_DEBUG: PRU Debug register range
0072  * @PRU_IOMEM_MAX: just keep this one at the end
0073  */
0074 enum pru_iomem {
0075     PRU_IOMEM_IRAM = 0,
0076     PRU_IOMEM_CTRL,
0077     PRU_IOMEM_DEBUG,
0078     PRU_IOMEM_MAX,
0079 };
0080 
0081 /**
0082  * enum pru_type - PRU core type identifier
0083  *
0084  * @PRU_TYPE_PRU: Programmable Real-time Unit
0085  * @PRU_TYPE_RTU: Auxiliary Programmable Real-Time Unit
0086  * @PRU_TYPE_TX_PRU: Transmit Programmable Real-Time Unit
0087  * @PRU_TYPE_MAX: just keep this one at the end
0088  */
0089 enum pru_type {
0090     PRU_TYPE_PRU = 0,
0091     PRU_TYPE_RTU,
0092     PRU_TYPE_TX_PRU,
0093     PRU_TYPE_MAX,
0094 };
0095 
0096 /**
0097  * struct pru_private_data - device data for a PRU core
0098  * @type: type of the PRU core (PRU, RTU, Tx_PRU)
0099  * @is_k3: flag used to identify the need for special load handling
0100  */
0101 struct pru_private_data {
0102     enum pru_type type;
0103     unsigned int is_k3 : 1;
0104 };
0105 
0106 /**
0107  * struct pru_rproc - PRU remoteproc structure
0108  * @id: id of the PRU core within the PRUSS
0109  * @dev: PRU core device pointer
0110  * @pruss: back-reference to parent PRUSS structure
0111  * @rproc: remoteproc pointer for this PRU core
0112  * @data: PRU core specific data
0113  * @mem_regions: data for each of the PRU memory regions
0114  * @fw_name: name of firmware image used during loading
0115  * @mapped_irq: virtual interrupt numbers of created fw specific mapping
0116  * @pru_interrupt_map: pointer to interrupt mapping description (firmware)
0117  * @pru_interrupt_map_sz: pru_interrupt_map size
0118  * @dbg_single_step: debug state variable to set PRU into single step mode
0119  * @dbg_continuous: debug state variable to restore PRU execution mode
0120  * @evt_count: number of mapped events
0121  */
0122 struct pru_rproc {
0123     int id;
0124     struct device *dev;
0125     struct pruss *pruss;
0126     struct rproc *rproc;
0127     const struct pru_private_data *data;
0128     struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
0129     const char *fw_name;
0130     unsigned int *mapped_irq;
0131     struct pru_irq_rsc *pru_interrupt_map;
0132     size_t pru_interrupt_map_sz;
0133     u32 dbg_single_step;
0134     u32 dbg_continuous;
0135     u8 evt_count;
0136 };
0137 
0138 static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg)
0139 {
0140     return readl_relaxed(pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
0141 }
0142 
0143 static inline
0144 void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val)
0145 {
0146     writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
0147 }
0148 
0149 static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg)
0150 {
0151     return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg);
0152 }
0153 
0154 static int regs_show(struct seq_file *s, void *data)
0155 {
0156     struct rproc *rproc = s->private;
0157     struct pru_rproc *pru = rproc->priv;
0158     int i, nregs = 32;
0159     u32 pru_sts;
0160     int pru_is_running;
0161 
0162     seq_puts(s, "============== Control Registers ==============\n");
0163     seq_printf(s, "CTRL      := 0x%08x\n",
0164            pru_control_read_reg(pru, PRU_CTRL_CTRL));
0165     pru_sts = pru_control_read_reg(pru, PRU_CTRL_STS);
0166     seq_printf(s, "STS (PC)  := 0x%08x (0x%08x)\n", pru_sts, pru_sts << 2);
0167     seq_printf(s, "WAKEUP_EN := 0x%08x\n",
0168            pru_control_read_reg(pru, PRU_CTRL_WAKEUP_EN));
0169     seq_printf(s, "CYCLE     := 0x%08x\n",
0170            pru_control_read_reg(pru, PRU_CTRL_CYCLE));
0171     seq_printf(s, "STALL     := 0x%08x\n",
0172            pru_control_read_reg(pru, PRU_CTRL_STALL));
0173     seq_printf(s, "CTBIR0    := 0x%08x\n",
0174            pru_control_read_reg(pru, PRU_CTRL_CTBIR0));
0175     seq_printf(s, "CTBIR1    := 0x%08x\n",
0176            pru_control_read_reg(pru, PRU_CTRL_CTBIR1));
0177     seq_printf(s, "CTPPR0    := 0x%08x\n",
0178            pru_control_read_reg(pru, PRU_CTRL_CTPPR0));
0179     seq_printf(s, "CTPPR1    := 0x%08x\n",
0180            pru_control_read_reg(pru, PRU_CTRL_CTPPR1));
0181 
0182     seq_puts(s, "=============== Debug Registers ===============\n");
0183     pru_is_running = pru_control_read_reg(pru, PRU_CTRL_CTRL) &
0184                 CTRL_CTRL_RUNSTATE;
0185     if (pru_is_running) {
0186         seq_puts(s, "PRU is executing, cannot print/access debug registers.\n");
0187         return 0;
0188     }
0189 
0190     for (i = 0; i < nregs; i++) {
0191         seq_printf(s, "GPREG%-2d := 0x%08x\tCT_REG%-2d := 0x%08x\n",
0192                i, pru_debug_read_reg(pru, PRU_DEBUG_GPREG(i)),
0193                i, pru_debug_read_reg(pru, PRU_DEBUG_CT_REG(i)));
0194     }
0195 
0196     return 0;
0197 }
0198 DEFINE_SHOW_ATTRIBUTE(regs);
0199 
0200 /*
0201  * Control PRU single-step mode
0202  *
0203  * This is a debug helper function used for controlling the single-step
0204  * mode of the PRU. The PRU Debug registers are not accessible when the
0205  * PRU is in RUNNING state.
0206  *
0207  * Writing a non-zero value sets the PRU into single-step mode irrespective
0208  * of its previous state. The PRU mode is saved only on the first set into
0209  * a single-step mode. Writing a zero value will restore the PRU into its
0210  * original mode.
0211  */
0212 static int pru_rproc_debug_ss_set(void *data, u64 val)
0213 {
0214     struct rproc *rproc = data;
0215     struct pru_rproc *pru = rproc->priv;
0216     u32 reg_val;
0217 
0218     val = val ? 1 : 0;
0219     if (!val && !pru->dbg_single_step)
0220         return 0;
0221 
0222     reg_val = pru_control_read_reg(pru, PRU_CTRL_CTRL);
0223 
0224     if (val && !pru->dbg_single_step)
0225         pru->dbg_continuous = reg_val;
0226 
0227     if (val)
0228         reg_val |= CTRL_CTRL_SINGLE_STEP | CTRL_CTRL_EN;
0229     else
0230         reg_val = pru->dbg_continuous;
0231 
0232     pru->dbg_single_step = val;
0233     pru_control_write_reg(pru, PRU_CTRL_CTRL, reg_val);
0234 
0235     return 0;
0236 }
0237 
0238 static int pru_rproc_debug_ss_get(void *data, u64 *val)
0239 {
0240     struct rproc *rproc = data;
0241     struct pru_rproc *pru = rproc->priv;
0242 
0243     *val = pru->dbg_single_step;
0244 
0245     return 0;
0246 }
0247 DEFINE_DEBUGFS_ATTRIBUTE(pru_rproc_debug_ss_fops, pru_rproc_debug_ss_get,
0248              pru_rproc_debug_ss_set, "%llu\n");
0249 
0250 /*
0251  * Create PRU-specific debugfs entries
0252  *
0253  * The entries are created only if the parent remoteproc debugfs directory
0254  * exists, and will be cleaned up by the remoteproc core.
0255  */
0256 static void pru_rproc_create_debug_entries(struct rproc *rproc)
0257 {
0258     if (!rproc->dbg_dir)
0259         return;
0260 
0261     debugfs_create_file("regs", 0400, rproc->dbg_dir,
0262                 rproc, &regs_fops);
0263     debugfs_create_file("single_step", 0600, rproc->dbg_dir,
0264                 rproc, &pru_rproc_debug_ss_fops);
0265 }
0266 
0267 static void pru_dispose_irq_mapping(struct pru_rproc *pru)
0268 {
0269     if (!pru->mapped_irq)
0270         return;
0271 
0272     while (pru->evt_count) {
0273         pru->evt_count--;
0274         if (pru->mapped_irq[pru->evt_count] > 0)
0275             irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
0276     }
0277 
0278     kfree(pru->mapped_irq);
0279     pru->mapped_irq = NULL;
0280 }
0281 
0282 /*
0283  * Parse the custom PRU interrupt map resource and configure the INTC
0284  * appropriately.
0285  */
0286 static int pru_handle_intrmap(struct rproc *rproc)
0287 {
0288     struct device *dev = rproc->dev.parent;
0289     struct pru_rproc *pru = rproc->priv;
0290     struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
0291     struct irq_fwspec fwspec;
0292     struct device_node *parent, *irq_parent;
0293     int i, ret = 0;
0294 
0295     /* not having pru_interrupt_map is not an error */
0296     if (!rsc)
0297         return 0;
0298 
0299     /* currently supporting only type 0 */
0300     if (rsc->type != 0) {
0301         dev_err(dev, "unsupported rsc type: %d\n", rsc->type);
0302         return -EINVAL;
0303     }
0304 
0305     if (rsc->num_evts > MAX_PRU_SYS_EVENTS)
0306         return -EINVAL;
0307 
0308     if (sizeof(*rsc) + rsc->num_evts * sizeof(struct pruss_int_map) !=
0309         pru->pru_interrupt_map_sz)
0310         return -EINVAL;
0311 
0312     pru->evt_count = rsc->num_evts;
0313     pru->mapped_irq = kcalloc(pru->evt_count, sizeof(unsigned int),
0314                   GFP_KERNEL);
0315     if (!pru->mapped_irq) {
0316         pru->evt_count = 0;
0317         return -ENOMEM;
0318     }
0319 
0320     /*
0321      * parse and fill in system event to interrupt channel and
0322      * channel-to-host mapping. The interrupt controller to be used
0323      * for these mappings for a given PRU remoteproc is always its
0324      * corresponding sibling PRUSS INTC node.
0325      */
0326     parent = of_get_parent(dev_of_node(pru->dev));
0327     if (!parent) {
0328         kfree(pru->mapped_irq);
0329         pru->mapped_irq = NULL;
0330         pru->evt_count = 0;
0331         return -ENODEV;
0332     }
0333 
0334     irq_parent = of_get_child_by_name(parent, "interrupt-controller");
0335     of_node_put(parent);
0336     if (!irq_parent) {
0337         kfree(pru->mapped_irq);
0338         pru->mapped_irq = NULL;
0339         pru->evt_count = 0;
0340         return -ENODEV;
0341     }
0342 
0343     fwspec.fwnode = of_node_to_fwnode(irq_parent);
0344     fwspec.param_count = 3;
0345     for (i = 0; i < pru->evt_count; i++) {
0346         fwspec.param[0] = rsc->pru_intc_map[i].event;
0347         fwspec.param[1] = rsc->pru_intc_map[i].chnl;
0348         fwspec.param[2] = rsc->pru_intc_map[i].host;
0349 
0350         dev_dbg(dev, "mapping%d: event %d, chnl %d, host %d\n",
0351             i, fwspec.param[0], fwspec.param[1], fwspec.param[2]);
0352 
0353         pru->mapped_irq[i] = irq_create_fwspec_mapping(&fwspec);
0354         if (!pru->mapped_irq[i]) {
0355             dev_err(dev, "failed to get virq for fw mapping %d: event %d chnl %d host %d\n",
0356                 i, fwspec.param[0], fwspec.param[1],
0357                 fwspec.param[2]);
0358             ret = -EINVAL;
0359             goto map_fail;
0360         }
0361     }
0362     of_node_put(irq_parent);
0363 
0364     return ret;
0365 
0366 map_fail:
0367     pru_dispose_irq_mapping(pru);
0368     of_node_put(irq_parent);
0369 
0370     return ret;
0371 }
0372 
0373 static int pru_rproc_start(struct rproc *rproc)
0374 {
0375     struct device *dev = &rproc->dev;
0376     struct pru_rproc *pru = rproc->priv;
0377     const char *names[PRU_TYPE_MAX] = { "PRU", "RTU", "Tx_PRU" };
0378     u32 val;
0379     int ret;
0380 
0381     dev_dbg(dev, "starting %s%d: entry-point = 0x%llx\n",
0382         names[pru->data->type], pru->id, (rproc->bootaddr >> 2));
0383 
0384     ret = pru_handle_intrmap(rproc);
0385     /*
0386      * reset references to pru interrupt map - they will stop being valid
0387      * after rproc_start returns
0388      */
0389     pru->pru_interrupt_map = NULL;
0390     pru->pru_interrupt_map_sz = 0;
0391     if (ret)
0392         return ret;
0393 
0394     val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16);
0395     pru_control_write_reg(pru, PRU_CTRL_CTRL, val);
0396 
0397     return 0;
0398 }
0399 
0400 static int pru_rproc_stop(struct rproc *rproc)
0401 {
0402     struct device *dev = &rproc->dev;
0403     struct pru_rproc *pru = rproc->priv;
0404     const char *names[PRU_TYPE_MAX] = { "PRU", "RTU", "Tx_PRU" };
0405     u32 val;
0406 
0407     dev_dbg(dev, "stopping %s%d\n", names[pru->data->type], pru->id);
0408 
0409     val = pru_control_read_reg(pru, PRU_CTRL_CTRL);
0410     val &= ~CTRL_CTRL_EN;
0411     pru_control_write_reg(pru, PRU_CTRL_CTRL, val);
0412 
0413     /* dispose irq mapping - new firmware can provide new mapping */
0414     pru_dispose_irq_mapping(pru);
0415 
0416     return 0;
0417 }
0418 
0419 /*
0420  * Convert PRU device address (data spaces only) to kernel virtual address.
0421  *
0422  * Each PRU has access to all data memories within the PRUSS, accessible at
0423  * different ranges. So, look through both its primary and secondary Data
0424  * RAMs as well as any shared Data RAM to convert a PRU device address to
0425  * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data
0426  * RAM1 is primary Data RAM for PRU1.
0427  */
0428 static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
0429 {
0430     struct pruss_mem_region dram0, dram1, shrd_ram;
0431     struct pruss *pruss = pru->pruss;
0432     u32 offset;
0433     void *va = NULL;
0434 
0435     if (len == 0)
0436         return NULL;
0437 
0438     dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0];
0439     dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1];
0440     /* PRU1 has its local RAM addresses reversed */
0441     if (pru->id == 1)
0442         swap(dram0, dram1);
0443     shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2];
0444 
0445     if (da >= PRU_PDRAM_DA && da + len <= PRU_PDRAM_DA + dram0.size) {
0446         offset = da - PRU_PDRAM_DA;
0447         va = (__force void *)(dram0.va + offset);
0448     } else if (da >= PRU_SDRAM_DA &&
0449            da + len <= PRU_SDRAM_DA + dram1.size) {
0450         offset = da - PRU_SDRAM_DA;
0451         va = (__force void *)(dram1.va + offset);
0452     } else if (da >= PRU_SHRDRAM_DA &&
0453            da + len <= PRU_SHRDRAM_DA + shrd_ram.size) {
0454         offset = da - PRU_SHRDRAM_DA;
0455         va = (__force void *)(shrd_ram.va + offset);
0456     }
0457 
0458     return va;
0459 }
0460 
0461 /*
0462  * Convert PRU device address (instruction space) to kernel virtual address.
0463  *
0464  * A PRU does not have an unified address space. Each PRU has its very own
0465  * private Instruction RAM, and its device address is identical to that of
0466  * its primary Data RAM device address.
0467  */
0468 static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
0469 {
0470     u32 offset;
0471     void *va = NULL;
0472 
0473     if (len == 0)
0474         return NULL;
0475 
0476     /*
0477      * GNU binutils do not support multiple address spaces. The GNU
0478      * linker's default linker script places IRAM at an arbitrary high
0479      * offset, in order to differentiate it from DRAM. Hence we need to
0480      * strip the artificial offset in the IRAM addresses coming from the
0481      * ELF file.
0482      *
0483      * The TI proprietary linker would never set those higher IRAM address
0484      * bits anyway. PRU architecture limits the program counter to 16-bit
0485      * word-address range. This in turn corresponds to 18-bit IRAM
0486      * byte-address range for ELF.
0487      *
0488      * Two more bits are added just in case to make the final 20-bit mask.
0489      * Idea is to have a safeguard in case TI decides to add banking
0490      * in future SoCs.
0491      */
0492     da &= 0xfffff;
0493 
0494     if (da >= PRU_IRAM_DA &&
0495         da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) {
0496         offset = da - PRU_IRAM_DA;
0497         va = (__force void *)(pru->mem_regions[PRU_IOMEM_IRAM].va +
0498                       offset);
0499     }
0500 
0501     return va;
0502 }
0503 
0504 /*
0505  * Provide address translations for only PRU Data RAMs through the remoteproc
0506  * core for any PRU client drivers. The PRU Instruction RAM access is restricted
0507  * only to the PRU loader code.
0508  */
0509 static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
0510 {
0511     struct pru_rproc *pru = rproc->priv;
0512 
0513     return pru_d_da_to_va(pru, da, len);
0514 }
0515 
0516 /* PRU-specific address translator used by PRU loader. */
0517 static void *pru_da_to_va(struct rproc *rproc, u64 da, size_t len, bool is_iram)
0518 {
0519     struct pru_rproc *pru = rproc->priv;
0520     void *va;
0521 
0522     if (is_iram)
0523         va = pru_i_da_to_va(pru, da, len);
0524     else
0525         va = pru_d_da_to_va(pru, da, len);
0526 
0527     return va;
0528 }
0529 
0530 static struct rproc_ops pru_rproc_ops = {
0531     .start      = pru_rproc_start,
0532     .stop       = pru_rproc_stop,
0533     .da_to_va   = pru_rproc_da_to_va,
0534 };
0535 
0536 /*
0537  * Custom memory copy implementation for ICSSG PRU/RTU/Tx_PRU Cores
0538  *
0539  * The ICSSG PRU/RTU/Tx_PRU cores have a memory copying issue with IRAM
0540  * memories, that is not seen on previous generation SoCs. The data is reflected
0541  * properly in the IRAM memories only for integer (4-byte) copies. Any unaligned
0542  * copies result in all the other pre-existing bytes zeroed out within that
0543  * 4-byte boundary, thereby resulting in wrong text/code in the IRAMs. Also, the
0544  * IRAM memory port interface does not allow any 8-byte copies (as commonly used
0545  * by ARM64 memcpy implementation) and throws an exception. The DRAM memory
0546  * ports do not show this behavior.
0547  */
0548 static int pru_rproc_memcpy(void *dest, const void *src, size_t count)
0549 {
0550     const u32 *s = src;
0551     u32 *d = dest;
0552     size_t size = count / 4;
0553     u32 *tmp_src = NULL;
0554 
0555     /*
0556      * TODO: relax limitation of 4-byte aligned dest addresses and copy
0557      * sizes
0558      */
0559     if ((long)dest % 4 || count % 4)
0560         return -EINVAL;
0561 
0562     /* src offsets in ELF firmware image can be non-aligned */
0563     if ((long)src % 4) {
0564         tmp_src = kmemdup(src, count, GFP_KERNEL);
0565         if (!tmp_src)
0566             return -ENOMEM;
0567         s = tmp_src;
0568     }
0569 
0570     while (size--)
0571         *d++ = *s++;
0572 
0573     kfree(tmp_src);
0574 
0575     return 0;
0576 }
0577 
0578 static int
0579 pru_rproc_load_elf_segments(struct rproc *rproc, const struct firmware *fw)
0580 {
0581     struct pru_rproc *pru = rproc->priv;
0582     struct device *dev = &rproc->dev;
0583     struct elf32_hdr *ehdr;
0584     struct elf32_phdr *phdr;
0585     int i, ret = 0;
0586     const u8 *elf_data = fw->data;
0587 
0588     ehdr = (struct elf32_hdr *)elf_data;
0589     phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
0590 
0591     /* go through the available ELF segments */
0592     for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
0593         u32 da = phdr->p_paddr;
0594         u32 memsz = phdr->p_memsz;
0595         u32 filesz = phdr->p_filesz;
0596         u32 offset = phdr->p_offset;
0597         bool is_iram;
0598         void *ptr;
0599 
0600         if (phdr->p_type != PT_LOAD || !filesz)
0601             continue;
0602 
0603         dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
0604             phdr->p_type, da, memsz, filesz);
0605 
0606         if (filesz > memsz) {
0607             dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
0608                 filesz, memsz);
0609             ret = -EINVAL;
0610             break;
0611         }
0612 
0613         if (offset + filesz > fw->size) {
0614             dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
0615                 offset + filesz, fw->size);
0616             ret = -EINVAL;
0617             break;
0618         }
0619 
0620         /* grab the kernel address for this device address */
0621         is_iram = phdr->p_flags & PF_X;
0622         ptr = pru_da_to_va(rproc, da, memsz, is_iram);
0623         if (!ptr) {
0624             dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
0625             ret = -EINVAL;
0626             break;
0627         }
0628 
0629         if (pru->data->is_k3) {
0630             ret = pru_rproc_memcpy(ptr, elf_data + phdr->p_offset,
0631                            filesz);
0632             if (ret) {
0633                 dev_err(dev, "PRU memory copy failed for da 0x%x memsz 0x%x\n",
0634                     da, memsz);
0635                 break;
0636             }
0637         } else {
0638             memcpy(ptr, elf_data + phdr->p_offset, filesz);
0639         }
0640 
0641         /* skip the memzero logic performed by remoteproc ELF loader */
0642     }
0643 
0644     return ret;
0645 }
0646 
0647 static const void *
0648 pru_rproc_find_interrupt_map(struct device *dev, const struct firmware *fw)
0649 {
0650     struct elf32_shdr *shdr, *name_table_shdr;
0651     const char *name_table;
0652     const u8 *elf_data = fw->data;
0653     struct elf32_hdr *ehdr = (struct elf32_hdr *)elf_data;
0654     u16 shnum = ehdr->e_shnum;
0655     u16 shstrndx = ehdr->e_shstrndx;
0656     int i;
0657 
0658     /* first, get the section header */
0659     shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
0660     /* compute name table section header entry in shdr array */
0661     name_table_shdr = shdr + shstrndx;
0662     /* finally, compute the name table section address in elf */
0663     name_table = elf_data + name_table_shdr->sh_offset;
0664 
0665     for (i = 0; i < shnum; i++, shdr++) {
0666         u32 size = shdr->sh_size;
0667         u32 offset = shdr->sh_offset;
0668         u32 name = shdr->sh_name;
0669 
0670         if (strcmp(name_table + name, ".pru_irq_map"))
0671             continue;
0672 
0673         /* make sure we have the entire irq map */
0674         if (offset + size > fw->size || offset + size < size) {
0675             dev_err(dev, ".pru_irq_map section truncated\n");
0676             return ERR_PTR(-EINVAL);
0677         }
0678 
0679         /* make sure irq map has at least the header */
0680         if (sizeof(struct pru_irq_rsc) > size) {
0681             dev_err(dev, "header-less .pru_irq_map section\n");
0682             return ERR_PTR(-EINVAL);
0683         }
0684 
0685         return shdr;
0686     }
0687 
0688     dev_dbg(dev, "no .pru_irq_map section found for this fw\n");
0689 
0690     return NULL;
0691 }
0692 
0693 /*
0694  * Use a custom parse_fw callback function for dealing with PRU firmware
0695  * specific sections.
0696  *
0697  * The firmware blob can contain optional ELF sections: .resource_table section
0698  * and .pru_irq_map one. The second one contains the PRUSS interrupt mapping
0699  * description, which needs to be setup before powering on the PRU core. To
0700  * avoid RAM wastage this ELF section is not mapped to any ELF segment (by the
0701  * firmware linker) and therefore is not loaded to PRU memory.
0702  */
0703 static int pru_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
0704 {
0705     struct device *dev = &rproc->dev;
0706     struct pru_rproc *pru = rproc->priv;
0707     const u8 *elf_data = fw->data;
0708     const void *shdr;
0709     u8 class = fw_elf_get_class(fw);
0710     u64 sh_offset;
0711     int ret;
0712 
0713     /* load optional rsc table */
0714     ret = rproc_elf_load_rsc_table(rproc, fw);
0715     if (ret == -EINVAL)
0716         dev_dbg(&rproc->dev, "no resource table found for this fw\n");
0717     else if (ret)
0718         return ret;
0719 
0720     /* find .pru_interrupt_map section, not having it is not an error */
0721     shdr = pru_rproc_find_interrupt_map(dev, fw);
0722     if (IS_ERR(shdr))
0723         return PTR_ERR(shdr);
0724 
0725     if (!shdr)
0726         return 0;
0727 
0728     /* preserve pointer to PRU interrupt map together with it size */
0729     sh_offset = elf_shdr_get_sh_offset(class, shdr);
0730     pru->pru_interrupt_map = (struct pru_irq_rsc *)(elf_data + sh_offset);
0731     pru->pru_interrupt_map_sz = elf_shdr_get_sh_size(class, shdr);
0732 
0733     return 0;
0734 }
0735 
0736 /*
0737  * Compute PRU id based on the IRAM addresses. The PRU IRAMs are
0738  * always at a particular offset within the PRUSS address space.
0739  */
0740 static int pru_rproc_set_id(struct pru_rproc *pru)
0741 {
0742     int ret = 0;
0743 
0744     switch (pru->mem_regions[PRU_IOMEM_IRAM].pa & PRU_IRAM_ADDR_MASK) {
0745     case TX_PRU0_IRAM_ADDR_MASK:
0746         fallthrough;
0747     case RTU0_IRAM_ADDR_MASK:
0748         fallthrough;
0749     case PRU0_IRAM_ADDR_MASK:
0750         pru->id = 0;
0751         break;
0752     case TX_PRU1_IRAM_ADDR_MASK:
0753         fallthrough;
0754     case RTU1_IRAM_ADDR_MASK:
0755         fallthrough;
0756     case PRU1_IRAM_ADDR_MASK:
0757         pru->id = 1;
0758         break;
0759     default:
0760         ret = -EINVAL;
0761     }
0762 
0763     return ret;
0764 }
0765 
0766 static int pru_rproc_probe(struct platform_device *pdev)
0767 {
0768     struct device *dev = &pdev->dev;
0769     struct device_node *np = dev->of_node;
0770     struct platform_device *ppdev = to_platform_device(dev->parent);
0771     struct pru_rproc *pru;
0772     const char *fw_name;
0773     struct rproc *rproc = NULL;
0774     struct resource *res;
0775     int i, ret;
0776     const struct pru_private_data *data;
0777     const char *mem_names[PRU_IOMEM_MAX] = { "iram", "control", "debug" };
0778 
0779     data = of_device_get_match_data(&pdev->dev);
0780     if (!data)
0781         return -ENODEV;
0782 
0783     ret = of_property_read_string(np, "firmware-name", &fw_name);
0784     if (ret) {
0785         dev_err(dev, "unable to retrieve firmware-name %d\n", ret);
0786         return ret;
0787     }
0788 
0789     rproc = devm_rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name,
0790                  sizeof(*pru));
0791     if (!rproc) {
0792         dev_err(dev, "rproc_alloc failed\n");
0793         return -ENOMEM;
0794     }
0795     /* use a custom load function to deal with PRU-specific quirks */
0796     rproc->ops->load = pru_rproc_load_elf_segments;
0797 
0798     /* use a custom parse function to deal with PRU-specific resources */
0799     rproc->ops->parse_fw = pru_rproc_parse_fw;
0800 
0801     /* error recovery is not supported for PRUs */
0802     rproc->recovery_disabled = true;
0803 
0804     /*
0805      * rproc_add will auto-boot the processor normally, but this is not
0806      * desired with PRU client driven boot-flow methodology. A PRU
0807      * application/client driver will boot the corresponding PRU
0808      * remote-processor as part of its state machine either through the
0809      * remoteproc sysfs interface or through the equivalent kernel API.
0810      */
0811     rproc->auto_boot = false;
0812 
0813     pru = rproc->priv;
0814     pru->dev = dev;
0815     pru->data = data;
0816     pru->pruss = platform_get_drvdata(ppdev);
0817     pru->rproc = rproc;
0818     pru->fw_name = fw_name;
0819 
0820     for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
0821         res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
0822                            mem_names[i]);
0823         pru->mem_regions[i].va = devm_ioremap_resource(dev, res);
0824         if (IS_ERR(pru->mem_regions[i].va)) {
0825             dev_err(dev, "failed to parse and map memory resource %d %s\n",
0826                 i, mem_names[i]);
0827             ret = PTR_ERR(pru->mem_regions[i].va);
0828             return ret;
0829         }
0830         pru->mem_regions[i].pa = res->start;
0831         pru->mem_regions[i].size = resource_size(res);
0832 
0833         dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
0834             mem_names[i], &pru->mem_regions[i].pa,
0835             pru->mem_regions[i].size, pru->mem_regions[i].va);
0836     }
0837 
0838     ret = pru_rproc_set_id(pru);
0839     if (ret < 0)
0840         return ret;
0841 
0842     platform_set_drvdata(pdev, rproc);
0843 
0844     ret = devm_rproc_add(dev, pru->rproc);
0845     if (ret) {
0846         dev_err(dev, "rproc_add failed: %d\n", ret);
0847         return ret;
0848     }
0849 
0850     pru_rproc_create_debug_entries(rproc);
0851 
0852     dev_dbg(dev, "PRU rproc node %pOF probed successfully\n", np);
0853 
0854     return 0;
0855 }
0856 
0857 static int pru_rproc_remove(struct platform_device *pdev)
0858 {
0859     struct device *dev = &pdev->dev;
0860     struct rproc *rproc = platform_get_drvdata(pdev);
0861 
0862     dev_dbg(dev, "%s: removing rproc %s\n", __func__, rproc->name);
0863 
0864     return 0;
0865 }
0866 
0867 static const struct pru_private_data pru_data = {
0868     .type = PRU_TYPE_PRU,
0869 };
0870 
0871 static const struct pru_private_data k3_pru_data = {
0872     .type = PRU_TYPE_PRU,
0873     .is_k3 = 1,
0874 };
0875 
0876 static const struct pru_private_data k3_rtu_data = {
0877     .type = PRU_TYPE_RTU,
0878     .is_k3 = 1,
0879 };
0880 
0881 static const struct pru_private_data k3_tx_pru_data = {
0882     .type = PRU_TYPE_TX_PRU,
0883     .is_k3 = 1,
0884 };
0885 
0886 static const struct of_device_id pru_rproc_match[] = {
0887     { .compatible = "ti,am3356-pru",    .data = &pru_data },
0888     { .compatible = "ti,am4376-pru",    .data = &pru_data },
0889     { .compatible = "ti,am5728-pru",    .data = &pru_data },
0890     { .compatible = "ti,am642-pru",     .data = &k3_pru_data },
0891     { .compatible = "ti,am642-rtu",     .data = &k3_rtu_data },
0892     { .compatible = "ti,am642-tx-pru",  .data = &k3_tx_pru_data },
0893     { .compatible = "ti,k2g-pru",       .data = &pru_data },
0894     { .compatible = "ti,am654-pru",     .data = &k3_pru_data },
0895     { .compatible = "ti,am654-rtu",     .data = &k3_rtu_data },
0896     { .compatible = "ti,am654-tx-pru",  .data = &k3_tx_pru_data },
0897     { .compatible = "ti,j721e-pru",     .data = &k3_pru_data },
0898     { .compatible = "ti,j721e-rtu",     .data = &k3_rtu_data },
0899     { .compatible = "ti,j721e-tx-pru",  .data = &k3_tx_pru_data },
0900     { .compatible = "ti,am625-pru",     .data = &k3_pru_data },
0901     {},
0902 };
0903 MODULE_DEVICE_TABLE(of, pru_rproc_match);
0904 
0905 static struct platform_driver pru_rproc_driver = {
0906     .driver = {
0907         .name   = "pru-rproc",
0908         .of_match_table = pru_rproc_match,
0909         .suppress_bind_attrs = true,
0910     },
0911     .probe  = pru_rproc_probe,
0912     .remove = pru_rproc_remove,
0913 };
0914 module_platform_driver(pru_rproc_driver);
0915 
0916 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
0917 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
0918 MODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>");
0919 MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver");
0920 MODULE_LICENSE("GPL v2");