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