Re: [PATCH] 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]>

On 8/18/26 05:29, Conor Dooley wrote:
> Hey Nathan,
>
> Sorry for missing this originally.
>
> On Fri, Jul 24, 2026 at 01:33:50PM -0400, Nathan Whitehorn wrote:
>> 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.
> These two I don't really mind, I can see the value in it.
>
>> 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.
> This I don't on the other hand. If linux needs it, it can go and get the
> information itself and if userspace needs it, I'd rather there was a
> small driver made to expose it on a dedicated interface rather than
> buried somewhere in the devicetree portion of sysfs. If it is just
> informational, the info has been emitted by U-Boot already.
> I'd also rather U-Boot didn't add undocumented properties to the
> devicetree.

Fair enough. It has been convenient for our use, but with the 
environment variables, we can also do this from a U-Boot script easily 
enough if we still want it. I'll remove this part for v2.

>> 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;
>> +	}
> blank line here please
>
>> +	designid[32] = 0;
> What is this doing?

This is meant to ensure NULL termination of the string.

>
>> +	for (idx = 0; idx < 16; idx++)
>> +		sprintf(&serialstring[2*idx], "%02x", device_serial_number[idx]);
> blank line here please.

Will do.

>
>> +	env_set("pf_serial_number", serialstring);
> Contrary to what I said yesterday, why not just make this
> "serial_number"? Not like the code is going to run on a non-polarfire.
>
>> +	env_set("pf_design_id", designid);
> Ditto here and below.

Sounds good to me.

>
>> +	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");
> Putting in the soc node doesn't really make sense anyway, the soc node
> is really the devices on axi buses.
> If this were to go anywhere, it should be in the root node.

I will just drop this part of the patch.
-Nathan

>
> Cheers,
> Conor.
>
>> +	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
>>

-- 
Nathan Whitehorn (he/him)
Associate Professor
Department of Physics and Astronomy
Michigan State University
Biomedical and Physical Sciences 3225
East Lansing, MI 48824
(517) 884-5563
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.