1*0a9764feSAndroid Build Coastguard Worker /*
2*0a9764feSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*0a9764feSAndroid Build Coastguard Worker *
4*0a9764feSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*0a9764feSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*0a9764feSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*0a9764feSAndroid Build Coastguard Worker *
8*0a9764feSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*0a9764feSAndroid Build Coastguard Worker *
10*0a9764feSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*0a9764feSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*0a9764feSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0a9764feSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*0a9764feSAndroid Build Coastguard Worker * limitations under the License.
15*0a9764feSAndroid Build Coastguard Worker */
16*0a9764feSAndroid Build Coastguard Worker
17*0a9764feSAndroid Build Coastguard Worker #define LOG_TAG "drmhwc"
18*0a9764feSAndroid Build Coastguard Worker
19*0a9764feSAndroid Build Coastguard Worker #include "DrmDevice.h"
20*0a9764feSAndroid Build Coastguard Worker
21*0a9764feSAndroid Build Coastguard Worker #include <xf86drm.h>
22*0a9764feSAndroid Build Coastguard Worker #include <xf86drmMode.h>
23*0a9764feSAndroid Build Coastguard Worker
24*0a9764feSAndroid Build Coastguard Worker #include <cinttypes>
25*0a9764feSAndroid Build Coastguard Worker #include <cstdint>
26*0a9764feSAndroid Build Coastguard Worker #include <string>
27*0a9764feSAndroid Build Coastguard Worker
28*0a9764feSAndroid Build Coastguard Worker #include "drm/DrmAtomicStateManager.h"
29*0a9764feSAndroid Build Coastguard Worker #include "drm/DrmPlane.h"
30*0a9764feSAndroid Build Coastguard Worker #include "drm/ResourceManager.h"
31*0a9764feSAndroid Build Coastguard Worker #include "utils/log.h"
32*0a9764feSAndroid Build Coastguard Worker #include "utils/properties.h"
33*0a9764feSAndroid Build Coastguard Worker
34*0a9764feSAndroid Build Coastguard Worker namespace android {
35*0a9764feSAndroid Build Coastguard Worker
CreateInstance(std::string const & path,ResourceManager * res_man)36*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::CreateInstance(std::string const &path,
37*0a9764feSAndroid Build Coastguard Worker ResourceManager *res_man)
38*0a9764feSAndroid Build Coastguard Worker -> std::unique_ptr<DrmDevice> {
39*0a9764feSAndroid Build Coastguard Worker if (!IsKMSDev(path.c_str())) {
40*0a9764feSAndroid Build Coastguard Worker return {};
41*0a9764feSAndroid Build Coastguard Worker }
42*0a9764feSAndroid Build Coastguard Worker
43*0a9764feSAndroid Build Coastguard Worker auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man));
44*0a9764feSAndroid Build Coastguard Worker
45*0a9764feSAndroid Build Coastguard Worker if (device->Init(path.c_str()) != 0) {
46*0a9764feSAndroid Build Coastguard Worker return {};
47*0a9764feSAndroid Build Coastguard Worker }
48*0a9764feSAndroid Build Coastguard Worker
49*0a9764feSAndroid Build Coastguard Worker return device;
50*0a9764feSAndroid Build Coastguard Worker }
51*0a9764feSAndroid Build Coastguard Worker
DrmDevice(ResourceManager * res_man)52*0a9764feSAndroid Build Coastguard Worker DrmDevice::DrmDevice(ResourceManager *res_man) : res_man_(res_man) {
53*0a9764feSAndroid Build Coastguard Worker drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
54*0a9764feSAndroid Build Coastguard Worker }
55*0a9764feSAndroid Build Coastguard Worker
Init(const char * path)56*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::Init(const char *path) -> int {
57*0a9764feSAndroid Build Coastguard Worker /* TODO: Use drmOpenControl here instead */
58*0a9764feSAndroid Build Coastguard Worker fd_ = MakeSharedFd(open(path, O_RDWR | O_CLOEXEC));
59*0a9764feSAndroid Build Coastguard Worker if (!fd_) {
60*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
61*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to open dri %s: %s", path, strerror(errno));
62*0a9764feSAndroid Build Coastguard Worker return -ENODEV;
63*0a9764feSAndroid Build Coastguard Worker }
64*0a9764feSAndroid Build Coastguard Worker
65*0a9764feSAndroid Build Coastguard Worker int ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
66*0a9764feSAndroid Build Coastguard Worker if (ret != 0) {
67*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to set universal plane cap %d", ret);
68*0a9764feSAndroid Build Coastguard Worker return ret;
69*0a9764feSAndroid Build Coastguard Worker }
70*0a9764feSAndroid Build Coastguard Worker
71*0a9764feSAndroid Build Coastguard Worker ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
72*0a9764feSAndroid Build Coastguard Worker if (ret != 0) {
73*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to set atomic cap %d", ret);
74*0a9764feSAndroid Build Coastguard Worker return ret;
75*0a9764feSAndroid Build Coastguard Worker }
76*0a9764feSAndroid Build Coastguard Worker
77*0a9764feSAndroid Build Coastguard Worker #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
78*0a9764feSAndroid Build Coastguard Worker ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
79*0a9764feSAndroid Build Coastguard Worker if (ret != 0) {
80*0a9764feSAndroid Build Coastguard Worker ALOGI("Failed to set writeback cap %d", ret);
81*0a9764feSAndroid Build Coastguard Worker }
82*0a9764feSAndroid Build Coastguard Worker #endif
83*0a9764feSAndroid Build Coastguard Worker
84*0a9764feSAndroid Build Coastguard Worker uint64_t cap_value = 0;
85*0a9764feSAndroid Build Coastguard Worker if (drmGetCap(*GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
86*0a9764feSAndroid Build Coastguard Worker ALOGW("drmGetCap failed. Fallback to no modifier support.");
87*0a9764feSAndroid Build Coastguard Worker cap_value = 0;
88*0a9764feSAndroid Build Coastguard Worker }
89*0a9764feSAndroid Build Coastguard Worker HasAddFb2ModifiersSupport_ = cap_value != 0;
90*0a9764feSAndroid Build Coastguard Worker
91*0a9764feSAndroid Build Coastguard Worker drmSetMaster(*GetFd());
92*0a9764feSAndroid Build Coastguard Worker if (drmIsMaster(*GetFd()) == 0) {
93*0a9764feSAndroid Build Coastguard Worker ALOGE("DRM/KMS master access required");
94*0a9764feSAndroid Build Coastguard Worker return -EACCES;
95*0a9764feSAndroid Build Coastguard Worker }
96*0a9764feSAndroid Build Coastguard Worker
97*0a9764feSAndroid Build Coastguard Worker auto res = MakeDrmModeResUnique(*GetFd());
98*0a9764feSAndroid Build Coastguard Worker if (!res) {
99*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to get DrmDevice resources");
100*0a9764feSAndroid Build Coastguard Worker return -ENODEV;
101*0a9764feSAndroid Build Coastguard Worker }
102*0a9764feSAndroid Build Coastguard Worker
103*0a9764feSAndroid Build Coastguard Worker min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
104*0a9764feSAndroid Build Coastguard Worker res->min_height);
105*0a9764feSAndroid Build Coastguard Worker max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
106*0a9764feSAndroid Build Coastguard Worker res->max_height);
107*0a9764feSAndroid Build Coastguard Worker
108*0a9764feSAndroid Build Coastguard Worker for (int i = 0; i < res->count_crtcs; ++i) {
109*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
110*0a9764feSAndroid Build Coastguard Worker auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
111*0a9764feSAndroid Build Coastguard Worker if (crtc) {
112*0a9764feSAndroid Build Coastguard Worker crtcs_.emplace_back(std::move(crtc));
113*0a9764feSAndroid Build Coastguard Worker }
114*0a9764feSAndroid Build Coastguard Worker }
115*0a9764feSAndroid Build Coastguard Worker
116*0a9764feSAndroid Build Coastguard Worker for (int i = 0; i < res->count_encoders; ++i) {
117*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
118*0a9764feSAndroid Build Coastguard Worker auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
119*0a9764feSAndroid Build Coastguard Worker if (enc) {
120*0a9764feSAndroid Build Coastguard Worker encoders_.emplace_back(std::move(enc));
121*0a9764feSAndroid Build Coastguard Worker }
122*0a9764feSAndroid Build Coastguard Worker }
123*0a9764feSAndroid Build Coastguard Worker
124*0a9764feSAndroid Build Coastguard Worker for (int i = 0; i < res->count_connectors; ++i) {
125*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
126*0a9764feSAndroid Build Coastguard Worker auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
127*0a9764feSAndroid Build Coastguard Worker
128*0a9764feSAndroid Build Coastguard Worker if (!conn) {
129*0a9764feSAndroid Build Coastguard Worker continue;
130*0a9764feSAndroid Build Coastguard Worker }
131*0a9764feSAndroid Build Coastguard Worker
132*0a9764feSAndroid Build Coastguard Worker if (conn->IsWriteback()) {
133*0a9764feSAndroid Build Coastguard Worker writeback_connectors_.emplace_back(std::move(conn));
134*0a9764feSAndroid Build Coastguard Worker } else {
135*0a9764feSAndroid Build Coastguard Worker connectors_.emplace_back(std::move(conn));
136*0a9764feSAndroid Build Coastguard Worker }
137*0a9764feSAndroid Build Coastguard Worker }
138*0a9764feSAndroid Build Coastguard Worker
139*0a9764feSAndroid Build Coastguard Worker auto plane_res = MakeDrmModePlaneResUnique(*GetFd());
140*0a9764feSAndroid Build Coastguard Worker if (!plane_res) {
141*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to get plane resources");
142*0a9764feSAndroid Build Coastguard Worker return -ENOENT;
143*0a9764feSAndroid Build Coastguard Worker }
144*0a9764feSAndroid Build Coastguard Worker
145*0a9764feSAndroid Build Coastguard Worker for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
146*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
147*0a9764feSAndroid Build Coastguard Worker auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
148*0a9764feSAndroid Build Coastguard Worker
149*0a9764feSAndroid Build Coastguard Worker if (plane) {
150*0a9764feSAndroid Build Coastguard Worker planes_.emplace_back(std::move(plane));
151*0a9764feSAndroid Build Coastguard Worker }
152*0a9764feSAndroid Build Coastguard Worker }
153*0a9764feSAndroid Build Coastguard Worker
154*0a9764feSAndroid Build Coastguard Worker return 0;
155*0a9764feSAndroid Build Coastguard Worker }
156*0a9764feSAndroid Build Coastguard Worker
RegisterUserPropertyBlob(void * data,size_t length) const157*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
158*0a9764feSAndroid Build Coastguard Worker -> DrmModeUserPropertyBlobUnique {
159*0a9764feSAndroid Build Coastguard Worker struct drm_mode_create_blob create_blob {};
160*0a9764feSAndroid Build Coastguard Worker create_blob.length = length;
161*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
162*0a9764feSAndroid Build Coastguard Worker create_blob.data = (__u64)data;
163*0a9764feSAndroid Build Coastguard Worker
164*0a9764feSAndroid Build Coastguard Worker auto ret = drmIoctl(*GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
165*0a9764feSAndroid Build Coastguard Worker if (ret != 0) {
166*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to create mode property blob %d", ret);
167*0a9764feSAndroid Build Coastguard Worker return {};
168*0a9764feSAndroid Build Coastguard Worker }
169*0a9764feSAndroid Build Coastguard Worker
170*0a9764feSAndroid Build Coastguard Worker return DrmModeUserPropertyBlobUnique(
171*0a9764feSAndroid Build Coastguard Worker new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
172*0a9764feSAndroid Build Coastguard Worker struct drm_mode_destroy_blob destroy_blob {};
173*0a9764feSAndroid Build Coastguard Worker destroy_blob.blob_id = (__u32)*it;
174*0a9764feSAndroid Build Coastguard Worker auto err = drmIoctl(*GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
175*0a9764feSAndroid Build Coastguard Worker &destroy_blob);
176*0a9764feSAndroid Build Coastguard Worker if (err != 0) {
177*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
178*0a9764feSAndroid Build Coastguard Worker err);
179*0a9764feSAndroid Build Coastguard Worker }
180*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
181*0a9764feSAndroid Build Coastguard Worker delete it;
182*0a9764feSAndroid Build Coastguard Worker });
183*0a9764feSAndroid Build Coastguard Worker }
184*0a9764feSAndroid Build Coastguard Worker
GetProperty(uint32_t obj_id,uint32_t obj_type,const char * prop_name,DrmProperty * property) const185*0a9764feSAndroid Build Coastguard Worker int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
186*0a9764feSAndroid Build Coastguard Worker const char *prop_name, DrmProperty *property) const {
187*0a9764feSAndroid Build Coastguard Worker drmModeObjectPropertiesPtr props = nullptr;
188*0a9764feSAndroid Build Coastguard Worker
189*0a9764feSAndroid Build Coastguard Worker props = drmModeObjectGetProperties(*GetFd(), obj_id, obj_type);
190*0a9764feSAndroid Build Coastguard Worker if (props == nullptr) {
191*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
192*0a9764feSAndroid Build Coastguard Worker return -ENODEV;
193*0a9764feSAndroid Build Coastguard Worker }
194*0a9764feSAndroid Build Coastguard Worker
195*0a9764feSAndroid Build Coastguard Worker bool found = false;
196*0a9764feSAndroid Build Coastguard Worker for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
197*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
198*0a9764feSAndroid Build Coastguard Worker drmModePropertyPtr p = drmModeGetProperty(*GetFd(), props->props[i]);
199*0a9764feSAndroid Build Coastguard Worker if (strcmp(p->name, prop_name) == 0) {
200*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
201*0a9764feSAndroid Build Coastguard Worker property->Init(obj_id, p, props->prop_values[i]);
202*0a9764feSAndroid Build Coastguard Worker found = true;
203*0a9764feSAndroid Build Coastguard Worker }
204*0a9764feSAndroid Build Coastguard Worker drmModeFreeProperty(p);
205*0a9764feSAndroid Build Coastguard Worker }
206*0a9764feSAndroid Build Coastguard Worker
207*0a9764feSAndroid Build Coastguard Worker drmModeFreeObjectProperties(props);
208*0a9764feSAndroid Build Coastguard Worker return found ? 0 : -ENOENT;
209*0a9764feSAndroid Build Coastguard Worker }
210*0a9764feSAndroid Build Coastguard Worker
GetName() const211*0a9764feSAndroid Build Coastguard Worker std::string DrmDevice::GetName() const {
212*0a9764feSAndroid Build Coastguard Worker auto *ver = drmGetVersion(*GetFd());
213*0a9764feSAndroid Build Coastguard Worker if (ver == nullptr) {
214*0a9764feSAndroid Build Coastguard Worker ALOGW("Failed to get drm version for fd=%d", *GetFd());
215*0a9764feSAndroid Build Coastguard Worker return "generic";
216*0a9764feSAndroid Build Coastguard Worker }
217*0a9764feSAndroid Build Coastguard Worker
218*0a9764feSAndroid Build Coastguard Worker std::string name(ver->name);
219*0a9764feSAndroid Build Coastguard Worker drmFreeVersion(ver);
220*0a9764feSAndroid Build Coastguard Worker return name;
221*0a9764feSAndroid Build Coastguard Worker }
222*0a9764feSAndroid Build Coastguard Worker
IsKMSDev(const char * path)223*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::IsKMSDev(const char *path) -> bool {
224*0a9764feSAndroid Build Coastguard Worker auto fd = MakeUniqueFd(open(path, O_RDWR | O_CLOEXEC));
225*0a9764feSAndroid Build Coastguard Worker if (!fd) {
226*0a9764feSAndroid Build Coastguard Worker return false;
227*0a9764feSAndroid Build Coastguard Worker }
228*0a9764feSAndroid Build Coastguard Worker
229*0a9764feSAndroid Build Coastguard Worker auto res = MakeDrmModeResUnique(*fd);
230*0a9764feSAndroid Build Coastguard Worker if (!res) {
231*0a9764feSAndroid Build Coastguard Worker return false;
232*0a9764feSAndroid Build Coastguard Worker }
233*0a9764feSAndroid Build Coastguard Worker
234*0a9764feSAndroid Build Coastguard Worker auto is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
235*0a9764feSAndroid Build Coastguard Worker res->count_encoders > 0;
236*0a9764feSAndroid Build Coastguard Worker
237*0a9764feSAndroid Build Coastguard Worker return is_kms;
238*0a9764feSAndroid Build Coastguard Worker }
239*0a9764feSAndroid Build Coastguard Worker
GetConnectors()240*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::GetConnectors()
241*0a9764feSAndroid Build Coastguard Worker -> const std::vector<std::unique_ptr<DrmConnector>> & {
242*0a9764feSAndroid Build Coastguard Worker return connectors_;
243*0a9764feSAndroid Build Coastguard Worker }
244*0a9764feSAndroid Build Coastguard Worker
GetWritebackConnectors()245*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::GetWritebackConnectors()
246*0a9764feSAndroid Build Coastguard Worker -> const std::vector<std::unique_ptr<DrmConnector>> & {
247*0a9764feSAndroid Build Coastguard Worker return writeback_connectors_;
248*0a9764feSAndroid Build Coastguard Worker }
249*0a9764feSAndroid Build Coastguard Worker
GetPlanes()250*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
251*0a9764feSAndroid Build Coastguard Worker return planes_;
252*0a9764feSAndroid Build Coastguard Worker }
253*0a9764feSAndroid Build Coastguard Worker
GetCrtcs()254*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
255*0a9764feSAndroid Build Coastguard Worker return crtcs_;
256*0a9764feSAndroid Build Coastguard Worker }
257*0a9764feSAndroid Build Coastguard Worker
GetEncoders()258*0a9764feSAndroid Build Coastguard Worker auto DrmDevice::GetEncoders()
259*0a9764feSAndroid Build Coastguard Worker -> const std::vector<std::unique_ptr<DrmEncoder>> & {
260*0a9764feSAndroid Build Coastguard Worker return encoders_;
261*0a9764feSAndroid Build Coastguard Worker }
262*0a9764feSAndroid Build Coastguard Worker
263*0a9764feSAndroid Build Coastguard Worker } // namespace android
264