]> Git Repo - J-u-boot.git/blob - drivers/remoteproc/pru_rproc.c
Merge tag 'u-boot-imx-master-20250127' of https://gitlab.denx.de/u-boot/custodians...
[J-u-boot.git] / drivers / remoteproc / pru_rproc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PRU-RTU remoteproc driver for various SoCs
4  *
5  * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
6  *      Keerthy <[email protected]>
7  */
8
9 #include <dm.h>
10 #include <elf.h>
11 #include <dm/of_access.h>
12 #include <remoteproc.h>
13 #include <errno.h>
14 #include <clk.h>
15 #include <reset.h>
16 #include <regmap.h>
17 #include <syscon.h>
18 #include <asm/io.h>
19 #include <power-domain.h>
20 #include <linux/pruss_driver.h>
21 #include <dm/device_compat.h>
22
23 /* PRU_ICSS_PRU_CTRL registers */
24 #define PRU_CTRL_CTRL           0x0000
25 #define PRU_CTRL_STS            0x0004
26 #define PRU_CTRL_WAKEUP_EN      0x0008
27 #define PRU_CTRL_CYCLE          0x000C
28 #define PRU_CTRL_STALL          0x0010
29 #define PRU_CTRL_CTBIR0         0x0020
30 #define PRU_CTRL_CTBIR1         0x0024
31 #define PRU_CTRL_CTPPR0         0x0028
32 #define PRU_CTRL_CTPPR1         0x002C
33
34 /* CTRL register bit-fields */
35 #define CTRL_CTRL_SOFT_RST_N    BIT(0)
36 #define CTRL_CTRL_EN            BIT(1)
37 #define CTRL_CTRL_SLEEPING      BIT(2)
38 #define CTRL_CTRL_CTR_EN        BIT(3)
39 #define CTRL_CTRL_SINGLE_STEP   BIT(8)
40 #define CTRL_CTRL_RUNSTATE      BIT(15)
41
42 #define RPROC_FLAGS_SHIFT       16
43 #define RPROC_FLAGS_NONE        0
44 #define RPROC_FLAGS_ELF_PHDR    BIT(0 + RPROC_FLAGS_SHIFT)
45 #define RPROC_FLAGS_ELF_SHDR    BIT(1 + RPROC_FLAGS_SHIFT)
46
47 /**
48  * enum pru_mem - PRU core memory range identifiers
49  */
50 enum pru_mem {
51         PRU_MEM_IRAM = 0,
52         PRU_MEM_CTRL,
53         PRU_MEM_DEBUG,
54         PRU_MEM_MAX,
55 };
56
57 struct pru_privdata {
58         phys_addr_t pru_iram;
59         phys_addr_t pru_ctrl;
60         phys_addr_t pru_debug;
61         fdt_size_t pru_iramsz;
62         fdt_size_t pru_ctrlsz;
63         fdt_size_t pru_debugsz;
64         const char *fw_name;
65         u32 iram_da;
66         u32 pdram_da;
67         u32 sdram_da;
68         u32 shrdram_da;
69         u32 bootaddr;
70         int id;
71         struct pruss *prusspriv;
72 };
73
74 static inline u32 pru_control_read_reg(struct pru_privdata *pru, unsigned int reg)
75 {
76         return readl(pru->pru_ctrl + reg);
77 }
78
79 static inline
80 void pru_control_write_reg(struct pru_privdata *pru, unsigned int reg, u32 val)
81 {
82         writel(val, pru->pru_ctrl + reg);
83 }
84
85 static inline
86 void pru_control_set_reg(struct pru_privdata *pru, unsigned int reg,
87                          u32 mask, u32 set)
88 {
89         u32 val;
90
91         val = pru_control_read_reg(pru, reg);
92         val &= ~mask;
93         val |= (set & mask);
94         pru_control_write_reg(pru, reg, val);
95 }
96
97 /**
98  * pru_rproc_set_ctable() - set the constant table index for the PRU
99  * @rproc: the rproc instance of the PRU
100  * @c: constant table index to set
101  * @addr: physical address to set it to
102  */
103 static int pru_rproc_set_ctable(struct pru_privdata *pru, enum pru_ctable_idx c, u32 addr)
104 {
105         unsigned int reg;
106         u32 mask, set;
107         u16 idx;
108         u16 idx_mask;
109
110         /* pointer is 16 bit and index is 8-bit so mask out the rest */
111         idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF;
112
113         /* ctable uses bit 8 and upwards only */
114         idx = (addr >> 8) & idx_mask;
115
116         /* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */
117         reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1);
118         mask = idx_mask << (16 * (c & 1));
119         set = idx << (16 * (c & 1));
120
121         pru_control_set_reg(pru, reg, mask, set);
122
123         return 0;
124 }
125
126 /**
127  * pru_start() - start the pru processor
128  * @dev:        corresponding k3 remote processor device
129  *
130  * Return: 0 if all goes good, else appropriate error message.
131  */
132 static int pru_start(struct udevice *dev)
133 {
134         struct pru_privdata *priv;
135         int val = 0;
136
137         priv = dev_get_priv(dev);
138
139         pru_rproc_set_ctable(priv, PRU_C28, 0x100 << 8);
140
141         val = CTRL_CTRL_EN | ((priv->bootaddr >> 2) << 16);
142         writel(val, priv->pru_ctrl + PRU_CTRL_CTRL);
143
144         return 0;
145 }
146
147 /**
148  * pru_stop() - Stop pru processor
149  * @dev:        corresponding k3 remote processor device
150  *
151  * Return: 0 if all goes good, else appropriate error message.
152  */
153 static int pru_stop(struct udevice *dev)
154 {
155         struct pru_privdata *priv;
156         int val = 0;
157
158         priv = dev_get_priv(dev);
159
160         val = readl(priv->pru_ctrl + PRU_CTRL_CTRL);
161         val &= ~CTRL_CTRL_EN;
162         writel(val, priv->pru_ctrl + PRU_CTRL_CTRL);
163
164         return 0;
165 }
166
167 /**
168  * pru_init() - Initialize the remote processor
169  * @dev:        rproc device pointer
170  *
171  * Return: 0 if all went ok, else return appropriate error
172  */
173 static int pru_init(struct udevice *dev)
174 {
175         return 0;
176 }
177
178 /*
179  * Convert PRU device address (data spaces only) to kernel virtual address
180  *
181  * Each PRU has access to all data memories within the PRUSS, accessible at
182  * different ranges. So, look through both its primary and secondary Data
183  * RAMs as well as any shared Data RAM to convert a PRU device address to
184  * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data
185  * RAM1 is primary Data RAM for PRU1.
186  */
187 static void *pru_d_da_to_pa(struct pru_privdata *priv, u32 da, int len)
188 {
189         u32 offset;
190         void *pa = NULL;
191         phys_addr_t dram0, dram1, shrdram2;
192         u32 dram0sz, dram1sz, shrdram2sz;
193
194         if (len <= 0)
195                 return NULL;
196
197         dram0 = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM0].pa;
198         dram1 = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].pa;
199         shrdram2 = priv->prusspriv->mem_regions[PRUSS_MEM_SHRD_RAM2].pa;
200         dram0sz = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM0].size;
201         dram1sz = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].size;
202         shrdram2sz = priv->prusspriv->mem_regions[PRUSS_MEM_SHRD_RAM2].size;
203
204         /* PRU1 has its local RAM addresses reversed */
205         if (priv->id == 1) {
206                 dram1 = dram0;
207                 dram1sz = dram0sz;
208
209                 dram0 =  priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].pa;
210                 dram0sz = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].size;
211         }
212
213         if (da >= priv->pdram_da && da + len <= priv->pdram_da + dram0sz) {
214                 offset = da - priv->pdram_da;
215                 pa = (__force void *)(dram0 + offset);
216         } else if (da >= priv->sdram_da &&
217                    da + len <= priv->sdram_da + dram1sz) {
218                 offset = da - priv->sdram_da;
219                 pa = (__force void *)(dram1 + offset);
220         } else if (da >= priv->shrdram_da &&
221                    da + len <= priv->shrdram_da + shrdram2sz) {
222                 offset = da - priv->shrdram_da;
223                 pa = (__force void *)(shrdram2 + offset);
224         }
225
226         return pa;
227 }
228
229 /*
230  * Convert PRU device address (instruction space) to kernel virtual address
231  *
232  * A PRU does not have an unified address space. Each PRU has its very own
233  * private Instruction RAM, and its device address is identical to that of
234  * its primary Data RAM device address.
235  */
236 static void *pru_i_da_to_pa(struct pru_privdata *priv, u32 da, int len)
237 {
238         u32 offset;
239         void *pa = NULL;
240
241         if (len <= 0)
242                 return NULL;
243
244         if (da >= priv->iram_da &&
245             da + len <= priv->iram_da + priv->pru_iramsz) {
246                 offset = da - priv->iram_da;
247                 pa = (__force void *)(priv->pru_iram + offset);
248         }
249
250         return pa;
251 }
252
253 /* PRU-specific address translator */
254 static void *pru_da_to_pa(struct pru_privdata *priv, u64 da, int len, u32 flags)
255 {
256         void *pa;
257         u32 exec_flag;
258
259         exec_flag = ((flags & RPROC_FLAGS_ELF_SHDR) ? flags & SHF_EXECINSTR :
260                      ((flags & RPROC_FLAGS_ELF_PHDR) ? flags & PF_X : 0));
261
262         if (exec_flag)
263                 pa = pru_i_da_to_pa(priv, da, len);
264         else
265                 pa = pru_d_da_to_pa(priv, da, len);
266
267         return pa;
268 }
269
270 /*
271  * Custom memory copy implementation for ICSSG PRU/RTU Cores
272  *
273  * The ICSSG PRU/RTU cores have a memory copying issue with IRAM memories, that
274  * is not seen on previous generation SoCs. The data is reflected properly in
275  * the IRAM memories only for integer (4-byte) copies. Any unaligned copies
276  * result in all the other pre-existing bytes zeroed out within that 4-byte
277  * boundary, thereby resulting in wrong text/code in the IRAMs. Also, the
278  * IRAM memory port interface does not allow any 8-byte copies (as commonly
279  * used by ARM64 memcpy implementation) and throws an exception. The DRAM
280  * memory ports do not show this behavior. Use this custom copying function
281  * to properly load the PRU/RTU firmware images on all memories for simplicity.
282  *
283  * TODO: Improve the function to deal with additional corner cases like
284  * unaligned copy sizes or sub-integer trailing bytes when the need arises.
285  */
286 static int pru_rproc_memcpy(void *dest, void *src, size_t count)
287 {
288         const int *s = src;
289         int *d = dest;
290         int size = count / 4;
291         int *tmp_src = NULL;
292
293         /* limited to 4-byte aligned addresses and copy sizes */
294         if ((long)dest % 4 || count % 4)
295                 return -EINVAL;
296
297         /* src offsets in ELF firmware image can be non-aligned */
298         if ((long)src % 4) {
299                 tmp_src = malloc(count);
300                 if (!tmp_src)
301                         return -ENOMEM;
302
303                 memcpy(tmp_src, src, count);
304                 s = tmp_src;
305         }
306
307         while (size--)
308                 *d++ = *s++;
309
310         kfree(tmp_src);
311
312         return 0;
313 }
314
315 /**
316  * pru_load() - Load pru firmware
317  * @dev:        corresponding k3 remote processor device
318  * @addr:       Address on the RAM from which firmware is to be loaded
319  * @size:       Size of the pru firmware in bytes
320  *
321  * Return: 0 if all goes good, else appropriate error message.
322  */
323 static int pru_load(struct udevice *dev, ulong addr, ulong size)
324 {
325         struct pru_privdata *priv;
326         Elf32_Ehdr *ehdr;
327         Elf32_Phdr *phdr;
328         int i, ret = 0;
329
330         priv = dev_get_priv(dev);
331
332         ehdr = (Elf32_Ehdr *)addr;
333         phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
334
335         /* go through the available ELF segments */
336         for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
337                 u32 da = phdr->p_paddr;
338                 u32 memsz = phdr->p_memsz;
339                 u32 filesz = phdr->p_filesz;
340                 u32 offset = phdr->p_offset;
341                 void *ptr;
342
343                 if (phdr->p_type != PT_LOAD)
344                         continue;
345
346                 dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
347                         phdr->p_type, da, memsz, filesz);
348
349                 if (filesz > memsz) {
350                         dev_dbg(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
351                                 filesz, memsz);
352                         ret = -EINVAL;
353                         break;
354                 }
355
356                 if (offset + filesz > size) {
357                         dev_dbg(dev, "truncated fw: need 0x%x avail 0x%zx\n",
358                                 offset + filesz, size);
359                         ret = -EINVAL;
360                         break;
361                 }
362
363                 /* grab the kernel address for this device address */
364                 ptr = pru_da_to_pa(priv, da, memsz,
365                                    RPROC_FLAGS_ELF_PHDR | phdr->p_flags);
366                 if (!ptr) {
367                         dev_dbg(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
368                         ret = -EINVAL;
369                         break;
370                 }
371
372                 /* skip the memzero logic performed by remoteproc ELF loader */
373                 if (!phdr->p_filesz)
374                         continue;
375
376                 ret = pru_rproc_memcpy(ptr,
377                                        (void *)addr + phdr->p_offset, filesz);
378                 if (ret) {
379                         dev_dbg(dev, "PRU custom memory copy failed for da 0x%x memsz 0x%x\n",
380                                 da, memsz);
381                         break;
382                 }
383         }
384
385         priv->bootaddr = ehdr->e_entry;
386
387         return ret;
388 }
389
390 static const struct dm_rproc_ops pru_ops = {
391         .init = pru_init,
392         .start = pru_start,
393         .stop = pru_stop,
394         .load = pru_load,
395 };
396
397 static void pru_set_id(struct pru_privdata *priv, struct udevice *dev)
398 {
399         u32 mask2 = 0x38000;
400
401         if (device_is_compatible(dev, "ti,am654-rtu") ||
402             device_is_compatible(dev, "ti,am642-rtu"))
403                 mask2 = 0x6000;
404
405         if (device_is_compatible(dev, "ti,am654-tx-pru") ||
406             device_is_compatible(dev, "ti,am642-tx-pru"))
407                 mask2 = 0xc000;
408
409         if ((priv->pru_iram & mask2) == mask2)
410                 priv->id = 1;
411         else
412                 priv->id = 0;
413 }
414
415 /**
416  * pru_probe() - Basic probe
417  * @dev:        corresponding k3 remote processor device
418  *
419  * Return: 0 if all goes good, else appropriate error message.
420  */
421 static int pru_probe(struct udevice *dev)
422 {
423         struct pru_privdata *priv;
424         ofnode node;
425
426         node = dev_ofnode(dev);
427
428         priv = dev_get_priv(dev);
429         priv->prusspriv = dev_get_priv(dev->parent);
430
431         priv->pru_iram = devfdt_get_addr_size_index(dev, PRU_MEM_IRAM,
432                                                     &priv->pru_iramsz);
433         priv->pru_ctrl = devfdt_get_addr_size_index(dev, PRU_MEM_CTRL,
434                                                     &priv->pru_ctrlsz);
435         priv->pru_debug = devfdt_get_addr_size_index(dev, PRU_MEM_DEBUG,
436                                                      &priv->pru_debugsz);
437
438         priv->iram_da = 0;
439         priv->pdram_da = 0;
440         priv->sdram_da = 0x2000;
441         priv->shrdram_da = 0x10000;
442
443         pru_set_id(priv, dev);
444
445         return 0;
446 }
447
448 static const struct udevice_id pru_ids[] = {
449         { .compatible = "ti,am654-pru"},
450         { .compatible = "ti,am654-rtu"},
451         { .compatible = "ti,am654-tx-pru" },
452         { .compatible = "ti,am642-pru"},
453         { .compatible = "ti,am642-rtu"},
454         { .compatible = "ti,am642-tx-pru" },
455         {}
456 };
457
458 U_BOOT_DRIVER(pru) = {
459         .name = "pru",
460         .of_match = pru_ids,
461         .id = UCLASS_REMOTEPROC,
462         .ops = &pru_ops,
463         .probe = pru_probe,
464         .priv_auto = sizeof(struct pru_privdata),
465 };
This page took 0.055594 seconds and 4 git commands to generate.