1 /*
2  * Copyright (c) 2017 Google Inc. All rights reserved
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 
24 #include <debug.h>
25 #include <dev/interrupt/arm_gic.h>
26 #include <dev/timer/arm_generic.h>
27 #include <imx-regs.h>
28 #include <kernel/vm.h>
29 #include <lk/init.h>
30 #include <string.h>
31 #ifdef WITH_TZASC
32 #include <platform/tzasc.h>
33 #include <tzasc_regions.h>
34 #endif
35 
36 #define ARM_GENERIC_TIMER_INT_CNTV 27
37 #define ARM_GENERIC_TIMER_INT_CNTPS 29
38 #define ARM_GENERIC_TIMER_INT_CNTP 30
39 
40 #define ARM_GENERIC_TIMER_INT_SELECTED(timer) ARM_GENERIC_TIMER_INT_##timer
41 #define XARM_GENERIC_TIMER_INT_SELECTED(timer) \
42     ARM_GENERIC_TIMER_INT_SELECTED(timer)
43 #define ARM_GENERIC_TIMER_INT \
44     XARM_GENERIC_TIMER_INT_SELECTED(TIMER_ARM_GENERIC_SELECTED)
45 
46 /* initial memory mappings. parsed by start.S */
47 struct mmu_initial_mapping mmu_initial_mappings[] = {
48         /* Mark next entry as dynamic as it might be updated
49            by platform_reset code to specify actual size and
50            location of RAM to use */
51         {.phys = MEMBASE + KERNEL_LOAD_OFFSET,
52          .virt = KERNEL_BASE + KERNEL_LOAD_OFFSET,
53          .size = MEMSIZE,
54          .flags = MMU_INITIAL_MAPPING_FLAG_DYNAMIC,
55          .name = "ram"},
56         {.phys = SOC_REGS_PHY,
57          .virt = SOC_REGS_VIRT,
58          .size = SOC_REGS_SIZE,
59          .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
60          .name = "soc"},
61         /* null entry to terminate the list */
62         {0}};
63 
64 static pmm_arena_t ram_arena = {.name = "ram",
65                                 .base = MEMBASE + KERNEL_LOAD_OFFSET,
66                                 .size = MEMSIZE,
67                                 .flags = PMM_ARENA_FLAG_KMAP};
68 
platform_init_mmu_mappings(void)69 void platform_init_mmu_mappings(void) {
70     /* go through mmu_initial_mapping to find dynamic entry
71      * matching ram_arena (by name) and adjust it.
72      */
73     struct mmu_initial_mapping* m = mmu_initial_mappings;
74     for (uint i = 0; i < countof(mmu_initial_mappings); i++, m++) {
75         if (!(m->flags & MMU_INITIAL_MAPPING_FLAG_DYNAMIC))
76             continue;
77 
78         if (strcmp(m->name, ram_arena.name) == 0) {
79             /* update ram_arena */
80             ram_arena.base = m->phys;
81             ram_arena.size = m->size;
82             ram_arena.flags = PMM_ARENA_FLAG_KMAP;
83 
84             break;
85         }
86     }
87     pmm_add_arena(&ram_arena);
88 }
89 
generic_arm64_map_regs(const char * name,vaddr_t vaddr,paddr_t paddr,size_t size)90 static void generic_arm64_map_regs(const char* name,
91                                    vaddr_t vaddr,
92                                    paddr_t paddr,
93                                    size_t size) {
94     status_t ret;
95     void* vaddrp = (void*)vaddr;
96 
97     ret = vmm_alloc_physical(
98             vmm_get_kernel_aspace(), name, size, &vaddrp, 0, paddr,
99             VMM_FLAG_VALLOC_SPECIFIC,
100             ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_NO_EXECUTE);
101     if (ret) {
102         dprintf(CRITICAL, "%s: failed %d name=%s\n", __func__, ret, name);
103     }
104 }
105 
platform_after_vm_init(uint level)106 static void platform_after_vm_init(uint level) {
107     generic_arm64_map_regs("gic", GIC_BASE_VIRT, GIC_BASE_PHY, GIC_REG_SIZE);
108 
109     /* Initialize the interrupt controller. */
110     arm_gic_init();
111 
112     /* Initialize the timer block. */
113     arm_generic_timer_init(ARM_GENERIC_TIMER_INT, 0);
114 
115     /* SOC is mapped in initial mapping */
116 
117 #ifdef WITH_TZASC
118     /* Initialize TZASC. */
119     /* TZASC registers are mapped by initial mapping */
120     initial_tzasc(tzasc_regions, countof(tzasc_regions));
121 #endif
122 }
123 
124 LK_INIT_HOOK(platform_after_vm, platform_after_vm_init, LK_INIT_LEVEL_VM + 1);
125 
126 #if WITH_VIRT_TIMER_INIT
127 extern void virt_timer_init(void);
128 
129 /* Reset CNTVOFF register to be able to use virt arch timer */
platform_per_cpu_virt_timer_init(uint level)130 static void platform_per_cpu_virt_timer_init(uint level) {
131     virt_timer_init();
132 }
133 
134 LK_INIT_HOOK_FLAGS(platform_per_cpu_virt_timer,
135                    platform_per_cpu_virt_timer_init,
136                    LK_INIT_LEVEL_PLATFORM_EARLY,
137                    LK_INIT_FLAG_ALL_CPUS);
138 
139 #endif
140