blob: 99b6a2e416aaa5cbda0fb9c927fde77514a9b62e [file] [log] [blame]
/*
* Copyright (c) 2015, 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 <utils/debug.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "hw_rotator.h"
#define __CLASS__ "HWRotator"
namespace sde {
DisplayError HWRotatorInterface::Create(BufferSyncHandler *buffer_sync_handler,
HWRotatorInterface **intf) {
DisplayError error = kErrorNone;
HWRotator *hw_rotator = NULL;
hw_rotator = new HWRotator(buffer_sync_handler);
if (!hw_rotator) {
error = kErrorMemory;
} else {
*intf = hw_rotator;
}
return error;
}
DisplayError HWRotatorInterface::Destroy(HWRotatorInterface *intf) {
delete intf;
intf = NULL;
return kErrorNone;
}
HWRotator::HWRotator(BufferSyncHandler *buffer_sync_handler) : HWDevice(buffer_sync_handler) {
HWDevice::device_type_ = kDeviceRotator;
HWDevice::device_name_ = "Rotator Device";
}
DisplayError HWRotator::Open() {
DisplayError error = kErrorNone;
char device_name[64] = {0};
snprintf(device_name, sizeof(device_name), "%s", "/dev/mdss_rotator");
HWDevice::device_fd_ = open_(device_name, O_RDWR);
if (HWDevice::device_fd_ < 0) {
DLOGE("open %s failed err = %d errstr = %s", device_name, errno, strerror(errno));
return kErrorResources;
}
return error;
}
DisplayError HWRotator::Close() {
if (HWDevice::device_fd_ > 0) {
close_(HWDevice::device_fd_);
}
return kErrorNone;
}
DisplayError HWRotator::OpenSession(HWRotatorSession *hw_rotator_session) {
uint32_t frame_rate = hw_rotator_session->hw_session_config.frame_rate;
LayerBufferFormat src_format = hw_rotator_session->hw_session_config.src_format;
LayerBufferFormat dst_format = hw_rotator_session->hw_session_config.dst_format;
bool rot90 = (hw_rotator_session->transform.rotation == 90.0f);
for (uint32_t i = 0; i < hw_rotator_session->hw_block_count; i++) {
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[i];
if (!hw_rotate_info->valid) {
continue;
}
uint32_t src_width = UINT32(hw_rotate_info->src_roi.right - hw_rotate_info->src_roi.left);
uint32_t src_height =
UINT32(hw_rotate_info->src_roi.bottom - hw_rotate_info->src_roi.top);
uint32_t dst_width = UINT32(hw_rotate_info->dst_roi.right - hw_rotate_info->dst_roi.left);
uint32_t dst_height =
UINT32(hw_rotate_info->dst_roi.bottom - hw_rotate_info->dst_roi.top);
STRUCT_VAR(mdp_rotation_config, mdp_rot_config);
mdp_rot_config.version = MDP_ROTATION_REQUEST_VERSION_1_0;
mdp_rot_config.input.width = src_width;
mdp_rot_config.input.height = src_height;
SetFormat(src_format, &mdp_rot_config.input.format);
mdp_rot_config.output.width = dst_width;
mdp_rot_config.output.height = dst_height;
SetFormat(dst_format, &mdp_rot_config.output.format);
mdp_rot_config.frame_rate = frame_rate;
if (rot90) {
mdp_rot_config.flags |= MDP_ROTATION_90;
}
if (ioctl_(device_fd_, MDSS_ROTATION_OPEN, &mdp_rot_config) < 0) {
IOCTL_LOGE(MDSS_ROTATION_OPEN, device_type_);
return kErrorHardware;
}
hw_rotate_info->rotate_id = mdp_rot_config.session_id;
DLOGV_IF(kTagDriverConfig, "session_id %d", hw_rotate_info->rotate_id);
}
return kErrorNone;
}
DisplayError HWRotator::CloseSession(HWRotatorSession *hw_rotator_session) {
for (uint32_t i = 0; i < hw_rotator_session->hw_block_count; i++) {
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[i];
if (!hw_rotate_info->valid) {
continue;
}
if (ioctl_(device_fd_, MDSS_ROTATION_CLOSE, UINT32(hw_rotate_info->rotate_id)) < 0) {
IOCTL_LOGE(MDSS_ROTATION_CLOSE, device_type_);
return kErrorHardware;
}
DLOGV_IF(kTagDriverConfig, "session_id %d", hw_rotate_info->rotate_id);
}
return kErrorNone;
}
void HWRotator::SetCtrlParams(HWLayers *hw_layers) {
DLOGV_IF(kTagDriverConfig, "************************* %s Validate Input ************************",
HWDevice::device_name_);
ResetParams();
HWLayersInfo &hw_layer_info = hw_layers->info;
uint32_t &rot_count = mdp_rot_request_.count;
for (uint32_t i = 0; i < hw_layer_info.count; i++) {
Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
bool rot90 = (layer.transform.rotation == 90.0f);
for (uint32_t count = 0; count < hw_rotator_session->hw_block_count; count++) {
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
if (hw_rotate_info->valid) {
mdp_rotation_item *mdp_rot_item = &mdp_rot_request_.list[rot_count];
SetMDPFlags(layer, &mdp_rot_item->flags);
SetRect(hw_rotate_info->src_roi, &mdp_rot_item->src_rect);
SetRect(hw_rotate_info->dst_roi, &mdp_rot_item->dst_rect);
// TODO(user): Need to assign the writeback id and pipe id returned from resource manager.
mdp_rot_item->pipe_idx = 0;
mdp_rot_item->wb_idx = 0;
mdp_rot_item->input.width = layer.input_buffer->width;
mdp_rot_item->input.height = layer.input_buffer->height;
SetFormat(layer.input_buffer->format, &mdp_rot_item->input.format);
mdp_rot_item->output.width = hw_rotator_session->output_buffer.width;
mdp_rot_item->output.height = hw_rotator_session->output_buffer.height;
SetFormat(hw_rotator_session->output_buffer.format, &mdp_rot_item->output.format);
mdp_rot_item->session_id = hw_rotate_info->rotate_id;
rot_count++;
DLOGV_IF(kTagDriverConfig, "******************** Layer[%d] %s rotate ********************",
i, count ? "Right" : "Left");
DLOGV_IF(kTagDriverConfig, "in_w %d, in_h %d, in_f %d,\t out_w %d, out_h %d, out_f %d",
mdp_rot_item->input.width, mdp_rot_item->input.height, mdp_rot_item->input.format,
mdp_rot_item->output.width, mdp_rot_item->output.height,
mdp_rot_item->output.format);
DLOGV_IF(kTagDriverConfig, "pipe_id 0x%x, wb_id %d, rot_flag 0x%x, session_id %d",
mdp_rot_item->pipe_idx, mdp_rot_item->wb_idx, mdp_rot_item->flags,
mdp_rot_item->session_id);
DLOGV_IF(kTagDriverConfig, "src_rect [%d, %d, %d, %d]", mdp_rot_item->src_rect.x,
mdp_rot_item->src_rect.y, mdp_rot_item->src_rect.w, mdp_rot_item->src_rect.h);
DLOGV_IF(kTagDriverConfig, "dst_rect [%d, %d, %d, %d]", mdp_rot_item->dst_rect.x,
mdp_rot_item->dst_rect.y, mdp_rot_item->dst_rect.w, mdp_rot_item->dst_rect.h);
DLOGV_IF(kTagDriverConfig, "*************************************************************");
}
}
}
}
void HWRotator::SetBufferParams(HWLayers *hw_layers) {
HWLayersInfo &hw_layer_info = hw_layers->info;
uint32_t rot_count = 0;
DLOGV_IF(kTagDriverConfig, "************************* %s Commit Input **************************",
HWDevice::device_name_);
DLOGV_IF(kTagDriverConfig, "Rotate layer count is %d", mdp_rot_request_.count);
for (uint32_t i = 0; i < hw_layer_info.count; i++) {
Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
for (uint32_t count = 0; count < hw_rotator_session->hw_block_count; count++) {
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
if (hw_rotate_info->valid) {
mdp_rotation_item *mdp_rot_item = &mdp_rot_request_.list[rot_count];
mdp_rot_item->input.planes[0].fd = layer.input_buffer->planes[0].fd;
mdp_rot_item->input.planes[0].offset = layer.input_buffer->planes[0].offset;
SetStride(device_type_, layer.input_buffer->format, layer.input_buffer->width,
&mdp_rot_item->input.planes[0].stride);
mdp_rot_item->input.plane_count = 1;
mdp_rot_item->input.fence = layer.input_buffer->acquire_fence_fd;
mdp_rot_item->output.planes[0].fd = hw_rotator_session->output_buffer.planes[0].fd;
mdp_rot_item->output.planes[0].offset = hw_rotator_session->output_buffer.planes[0].offset;
SetStride(device_type_, hw_rotator_session->output_buffer.format,
hw_rotator_session->output_buffer.planes[0].stride,
&mdp_rot_item->output.planes[0].stride);
mdp_rot_item->output.plane_count = 1;
mdp_rot_item->output.fence = -1;
rot_count++;
DLOGV_IF(kTagDriverConfig, "******************** Layer[%d] %s rotate ********************",
i, count ? "Right" : "Left");
DLOGV_IF(kTagDriverConfig, "in_buf_fd %d, in_buf_offset %d, in_stride %d, " \
"in_plane_count %d, in_fence %d", mdp_rot_item->input.planes[0].fd,
mdp_rot_item->input.planes[0].offset, mdp_rot_item->input.planes[0].stride,
mdp_rot_item->input.plane_count, mdp_rot_item->input.fence);
DLOGV_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d, out_plane_count %d, " \
"out_fence %d", mdp_rot_item->output.planes[0].fd,
mdp_rot_item->output.planes[0].offset, mdp_rot_item->output.planes[0].stride,
mdp_rot_item->output.plane_count, mdp_rot_item->output.fence);
DLOGV_IF(kTagDriverConfig, "*************************************************************");
}
}
}
}
void HWRotator::SetMDPFlags(const Layer &layer, uint32_t *mdp_flags) {
LayerTransform transform = layer.transform;
bool rot90 = (transform.rotation == 90.0f);
if (rot90) {
*mdp_flags |= MDP_ROTATION_90;
}
if (transform.flip_horizontal) {
*mdp_flags |= MDP_ROTATION_FLIP_LR;
}
if (transform.flip_vertical) {
*mdp_flags |= MDP_ROTATION_FLIP_UD;
}
if (layer.input_buffer->flags.secure) {
*mdp_flags |= MDP_ROTATION_SECURE;
}
}
DisplayError HWRotator::Validate(HWLayers *hw_layers) {
SetCtrlParams(hw_layers);
mdp_rot_request_.flags = MDSS_ROTATION_REQUEST_VALIDATE;
if (ioctl_(HWDevice::device_fd_, MDSS_ROTATION_REQUEST, &mdp_rot_request_) < 0) {
IOCTL_LOGE(MDSS_ROTATION_REQUEST, HWDevice::device_type_);
return kErrorHardware;
}
return kErrorNone;
}
DisplayError HWRotator::Commit(HWLayers *hw_layers) {
HWLayersInfo &hw_layer_info = hw_layers->info;
uint32_t rot_count = 0;
SetCtrlParams(hw_layers);
SetBufferParams(hw_layers);
mdp_rot_request_.flags &= ~MDSS_ROTATION_REQUEST_VALIDATE;
if (ioctl_(HWDevice::device_fd_, MDSS_ROTATION_REQUEST, &mdp_rot_request_) < 0) {
IOCTL_LOGE(MDSS_ROTATION_REQUEST, HWDevice::device_type_);
return kErrorHardware;
}
for (uint32_t i = 0; i < hw_layer_info.count; i++) {
Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
layer.input_buffer->release_fence_fd = -1;
for (uint32_t count = 0; count < hw_rotator_session->hw_block_count; count++) {
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
if (hw_rotate_info->valid) {
mdp_rotation_item *mdp_rot_item = &mdp_rot_request_.list[rot_count];
HWDevice::SyncMerge(layer.input_buffer->release_fence_fd, dup(mdp_rot_item->output.fence),
&layer.input_buffer->release_fence_fd);
hw_rotator_session->output_buffer.acquire_fence_fd = dup(mdp_rot_item->output.fence);
close_(mdp_rot_item->output.fence);
rot_count++;
}
}
}
return kErrorNone;
}
void HWRotator::ResetParams() {
memset(&mdp_rot_request_, 0, sizeof(mdp_rot_request_));
memset(&mdp_rot_layers_, 0, sizeof(mdp_rot_layers_));
for (uint32_t i = 0; i < kMaxSDELayers * 2; i++) {
mdp_rot_layers_[i].input.fence = -1;
mdp_rot_layers_[i].output.fence = -1;
}
mdp_rot_request_.version = MDP_ROTATION_REQUEST_VERSION_1_0;
mdp_rot_request_.list = mdp_rot_layers_;
}
} // namespace sde