1/* 2* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. 3* 4* Redistribution and use in source and binary forms, with or without modification, are permitted 5* provided that the following conditions are met: 6* * Redistributions of source code must retain the above copyright notice, this list of 7* conditions and the following disclaimer. 8* * Redistributions in binary form must reproduce the above copyright notice, this list of 9* conditions and the following disclaimer in the documentation and/or other materials provided 10* with the distribution. 11* * Neither the name of The Linux Foundation nor the names of its contributors may be used to 12* endorse or promote products derived from this software without specific prior written 13* permission. 14* 15* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 21* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*/ 24 25#include <utils/constants.h> 26#include <utils/debug.h> 27#include <map> 28#include <utility> 29#include <vector> 30 31#include "display_hdmi.h" 32#include "hw_interface.h" 33#include "hw_info_interface.h" 34 35#define __CLASS__ "DisplayHDMI" 36 37namespace sdm { 38 39DisplayHDMI::DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, 40 BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager) 41 : DisplayBase(kHDMI, event_handler, kDeviceHDMI, buffer_sync_handler, comp_manager, 42 hw_info_intf) { 43} 44 45DisplayError DisplayHDMI::Init() { 46 lock_guard<recursive_mutex> obj(recursive_mutex_); 47 48 DisplayError error = HWInterface::Create(kHDMI, hw_info_intf_, buffer_sync_handler_, 49 &hw_intf_); 50 if (error != kErrorNone) { 51 return error; 52 } 53 54 uint32_t active_mode_index; 55 char value[64] = "0"; 56 Debug::GetProperty("sdm.hdmi.s3d_mode", value); 57 HWS3DMode mode = (HWS3DMode)atoi(value); 58 if (mode > kS3DModeNone && mode < kS3DModeMax) { 59 active_mode_index = GetBestConfig(mode); 60 } else { 61 active_mode_index = GetBestConfig(kS3DModeNone); 62 } 63 64 error = hw_intf_->SetDisplayAttributes(active_mode_index); 65 if (error != kErrorNone) { 66 HWInterface::Destroy(hw_intf_); 67 } 68 69 error = DisplayBase::Init(); 70 if (error != kErrorNone) { 71 HWInterface::Destroy(hw_intf_); 72 return error; 73 } 74 75 GetScanSupport(); 76 underscan_supported_ = (scan_support_ == kScanAlwaysUnderscanned) || (scan_support_ == kScanBoth); 77 78 s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> 79 (kS3dFormatNone, kS3DModeNone)); 80 s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> 81 (kS3dFormatLeftRight, kS3DModeLR)); 82 s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> 83 (kS3dFormatRightLeft, kS3DModeRL)); 84 s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> 85 (kS3dFormatTopBottom, kS3DModeTB)); 86 s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> 87 (kS3dFormatFramePacking, kS3DModeFP)); 88 89 error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_); 90 if (error != kErrorNone) { 91 DisplayBase::Deinit(); 92 HWInterface::Destroy(hw_intf_); 93 DLOGE("Failed to create hardware events interface. Error = %d", error); 94 } 95 96 return error; 97} 98 99DisplayError DisplayHDMI::Prepare(LayerStack *layer_stack) { 100 lock_guard<recursive_mutex> obj(recursive_mutex_); 101 DisplayError error = kErrorNone; 102 uint32_t new_mixer_width = 0; 103 uint32_t new_mixer_height = 0; 104 uint32_t display_width = display_attributes_.x_pixels; 105 uint32_t display_height = display_attributes_.y_pixels; 106 107 if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) { 108 error = ReconfigureMixer(new_mixer_width, new_mixer_height); 109 if (error != kErrorNone) { 110 ReconfigureMixer(display_width, display_height); 111 } 112 } 113 114 SetS3DMode(layer_stack); 115 116 // Clean hw layers for reuse. 117 hw_layers_ = HWLayers(); 118 119 return DisplayBase::Prepare(layer_stack); 120} 121 122DisplayError DisplayHDMI::GetRefreshRateRange(uint32_t *min_refresh_rate, 123 uint32_t *max_refresh_rate) { 124 lock_guard<recursive_mutex> obj(recursive_mutex_); 125 DisplayError error = kErrorNone; 126 127 if (hw_panel_info_.min_fps && hw_panel_info_.max_fps) { 128 *min_refresh_rate = hw_panel_info_.min_fps; 129 *max_refresh_rate = hw_panel_info_.max_fps; 130 } else { 131 error = DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate); 132 } 133 134 return error; 135} 136 137DisplayError DisplayHDMI::SetRefreshRate(uint32_t refresh_rate) { 138 lock_guard<recursive_mutex> obj(recursive_mutex_); 139 140 if (!active_) { 141 return kErrorPermission; 142 } 143 144 DisplayError error = hw_intf_->SetRefreshRate(refresh_rate); 145 if (error != kErrorNone) { 146 return error; 147 } 148 149 return DisplayBase::ReconfigureDisplay(); 150} 151 152bool DisplayHDMI::IsUnderscanSupported() { 153 lock_guard<recursive_mutex> obj(recursive_mutex_); 154 return underscan_supported_; 155} 156 157DisplayError DisplayHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { 158 lock_guard<recursive_mutex> obj(recursive_mutex_); 159 return hw_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level); 160} 161 162uint32_t DisplayHDMI::GetBestConfig(HWS3DMode s3d_mode) { 163 uint32_t best_index = 0, index; 164 uint32_t num_modes = 0; 165 166 hw_intf_->GetNumDisplayAttributes(&num_modes); 167 168 // Get display attribute for each mode 169 std::vector<HWDisplayAttributes> attrib(num_modes); 170 for (index = 0; index < num_modes; index++) { 171 hw_intf_->GetDisplayAttributes(index, &attrib[index]); 172 } 173 174 // Select best config for s3d_mode. If s3d is not enabled, s3d_mode is kS3DModeNone 175 for (index = 0; index < num_modes; index ++) { 176 if (attrib[index].s3d_config[s3d_mode]) { 177 break; 178 } 179 } 180 if (index < num_modes) { 181 best_index = UINT32(index); 182 for (size_t index = best_index + 1; index < num_modes; index ++) { 183 if (!attrib[index].s3d_config[s3d_mode]) 184 continue; 185 186 // From the available configs, select the best 187 // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60 188 if (attrib[index].y_pixels > attrib[best_index].y_pixels) { 189 best_index = UINT32(index); 190 } else if (attrib[index].y_pixels == attrib[best_index].y_pixels) { 191 if (attrib[index].x_pixels > attrib[best_index].x_pixels) { 192 best_index = UINT32(index); 193 } else if (attrib[index].x_pixels == attrib[best_index].x_pixels) { 194 if (attrib[index].vsync_period_ns < attrib[best_index].vsync_period_ns) { 195 best_index = UINT32(index); 196 } 197 } 198 } 199 } 200 } else { 201 DLOGW("%s, could not support S3D mode from EDID info. S3D mode is %d", 202 __FUNCTION__, s3d_mode); 203 } 204 205 // Used for changing HDMI Resolution - override the best with user set config 206 uint32_t user_config = UINT32(Debug::GetHDMIResolution()); 207 if (user_config) { 208 uint32_t config_index = 0; 209 // For the config, get the corresponding index 210 DisplayError error = hw_intf_->GetConfigIndex(user_config, &config_index); 211 if (error == kErrorNone) 212 return config_index; 213 } 214 215 return best_index; 216} 217 218void DisplayHDMI::GetScanSupport() { 219 DisplayError error = kErrorNone; 220 uint32_t video_format = 0; 221 uint32_t max_cea_format = 0; 222 HWScanInfo scan_info = HWScanInfo(); 223 hw_intf_->GetHWScanInfo(&scan_info); 224 225 uint32_t active_mode_index = 0; 226 hw_intf_->GetActiveConfig(&active_mode_index); 227 228 error = hw_intf_->GetVideoFormat(active_mode_index, &video_format); 229 if (error != kErrorNone) { 230 return; 231 } 232 233 error = hw_intf_->GetMaxCEAFormat(&max_cea_format); 234 if (error != kErrorNone) { 235 return; 236 } 237 238 // The scan support for a given HDMI TV must be read from scan info corresponding to 239 // Preferred Timing if the preferred timing of the display is currently active, and if it is 240 // valid. In all other cases, we must read the scan support from CEA scan info if 241 // the resolution is a CEA resolution, or from IT scan info for all other resolutions. 242 if (active_mode_index == 0 && scan_info.pt_scan_support != kScanNotSupported) { 243 scan_support_ = scan_info.pt_scan_support; 244 } else if (video_format < max_cea_format) { 245 scan_support_ = scan_info.cea_scan_support; 246 } else { 247 scan_support_ = scan_info.it_scan_support; 248 } 249} 250 251void DisplayHDMI::SetS3DMode(LayerStack *layer_stack) { 252 uint32_t s3d_layer_count = 0; 253 HWS3DMode s3d_mode = kS3DModeNone; 254 uint32_t layer_count = UINT32(layer_stack->layers.size()); 255 256 // S3D mode is supported for the following scenarios: 257 // 1. Layer stack containing only one s3d layer which is not skip 258 // 2. Layer stack containing only one secure layer along with one s3d layer 259 for (uint32_t i = 0; i < layer_count; i++) { 260 Layer *layer = layer_stack->layers.at(i); 261 LayerBuffer &layer_buffer = layer->input_buffer; 262 263 if (layer_buffer.s3d_format != kS3dFormatNone) { 264 s3d_layer_count++; 265 if (s3d_layer_count > 1 || layer->flags.skip) { 266 s3d_mode = kS3DModeNone; 267 break; 268 } 269 270 std::map<LayerBufferS3DFormat, HWS3DMode>::iterator it = 271 s3d_format_to_mode_.find(layer_buffer.s3d_format); 272 if (it != s3d_format_to_mode_.end()) { 273 s3d_mode = it->second; 274 } 275 } else if (layer_buffer.flags.secure && layer_count > 2) { 276 s3d_mode = kS3DModeNone; 277 break; 278 } 279 } 280 281 if (hw_intf_->SetS3DMode(s3d_mode) != kErrorNone) { 282 hw_intf_->SetS3DMode(kS3DModeNone); 283 layer_stack->flags.s3d_mode_present = false; 284 } else if (s3d_mode != kS3DModeNone) { 285 layer_stack->flags.s3d_mode_present = true; 286 } 287 288 DisplayBase::ReconfigureDisplay(); 289} 290 291void DisplayHDMI::CECMessage(char *message) { 292 event_handler_->CECMessage(message); 293} 294 295DisplayError DisplayHDMI::VSync(int64_t timestamp) { 296 if (vsync_enable_) { 297 DisplayEventVSync vsync; 298 vsync.timestamp = timestamp; 299 event_handler_->VSync(vsync); 300 } 301 302 return kErrorNone; 303} 304 305} // namespace sdm 306 307