Home | History | Annotate | Line # | Download | only in hb68k
      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