kernel/0129-feat-Add-lpcpu-driver-for-linux-6.6.patch
2024-12-19 16:34:44 -05:00

527 lines
13 KiB
Diff

From 1d32363b458be27d8b78c7535ebde4bb010a0c2e Mon Sep 17 00:00:00 2001
From: hujiamiao <hujiamiao@eswincomputing.com>
Date: Fri, 12 Jul 2024 18:30:09 +0800
Subject: [PATCH 129/219] feat:Add lpcpu driver for linux-6.6
Changelogs:
1. add lpcpu driver
2. verify lpcpu boot status
Signed-off-by: hujiamiao <hujiamiao@eswincomputing.com>
---
arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts | 2 +-
.../boot/dts/eswin/hifive-premier-550.dts | 2 +-
arch/riscv/configs/win2030_defconfig | 1 +
drivers/mailbox/Kconfig | 7 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/eswin-lpcpu.c | 433 ++++++++++++++++++
6 files changed, 445 insertions(+), 2 deletions(-)
create mode 100644 drivers/mailbox/eswin-lpcpu.c
diff --git a/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts b/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts
index a6150c3b05db..c6927bc6814f 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts
@@ -262,7 +262,7 @@ &d0_ipc_scpu {
};
&d0_lpcpu {
- status = "disabled";
+ status = "okay";
};
&pcie {
diff --git a/arch/riscv/boot/dts/eswin/hifive-premier-550.dts b/arch/riscv/boot/dts/eswin/hifive-premier-550.dts
index 27b1121d9a52..5dd4d1e4380b 100644
--- a/arch/riscv/boot/dts/eswin/hifive-premier-550.dts
+++ b/arch/riscv/boot/dts/eswin/hifive-premier-550.dts
@@ -217,7 +217,7 @@ &d0_ipc_scpu {
};
&d0_lpcpu {
- status = "disabled";
+ status = "okay";
};
&pcie {
diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig
index 2ef6525451ad..0cfccd32280c 100644
--- a/arch/riscv/configs/win2030_defconfig
+++ b/arch/riscv/configs/win2030_defconfig
@@ -733,6 +733,7 @@ CONFIG_COMMON_CLK_WIN2030=y
CONFIG_TIMER_ESWIN=y
CONFIG_MAILBOX=y
CONFIG_ESWIN_MBOX=y
+CONFIG_ESWIN_LPCPU=m
CONFIG_ARM_SMMU_V3=y
CONFIG_RPMSG_VIRTIO=y
CONFIG_ARCH_ESWIN_EIC770X_SOC_FAMILY=y
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 3cc765e1ce8e..a44784068faf 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -304,4 +304,11 @@ config ESWIN_MBOX
to send message between application processors and MCU. Say Y here if
you want to build the eswin mailbox controller driver.
+config ESWIN_LPCPU
+ tristate "Eswin LPCPU"
+ depends on ESWIN_MBOX
+ help
+ Lpcpu driver implementation for the eswin platform. Say Y here if
+ you want to build the eswin lpcpu driver.
+
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 157518a5d716..917a154a1b64 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -64,3 +64,5 @@ obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
obj-$(CONFIG_ESWIN_MBOX) += eswin-mailbox.o
+
+obj-$(CONFIG_ESWIN_LPCPU) += eswin-lpcpu.o
diff --git a/drivers/mailbox/eswin-lpcpu.c b/drivers/mailbox/eswin-lpcpu.c
new file mode 100644
index 000000000000..0568e1ef57f5
--- /dev/null
+++ b/drivers/mailbox/eswin-lpcpu.c
@@ -0,0 +1,433 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 ESWIN
+ *
+ * Implementation of the WIN2030 lpcpu (client side).
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <uapi/linux/dma-heap.h>
+#include <linux/dma-buf.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+#include <linux/sched/signal.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/firmware.h>
+#include <linux/of_address.h>
+#include <linux/dma-map-ops.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/iommu.h>
+// #include <linux/mailbox/eswin-ipc-scpu.h>
+#include <linux/eswin-win2030-sid-cfg.h>
+
+#define LPCPU_FW_RESERVED
+#define FW_BOOT_ADDR 0x80000000
+
+struct lowpower_info {
+ int level;
+};
+
+#define LPCPU_IOC_MAGIC 'L'
+#define LPCPU_IOC_SAVEPOWER \
+ _IOWR(LPCPU_IOC_MAGIC, 0x1, struct lowpower_info)
+
+#define FW_LOAD_UNKNOW 0
+#define FW_LOAD_SUCC 0xacce55
+
+struct lpcpu_dev {
+ struct miscdevice mdev;
+ struct mutex lock;
+ struct mbox_chan *mbox_channel;
+ // struct dma_allocation_data send_buff;
+ wait_queue_head_t waitq;
+ u32 num;
+ u8 *req_msg;
+ u32 res_size;
+ int numa_id;
+ struct clk *core_clk;
+ struct clk *bus_clk;
+ struct reset_control *core_rst;
+ struct reset_control *bus_rst;
+ struct reset_control *dbg_rst;
+ void __iomem *mmio;
+ size_t fw_size;
+};
+
+static struct lpcpu_dev *lpcpu;
+static u32 load_event = FW_LOAD_UNKNOW;
+
+struct mbox_msg{
+ u32 data_l;
+ u32 data_h;
+};
+
+static void eswin_lpcpu_rx_callback(struct mbox_client *client, void *msg)
+{
+ struct mbox_msg *umsg = msg;
+ struct device *dev = lpcpu->mdev.parent;
+ dev_dbg(dev, "lpcpu rx callback : %llx\n",*(u64 *)msg);
+ printk("data_l= %x, data_h = %x\n",umsg->data_l,umsg->data_h);
+ if (load_event != FW_LOAD_SUCC) {
+ load_event = *(u32 *)msg;
+ wake_up(&lpcpu->waitq);
+ printk("eswin_lpcpu_rx_callback returned \n");
+ }
+
+ return;
+}
+
+static void eswin_lpcpu_tx_done(struct mbox_client *client, void *msg, int r)
+{
+ if (r)
+ dev_warn(client->dev, "Client: Message could not be sent:%d\n", r);
+ else
+ dev_dbg(client->dev, "Client: Message sent\n");
+}
+
+static struct mbox_chan *eswin_lpcpu_request_channel(struct platform_device *pdev,
+ const char *name)
+{
+ struct mbox_client *client;
+ struct mbox_chan *channel;
+
+ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->dev = &pdev->dev;
+ client->rx_callback = eswin_lpcpu_rx_callback;
+ client->tx_prepare = NULL;
+ client->tx_done = eswin_lpcpu_tx_done;
+ client->tx_block = false;
+ client->knows_txdone = false;
+
+ channel = mbox_request_channel_byname(client, name);
+ if (IS_ERR(channel)) {
+ dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
+ return NULL;
+ }
+ dev_dbg(&pdev->dev, "request mbox chan %s\n", name);
+
+ return channel;
+}
+
+static int eswin_lpcpu_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct device *dev = NULL;
+
+ dev = lpcpu->mdev.parent;
+
+ dev_info(dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static ssize_t eswin_lpcpu_read(struct file *filp, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ printk("lpcpu read\n");
+ return 0;
+}
+
+static ssize_t eswin_lpcpu_write(struct file *filp,
+ const char __user *userbuf, size_t count,
+ loff_t *ppos)
+{
+ printk("lpcpu write\n");
+ u8 msg[8];
+ msg[0] = 0xca;
+ msg[1] = 0xec;
+ msg[2] = 0x55;
+ int ret = 0;
+ ret = mbox_send_message(lpcpu->mbox_channel, msg);
+ if (ret < 0){
+ ret = -EAGAIN;
+ // dev_dbg(dev, "Failed to send message via mailbox\r\n");
+ }
+ return count;
+}
+
+static __poll_t eswin_lpcpu_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ poll_wait(filp, &lpcpu->waitq, wait);
+
+ // if (eswin_ipc_service_ready(session))
+ // return EPOLLIN | EPOLLRDNORM;
+ return 0;
+}
+
+static int eswin_lpcpu_release(struct inode *inode, struct file *filp)
+{
+
+ pr_info("%s called!\n", __func__);
+
+ return 0;
+}
+
+static long eswin_lpcpu_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct lowpower_info lowpower;
+ struct device *dev = lpcpu->mdev.parent;
+ u8 msg[8];
+ // void *cpu_vaddr = NULL;
+ // struct dmabuf_bank_info *info, *info_free;
+ // unsigned int cmd_size = 0;
+ // size_t buf_size = 0;
+ int ret = 0;
+ printk("ioctl: %x",cmd);
+
+ if (cmd & IOC_IN) {
+ if (copy_from_user(&lowpower, (void __user *)arg, sizeof(struct lowpower_info)) != 0) {
+ pr_err("ioctl copy_from_user failed.\n");
+ ret = -EFAULT;
+ return ret;
+ }
+ }
+ // else if (cmd & IOC_OUT) {
+ // memset(kdata, 0, usize);
+ // }
+
+ switch (cmd) {
+ /* alloc memory by driver using dmabuf heap helper API */
+ case LPCPU_IOC_SAVEPOWER: {
+ msg[0] = 0x55;
+ msg[1] = 0xaa;
+
+ ret = mbox_send_message(lpcpu->mbox_channel, msg);
+ if (ret < 0){
+ ret = -EAGAIN;
+ dev_dbg(dev, "Failed to send message via mailbox\r\n");
+ }
+
+ break;
+ }
+
+ default: {
+ dev_err(dev, "Invalid IOCTL command %u\n", cmd);
+ return -ENOTTY;
+ }
+ }
+
+ return ret;
+}
+
+static const struct file_operations eswin_lpcpu_ops = {
+ .owner = THIS_MODULE,
+ .write = eswin_lpcpu_write,
+ .read = eswin_lpcpu_read,
+ .open = eswin_lpcpu_open,
+ .poll = eswin_lpcpu_poll,
+ .release = eswin_lpcpu_release,
+ .unlocked_ioctl = eswin_lpcpu_ioctl,
+};
+
+static int lpcpu_boot_status(struct mbox_chan *mbox_channel)
+{
+ int ret = 0;
+ u8 msg[8];
+ msg[0] = 0xca;
+ msg[1] = 0xec;
+ msg[2] = 0x55;
+
+ ret = mbox_send_message(mbox_channel, msg);
+ if (ret < 0){
+ ret = -EAGAIN;
+ printk("Failed to send message via mailbox\r\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+// TODO: add clk, reset tbu config
+static int eswin_lpcpu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const char *mbox_channel_name;
+ const struct firmware *lpcpu_fw;
+ int numa_id = 0;
+ int ret;
+ struct device_node *node;
+ struct resource res_fw;
+ void __iomem *mem_fw;
+ long timeout;
+
+ lpcpu = devm_kzalloc(dev, sizeof(*lpcpu), GFP_KERNEL);
+ if (!lpcpu)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, lpcpu);
+
+ lpcpu->mdev.minor = MISC_DYNAMIC_MINOR;
+ lpcpu->mdev.name = "lpcpu";
+ lpcpu->mdev.fops = &eswin_lpcpu_ops;
+ lpcpu->mdev.parent = dev;
+
+ if(of_property_read_u32(pdev->dev.of_node, "numa-node-id", &numa_id)) {
+ numa_id = 0;
+ }
+ dev_dbg(&pdev->dev, "numa_id=%d\n", numa_id);
+ lpcpu->numa_id = numa_id;
+
+ ret = misc_register(&lpcpu->mdev);
+ if (ret) {
+ dev_err(dev, "failed to register misc device: %d\n", ret);
+ goto err_misc;
+ }
+
+ /*use eswin mailbox0 to send msg and mailbox1 receive msg*/
+ ret = device_property_read_string(&pdev->dev, "mbox-names",
+ &mbox_channel_name);
+ if (ret == 0) {
+ lpcpu->mbox_channel = eswin_lpcpu_request_channel(pdev, mbox_channel_name);
+ }else{
+ dev_err(dev, "given arguments are not valid: %d\n", ret);
+ goto err_mailbox;
+ }
+
+ mutex_init(&lpcpu->lock);
+ init_waitqueue_head(&lpcpu->waitq);
+
+ lpcpu->core_clk = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(lpcpu->core_clk)) {
+ dev_err(dev, "core clock source missing or invalid\n");
+ goto err_clkrst;
+ }
+
+ lpcpu->bus_clk = devm_clk_get(dev, "bus_clk");
+ if (IS_ERR(lpcpu->bus_clk)) {
+ dev_err(dev, "bus clock source missing or invalid\n");
+ goto err_clkrst;
+ }
+
+ lpcpu->core_rst = devm_reset_control_get_optional(&pdev->dev, "core_rst");
+ if (IS_ERR_OR_NULL(lpcpu->core_rst)) {
+ dev_err_probe(dev, PTR_ERR(lpcpu->core_rst), "unable to get core reset\n");
+ goto err_clkrst;
+ }
+
+ lpcpu->bus_rst = devm_reset_control_get_optional(&pdev->dev, "bus_rst");
+ if (IS_ERR_OR_NULL(lpcpu->bus_rst)) {
+ dev_err_probe(dev, PTR_ERR(lpcpu->bus_rst), "unable to get bus reset\n");
+ goto err_clkrst;
+ }
+
+ lpcpu->dbg_rst = devm_reset_control_get_optional(&pdev->dev, "dbg_rst");
+ if (IS_ERR_OR_NULL(lpcpu->dbg_rst)) {
+ dev_err_probe(dev, PTR_ERR(lpcpu->dbg_rst), "unable to get dbg reset\n");
+ goto err_clkrst;
+ }
+ #define LPCPU_BOOT_ADDR 0x51828314
+ if (!lpcpu->numa_id)
+ lpcpu->mmio = ioremap(LPCPU_BOOT_ADDR, 4);
+ else
+ lpcpu->mmio = ioremap(LPCPU_BOOT_ADDR+0x20000000, 4);
+
+ if (!lpcpu->mmio) {
+ pr_err("lpcpu ioremap fail.\n");
+ ret = -ENOMEM;
+ goto err_mmio;
+ }
+
+ ret = lpcpu_boot_status(lpcpu->mbox_channel);
+ if (ret < 0) {
+ dev_err(dev, "Send message to lpcpu via mailbox failed!\n");
+ goto err_mmio;
+ }
+ timeout = wait_event_timeout(lpcpu->waitq,
+ load_event == FW_LOAD_SUCC,usecs_to_jiffies(100000));
+
+ if (!timeout) {
+ dev_err(dev, "Lpcpu is not boot!\n");
+ ret = -EBUSY;
+ goto err_mmio;
+ }
+
+ dev_info(dev, "eswin lpcpu initialized\n");
+
+ return 0;
+
+err_mmio:
+err_clkrst:
+ mbox_free_channel(lpcpu->mbox_channel);
+err_mailbox:
+ misc_deregister(&lpcpu->mdev);
+err_misc:
+ devm_kfree(&pdev->dev,lpcpu);
+ return ret;
+}
+
+static int eswin_lpcpu_remove(struct platform_device *pdev)
+{
+ struct lpcpu_dev *_dev = platform_get_drvdata(pdev);
+
+ if (_dev->mbox_channel)
+ mbox_free_channel(_dev->mbox_channel);
+ misc_deregister(&_dev->mdev);
+ iounmap(_dev->mmio);
+ devm_kfree(&pdev->dev,_dev);
+ dev_dbg(&pdev->dev, "%s remove!\n", pdev->name);
+
+ return 0;
+}
+
+static const struct of_device_id eswin_lpcpu_match[] = {
+ {
+ .compatible = "eswin,win2030-lpcpu",
+ },
+ { /* Sentinel */ }
+};
+
+static struct platform_driver eswin_lpcpu_driver = {
+ .driver = {
+ .name = "win2030-lpcpu",
+ .of_match_table = eswin_lpcpu_match,
+ },
+ .probe = eswin_lpcpu_probe,
+ .remove = eswin_lpcpu_remove,
+};
+
+static int __init lpcpu_modules_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&eswin_lpcpu_driver);
+ if (err < 0){
+ pr_err("lpcpu:platform_register_drivers failed!err=%d\n",err);
+ }
+
+ return err;
+}
+module_init(lpcpu_modules_init);
+
+static void __exit lpcpu_modules_exit(void)
+{
+ platform_driver_unregister(&eswin_lpcpu_driver);
+}
+module_exit(lpcpu_modules_exit);
+
+MODULE_DESCRIPTION("ESWIN WIN2030 lpcpu driver");
+MODULE_LICENSE("GPL v2");
--
2.47.0