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
43 #include <string>
44
45 #include "hw_primary.h"
46 #include "hw_color_manager.h"
47
48 #define __CLASS__ "HWPrimary"
49
50 namespace sdm {
51
52 using std::string;
53
Create(HWInterface ** intf,HWInfoInterface * hw_info_intf,BufferSyncHandler * buffer_sync_handler,HWEventHandler * eventhandler)54 DisplayError HWPrimary::Create(HWInterface **intf, HWInfoInterface *hw_info_intf,
55 BufferSyncHandler *buffer_sync_handler,
56 HWEventHandler *eventhandler) {
57 DisplayError error = kErrorNone;
58 HWPrimary *hw_primary = NULL;
59
60 hw_primary = new HWPrimary(buffer_sync_handler, hw_info_intf);
61 error = hw_primary->Init(eventhandler);
62 if (error != kErrorNone) {
63 delete hw_primary;
64 } else {
65 *intf = hw_primary;
66 }
67
68 return error;
69 }
70
Destroy(HWInterface * intf)71 DisplayError HWPrimary::Destroy(HWInterface *intf) {
72 HWPrimary *hw_primary = static_cast<HWPrimary *>(intf);
73 hw_primary->Deinit();
74 delete hw_primary;
75
76 return kErrorNone;
77 }
78
HWPrimary(BufferSyncHandler * buffer_sync_handler,HWInfoInterface * hw_info_intf)79 HWPrimary::HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
80 : HWDevice(buffer_sync_handler) {
81 HWDevice::device_type_ = kDevicePrimary;
82 HWDevice::device_name_ = "Primary Display Device";
83 HWDevice::hw_info_intf_ = hw_info_intf;
84 }
85
Init(HWEventHandler * eventhandler)86 DisplayError HWPrimary::Init(HWEventHandler *eventhandler) {
87 DisplayError error = kErrorNone;
88 char node_path[kMaxStringLength] = { 0 };
89 char data[kMaxStringLength] = { 0 };
90 const char *event_name[kNumDisplayEvents] = {"vsync_event", "show_blank_event", "idle_notify",
91 "msm_fb_thermal_level"};
92
93 error = HWDevice::Init(eventhandler);
94 if (error != kErrorNone) {
95 goto CleanupOnError;
96 }
97
98 error = PopulateDisplayAttributes();
99 if (error != kErrorNone) {
100 goto CleanupOnError;
101 }
102
103 // Open nodes for polling
104 for (int event = 0; event < kNumDisplayEvents; event++) {
105 poll_fds_[event].fd = -1;
106 }
107
108 if (!fake_vsync_) {
109 for (int event = 0; event < kNumDisplayEvents; event++) {
110 pollfd &poll_fd = poll_fds_[event];
111
112 snprintf(node_path, sizeof(node_path), "%s%d/%s", fb_path_, fb_node_index_,
113 event_name[event]);
114
115 poll_fd.fd = Sys::open_(node_path, O_RDONLY);
116 if (poll_fd.fd < 0) {
117 DLOGE("open failed for event=%d, error=%s", event, strerror(errno));
118 error = kErrorHardware;
119 goto CleanupOnError;
120 }
121
122 // Read once on all fds to clear data on all fds.
123 Sys::pread_(poll_fd.fd, data , kMaxStringLength, 0);
124 poll_fd.events = POLLPRI | POLLERR;
125 }
126 }
127
128 // Start the Event thread
129 if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) {
130 DLOGE("Failed to start %s, error = %s", event_thread_name_);
131 error = kErrorResources;
132 goto CleanupOnError;
133 }
134
135 // Disable HPD at start if HDMI is external, it will be enabled later when the display powers on
136 // This helps for framework reboot or adb shell stop/start
137 EnableHotPlugDetection(0);
138 InitializeConfigs();
139
140 return kErrorNone;
141
142 CleanupOnError:
143 // Close all poll fds
144 for (int event = 0; event < kNumDisplayEvents; event++) {
145 int &fd = poll_fds_[event].fd;
146 if (fd >= 0) {
147 Sys::close_(fd);
148 }
149 }
150
151 return error;
152 }
153
GetCurrentModeFromSysfs(size_t * curr_x_pixels,size_t * curr_y_pixels)154 bool HWPrimary::GetCurrentModeFromSysfs(size_t *curr_x_pixels, size_t *curr_y_pixels) {
155 bool ret = false;
156 size_t len = kPageSize;
157 string mode_path = string(fb_path_) + string("0/mode");
158
159 FILE *fd = Sys::fopen_(mode_path.c_str(), "r");
160 if (fd) {
161 char *buffer = static_cast<char *>(calloc(len, sizeof(char)));
162
163 if (buffer == NULL) {
164 DLOGW("Failed to allocate memory");
165 Sys::fclose_(fd);
166 return false;
167 }
168
169 if (Sys::getline_(&buffer, &len, fd) > 0) {
170 // String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
171 // kernel has more info on the format.
172 size_t xpos = string(buffer).find(':');
173 size_t ypos = string(buffer).find('x');
174
175 if (xpos == string::npos || ypos == string::npos) {
176 DLOGI("Resolution switch not supported");
177 } else {
178 *curr_x_pixels = static_cast<size_t>(atoi(buffer + xpos + 1));
179 *curr_y_pixels = static_cast<size_t>(atoi(buffer + ypos + 1));
180 DLOGI("Current Config: %u x %u", *curr_x_pixels, *curr_y_pixels);
181 ret = true;
182 }
183 }
184
185 free(buffer);
186 Sys::fclose_(fd);
187 }
188
189 return ret;
190 }
191
InitializeConfigs()192 void HWPrimary::InitializeConfigs() {
193 size_t curr_x_pixels = 0;
194 size_t curr_y_pixels = 0;
195 size_t len = kPageSize;
196 string modes_path = string(fb_path_) + string("0/modes");
197
198 if (!GetCurrentModeFromSysfs(&curr_x_pixels, &curr_y_pixels)) {
199 return;
200 }
201
202 FILE *fd = Sys::fopen_(modes_path.c_str(), "r");
203 if (fd) {
204 char *buffer = static_cast<char *>(calloc(len, sizeof(char)));
205
206 if (buffer == NULL) {
207 DLOGW("Failed to allocate memory");
208 Sys::fclose_(fd);
209 return;
210 }
211
212 while (Sys::getline_(&buffer, &len, fd) > 0) {
213 DisplayConfigVariableInfo config;
214 size_t xpos = string(buffer).find(':');
215 size_t ypos = string(buffer).find('x');
216
217 if (xpos == string::npos || ypos == string::npos) {
218 continue;
219 }
220
221 config.x_pixels = UINT32(atoi(buffer + xpos + 1));
222 config.y_pixels = UINT32(atoi(buffer + ypos + 1));
223 DLOGI("Found mode %d x %d", config.x_pixels, config.y_pixels);
224 display_configs_.push_back(config);
225 display_config_strings_.push_back(string(buffer));
226
227 if (curr_x_pixels == config.x_pixels && curr_y_pixels == config.y_pixels) {
228 active_config_index_ = UINT32(display_configs_.size() - 1);
229 DLOGI("Active config index %u", active_config_index_);
230 }
231 }
232
233 free(buffer);
234 Sys::fclose_(fd);
235 } else {
236 DLOGI("Unable to process modes");
237 }
238 }
239
Deinit()240 DisplayError HWPrimary::Deinit() {
241 exit_threads_ = true;
242 Sys::pthread_cancel_(event_thread_);
243 pthread_join(event_thread_, NULL);
244
245 for (int event = 0; event < kNumDisplayEvents; event++) {
246 int &fd = poll_fds_[event].fd;
247 if (fd >= 0) {
248 Sys::close_(fd);
249 }
250 }
251
252 return HWDevice::Deinit();
253 }
254
GetNumDisplayAttributes(uint32_t * count)255 DisplayError HWPrimary::GetNumDisplayAttributes(uint32_t *count) {
256 *count = IsResolutionSwitchEnabled() ? UINT32(display_configs_.size()) : 1;
257 return kErrorNone;
258 }
259
GetActiveConfig(uint32_t * active_config_index)260 DisplayError HWPrimary::GetActiveConfig(uint32_t *active_config_index) {
261 *active_config_index = active_config_index_;
262 return kErrorNone;
263 }
264
GetDisplayAttributes(uint32_t index,HWDisplayAttributes * display_attributes)265 DisplayError HWPrimary::GetDisplayAttributes(uint32_t index,
266 HWDisplayAttributes *display_attributes) {
267 if (!display_attributes) {
268 return kErrorParameters;
269 }
270
271 if (IsResolutionSwitchEnabled() && index >= display_configs_.size()) {
272 return kErrorParameters;
273 }
274
275 *display_attributes = display_attributes_;
276 if (IsResolutionSwitchEnabled()) {
277 // Overwrite only the parent portion of object
278 display_attributes->x_pixels = display_configs_.at(index).x_pixels;
279 display_attributes->y_pixels = display_configs_.at(index).y_pixels;
280 }
281
282 return kErrorNone;
283 }
284
PopulateDisplayAttributes()285 DisplayError HWPrimary::PopulateDisplayAttributes() {
286 DTRACE_SCOPED();
287
288 // Variable screen info
289 STRUCT_VAR(fb_var_screeninfo, var_screeninfo);
290
291 if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &var_screeninfo) < 0) {
292 IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
293 return kErrorHardware;
294 }
295
296 // Frame rate
297 STRUCT_VAR(msmfb_metadata, meta_data);
298 meta_data.op = metadata_op_frame_rate;
299 if (Sys::ioctl_(device_fd_, MSMFB_METADATA_GET, &meta_data) < 0) {
300 IOCTL_LOGE(MSMFB_METADATA_GET, device_type_);
301 return kErrorHardware;
302 }
303
304 // If driver doesn't return width/height information, default to 160 dpi
305 if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
306 var_screeninfo.width = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f) + 0.5f);
307 var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f) + 0.5f);
308 }
309
310 display_attributes_.x_pixels = var_screeninfo.xres;
311 display_attributes_.y_pixels = var_screeninfo.yres;
312 display_attributes_.v_front_porch = var_screeninfo.lower_margin;
313 display_attributes_.v_back_porch = var_screeninfo.upper_margin;
314 display_attributes_.v_pulse_width = var_screeninfo.vsync_len;
315 uint32_t h_blanking = var_screeninfo.right_margin + var_screeninfo.left_margin +
316 var_screeninfo.hsync_len;
317 display_attributes_.h_total = var_screeninfo.xres + h_blanking;
318 display_attributes_.x_dpi =
319 (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
320 display_attributes_.y_dpi =
321 (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
322 display_attributes_.fps = meta_data.data.panel_frame_rate;
323 display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps);
324 display_attributes_.is_device_split = (hw_panel_info_.split_info.left_split ||
325 (var_screeninfo.xres > hw_resource_.max_mixer_width)) ? true : false;
326 display_attributes_.split_left = hw_panel_info_.split_info.left_split ?
327 hw_panel_info_.split_info.left_split : display_attributes_.x_pixels / 2;
328 display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
329
330 return kErrorNone;
331 }
332
SetDisplayAttributes(uint32_t index)333 DisplayError HWPrimary::SetDisplayAttributes(uint32_t index) {
334 DisplayError ret = kErrorNone;
335
336 if (!IsResolutionSwitchEnabled()) {
337 return kErrorNotSupported;
338 }
339
340 if (index >= display_configs_.size()) {
341 return kErrorParameters;
342 }
343
344 string mode_path = string(fb_path_) + string("0/mode");
345 int fd = Sys::open_(mode_path.c_str(), O_WRONLY);
346
347 if (fd < 0) {
348 DLOGE("Opening mode failed");
349 return kErrorNotSupported;
350 }
351
352 ssize_t written = Sys::pwrite_(fd, display_config_strings_.at(index).c_str(),
353 display_config_strings_.at(index).length(), 0);
354 if (written > 0) {
355 DLOGI("Successfully set config %u", index);
356 PopulateHWPanelInfo();
357 PopulateDisplayAttributes();
358 active_config_index_ = index;
359 } else {
360 DLOGE("Writing config index %u failed with error: %s", index, strerror(errno));
361 ret = kErrorParameters;
362 }
363
364 Sys::close_(fd);
365
366 return ret;
367 }
368
SetRefreshRate(uint32_t refresh_rate)369 DisplayError HWPrimary::SetRefreshRate(uint32_t refresh_rate) {
370 char node_path[kMaxStringLength] = {0};
371
372 if (refresh_rate == display_attributes_.fps) {
373 return kErrorNone;
374 }
375
376 snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
377
378 int fd = Sys::open_(node_path, O_WRONLY);
379 if (fd < 0) {
380 DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
381 return kErrorFileDescriptor;
382 }
383
384 char refresh_rate_string[kMaxStringLength];
385 snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
386 DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate);
387 ssize_t len = Sys::pwrite_(fd, refresh_rate_string, strlen(refresh_rate_string), 0);
388 if (len < 0) {
389 DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
390 Sys::close_(fd);
391 return kErrorUndefined;
392 }
393 Sys::close_(fd);
394
395 DisplayError error = PopulateDisplayAttributes();
396 if (error != kErrorNone) {
397 return error;
398 }
399
400 return kErrorNone;
401 }
402
GetConfigIndex(uint32_t mode,uint32_t * index)403 DisplayError HWPrimary::GetConfigIndex(uint32_t mode, uint32_t *index) {
404 return HWDevice::GetConfigIndex(mode, index);
405 }
406
PowerOff()407 DisplayError HWPrimary::PowerOff() {
408 if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) {
409 IOCTL_LOGE(FB_BLANK_POWERDOWN, device_type_);
410 return kErrorHardware;
411 }
412
413 return kErrorNone;
414 }
415
Doze()416 DisplayError HWPrimary::Doze() {
417 if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_NORMAL) < 0) {
418 IOCTL_LOGE(FB_BLANK_NORMAL, device_type_);
419 return kErrorHardware;
420 }
421
422 return kErrorNone;
423 }
424
DozeSuspend()425 DisplayError HWPrimary::DozeSuspend() {
426 if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_VSYNC_SUSPEND) < 0) {
427 IOCTL_LOGE(FB_BLANK_VSYNC_SUSPEND, device_type_);
428 return kErrorHardware;
429 }
430
431 return kErrorNone;
432 }
433
Validate(HWLayers * hw_layers)434 DisplayError HWPrimary::Validate(HWLayers *hw_layers) {
435 HWDevice::ResetDisplayParams();
436
437 mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
438
439 LayerRect left_roi = hw_layers->info.left_partial_update;
440 LayerRect right_roi = hw_layers->info.right_partial_update;
441 mdp_commit.left_roi.x = UINT32(left_roi.left);
442 mdp_commit.left_roi.y = UINT32(left_roi.top);
443 mdp_commit.left_roi.w = UINT32(left_roi.right - left_roi.left);
444 mdp_commit.left_roi.h = UINT32(left_roi.bottom - left_roi.top);
445
446 // SDM treats ROI as one full coordinate system.
447 // In case source split is disabled, However, Driver assumes Mixer to operate in
448 // different co-ordinate system.
449 if (!hw_resource_.is_src_split) {
450 mdp_commit.right_roi.x = UINT32(right_roi.left) - hw_panel_info_.split_info.left_split;
451 mdp_commit.right_roi.y = UINT32(right_roi.top);
452 mdp_commit.right_roi.w = UINT32(right_roi.right - right_roi.left);
453 mdp_commit.right_roi.h = UINT32(right_roi.bottom - right_roi.top);
454 }
455
456 return HWDevice::Validate(hw_layers);
457 }
458
DisplayEventThread(void * context)459 void* HWPrimary::DisplayEventThread(void *context) {
460 if (context) {
461 return reinterpret_cast<HWPrimary *>(context)->DisplayEventThreadHandler();
462 }
463
464 return NULL;
465 }
466
DisplayEventThreadHandler()467 void* HWPrimary::DisplayEventThreadHandler() {
468 char data[kMaxStringLength] = {0};
469
470 prctl(PR_SET_NAME, event_thread_name_, 0, 0, 0);
471 setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent);
472
473 if (fake_vsync_) {
474 while (!exit_threads_) {
475 // Fake vsync is used only when set explicitly through a property(todo) or when
476 // the vsync timestamp node cannot be opened at bootup. There is no
477 // fallback to fake vsync from the true vsync loop, ever, as the
478 // condition can easily escape detection.
479 // Also, fake vsync is delivered only for the primary display.
480 usleep(16666);
481 STRUCT_VAR(timeval, time_now);
482 gettimeofday(&time_now, NULL);
483 int64_t ts = int64_t(time_now.tv_sec)*1000000000LL +int64_t(time_now.tv_usec)*1000LL;
484
485 // Send Vsync event for primary display(0)
486 event_handler_->VSync(ts);
487 }
488
489 pthread_exit(0);
490 }
491
492 typedef void (HWPrimary::*EventHandler)(char*);
493 EventHandler event_handler[kNumDisplayEvents] = { &HWPrimary::HandleVSync,
494 &HWPrimary::HandleBlank,
495 &HWPrimary::HandleIdleTimeout,
496 &HWPrimary::HandleThermal };
497
498 while (!exit_threads_) {
499 int error = Sys::poll_(poll_fds_, kNumDisplayEvents, -1);
500 if (error <= 0) {
501 DLOGW("poll failed. error = %s", strerror(errno));
502 continue;
503 }
504
505 for (int event = 0; event < kNumDisplayEvents; event++) {
506 pollfd &poll_fd = poll_fds_[event];
507
508 if (poll_fd.revents & POLLPRI) {
509 if (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0) {
510 (this->*event_handler[event])(data);
511 }
512 }
513 }
514 }
515
516 pthread_exit(0);
517
518 return NULL;
519 }
520
HandleVSync(char * data)521 void HWPrimary::HandleVSync(char *data) {
522 int64_t timestamp = 0;
523 if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) {
524 timestamp = strtoll(data + strlen("VSYNC="), NULL, 0);
525 }
526 event_handler_->VSync(timestamp);
527 }
528
HandleBlank(char * data)529 void HWPrimary::HandleBlank(char *data) {
530 // TODO(user): Need to send blank Event
531 }
532
HandleIdleTimeout(char * data)533 void HWPrimary::HandleIdleTimeout(char *data) {
534 event_handler_->IdleTimeout();
535 }
536
HandleThermal(char * data)537 void HWPrimary::HandleThermal(char *data) {
538 int64_t thermal_level = 0;
539 if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) {
540 thermal_level = strtoll(data + strlen("thermal_level="), NULL, 0);
541 }
542
543 DLOGI("Received thermal notification with thermal level = %d", thermal_level);
544
545 event_handler_->ThermalEvent(thermal_level);
546 }
547
SetIdleTimeoutMs(uint32_t timeout_ms)548 void HWPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
549 char node_path[kMaxStringLength] = {0};
550
551 DLOGI_IF(kTagDriverConfig, "Setting idle timeout to = %d ms", timeout_ms);
552
553 snprintf(node_path, sizeof(node_path), "%s%d/idle_time", fb_path_, fb_node_index_);
554
555 // Open a sysfs node to send the timeout value to driver.
556 int fd = Sys::open_(node_path, O_WRONLY);
557 if (fd < 0) {
558 DLOGE("Unable to open %s, node %s", node_path, strerror(errno));
559 return;
560 }
561
562 char timeout_string[64];
563 snprintf(timeout_string, sizeof(timeout_string), "%d", timeout_ms);
564
565 // Notify driver about the timeout value
566 ssize_t length = Sys::pwrite_(fd, timeout_string, strlen(timeout_string), 0);
567 if (length <= 0) {
568 DLOGE("Unable to write into %s, node %s", node_path, strerror(errno));
569 }
570
571 Sys::close_(fd);
572 }
573
SetVSyncState(bool enable)574 DisplayError HWPrimary::SetVSyncState(bool enable) {
575 DTRACE_SCOPED();
576
577 int vsync_on = enable ? 1 : 0;
578 if (Sys::ioctl_(device_fd_, MSMFB_OVERLAY_VSYNC_CTRL, &vsync_on) < 0) {
579 IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL, device_type_);
580 return kErrorHardware;
581 }
582
583 return kErrorNone;
584 }
585
SetDisplayMode(const HWDisplayMode hw_display_mode)586 DisplayError HWPrimary::SetDisplayMode(const HWDisplayMode hw_display_mode) {
587 uint32_t mode = kModeDefault;
588
589 switch (hw_display_mode) {
590 case kModeVideo:
591 mode = kModeLPMVideo;
592 break;
593 case kModeCommand:
594 mode = kModeLPMCommand;
595 break;
596 default:
597 DLOGW("Failed to translate SDE display mode %d to a MSMFB_LPM_ENABLE mode",
598 hw_display_mode);
599 return kErrorParameters;
600 }
601
602 if (Sys::ioctl_(device_fd_, INT(MSMFB_LPM_ENABLE), &mode) < 0) {
603 IOCTL_LOGE(MSMFB_LPM_ENABLE, device_type_);
604 return kErrorHardware;
605 }
606
607 DLOGI("Triggering display mode change to %d on next commit.", hw_display_mode);
608 synchronous_commit_ = true;
609
610 return kErrorNone;
611 }
612
SetPanelBrightness(int level)613 DisplayError HWPrimary::SetPanelBrightness(int level) {
614 char buffer[MAX_SYSFS_COMMAND_LENGTH] = {0};
615
616 DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level);
617 int fd = Sys::open_(kBrightnessNode, O_RDWR);
618 if (fd < 0) {
619 DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode,
620 strerror(errno));
621 return kErrorFileDescriptor;
622 }
623
624 int32_t bytes = snprintf(buffer, MAX_SYSFS_COMMAND_LENGTH, "%d\n", level);
625 if (bytes < 0) {
626 DLOGV_IF(kTagDriverConfig, "Failed to copy new brightness level = %d", level);
627 Sys::close_(fd);
628 return kErrorUndefined;
629 }
630
631 ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
632 if (ret <= 0) {
633 DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode,
634 strerror(errno));
635 Sys::close_(fd);
636 return kErrorUndefined;
637 }
638 Sys::close_(fd);
639
640 return kErrorNone;
641 }
642
GetPanelBrightness(int * level)643 DisplayError HWPrimary::GetPanelBrightness(int *level) {
644 char brightness[kMaxStringLength] = {0};
645
646 if (!level) {
647 DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer.");
648 return kErrorParameters;
649 }
650
651 int fd = Sys::open_(kBrightnessNode, O_RDWR);
652 if (fd < 0) {
653 DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode,
654 strerror(errno));
655 return kErrorFileDescriptor;
656 }
657
658 if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) {
659 *level = atoi(brightness);
660 DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level);
661 }
662 Sys::close_(fd);
663
664 return kErrorNone;
665 }
666
SetAutoRefresh(bool enable)667 DisplayError HWPrimary::SetAutoRefresh(bool enable) {
668 const int kWriteLength = 2;
669 char buffer[kWriteLength] = {'\0'};
670 ssize_t bytes = snprintf(buffer, kWriteLength, "%d", enable);
671
672 if (enable == auto_refresh_) {
673 return kErrorNone;
674 }
675
676 if (HWDevice::SysFsWrite(kAutoRefreshNode, buffer, bytes) <= 0) { // Returns bytes written
677 return kErrorUndefined;
678 }
679
680 auto_refresh_ = enable;
681
682 return kErrorNone;
683 }
684
GetPPFeaturesVersion(PPFeatureVersion * vers)685 DisplayError HWPrimary::GetPPFeaturesVersion(PPFeatureVersion *vers) {
686 STRUCT_VAR(mdp_pp_feature_version, version);
687
688 uint32_t feature_id_mapping[kMaxNumPPFeatures] = { PCC, IGC, GC, GC, PA, DITHER, GAMUT };
689
690 for (int i(0); i < kMaxNumPPFeatures; i++) {
691 version.pp_feature = feature_id_mapping[i];
692
693 if (Sys::ioctl_(device_fd_, INT(MSMFB_MDP_PP_GET_FEATURE_VERSION), &version) < 0) {
694 IOCTL_LOGE(MSMFB_MDP_PP_GET_FEATURE_VERSION, device_type_);
695 return kErrorHardware;
696 }
697 vers->version[i] = version.version_info;
698 }
699
700 return kErrorNone;
701 }
702
703 // It was entered with PPFeaturesConfig::locker_ being hold.
SetPPFeatures(PPFeaturesConfig * feature_list)704 DisplayError HWPrimary::SetPPFeatures(PPFeaturesConfig *feature_list) {
705 STRUCT_VAR(msmfb_mdp_pp, kernel_params);
706 int ret = 0;
707 PPFeatureInfo *feature = NULL;
708
709 while (true) {
710 ret = feature_list->RetrieveNextFeature(&feature);
711 if (ret)
712 break;
713
714 if (feature) {
715 DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_);
716
717 if ((feature->feature_id_ < kMaxNumPPFeatures)) {
718 HWColorManager::SetFeature[feature->feature_id_](*feature, &kernel_params);
719 if (Sys::ioctl_(device_fd_, INT(MSMFB_MDP_PP), &kernel_params) < 0) {
720 IOCTL_LOGE(MSMFB_MDP_PP, device_type_);
721
722 feature_list->Reset();
723 return kErrorHardware;
724 }
725 }
726 }
727 } // while(true)
728
729 // Once all features were consumed, then destroy all feature instance from feature_list,
730 // Then mark it as non-dirty of PPFeaturesConfig cache.
731 feature_list->Reset();
732
733 return kErrorNone;
734 }
735
736 } // namespace sdm
737
738