| /* |
| * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <drm_logger.h> |
| |
| #include <string.h> |
| #include "drm_atomic_req.h" |
| #include "drm_connector.h" |
| #include "drm_crtc.h" |
| #include "drm_encoder.h" |
| #include "drm_manager.h" |
| #include "drm_plane.h" |
| |
| using std::lock_guard; |
| using std::mutex; |
| using std::pair; |
| using std::make_pair; |
| |
| extern "C" { |
| |
| int GetDRMManager(int fd, sde_drm::DRMManagerInterface **intf) { |
| sde_drm::DRMManager *drm_mgr = sde_drm::DRMManager::GetInstance(fd); |
| if (!drm_mgr) { |
| return -ENODEV; |
| } |
| |
| *intf = drm_mgr; |
| return 0; |
| } |
| |
| int DestroyDRMManager() { |
| sde_drm::DRMManager::Destroy(); |
| return 0; |
| } |
| |
| } // extern "C" |
| |
| namespace sde_drm { |
| |
| #define __CLASS__ "DRMManager" |
| |
| DRMManager *DRMManager::s_drm_instance = NULL; |
| mutex DRMManager::s_lock; |
| |
| DRMManager *DRMManager::GetInstance(int fd) { |
| lock_guard<mutex> lock(s_lock); |
| if (!s_drm_instance) { |
| s_drm_instance = new DRMManager(); |
| |
| int ret = s_drm_instance ? s_drm_instance->Init(fd) : DRM_ERR_INVALID; |
| if (ret) { |
| delete s_drm_instance; |
| s_drm_instance = nullptr; |
| } |
| } |
| |
| return s_drm_instance; |
| } |
| |
| void DRMManager::Destroy() { |
| lock_guard<mutex> lock(s_lock); |
| if (s_drm_instance) { |
| delete s_drm_instance; |
| s_drm_instance = nullptr; |
| } |
| } |
| |
| int DRMManager::Init(int drm_fd) { |
| fd_ = drm_fd; |
| |
| drmSetClientCap(fd_, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); |
| drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1); |
| |
| drmModeRes *resource = drmModeGetResources(fd_); |
| if (resource == NULL) { |
| DRM_LOGE("drmModeGetResources failed"); |
| return DRM_ERR_INVALID; |
| } |
| |
| conn_mgr_ = new DRMConnectorManager(fd_); |
| if (!conn_mgr_) { |
| DRM_LOGE("Failed to get Connector Mgr"); |
| return DRM_ERR_INVALID; |
| } |
| conn_mgr_->Init(resource); |
| |
| encoder_mgr_ = new DRMEncoderManager(fd_); |
| if (!encoder_mgr_) { |
| DRM_LOGE("Failed to get Encoder Mgr"); |
| return DRM_ERR_INVALID; |
| } |
| encoder_mgr_->Init(resource); |
| |
| crtc_mgr_ = new DRMCrtcManager(fd_); |
| if (!crtc_mgr_) { |
| DRM_LOGE("Failed to get Crtc Mgr"); |
| return DRM_ERR_INVALID; |
| } |
| crtc_mgr_->Init(resource); |
| |
| plane_mgr_ = new DRMPlaneManager(fd_); |
| if (!plane_mgr_) { |
| DRM_LOGE("Failed to get Plane Mgr"); |
| return DRM_ERR_INVALID; |
| } |
| plane_mgr_->Init(); |
| |
| dpps_mgr_intf_ = GetDppsManagerIntf(); |
| if (dpps_mgr_intf_) |
| dpps_mgr_intf_->Init(fd_, resource); |
| |
| panel_feature_mgr_intf_ = GetPanelFeatureManagerIntf(); |
| if (!panel_feature_mgr_intf_) { |
| DRM_LOGE("Failed to get Panel feature Mgr"); |
| return DRM_ERR_INVALID; |
| } |
| panel_feature_mgr_intf_->Init(fd_, resource); |
| |
| drmModeFreeResources(resource); |
| |
| return 0; |
| } |
| |
| int DRMManager::GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info) { |
| *info = {}; |
| return conn_mgr_->GetConnectorInfo(conn_id, info); |
| } |
| |
| int DRMManager::GetConnectorsInfo(DRMConnectorsInfo *infos) { |
| *infos = {}; |
| int ret = -ENODEV; |
| std::vector<uint32_t> conn_ids; |
| conn_mgr_->Update(); |
| conn_mgr_->GetConnectorList(&conn_ids); |
| for (auto iter : conn_ids) { |
| DRMConnectorInfo info; |
| ret = GetConnectorInfo(iter, &info); |
| if (!ret) { |
| (*infos)[iter] = info; |
| } else { |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| int DRMManager::GetEncoderInfo(uint32_t encoder_id, DRMEncoderInfo *info) { |
| *info = {}; |
| return encoder_mgr_->GetEncoderInfo(encoder_id, info); |
| } |
| |
| int DRMManager::GetEncodersInfo(DRMEncodersInfo *infos) { |
| *infos = {}; |
| int ret = -ENODEV; |
| std::vector<uint32_t> encoder_ids; |
| encoder_mgr_->GetEncoderList(&encoder_ids); |
| for (auto iter : encoder_ids) { |
| DRMEncoderInfo info; |
| ret = GetEncoderInfo(iter, &info); |
| if (!ret) { |
| (*infos)[iter] = info; |
| } else { |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| int DRMManager::GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info) { |
| *info = {}; |
| return crtc_mgr_->GetCrtcInfo(crtc_id, info); |
| } |
| |
| void DRMManager::GetPlanesInfo(DRMPlanesInfo *info) { |
| plane_mgr_->GetPlanesInfo(info); |
| } |
| |
| void DRMManager::GetCrtcPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info) { |
| crtc_mgr_->GetPPInfo(crtc_id, info); |
| } |
| |
| DRMPlaneManager *DRMManager::GetPlaneMgr() { |
| return plane_mgr_; |
| } |
| |
| DRMConnectorManager *DRMManager::GetConnectorMgr() { |
| return conn_mgr_; |
| } |
| |
| DRMEncoderManager *DRMManager::GetEncoderMgr() { |
| return encoder_mgr_; |
| } |
| |
| DRMCrtcManager *DRMManager::GetCrtcMgr() { |
| return crtc_mgr_; |
| } |
| |
| DRMDppsManagerIntf *DRMManager::GetDppsMgrIntf() { |
| return dpps_mgr_intf_; |
| } |
| |
| int DRMManager::RegisterDisplay(DRMDisplayType disp_type, DRMDisplayToken *token) { |
| int ret = conn_mgr_->Reserve(disp_type, token); |
| if (ret) { |
| if (ret == -ENODEV) { |
| DRM_LOGI("display type %d is not present", disp_type); |
| } else { |
| DRM_LOGE("Error reserving connector for display type %d. Error = %d (%s)", disp_type, ret, |
| strerror(abs(ret))); |
| } |
| return ret; |
| } |
| |
| std::set<uint32_t> possible_encoders; |
| ret = conn_mgr_->GetPossibleEncoders(token->conn_id, &possible_encoders); |
| if (ret) { |
| DRM_LOGE("Error retreiving possible encoders for display type %d. Error = %d (%s)", disp_type, |
| ret, strerror(abs(ret))); |
| return ret; |
| } |
| |
| ret = encoder_mgr_->Reserve(possible_encoders, token); |
| if (ret) { |
| DRM_LOGE("Error reserving encoder for display type %d. Error = %d (%s)", disp_type, ret, |
| strerror(abs(ret))); |
| conn_mgr_->Free(token); |
| return ret; |
| } |
| |
| std::set<uint32_t> possible_crtc_indices; |
| ret = encoder_mgr_->GetPossibleCrtcIndices(token->encoder_id, &possible_crtc_indices); |
| if (ret) { |
| DRM_LOGE("Error retreiving possible crtcs for display type %d. Error = %d (%s)", disp_type, |
| ret, strerror(abs(ret))); |
| return ret; |
| } |
| |
| ret = crtc_mgr_->Reserve(possible_crtc_indices, token); |
| if (ret) { |
| DRM_LOGE("Error reserving crtc for display type %d. Error = %d (%s)", disp_type, ret, |
| strerror(abs(ret))); |
| encoder_mgr_->Free(token); |
| conn_mgr_->Free(token); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| int DRMManager::RegisterDisplay(int32_t display_id, DRMDisplayToken *token) { |
| int ret = conn_mgr_->Reserve(display_id, token); |
| if (ret) { |
| DRM_LOGE("Error reserving connector %d. Error = %d (%s)", display_id, ret, strerror(abs(ret))); |
| return ret; |
| } |
| |
| std::set<uint32_t> possible_encoders; |
| ret = conn_mgr_->GetPossibleEncoders(token->conn_id, &possible_encoders); |
| if (ret) { |
| DRM_LOGE("Error retreiving possible encoders for display id %d. Error = %d (%s)", display_id, |
| ret, strerror(abs(ret))); |
| return ret; |
| } |
| |
| ret = encoder_mgr_->Reserve(possible_encoders, token); |
| if (ret) { |
| DRM_LOGE("Error reserving encoder for display %d. Error: %d (%s)", display_id, ret, |
| strerror(abs(ret))); |
| return ret; |
| } |
| |
| std::set<uint32_t> possible_crtc_indices; |
| ret = encoder_mgr_->GetPossibleCrtcIndices(token->encoder_id, &possible_crtc_indices); |
| if (ret) { |
| DRM_LOGE("Error retreiving possible crtcs for display id %d. Error = %d (%s)", display_id, |
| ret, strerror(abs(ret))); |
| encoder_mgr_->Free(token); |
| conn_mgr_->Free(token); |
| return ret; |
| } |
| |
| ret = crtc_mgr_->Reserve(possible_crtc_indices, token); |
| if (ret) { |
| DRM_LOGE("Error reserving crtc for display %d. Error: %d (%s)", display_id, |
| ret, strerror(abs(ret))); |
| encoder_mgr_->Free(token); |
| conn_mgr_->Free(token); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| void DRMManager::UnregisterDisplay(DRMDisplayToken *token) { |
| conn_mgr_->Free(token); |
| encoder_mgr_->Free(token); |
| crtc_mgr_->Free(token); |
| } |
| |
| DRMManager::~DRMManager() { |
| if (conn_mgr_) { |
| conn_mgr_->DeInit(); |
| delete conn_mgr_; |
| conn_mgr_ = NULL; |
| } |
| if (encoder_mgr_) { |
| encoder_mgr_->DeInit(); |
| delete encoder_mgr_; |
| encoder_mgr_ = NULL; |
| } |
| if (crtc_mgr_) { |
| crtc_mgr_->DeInit(); |
| delete crtc_mgr_; |
| crtc_mgr_ = NULL; |
| } |
| if (plane_mgr_) { |
| plane_mgr_->DeInit(); |
| delete plane_mgr_; |
| plane_mgr_ = NULL; |
| } |
| if (panel_feature_mgr_intf_) { |
| panel_feature_mgr_intf_->Deinit(); |
| } |
| } |
| |
| int DRMManager::CreateAtomicReq(const DRMDisplayToken &token, DRMAtomicReqInterface **intf) { |
| DRMAtomicReq *req = new DRMAtomicReq(fd_, this); |
| int ret = req ? req->Init(token) : -ENOMEM; |
| |
| if (ret < 0) { |
| DRM_LOGE("Initializing DRMAtomicReqInterface failed with error %d (%s)", ret, |
| strerror(abs(ret))); |
| delete req; |
| return ret; |
| } |
| *intf = req; |
| |
| return 0; |
| } |
| |
| int DRMManager::DestroyAtomicReq(DRMAtomicReqInterface *intf) { |
| delete intf; |
| return 0; |
| } |
| |
| int DRMManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) { |
| plane_mgr_->SetScalerLUT(lut_info); |
| crtc_mgr_->SetScalerLUT(lut_info); |
| return 0; |
| } |
| |
| int DRMManager::UnsetScalerLUT() { |
| plane_mgr_->UnsetScalerLUT(); |
| crtc_mgr_->UnsetScalerLUT(); |
| return 0; |
| } |
| |
| void DRMManager::GetDppsFeatureInfo(DRMDppsFeatureInfo *info) { |
| if (dpps_mgr_intf_) |
| dpps_mgr_intf_->GetDppsFeatureInfo(info); |
| } |
| |
| DRMPanelFeatureMgrIntf* DRMManager::GetPanelFeatureMgrIntf() { |
| return panel_feature_mgr_intf_; |
| } |
| |
| void DRMManager::GetPanelFeature(DRMPanelFeatureInfo *info) { |
| if (panel_feature_mgr_intf_) { |
| panel_feature_mgr_intf_->GetPanelFeatureInfo(info); |
| } else { |
| DRM_LOGE("Failed, panel feature mgr not available"); |
| } |
| } |
| |
| void DRMManager::SetPanelFeature(const DRMPanelFeatureInfo &info) { |
| if (panel_feature_mgr_intf_) { |
| panel_feature_mgr_intf_->CachePanelFeature(info); |
| } else { |
| DRM_LOGE("Failed, panel feature mgr not available"); |
| } |
| } |
| |
| void DRMManager::MarkPanelFeatureForNullCommit(const DRMDisplayToken &token, |
| const DRMPanelFeatureID &id) { |
| if (panel_feature_mgr_intf_) { |
| panel_feature_mgr_intf_->MarkForNullCommit(token, id); |
| } else { |
| DRM_LOGE("Failed, panel feature mgr not available"); |
| } |
| } |
| |
| void DRMManager::MapPlaneToConnector(std::map<uint32_t, uint32_t> *plane_to_connector) { |
| if (!plane_to_connector) { |
| DRM_LOGE("Map is NULL! Not expected."); |
| return; |
| } |
| |
| plane_to_connector->clear(); |
| |
| std::map<uint32_t, uint32_t> plane_to_crtc; |
| std::map<uint32_t, uint32_t> crtc_to_encoder; |
| std::map<uint32_t, uint32_t> encoder_to_connector; |
| |
| // Cont. Splash planes are detected by CRTC existence on the PLANE |
| // These are the planes that ultimately need to know their CONNECTOR |
| plane_mgr_->MapPlaneToCrtc(&plane_to_crtc); |
| if (!plane_to_crtc.size()) { |
| DRM_LOGI("No cont. splash planes found"); |
| return; |
| } |
| |
| // CRTC is connected to ENCODER. Find the ENCODERs who have CRTCs and establish |
| // reverse lookup CRTC --> ENCODER |
| encoder_mgr_->MapCrtcToEncoder(&crtc_to_encoder); |
| if (!crtc_to_encoder.size()) { |
| DRM_LOGW("Planes are associated with CRTCs but no CRTC to ENCODERs found"); |
| return; |
| } |
| |
| // ENCODER is connected to CONNECTOR. Find the CONNECTORs who have ENCODERs and establish |
| // reverse lookup ENCODER --> CONNECTOR |
| conn_mgr_->MapEncoderToConnector(&encoder_to_connector); |
| if (!encoder_to_connector.size()) { |
| DRM_LOGW("CRTCs are associated with ENCODERs but no ENCODERs to CONNECTORs found"); |
| return; |
| } |
| |
| // Link the Cont. Splash PLANEs with their CONNECTOR |
| for (auto &plane_entry : plane_to_crtc) { |
| uint32_t plane_id = plane_entry.first; |
| auto &crtc_id = plane_entry.second; |
| auto enc_entry = crtc_to_encoder.find(crtc_id); |
| if (enc_entry == crtc_to_encoder.end()) { |
| DRM_LOGW("Plane %u mapped to crtc %u didn't have an encoder. Not expected.", plane_id, |
| crtc_id); |
| continue; |
| } |
| auto &encoder_id = enc_entry->second; |
| auto conn_entry = encoder_to_connector.find(encoder_id); |
| if (conn_entry == encoder_to_connector.end()) { |
| DRM_LOGW("Plane %u, crtc %u, encoder %u, didn't have a connector. Not expected.", |
| plane_id, crtc_id, encoder_id); |
| continue; |
| } |
| uint32_t connector_id = conn_entry->second; |
| |
| plane_to_connector->insert(make_pair(plane_id, connector_id)); |
| } |
| } |
| |
| void DRMManager::GetRequiredDemuraFetchResourceCount( |
| std::map<uint32_t, uint8_t> *required_demura_fetch_cnt) { |
| conn_mgr_->GetPreferredModeLMCounts(required_demura_fetch_cnt); |
| } |
| |
| void DRMManager::GetInitialDemuraInfo(std::vector<uint32_t> *initial_demura_planes) { |
| if (panel_feature_mgr_intf_) { |
| initial_demura_planes->clear(); |
| std::vector<uint32_t> crtc_ids; |
| crtc_mgr_->GetCrtcList(&crtc_ids); |
| FetchResourceList frl; |
| for (auto &id : crtc_ids) { |
| DRMPanelFeatureInfo info; |
| info.prop_id = kDRMPanelFeatureDemuraResources; |
| info.obj_type = DRM_MODE_OBJECT_CRTC; |
| info.obj_id = id; |
| info.prop_ptr = reinterpret_cast<uint64_t>(&frl); |
| panel_feature_mgr_intf_->GetPanelFeatureInfo(&info); |
| } |
| // Safe to assume pipe to crtc to Demura associations are functionally correct |
| plane_mgr_->GetPlaneIdsFromDescriptions(frl, initial_demura_planes); |
| } |
| } |
| } // namespace sde_drm |