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