• 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   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