sdm: Add histogram event registration

Adds histogram event registration and handling to UEventThread.
This is similar to other events sourcing from /dev/dri/card0.
This registers the event, but it is not requested yet
(follow up patch will add requests for the event to the drm atomic commit)

Change-Id: Idd4ef25f883c1fbee70ca17e7170e5dda9b6e7c8
Signed-off-by: Kevin DuBois <kevindubois@google.com>
Signed-off-by: Lakshmi Narayana Kalavala <lkalaval@codeaurora.org>
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index 8d0e1bd..1aaf80d 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -87,20 +87,17 @@
   }
 
   if (hw_panel_info_.mode == kModeCommand) {
-    event_list_ = {HWEvent::VSYNC,
-                   HWEvent::EXIT,
-                   HWEvent::IDLE_NOTIFY,
-                   HWEvent::SHOW_BLANK_EVENT,
-                   HWEvent::THERMAL_LEVEL,
-                   HWEvent::IDLE_POWER_COLLAPSE,
-                   HWEvent::PINGPONG_TIMEOUT,
-                   HWEvent::PANEL_DEAD,
-                   HWEvent::HW_RECOVERY};
+    event_list_ = {HWEvent::VSYNC, HWEvent::EXIT,
+                   /*HWEvent::IDLE_NOTIFY, */
+                   HWEvent::SHOW_BLANK_EVENT, HWEvent::THERMAL_LEVEL, HWEvent::IDLE_POWER_COLLAPSE,
+                   HWEvent::PINGPONG_TIMEOUT, HWEvent::PANEL_DEAD, HWEvent::HW_RECOVERY,
+                   HWEvent::HISTOGRAM};
   } else {
     event_list_ = {HWEvent::VSYNC,         HWEvent::EXIT,
                    HWEvent::IDLE_NOTIFY,   HWEvent::SHOW_BLANK_EVENT,
                    HWEvent::THERMAL_LEVEL, HWEvent::PINGPONG_TIMEOUT,
-                   HWEvent::PANEL_DEAD,    HWEvent::HW_RECOVERY};
+                   HWEvent::PANEL_DEAD,    HWEvent::HW_RECOVERY,
+                   HWEvent::HISTOGRAM};
   }
 
   avr_prop_disabled_ = Debug::IsAVRDisabled();
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index 01d3747..4c8f3bc 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -44,6 +44,7 @@
 #include <drm/msm_drm.h>
 
 #include <algorithm>
+#include <array>
 #include <map>
 #include <utility>
 #include <vector>
@@ -136,6 +137,15 @@
         poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
         hw_recovery_index_ = i;
       } break;
+      case HWEvent::HISTOGRAM: {
+        poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
+        if (poll_fds_[i].fd < 0) {
+          DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
+          return kErrorResources;
+        }
+        poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
+        histogram_index_ = i;
+      } break;
       case HWEvent::CEC_READ_MESSAGE:
       case HWEvent::SHOW_BLANK_EVENT:
       case HWEvent::THERMAL_LEVEL:
@@ -179,6 +189,9 @@
       case HWEvent::HW_RECOVERY:
         event_data.event_parser = &HWEventsDRM::HandleHwRecovery;
         break;
+      case HWEvent::HISTOGRAM:
+        event_data.event_parser = &HWEventsDRM::HandleHistogram;
+        break;
       default:
         error = kErrorParameters;
         break;
@@ -234,12 +247,14 @@
   if (!disable_hw_recovery_) {
     RegisterHwRecovery(true);
   }
+  RegisterHistogram(true);
 
   return kErrorNone;
 }
 
 DisplayError HWEventsDRM::Deinit() {
   exit_threads_ = true;
+  RegisterHistogram(false);
   RegisterPanelDead(false);
   RegisterIdleNotify(false);
   RegisterIdlePowerCollapse(false);
@@ -356,6 +371,7 @@
         case HWEvent::IDLE_NOTIFY:
         case HWEvent::IDLE_POWER_COLLAPSE:
         case HWEvent::HW_RECOVERY:
+        case HWEvent::HISTOGRAM:
           if (poll_fd.revents & (POLLIN | POLLPRI | POLLERR)) {
             (this->*(event_data_list_[i]).event_parser)(nullptr);
           }
@@ -429,6 +445,31 @@
   return kErrorNone;
 }
 
