OSDN Git Service

drm_hwcomposer: allow to force mode by a property (v5)
[android-x86/external-drm_hwcomposer.git] / drm / DrmConnector.cpp
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 <cutils/properties.h>
22 #include <xf86drmMode.h>
23
24 #include <array>
25 #include <cerrno>
26 #include <cstdint>
27 #include <sstream>
28
29 #include "DrmDevice.h"
30 #include "utils/log.h"
31
32 #ifndef DRM_MODE_CONNECTOR_SPI
33 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
34 #define DRM_MODE_CONNECTOR_SPI 19
35 #endif
36
37 #ifndef DRM_MODE_CONNECTOR_USB
38 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
39 #define DRM_MODE_CONNECTOR_USB 20
40 #endif
41
42 namespace android {
43
44 constexpr size_t kTypesCount = 21;
45
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;
52 }
53
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);
59     return false;
60   }
61   return true;
62 }
63
64 auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
65                                   uint32_t index)
66     -> std::unique_ptr<DrmConnector> {
67   auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
68   if (!conn) {
69     ALOGE("Failed to get connector %d", connector_id);
70     return {};
71   }
72
73   auto c = std::unique_ptr<DrmConnector>(
74       new DrmConnector(std::move(conn), &dev, index));
75
76   if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
77       !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
78     return {};
79   }
80
81   c->UpdateEdidProperty();
82
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_))) {
90     return {};
91   }
92
93   return c;
94 }
95
96 int DrmConnector::UpdateEdidProperty() {
97   return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
98              ? 0
99              : -EINVAL;
100 }
101
102 auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
103   uint64_t blob_id = 0;
104   int ret = UpdateEdidProperty();
105   if (ret != 0) {
106     return {};
107   }
108
109   std::tie(ret, blob_id) = GetEdidProperty().value();
110   if (ret != 0) {
111     return {};
112   }
113
114   return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
115 }
116
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;
122 }
123
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;
130 }
131
132 bool DrmConnector::IsWriteback() const {
133 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
134   return connector_->connector_type == DRM_MODE_CONNECTOR_WRITEBACK;
135 #else
136   return false;
137 #endif
138 }
139
140 bool DrmConnector::IsValid() const {
141   return IsInternal() || IsExternal() || IsWriteback();
142 }
143
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"};
150
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();
156   }
157
158   ALOGE("Unknown type in connector %d, could not make his name", GetId());
159   return "None";
160 }
161
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) {
168       rate = 0;
169       if (sscanf(value, "%dx%d", &xres, &yres) != 2) {
170         xres = yres = 0;
171       }
172     }
173     ALOGI_IF(xres && yres, "force mode to %dx%d@%dHz", xres, yres, rate);
174   }
175
176   auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
177   if (!conn) {
178     ALOGE("Failed to get connector %d", GetId());
179     return -ENODEV;
180   }
181   connector_ = std::move(conn);
182
183   modes_.clear();
184   for (int i = 0; i < connector_->count_modes; ++i) {
185     bool exists = false;
186     for (const DrmMode &mode : modes_) {
187       if (mode == connector_->modes[i]) {
188         exists = true;
189         break;
190       }
191     }
192
193     if (!exists) {
194       DrmMode m(&connector_->modes[i]);
195       if (xres && yres) {
196         if (m.h_display() != xres || m.v_display() != yres ||
197               (rate && uint32_t(m.v_refresh()) != rate))
198           continue;
199       }
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());
202     }
203   }
204
205   return 0;
206 }
207
208 void DrmConnector::SetActiveMode(DrmMode &mode) {
209   active_mode_ = mode;
210 }
211
212 }  // namespace android