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