blob: 462e76782f5010bc8a64d760ffb94b05b63221c0 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/types.h>
#include "ExynosDisplayDrmInterface.h"
#include "ExynosDisplay.h"
#include "ExynosHWCDebug.h"
typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr;
struct _drmModeAtomicReqItem {
uint32_t object_id;
uint32_t property_id;
uint64_t value;
};
struct _drmModeAtomicReq {
uint32_t cursor;
uint32_t size_items;
drmModeAtomicReqItemPtr items;
};
extern struct exynos_hwc_control exynosHWCControl;
static const int32_t kUmPerInch = 25400;
ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay)
{
mType = INTERFACE_TYPE_DRM;
init(exynosDisplay);
}
ExynosDisplayDrmInterface::~ExynosDisplayDrmInterface()
{
if (mModeState.blob_id)
mDrmDevice->DestroyPropertyBlob(mModeState.blob_id);
if (mModeState.old_blob_id)
mDrmDevice->DestroyPropertyBlob(mModeState.old_blob_id);
}
void ExynosDisplayDrmInterface::init(ExynosDisplay *exynosDisplay)
{
mExynosDisplay = exynosDisplay;
mDrmDevice = NULL;
mDrmCrtc = NULL;
mDrmConnector = NULL;
mActiveConfig = -1;
}
void ExynosDisplayDrmInterface::initDrmDevice(DrmDevice *drmDevice)
{
if (mExynosDisplay == NULL) {
ALOGE("mExynosDisplay is not set");
return;
}
if ((mDrmDevice = drmDevice) == NULL) {
ALOGE("drmDevice is NULL");
return;
}
if ((mDrmCrtc = mDrmDevice->GetCrtcForDisplay(mExynosDisplay->mDisplayId)) == NULL) {
ALOGE("%s:: GetCrtcForDisplay is NULL", mExynosDisplay->mDisplayName.string());
return;
}
if ((mDrmConnector = mDrmDevice->GetConnectorForDisplay(mExynosDisplay->mDisplayId)) == NULL) {
ALOGE("%s:: GetConnectorForDisplay is NULL", mExynosDisplay->mDisplayName.string());
return;
}
/* TODO: We should map plane to ExynosMPP */
#if 0
for (auto &plane : mDrmDevice->planes()) {
uint32_t plane_id = plane->id();
ExynosMPP *exynosMPP =
mExynosDisplay->mResourceManager->getOtfMPPWithChannel(plane_id);
if (exynosMPP == NULL)
HWC_LOGE(mExynosDisplay, "getOtfMPPWithChannel fail, ch(%d)", plane_id);
mExynosMPPsForPlane[plane_id] = exynosMPP;
}
#endif
if (mExynosDisplay->mMaxWindowNum != getMaxWindowNum()) {
ALOGE("%s:: Invalid max window number (mMaxWindowNum: %d, getMaxWindowNum(): %d",
__func__, mExynosDisplay->mMaxWindowNum, getMaxWindowNum());
return;
}
mOldFbIds.assign(getMaxWindowNum(), 0);
mVsyncCallbak.init(mExynosDisplay->mDevice, mExynosDisplay);
mDrmVSyncWorker.Init(mDrmDevice, mExynosDisplay->mDisplayId);
mDrmVSyncWorker.RegisterCallback(std::shared_ptr<VsyncCallback>(&mVsyncCallbak));
chosePreferredConfig();
return;
}
void ExynosDisplayDrmInterface::ExynosVsyncCallback::init(
ExynosDevice *exynosDevice, ExynosDisplay *exynosDisplay)
{
mExynosDevice = exynosDevice;
mExynosDisplay = exynosDisplay;
}
void ExynosDisplayDrmInterface::ExynosVsyncCallback::Callback(
int display, int64_t timestamp)
{
mExynosDevice->compareVsyncPeriod();
if (mExynosDevice->mVsyncDisplay == (int)mExynosDisplay->mDisplayId) {
hwc2_callback_data_t callbackData =
mExynosDevice->mCallbackInfos[HWC2_CALLBACK_VSYNC].callbackData;
HWC2_PFN_VSYNC callbackFunc =
(HWC2_PFN_VSYNC)mExynosDevice->mCallbackInfos[HWC2_CALLBACK_VSYNC].funcPointer;
if (callbackFunc != NULL)
callbackFunc(callbackData, mExynosDisplay->mDisplayId, timestamp);
}
}
int32_t ExynosDisplayDrmInterface::setPowerMode(int32_t mode)
{
int ret = 0;
uint64_t dpms_value = 0;
if (mode == HWC_POWER_MODE_OFF) {
dpms_value = DRM_MODE_DPMS_OFF;
} else {
dpms_value = DRM_MODE_DPMS_ON;
}
const DrmProperty &prop = mDrmConnector->dpms_property();
if ((ret = drmModeConnectorSetProperty(mDrmDevice->fd(), mDrmConnector->id(), prop.id(),
dpms_value)) != NO_ERROR) {
HWC_LOGE(mExynosDisplay, "setPower mode ret (%d)", ret);
}
return ret;
}
int32_t ExynosDisplayDrmInterface::setVsyncEnabled(uint32_t enabled)
{
mDrmVSyncWorker.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
return NO_ERROR;
}
int32_t ExynosDisplayDrmInterface::getDisplayAttribute(
hwc2_config_t config,
int32_t attribute, int32_t* outValue)
{
auto mode = std::find_if(mDrmConnector->modes().begin(),
mDrmConnector->modes().end(),
[config](DrmMode const &m) {
return m.id() == config;
});
if (mode == mDrmConnector->modes().end()) {
ALOGE("Could not find active mode for %d", config);
return HWC2_ERROR_BAD_CONFIG;
}
uint32_t mm_width = mDrmConnector->mm_width();
uint32_t mm_height = mDrmConnector->mm_height();
switch (attribute) {
case HWC2_ATTRIBUTE_WIDTH:
*outValue = mode->h_display();
break;
case HWC2_ATTRIBUTE_HEIGHT:
*outValue = mode->v_display();
break;
case HWC2_ATTRIBUTE_VSYNC_PERIOD:
// in nanoseconds
*outValue = std::chrono::duration_cast<std::chrono::nanoseconds>((std::chrono::seconds)1).count() / mode->v_refresh();
break;
case HWC2_ATTRIBUTE_DPI_X:
// Dots per 1000 inches
*outValue = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1;
break;
case HWC2_ATTRIBUTE_DPI_Y:
// Dots per 1000 inches
*outValue = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1;
break;
default:
*outValue = -1;
return HWC2_ERROR_BAD_CONFIG;
}
return HWC2_ERROR_NONE;
}
int32_t ExynosDisplayDrmInterface::chosePreferredConfig()
{
uint32_t num_configs = 0;
int32_t err = getDisplayConfigs(&num_configs, NULL);
if (err != HWC2_ERROR_NONE || !num_configs)
return err;
ALOGI("Preferred mode id: %d", mDrmConnector->get_preferred_mode_id());
return setActiveConfig(mDrmConnector->get_preferred_mode_id());
}
int32_t ExynosDisplayDrmInterface::getDisplayConfigs(
uint32_t* outNumConfigs,
hwc2_config_t* outConfigs)
{
if (!outConfigs) {
int ret = mDrmConnector->UpdateModes();
if (ret) {
ALOGE("Failed to update display modes %d", ret);
return HWC2_ERROR_BAD_DISPLAY;
}
dumpDisplayConfigs();
}
uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size());
if (!outConfigs) {
*outNumConfigs = num_modes;
return HWC2_ERROR_NONE;
}
uint32_t idx = 0;
for (const DrmMode &mode : mDrmConnector->modes()) {
if (idx >= *outNumConfigs)
break;
outConfigs[idx++] = mode.id();
}
*outNumConfigs = idx;
return 0;
}
void ExynosDisplayDrmInterface::dumpDisplayConfigs()
{
uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size());
for (uint32_t i = 0; i < num_modes; i++) {
auto mode = mDrmConnector->modes().at(i);
ALOGD("%s display config[%d] %s:: id(%d), clock(%d), flags(%d), type(%d)",
mExynosDisplay->mDisplayName.string(), i, mode.name().c_str(), mode.id(), mode.clock(), mode.flags(), mode.type());
ALOGD("\th_display(%d), h_sync_start(%d), h_sync_end(%d), h_total(%d), h_skew(%d)",
mode.h_display(), mode.h_sync_start(), mode.h_sync_end(), mode.h_total(), mode.h_skew());
ALOGD("\tv_display(%d), v_sync_start(%d), v_sync_end(%d), v_total(%d), v_scan(%d), v_refresh(%f)",
mode.v_display(), mode.v_sync_start(), mode.v_sync_end(), mode.v_total(), mode.v_scan(), mode.v_refresh());
}
}
int32_t ExynosDisplayDrmInterface::getColorModes(
uint32_t* outNumModes,
int32_t* outModes)
{
*outNumModes = 1;
if (outModes != NULL) {
outModes[0] = HAL_COLOR_MODE_NATIVE;
}
return HWC2_ERROR_NONE;
}
int32_t ExynosDisplayDrmInterface::setColorMode(int32_t mode)
{
return 0;
}
int32_t ExynosDisplayDrmInterface::setActiveConfig(hwc2_config_t config)
{
ALOGI("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config);
if (mActiveConfig == config) {
ALOGI("%s:: Same display config is set", __func__);
return NO_ERROR;
}
auto mode = std::find_if(mDrmConnector->modes().begin(),
mDrmConnector->modes().end(),
[config](DrmMode const &m) {
return m.id() == config;
});
if (mode == mDrmConnector->modes().end()) {
HWC_LOGE(mExynosDisplay, "Could not find active mode for %d", config);
return HWC2_ERROR_BAD_CONFIG;
}
uint32_t mm_width = mDrmConnector->mm_width();
uint32_t mm_height = mDrmConnector->mm_height();
mActiveConfig = mode->id();
mExynosDisplay->mXres = mode->h_display();
mExynosDisplay->mYres = mode->v_display();
// in nanoseconds
mExynosDisplay->mVsyncPeriod = 1000 * 1000 * 1000 / mode->v_refresh();
// Dots per 1000 inches
mExynosDisplay->mXdpi = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1;
// Dots per 1000 inches
mExynosDisplay->mYdpi = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1;
mModeState.mode = *mode;
if (mModeState.blob_id)
mDrmDevice->DestroyPropertyBlob(mModeState.blob_id);
struct drm_mode_modeinfo drm_mode;
memset(&drm_mode, 0, sizeof(drm_mode));
mode->ToDrmModeModeInfo(&drm_mode);
uint32_t id = 0;
int ret = mDrmDevice->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
&id);
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to create mode property blob %d", ret);
return ret;
}
mModeState.blob_id = id;
mModeState.needs_modeset = true;
applyDisplayMode();
return 0;
}
int32_t ExynosDisplayDrmInterface::applyDisplayMode()
{
if (mModeState.needs_modeset == false)
return NO_ERROR;
int ret = NO_ERROR;
DrmModeAtomicReq drmReq;
ret = drmModeAtomicAddProperty(drmReq.pset(), mDrmCrtc->id(),
mDrmCrtc->active_property().id(), 1);
if (ret < 0) {
HWC_LOGE(mExynosDisplay, "Failed to add crtc active to pset\n");
return ret;
}
ret = drmModeAtomicAddProperty(drmReq.pset(), mDrmCrtc->id(), mDrmCrtc->mode_property().id(),
mModeState.blob_id) < 0 ||
drmModeAtomicAddProperty(drmReq.pset(), mDrmConnector->id(),
mDrmConnector->crtc_id_property().id(),
mDrmCrtc->id()) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to add blob %d to pset", mModeState.blob_id);
return ret;
}
if (!ret) {
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
ret = drmModeAtomicCommit(mDrmDevice->fd(), drmReq.pset(), flags, mDrmDevice);
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to commit pset ret=%d in applyDisplayMode()\n", ret);
return ret;
}
}
if (mModeState.old_blob_id) {
ret = mDrmDevice->DestroyPropertyBlob(mModeState.old_blob_id);
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to destroy old mode property blob %" PRIu32 "/%d",
mModeState.old_blob_id, ret);
}
}
mDrmConnector->set_active_mode(mModeState.mode);
mModeState.old_blob_id = mModeState.blob_id;
mModeState.blob_id = 0;
mModeState.needs_modeset = false;
return ret;
}
int32_t ExynosDisplayDrmInterface::setCursorPositionAsync(uint32_t x_pos, uint32_t y_pos)
{
return 0;
}
int32_t ExynosDisplayDrmInterface::getHdrCapabilities(uint32_t* outNumTypes,
int32_t* outTypes, float* outMaxLuminance,
float* outMaxAverageLuminance, float* outMinLuminance)
{
*outNumTypes = 0;
return 0;
}
int ExynosDisplayDrmInterface::getDeconChannel(ExynosMPP *otfMPP)
{
int32_t channelNum = sizeof(IDMA_CHANNEL_MAP)/sizeof(dpp_channel_map_t);
for (int i = 0; i < channelNum; i++) {
if((IDMA_CHANNEL_MAP[i].type == otfMPP->mPhysicalType) &&
(IDMA_CHANNEL_MAP[i].index == otfMPP->mPhysicalIndex))
return IDMA_CHANNEL_MAP[i].channel;
}
return -EINVAL;
}
int32_t ExynosDisplayDrmInterface::deliverWinConfigData()
{
int ret = NO_ERROR;
DrmModeAtomicReq drmReq;
std::unordered_map<uint32_t, uint32_t> planeEnableInfo;
std::vector<uint32_t> fbIds(getMaxWindowNum(), 0);
android::String8 result;
uint64_t out_fences[mDrmDevice->crtcs().size()];
if (mDrmCrtc->out_fence_ptr_property().id() != 0) {
ret = drmModeAtomicAddProperty(drmReq.pset(), mDrmCrtc->id(),
mDrmCrtc->out_fence_ptr_property().id(),
(uint64_t)&out_fences[mDrmCrtc->pipe()]);
if (ret < 0) {
HWC_LOGE(mExynosDisplay, "%s:: Failed to add OUT_FENCE_PTR property to pset: %d",
__func__, ret);
drmReq.setError(ret, this);
return ret;
}
}
for (auto &plane : mDrmDevice->planes()) {
planeEnableInfo[plane->id()] = 0;
}
for (size_t i = 0; i < mExynosDisplay->mDpuData.configs.size(); i++) {
exynos_win_config_data& config = mExynosDisplay->mDpuData.configs[i];
if (config.state == config.WIN_STATE_BUFFER) {
uint32_t fb_id = 0;
int channelId = 0;
if ((channelId = getDeconChannel(config.assignedMPP)) < 0) {
HWC_LOGE(mExynosDisplay, "%s:: Failed to get channel id (%d)",
__func__, channelId);
ret = -EINVAL;
drmReq.setError(ret, this);
return ret;
}
auto &plane = mDrmDevice->planes().at(channelId);
/* Set this plane is enabled */
planeEnableInfo[plane->id()] = 1;
int drmFormat = halFormatToDrmFormat(config.format);
if (drmFormat == DRM_FORMAT_UNDEFINED) {
HWC_LOGE(mExynosDisplay, "%s:: known drm format (%d)",
__func__, config.format);
ret = -EINVAL;
drmReq.setError(ret, this);
return ret;
}
uint32_t bpp = formatToBpp(config.format);
uint32_t pitches[HWC_DRM_BO_MAX_PLANES] = {0};
uint32_t offsets[HWC_DRM_BO_MAX_PLANES] = {0};
uint32_t buf_handles[HWC_DRM_BO_MAX_PLANES] = {0};
uint32_t planeNum = getBufferNumOfFormat(config.format);
for(uint32_t planeIndex = 0; planeIndex < planeNum; planeIndex++) {
pitches[planeIndex] = config.src.f_w * bpp;
buf_handles[planeIndex] = (uint32_t)config.fd_idma[planeIndex];
}
uint64_t modifiers[HWC_DRM_BO_MAX_PLANES] = {0};
if (config.compression)
modifiers[0] = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16);
ret = drmModeAddFB2WithModifiers(mDrmDevice->fd(), config.src.f_w, config.src.f_h,
drmFormat, buf_handles, pitches, offsets, modifiers, &fb_id, modifiers[0] ? DRM_MODE_FB_MODIFIERS : 0);
if (ret != NO_ERROR) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to add FB, fb_id(%d), ret(%d), f_w: %d, f_h: %d, format: %d, buf_handles[%d, %d, %d, %d], "
"pitches[%d, %d, %d, %d], offsets[%d, %d, %d, %d], modifiers[%#" PRIx64 ", %#" PRIx64 ", %#" PRIx64 ", %#" PRIx64 "]",
__func__, i, fb_id, ret,
config.src.f_w, config.src.f_h, drmFormat,
buf_handles[0], buf_handles[1], buf_handles[2], buf_handles[3],
pitches[0], pitches[1], pitches[2], pitches[3],
offsets[0], offsets[1], offsets[2], offsets[3],
modifiers[0], modifiers[1], modifiers[2], modifiers[3]);
drmReq.setError(ret, this);
return ret;
}
fbIds[i] = fb_id;
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_property().id(), mDrmCrtc->id()) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->fb_property().id(), fb_id) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_x_property().id(),
config.dst.x) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_y_property().id(),
config.dst.y) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_w_property().id(),
config.dst.w) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_h_property().id(),
config.dst.h) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->src_x_property().id(),
(int)(config.src.x) << 16) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->src_y_property().id(),
(int)(config.src.y) << 16) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->src_w_property().id(),
(int)(config.src.w) << 16) < 0;
ret |= drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->src_h_property().id(),
(int)(config.src.h) << 16) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to add plane %d to set, ret(%d)",
__func__, i, plane->id(), ret);
drmReq.setError(ret, this);
return ret;
}
uint64_t rotation = halTransformToDrmRot(config.transform);
uint64_t blend = 0;
if (plane->blend_property().id()) {
switch (config.blending) {
case HWC2_BLEND_MODE_PREMULTIPLIED:
std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
"Pre-multiplied");
break;
case HWC2_BLEND_MODE_COVERAGE:
std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
"Coverage");
break;
case HWC2_BLEND_MODE_NONE:
default:
std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
"None");
break;
}
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to get blend for plane %d, blend(%" PRId64 "), ret(%d)",
__func__, i, plane->id(), blend, ret);
drmReq.setError(ret, this);
return ret;
}
}
if (plane->zpos_property().id() &&
!plane->zpos_property().is_immutable()) {
uint64_t min_zpos = 0;
// Ignore ret and use min_zpos as 0 by default
std::tie(std::ignore, min_zpos) = plane->zpos_property().range_min();
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->zpos_property().id(),
i + min_zpos) < 0;
if (ret < 0) {
ALOGE("Failed to add zpos property %d to plane %d, ret(%d)",
plane->zpos_property().id(), plane->id(), ret);
break;
}
}
if (plane->rotation_property().id()) {
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->rotation_property().id(),
rotation) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to add rotation property %d for plane %d, ret(%d)",
__func__, i, plane->rotation_property().id(), plane->id(), ret);
drmReq.setError(ret, this);
return ret;
}
}
if (plane->blend_property().id()) {
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->blend_property().id(), blend) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to add pixel blend mode property %d for plane %d, ret(%d)",
__func__, i, plane->blend_property().id(), plane->id(), ret);
drmReq.setError(ret, this);
return ret;
}
}
if (plane->alpha_property().id()) {
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->alpha_property().id(), config.plane_alpha) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to add alpha property %d for plane %d, ret(%d)",
__func__, i, plane->alpha_property().id(), plane->id(), ret);
drmReq.setError(ret, this);
return ret;
}
}
if (config.acq_fence >= 0) {
int prop_id = plane->in_fence_fd_property().id();
if (prop_id == 0) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to get IN_FENCE_FD property id for plane %d",
__func__, i, plane->id());
break;
}
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(), prop_id, config.acq_fence) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: config[%zu]: Failed to add IN_FENCE_FD property to pset for plane %d, ret(%d)",
__func__, i, plane->id(), ret);
drmReq.setError(ret, this);
return ret;
}
}
}
}
/* Disable unused plane */
for (auto &plane : mDrmDevice->planes()) {
if (planeEnableInfo[plane->id()] == 0) {
#if 0
ExynosMPP* exynosMPP = mExynosMPPsForPlane[plane->id()];
/* Do not disable planes that are reserved to other dispaly */
if ((exynosMPP != NULL) && (mExynosDisplay != NULL) &&
(exynosMPP->mAssignedState & MPP_ASSIGN_STATE_RESERVED) &&
(exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mType))
continue;
#endif
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_property().id(), 0) < 0 ||
drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->fb_property().id(), 0) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: Failed to add plane %d disable to pset",
__func__, plane->id());
drmReq.setError(ret, this);
return ret;
}
}
}
if (!ret) {
uint32_t flags = 0;
ret = drmModeAtomicCommit(mDrmDevice->fd(), drmReq.pset(), flags, mDrmDevice);
dumpAtomicCommitInfo(result, drmReq.pset(), true);
for (size_t i = 0; i < getMaxWindowNum(); i++) {
if (mOldFbIds[i])
drmModeRmFB(mDrmDevice->fd(), mOldFbIds[i]);
mOldFbIds[i] = fbIds[i];
}
if (ret) {
HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset, ret(%d)", __func__, ret);
drmReq.setError(ret, this);
return ret;
}
} else {
HWC_LOGE(mExynosDisplay, "%s:: There was error to set properties for commit, ret(%d)", __func__, ret);
drmReq.setError(ret, this);
return ret;
}
mExynosDisplay->mDpuData.retire_fence = (int)out_fences[mDrmCrtc->pipe()];
/*
* [HACK] dup retire_fence for each layer's release fence
* Do not use hwc_dup because hwc_dup increase usage count of fence treacer
* Usage count of this fence is incresed by ExynosDisplay::deliverWinConfigData()
*/
for (auto &display_config : mExynosDisplay->mDpuData.configs) {
if ((display_config.state == display_config.WIN_STATE_BUFFER) ||
(display_config.state == display_config.WIN_STATE_CURSOR)) {
display_config.rel_fence =
dup((int)out_fences[mDrmCrtc->pipe()]);
}
}
return ret;
}
int32_t ExynosDisplayDrmInterface::clearDisplay()
{
int ret = NO_ERROR;
DrmModeAtomicReq drmReq;
/* Disable all planes */
for (auto &plane : mDrmDevice->planes()) {
#if 0
ExynosMPP* exynosMPP = mExynosMPPsForPlane[plane->id()];
/* Do not disable planes that are reserved to other dispaly */
if ((exynosMPP != NULL) && (mExynosDisplay != NULL) &&
(exynosMPP->mAssignedState & MPP_ASSIGN_STATE_RESERVED) &&
(exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mType))
continue;
#endif
ret = drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->crtc_property().id(), 0) < 0 ||
drmModeAtomicAddProperty(drmReq.pset(), plane->id(),
plane->fb_property().id(), 0) < 0;
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to add plane %d disable to pset", plane->id());
break;
}
}
if (!ret) {
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
ret = drmModeAtomicCommit(mDrmDevice->fd(), drmReq.pset(), flags, mDrmDevice);
}
return ret;
}
int32_t ExynosDisplayDrmInterface::disableSelfRefresh(uint32_t disable)
{
return 0;
}
int32_t ExynosDisplayDrmInterface::setForcePanic()
{
if (exynosHWCControl.forcePanic == 0)
return NO_ERROR;
usleep(20000);
FILE *forcePanicFd = fopen(HWC_FORCE_PANIC_PATH, "w");
if (forcePanicFd == NULL) {
ALOGW("%s:: Failed to open fd", __func__);
return -1;
}
int val = 1;
fwrite(&val, sizeof(int), 1, forcePanicFd);
fclose(forcePanicFd);
return 0;
}
String8& ExynosDisplayDrmInterface::dumpAtomicCommitInfo(String8 &result, drmModeAtomicReqPtr pset, bool debugPrint)
{
/* print log only if eDebugDisplayInterfaceConfig flag is set when debugPrint is true */
if (debugPrint &&
(hwcCheckDebugMessages(eDebugDisplayInterfaceConfig) == false))
return result;
for (uint32_t i = 0; i < (uint32_t)drmModeAtomicGetCursor(pset); i++) {
const DrmProperty *property = NULL;
String8 objectName;
/* Check crtc properties */
if (pset->items[i].object_id == mDrmCrtc->id()) {
for (auto property_ptr : mDrmCrtc->properties()) {
if (pset->items[i].property_id == property_ptr->id()){
property = property_ptr;
objectName.appendFormat("Crtc");
break;
}
}
if (property == NULL) {
HWC_LOGE(mExynosDisplay, "%s:: object id is crtc but there is no matched property",
__func__);
}
} else if (pset->items[i].object_id == mDrmConnector->id()) {
for (auto property_ptr : mDrmConnector->properties()) {
if (pset->items[i].property_id == property_ptr->id()){
property = property_ptr;
objectName.appendFormat("Connector");
break;
}
}
if (property == NULL) {
HWC_LOGE(mExynosDisplay, "%s:: object id is connector but there is no matched property",
__func__);
}
} else {
uint32_t channelId = 0;
for (auto &plane : mDrmDevice->planes()) {
if (pset->items[i].object_id == plane->id()) {
for (auto property_ptr : plane->properties()) {
if (pset->items[i].property_id == property_ptr->id()){
property = property_ptr;
objectName.appendFormat("Plane[%d]", channelId);
break;
}
}
if (property == NULL) {
HWC_LOGE(mExynosDisplay, "%s:: object id is plane but there is no matched property",
__func__);
}
}
channelId++;
}
}
if (property == NULL) {
HWC_LOGE(mExynosDisplay, "%s:: Fail to get property[%d] (object_id: %d, property_id: %d, value: %" PRId64 ")",
__func__, i, pset->items[i].object_id, pset->items[i].property_id,
pset->items[i].value);
continue;
}
if (debugPrint)
ALOGD("property[%d] %s object_id: %d, property_id: %d, name: %s, value: %" PRId64 ")\n",
i, objectName.string(), pset->items[i].object_id, pset->items[i].property_id, property->name().c_str(), pset->items[i].value);
else
result.appendFormat("property[%d] %s object_id: %d, property_id: %d, name: %s, value: %" PRId64 ")\n",
i, objectName.string(), pset->items[i].object_id, pset->items[i].property_id, property->name().c_str(), pset->items[i].value);
}
return result;
}
inline uint32_t ExynosDisplayDrmInterface::getMaxWindowNum()
{
return mDrmDevice->planes().size();
}
ExynosDisplayDrmInterface::DrmModeAtomicReq::~DrmModeAtomicReq()
{
if ((mError != 0) && (mDrmDisplayInterface != NULL)) {
android::String8 result;
result.appendFormat("atomic commit error\n");
mDrmDisplayInterface->dumpAtomicCommitInfo(result, mPset);
HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "%s", result.string());
}
if(mPset)
drmModeAtomicFree(mPset);
}