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