[U-Boot] [PATCHv1 4/5] arm: socfpga: stratix10: add console commands for RSU support

richard.gong at linux.intel.com richard.gong at linux.intel.com
Mon Sep 9 17:35:25 UTC 2019


From: Richard Gong <richard.gong at intel.com>

The Intel Remote System Update (RSU) provides a way for users to update
the QSPI configuration bitstream of a Intel Stratix 10 SoC device with
significantly reduced risk of corrupting the bitstream storage and
bricking the system.

This patch provides console commands to exercises the RSU APIs at
Intel Stratix10 SoC. The commands use the term "slot" to refer to a
sub-partition which is intended to contain a production image, and the
term "priority" to refer to the fact that the images are loaded by
firmware in the defined order.

The provided console commands are below, you can also refer to the
header file rsu.h for the details of RSU APIs:
	slot_count
	slot_by_name
	slot_get_info
	slot_size
	slot_priority
	slot_erase
	slot_program_buf
	slot_program_buf_raw
	slot_verify_buf
	slot_verify_buf_raw
	slot_enable
	slot_disable
	slot_load
	slot_load_factory
	slot_rename
	status_log
	list
	dtb
	update
	notify
	clear_error_status
	reset_retry_counter

Signed-off-by: Richard Gong <richard.gong at intel.com>
Signed-off-by: Radu Bacrau <radu.bacrau at intel.com>
Signed-off-by: Chin Liang See <chin.liang.see at intel.com>
---
 arch/arm/mach-socfpga/include/mach/rsu_s10.h |  46 ++
 arch/arm/mach-socfpga/rsu_s10.c              | 817 +++++++++++++++++++++++++++
 2 files changed, 863 insertions(+)
 create mode 100644 arch/arm/mach-socfpga/include/mach/rsu_s10.h
 create mode 100644 arch/arm/mach-socfpga/rsu_s10.c

