Home | History | Annotate | Download | only in fb
      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 
     60 namespace sdm {
     61 
     62 using std::string;
     63 using std::to_string;
     64 using std::fstream;
     65 
     66 DisplayError 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 
     82 DisplayError 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 
     90 HWPrimary::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 
     97 DisplayError 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 
    123 bool 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 
    152 void 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 
    191 DisplayError HWPrimary::Deinit() {
    192   return HWDevice::Deinit();
    193 }
    194 
    195 DisplayError HWPrimary::GetNumDisplayAttributes(uint32_t *count) {
    196   *count = IsResolutionSwitchEnabled() ? UINT32(display_configs_.size()) : 1;
    197   return kErrorNone;
    198 }
    199 
    200 DisplayError HWPrimary::GetActiveConfig(uint32_t *active_config_index) {
    201   *active_config_index = active_config_index_;
    202   return kErrorNone;
    203 }
    204 
    205 DisplayError 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 
    225 DisplayError 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 
    271 DisplayError 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 
    308 DisplayError 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 
    342 DisplayError HWPrimary::GetConfigIndex(uint32_t mode, uint32_t *index) {
    343   return HWDevice::GetConfigIndex(mode, index);
    344 }
    345 
    346 DisplayError 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 
    355 DisplayError 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 
    364 DisplayError 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 
    373 DisplayError 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 
    423 DisplayError 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 
    455 void 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 
    481 DisplayError HWPrimary::SetVSyncState(bool enable) {
    482   DTRACE_SCOPED();
    483   return HWDevice::SetVSyncState(enable);
    484 }
    485 
    486 DisplayError 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 
    513 DisplayError 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 
    543 DisplayError 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 
    567 DisplayError 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 
    585 DisplayError 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.
    604 DisplayError 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 
    636 DisplayError HWPrimary::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
    637   if (IsResolutionSwitchEnabled()) {
    638     return kErrorNotSupported;
    639   }
    640 
    641   return HWDevice::SetMixerAttributes(mixer_attributes);
    642 }
    643 
    644 void 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