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 23namespace Updater { 24void 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 31void DrmDriver::Blank(bool blank) 32{ 33 LOG(INFO) << "drm blank"; 34} 35 36void DrmDriver::Exit(void) 37{ 38 ModesetDestroyFb(&buff_); 39} 40 41void 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 49int 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 99drmModeCrtc *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 134drmModeConnector *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 151drmModeConnector *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 170drmModeConnector *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 208drmModeRes *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 221drmModeRes *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 264int 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 301bool 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 314void 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 342DrmDriver::~DrmDriver() 343{ 344 ModesetDestroyFb(&buff_); 345} 346} // namespace Updater 347