This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 2981ffcfdf1 arch/arm/src/imx9: scmi: Add SCMI notifications and LMM
events.
2981ffcfdf1 is described below
commit 2981ffcfdf125610cad12043d9f14c77c12da9b4
Author: Phil-Engljaehringer <[email protected]>
AuthorDate: Thu Oct 22 11:51:05 2026 +0200
arch/arm/src/imx9: scmi: Add SCMI notifications and LMM events.
Add support for SCMI platform-to-agent (P2A) notifications from the
System Manager and for LMM events of other logical machines, e.g. to
let the M7 react when the Linux LM reboots.
imx9_scmi_notify_register() installs a single callback for all
notifications. The SM writes a notification into the notify SMT
channel and rings MU5 general purpose interrupt 1. The handler passes
protocol and message ID to the callback in interrupt context, then
marks the channel free and rings the doorbell back so the SM can send
the next queued notification. The callback reads the message with a
protocol specific function, for now imx9_scmi_lmmevent().
imx9_scmi_lmmnotify() subscribes to boot/shutdown events of a logical
machine (LMM_NOTIFY). The SCMI protocol IDs move to the header so
callbacks can dispatch on them.
The MU5 IRQ is attached and enabled in imx9_scmi_notify_register():
imx9_scmi_initialize() runs from __start() before irq_initialize()
and up_irqinitialize(), which reset the vector table and NVIC, so the
IRQ set up there by imx9_mu_init() is lost. Polled SCMI calls are not
affected. The new imx9_mu_enable_irq() only attaches and enables the
MU IRQ; calling imx9_mu_init() again would also clear the MU
callbacks.
The notify channel is marked free on registration, because the SM
only sends notifications to a free channel.
Assisted-by: GitHub-Copilot:claude-opus-5.5
Signed-off-by: Phil-Engljaehringer <[email protected]>
---
arch/arm/src/imx9/imx9_mu.c | 9 +-
arch/arm/src/imx9/imx9_mu.h | 1 +
arch/arm/src/imx9/imx9_scmi.c | 214 ++++++++++++++++++++++++++++++++++++++----
arch/arm/src/imx9/imx9_scmi.h | 99 +++++++++++++++++++
4 files changed, 304 insertions(+), 19 deletions(-)
diff --git a/arch/arm/src/imx9/imx9_mu.c b/arch/arm/src/imx9/imx9_mu.c
index a7cb91c5b7b..b8f3867bb74 100644
--- a/arch/arm/src/imx9/imx9_mu.c
+++ b/arch/arm/src/imx9/imx9_mu.c
@@ -213,8 +213,7 @@ struct imx9_mudev_s *imx9_mu_init(int index)
return NULL;
}
- irq_attach(priv->irq, imx9_mu_interrupt, priv);
- up_enable_irq(priv->irq);
+ imx9_mu_enable_irq(priv);
priv->gpi_callback = NULL;
priv->msg_callback = NULL;
@@ -222,6 +221,12 @@ struct imx9_mudev_s *imx9_mu_init(int index)
return priv;
}
+void imx9_mu_enable_irq(struct imx9_mudev_s *priv)
+{
+ irq_attach(priv->irq, imx9_mu_interrupt, priv);
+ up_enable_irq(priv->irq);
+}
+
void imx9_mu_subscribe_msg(struct imx9_mudev_s *priv,
uint32_t msg_int_bitfield,
imx9_mu_msg_callback_t callback)
diff --git a/arch/arm/src/imx9/imx9_mu.h b/arch/arm/src/imx9/imx9_mu.h
index ceb3b16d06e..6ce21dc5e68 100644
--- a/arch/arm/src/imx9/imx9_mu.h
+++ b/arch/arm/src/imx9/imx9_mu.h
@@ -39,6 +39,7 @@ typedef void (*imx9_mu_gpi_callback_t)(int id, void *arg);
****************************************************************************/
struct imx9_mudev_s *imx9_mu_init(int index);
+void imx9_mu_enable_irq(struct imx9_mudev_s *priv);
void imx9_mu_subscribe_msg(struct imx9_mudev_s *priv,
uint32_t msg_int_bitfield,
imx9_mu_msg_callback_t callback);
diff --git a/arch/arm/src/imx9/imx9_scmi.c b/arch/arm/src/imx9/imx9_scmi.c
index ca440d99f89..ce7278ea172 100644
--- a/arch/arm/src/imx9/imx9_scmi.c
+++ b/arch/arm/src/imx9/imx9_scmi.c
@@ -74,23 +74,6 @@
#define SMT_CRC_J1850 2u /* J1850 standard CRC */
#define SMT_CRC_CRC32 3u /* CRC32 standard CRC */
-/* SCMI protocol message IDs */
-
-#define SCMI_PROTOCOL_BASE 0x10u /* Base protocol */
-#define SCMI_PROTOCOL_POWER 0x11u /* Power domain management protocol */
-#define SCMI_PROTOCOL_SYS 0x12u /* System power management protocol */
-#define SCMI_PROTOCOL_PERF 0x13u /* Performance domain management protocol
*/
-#define SCMI_PROTOCOL_CLOCK 0x14u /* Clock management protocol */
-#define SCMI_PROTOCOL_SENSOR 0x15u /* Sensor management protocol */
-#define SCMI_PROTOCOL_RESET 0x16u /* Reset domain management protocol */
-#define SCMI_PROTOCOL_VOLTAGE 0x17u /* Voltage domain management protocol */
-#define SCMI_PROTOCOL_PINCTRL 0x19u /* Pin control protocol */
-#define SCMI_PROTOCOL_LMM 0x80u /* LM management protocol */
-#define SCMI_PROTOCOL_BBM 0x81u /* BBM management protocol */
-#define SCMI_PROTOCOL_CPU 0x82u /* CPU management protocol */
-#define SCMI_PROTOCOL_FUSA 0x83u /* FuSa protocol */
-#define SCMI_PROTOCOL_MISC 0x84u /* Misc protocol */
-
/* SCMI clock protocol message IDs */
#define SCMI_MSG_CLOCK_ATTRIBUTES 0x3u /* Get clock attributes */
@@ -118,6 +101,14 @@
#define SCMI_MSG_MISC_SI_INFO 0xbu /* Get silicon info */
+/* SCMI LMM protocol message IDs (SCMI_MSG_LMM_EVENT is in imx9_scmi.h) */
+
+#define SCMI_MSG_LMM_NOTIFY 0x9u /* Configure LM notifications */
+
+/* SCMI message type of a P2A notification */
+
+#define SCMI_MSG_TYPE_NOTIFY 3u
+
/* SCMI header creation */
#define SCMI_HEADER_MSG(x) (((x) & 0xffu) << 0u)
@@ -189,6 +180,8 @@ typedef struct
static smt_chn_config_t s_smtconfig[SMT_MAX_CHN];
static struct imx9_mudev_s *g_mudev;
static mutex_t mutex = NXMUTEX_INITIALIZER;
+static imx9_scmi_notify_cb_t g_notify_cb;
+static void *g_notify_arg;
/****************************************************************************
* Private Functions
@@ -512,6 +505,36 @@ static int32_t imx9_smt_rx(uint32_t smtchannel, uint32_t
*len, bool callee)
return status;
}
+/* SCMI P2A notifications, called from the MU interrupt */
+
+static void imx9_scmi_gpi_callback(int id, void *arg)
+{
+ smt_buf_t *buf = imx9_smt_smaget(SM_PLATFORM_NOTIFY);
+ uint32_t header;
+
+ if (id != SM_PLATFORM_NOTIFY || buf == NULL ||
+ imx9_smt_channelfree(SM_PLATFORM_NOTIFY))
+ {
+ return;
+ }
+
+ header = buf->header;
+
+ if (g_notify_cb != NULL)
+ {
+ g_notify_cb(SCMI_HEADER_PROTOCOL_EX(header),
+ SCMI_HEADER_MSG_EX(header), g_notify_arg);
+ }
+
+ /* Hand the channel back; the doorbell makes the SM send the next queued
+ * notification. This must come after the callback, which reads the
+ * message from the channel buffer.
+ */
+
+ buf->channel_status |= SMT_FREE;
+ imx9_mu_trigger_interrupts(g_mudev, 1 << SM_PLATFORM_NOTIFY);
+}
+
/* SCMI generics */
static int32_t imx9_scmi_bufinit(uint32_t channel, void **msg)
@@ -1117,10 +1140,167 @@ void imx9_scmi_initialize()
/* Configure SMT */
imx9_smt_channelconfig(SM_PLATFORM_A2P, SM_PLATFORM_MU_INST);
+ imx9_smt_channelconfig(SM_PLATFORM_NOTIFY, SM_PLATFORM_MU_INST);
/* Configure MU */
g_mudev = imx9_mu_init(5);
}
+int32_t imx9_scmi_notify_register(imx9_scmi_notify_cb_t cb, void *arg)
+{
+ smt_buf_t *buf = imx9_smt_smaget(SM_PLATFORM_NOTIFY);
+
+ if (cb == NULL || buf == NULL)
+ {
+ return -EINVAL;
+ }
+
+ if (g_notify_cb != NULL)
+ {
+ return -EBUSY;
+ }
+
+ g_notify_cb = cb;
+ g_notify_arg = arg;
+
+ /* imx9_scmi_initialize() runs from __start(), before irq_initialize()
+ * and up_irqinitialize() reset the vector table and the NVIC, so the MU
+ * interrupt set up there is lost. Attach and enable it now.
+ */
+
+ imx9_mu_enable_irq(g_mudev);
+
+ /* The SM only sends a notification once the channel is marked free */
+
+ buf->channel_status = SMT_FREE;
+
+ imx9_mu_subscribe_gpi(g_mudev, 1 << SM_PLATFORM_NOTIFY,
+ imx9_scmi_gpi_callback);
+
+ return OK;
+}
+
+int32_t imx9_scmi_lmmnotify(uint32_t channel, uint32_t lmid, uint32_t flags)
+{
+ int32_t status;
+ uint32_t header;
+ void *msg;
+
+ /* Acquire lock */
+
+ SCMI_A2P_LOCK(channel);
+
+ /* Init buffer */
+
+ status = imx9_scmi_bufinit(channel, &msg);
+
+ /* Send request */
+
+ if (status == OK)
+ {
+ /* Request message structure */
+
+ typedef struct
+ {
+ uint32_t header;
+ uint32_t lmid;
+ uint32_t flags;
+ } msg_tlmm9_t;
+
+ msg_tlmm9_t *msgtx = (msg_tlmm9_t *)msg;
+
+ /* Fill in parameters */
+
+ msgtx->lmid = lmid;
+ msgtx->flags = flags;
+
+ /* Send message */
+
+ status = imx9_scmi_a2ptx(channel, SCMI_PROTOCOL_LMM,
+ SCMI_MSG_LMM_NOTIFY, sizeof(msg_tlmm9_t),
+ &header);
+ }
+
+ /* Receive response */
+
+ if (status == OK)
+ {
+ status = imx9_scmi_a2prx(channel, sizeof(msg_status_t), header);
+ }
+
+ /* Release lock */
+
+ SCMI_A2P_UNLOCK(channel);
+
+ /* Return status */
+
+ return status;
+}
+
+int32_t imx9_scmi_lmmevent(uint32_t *lmid, uint32_t *eventlm,
+ uint32_t *flags)
+{
+ /* Notification message structure */
+
+ typedef struct
+ {
+ uint32_t header;
+ uint32_t lmid;
+ uint32_t eventlm;
+ uint32_t flags;
+ } msg_rlmm0_t;
+
+ const msg_rlmm0_t *msgrx = imx9_smt_hdraddrget(SM_PLATFORM_NOTIFY);
+ int32_t status;
+ uint32_t len;
+
+ if (msgrx == NULL)
+ {
+ return -EINVAL;
+ }
+
+ /* Nothing pending; imx9_smt_rx() would wait for a message */
+
+ if (imx9_smt_channelfree(SM_PLATFORM_NOTIFY))
+ {
+ return -ENODATA;
+ }
+
+ /* Receive message, checks the CRC */
+
+ status = imx9_smt_rx(SM_PLATFORM_NOTIFY, &len, true);
+
+ if (status == OK &&
+ (len < sizeof(msg_rlmm0_t) ||
+ SCMI_HEADER_TYPE_EX(msgrx->header) != SCMI_MSG_TYPE_NOTIFY ||
+ SCMI_HEADER_PROTOCOL_EX(msgrx->header) != SCMI_PROTOCOL_LMM ||
+ SCMI_HEADER_MSG_EX(msgrx->header) != SCMI_MSG_LMM_EVENT))
+ {
+ status = -EPROTO;
+ }
+
+ /* Copy out if no error */
+
+ if (status == OK)
+ {
+ if (lmid != NULL)
+ {
+ *lmid = msgrx->lmid;
+ }
+
+ if (eventlm != NULL)
+ {
+ *eventlm = msgrx->eventlm;
+ }
+
+ if (flags != NULL)
+ {
+ *flags = msgrx->flags;
+ }
+ }
+
+ return status;
+}
+
#endif /* CONFIG_IMX9_SCMI */
diff --git a/arch/arm/src/imx9/imx9_scmi.h b/arch/arm/src/imx9/imx9_scmi.h
index b45282a0581..0e86b41ab06 100644
--- a/arch/arm/src/imx9/imx9_scmi.h
+++ b/arch/arm/src/imx9/imx9_scmi.h
@@ -38,6 +38,31 @@
#define SM_PLATFORM_NOTIFY 1 /* SCMI Platform -> SCMI Agent */
#define SM_PLATFORM_PRIORITY 2
+/* SCMI protocol IDs */
+
+#define SCMI_PROTOCOL_BASE 0x10u /* Base protocol */
+#define SCMI_PROTOCOL_POWER 0x11u /* Power domain management protocol */
+#define SCMI_PROTOCOL_SYS 0x12u /* System power management protocol */
+#define SCMI_PROTOCOL_PERF 0x13u /* Performance domain management protocol
*/
+#define SCMI_PROTOCOL_CLOCK 0x14u /* Clock management protocol */
+#define SCMI_PROTOCOL_SENSOR 0x15u /* Sensor management protocol */
+#define SCMI_PROTOCOL_RESET 0x16u /* Reset domain management protocol */
+#define SCMI_PROTOCOL_VOLTAGE 0x17u /* Voltage domain management protocol */
+#define SCMI_PROTOCOL_PINCTRL 0x19u /* Pin control protocol */
+#define SCMI_PROTOCOL_LMM 0x80u /* LM management protocol */
+#define SCMI_PROTOCOL_BBM 0x81u /* BBM management protocol */
+#define SCMI_PROTOCOL_CPU 0x82u /* CPU management protocol */
+#define SCMI_PROTOCOL_FUSA 0x83u /* FuSa protocol */
+#define SCMI_PROTOCOL_MISC 0x84u /* Misc protocol */
+
+/* SCMI LMM notification message ID and event flags */
+
+#define SCMI_MSG_LMM_EVENT 0x0u
+#define SCMI_LMM_EVENT_BOOT (1u << 0u)
+#define SCMI_LMM_EVENT_SHUTDOWN (1u << 1u)
+#define SCMI_LMM_EVENT_SUSPEND (1u << 2u)
+#define SCMI_LMM_EVENT_WAKE (1u << 3u)
+
#define SM_CLOCK_RATE_MASK 0xFFFFFFFFU
/* SCMI clock round options */
@@ -142,6 +167,11 @@ typedef struct
uint8_t siname[SCMI_MISC_MAX_SINAME]; /* Silicon name/revision string */
} scmi_si_info_t;
+/* SCMI notification callback, see imx9_scmi_notify_register() */
+
+typedef void (*imx9_scmi_notify_cb_t)(uint32_t protocol, uint32_t msgid,
+ void *arg);
+
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@@ -186,4 +216,73 @@ int32_t imx9_scmi_pinctrlconfigset(uint32_t channel,
uint32_t identifier,
int32_t imx9_scmi_siinfoget(uint32_t channel, scmi_si_info_t *info);
+/****************************************************************************
+ * Name: imx9_scmi_notify_register
+ *
+ * Description:
+ * Register the callback for SCMI notifications from the System Manager
+ * and enable their reception. The callback is called from interrupt
+ * context with the protocol and message ID of the notification and must
+ * not block, so it must not call the SCMI request functions (they lock
+ * the A2P channel); defer such work, e.g. with work_queue(). It may read
+ * the message with the matching event function
+ * (e.g. imx9_scmi_lmmevent()); this is only valid inside the callback.
+ * The channel is handed back to the System Manager when it returns.
+ * Must be called after the OS is initialized.
+ *
+ * Input Parameters:
+ * cb - Notification callback
+ * arg - Argument passed to the callback
+ *
+ * Returned Value:
+ * OK on success, -EBUSY if a callback is already registered, a negated
+ * errno value on other failures.
+ *
+ ****************************************************************************/
+
+int32_t imx9_scmi_notify_register(imx9_scmi_notify_cb_t cb, void *arg);
+
+/****************************************************************************
+ * Name: imx9_scmi_lmmnotify
+ *
+ * Description:
+ * Subscribe to boot/shutdown notifications of a logical machine via the
+ * SCMI LMM protocol. Register the notification callback first, the
+ * System Manager may send an event right away.
+ *
+ * Input Parameters:
+ * channel - SCMI channel to use for the request
+ * lmid - Logical machine to receive events from
+ * flags - Events to enable (SCMI_LMM_EVENT_*)
+ *
+ * Returned Value:
+ * OK on success, a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int32_t imx9_scmi_lmmnotify(uint32_t channel, uint32_t lmid, uint32_t flags);
+
+/****************************************************************************
+ * Name: imx9_scmi_lmmevent
+ *
+ * Description:
+ * Read the pending LMM event notification. Only valid in the
+ * notification callback for SCMI_PROTOCOL_LMM / SCMI_MSG_LMM_EVENT.
+ *
+ * Input Parameters:
+ * lmid - Returned ID of the logical machine that caused the
+ * transition, may be NULL
+ * eventlm - Returned ID of the logical machine the event is for, may be
+ * NULL
+ * flags - Returned events (SCMI_LMM_EVENT_*), may be NULL
+ *
+ * Returned Value:
+ * OK on success, -ENODATA if no notification is pending, -EIO on a CRC
+ * error, -EPROTO if the message is not an LMM event.
+ *
+ ****************************************************************************/
+
+int32_t imx9_scmi_lmmevent(uint32_t *lmid, uint32_t *eventlm,
+ uint32_t *flags);
+
#endif /* __ARCH_ARM_SRC_IMX9_IMX9_SCMI_H */