Home | History | Annotate | Download | only in fb
      1 /*
      2 * Copyright (c) 2015 - 2017, 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 #ifndef MDP_COMMIT_AVR_EN
     61 #define MDP_COMMIT_AVR_EN 0x08
     62 #endif
     63 
     64 #ifndef MDP_COMMIT_AVR_ONE_SHOT_MODE
     65 #define MDP_COMMIT_AVR_ONE_SHOT_MODE 0x10
     66 #endif
     67 
     68 #ifndef MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI
     69 #define MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI  0x20
     70 #endif
     71 
     72 namespace sdm {
     73 
     74 using std::string;
     75 using std::to_string;
     76 using std::fstream;
     77 
     78 HWPrimary::HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
     79   : HWDevice(buffer_sync_handler) {
     80   HWDevice::device_type_ = kDevicePrimary;
     81   HWDevice::device_name_ = "Primary Display Device";
     82   HWDevice::hw_info_intf_ = hw_info_intf;
     83 }
     84 
     85 DisplayError HWPrimary::Init() {
     86   DisplayError error = kErrorNone;
     87 
     88   error = HWDevice::Init();
     89   if (error != kErrorNone) {
     90     return error;
     91   }
     92 
     93   mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count);
     94 
     95   error = PopulateDisplayAttributes();
     96   if (error != kErrorNone) {
     97     return error;
     98   }
     99 
    100   UpdateMixerAttributes();
    101 
    102   // Need to enable HPD, but toggle at start when HDMI is external
    103   // This helps for framework reboot or adb shell stop/start
    104   EnableHotPlugDetection(0);
    105   EnableHotPlugDetection(1);
    106   InitializeConfigs();
    107 
    108   avr_prop_disabled_ = Debug::IsAVRDisabled();
    109 
    110   return error;
    111 }
    112 
    113 bool HWPrimary::GetCurrentModeFromSysfs(size_t *curr_x_pixels, size_t *curr_y_pixels) {
    114   bool ret = false;
    115   string mode_path = fb_path_ + string("0/mode");
    116 
    117   Sys::fstream fs(mode_path, fstream::in);
    118   if (!fs.is_open()) {
    119     return false;
    120   }
    121 
    122   string line;
    123   if (Sys::getline_(fs, line)) {
    124     // String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
    125     // kernel has more info on the format.
    126     size_t xpos = line.find(':');
    127     size_t ypos = line.find('x');
    128 
    129     if (xpos == string::npos || ypos == string::npos) {
    130       DLOGI("Resolution switch not supported");
    131     } else {
    132       *curr_x_pixels = static_cast<size_t>(atoi(line.c_str() + xpos + 1));
    133       *curr_y_pixels = static_cast<size_t>(atoi(line.c_str() + ypos + 1));
    134       DLOGI("Current Config: %u x %u", *curr_x_pixels, *curr_y_pixels);
    135       ret = true;
    136     }
    137   }
    138 
    139   return ret;
    140 }
    141 
    142 void HWPrimary::InitializeConfigs() {
    143   size_t curr_x_pixels = 0;
    144   size_t curr_y_pixels = 0;
    145 
    146   if (!GetCurrentModeFromSysfs(&curr_x_pixels, &curr_y_pixels)) {
    147     return;
    148   }
    149 
    150   string modes_path = string(fb_path_) + string("0/modes");
    151 
    152   Sys::fstream fs(modes_path, fstream::in);
    153   if (!fs.is_open()) {
    154     DLOGI("Unable to process modes");
    155     return;
    156   }
    157 
    158   string line;
    159   while (Sys::getline_(fs, line)) {
    160     DisplayConfigVariableInfo config;
    161     // std::getline (unlike ::getline) removes \n while driver expects it in mode, so add back
    162     line += '\n';
    163     size_t xpos = line.find(':');
    164     size_t ypos = line.find('x');
    165 
    166     if (xpos == string::npos || ypos == string::npos) {
    167       continue;
    168     }
    169 
    170     config.x_pixels = UINT32(atoi(line.c_str() + xpos + 1));
    171     config.y_pixels = UINT32(atoi(line.c_str() + ypos + 1));
    172     DLOGI("Found mode %d x %d", config.x_pixels, config.y_pixels);
    173     display_configs_.push_back(config);
    174     display_config_strings_.push_back(string(line.c_str()));
    175 
    176     if (curr_x_pixels == config.x_pixels && curr_y_pixels == config.y_pixels) {
    177       active_config_index_ = UINT32(display_configs_.size() - 1);
    178       DLOGI("Active config index %u", active_config_index_);
    179     }
    180   }
    181 }
    182 
    183 DisplayError HWPrimary::GetNumDisplayAttributes(uint32_t *count) {
    184   *count = IsResolutionSwitchEnabled() ? UINT32(display_configs_.size()) : 1;
    185   return kErrorNone;
    186 }
    187 
    188 DisplayError HWPrimary::GetActiveConfig(uint32_t *active_config_index) {
    189   *active_config_index = active_config_index_;
    190   return kErrorNone;
    191 }
    192 
    193 DisplayError HWPrimary::GetDisplayAttributes(uint32_t index,
    194                                              HWDisplayAttributes *display_attributes) {
    195   if (!display_attributes) {
    196     return kErrorParameters;
    197   }
    198 
    199   if (IsResolutionSwitchEnabled() && index >= display_configs_.size()) {
    200     return kErrorParameters;
    201   }
    202 
    203   *display_attributes = display_attributes_;
    204   if (IsResolutionSwitchEnabled()) {
    205     // Overwrite only the parent portion of object
    206     display_attributes->x_pixels = display_configs_.at(index).x_pixels;
    207     display_attributes->y_pixels = display_configs_.at(index).y_pixels;
    208   }
    209 
    210   return kErrorNone;
    211 }
    212 
    213 DisplayError HWPrimary::PopulateDisplayAttributes() {
    214   DTRACE_SCOPED();
    215 
    216   // Variable screen info
    217   fb_var_screeninfo var_screeninfo = {};
    218 
    219   if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &var_screeninfo) < 0) {
    220     IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
    221     return kErrorHardware;
    222   }
    223 
    224   // Frame rate
    225   msmfb_metadata meta_data = {};
    226   meta_data.op = metadata_op_frame_rate;
    227   if (Sys::ioctl_(device_fd_, MSMFB_METADATA_GET, &meta_data) < 0) {
    228     IOCTL_LOGE(MSMFB_METADATA_GET, device_type_);
    229     return kErrorHardware;
    230   }
    231 
    232   // If driver doesn't return width/height information, default to 320 dpi
    233   if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
    234     var_screeninfo.width  = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/320.0f) + 0.5f);
    235     var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/320.0f) + 0.5f);
    236     DLOGW("Driver doesn't report panel physical width and height - defaulting to 320dpi");
    237   }
    238 
    239   display_attributes_.x_pixels = var_screeninfo.xres;
    240   display_attributes_.y_pixels = var_screeninfo.yres;
    241   display_attributes_.v_front_porch = var_screeninfo.lower_margin;
    242   display_attributes_.v_back_porch = var_screeninfo.upper_margin;
    243   display_attributes_.v_pulse_width = var_screeninfo.vsync_len;
    244   uint32_t h_blanking = var_screeninfo.right_margin + var_screeninfo.left_margin +
    245       var_screeninfo.hsync_len;
    246   display_attributes_.h_total = var_screeninfo.xres + h_blanking;
    247   display_attributes_.x_dpi =
    248       (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
    249   display_attributes_.y_dpi =
    250       (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
    251   display_attributes_.fps = meta_data.data.panel_frame_rate;
    252   display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps);
    253   display_attributes_.is_device_split = (hw_panel_info_.split_info.right_split ||
    254       (var_screeninfo.xres > hw_resource_.max_mixer_width));
    255   display_attributes_.h_total += (display_attributes_.is_device_split ||
    256     hw_panel_info_.ping_pong_split)? h_blanking : 0;
    257 
    258   return kErrorNone;
    259 }
    260 
    261 DisplayError HWPrimary::SetDisplayAttributes(uint32_t index) {
    262   DisplayError ret = kErrorNone;
    263 
    264   if (!IsResolutionSwitchEnabled()) {
    265     return kErrorNotSupported;
    266   }
    267 
    268   if (index >= display_configs_.size()) {
    269     return kErrorParameters;
    270   }
    271 
    272   string mode_path = string(fb_path_) + string("0/mode");
    273   int fd = Sys::open_(mode_path.c_str(), O_WRONLY);
    274 
    275   if (fd < 0) {
    276     DLOGE("Opening mode failed");
    277     return kErrorNotSupported;
    278   }
    279 
    280   ssize_t written = Sys::pwrite_(fd, display_config_strings_.at(index).c_str(),
    281                                  display_config_strings_.at(index).length(), 0);
    282   if (written > 0) {
    283     DLOGI("Successfully set config %u", index);
    284     PopulateHWPanelInfo();
    285     PopulateDisplayAttributes();
    286     UpdateMixerAttributes();
    287     active_config_index_ = index;
    288   } else {
    289     DLOGE("Writing config index %u failed with error: %s", index, strerror(errno));
    290     ret = kErrorParameters;
    291   }
    292 
    293   Sys::close_(fd);
    294 
    295   return ret;
    296 }
    297 
    298 DisplayError HWPrimary::SetRefreshRate(uint32_t refresh_rate) {
    299   char node_path[kMaxStringLength] = {0};
    300 
    301   if (hw_resource_.has_avr && !avr_prop_disabled_) {
    302     return kErrorNotSupported;
    303   }
    304 
    305   snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
    306 
    307   int fd = Sys::open_(node_path, O_WRONLY);
    308   if (fd < 0) {
    309     DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
    310     return kErrorFileDescriptor;
    311   }
    312 
    313   char refresh_rate_string[kMaxStringLength];
    314   snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
    315   DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate);
    316   ssize_t len = Sys::pwrite_(fd, refresh_rate_string, strlen(refresh_rate_string), 0);
    317   if (len < 0) {
    318     DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
    319     Sys::close_(fd);
    320     return kErrorUndefined;
    321   }
    322   Sys::close_(fd);
    323 
    324   DisplayError error = PopulateDisplayAttributes();
    325   if (error != kErrorNone) {
    326     return error;
    327   }
    328 
    329   return kErrorNone;
    330 }
    331 
    332 DisplayError HWPrimary::GetConfigIndex(uint32_t mode, uint32_t *index) {
    333   return HWDevice::GetConfigIndex(mode, index);
    334 }
    335 
    336 DisplayError HWPrimary::PowerOff() {
    337   if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) {
    338     IOCTL_LOGE(FB_BLANK_POWERDOWN, device_type_);
    339     return kErrorHardware;
    340   }
    341 
    342   auto_refresh_ = false;
    343 
    344   return kErrorNone;
    345 }
    346 
    347 DisplayError HWPrimary::Doze() {
    348   if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_NORMAL) < 0) {
    349     IOCTL_LOGE(FB_BLANK_NORMAL, device_type_);
    350     return kErrorHardware;
    351   }
    352 
    353   return kErrorNone;
    354 }
    355 
    356 DisplayError HWPrimary::DozeSuspend() {
    357   if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_VSYNC_SUSPEND) < 0) {
    358     IOCTL_LOGE(FB_BLANK_VSYNC_SUSPEND, device_type_);
    359     return kErrorHardware;
    360   }
    361 
    362   return kErrorNone;
    363 }
    364 
    365 DisplayError HWPrimary::Validate(HWLayers *hw_layers) {
    366   HWLayersInfo &hw_layer_info = hw_layers->info;
    367   LayerStack *stack = hw_layer_info.stack;
    368 
    369   HWDevice::ResetDisplayParams();
    370 
    371   mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
    372 
    373   LayerRect left_roi = hw_layer_info.left_frame_roi.at(0);
    374   LayerRect right_roi = hw_layer_info.right_frame_roi.at(0);
    375 
    376   mdp_commit.left_roi.x = UINT32(left_roi.left);
    377   mdp_commit.left_roi.y = UINT32(left_roi.top);
    378   mdp_commit.left_roi.w = UINT32(left_roi.right - left_roi.left);
    379   mdp_commit.left_roi.h = UINT32(left_roi.bottom - left_roi.top);
    380 
    381   // Update second roi information in right_roi
    382   if (hw_layer_info.left_frame_roi.size() == 2) {
    383     mdp_commit.flags |= MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI;
    384     right_roi = hw_layer_info.left_frame_roi.at(1);
    385   }
    386 
    387   // SDM treats ROI as one full coordinate system.
    388   // In case source split is disabled, However, Driver assumes Mixer to operate in
    389   // different co-ordinate system.
    390   if (IsValid(right_roi)) {
    391     mdp_commit.right_roi.x = UINT32(right_roi.left);
    392     if (!hw_resource_.is_src_split) {
    393       mdp_commit.right_roi.x = UINT32(right_roi.left) - mixer_attributes_.split_left;
    394     }
    395     mdp_commit.right_roi.y = UINT32(right_roi.top);
    396     mdp_commit.right_roi.w = UINT32(right_roi.right - right_roi.left);
    397     mdp_commit.right_roi.h = UINT32(right_roi.bottom - right_roi.top);
    398   }
    399 
    400   if (stack->output_buffer && hw_resource_.has_concurrent_writeback) {
    401     LayerBuffer *output_buffer = stack->output_buffer;
    402     mdp_out_layer_.writeback_ndx = hw_resource_.writeback_index;
    403     mdp_out_layer_.buffer.width = output_buffer->unaligned_width;
    404     mdp_out_layer_.buffer.height = output_buffer->unaligned_height;
    405     mdp_out_layer_.buffer.comp_ratio.denom = 1000;
    406     mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000);
    407     mdp_out_layer_.buffer.fence = -1;
    408 #ifdef OUT_LAYER_COLOR_SPACE
    409     SetCSC(output_buffer->color_metadata, &mdp_out_layer_.color_space);
    410 #endif
    411     SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format);
    412     mdp_commit.flags |= MDP_COMMIT_CWB_EN;
    413     mdp_commit.flags |= (stack->flags.post_processed_output) ? MDP_COMMIT_CWB_DSPP : 0;
    414     DLOGI_IF(kTagDriverConfig, "****************** Conc WB Output buffer Info ******************");
    415     DLOGI_IF(kTagDriverConfig, "out_w %d, out_h %d, out_f %d, wb_id %d DSPP output %d",
    416              mdp_out_layer_.buffer.width, mdp_out_layer_.buffer.height,
    417              mdp_out_layer_.buffer.format, mdp_out_layer_.writeback_ndx,
    418              stack->flags.post_processed_output);
    419     DLOGI_IF(kTagDriverConfig, "****************************************************************");
    420   }
    421 
    422   if (hw_resource_.has_avr) {
    423     SetAVRFlags(hw_layers->hw_avr_info, &mdp_commit.flags);
    424   }
    425 
    426   return HWDevice::Validate(hw_layers);
    427 }
    428 
    429 DisplayError HWPrimary::Commit(HWLayers *hw_layers) {
    430   LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
    431 
    432   if (hw_resource_.has_concurrent_writeback && output_buffer) {
    433     if (output_buffer->planes[0].fd >= 0) {
    434       mdp_out_layer_.buffer.planes[0].fd = output_buffer->planes[0].fd;
    435       mdp_out_layer_.buffer.planes[0].offset = output_buffer->planes[0].offset;
    436       SetStride(device_type_, output_buffer->format, output_buffer->planes[0].stride,
    437                 &mdp_out_layer_.buffer.planes[0].stride);
    438       mdp_out_layer_.buffer.plane_count = 1;
    439       mdp_out_layer_.buffer.fence = -1;
    440 
    441       DLOGI_IF(kTagDriverConfig, "****************** Conc WB Output buffer Info ****************");
    442       DLOGI_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d",
    443                mdp_out_layer_.buffer.planes[0].fd, mdp_out_layer_.buffer.planes[0].offset,
    444                mdp_out_layer_.buffer.planes[0].stride);
    445       DLOGI_IF(kTagDriverConfig, "**************************************************************");
    446     } else {
    447       DLOGE("Invalid output buffer fd");
    448       return kErrorParameters;
    449     }
    450   }
    451 
    452   DisplayError ret = HWDevice::Commit(hw_layers);
    453 
    454   if (ret == kErrorNone && hw_resource_.has_concurrent_writeback && output_buffer) {
    455     output_buffer->release_fence_fd = mdp_out_layer_.buffer.fence;
    456   }
    457 
    458   return ret;
    459 }
    460 
    461 void HWPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
    462   char node_path[kMaxStringLength] = {0};
    463 
    464   DLOGI_IF(kTagDriverConfig, "Setting idle timeout to = %d ms", timeout_ms);
    465 
    466   snprintf(node_path, sizeof(node_path), "%s%d/idle_time", fb_path_, fb_node_index_);
    467 
    468   // Open a sysfs node to send the timeout value to driver.
    469   int fd = Sys::open_(node_path, O_WRONLY);
    470   if (fd < 0) {
    471     DLOGE("Unable to open %s, node %s", node_path, strerror(errno));
    472     return;
    473   }
    474 
    475   char timeout_string[64];
    476   snprintf(timeout_string, sizeof(timeout_string), "%d", timeout_ms);
    477 
    478   // Notify driver about the timeout value
    479   ssize_t length = Sys::pwrite_(fd, timeout_string, strlen(timeout_string), 0);
    480   if (length <= 0) {
    481     DLOGE("Unable to write into %s, node %s", node_path, strerror(errno));
    482   }
    483 
    484   Sys::close_(fd);
    485 }
    486 
    487 DisplayError HWPrimary::SetVSyncState(bool enable) {
    488   DTRACE_SCOPED();
    489   return HWDevice::SetVSyncState(enable);
    490 }
    491 
    492 DisplayError HWPrimary::SetDisplayMode(const HWDisplayMode hw_display_mode) {
    493   uint32_t mode = kModeDefault;
    494 
    495   switch (hw_display_mode) {
    496   case kModeVideo:
    497     mode = kModeLPMVideo;
    498     break;
    499   case kModeCommand:
    500     mode = kModeLPMCommand;
    501     break;
    502   default:
    503     DLOGW("Failed to translate SDE display mode %d to a MSMFB_LPM_ENABLE mode",
    504           hw_display_mode);
    505     return kErrorParameters;
    506   }
    507 
    508   if (Sys::ioctl_(device_fd_, INT(MSMFB_LPM_ENABLE), &mode) < 0) {
    509     IOCTL_LOGE(MSMFB_LPM_ENABLE, device_type_);
    510     return kErrorHardware;
    511   }
    512 
    513   DLOGI("Triggering display mode change to %d on next commit.", hw_display_mode);
    514   synchronous_commit_ = true;
    515 
    516   return kErrorNone;
    517 }
    518 
    519 DisplayError HWPrimary::SetPanelBrightness(int level) {
    520   char buffer[kMaxSysfsCommandLength] = {0};
    521 
    522   DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level);
    523   int fd = Sys::open_(kBrightnessNode, O_RDWR);
    524   if (fd < 0) {
    525     DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode,
    526              strerror(errno));
    527     return kErrorFileDescriptor;
    528   }
    529 
    530   int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level);
    531   if (bytes < 0) {
    532     DLOGV_IF(kTagDriverConfig, "Failed to copy new brightness level = %d", level);
    533     Sys::close_(fd);
    534     return kErrorUndefined;
    535   }
    536 
    537   ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
    538   if (ret <= 0) {
    539     DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode,
    540              strerror(errno));
    541     Sys::close_(fd);
    542     return kErrorUndefined;
    543   }
    544   Sys::close_(fd);
    545 
    546   return kErrorNone;
    547 }
    548 
    549 DisplayError HWPrimary::GetPanelBrightness(int *level) {
    550   char brightness[kMaxStringLength] = {0};
    551 
    552   if (!level) {
    553     DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer.");
    554     return kErrorParameters;
    555   }
    556 
    557   int fd = Sys::open_(kBrightnessNode, O_RDWR);
    558   if (fd < 0) {
    559     DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode,
    560              strerror(errno));
    561     return kErrorFileDescriptor;
    562   }
    563 
    564   if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
    565     *level = atoi(brightness);
    566     DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level);
    567   }
    568   Sys::close_(fd);
    569 
    570   return kErrorNone;
    571 }
    572 
    573 DisplayError HWPrimary::CachePanelBrightness(int level) {
    574   bl_level_update_commit = level;
    575   bl_update_commit = true;
    576   return kErrorNone;
    577 }
    578 
    579 DisplayError HWPrimary::SetAutoRefresh(bool enable) {
    580   const int kWriteLength = 2;
    581   char buffer[kWriteLength] = {'\0'};
    582   ssize_t bytes = snprintf(buffer, kWriteLength, "%d", enable);
    583 
    584   if (enable == auto_refresh_) {
    585     return kErrorNone;
    586   }
    587 
    588   if (HWDevice::SysFsWrite(kAutoRefreshNode, buffer, bytes) <= 0) {  // Returns bytes written
    589     return kErrorUndefined;
    590   }
    591 
    592   auto_refresh_ = enable;
    593 
    594   return kErrorNone;
    595 }
    596 
    597 DisplayError HWPrimary::GetPPFeaturesVersion(PPFeatureVersion *vers) {
    598   mdp_pp_feature_version version = {};
    599 
    600 #ifdef PA_DITHER
    601   uint32_t feature_id_mapping[kMaxNumPPFeatures] = { PCC, IGC, GC, GC, PA,
    602                                                      DITHER, GAMUT, PA_DITHER };
    603 #else
    604   uint32_t feature_id_mapping[kMaxNumPPFeatures] = { PCC, IGC, GC, GC, PA, DITHER, GAMUT };
    605 #endif
    606 
    607   for (int i(0); i < kMaxNumPPFeatures; i++) {
    608     version.pp_feature = feature_id_mapping[i];
    609 
    610     if (Sys::ioctl_(device_fd_,  INT(MSMFB_MDP_PP_GET_FEATURE_VERSION), &version) < 0) {
    611       IOCTL_LOGE(MSMFB_MDP_PP_GET_FEATURE_VERSION, device_type_);
    612       return kErrorHardware;
    613     }
    614     vers->version[i] = version.version_info;
    615   }
    616 
    617   return kErrorNone;
    618 }
    619 
    620 // It was entered with PPFeaturesConfig::locker_ being hold.
    621 DisplayError HWPrimary::SetPPFeatures(PPFeaturesConfig *feature_list) {
    622   msmfb_mdp_pp kernel_params = {};
    623   int ret = 0;
    624   PPFeatureInfo *feature = NULL;
    625 
    626   while (true) {
    627     ret = feature_list->RetrieveNextFeature(&feature);
    628     if (ret)
    629         break;
    630 
    631     if (feature) {
    632       DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_);
    633 
    634       if ((feature->feature_id_ < kMaxNumPPFeatures)) {
    635         HWColorManager::SetFeature[feature->feature_id_](*feature, &kernel_params);
    636         if (Sys::ioctl_(device_fd_, INT(MSMFB_MDP_PP), &kernel_params) < 0) {
    637           IOCTL_LOGE(MSMFB_MDP_PP, device_type_);
    638 
    639           feature_list->Reset();
    640           return kErrorHardware;
    641         }
    642       }
    643     }
    644   }  // while(true)
    645 
    646   // Once all features were consumed, then destroy all feature instance from feature_list,
    647   // Then mark it as non-dirty of PPFeaturesConfig cache.
    648   feature_list->Reset();
    649 
    650   return kErrorNone;
    651 }
    652 
    653 DisplayError HWPrimary::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
    654   if (IsResolutionSwitchEnabled()) {
    655     return kErrorNotSupported;
    656   }
    657 
    658   return HWDevice::SetMixerAttributes(mixer_attributes);
    659 }
    660 
    661 void HWPrimary::UpdateMixerAttributes() {
    662   mixer_attributes_.width = display_attributes_.x_pixels;
    663   mixer_attributes_.height = display_attributes_.y_pixels;
    664   mixer_attributes_.split_left = display_attributes_.is_device_split ?
    665       hw_panel_info_.split_info.left_split : mixer_attributes_.width;
    666 }
    667 
    668 void HWPrimary::SetAVRFlags(const HWAVRInfo &hw_avr_info, uint32_t *avr_flags) {
    669   if (hw_avr_info.enable) {
    670     *avr_flags |= MDP_COMMIT_AVR_EN;
    671   }
    672 
    673   if (hw_avr_info.mode == kOneShotMode) {
    674     *avr_flags |= MDP_COMMIT_AVR_ONE_SHOT_MODE;
    675   }
    676 }
    677 
    678 }  // namespace sdm
    679 
    680