diff --git a/arch/arm/mach-socfpga/include/mach/rsu_s10.h b/arch/arm/mach-socfpga/include/mach/rsu_s10.h
new file mode 100644
index 0000000..9a4ec53
--- /dev/null
+++ b/arch/arm/mach-socfpga/include/mach/rsu_s10.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Intel Corporation
+ *
+ */
+#ifndef _RSU_S10_H_
+#define _RSU_S10_H_
+
+extern u32 smc_rsu_update_address;
+
+#define RSU_S10_CPB_MAGIC_NUMBER	0x57789609
+#define RSU_S10_SPT_MAGIC_NUMBER	0x57713427
+
+#define SPT0_INDEX	1
+#define SPT1_INDEX	3
+
+/* CMF pointer block */
+struct socfpga_rsu_s10_cpb {
+	u32 magic_number;
+	u32 header_size;
+	u32 total_size;
+	u32 reserved1;
+	u32 iptab_offset;
+	u32 nslots;
+	u32 reserved2;
+	u64 pointer_slot[508];
+};
+
+/* sub partition slot */
+struct socfpga_rsu_s10_spt_slot {
+	char name[16];
+	u32 offset[2];
+	u32 length;
+	u32 flag;
+};
+
+/* sub partition table */
+struct socfpga_rsu_s10_spt {
+	u32 magic_number;
+	u32 version;
+	u32 entries;
+	u32 reserved[5];
+	struct socfpga_rsu_s10_spt_slot spt_slot[127];
+};
+
+#endif /* _RSU_S10_H_ */
diff --git a/arch/arm/mach-socfpga/rsu_s10.c b/arch/arm/mach-socfpga/rsu_s10.c
new file mode 100644
index 0000000..8127e08
--- /dev/null
+++ b/arch/arm/mach-socfpga/rsu_s10.c
@@ -0,0 +1,817 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2019 Intel Corporation
+ *
+ */
+
+#include <common.h>
+#include <linux/errno.h>
+#include <asm/arch/mailbox_s10.h>
+#include <asm/arch/rsu.h>
+#include <asm/arch/rsu_s10.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct socfpga_rsu_s10_cpb rsu_cpb = {0};
+struct socfpga_rsu_s10_spt rsu_spt = {0};
+u32 rsu_spt0_offset = 0, rsu_spt1_offset = 0;
+
+static int initialized;
+
+static int rsu_print_status(void)
+{
+	struct rsu_status_info status_info;
+
+	if (mbox_rsu_status((u32 *)&status_info, sizeof(status_info))) {
+		puts("RSU: Firmware or flash content not supporting RSU\n");
+		return -ENOTSUPP;
+	}
+	puts("RSU: Remote System Update Status\n");
+	printf("Current Image\t: 0x%08llx\n", status_info.current_image);
+	printf("Last Fail Image\t: 0x%08llx\n", status_info.fail_image);
+	printf("State\t\t: 0x%08x\n", status_info.state);
+	printf("Version\t\t: 0x%08x\n", status_info.version);
+	printf("Error location\t: 0x%08x\n", status_info.error_location);
+	printf("Error details\t: 0x%08x\n", status_info.error_details);
+	if (status_info.version)
+		printf("Retry counter\t: 0x%08x\n", status_info.retry_counter);
+
+	return 0;
+}
+
+static void rsu_print_spt_slot(void)
+{
+	int i;
+
+	puts("RSU: Sub-partition table content\n");
+	for (i = 0; i < rsu_spt.entries; i++) {
+		printf("%16s\tOffset:0x%08x%08x\tLength:0x%08x\tFlag:0x%08x\n",
+		       rsu_spt.spt_slot[i].name,
+		       rsu_spt.spt_slot[i].offset[1],
+		       rsu_spt.spt_slot[i].offset[0],
+		       rsu_spt.spt_slot[i].length,
+		       rsu_spt.spt_slot[i].flag);
+	}
+}
+
+static void rsu_print_cpb_slot(void)
+{
+	int i, j = 1;
+
+	puts("RSU: CMF pointer block's image pointer list\n");
+	for (i = rsu_cpb.nslots - 1; i >= 0; i--) {
+		if (rsu_cpb.pointer_slot[i] != ~0 &&
+		    rsu_cpb.pointer_slot[i] != 0) {
+			printf("Priority %d Offset: 0x%016llx nslot: %d\n",
+			       j, rsu_cpb.pointer_slot[i], i);
+			j++;
+		}
+	}
+}
+
+static u32 rsu_spt_slot_find_cpb(void)
+{
+	int i;
+
+	for (i = 0; i < rsu_spt.entries; i++) {
+		if (strstr(rsu_spt.spt_slot[i].name, "CPB0"))
+			return rsu_spt.spt_slot[i].offset[0];
+	}
+	puts("RSU: Cannot find SPT0 entry from sub-partition table\n");
+	return 0;
+}
+
+static u32 rsu_get_boot_part_len(void)
+{
+	int i;
+	u32 offset = 0, len = 0;
+
+	/* look for last entry that has largest offset */
+	for (i = 0; i < rsu_spt.entries; i++) {
+		if (rsu_spt.spt_slot[i].offset[0] > offset) {
+			offset = rsu_spt.spt_slot[i].offset[0];
+			len = rsu_spt.spt_slot[i].length;
+		}
+	}
+
+	/* With the len, we shall know the boot partition size */
+	len += offset;
+	return roundup(len, 64 << 10);	/* align to 64kB, flash sector size */
+}
+
+int rsu_spt_cpb_list(int argc, char * const argv[])
+{
+	u32 spt_offset[4];
+	u32 cpb_offset;
+	int err;
+	struct spi_flash *flash;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* print the RSU status */
+	err = rsu_print_status();
+	if (err)
+		return err;
+
+	/* retrieve the sub-partition table (spt) offset from firmware */
+	if (mbox_rsu_get_spt_offset(spt_offset, 4)) {
+		puts("RSU: Error from mbox_rsu_get_spt_offset\n");
+		return -ECOMM;
+	}
+	rsu_spt0_offset = spt_offset[SPT0_INDEX];
+	rsu_spt1_offset = spt_offset[SPT1_INDEX];
+
+	/* update into U-Boot env so we can update into DTS later */
+	env_set_hex("rsu_sbt0", rsu_spt0_offset);
+	env_set_hex("rsu_sbt1", rsu_spt1_offset);
+	printf("RSU: Sub-partition table 0 offset 0x%08x\n", rsu_spt0_offset);
+	printf("RSU: Sub-partition table 1 offset 0x%08x\n", rsu_spt1_offset);
+
+	/* retrieve sub-partition table (spt) from flash */
+	flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+				CONFIG_SF_DEFAULT_CS,
+				CONFIG_SF_DEFAULT_SPEED,
+				CONFIG_SF_DEFAULT_MODE);
+	if (!flash) {
+		puts("RSU: SPI probe failed.\n");
+		return -ENODEV;
+	}
+	if (spi_flash_read(flash, rsu_spt0_offset, sizeof(rsu_spt), &rsu_spt)) {
+		puts("RSU: spi_flash_read failed\n");
+		return -EIO;
+	}
+
+	/* valid the sub-partition table (spt) magic number */
+	if (rsu_spt.magic_number != RSU_S10_SPT_MAGIC_NUMBER) {
+		printf("RSU: SPT magic number is not match\n");
+		return -EFAULT;
+	}
+
+	/* list the sub-partition table (spt) content */
+	rsu_print_spt_slot();
+
+	/* locate where is CMF pointer block (cpb) */
+	cpb_offset = rsu_spt_slot_find_cpb();
+	if (!cpb_offset)
+		return -ENXIO;
+	printf("RSU: CMF pointer block offset 0x%08x\n", cpb_offset);
+
+	/* retrieve CMF pointer block (cpb) from flash */
+	if (spi_flash_read(flash, cpb_offset, sizeof(rsu_cpb), &rsu_cpb)) {
+		puts("RSU: spi_flash_read failed\n");
+		return -EIO;
+	}
+
+	/* valid the CMF pointer block (cpb) magic number */
+	if (rsu_cpb.magic_number != RSU_S10_CPB_MAGIC_NUMBER) {
+		printf("RSU: CMF pointer block magic number not match 0x%08x\n",
+		       rsu_cpb.magic_number);
+		return -EFAULT;
+	}
+
+	/* list the CMF pointer block (cpb) content */
+	rsu_print_cpb_slot();
+
+	return 0;
+}
+
+int rsu_update(int argc, char * const argv[])
+{
+	u32 flash_offset[2];
+	u64 addr;
+	char *endp;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	addr = simple_strtoul(argv[1], &endp, 16);
+
+	flash_offset[0] = lower_32_bits(addr);
+	flash_offset[1] = upper_32_bits(addr);
+
+	printf("RSU: RSU update to 0x%08x%08x\n",
+	       flash_offset[1], flash_offset[0]);
+	mbox_rsu_update(flash_offset);
+	return 0;
+}
+
+int rsu_dtb(int argc, char * const argv[])
+{
+	char flash0_string[100];
+	const char *fdt_flash0;
+	int nodeoffset, len;
+	u32 reg[2];
+	int err;
+
+	/* Extracting RSU info from bitstream */
+	err = rsu_spt_cpb_list(argc, argv);
+	if (err == -ENOTSUPP)
+		return 0;
+	else if (err)
+		return err;
+
+	/* Extract the flash0's reg from Linux DTB */
+	nodeoffset = fdt_path_offset(working_fdt, "/__symbols__");
+	if (nodeoffset < 0) {
+		puts("DTB: __symbols__ node not found\n");
+		puts("Ensure you load kernel dtb and fdt addr\n");
+		return -ENODEV;
+	}
+	fdt_flash0 = fdt_getprop(working_fdt, nodeoffset, "qspi_boot", &len);
+	if (!fdt_flash0) {
+		puts("DTB: qspi_boot alias node not found. Check your dts\n");
+		return -ENODEV;
+	}
+	strcpy(flash0_string, fdt_flash0);
+	printf("DTB: qspi_boot node at %s\n", flash0_string);
+
+	/* assemble new reg value for boot partition */
+	len = rsu_get_boot_part_len();
+	reg[0] = cpu_to_fdt32(rsu_spt0_offset);
+	reg[1] = cpu_to_fdt32(len  - rsu_spt0_offset);
+
+	/* update back to Linux DTB */
+	nodeoffset = fdt_path_offset(working_fdt, flash0_string);
+	if (nodeoffset < 0) {
+		printf("DTB: %s node not found\n", flash0_string);
+		return -ENODEV;
+	}
+	return fdt_setprop(working_fdt, nodeoffset, "reg", reg, sizeof(reg));
+}
+
+static int slot_count(int argc, char * const argv[])
+{
+	int count;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	count = rsu_slot_count();
+	if (count < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Number of slots = %d.\n", count);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_by_name(int argc, char * const argv[])
+{
+	char *name = argv[1];
+	int slot;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = rsu_slot_by_name(name);
+	if (slot < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot name '%s' is %d.\n", name, slot);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_get_info(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	struct rsu_slot_info info;
+	int ret;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	ret = rsu_slot_get_info(slot, &info);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	printf("NAME: %s\n", info.name);
+	printf("OFFSET: 0x%016llX\n", info.offset);
+	printf("SIZE: 0x%08X\n", info.size);
+	if (info.priority)
+		printf("PRIORITY: %i\n", info.priority);
+	else
+		printf("PRIORITY: [disabled]\n");
+
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_size(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	int size;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	size = rsu_slot_size(slot);
+	if (size < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d size = %d.\n", slot, size);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_priority(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	int priority;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	priority = rsu_slot_priority(slot);
+	if (priority < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d priority = %d.\n", slot, priority);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_erase(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	int ret;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	ret = rsu_slot_erase(slot);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d erased.\n", slot);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_program_buf(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	u64 address;
+	int size;
+	int ret;
+	int addr_lo;
+	int addr_hi;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	address = simple_strtoul(argv[2], &endp, 16);
+	size = simple_strtoul(argv[3], &endp, 16);
+
+	ret = rsu_slot_program_buf(slot, (void *)address, size);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	addr_hi = upper_32_bits(address);
+	addr_lo = lower_32_bits(address);
+	printf("Slot %d was programmed with buffer=0x%08x%08x size=%d.\n",
+	       slot, addr_hi, addr_lo, size);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_program_buf_raw(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	u64 address;
+	int size;
+	int ret;
+	int addr_lo;
+	int addr_hi;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	address = simple_strtoul(argv[2], &endp, 16);
+	size = simple_strtoul(argv[3], &endp, 16);
+
+	ret = rsu_slot_program_buf_raw(slot, (void *)address, size);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	addr_hi = upper_32_bits(address);
+	addr_lo = lower_32_bits(address);
+	printf("Slot %d was programmed with raw buffer=0x%08x%08x size=%d.\n",
+	       slot, addr_hi, addr_lo, size);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_verify_buf(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	u64 address;
+	int size;
+	int ret;
+	int addr_lo;
+	int addr_hi;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	address = simple_strtoul(argv[2], &endp, 16);
+	size = simple_strtoul(argv[3], &endp, 16);
+
+	ret = rsu_slot_verify_buf(slot, (void *)address, size);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	addr_hi = upper_32_bits(address);
+	addr_lo = lower_32_bits(address);
+	printf("Slot %d was verified with buffer=0x%08x%08x size=%d.\n",
+	       slot, addr_hi, addr_lo, size);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_verify_buf_raw(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	u64 address;
+	int size;
+	int ret;
+	int addr_lo;
+	int addr_hi;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	address = simple_strtoul(argv[2], &endp, 16);
+	size = simple_strtoul(argv[3], &endp, 16);
+
+	ret = rsu_slot_verify_buf_raw(slot, (void *)address, size);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	addr_hi = upper_32_bits(address);
+	addr_lo = lower_32_bits(address);
+	printf("Slot %d was verified with raw buffer=0x%08x%08x size=%d.\n",
+	       slot, addr_hi, addr_lo, size);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_enable(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	int ret;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	ret = rsu_slot_enable(slot);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d enabled.\n", slot);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_disable(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	int ret;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	ret = rsu_slot_disable(slot);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d disabled.\n", slot);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_load(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	int ret;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	ret = rsu_slot_load(slot);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d loading.\n", slot);
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_load_factory(int argc, char * const argv[])
+{
+	int ret;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	ret = rsu_slot_load_factory();
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Factory loading.\n");
+	return CMD_RET_SUCCESS;
+}
+
+static int slot_rename(int argc, char * const argv[])
+{
+	int slot;
+	char *endp;
+	char *name;
+	int ret;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	slot = simple_strtoul(argv[1], &endp, 16);
+	name = argv[2];
+
+	ret = rsu_slot_rename(slot, name);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Slot %d renamed to %s.\n", slot, name);
+	return CMD_RET_SUCCESS;
+}
+
+static int status_log(int argc, char * const argv[])
+{
+	struct rsu_status_info info;
+	int ret;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	if (!initialized) {
+		if (rsu_init(NULL))
+			return CMD_RET_FAILURE;
+
+		initialized = 1;
+	}
+
+	ret = rsu_status_log(&info);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	printf("Current Image\t: 0x%08llx\n", info.current_image);
+	printf("Last Fail Image\t: 0x%08llx\n", info.fail_image);
+	printf("State\t\t: 0x%08x\n", info.state);
+	printf("Version\t\t: 0x%08x\n", info.version);
+	printf("Error location\t: 0x%08x\n", info.error_location);
+	printf("Error details\t: 0x%08x\n", info.error_details);
+	if (info.version)
+		printf("Retry counter\t: 0x%08x\n", info.retry_counter);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int rsu_notify(int argc, char * const argv[])
+{
+	u32 stage;
+	char *endp;
+	int ret;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	stage = simple_strtoul(argv[1], &endp, 16) & GENMASK(0, 15);
+	ret = mbox_hps_stage_notify(stage);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	return CMD_RET_SUCCESS;
+}
+
+static int clear_error_status(int argc, char * const argv[])
+{
+	int arg;
+	int ret;
+
+	arg = RSU_NOTIFY_IGNORE_STAGE | RSU_NOTIFY_CLEAR_ERROR_STATUS;
+	ret = mbox_hps_stage_notify(arg);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	return CMD_RET_SUCCESS;
+}
+
+static int reset_retry_counter(int argc, char * const argv[])
+{
+	int arg;
+	int ret;
+
+	arg = RSU_NOTIFY_IGNORE_STAGE | RSU_NOTIFY_RESET_RETRY_COUNTER;
+	ret = mbox_hps_stage_notify(arg);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	return CMD_RET_SUCCESS;
+}
+
+struct func_t {
+	const char *cmd_string;
+	int (*func_ptr)(int cmd_argc, char * const cmd_argv[]);
+};
+
+static const struct func_t rsu_func_t[] = {
+	{"dtb", rsu_dtb},
+	{"list", rsu_spt_cpb_list},
+	{"slot_by_name", slot_by_name},
+	{"slot_count", slot_count},
+	{"slot_disable", slot_disable},
+	{"slot_enable", slot_enable},
+	{"slot_erase", slot_erase},
+	{"slot_get_info", slot_get_info},
+	{"slot_load", slot_load},
+	{"slot_load_factory", slot_load_factory},
+	{"slot_priority", slot_priority},
+	{"slot_program_buf", slot_program_buf},
+	{"slot_program_buf_raw", slot_program_buf_raw},
+	{"slot_rename", slot_rename},
+	{"slot_size", slot_size},
+	{"slot_verify_buf", slot_verify_buf},
+	{"slot_verify_buf_raw", slot_verify_buf_raw},
+	{"status_log", status_log},
+	{"update", rsu_update},
+	{"notify", rsu_notify},
+	{"clear_error_status", clear_error_status},
+	{"reset_retry_counter", reset_retry_counter}
+};
+
+int do_rsu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	const char *cmd;
+	int i;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	cmd = argv[1];
+	--argc;
+	++argv;
+
+	for (i = 0; i < ARRAY_SIZE(rsu_func_t); i++) {
+		if (!strcmp(cmd, rsu_func_t[i].cmd_string))
+			return rsu_func_t[i].func_ptr(argc, argv);
+	}
+
+	return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(rsu, 5, 1, do_rsu,
+	   "SoCFPGA Stratix10 SoC Remote System Update",
+	   "dtb   - Update Linux DTB qspi-boot parition offset with spt0 value\n"
+	   "list  - List down the available bitstreams in flash\n"
+	   "slot_by_name <name> - find slot by name and display the slot number\n"
+	   "slot_count - display the slot count\n"
+	   "slot_disable <slot> - remove slot from CPB\n"
+	   "slot_enable <slot> - make slot the highest priority\n"
+	   "slot_erase <slot> - erase slot\n"
+	   "slot_get_info <slot> - display slot information\n"
+	   "slot_load <slot> - load slot immediately\n"
+	   "slot_load_factory - load factory immediately\n"
+	   "slot_priority <slot> - display slot priority\n"
+	   "slot_program_buf <slot> <buffer> <size> - program buffer into slot, and make it highest priority\n"
+	   "slot_program_buf_raw <slot> <buffer> <size> - program raw buffer into slot\n"
+	   "slot_rename <slot> <name> - rename slot\n"
+	   "slot_size <slot> - display slot size\n"
+	   "slot_verify_buf <slot> <buffer> <size> - verify slot contents against buffer\n"
+	   "slot_verify_buf_raw <slot> <buffer> <size> - verify slot contents against raw buffer\n"
+	   "status_log - display RSU status\n"
+	   "update <flash_offset> - Initiate firmware to load bitstream as specified by flash_offset\n"
+	   "notify <value> - Let SDM know the current state of HPS software\n"
+	   "clear_error_status - clear the RSU error status\n"
+	   "reset_retry_counter - reset the RSU retry counter\n"
+	   ""
+);
-- 
2.7.4



More information about the U-Boot mailing list