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
21 #include <errno.h>
22 #include <log/log.h>
23 #include <stdint.h>
24 #include <xf86drmMode.h>
25
26 #include <array>
27 #include <sstream>
28
29 #include "DrmDevice.h"
30
31 namespace android {
32
33 constexpr size_t TYPES_COUNT = 17;
34
DrmConnector(DrmDevice * drm,drmModeConnectorPtr c,DrmEncoder * current_encoder,std::vector<DrmEncoder * > & possible_encoders)35 DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
36 DrmEncoder *current_encoder,
37 std::vector<DrmEncoder *> &possible_encoders)
38 : drm_(drm),
39 id_(c->connector_id),
40 encoder_(current_encoder),
41 display_(-1),
42 type_(c->connector_type),
43 type_id_(c->connector_type_id),
44 state_(c->connection),
45 mm_width_(c->mmWidth),
46 mm_height_(c->mmHeight),
47 possible_encoders_(possible_encoders) {
48 }
49
Init()50 int DrmConnector::Init() {
51 int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_);
52 if (ret) {
53 ALOGE("Could not get DPMS property\n");
54 return ret;
55 }
56 ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_);
57 if (ret) {
58 ALOGE("Could not get CRTC_ID property\n");
59 return ret;
60 }
61 ret = UpdateEdidProperty();
62 if (writeback()) {
63 ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
64 &writeback_pixel_formats_);
65 if (ret) {
66 ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
67 return ret;
68 }
69 ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
70 &writeback_fb_id_);
71 if (ret) {
72 ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
73 return ret;
74 }
75 ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
76 &writeback_out_fence_);
77 if (ret) {
78 ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
79 return ret;
80 }
81 }
82 return 0;
83 }
84
UpdateEdidProperty()85 int DrmConnector::UpdateEdidProperty() {
86 int ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
87 if (ret) {
88 ALOGW("Could not get EDID property\n");
89 }
90 return ret;
91 }
92
GetEdidBlob(drmModePropertyBlobPtr & blob)93 int DrmConnector::GetEdidBlob(drmModePropertyBlobPtr &blob) {
94 uint64_t blob_id;
95 int ret = UpdateEdidProperty();
96 if (ret) {
97 return ret;
98 }
99
100 std::tie(ret, blob_id) = edid_property().value();
101 if (ret) {
102 return ret;
103 }
104
105 blob = drmModeGetPropertyBlob(drm_->fd(), blob_id);
106 return !blob;
107 }
108
id() const109 uint32_t DrmConnector::id() const {
110 return id_;
111 }
112
display() const113 int DrmConnector::display() const {
114 return display_;
115 }
116
set_display(int display)117 void DrmConnector::set_display(int display) {
118 display_ = display;
119 }
120
internal() const121 bool DrmConnector::internal() const {
122 return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
123 type_ == DRM_MODE_CONNECTOR_DSI ||
124 type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI;
125 }
126
external() const127 bool DrmConnector::external() const {
128 return type_ == DRM_MODE_CONNECTOR_HDMIA ||
129 type_ == DRM_MODE_CONNECTOR_DisplayPort ||
130 type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
131 type_ == DRM_MODE_CONNECTOR_VGA;
132 }
133
writeback() const134 bool DrmConnector::writeback() const {
135 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
136 return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
137 #else
138 return false;
139 #endif
140 }
141
valid_type() const142 bool DrmConnector::valid_type() const {
143 return internal() || external() || writeback();
144 }
145
name() const146 std::string DrmConnector::name() const {
147 constexpr std::array<const char *, TYPES_COUNT> names =
148 {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite",
149 "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A",
150 "HDMI-B", "TV", "eDP", "Virtual", "DSI"};
151
152 if (type_ < TYPES_COUNT) {
153 std::ostringstream name_buf;
154 name_buf << names[type_] << "-" << type_id_;
155 return name_buf.str();
156 } else {
157 ALOGE("Unknown type in connector %d, could not make his name", id_);
158 return "None";
159 }
160 }
161
UpdateModes()162 int DrmConnector::UpdateModes() {
163 int fd = drm_->fd();
164
165 drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
166 if (!c) {
167 ALOGE("Failed to get connector %d", id_);
168 return -ENODEV;
169 }
170
171 state_ = c->connection;
172
173 bool preferred_mode_found = false;
174 std::vector<DrmMode> new_modes;
175 for (int i = 0; i < c->count_modes; ++i) {
176 bool exists = false;
177 for (const DrmMode &mode : modes_) {
178 if (mode == c->modes[i]) {
179 new_modes.push_back(mode);
180 exists = true;
181 break;
182 }
183 }
184 if (!exists) {
185 DrmMode m(&c->modes[i]);
186 m.set_id(drm_->next_mode_id());
187 new_modes.push_back(m);
188 }
189 // Use only the first DRM_MODE_TYPE_PREFERRED mode found
190 if (!preferred_mode_found &&
191 (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) {
192 preferred_mode_id_ = new_modes.back().id();
193 preferred_mode_found = true;
194 }
195 }
196 modes_.swap(new_modes);
197 if (!preferred_mode_found && modes_.size() != 0) {
198 preferred_mode_id_ = modes_[0].id();
199 }
200 return 0;
201 }
202
active_mode() const203 const DrmMode &DrmConnector::active_mode() const {
204 return active_mode_;
205 }
206
set_active_mode(const DrmMode & mode)207 void DrmConnector::set_active_mode(const DrmMode &mode) {
208 active_mode_ = mode;
209 }
210
dpms_property() const211 const DrmProperty &DrmConnector::dpms_property() const {
212 return dpms_property_;
213 }
214
crtc_id_property() const215 const DrmProperty &DrmConnector::crtc_id_property() const {
216 return crtc_id_property_;
217 }
218
edid_property() const219 const DrmProperty &DrmConnector::edid_property() const {
220 return edid_property_;
221 }
222
writeback_pixel_formats() const223 const DrmProperty &DrmConnector::writeback_pixel_formats() const {
224 return writeback_pixel_formats_;
225 }
226
writeback_fb_id() const227 const DrmProperty &DrmConnector::writeback_fb_id() const {
228 return writeback_fb_id_;
229 }
230
writeback_out_fence() const231 const DrmProperty &DrmConnector::writeback_out_fence() const {
232 return writeback_out_fence_;
233 }
234
encoder() const235 DrmEncoder *DrmConnector::encoder() const {
236 return encoder_;
237 }
238
set_encoder(DrmEncoder * encoder)239 void DrmConnector::set_encoder(DrmEncoder *encoder) {
240 encoder_ = encoder;
241 }
242
state() const243 drmModeConnection DrmConnector::state() const {
244 return state_;
245 }
246
mm_width() const247 uint32_t DrmConnector::mm_width() const {
248 return mm_width_;
249 }
250
mm_height() const251 uint32_t DrmConnector::mm_height() const {
252 return mm_height_;
253 }
254 } // namespace android
255