diff options
Diffstat (limited to 'platform/bcm2837/platform.c')
-rw-r--r-- | platform/bcm2837/platform.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/platform/bcm2837/platform.c b/platform/bcm2837/platform.c new file mode 100644 index 00000000..233ed4f5 --- /dev/null +++ b/platform/bcm2837/platform.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include <reg.h> +#include <err.h> +#include <debug.h> +#include <trace.h> +#include <libfdt.h> + +#include <dev/uart.h> +#include <arch.h> +#include <arch/arm64.h> +#include <arch/arm64/mmu.h> +#include <lk/init.h> +#include <kernel/vm.h> +#include <kernel/spinlock.h> +#include <dev/timer/arm_generic.h> +#include <platform.h> +#include <platform/interrupts.h> +#include <platform/bcm2837.h> + +extern void intc_init(void); +extern void arm_reset(void); + +/* initial memory mappings. parsed by start.S */ +struct mmu_initial_mapping mmu_initial_mappings[] = { + /* 1GB of sdram space */ + { + .phys = SDRAM_BASE, + .virt = KERNEL_BASE, + .size = MEMORY_APERTURE_SIZE, + .flags = 0, + .name = "memory" + }, + + /* peripherals */ + { + .phys = BCM_PERIPH_BASE_PHYS, + .virt = BCM_PERIPH_BASE_VIRT, + .size = BCM_PERIPH_SIZE, + .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE, + .name = "bcm peripherals" + }, + + /* null entry to terminate the list */ + { 0 } +}; + +static pmm_arena_t arena = { + .name = "sdram", + .base = SDRAM_BASE, + .size = MEMSIZE, + .flags = PMM_ARENA_FLAG_KMAP, +}; + +void platform_init_mmu_mappings(void) +{ +} + +void platform_early_init(void) +{ + uart_init_early(); + + intc_init(); + + arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000); + + + /* look for a flattened device tree just before the kernel */ + const void *fdt = (void *)KERNEL_BASE; + int err = fdt_check_header(fdt); + if (err >= 0) { + /* walk the nodes, looking for 'memory' */ + int depth = 0; + int offset = 0; + for (;;) { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0) + break; + + /* get the name */ + const char *name = fdt_get_name(fdt, offset, NULL); + if (!name) + continue; + + /* look for the 'memory' property */ + if (strcmp(name, "memory") == 0) { + printf("Found memory in fdt\n"); + int lenp; + const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); + if (prop_ptr && lenp == 0x10) { + /* we're looking at a memory descriptor */ + //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); + uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); + + /* trim size on certain platforms */ +#if ARCH_ARM + if (len > 1024*1024*1024U) { + len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ + printf("trimming memory to 1GB\n"); + } +#endif + + /* set the size in the pmm arena */ + arena.size = len; + } + } + } + } + + /* add the main memory arena */ + pmm_add_arena(&arena); + + /* reserve the first 64k of ram, which should be holding the fdt */ + struct list_node list = LIST_INITIAL_VALUE(list); + pmm_alloc_range(MEMBASE, 0x80000 / PAGE_SIZE, &list); + +#if WITH_SMP + /* start the other cpus */ + uintptr_t sec_entry = (uintptr_t)&arm_reset; + sec_entry -= (KERNEL_BASE - MEMBASE); + for (uint i = 1; i <= 3; i++) { + *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry; + } +#endif +} + +void platform_init(void) +{ + uart_init(); +} + +#define DEBUG_UART 1 + +void platform_dputc(char c) +{ + if (c == '\n') + uart_putc(DEBUG_UART, '\r'); + uart_putc(DEBUG_UART, c); +} + +int platform_dgetc(char *c, bool wait) +{ + int ret = uart_getc(DEBUG_UART, wait); + if (ret == -1) + return -1; + *c = ret; + return 0; +} + |