Commit 7cab811d authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'scmi-updates-6.11' of...

Merge tag 'scmi-updates-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers

Arm SCMI driver updates for v6.11

The main addition this time is the support for platform to agent(p2a
also referred sometimes as notification or Rx) channel completion via
interrupt driven method. Currently, the OSPM agent clears or
acknowledge the receipt of the norification or delayed response by
updating the flags in the shared memory region which the platform is
expected to poll.

On some platforms that are completely interrupt driven, the OSPM
agent is expected to send a response message instead. This change
adds the support for the same.

Other changes include addition of a separate mailing list specific to
SCMI to allow open discussions about the interface itself in addition
to the kernel driver updates and support for system suspend via the
platform noification used on some systems.

* tag 'scmi-updates-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Add support for platform to agent channel completion
  dt-bindings: firmware: arm,scmi: Add support for notification completion channel
  firmware: arm_scmi: Add support for system suspend in power control driver
  MAINTAINERS: Add mailing list for SCMI drivers

Link: https://lore.kernel.org/r/20240620093924.375244-3-sudeep.holla@arm.comSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents f2661062 fa8b28ba
......@@ -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:
......
......@@ -21795,6 +21795,7 @@ F: drivers/mfd/syscon.c
SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers
M: Sudeep Holla <sudeep.holla@arm.com>
R: Cristian Marussi <cristian.marussi@arm.com>
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
......
......@@ -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;
......
......@@ -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
......
......@@ -50,6 +50,7 @@
#include <linux/reboot.h>
#include <linux/scmi_protocol.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/time64.h>
#include <linux/timer.h>
#include <linux/types.h>
......@@ -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,
......
......@@ -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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment