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