1 /* $NetBSD: fdt_bootstrap.c,v 1.2 2026/08/05 01:34:06 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: fdt_bootstrap.c,v 1.2 2026/08/05 01:34:06 thorpej Exp $"); 34 35 #include "opt_hb68k_config.h" 36 #include "opt_m68k_arch.h" 37 38 #include <sys/types.h> 39 #include <sys/cpu.h> 40 41 #include <m68k/seglist.h> 42 43 #include <uvm/uvm_extern.h> 44 45 #include <dev/fdt/fdtvar.h> 46 #include <dev/fdt/fdt_memory.h> 47 #include <dev/fdt/fdt_platform.h> 48 49 #include <libfdt.h> 50 51 #include <dev/ofw/openfirm.h> 52 53 struct cpu_mmu_data { 54 int cpu_type; 55 int mmu_type; 56 }; 57 58 #if defined(M68010) 59 static const struct cpu_mmu_data cpu_data10 = { CPU_68010, MMU_CUSTOM }; 60 #endif 61 62 #if defined(M68020) 63 static const struct cpu_mmu_data cpu_data20 = { CPU_68020, MMU_UNKNOWN }; 64 #endif 65 66 #if defined(M68030) 67 static const struct cpu_mmu_data cpu_data030 = { CPU_68030, MMU_68030 }; 68 #endif 69 70 #if defined(M68040) 71 static const struct cpu_mmu_data cpu_data040 = { CPU_68040, MMU_68040 }; 72 #endif 73 74 #if defined(M68060) 75 static const struct cpu_mmu_data cpu_data060 = { CPU_68060, MMU_68040 }; 76 #endif 77 78 static const struct device_compatible_entry cpu_compat_data[] = { 79 #if defined(M68010) 80 { .compat = "motorola,68010", .data = &cpu_data010 }, 81 #endif 82 #if defined(M68020) 83 { .compat = "motorola,68020", .data = &cpu_data020 }, 84 #endif 85 #if defined(M68030) 86 { .compat = "motorola,68030", .data = &cpu_data030 }, 87 #endif 88 #if defined(M68040) 89 { .compat = "motorola,68040", .data = &cpu_data040 }, 90 { .compat = "motorola,68lc040", .data = &cpu_data040 }, 91 #endif 92 #if defined(M68060) 93 { .compat = "motorola,68060", .data = &cpu_data060 }, 94 { .compat = "motorola,68lc060", .data = &cpu_data060 }, 95 #endif 96 DEVICE_COMPAT_EOL 97 }; 98 99 static const struct device_compatible_entry mmu_compat_data[] = { 100 #if defined(M68K_MMU_68851) 101 { .compat = "motorola,68851", .value = MMU_68851 }, 102 #endif 103 DEVICE_COMPAT_EOL 104 }; 105 106 struct add_memory_physsegs_context { 107 phys_seg_list_t *segs; 108 unsigned int nsegs; 109 unsigned int npgs; 110 }; 111 112 static void 113 add_memory_physsegs(const struct fdt_memory *m, void *v) 114 { 115 struct add_memory_physsegs_context *ctx = v; 116 paddr_t first = m68k_round_page((paddr_t)m->start); 117 paddr_t last = m68k_trunc_page((paddr_t)m->end); 118 119 if (ctx->nsegs == VM_PHYSSEG_MAX) { 120 return; 121 } 122 123 if (ctx->nsegs > 0 && 124 ctx->segs[ctx->nsegs - 1].ps_end == first) { 125 ctx->segs[ctx->nsegs - 1].ps_end = 126 ctx->segs[ctx->nsegs - 1].ps_avail_end = last; 127 } else { 128 ctx->segs[ctx->nsegs].ps_start = 129 ctx->segs[ctx->nsegs].ps_avail_start = first; 130 ctx->segs[ctx->nsegs].ps_end = 131 ctx->segs[ctx->nsegs].ps_avail_end = last; 132 ctx->nsegs++; 133 } 134 135 ctx->npgs += m68k_btop(last - first); 136 } 137 138 /* 139 * fdt_bootstrap1 -- 140 * Very early bootstrap routine; we extract some vital information 141 * out of the Device Tree necessary for pmap_bootstrap1(). 142 * 143 * N.B. Because we have to make lots of calls into other parts 144 * of the kernel, this whole thing really only works if reloff == 0, 145 * i.e. the kernel is going to run VA==PA or if the MMU is 146 * already enabled and we're already running at our linked 147 * address. 148 */ 149 paddr_t 150 fdt_bootstrap1(paddr_t nextpa, paddr_t reloff) 151 { 152 const struct fdt_platform *plat; 153 const struct device_compatible_entry *dce; 154 int phandle; 155 156 if (reloff != 0) { 157 panic("%s: no hope...", __func__); 158 } 159 160 #if defined(CONFIG_STATIC_DEVICE_TREE) 161 extern uint8_t dt_blob_start[]; 162 if (! machine_fdt_init(dt_blob_start)) { 163 panic("%s: bad static device tree", __func__); 164 } 165 #else 166 /* 167 * XXX Assume that the device tree immediately follows 168 * the static kernel image. 169 */ 170 void *fdt_data = (void *)nextpa; 171 if (! machine_fdt_init(fdt_data)) { 172 panic("%s: don't know where the device tree is", __func__); 173 } 174 /* nextpa will be updated below */ 175 #endif /* CONFIG_STATIC_DEVICE_TREE */ 176 177 plat = machine_platform(); 178 if (plat == NULL) { 179 panic("%s: kernel is not configured for this platform", 180 __func__); 181 } 182 183 /* Determine the CPU / MMU type. */ 184 phandle = OF_finddevice("/cpus/cpu@0"); 185 if (phandle == -1) { 186 panic("%s: unable to find CPU node", __func__); 187 } 188 dce = of_compatible_lookup(phandle, cpu_compat_data); 189 if (dce == NULL) { 190 panic("%s: kernel is not configured for this CPU", __func__); 191 } 192 const struct cpu_mmu_data *cmd = dce->data; 193 cputype = cmd->cpu_type; 194 mmutype = cmd->mmu_type; 195 196 if (mmutype == MMU_UNKNOWN) { 197 char mmuprop[32]; 198 199 if (OF_getprop(phandle, "mmu-type", 200 mmuprop, sizeof(mmuprop)) >= 0) { 201 dce = device_compatible_lookup_strlist(mmuprop, 202 strlen(mmuprop) + 1, mmu_compat_data); 203 if (dce != NULL) { 204 mmutype = dce->value; 205 } 206 } 207 /* 208 * If it's still unknown at this point, the platform 209 * bootstrap routine will have a chance to weigh in. 210 */ 211 } 212 213 #if !defined(CONFIG_STATIC_DEVICE_TREE) 214 /* 215 * We're done with any potential changes to the device tree. 216 * Compact it and advance past it. 217 */ 218 fdt_pack(fdt_data); 219 nextpa = (nextpa + fdt_totalsize(fdt_data) + 3) & ~3U; 220 #endif 221 222 /* 223 * Platform-specific bootstrap. Any additional MMU configuration 224 * information, and a chance to patch up any /memory nodes, if 225 * necessary. 226 */ 227 if (plat->fp_bootstrap != NULL) { 228 nextpa = (*plat->fp_bootstrap)(nextpa, reloff); 229 } 230 231 /* Fatal if we still don't know the MMU type. */ 232 if (mmutype == MMU_UNKNOWN) { 233 panic("%s: don't know the MMU type", __func__); 234 } 235 236 uint64_t memory_start, memory_end; 237 fdt_memory_get(&memory_start, &memory_end); 238 fdt_memory_remove_reserved(memory_start, memory_end); 239 240 struct add_memory_physsegs_context ctx = { 241 .segs = phys_seg_list, 242 }; 243 fdt_memory_foreach(add_memory_physsegs, &ctx); 244 physmem = ctx.npgs; 245 246 return nextpa; 247 } 248