1 /*
2 * Copyright (c) 2021 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_common.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("hisilicon");
36 int drmFd = 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 }
117 drmModeFreeProperty(p);
118 }
119 drmModeFreeObjectProperties(props);
120 return found ? DISPLAY_SUCCESS : DISPLAY_NOT_SUPPORT;
121 }
122
Init()123 int32_t DrmDevice::Init()
124 {
125 int ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
126 DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE,
127 DISPLAY_LOGE("DRM_CLIENT_CAP_UNIVERSAL_PLANES set failed %{public}s", strerror(errno)));
128 ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_ATOMIC, 1);
129 DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE,
130 DISPLAY_LOGE("DRM_CLIENT_CAP_ATOMIC set failed %{public}s", strerror(errno)));
131
132 ret = drmSetMaster(GetDrmFd());
133 DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE, DISPLAY_LOGE("can not set to master errno : %{public}d", errno));
134
135 ret = drmIsMaster(GetDrmFd());
136 DISPLAY_CHK_RETURN((!ret), DISPLAY_FAILURE, DISPLAY_LOGE("is not master : %{public}d", errno));
137
138 return DISPLAY_SUCCESS;
139 }
140
DeInit()141 void DrmDevice::DeInit()
142 {
143 mDisplays.clear();
144 mCrtcs.clear();
145 }
146
FindAllCrtc(const drmModeResPtr & res)147 void DrmDevice::FindAllCrtc(const drmModeResPtr &res)
148 {
149 DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
150 mCrtcs.clear();
151 for (int i = 0; i < res->count_crtcs; i++) {
152 drmModeCrtcPtr crtc = drmModeGetCrtc(GetDrmFd(), res->crtcs[i]);
153 if (!crtc) {
154 DISPLAY_LOGE("can not get crtc %{public}d", i);
155 continue;
156 }
157 uint32_t crtc_id = crtc->crtc_id;
158 std::shared_ptr<DrmCrtc> drmCrtc = std::make_shared<DrmCrtc>(crtc, i);
159 int ret = drmCrtc->Init(*this);
160 drmModeFreeCrtc(crtc);
161 if (ret != DISPLAY_SUCCESS) {
162 DISPLAY_LOGE("crtc %{public}d init failed", i);
163 continue;
164 }
165 mCrtcs.emplace(crtc_id, std::move(drmCrtc));
166 }
167 }
168
FindAllEncoder(const drmModeResPtr & res)169 void DrmDevice::FindAllEncoder(const drmModeResPtr &res)
170 {
171 DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
172 mEncoders.clear();
173 for (int i = 0; i < res->count_encoders; i++) {
174 drmModeEncoderPtr encoder = drmModeGetEncoder(GetDrmFd(), res->encoders[i]);
175 if (!encoder) {
176 DISPLAY_LOGE("can not get encoder %{public}d", i);
177 continue;
178 }
179 std::shared_ptr<DrmEncoder> drmEncoder = std::make_shared<DrmEncoder>(*encoder);
180 mEncoders.emplace(encoder->encoder_id, std::move(drmEncoder));
181 drmModeFreeEncoder(encoder);
182 }
183 DISPLAY_LOGD("find encoder count %{public}zd", mEncoders.size());
184 }
185
FindAllConnector(const drmModeResPtr & res)186 void DrmDevice::FindAllConnector(const drmModeResPtr &res)
187 {
188 DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
189 mConnectors.clear();
190 int ret;
191 for (int i = 0; i < res->count_connectors; i++) {
192 drmModeConnectorPtr connector = drmModeGetConnector(GetDrmFd(), res->connectors[i]);
193 if (!connector) {
194 DISPLAY_LOGE("can not get connector mode %{public}d", i);
195 continue;
196 }
197 std::shared_ptr<DrmConnector> drmConnector = std::make_shared<DrmConnector>(*connector, mDrmFd);
198 ret = drmConnector->Init(*this);
199 drmModeFreeConnector(connector);
200 if (ret != DISPLAY_SUCCESS) {
201 continue;
202 }
203 int connectorId = drmConnector->GetId();
204 mConnectors.emplace(connectorId, std::move(drmConnector));
205 }
206 DISPLAY_LOGD("find connector count %{public}zd", mConnectors.size());
207 }
208
FindAllPlane()209 void DrmDevice::FindAllPlane()
210 {
211 mPlanes.clear();
212 int ret;
213 drmModePlaneResPtr planeRes = drmModeGetPlaneResources(GetDrmFd());
214 DISPLAY_CHK_RETURN_NOT_VALUE((planeRes == nullptr), DISPLAY_LOGE("can not get plane resource"));
215 DISPLAY_LOGD("count_planes %{public}d", planeRes->count_planes);
216 for (uint32_t i = 0; i < planeRes->count_planes; i++) {
217 drmModePlanePtr p = drmModeGetPlane(GetDrmFd(), planeRes->planes[i]);
218 if (!p) {
219 DISPLAY_LOGE("can not get plane %{public}d", i);
220 continue;
221 }
222 std::shared_ptr<DrmPlane> drmPlane = std::make_shared<DrmPlane>(*p);
223 DISPLAY_LOGD();
224 ret = drmPlane->Init(*this);
225 DISPLAY_LOGD();
226 drmModeFreePlane(p);
227 if (ret != DISPLAY_SUCCESS) {
228 DISPLAY_LOGE("drm plane %{public}d init failed", i);
229 continue;
230 }
231 mPlanes.emplace_back(std::move(drmPlane));
232 }
233 DISPLAY_LOGD("find plane count %{public}zd", mPlanes.size());
234 }
235
GetDrmEncoderFromId(uint32_t id)236 std::shared_ptr<DrmEncoder> DrmDevice::GetDrmEncoderFromId(uint32_t id)
237 {
238 auto iter = mEncoders.find(id);
239 if (iter != mEncoders.end()) {
240 return iter->second;
241 }
242 DISPLAY_LOGE("get drm encoder fail");
243 return nullptr;
244 }
245
GetDrmConnectorFromId(uint32_t id)246 std::shared_ptr<DrmConnector> DrmDevice::GetDrmConnectorFromId(uint32_t id)
247 {
248 auto iter = mConnectors.find(id);
249 if (iter != mConnectors.end()) {
250 return iter->second;
251 }
252 DISPLAY_LOGE("get drm connector fail");
253 return nullptr;
254 }
255
GetDrmCrtcFromId(uint32_t id)256 std::shared_ptr<DrmCrtc> DrmDevice::GetDrmCrtcFromId(uint32_t id)
257 {
258 auto iter = mCrtcs.find(id);
259 if (iter != mCrtcs.end()) {
260 return iter->second;
261 }
262 DISPLAY_LOGE("get drm crtc fail");
263 return nullptr;
264 }
265
GetDrmPlane(uint32_t pipe,uint32_t type)266 std::vector<std::shared_ptr<DrmPlane>> DrmDevice::GetDrmPlane(uint32_t pipe, uint32_t type)
267 {
268 std::vector<std::shared_ptr<DrmPlane>> planes;
269 for (const auto &plane : mPlanes) {
270 if (plane->IsIdle() && ((1 << pipe) & plane->GetPossibleCrtcs()) && (type == plane->GetType())) {
271 plane->BindToPipe(pipe);
272 planes.push_back(plane);
273 }
274 }
275 DISPLAY_LOGD("the planes count %{public}zd", planes.size());
276 return planes;
277 }
278
279
DiscoveryDisplay()280 std::unordered_map<uint32_t, std::shared_ptr<HdiDisplay>> DrmDevice::DiscoveryDisplay()
281 {
282 mDisplays.clear();
283 drmModeResPtr res = drmModeGetResources(GetDrmFd());
284 DISPLAY_CHK_RETURN((res == nullptr), mDisplays, DISPLAY_LOGE("can not get drm resource"));
285 // discovery all drm resource
286 FindAllCrtc(res);
287 FindAllEncoder(res);
288 FindAllConnector(res);
289 FindAllPlane();
290 DISPLAY_LOGD();
291 // travel all connector
292 for (const auto &connectorPair : mConnectors) {
293 auto connector = connectorPair.second;
294 uint32_t crtcId = 0;
295 int32_t ret = connector->PickIdleCrtcId(mEncoders, mCrtcs, crtcId);
296 if (ret != DISPLAY_SUCCESS) {
297 continue;
298 }
299 DISPLAY_LOGD();
300
301 auto crtcIter = mCrtcs.find(crtcId);
302 if (crtcIter == mCrtcs.end()) {
303 DISPLAY_LOGE("can not find crtc for the id %{public}d", connector->GetId());
304 continue;
305 }
306 DISPLAY_LOGD();
307 auto crtc = crtcIter->second;
308 // create the display
309 std::shared_ptr<HdiDisplay> display = std::make_shared<DrmDisplay>(connector, crtc, mInstance);
310 DISPLAY_LOGD();
311 display->Init();
312 mDisplays.emplace(display->GetId(), std::move(display));
313 }
314 DISPLAY_LOGD("find display size %{public}zd", mDisplays.size());
315 return mDisplays;
316 }
317 } // namespace OHOS
318 } // namespace HDI
319 } // namespace DISPLAY
320