Skip to content
Permalink
Browse files
firmware: xilinx: Add support to get the image meta-header info
Adds binary sysfs interface support to read the image meta-header
info from the user pointed PDI image. This meta-header info
will be used by the application to extract the UID (Unique ID).
This UID info will helps the application to validate the PDI image
before programming the device.

To get the meta-header info from the user provided PDI,
user needs to follow the below steps.

1) Copy the PDI firmware file to the path /lib/firmware.
-> cp /media/binary.pdi  /lib/firmware

2) echo the firmware file to the firmware property file.
   firmware attribute requests an image (User_firmware.pdi )
   using firmware class.
-> echo binary.pdi>/sys/devices/platform/firmware:versal-firmware/firmware

3) To read the meta-header from the user pointed PDI images
   using binary sysfs file.
-> hexdump /sys/devices/platform/firmware:versal-firmware/meta-header-read

Signed-off-by: Nava kishore Manne <nava.manne@xilinx.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
  • Loading branch information
Nava kishore Manne authored and Michal Simek committed Dec 16, 2021
1 parent b4f460e commit 22272cc48b5399af99792722fa7004735b769e0a
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
@@ -48,6 +49,8 @@ static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
static unsigned long register_address;
static struct platform_device *em_dev;

static char image_name[NAME_MAX];

/**
* struct pm_api_feature_data - PM API Feature data
* @pm_api_id: PM API Id, used as key to index into hashmap
@@ -1153,6 +1156,37 @@ int zynqmp_pm_get_uid_info(const u64 address, const u32 size, u32 *count)
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_uid_info);

/**
* zynqmp_pm_get_meta_header - It is used to get image meta header Info
* @src: PDI Image source buffer address.
* @dst: Meta-header destination buffer address
* @size: Size of the PDI image.
* @count: Number of bytes read from the firmware.
*
* This function provides a support to get the image meta header Info
*
* Return: Returns status, either success or error+reason
*/
int zynqmp_pm_get_meta_header(const u64 src, const u64 dst,
const u32 size, u32 *count)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;

if (!count)
return -EINVAL;

ret = zynqmp_pm_invoke_fn(PM_GET_META_HEADER_INFO_LIST,
upper_32_bits(src), lower_32_bits(src),
upper_32_bits(dst), lower_32_bits(dst),
size, ret_payload);

*count = ret_payload[1];

return ret;
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_meta_header);

/**
* zynqmp_pm_fpga_read - Perform the fpga configuration readback
* @reg_numframes: Configuration register offset (or) Number of frames to read
@@ -2294,6 +2328,21 @@ static ssize_t feature_config_value_store(struct device *device,

static DEVICE_ATTR_RW(feature_config_value);

static ssize_t firmware_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int len;

len = strscpy(image_name, buf, NAME_MAX);
/* lose terminating \n */
if (image_name[len - 1] == '\n')
image_name[len - 1] = 0;

return count;
}
static DEVICE_ATTR_WO(firmware);

static struct attribute *zynqmp_firmware_attrs[] = {
&dev_attr_ggs0.attr,
&dev_attr_ggs1.attr,
@@ -2308,6 +2357,7 @@ static struct attribute *zynqmp_firmware_attrs[] = {
&dev_attr_last_reset_reason.attr,
&dev_attr_feature_config_id.attr,
&dev_attr_feature_config_value.attr,
&dev_attr_firmware.attr,
NULL,
};

@@ -2502,6 +2552,56 @@ static const struct bin_attribute uid_attr = {
.read = firmware_uid_get_data,
};

static ssize_t firmware_meta_header_get_data(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
struct device *kdev = kobj_to_dev(kobj);
const struct firmware *fw;
dma_addr_t dma_addr = 0;
char *kbuf;
u32 size;
int ret;

ret = request_firmware(&fw, image_name, kdev);
if (ret) {
dev_err(kdev, "Error requesting firmware %s\n", image_name);
return ret;
}

kbuf = dma_alloc_coherent(kdev, fw->size, &dma_addr, GFP_KERNEL);
if (!kbuf) {
ret = -ENOMEM;
goto free_firmware;
}

memcpy(kbuf, fw->data, fw->size);

/* Read from the firmware memory */
ret = zynqmp_pm_get_meta_header(dma_addr, dma_addr, fw->size, &size);
if (ret)
goto free_dma;

memcpy(buf, kbuf, size);
ret = size;

free_dma:
dma_free_coherent(kdev, fw->size, kbuf, dma_addr);
free_firmware:
release_firmware(fw);

return ret;
}

static const struct bin_attribute meta_header_attr = {
.attr.name = "meta-header-read",
.attr.mode = 00400,
.size = 1,
.read = firmware_meta_header_get_data,
};

static int zynqmp_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -2577,6 +2677,13 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
return ret;
}

ret = sysfs_create_bin_file(&pdev->dev.kobj, &meta_header_attr);
if (ret) {
dev_err(dev, "%s() Failed to create sysfs binary file for meta-header-read with error%d\n",
__func__, ret);
return ret;
}

zynqmp_pm_api_debugfs_init();

np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
@@ -49,6 +49,8 @@
/* To Get UID info list */
#define PM_GET_UID_INFO_LIST 0x705

#define PM_GET_META_HEADER_INFO_LIST 0x706

/* Number of 32bits values in payload */
#define PAYLOAD_ARG_CNT 4U

@@ -742,6 +744,9 @@ int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config,
u32 value);
int zynqmp_pm_set_usb_config(u32 node, enum pm_usb_config_type config,
u32 value);
int zynqmp_pm_get_meta_header(const u64 src, const u64 dst,
const u32 size, u32 *count);

#else
static inline int zynqmp_pm_get_api_version(u32 *version)
{
@@ -1235,6 +1240,12 @@ static inline int zynqmp_pm_set_usb_config(u32 node,
{
return -ENODEV;
}

int zynqmp_pm_get_meta_header(const u64 src, const u64 dst,
const u32 size, u32 *count)
{
return -ENODEV;
}
#endif

#endif /* __FIRMWARE_ZYNQMP_H__ */

0 comments on commit 22272cc

Please sign in to comment.