1 /*
2 * Copyright (c) 2021-2022 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 #include "drm_driver.h"
16 #include <cstdio>
17 #include <unistd.h>
18 #include "log/log.h"
19 #include "securec.h"
20 #include "ui_rotation.h"
21 #include "updater_ui_const.h"
22
23 namespace Updater {
Flip(const uint8_t * buf)24 void DrmDriver::Flip(const uint8_t *buf)
25 {
26 if (buff_.vaddr != MAP_FAILED) {
27 UiRotation::GetInstance().RotateBuffer(buf, buff_.vaddr, buff_.size);
28 }
29 }
30
Blank(bool blank)31 void DrmDriver::Blank(bool blank)
32 {
33 LOG(INFO) << "drm blank";
34 }
35
Exit(void)36 void DrmDriver::Exit(void)
37 {
38 ModesetDestroyFb(&buff_);
39 }
40
GetGrSurface(GrSurface & surface)41 void DrmDriver::GetGrSurface(GrSurface &surface)
42 {
43 surface.width = static_cast<int>(buff_.width);
44 surface.height = static_cast<int>(buff_.height);
45 surface.rowBytes = 0;
46 surface.pixelBytes = 0;
47 }
48
ModesetCreateFb(struct BufferObject * bo)49 int DrmDriver::ModesetCreateFb(struct BufferObject *bo)
50 {
51 struct drm_mode_create_dumb create = {};
52 struct drm_mode_map_dumb map = {};
53 const int offsetNumber = 4;
54 uint32_t handles[offsetNumber] = {0};
55 uint32_t pitches[offsetNumber] = {0};
56 uint32_t offsets[offsetNumber] = {0};
57
58 /* create a dumb-buffer, the pixel format is XRGB888 */
59 const int pixelDepth = 32;
60 create.width = bo->width;
61 create.height = bo->height;
62 create.bpp = pixelDepth;
63 drmIoctl(fd_, DRM_IOCTL_MODE_CREATE_DUMB, &create);
64
65 /* bind the dumb-buffer to an FB object */
66 bo->pitch = create.pitch;
67 bo->size = create.size;
68 bo->handle = create.handle;
69
70 handles[0] = bo->handle;
71 pitches[0] = bo->pitch;
72 offsets[0] = 0;
73 int ret = drmModeAddFB2(fd_, bo->width, bo->height, DRM_FORMAT_ARGB8888, handles, pitches, offsets, &bo->fbId, 0);
74 if (ret) {
75 LOG(ERROR) << "[fbtest]failed to add fb (" << bo->width << "x" << bo->height << "): " << strerror(errno);
76 return -1;
77 }
78
79 /* map the dumb-buffer to userspace */
80 map.handle = create.handle;
81 drmIoctl(fd_, DRM_IOCTL_MODE_MAP_DUMB, &map);
82 bo->vaddr = static_cast<uint8_t *>(mmap(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, map.offset));
83 if (bo->vaddr == MAP_FAILED) {
84 LOG(ERROR) << "failed to mmap framebuffer";
85 return -1;
86 }
87 const uint32_t newColor = 0xff000000;
88 uint32_t i = 0;
89 uint32_t color = newColor;
90 while (i < bo->size) {
91 if (memcpy_s(&bo->vaddr[i], bo->size, &color, sizeof(color)) != EOK) {
92 return -1;
93 }
94 i += sizeof(color);
95 }
96 return 0;
97 }
98
GetCrtc(const drmModeRes & res,const int fd,const drmModeConnector & conn) const99 drmModeCrtc *DrmDriver::GetCrtc(const drmModeRes &res, const int fd, const drmModeConnector &conn) const
100 {
101 // if connector has one encoder, use it
102 drmModeEncoder *encoder = nullptr;
103 if (conn.encoder_id != 0) {
104 encoder = drmModeGetEncoder(fd, conn.encoder_id);
105 }
106 if (encoder != nullptr && encoder->crtc_id != 0) {
107 uint32_t crtcId = encoder->crtc_id;
108 drmModeFreeEncoder(encoder);
109 return drmModeGetCrtc(fd, crtcId);
110 }
111
112 if (encoder != nullptr) {
113 drmModeFreeEncoder(encoder);
114 }
115
116 // try get a vaild encoder and crtc
117 for (int i = 0; i < conn.count_encoders; i++) {
118 encoder = drmModeGetEncoder(fd, conn.encoders[i]);
119 if (encoder == nullptr) {
120 continue;
121 }
122
123 for (int j = 0; j < res.count_crtcs; j++) {
124 if ((encoder->possible_crtcs & (1u << static_cast<uint32_t>(j))) != 0) {
125 drmModeFreeEncoder(encoder);
126 return drmModeGetCrtc(fd, res.crtcs[j]);
127 }
128 }
129 drmModeFreeEncoder(encoder);
130 }
131 return nullptr;
132 }
133
GetFirstConnector(const drmModeRes & res,const int fd) const134 drmModeConnector *DrmDriver::GetFirstConnector(const drmModeRes &res, const int fd) const
135 {
136 // get connected connector
137 for (int i = 0; i < res.count_connectors; i++) {
138 drmModeConnector *conn = drmModeGetConnector(fd, res.connectors[i]);
139 if (conn == nullptr) {
140 continue;
141 }
142 if (conn->count_modes > 0 &&
143 conn->connection == DRM_MODE_CONNECTED) {
144 return conn;
145 }
146 drmModeFreeConnector(conn);
147 }
148 return nullptr;
149 }
150
GetConnectorByType(const drmModeRes & res,const int fd,const uint32_t type) const151 drmModeConnector *DrmDriver::GetConnectorByType(const drmModeRes &res, const int fd, const uint32_t type) const
152 {
153 // get connected connector
154 for (int i = 0; i < res.count_connectors; i++) {
155 drmModeConnector *conn = drmModeGetConnector(fd, res.connectors[i]);
156 if (conn == nullptr) {
157 continue;
158 }
159 if (conn->connector_type == type &&
160 conn->count_modes > 0 &&
161 conn->connection == DRM_MODE_CONNECTED) {
162 return conn;
163 }
164 drmModeFreeConnector(conn);
165 }
166 return nullptr;
167 }
168
169
GetConnector(const drmModeRes & res,const int fd,uint32_t & modeId) const170 drmModeConnector *DrmDriver::GetConnector(const drmModeRes &res, const int fd, uint32_t &modeId) const
171 {
172 // get main connector : lvds edp and dsi
173 uint32_t mainConnector[] = {
174 DRM_MODE_CONNECTOR_LVDS,
175 DRM_MODE_CONNECTOR_eDP,
176 DRM_MODE_CONNECTOR_DSI,
177 };
178
179 drmModeConnector *conn = nullptr;
180 for (uint32_t i = 0; i < sizeof(mainConnector) / sizeof(mainConnector[0]); i++) {
181 conn = GetConnectorByType(res, fd, mainConnector[i]);
182 if (conn != nullptr) {
183 break;
184 }
185 }
186
187 if (conn == nullptr) {
188 conn = GetFirstConnector(res, fd);
189 }
190
191 if (conn == nullptr) {
192 LOG(ERROR) << "DrmDriver cannot get vaild connector";
193 return nullptr;
194 }
195
196 // get preferred mode index
197 modeId = 0;
198 for (int i = 0; i < conn->count_modes; i++) {
199 if ((conn->modes[i].type & DRM_MODE_TYPE_PREFERRED) != 0) {
200 modeId = static_cast<uint32_t>(i);
201 break;
202 }
203 }
204
205 return conn;
206 }
207
GetResources(int & fd) const208 drmModeRes *DrmDriver::GetResources(int &fd) const
209 {
210 // 1: open drm resource
211 drmModeRes *res = nullptr;
212 for (int i = 0; i < DRM_MAX_MINOR; i++) {
213 res = GetOneResources(i, fd);
214 if (res != nullptr) {
215 break;
216 }
217 }
218 return res;
219 }
220
GetOneResources(const int devIndex,int & fd) const221 drmModeRes *DrmDriver::GetOneResources(const int devIndex, int &fd) const
222 {
223 // 1: open drm device
224 fd = -1;
225 std::string devName = std::string("/dev/dri/card") + std::to_string(devIndex);
226 int tmpFd = open(devName.c_str(), O_RDWR | O_CLOEXEC);
227 if (tmpFd < 0) {
228 LOG(ERROR) << "open failed " << devName;
229 return nullptr;
230 }
231 // 2: check drm capacity
232 uint64_t cap = 0;
233 int ret = drmGetCap(tmpFd, DRM_CAP_DUMB_BUFFER, &cap);
234 if (ret != 0 || cap == 0) {
235 LOG(ERROR) << "drmGetCap failed";
236 close(tmpFd);
237 return nullptr;
238 }
239
240 // 3: get drm resources
241 drmModeRes *res = drmModeGetResources(tmpFd);
242 if (res == nullptr) {
243 LOG(ERROR) << "drmModeGetResources failed";
244 close(tmpFd);
245 return nullptr;
246 }
247
248 // 4: check it has connected connector and crtc
249 if (res->count_crtcs > 0 && res->count_connectors > 0 && res->count_encoders > 0) {
250 drmModeConnector *conn = GetFirstConnector(*res, tmpFd);
251 if (conn != nullptr) {
252 // don't close fd
253 LOG(INFO) << "drm dev:" << devName;
254 drmModeFreeConnector(conn);
255 fd = tmpFd;
256 return res;
257 }
258 }
259 close(tmpFd);
260 drmModeFreeResources(res);
261 return nullptr;
262 }
263
DrmInit(void)264 int DrmDriver::DrmInit(void)
265 {
266 // 1: open drm resource
267 res_ = GetResources(fd_);
268 if (fd_ < 0 || res_ == nullptr) {
269 LOG(ERROR) << "DrmInit: GetResources failed";
270 return -1;
271 }
272
273 // 2 : get connected connector
274 uint32_t modeId;
275 conn_ = GetConnector(*res_, fd_, modeId);
276 if (conn_ == nullptr) {
277 LOG(ERROR) << "DrmInit: GetConnector failed";
278 return -1;
279 }
280
281 // 3: get vaild encoder and crtc
282 crtc_ = GetCrtc(*res_, fd_, *conn_);
283 if (crtc_ == nullptr) {
284 LOG(ERROR) << "DrmInit: GetCrtc failed";
285 return -1;
286 }
287
288 // 4: create userspace buffer
289 buff_.width = conn_->modes[modeId].hdisplay;
290 buff_.height = conn_->modes[modeId].vdisplay;
291 ModesetCreateFb(&buff_);
292
293 // 5: bind ctrc and connector
294 drmModeSetCrtc(fd_, crtc_->crtc_id, buff_.fbId, 0, 0, &conn_->connector_id, 1, &conn_->modes[modeId]);
295 LOG(INFO) << "DrmInit: buff_.width:" << buff_.width << " buff_.height:" << buff_.height;
296 LOG(INFO) << "DrmInit: crtc_id:" << crtc_->crtc_id << " connector_id:" << conn_->connector_id;
297 LOG(INFO) << " drm init success.";
298 return 0;
299 }
300
Init()301 bool DrmDriver::Init()
302 {
303 // this static variable can guarantee Init be called only once
304 static bool res = [this] () {
305 if (DrmInit() == -1) {
306 LOG(ERROR) << "load drm driver fail";
307 return false;
308 }
309 return true;
310 } ();
311 return res;
312 }
313
ModesetDestroyFb(struct BufferObject * bo)314 void DrmDriver::ModesetDestroyFb(struct BufferObject *bo)
315 {
316 if (fd_ > 0 && bo->fbId != 0) {
317 drmModeRmFB(fd_, bo->fbId);
318 }
319 if (bo->vaddr != MAP_FAILED) {
320 munmap(bo->vaddr, bo->size);
321 }
322 if (fd_ > 0) {
323 struct drm_mode_destroy_dumb destroy = {};
324 destroy.handle = bo->handle;
325 drmIoctl(fd_, DRM_IOCTL_GEM_CLOSE, &destroy);
326 }
327 if (crtc_ != nullptr) {
328 drmModeFreeCrtc(crtc_);
329 }
330 if (conn_ != nullptr) {
331 drmModeFreeConnector(conn_);
332 }
333 if (res_ != nullptr) {
334 drmModeFreeResources(res_);
335 }
336 if (fd_ > 0) {
337 close(fd_);
338 fd_ = -1;
339 }
340 }
341
~DrmDriver()342 DrmDriver::~DrmDriver()
343 {
344 ModesetDestroyFb(&buff_);
345 }
346 } // namespace Updater
347