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.
19 #include <libsyscommon/resource-manager.h>
20 #include <system/syscommon-plugin-deviced-display.h>
21 #include <system/syscommon-plugin-deviced-power-interface.h>
22 #include <system/syscommon-plugin-deviced-common-interface.h>
24 #include "shared/log.h"
25 #include "power/power.h"
26 #include "power/power-suspend.h"
27 #include "power/power-doze.h"
28 #include "ambient-mode.h"
29 #include "device-interface.h"
30 #include "display-lock.h"
31 #include "display-misc.h"
32 #include "display-panel.h"
33 #include "display-plugin.h"
34 #include "display-signal.h"
35 #include "display-state-transition.h"
36 #include "display-util.h"
37 #include "led/touch-key.h"
39 #define MAX_WHITE_BALANCE_GAIN 2047
40 #define MAX_WHITE_BALANCE_OFFSET 2047
41 #define DEFAULT_WHITE_BALANCE_GAIN 1024
42 #define DEFAULT_WHITE_BALANCE_OFFSET 0
44 #define LCD_PHASED_MIN_BRIGHTNESS 1
45 #define LCD_PHASED_CHANGE_STEP 5
47 #define DIFF_TIMEVAL_MS(a, b) \
48 (((a.tv_sec * 1000000 + a.tv_usec) - \
49 (b.tv_sec * 1000000 + b.tv_usec)) \
52 static bool lcd_paneloff_mode = false;
53 static bool lcd_on_broadcasted = true;
54 static struct timeval lcd_on_timeval;
56 /* FIXME: This function is for temporary use, should be fixed after plugin refactoring */
57 int display_panel_set_dpms_state(int dpms_on, enum device_flags flags)
60 dpms_set_state(dpms_on);
63 enum deviced_display_state current;
65 if (display_state_get_current(¤t) < 0)
68 if (dpms_on == DPMS_ON)
69 pm_history_save(PM_LOG_LCD_ON_COMPLETE, current);
70 else if (dpms_on == DPMS_OFF || dpms_on == DPMS_FORCE_OFF)
71 pm_history_save(PM_LOG_LCD_OFF_COMPLETE, current);
73 pm_history_save(PM_LOG_LCD_CONTROL_FAIL, dpms_on);
79 int display_panel_set_white_balance(enum hal_display_white_balance white_balance_type,
84 if (!display_is_hal_backend_available()) {
85 _E("There is no display device.");
89 switch (white_balance_type) {
90 case HAL_DISPLAY_WHITE_BALANCE_R_GAIN:
91 case HAL_DISPLAY_WHITE_BALANCE_G_GAIN:
92 case HAL_DISPLAY_WHITE_BALANCE_B_GAIN:
93 if (value > MAX_WHITE_BALANCE_GAIN)
94 value = DEFAULT_WHITE_BALANCE_GAIN;
96 case HAL_DISPLAY_WHITE_BALANCE_R_OFFSET:
97 case HAL_DISPLAY_WHITE_BALANCE_G_OFFSET:
98 case HAL_DISPLAY_WHITE_BALANCE_B_OFFSET:
99 if (value > MAX_WHITE_BALANCE_OFFSET)
100 value = DEFAULT_WHITE_BALANCE_OFFSET;
103 _E("Unknown white balance type");
107 ret = hal_device_display_set_white_balance(white_balance_type, value);
109 _E("Set white balance is not supported.");
111 _E("Failed to set white balance value.");
116 int display_panel_get_white_balance(enum hal_display_white_balance white_balance_type,
121 if (!display_is_hal_backend_available()) {
122 _E("There is no display device.");
126 switch (white_balance_type) {
127 case HAL_DISPLAY_WHITE_BALANCE_R_GAIN:
128 case HAL_DISPLAY_WHITE_BALANCE_G_GAIN:
129 case HAL_DISPLAY_WHITE_BALANCE_B_GAIN:
130 case HAL_DISPLAY_WHITE_BALANCE_R_OFFSET:
131 case HAL_DISPLAY_WHITE_BALANCE_G_OFFSET:
132 case HAL_DISPLAY_WHITE_BALANCE_B_OFFSET:
135 _E("Unknown white balance type");
139 ret = hal_device_display_get_white_balance(white_balance_type, value);
141 _E("Get white balance is not supported.");
143 _E("Failed to get white balance value.");
148 int display_panel_set_panel_state_by_on_state(enum device_flags flags)
153 _I("[DPMS XLIB Backlight] LCD on %#x cnt:%d", flags, cnt);
156 ret = display_panel_set_dpms_state(DPMS_ON, flags);
159 enum deviced_display_state current;
161 if (display_state_get_current(¤t) < 0)
164 pm_history_save(PM_LOG_LCD_ON, current);
169 int display_panel_set_panel_state_by_off_state(enum device_flags flags)
172 static int cnt, ambient_cnt;
173 int default_brightness = 0;
175 display_backlight_get_default_brightness(&default_brightness);
177 if (flags & AMBIENT_MODE) {
178 _I("[DPMS XLIB Backlight] LCD suspend %#x cnt:%d", flags, ambient_cnt);
183 _I("[DPMS XLIB Backlight] LCD off %#x cnt:%d", flags, cnt);
186 if (flags & LCD_PHASED_TRANSIT_MODE)
187 display_backlight_change_brightness(default_brightness,
188 LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
190 if (flags & FORCE_OFF_MODE)
191 ret = display_panel_set_dpms_state(DPMS_FORCE_OFF, flags);
193 ret = display_panel_set_dpms_state(DPMS_OFF, flags);
196 enum deviced_display_state current;
198 if (display_state_get_current(¤t) < 0)
201 pm_history_save(PM_LOG_LCD_OFF, current);
206 int display_panel_set_panel_state_by_standby_state(bool standby_on)
210 if ((dpms_get_cached_state() == DPMS_ON) || standby_on) {
212 ret = display_panel_set_dpms_state(DPMS_STANDBY, 0);
218 /* FIXME: display_plugin_~ function return value should be handling after refactoring */
219 void display_panel_set_lcd_paneloff_mode(bool on)
221 _I("Lcd paneloff mode: %d", on);
222 lcd_paneloff_mode = on;
224 display_state_transition_request_state_transition_with_option(DEVICED_EVENT_DISPLAY, LCD_NORMAL);
227 /* FIXME: This function is temporary, it can be redefined or not */
228 void display_panel_get_lcd_paneloff_mode(bool *on)
231 _E("Inavlid parameter to get lcd paneloff mode");
235 *on = lcd_paneloff_mode;
238 void display_panel_lcd_on_procedure(int state, enum device_flags flag)
240 unsigned long flags = NORMAL_MODE;
241 display_util_get_device_flags(&flags);
244 if (display_plugin_lcd_on_procedure(state, flag) == 0)
247 * Display on procedure
249 * step 2. broadcast lcd on signal with cause
250 * step 3. set brightness
251 * step 4. set pmstate of vconf
252 * step 5. display on operate
254 * - b. TSP(touch screen) and touchkey enable
255 * step 6. broadcast lcd on complete signal
256 * step 7. key backlight enable
260 _I("[lcdstep] 0x%lx", flags);
262 /* send LCDOn dbus signal */
263 if (!lcd_on_broadcasted)
264 broadcast_lcd_on(SIGNAL_PRE, flags);
266 /* Update brightness level */
267 if (state == LCD_DIM)
268 display_backlight_set_brightness_by_dim_brightness();
269 else if (state == LCD_NORMAL)
270 display_backlight_update_by_default_brightness();
272 if (state == LCD_NORMAL)
273 set_setting_pmstate(DEVICED_DISPLAY_STATE_ON);
274 else if (state == LCD_DIM)
275 set_setting_pmstate(DEVICED_DISPLAY_STATE_DIM);
277 display_start_dependent_device(flags);
279 if (!lcd_on_broadcasted) {
280 broadcast_lcd_on(SIGNAL_POST, flags);
281 lcd_on_broadcasted = true;
284 touchled_control_backlight(TOUCHLED_DIRECT_ON);
286 display_misc_set_touch_event_blocked(false);
289 void display_panel_lcd_off_procedure(enum device_flags flag)
291 unsigned long flags = NORMAL_MODE;
292 display_util_get_device_flags(&flags);
295 if (display_plugin_lcd_off_procedure(flag) == 0)
298 * Display off procedure
299 * step 0. enhance mode off using nofity (e.g mdnie, HBM, LBM)
300 * step 1. broadcast lcd off signal with cause
301 * step 2. set pmstate of vconf
302 * step 3. display off operate
304 * - b. TSP(touch screen) and touchkey disable
305 * step 4. broadcast lcd off complete siganl
306 * step 5. enter doze mode if it is enabled
308 _I("[lcdstep] 0x%lx", flags);
312 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_LCD_OFF, NULL);
314 if (lcd_on_broadcasted) {
315 broadcast_lcd_off(SIGNAL_PRE, flags);
316 lcd_on_broadcasted = false;
321 display_misc_set_touch_event_blocked(true);
323 set_setting_pmstate(DEVICED_DISPLAY_STATE_OFF);
325 touchled_control_backlight(TOUCHLED_DIRECT_OFF);
327 display_stop_dependent_device(flags);
329 broadcast_lcd_off(SIGNAL_POST, flags);
330 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_LCD_OFF_COMPLETE, NULL);
335 void display_panel_lcd_on_direct(enum device_flags flags)
337 enum hal_device_power_transition_reason reason;
339 if (flags & LCD_ON_BY_POWER_KEY)
340 reason = HAL_DEVICE_POWER_TRANSITION_REASON_POWER_KEY;
341 else if (flags & LCD_ON_BY_TOUCH)
342 reason = HAL_DEVICE_POWER_TRANSITION_REASON_TOUCH_SCREEN;
344 reason = HAL_DEVICE_POWER_TRANSITION_REASON_UNKNOWN;
346 syscommon_resman_set_resource_attr_uint64_4(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
347 DEVICED_POWER_ATTR_SET_UINT64_4_CURRENT_STATE,
348 DEVICED_POWER_STATE_SLEEP, DEVICED_POWER_STATE_NORMAL, reason, 0);
350 set_pm_cur_state(DEVICED_DISPLAY_STATE_ON);
352 _D("lcd is on directly");
353 display_panel_update_lcd_on_timeval();
354 display_panel_lcd_on_procedure(LCD_NORMAL, flags);
356 display_state_transition_update_lock_screen_timeout(LOCK_SCREEN_INPUT_TIMEOUT);
359 /* FIXME: timer_refresh_cb seems legacy code, it can be removed after discussion */
360 static gboolean timer_refresh_cb(gpointer data)
362 display_state_set_current(DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT);
366 int display_panel_custom_lcd_on(int timeout)
368 if (display_plugin_custom_lcd_on(timeout) == 0)
374 if (display_panel_get_dpms_cached_state() != DPMS_ON)
375 display_panel_lcd_on_direct(LCD_ON_BY_GESTURE);
377 _I("Custom lcd on timeout(%d ms).", timeout);
378 if (set_custom_lcdon_timeout(timeout))
379 display_state_transition_update_display_state_timeout_by_priority();
381 display_state_set_current(DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT);
383 g_idle_add(timer_refresh_cb, NULL);
388 int display_panel_custom_lcd_off(enum device_flags flag)
390 if (display_plugin_custom_lcd_off(flag) == 0)
393 /* check holdkey block flag in lock node */
394 if (display_lock_is_state_locked(DEVICED_DISPLAY_STATE_ON) || display_lock_is_state_locked(DEVICED_DISPLAY_STATE_DIM)) {
396 * When another proccess is normal lock, device is received call then,
397 * call app can be changed to lcd state by proximity.
398 * If proximity is near then normal lock will be unlocked.
400 if (flag & LCD_OFF_BY_PROXIMITY) {
401 _I("custom lcd off by proximity, delete normal lock");
402 display_lock_release_lock_all(DEVICED_DISPLAY_STATE_ON);
404 _I("skip custom lcd off");
409 _I("custom lcd off by flag(%d)", flag);
410 if (display_panel_get_dpms_cached_state() == DPMS_ON)
411 display_panel_lcd_off_procedure(flag);
413 if (set_custom_lcdon_timeout(0) == true)
414 display_state_transition_update_display_state_timeout_by_priority();
416 display_state_set_current(DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT);
421 /** FIXME: handling method should be considered later,
422 * because the handling is too similar for the same lcd on/off procedure, display state transition.
424 int display_panel_display_turn_on_by_reason(const char *reason, int timeout)
429 if (display_plugin_display_on_by_reason(reason, timeout) == 0)
435 str_len = strlen(reason);
437 if (!strncmp(reason, GESTURE_STR, str_len)) {
438 flag = LCD_ON_BY_GESTURE;
439 } else if (!strncmp(reason, EVENT_STR, str_len)) {
440 flag = LCD_ON_BY_EVENT;
442 _E("Reason is unknown(%s)", reason);
447 _E("Cannot setting timeout %d", timeout);
451 if (display_panel_get_dpms_cached_state() != DPMS_ON)
452 display_panel_lcd_on_direct(flag);
454 _I("platform lcd on by %s (%d ms)", reason, timeout);
455 if (set_custom_lcdon_timeout(timeout) == true)
456 display_state_transition_update_display_state_timeout_by_priority();
458 display_state_set_current(DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT);
463 int display_panel_display_turn_off_by_reason(const char *reason)
468 if (display_plugin_display_off_by_reason(reason) == 0)
474 str_len = strlen(reason);
476 if (!strncmp(reason, GESTURE_STR, str_len)) {
477 if (display_lock_is_state_locked(DEVICED_DISPLAY_STATE_ON) || display_lock_is_state_locked(DEVICED_DISPLAY_STATE_DIM)) {
478 _I("skip platform lcd off by gesture");
481 flag = LCD_OFF_BY_GESTURE;
482 } else if (!strncmp(reason, PALM_STR, str_len)) {
483 display_lock_release_lock_all(DEVICED_DISPLAY_STATE_ON);
484 display_lock_release_lock_all(DEVICED_DISPLAY_STATE_DIM);
486 flag = LCD_OFF_BY_PALM;
488 _E("Reason is unknown(%s)", reason);
492 _I("platform lcd off by %s", reason);
493 if (display_panel_get_dpms_cached_state() == DPMS_ON)
494 display_panel_lcd_off_procedure(flag);
496 display_state_set_current(DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT);
501 bool display_panel_is_lcd_on_state_broadcasted(void)
503 return lcd_on_broadcasted;
506 /* FIXME: lcd on time calculation should be discussed, because it is only for lcd_on_direct routine */
507 void display_panel_update_lcd_on_timeval(void)
509 gettimeofday(&lcd_on_timeval, NULL);
512 int display_panel_calculate_diff_time_between_lcd_on_direct_and_state_action(int *diff_time)
514 struct timeval now_timeval;
519 if (lcd_on_timeval.tv_sec != 0) {
520 gettimeofday(&now_timeval, NULL);
521 *diff_time = DIFF_TIMEVAL_MS(now_timeval, lcd_on_timeval);
522 lcd_on_timeval.tv_sec = 0;
529 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
530 int display_panel_get_dpms_state(void)
533 enum display_state val;
535 ret = hal_device_display_get_state(&val);
540 * FIXME: Ambient mode is currently not the display core feature but wearable profile exclusive
541 * feature. Therefore exclude this condition statement from the display core logic.
542 * Please consider this condition statement when the ambient feature comes into the display core.
544 //if (val == DISPLAY_ON && ambient_get_state())
550 case DISPLAY_STANDBY:
552 case DISPLAY_SUSPEND:
563 int display_panel_get_dpms_cached_state(void)
565 return dpms_get_cached_state();
568 bool display_panel_init_dpms(void)
573 void display_panel_exit_dpms(void)
578 void __display_panel_register_dpms_checklist(int mode, void (*checker)(void), const char *caller)
580 register_dpms_checklist(mode, checker, caller);
583 /* FIXME: This function is used for only wearable profile, should be fixed after plugin refactoring */
584 int display_panel_set_image_effect(enum display_image_effect effect)
588 if (!display_is_hal_backend_available()) {
589 _E("There is no display device.");
593 ret = hal_device_display_set_image_effect(effect);
596 _E("Set image effect is not supported.");
598 _E("Failed to set image effect: %d", ret);
605 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
606 int display_panel_get_image_effect(enum display_image_effect *effect)
609 enum display_image_effect val;
614 if (!display_is_hal_backend_available()) {
615 _E("There is no display device.");
619 ret = hal_device_display_get_image_effect(&val);
622 _E("Get image effect is not supported.");
624 _E("Failed to get image effect: %d", ret);
633 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
634 int display_panel_set_panel_mode(enum display_panel_mode mode)
638 if (!display_is_hal_backend_available()) {
639 _E("There is no display device.");
643 ret = hal_device_display_set_panel_mode(mode);
646 _E("Set panel mode is not supported.");
648 _E("Failed to set panel mode(%d)", ret);
655 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
656 int display_panel_get_panel_mode(enum display_panel_mode *mode)
659 enum display_panel_mode val;
664 if (!display_is_hal_backend_available()) {
665 _E("There is no display device.");
669 ret = hal_device_display_get_panel_mode(&val);
672 _E("Get panel mode is not supported.");
674 _E("Failed to get panel mode(%d)", ret);
683 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
684 int display_panel_set_frame_rate(int frame_rate)
687 static int fmin = -1, fmax = -1;
689 if (!display_is_hal_backend_available())
693 ret = hal_device_display_get_min_frame_rate(&fmin);
695 _E("Failed to get min frate rate: %d", ret);
699 if ((ret != -ENODEV) && (frame_rate < fmin)) {
700 _E("Invalid rate(%d). (Valid rate: %d <= rate)", frame_rate, fmin);
705 ret = hal_device_display_get_max_frame_rate(&fmax);
707 _E("Failed to get max frate rate: %d", ret);
711 if ((ret != -ENODEV) && (frame_rate > fmax)) {
712 _E("Invalid rate(%d). (Valid rate: rate <= %d)", frame_rate, fmax);
716 return hal_device_display_set_frame_rate(frame_rate);
719 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
720 int display_panel_get_frame_rate(int *frame_rate)
725 if (!display_is_hal_backend_available())
728 return hal_device_display_get_frame_rate(frame_rate);