From 08070351c87879e5ca0b7b9bd6c2aa5bb2a4f11e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Jun 2024 17:57:18 +0300 Subject: [PATCH 1/4] MAINTAINERS: Add mailing list for SCMI drivers We have created a new mailing list specific to SCMI. Add it to the MAINTAINERS file. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/a9706e17-09ad-4304-828d-c0987befc8f7@moroto.mountain Signed-off-by: Sudeep Holla --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index d6c90161c7bf..15f230b3f237 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21798,6 +21798,7 @@ F: drivers/mfd/syscon.c SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers M: Sudeep Holla R: Cristian Marussi +L: arm-scmi@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/firmware/arm,sc[mp]i.yaml From dd22cc907a749ff34526e5b22a664d674f71c3de Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 28 Apr 2024 15:51:05 +0800 Subject: [PATCH 2/4] firmware: arm_scmi: Add support for system suspend in power control driver SCMI supports system suspend notification from the platform. The suuport for the same can be added in SCMI power control driver. However, currently there is no way to pass suspend level to pm_suspend() call from this driver, so use suspend-to-ram(S2R) will be used. Couple of things to note: 1) The userspace can still configure whatever default behaviour expected for S2R. 2) The userspace needs to keep the wakeup source enabled, otherwise the system may never resume back. Signed-off-by: Peng Fan Reviewed-by: Cristian Marussi Link: https://lore.kernel.org/r/20240428075105.2187837-1-peng.fan@oss.nxp.com Signed-off-by: Sudeep Holla --- .../firmware/arm_scmi/scmi_power_control.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/scmi_power_control.c b/drivers/firmware/arm_scmi/scmi_power_control.c index 6eb7d2a4b6b1..21f467a92942 100644 --- a/drivers/firmware/arm_scmi/scmi_power_control.c +++ b/drivers/firmware/arm_scmi/scmi_power_control.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ enum scmi_syspower_state { * @reboot_nb: A notifier_block optionally used to track reboot progress * @forceful_work: A worker used to trigger a forceful transition once a * graceful has timed out. + * @suspend_work: A worker used to trigger system suspend */ struct scmi_syspower_conf { struct device *dev; @@ -90,6 +92,7 @@ struct scmi_syspower_conf { struct notifier_block reboot_nb; struct delayed_work forceful_work; + struct work_struct suspend_work; }; #define userspace_nb_to_sconf(x) \ @@ -249,6 +252,9 @@ static void scmi_request_graceful_transition(struct scmi_syspower_conf *sc, case SCMI_SYSTEM_WARMRESET: orderly_reboot(); break; + case SCMI_SYSTEM_SUSPEND: + schedule_work(&sc->suspend_work); + break; default: break; } @@ -277,7 +283,8 @@ static int scmi_userspace_notifier(struct notifier_block *nb, struct scmi_system_power_state_notifier_report *er = data; struct scmi_syspower_conf *sc = userspace_nb_to_sconf(nb); - if (er->system_state >= SCMI_SYSTEM_POWERUP) { + if (er->system_state >= SCMI_SYSTEM_MAX || + er->system_state == SCMI_SYSTEM_POWERUP) { dev_err(sc->dev, "Ignoring unsupported system_state: 0x%X\n", er->system_state); return NOTIFY_DONE; @@ -315,6 +322,16 @@ static int scmi_userspace_notifier(struct notifier_block *nb, return NOTIFY_OK; } +static void scmi_suspend_work_func(struct work_struct *work) +{ + struct scmi_syspower_conf *sc = + container_of(work, struct scmi_syspower_conf, suspend_work); + + pm_suspend(PM_SUSPEND_MEM); + + sc->state = SCMI_SYSPOWER_IDLE; +} + static int scmi_syspower_probe(struct scmi_device *sdev) { int ret; @@ -338,6 +355,8 @@ static int scmi_syspower_probe(struct scmi_device *sdev) sc->userspace_nb.notifier_call = &scmi_userspace_notifier; sc->dev = &sdev->dev; + INIT_WORK(&sc->suspend_work, scmi_suspend_work_func); + return handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_SYSTEM, SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, From d0398f51ffb3f706f38b235c7bb17da8658e3392 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 10 May 2024 11:19:47 +0800 Subject: [PATCH 3/4] dt-bindings: firmware: arm,scmi: Add support for notification completion channel Per System Control Management Interface specification: "Completion interrupts: This transport supports polling or interrupt driven modes of communication. In interrupt mode, when the callee completes processing a message, it raises an interrupt to the caller. Hardware support for completion interrupts is optional." So, add an optional mailbox channel for notification completion interrupts. Signed-off-by: Peng Fan Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240510-scmi-notify-v2-1-e994cf14ef86@nxp.com Signed-off-by: Sudeep Holla --- .../devicetree/bindings/firmware/arm,scmi.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml index 7de2c29606e5..308af58180d1 100644 --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml @@ -72,14 +72,17 @@ properties: - const: tx - const: tx_reply - const: rx + - const: rx_reply minItems: 2 mboxes: description: List of phandle and mailbox channel specifiers. It should contain - exactly one, two or three mailboxes; the first one or two for transmitting - messages ("tx") and another optional ("rx") for receiving notifications - and delayed responses, if supported by the platform. + exactly one, two, three or four mailboxes; the first one or two for + transmitting messages ("tx") and another optional ("rx") for receiving + notifications and delayed responses, if supported by the platform. + The optional ("rx_reply") is for notifications completion interrupt, + if supported by the platform. The number of mailboxes needed for transmitting messages depends on the type of channels exposed by the specific underlying mailbox controller; one single channel descriptor is enough if such channel is bidirectional, @@ -92,9 +95,10 @@ properties: 2 mbox / 2 shmem => SCMI TX and RX over 2 mailbox bidirectional channels 2 mbox / 1 shmem => SCMI TX over 2 mailbox unidirectional channels 3 mbox / 2 shmem => SCMI TX and RX over 3 mailbox unidirectional channels + 4 mbox / 2 shmem => SCMI TX and RX over 4 mailbox unidirectional channels Any other combination of mboxes and shmem is invalid. minItems: 1 - maxItems: 3 + maxItems: 4 shmem: description: From fa8b28ba22d95be4d2dd3c37fbdbdc066af82941 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 10 May 2024 11:19:48 +0800 Subject: [PATCH 4/4] firmware: arm_scmi: Add support for platform to agent channel completion On some systems the SCMI platform to agent(p2a) communication can be fully interrupt driven. The notification(p2a) channel needs completion interrupt to drive its notification queue at the platform. Without it, the platform notification will not work as the platform will wait for agent indication of clearing the channel via interrupt unlike few platforms which can poll instead. To support such systems, an optional unidirectional mailbox channel for p2a reply communication. If the platform sets channel INTR flag set indicating that it expects the agent to trigger the interrupt to acknowledge the reciept of the notification or any p2a message, and the completion interrupt channel is provided, send a mailbox message to the platform after the p2a message is read and channel is freed to accept new notifications or p2a messages. Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20240510-scmi-notify-v2-2-e994cf14ef86@nxp.com Reviewed-by: Cristian Marussi Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 1 + drivers/firmware/arm_scmi/mailbox.c | 57 ++++++++++++++++++++++++++--- drivers/firmware/arm_scmi/shmem.c | 5 +++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index b5ac25dbc1ca..4b8c5250cdb5 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -326,6 +326,7 @@ void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); +bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem); /* declarations for message passing transports */ struct scmi_msg_payld; diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 615a3b2ad83d..0219a12e3209 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -21,6 +21,7 @@ * @cl: Mailbox Client * @chan: Transmit/Receive mailbox uni/bi-directional channel * @chan_receiver: Optional Receiver mailbox unidirectional channel + * @chan_platform_receiver: Optional Platform Receiver mailbox unidirectional channel * @cinfo: SCMI channel info * @shmem: Transmit/Receive shared memory area */ @@ -28,6 +29,7 @@ struct scmi_mailbox { struct mbox_client cl; struct mbox_chan *chan; struct mbox_chan *chan_receiver; + struct mbox_chan *chan_platform_receiver; struct scmi_chan_info *cinfo; struct scmi_shared_mem __iomem *shmem; }; @@ -91,6 +93,8 @@ static bool mailbox_chan_available(struct device_node *of_node, int idx) * for replies on the a2p channel. Set as zero if not present. * @p2a_chan: A reference to the optional p2a channel. * Set as zero if not present. + * @p2a_rx_chan: A reference to the optional p2a completion channel. + * Set as zero if not present. * * At first, validate the transport configuration as described in terms of * 'mboxes' and 'shmem', then determin which mailbox channel indexes are @@ -98,8 +102,8 @@ static bool mailbox_chan_available(struct device_node *of_node, int idx) * * Return: 0 on Success or error */ -static int mailbox_chan_validate(struct device *cdev, - int *a2p_rx_chan, int *p2a_chan) +static int mailbox_chan_validate(struct device *cdev, int *a2p_rx_chan, + int *p2a_chan, int *p2a_rx_chan) { int num_mb, num_sh, ret = 0; struct device_node *np = cdev->of_node; @@ -109,8 +113,9 @@ static int mailbox_chan_validate(struct device *cdev, dev_dbg(cdev, "Found %d mboxes and %d shmems !\n", num_mb, num_sh); /* Bail out if mboxes and shmem descriptors are inconsistent */ - if (num_mb <= 0 || num_sh <= 0 || num_sh > 2 || num_mb > 3 || - (num_mb == 1 && num_sh != 1) || (num_mb == 3 && num_sh != 2)) { + if (num_mb <= 0 || num_sh <= 0 || num_sh > 2 || num_mb > 4 || + (num_mb == 1 && num_sh != 1) || (num_mb == 3 && num_sh != 2) || + (num_mb == 4 && num_sh != 2)) { dev_warn(cdev, "Invalid channel descriptor for '%s' - mbs:%d shm:%d\n", of_node_full_name(np), num_mb, num_sh); @@ -139,6 +144,7 @@ static int mailbox_chan_validate(struct device *cdev, case 1: *a2p_rx_chan = 0; *p2a_chan = 0; + *p2a_rx_chan = 0; break; case 2: if (num_sh == 2) { @@ -148,10 +154,17 @@ static int mailbox_chan_validate(struct device *cdev, *a2p_rx_chan = 1; *p2a_chan = 0; } + *p2a_rx_chan = 0; break; case 3: *a2p_rx_chan = 1; *p2a_chan = 2; + *p2a_rx_chan = 0; + break; + case 4: + *a2p_rx_chan = 1; + *p2a_chan = 2; + *p2a_rx_chan = 3; break; } } @@ -166,12 +179,12 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, struct device *cdev = cinfo->dev; struct scmi_mailbox *smbox; struct device_node *shmem; - int ret, a2p_rx_chan, p2a_chan, idx = tx ? 0 : 1; + int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan, idx = tx ? 0 : 1; struct mbox_client *cl; resource_size_t size; struct resource res; - ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan); + ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan, &p2a_rx_chan); if (ret) return ret; @@ -229,6 +242,17 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, } } + if (!tx && p2a_rx_chan) { + smbox->chan_platform_receiver = mbox_request_channel(cl, p2a_rx_chan); + if (IS_ERR(smbox->chan_platform_receiver)) { + ret = PTR_ERR(smbox->chan_platform_receiver); + if (ret != -EPROBE_DEFER) + dev_err(cdev, "failed to request SCMI P2A Receiver mailbox\n"); + return ret; + } + } + + cinfo->transport_info = smbox; smbox->cinfo = cinfo; @@ -243,9 +267,11 @@ static int mailbox_chan_free(int id, void *p, void *data) if (smbox && !IS_ERR(smbox->chan)) { mbox_free_channel(smbox->chan); mbox_free_channel(smbox->chan_receiver); + mbox_free_channel(smbox->chan_platform_receiver); cinfo->transport_info = NULL; smbox->chan = NULL; smbox->chan_receiver = NULL; + smbox->chan_platform_receiver = NULL; smbox->cinfo = NULL; } @@ -300,8 +326,27 @@ static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, static void mailbox_clear_channel(struct scmi_chan_info *cinfo) { struct scmi_mailbox *smbox = cinfo->transport_info; + struct mbox_chan *intr_chan; + int ret; shmem_clear_channel(smbox->shmem); + + if (!shmem_channel_intr_enabled(smbox->shmem)) + return; + + if (smbox->chan_platform_receiver) + intr_chan = smbox->chan_platform_receiver; + else if (smbox->chan) + intr_chan = smbox->chan; + else + return; + + ret = mbox_send_message(intr_chan, NULL); + /* mbox_send_message returns non-negative value on success, so reset */ + if (ret > 0) + ret = 0; + + mbox_client_txdone(intr_chan, ret); } static bool diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 8bf495bcad09..b74e5a740f2c 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -128,3 +128,8 @@ bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) return (ioread32(&shmem->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); } + +bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) +{ + return ioread32(&shmem->flags) & SCMI_SHMEM_FLAG_INTR_ENABLED; +}