4 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include "shared/log.h"
21 #include "power/power.h"
22 #include "power/power-suspend.h"
23 #include "power/power-doze.h"
24 #include "ambient-mode.h"
25 #include "device-interface.h"
26 #include "display-lock.h"
27 #include "display-misc.h"
28 #include "display-panel.h"
29 #include "display-plugin.h"
30 #include "display-signal.h"
31 #include "display-state-transition.h"
32 #include "display-util.h"
33 #include "led/touch-key.h"
35 #define MAX_WHITE_BALANCE_GAIN 2047
36 #define MAX_WHITE_BALANCE_OFFSET 2047
37 #define DEFAULT_WHITE_BALANCE_GAIN 1024
38 #define DEFAULT_WHITE_BALANCE_OFFSET 0
40 #define LCD_PHASED_MIN_BRIGHTNESS 1
41 #define LCD_PHASED_CHANGE_STEP 5
43 #define DIFF_TIMEVAL_MS(a, b) \
44 (((a.tv_sec * 1000000 + a.tv_usec) - \
45 (b.tv_sec * 1000000 + b.tv_usec)) \
48 static bool lcd_paneloff_mode = false;
49 static bool lcd_on_broadcasted = true;
50 static struct timeval lcd_on_timeval;
52 /* FIXME: This function is for temporary use, should be fixed after plugin refactoring */
53 int display_panel_set_dpms_state(int dpms_on, enum device_flags flags)
55 dpms_set_state(dpms_on);
58 if (dpms_on == DPMS_ON)
59 pm_history_save(PM_LOG_LCD_ON_COMPLETE, get_pm_cur_state());
60 else if (dpms_on == DPMS_OFF || dpms_on == DPMS_FORCE_OFF)
61 pm_history_save(PM_LOG_LCD_OFF_COMPLETE, get_pm_cur_state());
63 pm_history_save(PM_LOG_LCD_CONTROL_FAIL, dpms_on);
69 int display_panel_set_white_balance(enum hal_display_white_balance white_balance_type,
74 if (!display_is_hal_backend_available()) {
75 _E("There is no display device.");
79 switch (white_balance_type) {
80 case HAL_DISPLAY_WHITE_BALANCE_R_GAIN:
81 case HAL_DISPLAY_WHITE_BALANCE_G_GAIN:
82 case HAL_DISPLAY_WHITE_BALANCE_B_GAIN:
83 if (value > MAX_WHITE_BALANCE_GAIN)
84 value = DEFAULT_WHITE_BALANCE_GAIN;
86 case HAL_DISPLAY_WHITE_BALANCE_R_OFFSET:
87 case HAL_DISPLAY_WHITE_BALANCE_G_OFFSET:
88 case HAL_DISPLAY_WHITE_BALANCE_B_OFFSET:
89 if (value > MAX_WHITE_BALANCE_OFFSET)
90 value = DEFAULT_WHITE_BALANCE_OFFSET;
93 _E("Unknown white balance type");
97 ret = hal_device_display_set_white_balance(white_balance_type, value);
99 _E("Set white balance is not supported.");
101 _E("Failed to set white balance value.");
106 int display_panel_get_white_balance(enum hal_display_white_balance white_balance_type,
111 if (!display_is_hal_backend_available()) {
112 _E("There is no display device.");
116 switch (white_balance_type) {
117 case HAL_DISPLAY_WHITE_BALANCE_R_GAIN:
118 case HAL_DISPLAY_WHITE_BALANCE_G_GAIN:
119 case HAL_DISPLAY_WHITE_BALANCE_B_GAIN:
120 case HAL_DISPLAY_WHITE_BALANCE_R_OFFSET:
121 case HAL_DISPLAY_WHITE_BALANCE_G_OFFSET:
122 case HAL_DISPLAY_WHITE_BALANCE_B_OFFSET:
125 _E("Unknown white balance type");
129 ret = hal_device_display_get_white_balance(white_balance_type, value);
131 _E("Get white balance is not supported.");
133 _E("Failed to get white balance value.");
138 int display_panel_set_panel_state_by_on_state(enum device_flags flags)
143 _I("[DPMS XLIB Backlight] LCD on %#x cnt:%d", flags, cnt);
146 ret = display_panel_set_dpms_state(DPMS_ON, flags);
149 pm_history_save(PM_LOG_LCD_ON, get_pm_cur_state());
154 int display_panel_set_panel_state_by_off_state(enum device_flags flags)
157 static int cnt, ambient_cnt;
158 int default_brightness = 0;
160 display_backlight_get_default_brightness(&default_brightness);
162 if (flags & AMBIENT_MODE) {
163 _I("[DPMS XLIB Backlight] LCD suspend %#x cnt:%d", flags, ambient_cnt);
168 _I("[DPMS XLIB Backlight] LCD off %#x cnt:%d", flags, cnt);
171 if (flags & LCD_PHASED_TRANSIT_MODE)
172 display_backlight_change_brightness(default_brightness,
173 LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
175 if (flags & FORCE_OFF_MODE)
176 ret = display_panel_set_dpms_state(DPMS_FORCE_OFF, flags);
178 ret = display_panel_set_dpms_state(DPMS_OFF, flags);
181 pm_history_save(PM_LOG_LCD_OFF, get_pm_cur_state());
186 int display_panel_set_panel_state_by_standby_state(bool standby_on)
190 if ((dpms_get_cached_state() == DPMS_ON) || standby_on) {
192 ret = display_panel_set_dpms_state(DPMS_STANDBY, 0);
198 /* FIXME: display_plugin_~ function return value should be handling after refactoring */
199 void display_panel_set_lcd_paneloff_mode(bool on)
201 _I("Lcd paneloff mode: %d", on);
202 lcd_paneloff_mode = on;
204 display_state_transition_request_state_transition_with_option(INTERNAL_LOCK_PM, LCD_NORMAL);
207 /* FIXME: This function is temporary, it can be redefined or not */
208 void display_panel_get_lcd_paneloff_mode(bool *on)
211 _E("Inavlid parameter to get lcd paneloff mode");
215 *on = lcd_paneloff_mode;
218 void display_panel_lcd_on_procedure(int state, enum device_flags flag)
220 unsigned long flags = NORMAL_MODE;
221 display_util_get_device_flags(&flags);
224 if (display_plugin_lcd_on_procedure(state, flag) == 0)
227 * Display on procedure
229 * step 2. broadcast lcd on signal with cause
230 * step 3. set brightness
231 * step 4. set pmstate of vconf
232 * step 5. display on operate
234 * - b. TSP(touch screen) and touchkey enable
235 * step 6. broadcast lcd on complete signal
236 * step 7. key backlight enable
240 _I("[lcdstep] 0x%lx", flags);
242 /* send LCDOn dbus signal */
243 if (!lcd_on_broadcasted)
244 broadcast_lcd_on(SIGNAL_PRE, flags);
246 /* Update brightness level */
247 if (state == LCD_DIM)
248 display_backlight_set_brightness_by_dim_brightness();
249 else if (state == LCD_NORMAL)
250 display_backlight_update_by_default_brightness();
252 if (state == LCD_NORMAL)
253 set_setting_pmstate(S_NORMAL);
254 else if (state == LCD_DIM)
255 set_setting_pmstate(S_LCDDIM);
257 display_start_dependent_device(flags);
259 if (!lcd_on_broadcasted) {
260 broadcast_lcd_on(SIGNAL_POST, flags);
261 lcd_on_broadcasted = true;
264 touchled_control_backlight(TOUCHLED_DIRECT_ON);
266 display_misc_set_touch_event_blocked(false);
269 void display_panel_lcd_off_procedure(enum device_flags flag)
271 unsigned long flags = NORMAL_MODE;
272 display_util_get_device_flags(&flags);
275 if (display_plugin_lcd_off_procedure(flag) == 0)
278 * Display off procedure
279 * step 0. enhance mode off using nofity (e.g mdnie, HBM, LBM)
280 * step 1. broadcast lcd off signal with cause
281 * step 2. set pmstate of vconf
282 * step 3. display off operate
284 * - b. TSP(touch screen) and touchkey disable
285 * step 4. broadcast lcd off complete siganl
286 * step 5. enter doze mode if it is enabled
288 _I("[lcdstep] 0x%lx", flags);
292 device_notify(DEVICE_NOTIFIER_LCD_OFF, NULL);
294 if (lcd_on_broadcasted) {
295 broadcast_lcd_off(SIGNAL_PRE, flags);
296 lcd_on_broadcasted = false;
301 display_misc_set_touch_event_blocked(true);
303 set_setting_pmstate(S_LCDOFF);
305 touchled_control_backlight(TOUCHLED_DIRECT_OFF);
307 display_stop_dependent_device(flags);
309 broadcast_lcd_off(SIGNAL_POST, flags);
310 device_notify(DEVICE_NOTIFIER_LCD_OFF_COMPLETE, NULL);
315 void display_panel_lcd_on_direct(enum device_flags flags)
317 enum hal_device_power_transition_reason reason;
319 if (flags & LCD_ON_BY_POWER_KEY)
320 reason = HAL_DEVICE_POWER_TRANSITION_REASON_POWER_KEY;
321 else if (flags & LCD_ON_BY_TOUCH)
322 reason = HAL_DEVICE_POWER_TRANSITION_REASON_TOUCH_SCREEN;
324 reason = HAL_DEVICE_POWER_TRANSITION_REASON_UNKNOWN;
326 power_request_change_state_strict(DEVICED_POWER_STATE_SLEEP, DEVICED_POWER_STATE_NORMAL, reason, NULL);
327 set_pm_cur_state(S_NORMAL);
329 _D("lcd is on directly");
330 display_panel_update_lcd_on_timeval();
331 display_panel_lcd_on_procedure(LCD_NORMAL, flags);
333 display_state_transition_update_lock_screen_timeout(LOCK_SCREEN_INPUT_TIMEOUT);
336 static void display_state_updated_to_next_and_do_action(enum state_t next)
339 set_pm_old_state(get_pm_cur_state());
340 set_pm_cur_state(next);
342 display_plugin_state_get_timeout(get_pm_cur_state(), &timeout);
343 display_state_transition_do_state_action(timeout);
346 /* FIXME: timer_refresh_cb seems legacy code, it can be removed after discussion */
347 static gboolean timer_refresh_cb(gpointer data)
349 display_state_updated_to_next_and_do_action(S_NORMAL);
353 int display_panel_custom_lcd_on(int timeout)
355 if (display_plugin_custom_lcd_on(timeout) == 0)
361 if (display_panel_get_dpms_cached_state() != DPMS_ON)
362 display_panel_lcd_on_direct(LCD_ON_BY_GESTURE);
364 _I("Custom lcd on timeout(%d ms).", timeout);
365 if (set_custom_lcdon_timeout(timeout))
366 display_state_transition_update_display_state_timeout_by_priority();
368 display_state_updated_to_next_and_do_action(S_NORMAL);
370 g_idle_add(timer_refresh_cb, NULL);
375 int display_panel_custom_lcd_off(enum device_flags flag)
377 if (display_plugin_custom_lcd_off(flag) == 0)
380 /* check holdkey block flag in lock node */
381 if (display_lock_is_state_locked(S_NORMAL) || display_lock_is_state_locked(S_LCDDIM)) {
383 * When another proccess is normal lock, device is received call then,
384 * call app can be changed to lcd state by proximity.
385 * If proximity is near then normal lock will be unlocked.
387 if (flag & LCD_OFF_BY_PROXIMITY) {
388 _I("custom lcd off by proximity, delete normal lock");
389 display_lock_release_lock_all(S_NORMAL);
391 _I("skip custom lcd off");
396 _I("custom lcd off by flag(%d)", flag);
397 if (display_panel_get_dpms_cached_state() == DPMS_ON)
398 display_panel_lcd_off_procedure(flag);
400 if (set_custom_lcdon_timeout(0) == true)
401 display_state_transition_update_display_state_timeout_by_priority();
403 display_state_updated_to_next_and_do_action(S_LCDOFF);
408 /** FIXME: handling method should be considered later,
409 * because the handling is too similar for the same lcd on/off procedure, display state transition.
411 int display_panel_display_turn_on_by_reason(const char *reason, int timeout)
416 if (display_plugin_display_on_by_reason(reason, timeout) == 0)
422 str_len = strlen(reason);
424 if (!strncmp(reason, GESTURE_STR, str_len)) {
425 flag = LCD_ON_BY_GESTURE;
426 } else if (!strncmp(reason, EVENT_STR, str_len)) {
427 flag = LCD_ON_BY_EVENT;
429 _E("Reason is unknown(%s)", reason);
434 _E("Cannot setting timeout %d", timeout);
438 if (display_panel_get_dpms_cached_state() != DPMS_ON)
439 display_panel_lcd_on_direct(flag);
441 _I("platform lcd on by %s (%d ms)", reason, timeout);
442 if (set_custom_lcdon_timeout(timeout) == true)
443 display_state_transition_update_display_state_timeout_by_priority();
445 display_state_updated_to_next_and_do_action(S_NORMAL);
450 int display_panel_display_turn_off_by_reason(const char *reason)
455 if (display_plugin_display_off_by_reason(reason) == 0)
461 str_len = strlen(reason);
463 if (!strncmp(reason, GESTURE_STR, str_len)) {
464 if (display_lock_is_state_locked(S_NORMAL) || display_lock_is_state_locked(S_LCDDIM)) {
465 _I("skip platform lcd off by gesture");
468 flag = LCD_OFF_BY_GESTURE;
469 } else if (!strncmp(reason, PALM_STR, str_len)) {
470 display_lock_release_lock_all(S_NORMAL);
471 display_lock_release_lock_all(S_LCDDIM);
473 flag = LCD_OFF_BY_PALM;
475 _E("Reason is unknown(%s)", reason);
479 _I("platform lcd off by %s", reason);
480 if (display_panel_get_dpms_cached_state() == DPMS_ON)
481 display_panel_lcd_off_procedure(flag);
483 display_state_updated_to_next_and_do_action(S_LCDOFF);
488 bool display_panel_is_lcd_on_state_broadcasted(void)
490 return lcd_on_broadcasted;
493 /* FIXME: lcd on time calculation should be discussed, because it is only for lcd_on_direct routine */
494 void display_panel_update_lcd_on_timeval(void)
496 gettimeofday(&lcd_on_timeval, NULL);
499 int display_panel_calculate_diff_time_between_lcd_on_direct_and_state_action(int *diff_time)
501 struct timeval now_timeval;
506 if (lcd_on_timeval.tv_sec != 0) {
507 gettimeofday(&now_timeval, NULL);
508 *diff_time = DIFF_TIMEVAL_MS(now_timeval, lcd_on_timeval);
509 lcd_on_timeval.tv_sec = 0;
516 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
517 int display_panel_get_dpms_state(void)
520 enum display_state val;
522 ret = hal_device_display_get_state(&val);
527 * FIXME: Ambient mode is currently not the display core feature but wearable profile exclusive
528 * feature. Therefore exclude this condition statement from the display core logic.
529 * Please consider this condition statement when the ambient feature comes into the display core.
531 //if (val == DISPLAY_ON && ambient_get_state())
537 case DISPLAY_STANDBY:
539 case DISPLAY_SUSPEND:
550 int display_panel_get_dpms_cached_state(void)
552 return dpms_get_cached_state();
555 bool display_panel_init_dpms(void)
560 void display_panel_exit_dpms(void)
565 void __display_panel_register_dpms_checklist(int mode, void (*checker)(void), const char *caller)
567 register_dpms_checklist(mode, checker, caller);
570 /* FIXME: This function is used for only wearable profile, should be fixed after plugin refactoring */
571 int display_panel_set_image_effect(enum display_image_effect effect)
575 if (!display_is_hal_backend_available()) {
576 _E("There is no display device.");
580 ret = hal_device_display_set_image_effect(effect);
583 _E("Set image effect is not supported.");
585 _E("Failed to set image effect: %d", ret);
592 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
593 int display_panel_get_image_effect(enum display_image_effect *effect)
596 enum display_image_effect val;
601 if (!display_is_hal_backend_available()) {
602 _E("There is no display device.");
606 ret = hal_device_display_get_image_effect(&val);
609 _E("Get image effect is not supported.");
611 _E("Failed to get image effect: %d", ret);
620 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
621 int display_panel_set_panel_mode(enum display_panel_mode mode)
625 if (!display_is_hal_backend_available()) {
626 _E("There is no display device.");
630 ret = hal_device_display_set_panel_mode(mode);
633 _E("Set panel mode is not supported.");
635 _E("Failed to set panel mode(%d)", ret);
642 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
643 int display_panel_get_panel_mode(enum display_panel_mode *mode)
646 enum display_panel_mode val;
651 if (!display_is_hal_backend_available()) {
652 _E("There is no display device.");
656 ret = hal_device_display_get_panel_mode(&val);
659 _E("Get panel mode is not supported.");
661 _E("Failed to get panel mode(%d)", ret);
670 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
671 int display_panel_set_frame_rate(int frame_rate)
674 static int fmin = -1, fmax = -1;
676 if (!display_is_hal_backend_available())
680 ret = hal_device_display_get_min_frame_rate(&fmin);
682 _E("Failed to get min frate rate: %d", ret);
686 if ((ret != -ENODEV) && (frame_rate < fmin)) {
687 _E("Invalid rate(%d). (Valid rate: %d <= rate)", frame_rate, fmin);
692 ret = hal_device_display_get_max_frame_rate(&fmax);
694 _E("Failed to get max frate rate: %d", ret);
698 if ((ret != -ENODEV) && (frame_rate > fmax)) {
699 _E("Invalid rate(%d). (Valid rate: rate <= %d)", frame_rate, fmax);
703 return hal_device_display_set_frame_rate(frame_rate);
706 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
707 int display_panel_get_frame_rate(int *frame_rate)
712 if (!display_is_hal_backend_available())
715 return hal_device_display_get_frame_rate(frame_rate);