linux-gbmc: aspeed-g7: edaf: device driver for moving data
Add a device driver to move the blob to the given reserved memory.
Tested:
````
// device nodes for dual nodes created successfully.
:~# ls -la /dev/edaf-map*
crw------- 1 root root 248, 0 Jul 10 23:14 /dev/edaf-map0
crw------- 1 root root 247, 0 Jul 10 23:14 /dev/edaf-map1
```
Google-Bug-Id: 401416725
Change-Id: I8fd15c3c027dee540049855e6907a9cd734a80a6
Signed-off-by: wukaihua <eason.kh.wu@fii-na.corp-partner.google.com>
diff --git a/recipes-kernel/linux/files/0030-data-transfer-to-reserved-memory-for-edaf.patch b/recipes-kernel/linux/files/0030-data-transfer-to-reserved-memory-for-edaf.patch
new file mode 100644
index 0000000..2ccbfe8
--- /dev/null
+++ b/recipes-kernel/linux/files/0030-data-transfer-to-reserved-memory-for-edaf.patch
@@ -0,0 +1,324 @@
+From 1182b60689cd5034c9ee3fd150e968bd36f4972c Mon Sep 17 00:00:00 2001
+From: wukaihua <eason.kh.wu@fii-na.corp-partner.google.com>
+Date: Fri, 11 Jul 2025 12:45:14 +0800
+Subject: [PATCH] data transfer to reserved memory for edaf
+
+Signed-off-by: wukaihua <eason.kh.wu@fii-na.corp-partner.google.com>
+---
+ drivers/misc/Kconfig | 8 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/ast2700-fii-edaf-map.c | 274 ++++++++++++++++++++++++++++
+ 3 files changed, 283 insertions(+)
+ create mode 100644 drivers/misc/ast2700-fii-edaf-map.c
+
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 36ddfdbb5..c68d205b7 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -562,6 +562,14 @@ config TPS6594_PFSM
+ This driver can also be built as a module. If so, the module
+ will be called tps6594-pfsm.
+
++config AST2700_FII_EDAF_MAP
++ tristate "FXN EDAF MAP on AST2700"
++ select REGMAP
++ select MFD_SYSCON
++ default ARCH_ASPEED
++ help
++ Transfer data from/to reserved memory
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/gbmc/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index c817fa6a9..c10994a67 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -68,3 +68,4 @@ obj-$(CONFIG_TMR_MANAGER) += xilinx_tmr_manager.o
+ obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o
+ obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o
+ obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o
++obj-$(CONFIG_AST2700_FII_EDAF_MAP) += ast2700-fii-edaf-map.o
+diff --git a/drivers/misc/ast2700-fii-edaf-map.c b/drivers/misc/ast2700-fii-edaf-map.c
+new file mode 100644
+index 000000000..f8c131f28
+--- /dev/null
++++ b/drivers/misc/ast2700-fii-edaf-map.c
+@@ -0,0 +1,274 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/of_device.h>
++#include <linux/of_address.h>
++#include <linux/regmap.h>
++#include <linux/sizes.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/cdev.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/err.h>
++#include <linux/types.h>
++#include <linux/semaphore.h>
++
++#define DEVICE_NAME "edaf-map"
++#define READ_SIZE 4096
++
++static DEFINE_IDA(fii_edaf_mapping_ida);
++static struct semaphore sem;
++
++struct edaf_blob_ioctl {
++ u64 offset;
++ u64 trans_bytes;
++ u8 buf[READ_SIZE];
++};
++
++#define MAP_TO_MEM _IOW(0xb2, 0, struct edaf_blob_ioctl)
++#define MAP_TO_DEV _IOR(0xb2, 1, struct edaf_blob_ioctl)
++
++static dev_t edaf_devno;
++static struct class *edaf_class;
++struct edaf_chardev {
++ struct device parent_dev;
++ struct device *chdev;
++ int (*cntlwrfn)(struct edaf_blob_ioctl *blob_ioctl, struct device *dev);
++ int (*cntlrdfn)(struct edaf_blob_ioctl *blob_ioctl, struct device *dev);
++ struct cdev edafcdev;
++};
++
++struct edaf_map {
++ u8 node;
++ char *devname;
++ volatile void *mem_addr;
++ struct resource res;
++};
++
++static int edaf_chdev_open(struct inode *inode, struct file *filp) {
++ struct edaf_chardev *edaf_cdev;
++
++ edaf_cdev = container_of(inode->i_cdev, struct edaf_chardev, edafcdev);
++ filp->private_data = edaf_cdev;
++ return 0;
++}
++
++static int edaf_chdev_close(struct inode *inode, struct file *filp) {
++ filp->private_data = NULL;
++ return 0;
++}
++
++int wrfn(struct edaf_blob_ioctl *blob_ioctl, struct device *dev) {
++ struct platform_device *pdev;
++ struct edaf_map *edaf;
++
++ pdev = container_of(dev, struct platform_device, dev);
++ edaf = (struct edaf_map *) platform_get_drvdata(pdev);
++
++ edaf->mem_addr = memremap(edaf->res.start,
++ edaf->res.end - edaf->res.start + 1, MEMREMAP_WT);
++ if (!edaf->mem_addr) {
++ dev_err(dev, "Error returned from memremap()\n");
++ return -ENOMEM;
++ }
++ memcpy(edaf->mem_addr + blob_ioctl->offset, blob_ioctl->buf, blob_ioctl->trans_bytes);
++ wmb();
++ memunmap(edaf->mem_addr);
++ return 0;
++}
++
++int rdfn(struct edaf_blob_ioctl *blob_ioctl, struct device *dev) {
++ struct platform_device *pdev;
++ struct edaf_map *edaf;
++
++ pdev = container_of(dev, struct platform_device, dev);
++ edaf = (struct edaf_map *) platform_get_drvdata(pdev);
++
++ edaf->mem_addr = memremap(edaf->res.start,
++ edaf->res.end - edaf->res.start + 1, MEMREMAP_WT);
++ if (!edaf->mem_addr) {
++ dev_err(dev, "Error returned from memremap()\n");
++ return -ENOMEM;
++ }
++
++ rmb();
++ memcpy(blob_ioctl->buf, edaf->mem_addr + blob_ioctl->offset, READ_SIZE);
++ memunmap(edaf->mem_addr);
++ blob_ioctl->offset += READ_SIZE;
++ blob_ioctl->trans_bytes = READ_SIZE;
++ return 0;
++}
++
++static long mem_mapping_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
++ struct edaf_blob_ioctl blob_ioctl;
++ struct edaf_chardev *edaf_cdev;
++ long rc = 0;
++
++ down(&sem);
++ edaf_cdev = filp->private_data;
++ switch (cmd) {
++ case MAP_TO_MEM:
++ if (copy_from_user(&blob_ioctl, (struct edaf_blob_ioctl *) arg,
++ sizeof(struct edaf_blob_ioctl)) != 0) {
++ pr_err("edaf %s(): error occurs when receiving info\n", __func__);
++ rc = -EFAULT;
++ break;
++ }
++ edaf_cdev->cntlwrfn(&blob_ioctl, &edaf_cdev->parent_dev);
++ break;
++ case MAP_TO_DEV:
++ if (copy_from_user(&blob_ioctl, (struct edaf_blob_ioctl *) arg,
++ sizeof(struct edaf_blob_ioctl)) != 0) {
++ pr_err("edaf %s(): error occurs when receiving info\n", __func__);
++ rc = -EFAULT;
++ break;
++ }
++ edaf_cdev->cntlrdfn(&blob_ioctl, &edaf_cdev->parent_dev);
++ if (copy_to_user((struct edaf_blob_ioctl *) arg, &blob_ioctl,
++ sizeof(struct edaf_blob_ioctl)) != 0) {
++ pr_err("edaf %s(): error occurs when data returns\n", __func__);
++ rc = -EFAULT;
++ }
++ break;
++ default:
++ pr_err("edaf %s(): unsupport command\n", __func__);
++ rc = -EINVAL;
++ break;
++ }
++
++ up(&sem);
++ return rc;
++}
++
++static const struct file_operations edaf_map_fops = {
++ .owner = THIS_MODULE,
++ .open = edaf_chdev_open,
++ .release = edaf_chdev_close,
++ .unlocked_ioctl = mem_mapping_ioctl,
++};
++
++static int init_dev_node(char *devname) {
++ int rc = 0;
++
++ rc = alloc_chrdev_region(&edaf_devno, 0, 1, devname);
++ if (rc < 0) {
++ pr_err("%s(): err %d when alloc chrdev region\n", __func__, rc);
++ return rc;
++ }
++ edaf_class = class_create(devname);
++ if (edaf_class == NULL) {
++ pr_err("%s(): err when creating chrdev device\n", __func__);
++ goto unreg_chrdev;
++ }
++ return rc;
++
++unreg_chrdev:
++ unregister_chrdev_region(edaf_devno, 1);
++ return rc;
++}
++
++int setup_edaf_chardev(struct edaf_chardev *edaf_cdev, char *devname) {
++ struct device *chdev;
++ int rc;
++
++ chdev = device_create(edaf_class, &edaf_cdev->parent_dev,
++ edaf_devno, NULL, devname);
++ if (chdev == NULL) {
++ pr_err("Error when creating a char device and registers it with sysfs\n");
++ return -EIO;
++ }
++ edaf_cdev->chdev = chdev;
++ edaf_cdev->cntlwrfn = wrfn;
++ edaf_cdev->cntlrdfn = rdfn;
++
++ cdev_init(&edaf_cdev->edafcdev, &edaf_map_fops);
++ rc = cdev_add(&edaf_cdev->edafcdev, edaf_devno, 1);
++ if (rc) {
++ pr_err("Error when adding char device: %d\n", rc);
++ device_destroy(edaf_class, edaf_devno);
++ }
++
++ return rc;
++}
++
++static int fii_edaf_map_probe(struct platform_device *pdev) {
++ int rc = 0;
++ struct device *dev;
++ struct device_node *np;
++ struct edaf_chardev *edaf_cdev;
++ struct edaf_map *edaf;
++
++ dev = &pdev->dev;
++ edaf = devm_kzalloc(dev, sizeof(struct edaf_map), GFP_KERNEL);
++ if (!edaf) {
++ dev_err(dev, "No memory address assgined\n");
++ return -ENOMEM;
++ }
++
++ np = of_parse_phandle(dev->of_node, "memory-region", 0);
++ if (!np) {
++ dev_err(dev, "No %s specified\n", "memory-region");
++ return -ENODEV;
++ }
++ rc = of_address_to_resource(np, 0, &edaf->res);
++ if (rc) {
++ dev_err(dev, "No memory address assigned to the region\n");
++ return -EINVAL;
++ }
++
++ edaf->node = ida_alloc(&fii_edaf_mapping_ida, GFP_KERNEL);
++ edaf->devname = devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, edaf->node);
++ dev_info(dev, "devname: %s\n", edaf->devname);
++ platform_set_drvdata(pdev, edaf);
++
++ sema_init(&sem, 1);
++
++ rc = init_dev_node(edaf->devname);
++ if (rc) {
++ return rc;
++ }
++
++ edaf_cdev = devm_kzalloc(dev, sizeof(struct edaf_chardev), GFP_KERNEL);
++ if (edaf_cdev == NULL) {
++ dev_err(dev, "%s(): No space for allocating the structure\n", __func__);
++ return -ENOMEM;
++ }
++ edaf_cdev->parent_dev = *dev;
++ rc = setup_edaf_chardev(edaf_cdev, edaf->devname);
++ return rc;
++}
++
++static int fii_edaf_map_remove(struct platform_device *pdev) {
++ int rc = 0;
++ struct edaf_map *edaf;
++ struct edaf_chardev *edaf_cdev;
++
++ edaf_cdev = container_of(&pdev->dev, struct edaf_chardev, parent_dev);
++ cdev_del(&edaf_cdev->edafcdev);
++ device_destroy(edaf_class, edaf_devno);
++ class_destroy(edaf_class);
++ unregister_chrdev_region(edaf_devno, 1);
++
++ edaf = platform_get_drvdata(pdev);
++ platform_set_drvdata(pdev, NULL);
++
++ return rc;
++}
++
++static const struct of_device_id fii_edaf_map_of_matches[] = {
++ { .compatible = "edaf-map" },
++};
++MODULE_DEVICE_TABLE(of, fii_edaf_map_of_matches);
++
++static struct platform_driver fii_edaf_map_driver = {
++ .driver = {
++ .name = "fii-edaf-map",
++ .of_match_table = fii_edaf_map_of_matches,
++ },
++ .probe = fii_edaf_map_probe,
++ .remove = fii_edaf_map_remove,
++};
++module_platform_driver(fii_edaf_map_driver);
++
++MODULE_AUTHOR("Wu, Kai-Hua <eason.kh.wu@fii-foxconn.com>");
++MODULE_DESCRIPTION("AST2700 FII ESPI EDAF MAPPING");
++MODULE_LICENSE("GPL");
+--
+2.34.1
+
diff --git a/recipes-kernel/linux/files/aspeed-g7-gbmc.cfg b/recipes-kernel/linux/files/aspeed-g7-gbmc.cfg
index c34791c..fab63bd 100644
--- a/recipes-kernel/linux/files/aspeed-g7-gbmc.cfg
+++ b/recipes-kernel/linux/files/aspeed-g7-gbmc.cfg
@@ -330,5 +330,6 @@
# CONFIG_SCHED_DEBUG is not set
CONFIG_DEBUG_LIST=y
CONFIG_FUNCTION_TRACER=y
+CONFIG_AST2700_FII_EDAF_MAP=y
# CONFIG_STRICT_DEVMEM is not set
# CONFIG_RUNTIME_TESTING_MENU is not set
diff --git a/recipes-kernel/linux/linux-gbmc_aspeedg7.bb b/recipes-kernel/linux/linux-gbmc_aspeedg7.bb
index 6b1f827..97b5039 100644
--- a/recipes-kernel/linux/linux-gbmc_aspeedg7.bb
+++ b/recipes-kernel/linux/linux-gbmc_aspeedg7.bb
@@ -77,6 +77,7 @@
# Server3.0 ast2750 customized patches
SRC_URI:append:aspeed-g7 = " \
file://0027-Add-setting-SGPIO-default-value.patch \
+ file://0030-data-transfer-to-reserved-memory-for-edaf.patch \
"
KCONFIG_MODE="--allnoconfig"