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