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 <stdint.h>
24 
25 #include <array>
26 #include <sstream>
27 
28 #include <log/log.h>
29 #include <xf86drmMode.h>
30 
31 #ifndef DRM_MODE_CONNECTOR_WRITEBACK
32 #define DRM_MODE_CONNECTOR_WRITEBACK 18
33 #endif
34 
35 namespace android {
36 
37 constexpr size_t TYPES_COUNT = 18;
38 
DrmConnector(DrmDevice * drm,drmModeConnectorPtr c,DrmEncoder * current_encoder,std::vector<DrmEncoder * > & possible_encoders)39 DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
40                            DrmEncoder *current_encoder,
41                            std::vector<DrmEncoder *> &possible_encoders)
42     : drm_(drm),
43       id_(c->connector_id),
44       encoder_(current_encoder),
45       display_(-1),
46       type_(c->connector_type),
47       type_id_(c->connector_type_id),
48       state_(c->connection),
49       mm_width_(c->mmWidth),
50       mm_height_(c->mmHeight),
51       possible_encoders_(possible_encoders) {
52 }
53 
Init()54 int DrmConnector::Init() {
55   int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_);
56   if (ret) {
57     ALOGE("Could not get DPMS property\n");
58     return ret;
59   }
60   ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_);
61   if (ret) {
62     ALOGE("Could not get CRTC_ID property\n");
63     return ret;
64   }
65   ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
66   if (ret) {
67     ALOGW("Could not get EDID property\n");
68   }
69   if (writeback()) {
70     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
71                                      &writeback_pixel_formats_);
72     if (ret) {
73       ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
74       return ret;
75     }
76     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
77                                      &writeback_fb_id_);
78     if (ret) {
79       ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
80       return ret;
81     }
82     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
83                                      &writeback_out_fence_);
84     if (ret) {
85       ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
86       return ret;
87     }
88   }
89 
90   ret = drm_->GetConnectorProperty(*this, "max_luminance", &max_luminance_);
91   if (ret) {
92     ALOGE("Could not get max_luminance property\n");
93   }
94 
95   ret = drm_->GetConnectorProperty(*this, "max_avg_luminance", &max_avg_luminance_);
96   if (ret) {
97     ALOGE("Could not get max_avg_luminance property\n");
98   }
99 
100   ret = drm_->GetConnectorProperty(*this, "min_luminance", &min_luminance_);
101   if (ret) {
102     ALOGE("Could not get min_luminance property\n");
103   }
104 
105   ret = drm_->GetConnectorProperty(*this, "hdr_formats", &hdr_formats_);
106   if (ret) {
107     ALOGE("Could not get hdr_formats property\n");
108   }
109 
110   ret = drm_->GetConnectorProperty(*this, "lp_mode", &lp_mode_);
111   if (ret) {
112       ALOGE("Could not get lp_mode property\n");
113   }
114 
115   ret = drm_->GetConnectorProperty(*this, "brightness_capability", &brightness_cap_);
116   if (ret) {
117       ALOGE("Could not get brightness_capability property\n");
118   }
119 
120   ret = drm_->GetConnectorProperty(*this, "brightness_level", &brightness_level_);
121   if (ret) {
122       ALOGE("Could not get brightness_level property\n");
123   }
124 
125   ret = drm_->GetConnectorProperty(*this, "hbm_mode", &hbm_mode_);
126   if (ret) {
127       ALOGE("Could not get hbm_mode property\n");
128   }
129 
130   ret = drm_->GetConnectorProperty(*this, "dimming_on", &dimming_on_);
131   if (ret) {
132       ALOGE("Could not get dimming_on property\n");
133   }
134 
135   ret = drm_->GetConnectorProperty(*this, "local_hbm_mode", &lhbm_on_);
136   if (ret) {
137       ALOGE("Could not get local_hbm_mode property\n");
138   }
139 
140   ret = drm_->GetConnectorProperty(*this, "sync_rr_switch", &sync_rr_switch_);
141   if (ret) {
142       ALOGE("Could not get sync_rr_switch property\n");
143   }
144 
145   properties_.push_back(&dpms_property_);
146   properties_.push_back(&crtc_id_property_);
147   properties_.push_back(&edid_property_);
148   if (writeback()) {
149       properties_.push_back(&writeback_pixel_formats_);
150       properties_.push_back(&writeback_fb_id_);
151       properties_.push_back(&writeback_out_fence_);
152   }
153   properties_.push_back(&max_luminance_);
154   properties_.push_back(&max_avg_luminance_);
155   properties_.push_back(&min_luminance_);
156   properties_.push_back(&hdr_formats_);
157   properties_.push_back(&lp_mode_);
158   properties_.push_back(&brightness_cap_);
159   properties_.push_back(&brightness_level_);
160   properties_.push_back(&hbm_mode_);
161   properties_.push_back(&dimming_on_);
162   properties_.push_back(&lhbm_on_);
163   properties_.push_back(&sync_rr_switch_);
164 
165   return 0;
166 }
167 
id() const168 uint32_t DrmConnector::id() const {
169   return id_;
170 }
171 
display() const172 int DrmConnector::display() const {
173   return display_;
174 }
175 
set_display(int display)176 void DrmConnector::set_display(int display) {
177   display_ = display;
178 }
179 
internal() const180 bool DrmConnector::internal() const {
181   return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
182          type_ == DRM_MODE_CONNECTOR_DSI ||
183          type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI;
184 }
185 
external() const186 bool DrmConnector::external() const {
187   return type_ == DRM_MODE_CONNECTOR_HDMIA ||
188          type_ == DRM_MODE_CONNECTOR_DisplayPort ||
189          type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
190          type_ == DRM_MODE_CONNECTOR_VGA;
191 }
192 
writeback() const193 bool DrmConnector::writeback() const {
194 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
195   return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
196 #else
197   return false;
198 #endif
199 }
200 
valid_type() const201 bool DrmConnector::valid_type() const {
202   return internal() || external() || writeback();
203 }
204 
name() const205 std::string DrmConnector::name() const {
206   constexpr std::array<const char *, TYPES_COUNT> names =
207       {"None",   "VGA",  "DVI-I",     "DVI-D",   "DVI-A", "Composite",
208        "SVIDEO", "LVDS", "Component", "DIN",     "DP",    "HDMI-A",
209        "HDMI-B", "TV",   "eDP",       "Virtual", "DSI",   "DPI"};
210 
211   if (type_ < TYPES_COUNT) {
212     std::ostringstream name_buf;
213     name_buf << names[type_] << "-" << type_id_;
214     return name_buf.str();
215   } else {
216     ALOGE("Unknown type in connector %d, could not make his name", id_);
217     return "None";
218   }
219 }
220 
UpdateModes()221 int DrmConnector::UpdateModes() {
222   int fd = drm_->fd();
223 
224   drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
225   if (!c) {
226     ALOGE("Failed to get connector %d", id_);
227     return -ENODEV;
228   }
229 
230   state_ = c->connection;
231 
232   bool preferred_mode_found = false;
233   std::vector<DrmMode> new_modes;
234   for (int i = 0; i < c->count_modes; ++i) {
235     bool exists = false;
236     for (const DrmMode &mode : modes_) {
237       if (mode == c->modes[i]) {
238         new_modes.push_back(mode);
239         exists = true;
240         break;
241       }
242     }
243     if (!exists) {
244     DrmMode m(&c->modes[i]);
245     m.set_id(drm_->next_mode_id());
246     new_modes.push_back(m);
247   }
248     // Use only the first DRM_MODE_TYPE_PREFERRED mode found
249     if (!preferred_mode_found &&
250         (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) {
251       preferred_mode_id_ = new_modes.back().id();
252       preferred_mode_found = true;
253     }
254   }
255   modes_.swap(new_modes);
256   if (!preferred_mode_found && modes_.size() != 0) {
257     preferred_mode_id_ = modes_[0].id();
258   }
259   return 0;
260 }
261 
active_mode() const262 const DrmMode &DrmConnector::active_mode() const {
263   return active_mode_;
264 }
265 
set_active_mode(const DrmMode & mode)266 void DrmConnector::set_active_mode(const DrmMode &mode) {
267   active_mode_ = mode;
268 }
269 
dpms_property() const270 const DrmProperty &DrmConnector::dpms_property() const {
271   return dpms_property_;
272 }
273 
crtc_id_property() const274 const DrmProperty &DrmConnector::crtc_id_property() const {
275   return crtc_id_property_;
276 }
277 
edid_property() const278 const DrmProperty &DrmConnector::edid_property() const {
279   return edid_property_;
280 }
281 
writeback_pixel_formats() const282 const DrmProperty &DrmConnector::writeback_pixel_formats() const {
283   return writeback_pixel_formats_;
284 }
285 
writeback_fb_id() const286 const DrmProperty &DrmConnector::writeback_fb_id() const {
287   return writeback_fb_id_;
288 }
289 
writeback_out_fence() const290 const DrmProperty &DrmConnector::writeback_out_fence() const {
291   return writeback_out_fence_;
292 }
293 
max_luminance() const294 const DrmProperty &DrmConnector::max_luminance() const {
295   return max_luminance_;
296 }
297 
max_avg_luminance() const298 const DrmProperty &DrmConnector::max_avg_luminance() const {
299   return max_avg_luminance_;
300 }
301 
min_luminance() const302 const DrmProperty &DrmConnector::min_luminance() const {
303   return min_luminance_;
304 }
305 
brightness_cap() const306 const DrmProperty &DrmConnector::brightness_cap() const {
307     return brightness_cap_;
308 }
309 
brightness_level() const310 const DrmProperty &DrmConnector::brightness_level() const {
311     return brightness_level_;
312 }
313 
hbm_mode() const314 const DrmProperty &DrmConnector::hbm_mode() const {
315     return hbm_mode_;
316 }
317 
dimming_on() const318 const DrmProperty &DrmConnector::dimming_on() const {
319     return dimming_on_;
320 }
321 
lhbm_on() const322 const DrmProperty &DrmConnector::lhbm_on() const {
323     return lhbm_on_;
324 }
325 
sync_rr_switch() const326 const DrmProperty &DrmConnector::sync_rr_switch() const {
327     return sync_rr_switch_;
328 }
329 
hdr_formats() const330 const DrmProperty &DrmConnector::hdr_formats() const {
331   return hdr_formats_;
332 }
333 
lp_mode() const334 const DrmProperty &DrmConnector::lp_mode() const {
335     return lp_mode_;
336 }
337 
encoder() const338 DrmEncoder *DrmConnector::encoder() const {
339   return encoder_;
340 }
341 
set_encoder(DrmEncoder * encoder)342 void DrmConnector::set_encoder(DrmEncoder *encoder) {
343   encoder_ = encoder;
344 }
345 
state() const346 drmModeConnection DrmConnector::state() const {
347   return state_;
348 }
349 
mm_width() const350 uint32_t DrmConnector::mm_width() const {
351   return mm_width_;
352 }
353 
mm_height() const354 uint32_t DrmConnector::mm_height() const {
355   return mm_height_;
356 }
357 }  // namespace android
358