All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Simek <michal.simek@xilinx.com>
To: u-boot@lists.denx.de
Subject: [PATCH 3/4] xilinx: cmd: Add basic fru format generator
Date: Tue, 20 Oct 2020 16:50:29 +0200	[thread overview]
Message-ID: <63b0e9b6925d1e5c6d6a4e4a616e5a70e5de5073.1603205426.git.michal.simek@xilinx.com> (raw)
In-Reply-To: <cover.1603205426.git.michal.simek@xilinx.com>

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>
---

 board/xilinx/common/fru.c     |  20 ++++++-
 board/xilinx/common/fru.h     |  17 ++++++
 board/xilinx/common/fru_ops.c | 101 +++++++++++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/board/xilinx/common/fru.c b/board/xilinx/common/fru.c
index 0ab9f2a78bd9..ccf48723ff89 100644
--- a/board/xilinx/common/fru.c
+++ b/board/xilinx/common/fru.c
@@ -33,9 +33,23 @@ static int do_fru_display(struct cmd_tbl *cmdtp, int flag, int argc,
 	return CMD_RET_SUCCESS;
 }
 
+static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	unsigned long addr;
+
+	if (argc < cmdtp->maxargs)
+		return CMD_RET_USAGE;
+
+	addr = simple_strtoul(argv[2], NULL, 16);
+
+	return fru_generate(addr, argv[3], argv[4], argv[5], argv[6], argv[7]);
+}
+
 static struct cmd_tbl cmd_fru_sub[] = {
 	U_BOOT_CMD_MKENT(capture, 3, 0, do_fru_capture, "", ""),
 	U_BOOT_CMD_MKENT(display, 2, 0, do_fru_display, "", ""),
+	U_BOOT_CMD_MKENT(board_gen, 8, 0, do_fru_generate, "", ""),
 };
 
 static int do_fru(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -63,11 +77,15 @@ static char fru_help_text[] =
 	"capture <addr> - Parse and capture FRU table present at address.\n"
 	"fru display - Displays content of FRU table that was captured using\n"
 	"              fru capture command\n"
+	"fru board_gen <addr> <manufacturer> <board name> <serial number>\n"
+	"              <part number> <revision> - Generate FRU format with\n"
+	"              board info area filled based on parameters. <addr> is\n"
+	"              pointing to place where FRU is generated.\n"
 	;
 #endif
 
 U_BOOT_CMD(
-	fru, 3, 1, do_fru,
+	fru, 8, 1, do_fru,
 	"FRU table info",
 	fru_help_text
 )
diff --git a/board/xilinx/common/fru.h b/board/xilinx/common/fru.h
index a0413cf7f698..a3e652025714 100644
--- a/board/xilinx/common/fru.h
+++ b/board/xilinx/common/fru.h
@@ -20,6 +20,18 @@ struct fru_common_hdr {
 
 #define FRU_BOARD_MAX_LEN	32
 
+struct __packed fru_board_info_header {
+	u8 ver;
+	u8 len;
+	u8 lang_code;
+	u8 time[3];
+};
+
+struct __packed fru_board_info_member {
+	u8 type_len;
+	u8 *name;
+};
+
 struct fru_board_data {
 	u8 ver;
 	u8 len;
@@ -35,6 +47,9 @@ struct fru_board_data {
 	u8 part_number[FRU_BOARD_MAX_LEN];
 	u8 file_id_type_len;
 	u8 file_id[FRU_BOARD_MAX_LEN];
+	/* Xilinx custom fields */
+	u8 rev_type_len;
+	u8 rev[FRU_BOARD_MAX_LEN];
 };
 
 struct fru_table {
@@ -59,6 +74,8 @@ struct fru_table {
 
 int fru_display(int verbose);
 int fru_capture(unsigned long addr);
+int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
+		 char *serial_no, char *part_no, char *revision);
 u8 fru_checksum(u8 *addr, u8 len);
 
 extern struct fru_table fru_data;
diff --git a/board/xilinx/common/fru_ops.c b/board/xilinx/common/fru_ops.c
index 491e92a7afba..fc3add7d93da 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) {
-- 
2.28.0

  parent reply	other threads:[~2020-10-20 14:50 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-20 14:50 [PATCH 0/4] Add support for I2C Legacy/FRU decoding Michal Simek
2020-10-20 14:50 ` [PATCH 1/4] xilinx: common: Add Makefile to common folder Michal Simek
2020-10-20 14:50 ` [PATCH 2/4] xilinx: cmd: Add support for FRU commands Michal Simek
2020-10-20 14:50 ` Michal Simek [this message]
2020-10-20 14:50 ` [PATCH 4/4] xilinx: board: Add FRU decoder support Michal Simek
2020-10-27  7:25 ` [PATCH 0/4] Add support for I2C Legacy/FRU decoding Michal Simek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=63b0e9b6925d1e5c6d6a4e4a616e5a70e5de5073.1603205426.git.michal.simek@xilinx.com \
    --to=michal.simek@xilinx.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.