sdm: Implement idle fallback support in DRM.
Add CRTC property to set idle timeout. Enhance DRM event
handler for idle fall back custom event registration and
event handling
CRs-Fixed: 2097588
Change-Id: I543286a59a4ae95bc32b25960d1fc43551391951
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index f40f324..53a709e 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -242,6 +242,12 @@
*/
CRTC_SET_SOLIDFILL_STAGES,
/*
+ * Op: Sets idle timeout.
+ * Arg: uint32_t - CRTC ID
+ * uint32_t - idle timeout in ms
+ */
+ CRTC_SET_IDLE_TIMEOUT,
+ /*
* Op: Returns retire fence for this commit. Should be called after Commit() on
* DRMAtomicReqInterface.
* Arg: uint32_t - Connector ID
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index 1135475..0c8760e 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -166,10 +166,7 @@
void DisplayPrimary::SetIdleTimeoutMs(uint32_t active_ms) {
lock_guard<recursive_mutex> obj(recursive_mutex_);
-
- if (comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, active_ms) == kErrorNone) {
- hw_intf_->SetIdleTimeoutMs(active_ms);
- }
+ comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, active_ms);
}
DisplayError DisplayPrimary::SetDisplayMode(uint32_t mode) {
@@ -208,7 +205,7 @@
ControlPartialUpdate(false /* enable */, &pending);
} else if (mode == kModeCommand) {
// Flush idle timeout value currently set.
- hw_intf_->SetIdleTimeoutMs(0);
+ comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, 0);
switch_to_cmd_ = true;
}
}
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index ecc0f63..da33a25 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -905,6 +905,13 @@
}
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, ¤t_mode);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
+
+ if (!validate && (hw_layer_info.set_idle_time_ms >= 0)) {
+ DLOGI_IF(kTagDriverConfig, "Setting idle timeout to = %d ms",
+ hw_layer_info.set_idle_time_ms);
+ drm_atomic_intf_->Perform(DRMOps::CRTC_SET_IDLE_TIMEOUT, token_.crtc_id,
+ hw_layer_info.set_idle_time_ms);
+ }
}
void HWDeviceDRM::AddSolidfillStage(const HWSolidfillStage &sf, uint32_t plane_alpha) {
@@ -1230,7 +1237,9 @@
return kErrorNotSupported;
}
-void HWDeviceDRM::SetIdleTimeoutMs(uint32_t timeout_ms) {}
+void HWDeviceDRM::SetIdleTimeoutMs(uint32_t timeout_ms) {
+ // TODO(user): This function can be removed after fb is deprecated
+}
DisplayError HWDeviceDRM::SetDisplayMode(const HWDisplayMode hw_display_mode) {
return kErrorNotSupported;
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index 2745ee7..a90d294 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -40,6 +40,7 @@
#include <utils/debug.h>
#include <utils/sys.h>
#include <xf86drm.h>
+#include <drm/msm_drm.h>
#include <algorithm>
#include <map>
@@ -86,7 +87,15 @@
// Clear any existing data
Sys::pread_(poll_fds_[i].fd, data, kMaxStringLength, 0);
} break;
- case HWEvent::IDLE_NOTIFY:
+ case HWEvent::IDLE_NOTIFY: {
+ 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;
+ idle_notify_index_ = i;
+ } break;
case HWEvent::CEC_READ_MESSAGE:
case HWEvent::SHOW_BLANK_EVENT:
case HWEvent::THERMAL_LEVEL:
@@ -182,6 +191,7 @@
}
RegisterPanelDead(true);
+ RegisterIdleNotify(true);
return kErrorNone;
}
@@ -189,6 +199,7 @@
DisplayError HWEventsDRM::Deinit() {
exit_threads_ = true;
RegisterPanelDead(false);
+ RegisterIdleNotify(false);
Sys::pthread_cancel_(event_thread_);
WakeUpEventThread();
pthread_join(event_thread_, NULL);
@@ -294,6 +305,7 @@
switch (event_data_list_[i].event_type) {
case HWEvent::VSYNC:
case HWEvent::PANEL_DEAD:
+ case HWEvent::IDLE_NOTIFY:
if (poll_fd.revents & (POLLIN | POLLPRI | POLLERR)) {
(this->*(event_data_list_[i]).event_parser)(nullptr);
}
@@ -304,7 +316,6 @@
(this->*(event_data_list_[i]).event_parser)(data);
}
break;
- case HWEvent::IDLE_NOTIFY:
case HWEvent::CEC_READ_MESSAGE:
case HWEvent::SHOW_BLANK_EVENT:
case HWEvent::THERMAL_LEVEL:
@@ -374,6 +385,39 @@
return kErrorNone;
}
+DisplayError HWEventsDRM::RegisterIdleNotify(bool enable) {
+ uint32_t i = 0;
+ for (; i < event_data_list_.size(); i++) {
+ if (event_data_list_[i].event_type == HWEvent::IDLE_NOTIFY) {
+ break;
+ }
+ }
+
+ if (i == event_data_list_.size()) {
+ DLOGI("idle notify 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_IDLE_NOTIFY;
+ if (enable) {
+ ret = drmIoctl(poll_fds_[idle_notify_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
+ } else {
+ ret = drmIoctl(poll_fds_[idle_notify_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
+ }
+
+ if (ret) {
+ DLOGE("register idle notify enable:%d failed", enable);
+ return kErrorResources;
+ }
+
+ return kErrorNone;
+}
+
void HWEventsDRM::HandleVSync(char *data) {
drmEventContext event = {};
event.version = DRM_EVENT_CONTEXT_VERSION;
@@ -432,7 +476,45 @@
}
void HWEventsDRM::HandleIdleTimeout(char *data) {
- event_handler_->IdleTimeout();
+ char event_data[kMaxStringLength];
+ int32_t size;
+ struct drm_msm_event_resp *event_resp = NULL;
+
+ size = (int32_t)Sys::pread_(poll_fds_[idle_notify_index_].fd, event_data, kMaxStringLength, 0);
+ if (size < 0) {
+ return;
+ }
+
+ if (size > kMaxStringLength) {
+ DLOGE("event size %d is greater than event buffer size %zd\n", size, kMaxStringLength);
+ return;
+ }
+
+ if (size < (int32_t)sizeof(*event_resp)) {
+ DLOGE("size %d exp %zd\n", size, sizeof(*event_resp));
+ return;
+ }
+
+ int32_t i = 0;
+
+ while (i < size) {
+ event_resp = (struct drm_msm_event_resp *)&event_data[i];
+ switch (event_resp->base.type) {
+ case DRM_EVENT_IDLE_NOTIFY:
+ {
+ DLOGV("Received Idle time event");
+ event_handler_->IdleTimeout();
+ break;
+ }
+ default: {
+ DLOGE("invalid event %d", event_resp->base.type);
+ break;
+ }
+ }
+ i += event_resp->base.length;
+ }
+
+ return;
}
void HWEventsDRM::HandleCECMessage(char *data) {
diff --git a/sdm/libs/core/drm/hw_events_drm.h b/sdm/libs/core/drm/hw_events_drm.h
index 4db0346..a7fb463 100644
--- a/sdm/libs/core/drm/hw_events_drm.h
+++ b/sdm/libs/core/drm/hw_events_drm.h
@@ -83,6 +83,7 @@
DisplayError CloseFds();
DisplayError RegisterVSync();
DisplayError RegisterPanelDead(bool enable);
+ DisplayError RegisterIdleNotify(bool enable);
HWEventHandler *event_handler_{};
vector<HWEventData> event_data_list_{};
@@ -92,6 +93,7 @@
bool exit_threads_ = false;
uint32_t vsync_index_ = 0;
bool vsync_enabled_ = false;
+ uint32_t idle_notify_index_ = 0;
sde_drm::DRMDisplayToken token_ = {};
bool is_primary_ = false;
uint32_t panel_dead_index_ = 0;