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