| /* |
| * 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 |
| |