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