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