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 properties_.push_back(&dpms_property_);
164 properties_.push_back(&crtc_id_property_);
165 properties_.push_back(&edid_property_);
166 if (writeback()) {
167 properties_.push_back(&writeback_pixel_formats_);
168 properties_.push_back(&writeback_fb_id_);
169 properties_.push_back(&writeback_out_fence_);
170 }
171 properties_.push_back(&max_luminance_);
172 properties_.push_back(&max_avg_luminance_);
173 properties_.push_back(&min_luminance_);
174 properties_.push_back(&hdr_formats_);
175 properties_.push_back(&orientation_);
176 properties_.push_back(&lp_mode_property_);
177 properties_.push_back(&brightness_cap_);
178 properties_.push_back(&brightness_level_);
179 properties_.push_back(&hbm_mode_);
180 properties_.push_back(&dimming_on_);
181 properties_.push_back(&lhbm_on_);
182 properties_.push_back(&mipi_sync_);
183 properties_.push_back(&panel_idle_support_);
184 properties_.push_back(&vrr_switch_duration_);
185
186 return 0;
187 }
188
id() const189 uint32_t DrmConnector::id() const {
190 return id_;
191 }
192
display() const193 int DrmConnector::display() const {
194 return display_;
195 }
196
set_display(int display)197 void DrmConnector::set_display(int display) {
198 display_ = display;
199 }
200
internal() const201 bool DrmConnector::internal() const {
202 return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
203 type_ == DRM_MODE_CONNECTOR_DSI ||
204 type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI;
205 }
206
external() const207 bool DrmConnector::external() const {
208 return type_ == DRM_MODE_CONNECTOR_HDMIA ||
209 type_ == DRM_MODE_CONNECTOR_DisplayPort ||
210 type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
211 type_ == DRM_MODE_CONNECTOR_VGA;
212 }
213
writeback() const214 bool DrmConnector::writeback() const {
215 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
216 return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
217 #else
218 return false;
219 #endif
220 }
221
valid_type() const222 bool DrmConnector::valid_type() const {
223 return internal() || external() || writeback();
224 }
225
name() const226 std::string DrmConnector::name() const {
227 constexpr std::array<const char *, TYPES_COUNT> names =
228 {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite",
229 "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A",
230 "HDMI-B", "TV", "eDP", "Virtual", "DSI", "DPI"};
231
232 if (type_ < TYPES_COUNT) {
233 std::ostringstream name_buf;
234 name_buf << names[type_] << "-" << type_id_;
235 return name_buf.str();
236 } else {
237 ALOGE("Unknown type in connector %d, could not make his name", id_);
238 return "None";
239 }
240 }
241
UpdateModes()242 int DrmConnector::UpdateModes() {
243 int fd = drm_->fd();
244
245 drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
246 if (!c) {
247 ALOGE("Failed to get connector %d", id_);
248 return -ENODEV;
249 }
250
251 state_ = c->connection;
252
253 bool preferred_mode_found = false;
254 std::vector<DrmMode> new_modes;
255 for (int i = 0; i < c->count_modes; ++i) {
256 bool exists = false;
257 for (const DrmMode &mode : modes_) {
258 if (mode == c->modes[i]) {
259 new_modes.push_back(mode);
260 exists = true;
261 break;
262 }
263 }
264 if (!exists) {
265 DrmMode m(&c->modes[i]);
266 m.set_id(drm_->next_mode_id());
267 new_modes.push_back(m);
268 }
269 // Use only the first DRM_MODE_TYPE_PREFERRED mode found
270 if (!preferred_mode_found &&
271 (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) {
272 preferred_mode_id_ = new_modes.back().id();
273 preferred_mode_found = true;
274 }
275 }
276 modes_.swap(new_modes);
277 if (!preferred_mode_found && modes_.size() != 0) {
278 preferred_mode_id_ = modes_[0].id();
279 }
280 return 0;
281 }
282
active_mode() const283 const DrmMode &DrmConnector::active_mode() const {
284 return active_mode_;
285 }
286
set_active_mode(const DrmMode & mode)287 void DrmConnector::set_active_mode(const DrmMode &mode) {
288 active_mode_ = mode;
289 }
290
dpms_property() const291 const DrmProperty &DrmConnector::dpms_property() const {
292 return dpms_property_;
293 }
294
crtc_id_property() const295 const DrmProperty &DrmConnector::crtc_id_property() const {
296 return crtc_id_property_;
297 }
298
edid_property() const299 const DrmProperty &DrmConnector::edid_property() const {
300 return edid_property_;
301 }
302
writeback_pixel_formats() const303 const DrmProperty &DrmConnector::writeback_pixel_formats() const {
304 return writeback_pixel_formats_;
305 }
306
writeback_fb_id() const307 const DrmProperty &DrmConnector::writeback_fb_id() const {
308 return writeback_fb_id_;
309 }
310
writeback_out_fence() const311 const DrmProperty &DrmConnector::writeback_out_fence() const {
312 return writeback_out_fence_;
313 }
314
max_luminance() const315 const DrmProperty &DrmConnector::max_luminance() const {
316 return max_luminance_;
317 }
318
max_avg_luminance() const319 const DrmProperty &DrmConnector::max_avg_luminance() const {
320 return max_avg_luminance_;
321 }
322
min_luminance() const323 const DrmProperty &DrmConnector::min_luminance() const {
324 return min_luminance_;
325 }
326
brightness_cap() const327 const DrmProperty &DrmConnector::brightness_cap() const {
328 return brightness_cap_;
329 }
330
brightness_level() const331 const DrmProperty &DrmConnector::brightness_level() const {
332 return brightness_level_;
333 }
334
hbm_mode() const335 const DrmProperty &DrmConnector::hbm_mode() const {
336 return hbm_mode_;
337 }
338
dimming_on() const339 const DrmProperty &DrmConnector::dimming_on() const {
340 return dimming_on_;
341 }
342
lhbm_on() const343 const DrmProperty &DrmConnector::lhbm_on() const {
344 return lhbm_on_;
345 }
346
mipi_sync() const347 const DrmProperty &DrmConnector::mipi_sync() const {
348 return mipi_sync_;
349 }
350
hdr_formats() const351 const DrmProperty &DrmConnector::hdr_formats() const {
352 return hdr_formats_;
353 }
354
orientation() const355 const DrmProperty &DrmConnector::orientation() const {
356 return orientation_;
357 }
358
lp_mode() const359 const DrmMode &DrmConnector::lp_mode() const {
360 return lp_mode_;
361 }
362
UpdateLpMode()363 int DrmConnector::UpdateLpMode() {
364 auto [ret, blobId] = lp_mode_property_.value();
365 if (ret) {
366 ALOGE("Fail to get blob id for lp mode");
367 return ret;
368 }
369 drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(drm_->fd(), blobId);
370 if (!blob) {
371 ALOGE("Fail to get blob for lp mode(%" PRId64 ")", blobId);
372 return -ENOENT;
373 }
374
375 auto modeInfoPtr = static_cast<drmModeModeInfoPtr>(blob->data);
376 lp_mode_ = DrmMode(modeInfoPtr);
377 drmModeFreePropertyBlob(blob);
378
379 ALOGD("Updating LP mode to: %s", lp_mode_.name().c_str());
380
381 return 0;
382 }
383
ResetLpMode()384 int DrmConnector::ResetLpMode() {
385 int ret = drm_->UpdateConnectorProperty(*this, &lp_mode_property_);
386
387 if (ret) {
388 return ret;
389 }
390
391 UpdateLpMode();
392
393 return 0;
394 }
395
panel_idle_support() const396 const DrmProperty &DrmConnector::panel_idle_support() const {
397 return panel_idle_support_;
398 }
399
vrr_switch_duration() const400 const DrmProperty &DrmConnector::vrr_switch_duration() const {
401 return vrr_switch_duration_;
402 }
403
encoder() const404 DrmEncoder *DrmConnector::encoder() const {
405 return encoder_;
406 }
407
set_encoder(DrmEncoder * encoder)408 void DrmConnector::set_encoder(DrmEncoder *encoder) {
409 encoder_ = encoder;
410 }
411
state() const412 drmModeConnection DrmConnector::state() const {
413 return state_;
414 }
415
mm_width() const416 uint32_t DrmConnector::mm_width() const {
417 return mm_width_;
418 }
419
mm_height() const420 uint32_t DrmConnector::mm_height() const {
421 return mm_height_;
422 }
423 } // namespace android
424