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"