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 <xf86drmMode.h>
22
23 #include <array>
24 #include <cerrno>
25 #include <cstdint>
26 #include <sstream>
27
28 #include "DrmDevice.h"
29 #include "utils/log.h"
30
31 #ifndef DRM_MODE_CONNECTOR_SPI
32 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
33 #define DRM_MODE_CONNECTOR_SPI 19
34 #endif
35
36 #ifndef DRM_MODE_CONNECTOR_USB
37 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
38 #define DRM_MODE_CONNECTOR_USB 20
39 #endif
40
41 namespace android {
42
43 constexpr size_t kTypesCount = 21;
44
GetOptionalConnectorProperty(const DrmDevice & dev,const DrmConnector & connector,const char * prop_name,DrmProperty * property)45 static bool GetOptionalConnectorProperty(const DrmDevice &dev,
46 const DrmConnector &connector,
47 const char *prop_name,
48 DrmProperty *property) {
49 return dev.GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR,
50 prop_name, property) == 0;
51 }
52
GetConnectorProperty(const DrmDevice & dev,const DrmConnector & connector,const char * prop_name,DrmProperty * property)53 static bool GetConnectorProperty(const DrmDevice &dev,
54 const DrmConnector &connector,
55 const char *prop_name, DrmProperty *property) {
56 if (!GetOptionalConnectorProperty(dev, connector, prop_name, property)) {
57 ALOGE("Could not get %s property\n", prop_name);
58 return false;
59 }
60 return true;
61 }
62
CreateInstance(DrmDevice & dev,uint32_t connector_id,uint32_t index)63 auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
64 uint32_t index)
65 -> std::unique_ptr<DrmConnector> {
66 auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
67 if (!conn) {
68 ALOGE("Failed to get connector %d", connector_id);
69 return {};
70 }
71
72 auto c = std::unique_ptr<DrmConnector>(
73 new DrmConnector(std::move(conn), &dev, index));
74
75 if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
76 !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
77 return {};
78 }
79
80 c->UpdateEdidProperty();
81
82 if (c->IsWriteback() &&
83 (!GetConnectorProperty(dev, *c, "WRITEBACK_PIXEL_FORMATS",
84 &c->writeback_pixel_formats_) ||
85 !GetConnectorProperty(dev, *c, "WRITEBACK_FB_ID",
86 &c->writeback_fb_id_) ||
87 !GetConnectorProperty(dev, *c, "WRITEBACK_OUT_FENCE_PTR",
88 &c->writeback_out_fence_))) {
89 return {};
90 }
91
92 return c;
93 }
94
UpdateEdidProperty()95 int DrmConnector::UpdateEdidProperty() {
96 return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
97 ? 0
98 : -EINVAL;
99 }
100
GetEdidBlob()101 auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
102 uint64_t blob_id = 0;
103 int ret = UpdateEdidProperty();
104 if (ret != 0) {
105 return {};
106 }
107
108 std::tie(ret, blob_id) = GetEdidProperty().value();
109 if (ret != 0) {
110 return {};
111 }
112
113 return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
114 }
115
IsInternal() const116 bool DrmConnector::IsInternal() const {
117 auto type = connector_->connector_type;
118 return type == DRM_MODE_CONNECTOR_LVDS || type == DRM_MODE_CONNECTOR_eDP ||
119 type == DRM_MODE_CONNECTOR_DSI || type == DRM_MODE_CONNECTOR_VIRTUAL ||
120 type == DRM_MODE_CONNECTOR_DPI || type == DRM_MODE_CONNECTOR_SPI;
121 }
122
IsExternal() const123 bool DrmConnector::IsExternal() const {
124 auto type = connector_->connector_type;
125 return type == DRM_MODE_CONNECTOR_HDMIA ||
126 type == DRM_MODE_CONNECTOR_DisplayPort ||
127 type == DRM_MODE_CONNECTOR_DVID || type == DRM_MODE_CONNECTOR_DVII ||
128 type == DRM_MODE_CONNECTOR_VGA || type == DRM_MODE_CONNECTOR_USB;
129 }
130
IsWriteback() const131 bool DrmConnector::IsWriteback() const {
132 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
133 return connector_->connector_type == DRM_MODE_CONNECTOR_WRITEBACK;
134 #else
135 return false;
136 #endif
137 }
138
IsValid() const139 bool DrmConnector::IsValid() const {
140 return IsInternal() || IsExternal() || IsWriteback();
141 }
142
GetName() const143 std::string DrmConnector::GetName() const {
144 constexpr std::array<const char *, kTypesCount> kNames =
145 {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite",
146 "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A",
147 "HDMI-B", "TV", "eDP", "Virtual", "DSI", "DPI",
148 "Writeback", "SPI", "USB"};
149
150 if (connector_->connector_type < kTypesCount) {
151 std::ostringstream name_buf;
152 name_buf << kNames[connector_->connector_type] << "-"
153 << connector_->connector_type_id;
154 return name_buf.str();
155 }
156
157 ALOGE("Unknown type in connector %d, could not make his name", GetId());
158 return "None";
159 }
160
UpdateModes()161 int DrmConnector::UpdateModes() {
162 auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
163 if (!conn) {
164 ALOGE("Failed to get connector %d", GetId());
165 return -ENODEV;
166 }
167 connector_ = std::move(conn);
168
169 modes_.clear();
170 for (int i = 0; i < connector_->count_modes; ++i) {
171 bool exists = false;
172 for (const DrmMode &mode : modes_) {
173 if (mode == connector_->modes[i]) {
174 exists = true;
175 break;
176 }
177 }
178
179 if (!exists) {
180 modes_.emplace_back(DrmMode(&connector_->modes[i]));
181 }
182 }
183
184 return 0;
185 }
186
SetActiveMode(DrmMode & mode)187 void DrmConnector::SetActiveMode(DrmMode &mode) {
188 active_mode_ = mode;
189 }
190
191 } // namespace android
192