• 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 "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