blob: 04a4b15982aec6d808a819cc8b780073e81a3caa [file] [log] [blame]
/*
* 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