• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "hwc-drm-connector"
18 
19 #include "drmconnector.h"
20 
21 #include <cutils/properties.h>
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <log/log.h>
25 #include <stdint.h>
26 #include <xf86drmMode.h>
27 
28 #include <array>
29 #include <sstream>
30 
31 #include "drmdevice.h"
32 
33 #ifndef DRM_MODE_CONNECTOR_WRITEBACK
34 #define DRM_MODE_CONNECTOR_WRITEBACK 18
35 #endif
36 
37 namespace android {
38 
39 constexpr size_t TYPES_COUNT = 18;
40 
DrmConnector(DrmDevice * drm,drmModeConnectorPtr c,DrmEncoder * current_encoder,std::vector<DrmEncoder * > & possible_encoders)41 DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
42                            DrmEncoder *current_encoder,
43                            std::vector<DrmEncoder *> &possible_encoders)
44     : drm_(drm),
45       id_(c->connector_id),
46       encoder_(current_encoder),
47       display_(-1),
48       type_(c->connector_type),
49       type_id_(c->connector_type_id),
50       state_(c->connection),
51       mm_width_(c->mmWidth),
52       mm_height_(c->mmHeight),
53       possible_encoders_(possible_encoders) {
54 }
55 
Init()56 int DrmConnector::Init() {
57   int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_);
58   if (ret) {
59     ALOGE("Could not get DPMS property\n");
60     return ret;
61   }
62   ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_);
63   if (ret) {
64     ALOGE("Could not get CRTC_ID property\n");
65     return ret;
66   }
67   ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
68   if (ret) {
69     ALOGW("Could not get EDID property\n");
70   }
71   if (writeback()) {
72     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
73                                      &writeback_pixel_formats_);
74     if (ret) {
75       ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
76       return ret;
77     }
78     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
79                                      &writeback_fb_id_);
80     if (ret) {
81       ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
82       return ret;
83     }
84     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
85                                      &writeback_out_fence_);
86     if (ret) {
87       ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
88       return ret;
89     }
90   }
91 
92   ret = drm_->GetConnectorProperty(*this, "max_luminance", &max_luminance_);
93   if (ret) {
94     ALOGE("Could not get max_luminance property\n");
95   }
96 
97   ret = drm_->GetConnectorProperty(*this, "max_avg_luminance", &max_avg_luminance_);
98   if (ret) {
99     ALOGE("Could not get max_avg_luminance property\n");
100   }
101 
102   ret = drm_->GetConnectorProperty(*this, "min_luminance", &min_luminance_);
103   if (ret) {
104     ALOGE("Could not get min_luminance property\n");
105   }
106 
107   ret = drm_->GetConnectorProperty(*this, "hdr_formats", &hdr_formats_);
108   if (ret) {
109     ALOGE("Could not get hdr_formats property\n");
110   }
111 
112   ret = drm_->GetConnectorProperty(*this, "panel orientation", &orientation_);
113   if (ret) {
114     ALOGE("Could not get orientation property\n");
115   }
116 
117   ret = drm_->GetConnectorProperty(*this, "lp_mode", &lp_mode_property_);
118   if (!ret) {
119       UpdateLpMode();
120   } else {
121       ALOGE("Could not get lp_mode property\n");
122   }
123 
124   ret = drm_->GetConnectorProperty(*this, "brightness_capability", &brightness_cap_);
125   if (ret) {
126       ALOGE("Could not get brightness_capability property\n");
127   }
128 
129   ret = drm_->GetConnectorProperty(*this, "brightness_level", &brightness_level_);
130   if (ret) {
131       ALOGE("Could not get brightness_level property\n");
132   }
133 
134   ret = drm_->GetConnectorProperty(*this, "hbm_mode", &hbm_mode_);
135   if (ret) {
136       ALOGE("Could not get hbm_mode property\n");
137   }
138 
139   ret = drm_->GetConnectorProperty(*this, "dimming_on", &dimming_on_);
140   if (ret) {
141       ALOGE("Could not get dimming_on property\n");
142   }
143 
144   ret = drm_->GetConnectorProperty(*this, "local_hbm_mode", &lhbm_on_);
145   if (ret) {
146       ALOGE("Could not get local_hbm_mode property\n");
147   }
148 
149   ret = drm_->GetConnectorProperty(*this, "mipi_sync", &mipi_sync_);
150   if (ret) {
151       ALOGE("Could not get mipi_sync property\n");
152   }
153 
154   ret = drm_->GetConnectorProperty(*this, "panel_idle_support", &panel_idle_support_);
155   if (ret) {
156       ALOGE("Could not get panel_idle_support property\n");
157   }
158 
159   ret = drm_->GetConnectorProperty(*this, "rr_switch_duration", &rr_switch_duration_);
160   if (ret) {
161       ALOGE("Could not get rr_switch_duration property\n");
162   }
163 
164   ret = drm_->GetConnectorProperty(*this, "operation_rate", &operation_rate_);
165   if (ret) {
166     ALOGE("Could not get operation_rate property\n");
167   }
168 
169   ret = drm_->GetConnectorProperty(*this, "refresh_on_lp", &refresh_on_lp_);
170   if (ret) {
171     ALOGE("Could not get refresh_on_lp property\n");
172   }
173 
174   ret = drm_->GetConnectorProperty(*this, "Content Protection", &content_protection_);
175   if (ret) {
176     ALOGE("Could not get Content Protection property\n");
177   }
178 
179   properties_.push_back(&dpms_property_);
180   properties_.push_back(&crtc_id_property_);
181   properties_.push_back(&edid_property_);
182   if (writeback()) {
183       properties_.push_back(&writeback_pixel_formats_);
184       properties_.push_back(&writeback_fb_id_);
185       properties_.push_back(&writeback_out_fence_);
186   }
187   properties_.push_back(&max_luminance_);
188   properties_.push_back(&max_avg_luminance_);
189   properties_.push_back(&min_luminance_);
190   properties_.push_back(&hdr_formats_);
191   properties_.push_back(&orientation_);
192   properties_.push_back(&lp_mode_property_);
193   properties_.push_back(&brightness_cap_);
194   properties_.push_back(&brightness_level_);
195   properties_.push_back(&hbm_mode_);
196   properties_.push_back(&dimming_on_);
197   properties_.push_back(&lhbm_on_);
198   properties_.push_back(&mipi_sync_);
199   properties_.push_back(&panel_idle_support_);
200   properties_.push_back(&rr_switch_duration_);
201   properties_.push_back(&operation_rate_);
202   properties_.push_back(&refresh_on_lp_);
203   properties_.push_back(&content_protection_);
204 
205   return 0;
206 }
207 
id() const208 uint32_t DrmConnector::id() const {
209   return id_;
210 }
211 
display() const212 int DrmConnector::display() const {
213   return display_;
214 }
215 
set_display(int display)216 void DrmConnector::set_display(int display) {
217   display_ = display;
218 }
219 
internal() const220 bool DrmConnector::internal() const {
221   return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
222          type_ == DRM_MODE_CONNECTOR_DSI ||
223          type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI;
224 }
225 
external() const226 bool DrmConnector::external() const {
227   return type_ == DRM_MODE_CONNECTOR_HDMIA ||
228          type_ == DRM_MODE_CONNECTOR_DisplayPort ||
229          type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
230          type_ == DRM_MODE_CONNECTOR_VGA;
231 }
232 
writeback() const233 bool DrmConnector::writeback() const {
234 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
235   return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
236 #else
237   return false;
238 #endif
239 }
240 
valid_type() const241 bool DrmConnector::valid_type() const {
242   return internal() || external() || writeback();
243 }
244 
name() const245 std::string DrmConnector::name() const {
246   constexpr std::array<const char *, TYPES_COUNT> names =
247       {"None",   "VGA",  "DVI-I",     "DVI-D",   "DVI-A", "Composite",
248        "SVIDEO", "LVDS", "Component", "DIN",     "DP",    "HDMI-A",
249        "HDMI-B", "TV",   "eDP",       "Virtual", "DSI",   "DPI"};
250 
251   if (type_ < TYPES_COUNT) {
252     std::ostringstream name_buf;
253     name_buf << names[type_] << "-" << type_id_;
254     return name_buf.str();
255   } else {
256     ALOGE("Unknown type in connector %d, could not make his name", id_);
257     return "None";
258   }
259 }
260 
UpdateModes(bool is_vrr_mode)261 int DrmConnector::UpdateModes(bool is_vrr_mode) {
262   std::lock_guard<std::recursive_mutex> lock(modes_lock_);
263 
264   int fd = drm_->fd();
265 
266   drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
267   if (!c) {
268     ALOGE("Failed to get connector %d", id_);
269     return -ENODEV;
270   }
271 
272   if (state_ == DRM_MODE_CONNECTED &&
273       c->connection == DRM_MODE_CONNECTED && modes_.size() > 0) {
274     // no need to update modes
275     return 0;
276   }
277 
278   if (state_ == DRM_MODE_DISCONNECTED &&
279       c->connection == DRM_MODE_DISCONNECTED && modes_.size() == 0) {
280     // no need to update modes
281     return 0;
282   }
283 
284   state_ = c->connection;
285 
286   // Update mm_width_ and mm_height_ for xdpi/ydpi calculations
287   mm_width_ = c->mmWidth;
288   mm_height_ = c->mmHeight;
289 
290   bool preferred_mode_found = false;
291   std::vector<DrmMode> new_modes;
292   for (int i = 0; i < c->count_modes; ++i) {
293     bool exists = false;
294     for (const DrmMode &mode : modes_) {
295       if (mode == c->modes[i]) {
296         new_modes.push_back(mode);
297         exists = true;
298         break;
299       }
300     }
301     if (!exists) {
302       // Remove modes that mismatch with the VRR setting..
303       if (is_vrr_mode != ((c->modes[i].type & DRM_MODE_TYPE_VRR) != 0)) {
304         continue;
305       }
306       DrmMode m(&c->modes[i]);
307       m.set_id(drm_->next_mode_id());
308       new_modes.push_back(m);
309     }
310     // Use only the first DRM_MODE_TYPE_PREFERRED mode found
311     if (!preferred_mode_found &&
312         (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) {
313       preferred_mode_id_ = new_modes.back().id();
314       preferred_mode_found = true;
315     }
316   }
317   modes_.swap(new_modes);
318   if (!preferred_mode_found && modes_.size() != 0) {
319     preferred_mode_id_ = modes_[0].id();
320   }
321   return 1;
322 }
323 
UpdateEdidProperty()324 int DrmConnector::UpdateEdidProperty() {
325   return drm_->UpdateConnectorProperty(*this, &edid_property_);
326 }
327 
UpdateLuminanceAndHdrProperties()328 int DrmConnector::UpdateLuminanceAndHdrProperties() {
329   int res = 0;
330 
331   res = drm_->UpdateConnectorProperty(*this, &max_luminance_);
332   if (res)
333     return res;
334   res = drm_->UpdateConnectorProperty(*this, &max_avg_luminance_);
335   if (res)
336     return res;
337   res = drm_->UpdateConnectorProperty(*this, &min_luminance_);
338   if (res)
339     return res;
340   res = drm_->UpdateConnectorProperty(*this, &hdr_formats_);
341   if (res)
342     return res;
343   return 0;
344 }
345 
active_mode() const346 const DrmMode &DrmConnector::active_mode() const {
347   return active_mode_;
348 }
349 
set_active_mode(const DrmMode & mode)350 void DrmConnector::set_active_mode(const DrmMode &mode) {
351   active_mode_ = mode;
352 }
353 
dpms_property() const354 const DrmProperty &DrmConnector::dpms_property() const {
355   return dpms_property_;
356 }
357 
crtc_id_property() const358 const DrmProperty &DrmConnector::crtc_id_property() const {
359   return crtc_id_property_;
360 }
361 
edid_property() const362 const DrmProperty &DrmConnector::edid_property() const {
363   return edid_property_;
364 }
365 
writeback_pixel_formats() const366 const DrmProperty &DrmConnector::writeback_pixel_formats() const {
367   return writeback_pixel_formats_;
368 }
369 
writeback_fb_id() const370 const DrmProperty &DrmConnector::writeback_fb_id() const {
371   return writeback_fb_id_;
372 }
373 
writeback_out_fence() const374 const DrmProperty &DrmConnector::writeback_out_fence() const {
375   return writeback_out_fence_;
376 }
377 
max_luminance() const378 const DrmProperty &DrmConnector::max_luminance() const {
379   return max_luminance_;
380 }
381 
max_avg_luminance() const382 const DrmProperty &DrmConnector::max_avg_luminance() const {
383   return max_avg_luminance_;
384 }
385 
min_luminance() const386 const DrmProperty &DrmConnector::min_luminance() const {
387   return min_luminance_;
388 }
389 
brightness_cap() const390 const DrmProperty &DrmConnector::brightness_cap() const {
391     return brightness_cap_;
392 }
393 
brightness_level() const394 const DrmProperty &DrmConnector::brightness_level() const {
395     return brightness_level_;
396 }
397 
hbm_mode() const398 const DrmProperty &DrmConnector::hbm_mode() const {
399     return hbm_mode_;
400 }
401 
dimming_on() const402 const DrmProperty &DrmConnector::dimming_on() const {
403     return dimming_on_;
404 }
405 
lhbm_on() const406 const DrmProperty &DrmConnector::lhbm_on() const {
407     return lhbm_on_;
408 }
409 
mipi_sync() const410 const DrmProperty &DrmConnector::mipi_sync() const {
411     return mipi_sync_;
412 }
413 
hdr_formats() const414 const DrmProperty &DrmConnector::hdr_formats() const {
415   return hdr_formats_;
416 }
417 
orientation() const418 const DrmProperty &DrmConnector::orientation() const {
419   return orientation_;
420 }
421 
lp_mode() const422 const DrmMode &DrmConnector::lp_mode() const {
423     return lp_mode_;
424 }
425 
operation_rate() const426 const DrmProperty &DrmConnector::operation_rate() const {
427     return operation_rate_;
428 }
429 
refresh_on_lp() const430 const DrmProperty &DrmConnector::refresh_on_lp() const {
431     return refresh_on_lp_;
432 }
433 
UpdateLpMode()434 int DrmConnector::UpdateLpMode() {
435     auto [ret, blobId] = lp_mode_property_.value();
436     if (ret) {
437         ALOGE("Fail to get blob id for lp mode");
438         return ret;
439     }
440     drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(drm_->fd(), blobId);
441     if (!blob) {
442         ALOGE("Fail to get blob for lp mode(%" PRId64 ")", blobId);
443         return -ENOENT;
444     }
445 
446     auto modeInfoPtr = static_cast<drmModeModeInfoPtr>(blob->data);
447     lp_mode_ = DrmMode(modeInfoPtr);
448     drmModeFreePropertyBlob(blob);
449 
450     ALOGD("Updating LP mode to: %s", lp_mode_.name().c_str());
451 
452     return 0;
453 }
454 
ResetLpMode()455 int DrmConnector::ResetLpMode() {
456     int ret = drm_->UpdateConnectorProperty(*this, &lp_mode_property_);
457 
458     if (ret) {
459         return ret;
460     }
461 
462     UpdateLpMode();
463 
464     return 0;
465 }
466 
panel_idle_support() const467 const DrmProperty &DrmConnector::panel_idle_support() const {
468     return panel_idle_support_;
469 }
470 
rr_switch_duration() const471 const DrmProperty &DrmConnector::rr_switch_duration() const {
472     return rr_switch_duration_;
473 }
474 
content_protection() const475 const DrmProperty &DrmConnector::content_protection() const {
476     return content_protection_;
477 }
478 
encoder() const479 DrmEncoder *DrmConnector::encoder() const {
480   return encoder_;
481 }
482 
set_encoder(DrmEncoder * encoder)483 void DrmConnector::set_encoder(DrmEncoder *encoder) {
484   encoder_ = encoder;
485 }
486 
state() const487 drmModeConnection DrmConnector::state() const {
488   return state_;
489 }
490 
mm_width() const491 uint32_t DrmConnector::mm_width() const {
492   return mm_width_;
493 }
494 
mm_height() const495 uint32_t DrmConnector::mm_height() const {
496   return mm_height_;
497 }
498 }  // namespace android
499