Home | History | Annotate | Line # | Download | only in sam460ex
      1 /*	$NetBSD: sam460ex_fdt.c,v 1.2 2026/06/16 23:37:49 rkujawa Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2012, 2014, 2024, 2026 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Radoslaw Kujawa.
      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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * Flattened-device-tree bootstrap for the Sam460ex.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 __KERNEL_RCSID(0, "$NetBSD: sam460ex_fdt.c,v 1.2 2026/06/16 23:37:49 rkujawa Exp $");
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/device.h>
     41 
     42 #include <machine/sam460ex.h>
     43 
     44 #include <dev/ofw/openfirm.h>
     45 #include <dev/fdt/fdtvar.h>
     46 #include <dev/fdt/fdt_console.h>
     47 
     48 #include <libfdt.h>
     49 
     50 struct sam460ex_fdt_info sam460ex_fdt_info;
     51 
     52 /* see consinit() */
     53 static int
     54 sam460ex_fdt_console_nomatch(int phandle)
     55 {
     56 	return 0;
     57 }
     58 
     59 static const struct fdt_console sam460ex_fdt_console_none = {
     60 	.match = sam460ex_fdt_console_nomatch,
     61 	.consinit = NULL,
     62 };
     63 FDT_CONSOLE(sam460ex_none, &sam460ex_fdt_console_none);
     64 
     65 /*
     66  * Our own copy of the device tree, kept live for the lifetime of the
     67  * kernel.
     68  */
     69 #define	SAM460EX_FDT_BUFSIZE	(64 * 1024)
     70 static uint64_t fdt_buf[SAM460EX_FDT_BUFSIZE / sizeof(uint64_t)];
     71 
     72 static char bootargs_buf[256];
     73 
     74 static const struct device_compatible_entry emac_compat[] = {
     75 	{ .compat = "ibm,emac4sync" },
     76 	DEVICE_COMPAT_EOL
     77 };
     78 
     79 /*
     80  * Recursively collect the per-EMAC MAC addresses.
     81  */
     82 static void
     83 sam460ex_fdt_emac(int node)
     84 {
     85 	int child;
     86 
     87 	for (child = OF_child(node); child; child = OF_peer(child)) {
     88 		uint32_t idx;
     89 		uint8_t mac[6];
     90 		int j;
     91 
     92 		if (of_compatible_match(child, emac_compat) != 0 &&
     93 		    of_getprop_uint32(child, "cell-index", &idx) == 0 &&
     94 		    idx < SAM460EX_NEMAC &&
     95 		    OF_getprop(child, "local-mac-address", mac, sizeof(mac)) ==
     96 		    (int)sizeof(mac)) {
     97 			for (j = 0; j < 6; j++)
     98 				if (mac[j] != 0)
     99 					break;
    100 			if (j != 6) {
    101 				memcpy(sam460ex_fdt_info.fi_enaddr[idx], mac, 6);
    102 				sam460ex_fdt_info.fi_enaddr_valid[idx] = true;
    103 			}
    104 		}
    105 		sam460ex_fdt_emac(child);
    106 	}
    107 }
    108 
    109 /*
    110  * Parse the device tree at the physical address U-Boot passed in r3.
    111  */
    112 bool
    113 sam460ex_fdt_parse(paddr_t fdt_pa)
    114 {
    115 	struct sam460ex_fdt_info *info = &sam460ex_fdt_info;
    116 	const void *src = (const void *)fdt_pa;
    117 	uint32_t ac, sc;
    118 	int root, node, len;
    119 
    120 	memset(info, 0, sizeof(*info));
    121 
    122 	if (fdt_pa == 0 || fdt_pa >= 0x10000000 ||
    123 	    fdt_check_header(src) != 0 ||
    124 	    (size_t)fdt_totalsize(src) > sizeof(fdt_buf))
    125 		return false;
    126 
    127 	/*
    128 	 * Copy the blob into our own buf
    129 	 */
    130 	if (fdt_open_into(src, fdt_buf, sizeof(fdt_buf)) != 0 ||
    131 	    !fdtbus_init(fdt_buf))
    132 		return false;
    133 
    134 	root = OF_finddevice("/");
    135 
    136 	/*
    137 	 * RAM size: /memory "reg" = <address... size...>.
    138 	 */
    139 	ac = 2;
    140 	sc = 1;
    141 	of_getprop_uint32(root, "#address-cells", &ac);
    142 	of_getprop_uint32(root, "#size-cells", &sc);
    143 	node = OF_finddevice("/memory");
    144 	if (node >= 0 && ac > 0 && sc > 0 && ac + sc <= 4) {
    145 		uint32_t reg[4];
    146 
    147 		if (of_getprop_uint32_array(node, "reg", reg, ac + sc) == 0)
    148 			info->fi_memsize = reg[ac + sc - 1];
    149 	}
    150 
    151 	/* CPU and timebase clocks (the timebase runs at the CPU clock). */
    152 	node = OF_finddevice("/cpus/cpu@0");
    153 	if (node >= 0) {
    154 		of_getprop_uint32(node, "clock-frequency", &info->fi_cpu_freq);
    155 		of_getprop_uint32(node, "timebase-frequency",
    156 		    &info->fi_timebase_freq);
    157 	}
    158 
    159 	/* OPB (peripheral) clock. */
    160 	node = OF_finddevice("/plb/opb");
    161 	if (node >= 0)
    162 		of_getprop_uint32(node, "clock-frequency", &info->fi_opb_freq);
    163 
    164 	/* UART input clock: the first ns16550 in the tree. */
    165 	node = of_find_bycompat(root, "ns16550");
    166 	if (node != -1)
    167 		of_getprop_uint32(node, "clock-frequency", &info->fi_uart_freq);
    168 
    169 	/* Per-EMAC MAC addresses. */
    170 	sam460ex_fdt_emac(root);
    171 
    172 	/* Kernel command line from /chosen. */
    173 	node = OF_finddevice("/chosen");
    174 	if (node >= 0) {
    175 		len = OF_getprop(node, "bootargs", bootargs_buf,
    176 		    sizeof(bootargs_buf));
    177 		if (len > 1)	/* length includes the terminating NUL */
    178 			info->fi_bootargs = bootargs_buf;
    179 	}
    180 
    181 	return true;
    182 }
    183