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