+DisplayError HWEventsDRM::RegisterHistogram(bool enable) {
+  if (histogram_index_ == UINT32_MAX) {
+    DLOGI("histogram is not supported event");
+    return kErrorNone;
+  }
+  struct drm_msm_event_req req = {};
+  int ret = 0;
+
+  req.object_id = token_.crtc_id;
+  req.object_type = DRM_MODE_OBJECT_CRTC;
+  req.event = DRM_EVENT_HISTOGRAM;
+  if (enable) {
+    ret = drmIoctl(poll_fds_[histogram_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
+  } else {
+    ret = drmIoctl(poll_fds_[histogram_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
+  }
+
+  if (ret) {
+    DLOGE("register idle notify enable:%d failed", enable);
+    return kErrorResources;
+  }
+
+  return kErrorNone;
+}
+
 DisplayError HWEventsDRM::RegisterIdleNotify(bool enable) {
   if (idle_notify_index_ == UINT32_MAX) {
     DLOGI("idle notify is not supported event");
@@ -721,6 +762,20 @@
   return;
 }
 
+void HWEventsDRM::HandleHistogram(char * /*data*/) {
+  auto constexpr expected_size = sizeof(drm_msm_event_resp) + sizeof(uint32_t);
+  std::array<char, expected_size> event_data{'\0'};
+  auto size = Sys::pread_(poll_fds_[histogram_index_].fd, event_data.data(), event_data.size(), 0);
+  if (size != expected_size) {
+    DLOGE("event size %d is unexpected. skipping this histogram event", size);
+    return;
+  }
+
+  auto msm_event = reinterpret_cast<struct drm_msm_event_resp *>(event_data.data());
+  auto blob_id = reinterpret_cast<uint32_t *>(msm_event->data);
+  DLOGI("Received histogram event %i", *blob_id);
+}
+
 int HWEventsDRM::SetHwRecoveryEvent(const uint32_t hw_event_code, HWRecoveryEvent *sdm_event_code) {
   switch (hw_event_code) {
      case SDE_RECOVERY_SUCCESS:
diff --git a/sdm/libs/core/drm/hw_events_drm.h b/sdm/libs/core/drm/hw_events_drm.h
index 2a98504..5838a4a 100644
--- a/sdm/libs/core/drm/hw_events_drm.h
+++ b/sdm/libs/core/drm/hw_events_drm.h
@@ -78,6 +78,7 @@
   void HandleIdlePowerCollapse(char *data);
   void HandlePanelDead(char *data);
   void HandleHwRecovery(char *data);
+  void HandleHistogram(char *data);
   int SetHwRecoveryEvent(const uint32_t hw_event_code, HWRecoveryEvent *sdm_event_code);
   void PopulateHWEventData(const vector<HWEvent> &event_list);
   void WakeUpEventThread();
@@ -89,6 +90,7 @@
   DisplayError RegisterIdleNotify(bool enable);
   DisplayError RegisterIdlePowerCollapse(bool enable);
   DisplayError RegisterHwRecovery(bool enable);
+  DisplayError RegisterHistogram(bool enable);
 
   HWEventHandler *event_handler_{};
   vector<HWEventData> event_data_list_{};
@@ -97,6 +99,7 @@
   std::string event_thread_name_ = "SDM_EventThread";
   bool exit_threads_ = false;
   uint32_t vsync_index_ = UINT32_MAX;
+  uint32_t histogram_index_ = UINT32_MAX;
   bool vsync_enabled_ = false;
   bool vsync_registered_ = false;
   std::mutex vsync_mutex_;  // To protect vsync_enabled_ and vsync_registered_
diff --git a/sdm/libs/core/hw_events_interface.h b/sdm/libs/core/hw_events_interface.h
index 81d9b04..d32485f 100644
--- a/sdm/libs/core/hw_events_interface.h
+++ b/sdm/libs/core/hw_events_interface.h
@@ -46,6 +46,7 @@
   PINGPONG_TIMEOUT,
   PANEL_DEAD,
   HW_RECOVERY,
+  HISTOGRAM,
 };
 
 class HWEventsInterface {