1 /*
2 * Copyright (c) 2019-2020, 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 <stdint.h>
31 #include <stdlib.h>
32 #include <drm.h>
33 #include <drm/sde_drm.h>
34 #include <drm/msm_drm.h>
35 #include <drm_logger.h>
36 #include <errno.h>
37 #include <string.h>
38
39 #include <algorithm>
40 #include <map>
41 #include <memory>
42 #include <sstream>
43 #include <string>
44 #include <utility>
45 #include <vector>
46 #include <mutex>
47
48 #include "drm_utils.h"
49 #include "drm_property.h"
50 #include "drm_connector.h"
51
52 namespace sde_drm {
53
54 using std::string;
55 using std::stringstream;
56 using std::pair;
57 using std::vector;
58 using std::unique_ptr;
59 using std::map;
60 using std::mutex;
61 using std::lock_guard;
62 using std::set;
63
64 static uint8_t ON = 0;
65 static uint8_t DOZE = 1;
66 static uint8_t DOZE_SUSPEND = 2;
67 static uint8_t OFF = 5;
68
69 // Connector FB Secure Modes
70 static uint8_t NON_SECURE = 0;
71 static uint8_t SECURE = 1;
72
73 static uint8_t QSYNC_MODE_NONE = 0;
74 static uint8_t QSYNC_MODE_CONTINUOUS = 1;
75 static uint8_t QSYNC_MODE_ONESHOT = 2;
76
77 static uint8_t FRAME_TRIGGER_DEFAULT = 0;
78 static uint8_t FRAME_TRIGGER_SERIALIZE = 1;
79 static uint8_t FRAME_TRIGGER_POSTED_START = 2;
80
81 static uint8_t DRM_MODE_COLORIMETRY_DEFAULT = 0;
82 static uint8_t DRM_MODE_COLORIMETRY_SMPTE_170M_YCC = 1;
83 static uint8_t DRM_MODE_COLORIMETRY_BT709_YCC = 2;
84 static uint8_t DRM_MODE_COLORIMETRY_XVYCC_601 = 3;
85 static uint8_t DRM_MODE_COLORIMETRY_XVYCC_709 = 4;
86 static uint8_t DRM_MODE_COLORIMETRY_SYCC_601 = 5;
87 static uint8_t DRM_MODE_COLORIMETRY_OPYCC_601 = 6;
88 static uint8_t DRM_MODE_COLORIMETRY_OPRGB = 7;
89 static uint8_t DRM_MODE_COLORIMETRY_BT2020_CYCC = 8;
90 static uint8_t DRM_MODE_COLORIMETRY_BT2020_RGB = 9;
91 static uint8_t DRM_MODE_COLORIMETRY_BT2020_YCC = 10;
92 static uint8_t DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 = 11;
93 static uint8_t DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER = 12;
94
PopulatePowerModes(drmModePropertyRes * prop)95 static void PopulatePowerModes(drmModePropertyRes *prop) {
96 for (auto i = 0; i < prop->count_enums; i++) {
97 string enum_name(prop->enums[i].name);
98 if (enum_name == "ON") {
99 ON = prop->enums[i].value;
100 } else if (enum_name == "LP1") {
101 DOZE = prop->enums[i].value;
102 } else if (enum_name == "LP2") {
103 DOZE_SUSPEND = prop->enums[i].value;
104 } else if (enum_name == "OFF") {
105 OFF = prop->enums[i].value;
106 }
107 }
108 }
109
PopulateSecureModes(drmModePropertyRes * prop)110 static void PopulateSecureModes(drmModePropertyRes *prop) {
111 for (auto i = 0; i < prop->count_enums; i++) {
112 string enum_name(prop->enums[i].name);
113 if (enum_name == "non_sec") {
114 NON_SECURE = prop->enums[i].value;
115 } else if (enum_name == "sec") {
116 SECURE = prop->enums[i].value;
117 }
118 }
119 }
120
PopulateSupportedColorspaces(drmModePropertyRes * prop)121 static void PopulateSupportedColorspaces(drmModePropertyRes *prop) {
122 for (auto i = 0; i < prop->count_enums; i++) {
123 string enum_name(prop->enums[i].name);
124 if (enum_name == "Default") {
125 DRM_MODE_COLORIMETRY_DEFAULT = prop->enums[i].value;
126 } else if (enum_name == "SMPTE_170M_YCC") {
127 DRM_MODE_COLORIMETRY_SMPTE_170M_YCC = prop->enums[i].value;
128 } else if (enum_name == "BT709_YCC") {
129 DRM_MODE_COLORIMETRY_BT709_YCC = prop->enums[i].value;
130 } else if (enum_name == "XVYCC_601") {
131 DRM_MODE_COLORIMETRY_XVYCC_601 = prop->enums[i].value;
132 } else if (enum_name == "XVYCC_709") {
133 DRM_MODE_COLORIMETRY_XVYCC_709 = prop->enums[i].value;
134 } else if (enum_name == "SYCC_601") {
135 DRM_MODE_COLORIMETRY_SYCC_601 = prop->enums[i].value;
136 } else if (enum_name == "opYCC_601") {
137 DRM_MODE_COLORIMETRY_OPYCC_601 = prop->enums[i].value;
138 } else if (enum_name == "opRGB") {
139 DRM_MODE_COLORIMETRY_OPRGB = prop->enums[i].value;
140 } else if (enum_name == "BT2020_CYCC") {
141 DRM_MODE_COLORIMETRY_BT2020_CYCC = prop->enums[i].value;
142 } else if (enum_name == "BT2020_RGB") {
143 DRM_MODE_COLORIMETRY_BT2020_RGB = prop->enums[i].value;
144 } else if (enum_name == "BT2020_YCC") {
145 DRM_MODE_COLORIMETRY_BT2020_YCC = prop->enums[i].value;
146 } else if (enum_name == "DCI_P3_RGB_D65") {
147 DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 = prop->enums[i].value;
148 } else if (enum_name == "DCI_P3_RGB_Theater") {
149 DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER = prop->enums[i].value;
150 }
151 }
152 }
153
GetTopologyEnum(const string & topology)154 static DRMTopology GetTopologyEnum(const string &topology) {
155 if (topology == "sde_singlepipe") return DRMTopology::SINGLE_LM;
156 if (topology == "sde_singlepipe_dsc") return DRMTopology::SINGLE_LM_DSC;
157 if (topology == "sde_dualpipe") return DRMTopology::DUAL_LM;
158 if (topology == "sde_dualpipe_dsc") return DRMTopology::DUAL_LM_DSC;
159 if (topology == "sde_dualpipemerge") return DRMTopology::DUAL_LM_MERGE;
160 if (topology == "sde_dualpipemerge_dsc") return DRMTopology::DUAL_LM_MERGE_DSC;
161 if (topology == "sde_dualpipe_dscmerge") return DRMTopology::DUAL_LM_DSCMERGE;
162 if (topology == "sde_quadpipemerge") return DRMTopology::QUAD_LM_MERGE;
163 if (topology == "sde_quadpipe_dscmerge") return DRMTopology::QUAD_LM_DSCMERGE;
164 if (topology == "sde_quadpipe_3dmerge_dsc") return DRMTopology::QUAD_LM_MERGE_DSC;
165 if (topology == "sde_ppsplit") return DRMTopology::PPSPLIT;
166 return DRMTopology::UNKNOWN;
167 }
168
PopulateQsyncModes(drmModePropertyRes * prop)169 static void PopulateQsyncModes(drmModePropertyRes *prop) {
170 for (auto i = 0; i < prop->count_enums; i++) {
171 string enum_name(prop->enums[i].name);
172 if (enum_name == "none") {
173 QSYNC_MODE_NONE = prop->enums[i].value;
174 } else if (enum_name == "continuous") {
175 QSYNC_MODE_CONTINUOUS = prop->enums[i].value;
176 } else if (enum_name == "one_shot") {
177 QSYNC_MODE_ONESHOT = prop->enums[i].value;
178 }
179 }
180 }
181
PopulateFrameTriggerModes(drmModePropertyRes * prop)182 static void PopulateFrameTriggerModes(drmModePropertyRes *prop) {
183 for (auto i = 0; i < prop->count_enums; i++) {
184 string enum_name(prop->enums[i].name);
185 if (enum_name == "default") {
186 FRAME_TRIGGER_DEFAULT = prop->enums[i].value;
187 } else if (enum_name == "serilize_frame_trigger") {
188 FRAME_TRIGGER_SERIALIZE = prop->enums[i].value;
189 } else if (enum_name == "posted_start") {
190 FRAME_TRIGGER_POSTED_START = prop->enums[i].value;
191 }
192 }
193 }
194
GetColorspace(DRMColorspace drm_colorspace)195 static int32_t GetColorspace(DRMColorspace drm_colorspace) {
196 uint32_t colorspace = 0;
197 switch (drm_colorspace) {
198 case (DRMColorspace::DEFAULT):
199 colorspace = DRM_MODE_COLORIMETRY_DEFAULT;
200 break;
201 case (DRMColorspace::SMPTE_170M_YCC):
202 colorspace = DRM_MODE_COLORIMETRY_SMPTE_170M_YCC;
203 break;
204 case (DRMColorspace::BT709_YCC):
205 colorspace = DRM_MODE_COLORIMETRY_BT709_YCC;
206 break;
207 case (DRMColorspace::XVYCC_601):
208 colorspace = DRM_MODE_COLORIMETRY_XVYCC_601;
209 break;
210 case (DRMColorspace::XVYCC_709):
211 colorspace = DRM_MODE_COLORIMETRY_XVYCC_709;
212 break;
213 case (DRMColorspace::SYCC_601):
214 colorspace = DRM_MODE_COLORIMETRY_SYCC_601;
215 break;
216 case (DRMColorspace::OPYCC_601):
217 colorspace = DRM_MODE_COLORIMETRY_OPYCC_601;
218 break;
219 case (DRMColorspace::OPRGB):
220 colorspace = DRM_MODE_COLORIMETRY_OPRGB;
221 break;
222 case (DRMColorspace::BT2020_CYCC):
223 colorspace = DRM_MODE_COLORIMETRY_BT2020_CYCC;
224 break;
225 case (DRMColorspace::BT2020_RGB):
226 colorspace = DRM_MODE_COLORIMETRY_BT2020_RGB;
227 break;
228 case (DRMColorspace::BT2020_YCC):
229 colorspace = DRM_MODE_COLORIMETRY_BT2020_YCC;
230 break;
231 case (DRMColorspace::DCI_P3_RGB_D65):
232 colorspace = DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65;
233 break;
234 case (DRMColorspace::DCI_P3_RGB_THEATER):
235 colorspace = DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER;
236 break;
237 default:
238 colorspace = -1;
239 break;
240 }
241 return colorspace;
242 }
243
244 #define __CLASS__ "DRMConnectorManager"
245
Init(drmModeRes * resource)246 void DRMConnectorManager::Init(drmModeRes *resource) {
247 lock_guard<mutex> lock(lock_);
248 for (int i = 0; i < resource->count_connectors; i++) {
249 unique_ptr<DRMConnector> conn(new DRMConnector(fd_));
250 drmModeConnector *libdrm_conn = drmModeGetConnector(fd_, resource->connectors[i]);
251 if (libdrm_conn) {
252 conn->InitAndParse(libdrm_conn);
253 connector_pool_[resource->connectors[i]] = std::move(conn);
254 } else {
255 DRM_LOGE("Critical error: drmModeGetConnector() failed for connector %u.",
256 resource->connectors[i]);
257 }
258 }
259 }
260
Update()261 void DRMConnectorManager::Update() {
262 lock_guard<mutex> lock(lock_);
263 drmModeRes *resource = drmModeGetResources(fd_);
264
265 if (NULL == resource) {
266 DRM_LOGE("drmModeGetResources() failed. Connector status not updated.");
267 return;
268 }
269
270 // Build a map of the updated list of connector ids.
271 std::map<uint32_t, uint32_t> drm_connectors;
272 for (int i = 0; i < resource->count_connectors; i++) {
273 drm_connectors[resource->connectors[i]] = resource->connectors[i];
274 }
275
276 // Delete connectors in connector pool.
277 for (auto conn = connector_pool_.cbegin(); conn != connector_pool_.cend();) {
278 auto drmconn = drm_connectors.find(conn->first);
279 if (drmconn == drm_connectors.end()) {
280 // A DRM Connector in our pool was deleted.
281 if (conn->second->GetStatus() == DRMStatus::FREE) {
282 DRM_LOGD("Removing connector id %u from pool.", conn->first);
283 conn = connector_pool_.erase(conn);
284 } else {
285 // Physically removed DRM Connectors (displays) first go to disconnected state. When its
286 // reserved resources are freed up, they are removed from the driver's connector list. Do
287 // not remove DRM Connectors that are DRMStatus::BUSY.
288 DRM_LOGW("In-use connector id %u removed by DRM.", conn->first);
289 conn++;
290 }
291 } else {
292 // Remove DRM Connector present in both lists to ensure that only new connector ids remain.
293 drm_connectors.erase(drmconn);
294 conn++;
295 }
296 }
297
298 // Add new connectors in connector pool.
299 for (auto &drmconn : drm_connectors) {
300 DRM_LOGD("Adding connector id %u to pool.", drmconn.first);
301 unique_ptr<DRMConnector> conn(new DRMConnector(fd_));
302 drmModeConnector *libdrm_conn = drmModeGetConnector(fd_, drmconn.first);
303 if (libdrm_conn) {
304 conn->InitAndParse(libdrm_conn);
305 conn->SetSkipConnectorReload(true);
306 connector_pool_[drmconn.first] = std::move(conn);
307 } else {
308 DRM_LOGE("Critical error: drmModeGetConnector() failed for connector %u.", drmconn.first);
309 }
310 }
311
312 drmModeFreeResources(resource);
313 }
314
DumpByID(uint32_t id)315 void DRMConnectorManager::DumpByID(uint32_t id) {
316 lock_guard<mutex> lock(lock_);
317 connector_pool_[id]->Dump();
318 }
319
DumpAll()320 void DRMConnectorManager::DumpAll() {
321 lock_guard<mutex> lock(lock_);
322 for (auto &conn : connector_pool_) {
323 conn.second->Dump();
324 }
325 }
326
Perform(DRMOps code,uint32_t obj_id,drmModeAtomicReq * req,va_list args)327 void DRMConnectorManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req,
328 va_list args) {
329 lock_guard<mutex> lock(lock_);
330 auto it = connector_pool_.find(obj_id);
331 if (it == connector_pool_.end()) {
332 DRM_LOGE("Invalid connector id %d", obj_id);
333 return;
334 }
335
336 it->second->Perform(code, req, args);
337 }
338
GetConnectorInfo(uint32_t conn_id,DRMConnectorInfo * info)339 int DRMConnectorManager::GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info) {
340 lock_guard<mutex> lock(lock_);
341 int ret = -ENODEV;
342 auto iter = connector_pool_.find(conn_id);
343
344 if (iter != connector_pool_.end()) {
345 ret = connector_pool_[conn_id]->GetInfo(info);
346 }
347
348 return ret;
349 }
350
GetConnectorList(std::vector<uint32_t> * conn_ids)351 void DRMConnectorManager::GetConnectorList(std::vector<uint32_t> *conn_ids) {
352 lock_guard<mutex> lock(lock_);
353 if (!conn_ids) {
354 DRM_LOGE("No output parameter provided.");
355 return;
356 }
357 conn_ids->clear();
358 for (auto &conn : connector_pool_) {
359 conn_ids->push_back(conn.first);
360 }
361 }
362
IsTVConnector(uint32_t type)363 static bool IsTVConnector(uint32_t type) {
364 return (type == DRM_MODE_CONNECTOR_TV || type == DRM_MODE_CONNECTOR_HDMIA ||
365 type == DRM_MODE_CONNECTOR_HDMIB || type == DRM_MODE_CONNECTOR_DisplayPort ||
366 type == DRM_MODE_CONNECTOR_VGA);
367 }
368
Reserve(DRMDisplayType disp_type,DRMDisplayToken * token)369 int DRMConnectorManager::Reserve(DRMDisplayType disp_type, DRMDisplayToken *token) {
370 lock_guard<mutex> lock(lock_);
371 int ret = -ENODEV;
372 token->conn_id = 0;
373
374 for (auto &conn : connector_pool_) {
375 if (conn.second->GetStatus() == DRMStatus::FREE) {
376 uint32_t conn_type;
377 conn.second->GetType(&conn_type);
378 if ((disp_type == DRMDisplayType::PERIPHERAL && conn_type == DRM_MODE_CONNECTOR_DSI) ||
379 (disp_type == DRMDisplayType::VIRTUAL && conn_type == DRM_MODE_CONNECTOR_VIRTUAL) ||
380 (disp_type == DRMDisplayType::TV && IsTVConnector(conn_type))) {
381 if (conn.second->IsConnected()) {
382 // Free-up previously reserved connector, if any.
383 if (token->conn_id) {
384 connector_pool_[token->conn_id]->Unlock();
385 }
386 conn.second->Lock();
387 token->conn_id = conn.first;
388 ret = 0;
389 break;
390 } else {
391 // Hold on to the first reserved connector.
392 if (token->conn_id) {
393 continue;
394 }
395 // Prefer a connector that is connected. Continue search.
396 conn.second->Lock();
397 token->conn_id = conn.first;
398 ret = 0;
399 }
400 }
401 }
402 }
403
404 return ret;
405 }
406
Reserve(uint32_t conn_id,DRMDisplayToken * token)407 int DRMConnectorManager::Reserve(uint32_t conn_id, DRMDisplayToken *token) {
408 lock_guard<mutex> lock(lock_);
409 int ret = -ENODEV;
410
411 auto iter = connector_pool_.find(conn_id);
412 if ((iter != connector_pool_.end()) && (iter->second->GetStatus() == DRMStatus::FREE)) {
413 iter->second->Lock();
414 token->conn_id = iter->first;
415 ret = 0;
416 }
417
418 return ret;
419 }
420
GetPossibleEncoders(uint32_t connector_id,set<uint32_t> * possible_encoders)421 int DRMConnectorManager::GetPossibleEncoders(uint32_t connector_id,
422 set<uint32_t> *possible_encoders) {
423 lock_guard<mutex> lock(lock_);
424 return connector_pool_[connector_id]->GetPossibleEncoders(possible_encoders);
425 }
426
427
Free(DRMDisplayToken * token)428 void DRMConnectorManager::Free(DRMDisplayToken *token) {
429 lock_guard<mutex> lock(lock_);
430 connector_pool_.at(token->conn_id)->Unlock();
431 token->conn_id = 0;
432 }
433
434 // ==============================================================================================//
435
436 #undef __CLASS__
437 #define __CLASS__ "DRMConnector"
438
~DRMConnector()439 DRMConnector::~DRMConnector() {
440 if (drm_connector_) {
441 drmModeFreeConnector(drm_connector_);
442 }
443 }
444
ParseProperties()445 void DRMConnector::ParseProperties() {
446 drmModeObjectProperties *props =
447 drmModeObjectGetProperties(fd_, drm_connector_->connector_id, DRM_MODE_OBJECT_CONNECTOR);
448 if (!props || !props->props || !props->prop_values) {
449 drmModeFreeObjectProperties(props);
450 return;
451 }
452
453 for (uint32_t j = 0; j < props->count_props; j++) {
454 drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
455 if (!info) {
456 continue;
457 }
458
459 string property_name(info->name);
460 DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
461
462 if (prop_enum == DRMProperty::INVALID) {
463 DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
464 drmModeFreeProperty(info);
465 continue;
466 }
467
468 if (prop_enum == DRMProperty::LP) {
469 PopulatePowerModes(info);
470 } else if (prop_enum == DRMProperty::FB_TRANSLATION_MODE) {
471 PopulateSecureModes(info);
472 } else if (prop_enum == DRMProperty::QSYNC_MODE) {
473 PopulateQsyncModes(info);
474 } else if (prop_enum == DRMProperty::FRAME_TRIGGER) {
475 PopulateFrameTriggerModes(info);
476 } else if (prop_enum == DRMProperty::COLORSPACE) {
477 PopulateSupportedColorspaces(info);
478 }
479
480 prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
481 drmModeFreeProperty(info);
482 }
483
484 drmModeFreeObjectProperties(props);
485 }
486
ParseCapabilities(uint64_t blob_id,DRMConnectorInfo * info)487 void DRMConnector::ParseCapabilities(uint64_t blob_id, DRMConnectorInfo *info) {
488 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
489 if (!blob) {
490 return;
491 }
492 char *fmt_str = new char[blob->length + 1];
493 memcpy (fmt_str, blob->data, blob->length);
494 fmt_str[blob->length] = '\0';
495 stringstream stream(fmt_str);
496 DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(),
497 blob->data, blob->length);
498 string line = {};
499 const string display_type = "display type=";
500 const string panel_name = "panel name=";
501 const string panel_mode = "panel mode=";
502 const string dfps_support = "dfps support=";
503 const string pixel_formats = "pixel_formats=";
504 const string max_linewidth = "maxlinewidth=";
505 const string panel_orientation = "panel orientation=";
506 const string qsync_support = "qsync support=";
507 const string wb_ubwc = "wb_ubwc";
508 const string dyn_bitclk_support = "dyn bitclk support=";
509
510 while (std::getline(stream, line)) {
511 if (line.find(pixel_formats) != string::npos) {
512 vector<pair<uint32_t, uint64_t>> formats_supported;
513 ParseFormats(line.erase(0, pixel_formats.length()), &formats_supported);
514 info->formats_supported = move(formats_supported);
515 } else if (line.find(max_linewidth) != string::npos) {
516 info->max_linewidth = std::stoi(string(line, max_linewidth.length()));
517 } else if (line.find(display_type) != string::npos) {
518 info->is_primary = (string(line, display_type.length()) == "primary");
519 } else if (line.find(panel_name) != string::npos) {
520 info->panel_name = string(line, panel_name.length());
521 } else if (line.find(panel_mode) != string::npos) {
522 info->panel_mode = (string(line, panel_mode.length()) == "video") ? DRMPanelMode::VIDEO
523 : DRMPanelMode::COMMAND;
524 } else if (line.find(dfps_support) != string::npos) {
525 info->dynamic_fps = (string(line, dfps_support.length()) == "true");
526 } else if (line.find(panel_orientation) != string::npos) {
527 if (string(line, panel_orientation.length()) == "horz flip") {
528 info->panel_orientation = DRMRotation::FLIP_H;
529 } else if (string(line, panel_orientation.length()) == "vert flip") {
530 info->panel_orientation = DRMRotation::FLIP_V;
531 } else if (string(line, panel_orientation.length()) == "horz & vert flip") {
532 info->panel_orientation = DRMRotation::ROT_180;
533 }
534 } else if (line.find(qsync_support) != string::npos) {
535 info->qsync_support = (string(line, qsync_support.length()) == "true");
536 } else if (line.find(wb_ubwc) != string::npos) {
537 info->is_wb_ubwc_supported = true;
538 } else if (line.find(dyn_bitclk_support) != string::npos) {
539 info->dyn_bitclk_support = (string(line, dyn_bitclk_support.length()) == "true");
540 }
541 }
542
543 drmModeFreePropertyBlob(blob);
544 }
545
ParseCapabilities(uint64_t blob_id,drm_panel_hdr_properties * hdr_info)546 void DRMConnector::ParseCapabilities(uint64_t blob_id, drm_panel_hdr_properties *hdr_info) {
547 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
548 if (!blob) {
549 return;
550 }
551
552 struct drm_panel_hdr_properties *hdr_data = (struct drm_panel_hdr_properties*)(blob->data);
553
554 if (hdr_data) {
555 hdr_info->hdr_enabled = hdr_data->hdr_enabled;
556 hdr_info->peak_brightness = hdr_data->peak_brightness;
557 hdr_info->blackness_level = hdr_data->blackness_level;
558 for (int i = 0; i < DISPLAY_PRIMARIES_MAX; i++) {
559 hdr_info->display_primaries[i] = hdr_data->display_primaries[i];
560 }
561 }
562 drmModeFreePropertyBlob(blob);
563 }
564
ParseModeProperties(uint64_t blob_id,DRMConnectorInfo * info)565 void DRMConnector::ParseModeProperties(uint64_t blob_id, DRMConnectorInfo *info) {
566 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
567 if (!blob) {
568 return;
569 }
570
571 if (!info->modes.size()) {
572 return;
573 }
574
575 char *fmt_str = new char[blob->length + 1];
576 memcpy (fmt_str, blob->data, blob->length);
577 fmt_str[blob->length] = '\0';
578 stringstream stream(fmt_str);
579 DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(),
580 blob->data, blob->length);
581
582 string line = {};
583 const string mode_name = "mode_name=";
584 const string topology = "topology=";
585 const string pu_num_roi = "partial_update_num_roi=";
586 const string pu_xstart = "partial_update_xstart=";
587 const string pu_ystart = "partial_update_ystart=";
588 const string pu_walign = "partial_update_walign=";
589 const string pu_halign = "partial_update_halign=";
590 const string pu_wmin = "partial_update_wmin=";
591 const string pu_hmin = "partial_update_hmin=";
592 const string pu_roimerge = "partial_update_roimerge=";
593 const string bit_clk_rate = "bit_clk_rate=";
594 const string mdp_transfer_time_us = "mdp_transfer_time_us=";
595
596 DRMModeInfo *mode_item = &info->modes.at(0);
597 unsigned int index = 0;
598
599 while (std::getline(stream, line)) {
600 if (line.find(mode_name) != string::npos) {
601 string name(line, mode_name.length());
602 if (index >= info->modes.size()) {
603 break;
604 }
605 // Move to the next mode_item
606 mode_item = &info->modes.at(index++);
607 } else if (line.find(topology) != string::npos) {
608 mode_item->topology = GetTopologyEnum(string(line, topology.length()));;
609 } else if (line.find(pu_num_roi) != string::npos) {
610 mode_item->num_roi = std::stoi(string(line, pu_num_roi.length()));
611 } else if (line.find(pu_xstart) != string::npos) {
612 mode_item->xstart = std::stoi(string(line, pu_xstart.length()));
613 } else if (line.find(pu_ystart) != string::npos) {
614 mode_item->ystart = std::stoi(string(line, pu_ystart.length()));
615 } else if (line.find(pu_walign) != string::npos) {
616 mode_item->walign = std::stoi(string(line, pu_walign.length()));
617 } else if (line.find(pu_halign) != string::npos) {
618 mode_item->halign = std::stoi(string(line, pu_halign.length()));
619 } else if (line.find(pu_wmin) != string::npos) {
620 mode_item->wmin = std::stoi(string(line, pu_wmin.length()));
621 } else if (line.find(pu_hmin) != string::npos) {
622 mode_item->hmin = std::stoi(string(line, pu_hmin.length()));
623 } else if (line.find(pu_roimerge) != string::npos) {
624 mode_item->roi_merge = std::stoi(string(line, pu_roimerge.length()));
625 } else if (line.find(bit_clk_rate) != string::npos) {
626 mode_item->bit_clk_rate = std::stoi(string(line, bit_clk_rate.length()));
627 } else if (line.find(mdp_transfer_time_us) != string::npos) {
628 mode_item->transfer_time_us = std::stoi(string(line, mdp_transfer_time_us.length()));
629 }
630 }
631
632 drmModeFreePropertyBlob(blob);
633 }
634
ParseCapabilities(uint64_t blob_id,drm_msm_ext_hdr_properties * hdr_info)635 void DRMConnector::ParseCapabilities(uint64_t blob_id, drm_msm_ext_hdr_properties *hdr_info) {
636 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
637 if (!blob) {
638 return;
639 }
640
641 struct drm_msm_ext_hdr_properties *hdr_cdata = (struct drm_msm_ext_hdr_properties*)(blob->data);
642
643 if (hdr_cdata) {
644 hdr_info->hdr_supported = hdr_cdata->hdr_supported;
645 hdr_info->hdr_plus_supported = hdr_cdata->hdr_plus_supported;
646 hdr_info->hdr_eotf = hdr_cdata->hdr_eotf;
647 hdr_info->hdr_metadata_type_one = hdr_cdata->hdr_metadata_type_one;
648 hdr_info->hdr_max_luminance = hdr_cdata->hdr_max_luminance;
649 hdr_info->hdr_avg_luminance = hdr_cdata->hdr_avg_luminance;
650 hdr_info->hdr_min_luminance = hdr_cdata->hdr_min_luminance;
651 DRM_LOGI("hdr_supported = %d, hdr_plus_supported = %d, hdr_eotf = %d, "
652 "hdr_metadata_type_one = %d, hdr_max_luminance = %d, hdr_avg_luminance = %d, "
653 "hdr_min_luminance = %d\n", hdr_info->hdr_supported,
654 hdr_info->hdr_plus_supported,
655 hdr_info->hdr_eotf, hdr_info->hdr_metadata_type_one, hdr_info->hdr_max_luminance,
656 hdr_info->hdr_avg_luminance, hdr_info->hdr_min_luminance);
657 }
658 drmModeFreePropertyBlob(blob);
659 }
660
ParseCapabilities(uint64_t blob_id,std::vector<uint8_t> * edid)661 void DRMConnector::ParseCapabilities(uint64_t blob_id, std::vector<uint8_t> *edid) {
662 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
663 if (!blob) {
664 return;
665 }
666
667 uint8_t *edid_blob = (uint8_t*)(blob->data);
668 uint32_t length = blob->length;
669 (*edid).assign(edid_blob, edid_blob + length);
670
671 drmModeFreePropertyBlob(blob);
672 }
673
GetInfo(DRMConnectorInfo * info)674 int DRMConnector::GetInfo(DRMConnectorInfo *info) {
675 uint32_t conn_id = drm_connector_->connector_id;
676 if (!skip_connector_reload_ && (IsTVConnector(drm_connector_->connector_type)
677 || (DRM_MODE_CONNECTOR_VIRTUAL == drm_connector_->connector_type))) {
678 // Reload since for some connectors like Virtual and DP, modes may change.
679 drmModeConnectorPtr drm_connector = drmModeGetConnector(fd_, conn_id);
680 if (!drm_connector) {
681 // Connector resource not found. This could happen if a connector is removed before a commit
682 // was done on it. Mark the connector as disconnected for graceful teardown. Update 'info'
683 // with basic information from previously initialized drm_connector_ for graceful teardown.
684 info->is_connected = false;
685 info->modes.clear();
686 info->type = drm_connector_->connector_type;
687 info->type_id = drm_connector_->connector_type_id;
688 DLOGW("Connector %u not found. Possibly removed.", conn_id);
689 return 0;
690 }
691 drmModeFreeConnector(drm_connector_);
692 drm_connector_ = drm_connector;
693 }
694
695 SetSkipConnectorReload(false); // Reset skip_connector_reload_ setting.
696 info->modes.clear();
697 if (!drm_connector_->count_modes) {
698 DRM_LOGW("Zero modes on connector %u.", conn_id);
699 }
700 for (auto i = 0; i < drm_connector_->count_modes; i++) {
701 DRMModeInfo modes_item {};
702 modes_item.mode = drm_connector_->modes[i];
703 info->modes.push_back(modes_item);
704 }
705 info->mmWidth = drm_connector_->mmWidth;
706 info->mmHeight = drm_connector_->mmHeight;
707 info->type = drm_connector_->connector_type;
708 info->type_id = drm_connector_->connector_type_id;
709 info->is_connected = IsConnected();
710
711 drmModeObjectProperties *props =
712 drmModeObjectGetProperties(fd_, drm_connector_->connector_id, DRM_MODE_OBJECT_CONNECTOR);
713 if (!props || !props->props || !props->prop_values) {
714 drmModeFreeObjectProperties(props);
715 return -ENODEV;
716 }
717
718 uint32_t index = UINT32_MAX;
719
720 if (prop_mgr_.IsPropertyAvailable(DRMProperty::HDR_PROPERTIES)) {
721 index = std::distance(props->props,
722 std::find(props->props, props->props + props->count_props,
723 prop_mgr_.GetPropertyId(DRMProperty::HDR_PROPERTIES)));
724 if (index < props->count_props)
725 ParseCapabilities(props->prop_values[index], &info->panel_hdr_prop);
726 }
727
728 if (prop_mgr_.IsPropertyAvailable(DRMProperty::CAPABILITIES)) {
729 index = std::distance(props->props,
730 std::find(props->props, props->props + props->count_props,
731 prop_mgr_.GetPropertyId(DRMProperty::CAPABILITIES)));
732 if (index < props->count_props)
733 ParseCapabilities(props->prop_values[index], info);
734 }
735
736 if (prop_mgr_.IsPropertyAvailable(DRMProperty::MODE_PROPERTIES)) {
737 index = std::distance(props->props,
738 std::find(props->props, props->props + props->count_props,
739 prop_mgr_.GetPropertyId(DRMProperty::MODE_PROPERTIES)));
740 if (index < props->count_props)
741 ParseModeProperties(props->prop_values[index], info);
742 }
743
744 if (prop_mgr_.IsPropertyAvailable(DRMProperty::EXT_HDR_PROPERTIES)) {
745 index = std::distance(props->props,
746 std::find(props->props, props->props + props->count_props,
747 prop_mgr_.GetPropertyId(DRMProperty::EXT_HDR_PROPERTIES)));
748 if (index < props->count_props)
749 ParseCapabilities(props->prop_values[index], &info->ext_hdr_prop);
750 }
751
752 if (prop_mgr_.IsPropertyAvailable(DRMProperty::TOPOLOGY_CONTROL)) {
753 index = std::distance(props->props,
754 std::find(props->props, props->props + props->count_props,
755 prop_mgr_.GetPropertyId(DRMProperty::TOPOLOGY_CONTROL)));
756 info->topology_control = props->prop_values[index];
757 }
758 if (prop_mgr_.IsPropertyAvailable(DRMProperty::EDID)) {
759 index = std::distance(props->props,
760 std::find(props->props, props->props + props->count_props,
761 prop_mgr_.GetPropertyId(DRMProperty::EDID)));
762 ParseCapabilities(props->prop_values[index], &info->edid);
763 }
764
765 if (prop_mgr_.IsPropertyAvailable(DRMProperty::SUPPORTED_COLORSPACES)) {
766 index = std::distance(props->props,
767 std::find(props->props, props->props + props->count_props,
768 prop_mgr_.GetPropertyId(DRMProperty::SUPPORTED_COLORSPACES)));
769 info->supported_colorspaces = props->prop_values[index];
770 }
771
772 drmModeFreeObjectProperties(props);
773
774 return 0;
775 }
776
InitAndParse(drmModeConnector * conn)777 void DRMConnector::InitAndParse(drmModeConnector *conn) {
778 drm_connector_ = conn;
779 ParseProperties();
780 pp_mgr_ = std::unique_ptr<DRMPPManager>(new DRMPPManager(fd_));
781 pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_CONNECTOR);
782 }
783
Perform(DRMOps code,drmModeAtomicReq * req,va_list args)784 void DRMConnector::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
785 uint32_t obj_id = drm_connector_->connector_id;
786
787 switch (code) {
788 case DRMOps::CONNECTOR_SET_CRTC: {
789 uint32_t crtc = va_arg(args, uint32_t);
790 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::CRTC_ID), crtc);
791 DRM_LOGD("Connector %d: Setting CRTC %d", obj_id, crtc);
792 } break;
793
794 case DRMOps::CONNECTOR_GET_RETIRE_FENCE: {
795 int64_t *fence = va_arg(args, int64_t *);
796 *fence = -1;
797 uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::RETIRE_FENCE);
798 drmModeAtomicAddProperty(req, obj_id, prop_id, reinterpret_cast<uint64_t>(fence));
799 } break;
800
801 case DRMOps::CONNECTOR_SET_OUTPUT_RECT: {
802 DRMRect rect = va_arg(args, DRMRect);
803 drmModeAtomicAddProperty(req, obj_id,
804 prop_mgr_.GetPropertyId(DRMProperty::DST_X), rect.left);
805 drmModeAtomicAddProperty(req, obj_id,
806 prop_mgr_.GetPropertyId(DRMProperty::DST_Y), rect.top);
807 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::DST_W),
808 rect.right - rect.left);
809 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::DST_H),
810 rect.bottom - rect.top);
811 DRM_LOGD("Connector %d: Setting dst [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
812 rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
813 } break;
814
815 case DRMOps::CONNECTOR_SET_OUTPUT_FB_ID: {
816 uint32_t fb_id = va_arg(args, uint32_t);
817 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::FB_ID), fb_id);
818 DRM_LOGD("Connector %d: Setting fb_id %d", obj_id, fb_id);
819 } break;
820
821 case DRMOps::CONNECTOR_SET_POWER_MODE: {
822 int drm_power_mode = va_arg(args, int);
823 uint32_t power_mode = ON;
824 switch (drm_power_mode) {
825 case (int)DRMPowerMode::ON:
826 power_mode = ON;
827 break;
828 case (int)DRMPowerMode::DOZE:
829 power_mode = DOZE;
830 break;
831 case (int)DRMPowerMode::DOZE_SUSPEND:
832 power_mode = DOZE_SUSPEND;
833 break;
834 case (int)DRMPowerMode::OFF:
835 power_mode = OFF;
836 break;
837 default:
838 DRM_LOGE("Invalid power mode %d to set on connector %d", drm_power_mode, obj_id);
839 break;
840 }
841 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::LP), power_mode);
842 DRM_LOGD("Connector %d: Setting power_mode %d", obj_id, power_mode);
843 } break;
844
845 case DRMOps::CONNECTOR_SET_ROI: {
846 uint32_t num_roi = va_arg(args, uint32_t);
847 DRMRect *conn_rois = va_arg(args, DRMRect*);
848 SetROI(req, obj_id, num_roi, conn_rois);
849 } break;
850
851 case DRMOps::CONNECTOR_SET_AUTOREFRESH: {
852 uint32_t enable = va_arg(args, uint32_t);
853 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::AUTOREFRESH),
854 enable);
855 DRM_LOGD("Connector %d: Setting autorefresh %d", obj_id, enable);
856 } break;
857
858 case DRMOps::CONNECTOR_SET_FB_SECURE_MODE: {
859 int secure_mode = va_arg(args, int);
860 uint32_t fb_secure_mode = (secure_mode == (int)DRMSecureMode::SECURE) ? SECURE : NON_SECURE;
861 drmModeAtomicAddProperty(req, obj_id,
862 prop_mgr_.GetPropertyId(DRMProperty::FB_TRANSLATION_MODE),
863 fb_secure_mode);
864 DRM_LOGD("Connector %d: Setting FB secure mode %d", obj_id, fb_secure_mode);
865 } break;
866
867 case DRMOps::CONNECTOR_SET_POST_PROC: {
868 DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
869 if (data)
870 pp_mgr_->SetPPFeature(req, obj_id, *data);
871 } break;
872
873 case DRMOps::CONNECTOR_SET_HDR_METADATA: {
874 drm_msm_ext_hdr_metadata *hdr_metadata = va_arg(args, drm_msm_ext_hdr_metadata *);
875 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::HDR_METADATA),
876 reinterpret_cast<uint64_t>(hdr_metadata));
877 } break;
878
879 case DRMOps::CONNECTOR_SET_QSYNC_MODE: {
880 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::QSYNC_MODE)) {
881 return;
882 }
883 int drm_qsync_mode = va_arg(args, int);
884 uint32_t qsync_mode = static_cast<uint32_t>(drm_qsync_mode);
885 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::QSYNC_MODE),
886 qsync_mode);
887 DRM_LOGD("Connector %d: Setting Qsync mode %d", obj_id, qsync_mode);
888 } break;
889
890 case DRMOps::CONNECTOR_SET_TOPOLOGY_CONTROL: {
891 uint32_t topology_control = va_arg(args, uint32_t);
892 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::TOPOLOGY_CONTROL),
893 topology_control);
894 } break;
895
896 case DRMOps::CONNECTOR_SET_FRAME_TRIGGER: {
897 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::FRAME_TRIGGER)) {
898 return;
899 }
900 int drm_frame_trigger_mode = va_arg(args, int);
901 DRMFrameTriggerMode mode = static_cast<DRMFrameTriggerMode>(drm_frame_trigger_mode);
902 int32_t frame_trigger_mode = -1;
903 switch (mode) {
904 case (DRMFrameTriggerMode::FRAME_DONE_WAIT_DEFAULT):
905 frame_trigger_mode = FRAME_TRIGGER_DEFAULT;
906 break;
907 case (DRMFrameTriggerMode::FRAME_DONE_WAIT_SERIALIZE):
908 frame_trigger_mode = FRAME_TRIGGER_SERIALIZE;
909 break;
910 case (DRMFrameTriggerMode::FRAME_DONE_WAIT_POSTED_START):
911 frame_trigger_mode = FRAME_TRIGGER_POSTED_START;
912 break;
913 default:
914 DRM_LOGE("Invalid frame trigger mode %d to set on connector %d",
915 drm_frame_trigger_mode, obj_id);
916 break;
917 }
918 if (frame_trigger_mode >= 0) {
919 uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::FRAME_TRIGGER);
920 int ret = drmModeAtomicAddProperty(req, obj_id, prop_id, frame_trigger_mode);
921 if (ret < 0) {
922 DRM_LOGE("AtomicAddProperty failed obj_id 0x%x, prop_id %d mode %d ret %d",
923 obj_id, prop_id, frame_trigger_mode, ret);
924 } else {
925 DRM_LOGD("Connector %d: Setting frame trigger mode %d", obj_id, frame_trigger_mode);
926 }
927 }
928 } break;
929
930 case DRMOps::CONNECTOR_SET_COLORSPACE: {
931 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::COLORSPACE)) {
932 return;
933 }
934 DRMColorspace drm_colorspace = static_cast<DRMColorspace>(va_arg(args, uint32_t));
935 int32_t colorspace = 0;
936 colorspace = GetColorspace(drm_colorspace);
937 if (colorspace >= 0) {
938 uint32_t prop_id = prop_mgr_.GetPropertyId(DRMProperty::COLORSPACE);
939 int ret = drmModeAtomicAddProperty(req, obj_id, prop_id, colorspace);
940 if (ret < 0) {
941 DRM_LOGE("AtomicAddProperty failed obj_id 0x%x, prop_id %d mode %d ret %d",
942 obj_id, prop_id, colorspace, ret);
943 } else {
944 DRM_LOGD("Connector %d: Setting colorspace %d", obj_id, colorspace);
945 }
946 } else {
947 DRM_LOGE("Invalid colorspace %d", colorspace);
948 }
949 } break;
950
951 default:
952 DRM_LOGE("Invalid opcode %d to set on connector %d", code, obj_id);
953 break;
954 }
955 }
956
SetROI(drmModeAtomicReq * req,uint32_t obj_id,uint32_t num_roi,DRMRect * conn_rois)957 void DRMConnector::SetROI(drmModeAtomicReq *req, uint32_t obj_id, uint32_t num_roi,
958 DRMRect *conn_rois) {
959 #ifdef SDE_MAX_ROI_V1
960 if (num_roi > SDE_MAX_ROI_V1 || !prop_mgr_.IsPropertyAvailable(DRMProperty::ROI_V1)) {
961 return;
962 }
963 if (!num_roi || !conn_rois) {
964 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::ROI_V1), 0);
965 DRM_LOGD("Connector ROI is set to NULL to indicate full frame update");
966 return;
967 }
968
969 static struct sde_drm_roi_v1 roi_v1 {};
970 memset(&roi_v1, 0, sizeof(roi_v1));
971 roi_v1.num_rects = num_roi;
972
973 for (uint32_t i = 0; i < num_roi; i++) {
974 roi_v1.roi[i].x1 = conn_rois[i].left;
975 roi_v1.roi[i].x2 = conn_rois[i].right;
976 roi_v1.roi[i].y1 = conn_rois[i].top;
977 roi_v1.roi[i].y2 = conn_rois[i].bottom;
978 DRM_LOGD("Conn %d, ROI[l,t,b,r][%d %d %d %d]", obj_id,
979 roi_v1.roi[i].x1,roi_v1.roi[i].y1,roi_v1.roi[i].x2,roi_v1.roi[i].y2);
980 }
981 drmModeAtomicAddProperty(req, obj_id, prop_mgr_.GetPropertyId(DRMProperty::ROI_V1),
982 reinterpret_cast<uint64_t>(&roi_v1));
983 #endif
984 }
985
GetPossibleEncoders(set<uint32_t> * possible_encoders)986 int DRMConnector::GetPossibleEncoders(set<uint32_t> *possible_encoders) {
987 if (!possible_encoders) {
988 return -EINVAL;
989 }
990
991 uint32_t count_enc = drm_connector_->count_encoders;
992 if (count_enc == 0) {
993 DRM_LOGW("No possible encoders for connector %u", drm_connector_->connector_id);
994 }
995
996 (*possible_encoders).clear();
997 for (uint32_t i = 0; i < count_enc; i++) {
998 (*possible_encoders).insert(drm_connector_->encoders[i]);
999 }
1000
1001 return 0;
1002 }
1003
Dump()1004 void DRMConnector::Dump() {
1005 DRM_LOGE("id: %d\tenc_id: %d\tconn: %d\ttype: %d\tPhy: %dx%d\n", drm_connector_->connector_id,
1006 drm_connector_->encoder_id, drm_connector_->connection, drm_connector_->connector_type,
1007 drm_connector_->mmWidth, drm_connector_->mmHeight);
1008 DRM_LOGE("Modes: \n");
1009 for (uint32_t i = 0; i < (uint32_t)drm_connector_->count_modes; i++) {
1010 DRM_LOGE(
1011 "Name: %s\tvref: %d\thdisp: %d\t hsync_s: %d\thsync_e:%d\thtotal: %d\t"
1012 "vdisp: %d\tvsync_s: %d\tvsync_e: %d\tvtotal: %d\n",
1013 drm_connector_->modes[i].name, drm_connector_->modes[i].vrefresh,
1014 drm_connector_->modes[i].hdisplay, drm_connector_->modes[i].hsync_start,
1015 drm_connector_->modes[i].hsync_end, drm_connector_->modes[i].htotal,
1016 drm_connector_->modes[i].vdisplay, drm_connector_->modes[i].vsync_start,
1017 drm_connector_->modes[i].vsync_end, drm_connector_->modes[i].vtotal);
1018 }
1019 }
1020
1021 } // namespace sde_drm
1022