rockchip: rk3399: derive ethaddr from cpuid
authorRohan Garg <rohan.garg@collabora.com>
Mon, 12 Aug 2019 15:04:34 +0000 (17:04 +0200)
committerKever Yang <kever.yang@rock-chips.com>
Fri, 23 Aug 2019 10:15:31 +0000 (18:15 +0800)
Generate a MAC address based on the cpuid available in the efuse
block: Use the first 6 byte of the cpuid's SHA256 hash and set the
locally administered bits. Also ensure that the multicast bit is
cleared.

The MAC address is only generated and set if there is no ethaddr
present in the saved environment.

This is based off of Klaus Goger's work in 8adc9d

Signed-off-by: Rohan Garg <rohan.garg@collabora.com>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
arch/arm/include/asm/arch-rockchip/misc.h [new file with mode: 0644]
arch/arm/mach-rockchip/Makefile
arch/arm/mach-rockchip/board.c
arch/arm/mach-rockchip/misc.c [new file with mode: 0644]

diff --git a/arch/arm/include/asm/arch-rockchip/misc.h b/arch/arm/include/asm/arch-rockchip/misc.h
new file mode 100644 (file)
index 0000000..b6b03c9
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * RK3399: Architecture common definitions
+ *
+ * Copyright (C) 2019 Collabora Inc - https://www.collabora.com/
+ *      Rohan Garg <rohan.garg@collabora.com>
+ */
+
+int rockchip_cpuid_from_efuse(const u32 cpuid_offset,
+                             const u32 cpuid_length,
+                             u8 *cpuid);
+int rockchip_cpuid_set(const u8 *cpuid, const u32 cpuid_length);
+int rockchip_setup_macaddr(void);
index aed379a0dc62571fed81b69cf83dcc6b24ab51c1..207f9000110db46b5f7fae6978b9b94a51a60d6b 100644 (file)
@@ -25,6 +25,10 @@ endif
 
 obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram_common.o
 
+ifdef CONFIG_MISC_INIT_R
+obj-y += misc.o
+endif
+
 obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/
 obj-$(CONFIG_ROCKCHIP_RK3128) += rk3128/
 ifndef CONFIG_TPL_BUILD
index b2a88e789d830cd5418cb3da8a2e128eae09458f..8ca34637315904e4c27cc802d8c8aee60c1e7410 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/arch-rockchip/boot_mode.h>
 #include <asm/arch-rockchip/clock.h>
 #include <asm/arch-rockchip/periph.h>
+#include <asm/arch-rockchip/misc.h>
 #include <power/regulator.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -102,3 +103,25 @@ int fastboot_set_reboot_flag(void)
        return 0;
 }
 #endif
+
+#ifdef CONFIG_MISC_INIT_R
+__weak int misc_init_r(void)
+{
+       const u32 cpuid_offset = 0x7;
+       const u32 cpuid_length = 0x10;
+       u8 cpuid[cpuid_length];
+       int ret;
+
+       ret = rockchip_cpuid_from_efuse(cpuid_offset, cpuid_length, cpuid);
+       if (ret)
+               return ret;
+
+       ret = rockchip_cpuid_set(cpuid, cpuid_length);
+       if (ret)
+               return ret;
+
+       ret = rockchip_setup_macaddr();
+
+       return ret;
+}
+#endif
diff --git a/arch/arm/mach-rockchip/misc.c b/arch/arm/mach-rockchip/misc.c
new file mode 100644 (file)
index 0000000..fdb763c
--- /dev/null
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * RK3399: Architecture common definitions
+ *
+ * Copyright (C) 2019 Collabora Inc - https://www.collabora.com/
+ *      Rohan Garg <rohan.garg@collabora.com>
+ *
+ * Based on puma-rk3399.c:
+ *      (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <env.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <misc.h>
+#include <u-boot/sha256.h>
+
+#include <asm/arch-rockchip/misc.h>
+
+int rockchip_setup_macaddr(void)
+{
+#if CONFIG_IS_ENABLED(CMD_NET)
+       int ret;
+       const char *cpuid = env_get("cpuid#");
+       u8 hash[SHA256_SUM_LEN];
+       int size = sizeof(hash);
+       u8 mac_addr[6];
+
+       /* Only generate a MAC address, if none is set in the environment */
+       if (env_get("ethaddr"))
+               return -1;
+
+       if (!cpuid) {
+               debug("%s: could not retrieve 'cpuid#'\n", __func__);
+               return -1;
+       }
+
+       ret = hash_block("sha256", (void *)cpuid, strlen(cpuid), hash, &size);
+       if (ret) {
+               debug("%s: failed to calculate SHA256\n", __func__);
+               return -1;
+       }
+
+       /* Copy 6 bytes of the hash to base the MAC address on */
+       memcpy(mac_addr, hash, 6);
+
+       /* Make this a valid MAC address and set it */
+       mac_addr[0] &= 0xfe;  /* clear multicast bit */
+       mac_addr[0] |= 0x02;  /* set local assignment bit (IEEE802) */
+       eth_env_set_enetaddr("ethaddr", mac_addr);
+#endif
+       return 0;
+}
+
+int rockchip_cpuid_from_efuse(const u32 cpuid_offset,
+                             const u32 cpuid_length,
+                             u8 *cpuid)
+{
+#if CONFIG_IS_ENABLED(ROCKCHIP_EFUSE)
+       struct udevice *dev;
+       int ret;
+
+       /* retrieve the device */
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                                         DM_GET_DRIVER(rockchip_efuse), &dev);
+       if (ret) {
+               debug("%s: could not find efuse device\n", __func__);
+               return -1;
+       }
+
+       /* read the cpu_id range from the efuses */
+       ret = misc_read(dev, cpuid_offset, cpuid, sizeof(cpuid));
+       if (ret) {
+               debug("%s: reading cpuid from the efuses failed\n",
+                     __func__);
+               return -1;
+       }
+#endif
+       return 0;
+}
+
+int rockchip_cpuid_set(const u8 *cpuid, const u32 cpuid_length)
+{
+       u8 low[cpuid_length / 2], high[cpuid_length / 2];
+       char cpuid_str[cpuid_length * 2 + 1];
+       u64 serialno;
+       char serialno_str[17];
+       int i;
+
+       memset(cpuid_str, 0, sizeof(cpuid_str));
+       for (i = 0; i < 16; i++)
+               sprintf(&cpuid_str[i * 2], "%02x", cpuid[i]);
+
+       debug("cpuid: %s\n", cpuid_str);
+
+       /*
+        * Mix the cpuid bytes using the same rules as in
+        *   ${linux}/drivers/soc/rockchip/rockchip-cpuinfo.c
+        */
+       for (i = 0; i < 8; i++) {
+               low[i] = cpuid[1 + (i << 1)];
+               high[i] = cpuid[i << 1];
+       }
+
+       serialno = crc32_no_comp(0, low, 8);
+       serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32;
+       snprintf(serialno_str, sizeof(serialno_str), "%016llx", serialno);
+
+       env_set("cpuid#", cpuid_str);
+       env_set("serial#", serialno_str);
+
+       return 0;
+}