96908e1f6a0a45b55938a6844c8c1d46b2b95c74
1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 *
5 * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <stdio.h>
32 #include <string.h>
33 #include "machine.h"
34 #include "openamp/env.h"
35 unsigned char ARM_AR_ISR_IRQ_Data[ARM_AR_ISR_STACK_SIZE];
36 unsigned char ARM_AR_ISR_FIQ_Data[ARM_AR_ISR_STACK_SIZE];
37 unsigned char ARM_AR_ISR_SUP_Stack[ARM_AR_ISR_STACK_SIZE];
38 unsigned char ARM_AR_ISR_SYS_Stack[ARM_AR_ISR_STACK_SIZE];
40 static inline unsigned int get_cpu_id_arm(void);
42 int zc702evk_gic_initialize()
43 {
45 unsigned long reg_val;
47 /* Disable architecture interrupts (IRQ and FIQ)
48 * before initialization */
49 ARM_AR_CPSR_CXSF_READ(®_val);
50 reg_val |= (0x02 << 6);
51 ARM_AR_CPSR_CXSF_WRITE(reg_val);
53 zc702evk_gic_pr_int_initialize();
55 /* Enable architecture Interrupts */
56 ARM_AR_CPSR_CXSF_READ(®_val);
57 reg_val &= ~(0x02 << 6);
58 ARM_AR_CPSR_CXSF_WRITE(reg_val);
60 return 0;
61 }
63 /* Only applicable for remote/slave node */
64 void zc702evk_gic_pr_int_initialize(void)
65 {
67 /* Disable the GIC controller */
68 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_CTRL, 0x00000000);
70 /* Enable the interrupt distributor controller */
71 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_CTRL, INT_DIST_ENABLE);
73 /* Secondary cores just need to disable their private interrupts */
74 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_ENABLE_CLEAR + 0x00,
75 0xffffffff);
76 /* 0 - 31 */
78 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_CONFIG + 0x00, 0xAAAAAAAA);
79 /* 0 - 15 */
80 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_CONFIG + 0x04, 0xAAAAAAAA);
82 /* Disable the CPU Interface */
83 MEM_WRITE32(INT_GIC_CPU_BASE + INT_GIC_CPU_CTRL, 0x00000000);
85 /* Allow interrupts with more priority (i.e. lower number) than FF */
86 MEM_WRITE32(INT_GIC_CPU_BASE + INT_GIC_CPU_PRIORITY, 0x000000FF);
88 /* No binary point */
89 MEM_WRITE32(INT_GIC_CPU_BASE + INT_GIC_CPU_POINT, 0x00000000);
91 /* Enable the CPU Interface */
92 MEM_WRITE32(INT_GIC_CPU_BASE + INT_GIC_CPU_CTRL, INT_CPU_ENABLE);
93 }
95 int platform_interrupt_enable(unsigned int vector_id, unsigned int polarity,
96 unsigned int priority)
97 {
98 unsigned long reg_offset;
99 unsigned long bit_shift;
100 unsigned long temp32 = 0;
101 unsigned long targ_cpu;
103 temp32 = get_cpu_id_arm();
105 /* Determine the necessary bit shift in this target / priority register
106 for this interrupt vector ID */
107 bit_shift = ((vector_id) % 4) * 8;
109 /* Build a target value based on the bit shift calculated above and the CPU core
110 that this code is executing on */
111 targ_cpu = (1 << temp32) << bit_shift;
113 /* Determine the Global interrupt controller target / priority register
114 offset for this interrupt vector ID
115 NOTE: Each target / priority register supports 4 interrupts */
116 reg_offset = ((vector_id) / 4) * 4;
118 /* Read-modify-write the priority register for this interrupt */
119 temp32 = MEM_READ32(INT_GIC_DIST_BASE + INT_GIC_DIST_PRI + reg_offset);
121 /* Set new priority. */
122 temp32 |= (priority << (bit_shift + 4));
123 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_PRI + reg_offset, temp32);
125 /* Read-modify-write the target register for this interrupt to allow this
126 cpu to accept this interrupt */
127 temp32 =
128 MEM_READ32(INT_GIC_DIST_BASE + INT_GIC_DIST_TARGET + reg_offset);
129 temp32 |= targ_cpu;
130 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_TARGET + reg_offset,
131 temp32);
133 /* Determine the Global interrupt controller enable set register offset
134 for this vector ID
135 NOTE: There are 32 interrupts in each enable set register */
136 reg_offset = (vector_id / 32) * 4;
138 /* Write to the appropriate bit in the enable set register for this
139 vector ID to enable the interrupt */
141 temp32 = (1UL << (vector_id - (reg_offset * 0x08)));
142 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_ENABLE_SET + reg_offset,
143 temp32);
145 /* Return the vector ID */
146 return (vector_id);
147 }
149 int platform_interrupt_disable(unsigned int vector_id)
150 {
151 unsigned long reg_offset;
152 unsigned long bit_shift;
153 unsigned long temp32 = 0;
154 unsigned long targ_cpu;
156 temp32 = get_cpu_id_arm();
158 /* Determine the Global interrupt controller enable set register offset
159 for this vector ID
160 NOTE: There are 32 interrupts in each enable set register */
161 reg_offset = (vector_id / 32) * 4;
163 /* Write to the appropriate bit in the enable clear register for this
164 vector ID to disable the interrupt */
166 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_ENABLE_CLEAR + reg_offset,
167 (1UL << (vector_id - (reg_offset * 0x08))));
169 /* Determine the Global interrupt controller target register offset for
170 this interrupt vector ID
171 NOTE: Each target register supports 4 interrupts */
172 reg_offset = (vector_id / 4) * 4;
174 /* Determine the necessary bit shift in this target register for this
175 vector ID */
176 bit_shift = (vector_id % 4) * 8;
178 /* Build a value based on the bit shift calculated above and the CPU core
179 that this code is executing on */
180 targ_cpu = (1 << temp32) << bit_shift;
182 /* Read-modify-write the target register for this interrupt and remove this cpu from
183 accepting this interrupt */
184 temp32 =
185 MEM_READ32(INT_GIC_DIST_BASE + INT_GIC_DIST_TARGET + reg_offset);
186 temp32 &= ~targ_cpu;
188 MEM_WRITE32(INT_GIC_DIST_BASE + INT_GIC_DIST_TARGET + reg_offset,
189 temp32);
191 /* Return the vector ID */
192 return (vector_id);
193 }
195 void arm_arch_install_isr_vector_table(unsigned long addr)
196 {
197 unsigned long arch = 0;
198 void *dst_addr;
200 /* Assign destination address of vector table to RAM address */
201 dst_addr = (void *)addr;
202 /* Read Main ID Register (MIRD) */
203 ARM_AR_CP_READ(p15, 0, &arch, c0, c0, 0);
205 /* Check if Cortex-A series of ARMv7 architecture. */
206 if (((arch & MIDR_ARCH_MASK) >> 16) == MIDR_ARCH_ARMV7
207 && ((arch & MIDR_PART_NO_MASK) >> 4)
208 == MIDR_PART_NO_CORTEX_A) {
209 /* Set vector base address */
210 ARM_AR_CP_WRITE(p15, 0, dst_addr, c12, c0, 0);
211 ARM_AR_NOP_EXECUTE();
212 ARM_AR_NOP_EXECUTE();
213 ARM_AR_NOP_EXECUTE();
214 }
215 }
217 extern void bm_env_isr(int vector);
219 /* IRQ handler */
220 void __attribute__ ((interrupt("IRQ"))) __cs3_isr_irq()
221 {
222 unsigned long raw_irq;
223 int irq_vector;
225 /* Read the Interrupt ACK register */
226 raw_irq = MEM_READ32(INT_GIC_CPU_BASE + INT_GIC_CPU_ACK);
228 /* mask interrupt to get vector */
229 irq_vector = raw_irq & INT_ACK_MASK;
231 bm_env_isr(irq_vector);
233 /* Clear the interrupt */
234 MEM_WRITE32(INT_GIC_CPU_BASE + INT_GIC_CPU_ENDINT, raw_irq);
235 }
237 /* FIQ Handler */
238 void __attribute__ ((interrupt("FIQ"))) __cs3_isr_fiq()
239 {
240 while (1) ;
241 }
243 static inline unsigned int get_cpu_id_arm(void)
244 {
245 unsigned long cpu_id = 0;
247 asm volatile ("MRC p15 ,"
248 "0," "%0," "c0," "c0," "5":[cpu_id] "=&r"(cpu_id)
249 : /* No inputs */ );
251 /*
252 * Return cpu id to caller, extract last two bits from Multiprocessor
253 * Affinity Register */
254 return (cpu_id & 0x03);
255 }
257 int old_value = 0;
259 void restore_global_interrupts()
260 {
261 ARM_AR_INT_BITS_SET(old_value);
262 }
264 void disable_global_interrupts()
265 {
266 int value = 0;
267 ARM_AR_INT_BITS_GET(&value);
268 if (value != old_value) {
269 ARM_AR_INT_BITS_SET(ARM_AR_INTERRUPTS_DISABLE_BITS);
270 old_value = value;
271 }
272 }
274 void init_arm_stacks(void)
275 {
277 /* Switch to IRQ mode (keeping interrupts disabled) */
278 ARM_AR_CPSR_C_WRITE(ARM_AR_INT_CPSR_IRQ_MODE |
279 ARM_AR_INTERRUPTS_DISABLE_BITS);
281 /* Set IRQ stack pointer */
282 ARM_AR_SP_WRITE(ARM_GE_STK_ALIGN
283 (&ARM_AR_ISR_IRQ_Data[ARM_AR_ISR_STACK_SIZE - 1]));
285 /* Switch to FIQ mode (keeping interrupts disabled) */
286 ARM_AR_CPSR_C_WRITE(ARM_AR_INT_CPSR_FIQ_MODE |
287 ARM_AR_INTERRUPTS_DISABLE_BITS);
289 /* Set FIQ stack pointer */
290 ARM_AR_SP_WRITE(ARM_GE_STK_ALIGN
291 (ARM_AR_ISR_FIQ_Data[ARM_AR_ISR_STACK_SIZE - 1]));
293 /* Switch to Supervisor mode (keeping interrupts disabled) */
294 ARM_AR_CPSR_C_WRITE(ARM_AR_INT_CPSR_SUP_MODE |
295 ARM_AR_INTERRUPTS_DISABLE_BITS);
297 /* Set Supervisor stack pointer */
298 ARM_AR_SP_WRITE(ARM_GE_STK_ALIGN
299 (&ARM_AR_ISR_SUP_Stack[ARM_AR_ISR_STACK_SIZE - 1]));
301 /* Switch to System mode (keeping interrupts disabled) */
302 ARM_AR_CPSR_C_WRITE(ARM_AR_INT_CPSR_SYS_DISABLED);
303 }
305 /***********************************************************************
306 *
307 * arm_ar_mem_enable_mmu
308 *
309 * Enables MMU and MAP the required memory regions.
310 *
311 ***********************************************************************/
312 int arm_ar_mem_enable_mmu()
313 {
314 unsigned int cp15_ctrl_val;
315 void *tlb_mem = (void *)TLB_MEM_START;
317 ARM_AR_MEM_CACHE_ALL_INVALIDATE();
319 /* Read current CP15 control register value */
320 ARM_AR_CP_READ(ARM_AR_CP15, 0, &cp15_ctrl_val, ARM_AR_C1, ARM_AR_C0, 0);
322 /* Clear the V bit(13) to set Normal exception vectors range. */
323 cp15_ctrl_val &= ~(ARM_AR_MEM_CP15_CTRL_V);
325 /* Clear the alignment bit(1) to enable unaligned memory accesses */
326 cp15_ctrl_val &= ~(ARM_AR_MEM_CP15_CTRL_A);
328 /* Write updated CP15 control register value */
329 ARM_AR_CP_WRITE(ARM_AR_CP15, 0, cp15_ctrl_val, ARM_AR_C1, ARM_AR_C0, 0);
331 ARM_AR_NOP_EXECUTE();
332 ARM_AR_NOP_EXECUTE();
333 ARM_AR_NOP_EXECUTE();
335 /* Check alignment of available memory pointer */
336 if (!(MEM_ALIGNED_CHECK(tlb_mem, ARM_AR_MEM_TTB_SIZE))) {
337 /* Align the pointer to the required boundary */
338 tlb_mem = MEM_PTR_ALIGN(tlb_mem, ARM_AR_MEM_TTB_SIZE);
339 }
341 /* Clear the entire translation table */
342 memset(tlb_mem, 0x00, ARM_AR_MEM_TTB_SIZE);
344 /* Set translation table base address */
345 ARM_AR_CP_WRITE(ARM_AR_CP15, 0, tlb_mem, ARM_AR_C2, ARM_AR_C0, 0);
347 ARM_AR_CP_READ(ARM_AR_CP15, 0, &cp15_ctrl_val, ARM_AR_C2, ARM_AR_C0, 0);
349 /* Map the given memory regions here */
350 arm_ar_map_mem_region(ELF_START, ELF_START, ELF_END, 0, WRITEBACK);
351 arm_ar_map_mem_region((unsigned int)tlb_mem, (unsigned int)tlb_mem,
352 TLB_SIZE, 0, NOCACHE);
353 arm_ar_map_mem_region(PERIPH_BASE, PERIPH_BASE,
354 PERIPH_SIZE, 1, NOCACHE);
355 arm_ar_map_mem_region(SLCR_BASE, SLCR_BASE, SLCR_SIZE, 1, NOCACHE);
356 arm_ar_map_mem_region(CPU_BASE, CPU_BASE, CPU_SIZE, 1, NOCACHE);
358 /* Set the domain access for domain D0 */
359 ARM_AR_CP_WRITE(ARM_AR_CP15, 0, ARM_AR_MEM_DOMAIN_D0_MANAGER_ACCESS,
360 ARM_AR_C3, ARM_AR_C0, 0);
362 ARM_AR_CP_READ(ARM_AR_CP15, 0, &cp15_ctrl_val, ARM_AR_C3, ARM_AR_C0, 0);
364 /* Invalidate all TLB entries before enabling the MMU */
365 ARM_AR_CP_WRITE(ARM_AR_CP15, 0, 0, ARM_AR_C8, ARM_AR_C7, 0);
367 /* Read current CP15 control register value */
368 ARM_AR_CP_READ(ARM_AR_CP15, 0, &cp15_ctrl_val, ARM_AR_C1, ARM_AR_C0, 0);
370 /* Set instruction cache enable / data cache enable / MMU enable bits */
371 cp15_ctrl_val |= (ARM_AR_MEM_CP15_CTRL_I | ARM_AR_MEM_CP15_CTRL_C
372 | ARM_AR_MEM_CP15_CTRL_M | ARM_AR_MEM_CP15_CTRL_Z);
374 /* Write updated CP15 control register value */
375 ARM_AR_CP_WRITE(ARM_AR_CP15, 0, cp15_ctrl_val, ARM_AR_C1, ARM_AR_C0, 0);
377 ARM_AR_NOP_EXECUTE();
378 ARM_AR_NOP_EXECUTE();
379 ARM_AR_NOP_EXECUTE();
381 return 0;
382 }
384 /***********************************************************************
385 *
386 *
387 * arm_ar_map_mem_region
388 *
389 *
390 * This function sets-up the region of memory based on the given
391 * attributes
393 *
394 * @param vrt_addr - virtual address of region
395 * @param phy_addr - physical address of region
396 * @parma size - size of region
397 * @param is_mem_mapped - memory mapped or not
399 * @param cache_type - cache type of region
400 *
401 *
402 * OUTPUTS
403 *
404 * None
405 *
406 ***********************************************************************/
407 void arm_ar_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr,
408 unsigned int size, int is_mem_mapped,
409 CACHE_TYPE cache_type)
410 {
411 unsigned int section_offset;
412 unsigned int ttb_offset;
413 unsigned int ttb_value;
414 unsigned int ttb_base;
416 /* Read ttb base address */
417 ARM_AR_CP_READ(ARM_AR_CP15, 0, &ttb_base, ARM_AR_C2, ARM_AR_C0, 0);
419 /* Ensure the virtual and physical addresses are aligned on a
420 section boundary */
421 vrt_addr &= ARM_AR_MEM_TTB_SECT_SIZE_MASK;
422 phy_addr &= ARM_AR_MEM_TTB_SECT_SIZE_MASK;
424 /* Loop through entire region of memory (one MMU section at a time).
425 Each section requires a TTB entry. */
426 for (section_offset = 0; section_offset < size; section_offset +=
427 ARM_AR_MEM_TTB_SECT_SIZE) {
429 /* Calculate translation table entry offset for this memory section */
430 ttb_offset = ((vrt_addr + section_offset)
431 >> ARM_AR_MEM_TTB_SECT_TO_DESC_SHIFT);
433 /* Build translation table entry value */
434 ttb_value = (phy_addr + section_offset)
435 | ARM_AR_MEM_TTB_DESC_ALL_ACCESS;
437 if (!is_mem_mapped) {
439 /* Set cache related bits in translation table entry.
440 NOTE: Default is uncached instruction and data. */
441 if (cache_type == WRITEBACK) {
442 /* Update translation table entry value */
443 ttb_value |=
444 (ARM_AR_MEM_TTB_DESC_B |
445 ARM_AR_MEM_TTB_DESC_C);
446 } else if (cache_type == WRITETHROUGH) {
447 /* Update translation table entry value */
448 ttb_value |= ARM_AR_MEM_TTB_DESC_C;
449 }
450 /* In case of un-cached memory, set TEX 0 bit to set memory
451 attribute to normal. */
452 else if (cache_type == NOCACHE) {
453 ttb_value |= ARM_AR_MEM_TTB_DESC_TEX;
454 }
455 }
457 /* Write translation table entry value to entry address */
458 MEM_WRITE32(ttb_base + ttb_offset, ttb_value);
460 } /* for loop */
461 }
463 void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr,
464 unsigned int size, unsigned int flags)
465 {
466 int is_mem_mapped = 0;
467 int cache_type = 0;
469 if ((flags & (0x0f << 4)) == MEM_MAPPED) {
470 is_mem_mapped = 1;
471 }
473 if ((flags & 0x0f) == WB_CACHE) {
474 cache_type = WRITEBACK;
475 } else if ((flags & 0x0f) == WT_CACHE) {
476 cache_type = WRITETHROUGH;
477 } else {
478 cache_type = NOCACHE;
479 }
481 arm_ar_map_mem_region(vrt_addr, phy_addr, size, is_mem_mapped,
482 cache_type);
483 }
485 void platform_cache_all_flush_invalidate()
486 {
487 ARM_AR_MEM_DCACHE_ALL_OP(1);
488 }
490 void platform_cache_disable()
491 {
492 ARM_AR_MEM_CACHE_DISABLE();
493 }
495 unsigned long platform_vatopa(void *addr)
496 {
497 return (((unsigned long)addr & (~(0x0fff << 20))) | (0x08 << 24));
498 }
500 void *platform_patova(unsigned long addr)
501 {
502 return ((void *)addr);
504 }
506 /*==================================================================*/
507 /* The function definitions below are provided to prevent the build */
508 /* warnings for missing I/O function stubs in case of unhosted libs */
509 /*==================================================================*/
511 #include <sys/stat.h>
513 /**
514 * _fstat
515 *
516 * Status of an open file. For consistency with other minimal
517 * implementations in these examples, all files are regarded
518 * as character special devices.
519 *
520 * @param file - Unused.
521 * @param st - Status structure.
522 *
523 *
524 * A constant value of 0.
525 *
526 **/
527 __attribute__ ((weak))
528 int _fstat(int file, struct stat *st)
529 {
530 return (0);
531 }
533 /**
534 * isatty
535 *
536 *
537 * Query whether output stream is a terminal. For consistency
538 * with the other minimal implementations, which only support
539 * output to stdout, this minimal implementation is suggested
540 *
541 * @param file - Unused
542 *
543 * @return s - A constant value of 1.
544 *
545 */
546 __attribute__ ((weak))
547 int _isatty(int file)
548 {
549 return (1);
550 }
552 /**
553 *_lseek
554 *
555 * Set position in a file. Minimal implementation.
557 *
558 * @param file - Unused
559 *
560 * @param ptr - Unused
561 *
562 * @param dir - Unused
563 *
564 * @return - A constant value of 0.
565 *
566 */
567 __attribute__ ((weak))
568 int _lseek(int file, int ptr, int dir)
569 {
570 return (0);
571 }
573 /**
574 * _open
575 *
576 * Open a file. Minimal implementation
577 *
578 * @param filename - Unused
579 * @param flags - Unused
580 * @param mode - Unused
581 *
582 * return - A constant value of 1.
583 *
584 */
585 __attribute__ ((weak))
586 int _open(const char *filename, int flags, int mode)
587 {
588 /* Any number will work. */
589 return (1);
590 }
592 /**
593 * _close
594 *
595 * Close a file. Minimal implementation.
596 *
597 *
598 * @param file - Unused
599 *
600 *
601 * return A constant value of -1.
602 *
603 */
604 __attribute__ ((weak))
605 int _close(int file)
606 {
607 return (-1);
608 }
610 /**
611 * _read
612 *
613 * Low level function to redirect IO to serial.
614 *
615 * @param fd - Unused
616 * @param buffer - Buffer where read data will be placed.
617 * @param buflen - Size (in bytes) of buffer.
618 *
619 * return - A constant value of 1.
620 *
621 */
622 __attribute__ ((weak))
623 int _read(int fd, char *buffer, int buflen)
624 {
625 return -1;
626 }
628 /**
629 * _write
630 *
631 * Low level function to redirect IO to serial.
632 *
633 *
634 * @param file - Unused
635 * @param CHAR *ptr - String to output
636 * @param len - Length of the string
637 *
638 * return len - The length of the string
639 *
640 */
641 __attribute__ ((weak))
642 int _write(int file, const char *ptr, int len)
643 {
644 return 0;
645 }