blob: 4db6f3158c395dcb2cec2fff319dd0cea5801cce [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Calvin Johnson781b8382018-03-08 15:30:25 +05302/*
3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
4 * Copyright 2017 NXP
Calvin Johnson781b8382018-03-08 15:30:25 +05305 */
Simon Glass0f2af882020-05-10 11:40:05 -06006#include <log.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -06007#include <linux/bitops.h>
Calvin Johnson781b8382018-03-08 15:30:25 +05308#include <net/pfe_eth/pfe_eth.h>
9#include <net/pfe_eth/pfe/pfe_hw.h>
10
11static struct pe_info pe[MAX_PE];
12
13/*
14 * Initializes the PFE library.
15 * Must be called before using any of the library functions.
16 */
17void pfe_lib_init(void)
18{
19 int pfe_pe_id;
20
21 for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
22 pe[pfe_pe_id].dmem_base_addr =
23 (u32)CLASS_DMEM_BASE_ADDR(pfe_pe_id);
24 pe[pfe_pe_id].pmem_base_addr =
25 (u32)CLASS_IMEM_BASE_ADDR(pfe_pe_id);
26 pe[pfe_pe_id].pmem_size = (u32)CLASS_IMEM_SIZE;
27 pe[pfe_pe_id].mem_access_wdata =
28 (void *)CLASS_MEM_ACCESS_WDATA;
29 pe[pfe_pe_id].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
30 pe[pfe_pe_id].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
31 }
32
33 for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
34 if (pfe_pe_id == TMU2_ID)
35 continue;
36 pe[pfe_pe_id].dmem_base_addr =
37 (u32)TMU_DMEM_BASE_ADDR(pfe_pe_id - TMU0_ID);
38 pe[pfe_pe_id].pmem_base_addr =
39 (u32)TMU_IMEM_BASE_ADDR(pfe_pe_id - TMU0_ID);
40 pe[pfe_pe_id].pmem_size = (u32)TMU_IMEM_SIZE;
41 pe[pfe_pe_id].mem_access_wdata = (void *)TMU_MEM_ACCESS_WDATA;
42 pe[pfe_pe_id].mem_access_addr = (void *)TMU_MEM_ACCESS_ADDR;
43 pe[pfe_pe_id].mem_access_rdata = (void *)TMU_MEM_ACCESS_RDATA;
44 }
45}
46
47/*
48 * Writes a buffer to PE internal memory from the host
49 * through indirect access registers.
50 *
51 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
52 * ..., UTIL_ID)
53 * @param[in] mem_access_addr DMEM destination address (must be 32bit
54 * aligned)
55 * @param[in] src Buffer source address
56 * @param[in] len Number of bytes to copy
57 */
58static void pe_mem_memcpy_to32(int id, u32 mem_access_addr, const void *src,
59 unsigned int len)
60{
61 u32 offset = 0, val, addr;
62 unsigned int len32 = len >> 2;
63 int i;
64
65 addr = mem_access_addr | PE_MEM_ACCESS_WRITE |
66 PE_MEM_ACCESS_BYTE_ENABLE(0, 4);
67
68 for (i = 0; i < len32; i++, offset += 4, src += 4) {
69 val = *(u32 *)src;
70 writel(cpu_to_be32(val), pe[id].mem_access_wdata);
71 writel(addr + offset, pe[id].mem_access_addr);
72 }
73
74 len = (len & 0x3);
75 if (len) {
76 val = 0;
77
78 addr = (mem_access_addr | PE_MEM_ACCESS_WRITE |
79 PE_MEM_ACCESS_BYTE_ENABLE(0, len)) + offset;
80
81 for (i = 0; i < len; i++, src++)
82 val |= (*(u8 *)src) << (8 * i);
83
84 writel(cpu_to_be32(val), pe[id].mem_access_wdata);
85 writel(addr, pe[id].mem_access_addr);
86 }
87}
88
89/*
90 * Writes a buffer to PE internal data memory (DMEM) from the host
91 * through indirect access registers.
92 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
93 * ..., UTIL_ID)
94 * @param[in] dst DMEM destination address (must be 32bit
95 * aligned)
96 * @param[in] src Buffer source address
97 * @param[in] len Number of bytes to copy
98 */
99static void pe_dmem_memcpy_to32(int id, u32 dst, const void *src,
100 unsigned int len)
101{
102 pe_mem_memcpy_to32(id, pe[id].dmem_base_addr | dst | PE_MEM_ACCESS_DMEM,
103 src, len);
104}
105
106/*
107 * Writes a buffer to PE internal program memory (PMEM) from the host
108 * through indirect access registers.
109 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
110 * ..., TMU3_ID)
111 * @param[in] dst PMEM destination address (must be 32bit
112 * aligned)
113 * @param[in] src Buffer source address
114 * @param[in] len Number of bytes to copy
115 */
116static void pe_pmem_memcpy_to32(int id, u32 dst, const void *src,
117 unsigned int len)
118{
119 pe_mem_memcpy_to32(id, pe[id].pmem_base_addr | (dst & (pe[id].pmem_size
120 - 1)) | PE_MEM_ACCESS_IMEM, src, len);
121}
122
123/*
124 * Reads PE internal program memory (IMEM) from the host
125 * through indirect access registers.
126 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
127 * ..., TMU3_ID)
128 * @param[in] addr PMEM read address (must be aligned on size)
129 * @param[in] size Number of bytes to read (maximum 4, must not
130 * cross 32bit boundaries)
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100131 * Return: the data read (in PE endianness, i.e BE).
Calvin Johnson781b8382018-03-08 15:30:25 +0530132 */
133u32 pe_pmem_read(int id, u32 addr, u8 size)
134{
135 u32 offset = addr & 0x3;
136 u32 mask = 0xffffffff >> ((4 - size) << 3);
137 u32 val;
138
139 addr = pe[id].pmem_base_addr | ((addr & ~0x3) & (pe[id].pmem_size - 1))
140 | PE_MEM_ACCESS_READ | PE_MEM_ACCESS_IMEM |
141 PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
142
143 writel(addr, pe[id].mem_access_addr);
144 val = be32_to_cpu(readl(pe[id].mem_access_rdata));
145
146 return (val >> (offset << 3)) & mask;
147}
148
149/*
150 * Writes PE internal data memory (DMEM) from the host
151 * through indirect access registers.
152 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
153 * ..., UTIL_ID)
154 * @param[in] val Value to write (in PE endianness, i.e BE)
155 * @param[in] addr DMEM write address (must be aligned on size)
156 * @param[in] size Number of bytes to write (maximum 4, must not
157 * cross 32bit boundaries)
158 */
159void pe_dmem_write(int id, u32 val, u32 addr, u8 size)
160{
161 u32 offset = addr & 0x3;
162
163 addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_WRITE |
164 PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
165
166 /* Indirect access interface is byte swapping data being written */
167 writel(cpu_to_be32(val << (offset << 3)), pe[id].mem_access_wdata);
168 writel(addr, pe[id].mem_access_addr);
169}
170
171/*
172 * Reads PE internal data memory (DMEM) from the host
173 * through indirect access registers.
174 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
175 * ..., UTIL_ID)
176 * @param[in] addr DMEM read address (must be aligned on size)
177 * @param[in] size Number of bytes to read (maximum 4, must not
178 * cross 32bit boundaries)
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100179 * Return: the data read (in PE endianness, i.e BE).
Calvin Johnson781b8382018-03-08 15:30:25 +0530180 */
181u32 pe_dmem_read(int id, u32 addr, u8 size)
182{
183 u32 offset = addr & 0x3;
184 u32 mask = 0xffffffff >> ((4 - size) << 3);
185 u32 val;
186
187 addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_READ |
188 PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
189
190 writel(addr, pe[id].mem_access_addr);
191
192 /* Indirect access interface is byte swapping data being read */
193 val = be32_to_cpu(readl(pe[id].mem_access_rdata));
194
195 return (val >> (offset << 3)) & mask;
196}
197
198/*
199 * This function is used to write to CLASS internal bus peripherals (ccu,
200 * pe-lem) from the host
201 * through indirect access registers.
202 * @param[in] val value to write
203 * @param[in] addr Address to write to (must be aligned on size)
204 * @param[in] size Number of bytes to write (1, 2 or 4)
205 *
206 */
207static void class_bus_write(u32 val, u32 addr, u8 size)
208{
209 u32 offset = addr & 0x3;
210
211 writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
212
213 addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | PE_MEM_ACCESS_WRITE |
214 (size << 24);
215
216 writel(cpu_to_be32(val << (offset << 3)), CLASS_BUS_ACCESS_WDATA);
217 writel(addr, CLASS_BUS_ACCESS_ADDR);
218}
219
220/*
221 * Reads from CLASS internal bus peripherals (ccu, pe-lem) from the host
222 * through indirect access registers.
223 * @param[in] addr Address to read from (must be aligned on size)
224 * @param[in] size Number of bytes to read (1, 2 or 4)
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100225 * Return: the read data
Calvin Johnson781b8382018-03-08 15:30:25 +0530226 */
227static u32 class_bus_read(u32 addr, u8 size)
228{
229 u32 offset = addr & 0x3;
230 u32 mask = 0xffffffff >> ((4 - size) << 3);
231 u32 val;
232
233 writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
234
235 addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | (size << 24);
236
237 writel(addr, CLASS_BUS_ACCESS_ADDR);
238 val = be32_to_cpu(readl(CLASS_BUS_ACCESS_RDATA));
239
240 return (val >> (offset << 3)) & mask;
241}
242
243/*
244 * Writes data to the cluster memory (PE_LMEM)
245 * @param[in] dst PE LMEM destination address (must be 32bit aligned)
246 * @param[in] src Buffer source address
247 * @param[in] len Number of bytes to copy
248 */
249static void class_pe_lmem_memcpy_to32(u32 dst, const void *src,
250 unsigned int len)
251{
252 u32 len32 = len >> 2;
253 int i;
254
255 for (i = 0; i < len32; i++, src += 4, dst += 4)
256 class_bus_write(*(u32 *)src, dst, 4);
257
258 if (len & 0x2) {
259 class_bus_write(*(u16 *)src, dst, 2);
260 src += 2;
261 dst += 2;
262 }
263
264 if (len & 0x1) {
265 class_bus_write(*(u8 *)src, dst, 1);
266 src++;
267 dst++;
268 }
269}
270
271/*
272 * Writes value to the cluster memory (PE_LMEM)
273 * @param[in] dst PE LMEM destination address (must be 32bit aligned)
274 * @param[in] val Value to write
275 * @param[in] len Number of bytes to write
276 */
277static void class_pe_lmem_memset(u32 dst, int val, unsigned int len)
278{
279 u32 len32 = len >> 2;
280 int i;
281
282 val = val | (val << 8) | (val << 16) | (val << 24);
283
284 for (i = 0; i < len32; i++, dst += 4)
285 class_bus_write(val, dst, 4);
286
287 if (len & 0x2) {
288 class_bus_write(val, dst, 2);
289 dst += 2;
290 }
291
292 if (len & 0x1) {
293 class_bus_write(val, dst, 1);
294 dst++;
295 }
296}
297
298/*
299 * Reads data from the cluster memory (PE_LMEM)
300 * @param[out] dst pointer to the source buffer data are copied to
301 * @param[in] len length in bytes of the amount of data to read
302 * from cluster memory
303 * @param[in] offset offset in bytes in the cluster memory where data are
304 * read from
305 */
306void pe_lmem_read(u32 *dst, u32 len, u32 offset)
307{
308 u32 len32 = len >> 2;
309 int i = 0;
310
311 for (i = 0; i < len32; dst++, i++, offset += 4)
312 *dst = class_bus_read(PE_LMEM_BASE_ADDR + offset, 4);
313
314 if (len & 0x03)
315 *dst = class_bus_read(PE_LMEM_BASE_ADDR + offset, (len & 0x03));
316}
317
318/*
319 * Writes data to the cluster memory (PE_LMEM)
320 * @param[in] src pointer to the source buffer data are copied from
321 * @param[in] len length in bytes of the amount of data to write to the
322 * cluster memory
323 * @param[in] offset offset in bytes in the cluster memory where data are
324 * written to
325 */
326void pe_lmem_write(u32 *src, u32 len, u32 offset)
327{
328 u32 len32 = len >> 2;
329 int i = 0;
330
331 for (i = 0; i < len32; src++, i++, offset += 4)
332 class_bus_write(*src, PE_LMEM_BASE_ADDR + offset, 4);
333
334 if (len & 0x03)
335 class_bus_write(*src, PE_LMEM_BASE_ADDR + offset, (len &
336 0x03));
337}
338
339/*
340 * Loads an elf section into pmem
341 * Code needs to be at least 16bit aligned and only PROGBITS sections are
342 * supported
343 *
344 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID, ...,
345 * TMU3_ID)
346 * @param[in] data pointer to the elf firmware
347 * @param[in] shdr pointer to the elf section header
348 */
349static int pe_load_pmem_section(int id, const void *data, Elf32_Shdr *shdr)
350{
351 u32 offset = be32_to_cpu(shdr->sh_offset);
352 u32 addr = be32_to_cpu(shdr->sh_addr);
353 u32 size = be32_to_cpu(shdr->sh_size);
354 u32 type = be32_to_cpu(shdr->sh_type);
355
356 if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
357 printf(
358 "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
359 __func__, addr, (unsigned long)data + offset);
360
361 return -1;
362 }
363
364 if (addr & 0x1) {
365 printf("%s: load address(%x) is not 16bit aligned\n",
366 __func__, addr);
367 return -1;
368 }
369
370 if (size & 0x1) {
371 printf("%s: load size(%x) is not 16bit aligned\n", __func__,
372 size);
373 return -1;
374 }
375
376 debug("pmem pe%d @%x len %d\n", id, addr, size);
377 switch (type) {
378 case SHT_PROGBITS:
379 pe_pmem_memcpy_to32(id, addr, data + offset, size);
380 break;
381
382 default:
383 printf("%s: unsupported section type(%x)\n", __func__, type);
384 return -1;
385 }
386
387 return 0;
388}
389
390/*
391 * Loads an elf section into dmem
392 * Data needs to be at least 32bit aligned, NOBITS sections are correctly
393 * initialized to 0
394 *
395 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
396 * ..., UTIL_ID)
397 * @param[in] data pointer to the elf firmware
398 * @param[in] shdr pointer to the elf section header
399 */
400static int pe_load_dmem_section(int id, const void *data, Elf32_Shdr *shdr)
401{
402 u32 offset = be32_to_cpu(shdr->sh_offset);
403 u32 addr = be32_to_cpu(shdr->sh_addr);
404 u32 size = be32_to_cpu(shdr->sh_size);
405 u32 type = be32_to_cpu(shdr->sh_type);
406 u32 size32 = size >> 2;
407 int i;
408
409 if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
410 printf(
411 "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
412 __func__, addr, (unsigned long)data + offset);
413
414 return -1;
415 }
416
417 if (addr & 0x3) {
418 printf("%s: load address(%x) is not 32bit aligned\n",
419 __func__, addr);
420 return -1;
421 }
422
423 switch (type) {
424 case SHT_PROGBITS:
425 debug("dmem pe%d @%x len %d\n", id, addr, size);
426 pe_dmem_memcpy_to32(id, addr, data + offset, size);
427 break;
428
429 case SHT_NOBITS:
430 debug("dmem zero pe%d @%x len %d\n", id, addr, size);
431 for (i = 0; i < size32; i++, addr += 4)
432 pe_dmem_write(id, 0, addr, 4);
433
434 if (size & 0x3)
435 pe_dmem_write(id, 0, addr, size & 0x3);
436
437 break;
438
439 default:
440 printf("%s: unsupported section type(%x)\n", __func__, type);
441 return -1;
442 }
443
444 return 0;
445}
446
447/*
448 * Loads an elf section into DDR
449 * Data needs to be at least 32bit aligned, NOBITS sections are correctly
450 * initialized to 0
451 *
452 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
453 * ..., UTIL_ID)
454 * @param[in] data pointer to the elf firmware
455 * @param[in] shdr pointer to the elf section header
456 */
457static int pe_load_ddr_section(int id, const void *data, Elf32_Shdr *shdr)
458{
459 u32 offset = be32_to_cpu(shdr->sh_offset);
460 u32 addr = be32_to_cpu(shdr->sh_addr);
461 u32 size = be32_to_cpu(shdr->sh_size);
462 u32 type = be32_to_cpu(shdr->sh_type);
463 u32 flags = be32_to_cpu(shdr->sh_flags);
464
465 switch (type) {
466 case SHT_PROGBITS:
467 debug("ddr pe%d @%x len %d\n", id, addr, size);
468 if (flags & SHF_EXECINSTR) {
469 if (id <= CLASS_MAX_ID) {
470 /* DO the loading only once in DDR */
471 if (id == CLASS0_ID) {
472 debug(
473 "%s: load address(%x) and elf file address(%lx) rcvd\n"
474 , __func__, addr,
475 (unsigned long)data + offset);
476 if (((unsigned long)(data + offset)
477 & 0x3) != (addr & 0x3)) {
478 printf(
479 "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
480 __func__, addr,
481 (unsigned long)data +
482 offset);
483
484 return -1;
485 }
486
487 if (addr & 0x1) {
488 printf(
489 "%s: load address(%x) is not 16bit aligned\n"
490 , __func__, addr);
491 return -1;
492 }
493
494 if (size & 0x1) {
495 printf(
496 "%s: load length(%x) is not 16bit aligned\n"
497 , __func__, size);
498 return -1;
499 }
500
501 memcpy((void *)DDR_PFE_TO_VIRT(addr),
502 data + offset, size);
503 }
504 } else {
505 printf(
506 "%s: unsupported ddr section type(%x) for PE(%d)\n"
507 , __func__, type, id);
508 return -1;
509 }
510
511 } else {
512 memcpy((void *)DDR_PFE_TO_VIRT(addr), data + offset,
513 size);
514 }
515
516 break;
517
518 case SHT_NOBITS:
519 debug("ddr zero pe%d @%x len %d\n", id, addr, size);
520 memset((void *)DDR_PFE_TO_VIRT(addr), 0, size);
521
522 break;
523
524 default:
525 printf("%s: unsupported section type(%x)\n", __func__, type);
526 return -1;
527 }
528
529 return 0;
530}
531
532/*
533 * Loads an elf section into pe lmem
534 * Data needs to be at least 32bit aligned, NOBITS sections are correctly
535 * initialized to 0
536 *
537 * @param[in] id PE identification (CLASS0_ID,..., CLASS5_ID)
538 * @param[in] data pointer to the elf firmware
539 * @param[in] shdr pointer to the elf section header
540 */
541static int pe_load_pe_lmem_section(int id, const void *data, Elf32_Shdr *shdr)
542{
543 u32 offset = be32_to_cpu(shdr->sh_offset);
544 u32 addr = be32_to_cpu(shdr->sh_addr);
545 u32 size = be32_to_cpu(shdr->sh_size);
546 u32 type = be32_to_cpu(shdr->sh_type);
547
548 if (id > CLASS_MAX_ID) {
549 printf("%s: unsupported pe-lmem section type(%x) for PE(%d)\n",
550 __func__, type, id);
551 return -1;
552 }
553
554 if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
555 printf(
556 "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
557 __func__, addr, (unsigned long)data + offset);
558
559 return -1;
560 }
561
562 if (addr & 0x3) {
563 printf("%s: load address(%x) is not 32bit aligned\n",
564 __func__, addr);
565 return -1;
566 }
567
568 debug("lmem pe%d @%x len %d\n", id, addr, size);
569
570 switch (type) {
571 case SHT_PROGBITS:
572 class_pe_lmem_memcpy_to32(addr, data + offset, size);
573 break;
574
575 case SHT_NOBITS:
576 class_pe_lmem_memset(addr, 0, size);
577 break;
578
579 default:
580 printf("%s: unsupported section type(%x)\n", __func__, type);
581 return -1;
582 }
583
584 return 0;
585}
586
587/*
588 * Loads an elf section into a PE
589 * For now only supports loading a section to dmem (all PE's), pmem (class and
590 * tmu PE's), DDDR (util PE code)
591 * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
592 * ..., UTIL_ID)
593 * @param[in] data pointer to the elf firmware
594 * @param[in] shdr pointer to the elf section header
595 */
596int pe_load_elf_section(int id, const void *data, Elf32_Shdr *shdr)
597{
598 u32 addr = be32_to_cpu(shdr->sh_addr);
599 u32 size = be32_to_cpu(shdr->sh_size);
600
601 if (IS_DMEM(addr, size))
602 return pe_load_dmem_section(id, data, shdr);
603 else if (IS_PMEM(addr, size))
604 return pe_load_pmem_section(id, data, shdr);
605 else if (IS_PFE_LMEM(addr, size))
606 return 0;
607 else if (IS_PHYS_DDR(addr, size))
608 return pe_load_ddr_section(id, data, shdr);
609 else if (IS_PE_LMEM(addr, size))
610 return pe_load_pe_lmem_section(id, data, shdr);
611
612 printf("%s: unsupported memory range(%x)\n", __func__, addr);
613
614 return 0;
615}
616
617/**************************** BMU ***************************/
618/*
619 * Resets a BMU block.
620 * @param[in] base BMU block base address
621 */
622static inline void bmu_reset(void *base)
623{
624 writel(CORE_SW_RESET, base + BMU_CTRL);
625
626 /* Wait for self clear */
627 while (readl(base + BMU_CTRL) & CORE_SW_RESET)
628 ;
629}
630
631/*
632 * Enabled a BMU block.
633 * @param[in] base BMU block base address
634 */
635void bmu_enable(void *base)
636{
637 writel(CORE_ENABLE, base + BMU_CTRL);
638}
639
640/*
641 * Disables a BMU block.
642 * @param[in] base BMU block base address
643 */
644static inline void bmu_disable(void *base)
645{
646 writel(CORE_DISABLE, base + BMU_CTRL);
647}
648
649/*
650 * Sets the configuration of a BMU block.
651 * @param[in] base BMU block base address
652 * @param[in] cfg BMU configuration
653 */
654static inline void bmu_set_config(void *base, struct bmu_cfg *cfg)
655{
656 writel(cfg->baseaddr, base + BMU_UCAST_BASE_ADDR);
657 writel(cfg->count & 0xffff, base + BMU_UCAST_CONFIG);
658 writel(cfg->size & 0xffff, base + BMU_BUF_SIZE);
659
660 /* Interrupts are never used */
661 writel(0x0, base + BMU_INT_ENABLE);
662}
663
664/*
665 * Initializes a BMU block.
666 * @param[in] base BMU block base address
667 * @param[in] cfg BMU configuration
668 */
669void bmu_init(void *base, struct bmu_cfg *cfg)
670{
671 bmu_disable(base);
672
673 bmu_set_config(base, cfg);
674
675 bmu_reset(base);
676}
677
678/**************************** GPI ***************************/
679/*
680 * Resets a GPI block.
681 * @param[in] base GPI base address
682 */
683static inline void gpi_reset(void *base)
684{
685 writel(CORE_SW_RESET, base + GPI_CTRL);
686}
687
688/*
689 * Enables a GPI block.
690 * @param[in] base GPI base address
691 */
692void gpi_enable(void *base)
693{
694 writel(CORE_ENABLE, base + GPI_CTRL);
695}
696
697/*
698 * Disables a GPI block.
699 * @param[in] base GPI base address
700 */
701void gpi_disable(void *base)
702{
703 writel(CORE_DISABLE, base + GPI_CTRL);
704}
705
706/*
707 * Sets the configuration of a GPI block.
708 * @param[in] base GPI base address
709 * @param[in] cfg GPI configuration
710 */
711static inline void gpi_set_config(void *base, struct gpi_cfg *cfg)
712{
713 writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_ALLOC_CTRL), base
714 + GPI_LMEM_ALLOC_ADDR);
715 writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_FREE_CTRL), base
716 + GPI_LMEM_FREE_ADDR);
717 writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_ALLOC_CTRL), base
718 + GPI_DDR_ALLOC_ADDR);
719 writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL), base
720 + GPI_DDR_FREE_ADDR);
721 writel(CBUS_VIRT_TO_PFE(CLASS_INQ_PKTPTR), base + GPI_CLASS_ADDR);
722 writel(DDR_HDR_SIZE, base + GPI_DDR_DATA_OFFSET);
723 writel(LMEM_HDR_SIZE, base + GPI_LMEM_DATA_OFFSET);
724 writel(0, base + GPI_LMEM_SEC_BUF_DATA_OFFSET);
725 writel(0, base + GPI_DDR_SEC_BUF_DATA_OFFSET);
726 writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, base + GPI_HDR_SIZE);
727 writel((DDR_BUF_SIZE << 16) | LMEM_BUF_SIZE, base + GPI_BUF_SIZE);
728
729 writel(((cfg->lmem_rtry_cnt << 16) | (GPI_DDR_BUF_EN << 1) |
730 GPI_LMEM_BUF_EN), base + GPI_RX_CONFIG);
731 writel(cfg->tmlf_txthres, base + GPI_TMLF_TX);
732 writel(cfg->aseq_len, base + GPI_DTX_ASEQ);
733
734 /*Make GPI AXI transactions non-bufferable */
735 writel(0x1, base + GPI_AXI_CTRL);
736}
737
738/*
739 * Initializes a GPI block.
740 * @param[in] base GPI base address
741 * @param[in] cfg GPI configuration
742 */
743void gpi_init(void *base, struct gpi_cfg *cfg)
744{
745 gpi_reset(base);
746
747 gpi_disable(base);
748
749 gpi_set_config(base, cfg);
750}
751
752/**************************** CLASSIFIER ***************************/
753/*
754 * Resets CLASSIFIER block.
755 */
756static inline void class_reset(void)
757{
758 writel(CORE_SW_RESET, CLASS_TX_CTRL);
759}
760
761/*
762 * Enables all CLASS-PE's cores.
763 */
764void class_enable(void)
765{
766 writel(CORE_ENABLE, CLASS_TX_CTRL);
767}
768
769/*
770 * Disables all CLASS-PE's cores.
771 */
772void class_disable(void)
773{
774 writel(CORE_DISABLE, CLASS_TX_CTRL);
775}
776
777/*
778 * Sets the configuration of the CLASSIFIER block.
779 * @param[in] cfg CLASSIFIER configuration
780 */
781static inline void class_set_config(struct class_cfg *cfg)
782{
783 if (PLL_CLK_EN == 0) {
784 /* Clock ratio: for 1:1 the value is 0 */
785 writel(0x0, CLASS_PE_SYS_CLK_RATIO);
786 } else {
787 /* Clock ratio: for 1:2 the value is 1 */
788 writel(0x1, CLASS_PE_SYS_CLK_RATIO);
789 }
790 writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, CLASS_HDR_SIZE);
791 writel(LMEM_BUF_SIZE, CLASS_LMEM_BUF_SIZE);
792 writel(CLASS_ROUTE_ENTRY_SIZE(CLASS_ROUTE_SIZE) |
793 CLASS_ROUTE_HASH_SIZE(cfg->route_table_hash_bits),
794 CLASS_ROUTE_HASH_ENTRY_SIZE);
795 writel(HASH_CRC_PORT_IP | QB2BUS_LE, CLASS_ROUTE_MULTI);
796
797 writel(cfg->route_table_baseaddr, CLASS_ROUTE_TABLE_BASE);
798 memset((void *)DDR_PFE_TO_VIRT(cfg->route_table_baseaddr), 0,
799 ROUTE_TABLE_SIZE);
800
801 writel(CLASS_PE0_RO_DM_ADDR0_VAL, CLASS_PE0_RO_DM_ADDR0);
802 writel(CLASS_PE0_RO_DM_ADDR1_VAL, CLASS_PE0_RO_DM_ADDR1);
803 writel(CLASS_PE0_QB_DM_ADDR0_VAL, CLASS_PE0_QB_DM_ADDR0);
804 writel(CLASS_PE0_QB_DM_ADDR1_VAL, CLASS_PE0_QB_DM_ADDR1);
805 writel(CBUS_VIRT_TO_PFE(TMU_PHY_INQ_PKTPTR), CLASS_TM_INQ_ADDR);
806
807 writel(23, CLASS_AFULL_THRES);
808 writel(23, CLASS_TSQ_FIFO_THRES);
809
810 writel(24, CLASS_MAX_BUF_CNT);
811 writel(24, CLASS_TSQ_MAX_CNT);
812
813 /*Make Class AXI transactions non-bufferable */
814 writel(0x1, CLASS_AXI_CTRL);
815
816 /*Make Util AXI transactions non-bufferable */
817 /*Util is disabled in U-boot, do it from here */
818 writel(0x1, UTIL_AXI_CTRL);
819}
820
821/*
822 * Initializes CLASSIFIER block.
823 * @param[in] cfg CLASSIFIER configuration
824 */
825void class_init(struct class_cfg *cfg)
826{
827 class_reset();
828
829 class_disable();
830
831 class_set_config(cfg);
832}
833
834/**************************** TMU ***************************/
835/*
836 * Enables TMU-PE cores.
837 * @param[in] pe_mask TMU PE mask
838 */
839void tmu_enable(u32 pe_mask)
840{
841 writel(readl(TMU_TX_CTRL) | (pe_mask & 0xF), TMU_TX_CTRL);
842}
843
844/*
845 * Disables TMU cores.
846 * @param[in] pe_mask TMU PE mask
847 */
848void tmu_disable(u32 pe_mask)
849{
850 writel(readl(TMU_TX_CTRL) & ~(pe_mask & 0xF), TMU_TX_CTRL);
851}
852
853/*
854 * Initializes TMU block.
855 * @param[in] cfg TMU configuration
856 */
857void tmu_init(struct tmu_cfg *cfg)
858{
859 int q, phyno;
860
861 /* keep in soft reset */
862 writel(SW_RESET, TMU_CTRL);
863
864 /*Make Class AXI transactions non-bufferable */
865 writel(0x1, TMU_AXI_CTRL);
866
867 /* enable EMAC PHY ports */
868 writel(0x3, TMU_SYS_GENERIC_CONTROL);
869
870 writel(750, TMU_INQ_WATERMARK);
871
872 writel(CBUS_VIRT_TO_PFE(EGPI1_BASE_ADDR + GPI_INQ_PKTPTR),
873 TMU_PHY0_INQ_ADDR);
874 writel(CBUS_VIRT_TO_PFE(EGPI2_BASE_ADDR + GPI_INQ_PKTPTR),
875 TMU_PHY1_INQ_ADDR);
876
877 writel(CBUS_VIRT_TO_PFE(HGPI_BASE_ADDR + GPI_INQ_PKTPTR),
878 TMU_PHY3_INQ_ADDR);
879 writel(CBUS_VIRT_TO_PFE(HIF_NOCPY_RX_INQ0_PKTPTR), TMU_PHY4_INQ_ADDR);
880 writel(CBUS_VIRT_TO_PFE(UTIL_INQ_PKTPTR), TMU_PHY5_INQ_ADDR);
881 writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL),
882 TMU_BMU_INQ_ADDR);
883
884 /* enabling all 10 schedulers [9:0] of each TDQ */
885 writel(0x3FF, TMU_TDQ0_SCH_CTRL);
886 writel(0x3FF, TMU_TDQ1_SCH_CTRL);
887 writel(0x3FF, TMU_TDQ3_SCH_CTRL);
888
889 if (PLL_CLK_EN == 0) {
890 /* Clock ratio: for 1:1 the value is 0 */
891 writel(0x0, TMU_PE_SYS_CLK_RATIO);
892 } else {
893 /* Clock ratio: for 1:2 the value is 1 */
894 writel(0x1, TMU_PE_SYS_CLK_RATIO);
895 }
896
897 /* Extra packet pointers will be stored from this address onwards */
898 debug("TMU_LLM_BASE_ADDR %x\n", cfg->llm_base_addr);
899 writel(cfg->llm_base_addr, TMU_LLM_BASE_ADDR);
900
901 debug("TMU_LLM_QUE_LEN %x\n", cfg->llm_queue_len);
902 writel(cfg->llm_queue_len, TMU_LLM_QUE_LEN);
903
904 writel(5, TMU_TDQ_IIFG_CFG);
905 writel(DDR_BUF_SIZE, TMU_BMU_BUF_SIZE);
906
907 writel(0x0, TMU_CTRL);
908
909 /* MEM init */
910 writel(MEM_INIT, TMU_CTRL);
911
912 while (!(readl(TMU_CTRL) & MEM_INIT_DONE))
913 ;
914
915 /* LLM init */
916 writel(LLM_INIT, TMU_CTRL);
917
918 while (!(readl(TMU_CTRL) & LLM_INIT_DONE))
919 ;
920
921 /* set up each queue for tail drop */
922 for (phyno = 0; phyno < 4; phyno++) {
923 if (phyno == 2)
924 continue;
925 for (q = 0; q < 16; q++) {
926 u32 qmax;
927
928 writel((phyno << 8) | q, TMU_TEQ_CTRL);
929 writel(BIT(22), TMU_TEQ_QCFG);
930
931 if (phyno == 3)
932 qmax = DEFAULT_TMU3_QDEPTH;
933 else
934 qmax = (q == 0) ? DEFAULT_Q0_QDEPTH :
935 DEFAULT_MAX_QDEPTH;
936
937 writel(qmax << 18, TMU_TEQ_HW_PROB_CFG2);
938 writel(qmax >> 14, TMU_TEQ_HW_PROB_CFG3);
939 }
940 }
941 writel(0x05, TMU_TEQ_DISABLE_DROPCHK);
942 writel(0, TMU_CTRL);
943}
944
945/**************************** HIF ***************************/
946/*
947 * Enable hif tx DMA and interrupt
948 */
949void hif_tx_enable(void)
950{
951 writel(HIF_CTRL_DMA_EN, HIF_TX_CTRL);
952}
953
954/*
955 * Disable hif tx DMA and interrupt
956 */
957void hif_tx_disable(void)
958{
959 u32 hif_int;
960
961 writel(0, HIF_TX_CTRL);
962
963 hif_int = readl(HIF_INT_ENABLE);
964 hif_int &= HIF_TXPKT_INT_EN;
965 writel(hif_int, HIF_INT_ENABLE);
966}
967
968/*
969 * Enable hif rx DMA and interrupt
970 */
971void hif_rx_enable(void)
972{
973 writel((HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
974}
975
976/*
977 * Disable hif rx DMA and interrupt
978 */
979void hif_rx_disable(void)
980{
981 u32 hif_int;
982
983 writel(0, HIF_RX_CTRL);
984
985 hif_int = readl(HIF_INT_ENABLE);
986 hif_int &= HIF_RXPKT_INT_EN;
987 writel(hif_int, HIF_INT_ENABLE);
988}
989
990/*
991 * Initializes HIF copy block.
992 */
993void hif_init(void)
994{
995 /* Initialize HIF registers */
996 writel(HIF_RX_POLL_CTRL_CYCLE << 16 | HIF_TX_POLL_CTRL_CYCLE,
997 HIF_POLL_CTRL);
998 /* Make HIF AXI transactions non-bufferable */
999 writel(0x1, HIF_AXI_CTRL);
1000}