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 */

Reply via email to