summaryrefslogtreecommitdiff
path: root/board/xilinx/common/fru_ops.c
diff options
context:
space:
mode:
authorMichal Simek <michal.simek@xilinx.com>2019-04-15 13:54:09 +0200
committerMichal Simek <michal.simek@xilinx.com>2020-10-27 08:13:32 +0100
commit4489e0aa9b5548a2ad1beb2853bbc0db56cf1db5 (patch)
tree42417e9ef40971ee53320c454af99bd464038247 /board/xilinx/common/fru_ops.c
parentf1b97b5f18a8e03c534cb7dbde22cd23d5d753f7 (diff)
downloadu-boot-4489e0aa9b5548a2ad1beb2853bbc0db56cf1db5.tar.gz
xilinx: cmd: Add basic fru format generator
Idea is to have something what can be used for board bringup from generic board perspective. There is a violation compare to spec that FRU ID is ASCII8 instead of binary format but this is really for having something to pass boot and boot to OS which has better generating options. Also time should be filled properly. For example: fru board_gen 1000 XILINX versal-x-prc-01-revA serialX partX There is also support for revision field which is Xilinx specific field. Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Diffstat (limited to 'board/xilinx/common/fru_ops.c')
-rw-r--r--board/xilinx/common/fru_ops.c101
1 files changed, 100 insertions, 1 deletions
diff --git a/board/xilinx/common/fru_ops.c b/board/xilinx/common/fru_ops.c
index 491e92a7af..fc3add7d93 100644
--- a/board/xilinx/common/fru_ops.c
+++ b/board/xilinx/common/fru_ops.c
@@ -62,6 +62,103 @@ static int fru_check_type_len(u8 type_len, u8 language, u8 *type)
return len;
}
+/* Return len */
+static u8 fru_gen_type_len(u8 *addr, char *name)
+{
+ int len = strlen(name);
+ struct fru_board_info_member *member;
+
+ member = (struct fru_board_info_member *)addr;
+ member->type_len = FRU_TYPELEN_TYPE_ASCII8 << FRU_TYPELEN_TYPE_SHIFT;
+ member->type_len |= len;
+
+ debug("%lx/%lx: Add %s to 0x%lx (len 0x%x)\n", (ulong)addr,
+ (ulong)&member->type_len, name, (ulong)&member->name, len);
+ memcpy(&member->name, name, len);
+
+ /* Add +1 for type_len parameter */
+ return 1 + len;
+}
+
+int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
+ char *serial_no, char *part_no, char *revision)
+{
+ struct fru_common_hdr *header = (struct fru_common_hdr *)addr;
+ struct fru_board_info_header *board_info;
+ u8 *member;
+ u8 len, pad, modulo;
+
+ header->version = 1; /* Only version 1.0 is supported now */
+ header->off_internal = 0; /* not present */
+ header->off_chassis = 0; /* not present */
+ header->off_board = (sizeof(*header)) / 8; /* Starting offset 8 */
+ header->off_product = 0; /* not present */
+ header->off_multirec = 0; /* not present */
+ header->pad = 0;
+ /*
+ * This unsigned byte can be used to calculate a zero checksum
+ * for the data area following the header. I.e. the modulo 256 sum of
+ * the record data bytes plus the checksum byte equals zero.
+ */
+ header->crc = 0; /* Clear before calculation */
+ header->crc = 0 - fru_checksum((u8 *)header, sizeof(*header));
+
+ /* board info is just right after header */
+ board_info = (void *)((u8 *)header + sizeof(*header));
+
+ debug("header %lx, board_info %lx\n", (ulong)header, (ulong)board_info);
+
+ board_info->ver = 1; /* 1.0 spec */
+ board_info->lang_code = 0; /* English */
+ board_info->time[0] = 0; /* unspecified */
+ board_info->time[1] = 0; /* unspecified */
+ board_info->time[2] = 0; /* unspecified */
+
+ /* Member fields are just after board_info header */
+ member = (u8 *)board_info + sizeof(*board_info);
+
+ len = fru_gen_type_len(member, manufacturer); /* Board Manufacturer */
+ member += len;
+ len = fru_gen_type_len(member, board_name); /* Board Product name */
+ member += len;
+ len = fru_gen_type_len(member, serial_no); /* Board Serial number */
+ member += len;
+ len = fru_gen_type_len(member, part_no); /* Board part number */
+ member += len;
+ len = fru_gen_type_len(member, "U-Boot generator"); /* File ID */
+ member += len;
+ len = fru_gen_type_len(member, revision); /* Revision */
+ member += len;
+
+ *member++ = 0xc1; /* Indication of no more fields */
+
+ len = member - (u8 *)board_info; /* Find current length */
+ len += 1; /* Add checksum there too for calculation */
+
+ modulo = len % 8;
+
+ if (modulo) {
+ /* Do not fill last item which is checksum */
+ for (pad = 0; pad < 8 - modulo; pad++)
+ *member++ = 0;
+
+ /* Increase structure size */
+ len += 8 - modulo;
+ }
+
+ board_info->len = len / 8; /* Size in multiples of 8 bytes */
+
+ *member = 0; /* Clear before calculation */
+ *member = 0 - fru_checksum((u8 *)board_info, len);
+
+ debug("checksum %x(addr %x)\n", *member, len);
+
+ env_set_hex("fru_addr", addr);
+ env_set_hex("filesize", (unsigned long)member - addr + 1);
+
+ return 0;
+}
+
static int fru_parse_board(unsigned long addr)
{
u8 i, type;
@@ -153,7 +250,9 @@ static int fru_display_board(struct fru_board_data *brd, int verbose)
"Product Name",
"Serial No",
"Part Number",
- "File ID"
+ "File ID",
+ /* Xilinx spec */
+ "Revision Number",
};
if (verbose) {