• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012 Travis Geiselbrecht
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include <arch.h>
24 #include <arch/arm.h>
25 #include <arch/arm/mmu.h>
26 #include <debug.h>
27 #include <dev/interrupt/arm_gic.h>
28 #include <dev/timer/arm_generic.h>
29 #include <err.h>
30 #include <kernel/thread.h>
31 #include <kernel/vm.h>
32 #include <lk/init.h>
33 #include <platform.h>
34 #include <platform/gic.h>
35 #include <platform/interrupts.h>
36 #include <platform/vexpress-a15.h>
37 #include <reg.h>
38 #include <string.h>
39 #include "platform_p.h"
40 
41 #if WITH_LIB_KMAP
42 #include <lib/kmap.h>
43 #endif
44 
45 #if WITH_SMP
46 void platform_secondary_entry(void);
47 paddr_t platform_secondary_entry_paddr;
48 #endif
49 
50 /* initial memory mappings. parsed by start.S */
51 struct mmu_initial_mapping mmu_initial_mappings[] = {
52         /* Mark next entry as dynamic as it might be updated
53            by platform_reset code to specify actual size and
54            location of RAM to use */
55         {.phys = MEMBASE + KERNEL_LOAD_OFFSET,
56          .virt = KERNEL_BASE + KERNEL_LOAD_OFFSET,
57          .size = MEMSIZE,
58          .flags = MMU_INITIAL_MAPPING_FLAG_DYNAMIC,
59          .name = "ram"},
60 
61         {.phys = REGISTER_BANK_0_PADDR,
62          .virt = REGISTER_BANK_0_VADDR,
63          .size = 0x00100000,
64          .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
65          .name = "bank-0"},
66 
67         {.phys = REGISTER_BANK_1_PADDR,
68          .virt = REGISTER_BANK_1_VADDR,
69          .size = 0x00100000,
70          .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
71          .name = "bank-1"},
72 
73         {.phys = REGISTER_BANK_2_PADDR,
74          .virt = REGISTER_BANK_2_VADDR,
75          .size = 0x00100000,
76          .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
77          .name = "bank-2"},
78 
79         /* null entry to terminate the list */
80         {0}};
81 
82 static pmm_arena_t ram_arena = {.name = "ram",
83                                 .base = MEMBASE + KERNEL_LOAD_OFFSET,
84                                 .size = MEMSIZE,
85                                 .flags = PMM_ARENA_FLAG_KMAP};
86 
get_cpuid(void)87 static uint32_t get_cpuid(void) {
88     u_int cpuid;
89 
90     __asm__ volatile("mrc p15, 0, %0, c0, c0, 5 @ read MPIDR\n" : "=r"(cpuid));
91 
92     return cpuid & 0xF;
93 }
94 
platform_init_mmu_mappings(void)95 void platform_init_mmu_mappings(void) {
96     if (get_cpuid())
97         return;
98 
99     /* go through mmu_initial_mapping to find dynamic entry
100      * matching ram_arena (by name) and adjust it.
101      */
102     struct mmu_initial_mapping* m = mmu_initial_mappings;
103     for (size_t i = 0; i < countof(mmu_initial_mappings); i++, m++) {
104         if (!(m->flags & MMU_INITIAL_MAPPING_FLAG_DYNAMIC))
105             continue;
106 
107         if (strcmp(m->name, ram_arena.name) == 0) {
108             /* update ram_arena */
109             ram_arena.base = m->phys;
110             ram_arena.size = m->size;
111             ram_arena.flags = PMM_ARENA_FLAG_KMAP;
112 
113             break;
114         }
115     }
116     pmm_add_arena(&ram_arena);
117 }
118 
read_mpidr(void)119 static uint32_t read_mpidr(void) {
120     int mpidr;
121     __asm__ volatile("mrc		p15, 0, %0, c0, c0, 5" : "=r"(mpidr));
122     return mpidr;
123 }
124 
platform_early_init(void)125 void platform_early_init(void) {
126     /* initialize the interrupt controller */
127     arm_gic_init();
128 
129     /* initialize the timer block */
130     arm_generic_timer_init(ARM_GENERIC_TIMER_INT, 0);
131 
132 #if WITH_SMP
133     dprintf(INFO, "Booting secondary CPUs. Main CPU MPIDR = %x\n",
134             read_mpidr());
135     platform_secondary_entry_paddr = vaddr_to_paddr(platform_secondary_entry);
136     writel(platform_secondary_entry_paddr, SECONDARY_BOOT_ADDR);
137     arm_gic_sgi(0, ARM_GIC_SGI_FLAG_TARGET_FILTER_NOT_SENDER, 0);
138 #endif
139 }
140 
141 #if WITH_SMP
142 
143 #define GICC_CTLR (GICC_OFFSET + 0x0000)
144 #define GICC_IAR (GICC_OFFSET + 0x000c)
145 #define GICC_EOIR (GICC_OFFSET + 0x0010)
146 
platform_secondary_init(uint level)147 static void platform_secondary_init(uint level) {
148     u_int val;
149     dprintf(INFO, "Booted secondary CPU, MPIDR = %x\n", read_mpidr());
150     val = *REG32(GICBASE(0) + GICC_IAR);
151     if (val)
152         dprintf(INFO, "bad interrupt number on secondary CPU: %x\n", val);
153     *REG32(GICBASE(0) + GICC_EOIR) = val & 0x3ff;
154 }
155 
156 LK_INIT_HOOK_FLAGS(vexpress_a15,
157                    platform_secondary_init,
158                    LK_INIT_LEVEL_PLATFORM,
159                    LK_INIT_FLAG_SECONDARY_CPUS);
160 #endif
161 
platform_init(void)162 void platform_init(void) {}
163