From b85dc63a28fce3c34cb169c962b76c808ca00f54 Mon Sep 17 00:00:00 2001 From: hujiamiao Date: Fri, 12 Jul 2024 18:30:09 +0800 Subject: [PATCH 129/222] feat:Add lpcpu driver for linux-6.6 Changelogs: 1. add lpcpu driver 2. verify lpcpu boot status Signed-off-by: hujiamiao --- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include + +#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