| /* |
| * Copyright (c) 2014 - 2016, 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/constants.h> |
| #include <utils/debug.h> |
| |
| #include "display_primary.h" |
| #include "hw_interface.h" |
| #include "hw_info_interface.h" |
| #include "fb/hw_primary.h" |
| |
| #define __CLASS__ "DisplayPrimary" |
| |
| namespace sdm { |
| |
| DisplayPrimary::DisplayPrimary(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, |
| BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager, |
| RotatorInterface *rotator_intf) |
| : DisplayBase(kPrimary, event_handler, kDevicePrimary, buffer_sync_handler, comp_manager, |
| rotator_intf, hw_info_intf) { |
| } |
| |
| DisplayError DisplayPrimary::Init() { |
| SCOPE_LOCK(locker_); |
| |
| DisplayError error = HWPrimary::Create(&hw_intf_, hw_info_intf_, |
| DisplayBase::buffer_sync_handler_); |
| |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| error = DisplayBase::Init(); |
| if (error != kErrorNone) { |
| HWPrimary::Destroy(hw_intf_); |
| return error; |
| } |
| |
| idle_timeout_ms_ = Debug::GetIdleTimeoutMs(); |
| |
| if (hw_panel_info_.mode == kModeCommand && Debug::IsVideoModeEnabled()) { |
| error = hw_intf_->SetDisplayMode(kModeVideo); |
| if (error != kErrorNone) { |
| DLOGW("Retaining current display mode. Current = %d, Requested = %d", hw_panel_info_.mode, |
| kModeVideo); |
| } |
| } |
| |
| error = HWEventsInterface::Create(INT(display_type_), this, &event_list_, &hw_events_intf_); |
| if (error != kErrorNone) { |
| DLOGE("Failed to create hardware events interface. Error = %d", error); |
| DisplayBase::Deinit(); |
| HWPrimary::Destroy(hw_intf_); |
| } |
| |
| return error; |
| } |
| |
| DisplayError DisplayPrimary::Deinit() { |
| SCOPE_LOCK(locker_); |
| |
| DisplayError error = DisplayBase::Deinit(); |
| HWPrimary::Destroy(hw_intf_); |
| |
| return error; |
| } |
| |
| DisplayError DisplayPrimary::Prepare(LayerStack *layer_stack) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::Prepare(layer_stack); |
| } |
| |
| DisplayError DisplayPrimary::Commit(LayerStack *layer_stack) { |
| SCOPE_LOCK(locker_); |
| DisplayError error = kErrorNone; |
| HWPanelInfo panel_info; |
| HWDisplayAttributes display_attributes; |
| uint32_t active_index = 0; |
| |
| // Enabling auto refresh is async and needs to happen before commit ioctl |
| if (hw_panel_info_.mode == kModeCommand) { |
| hw_intf_->SetAutoRefresh(layer_stack->flags.single_buffered_layer_present); |
| } |
| |
| bool set_idle_timeout = comp_manager_->CanSetIdleTimeout(display_comp_ctx_); |
| |
| error = DisplayBase::Commit(layer_stack); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| hw_intf_->GetHWPanelInfo(&panel_info); |
| hw_intf_->GetActiveConfig(&active_index); |
| hw_intf_->GetDisplayAttributes(active_index, &display_attributes); |
| |
| if (panel_info != hw_panel_info_) { |
| error = comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, panel_info); |
| hw_panel_info_ = panel_info; |
| } |
| |
| if (hw_panel_info_.mode == kModeVideo) { |
| if (set_idle_timeout && !layer_stack->flags.single_buffered_layer_present) { |
| hw_intf_->SetIdleTimeoutMs(idle_timeout_ms_); |
| } else { |
| hw_intf_->SetIdleTimeoutMs(0); |
| } |
| } |
| |
| return error; |
| } |
| |
| DisplayError DisplayPrimary::Flush() { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::Flush(); |
| } |
| |
| DisplayError DisplayPrimary::GetDisplayState(DisplayState *state) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::GetDisplayState(state); |
| } |
| |
| DisplayError DisplayPrimary::GetNumVariableInfoConfigs(uint32_t *count) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::GetNumVariableInfoConfigs(count); |
| } |
| |
| DisplayError DisplayPrimary::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::GetConfig(index, variable_info); |
| } |
| |
| DisplayError DisplayPrimary::GetActiveConfig(uint32_t *index) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::GetActiveConfig(index); |
| } |
| |
| DisplayError DisplayPrimary::GetVSyncState(bool *enabled) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::GetVSyncState(enabled); |
| } |
| |
| bool DisplayPrimary::IsUnderscanSupported() { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::IsUnderscanSupported(); |
| } |
| |
| DisplayError DisplayPrimary::SetDisplayState(DisplayState state) { |
| SCOPE_LOCK(locker_); |
| DisplayError error = kErrorNone; |
| error = DisplayBase::SetDisplayState(state); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| // Set vsync enable state to false, as driver disables vsync during display power off. |
| if (state == kStateOff) { |
| vsync_enable_ = false; |
| } |
| |
| return kErrorNone; |
| } |
| |
| DisplayError DisplayPrimary::SetActiveConfig(DisplayConfigVariableInfo *variable_info) { |
| SCOPE_LOCK(locker_); |
| return kErrorNotSupported; |
| } |
| |
| DisplayError DisplayPrimary::SetActiveConfig(uint32_t index) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::SetActiveConfig(index); |
| } |
| |
| DisplayError DisplayPrimary::SetVSyncState(bool enable) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::SetVSyncState(enable); |
| } |
| |
| void DisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) { |
| SCOPE_LOCK(locker_); |
| |
| // Idle fallback feature is supported only for video mode panel. |
| if (hw_panel_info_.mode == kModeVideo) { |
| hw_intf_->SetIdleTimeoutMs(timeout_ms); |
| } |
| idle_timeout_ms_ = timeout_ms; |
| } |
| |
| DisplayError DisplayPrimary::SetMaxMixerStages(uint32_t max_mixer_stages) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::SetMaxMixerStages(max_mixer_stages); |
| } |
| |
| DisplayError DisplayPrimary::SetDisplayMode(uint32_t mode) { |
| SCOPE_LOCK(locker_); |
| DisplayError error = kErrorNone; |
| HWDisplayMode hw_display_mode = kModeDefault; |
| |
| if (!active_) { |
| DLOGW("Invalid display state = %d. Panel must be on.", state_); |
| return kErrorNotSupported; |
| } |
| |
| switch (mode) { |
| case kModeVideo: |
| hw_display_mode = kModeVideo; |
| break; |
| case kModeCommand: |
| hw_display_mode = kModeCommand; |
| break; |
| default: |
| DLOGW("Invalid panel mode parameters. Requested = %d", mode); |
| return kErrorParameters; |
| } |
| |
| if (hw_display_mode == hw_panel_info_.mode) { |
| DLOGW("Same display mode requested. Current = %d, Requested = %d", hw_panel_info_.mode, |
| hw_display_mode); |
| return kErrorNone; |
| } |
| |
| error = hw_intf_->SetDisplayMode(hw_display_mode); |
| if (error != kErrorNone) { |
| DLOGW("Retaining current display mode. Current = %d, Requested = %d", hw_panel_info_.mode, |
| hw_display_mode); |
| return error; |
| } |
| |
| // Disable PU if the previous PU state is on when switching to video mode, and re-enable PU when |
| // switching back to command mode. |
| bool toggle_partial_update = !(hw_display_mode == kModeVideo); |
| if (partial_update_control_) { |
| comp_manager_->ControlPartialUpdate(display_comp_ctx_, toggle_partial_update); |
| } |
| |
| if (hw_display_mode == kModeVideo) { |
| hw_intf_->SetIdleTimeoutMs(idle_timeout_ms_); |
| } else if (hw_display_mode == kModeCommand) { |
| hw_intf_->SetIdleTimeoutMs(0); |
| } |
| |
| return error; |
| } |
| |
| DisplayError DisplayPrimary::SetPanelBrightness(int level) { |
| SCOPE_LOCK(locker_); |
| return hw_intf_->SetPanelBrightness(level); |
| } |
| |
| DisplayError DisplayPrimary::IsScalingValid(const LayerRect &crop, const LayerRect &dst, |
| bool rotate90) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::IsScalingValid(crop, dst, rotate90); |
| } |
| |
| DisplayError DisplayPrimary::GetRefreshRateRange(uint32_t *min_refresh_rate, |
| uint32_t *max_refresh_rate) { |
| SCOPE_LOCK(locker_); |
| DisplayError error = kErrorNone; |
| |
| if (hw_panel_info_.min_fps && hw_panel_info_.max_fps) { |
| *min_refresh_rate = hw_panel_info_.min_fps; |
| *max_refresh_rate = hw_panel_info_.max_fps; |
| } else { |
| error = DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate); |
| } |
| |
| return error; |
| } |
| |
| DisplayError DisplayPrimary::SetRefreshRate(uint32_t refresh_rate) { |
| SCOPE_LOCK(locker_); |
| |
| if (!active_ || !hw_panel_info_.dynamic_fps) { |
| return kErrorNotSupported; |
| } |
| |
| if (refresh_rate < hw_panel_info_.min_fps || refresh_rate > hw_panel_info_.max_fps) { |
| DLOGE("Invalid Fps = %d request", refresh_rate); |
| return kErrorParameters; |
| } |
| |
| DisplayError error = hw_intf_->SetRefreshRate(refresh_rate); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| HWDisplayAttributes display_attributes; |
| uint32_t active_index = 0; |
| error = hw_intf_->GetActiveConfig(&active_index); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| error = hw_intf_->GetDisplayAttributes(active_index, &display_attributes); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, hw_panel_info_); |
| |
| return kErrorNone; |
| } |
| |
| void DisplayPrimary::AppendDump(char *buffer, uint32_t length) { |
| SCOPE_LOCK(locker_); |
| DisplayBase::AppendDump(buffer, length); |
| } |
| |
| DisplayError DisplayPrimary::VSync(int64_t timestamp) { |
| if (vsync_enable_) { |
| DisplayEventVSync vsync; |
| vsync.timestamp = timestamp; |
| event_handler_->VSync(vsync); |
| } |
| |
| return kErrorNone; |
| } |
| |
| DisplayError DisplayPrimary::SetCursorPosition(int x, int y) { |
| SCOPE_LOCK(locker_); |
| return DisplayBase::SetCursorPosition(x, y); |
| } |
| |
| DisplayError DisplayPrimary::Blank(bool blank) { |
| SCOPE_LOCK(locker_); |
| return kErrorNone; |
| } |
| |
| void DisplayPrimary::IdleTimeout() { |
| event_handler_->Refresh(); |
| comp_manager_->ProcessIdleTimeout(display_comp_ctx_); |
| } |
| |
| void DisplayPrimary::ThermalEvent(int64_t thermal_level) { |
| SCOPE_LOCK(locker_); |
| comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level); |
| } |
| |
| DisplayError DisplayPrimary::GetPanelBrightness(int *level) { |
| SCOPE_LOCK(locker_); |
| return hw_intf_->GetPanelBrightness(level); |
| } |
| |
| } // namespace sdm |
| |