2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "hwc-drm-connector"
19 #include "DrmConnector.h"
21 #include <cutils/properties.h>
22 #include <xf86drmMode.h>
29 #include "DrmDevice.h"
30 #include "utils/log.h"
32 #ifndef DRM_MODE_CONNECTOR_SPI
33 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
34 #define DRM_MODE_CONNECTOR_SPI 19
37 #ifndef DRM_MODE_CONNECTOR_USB
38 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
39 #define DRM_MODE_CONNECTOR_USB 20
44 constexpr size_t kTypesCount = 21;
46 static bool GetOptionalConnectorProperty(const DrmDevice &dev,
47 const DrmConnector &connector,
48 const char *prop_name,
49 DrmProperty *property) {
50 return dev.GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR,
51 prop_name, property) == 0;
54 static bool GetConnectorProperty(const DrmDevice &dev,
55 const DrmConnector &connector,
56 const char *prop_name, DrmProperty *property) {
57 if (!GetOptionalConnectorProperty(dev, connector, prop_name, property)) {
58 ALOGE("Could not get %s property\n", prop_name);
64 auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
66 -> std::unique_ptr<DrmConnector> {
67 auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
69 ALOGE("Failed to get connector %d", connector_id);
73 auto c = std::unique_ptr<DrmConnector>(
74 new DrmConnector(std::move(conn), &dev, index));
76 if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
77 !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
81 c->UpdateEdidProperty();
83 if (c->IsWriteback() &&
84 (!GetConnectorProperty(dev, *c, "WRITEBACK_PIXEL_FORMATS",
85 &c->writeback_pixel_formats_) ||
86 !GetConnectorProperty(dev, *c, "WRITEBACK_FB_ID",
87 &c->writeback_fb_id_) ||
88 !GetConnectorProperty(dev, *c, "WRITEBACK_OUT_FENCE_PTR",
89 &c->writeback_out_fence_))) {
96 int DrmConnector::UpdateEdidProperty() {
97 return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
102 auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
103 uint64_t blob_id = 0;
104 int ret = UpdateEdidProperty();
109 std::tie(ret, blob_id) = GetEdidProperty().value();
114 return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
117 bool DrmConnector::IsInternal() const {
118 auto type = connector_->connector_type;
119 return type == DRM_MODE_CONNECTOR_LVDS || type == DRM_MODE_CONNECTOR_eDP ||
120 type == DRM_MODE_CONNECTOR_DSI || type == DRM_MODE_CONNECTOR_VIRTUAL ||
121 type == DRM_MODE_CONNECTOR_DPI || type == DRM_MODE_CONNECTOR_SPI;
124 bool DrmConnector::IsExternal() const {
125 auto type = connector_->connector_type;
126 return type == DRM_MODE_CONNECTOR_HDMIA ||
127 type == DRM_MODE_CONNECTOR_DisplayPort ||
128 type == DRM_MODE_CONNECTOR_DVID || type == DRM_MODE_CONNECTOR_DVII ||
129 type == DRM_MODE_CONNECTOR_VGA || type == DRM_MODE_CONNECTOR_USB;
132 bool DrmConnector::IsWriteback() const {
133 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
134 return connector_->connector_type == DRM_MODE_CONNECTOR_WRITEBACK;
140 bool DrmConnector::IsValid() const {
141 return IsInternal() || IsExternal() || IsWriteback();
144 std::string DrmConnector::GetName() const {
145 constexpr std::array<const char *, kTypesCount> kNames =
146 {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite",
147 "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A",
148 "HDMI-B", "TV", "eDP", "Virtual", "DSI", "DPI",
149 "Writeback", "SPI", "USB"};
151 if (connector_->connector_type < kTypesCount) {
152 std::ostringstream name_buf;
153 name_buf << kNames[connector_->connector_type] << "-"
154 << connector_->connector_type_id;
155 return name_buf.str();
158 ALOGE("Unknown type in connector %d, could not make his name", GetId());
162 int DrmConnector::UpdateModes() {
163 char value[PROPERTY_VALUE_MAX];
164 uint32_t xres = 0, yres = 0, rate = 0;
165 if (property_get("debug.drm.mode.force", value, NULL)) {
166 // parse <xres>x<yres>[@<refreshrate>]
167 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
169 if (sscanf(value, "%dx%d", &xres, &yres) != 2) {
173 ALOGI_IF(xres && yres, "force mode to %dx%d@%dHz", xres, yres, rate);
176 auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
178 ALOGE("Failed to get connector %d", GetId());
181 connector_ = std::move(conn);
184 for (int i = 0; i < connector_->count_modes; ++i) {
186 for (const DrmMode &mode : modes_) {
187 if (mode == connector_->modes[i]) {
194 DrmMode m(&connector_->modes[i]);
196 if (m.h_display() != xres || m.v_display() != yres ||
197 (rate && uint32_t(m.v_refresh()) != rate))
200 modes_.emplace_back(DrmMode(&connector_->modes[i]));
201 ALOGD("add new mode %dx%d@%.1f for connector %d", m.h_display(), m.v_display(), m.v_refresh(), GetId());
208 void DrmConnector::SetActiveMode(DrmMode &mode) {
212 } // namespace android