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 three 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 (pf_serial_number, pf_design_id, pf_design_ver [the version], and pf_design_backl [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. 3. Stores the same information in the device tree (under /soc) as fpga-design-version, fpga-design, and fpga-design-version-backlevel. These things are also available through the Linux system-controller driver directly, but it is handy to have them in the device tree as well. Signed-off-by: Nathan Whitehorn <[email protected]> --- board/microchip/mpfs_generic/mpfs_generic.c | 31 ++++++++++++ drivers/misc/mpfs_syscontroller.c | 52 +++++++++++++++++++++ include/mpfs-mailbox.h | 1 + 3 files changed, 84 insertions(+) diff --git a/board/microchip/mpfs_generic/mpfs_generic.c b/board/microchip/mpfs_generic/mpfs_generic.c index f57f5f4046b..469e914e083 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,24 @@ int board_late_init(void) return -EINVAL; } + /* Store design info and serial number in environment */ + ret = mpfs_syscontroller_read_design_info(sys_serv_priv, designid, &designver, &designbacklevel); + if (ret) { + printf("Cannot read device design information\n"); + return -EINVAL; + } + designid[32] = 0; + for (idx = 0; idx < 16; idx++) + sprintf(&serialstring[2*idx], "%02x", device_serial_number[idx]); + env_set("pf_serial_number", serialstring); + env_set("pf_design_id", designid); + env_set_ulong("pf_design_ver", designver); + env_set_ulong("pf_design_backl", 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; @@ -182,6 +203,16 @@ int ft_board_setup(void *blob, struct bd_info *bd) u32 ret; int node; + node = fdt_path_offset(blob, "/soc"); + if (node >= 0) { + if (env_get("pf_design_ver") != NULL) + fdt_setprop(blob, node, "fpga-design-version", env_get("pf_design_ver"), strlen(env_get("pf_design_id")) + 1); + if (env_get("pf_design_backl") != NULL) + fdt_setprop(blob, node, "fpga-design-version-backlevel", env_get("pf_design_backl"), strlen(env_get("pf_design_backl")) + 1); + if (env_get("pf_design_id") != NULL) + fdt_setprop(blob, node, "fpga-design", env_get("pf_design_id"), strlen(env_get("pf_design_id")) + 1); + } + node = fdt_path_offset(blob, "/soc/ethernet@20110000"); if (node >= 0) { ret = fdt_setprop(blob, node, "local-mac-address", mac_addr, 6); diff --git a/drivers/misc/mpfs_syscontroller.c b/drivers/misc/mpfs_syscontroller.c index f608d5518b0..ef03ce7b262 100644 --- a/drivers/misc/mpfs_syscontroller.c +++ b/drivers/misc/mpfs_syscontroller.c @@ -129,6 +129,58 @@ int mpfs_syscontroller_read_sernum(struct mpfs_sys_serv *sys_serv_priv, u8 *devi } EXPORT_SYMBOL(mpfs_syscontroller_read_sernum); +/** + * mpfs_syscontroller_read_sernum() - Use system service to read the device serial number + * @sys_serv_priv: system service private data + * @device_serial_number: device serial number + * + * 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 = mbox_recv(&sys_serv_priv->sys_controller->chan, &msg, timeoutsecs); + if (ret) { + dev_err(sys_serv_priv->sys_controller->chan.dev, "Service failed: %d, abort. Failure: %u\n", ret, msg.response->resp_status); + 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 c0ff327a4ce..5c1ade3e918 100644 --- a/include/mpfs-mailbox.h +++ b/include/mpfs-mailbox.h @@ -59,6 +59,7 @@ struct mpfs_sys_serv { int mpfs_syscontroller_run_service(struct mpfs_syscontroller_priv *sys_controller, struct mpfs_mss_msg *msg); 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.34.1
