1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "drm_device.h"
17 #include <string>
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <memory>
21 #include <drm_fourcc.h>
22 #include "display_log.h"
23 #include "drm_display.h"
24 
25 namespace OHOS {
26 namespace HDI {
27 namespace DISPLAY {
28 FdPtr DrmDevice::mDrmFd = nullptr;
29 std::shared_ptr<DrmDevice> DrmDevice::mInstance;
30 
Create()31 std::shared_ptr<HdiDeviceInterface> DrmDevice::Create()
32 {
33     DISPLAY_LOGD();
34     if (mDrmFd == nullptr) {
35         const std::string name("rockchip");
36         int drmFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); // drmOpen(name.c_str(), nullptr);
37         if (drmFd < 0) {
38             DISPLAY_LOGE("drm file:%{public}s open failed %{public}s", name.c_str(), strerror(errno));
39             return nullptr;
40         }
41         DISPLAY_LOGD("the drm fd is %{public}d", drmFd);
42         mDrmFd = std::make_shared<HdiFd>(drmFd);
43     }
44     if (mInstance == nullptr) {
45         mInstance = std::make_shared<DrmDevice>();
46     }
47     return mInstance;
48 }
49 
GetDrmFd()50 int DrmDevice::GetDrmFd()
51 {
52     if (mDrmFd == nullptr) {
53         DISPLAY_LOGE("the drmfd is null not open");
54         return -1;
55     }
56     return mDrmFd->GetFd();
57 }
58 
59 using PixelFormatConvertTbl = struct PixFmtConvertTbl {
60     uint32_t drmFormat;
61     PixelFormat pixFormat;
62 };
63 
ConvertToDrmFormat(PixelFormat fmtIn)64 uint32_t DrmDevice::ConvertToDrmFormat(PixelFormat fmtIn)
65 {
66     static const PixelFormatConvertTbl convertTable[] = {
67         {DRM_FORMAT_XBGR8888, PIXEL_FMT_RGBX_8888}, {DRM_FORMAT_ABGR8888, PIXEL_FMT_RGBA_8888},
68         {DRM_FORMAT_RGB888, PIXEL_FMT_RGB_888}, {DRM_FORMAT_RGB565, PIXEL_FMT_BGR_565},
69         {DRM_FORMAT_BGRX4444, PIXEL_FMT_BGRX_4444}, {DRM_FORMAT_BGRA4444, PIXEL_FMT_BGRA_4444},
70         {DRM_FORMAT_RGBA4444, PIXEL_FMT_RGBA_4444}, {DRM_FORMAT_RGBX4444, PIXEL_FMT_RGBX_4444},
71         {DRM_FORMAT_BGRX5551, PIXEL_FMT_BGRX_5551}, {DRM_FORMAT_BGRA5551, PIXEL_FMT_BGRA_5551},
72         {DRM_FORMAT_BGRX8888, PIXEL_FMT_BGRX_8888}, {DRM_FORMAT_ARGB8888, PIXEL_FMT_BGRA_8888},
73         {DRM_FORMAT_NV12, PIXEL_FMT_YCBCR_420_SP}, {DRM_FORMAT_NV21, PIXEL_FMT_YCRCB_420_SP},
74         {DRM_FORMAT_YUV420, PIXEL_FMT_YCBCR_420_P}, {DRM_FORMAT_YVU420, PIXEL_FMT_YCRCB_420_P},
75         {DRM_FORMAT_NV16, PIXEL_FMT_YCBCR_422_SP}, {DRM_FORMAT_NV61, PIXEL_FMT_YCRCB_422_SP},
76         {DRM_FORMAT_YUV422, PIXEL_FMT_YCBCR_422_P}, {DRM_FORMAT_YVU422, PIXEL_FMT_YCRCB_422_P},
77     };
78     uint32_t fmtOut = 0;
79     for (uint32_t i = 0; i < sizeof(convertTable) / sizeof(convertTable[0]); i++) {
80         if (convertTable[i].pixFormat == fmtIn) {
81             fmtOut = convertTable[i].drmFormat;
82         }
83     }
84     DISPLAY_LOGD("fmtIn %{public}d, outFmt %{public}d", fmtIn, fmtOut);
85     return fmtOut;
86 }
87 
DrmDevice()88 DrmDevice::DrmDevice() {}
89 
GetCrtcProperty(const DrmCrtc & crtc,const std::string & name,DrmProperty & prop)90 int32_t DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const std::string &name, DrmProperty &prop)
91 {
92     return GetProperty(crtc.GetId(), DRM_MODE_OBJECT_CRTC, name, prop);
93 }
94 
GetConnectorProperty(const DrmConnector & connector,const std::string & name,DrmProperty & prop)95 int32_t DrmDevice::GetConnectorProperty(const DrmConnector &connector, const std::string &name, DrmProperty &prop)
96 {
97     return GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR, name, prop);
98 }
99 
GetPlaneProperty(const DrmPlane & plane,const std::string & name,DrmProperty & prop)100 int32_t DrmDevice::GetPlaneProperty(const DrmPlane &plane, const std::string &name, DrmProperty &prop)
101 {
102     return GetProperty(plane.GetId(), DRM_MODE_OBJECT_PLANE, name, prop);
103 }
104 
GetProperty(uint32_t objId,uint32_t objType,const std::string & name,DrmProperty & prop)105 int32_t DrmDevice::GetProperty(uint32_t objId, uint32_t objType, const std::string &name, DrmProperty &prop)
106 {
107     drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(GetDrmFd(), objId, objType);
108     DISPLAY_CHK_RETURN((!props), DISPLAY_FAILURE, DISPLAY_LOGE("can not get properties"));
109     bool found = false;
110     for (uint32_t i = 0; i < props->count_props; i++) {
111         drmModePropertyPtr p = drmModeGetProperty(GetDrmFd(), props->props[i]);
112         if (strcmp(p->name, name.c_str()) == 0) {
113             found = true;
114             prop.propId = p->prop_id;
115             prop.value = props->prop_values[i];
116             prop.name = p->name;
117             prop.flags = p->flags;
118 
119             for (int i = 0; i < p->count_values; ++i) {
120                 prop.values.push_back(p->values[i]);
121             }
122             for (int i = 0; i < p->count_enums; ++i) {
123                 prop.enums.push_back(DrmPropertyEnum(&p->enums[i]));
124             }
125 
126             for (int i = 0; i < p->count_blobs; ++i) {
127                 prop.blob_ids.push_back(p->blob_ids[i]);
128             }
129             if (prop.flags & DRM_MODE_PROP_RANGE) {
130                 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_INT);
131             } else if (prop.flags & DRM_MODE_PROP_ENUM) {
132                 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_ENUM);
133             } else if (prop.flags & DRM_MODE_PROP_OBJECT) {
134                 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_OBJECT);
135             } else if (prop.flags & DRM_MODE_PROP_BLOB) {
136                 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_BLOB);
137             } else if (prop.flags & DRM_MODE_PROP_BITMASK) {
138                 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_BITMASK);
139             }
140         }
141         drmModeFreeProperty(p);
142     }
143     drmModeFreeObjectProperties(props);
144     return found ? DISPLAY_SUCCESS : DISPLAY_NOT_SUPPORT;
145 }
146 
Init()147 int32_t DrmDevice::Init()
148 {
149     int ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
150     DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE,
151         DISPLAY_LOGE("DRM_CLIENT_CAP_UNIVERSAL_PLANES set failed %{public}s", strerror(errno)));
152     ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_ATOMIC, 1);
153     DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE,
154         DISPLAY_LOGE("DRM_CLIENT_CAP_ATOMIC set failed %{public}s", strerror(errno)));
155 
156     ret = drmSetMaster(GetDrmFd());
157     DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE, DISPLAY_LOGE("can not set to master errno : %{public}d", errno));
158     DISPLAY_LOGE("chenyf master");
159     ret = drmIsMaster(GetDrmFd());
160     DISPLAY_CHK_RETURN((!ret), DISPLAY_FAILURE, DISPLAY_LOGE("is not master : %{public}d", errno));
161 
162     return DISPLAY_SUCCESS;
163 }
164 
DeInit()165 void DrmDevice::DeInit()
166 {
167     mDisplays.clear();
168     mCrtcs.clear();
169 }
170 
FindAllCrtc(const drmModeResPtr & res)171 void DrmDevice::FindAllCrtc(const drmModeResPtr &res)
172 {
173     DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
174     mCrtcs.clear();
175     for (int i = 0; i < res->count_crtcs; i++) {
176         drmModeCrtcPtr crtc = drmModeGetCrtc(GetDrmFd(), res->crtcs[i]);
177         if (!crtc) {
178             DISPLAY_LOGE("can not get crtc %{public}d", i);
179             continue;
180         }
181         uint32_t crtc_id = crtc->crtc_id;
182         std::shared_ptr<DrmCrtc> drmCrtc = std::make_shared<DrmCrtc>(crtc, i);
183         int ret = drmCrtc->Init(*this);
184         drmModeFreeCrtc(crtc);
185         if (ret != DISPLAY_SUCCESS) {
186             DISPLAY_LOGE("crtc %{public}d init failed", i);
187             continue;
188         }
189         mCrtcs.emplace(crtc_id, std::move(drmCrtc));
190     }
191 }
192 
FindAllEncoder(const drmModeResPtr & res)193 void DrmDevice::FindAllEncoder(const drmModeResPtr &res)
194 {
195     DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
196     mEncoders.clear();
197     for (int i = 0; i < res->count_encoders; i++) {
198         drmModeEncoderPtr encoder = drmModeGetEncoder(GetDrmFd(), res->encoders[i]);
199         if (!encoder) {
200             DISPLAY_LOGE("can not get encoder %{public}d", i);
201             continue;
202         }
203         std::shared_ptr<DrmEncoder> drmEncoder = std::make_shared<DrmEncoder>(*encoder);
204         mEncoders.emplace(encoder->encoder_id, std::move(drmEncoder));
205         drmModeFreeEncoder(encoder);
206     }
207     DISPLAY_LOGD("find encoder count %{public}zd", mEncoders.size());
208 }
209 
FindAllConnector(const drmModeResPtr & res)210 void DrmDevice::FindAllConnector(const drmModeResPtr &res)
211 {
212     DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
213     mConnectors.clear();
214     int ret;
215     for (int i = 0; i < res->count_connectors; i++) {
216         drmModeConnectorPtr connector = drmModeGetConnector(GetDrmFd(), res->connectors[i]);
217         if (!connector) {
218             DISPLAY_LOGE("can not get connector mode %{public}d", i);
219             continue;
220         }
221         std::shared_ptr<DrmConnector> drmConnector = std::make_shared<DrmConnector>(*connector, mDrmFd);
222         ret = drmConnector->Init(*this);
223         drmModeFreeConnector(connector);
224         if (ret != DISPLAY_SUCCESS) {
225             continue;
226         }
227         int connectorId = drmConnector->GetId();
228         mConnectors.emplace(connectorId, std::move(drmConnector));
229     }
230     DISPLAY_LOGD("find connector count %{public}zd", mConnectors.size());
231 }
232 
FindAllPlane()233 void DrmDevice::FindAllPlane()
234 {
235     mPlanes.clear();
236     int ret;
237     drmModePlaneResPtr planeRes = drmModeGetPlaneResources(GetDrmFd());
238     DISPLAY_CHK_RETURN_NOT_VALUE((planeRes == nullptr), DISPLAY_LOGE("can not get plane resource"));
239     DISPLAY_LOGD("count_planes %{public}d", planeRes->count_planes);
240     for (uint32_t i = 0; i < planeRes->count_planes; i++) {
241         drmModePlanePtr p = drmModeGetPlane(GetDrmFd(), planeRes->planes[i]);
242         if (!p) {
243             DISPLAY_LOGE("can not get plane %{public}d", i);
244             continue;
245         }
246         std::shared_ptr<DrmPlane> drmPlane = std::make_shared<DrmPlane>(*p);
247         DISPLAY_LOGD();
248         ret = drmPlane->Init(*this);
249         DISPLAY_LOGD();
250         drmModeFreePlane(p);
251         if (ret != DISPLAY_SUCCESS) {
252             DISPLAY_LOGE("drm plane %{public}d init failed", i);
253             continue;
254         }
255         mPlanes.emplace_back(std::move(drmPlane));
256     }
257     DISPLAY_LOGD("find plane count %{public}zd", mPlanes.size());
258 }
259 
GetDrmEncoderFromId(uint32_t id)260 std::shared_ptr<DrmEncoder> DrmDevice::GetDrmEncoderFromId(uint32_t id)
261 {
262     return nullptr;
263 }
264 
GetDrmConnectorFromId(uint32_t id)265 std::shared_ptr<DrmConnector> DrmDevice::GetDrmConnectorFromId(uint32_t id)
266 {
267     return nullptr;
268 }
269 
GetDrmCrtcFromId(uint32_t id)270 std::shared_ptr<DrmCrtc> DrmDevice::GetDrmCrtcFromId(uint32_t id)
271 {
272     return nullptr;
273 }
274 
GetDrmPlane(uint32_t pipe,uint32_t type)275 std::vector<std::shared_ptr<DrmPlane>> DrmDevice::GetDrmPlane(uint32_t pipe, uint32_t type)
276 {
277     std::vector<std::shared_ptr<DrmPlane>> planes;
278     for (const auto &plane : mPlanes) {
279         if (plane->IsIdle() && ((1 << pipe) & plane->GetPossibleCrtcs()) && (type == plane->GetType())) {
280             planes.push_back(plane);
281         }
282     }
283     DISPLAY_LOGD("the planes count %{public}zd", planes.size());
284     return planes;
285 }
286 
HandleHotplug(uint32_t dispId,bool plugIn)287 bool DrmDevice::HandleHotplug(uint32_t dispId, bool plugIn)
288 {
289     uint32_t find = 0;
290     uint32_t connectorId;
291 
292     for (auto &dispConnectorIdMap : dispConnectorIdMaps_) {
293         if (dispConnectorIdMap.first == dispId) {
294             connectorId = dispConnectorIdMap.second;
295             find = 1;
296             break;
297         }
298     }
299 
300     if (find == 0) {
301         return false;
302     }
303 
304     for (auto &connectorPair : mConnectors) {
305         auto connector = connectorPair.second;
306         if (connectorId == connector->GetId()) {
307             if (connector->HandleHotplug(mEncoders, mCrtcs, plugIn) == true) {
308                 connector->Init(*this);
309                 return true;
310             }
311         }
312     }
313     return false;
314 }
315 
DiscoveryDisplay()316 std::unordered_map<uint32_t, std::shared_ptr<HdiDisplay>> DrmDevice::DiscoveryDisplay()
317 {
318     uint32_t dispId;
319     uint32_t connectorId;
320 
321     dispConnectorIdMaps_.clear();
322     mDisplays.clear();
323     drmModeResPtr res = drmModeGetResources(GetDrmFd());
324     DISPLAY_CHK_RETURN((res == nullptr), mDisplays, DISPLAY_LOGE("can not get drm resource"));
325     // discovery all drm resource
326     FindAllCrtc(res);
327     FindAllEncoder(res);
328     FindAllConnector(res);
329     FindAllPlane();
330     DISPLAY_LOGD();
331     // travel all connector
332     for (auto &connectorPair : mConnectors) {
333         auto connector = connectorPair.second;
334         uint32_t crtcId = 0;
335         int32_t ret = connector->PickIdleCrtcId(mEncoders, mCrtcs, crtcId);
336         if (ret != DISPLAY_SUCCESS) {
337             continue;
338         }
339         DISPLAY_LOGD();
340 
341         auto crtcIter = mCrtcs.find(crtcId);
342         if (crtcIter == mCrtcs.end()) {
343             DISPLAY_LOGE("can not find crtc for the id %{public}d", connector->GetId());
344             continue;
345         }
346         DISPLAY_LOGD();
347         auto crtc = crtcIter->second;
348         // create the display
349         std::shared_ptr<HdiDisplay> display = std::make_shared<DrmDisplay>(connector, crtc, mInstance);
350         DISPLAY_LOGD();
351         display->Init();
352         dispId = display->GetId();
353         connectorId = connector->GetId();
354         mDisplays.emplace(dispId, std::move(display));
355         dispConnectorIdMaps_.emplace(dispId, connectorId);
356     }
357     DISPLAY_LOGD("find display size %{public}zd", mDisplays.size());
358     return mDisplays;
359 }
360 } // namespace OHOS
361 } // namespace HDI
362 } // namespace DISPLAY
363