]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
arm64: zynqmp: Add board detection based on FRU
authorMichal Simek <michal.simek@xilinx.com>
Fri, 12 Apr 2019 09:26:29 +0000 (11:26 +0200)
committerMichal Simek <michal.simek@xilinx.com>
Thu, 6 Jun 2019 11:46:52 +0000 (13:46 +0200)
Identification depends on eeprom with FRU content.

For example 2 eeproms to check.
chosen {
xlnx,eeprom = <&eeprom>, <&eeprom2>;
};

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
board/xilinx/zynqmp/Kconfig
board/xilinx/zynqmp/Makefile
board/xilinx/zynqmp/board_detect_fru.c [new file with mode: 0644]

index 7d1f7398c3e99e0601b4b844b591a20164931a87..e81ae2de5558aea1ea0bded9c5913fd30d96d4bd 100644 (file)
@@ -15,4 +15,11 @@ config CMD_ZYNQMP
          and authentication feature enabled while generating
          BOOT.BIN using Xilinx bootgen tool.
 
+config ZYNQMP_BOARD_DETECT_FRU
+       bool "Enable ZynqMP board detection via FRU"
+       help
+         Enabling this option u-boot will look at chosen/xlnx,eeprom
+         property and will try to decode board name written in IPMI
+         FRU format.
+
 endif
index b4d39edc118f93b70fdca24896c3e0020e41ada7..2592faee673a4c96df3c1e79b3954bdab0a9153d 100644 (file)
@@ -39,6 +39,7 @@ $(obj)/pm_cfg_obj.o: $(shell cd $(srctree); readlink -f $(CONFIG_ZYNQMP_SPL_PM_C
 endif
 
 obj-$(CONFIG_MMC_SDHCI_ZYNQ) += tap_delays.o
+obj-$(CONFIG_ZYNQMP_BOARD_DETECT_FRU) += board_detect_fru.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_CMD_ZYNQMP) += cmds.o
diff --git a/board/xilinx/zynqmp/board_detect_fru.c b/board/xilinx/zynqmp/board_detect_fru.c
new file mode 100644 (file)
index 0000000..a3fe956
--- /dev/null
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 - 2019 Xilinx, Inc.
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ */
+
+#define DEBUG
+
+#include <common.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <i2c.h>
+#include <fru.h>
+
+#ifndef CONFIG_SPL_BUILD
+
+#define FRU_DATA_START 0
+#define FRU_DATA_SIZE  256
+
+#if defined(CONFIG_DTB_RESELECT)
+static int get_fru(uint8_t *fru_space)
+{
+       struct udevice *dev;
+       int ret, i, count;
+       u32 *phandles;
+       ofnode chosen_node;
+
+       chosen_node = ofnode_path("/chosen");
+
+       count = ofnode_count_phandle_with_args(chosen_node, "xlnx,eeprom",
+                                              NULL);
+       /* If there is no node or count is 0 fail */
+       if (count < 0 || !count) {
+               debug("%s: Incorrect or missing xlnx,eeprom property %d\n",
+                     __func__, count);
+               return -EINVAL;
+       }
+
+       debug("%s: Found %d eeprom phandles\n", __func__, count);
+
+       phandles = calloc(count, sizeof(*phandles));
+       if (!phandles)
+               return -ENOMEM;
+
+       ret = ofnode_read_u32_array(chosen_node, "xlnx,eeprom",
+                                   phandles, count);
+       if (ret) {
+               debug("%s: Reading phandles failed\n", __func__);
+               return ret;
+       }
+
+       /* Interate over phandles and try to read FRU data */
+       for (i = 0; i < count; i++) {
+               debug("%s: %d: Reading device phandle %x\n",
+                     __func__, i, phandles[i]);
+               /* Get device from phandle_id */
+               ret = uclass_get_device_by_phandle_id(UCLASS_I2C_EEPROM,
+                                                     phandles[i], &dev);
+               if (ret) {
+                       debug("%s: %d: Get device phandle %x failed %d\n",
+                             __func__, i, phandles[i], ret);
+                       continue;
+               }
+
+               /* Setup alen to 2 */
+               ret = i2c_set_chip_offset_len(dev, 2);
+               if (ret)
+                       break;
+
+               /* Read data to fru_space */
+               ret = dm_i2c_read(dev, FRU_DATA_START, fru_space,
+                                 FRU_DATA_SIZE);
+               if (!ret) {
+                       debug("%s: %i: I2C FRU location %p\n",
+                             __func__, i, fru_space);
+                       break;
+               }
+
+               debug("%s: %d: I2C FRU read failed\n", __func__, i);
+       }
+
+       free(phandles);
+       return ret;
+}
+
+static int do_board_detect(void)
+{
+       int ret;
+       void *fru_space;
+
+       fru_space = calloc(FRU_DATA_SIZE, sizeof(u8));
+       if (!fru_space) {
+               debug("%s: Malloc failed\n", __func__);
+               return -ENOMEM;
+       }
+
+       ret = get_fru(fru_space);
+       if (!ret) {
+               ret = fru_capture((ulong)fru_space);
+               if (ret)
+                       debug("%s: FRU decoding failed\n", __func__);
+               else
+                       debug("%s: Board detected via FRU\n", __func__);
+
+       } else {
+               debug("%s: Cannot read EEPROM\n", __func__);
+       }
+
+       free(fru_space);
+       return ret;
+}
+
+int embedded_dtb_select(void)
+{
+       int ret;
+
+       debug("%s: Start board detect\n", __func__);
+
+       ret = do_board_detect();
+       if (ret < 0)
+               debug("%s: Board detection failed\n", __func__);
+
+       fdtdec_setup();
+
+       return 0;
+}
+#endif
+
+int board_fit_config_name_match(const char *name)
+{
+       if (!fru_data.captured) {
+               debug("%s: FRU data not captured\n", __func__);
+               return -EINVAL;
+       }
+
+       debug("%s: checking name %s with %s\n", __func__, name,
+             fru_data.brd.product_name);
+
+       if (!strcmp(name, (char *)fru_data.brd.product_name)) {
+               debug("Board found finally\n");
+               return 0;
+       }
+
+       return -EINVAL;
+}
+#endif
+