display: Fix typo
[platform/core/system/deviced.git] / src / display / display-panel.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18 #include <sys/time.h>
19
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"
34
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
39
40 #define LCD_PHASED_MIN_BRIGHTNESS       1
41 #define LCD_PHASED_CHANGE_STEP          5
42
43 #define DIFF_TIMEVAL_MS(a, b) \
44         (((a.tv_sec * 1000000 + a.tv_usec) - \
45         (b.tv_sec * 1000000 + b.tv_usec)) \
46         / 1000)
47
48 static bool lcd_paneloff_mode = false;
49 static bool lcd_on_broadcasted = true;
50 static struct timeval lcd_on_timeval;
51
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)
54 {
55         dpms_set_state(dpms_on);
56
57 #ifdef ENABLE_PM_LOG
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());
62         else
63                 pm_history_save(PM_LOG_LCD_CONTROL_FAIL, dpms_on);
64 #endif
65
66         return 0;
67 }
68
69 int display_panel_set_white_balance(enum hal_display_white_balance white_balance_type,
70                                         int value)
71 {
72         int ret = 0;
73
74         if (!display_is_hal_backend_available()) {
75                 _E("There is no display device.");
76                 return -ENOENT;
77         }
78
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;
85                 break;
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;
91                 break;
92         default:
93                 _E("Unknown white balance type");
94                 return -EINVAL;
95         }
96
97         ret = hal_device_display_set_white_balance(white_balance_type, value);
98         if (ret == -ENODEV)
99                 _E("Set white balance is not supported.");
100         else if (ret < 0)
101                 _E("Failed to set white balance value.");
102
103         return ret;
104 }
105
106 int display_panel_get_white_balance(enum hal_display_white_balance white_balance_type,
107                                         int* value)
108 {
109         int ret = 0;
110
111         if (!display_is_hal_backend_available()) {
112                 _E("There is no display device.");
113                 return -ENOENT;
114         }
115
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:
123                 break;
124         default:
125                 _E("Unknown white balance type");
126                 return -EINVAL;
127         }
128
129         ret = hal_device_display_get_white_balance(white_balance_type, value);
130         if (ret == -ENODEV)
131                 _E("Get white balance is not supported.");
132         else if (ret < 0)
133                 _E("Failed to get white balance value.");
134
135         return ret;
136 }
137
138 int display_panel_set_panel_state_by_on_state(enum device_flags flags)
139 {
140         int ret = -1;
141         static int cnt;
142
143         _I("[DPMS XLIB Backlight] LCD on %#x cnt:%d", flags, cnt);
144
145         cnt++;
146         ret = display_panel_set_dpms_state(DPMS_ON, flags);
147
148 #ifdef ENABLE_PM_LOG
149         pm_history_save(PM_LOG_LCD_ON, get_pm_cur_state());
150 #endif
151         return ret;
152 }
153
154 int display_panel_set_panel_state_by_off_state(enum device_flags flags)
155 {
156         int ret = -1;
157         static int cnt, ambient_cnt;
158         int default_brightness = 0;
159
160         display_backlight_get_default_brightness(&default_brightness);
161
162         if (flags & AMBIENT_MODE) {
163                 _I("[DPMS XLIB Backlight] LCD suspend %#x cnt:%d", flags, ambient_cnt);
164                 ambient_cnt++;
165                 return 0;
166         }
167
168         _I("[DPMS XLIB Backlight] LCD off %#x cnt:%d", flags, cnt);
169         cnt++;
170
171         if (flags & LCD_PHASED_TRANSIT_MODE)
172                 display_backlight_change_brightness(default_brightness,
173                         LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
174
175         if (flags & FORCE_OFF_MODE)
176                 ret = display_panel_set_dpms_state(DPMS_FORCE_OFF, flags);
177         else
178                 ret = display_panel_set_dpms_state(DPMS_OFF, flags);
179
180 #ifdef ENABLE_PM_LOG
181         pm_history_save(PM_LOG_LCD_OFF, get_pm_cur_state());
182 #endif
183         return ret;
184 }
185
186 int display_panel_set_panel_state_by_standby_state(bool standby_on)
187 {
188         int ret = -1;
189
190         if ((dpms_get_cached_state() == DPMS_ON) || standby_on) {
191                 _I("LCD standby");
192                 ret = display_panel_set_dpms_state(DPMS_STANDBY, 0);
193         }
194
195         return ret;
196 }
197
198 /* FIXME: display_plugin_~ function return value should be handling after refactoring */
199 void display_panel_set_lcd_paneloff_mode(bool on)
200 {
201         _I("Lcd paneloff mode: %d", on);
202         lcd_paneloff_mode = on;
203
204         display_state_transition_request_state_transition_with_option(INTERNAL_LOCK_PM, LCD_NORMAL);
205 }
206
207 /* FIXME: This function is temporary, it can be redefined or not */
208 void display_panel_get_lcd_paneloff_mode(bool *on)
209 {
210         if (!on) {
211                 _E("Inavlid parameter to get lcd paneloff mode");
212                 return;
213         }
214
215         *on = lcd_paneloff_mode;
216 }
217
218 void display_panel_lcd_on_procedure(int state, enum device_flags flag)
219 {
220         unsigned long flags = NORMAL_MODE;
221         display_util_get_device_flags(&flags);
222         flags |= flag;
223
224         if (display_plugin_lcd_on_procedure(state, flag) == 0)
225                 return;
226         /*
227          * Display on procedure
228          * step 1. leave doze
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
233          *  - a. display on
234          *  - b. TSP(touch screen) and touchkey enable
235          * step 6. broadcast lcd on complete signal
236          * step 7. key backlight enable
237          */
238         leave_doze();
239
240         _I("[lcdstep] 0x%lx", flags);
241
242         /* send LCDOn dbus signal */
243         if (!lcd_on_broadcasted)
244                 broadcast_lcd_on(SIGNAL_PRE, flags);
245
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();
251
252         if (state == LCD_NORMAL)
253                 set_setting_pmstate(S_NORMAL);
254         else if (state == LCD_DIM)
255                 set_setting_pmstate(S_LCDDIM);
256
257         display_start_dependent_device(flags);
258
259         if (!lcd_on_broadcasted) {
260         broadcast_lcd_on(SIGNAL_POST, flags);
261                 lcd_on_broadcasted = true;
262         }
263
264         touchled_control_backlight(TOUCHLED_DIRECT_ON);
265
266         display_misc_set_touch_event_blocked(false);
267 }
268
269 void display_panel_lcd_off_procedure(enum device_flags flag)
270 {
271         unsigned long flags = NORMAL_MODE;
272         display_util_get_device_flags(&flags);
273         flags |= flag;
274
275         if (display_plugin_lcd_off_procedure(flag) == 0)
276                 return;
277         /*
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
283          *  - a. display off
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
287          */
288         _I("[lcdstep] 0x%lx", flags);
289
290         /* notification */
291
292         device_notify(DEVICE_NOTIFIER_LCD_OFF, NULL);
293
294         if (lcd_on_broadcasted) {
295                 broadcast_lcd_off(SIGNAL_PRE, flags);
296                 lcd_on_broadcasted = false;
297         }
298
299         /* operation */
300
301         display_misc_set_touch_event_blocked(true);
302
303         set_setting_pmstate(S_LCDOFF);
304
305         touchled_control_backlight(TOUCHLED_DIRECT_OFF);
306
307         display_stop_dependent_device(flags);
308
309         broadcast_lcd_off(SIGNAL_POST, flags);
310         device_notify(DEVICE_NOTIFIER_LCD_OFF_COMPLETE, NULL);
311
312         enter_doze();
313 }
314
315 void display_panel_lcd_on_direct(enum device_flags flags)
316 {
317         enum hal_device_power_transition_reason reason;
318
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;
323         else
324                 reason = HAL_DEVICE_POWER_TRANSITION_REASON_UNKNOWN;
325
326         power_request_change_state_strict(DEVICED_POWER_STATE_SLEEP, DEVICED_POWER_STATE_NORMAL, reason, NULL);
327         set_pm_cur_state(S_NORMAL);
328
329         _D("lcd is on directly");
330         display_panel_update_lcd_on_timeval();
331         display_panel_lcd_on_procedure(LCD_NORMAL, flags);
332
333         display_state_transition_update_lock_screen_timeout(LOCK_SCREEN_INPUT_TIMEOUT);
334 }
335
336 static void display_state_updated_to_next_and_do_action(enum state_t next)
337 {
338         int timeout = 0;
339         set_pm_old_state(get_pm_cur_state());
340         set_pm_cur_state(next);
341
342         display_plugin_state_get_timeout(get_pm_cur_state(), &timeout);
343         display_state_transition_do_state_action(timeout);
344 }
345
346 /* FIXME: timer_refresh_cb seems legacy code, it can be removed after discussion */
347 static gboolean timer_refresh_cb(gpointer data)
348 {
349         display_state_updated_to_next_and_do_action(S_NORMAL);
350         return 0;
351 }
352
353 int display_panel_custom_lcd_on(int timeout)
354 {
355         if (display_plugin_custom_lcd_on(timeout) == 0)
356                 return 0;
357
358         if (timeout <= 0)
359                 return -EINVAL;
360
361         if (display_panel_get_dpms_cached_state() != DPMS_ON)
362                 display_panel_lcd_on_direct(LCD_ON_BY_GESTURE);
363
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();
367
368         display_state_updated_to_next_and_do_action(S_NORMAL);
369
370         g_idle_add(timer_refresh_cb, NULL);
371
372         return 0;
373 }
374
375 int display_panel_custom_lcd_off(enum device_flags flag)
376 {
377         if (display_plugin_custom_lcd_off(flag) == 0)
378                 return 0;
379
380         /* check holdkey block flag in lock node */
381         if (display_lock_is_state_locked(S_NORMAL) || display_lock_is_state_locked(S_LCDDIM)) {
382                 /*
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.
386                  */
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);
390                 } else {
391                         _I("skip custom lcd off");
392                         return -ECANCELED;
393                 }
394         }
395
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);
399
400         if (set_custom_lcdon_timeout(0) == true)
401                 display_state_transition_update_display_state_timeout_by_priority();
402
403         display_state_updated_to_next_and_do_action(S_LCDOFF);
404
405         return 0;
406 }
407
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.
410 */
411 int display_panel_display_turn_on_by_reason(const char *reason, int timeout)
412 {
413         int flag;
414         int str_len;
415
416         if (display_plugin_display_on_by_reason(reason, timeout) == 0)
417                 return 0;
418
419         if (!reason)
420                 return -EINVAL;
421
422         str_len = strlen(reason);
423
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;
428         } else {
429                 _E("Reason is unknown(%s)", reason);
430                 return -EINVAL;
431         }
432
433         if (timeout <= 0) {
434                 _E("Cannot setting timeout %d", timeout);
435                 return -EINVAL;
436         }
437
438         if (display_panel_get_dpms_cached_state() != DPMS_ON)
439                 display_panel_lcd_on_direct(flag);
440
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();
444
445         display_state_updated_to_next_and_do_action(S_NORMAL);
446
447         return 0;
448 }
449
450 int display_panel_display_turn_off_by_reason(const char *reason)
451 {
452         int flag;
453         int str_len;
454
455         if (display_plugin_display_off_by_reason(reason) == 0)
456                 return 0;
457
458         if (!reason)
459                 return -EINVAL;
460
461         str_len = strlen(reason);
462
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");
466                         return -ECANCELED;
467                 }
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);
472
473                 flag = LCD_OFF_BY_PALM;
474         } else {
475                 _E("Reason is unknown(%s)", reason);
476                 return -EINVAL;
477         }
478
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);
482
483         display_state_updated_to_next_and_do_action(S_LCDOFF);
484
485         return 0;
486 }
487
488 bool display_panel_is_lcd_on_state_broadcasted(void)
489 {
490         return lcd_on_broadcasted;
491 }
492
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)
495 {
496         gettimeofday(&lcd_on_timeval, NULL);
497 }
498
499 int display_panel_calculate_diff_time_between_lcd_on_direct_and_state_action(int *diff_time)
500 {
501         struct timeval now_timeval;
502
503         if (!diff_time)
504                 return -EINVAL;
505
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;
510                 return 0;
511         }
512
513         return -1;
514 }
515
516 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
517 int display_panel_get_dpms_state(void)
518 {
519         int ret;
520         enum display_state val;
521
522         ret = hal_device_display_get_state(&val);
523         if (ret < 0)
524                 return ret;
525
526         /**
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.
530          */
531         //if (val == DISPLAY_ON && ambient_get_state())
532         //      return DPMS_OFF;
533
534         switch (val) {
535                 case DISPLAY_ON:
536                         return DPMS_ON;
537                 case DISPLAY_STANDBY:
538                         return DPMS_STANDBY;
539                 case DISPLAY_SUSPEND:
540                         return DPMS_SUSPEND;
541                 case DISPLAY_OFF:
542                         return DPMS_OFF;
543                 case DISPLAY_DETACH:
544                         return DPMS_DETACH;
545                 default:
546                         return -EINVAL;
547         }
548 }
549
550 int display_panel_get_dpms_cached_state(void)
551 {
552         return dpms_get_cached_state();
553 }
554
555 bool display_panel_init_dpms(void)
556 {
557         return dpms_init();
558 }
559
560 void display_panel_exit_dpms(void)
561 {
562         dpms_exit();
563 }
564
565 void __display_panel_register_dpms_checklist(int mode, void (*checker)(void), const char *caller)
566 {
567         register_dpms_checklist(mode, checker, caller);
568 }
569
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)
572 {
573         int ret;
574
575         if (!display_is_hal_backend_available()) {
576                 _E("There is no display device.");
577                 return -ENOENT;
578         }
579
580         ret = hal_device_display_set_image_effect(effect);
581         if (ret < 0) {
582                 if (ret == -ENODEV)
583                         _E("Set image effect is not supported.");
584                 else
585                         _E("Failed to set image effect: %d", ret);
586                 return ret;
587         }
588
589         return 0;
590 }
591
592 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
593 int display_panel_get_image_effect(enum display_image_effect *effect)
594 {
595         int ret;
596         enum display_image_effect val;
597
598         if (!effect)
599                 return -EINVAL;
600
601         if (!display_is_hal_backend_available()) {
602                 _E("There is no display device.");
603                 return -ENOENT;
604         }
605
606         ret = hal_device_display_get_image_effect(&val);
607         if (ret < 0) {
608                 if (ret == -ENODEV)
609                         _E("Get image effect is not supported.");
610                 else
611                         _E("Failed to get image effect: %d", ret);
612                 return ret;
613         }
614
615         *effect = val;
616
617         return 0;
618 }
619
620 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
621 int display_panel_set_panel_mode(enum display_panel_mode mode)
622 {
623         int ret;
624
625         if (!display_is_hal_backend_available()) {
626                 _E("There is no display device.");
627                 return -ENOENT;
628         }
629
630         ret = hal_device_display_set_panel_mode(mode);
631         if (ret < 0) {
632                 if (ret == -ENODEV)
633                         _E("Set panel mode is not supported.");
634                 else
635                         _E("Failed to set panel mode(%d)", ret);
636                 return ret;
637         }
638
639         return 0;
640 }
641
642 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
643 int display_panel_get_panel_mode(enum display_panel_mode *mode)
644 {
645         int ret;
646         enum display_panel_mode val;
647
648         if (!mode)
649                 return -EINVAL;
650
651         if (!display_is_hal_backend_available()) {
652                 _E("There is no display device.");
653                 return -ENOENT;
654         }
655
656         ret = hal_device_display_get_panel_mode(&val);
657         if (ret < 0) {
658                 if (ret == -ENODEV)
659                         _E("Get panel mode is not supported.");
660                 else
661                         _E("Failed to get panel mode(%d)", ret);
662                 return ret;
663         }
664
665         *mode = val;
666
667         return 0;
668 }
669
670 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
671 int display_panel_set_frame_rate(int frame_rate)
672 {
673         int ret = 0;
674         static int fmin = -1, fmax = -1;
675
676         if (!display_is_hal_backend_available())
677                 return -ENOTSUP;
678
679         if (fmin < 0) {
680                 ret = hal_device_display_get_min_frame_rate(&fmin);
681                 if (ret < 0) {
682                         _E("Failed to get min frate rate: %d", ret);
683                         return ret;
684                 }
685         }
686         if ((ret != -ENODEV) && (frame_rate < fmin)) {
687                 _E("Invalid rate(%d). (Valid rate: %d <= rate)", frame_rate, fmin);
688                 return -EINVAL;
689         }
690
691         if (fmax < 0) {
692                 ret = hal_device_display_get_max_frame_rate(&fmax);
693                 if (ret < 0) {
694                         _E("Failed to get max frate rate: %d", ret);
695                         return ret;
696                 }
697         }
698         if ((ret != -ENODEV) && (frame_rate > fmax)) {
699                 _E("Invalid rate(%d). (Valid rate: rate <= %d)", frame_rate, fmax);
700                 return -EINVAL;
701         }
702
703         return hal_device_display_set_frame_rate(frame_rate);
704 }
705
706 /* FIXME: This function is deprecated, should be fixed after plugin refactoring */
707 int display_panel_get_frame_rate(int *frame_rate)
708 {
709         if (!frame_rate)
710                 return -EINVAL;
711
712         if (!display_is_hal_backend_available())
713                 return -ENOTSUP;
714
715         return hal_device_display_get_frame_rate(frame_rate);
716 }