summaryrefslogtreecommitdiff
path: root/msm8909/sdm/libs/core/display_hdmi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'msm8909/sdm/libs/core/display_hdmi.cpp')
-rw-r--r--msm8909/sdm/libs/core/display_hdmi.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/msm8909/sdm/libs/core/display_hdmi.cpp b/msm8909/sdm/libs/core/display_hdmi.cpp
new file mode 100644
index 00000000..5f8eeb4d
--- /dev/null
+++ b/msm8909/sdm/libs/core/display_hdmi.cpp
@@ -0,0 +1,303 @@
+/*
+* Copyright (c) 2014 - 2018, 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 <map>
+#include <utility>
+#include <vector>
+
+#include "display_hdmi.h"
+#include "hw_interface.h"
+#include "hw_info_interface.h"
+
+#define __CLASS__ "DisplayHDMI"
+
+namespace sdm {
+
+DisplayHDMI::DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
+ CompManager *comp_manager)
+ : DisplayBase(kHDMI, event_handler, kDeviceHDMI, buffer_sync_handler, buffer_allocator,
+ comp_manager, hw_info_intf) {
+}
+
+DisplayError DisplayHDMI::Init() {
+ lock_guard<recursive_mutex> obj(recursive_mutex_);
+
+ DisplayError error = HWInterface::Create(kHDMI, hw_info_intf_, buffer_sync_handler_,
+ buffer_allocator_, &hw_intf_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ uint32_t active_mode_index;
+ char value[64] = "0";
+ Debug::GetProperty(HDMI_S3D_MODE_PROP, value);
+ HWS3DMode mode = (HWS3DMode)atoi(value);
+ if (mode > kS3DModeNone && mode < kS3DModeMax) {
+ active_mode_index = GetBestConfig(mode);
+ } else {
+ active_mode_index = GetBestConfig(kS3DModeNone);
+ }
+
+ error = hw_intf_->SetDisplayAttributes(active_mode_index);
+ if (error != kErrorNone) {
+ HWInterface::Destroy(hw_intf_);
+ }
+
+ error = DisplayBase::Init();
+ if (error != kErrorNone) {
+ HWInterface::Destroy(hw_intf_);
+ return error;
+ }
+
+ GetScanSupport();
+ underscan_supported_ = (scan_support_ == kScanAlwaysUnderscanned) || (scan_support_ == kScanBoth);
+
+ s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode>
+ (kS3dFormatNone, kS3DModeNone));
+ s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode>
+ (kS3dFormatLeftRight, kS3DModeLR));
+ s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode>
+ (kS3dFormatRightLeft, kS3DModeRL));
+ s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode>
+ (kS3dFormatTopBottom, kS3DModeTB));
+ s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode>
+ (kS3dFormatFramePacking, kS3DModeFP));
+
+ error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_);
+ if (error != kErrorNone) {
+ DisplayBase::Deinit();
+ HWInterface::Destroy(hw_intf_);
+ DLOGE("Failed to create hardware events interface. Error = %d", error);
+ }
+
+ return error;
+}
+
+DisplayError DisplayHDMI::Prepare(LayerStack *layer_stack) {
+ lock_guard<recursive_mutex> obj(recursive_mutex_);
+ DisplayError error = kErrorNone;
+ uint32_t new_mixer_width = 0;
+ uint32_t new_mixer_height = 0;
+ uint32_t display_width = display_attributes_.x_pixels;
+ uint32_t display_height = display_attributes_.y_pixels;
+
+ if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) {
+ error = ReconfigureMixer(new_mixer_width, new_mixer_height);
+ if (error != kErrorNone) {
+ ReconfigureMixer(display_width, display_height);
+ }
+ }
+
+ SetS3DMode(layer_stack);
+
+ // Clean hw layers for reuse.
+ hw_layers_ = HWLayers();
+
+ return DisplayBase::Prepare(layer_stack);
+}
+
+DisplayError DisplayHDMI::GetRefreshRateRange(uint32_t *min_refresh_rate,
+ uint32_t *max_refresh_rate) {
+ lock_guard<recursive_mutex> obj(recursive_mutex_);
+ 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 DisplayHDMI::SetRefreshRate(uint32_t refresh_rate) {
+ lock_guard<recursive_mutex> obj(recursive_mutex_);
+
+ if (!active_) {
+ return kErrorPermission;
+ }
+
+ DisplayError error = hw_intf_->SetRefreshRate(refresh_rate);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return DisplayBase::ReconfigureDisplay();
+}
+
+bool DisplayHDMI::IsUnderscanSupported() {
+ lock_guard<recursive_mutex> obj(recursive_mutex_);
+ return underscan_supported_;
+}
+
+DisplayError DisplayHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
+ lock_guard<recursive_mutex> obj(recursive_mutex_);
+ return hw_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level);
+}
+
+uint32_t DisplayHDMI::GetBestConfig(HWS3DMode s3d_mode) {
+ uint32_t best_index = 0, index;
+ uint32_t num_modes = 0;
+
+ hw_intf_->GetNumDisplayAttributes(&num_modes);
+
+ // Get display attribute for each mode
+ std::vector<HWDisplayAttributes> attrib(num_modes);
+ for (index = 0; index < num_modes; index++) {
+ hw_intf_->GetDisplayAttributes(index, &attrib[index]);
+ }
+
+ // Select best config for s3d_mode. If s3d is not enabled, s3d_mode is kS3DModeNone
+ for (index = 0; index < num_modes; index ++) {
+ if (attrib[index].s3d_config[s3d_mode]) {
+ break;
+ }
+ }
+ if (index < num_modes) {
+ best_index = UINT32(index);
+ for (size_t index = best_index + 1; index < num_modes; index ++) {
+ if (!attrib[index].s3d_config[s3d_mode])
+ continue;
+
+ // From the available configs, select the best
+ // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60
+ if (attrib[index].y_pixels > attrib[best_index].y_pixels) {
+ best_index = UINT32(index);
+ } else if (attrib[index].y_pixels == attrib[best_index].y_pixels) {
+ if (attrib[index].x_pixels > attrib[best_index].x_pixels) {
+ best_index = UINT32(index);
+ } else if (attrib[index].x_pixels == attrib[best_index].x_pixels) {
+ if (attrib[index].vsync_period_ns < attrib[best_index].vsync_period_ns) {
+ best_index = UINT32(index);
+ }
+ }
+ }
+ }
+ } else {
+ DLOGW("%s, could not support S3D mode from EDID info. S3D mode is %d",
+ __FUNCTION__, s3d_mode);
+ }
+
+ // Used for changing HDMI Resolution - override the best with user set config
+ uint32_t user_config = UINT32(Debug::GetHDMIResolution());
+ if (user_config) {
+ uint32_t config_index = 0;
+ // For the config, get the corresponding index
+ DisplayError error = hw_intf_->GetConfigIndex(user_config, &config_index);
+ if (error == kErrorNone)
+ return config_index;
+ }
+
+ return best_index;
+}
+
+void DisplayHDMI::GetScanSupport() {
+ DisplayError error = kErrorNone;
+ uint32_t video_format = 0;
+ uint32_t max_cea_format = 0;
+ HWScanInfo scan_info = HWScanInfo();
+ hw_intf_->GetHWScanInfo(&scan_info);
+
+ uint32_t active_mode_index = 0;
+ hw_intf_->GetActiveConfig(&active_mode_index);
+
+ error = hw_intf_->GetVideoFormat(active_mode_index, &video_format);
+ if (error != kErrorNone) {
+ return;
+ }
+
+ error = hw_intf_->GetMaxCEAFormat(&max_cea_format);
+ if (error != kErrorNone) {
+ return;
+ }
+
+ // The scan support for a given HDMI TV must be read from scan info corresponding to
+ // Preferred Timing if the preferred timing of the display is currently active, and if it is
+ // valid. In all other cases, we must read the scan support from CEA scan info if
+ // the resolution is a CEA resolution, or from IT scan info for all other resolutions.
+ if (active_mode_index == 0 && scan_info.pt_scan_support != kScanNotSupported) {
+ scan_support_ = scan_info.pt_scan_support;
+ } else if (video_format < max_cea_format) {
+ scan_support_ = scan_info.cea_scan_support;
+ } else {
+ scan_support_ = scan_info.it_scan_support;
+ }
+}
+
+void DisplayHDMI::SetS3DMode(LayerStack *layer_stack) {
+ uint32_t s3d_layer_count = 0;
+ HWS3DMode s3d_mode = kS3DModeNone;
+ uint32_t layer_count = UINT32(layer_stack->layers.size());
+
+ // S3D mode is supported for the following scenarios:
+ // 1. Layer stack containing only one s3d layer which is not skip
+ // 2. Layer stack containing only one secure layer along with one s3d layer
+ for (uint32_t i = 0; i < layer_count; i++) {
+ Layer *layer = layer_stack->layers.at(i);
+ LayerBuffer &layer_buffer = layer->input_buffer;
+
+ if (layer_buffer.s3d_format != kS3dFormatNone) {
+ s3d_layer_count++;
+ if (s3d_layer_count > 1 || layer->flags.skip) {
+ s3d_mode = kS3DModeNone;
+ break;
+ }
+
+ std::map<LayerBufferS3DFormat, HWS3DMode>::iterator it =
+ s3d_format_to_mode_.find(layer_buffer.s3d_format);
+ if (it != s3d_format_to_mode_.end()) {
+ s3d_mode = it->second;
+ }
+ } else if (layer_buffer.flags.secure && layer_count > 2) {
+ s3d_mode = kS3DModeNone;
+ break;
+ }
+ }
+
+ if (hw_intf_->SetS3DMode(s3d_mode) != kErrorNone) {
+ hw_intf_->SetS3DMode(kS3DModeNone);
+ layer_stack->flags.s3d_mode_present = false;
+ } else if (s3d_mode != kS3DModeNone) {
+ layer_stack->flags.s3d_mode_present = true;
+ }
+
+ DisplayBase::ReconfigureDisplay();
+}
+
+DisplayError DisplayHDMI::VSync(int64_t timestamp) {
+ if (vsync_enable_) {
+ DisplayEventVSync vsync;
+ vsync.timestamp = timestamp;
+ event_handler_->VSync(vsync);
+ }
+
+ return kErrorNone;
+}
+
+} // namespace sdm
+