sam460ex_fdt.c revision 1.1 1 /* $NetBSD: sam460ex_fdt.c,v 1.1 2026/06/16 21:51:20 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 * Minimal flattened-device-tree parsing for the Sam460ex.
33 * Extract just enough for early bootstrap.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: sam460ex_fdt.c,v 1.1 2026/06/16 21:51:20 rkujawa Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41
42 #include <machine/sam460ex.h>
43
44 #include <libfdt.h>
45
46 struct sam460ex_fdt_info sam460ex_fdt_info;
47
48 static char bootargs_buf[256];
49
50 static uint32_t
51 fdt_getprop_u32(const void *fdt, int node, const char *prop, uint32_t defval)
52 {
53 const fdt32_t *p;
54 int len;
55
56 p = fdt_getprop(fdt, node, prop, &len);
57 if (p == NULL || len < (int)sizeof(*p))
58 return defval;
59 return fdt32_to_cpu(*p);
60 }
61
62 /*
63 * Parse the FDT at fdt_pa
64 */
65 bool
66 sam460ex_fdt_parse(paddr_t fdt_pa)
67 {
68 struct sam460ex_fdt_info *info = &sam460ex_fdt_info;
69 const void *fdt = (const void *)fdt_pa;
70 const fdt32_t *reg;
71 const char *args;
72 int node, len, addr_cells, size_cells;
73
74 memset(info, 0, sizeof(*info));
75
76 if (fdt_pa == 0 || fdt_pa >= 0x10000000 ||
77 fdt_check_header(fdt) != 0)
78 return false;
79
80 /* /memory reg = <addr-cells..., size-cells...> */
81 addr_cells = fdt_address_cells(fdt, 0);
82 size_cells = fdt_size_cells(fdt, 0);
83 node = fdt_path_offset(fdt, "/memory");
84 if (node >= 0 && addr_cells > 0 && size_cells > 0) {
85 reg = fdt_getprop(fdt, node, "reg", &len);
86 if (reg != NULL &&
87 len >= (int)((addr_cells + size_cells) * sizeof(*reg))) {
88 /* memory starts at 0; sum is the low size word */
89 info->fi_memsize =
90 fdt32_to_cpu(reg[addr_cells + size_cells - 1]);
91 }
92 }
93
94 node = fdt_path_offset(fdt, "/cpus/cpu@0");
95 if (node >= 0) {
96 info->fi_cpu_freq =
97 fdt_getprop_u32(fdt, node, "clock-frequency", 0);
98 info->fi_timebase_freq =
99 fdt_getprop_u32(fdt, node, "timebase-frequency", 0);
100 }
101
102 node = fdt_path_offset(fdt, "/plb/opb");
103 if (node >= 0)
104 info->fi_opb_freq =
105 fdt_getprop_u32(fdt, node, "clock-frequency", 0);
106
107 node = fdt_node_offset_by_compatible(fdt, -1, "ns16550");
108 if (node >= 0)
109 info->fi_uart_freq =
110 fdt_getprop_u32(fdt, node, "clock-frequency", 0);
111
112 /*
113 * EMAC MAC addresses
114 */
115 node = -1;
116 while ((node = fdt_node_offset_by_compatible(fdt, node,
117 "ibm,emac4sync")) >= 0) {
118 const uint8_t *mac;
119 uint32_t idx;
120 int j;
121
122 idx = fdt_getprop_u32(fdt, node, "cell-index", ~0U);
123 if (idx >= SAM460EX_NEMAC)
124 continue;
125 mac = fdt_getprop(fdt, node, "local-mac-address", &len);
126 if (mac == NULL || len < 6)
127 continue;
128 for (j = 0; j < 6; j++)
129 if (mac[j] != 0)
130 break;
131 if (j == 6)
132 continue; /* all-zero: not fixed up */
133 memcpy(info->fi_enaddr[idx], mac, 6);
134 info->fi_enaddr_valid[idx] = true;
135 }
136
137 node = fdt_path_offset(fdt, "/chosen");
138 if (node >= 0) {
139 args = fdt_getprop(fdt, node, "bootargs", &len);
140 if (args != NULL && len > 0) {
141 strlcpy(bootargs_buf, args,
142 uimin(sizeof(bootargs_buf), (size_t)len + 1));
143 info->fi_bootargs = bootargs_buf;
144 }
145 }
146
147 return true;
148 }
149