1/*
2* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are
6* met:
7*     * Redistributions of source code must retain the above copyright
8*       notice, this list of conditions and the following disclaimer.
9*     * Redistributions in binary form must reproduce the above
10*       copyright notice, this list of conditions and the following
11*       disclaimer in the documentation and/or other materials provided
12*       with the distribution.
13*     * Neither the name of The Linux Foundation nor the names of its
14*       contributors may be used to endorse or promote products derived
15*       from this software without specific prior written permission.
16*
17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#include <stdio.h>
31#include <unistd.h>
32#include <string.h>
33#include <pthread.h>
34#include <fcntl.h>
35#include <sys/prctl.h>
36#include <sys/ioctl.h>
37#include <sys/time.h>
38#include <sys/resource.h>
39#include <utils/debug.h>
40#include <utils/sys.h>
41#include <core/display_interface.h>
42#include <linux/msm_mdp_ext.h>
43#include <utils/rect.h>
44
45#include <string>
46
47#include "hw_primary.h"
48#include "hw_color_manager.h"
49
50#define __CLASS__ "HWPrimary"
51
52#ifndef MDP_COMMIT_CWB_EN
53#define MDP_COMMIT_CWB_EN 0x800
54#endif
55
56#ifndef MDP_COMMIT_CWB_DSPP
57#define MDP_COMMIT_CWB_DSPP 0x1000
58#endif
59
60namespace sdm {
61
62using std::string;
63using std::to_string;
64using std::fstream;
65
66DisplayError HWPrimary::Create(HWInterface **intf, HWInfoInterface *hw_info_intf,
67                               BufferSyncHandler *buffer_sync_handler) {
68  DisplayError error = kErrorNone;
69  HWPrimary *hw_primary = NULL;
70
71  hw_primary = new HWPrimary(buffer_sync_handler, hw_info_intf);
72  error = hw_primary->Init();
73  if (error != kErrorNone) {
74    delete hw_primary;
75  } else {
76    *intf = hw_primary;
77  }
78
79  return error;
80}
81
82DisplayError HWPrimary::Destroy(HWInterface *intf) {
83  HWPrimary *hw_primary = static_cast<HWPrimary *>(intf);
84  hw_primary->Deinit();
85  delete hw_primary;
86
87  return kErrorNone;
88}
89
90HWPrimary::HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
91  : HWDevice(buffer_sync_handler) {
92  HWDevice::device_type_ = kDevicePrimary;
93  HWDevice::device_name_ = "Primary Display Device";
94  HWDevice::hw_info_intf_ = hw_info_intf;
95}
96
97DisplayError HWPrimary::Init() {
98  DisplayError error = kErrorNone;
99
100  error = HWDevice::Init();
101  if (error != kErrorNone) {
102    return error;
103  }
104
105  mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
106
107  error = PopulateDisplayAttributes();
108  if (error != kErrorNone) {
109    return error;
110  }
111
112  UpdateMixerAttributes();
113
114  // Need to enable HPD, but toggle at start when HDMI is external
115  // This helps for framework reboot or adb shell stop/start
116  EnableHotPlugDetection(0);
117  EnableHotPlugDetection(1);
118  InitializeConfigs();
119
120  return error;
121}
122
123bool HWPrimary::GetCurrentModeFromSysfs(size_t *curr_x_pixels, size_t *curr_y_pixels) {
124  bool ret = false;
125  string mode_path = fb_path_ + string("0/mode");
126
127  Sys::fstream fs(mode_path, fstream::in);
128  if (!fs.is_open()) {
129    return false;
130  }
131
132  string line;
133  if (Sys::getline_(fs, line)) {
134    // String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
135    // kernel has more info on the format.
136    size_t xpos = line.find(':');
137    size_t ypos = line.find('x');
138
139    if (xpos == string::npos || ypos == string::npos) {
140      DLOGI("Resolution switch not supported");
141    } else {
142      *curr_x_pixels = static_cast<size_t>(atoi(line.c_str() + xpos + 1));
143      *curr_y_pixels = static_cast<size_t>(atoi(line.c_str() + ypos + 1));
144      DLOGI("Current Config: %u x %u", *curr_x_pixels, *curr_y_pixels);
145      ret = true;
146    }
147  }
148
149  return ret;
150}
151
152void HWPrimary::InitializeConfigs() {
153  size_t curr_x_pixels = 0;
154  size_t curr_y_pixels = 0;
155
156  if (!GetCurrentModeFromSysfs(&curr_x_pixels, &curr_y_pixels)) {
157    return;
158  }
159
160  string modes_path = string(fb_path_) + string("0/modes");
161
162  Sys::fstream fs(modes_path, fstream::in);
163  if (!fs.is_open()) {
164    DLOGI("Unable to process modes");
165    return;
166  }
167
168  string line;
169  while (Sys::getline_(fs, line)) {
170    DisplayConfigVariableInfo config;
171    size_t xpos = line.find(':');
172    size_t ypos = line.find('x');
173
174    if (xpos == string::npos || ypos == string::npos) {
175      continue;
176    }
177
178    config.x_pixels = UINT32(atoi(line.c_str() + xpos + 1));
179    config.y_pixels = UINT32(atoi(line.c_str() + ypos + 1));
180    DLOGI("Found mode %d x %d", config.x_pixels, config.y_pixels);
181    display_configs_.push_back(config);
182    display_config_strings_.push_back(string(line.c_str()));
183
184    if (curr_x_pixels == config.x_pixels && curr_y_pixels == config.y_pixels) {
185      active_config_index_ = UINT32(display_configs_.size() - 1);
186      DLOGI("Active config index %u", active_config_index_);
187    }
188  }
189}
190
191DisplayError HWPrimary::Deinit() {
192  return HWDevice::Deinit();
193}
194
195DisplayError HWPrimary::GetNumDisplayAttributes(uint32_t *count) {
196  *count = IsResolutionSwitchEnabled() ? UINT32(display_configs_.size()) : 1;
197  return kErrorNone;
198}
199
200DisplayError HWPrimary::GetActiveConfig(uint32_t *active_config_index) {
201  *active_config_index = active_config_index_;
202  return kErrorNone;
203}
204
205DisplayError HWPrimary::GetDisplayAttributes(uint32_t index,
206                                             HWDisplayAttributes *display_attributes) {
207  if (!display_attributes) {
208    return kErrorParameters;
209  }
210
211  if (IsResolutionSwitchEnabled() && index >= display_configs_.size()) {
212    return kErrorParameters;
213  }
214
215  *display_attributes = display_attributes_;
216  if (IsResolutionSwitchEnabled()) {
217    // Overwrite only the parent portion of object
218    display_attributes->x_pixels = display_configs_.at(index).x_pixels;
219    display_attributes->y_pixels = display_configs_.at(index).y_pixels;
220  }
221
222  return kErrorNone;
223}
224
225DisplayError HWPrimary::PopulateDisplayAttributes() {
226  DTRACE_SCOPED();
227
228  // Variable screen info
229  fb_var_screeninfo var_screeninfo = {};
230
231  if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &var_screeninfo) < 0) {
232    IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
233    return kErrorHardware;
234  }
235
236  // Frame rate
237  msmfb_metadata meta_data = {};
238  meta_data.op = metadata_op_frame_rate;
239  if (Sys::ioctl_(device_fd_, MSMFB_METADATA_GET, &meta_data) < 0) {
240    IOCTL_LOGE(MSMFB_METADATA_GET, device_type_);
241    return kErrorHardware;
242  }
243
244  // If driver doesn't return width/height information, default to 160 dpi
245  if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
246    var_screeninfo.width  = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f) + 0.5f);
247    var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f) + 0.5f);
248  }
249
250  display_attributes_.x_pixels = var_screeninfo.xres;
251  display_attributes_.y_pixels = var_screeninfo.yres;
252  display_attributes_.v_front_porch = var_screeninfo.lower_margin;
253  display_attributes_.v_back_porch = var_screeninfo.upper_margin;
254  display_attributes_.v_pulse_width = var_screeninfo.vsync_len;
255  uint32_t h_blanking = var_screeninfo.right_margin + var_screeninfo.left_margin +
256      var_screeninfo.hsync_len;
257  display_attributes_.h_total = var_screeninfo.xres + h_blanking;
258  display_attributes_.x_dpi =
259      (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
260  display_attributes_.y_dpi =
261      (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
262  display_attributes_.fps = meta_data.data.panel_frame_rate;
263  display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps);
264  display_attributes_.is_device_split = (hw_panel_info_.split_info.left_split ||
265      (var_screeninfo.xres > hw_resource_.max_mixer_width)) ? true : false;
266  display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
267
268  return kErrorNone;
269}
270
271DisplayError HWPrimary::SetDisplayAttributes(uint32_t index) {
272  DisplayError ret = kErrorNone;
273
274  if (!IsResolutionSwitchEnabled()) {
275    return kErrorNotSupported;
276  }
277
278  if (index >= display_configs_.size()) {
279    return kErrorParameters;
280  }
281
282  string mode_path = string(fb_path_) + string("0/mode");
283  int fd = Sys::open_(mode_path.c_str(), O_WRONLY);
284
285  if (fd < 0) {
286    DLOGE("Opening mode failed");
287    return kErrorNotSupported;
288  }
289
290  ssize_t written = Sys::pwrite_(fd, display_config_strings_.at(index).c_str(),
291                                 display_config_strings_.at(index).length(), 0);
292  if (written > 0) {
293    DLOGI("Successfully set config %u", index);
294    PopulateHWPanelInfo();
295    PopulateDisplayAttributes();
296    UpdateMixerAttributes();
297    active_config_index_ = index;
298  } else {
299    DLOGE("Writing config index %u failed with error: %s", index, strerror(errno));
300    ret = kErrorParameters;
301  }
302
303  Sys::close_(fd);
304
305  return ret;
306}
307
308DisplayError HWPrimary::SetRefreshRate(uint32_t refresh_rate) {
309  char node_path[kMaxStringLength] = {0};
310
311  if (refresh_rate == display_attributes_.fps) {
312    return kErrorNone;
313  }
314
315  snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
316
317  int fd = Sys::open_(node_path, O_WRONLY);
318  if (fd < 0) {
319    DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
320    return kErrorFileDescriptor;
321  }
322
323  char refresh_rate_string[kMaxStringLength];
324  snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
325  DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate);
326  ssize_t len = Sys::pwrite_(fd, refresh_rate_string, strlen(refresh_rate_string), 0);
327  if (len < 0) {
328    DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
329    Sys::close_(fd);
330    return kErrorUndefined;
331  }
332  Sys::close_(fd);
333
334  DisplayError error = PopulateDisplayAttributes();
335  if (error != kErrorNone) {
336    return error;
337  }
338
339  return kErrorNone;
340}
341
342DisplayError HWPrimary::GetConfigIndex(uint32_t mode, uint32_t *index) {
343  return HWDevice::GetConfigIndex(mode, index);
344}
345
346DisplayError HWPrimary::PowerOff() {
347  if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) {
348    IOCTL_LOGE(FB_BLANK_POWERDOWN, device_type_);
349    return kErrorHardware;
350  }
351
352  return kErrorNone;
353}
354
355DisplayError HWPrimary::Doze() {
356  if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_NORMAL) < 0) {
357    IOCTL_LOGE(FB_BLANK_NORMAL, device_type_);
358    return kErrorHardware;
359  }
360
361  return kErrorNone;
362}
363
364DisplayError HWPrimary::DozeSuspend() {
365  if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_VSYNC_SUSPEND) < 0) {
366    IOCTL_LOGE(FB_BLANK_VSYNC_SUSPEND, device_type_);
367    return kErrorHardware;
368  }
369
370  return kErrorNone;
371}
372
373DisplayError HWPrimary::Validate(HWLayers *hw_layers) {
374  HWLayersInfo &hw_layer_info = hw_layers->info;
375  LayerStack *stack = hw_layer_info.stack;
376
377  HWDevice::ResetDisplayParams();
378
379  mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
380
381  LayerRect left_roi = hw_layer_info.left_partial_update;
382  LayerRect right_roi = hw_layer_info.right_partial_update;
383  mdp_commit.left_roi.x = UINT32(left_roi.left);
384  mdp_commit.left_roi.y = UINT32(left_roi.top);
385  mdp_commit.left_roi.w = UINT32(left_roi.right - left_roi.left);
386  mdp_commit.left_roi.h = UINT32(left_roi.bottom - left_roi.top);
387
388  // SDM treats ROI as one full coordinate system.
389  // In case source split is disabled, However, Driver assumes Mixer to operate in
390  // different co-ordinate system.
391  if (!hw_resource_.is_src_split && IsValid(right_roi)) {
392    mdp_commit.right_roi.x = UINT32(right_roi.left) - mixer_attributes_.split_left;
393    mdp_commit.right_roi.y = UINT32(right_roi.top);
394    mdp_commit.right_roi.w = UINT32(right_roi.right - right_roi.left);
395    mdp_commit.right_roi.h = UINT32(right_roi.bottom - right_roi.top);
396  }
397
398  if (stack->output_buffer && hw_resource_.has_concurrent_writeback) {
399    LayerBuffer *output_buffer = stack->output_buffer;
400    mdp_out_layer_.writeback_ndx = hw_resource_.writeback_index;
401    mdp_out_layer_.buffer.width = output_buffer->width;
402    mdp_out_layer_.buffer.height = output_buffer->height;
403    mdp_out_layer_.buffer.comp_ratio.denom = 1000;
404    mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000);
405    mdp_out_layer_.buffer.fence = -1;
406#ifdef OUT_LAYER_COLOR_SPACE
407    SetCSC(output_buffer->csc, &mdp_out_layer_.color_space);
408#endif
409    SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format);
410    mdp_commit.flags |= MDP_COMMIT_CWB_EN;
411    mdp_commit.flags |= (stack->flags.post_processed_output) ? MDP_COMMIT_CWB_DSPP : 0;
412    DLOGI_IF(kTagDriverConfig, "****************** Conc WB Output buffer Info ******************");
413    DLOGI_IF(kTagDriverConfig, "out_w %d, out_h %d, out_f %d, wb_id %d DSPP output %d",
414             mdp_out_layer_.buffer.width, mdp_out_layer_.buffer.height,
415             mdp_out_layer_.buffer.format, mdp_out_layer_.writeback_ndx,
416             stack->flags.post_processed_output);
417    DLOGI_IF(kTagDriverConfig, "****************************************************************");
418  }
419
420  return HWDevice::Validate(hw_layers);
421}
422
423DisplayError HWPrimary::Commit(HWLayers *hw_layers) {
424  LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
425
426  if (hw_resource_.has_concurrent_writeback && output_buffer) {
427    if (output_buffer->planes[0].fd >= 0) {
428      mdp_out_layer_.buffer.planes[0].fd = output_buffer->planes[0].fd;
429      mdp_out_layer_.buffer.planes[0].offset = output_buffer->planes[0].offset;
430      SetStride(device_type_, output_buffer->format, output_buffer->planes[0].stride,
431                &mdp_out_layer_.buffer.planes[0].stride);
432      mdp_out_layer_.buffer.plane_count = 1;
433      mdp_out_layer_.buffer.fence = -1;
434
435      DLOGI_IF(kTagDriverConfig, "****************** Conc WB Output buffer Info ****************");
436      DLOGI_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d",
437               mdp_out_layer_.buffer.planes[0].fd, mdp_out_layer_.buffer.planes[0].offset,
438               mdp_out_layer_.buffer.planes[0].stride);
439      DLOGI_IF(kTagDriverConfig, "**************************************************************");
440    } else {
441      DLOGE("Invalid output buffer fd");
442      return kErrorParameters;
443    }
444  }
445
446  DisplayError ret = HWDevice::Commit(hw_layers);
447
448  if (ret == kErrorNone && hw_resource_.has_concurrent_writeback && output_buffer) {
449    output_buffer->release_fence_fd = mdp_out_layer_.buffer.fence;
450  }
451
452  return ret;
453}
454
455void HWPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
456  char node_path[kMaxStringLength] = {0};
457
458  DLOGI_IF(kTagDriverConfig, "Setting idle timeout to = %d ms", timeout_ms);
459
460  snprintf(node_path, sizeof(node_path), "%s%d/idle_time", fb_path_, fb_node_index_);
461
462  // Open a sysfs node to send the timeout value to driver.
463  int fd = Sys::open_(node_path, O_WRONLY);
464  if (fd < 0) {
465    DLOGE("Unable to open %s, node %s", node_path, strerror(errno));
466    return;
467  }
468
469  char timeout_string[64];
470  snprintf(timeout_string, sizeof(timeout_string), "%d", timeout_ms);
471
472  // Notify driver about the timeout value
473  ssize_t length = Sys::pwrite_(fd, timeout_string, strlen(timeout_string), 0);
474  if (length <= 0) {
475    DLOGE("Unable to write into %s, node %s", node_path, strerror(errno));
476  }
477
478  Sys::close_(fd);
479}
480
481DisplayError HWPrimary::SetVSyncState(bool enable) {
482  DTRACE_SCOPED();
483  return HWDevice::SetVSyncState(enable);
484}
485
486DisplayError HWPrimary::SetDisplayMode(const HWDisplayMode hw_display_mode) {
487  uint32_t mode = kModeDefault;
488
489  switch (hw_display_mode) {
490  case kModeVideo:
491    mode = kModeLPMVideo;
492    break;
493  case kModeCommand:
494    mode = kModeLPMCommand;
495    break;
496  default:
497    DLOGW("Failed to translate SDE display mode %d to a MSMFB_LPM_ENABLE mode",
498          hw_display_mode);
499    return kErrorParameters;
500  }
501
502  if (Sys::ioctl_(device_fd_, INT(MSMFB_LPM_ENABLE), &mode) < 0) {
503    IOCTL_LOGE(MSMFB_LPM_ENABLE, device_type_);
504    return kErrorHardware;
505  }
506
507  DLOGI("Triggering display mode change to %d on next commit.", hw_display_mode);
508  synchronous_commit_ = true;
509
510  return kErrorNone;
511}
512
513DisplayError HWPrimary::SetPanelBrightness(int level) {
514  char buffer[MAX_SYSFS_COMMAND_LENGTH] = {0};
515
516  DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level);
517  int fd = Sys::open_(kBrightnessNode, O_RDWR);
518  if (fd < 0) {
519    DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode,
520             strerror(errno));
521    return kErrorFileDescriptor;
522  }
523
524  int32_t bytes = snprintf(buffer, MAX_SYSFS_COMMAND_LENGTH, "%d\n", level);
525  if (bytes < 0) {
526    DLOGV_IF(kTagDriverConfig, "Failed to copy new brightness level = %d", level);
527    Sys::close_(fd);
528    return kErrorUndefined;
529  }
530
531  ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
532  if (ret <= 0) {
533    DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode,
534             strerror(errno));
535    Sys::close_(fd);
536    return kErrorUndefined;
537  }
538  Sys::close_(fd);
539
540  return kErrorNone;
541}
542
543DisplayError HWPrimary::GetPanelBrightness(int *level) {
544  char brightness[kMaxStringLength] = {0};
545
546  if (!level) {
547    DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer.");
548    return kErrorParameters;
549  }
550
551  int fd = Sys::open_(kBrightnessNode, O_RDWR);
552  if (fd < 0) {
553    DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode,
554             strerror(errno));
555    return kErrorFileDescriptor;
556  }
557
558  if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
559    *level = atoi(brightness);
560    DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level);
561  }
562  Sys::close_(fd);
563
564  return kErrorNone;
565}
566
567DisplayError HWPrimary::SetAutoRefresh(bool enable) {
568  const int kWriteLength = 2;
569  char buffer[kWriteLength] = {'\0'};
570  ssize_t bytes = snprintf(buffer, kWriteLength, "%d", enable);
571
572  if (enable == auto_refresh_) {
573    return kErrorNone;
574  }
575
576  if (HWDevice::SysFsWrite(kAutoRefreshNode, buffer, bytes) <= 0) {  // Returns bytes written
577    return kErrorUndefined;
578  }
579
580  auto_refresh_ = enable;
581
582  return kErrorNone;
583}
584
585DisplayError HWPrimary::GetPPFeaturesVersion(PPFeatureVersion *vers) {
586  mdp_pp_feature_version version = {};
587
588  uint32_t feature_id_mapping[kMaxNumPPFeatures] = { PCC, IGC, GC, GC, PA, DITHER, GAMUT };
589
590  for (int i(0); i < kMaxNumPPFeatures; i++) {
591    version.pp_feature = feature_id_mapping[i];
592
593    if (Sys::ioctl_(device_fd_,  INT(MSMFB_MDP_PP_GET_FEATURE_VERSION), &version) < 0) {
594      IOCTL_LOGE(MSMFB_MDP_PP_GET_FEATURE_VERSION, device_type_);
595      return kErrorHardware;
596    }
597    vers->version[i] = version.version_info;
598  }
599
600  return kErrorNone;
601}
602
603// It was entered with PPFeaturesConfig::locker_ being hold.
604DisplayError HWPrimary::SetPPFeatures(PPFeaturesConfig *feature_list) {
605  msmfb_mdp_pp kernel_params = {};
606  int ret = 0;
607  PPFeatureInfo *feature = NULL;
608
609  while (true) {
610    ret = feature_list->RetrieveNextFeature(&feature);
611    if (ret)
612        break;
613
614    if (feature) {
615      DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_);
616
617      if ((feature->feature_id_ < kMaxNumPPFeatures)) {
618        HWColorManager::SetFeature[feature->feature_id_](*feature, &kernel_params);
619        if (Sys::ioctl_(device_fd_, INT(MSMFB_MDP_PP), &kernel_params) < 0) {
620          IOCTL_LOGE(MSMFB_MDP_PP, device_type_);
621
622          feature_list->Reset();
623          return kErrorHardware;
624        }
625      }
626    }
627  }  // while(true)
628
629  // Once all features were consumed, then destroy all feature instance from feature_list,
630  // Then mark it as non-dirty of PPFeaturesConfig cache.
631  feature_list->Reset();
632
633  return kErrorNone;
634}
635
636DisplayError HWPrimary::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
637  if (IsResolutionSwitchEnabled()) {
638    return kErrorNotSupported;
639  }
640
641  return HWDevice::SetMixerAttributes(mixer_attributes);
642}
643
644void HWPrimary::UpdateMixerAttributes() {
645  mixer_attributes_.width = display_attributes_.x_pixels;
646  mixer_attributes_.height = display_attributes_.y_pixels;
647  mixer_attributes_.split_left = display_attributes_.is_device_split ?
648      hw_panel_info_.split_info.left_split : mixer_attributes_.width;
649}
650
651}  // namespace sdm
652
653