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