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_device.h" 17#include <string> 18#include <cerrno> 19#include <fcntl.h> 20#include <memory> 21#include <drm_fourcc.h> 22#include "display_log.h" 23#include "drm_display.h" 24 25namespace OHOS { 26namespace HDI { 27namespace DISPLAY { 28FdPtr DrmDevice::mDrmFd = nullptr; 29std::shared_ptr<DrmDevice> DrmDevice::mInstance; 30 31std::shared_ptr<HdiDeviceInterface> DrmDevice::Create() 32{ 33 DISPLAY_LOGD(); 34 if (mDrmFd == nullptr) { 35 const std::string name("rockchip"); 36 int drmFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); // drmOpen(name.c_str(), nullptr); 37 if (drmFd < 0) { 38 DISPLAY_LOGE("drm file:%{public}s open failed %{public}s", name.c_str(), strerror(errno)); 39 return nullptr; 40 } 41 DISPLAY_LOGD("the drm fd is %{public}d", drmFd); 42 mDrmFd = std::make_shared<HdiFd>(drmFd); 43 } 44 if (mInstance == nullptr) { 45 mInstance = std::make_shared<DrmDevice>(); 46 } 47 return mInstance; 48} 49 50int DrmDevice::GetDrmFd() 51{ 52 if (mDrmFd == nullptr) { 53 DISPLAY_LOGE("the drmfd is null not open"); 54 return -1; 55 } 56 return mDrmFd->GetFd(); 57} 58 59using PixelFormatConvertTbl = struct PixFmtConvertTbl { 60 uint32_t drmFormat; 61 PixelFormat pixFormat; 62}; 63 64uint32_t DrmDevice::ConvertToDrmFormat(PixelFormat fmtIn) 65{ 66 static const PixelFormatConvertTbl convertTable[] = { 67 {DRM_FORMAT_XBGR8888, PIXEL_FMT_RGBX_8888}, {DRM_FORMAT_ABGR8888, PIXEL_FMT_RGBA_8888}, 68 {DRM_FORMAT_RGB888, PIXEL_FMT_RGB_888}, {DRM_FORMAT_RGB565, PIXEL_FMT_BGR_565}, 69 {DRM_FORMAT_BGRX4444, PIXEL_FMT_BGRX_4444}, {DRM_FORMAT_BGRA4444, PIXEL_FMT_BGRA_4444}, 70 {DRM_FORMAT_RGBA4444, PIXEL_FMT_RGBA_4444}, {DRM_FORMAT_RGBX4444, PIXEL_FMT_RGBX_4444}, 71 {DRM_FORMAT_BGRX5551, PIXEL_FMT_BGRX_5551}, {DRM_FORMAT_BGRA5551, PIXEL_FMT_BGRA_5551}, 72 {DRM_FORMAT_BGRX8888, PIXEL_FMT_BGRX_8888}, {DRM_FORMAT_ARGB8888, PIXEL_FMT_BGRA_8888}, 73 {DRM_FORMAT_NV12, PIXEL_FMT_YCBCR_420_SP}, {DRM_FORMAT_NV21, PIXEL_FMT_YCRCB_420_SP}, 74 {DRM_FORMAT_YUV420, PIXEL_FMT_YCBCR_420_P}, {DRM_FORMAT_YVU420, PIXEL_FMT_YCRCB_420_P}, 75 {DRM_FORMAT_NV16, PIXEL_FMT_YCBCR_422_SP}, {DRM_FORMAT_NV61, PIXEL_FMT_YCRCB_422_SP}, 76 {DRM_FORMAT_YUV422, PIXEL_FMT_YCBCR_422_P}, {DRM_FORMAT_YVU422, PIXEL_FMT_YCRCB_422_P}, 77 }; 78 uint32_t fmtOut = 0; 79 for (uint32_t i = 0; i < sizeof(convertTable) / sizeof(convertTable[0]); i++) { 80 if (convertTable[i].pixFormat == fmtIn) { 81 fmtOut = convertTable[i].drmFormat; 82 } 83 } 84 DISPLAY_LOGD("fmtIn %{public}d, outFmt %{public}d", fmtIn, fmtOut); 85 return fmtOut; 86} 87 88DrmDevice::DrmDevice() {} 89 90int32_t DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const std::string &name, DrmProperty &prop) 91{ 92 return GetProperty(crtc.GetId(), DRM_MODE_OBJECT_CRTC, name, prop); 93} 94 95int32_t DrmDevice::GetConnectorProperty(const DrmConnector &connector, const std::string &name, DrmProperty &prop) 96{ 97 return GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR, name, prop); 98} 99 100int32_t DrmDevice::GetPlaneProperty(const DrmPlane &plane, const std::string &name, DrmProperty &prop) 101{ 102 return GetProperty(plane.GetId(), DRM_MODE_OBJECT_PLANE, name, prop); 103} 104 105int32_t DrmDevice::GetProperty(uint32_t objId, uint32_t objType, const std::string &name, DrmProperty &prop) 106{ 107 drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(GetDrmFd(), objId, objType); 108 DISPLAY_CHK_RETURN((!props), DISPLAY_FAILURE, DISPLAY_LOGE("can not get properties")); 109 bool found = false; 110 for (uint32_t i = 0; i < props->count_props; i++) { 111 drmModePropertyPtr p = drmModeGetProperty(GetDrmFd(), props->props[i]); 112 if (strcmp(p->name, name.c_str()) == 0) { 113 found = true; 114 prop.propId = p->prop_id; 115 prop.value = props->prop_values[i]; 116 prop.name = p->name; 117 prop.flags = p->flags; 118 119 for (int i = 0; i < p->count_values; ++i) { 120 prop.values.push_back(p->values[i]); 121 } 122 for (int i = 0; i < p->count_enums; ++i) { 123 prop.enums.push_back(DrmPropertyEnum(&p->enums[i])); 124 } 125 126 for (int i = 0; i < p->count_blobs; ++i) { 127 prop.blob_ids.push_back(p->blob_ids[i]); 128 } 129 if (prop.flags & DRM_MODE_PROP_RANGE) { 130 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_INT); 131 } else if (prop.flags & DRM_MODE_PROP_ENUM) { 132 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_ENUM); 133 } else if (prop.flags & DRM_MODE_PROP_OBJECT) { 134 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_OBJECT); 135 } else if (prop.flags & DRM_MODE_PROP_BLOB) { 136 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_BLOB); 137 } else if (prop.flags & DRM_MODE_PROP_BITMASK) { 138 prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_BITMASK); 139 } 140 } 141 drmModeFreeProperty(p); 142 } 143 drmModeFreeObjectProperties(props); 144 return found ? DISPLAY_SUCCESS : DISPLAY_NOT_SUPPORT; 145} 146 147int32_t DrmDevice::Init() 148{ 149 int ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); 150 DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE, 151 DISPLAY_LOGE("DRM_CLIENT_CAP_UNIVERSAL_PLANES set failed %{public}s", strerror(errno))); 152 ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_ATOMIC, 1); 153 DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE, 154 DISPLAY_LOGE("DRM_CLIENT_CAP_ATOMIC set failed %{public}s", strerror(errno))); 155 156 ret = drmSetMaster(GetDrmFd()); 157 DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE, DISPLAY_LOGE("can not set to master errno : %{public}d", errno)); 158 DISPLAY_LOGE("chenyf master"); 159 ret = drmIsMaster(GetDrmFd()); 160 DISPLAY_CHK_RETURN((!ret), DISPLAY_FAILURE, DISPLAY_LOGE("is not master : %{public}d", errno)); 161 162 return DISPLAY_SUCCESS; 163} 164 165void DrmDevice::DeInit() 166{ 167 mDisplays.clear(); 168 mCrtcs.clear(); 169} 170 171void DrmDevice::FindAllCrtc(const drmModeResPtr &res) 172{ 173 DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null")); 174 mCrtcs.clear(); 175 for (int i = 0; i < res->count_crtcs; i++) { 176 drmModeCrtcPtr crtc = drmModeGetCrtc(GetDrmFd(), res->crtcs[i]); 177 if (!crtc) { 178 DISPLAY_LOGE("can not get crtc %{public}d", i); 179 continue; 180 } 181 uint32_t crtc_id = crtc->crtc_id; 182 std::shared_ptr<DrmCrtc> drmCrtc = std::make_shared<DrmCrtc>(crtc, i); 183 int ret = drmCrtc->Init(*this); 184 drmModeFreeCrtc(crtc); 185 if (ret != DISPLAY_SUCCESS) { 186 DISPLAY_LOGE("crtc %{public}d init failed", i); 187 continue; 188 } 189 mCrtcs.emplace(crtc_id, std::move(drmCrtc)); 190 } 191} 192 193void DrmDevice::FindAllEncoder(const drmModeResPtr &res) 194{ 195 DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null")); 196 mEncoders.clear(); 197 for (int i = 0; i < res->count_encoders; i++) { 198 drmModeEncoderPtr encoder = drmModeGetEncoder(GetDrmFd(), res->encoders[i]); 199 if (!encoder) { 200 DISPLAY_LOGE("can not get encoder %{public}d", i); 201 continue; 202 } 203 std::shared_ptr<DrmEncoder> drmEncoder = std::make_shared<DrmEncoder>(*encoder); 204 mEncoders.emplace(encoder->encoder_id, std::move(drmEncoder)); 205 drmModeFreeEncoder(encoder); 206 } 207 DISPLAY_LOGD("find encoder count %{public}zd", mEncoders.size()); 208} 209 210void DrmDevice::FindAllConnector(const drmModeResPtr &res) 211{ 212 DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null")); 213 mConnectors.clear(); 214 int ret; 215 for (int i = 0; i < res->count_connectors; i++) { 216 drmModeConnectorPtr connector = drmModeGetConnector(GetDrmFd(), res->connectors[i]); 217 if (!connector) { 218 DISPLAY_LOGE("can not get connector mode %{public}d", i); 219 continue; 220 } 221 std::shared_ptr<DrmConnector> drmConnector = std::make_shared<DrmConnector>(*connector, mDrmFd); 222 ret = drmConnector->Init(*this); 223 drmModeFreeConnector(connector); 224 if (ret != DISPLAY_SUCCESS) { 225 continue; 226 } 227 int connectorId = drmConnector->GetId(); 228 mConnectors.emplace(connectorId, std::move(drmConnector)); 229 } 230 DISPLAY_LOGD("find connector count %{public}zd", mConnectors.size()); 231} 232 233void DrmDevice::FindAllPlane() 234{ 235 mPlanes.clear(); 236 int ret; 237 drmModePlaneResPtr planeRes = drmModeGetPlaneResources(GetDrmFd()); 238 DISPLAY_CHK_RETURN_NOT_VALUE((planeRes == nullptr), DISPLAY_LOGE("can not get plane resource")); 239 DISPLAY_LOGD("count_planes %{public}d", planeRes->count_planes); 240 for (uint32_t i = 0; i < planeRes->count_planes; i++) { 241 drmModePlanePtr p = drmModeGetPlane(GetDrmFd(), planeRes->planes[i]); 242 if (!p) { 243 DISPLAY_LOGE("can not get plane %{public}d", i); 244 continue; 245 } 246 std::shared_ptr<DrmPlane> drmPlane = std::make_shared<DrmPlane>(*p); 247 DISPLAY_LOGD(); 248 ret = drmPlane->Init(*this); 249 DISPLAY_LOGD(); 250 drmModeFreePlane(p); 251 if (ret != DISPLAY_SUCCESS) { 252 DISPLAY_LOGE("drm plane %{public}d init failed", i); 253 continue; 254 } 255 mPlanes.emplace_back(std::move(drmPlane)); 256 } 257 DISPLAY_LOGD("find plane count %{public}zd", mPlanes.size()); 258} 259 260std::shared_ptr<DrmEncoder> DrmDevice::GetDrmEncoderFromId(uint32_t id) 261{ 262 return nullptr; 263} 264 265std::shared_ptr<DrmConnector> DrmDevice::GetDrmConnectorFromId(uint32_t id) 266{ 267 return nullptr; 268} 269 270std::shared_ptr<DrmCrtc> DrmDevice::GetDrmCrtcFromId(uint32_t id) 271{ 272 return nullptr; 273} 274 275std::vector<std::shared_ptr<DrmPlane>> DrmDevice::GetDrmPlane(uint32_t pipe, uint32_t type) 276{ 277 std::vector<std::shared_ptr<DrmPlane>> planes; 278 for (const auto &plane : mPlanes) { 279 if (plane->IsIdle() && ((1 << pipe) & plane->GetPossibleCrtcs()) && (type == plane->GetType())) { 280 planes.push_back(plane); 281 } 282 } 283 DISPLAY_LOGD("the planes count %{public}zd", planes.size()); 284 return planes; 285} 286 287bool DrmDevice::HandleHotplug(uint32_t dispId, bool plugIn) 288{ 289 uint32_t find = 0; 290 uint32_t connectorId; 291 292 for (auto &dispConnectorIdMap : dispConnectorIdMaps_) { 293 if (dispConnectorIdMap.first == dispId) { 294 connectorId = dispConnectorIdMap.second; 295 find = 1; 296 break; 297 } 298 } 299 300 if (find == 0) { 301 return false; 302 } 303 304 for (auto &connectorPair : mConnectors) { 305 auto connector = connectorPair.second; 306 if (connectorId == connector->GetId()) { 307 if (connector->HandleHotplug(mEncoders, mCrtcs, plugIn) == true) { 308 connector->Init(*this); 309 return true; 310 } 311 } 312 } 313 return false; 314} 315 316std::unordered_map<uint32_t, std::shared_ptr<HdiDisplay>> DrmDevice::DiscoveryDisplay() 317{ 318 uint32_t dispId; 319 uint32_t connectorId; 320 321 dispConnectorIdMaps_.clear(); 322 mDisplays.clear(); 323 drmModeResPtr res = drmModeGetResources(GetDrmFd()); 324 DISPLAY_CHK_RETURN((res == nullptr), mDisplays, DISPLAY_LOGE("can not get drm resource")); 325 // discovery all drm resource 326 FindAllCrtc(res); 327 FindAllEncoder(res); 328 FindAllConnector(res); 329 FindAllPlane(); 330 DISPLAY_LOGD(); 331 // travel all connector 332 for (auto &connectorPair : mConnectors) { 333 auto connector = connectorPair.second; 334 uint32_t crtcId = 0; 335 int32_t ret = connector->PickIdleCrtcId(mEncoders, mCrtcs, crtcId); 336 if (ret != DISPLAY_SUCCESS) { 337 continue; 338 } 339 DISPLAY_LOGD(); 340 341 auto crtcIter = mCrtcs.find(crtcId); 342 if (crtcIter == mCrtcs.end()) { 343 DISPLAY_LOGE("can not find crtc for the id %{public}d", connector->GetId()); 344 continue; 345 } 346 DISPLAY_LOGD(); 347 auto crtc = crtcIter->second; 348 // create the display 349 std::shared_ptr<HdiDisplay> display = std::make_shared<DrmDisplay>(connector, crtc, mInstance); 350 DISPLAY_LOGD(); 351 display->Init(); 352 dispId = display->GetId(); 353 connectorId = connector->GetId(); 354 mDisplays.emplace(dispId, std::move(display)); 355 dispConnectorIdMaps_.emplace(dispId, connectorId); 356 } 357 DISPLAY_LOGD("find display size %{public}zd", mDisplays.size()); 358 return mDisplays; 359} 360} // namespace OHOS 361} // namespace HDI 362} // namespace DISPLAY 363