1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** ThreadX Component */
16 /** */
17 /** Zynq UltraScale+ MPSoC / Cortex-A53-SMP - Low-level functions */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #include "tx_api.h"
23 #include "tx_zynqmp.h"
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <arm64_ghs.h>
27
28 /* Disable the data cache. By default the data cache is enabled. */
29 /*
30 #define TX_DCACHE_OFF
31 */
32
33 /* GIC base address (CBAR register) */
34 #define INIT_CBAR uint64_t CBAR = __MRS(__GENERIC_SYS_REG(3,1,15,3,0));
35
36 /* GIC Distributor Registers */
37 #define GIC_BASEADDR (CBAR+0x10000ull)
38 #define GIC_REG(offset) *((volatile uint32_t *)(GIC_BASEADDR+offset))
39
40 #define GICD_CTLR GIC_REG(0x000)
41 #define GICD_ISENABLER(i) GIC_REG(0x100 + 4*(i))
42 #define GICD_ICENABLER(i) GIC_REG(0x180 + 4*(i))
43 #define GICD_ICPENDR(i) GIC_REG(0x280 + 4*(i))
44 #define GICD_ISACTIVER(i) GIC_REG(0x300 + 4*(i))
45 #define GICD_ICACTIVER(i) GIC_REG(0x380 + 4*(i))
46 #define GICD_IPRIORITY(i) GIC_REG(0x400 + 4*(i))
47 #define GICD_IPRIORITYB(i) *((volatile uint8_t *)(GIC_BASEADDR+0x400+(i)))
48 #define GICD_ITARGETSR(i) GIC_REG(0x800 + 4*(i))
49 #define GICD_ITARGETSRB(i) *((volatile uint8_t *)(GIC_BASEADDR+0x800+(i)))
50 #define GICD_ICFGR(i) GIC_REG(0xc00 + 4*(i))
51
52 /* GIC CPU Registers */
53 #define GIC_CPU_BASEADDR (CBAR+0x20000ull)
54 #define GIC_CPU_REG(offset) *((volatile uint32_t *)(GIC_CPU_BASEADDR+offset))
55
56 #define GICC_CTLR GIC_CPU_REG(0x000)
57 #define GICC_PMR GIC_CPU_REG(0x004)
58 #define GICC_IAR GIC_CPU_REG(0x00c)
59 #define GICC_EOIR GIC_CPU_REG(0x010)
60
61 /* CRF_APB Clock and Reset control registers */
62 #define RST_FPD_APU *((volatile uint32_t *) 0xfd1a0104ull)
63
64
65 /* Interrupt handler table */
66 #define IRQ_ID_MAX 192
67 uint64_t _tx_platform_irq_handlers[2*IRQ_ID_MAX];
68
69 /* default handler */
tx_irq_default_handler(uint64_t id)70 static void tx_irq_default_handler(uint64_t id)
71 {
72 INIT_CBAR
73
74 /* unexpected interrupt... disable it! */
75 GICD_ICENABLER(id>>5) = 1 << (id & 0x1f);
76
77 #if 0 /* debug */
78 while(1);
79 #endif
80 }
81
82 /* inter-processor software interrupt */
tx_core_interrupt(void * data)83 static void tx_core_interrupt(void *data)
84 {
85 /* nothing to do, just used to wakeup the core */
86 }
87
88
89 /* Generic Timer Registers */
CNTFRQ_READ(void)90 static inline uint32_t CNTFRQ_READ(void)
91 {
92 return __MRS(__CNTFRQ_EL0);
93 }
94
CNTPCT_READ(void)95 static inline uint64_t CNTPCT_READ(void)
96 {
97 return __MRS(__CNTPCT_EL0);
98 }
99
CNTP_CTL_WRITE(uint32_t v)100 static inline void CNTP_CTL_WRITE(uint32_t v)
101 {
102 __MSR(__CNTPS_CTL_EL1, v);
103 }
104
CNTP_CVAL_READ(void)105 static inline uint64_t CNTP_CVAL_READ(void)
106 {
107 return __MRS(__CNTPS_CVAL_EL1);
108 }
109
CNTP_CVAL_WRITE(uint64_t v)110 static inline void CNTP_CVAL_WRITE(uint64_t v)
111 {
112 __MSR(__CNTPS_CVAL_EL1, v);
113 }
114
115 /* Generic Timer Interrupt */
116 #define GENERIC_TIMER_IRQ_ID 29
117
118
119 /* ThreadX timer interrupt */
120 extern void _tx_timer_interrupt(void);
121
122 static uint32_t tx_timer_delay;
123
tx_generic_timer_interrupt(void * data)124 static void tx_generic_timer_interrupt(void *data)
125 {
126 /* update next timer expiration */
127 CNTP_CVAL_WRITE(CNTP_CVAL_READ() + tx_timer_delay);
128
129 /* call ThreadX timer interrupt handler */
130 _tx_timer_interrupt();
131 }
132
133 #ifndef TX_DCACHE_OFF
134
135 /* MMU Tables */
136
137 #pragma ghs section bss=".mmu_tbl0"
138 static uint64_t mmu_tbl0[2];
139
140 #pragma ghs section bss=".mmu_tbl1"
141 static uint64_t mmu_tbl1[0x400];
142
143 #pragma ghs section bss=".mmu_tbl2"
144 static uint64_t mmu_tbl2[0x800];
145
146 #pragma ghs section bss=default
147
148 /* set MMU tables */
mmu_tbl_init(void)149 static void mmu_tbl_init(void)
150 {
151 int i;
152 uint64_t sect;
153 /*| | Memory Range | Definition in Translation Table |
154 *|-----------------------|-----------------------------|-----------------------------------|
155 *| DDR | 0x0000000000 - 0x007FFFFFFF | Normal write-back Cacheable |
156 *| PL | 0x0080000000 - 0x00BFFFFFFF | Strongly Ordered |
157 *| QSPI, lower PCIe | 0x00C0000000 - 0x00EFFFFFFF | Strongly Ordered |
158 *| Reserved | 0x00F0000000 - 0x00F7FFFFFF | Unassigned |
159 *| STM Coresight | 0x00F8000000 - 0x00F8FFFFFF | Strongly Ordered |
160 *| GIC | 0x00F9000000 - 0x00F91FFFFF | Strongly Ordered |
161 *| Reserved | 0x00F9200000 - 0x00FCFFFFFF | Unassigned |
162 *| FPS, LPS slaves | 0x00FD000000 - 0x00FFBFFFFF | Strongly Ordered |
163 *| CSU, PMU | 0x00FFC00000 - 0x00FFDFFFFF | Strongly Ordered |
164 *| TCM, OCM | 0x00FFE00000 - 0x00FFFFFFFF | Normal inner write-back cacheable |
165 *| Reserved | 0x0100000000 - 0x03FFFFFFFF | Unassigned |
166 *| PL, PCIe | 0x0400000000 - 0x07FFFFFFFF | Strongly Ordered |
167 *| DDR | 0x0800000000 - 0x0FFFFFFFFF | Normal inner write-back cacheable |
168 *| PL, PCIe | 0x1000000000 - 0xBFFFFFFFFF | Strongly Ordered |
169 *| Reserved | 0xC000000000 - 0xFFFFFFFFFF | Unassigned |*/
170
171 #define MMU_RESERVED 0
172 #define MMU_MEMORY 0x705
173 #define MMU_DEVICE (0x409 | (1ull << 53) | (1ull << 54))
174
175 /* 0x00_0000_0000 - 0x7F_FFFF_FFFF */
176 mmu_tbl0[0] = ((uint64_t) mmu_tbl1) + 0x3;
177 /* 0x80_0000_0000 - 0xFF_FFFF_FFFF */
178 mmu_tbl0[1] = ((uint64_t) mmu_tbl1) + 0x1000 + 0x3;
179
180 /* 0x00_0000_0000 - 0x00_FFFF_FFFF */
181 /* 2GB DDR, PL, other devices memory */
182 sect = (uint64_t) mmu_tbl2;
183 i = 0;
184 for (; i < 0x004; i++, sect += 0x1000) {
185 mmu_tbl1[i] = sect + 0x3;
186 }
187 /* 0x01_0000_0000 - 0x03_FFFF_FFFF */
188 /* 16GB Reserved */
189 sect = 0x100000000ull;
190 for (; i < 0x010; i++, sect += 0x40000000) {
191 mmu_tbl1[i] = sect + MMU_RESERVED;
192 }
193 /* 0x04_0000_0000 - 0x07_FFFF_FFFF */
194 /* 8GB PL, 8GB PCIe */
195 for (; i < 0x020; i++, sect += 0x40000000) {
196 mmu_tbl1[i] = sect + MMU_DEVICE;
197 }
198 /* 0x08_0000_0000 - 0x0F_7FFF_FFFF */
199 /* 2GB DDR */
200 #define DDR_1_SIZE 0x80000000u
201 #define DDR_1_REG (DDR_1_SIZE/0x40000000)
202 for (; i < (0x020 + DDR_1_REG); i++, sect += 0x40000000) {
203 mmu_tbl1[i] = sect + MMU_MEMORY;
204 }
205 #if DDR_1_REG < 0x20
206 /* reserved for region where DDR is absent */
207 for (; i < 0x040; i++, sect += 0x40000000) {
208 mmu_tbl1[i] = sect + MMU_RESERVED;
209 }
210 #endif
211 /* 0x10_0000_0000 - 0x7F_FFFF_FFFF */
212 /* 448GB PL */
213 for (; i < 0x200; i++, sect += 0x40000000) {
214 mmu_tbl1[i] = sect + MMU_DEVICE;
215 }
216 /* 0x80_0000_0000 - 0xBF_FFFF_FFFF */
217 /* 256GB PCIe */
218 for (; i < 0x300; i++, sect += 0x40000000) {
219 mmu_tbl1[i] = sect + MMU_DEVICE;
220 }
221 /* 0xC0_0000_0000 - 0xFF_FFFF_FFFF */
222 /* 256GB reserved */
223 for (; i < 0x400; i++, sect += 0x40000000) {
224 mmu_tbl1[i] = sect + MMU_RESERVED;
225 }
226
227 sect = 0;
228 i = 0;
229 /* 0x0000_0000 - 0x7FFF_FFFF */
230 /* 2GB DDR */
231 #define DDR_0_SIZE 0x80000000u
232 #define DDR_0_REG (DDR_0_SIZE/0x200000)
233 for (; i < DDR_0_REG; i++, sect += 0x200000) {
234 mmu_tbl2[i] = sect + MMU_MEMORY;
235 }
236 /* reserved for region where DDR is absent */
237 for (; i < 0x400; i++, sect += 0x200000) {
238 mmu_tbl2[i] = sect + MMU_RESERVED;
239 }
240 /* 0x8000_0000 - 0xBFFF_FFFF */
241 /* 1GB lower PL */
242 for (; i < 0x600; i++, sect += 0x200000) {
243 mmu_tbl2[i] = sect + MMU_DEVICE;
244 }
245 /* 0xC000_0000 - 0xDFFF_FFFF */
246 /* 512MB QSPI */
247 for (; i < 0x700; i++, sect += 0x200000) {
248 mmu_tbl2[i] = sect + MMU_DEVICE;
249 }
250 /* 0xE000_0000 - 0xEFFF_FFFF */
251 /* 256MB lower PCIe */
252 for (; i < 0x780; i++, sect += 0x200000) {
253 mmu_tbl2[i] = sect + MMU_DEVICE;
254 }
255 /* 0xF000_0000 - 0xF7FF_FFFF */
256 /* 128MB Reserved */
257 for (; i < 0x7c0; i++, sect += 0x200000) {
258 mmu_tbl2[i] = sect + MMU_RESERVED;
259 }
260 /* 0xF800_0000 - 0xFFDF_FFFF */
261 /* set all range as device */
262 for (; i < 0x7ff; i++, sect += 0x200000) {
263 mmu_tbl2[i] = sect + MMU_DEVICE;
264 }
265 /* 0xFFE0_0000 - 0xFFFF_FFFF*/
266 /* 2MB OCM/TCM */
267 for (; i < 0x800; i++, sect += 0x200000) {
268 mmu_tbl2[i] = sect + MMU_MEMORY;
269 }
270 }
271
272 #endif /* !TX_DCACHE_OFF */
273
274 /* enable MMU and caches */
tx_caches_enable(void)275 static void tx_caches_enable(void)
276 {
277 #ifndef TX_DCACHE_OFF
278 /* set level 0 TTBR0_EL3 */
279 __DSB_OPT(__BARRIER_SY);
280 __MSR(__TTBR0_EL3, (uint64_t) mmu_tbl0);
281 /* set memory attributes */
282 __MSR(__MAIR_EL3, 0x000000BB0400FF44ull);
283 /* set TCR_EL3 */
284 __MSR(__TCR_EL3, 0x80823518ull);
285
286 /* set SCTLR_EL3: enable mmu and caches + SP alignment check */
287 __MSR(__SCTLR_EL3, __MRS(__SCTLR_EL3) | 0x100d);
288
289 __DSB_OPT(__BARRIER_SY);
290 __ISB();
291 #else
292 /* set SCTLR_EL3: enable instruction cache + SP alignment check */
293 __MSR(__SCTLR_EL3, __MRS(__SCTLR_EL3) | 0x1008);
294 #endif
295 }
296
297
298 /**************************************************************************/
299 /* */
300 /* FUNCTION RELEASE */
301 /* */
302 /* _tx_platform_initialize_low_level */
303 /* Zynq UltraScale+ MPSoC Cortex-A53-SMP/GHS */
304 /* 6.1 */
305 /* AUTHOR */
306 /* */
307 /* William E. Lamie, Microsoft Corporation */
308 /* */
309 /* DESCRIPTION */
310 /* */
311 /* This function initializes the Interrupt Controller and configures */
312 /* the Generic Timer for the ThreadX periodic timer interrupt source */
313 /* */
314 /* INPUT */
315 /* */
316 /* None */
317 /* */
318 /* OUTPUT */
319 /* */
320 /* None */
321 /* */
322 /* CALLS */
323 /* */
324 /* CALLED BY */
325 /* */
326 /* _tx_initialize_low_level ThreadX low level initialization */
327 /* */
328 /* RELEASE HISTORY */
329 /* */
330 /* DATE NAME DESCRIPTION */
331 /* */
332 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
333 /* */
334 /**************************************************************************/
_tx_platform_initialize_low_level(void)335 void _tx_platform_initialize_low_level(void)
336 {
337 INIT_CBAR
338 int i;
339
340 #ifndef TX_DCACHE_OFF
341 /* initialize MMU tables */
342 mmu_tbl_init();
343 #endif
344 /* enable data and instruction caches */
345 tx_caches_enable();
346
347 /* set default interrupt handlers */
348 for (i=0; i<IRQ_ID_MAX; i++)
349 {
350 _tx_platform_irq_handlers[2*i] = (uint64_t) tx_irq_default_handler;
351 _tx_platform_irq_handlers[2*i+1] = (uint64_t) i;
352 }
353
354 /* initialize the interrupt controller: */
355 /* enable global distributor */
356 GICD_CTLR |= 1;
357 /* disable all interrupts */
358 for (i=0; i<(IRQ_ID_MAX + 31)/32; i++)
359 {
360 GICD_ICENABLER(i) = ~0;
361 GICD_ICPENDR(i) = ~0;
362 GICD_ICACTIVER(i) = ~0;
363 }
364 /* redirect all interrupts to cpu #0 */
365 for (i=8; i<(IRQ_ID_MAX + 3)/4; i++)
366 {
367 GICD_ITARGETSR(i) = 0x01010101;
368 }
369 /* set default priority to 0 */
370 for (i=0; i<(IRQ_ID_MAX + 3)/4; i++)
371 {
372 GICD_IPRIORITY(i) = 0x00000000;
373 }
374 /* set default configuration as level-sensitive */
375 for (i=2; i<(IRQ_ID_MAX + 15)/16; i++)
376 {
377 GICD_ICFGR(i) &= 0x55555555;
378 }
379
380 /* initialize the interrupt controller: */
381 /* enable physical cpu interface */
382 GICC_CTLR |= 1;
383 /* enable all priorities */
384 GICC_PMR = 0xff;
385
386 /* Use the Generic Timer for generating clock ticks: */
387 /* compute tick delay from counter frequency */
388 tx_timer_delay = CNTFRQ_READ() / TX_TIMER_TICKS_PER_SECOND;
389 /* set timer expiration from current counter value */
390 CNTP_CVAL_WRITE(CNTPCT_READ() + tx_timer_delay);
391 /* configure CNTP_CTL to enable timer interrupts */
392 CNTP_CTL_WRITE(1);
393 /* install timer interrupt handler */
394 tx_zynqmp_irq_enable(GENERIC_TIMER_IRQ_ID, tx_generic_timer_interrupt, NULL);
395
396 /* set handler for software interrupt 0 */
397 tx_zynqmp_irq_enable(0, tx_core_interrupt, NULL);
398
399 /* release reset for cores 1-(MAX_CORES-1) */
400 RST_FPD_APU &= ~((1 << TX_THREAD_SMP_MAX_CORES) - 2);
401 }
402
403
404 /**************************************************************************/
405 /* */
406 /* FUNCTION RELEASE */
407 /* */
408 /* _tx_platform_smp_initialize_low_level */
409 /* Zynq UltraScale+ MPSoC Cortex-A53-SMP/GHS */
410 /* 6.1 */
411 /* AUTHOR */
412 /* */
413 /* William E. Lamie, Microsoft Corporation */
414 /* */
415 /* DESCRIPTION */
416 /* */
417 /* This function initializes the cores 1-3 for SMP processing */
418 /* */
419 /* INPUT */
420 /* */
421 /* None */
422 /* */
423 /* OUTPUT */
424 /* */
425 /* None */
426 /* */
427 /* CALLS */
428 /* */
429 /* None */
430 /* */
431 /* CALLED BY */
432 /* */
433 /* _boot_smp cores 1-3 startup code */
434 /* */
435 /* RELEASE HISTORY */
436 /* */
437 /* DATE NAME DESCRIPTION */
438 /* */
439 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
440 /* */
441 /**************************************************************************/
_tx_platform_smp_initialize_low_level(void)442 void _tx_platform_smp_initialize_low_level(void)
443 {
444 INIT_CBAR
445
446 /* enable data and instruction caches */
447 tx_caches_enable();
448
449 /* initialize the interrupt controller: */
450 /* enable physical cpu interface */
451 GICC_CTLR |= 1;
452 /* enable all priorities */
453 GICC_PMR = 0xff;
454 }
455
456
457 /**************************************************************************/
458 /* */
459 /* FUNCTION RELEASE */
460 /* */
461 /* tx_zynqmp_irq_enable Zynq UltraScale+ MPSoC Cortex-A53-SMP/GHS */
462 /* 6.1 */
463 /* AUTHOR */
464 /* */
465 /* William E. Lamie, Microsoft Corporation */
466 /* */
467 /* DESCRIPTION */
468 /* */
469 /* This function attachs a handler to an interrupt and enables */
470 /* the interrupt. */
471 /* */
472 /* INPUT */
473 /* */
474 /* id The ID of the interrupt */
475 /* handler The interrupt handler */
476 /* data The data to pass to the */
477 /* handler. */
478 /* */
479 /* OUTPUT */
480 /* */
481 /* None */
482 /* */
483 /* CALLS */
484 /* */
485 /* None */
486 /* */
487 /* CALLED BY */
488 /* */
489 /* Application */
490 /* */
491 /* RELEASE HISTORY */
492 /* */
493 /* DATE NAME DESCRIPTION */
494 /* */
495 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
496 /* */
497 /**************************************************************************/
tx_zynqmp_irq_enable(unsigned id,void (* handler)(void *),void * data)498 void tx_zynqmp_irq_enable(unsigned id, void (*handler)(void *), void *data)
499 {
500 INIT_CBAR
501
502 if (id >= IRQ_ID_MAX)
503 {
504 return;
505 }
506
507 /* set handler */
508 _tx_platform_irq_handlers[2*id] = (uint64_t) handler;
509 _tx_platform_irq_handlers[2*id+1] = (uint64_t) data;
510 __DSB_OPT(__BARRIER_SY); // ensure we're in sync...
511
512 /* enable interrupt */
513 GICD_ISENABLER(id>>5) = 1 << (id & 0x1f);
514 }
515
516
517 /**************************************************************************/
518 /* */
519 /* FUNCTION RELEASE */
520 /* */
521 /* tx_zynqmp_irq_disable Zynq UltraScale+ MPSoC Cortex-A53-SMP/GHS */
522 /* 6.1 */
523 /* AUTHOR */
524 /* */
525 /* William E. Lamie, Microsoft Corporation */
526 /* */
527 /* DESCRIPTION */
528 /* */
529 /* This function disables an interrupt and removes the previously */
530 /* attached handler */
531 /* */
532 /* INPUT */
533 /* */
534 /* id The ID of the interrupt */
535 /* */
536 /* OUTPUT */
537 /* */
538 /* None */
539 /* */
540 /* CALLS */
541 /* */
542 /* None */
543 /* */
544 /* CALLED BY */
545 /* */
546 /* Application */
547 /* */
548 /* RELEASE HISTORY */
549 /* */
550 /* DATE NAME DESCRIPTION */
551 /* */
552 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
553 /* */
554 /**************************************************************************/
tx_zynqmp_irq_disable(unsigned id)555 void tx_zynqmp_irq_disable(unsigned id)
556 {
557 INIT_CBAR
558
559 if (id >= IRQ_ID_MAX)
560 {
561 return;
562 }
563
564 /* disable interrupt */
565 GICD_ICENABLER(id>>5) = 1 << (id & 0x1f);
566
567 /* clear pending state */
568 GICD_ICPENDR(id>>5) = 1 << (id & 0x1f);
569
570 /* ensure the interrupt is not still active before returning */
571 while (GICD_ISACTIVER(id>>5) & (1 << (id & 0x1f)))
572 {
573 }
574
575 /* restore default handler */
576 _tx_platform_irq_handlers[2*id] = (uint64_t) tx_irq_default_handler;
577 _tx_platform_irq_handlers[2*id+1] = (uint64_t) id;
578 }
579
580
581 /**************************************************************************/
582 /* */
583 /* FUNCTION RELEASE */
584 /* */
585 /* tx_zynqmp_irq_priority Zynq UltraScale+ MPSoC Cortex-A53-SMP/GHS */
586 /* 6.1 */
587 /* AUTHOR */
588 /* */
589 /* William E. Lamie, Microsoft Corporation */
590 /* */
591 /* DESCRIPTION */
592 /* */
593 /* This function sets the priority of an interrupt */
594 /* */
595 /* INPUT */
596 /* */
597 /* id The ID of the interrupt */
598 /* prio The interrupt priority 0-255 */
599 /* */
600 /* OUTPUT */
601 /* */
602 /* None */
603 /* */
604 /* CALLS */
605 /* */
606 /* None */
607 /* */
608 /* CALLED BY */
609 /* */
610 /* Application */
611 /* */
612 /* RELEASE HISTORY */
613 /* */
614 /* DATE NAME DESCRIPTION */
615 /* */
616 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
617 /* */
618 /**************************************************************************/
tx_zynqmp_irq_priority(unsigned id,unsigned prio)619 void tx_zynqmp_irq_priority(unsigned id, unsigned prio)
620 {
621 INIT_CBAR
622
623 if (id >= IRQ_ID_MAX)
624 {
625 return;
626 }
627
628 /* set priority */
629 GICD_IPRIORITYB(id) = (uint8_t) prio;
630 }
631
632
633 /**************************************************************************/
634 /* */
635 /* FUNCTION RELEASE */
636 /* */
637 /* tx_zynqmp_irq_config Zynq UltraScale+ MPSoC Cortex-A53/GHS */
638 /* 6.1 */
639 /* AUTHOR */
640 /* */
641 /* William E. Lamie, Microsoft Corporation */
642 /* */
643 /* DESCRIPTION */
644 /* */
645 /* This function configures an interrupt as level-sensitive or */
646 /* edge-triggered */
647 /* Only SPI interrupts (ID >= 32) can be configured */
648 /* */
649 /* INPUT */
650 /* */
651 /* id The ID of the interrupt */
652 /* edge Configure the interrupt as */
653 /* level-sensitive (0) or */
654 /* edge-triggered (non 0) */
655 /* */
656 /* OUTPUT */
657 /* */
658 /* None */
659 /* */
660 /* CALLS */
661 /* */
662 /* None */
663 /* */
664 /* CALLED BY */
665 /* */
666 /* Application */
667 /* */
668 /* RELEASE HISTORY */
669 /* */
670 /* DATE NAME DESCRIPTION */
671 /* */
672 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
673 /* */
674 /**************************************************************************/
tx_zynqmp_irq_config(unsigned id,int edge)675 void tx_zynqmp_irq_config(unsigned id, int edge)
676 {
677 INIT_CBAR
678 TX_INTERRUPT_SAVE_AREA
679 uint32_t value;
680
681 if (id < 32 || id >= IRQ_ID_MAX)
682 {
683 return;
684 }
685
686 TX_DISABLE
687
688 /* set edge or level sensitive */
689 value = GICD_ICFGR(id>>4);
690 if (edge)
691 {
692 value |= 2 << (2*(id & 0xf));
693 }
694 else
695 {
696 value &= ~(2 << (2*(id & 0xf)));
697 }
698 GICD_ICFGR(id>>4) = value;
699
700 TX_RESTORE
701 }
702
703
704 /**************************************************************************/
705 /* */
706 /* FUNCTION RELEASE */
707 /* */
708 /* tx_zynqmp_irq_smp_core Zynq UltraScale+ MPSoC Cortex-A53/GHS */
709 /* 6.1 */
710 /* AUTHOR */
711 /* */
712 /* William E. Lamie, Microsoft Corporation */
713 /* */
714 /* DESCRIPTION */
715 /* */
716 /* This function selects on which core an interrupt will be handled */
717 /* Only SPI interrupts (ID >= 32) can be configured */
718 /* */
719 /* INPUT */
720 /* */
721 /* irq_id The ID of the interrupt */
722 /* core_id The ID of the core 0-3 */
723 /* */
724 /* OUTPUT */
725 /* */
726 /* None */
727 /* */
728 /* CALLS */
729 /* */
730 /* None */
731 /* */
732 /* CALLED BY */
733 /* */
734 /* Application */
735 /* */
736 /* RELEASE HISTORY */
737 /* */
738 /* DATE NAME DESCRIPTION */
739 /* */
740 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
741 /* */
742 /**************************************************************************/
tx_zynqmp_irq_smp_core(unsigned irq_id,unsigned core_id)743 void tx_zynqmp_irq_smp_core(unsigned irq_id, unsigned core_id)
744 {
745 INIT_CBAR
746
747 if (irq_id < 32 || irq_id >= IRQ_ID_MAX || core_id >= TX_THREAD_SMP_MAX_CORES)
748 {
749 return;
750 }
751
752 /* set interrupt processor target */
753 GICD_ITARGETSRB(irq_id) = 1 << core_id;
754 }
755
756
757 /**************************************************************************/
758 /* */
759 /* FUNCTION RELEASE */
760 /* */
761 /* tx_zynqmp_udelay Zynq UltraScale+ MPSoC Cortex-A53/GHS */
762 /* 6.1 */
763 /* AUTHOR */
764 /* */
765 /* William E. Lamie, Microsoft Corporation */
766 /* */
767 /* DESCRIPTION */
768 /* */
769 /* This function waits for a given small delay expressed in */
770 /* microseconds. */
771 /* */
772 /* INPUT */
773 /* */
774 /* usecs The number of microseconds */
775 /* to wait for */
776 /* */
777 /* OUTPUT */
778 /* */
779 /* None */
780 /* */
781 /* CALLS */
782 /* */
783 /* None */
784 /* */
785 /* CALLED BY */
786 /* */
787 /* Application */
788 /* */
789 /* RELEASE HISTORY */
790 /* */
791 /* DATE NAME DESCRIPTION */
792 /* */
793 /* 09-30-2020 William E. Lamie Initial Version 6.1 */
794 /* */
795 /**************************************************************************/
tx_zynqmp_udelay(unsigned usecs)796 void tx_zynqmp_udelay(unsigned usecs)
797 {
798 uint64_t t;
799 /* get current time */
800 t = CNTPCT_READ();
801 /* compute expiration time */
802 t += ((uint64_t) usecs * CNTFRQ_READ()) / 1000000U;
803 while ((int64_t) (t - CNTPCT_READ()) > 0) {}
804 }
805