[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