• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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