1 /*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lk/reg.h>
9 #include <lk/err.h>
10 #include <lk/debug.h>
11 #include <lk/trace.h>
12
13 #include <dev/uart.h>
14 #include <arch.h>
15 #include <lk/init.h>
16 #include <kernel/vm.h>
17 #include <kernel/spinlock.h>
18 #include <dev/timer/arm_generic.h>
19 #include <platform.h>
20 #include <platform/interrupts.h>
21 #include <platform/bcm28xx.h>
22
23 #if BCM2836
24 #include <arch/arm.h>
25 #include <arch/arm/mmu.h>
26
27 /* initial memory mappings. parsed by start.S */
28 struct mmu_initial_mapping mmu_initial_mappings[] = {
29 /* 1GB of sdram space */
30 {
31 .phys = SDRAM_BASE,
32 .virt = KERNEL_BASE,
33 .size = MEMSIZE,
34 .flags = 0,
35 .name = "memory"
36 },
37
38 /* peripherals */
39 {
40 .phys = BCM_PERIPH_BASE_PHYS,
41 .virt = BCM_PERIPH_BASE_VIRT,
42 .size = BCM_PERIPH_SIZE,
43 .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
44 .name = "bcm peripherals"
45 },
46
47 /* identity map to let the boot code run */
48 {
49 .phys = SDRAM_BASE,
50 .virt = SDRAM_BASE,
51 .size = 16*1024*1024,
52 .flags = MMU_INITIAL_MAPPING_TEMPORARY
53 },
54 /* null entry to terminate the list */
55 { 0 }
56 };
57
58 #define DEBUG_UART 0
59
60 #elif BCM2837
61 #include <libfdt.h>
62 #include <arch/arm64.h>
63 #include <arch/arm64/mmu.h>
64 #include <platform/mailbox.h>
65
66 /* initial memory mappings. parsed by start.S */
67 struct mmu_initial_mapping mmu_initial_mappings[] = {
68 /* 1GB of sdram space */
69 {
70 .phys = SDRAM_BASE,
71 .virt = KERNEL_BASE,
72 .size = MEMORY_APERTURE_SIZE,
73 .flags = 0,
74 .name = "memory"
75 },
76
77 /* peripherals */
78 {
79 .phys = BCM_PERIPH_BASE_PHYS,
80 .virt = BCM_PERIPH_BASE_VIRT,
81 .size = BCM_PERIPH_SIZE,
82 .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
83 .name = "bcm peripherals"
84 },
85
86 /* null entry to terminate the list */
87 { 0 }
88 };
89
90 #define DEBUG_UART 1
91
92 #else
93 #error Unknown BCM28XX Variant
94 #endif
95
96 extern void intc_init(void);
97 extern void arm_reset(void);
98
99
100 static pmm_arena_t arena = {
101 .name = "sdram",
102 .base = SDRAM_BASE,
103 .size = MEMSIZE,
104 .flags = PMM_ARENA_FLAG_KMAP,
105 };
106
platform_init_mmu_mappings(void)107 void platform_init_mmu_mappings(void) {
108 }
109
platform_early_init(void)110 void platform_early_init(void) {
111 uart_init_early();
112
113 intc_init();
114
115 #if BCM2837
116 arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 0);
117
118 /* look for a flattened device tree just before the kernel */
119 const void *fdt = (void *)KERNEL_BASE;
120 int err = fdt_check_header(fdt);
121 if (err >= 0) {
122 /* walk the nodes, looking for 'memory' */
123 int depth = 0;
124 int offset = 0;
125 for (;;) {
126 offset = fdt_next_node(fdt, offset, &depth);
127 if (offset < 0)
128 break;
129
130 /* get the name */
131 const char *name = fdt_get_name(fdt, offset, NULL);
132 if (!name)
133 continue;
134
135 /* look for the 'memory' property */
136 if (strcmp(name, "memory") == 0) {
137 printf("Found memory in fdt\n");
138 int lenp;
139 const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp);
140 if (prop_ptr && lenp == 0x10) {
141 /* we're looking at a memory descriptor */
142 //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr);
143 uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1));
144
145 /* trim size on certain platforms */
146 #if ARCH_ARM
147 if (len > 1024*1024*1024U) {
148 len = 1024*1024*1024; /* only use the first 1GB on ARM32 */
149 printf("trimming memory to 1GB\n");
150 }
151 #endif
152
153 /* set the size in the pmm arena */
154 arena.size = len;
155 }
156 }
157 }
158 }
159
160 #elif BCM2836
161 arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000);
162 #else
163 #error Unknown BCM28XX Variant
164 #endif
165
166 /* add the main memory arena */
167 pmm_add_arena(&arena);
168
169 #if BCM2837
170 /* reserve the first 64k of ram, which should be holding the fdt */
171 struct list_node list = LIST_INITIAL_VALUE(list);
172 pmm_alloc_range(MEMBASE, 0x80000 / PAGE_SIZE, &list);
173 #endif
174
175 #if WITH_SMP
176 #if BCM2837
177 uintptr_t sec_entry = (uintptr_t)(&arm_reset - KERNEL_ASPACE_BASE);
178 unsigned long long *spin_table = (void *)(KERNEL_ASPACE_BASE + 0xd8);
179
180 for (uint i = 1; i <= 3; i++) {
181 spin_table[i] = sec_entry;
182 __asm__ __volatile__ ("" : : : "memory");
183 arch_clean_cache_range(0xffff000000000000,256);
184 __asm__ __volatile__("sev");
185 }
186 #else
187 /* start the other cpus */
188 uintptr_t sec_entry = (uintptr_t)&arm_reset;
189 sec_entry -= (KERNEL_BASE - MEMBASE);
190 for (uint i = 1; i <= 3; i++) {
191 *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry;
192 }
193 #endif
194 #endif
195 }
196
platform_init(void)197 void platform_init(void) {
198 uart_init();
199 #if BCM2837
200 init_framebuffer();
201 #endif
202 }
203
platform_dputc(char c)204 void platform_dputc(char c) {
205 if (c == '\n')
206 uart_putc(DEBUG_UART, '\r');
207 uart_putc(DEBUG_UART, c);
208 }
209
platform_dgetc(char * c,bool wait)210 int platform_dgetc(char *c, bool wait) {
211 int ret = uart_getc(DEBUG_UART, wait);
212 if (ret == -1)
213 return -1;
214 *c = ret;
215 return 0;
216 }
217
218