From fc37c58ab3ed881e91e60063ddf2621fa9b9ef4b Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 8 Nov 2023 13:32:06 +0900 Subject: [PATCH 01/16] RISCV: dts: starfive: Add eeprom node Add atmel eeprom driver node. Apply the eeprom node by referring to the Vendor branch. [https://github.com/starfive-tech/linux/blob/22e0315434b13cdde93ded101b567d5d1c4d5a2e/arch/riscv/boot/dts/starfive/jh7110-visionfive-v2.dtsi#L504] Change-Id: I830acf5a0b6a226a4822dd00a278aea6aee827d5 Signed-off-by: Hoegeun Kwon --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 1a71179..b109da9 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -218,6 +218,12 @@ pinctrl-0 = <&i2c5_pins>; status = "okay"; + eeprom@50 { + compatible = "atmel,24c04"; + reg = <0x50>; + pagesize = <16>; + }; + axp15060: pmic@36 { compatible = "x-powers,axp15060"; reg = <0x36>; -- 2.7.4 From bdf5931a13b2990cbd92d8a9c0c957d16591ba6f Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 8 Nov 2023 13:34:00 +0900 Subject: [PATCH 02/16] RISCV: config: Enable eeprom at24 Enable eeprom at24 driver. Change-Id: I3485a08f72ee1b20147a98c33440a27c4978bf02 Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_visionfive2_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/configs/tizen_visionfive2_defconfig b/arch/riscv/configs/tizen_visionfive2_defconfig index bf1ac17..875eeb5e 100644 --- a/arch/riscv/configs/tizen_visionfive2_defconfig +++ b/arch/riscv/configs/tizen_visionfive2_defconfig @@ -211,6 +211,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_VIRTIO_BLK=y CONFIG_BLK_DEV_NVME=m +CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_SCSI_VIRTIO=y -- 2.7.4 From 7a5856d3bf3b896f9830cd55622dc3e4b6241939 Mon Sep 17 00:00:00 2001 From: "shanlong.li" Date: Thu, 8 Jun 2023 00:07:15 -0700 Subject: [PATCH 03/16] driver:mailbox: add mailbox driver add mailbox driver Signed-off-by: shanlong.li [hoegeun.kwon: cherry-pick the commit a070a8d2467d from https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_6.1.y_devel] Signed-off-by: Hoegeun Kwon Change-Id: Iedb770bbdc8ec148c1b7eebf48df3b0e273063f6 --- drivers/mailbox/Kconfig | 13 + drivers/mailbox/Makefile | 4 + drivers/mailbox/starfive_mailbox-test.c | 407 ++++++++++++++++++++++++++++++++ drivers/mailbox/starfive_mailbox.c | 347 +++++++++++++++++++++++++++ 4 files changed, 771 insertions(+) create mode 100644 drivers/mailbox/starfive_mailbox-test.c create mode 100644 drivers/mailbox/starfive_mailbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 05d6fae..e272ece 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -294,4 +294,17 @@ config QCOM_IPCC acts as an interrupt controller for receiving interrupts from clients. Say Y here if you want to build this driver. +config STARFIVE_MBOX + tristate "Platform Starfive Mailbox" + depends on OF + help + Say Y here if you want to build a platform specific variant RISCV + controller driver. + +config STARFIVE_MBOX_TEST + tristate "Starfive Mailbox Test Client" + depends on OF + depends on HAS_IOMEM + help + Test client to help with testing new Controller driver implementations. endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index fc93761..f5ff98b 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -62,3 +62,7 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o + +obj-$(CONFIG_STARFIVE_MBOX) += starfive_mailbox.o + +obj-$(CONFIG_STARFIVE_MBOX_TEST) += starfive_mailbox-test.o diff --git a/drivers/mailbox/starfive_mailbox-test.c b/drivers/mailbox/starfive_mailbox-test.c new file mode 100644 index 0000000..4da8664 --- /dev/null +++ b/drivers/mailbox/starfive_mailbox-test.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2015 ST Microelectronics + * + * Author: Lee Jones + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MBOX_MAX_SIG_LEN 8 +#define MBOX_MAX_MSG_LEN 16 +#define MBOX_BYTES_PER_LINE 16 +#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2) +#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +static bool mbox_data_ready; + +struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; + void __iomem *rx_mmio; + struct mbox_chan *tx_channel; + struct mbox_chan *rx_channel; + char *rx_buffer; + char *signal; + char *message; + spinlock_t lock; + wait_queue_head_t waitq; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; +}; + +static ssize_t mbox_test_signal_write(struct file *filp, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct mbox_test_device *tdev = filp->private_data; + + if (!tdev->tx_channel) { + dev_err(tdev->dev, "Channel cannot do Tx\n"); + return -EINVAL; + } + + if (count > MBOX_MAX_SIG_LEN) { + dev_err(tdev->dev, + "Signal length %zd greater than max allowed %d\n", + count, MBOX_MAX_SIG_LEN); + return -EINVAL; + } + + /* Only allocate memory if we need to */ + if (!tdev->signal) { + tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL); + if (!tdev->signal) + return -ENOMEM; + } + + if (copy_from_user(tdev->signal, userbuf, count)) { + kfree(tdev->signal); + tdev->signal = NULL; + return -EFAULT; + } + + return count; +} + +static const struct file_operations mbox_test_signal_ops = { + .write = mbox_test_signal_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static int mbox_test_message_fasync(int fd, struct file *filp, int on) +{ + struct mbox_test_device *tdev = filp->private_data; + + return fasync_helper(fd, filp, on, &tdev->async_queue); +} + +static ssize_t mbox_test_message_write(struct file *filp, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct mbox_test_device *tdev = filp->private_data; + void *data; + int ret; + + if (!tdev->tx_channel) { + dev_err(tdev->dev, "Channel cannot do Tx\n"); + return -EINVAL; + } + + if (count > MBOX_MAX_MSG_LEN) { + dev_err(tdev->dev, + "Message length %zd greater than max allowed %d\n", + count, MBOX_MAX_MSG_LEN); + return -EINVAL; + } + + tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); + if (!tdev->message) + return -ENOMEM; + + ret = copy_from_user(tdev->message, userbuf, count); + if (ret) { + ret = -EFAULT; + goto out; + } + + if (tdev->tx_mmio && tdev->signal) { + print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS, + tdev->signal, MBOX_MAX_SIG_LEN); + + data = tdev->signal; + } else + data = tdev->message; + + print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS, + tdev->message, MBOX_MAX_MSG_LEN); + + ret = mbox_send_message(tdev->tx_channel, data); + mbox_chan_txdone(tdev->tx_channel, ret); + if (ret < 0) + dev_err(tdev->dev, "Failed to send message via mailbox\n"); + +out: + kfree(tdev->signal); + kfree(tdev->message); + tdev->signal = NULL; + + return ret < 0 ? ret : count; +} + +static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) +{ + bool data_ready; + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); + data_ready = mbox_data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +} + +static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct mbox_test_device *tdev = filp->private_data; + unsigned long flags; + char *touser, *ptr; + int ret; + + touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL); + if (!touser) + return -ENOMEM; + + if (!tdev->rx_channel) { + ret = snprintf(touser, 20, "\n"); + ret = simple_read_from_buffer(userbuf, count, ppos, + touser, ret); + goto kfree_err; + } + + do { + if (mbox_test_message_data_ready(tdev)) + break; + + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto waitq_err; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto waitq_err; + } + schedule(); + + } while (1); + + spin_lock_irqsave(&tdev->lock, flags); + + ptr = tdev->rx_buffer; + + mbox_data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + if (copy_to_user((void __user *)userbuf, ptr, 4)) + ret = -EFAULT; + +waitq_err: + __set_current_state(TASK_RUNNING); +kfree_err: + kfree(touser); + return ret; +} + +static __poll_t +mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct mbox_test_device *tdev = filp->private_data; + + poll_wait(filp, &tdev->waitq, wait); + + if (mbox_test_message_data_ready(tdev)) + return EPOLLIN | EPOLLRDNORM; + return 0; +} + +static const struct file_operations mbox_test_message_ops = { + .write = mbox_test_message_write, + .read = mbox_test_message_read, + .fasync = mbox_test_message_fasync, + .poll = mbox_test_message_poll, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static int mbox_test_add_debugfs(struct platform_device *pdev, + struct mbox_test_device *tdev) +{ + if (!debugfs_initialized()) + return 0; + + tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL); + if (!tdev->root_debugfs_dir) { + dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n"); + return -EINVAL; + } + + debugfs_create_file("message", 0600, tdev->root_debugfs_dir, + tdev, &mbox_test_message_ops); + + debugfs_create_file("signal", 0200, tdev->root_debugfs_dir, + tdev, &mbox_test_signal_ops); + + return 0; +} + +static void mbox_test_receive_message(struct mbox_client *client, void *message) +{ + struct mbox_test_device *tdev = dev_get_drvdata(client->dev); + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); + if (tdev->rx_mmio) { + memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN); + print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS, + tdev->rx_buffer, MBOX_MAX_MSG_LEN); + } else if (message) { + print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS, + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } + mbox_data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); +} + +static void mbox_test_prepare_message(struct mbox_client *client, void *message) +{ + struct mbox_test_device *tdev = dev_get_drvdata(client->dev); + + if (tdev->tx_mmio) { + if (tdev->signal) + memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN); + else + memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN); + } +} + +static struct mbox_chan * +mbox_test_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 = mbox_test_receive_message; + client->tx_prepare = mbox_test_prepare_message; + client->tx_block = false; + client->knows_txdone = false; + client->tx_tout = 500; + + channel = mbox_request_channel_byname(client, name); + if (IS_ERR(channel)) { + dev_warn(&pdev->dev, "Failed to request %s channel\n", name); + return NULL; + } + + return channel; +} + +static int mbox_test_probe(struct platform_device *pdev) +{ + struct mbox_test_device *tdev; + struct resource *res; + resource_size_t size; + int ret; + + tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); + if (!tdev) + return -ENOMEM; + + /* It's okay for MMIO to be NULL */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { + /* if reserved area in SRAM, try just ioremap */ + size = resource_size(res); + tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); + } else if (IS_ERR(tdev->tx_mmio)) { + tdev->tx_mmio = NULL; + } + + /* If specified, second reg entry is Rx MMIO */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res); + if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { + size = resource_size(res); + tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); + } else if (IS_ERR(tdev->rx_mmio)) { + tdev->rx_mmio = tdev->tx_mmio; + } + + tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); + tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); + + if (!tdev->tx_channel && !tdev->rx_channel) + return -EPROBE_DEFER; + + /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + + tdev->dev = &pdev->dev; + platform_set_drvdata(pdev, tdev); + + spin_lock_init(&tdev->lock); + + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); + if (!tdev->rx_buffer) + return -ENOMEM; + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) + return ret; + + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +} + +static int mbox_test_remove(struct platform_device *pdev) +{ + struct mbox_test_device *tdev = platform_get_drvdata(pdev); + + debugfs_remove_recursive(tdev->root_debugfs_dir); + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); + if (tdev->rx_channel) + mbox_free_channel(tdev->rx_channel); + + return 0; +} + +static const struct of_device_id mbox_test_match[] = { + { .compatible = "starfive,mailbox-test" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mbox_test_match); + +static struct platform_driver mbox_test_driver = { + .driver = { + .name = "mailbox_test", + .of_match_table = mbox_test_match, + }, + .probe = mbox_test_probe, + .remove = mbox_test_remove, +}; +module_platform_driver(mbox_test_driver); + +MODULE_DESCRIPTION("Generic Mailbox Testing Facility"); +MODULE_AUTHOR("Lee Jones + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mailbox.h" + +#define MBOX_CHAN_MAX 4 + +#define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x10)) +#define MBOX_IRQ_REG 0x00 +#define MBOX_SET_REG 0x04 +#define MBOX_CLR_REG 0x08 +#define MBOX_CMD_REG 0x0c +#define MBC_PEND_SMRY 0x100 + +typedef enum { + MAILBOX_CORE_U7 = 0, + MAILBOX_CORE_HIFI4, + MAILBOX_CORE_E2, + MAILBOX_CORE_RSVD0, + MAILBOX_CORE_NUM, +} mailbox_core_t; + +struct mailbox_irq_name_c{ + int id; + char name[16]; +}; + +static const struct mailbox_irq_name_c irq_peer_name[MBOX_CHAN_MAX] = { + {MAILBOX_CORE_U7, "u74_core"}, + {MAILBOX_CORE_HIFI4, "hifi4_core"}, + {MAILBOX_CORE_E2, "e24_core"}, + {MAILBOX_CORE_RSVD0, "" }, +}; + +/** + * starfive mailbox channel information + * + * A channel can be used for TX or RX, it can trigger remote + * processor interrupt to notify remote processor and can receive + * interrupt if has incoming message. + * + * @dst_irq: Interrupt vector for remote processor + * @core_id: id for remote processor + */ +struct starfive_chan_info { + unsigned int dst_irq; + mailbox_core_t core_id; +}; + +/** + * starfive mailbox controller data + * + * Mailbox controller includes 4 channels and can allocate + * channel for message transferring. + * + * @dev: Device to which it is attached + * @base: Base address of the register mapping region + * @chan: Representation of channels in mailbox controller + * @mchan: Representation of channel info + * @controller: Representation of a communication channel controller + */ +struct starfive_mbox { + struct device *dev; + void __iomem *base; + struct mbox_chan chan[MBOX_CHAN_MAX]; + struct starfive_chan_info mchan[MBOX_CHAN_MAX]; + struct mbox_controller controller; + struct clk *clk; + struct reset_control *rst_rresetn; +}; + +static struct starfive_mbox *to_starfive_mbox(struct mbox_controller *mbox) +{ + return container_of(mbox, struct starfive_mbox, controller); +} + +static struct mbox_chan * +starfive_of_mbox_index_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) +{ + struct starfive_mbox *sbox; + + int ind = sp->args[0]; + int core_id = sp->args[1]; + + if (ind >= mbox->num_chans || core_id >= MAILBOX_CORE_NUM) + return ERR_PTR(-EINVAL); + + sbox = to_starfive_mbox(mbox); + + sbox->mchan[ind].core_id = core_id; + + return &mbox->chans[ind]; +} + +static irqreturn_t starfive_rx_irq_handler(int irq, void *p) +{ + struct mbox_chan *chan = p; + unsigned long ch = (unsigned long)chan->con_priv; + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); + void __iomem *base = MBOX_BASE(mbox, ch); + u32 val; + + val = readl(base + MBOX_CMD_REG); + if (!val) + return IRQ_NONE; + + mbox_chan_received_data(chan, (void *)&val); + writel(val, base + MBOX_CLR_REG); + return IRQ_HANDLED; +} + +static int starfive_mbox_check_state(struct mbox_chan *chan) +{ + unsigned long ch = (unsigned long)chan->con_priv; + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); + unsigned long irq_flag = IRQF_SHARED; + long ret = 0; + + pm_runtime_get_sync(mbox->dev); + /* MAILBOX should be with IRQF_NO_SUSPEND set */ + if (!mbox->dev->pm_domain) + irq_flag |= IRQF_NO_SUSPEND; + + /* Mailbox is idle so directly bail out */ + if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) + return -EBUSY; + + if (mbox->mchan[ch].dst_irq > 0) { + dev_dbg(mbox->dev, "%s: host IRQ = %d, ch:%ld", __func__, mbox->mchan[ch].dst_irq, ch); + ret = devm_request_irq(mbox->dev, mbox->mchan[ch].dst_irq, starfive_rx_irq_handler, + irq_flag, irq_peer_name[ch].name, chan); + if (ret < 0) + dev_err(mbox->dev, "request_irq %d failed\n", mbox->mchan[ch].dst_irq); + } + + return ret; +} + +static int starfive_mbox_startup(struct mbox_chan *chan) +{ + return starfive_mbox_check_state(chan); +} + +static void starfive_mbox_shutdown(struct mbox_chan *chan) +{ + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); + unsigned long ch = (unsigned long)chan->con_priv; + void __iomem *base = MBOX_BASE(mbox, ch); + + writel(0x0, base + MBOX_IRQ_REG); + writel(0x0, base + MBOX_CLR_REG); + + if (mbox->mchan[ch].dst_irq > 0) + devm_free_irq(mbox->dev, mbox->mchan[ch].dst_irq, chan); + pm_runtime_put_sync(mbox->dev); +} + +static int starfive_mbox_send_data(struct mbox_chan *chan, void *msg) +{ + unsigned long ch = (unsigned long)chan->con_priv; + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox); + struct starfive_chan_info *mchan = &mbox->mchan[ch]; + void __iomem *base = MBOX_BASE(mbox, ch); + u32 *buf = msg; + + /* Ensure channel is released */ + if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) { + pr_debug("%s:%d. busy\n", __func__, __LINE__); + return -EBUSY; + } + + /* Clear mask for destination interrupt */ + writel(BIT(mchan->core_id), base + MBOX_IRQ_REG); + + /* Fill message data */ + writel(*buf, base + MBOX_SET_REG); + return 0; +} + +static struct mbox_chan_ops starfive_mbox_ops = { + .startup = starfive_mbox_startup, + .send_data = starfive_mbox_send_data, + .shutdown = starfive_mbox_shutdown, +}; + +static const struct of_device_id starfive_mbox_of_match[] = { + { .compatible = "starfive,mail_box",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, starfive_mbox_of_match); + +void starfive_mailbox_init(struct starfive_mbox *mbox) +{ + mbox->clk = devm_clk_get_optional(mbox->dev, "clk_apb"); + if (IS_ERR(mbox->clk)) { + dev_err(mbox->dev, "failed to get mailbox\n"); + return; + } + + mbox->rst_rresetn = devm_reset_control_get_exclusive(mbox->dev, "mbx_rre"); + if (IS_ERR(mbox->rst_rresetn)) { + dev_err(mbox->dev, "failed to get mailbox reset\n"); + return; + } + + clk_prepare_enable(mbox->clk); + reset_control_deassert(mbox->rst_rresetn); +} + +static int starfive_mbox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct starfive_mbox *mbox; + struct mbox_chan *chan; + struct resource *res; + unsigned long ch; + int err; + + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mbox->base = devm_ioremap_resource(dev, res); + mbox->dev = dev; + + if (IS_ERR(mbox->base)) + return PTR_ERR(mbox->base); + + starfive_mailbox_init(mbox); + + mbox->controller.dev = dev; + mbox->controller.chans = mbox->chan; + mbox->controller.num_chans = MBOX_CHAN_MAX; + mbox->controller.ops = &starfive_mbox_ops; + mbox->controller.of_xlate = starfive_of_mbox_index_xlate; + mbox->controller.txdone_irq = true; + mbox->controller.txdone_poll = false; + + /* Initialize mailbox channel data */ + chan = mbox->chan; + for (ch = 0; ch < MBOX_CHAN_MAX; ch++) { + mbox->mchan[ch].dst_irq = 0; + mbox->mchan[ch].core_id = (mailbox_core_t)ch; + chan[ch].con_priv = (void *)ch; + } + mbox->mchan[MAILBOX_CORE_HIFI4].dst_irq = platform_get_irq(pdev, 0); + mbox->mchan[MAILBOX_CORE_E2].dst_irq = platform_get_irq(pdev, 1); + + err = mbox_controller_register(&mbox->controller); + if (err) { + dev_err(dev, "Failed to register mailbox %d\n", err); + return err; + } + + platform_set_drvdata(pdev, mbox); + dev_info(dev, "Mailbox enabled\n"); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static int starfive_mbox_remove(struct platform_device *pdev) +{ + struct starfive_mbox *mbox = platform_get_drvdata(pdev); + + mbox_controller_unregister(&mbox->controller); + devm_clk_put(mbox->dev, mbox->clk); + pm_runtime_disable(mbox->dev); + + return 0; +} + +static int __maybe_unused starfive_mbox_suspend(struct device *dev) +{ + struct starfive_mbox *mbox = dev_get_drvdata(dev); + + clk_disable_unprepare(mbox->clk); + + return 0; +} + +static int __maybe_unused starfive_mbox_resume(struct device *dev) +{ + struct starfive_mbox *mbox = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(mbox->clk); + if (ret) + dev_err(dev, "failed to enable clock\n"); + + return ret; +} + +static const struct dev_pm_ops starfive_mbox_pm_ops = { + .suspend = starfive_mbox_suspend, + .resume = starfive_mbox_resume, + SET_RUNTIME_PM_OPS(starfive_mbox_suspend, starfive_mbox_resume, NULL) +}; +static struct platform_driver starfive_mbox_driver = { + .probe = starfive_mbox_probe, + .remove = starfive_mbox_remove, + .driver = { + .name = "mailbox", + .of_match_table = starfive_mbox_of_match, + .pm = &starfive_mbox_pm_ops, + }, +}; + +static int __init starfive_mbox_init(void) +{ + return platform_driver_register(&starfive_mbox_driver); +} +core_initcall(starfive_mbox_init); + +static void __exit starfive_mbox_exit(void) +{ + platform_driver_unregister(&starfive_mbox_driver); +} +module_exit(starfive_mbox_exit); + +MODULE_DESCRIPTION("StarFive Mailbox Controller driver"); +MODULE_AUTHOR("Shanlong Li "); +MODULE_LICENSE("GPL"); -- 2.7.4 From 9c161009d67386c581f94d8a90e4b8ef3a7da593 Mon Sep 17 00:00:00 2001 From: "shanlong.li" Date: Fri, 10 Nov 2023 15:43:01 +0900 Subject: [PATCH 04/16] RISCV: dts: starfive: jh7110: Add mailbox node Add mailbox driver node. Signed-off-by: shanlong.li [hoegeun.kwon: cherry-pick the commit 802f9261f654 from https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_6.1.y_devel] Signed-off-by: Hoegeun Kwon Change-Id: I8a3cf94272404a94bdf2fef05ecfb399417914d1 --- .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++++++ arch/riscv/boot/dts/starfive/jh7110.dtsi | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index b109da9..0abea4b 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -614,3 +614,11 @@ pinctrl-0 = <&pwmdac0_pins>; status = "okay"; }; + +&mailbox_contrl0 { + status = "okay"; +}; + +&mailbox_client0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index d24ed3b..e55e5b8 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -303,6 +303,13 @@ ports = <&dc_out>; }; + mailbox_client0: mailbox_client { + compatible = "starfive,mailbox-test"; + mbox-names = "rx", "tx"; + mboxes = <&mailbox_contrl0 0 1>,<&mailbox_contrl0 1 0>; + status = "disabled"; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -833,6 +840,18 @@ "ch2", "ch3"; }; + mailbox_contrl0: mailbox@13060000 { + compatible = "starfive,mail_box"; + reg = <0x0 0x13060000 0x0 0x0001000>; + clocks = <&syscrg JH7110_SYSCLK_MAILBOX_APB>; + clock-names = "clk_apb"; + resets = <&syscrg JH7110_SYSRST_MAILBOX_APB>; + reset-names = "mbx_rre"; + interrupts = <26 27>; + #mbox-cells = <2>; + status = "disabled"; + }; + wdog: watchdog@13070000 { compatible = "starfive,jh7110-wdt"; reg = <0x0 0x13070000 0x0 0x10000>; -- 2.7.4 From 0d0eff1e3bdb86e83dc74137e64ca03fb9403b58 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Fri, 10 Nov 2023 15:56:46 +0900 Subject: [PATCH 05/16] RISCV: config: Enable starfive mailbox Enable starfive mailbox driver. Change-Id: If6f44164c2261bd7d18387e617a522c3251564fa Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_visionfive2_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/configs/tizen_visionfive2_defconfig b/arch/riscv/configs/tizen_visionfive2_defconfig index 875eeb5e..2aea5b9 100644 --- a/arch/riscv/configs/tizen_visionfive2_defconfig +++ b/arch/riscv/configs/tizen_visionfive2_defconfig @@ -353,6 +353,9 @@ CONFIG_CLK_STARFIVE_JH7110_AON=y CONFIG_CLK_STARFIVE_JH7110_STG=y CONFIG_CLK_STARFIVE_JH7110_ISP=y CONFIG_CLK_STARFIVE_JH7110_VOUT=y +CONFIG_MAILBOX=y +CONFIG_STARFIVE_MBOX=m +CONFIG_STARFIVE_MBOX_TEST=m CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_CTRL=y CONFIG_RPMSG_VIRTIO=y -- 2.7.4 From 13265eb7a6e8f49b1b189d187b81038c11a8b710 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Wed, 22 Nov 2023 09:54:26 +0900 Subject: [PATCH 06/16] RISCV: config: tizen_qemu: Sync with savedefconfig Sync with auto generated defconfig by savedefconfig. Change-Id: I6b1dacf375f8c44c167026388defddb86f193d13 Signed-off-by: Seung-Woo Kim --- arch/riscv/configs/tizen_qemu_defconfig | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/arch/riscv/configs/tizen_qemu_defconfig b/arch/riscv/configs/tizen_qemu_defconfig index bfa8edc..6135f95 100644 --- a/arch/riscv/configs/tizen_qemu_defconfig +++ b/arch/riscv/configs/tizen_qemu_defconfig @@ -2,18 +2,21 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_CGROUPS=y +CONFIG_MEMCG=y CONFIG_CGROUP_SCHED=y CONFIG_CFS_BANDWIDTH=y +CONFIG_CPUSETS=y CONFIG_CGROUP_BPF=y CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_CHECKPOINT_RESTORE=y CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y -CONFIG_BPF_SYSCALL=y +# CONFIG_SYSFS_SYSCALL is not set CONFIG_SOC_SIFIVE=y CONFIG_SOC_VIRT=y CONFIG_SMP=y @@ -39,10 +42,10 @@ CONFIG_PCI_HOST_GENERIC=y CONFIG_PCIE_XILINX=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_BLK_DEV_LOOP=y CONFIG_VIRTIO_BLK=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y @@ -64,8 +67,6 @@ CONFIG_INPUT_MOUSEDEV=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_SERIAL_EARLYCON_RISCV_SBI=y -CONFIG_HVC_RISCV_SBI=y CONFIG_SERIAL_DEV_BUS=y CONFIG_TTY_PRINTK=y CONFIG_VIRTIO_CONSOLE=y @@ -73,10 +74,9 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y CONFIG_SPI=y CONFIG_SPI_SIFIVE=y +# CONFIG_PTP_1588_CLOCK is not set CONFIG_GPIOLIB=y CONFIG_GPIO_SIFIVE=y -# CONFIG_PTP_1588_CLOCK is not set -CONFIG_POWER_RESET=y CONFIG_DRM=y CONFIG_DRM_VIRTIO_GPU=y CONFIG_FB=y @@ -119,10 +119,12 @@ CONFIG_NFS_V4_1=y CONFIG_NFS_V4_2=y CONFIG_ROOT_NFS=y CONFIG_9P_FS=y +CONFIG_SECURITY=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_FS=y CONFIG_DEBUG_PAGEALLOC=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_DEBUG_VM=y @@ -137,22 +139,11 @@ CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_RWSEMS=y CONFIG_DEBUG_ATOMIC_SLEEP=y -CONFIG_STACKTRACE=y CONFIG_DEBUG_LIST=y CONFIG_DEBUG_PLIST=y CONFIG_DEBUG_SG=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_EQS_DEBUG=y -CONFIG_DEBUG_BLOCK_EXT_DEVT=y -CONFIG_FTRACE=y +CONFIG_BLK_DEV_IO_TRACE=y # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_MEMTEST=y -# CONFIG_SYSFS_SYSCALL is not set -CONFIG_EFI=y -CONFIG_FPU=y -CONFIG_SECURITY=y -CONFIG_SECURITY_SMACK=y -CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y -CONFIG_MEMCG=y -CONFIG_CPUSETS=y -CONFIG_BLK_DEV_IO_TRACE=y -- 2.7.4 From 03089ee5f1f7dbf1262ca4e907898e2692f970f7 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Tue, 21 Nov 2023 15:51:06 +0900 Subject: [PATCH 07/16] RISCV: config: tizen_*: Enable ZRAM support Enable CONFIG_ZRAM with ZSTD compression. Change-Id: Ia21d71f8db87b4437d17183e9e82ad14898af76f Signed-off-by: Seung-Woo Kim --- arch/riscv/configs/tizen_qemu_defconfig | 3 +++ arch/riscv/configs/tizen_visionfive2_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/riscv/configs/tizen_qemu_defconfig b/arch/riscv/configs/tizen_qemu_defconfig index 6135f95..786bb3a 100644 --- a/arch/riscv/configs/tizen_qemu_defconfig +++ b/arch/riscv/configs/tizen_qemu_defconfig @@ -42,6 +42,7 @@ CONFIG_PCI_HOST_GENERIC=y CONFIG_PCIE_XILINX=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -122,6 +123,8 @@ CONFIG_9P_FS=y CONFIG_SECURITY=y CONFIG_SECURITY_SMACK=y CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_ZSTD=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_PRINTK_TIME=y diff --git a/arch/riscv/configs/tizen_visionfive2_defconfig b/arch/riscv/configs/tizen_visionfive2_defconfig index 2aea5b9..7d1fc68 100644 --- a/arch/riscv/configs/tizen_visionfive2_defconfig +++ b/arch/riscv/configs/tizen_visionfive2_defconfig @@ -205,6 +205,7 @@ CONFIG_PCIE_FU740=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_CONNECTOR=y +CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -403,6 +404,8 @@ CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y # CONFIG_INTEGRITY_AUDIT is not set CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,bpf,smack" CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_ZSTD=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_CRYPTO_DEV_JH7110=y -- 2.7.4 From d3cbb03f3fb1c7b7a7fba48c408add44fb08cb34 Mon Sep 17 00:00:00 2001 From: Mason Huo Date: Tue, 4 Apr 2023 11:29:08 +0800 Subject: [PATCH 08/16] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation The priority and enable registers of plic will be reset during hibernation power cycle in poweroff mode, add the syscore callbacks to save/restore those registers. Signed-off-by: Mason Huo Reviewed-by: Ley Foon Tan Reviewed-by: Sia Jee Heng Reported-by: Dan Carpenter Link: https://lore.kernel.org/r/202302140709.CdkxgtPi-lkp@intel.com/ Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230404032908.89638-1-mason.huo@starfivetech.com [hoegeun.kwon: cherry-pick the commit e80f0b6a2cf30 from mainline] Signed-off-by: Hoegeun Kwon Change-Id: Ic549e1d59da713ac7b2bc0d1d827c6332cbdc3c8 --- drivers/irqchip/irq-sifive-plic.c | 93 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 2f47848..2323606 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -67,6 +68,8 @@ struct plic_priv { struct irq_domain *irqdomain; void __iomem *regs; unsigned long plic_quirks; + unsigned int nr_irqs; + unsigned long *prio_save; }; struct plic_handler { @@ -78,6 +81,7 @@ struct plic_handler { */ raw_spinlock_t enable_lock; void __iomem *enable_base; + u32 *enable_save; struct plic_priv *priv; }; static int plic_parent_irq __ro_after_init; @@ -227,6 +231,71 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type) return IRQ_SET_MASK_OK; } +static int plic_irq_suspend(void) +{ + unsigned int i, cpu; + u32 __iomem *reg; + struct plic_priv *priv; + + priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; + + for (i = 0; i < priv->nr_irqs; i++) + if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)) + __set_bit(i, priv->prio_save); + else + __clear_bit(i, priv->prio_save); + + for_each_cpu(cpu, cpu_present_mask) { + struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); + + if (!handler->present) + continue; + + raw_spin_lock(&handler->enable_lock); + for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { + reg = handler->enable_base + i * sizeof(u32); + handler->enable_save[i] = readl(reg); + } + raw_spin_unlock(&handler->enable_lock); + } + + return 0; +} + +static void plic_irq_resume(void) +{ + unsigned int i, index, cpu; + u32 __iomem *reg; + struct plic_priv *priv; + + priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; + + for (i = 0; i < priv->nr_irqs; i++) { + index = BIT_WORD(i); + writel((priv->prio_save[index] & BIT_MASK(i)) ? 1 : 0, + priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID); + } + + for_each_cpu(cpu, cpu_present_mask) { + struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); + + if (!handler->present) + continue; + + raw_spin_lock(&handler->enable_lock); + for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { + reg = handler->enable_base + i * sizeof(u32); + writel(handler->enable_save[i], reg); + } + raw_spin_unlock(&handler->enable_lock); + } +} + +static struct syscore_ops plic_irq_syscore_ops = { + .suspend = plic_irq_suspend, + .resume = plic_irq_resume, +}; + static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { @@ -343,6 +412,7 @@ static int __init __plic_init(struct device_node *node, u32 nr_irqs; struct plic_priv *priv; struct plic_handler *handler; + unsigned int cpu; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -361,15 +431,21 @@ static int __init __plic_init(struct device_node *node, if (WARN_ON(!nr_irqs)) goto out_iounmap; + priv->nr_irqs = nr_irqs; + + priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL); + if (!priv->prio_save) + goto out_free_priority_reg; + nr_contexts = of_irq_count(node); if (WARN_ON(!nr_contexts)) - goto out_iounmap; + goto out_free_priority_reg; error = -ENOMEM; priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1, &plic_irqdomain_ops, priv); if (WARN_ON(!priv->irqdomain)) - goto out_iounmap; + goto out_free_priority_reg; for (i = 0; i < nr_contexts; i++) { struct of_phandle_args parent; @@ -439,6 +515,11 @@ static int __init __plic_init(struct device_node *node, handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE + i * CONTEXT_ENABLE_SIZE; handler->priv = priv; + + handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32), + sizeof(*handler->enable_save), GFP_KERNEL); + if (!handler->enable_save) + goto out_free_enable_reg; done: for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { plic_toggle(handler, hwirq, 0); @@ -459,11 +540,19 @@ done: plic_starting_cpu, plic_dying_cpu); plic_cpuhp_setup_done = true; } + register_syscore_ops(&plic_irq_syscore_ops); pr_info("%pOFP: mapped %d interrupts with %d handlers for" " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts); return 0; +out_free_enable_reg: + for_each_cpu(cpu, cpu_present_mask) { + handler = per_cpu_ptr(&plic_handlers, cpu); + kfree(handler->enable_save); + } +out_free_priority_reg: + kfree(priv->prio_save); out_iounmap: iounmap(priv->regs); out_free_priv: -- 2.7.4 From 5fcaa5eba5481847dc26d887302ee9e1b2978357 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 22 Nov 2023 16:43:30 +0900 Subject: [PATCH 09/16] riscv: hibernate: Add missing configuration and comment Add missing HIBERNATION configuration and fix missing comment by mainline. Fixes : ae555bcd50e1 ("RISC-V: Add arch functions to support hibernation/suspend-to-disk") [https://lore.kernel.org/all/20230330064321.1008373-1-jeeheng.sia@starfivetech.com/] Change-Id: I505e3cd130ffe0ed2e79f137b8b40e5b046063db Signed-off-by: Hoegeun Kwon --- arch/riscv/Kconfig | 2 +- arch/riscv/kernel/hibernate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c988995..fbfae8d 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -52,7 +52,7 @@ config RISCV select CLONE_BACKWARDS select CLINT_TIMER if !MMU select COMMON_CLK - select CPU_PM if CPU_IDLE + select CPU_PM if CPU_IDLE || HIBERNATION select EDAC_SUPPORT select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT diff --git a/arch/riscv/kernel/hibernate.c b/arch/riscv/kernel/hibernate.c index f11be60..264b2dc 100644 --- a/arch/riscv/kernel/hibernate.c +++ b/arch/riscv/kernel/hibernate.c @@ -40,7 +40,7 @@ EXPORT_SYMBOL_GPL(relocated_restore_code); /** * struct arch_hibernate_hdr_invariants - container to store kernel build version. - * @uts_version: to save the build number and date so that the we do not resume with + * @uts_version: to save the build number and date so that we do not resume with * a different kernel. */ struct arch_hibernate_hdr_invariants { -- 2.7.4 From 60a19eddc28c8806b24ef578d68c2c5aee66f40d Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Mon, 29 May 2023 18:15:24 +0800 Subject: [PATCH 10/16] riscv: Enable ARCH_SUSPEND_POSSIBLE for s2idle With this configuration opened, the basic platform-independent s2idle is provided by the sole "s2idle" string in `/sys/power/mem_sleep`. At the end of s2idle, harts will hit the `wfi` instruction or enter the SUSPENDED state through the sbi_cpuidle driver. The interrupt of possible wakeup devices will be kept to wake the system up. And platform-specific sleep states can be provided by future ACPI and SBI SUSP extension support. Signed-off-by: Song Shuai Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20230529101524.322076-1-songshuaishuai@tinylab.org Signed-off-by: Palmer Dabbelt [hoegeun.kwon: cherry-pick the commit c1f048a6bd7d from mainline] Signed-off-by: Hoegeun Kwon Change-Id: I535adff9152e6f20b9ad825b03cadfec6ac39684 --- arch/riscv/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index fbfae8d..5fd3503 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -715,6 +715,9 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_HIBERNATION_HEADER def_bool HIBERNATION +config ARCH_SUSPEND_POSSIBLE + def_bool y + endmenu # "Power management options" menu "CPU Power Management" -- 2.7.4 From d5a3fbda7243a6e179a753fe9e9a941f904a28fc Mon Sep 17 00:00:00 2001 From: "minda.chen" Date: Tue, 17 Oct 2023 15:29:59 +0900 Subject: [PATCH 11/16] usb: cdns3: add hibernation pm notifier to set roothub wakeup In hibernation resume case. usb devices maybe not emulated, roothub is suspended, In this case, usb devices will be resume fail. Set roothub active while hibernation resume. Signed-off-by: minda.chen [hoegeun.kwon: cherry-pick the commit d86ba4820f59 from https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_6.1.y_devel] Signed-off-by: Hoegeun Kwon Change-Id: Idd244d8d3e50fd8e84cb72ff5fcdb50ff4399788 --- drivers/usb/cdns3/cdns3-starfive.c | 16 ++++++- drivers/usb/cdns3/core.h | 1 + drivers/usb/cdns3/host.c | 88 +++++++++++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c index 55ae4ac..f43da41 100644 --- a/drivers/usb/cdns3/cdns3-starfive.c +++ b/drivers/usb/cdns3/cdns3-starfive.c @@ -176,6 +176,20 @@ static const unsigned int supported_cable[] = { }; #endif +static struct cdns3_platform_data cdns_starfive_pdata = { +#ifdef CONFIG_PM_SLEEP + .quirks = CDNS3_REGISTER_PM_NOTIFIER, +#endif +}; + +static const struct of_dev_auxdata cdns_starfive_auxdata[] = { + { + .compatible = "cdns,usb3", + .platform_data = &cdns_starfive_pdata, + }, + {}, +}; + static int cdns_starfive_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -239,7 +253,7 @@ static int cdns_starfive_probe(struct platform_device *pdev) if (ret) return ret; - ret = of_platform_populate(node, NULL, NULL, dev); + ret = of_platform_populate(node, NULL, cdns_starfive_auxdata, dev); if (ret) return dev_err_probe(dev, ret, "Failed to create children\n"); diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h index 2d332a7..f5ad30f 100644 --- a/drivers/usb/cdns3/core.h +++ b/drivers/usb/cdns3/core.h @@ -44,6 +44,7 @@ struct cdns3_platform_data { bool suspend, bool wakeup); unsigned long quirks; #define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0) +#define CDNS3_REGISTER_PM_NOTIFIER BIT(1) }; /** diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index 6164fc4..ac1276f 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -24,7 +24,7 @@ #define CFG_RXDET_P3_EN BIT(15) #define LPM_2_STB_SWITCH_EN BIT(25) -static void xhci_cdns3_plat_start(struct usb_hcd *hcd) +static void xhci_cdns3_plat_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); u32 value; @@ -45,9 +45,18 @@ static void xhci_cdns3_plat_start(struct usb_hcd *hcd) } } +static void xhci_cdns3_plat_start(struct usb_hcd *hcd) +{ + xhci_cdns3_plat_setup(hcd); +#ifdef CONFIG_PM_SLEEP + if (cdns3_hiber_data.pm_setup) + cdns3_hiber_data.pm_setup(hcd); +#endif +} + static int xhci_cdns3_resume_quirk(struct usb_hcd *hcd) { - xhci_cdns3_plat_start(hcd); + xhci_cdns3_plat_setup(hcd); return 0; } @@ -57,6 +66,67 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = { .resume_quirk = xhci_cdns3_resume_quirk, }; +#ifdef CONFIG_PM_SLEEP +struct cdns_hiber_data { + struct usb_hcd *hcd; + struct usb_hcd *shared_hcd; + struct notifier_block pm_notifier; + int (*pm_setup)(struct usb_hcd *hcd); + int (*pm_remove)(struct cdns *cdns); +}; +static struct cdns_hiber_data cdns3_hiber_data; + +static int cdns_hiber_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct usb_hcd *hcd = cdns3_hiber_data.hcd; + struct usb_hcd *shared_hcd = cdns3_hiber_data.shared_hcd; + + switch (action) { + case PM_RESTORE_PREPARE: + if (hcd->state == HC_STATE_SUSPENDED) { + usb_hcd_resume_root_hub(hcd); + usb_disable_autosuspend(hcd->self.root_hub); + } + if (shared_hcd->state == HC_STATE_SUSPENDED) { + usb_hcd_resume_root_hub(shared_hcd); + usb_disable_autosuspend(shared_hcd->self.root_hub); + } + break; + case PM_POST_RESTORE: + usb_enable_autosuspend(hcd->self.root_hub); + usb_enable_autosuspend(shared_hcd->self.root_hub); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static int cdns_register_pm_notifier(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + cdns3_hiber_data.hcd = xhci->main_hcd; + cdns3_hiber_data.shared_hcd = xhci->shared_hcd; + cdns3_hiber_data.pm_notifier.notifier_call = cdns_hiber_notifier; + return register_pm_notifier(&cdns3_hiber_data.pm_notifier); +} + +static int cdns_unregister_pm_notifier(struct cdns *cdns) +{ + int ret; + + ret = unregister_pm_notifier(&cdns3_hiber_data.pm_notifier); + + cdns3_hiber_data.hcd = NULL; + cdns3_hiber_data.shared_hcd = NULL; + + return ret; +} +#endif + static int __cdns_host_init(struct cdns *cdns) { struct platform_device *xhci; @@ -91,6 +161,12 @@ static int __cdns_host_init(struct cdns *cdns) if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)) cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; +#ifdef CONFIG_PM_SLEEP + if (cdns->pdata && (cdns->pdata->quirks & CDNS3_REGISTER_PM_NOTIFIER)) { + cdns3_hiber_data.pm_setup = cdns_register_pm_notifier; + cdns3_hiber_data.pm_remove = cdns_unregister_pm_notifier; + } +#endif ret = platform_device_add_data(xhci, cdns->xhci_plat_data, sizeof(struct xhci_plat_priv)); if (ret) @@ -118,6 +194,14 @@ err1: static void cdns_host_exit(struct cdns *cdns) { +#ifdef CONFIG_PM_SLEEP + if (cdns3_hiber_data.pm_remove) { + cdns3_hiber_data.pm_remove(cdns); + cdns3_hiber_data.pm_remove = NULL; + cdns3_hiber_data.pm_setup = NULL; + } +#endif + kfree(cdns->xhci_plat_data); platform_device_unregister(cdns->host_dev); cdns->host_dev = NULL; -- 2.7.4 From d6eafee192960621ee44c480ece6e620207f3f25 Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Mon, 12 Jun 2023 09:41:32 +0800 Subject: [PATCH 12/16] usb: cdns: fix compile error and duplicate register pm notify Find kernel 6.1 USB cdns3 two host controller (usb_hcd) call plat_start function. It will cause register notification twice. Fix this issue. Signed-off-by: Minda Chen [hoegeun.kwon: cherry-pick the commit b7aab6bc6c57 from https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_6.1.y_devel] Signed-off-by: Hoegeun Kwon Change-Id: Ia080aa84284fb6da4acd9357063272b50123b128 --- drivers/usb/cdns3/host.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index ac1276f..d368748 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -24,6 +24,19 @@ #define CFG_RXDET_P3_EN BIT(15) #define LPM_2_STB_SWITCH_EN BIT(25) +#ifdef CONFIG_PM_SLEEP +struct cdns_hiber_data { + struct usb_hcd *hcd; + struct usb_hcd *shared_hcd; + struct notifier_block pm_notifier; + int (*pm_setup)(struct usb_hcd *hcd); + int (*pm_remove)(struct cdns *cdns); + bool notify_registered; +}; + +static struct cdns_hiber_data cdns3_hiber_data; +#endif + static void xhci_cdns3_plat_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -67,15 +80,6 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = { }; #ifdef CONFIG_PM_SLEEP -struct cdns_hiber_data { - struct usb_hcd *hcd; - struct usb_hcd *shared_hcd; - struct notifier_block pm_notifier; - int (*pm_setup)(struct usb_hcd *hcd); - int (*pm_remove)(struct cdns *cdns); -}; -static struct cdns_hiber_data cdns3_hiber_data; - static int cdns_hiber_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -88,14 +92,15 @@ static int cdns_hiber_notifier(struct notifier_block *nb, unsigned long action, usb_hcd_resume_root_hub(hcd); usb_disable_autosuspend(hcd->self.root_hub); } - if (shared_hcd->state == HC_STATE_SUSPENDED) { + if (shared_hcd && shared_hcd->state == HC_STATE_SUSPENDED) { usb_hcd_resume_root_hub(shared_hcd); usb_disable_autosuspend(shared_hcd->self.root_hub); } break; case PM_POST_RESTORE: usb_enable_autosuspend(hcd->self.root_hub); - usb_enable_autosuspend(shared_hcd->self.root_hub); + if (shared_hcd) + usb_enable_autosuspend(shared_hcd->self.root_hub); break; default: break; @@ -107,11 +112,25 @@ static int cdns_hiber_notifier(struct notifier_block *nb, unsigned long action, static int cdns_register_pm_notifier(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + if (!xhci->main_hcd) + return 0; + + if (xhci->shared_hcd) + cdns3_hiber_data.shared_hcd = xhci->shared_hcd; + + if (cdns3_hiber_data.notify_registered) + return 0; cdns3_hiber_data.hcd = xhci->main_hcd; - cdns3_hiber_data.shared_hcd = xhci->shared_hcd; cdns3_hiber_data.pm_notifier.notifier_call = cdns_hiber_notifier; - return register_pm_notifier(&cdns3_hiber_data.pm_notifier); + ret = register_pm_notifier(&cdns3_hiber_data.pm_notifier); + if (ret) + return ret; + cdns3_hiber_data.notify_registered = 1; + + return 0; } static int cdns_unregister_pm_notifier(struct cdns *cdns) @@ -120,6 +139,7 @@ static int cdns_unregister_pm_notifier(struct cdns *cdns) ret = unregister_pm_notifier(&cdns3_hiber_data.pm_notifier); + cdns3_hiber_data.notify_registered = 0; cdns3_hiber_data.hcd = NULL; cdns3_hiber_data.shared_hcd = NULL; -- 2.7.4 From 2c4e4387c1bdecc4adaef767d761ea3e525702d8 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 22 Nov 2023 16:41:21 +0900 Subject: [PATCH 13/16] clocksource/drivers/starfive: Fix shutdown ktime_get call problem There is a problem where a warning occurs when ktime_get is called while in suspend. There is no need to call ktime_get when entering timer_shutdown. Fix starfive_timer_disable to be called. [ 58.338211] WARNING: CPU: 0 PID: 928 at kernel/time/timekeeping.c:843 ktime_get+0xf4/0x110 [ 58.338211] Modules linked in: wave5 videobuf2_dma_contig v4l2_mem2mem starfive_mailbox starfive_mailbox_test [ 58.338211] CPU: 0 PID: 928 Comm: bash Not tainted 6.1.39-00014-g40bc52190beb-dirty #59 [ 58.338211] Hardware name: StarFive VisionFive 2 v1.3B (DT) [ 58.338211] epc : ktime_get+0xf4/0x110 [ 58.338211] ra : starfive_timer_suspend+0x5c/0xc6 [ 58.338211] epc : ffffffff80098a74 ra : ffffffff809bb316 sp : ffffffc8296e3bc0 [ 58.338211] gp : ffffffff81e6ff10 tp : ffffffd8d3f3de00 t0 : 20646e6570737573 [ 58.338211] t1 : ffffffff81c9b1f8 t2 : 7573205d36363831 s0 : ffffffc8296e3bf0 [ 58.338211] s1 : ffffffd8c3dce880 a0 : ffffffd8c3dce880 a1 : 0000000200000020 [ 58.338211] a2 : 000585b146000000 a3 : 0000000000000000 a4 : 0000000000000000 [ 58.338211] a5 : 0000000000000001 a6 : 0000000010395283 a7 : ffffffffffffffff [ 58.338211] s2 : ffffffff81228678 s3 : ffffffff81c9b1f8 s4 : ffffffff81eb0ff0 [ 58.338211] s5 : ffffffff81e74040 s6 : 0000000000000000 s7 : 0000003fb94c0d50 [ 58.338211] s8 : 0000000000000001 s9 : 0000003fc2b7d6d0 s10: 000000000000002d [ 58.338211] s11: 0000002ac45aeb3c t3 : ffffffff81c9b1f8 t4 : ffffffff81e947af [ 58.338211] t5 : ffffffff81e94788 t6 : ffffffff81eaa8b0 [ 58.338211] status: 0000000200000100 badaddr: 0000000000000000 cause: 0000000000000003 [ 58.338211] [] ktime_get+0xf4/0x110 [ 58.338211] [] starfive_timer_suspend+0x5c/0xc6 [ 58.338211] [] clockevents_suspend+0x30/0x46 [ 58.338211] [] timekeeping_suspend+0x236/0x25c [ 58.338211] [] syscore_suspend+0x5a/0x1e0 [ 58.338211] [] hibernation_snapshot+0x1c8/0x50e [ 58.338211] [] hibernate+0xf8/0x29c [ 58.338211] [] state_store+0xbe/0xc2 [ 58.338211] [] kobj_attr_store+0xe/0x1a [ 58.338211] [] sysfs_kf_write+0x2a/0x34 [ 58.338211] [] kernfs_fop_write_iter+0xe8/0x16c [ 58.338211] [] vfs_write+0x188/0x328 [ 58.338211] [] ksys_write+0x58/0xd0 [ 58.338211] [] sys_write+0xe/0x16 [ 58.338211] [] ret_from_syscall+0x0/0x2 Change-Id: I3e961637f1204a98b4ea0337dc5ce3a7fc02d191 Signed-off-by: Hoegeun Kwon --- drivers/clocksource/timer-starfive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-starfive.c b/drivers/clocksource/timer-starfive.c index 5316394..7e6d9332 100644 --- a/drivers/clocksource/timer-starfive.c +++ b/drivers/clocksource/timer-starfive.c @@ -144,7 +144,7 @@ static void starfive_timer_suspend(struct clock_event_device *evt) struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); clkevt->reload_val = starfive_timer_get_val(clkevt); - starfive_timer_shutdown(evt); + starfive_timer_disable(clkevt); } static void starfive_timer_resume(struct clock_event_device *evt) -- 2.7.4 From a53bf572588116b89ba5449ab1039a576b16841f Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 22 Nov 2023 16:53:23 +0900 Subject: [PATCH 14/16] RISCV: config: Enable hibernation and swap partition Enable the hibernation configuration and related PM features for debuf purprose. Change-Id: I635a1c783e0e4e2a4f3c518d90a45b32d10e9d2d Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_visionfive2_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/configs/tizen_visionfive2_defconfig b/arch/riscv/configs/tizen_visionfive2_defconfig index 7d1fc68..66f1822 100644 --- a/arch/riscv/configs/tizen_visionfive2_defconfig +++ b/arch/riscv/configs/tizen_visionfive2_defconfig @@ -31,8 +31,8 @@ CONFIG_SOC_SIFIVE=y CONFIG_SOC_STARFIVE=y CONFIG_SOC_VIRT=y CONFIG_SMP=y -CONFIG_HOTPLUG_CPU=y -CONFIG_PM=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="PARTLABEL=hibernation" CONFIG_CPU_IDLE=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y -- 2.7.4 From 5062cfad3a4c4b412871d5f8d664b377c52acb52 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 27 Nov 2023 19:17:55 +0900 Subject: [PATCH 15/16] Revert "RISCV: dts: starfive: Fix the property of memory" This reverts commit e750d985a70a0ceab8166131c39a73b962f91fd6. It's Workaround code until supporting eeprom. Change-Id: I3e01ed8fe90ef936b2a0f71d21bfbdabcf3f499a Signed-off-by: Jaehoon Chung --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 0abea4b..ff1d920 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -32,7 +32,7 @@ memory@40000000 { device_type = "memory"; - reg = <0x0 0x40000000 0x2 0x0>; + reg = <0x0 0x40000000 0x1 0x0>; }; thermal-zones { -- 2.7.4 From a0c2693d6b6d002886c8c688d0e9a1d760969cb6 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 7 Dec 2023 19:00:00 +0900 Subject: [PATCH 16/16] sound: soc: ac108: Remove unused function ac101_set_clock() Remove unused function ac101_set_clock() which causes following build warning: sound/soc/codecs/ac101.c:1240:12: warning: 'ac101_set_clock' defined but not used [-Wunused-function] 1240 | static int ac101_set_clock(int y_start_n_stop) { | ^~~~~~~~~~~~~~~ Change-Id: Ic7adb2d90f59738f9f1acbec0c5db1606a0205b4 Signed-off-by: Seung-Woo Kim --- sound/soc/codecs/ac101.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/sound/soc/codecs/ac101.c b/sound/soc/codecs/ac101.c index 0a32950..2d56e3fa 100644 --- a/sound/soc/codecs/ac101.c +++ b/sound/soc/codecs/ac101.c @@ -1236,22 +1236,6 @@ int ac101_audio_startup(struct snd_pcm_substream *substream, return 0; } -#if _MASTER_MULTI_CODEC == _MASTER_AC101 -static int ac101_set_clock(int y_start_n_stop) { - int r; - - if (y_start_n_stop) { - /* enable global clock */ - r = ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_PRE_PMU, 1); - } else { - /* disable global clock */ - static_ac10x->aif1_clken = 1; - r = ac101_aif1clk(static_ac10x->codec, SND_SOC_DAPM_POST_PMD, 0); - } - return r; -} -#endif - int ac101_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -1405,10 +1389,6 @@ int ac101_codec_probe(struct snd_soc_codec *codec) ac10x->aif1_clken = 0; mutex_init(&ac10x->dac_mutex); - #if _MASTER_MULTI_CODEC == _MASTER_AC101 - //seeed_voice_card_register_set_clock(SNDRV_PCM_STREAM_PLAYBACK, ac101_set_clock); - #endif - set_configuration(ac10x->codec); /*enable this bit to prevent leakage from ldoin*/ -- 2.7.4