Home | History | Annotate | Line # | Download | only in sam460ex
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