1 /* 2 * Copyright (c) 2021 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 16 #include "drm_connector.h" 17 #include <xf86drm.h> 18 #include <xf86drmMode.h> 19 #include <cinttypes> 20 #include <securec.h> 21 #include "drm_device.h" 22 #include "drm_vsync_worker.h" 23 24 namespace OHOS { 25 namespace HDI { 26 namespace DISPLAY { ConvertToHdiMode(DisplayModeInfo &hdiMode)27 void DrmMode::ConvertToHdiMode(DisplayModeInfo &hdiMode) 28 { 29 hdiMode.height = mModeInfo.vdisplay; 30 hdiMode.width = mModeInfo.hdisplay; 31 hdiMode.freshRate = mModeInfo.vrefresh; 32 hdiMode.id = mId; 33 } 34 DrmConnector(drmModeConnector c, FdPtr &fd)35 DrmConnector::DrmConnector(drmModeConnector c, FdPtr &fd) 36 : mId(c.connector_id), mPhyWidth(c.mmWidth), mPhyHeight(c.mmHeight), mEncoderId(c.encoder_id), 37 mConnectState(c.connection), mDrmFdPtr(fd) 38 { 39 DISPLAY_DEBUGLOG("encoder_id %{public}d", mEncoderId); 40 DISPLAY_DEBUGLOG("the connect state is %{public}d", mConnectState); 41 42 for (int i = 0; i < c.count_encoders; i++) { 43 mPossibleEncoders.push_back(c.encoders[i]); 44 DISPLAY_DEBUGLOG("add possible encoder id %{public}d", c.encoders[i]); 45 } 46 47 ConvertToHdiType(c.connector_type, mType); 48 ConvertTypeToName(mType, mName); 49 InitModes(c); 50 DISPLAY_DEBUGLOG("name %{public}s", mName.c_str()); 51 } 52 InitModes(drmModeConnector c)53 void DrmConnector::InitModes(drmModeConnector c) 54 { 55 DISPLAY_DEBUGLOG("id %{public}d mode size %{public}d", mId, c.count_modes); 56 mModes.clear(); 57 mPreferenceId = INVALID_MODE_ID; 58 for (int i = 0; i < c.count_modes; i++) { 59 drmModeModeInfoPtr mode = c.modes + i; 60 DISPLAY_DEBUGLOG( 61 "mode: hdisplay %{public}d, vdisplay %{public}d vrefresh %{public}d type %{public}d", 62 mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->type); 63 if ((mPreferenceId == INVALID_MODE_ID) && (mode->type & DRM_MODE_TYPE_PREFERRED)) { 64 DISPLAY_DEBUGLOG("set it to prefernce id %{public}d", i); 65 mPreferenceId = i; 66 } 67 mModes.emplace(i, DrmMode {*mode, i}); 68 } 69 DISPLAY_DEBUGLOG("mode count %{public}zd", mModes.size()); 70 } 71 Init(DrmDevice &drmDevice)72 int32_t DrmConnector::Init(DrmDevice &drmDevice) 73 { 74 int32_t ret; 75 DrmProperty prop; 76 DISPLAY_DEBUGLOG(); 77 DISPLAY_CHK_RETURN((mDrmFdPtr == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("the mDrmFdPtr is NULL")); 78 DISPLAY_CHK_RETURN((mDrmFdPtr->GetFd() == -1), DISPLAY_FAILURE, DISPLAY_LOGE("the drm fd is -1")); 79 // find dpms prop 80 ret = drmDevice.GetConnectorProperty(*this, PROP_DPMS, prop); 81 DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("can not get mode prop id")); 82 mPropDpmsId = prop.propId; 83 mDpmsState = prop.value; 84 DISPLAY_DEBUGLOG("dpms state : %{public}" PRIu64 "", mDpmsState); 85 // find the crtcid 86 ret = drmDevice.GetConnectorProperty(*this, PROP_CRTCID, prop); 87 DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, 88 DISPLAY_LOGE("cat not get out fence prop id")); 89 mPropCrtcId = prop.propId; 90 DISPLAY_DEBUGLOG("encoder_id %{public}d", mEncoderId); 91 DISPLAY_DEBUGLOG("mPropCrtcId %{public}d", mPropCrtcId); 92 // find the brightness 93 ret = drmDevice.GetConnectorProperty(*this, PROP_BRIGHTNESS, prop); 94 if (ret == DISPLAY_SUCCESS) { 95 mPropBrightnessId = prop.propId; 96 mBrightnessLevel = static_cast<uint32_t>(prop.value); 97 DISPLAY_DEBUGLOG("prop brightness is %{public}d, level is %{public}d", mPropBrightnessId, 98 mBrightnessLevel); 99 } else { 100 DISPLAY_LOGW("can not get the brightness prop, can not set the brightness"); 101 } 102 return DISPLAY_SUCCESS; 103 } 104 GetBrightness(uint32_t &level)105 int32_t DrmConnector::GetBrightness(uint32_t &level) 106 { 107 if (mPropBrightnessId == DRM_INVALID_ID) { 108 DISPLAY_LOGE("the prop id of brightness is invalid"); 109 return DISPLAY_NOT_SUPPORT; 110 } 111 level = mBrightnessLevel; 112 return DISPLAY_SUCCESS; 113 } 114 SetBrightness(uint32_t level)115 int32_t DrmConnector::SetBrightness(uint32_t level) 116 { 117 static int32_t brFd = 0; 118 const int32_t buffer_size = 10; /* buffer size */ 119 char buffer[buffer_size]; 120 121 DISPLAY_DEBUGLOG("set %{public}d", level); 122 if (mPropBrightnessId == DRM_INVALID_ID) { 123 DISPLAY_LOGE("the prop id of brightness is invalid"); 124 return DISPLAY_NOT_SUPPORT; 125 } 126 if (brFd <= 0) { 127 brFd = open("/sys/class/backlight/backlight/brightness", O_RDWR); 128 if (brFd < 0) { 129 DISPLAY_LOGE("open brightness file failed\n"); 130 return DISPLAY_NOT_SUPPORT; 131 } 132 } 133 errno_t ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); 134 if (ret != EOK) { 135 DISPLAY_LOGE("memset_s failed\n"); 136 return DISPLAY_FAILURE; 137 } 138 int bytes = sprintf_s(buffer, sizeof(buffer), "%d\n", level); 139 if (bytes < 0) { 140 DISPLAY_LOGE("change failed\n"); 141 return DISPLAY_FAILURE; 142 } 143 write(brFd, buffer, bytes); 144 mBrightnessLevel = level; 145 return DISPLAY_SUCCESS; 146 } 147 GetDisplayCap(DisplayCapability &cap)148 void DrmConnector::GetDisplayCap(DisplayCapability &cap) 149 { 150 cap.phyHeight = mPhyHeight; 151 cap.phyWidth = mPhyWidth; 152 cap.type = mType; 153 memcpy_s(cap.name, sizeof(cap.name), mName.c_str(), mName.size()); 154 if (mName.size() >= sizeof(cap.name)) { 155 cap.name[sizeof(cap.name) - 1] = 0; 156 } else { 157 cap.name[mName.size()] = 0; 158 } 159 cap.supportLayers = mSupportLayers; 160 cap.virtualDispCount = mVirtualDispCount; 161 cap.supportWriteBack = mSupportWriteBack; 162 cap.propertyCount = mPropertyCount; 163 } 164 ConvertTypeToName(uint32_t type, std::string &name)165 void DrmConnector::ConvertTypeToName(uint32_t type, std::string &name) 166 { 167 DISPLAY_DEBUGLOG("type %{public}d", type); 168 switch (type) { 169 case DISP_INTF_VGA: 170 name = "VGA"; 171 break; 172 case DISP_INTF_HDMI: 173 name = "HDMI"; 174 break; 175 case DISP_INTF_MIPI: 176 name = "MIPI"; 177 break; 178 default: 179 name = "Unknown"; 180 break; 181 } 182 } 183 ConvertToHdiType(uint32_t type, InterfaceType &hdiType)184 void DrmConnector::ConvertToHdiType(uint32_t type, InterfaceType &hdiType) 185 { 186 switch (type) { 187 case DRM_MODE_CONNECTOR_VGA: 188 hdiType = DISP_INTF_VGA; 189 break; 190 case DRM_MODE_CONNECTOR_DSI: 191 hdiType = DISP_INTF_MIPI; 192 break; 193 case DRM_MODE_CONNECTOR_HDMIA: 194 case DRM_MODE_CONNECTOR_HDMIB: 195 hdiType = DISP_INTF_HDMI; 196 break; 197 default: 198 hdiType = DISP_INTF_BUTT; 199 break; 200 } 201 } TryPickEncoder(IdMapPtr<DrmEncoder> &encoders, uint32_t encoderId, IdMapPtr<DrmCrtc> &crtcs, uint32_t &crtcId)202 int32_t DrmConnector::TryPickEncoder(IdMapPtr<DrmEncoder> &encoders, uint32_t encoderId, 203 IdMapPtr<DrmCrtc> &crtcs, uint32_t &crtcId) 204 { 205 int ret; 206 auto encoderIter = encoders.find(encoderId); 207 if (encoderIter == encoders.end()) { 208 DISPLAY_LOGW("can not find encoder for id : %{public}d", encoderId); 209 return DISPLAY_FAILURE; 210 } 211 212 auto &encoder = encoderIter->second; 213 DISPLAY_DEBUGLOG("connector : %{public}d encoder : %{public}d", mId, encoder->GetId()); 214 ret = encoder->PickIdleCrtcId(crtcs, crtcId); 215 DISPLAY_CHK_RETURN( 216 (ret == DISPLAY_SUCCESS), DISPLAY_SUCCESS, 217 DISPLAY_DEBUGLOG("connector : %{public}d pick encoder : %{public}d", mId, encoder->GetId())); 218 return DISPLAY_FAILURE; 219 } 220 PickIdleCrtcId(IdMapPtr<DrmEncoder> &encoders, IdMapPtr<DrmCrtc> &crtcs, uint32_t &crtcId)221 int32_t DrmConnector::PickIdleCrtcId(IdMapPtr<DrmEncoder> &encoders, IdMapPtr<DrmCrtc> &crtcs, 222 uint32_t &crtcId) 223 { 224 DISPLAY_DEBUGLOG(); 225 DISPLAY_DEBUGLOG("encoder_id %{public}d", mEncoderId); 226 int ret = TryPickEncoder(encoders, mEncoderId, crtcs, crtcId); 227 DISPLAY_CHK_RETURN( 228 (ret == DISPLAY_SUCCESS), DISPLAY_SUCCESS, 229 DISPLAY_DEBUGLOG("connector : %{public}d pick endcoder : %{public}d crtcId : %{public}d", mId, 230 mEncoderId, crtcId)); 231 232 for (auto encoder : mPossibleEncoders) { 233 ret = TryPickEncoder(encoders, encoder, crtcs, crtcId); 234 DISPLAY_CHK_RETURN( 235 (ret == DISPLAY_SUCCESS), DISPLAY_SUCCESS, 236 DISPLAY_DEBUGLOG("connector : %{public}d pick endcoder : %{public}d crtcId : %{public}d", mId, 237 mEncoderId, crtcId)); 238 } 239 240 DISPLAY_LOGW("can not pick a crtc for connector"); 241 return DISPLAY_FAILURE; 242 } 243 UpdateModes()244 int32_t DrmConnector::UpdateModes() 245 { 246 int drmFd = mDrmFdPtr->GetFd(); 247 drmModeConnectorPtr c = drmModeGetConnector(drmFd, mId); 248 DISPLAY_CHK_RETURN((c == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("can not get connector")); 249 mConnectState = c->connection; 250 // init the modes 251 InitModes(*c); 252 drmModeFreeConnector(c); 253 return DISPLAY_SUCCESS; 254 } 255 UpdateCrtcId(IdMapPtr<DrmEncoder> &encoders, IdMapPtr<DrmCrtc> &crtcs, bool plugIn, drmModeConnectorPtr c, int *crtc_id)256 std::shared_ptr<DrmCrtc> DrmConnector::UpdateCrtcId(IdMapPtr<DrmEncoder> &encoders, 257 IdMapPtr<DrmCrtc> &crtcs, bool plugIn, 258 drmModeConnectorPtr c, int *crtc_id) 259 { 260 std::shared_ptr<DrmCrtc> crtc = nullptr; 261 int encoderid = c->encoders[0]; 262 auto encoderIter = encoders.find(encoderid); 263 if (encoderIter == encoders.end()) { 264 DISPLAY_LOGW("can not find encoder for id : %{public}d", encoderid); 265 return crtc; 266 } 267 268 auto &encoder = encoderIter->second; 269 int possibleCrtcs = encoder->GetPossibleCrtcs(); 270 271 for (auto crtcIter = crtcs.begin(); crtcIter != crtcs.end(); ++crtcIter) { 272 auto &posCrts = crtcIter->second; 273 if (possibleCrtcs == (1 << posCrts->GetPipe())) { 274 DISPLAY_DEBUGLOG("find crtc id %{public}d, pipe %{public}d", posCrts->GetId(), 275 posCrts->GetPipe()); 276 crtc = posCrts; 277 *crtc_id = posCrts->GetId(); 278 } 279 } 280 if (plugIn) { 281 encoder->SetCrtcId(*crtc_id); 282 mEncoderId = c->encoders[0]; 283 } else if (!plugIn) { 284 *crtc_id = 0; 285 mEncoderId = 0; 286 encoder->SetCrtcId(0); 287 } 288 return crtc; 289 } 290 HandleHotplug(IdMapPtr<DrmEncoder> &encoders, IdMapPtr<DrmCrtc> &crtcs, bool plugIn)291 bool DrmConnector::HandleHotplug(IdMapPtr<DrmEncoder> &encoders, IdMapPtr<DrmCrtc> &crtcs, bool plugIn) 292 { 293 DISPLAY_DEBUGLOG("plug %{public}d", plugIn); 294 int drmFd = mDrmFdPtr->GetFd(); 295 int ret; 296 int crtc_id = 0; 297 std::shared_ptr<DrmCrtc> crtc; 298 uint32_t blob_id; 299 drmModeAtomicReq *pset = drmModeAtomicAlloc(); 300 DISPLAY_CHK_RETURN((pset == nullptr), DISPLAY_NULL_PTR, 301 DISPLAY_LOGE("drm atomic alloc failed errno %{public}d", errno)); 302 303 drmModeConnectorPtr c = drmModeGetConnector(drmFd, mId); 304 DISPLAY_CHK_RETURN((c == nullptr), false, DISPLAY_LOGE("can not get connector")); 305 if (mConnectState == c->connection) { 306 drmModeFreeConnector(c); 307 return false; 308 } else { 309 crtc = UpdateCrtcId(encoders, crtcs, plugIn, c, &crtc_id); 310 if (crtc == nullptr) { 311 return DISPLAY_FAILURE; 312 } 313 DISPLAY_DEBUGLOG("get crtc id %{public}d ", crtc_id); 314 315 DrmVsyncWorker::GetInstance().EnableVsync(plugIn); 316 drmModeCreatePropertyBlob(drmFd, &c->modes[0], sizeof(c->modes[0]), &blob_id); 317 ret = drmModeAtomicAddProperty(pset, crtc->GetId(), crtc->GetActivePropId(), (int)plugIn); 318 ret |= drmModeAtomicAddProperty(pset, crtc->GetId(), crtc->GetModePropId(), blob_id); 319 ret |= drmModeAtomicAddProperty(pset, GetId(), GetPropCrtcId(), crtc_id); 320 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, 321 DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno)); 322 323 ret = drmModeAtomicCommit(drmFd, pset, DRM_MODE_ATOMIC_ALLOW_MODESET, nullptr); 324 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, 325 DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno)); 326 drmModeAtomicFree(pset); 327 328 mConnectState = c->connection; 329 InitModes(*c); 330 drmModeFreeConnector(c); 331 return true; 332 } 333 } 334 GetDisplaySupportedModes(uint32_t *num, DisplayModeInfo *modes)335 int32_t DrmConnector::GetDisplaySupportedModes(uint32_t *num, DisplayModeInfo *modes) 336 { 337 DISPLAY_CHK_RETURN((num == nullptr), DISPLAY_NULL_PTR, DISPLAY_LOGE("num is nullptr")); 338 *num = static_cast<int32_t>(mModes.size()); 339 if (modes != nullptr) { 340 int i = 0; 341 for (const auto &modeMap : mModes) { 342 DrmMode mode = modeMap.second; 343 mode.ConvertToHdiMode(*(modes + i)); 344 i++; 345 } 346 } 347 return DISPLAY_SUCCESS; 348 } 349 SetDpmsState(uint64_t dmps)350 int32_t DrmConnector::SetDpmsState(uint64_t dmps) 351 { 352 DISPLAY_DEBUGLOG("dmps %{public}" PRIu64 "", dmps); 353 int ret = drmModeConnectorSetProperty(mDrmFdPtr->GetFd(), mId, mPropDpmsId, dmps); 354 DISPLAY_CHK_RETURN((ret != 0), DISPLAY_FAILURE, DISPLAY_LOGE("can not set dpms")); 355 mDpmsState = dmps; 356 return DISPLAY_SUCCESS; 357 } 358 IsConnected()359 bool DrmConnector::IsConnected() 360 { 361 return (mConnectState == DRM_MODE_CONNECTED); 362 } 363 GetModeFromId(int32_t id, DrmMode &mode)364 int32_t DrmConnector::GetModeFromId(int32_t id, DrmMode &mode) 365 { 366 DISPLAY_DEBUGLOG(); 367 auto iter = mModes.find(id); 368 if (iter == mModes.end()) { 369 return DISPLAY_FAILURE; 370 } 371 mode = mModes[id]; 372 return DISPLAY_SUCCESS; 373 } 374 GetModeBlockFromId(int32_t id)375 std::unique_ptr<DrmModeBlock> DrmConnector::GetModeBlockFromId(int32_t id) 376 { 377 DISPLAY_DEBUGLOG("id %{public}d", id); 378 auto iter = mModes.find(id); 379 DISPLAY_CHK_RETURN((iter == mModes.end()), nullptr, DISPLAY_LOGE("can not the mode %{public}d", id)); 380 return std::make_unique<DrmModeBlock>(mModes[id]); 381 } 382 DrmModeBlock(DrmMode &mode)383 DrmModeBlock::DrmModeBlock(DrmMode &mode) 384 { 385 DISPLAY_DEBUGLOG(); 386 Init(mode); 387 } 388 Init(DrmMode &mode)389 int32_t DrmModeBlock::Init(DrmMode &mode) 390 { 391 int ret; 392 int drmFd = DrmDevice::GetDrmFd(); 393 DISPLAY_CHK_RETURN((drmFd < 0), DISPLAY_FAILURE, DISPLAY_LOGE("the drm fd is invalid")); 394 drmModeModeInfo modeInfo = *(mode.GetModeInfoPtr()); 395 ret = drmModeCreatePropertyBlob(drmFd, static_cast<void *>(&modeInfo), sizeof(modeInfo), &mBlockId); 396 DISPLAY_CHK_RETURN((ret != 0), DISPLAY_FAILURE, DISPLAY_LOGE("create property blob failed")); 397 DISPLAY_DEBUGLOG("mBlockId %{public}d", mBlockId); 398 return DISPLAY_SUCCESS; 399 } 400 ~DrmModeBlock()401 DrmModeBlock::~DrmModeBlock() 402 { 403 DISPLAY_DEBUGLOG("mBlockId %{public}d", mBlockId); 404 int drmFd = DrmDevice::GetDrmFd(); 405 if ((mBlockId != DRM_INVALID_ID) && (drmFd >= 0)) { 406 int ret = drmModeDestroyPropertyBlob(drmFd, mBlockId); 407 if (ret != 0) { 408 DISPLAY_LOGE("destroy property blob failed errno %{public}d", errno); 409 } 410 } else { 411 DISPLAY_LOGE("can not destruct the block id %{public}d drmFd %{public}d", mBlockId, drmFd); 412 } 413 } 414 } // namespace OHOS 415 } // namespace HDI 416 } // namespace DISPLAY 417