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