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