sam460ex_fdt.c revision 1.2 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