[PATCH v2] riscv: mpfs: Read and store FPGA design information on MPFS hardware.

Nathan Whitehorn <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
When working with systems with multiple FPGA firmwares, it is sometimes
useful to be able to use the same U-Boot and script conditional behavior
based on the FPGA firmware ID and version number. This, allows, for
example, flashing new FPGA images without flashing the bootloader and
letting U-Boot and the Linux kernel adapt appropriately.

This does two things with the information:
1. Prints the FPGA design ID and version to the console as part of U-Boot
   startup, which is helpful to a human working with the board.
2. Stores the same information, plus the already-acquired FPGA serial
   number, in a new set of environment variables (serial_number,
   design_id, design_ver [the version], and design_backlevel
   [minimum-version backlevel]). These can be used in a U-Boot script to
   load different kernels, device trees, etc. depending on the currently
   installed firmware, which allows U-Boot and the kernel to adapt
   cleanly to FPGA firmware updates that change accessible peripherals
   etc.

Signed-off-by: Nathan Whitehorn <[email protected]>
---
Changes for v2:
- Rename environment variables to remove the pf_ prefix
- Remove portions of the patch that added properties to the device tree
- Style changes
- Rebase after a5f93037f28624c612288e2d97604d73e03af5a3

Thanks to Conor Dooley and Tim Ouyang for helpful suggestions.

 board/microchip/mpfs_generic/mpfs_generic.c | 26 ++++++++++
 drivers/misc/mpfs_syscontroller.c           | 54 +++++++++++++++++++++
 include/mpfs-mailbox.h                      |  2 +
 3 files changed, 82 insertions(+)

diff --git a/board/microchip/mpfs_generic/mpfs_generic.c b/board/microchip/mpfs_generic/mpfs_generic.c
index f57f5f4046b..4423dd1e38c 100644
--- a/board/microchip/mpfs_generic/mpfs_generic.c
+++ b/board/microchip/mpfs_generic/mpfs_generic.c
@@ -114,7 +114,10 @@ int board_late_init(void)
 {
 	u32 ret;
 	int node;
+	int idx;
 	u8 device_serial_number[16] = {0};
+	char serialstring[33], designid[33];
+	u16 designver, designbacklevel;
 	void *blob = (void *)gd->fdt_blob;
 	struct udevice *dev;
 	struct mpfs_sys_serv *sys_serv_priv;
@@ -144,6 +147,29 @@ int board_late_init(void)
 		return -EINVAL;
 	}
 
+	/* Store design info and serial number in environment */
+	memset(designid, 0, sizeof(designid));
+	memset(serialstring, 0, sizeof(serialstring));
+
+	ret = mpfs_syscontroller_read_design_info(sys_serv_priv, designid,
+			&designver, &designbacklevel);
+	if (ret) {
+		printf("Cannot read device design information\n");
+		return -EINVAL;
+	}
+	for (idx = 0; idx < 16; idx++)
+		sprintf(&serialstring[2*idx], "%02x", device_serial_number[idx]);
+
+	env_set("serial_number", serialstring);
+	env_set("design_id", designid);
+	env_set_ulong("design_ver", designver);
+	env_set_ulong("design_backlevel", designbacklevel);
+
+	printf("FPGA Design name: %s\n", designid);
+	printf("FPGA Serial: %s\n", serialstring);
+	printf("Design version number %d (backlevel %d)\n", designver,
+			designbacklevel);
+
 	/* Update MAC address with device serial number */
 	mac_addr[0] = 0x00;
 	mac_addr[1] = 0x04;
diff --git a/drivers/misc/mpfs_syscontroller.c b/drivers/misc/mpfs_syscontroller.c
index b9aea7e1181..07a788db76e 100644
--- a/drivers/misc/mpfs_syscontroller.c
+++ b/drivers/misc/mpfs_syscontroller.c
@@ -152,6 +152,60 @@ int mpfs_syscontroller_read_sernum(struct mpfs_sys_serv *sys_serv_priv, u8 *devi
 }
 EXPORT_SYMBOL(mpfs_syscontroller_read_sernum);
 
+/**
+ * mpfs_syscontroller_read_design_info() - Use system service to read FPGA design info
+ * @sys_serv_priv:	system service private data
+ * @designid:		30-byte string name of top module in FPGA logic design
+ * 			NB: null termination is not guaranteed
+ * @designver:		version number of the FPGA design
+ * @backlevel:		programmed minimum allowed FPGA design version
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+int mpfs_syscontroller_read_design_info(struct mpfs_sys_serv *sys_serv_priv,
+		u8 *designid, u16 *designver, u16 *backlevel)
+{
+	unsigned long timeoutsecs = 300;
+	u8 data[36];
+	int ret;
+
+	struct mpfs_mss_response response = {
+		.resp_status = 0U,
+		.resp_msg = (u32 *)data,
+		.resp_size = sizeof(data)};
+	struct mpfs_mss_msg msg = {
+		.cmd_opcode = 2,
+		.cmd_data_size = CMD_DATA_SIZE,
+		.response = &response,
+		.cmd_data = CMD_DATA,
+		.mbox_offset = MBOX_OFFSET,
+		.resp_offset = RESP_OFFSET};
+
+	ret = mpfs_syscontroller_run_service(sys_serv_priv->sys_controller, &msg);
+	if (ret) {
+		dev_err(sys_serv_priv->sys_controller->chan.dev, "Service failed: %d, abort\n", ret);
+		return ret;
+	}
+
+	/* Receive the response */
+	ret = mpfs_syscontroller_recv_response(sys_serv_priv->sys_controller, &msg, timeoutsecs);
+	if (ret)
+		return ret;
+
+	debug("%s: Read successful %s\n",
+	      __func__, sys_serv_priv->sys_controller->chan.dev->name);
+
+	if (designid != NULL)
+		memcpy(designid, &data[2], 30);
+	if (designver != NULL)
+		memcpy(designver, &data[32], 2);
+	if (backlevel != NULL)
+		memcpy(backlevel, &data[34], 2);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpfs_syscontroller_read_design_info);
+
 static u16 mpfs_syscontroller_service_spi_copy(struct mpfs_sys_serv *sys_serv_priv, u64 dst_addr, u32 src_addr, u32 length)
 {
 	int ret;
diff --git a/include/mpfs-mailbox.h b/include/mpfs-mailbox.h
index 39c998e4c8d..bb9a162fb20 100644
--- a/include/mpfs-mailbox.h
+++ b/include/mpfs-mailbox.h
@@ -61,6 +61,8 @@ int mpfs_syscontroller_run_service(struct mpfs_syscontroller_priv *sys_controlle
 int mpfs_syscontroller_recv_response(struct mpfs_syscontroller_priv
 	*sys_controller, struct mpfs_mss_msg *msg, unsigned long timeout_ms);
 int mpfs_syscontroller_read_sernum(struct mpfs_sys_serv *sys_serv_priv, u8 *device_serial_number);
+int mpfs_syscontroller_read_design_info(struct mpfs_sys_serv *sys_serv_priv,
+		u8 *designid, u16 *designver, u16 *backlevel);
 void mpfs_syscontroller_process_dtbo(struct mpfs_sys_serv *sys_serv_priv);
 struct mpfs_syscontroller_priv *mpfs_syscontroller_get(struct udevice *dev);
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.