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