1 /*
2 * Copyright (c) 2014 - 2016, 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
30 #include "display_hdmi.h"
31 #include "hw_interface.h"
32 #include "hw_info_interface.h"
33 #include "fb/hw_hdmi.h"
34
35 #define __CLASS__ "DisplayHDMI"
36
37 namespace sdm {
38
DisplayHDMI(DisplayEventHandler * event_handler,HWInfoInterface * hw_info_intf,BufferSyncHandler * buffer_sync_handler,CompManager * comp_manager,RotatorInterface * rotator_intf)39 DisplayHDMI::DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
40 BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
41 RotatorInterface *rotator_intf)
42 : DisplayBase(kHDMI, event_handler, kDeviceHDMI, buffer_sync_handler, comp_manager,
43 rotator_intf, hw_info_intf) {
44 }
45
Init()46 DisplayError DisplayHDMI::Init() {
47 SCOPE_LOCK(locker_);
48
49 DisplayError error = HWHDMI::Create(&hw_intf_, hw_info_intf_,
50 DisplayBase::buffer_sync_handler_);
51 if (error != kErrorNone) {
52 return error;
53 }
54
55 uint32_t active_mode_index;
56 char value[64] = "0";
57 Debug::GetProperty("sdm.hdmi.s3d_mode", value);
58 HWS3DMode mode = (HWS3DMode)atoi(value);
59 if (mode > kS3DModeNone && mode < kS3DModeMax) {
60 active_mode_index = GetBestConfig(mode);
61 } else {
62 active_mode_index = GetBestConfig(kS3DModeNone);
63 }
64
65 error = hw_intf_->SetDisplayAttributes(active_mode_index);
66 if (error != kErrorNone) {
67 HWHDMI::Destroy(hw_intf_);
68 }
69
70 error = DisplayBase::Init();
71 if (error != kErrorNone) {
72 HWHDMI::Destroy(hw_intf_);
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 return error;
89 }
90
Deinit()91 DisplayError DisplayHDMI::Deinit() {
92 SCOPE_LOCK(locker_);
93
94 DisplayError error = DisplayBase::Deinit();
95 HWHDMI::Destroy(hw_intf_);
96
97 return error;
98 }
99
Prepare(LayerStack * layer_stack)100 DisplayError DisplayHDMI::Prepare(LayerStack *layer_stack) {
101 SCOPE_LOCK(locker_);
102
103 SetS3DMode(layer_stack);
104
105 return DisplayBase::Prepare(layer_stack);
106 }
107
Commit(LayerStack * layer_stack)108 DisplayError DisplayHDMI::Commit(LayerStack *layer_stack) {
109 SCOPE_LOCK(locker_);
110 return DisplayBase::Commit(layer_stack);
111 }
112
Flush()113 DisplayError DisplayHDMI::Flush() {
114 SCOPE_LOCK(locker_);
115 return DisplayBase::Flush();
116 }
117
GetDisplayState(DisplayState * state)118 DisplayError DisplayHDMI::GetDisplayState(DisplayState *state) {
119 SCOPE_LOCK(locker_);
120 return DisplayBase::GetDisplayState(state);
121 }
122
GetNumVariableInfoConfigs(uint32_t * count)123 DisplayError DisplayHDMI::GetNumVariableInfoConfigs(uint32_t *count) {
124 SCOPE_LOCK(locker_);
125 return DisplayBase::GetNumVariableInfoConfigs(count);
126 }
127
GetConfig(uint32_t index,DisplayConfigVariableInfo * variable_info)128 DisplayError DisplayHDMI::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) {
129 SCOPE_LOCK(locker_);
130 return DisplayBase::GetConfig(index, variable_info);
131 }
132
GetActiveConfig(uint32_t * index)133 DisplayError DisplayHDMI::GetActiveConfig(uint32_t *index) {
134 SCOPE_LOCK(locker_);
135 return DisplayBase::GetActiveConfig(index);
136 }
137
GetVSyncState(bool * enabled)138 DisplayError DisplayHDMI::GetVSyncState(bool *enabled) {
139 SCOPE_LOCK(locker_);
140 return DisplayBase::GetVSyncState(enabled);
141 }
142
SetDisplayState(DisplayState state)143 DisplayError DisplayHDMI::SetDisplayState(DisplayState state) {
144 SCOPE_LOCK(locker_);
145 return DisplayBase::SetDisplayState(state);
146 }
147
SetActiveConfig(DisplayConfigVariableInfo * variable_info)148 DisplayError DisplayHDMI::SetActiveConfig(DisplayConfigVariableInfo *variable_info) {
149 SCOPE_LOCK(locker_);
150 return kErrorNotSupported;
151 }
152
SetActiveConfig(uint32_t index)153 DisplayError DisplayHDMI::SetActiveConfig(uint32_t index) {
154 SCOPE_LOCK(locker_);
155 return DisplayBase::SetActiveConfig(index);
156 }
157
SetVSyncState(bool enable)158 DisplayError DisplayHDMI::SetVSyncState(bool enable) {
159 SCOPE_LOCK(locker_);
160 return kErrorNotSupported;
161 }
162
SetIdleTimeoutMs(uint32_t timeout_ms)163 void DisplayHDMI::SetIdleTimeoutMs(uint32_t timeout_ms) { }
164
SetMaxMixerStages(uint32_t max_mixer_stages)165 DisplayError DisplayHDMI::SetMaxMixerStages(uint32_t max_mixer_stages) {
166 SCOPE_LOCK(locker_);
167 return DisplayBase::SetMaxMixerStages(max_mixer_stages);
168 }
169
SetDisplayMode(uint32_t mode)170 DisplayError DisplayHDMI::SetDisplayMode(uint32_t mode) {
171 SCOPE_LOCK(locker_);
172 return DisplayBase::SetDisplayMode(mode);
173 }
174
IsScalingValid(const LayerRect & crop,const LayerRect & dst,bool rotate90)175 DisplayError DisplayHDMI::IsScalingValid(const LayerRect &crop, const LayerRect &dst,
176 bool rotate90) {
177 SCOPE_LOCK(locker_);
178 return DisplayBase::IsScalingValid(crop, dst, rotate90);
179 }
180
GetRefreshRateRange(uint32_t * min_refresh_rate,uint32_t * max_refresh_rate)181 DisplayError DisplayHDMI::GetRefreshRateRange(uint32_t *min_refresh_rate,
182 uint32_t *max_refresh_rate) {
183 SCOPE_LOCK(locker_);
184 return DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate);
185 }
186
SetRefreshRate(uint32_t refresh_rate)187 DisplayError DisplayHDMI::SetRefreshRate(uint32_t refresh_rate) {
188 SCOPE_LOCK(locker_);
189 return kErrorNotSupported;
190 }
191
IsUnderscanSupported()192 bool DisplayHDMI::IsUnderscanSupported() {
193 SCOPE_LOCK(locker_);
194 return DisplayBase::IsUnderscanSupported();
195 }
196
SetPanelBrightness(int level)197 DisplayError DisplayHDMI::SetPanelBrightness(int level) {
198 SCOPE_LOCK(locker_);
199 return DisplayBase::SetPanelBrightness(level);
200 }
201
OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level)202 DisplayError DisplayHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
203 SCOPE_LOCK(locker_);
204 return hw_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level);
205 }
206
GetBestConfig(HWS3DMode s3d_mode)207 uint32_t DisplayHDMI::GetBestConfig(HWS3DMode s3d_mode) {
208 uint32_t best_index = 0, index;
209 uint32_t num_modes = 0;
210 HWDisplayAttributes best_attrib;
211
212 hw_intf_->GetNumDisplayAttributes(&num_modes);
213
214 // Get display attribute for each mode
215 HWDisplayAttributes *attrib = new HWDisplayAttributes[num_modes];
216 for (index = 0; index < num_modes; index++) {
217 hw_intf_->GetDisplayAttributes(index, &attrib[index]);
218 }
219
220 // Select best config for s3d_mode. If s3d is not enabled, s3d_mode is kS3DModeNone
221 for (index = 0; index < num_modes; index ++) {
222 if (IS_BIT_SET(attrib[index].s3d_config, s3d_mode)) {
223 break;
224 }
225 }
226 if (index < num_modes) {
227 best_index = UINT32(index);
228 for (size_t index = best_index + 1; index < num_modes; index ++) {
229 if (!IS_BIT_SET(attrib[index].s3d_config, s3d_mode))
230 continue;
231
232 // From the available configs, select the best
233 // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60
234 if (attrib[index].y_pixels > attrib[best_index].y_pixels) {
235 best_index = UINT32(index);
236 } else if (attrib[index].y_pixels == attrib[best_index].y_pixels) {
237 if (attrib[index].x_pixels > attrib[best_index].x_pixels) {
238 best_index = UINT32(index);
239 } else if (attrib[index].x_pixels == attrib[best_index].x_pixels) {
240 if (attrib[index].vsync_period_ns < attrib[best_index].vsync_period_ns) {
241 best_index = UINT32(index);
242 }
243 }
244 }
245 }
246 } else {
247 DLOGW("%s, could not support S3D mode from EDID info. S3D mode is %d",
248 __FUNCTION__, s3d_mode);
249 }
250 delete[] attrib;
251
252 // Used for changing HDMI Resolution - override the best with user set config
253 uint32_t user_config = UINT32(Debug::GetHDMIResolution());
254 if (user_config) {
255 uint32_t config_index = 0;
256 // For the config, get the corresponding index
257 DisplayError error = hw_intf_->GetConfigIndex(user_config, &config_index);
258 if (error == kErrorNone)
259 return config_index;
260 }
261
262 return best_index;
263 }
264
GetScanSupport()265 void DisplayHDMI::GetScanSupport() {
266 DisplayError error = kErrorNone;
267 uint32_t video_format = 0;
268 uint32_t max_cea_format = 0;
269 HWScanInfo scan_info = HWScanInfo();
270 hw_intf_->GetHWScanInfo(&scan_info);
271
272 uint32_t active_mode_index = 0;
273 hw_intf_->GetActiveConfig(&active_mode_index);
274
275 error = hw_intf_->GetVideoFormat(active_mode_index, &video_format);
276 if (error != kErrorNone) {
277 return;
278 }
279
280 error = hw_intf_->GetMaxCEAFormat(&max_cea_format);
281 if (error != kErrorNone) {
282 return;
283 }
284
285 // The scan support for a given HDMI TV must be read from scan info corresponding to
286 // Preferred Timing if the preferred timing of the display is currently active, and if it is
287 // valid. In all other cases, we must read the scan support from CEA scan info if
288 // the resolution is a CEA resolution, or from IT scan info for all other resolutions.
289 if (active_mode_index == 0 && scan_info.pt_scan_support != kScanNotSupported) {
290 scan_support_ = scan_info.pt_scan_support;
291 } else if (video_format < max_cea_format) {
292 scan_support_ = scan_info.cea_scan_support;
293 } else {
294 scan_support_ = scan_info.it_scan_support;
295 }
296 }
297
AppendDump(char * buffer,uint32_t length)298 void DisplayHDMI::AppendDump(char *buffer, uint32_t length) {
299 SCOPE_LOCK(locker_);
300 DisplayBase::AppendDump(buffer, length);
301 }
302
SetCursorPosition(int x,int y)303 DisplayError DisplayHDMI::SetCursorPosition(int x, int y) {
304 SCOPE_LOCK(locker_);
305 return DisplayBase::SetCursorPosition(x, y);
306 }
307
SetS3DMode(LayerStack * layer_stack)308 void DisplayHDMI::SetS3DMode(LayerStack *layer_stack) {
309 uint32_t s3d_layer_count = 0;
310 HWS3DMode s3d_mode = kS3DModeNone;
311 HWPanelInfo panel_info;
312 HWDisplayAttributes display_attributes;
313 uint32_t active_index = 0;
314 uint32_t layer_count = layer_stack->layer_count;
315
316 // S3D mode is supported for the following scenarios:
317 // 1. Layer stack containing only one s3d layer which is not skip
318 // 2. Layer stack containing only one secure layer along with one s3d layer
319 for (uint32_t i = 0; i < layer_count; i++) {
320 Layer &layer = layer_stack->layers[i];
321 LayerBuffer *layer_buffer = layer.input_buffer;
322
323 if (layer_buffer->s3d_format != kS3dFormatNone) {
324 s3d_layer_count++;
325 if (s3d_layer_count > 1 || layer.flags.skip) {
326 s3d_mode = kS3DModeNone;
327 break;
328 }
329
330 std::map<LayerBufferS3DFormat, HWS3DMode>::iterator it =
331 s3d_format_to_mode_.find(layer_buffer->s3d_format);
332 if (it != s3d_format_to_mode_.end()) {
333 s3d_mode = it->second;
334 }
335 } else if (layer_buffer->flags.secure && layer_count > 2) {
336 s3d_mode = kS3DModeNone;
337 break;
338 }
339 }
340
341 if (hw_intf_->SetS3DMode(s3d_mode) != kErrorNone) {
342 hw_intf_->SetS3DMode(kS3DModeNone);
343 layer_stack->flags.s3d_mode_present = false;
344 } else if (s3d_mode != kS3DModeNone) {
345 layer_stack->flags.s3d_mode_present = true;
346 }
347
348 hw_intf_->GetHWPanelInfo(&panel_info);
349 hw_intf_->GetActiveConfig(&active_index);
350 hw_intf_->GetDisplayAttributes(active_index, &display_attributes);
351
352 if (panel_info != hw_panel_info_) {
353 comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, panel_info);
354 hw_panel_info_ = panel_info;
355 }
356 }
357
358 } // namespace sdm
359
360