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