#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sam460ex_fdt.c,v 1.2 2026/06/16 23:37:49 rkujawa Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/sam460ex.h>
#include <dev/ofw/openfirm.h>
#include <dev/fdt/fdtvar.h>
#include <dev/fdt/fdt_console.h>
#include <libfdt.h>
struct sam460ex_fdt_info sam460ex_fdt_info;
static int
sam460ex_fdt_console_nomatch(int phandle)
{
return 0;
}
static const struct fdt_console sam460ex_fdt_console_none = {
.match = sam460ex_fdt_console_nomatch,
.consinit = NULL,
};
FDT_CONSOLE(sam460ex_none, &sam460ex_fdt_console_none);
#define SAM460EX_FDT_BUFSIZE (64 * 1024)
static uint64_t fdt_buf[SAM460EX_FDT_BUFSIZE / sizeof(uint64_t)];
static char bootargs_buf[256];
static const struct device_compatible_entry emac_compat[] = {
{ .compat = "ibm,emac4sync" },
DEVICE_COMPAT_EOL
};
static void
sam460ex_fdt_emac(int node)
{
int child;
for (child = OF_child(node); child; child = OF_peer(child)) {
uint32_t idx;
uint8_t mac[6];
int j;
if (of_compatible_match(child, emac_compat) != 0 &&
of_getprop_uint32(child, "cell-index", &idx) == 0 &&
idx < SAM460EX_NEMAC &&
OF_getprop(child, "local-mac-address", mac, sizeof(mac)) ==
(int)sizeof(mac)) {
for (j = 0; j < 6; j++)
if (mac[j] != 0)
break;
if (j != 6) {
memcpy(sam460ex_fdt_info.fi_enaddr[idx], mac, 6);
sam460ex_fdt_info.fi_enaddr_valid[idx] = true;
}
}
sam460ex_fdt_emac(child);
}
}
bool
sam460ex_fdt_parse(paddr_t fdt_pa)
{
struct sam460ex_fdt_info *info = &sam460ex_fdt_info;
const void *src = (const void *)fdt_pa;
uint32_t ac, sc;
int root, node, len;
memset(info, 0, sizeof(*info));
if (fdt_pa == 0 || fdt_pa >= 0x10000000 ||
fdt_check_header(src) != 0 ||
(size_t)fdt_totalsize(src) > sizeof(fdt_buf))
return false;
if (fdt_open_into(src, fdt_buf, sizeof(fdt_buf)) != 0 ||
!fdtbus_init(fdt_buf))
return false;
root = OF_finddevice("/");
ac = 2;
sc = 1;
of_getprop_uint32(root, "#address-cells", &ac);
of_getprop_uint32(root, "#size-cells", &sc);
node = OF_finddevice("/memory");
if (node >= 0 && ac > 0 && sc > 0 && ac + sc <= 4) {
uint32_t reg[4];
if (of_getprop_uint32_array(node, "reg", reg, ac + sc) == 0)
info->fi_memsize = reg[ac + sc - 1];
}
node = OF_finddevice("/cpus/cpu@0");
if (node >= 0) {
of_getprop_uint32(node, "clock-frequency", &info->fi_cpu_freq);
of_getprop_uint32(node, "timebase-frequency",
&info->fi_timebase_freq);
}
node = OF_finddevice("/plb/opb");
if (node >= 0)
of_getprop_uint32(node, "clock-frequency", &info->fi_opb_freq);
node = of_find_bycompat(root, "ns16550");
if (node != -1)
of_getprop_uint32(node, "clock-frequency", &info->fi_uart_freq);
sam460ex_fdt_emac(root);
node = OF_finddevice("/chosen");
if (node >= 0) {
len = OF_getprop(node, "bootargs", bootargs_buf,
sizeof(bootargs_buf));
if (len > 1)
info->fi_bootargs = bootargs_buf;
}
return true;
}