#define OPAL_FLASH_VALIDATE                    76
 #define OPAL_FLASH_MANAGE                      77
 #define OPAL_FLASH_UPDATE                      78
+#define OPAL_GET_MSG                           85
+#define OPAL_CHECK_ASYNC_COMPLETION            86
 
 #ifndef __ASSEMBLY__
 
        OPAL_EVENT_ERROR_LOG            = 0x40,
        OPAL_EVENT_EPOW                 = 0x80,
        OPAL_EVENT_LED_STATUS           = 0x100,
-       OPAL_EVENT_PCI_ERROR            = 0x200
+       OPAL_EVENT_PCI_ERROR            = 0x200,
+       OPAL_EVENT_MSG_PENDING          = 0x800,
+};
+
+enum OpalMessageType {
+       OPAL_MSG_ASYNC_COMP             = 0,
+       OPAL_MSG_MEM_ERR,
+       OPAL_MSG_EPOW,
+       OPAL_MSG_SHUTDOWN,
+       OPAL_MSG_TYPE_MAX,
 };
 
 /* Machine check related definitions */
        OPAL_LPC_FW     = 2,
 };
 
+struct opal_msg {
+       uint32_t msg_type;
+       uint32_t reserved;
+       uint64_t params[8];
+};
+
 struct opal_machine_check_event {
        enum OpalMCE_Version    version:8;      /* 0x00 */
        uint8_t                 in_use;         /* 0x01 */
 int64_t opal_manage_flash(uint8_t op);
 int64_t opal_update_flash(uint64_t blk_list);
 
+int64_t opal_get_msg(uint64_t buffer, size_t size);
+int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
+
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
 
                                   int depth, void *data);
 
 extern int opal_notifier_register(struct notifier_block *nb);
+extern int opal_message_notifier_register(enum OpalMessageType msg_type,
+                                               struct notifier_block *nb);
 extern void opal_notifier_enable(void);
 extern void opal_notifier_disable(void);
 extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
 
 static unsigned int *opal_irqs;
 static unsigned int opal_irq_count;
 static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
+static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
 static DEFINE_SPINLOCK(opal_notifier_lock);
 static uint64_t last_notified_mask = 0x0ul;
 static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
        atomic_set(&opal_notifier_hold, 1);
 }
 
+/*
+ * Opal message notifier based on message type. Allow subscribers to get
+ * notified for specific messgae type.
+ */
+int opal_message_notifier_register(enum OpalMessageType msg_type,
+                                       struct notifier_block *nb)
+{
+       if (!nb) {
+               pr_warning("%s: Invalid argument (%p)\n",
+                          __func__, nb);
+               return -EINVAL;
+       }
+       if (msg_type > OPAL_MSG_TYPE_MAX) {
+               pr_warning("%s: Invalid message type argument (%d)\n",
+                          __func__, msg_type);
+               return -EINVAL;
+       }
+       return atomic_notifier_chain_register(
+                               &opal_msg_notifier_head[msg_type], nb);
+}
+
+static void opal_message_do_notify(uint32_t msg_type, void *msg)
+{
+       /* notify subscribers */
+       atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type],
+                                       msg_type, msg);
+}
+
+static void opal_handle_message(void)
+{
+       s64 ret;
+       /*
+        * TODO: pre-allocate a message buffer depending on opal-msg-size
+        * value in /proc/device-tree.
+        */
+       static struct opal_msg msg;
+
+       ret = opal_get_msg(__pa(&msg), sizeof(msg));
+       /* No opal message pending. */
+       if (ret == OPAL_RESOURCE)
+               return;
+
+       /* check for errors. */
+       if (ret) {
+               pr_warning("%s: Failed to retrive opal message, err=%lld\n",
+                               __func__, ret);
+               return;
+       }
+
+       /* Sanity check */
+       if (msg.msg_type > OPAL_MSG_TYPE_MAX) {
+               pr_warning("%s: Unknown message type: %u\n",
+                               __func__, msg.msg_type);
+               return;
+       }
+       opal_message_do_notify(msg.msg_type, (void *)&msg);
+}
+
+static int opal_message_notify(struct notifier_block *nb,
+                         unsigned long events, void *change)
+{
+       if (events & OPAL_EVENT_MSG_PENDING)
+               opal_handle_message();
+       return 0;
+}
+
+static struct notifier_block opal_message_nb = {
+       .notifier_call  = opal_message_notify,
+       .next           = NULL,
+       .priority       = 0,
+};
+
+static int __init opal_message_init(void)
+{
+       int ret, i;
+
+       for (i = 0; i < OPAL_MSG_TYPE_MAX; i++)
+               ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]);
+
+       ret = opal_notifier_register(&opal_message_nb);
+       if (ret) {
+               pr_err("%s: Can't register OPAL event notifier (%d)\n",
+                      __func__, ret);
+               return ret;
+       }
+       return 0;
+}
+early_initcall(opal_message_init);
+
 int opal_get_chars(uint32_t vtermno, char *buf, int count)
 {
        s64 rc;