ARM: tegra: Implement cboot_get_ethaddr()

This function will attempt to look up an Ethernet address in the DTB
that was passed in from cboot. It does so by first trying to locate the
default Ethernet device for the board (identified by the "ethernet"
alias) and if found, reads the "local-mac-address" property. If the
"ethernet" alias does not exist, or if it points to a device tree node
that doesn't exist, or if the device tree node that it points to does
not have a "local-mac-address" property or if the value is invalid, it
will fall back to the legacy mechanism of looking for the MAC address
stored in the "nvidia,ethernet-mac" or "nvidia,ether-mac" properties of
the "/chosen" node.

The MAC address is then written to the default Ethernet device for the
board (again identified by the "ethernet" alias) in U-Boot's control
DTB. This allows the device driver for that device to read the MAC
address from the standard location in device tree.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
diff --git a/arch/arm/mach-tegra/cboot.c b/arch/arm/mach-tegra/cboot.c
index a302ca4..628909f 100644
--- a/arch/arm/mach-tegra/cboot.c
+++ b/arch/arm/mach-tegra/cboot.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <environment.h>
 #include <fdt_support.h>
 #include <fdtdec.h>
 #include <stdlib.h>
@@ -465,46 +466,108 @@
  * Attempt to use /chosen/nvidia,ether-mac in the cboot DTB to U-Boot's
  * ethaddr environment variable if possible.
  */
-static int set_ethaddr_from_cboot(void)
+static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN])
 {
-	const void *cboot_blob = (void *)cboot_boot_x0;
-	int ret, node, len;
-	const u32 *prop;
+	const char *const properties[] = {
+		"nvidia,ethernet-mac",
+		"nvidia,ether-mac",
+	};
+	const char *prop;
+	unsigned int i;
+	int node, len;
 
-	/* Already a valid address in the environment? If so, keep it */
-	if (env_get("ethaddr"))
-		return 0;
-
-	node = fdt_path_offset(cboot_blob, "/chosen");
+	node = fdt_path_offset(fdt, "/chosen");
 	if (node < 0) {
 		printf("Can't find /chosen node in cboot DTB\n");
 		return node;
 	}
-	prop = fdt_getprop(cboot_blob, node, "nvidia,ether-mac", &len);
+
+	for (i = 0; i < ARRAY_SIZE(properties); i++) {
+		prop = fdt_getprop(fdt, node, properties[i], &len);
+		if (prop)
+			break;
+	}
+
 	if (!prop) {
-		printf("Can't find nvidia,ether-mac property in cboot DTB\n");
+		printf("Can't find Ethernet MAC address in cboot DTB\n");
 		return -ENOENT;
 	}
 
-	ret = env_set("ethaddr", (void *)prop);
-	if (ret) {
-		printf("Failed to set ethaddr from cboot DTB: %d\n", ret);
-		return ret;
+	eth_parse_enetaddr(prop, mac);
+
+	if (!is_valid_ethaddr(mac)) {
+		printf("Invalid MAC address: %s\n", prop);
+		return -EINVAL;
 	}
 
+	debug("Legacy MAC address: %pM\n", mac);
+
 	return 0;
 }
 
+int cboot_get_ethaddr(const void *fdt, uint8_t mac[ETH_ALEN])
+{
+	int node, len, err = 0;
+	const uchar *prop;
+	const char *path;
+
+	path = fdt_get_alias(fdt, "ethernet");
+	if (!path) {
+		err = -ENOENT;
+		goto out;
+	}
+
+	debug("ethernet alias found: %s\n", path);
+
+	node = fdt_path_offset(fdt, path);
+	if (node < 0) {
+		err = -ENOENT;
+		goto out;
+	}
+
+	prop = fdt_getprop(fdt, node, "local-mac-address", &len);
+	if (!prop) {
+		err = -ENOENT;
+		goto out;
+	}
+
+	if (len != ETH_ALEN) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	debug("MAC address: %pM\n", prop);
+	memcpy(mac, prop, ETH_ALEN);
+
+out:
+	if (err < 0)
+		err = cboot_get_ethaddr_legacy(fdt, mac);
+
+	return err;
+}
+
 int cboot_late_init(void)
 {
+	const void *fdt = (const void *)cboot_boot_x0;
+	uint8_t mac[ETH_ALEN];
+	int err;
+
 	set_calculated_env_vars();
 	/*
 	 * Ignore errors here; the value may not be used depending on
 	 * extlinux.conf or boot script content.
 	 */
 	set_fdt_addr();
+
 	/* Ignore errors here; not all cases care about Ethernet addresses */
-	set_ethaddr_from_cboot();
+	err = cboot_get_ethaddr(fdt, mac);
+	if (!err) {
+		void *blob = (void *)gd->fdt_blob;
+
+		err = fdtdec_set_ethernet_mac_address(blob, mac, sizeof(mac));
+		if (err < 0)
+			printf("failed to set MAC address %pM: %d\n", mac, err);
+	}
 
 	return 0;
 }