• 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 #include "drmdevice.h"
21 
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <stdint.h>
25 
26 #include <array>
27 #include <sstream>
28 
29 #include <log/log.h>
30 #include <xf86drmMode.h>
31 
32 #ifndef DRM_MODE_CONNECTOR_WRITEBACK
33 #define DRM_MODE_CONNECTOR_WRITEBACK 18
34 #endif
35 
36 namespace android {
37 
38 constexpr size_t TYPES_COUNT = 18;
39 
DrmConnector(DrmDevice * drm,drmModeConnectorPtr c,DrmEncoder * current_encoder,std::vector<DrmEncoder * > & possible_encoders)40 DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
41                            DrmEncoder *current_encoder,
42                            std::vector<DrmEncoder *> &possible_encoders)
43     : drm_(drm),
44       id_(c->connector_id),
45       encoder_(current_encoder),
46       display_(-1),
47       type_(c->connector_type),
48       type_id_(c->connector_type_id),
49       state_(c->connection),
50       mm_width_(c->mmWidth),
51       mm_height_(c->mmHeight),
52       possible_encoders_(possible_encoders) {
53 }
54 
Init()55 int DrmConnector::Init() {
56   int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_);
57   if (ret) {
58     ALOGE("Could not get DPMS property\n");
59     return ret;
60   }
61   ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_);
62   if (ret) {
63     ALOGE("Could not get CRTC_ID property\n");
64     return ret;
65   }
66   ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
67   if (ret) {
68     ALOGW("Could not get EDID property\n");
69   }
70   if (writeback()) {
71     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
72                                      &writeback_pixel_formats_);
73     if (ret) {
74       ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
75       return ret;
76     }
77     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
78                                      &writeback_fb_id_);
79     if (ret) {
80       ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
81       return ret;
82     }
83     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
84                                      &writeback_out_fence_);
85     if (ret) {
86       ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
87       return ret;
88     }
89   }
90 
91   ret = drm_->GetConnectorProperty(*this, "max_luminance", &max_luminance_);
92   if (ret) {
93     ALOGE("Could not get max_luminance property\n");
94   }
95 
96   ret = drm_->GetConnectorProperty(*this, "max_avg_luminance", &max_avg_luminance_);
97   if (ret) {
98     ALOGE("Could not get max_avg_luminance property\n");
99   }
100 
101   ret = drm_->GetConnectorProperty(*this, "min_luminance", &min_luminance_);
102   if (ret) {
103     ALOGE("Could not get min_luminance property\n");
104   }
105 
106   ret = drm_->GetConnectorProperty(*this, "hdr_formats", &hdr_formats_);
107   if (ret) {
108     ALOGE("Could not get hdr_formats property\n");
109   }
110 
111   ret = drm_->GetConnectorProperty(*this, "panel orientation", &orientation_);
112   if (ret) {
113     ALOGE("Could not get orientation property\n");
114   }
115 
116   ret = drm_->GetConnectorProperty(*this, "lp_mode", &lp_mode_property_);
117   if (!ret) {
118       UpdateLpMode();
119   } else {
120       ALOGE("Could not get lp_mode property\n");
121   }
122 
123   ret = drm_->GetConnectorProperty(*this, "brightness_capability", &brightness_cap_);
124   if (ret) {
125       ALOGE("Could not get brightness_capability property\n");
126   }
127 
128   ret = drm_->GetConnectorProperty(*this, "brightness_level", &brightness_level_);
129   if (ret) {
130       ALOGE("Could not get brightness_level property\n");
131   }
132 
133   ret = drm_->GetConnectorProperty(*this, "hbm_mode", &hbm_mode_);
134   if (ret) {
135       ALOGE("Could not get hbm_mode property\n");
136   }
137 
138   ret = drm_->GetConnectorProperty(*this, "dimming_on", &dimming_on_);
139   if (ret) {
140       ALOGE("Could not get dimming_on property\n");
141   }
142 
143   ret = drm_->GetConnectorProperty(*this, "local_hbm_mode", &lhbm_on_);
144   if (ret) {
145       ALOGE("Could not get local_hbm_mode property\n");
146   }
147 
148   ret = drm_->GetConnectorProperty(*this, "mipi_sync", &mipi_sync_);
149   if (ret) {
150       ALOGE("Could not get mipi_sync property\n");
151   }
152 
153   ret = drm_->GetConnectorProperty(*this, "panel_idle_support", &panel_idle_support_);
154   if (ret) {
155       ALOGE("Could not get panel_idle_support property\n");
156   }
157 
158   ret = drm_->GetConnectorProperty(*this, "vrr_switch_duration", &vrr_switch_duration_);
159   if (ret) {
160     ALOGE("Could not get vrr_switch_duration property\n");
161   }
162 
163   ret = drm_->GetConnectorProperty(*this, "operation_rate", &operation_rate_);
164   if (ret) {
165     ALOGE("Could not get operation_rate property\n");
166   }
167 
168   ret = drm_->GetConnectorProperty(*this, "refresh_on_lp", &refresh_on_lp_);
169   if (ret) {
170     ALOGE("Could not get refresh_on_lp property\n");
171   }
172 
173   properties_.push_back(&dpms_property_);
174   properties_.push_back(&crtc_id_property_);
175   properties_.push_back(&edid_property_);
176   if (writeback()) {
177       properties_.push_back(&writeback_pixel_formats_);
178       properties_.push_back(&writeback_fb_id_);
179       properties_.push_back(&writeback_out_fence_);
180   }
181   properties_.push_back(&max_luminance_);
182   properties_.push_back(&max_avg_luminance_);
183   properties_.push_back(&min_luminance_);
184   properties_.push_back(&hdr_formats_);
185   properties_.push_back(&orientation_);
186   properties_.push_back(&lp_mode_property_);
187   properties_.push_back(&brightness_cap_);
188   properties_.push_back(&brightness_level_);
189   properties_.push_back(&hbm_mode_);
190   properties_.push_back(&dimming_on_);
191   properties_.push_back(&lhbm_on_);
192   properties_.push_back(&mipi_sync_);
193   properties_.push_back(&panel_idle_support_);
194   properties_.push_back(&vrr_switch_duration_);
195   properties_.push_back(&operation_rate_);
196   properties_.push_back(&refresh_on_lp_);
197 
198   return 0;
199 }
200 
id() const201 uint32_t DrmConnector::id() const {
202   return id_;
203 }
204 
display() const205 int DrmConnector::display() const {
206   return display_;
207 }
208 
set_display(int display)209 void DrmConnector::set_display(int display) {
210   display_ = display;
211 }
212 
internal() const213 bool DrmConnector::internal() const {
214   return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
215          type_ == DRM_MODE_CONNECTOR_DSI ||
216          type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI;
217 }
218 
external() const219 bool DrmConnector::external() const {
220   return type_ == DRM_MODE_CONNECTOR_HDMIA ||
221          type_ == DRM_MODE_CONNECTOR_DisplayPort ||
222          type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
223          type_ == DRM_MODE_CONNECTOR_VGA;
224 }
225 
writeback() const226 bool DrmConnector::writeback() const {
227 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
228   return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
229 #else
230   return false;
231 #endif
232 }
233 
valid_type() const234 bool DrmConnector::valid_type() const {
235   return internal() || external() || writeback();
236 }
237 
name() const238 std::string DrmConnector::name() const {
239   constexpr std::array<const char *, TYPES_COUNT> names =
240       {"None",   "VGA",  "DVI-I",     "DVI-D",   "DVI-A", "Composite",
241        "SVIDEO", "LVDS", "Component", "DIN",     "DP",    "HDMI-A",
242        "HDMI-B", "TV",   "eDP",       "Virtual", "DSI",   "DPI"};
243 
244   if (type_ < TYPES_COUNT) {
245     std::ostringstream name_buf;
246     name_buf << names[type_] << "-" << type_id_;
247     return name_buf.str();
248   } else {
249     ALOGE("Unknown type in connector %d, could not make his name", id_);
250     return "None";
251   }
252 }
253 
UpdateModes()254 int DrmConnector::UpdateModes() {
255   std::lock_guard<std::recursive_mutex> lock(modes_lock_);
256 
257   int fd = drm_->fd();
258 
259   drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
260   if (!c) {
261     ALOGE("Failed to get connector %d", id_);
262     return -ENODEV;
263   }
264 
265   if (state_ == DRM_MODE_CONNECTED &&
266       c->connection == DRM_MODE_CONNECTED && modes_.size() > 0) {
267     // no need to update modes
268     return 0;
269   }
270 
271   if (state_ == DRM_MODE_DISCONNECTED &&
272       c->connection == DRM_MODE_DISCONNECTED && modes_.size() == 0) {
273     // no need to update modes
274     return 0;
275   }
276 
277   state_ = c->connection;
278 
279   bool preferred_mode_found = false;
280   std::vector<DrmMode> new_modes;
281   for (int i = 0; i < c->count_modes; ++i) {
282     bool exists = false;
283     for (const DrmMode &mode : modes_) {
284       if (mode == c->modes[i]) {
285         new_modes.push_back(mode);
286         exists = true;
287         break;
288       }
289     }
290     if (!exists) {
291       DrmMode m(&c->modes[i]);
292       m.set_id(drm_->next_mode_id());
293       new_modes.push_back(m);
294     }
295     // Use only the first DRM_MODE_TYPE_PREFERRED mode found
296     if (!preferred_mode_found &&
297         (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) {
298       preferred_mode_id_ = new_modes.back().id();
299       preferred_mode_found = true;
300     }
301   }
302   modes_.swap(new_modes);
303   if (!preferred_mode_found && modes_.size() != 0) {
304     preferred_mode_id_ = modes_[0].id();
305   }
306   return 1;
307 }
308 
UpdateEdidProperty()309 int DrmConnector::UpdateEdidProperty() {
310   return drm_->UpdateConnectorProperty(*this, &edid_property_);
311 }
312 
active_mode() const313 const DrmMode &DrmConnector::active_mode() const {
314   return active_mode_;
315 }
316 
set_active_mode(const DrmMode & mode)317 void DrmConnector::set_active_mode(const DrmMode &mode) {
318   active_mode_ = mode;
319 }
320 
dpms_property() const321 const DrmProperty &DrmConnector::dpms_property() const {
322   return dpms_property_;
323 }
324 
crtc_id_property() const325 const DrmProperty &DrmConnector::crtc_id_property() const {
326   return crtc_id_property_;
327 }
328 
edid_property() const329 const DrmProperty &DrmConnector::edid_property() const {
330   return edid_property_;
331 }
332 
writeback_pixel_formats() const333 const DrmProperty &DrmConnector::writeback_pixel_formats() const {
334   return writeback_pixel_formats_;
335 }
336 
writeback_fb_id() const337 const DrmProperty &DrmConnector::writeback_fb_id() const {
338   return writeback_fb_id_;
339 }
340 
writeback_out_fence() const341 const DrmProperty &DrmConnector::writeback_out_fence() const {
342   return writeback_out_fence_;
343 }
344 
max_luminance() const345 const DrmProperty &DrmConnector::max_luminance() const {
346   return max_luminance_;
347 }
348 
max_avg_luminance() const349 const DrmProperty &DrmConnector::max_avg_luminance() const {
350   return max_avg_luminance_;
351 }
352 
min_luminance() const353 const DrmProperty &DrmConnector::min_luminance() const {
354   return min_luminance_;
355 }
356 
brightness_cap() const357 const DrmProperty &DrmConnector::brightness_cap() const {
358     return brightness_cap_;
359 }
360 
brightness_level() const361 const DrmProperty &DrmConnector::brightness_level() const {
362     return brightness_level_;
363 }
364 
hbm_mode() const365 const DrmProperty &DrmConnector::hbm_mode() const {
366     return hbm_mode_;
367 }
368 
dimming_on() const369 const DrmProperty &DrmConnector::dimming_on() const {
370     return dimming_on_;
371 }
372 
lhbm_on() const373 const DrmProperty &DrmConnector::lhbm_on() const {
374     return lhbm_on_;
375 }
376 
mipi_sync() const377 const DrmProperty &DrmConnector::mipi_sync() const {
378     return mipi_sync_;
379 }
380 
hdr_formats() const381 const DrmProperty &DrmConnector::hdr_formats() const {
382   return hdr_formats_;
383 }
384 
orientation() const385 const DrmProperty &DrmConnector::orientation() const {
386   return orientation_;
387 }
388 
lp_mode() const389 const DrmMode &DrmConnector::lp_mode() const {
390     return lp_mode_;
391 }
392 
operation_rate() const393 const DrmProperty &DrmConnector::operation_rate() const {
394     return operation_rate_;
395 }
396 
refresh_on_lp() const397 const DrmProperty &DrmConnector::refresh_on_lp() const {
398     return refresh_on_lp_;
399 }
400 
UpdateLpMode()401 int DrmConnector::UpdateLpMode() {
402     auto [ret, blobId] = lp_mode_property_.value();
403     if (ret) {
404         ALOGE("Fail to get blob id for lp mode");
405         return ret;
406     }
407     drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(drm_->fd(), blobId);
408     if (!blob) {
409         ALOGE("Fail to get blob for lp mode(%" PRId64 ")", blobId);
410         return -ENOENT;
411     }
412 
413     auto modeInfoPtr = static_cast<drmModeModeInfoPtr>(blob->data);
414     lp_mode_ = DrmMode(modeInfoPtr);
415     drmModeFreePropertyBlob(blob);
416 
417     ALOGD("Updating LP mode to: %s", lp_mode_.name().c_str());
418 
419     return 0;
420 }
421 
ResetLpMode()422 int DrmConnector::ResetLpMode() {
423     int ret = drm_->UpdateConnectorProperty(*this, &lp_mode_property_);
424 
425     if (ret) {
426         return ret;
427     }
428 
429     UpdateLpMode();
430 
431     return 0;
432 }
433 
panel_idle_support() const434 const DrmProperty &DrmConnector::panel_idle_support() const {
435     return panel_idle_support_;
436 }
437 
vrr_switch_duration() const438 const DrmProperty &DrmConnector::vrr_switch_duration() const {
439   return vrr_switch_duration_;
440 }
441 
encoder() const442 DrmEncoder *DrmConnector::encoder() const {
443   return encoder_;
444 }
445 
set_encoder(DrmEncoder * encoder)446 void DrmConnector::set_encoder(DrmEncoder *encoder) {
447   encoder_ = encoder;
448 }
449 
state() const450 drmModeConnection DrmConnector::state() const {
451   return state_;
452 }
453 
mm_width() const454 uint32_t DrmConnector::mm_width() const {
455   return mm_width_;
456 }
457 
mm_height() const458 uint32_t DrmConnector::mm_height() const {
459   return mm_height_;
460 }
461 }  // namespace android
462