1 /*
2 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <drm_master.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <math.h>
34 #include <pthread.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/prctl.h>
38 #include <sys/resource.h>
39 #include <sys/types.h>
40 #include <utils/debug.h>
41 #include <utils/sys.h>
42 #include <xf86drm.h>
43 #include <drm/msm_drm.h>
44
45 #include <algorithm>
46 #include <map>
47 #include <utility>
48 #include <vector>
49
50 #include "hw_events_drm.h"
51
52 #define __CLASS__ "HWEventsDRM"
53
54 namespace sdm {
55
56 using drm_utils::DRMMaster;
57
InitializePollFd()58 DisplayError HWEventsDRM::InitializePollFd() {
59 for (uint32_t i = 0; i < event_data_list_.size(); i++) {
60 char data[kMaxStringLength]{};
61 HWEventData &event_data = event_data_list_[i];
62 poll_fds_[i] = {};
63 poll_fds_[i].fd = -1;
64
65 switch (event_data.event_type) {
66 case HWEvent::VSYNC: {
67 poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
68 if (is_primary_) {
69 DRMMaster *master = nullptr;
70 int ret = DRMMaster::GetInstance(&master);
71 if (ret < 0) {
72 DLOGE("Failed to acquire DRMMaster instance");
73 return kErrorNotSupported;
74 }
75 master->GetHandle(&poll_fds_[i].fd);
76 } else {
77 poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
78 }
79 vsync_index_ = i;
80 } break;
81 case HWEvent::EXIT: {
82 // Create an eventfd to be used to unblock the poll system call when
83 // a thread is exiting.
84 poll_fds_[i].fd = Sys::eventfd_(0, 0);
85 poll_fds_[i].events |= POLLIN;
86 // Clear any existing data
87 Sys::pread_(poll_fds_[i].fd, data, kMaxStringLength, 0);
88 } break;
89 case HWEvent::IDLE_NOTIFY: {
90 poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
91 if (poll_fds_[i].fd < 0) {
92 DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
93 return kErrorResources;
94 }
95 poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
96 idle_notify_index_ = i;
97 } break;
98 case HWEvent::IDLE_POWER_COLLAPSE: {
99 poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
100 if (poll_fds_[i].fd < 0) {
101 DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
102 return kErrorResources;
103 }
104 poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
105 idle_pc_index_ = i;
106 } break;
107 case HWEvent::PANEL_DEAD: {
108 poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
109 if (poll_fds_[i].fd < 0) {
110 DLOGE("drmOpen failed with error %d", poll_fds_[i].fd);
111 return kErrorResources;
112 }
113 poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
114 panel_dead_index_ = i;
115 } break;
116 case HWEvent::CEC_READ_MESSAGE:
117 case HWEvent::SHOW_BLANK_EVENT:
118 case HWEvent::THERMAL_LEVEL:
119 case HWEvent::PINGPONG_TIMEOUT:
120 break;
121 }
122 }
123
124 return kErrorNone;
125 }
126
SetEventParser()127 DisplayError HWEventsDRM::SetEventParser() {
128 DisplayError error = kErrorNone;
129
130 for (auto &event_data : event_data_list_) {
131 switch (event_data.event_type) {
132 case HWEvent::VSYNC:
133 event_data.event_parser = &HWEventsDRM::HandleVSync;
134 break;
135 case HWEvent::IDLE_NOTIFY:
136 event_data.event_parser = &HWEventsDRM::HandleIdleTimeout;
137 break;
138 case HWEvent::CEC_READ_MESSAGE:
139 event_data.event_parser = &HWEventsDRM::HandleCECMessage;
140 break;
141 case HWEvent::EXIT:
142 event_data.event_parser = &HWEventsDRM::HandleThreadExit;
143 break;
144 case HWEvent::SHOW_BLANK_EVENT:
145 event_data.event_parser = &HWEventsDRM::HandleBlank;
146 break;
147 case HWEvent::THERMAL_LEVEL:
148 event_data.event_parser = &HWEventsDRM::HandleThermal;
149 break;
150 case HWEvent::IDLE_POWER_COLLAPSE:
151 event_data.event_parser = &HWEventsDRM::HandleIdlePowerCollapse;
152 break;
153 case HWEvent::PANEL_DEAD:
154 event_data.event_parser = &HWEventsDRM::HandlePanelDead;
155 break;
156 default:
157 error = kErrorParameters;
158 break;
159 }
160 }
161
162 return error;
163 }
164
PopulateHWEventData(const vector<HWEvent> & event_list)165 void HWEventsDRM::PopulateHWEventData(const vector<HWEvent> &event_list) {
166 for (auto &event : event_list) {
167 HWEventData event_data;
168 event_data.event_type = event;
169 event_data_list_.push_back(std::move(event_data));
170 }
171
172 SetEventParser();
173 InitializePollFd();
174 }
175
Init(int display_type,HWEventHandler * event_handler,const vector<HWEvent> & event_list,const HWInterface * hw_intf)176 DisplayError HWEventsDRM::Init(int display_type, HWEventHandler *event_handler,
177 const vector<HWEvent> &event_list,
178 const HWInterface *hw_intf) {
179 if (!event_handler)
180 return kErrorParameters;
181
182 static_cast<const HWDeviceDRM *>(hw_intf)->GetDRMDisplayToken(&token_);
183 is_primary_ = static_cast<const HWDeviceDRM *>(hw_intf)->IsPrimaryDisplay();
184
185 DLOGI("Setup event handler for display %d, CRTC %d, Connector %d",
186 display_type, token_.crtc_id, token_.conn_id);
187
188 event_handler_ = event_handler;
189 poll_fds_.resize(event_list.size());
190 event_thread_name_ += " - " + std::to_string(display_type);
191
192 PopulateHWEventData(event_list);
193
194 if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) {
195 DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str());
196 return kErrorResources;
197 }
198
199 RegisterVSync();
200 vsync_registered_ = true;
201 RegisterPanelDead(true);
202 RegisterIdleNotify(true);
203 RegisterIdlePowerCollapse(true);
204
205 return kErrorNone;
206 }
207
Deinit()208 DisplayError HWEventsDRM::Deinit() {
209 exit_threads_ = true;
210 RegisterPanelDead(false);
211 RegisterIdleNotify(false);
212 RegisterIdlePowerCollapse(false);
213 Sys::pthread_cancel_(event_thread_);
214 WakeUpEventThread();
215 pthread_join(event_thread_, NULL);
216 CloseFds();
217
218 return kErrorNone;
219 }
220
SetEventState(HWEvent event,bool enable,void * arg)221 DisplayError HWEventsDRM::SetEventState(HWEvent event, bool enable, void *arg) {
222 switch (event) {
223 case HWEvent::VSYNC: {
224 std::lock_guard<std::mutex> lock(vsync_mutex_);
225 vsync_enabled_ = enable;
226 if (vsync_enabled_ && !vsync_registered_) {
227 RegisterVSync();
228 vsync_registered_ = true;
229 }
230 } break;
231 default:
232 DLOGE("Event not supported");
233 return kErrorNotSupported;
234 }
235
236 return kErrorNone;
237 }
238
WakeUpEventThread()239 void HWEventsDRM::WakeUpEventThread() {
240 for (uint32_t i = 0; i < event_data_list_.size(); i++) {
241 if (event_data_list_[i].event_type == HWEvent::EXIT && poll_fds_[i].fd >= 0) {
242 uint64_t exit_value = 1;
243 ssize_t write_size = Sys::write_(poll_fds_[i].fd, &exit_value, sizeof(uint64_t));
244 if (write_size != sizeof(uint64_t)) {
245 DLOGW("Error triggering exit fd (%d). write size = %d, error = %s", poll_fds_[i].fd,
246 write_size, strerror(errno));
247 }
248 break;
249 }
250 }
251 }
252
CloseFds()253 DisplayError HWEventsDRM::CloseFds() {
254 for (uint32_t i = 0; i < event_data_list_.size(); i++) {
255 switch (event_data_list_[i].event_type) {
256 case HWEvent::VSYNC:
257 if (!is_primary_) {
258 Sys::close_(poll_fds_[i].fd);
259 }
260 poll_fds_[i].fd = -1;
261 break;
262 case HWEvent::EXIT:
263 Sys::close_(poll_fds_[i].fd);
264 poll_fds_[i].fd = -1;
265 break;
266 case HWEvent::IDLE_NOTIFY:
267 case HWEvent::IDLE_POWER_COLLAPSE:
268 case HWEvent::PANEL_DEAD:
269 drmClose(poll_fds_[i].fd);
270 poll_fds_[i].fd = -1;
271 break;
272 case HWEvent::CEC_READ_MESSAGE:
273 case HWEvent::SHOW_BLANK_EVENT:
274 case HWEvent::THERMAL_LEVEL:
275 break;
276 default:
277 return kErrorNotSupported;
278 }
279 }
280
281 return kErrorNone;
282 }
283
DisplayEventThread(void * context)284 void *HWEventsDRM::DisplayEventThread(void *context) {
285 if (context) {
286 return reinterpret_cast<HWEventsDRM *>(context)->DisplayEventHandler();
287 }
288
289 return NULL;
290 }
291
DisplayEventHandler()292 void *HWEventsDRM::DisplayEventHandler() {
293 char data[kMaxStringLength]{};
294
295 prctl(PR_SET_NAME, event_thread_name_.c_str(), 0, 0, 0);
296 setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent);
297
298 while (!exit_threads_) {
299 int error = Sys::poll_(poll_fds_.data(), UINT32(poll_fds_.size()), -1);
300 if (error <= 0) {
301 DLOGW("poll failed. error = %s", strerror(errno));
302 continue;
303 }
304
305 for (uint32_t i = 0; i < event_data_list_.size(); i++) {
306 pollfd &poll_fd = poll_fds_[i];
307 if (poll_fd.fd < 0) {
308 continue;
309 }
310
311 switch (event_data_list_[i].event_type) {
312 case HWEvent::VSYNC:
313 case HWEvent::PANEL_DEAD:
314 case HWEvent::IDLE_NOTIFY:
315 case HWEvent::IDLE_POWER_COLLAPSE:
316 if (poll_fd.revents & (POLLIN | POLLPRI | POLLERR)) {
317 (this->*(event_data_list_[i]).event_parser)(nullptr);
318 }
319 break;
320 case HWEvent::EXIT:
321 if ((poll_fd.revents & POLLIN) &&
322 (Sys::read_(poll_fd.fd, data, kMaxStringLength) > 0)) {
323 (this->*(event_data_list_[i]).event_parser)(data);
324 }
325 break;
326 case HWEvent::CEC_READ_MESSAGE:
327 case HWEvent::SHOW_BLANK_EVENT:
328 case HWEvent::THERMAL_LEVEL:
329 case HWEvent::PINGPONG_TIMEOUT:
330 if ((poll_fd.revents & POLLPRI) &&
331 (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) {
332 (this->*(event_data_list_[i]).event_parser)(data);
333 }
334 break;
335 }
336 }
337 }
338
339 pthread_exit(0);
340
341 return nullptr;
342 }
343
RegisterVSync()344 DisplayError HWEventsDRM::RegisterVSync() {
345 drmVBlank vblank {};
346 uint32_t high_crtc = token_.crtc_index << DRM_VBLANK_HIGH_CRTC_SHIFT;
347 vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT |
348 (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
349 vblank.request.sequence = 1;
350 // DRM hack to pass in context to unused field signal. Driver will write this to the node being
351 // polled on, and will be read as part of drm event handling and sent to handler
352 vblank.request.signal = reinterpret_cast<unsigned long>(this); // NOLINT
353 int error = drmWaitVBlank(poll_fds_[vsync_index_].fd, &vblank);
354 if (error < 0) {
355 DLOGE("drmWaitVBlank failed with err %d", errno);
356 return kErrorResources;
357 }
358
359 return kErrorNone;
360 }
361
RegisterPanelDead(bool enable)362 DisplayError HWEventsDRM::RegisterPanelDead(bool enable) {
363 uint32_t i = 0;
364 for (; i < event_data_list_.size(); i++) {
365 if (event_data_list_[i].event_type == HWEvent::PANEL_DEAD) {
366 break;
367 }
368 }
369
370 if (i == event_data_list_.size()) {
371 DLOGI("panel dead is not supported event");
372 return kErrorNone;
373 }
374
375 struct drm_msm_event_req req = {};
376 int ret = 0;
377
378 req.object_id = token_.conn_id;
379 req.object_type = DRM_MODE_OBJECT_CONNECTOR;
380 req.event = DRM_EVENT_PANEL_DEAD;
381 if (enable) {
382 ret = drmIoctl(poll_fds_[panel_dead_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
383 } else {
384 ret = drmIoctl(poll_fds_[panel_dead_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
385 }
386
387 if (ret) {
388 DLOGE("register panel dead enable:%d failed", enable);
389 return kErrorResources;
390 }
391
392 return kErrorNone;
393 }
394
RegisterIdleNotify(bool enable)395 DisplayError HWEventsDRM::RegisterIdleNotify(bool enable) {
396 uint32_t i = 0;
397 for (; i < event_data_list_.size(); i++) {
398 if (event_data_list_[i].event_type == HWEvent::IDLE_NOTIFY) {
399 break;
400 }
401 }
402
403 if (i == event_data_list_.size()) {
404 DLOGI("idle notify is not supported event");
405 return kErrorNone;
406 }
407
408 struct drm_msm_event_req req = {};
409 int ret = 0;
410
411 req.object_id = token_.crtc_id;
412 req.object_type = DRM_MODE_OBJECT_CRTC;
413 req.event = DRM_EVENT_IDLE_NOTIFY;
414 if (enable) {
415 ret = drmIoctl(poll_fds_[idle_notify_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
416 } else {
417 ret = drmIoctl(poll_fds_[idle_notify_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
418 }
419
420 if (ret) {
421 DLOGE("register idle notify enable:%d failed", enable);
422 return kErrorResources;
423 }
424
425 return kErrorNone;
426 }
427
RegisterIdlePowerCollapse(bool enable)428 DisplayError HWEventsDRM::RegisterIdlePowerCollapse(bool enable) {
429 uint32_t i = 0;
430 for (; i < event_data_list_.size(); i++) {
431 if (event_data_list_[i].event_type == HWEvent::IDLE_POWER_COLLAPSE) {
432 break;
433 }
434 }
435
436 if (i == event_data_list_.size()) {
437 DLOGI("idle power collapse is not supported event");
438 return kErrorNone;
439 }
440
441 struct drm_msm_event_req req = {};
442 int ret = 0;
443
444 req.object_id = token_.crtc_id;
445 req.object_type = DRM_MODE_OBJECT_CRTC;
446 req.event = DRM_EVENT_SDE_POWER;
447 if (enable) {
448 ret = drmIoctl(poll_fds_[idle_pc_index_].fd, DRM_IOCTL_MSM_REGISTER_EVENT, &req);
449 } else {
450 ret = drmIoctl(poll_fds_[idle_pc_index_].fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &req);
451 }
452
453 if (ret) {
454 DLOGE("register idle power collapse enable:%d failed", enable);
455 return kErrorResources;
456 }
457
458 return kErrorNone;
459 }
460
HandleVSync(char * data)461 void HWEventsDRM::HandleVSync(char *data) {
462 drmEventContext event = {};
463 event.version = DRM_EVENT_CONTEXT_VERSION;
464 event.vblank_handler = &HWEventsDRM::VSyncHandlerCallback;
465 int error = drmHandleEvent(poll_fds_[vsync_index_].fd, &event);
466 if (error != 0) {
467 DLOGE("drmHandleEvent failed: %i", error);
468 }
469
470 std::lock_guard<std::mutex> lock(vsync_mutex_);
471 vsync_registered_ = false;
472 if (vsync_enabled_) {
473 RegisterVSync();
474 vsync_registered_ = true;
475 }
476 }
477
HandlePanelDead(char * data)478 void HWEventsDRM::HandlePanelDead(char *data) {
479 char event_data[kMaxStringLength] = {0};
480 int32_t size;
481 struct drm_msm_event_resp *event_resp = NULL;
482
483 size = (int32_t)Sys::pread_(poll_fds_[panel_dead_index_].fd, event_data, kMaxStringLength, 0);
484 if (size <= 0) {
485 return;
486 }
487
488 if (size > kMaxStringLength) {
489 DLOGE("event size %d is greater than event buffer size %zd\n", size, kMaxStringLength);
490 return;
491 }
492
493 if (size < (int32_t)sizeof(*event_resp)) {
494 DLOGE("Invalid event size %d expected %zd\n", size, sizeof(*event_resp));
495 return;
496 }
497
498 int32_t i = 0;
499 while (i < size) {
500 event_resp = (struct drm_msm_event_resp *)&event_data[i];
501 switch (event_resp->base.type) {
502 case DRM_EVENT_PANEL_DEAD:
503 {
504 DLOGI("Received panel dead event");
505 event_handler_->PanelDead();
506 break;
507 }
508 default: {
509 DLOGE("invalid event %d", event_resp->base.type);
510 break;
511 }
512 }
513 i += event_resp->base.length;
514 }
515
516 return;
517 }
518
VSyncHandlerCallback(int fd,unsigned int sequence,unsigned int tv_sec,unsigned int tv_usec,void * data)519 void HWEventsDRM::VSyncHandlerCallback(int fd, unsigned int sequence, unsigned int tv_sec,
520 unsigned int tv_usec, void *data) {
521 int64_t timestamp = (int64_t)(tv_sec)*1000000000 + (int64_t)(tv_usec)*1000;
522 reinterpret_cast<HWEventsDRM *>(data)->event_handler_->VSync(timestamp);
523 }
524
HandleIdleTimeout(char * data)525 void HWEventsDRM::HandleIdleTimeout(char *data) {
526 char event_data[kMaxStringLength];
527 int32_t size;
528 struct drm_msm_event_resp *event_resp = NULL;
529
530 size = (int32_t)Sys::pread_(poll_fds_[idle_notify_index_].fd, event_data, kMaxStringLength, 0);
531 if (size < 0) {
532 return;
533 }
534
535 if (size > kMaxStringLength) {
536 DLOGE("event size %d is greater than event buffer size %zd\n", size, kMaxStringLength);
537 return;
538 }
539
540 if (size < (int32_t)sizeof(*event_resp)) {
541 DLOGE("size %d exp %zd\n", size, sizeof(*event_resp));
542 return;
543 }
544
545 int32_t i = 0;
546
547 while (i < size) {
548 event_resp = (struct drm_msm_event_resp *)&event_data[i];
549 switch (event_resp->base.type) {
550 case DRM_EVENT_IDLE_NOTIFY:
551 {
552 DLOGV("Received Idle time event");
553 event_handler_->IdleTimeout();
554 break;
555 }
556 default: {
557 DLOGE("invalid event %d", event_resp->base.type);
558 break;
559 }
560 }
561 i += event_resp->base.length;
562 }
563
564 return;
565 }
566
HandleCECMessage(char * data)567 void HWEventsDRM::HandleCECMessage(char *data) {
568 event_handler_->CECMessage(data);
569 }
570
HandleIdlePowerCollapse(char * data)571 void HWEventsDRM::HandleIdlePowerCollapse(char *data) {
572 char event_data[kMaxStringLength];
573 int32_t size;
574 struct drm_msm_event_resp *event_resp = NULL;
575
576 size = (int32_t)Sys::pread_(poll_fds_[idle_pc_index_].fd, event_data, kMaxStringLength, 0);
577 if (size < 0) {
578 return;
579 }
580
581 if (size > kMaxStringLength) {
582 DLOGE("event size %d is greater than event buffer size %zd\n", size, kMaxStringLength);
583 return;
584 }
585
586 if (size < (int32_t)sizeof(*event_resp)) {
587 DLOGE("size %d exp %zd\n", size, sizeof(*event_resp));
588 return;
589 }
590
591 int32_t i = 0;
592
593 while (i < size) {
594 event_resp = (struct drm_msm_event_resp *)&event_data[i];
595 switch (event_resp->base.type) {
596 case DRM_EVENT_SDE_POWER:
597 {
598 uint32_t* event_payload = reinterpret_cast<uint32_t *>(event_resp->data);
599 if (*event_payload == 0) {
600 DLOGV("Received Idle power collapse event");
601 event_handler_->IdlePowerCollapse();
602 }
603 break;
604 }
605 default: {
606 DLOGE("invalid event %d", event_resp->base.type);
607 break;
608 }
609 }
610 i += event_resp->base.length;
611 }
612
613 return;
614 }
615
616 } // namespace sdm
617