blob: ece9437aabcc26a033921db802c5ae0ca047fdbc [file] [log] [blame]
Sean Paul6a55e9f2015-04-30 15:31:06 -04001/*
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
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +010017#define LOG_TAG "hwc-drm-device"
Sean Paul6a55e9f2015-04-30 15:31:06 -040018
Roman Stratiienko13cc3662020-08-29 21:35:39 +030019#include "DrmDevice.h"
Sean Paul6a55e9f2015-04-30 15:31:06 -040020
Sean Paul6a55e9f2015-04-30 15:31:06 -040021#include <fcntl.h>
Sean Paul6a55e9f2015-04-30 15:31:06 -040022#include <xf86drm.h>
23#include <xf86drmMode.h>
24
Roman Kovalivskyid07c3702019-11-04 17:54:31 +020025#include <algorithm>
26#include <array>
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +020027#include <cerrno>
Roman Stratiienko13cc3662020-08-29 21:35:39 +030028#include <cinttypes>
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +020029#include <cstdint>
Roman Stratiienkob2e9fe22020-10-03 10:52:36 +030030#include <sstream>
Roman Kovalivskyid07c3702019-11-04 17:54:31 +020031#include <string>
32
Roman Stratiienko24a7fc42021-12-23 16:25:20 +020033#include "drm/DrmPlane.h"
Roman Stratiienkod518a052021-02-25 19:15:14 +020034#include "utils/log.h"
35#include "utils/properties.h"
36
Sean Paul6a55e9f2015-04-30 15:31:06 -040037namespace android {
38
Roman Stratiienko1e053b42021-10-25 22:54:20 +030039DrmDevice::DrmDevice() {
Roman Stratiienko7d899112022-01-31 11:30:27 +020040 drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
Sean Paul047b9b22015-07-28 14:15:42 -040041}
42
Roman Stratiienko5f2f3ce2021-12-22 11:46:03 +020043// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
Alexandru Gheorghec5463582018-03-27 15:52:02 +010044std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
Sean Paul6a55e9f2015-04-30 15:31:06 -040045 /* TODO: Use drmOpenControl here instead */
Roman Stratiienko0fade372021-02-20 13:59:55 +020046 fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
Roman Stratiienko7d899112022-01-31 11:30:27 +020047 if (!fd_) {
Roman Stratiienko5f2f3ce2021-12-22 11:46:03 +020048 // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
Peter Collingbournec77052e2020-02-19 11:25:08 -080049 ALOGE("Failed to open dri %s: %s", path, strerror(errno));
Alexandru Gheorghec5463582018-03-27 15:52:02 +010050 return std::make_tuple(-ENODEV, 0);
Sean Paul6a55e9f2015-04-30 15:31:06 -040051 }
52
Roman Stratiienko7d899112022-01-31 11:30:27 +020053 int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
54 if (ret != 0) {
Sean Paul6a55e9f2015-04-30 15:31:06 -040055 ALOGE("Failed to set universal plane cap %d", ret);
Alexandru Gheorghec5463582018-03-27 15:52:02 +010056 return std::make_tuple(ret, 0);
Sean Paul6a55e9f2015-04-30 15:31:06 -040057 }
58
Roman Stratiienko7d899112022-01-31 11:30:27 +020059 ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
60 if (ret != 0) {
Sean Paul6a55e9f2015-04-30 15:31:06 -040061 ALOGE("Failed to set atomic cap %d", ret);
Alexandru Gheorghec5463582018-03-27 15:52:02 +010062 return std::make_tuple(ret, 0);
Sean Paul6a55e9f2015-04-30 15:31:06 -040063 }
64
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +000065#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
Roman Stratiienko7d899112022-01-31 11:30:27 +020066 ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
67 if (ret != 0) {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +000068 ALOGI("Failed to set writeback cap %d", ret);
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +000069 }
70#endif
71
Roman Stratiienko8666dc92021-02-09 17:49:55 +020072 uint64_t cap_value = 0;
Roman Stratiienko7d899112022-01-31 11:30:27 +020073 if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
Roman Stratiienko8666dc92021-02-09 17:49:55 +020074 ALOGW("drmGetCap failed. Fallback to no modifier support.");
75 cap_value = 0;
76 }
77 HasAddFb2ModifiersSupport_ = cap_value != 0;
78
Roman Stratiienko7d899112022-01-31 11:30:27 +020079 drmSetMaster(GetFd());
80 if (drmIsMaster(GetFd()) == 0) {
John Stultzfa002332021-02-02 01:34:45 +000081 ALOGE("DRM/KMS master access required");
82 return std::make_tuple(-EACCES, 0);
Roman Stratiienko3b24cd92021-01-13 10:32:04 +020083 }
84
Roman Stratiienko7d899112022-01-31 11:30:27 +020085 auto res = MakeDrmModeResUnique(GetFd());
Sean Paul6a55e9f2015-04-30 15:31:06 -040086 if (!res) {
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +010087 ALOGE("Failed to get DrmDevice resources");
Alexandru Gheorghec5463582018-03-27 15:52:02 +010088 return std::make_tuple(-ENODEV, 0);
Sean Paul6a55e9f2015-04-30 15:31:06 -040089 }
90
Sean Paulf72cccd2018-08-27 13:59:08 -040091 min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
92 res->min_height);
93 max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
94 res->max_height);
Sean Paul406dbfc2016-02-10 15:35:17 -080095
Roman Stratiienko10be8752022-01-30 20:28:46 +020096 for (int i = 0; i < res->count_crtcs; ++i) {
97 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
98 auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
99 if (crtc) {
100 crtcs_.emplace_back(std::move(crtc));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400101 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400102 }
103
Roman Stratiienko027987b2022-01-30 21:06:35 +0200104 for (int i = 0; i < res->count_encoders; ++i) {
105 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
106 auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
107 if (enc) {
108 encoders_.emplace_back(std::move(enc));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400109 }
Alexandru Gheorghee8b668c2018-03-22 11:31:29 +0000110 }
111
Roman Stratiienko650299a2022-01-30 23:46:10 +0200112 for (int i = 0; i < res->count_connectors; ++i) {
113 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
114 auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
115
116 if (!conn) {
117 continue;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400118 }
119
Roman Stratiienko650299a2022-01-30 23:46:10 +0200120 if (conn->IsWriteback()) {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +0000121 writeback_connectors_.emplace_back(std::move(conn));
Roman Stratiienko650299a2022-01-30 23:46:10 +0200122 } else {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +0000123 connectors_.emplace_back(std::move(conn));
Roman Stratiienko650299a2022-01-30 23:46:10 +0200124 }
Robert Foss610d9892017-11-01 12:50:04 -0500125 }
126
Roman Stratiienko7d899112022-01-31 11:30:27 +0200127 auto plane_res = MakeDrmModePlaneResUnique(GetFd());
Sean Paul6a55e9f2015-04-30 15:31:06 -0400128 if (!plane_res) {
129 ALOGE("Failed to get plane resources");
Alexandru Gheorghec5463582018-03-27 15:52:02 +0100130 return std::make_tuple(-ENOENT, 0);
Sean Paul6a55e9f2015-04-30 15:31:06 -0400131 }
132
133 for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
Roman Stratiienkob671fab2022-01-29 00:50:22 +0200134 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
135 auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
136
137 if (plane) {
138 planes_.emplace_back(std::move(plane));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400139 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400140 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400141
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200142 auto add_displays = [this, &num_displays](bool internal, bool connected) {
143 for (auto &conn : connectors_) {
144 bool is_connected = conn->IsConnected();
145 if ((internal ? conn->IsInternal() : conn->IsExternal()) &&
146 (connected ? is_connected : !is_connected)) {
147 auto pipe = DrmDisplayPipeline::CreatePipeline(*conn);
148 if (pipe) {
149 pipelines_[num_displays] = std::move(pipe);
150 ++num_displays;
151 }
152 }
Sean Paul57355412015-09-19 09:14:34 -0400153 }
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200154 };
155
156 /* Put internal first to ensure Primary display will be internal
157 * in case at least 1 internal is available
158 */
159 add_displays(/*internal = */ true, /*connected = */ true);
160 add_displays(/*internal = */ false, /*connected = */ true);
161 add_displays(/*internal = */ true, /*connected = */ false);
162 add_displays(/*internal = */ false, /*connected = */ false);
163
164 return std::make_tuple(0, pipelines_.size());
Alexandru Gheorghec5463582018-03-27 15:52:02 +0100165}
166
167bool DrmDevice::HandlesDisplay(int display) const {
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200168 return pipelines_.count(display) != 0;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400169}
170
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100171DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200172 return pipelines_.at(display)->connector->Get();
Sean Paul6a55e9f2015-04-30 15:31:06 -0400173}
174
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100175DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200176 return pipelines_.at(display)->crtc->Get();
Sean Paul6a55e9f2015-04-30 15:31:06 -0400177}
178
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200179auto DrmDevice::GetDisplayId(DrmConnector *conn) -> int {
180 for (auto &dpipe : pipelines_) {
181 if (dpipe.second->connector->Get() == conn) {
182 return dpipe.first;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400183 }
184 }
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200185 return -1;
Sean Paul877be972015-06-03 14:08:27 -0400186}
187
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300188auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
189 -> DrmModeUserPropertyBlobUnique {
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200190 struct drm_mode_create_blob create_blob {};
Sean Paul877be972015-06-03 14:08:27 -0400191 create_blob.length = length;
Roman Stratiienko7d899112022-01-31 11:30:27 +0200192 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
Sean Paul877be972015-06-03 14:08:27 -0400193 create_blob.data = (__u64)data;
194
Roman Stratiienko7d899112022-01-31 11:30:27 +0200195 int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
196 if (ret != 0) {
Sean Paul877be972015-06-03 14:08:27 -0400197 ALOGE("Failed to create mode property blob %d", ret);
Roman Stratiienko780f7da2022-01-10 16:04:15 +0200198 return {};
Sean Paul877be972015-06-03 14:08:27 -0400199 }
Sean Paul877be972015-06-03 14:08:27 -0400200
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300201 return DrmModeUserPropertyBlobUnique(
202 new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
203 struct drm_mode_destroy_blob destroy_blob {};
204 destroy_blob.blob_id = (__u32)*it;
Roman Stratiienko7d899112022-01-31 11:30:27 +0200205 int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
206 &destroy_blob);
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300207 if (err != 0) {
208 ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
209 err);
210 }
211 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
212 delete it;
213 });
Sean Paul877be972015-06-03 14:08:27 -0400214}
215
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100216int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200217 const char *prop_name, DrmProperty *property) const {
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200218 drmModeObjectPropertiesPtr props = nullptr;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400219
Roman Stratiienko7d899112022-01-31 11:30:27 +0200220 props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
221 if (props == nullptr) {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400222 ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
223 return -ENODEV;
224 }
225
226 bool found = false;
227 for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
Roman Stratiienko7d899112022-01-31 11:30:27 +0200228 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
229 drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
230 if (strcmp(p->name, prop_name) == 0) {
231 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Roman Stratiienko7fd8f882021-09-29 12:46:54 +0300232 property->Init(obj_id, p, props->prop_values[i]);
Sean Paul6a55e9f2015-04-30 15:31:06 -0400233 found = true;
234 }
235 drmModeFreeProperty(p);
236 }
237
238 drmModeFreeObjectProperties(props);
239 return found ? 0 : -ENOENT;
240}
241
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200242std::string DrmDevice::GetName() const {
Roman Stratiienko7d899112022-01-31 11:30:27 +0200243 auto *ver = drmGetVersion(GetFd());
244 if (ver == nullptr) {
245 ALOGW("Failed to get drm version for fd=%d", GetFd());
Matvii Zorinef3c7972020-08-11 15:15:44 +0300246 return "generic";
247 }
248
249 std::string name(ver->name);
250 drmFreeVersion(ver);
251 return name;
252}
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300253
254auto DrmDevice::IsKMSDev(const char *path) -> bool {
255 auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
256 if (!fd) {
257 return false;
258 }
259
260 auto res = MakeDrmModeResUnique(fd.Get());
261 if (!res) {
262 return false;
263 }
264
265 bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
266 res->count_encoders > 0;
267
268 return is_kms;
269}
270
Roman Stratiienko7d899112022-01-31 11:30:27 +0200271auto DrmDevice::GetConnectors()
272 -> const std::vector<std::unique_ptr<DrmConnector>> & {
273 return connectors_;
274}
275
276auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
277 return planes_;
278}
279
280auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
281 return crtcs_;
282}
283
284auto DrmDevice::GetEncoders()
285 -> const std::vector<std::unique_ptr<DrmEncoder>> & {
286 return encoders_;
287}
288
Sean Paulf72cccd2018-08-27 13:59:08 -0400289} // namespace android