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