xref: /aosp_15_r20/external/drm_hwcomposer/drm/DrmDevice.cpp (revision 0a9764fe0a15e71ebbeb85e87e10990c23aab47f)
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