1 /*
2 * Allwinner SoCs display driver.
3 *
4 * Copyright (C) 2016 Allwinner.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11 #include "disp_smart_backlight.h"
12 #include <hal_atomic.h>
13
14 struct disp_smbl_private_data {
15 struct disp_smbl_info info;
16 bool applied;
17
18 s32 (*shadow_protect)(u32 sel, bool protect);
19
20 u32 enabled;
21 hal_sem_t mlock;
22 };
23 static u32 smbl_data_lock;
24
25 /* #define SMBL_NO_AL */
26 static struct disp_smbl *smbls;
27 static struct disp_smbl_private_data *smbl_private;
28
disp_get_smbl(u32 disp)29 struct disp_smbl *disp_get_smbl(u32 disp)
30 {
31 u32 num_screens;
32
33 num_screens = bsp_disp_feat_get_num_screens();
34 if (disp >= num_screens) {
35 DE_WRN("disp %d out of range\n", disp);
36 return NULL;
37 }
38 DE_INF("get smbl%d ok\n", disp);
39
40 if (bsp_disp_feat_is_support_smbl(disp))
41 return &smbls[disp];
42 else
43 return NULL;
44 }
disp_smbl_get_priv(struct disp_smbl * smbl)45 static struct disp_smbl_private_data *disp_smbl_get_priv(struct disp_smbl *smbl)
46 {
47 if (smbl == NULL) {
48 DE_INF("NULL hdl!\n");
49 return NULL;
50 }
51
52 return &smbl_private[smbl->disp];
53 }
54
disp_smbl_update_regs(struct disp_smbl * smbl)55 static s32 disp_smbl_update_regs(struct disp_smbl *smbl)
56 {
57 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
58 bool applied = false;
59
60 if ((smbl == NULL) || (smblp == NULL)) {
61 DE_INF("NULL hdl!\n");
62 return -1;
63 }
64 smbl_data_lock = hal_spin_lock_irqsave(&disp_lock);
65 if (true == smblp->applied) {
66 applied = true;
67 smblp->applied = false;
68 }
69 hal_spin_unlock_irqrestore(&disp_lock, smbl_data_lock);
70
71 disp_al_smbl_update_regs(smbl->disp);
72
73 return 0;
74 }
75
76 /* should protect width @mlock */
disp_smbl_update_backlight(struct disp_smbl * smbl,unsigned int bl)77 static s32 disp_smbl_update_backlight(struct disp_smbl *smbl, unsigned int bl)
78 {
79 if (smbl == NULL) {
80 DE_INF("NULL hdl!\n");
81 return -1;
82 }
83
84 smbl->backlight = bl;
85 smbl->apply(smbl);
86
87 return 0;
88 }
89
90 /* should protect width @mlock */
disp_smbl_apply(struct disp_smbl * smbl)91 static s32 disp_smbl_apply(struct disp_smbl *smbl)
92 {
93 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
94 struct disp_smbl_info info;
95
96 if ((smbl == NULL) || (smblp == NULL)) {
97 DE_INF("NULL hdl!\n");
98 return -1;
99 }
100
101 memset(&info, 0, sizeof(struct disp_smbl_info));
102
103 /* disp_sys_mutex_lock(&smblp->mlock); */
104 if (smbl->backlight != smblp->info.backlight) {
105 smblp->info.backlight = smbl->backlight;
106 smblp->info.flags |= SMBL_DIRTY_BL;
107 }
108 if (smblp->info.flags != SMBL_DIRTY_NONE) {
109 memcpy(&info, &smblp->info, sizeof(struct disp_smbl_info));
110 smblp->info.flags = SMBL_DIRTY_NONE;
111 disp_smbl_shadow_protect(smbl, true);
112 disp_al_smbl_apply(smbl->disp, &info);
113 disp_smbl_shadow_protect(smbl, false);
114 smbl_data_lock = hal_spin_lock_irqsave(&disp_lock);
115 smblp->applied = true;
116 hal_spin_unlock_irqrestore(&disp_lock, smbl_data_lock);
117 }
118 /* disp_sys_mutex_unlock(&smblp->mlock); */
119
120 return 0;
121 }
122
disp_smbl_force_apply(struct disp_smbl * smbl)123 static s32 disp_smbl_force_apply(struct disp_smbl *smbl)
124 {
125 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
126
127 if ((smbl == NULL) || (smblp == NULL)) {
128 DE_INF("NULL hdl!\n");
129 return -1;
130 }
131
132 disp_sys_mutex_lock(&smblp->mlock);
133 smblp->info.flags = SMBL_DIRTY_ALL;
134 disp_smbl_apply(smbl);
135 disp_smbl_update_regs(smbl);
136 disp_sys_mutex_unlock(&smblp->mlock);
137
138 return 0;
139 }
140
disp_smbl_sync(struct disp_smbl * smbl)141 static s32 disp_smbl_sync(struct disp_smbl *smbl)
142 {
143 if (smbl == NULL) {
144 DE_INF("NULL hdl!\n");
145 return -1;
146 }
147
148 disp_smbl_update_regs(smbl);
149
150 return 0;
151 }
152
disp_smbl_tasklet(struct disp_smbl * smbl)153 static s32 disp_smbl_tasklet(struct disp_smbl *smbl)
154 {
155 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
156 struct disp_manager *mgr;
157 unsigned int dimming;
158 bool dimming_update = false;
159
160 if ((smbl == NULL) || (smblp == NULL)) {
161 DE_INF("NULL hdl!\n");
162 return -1;
163 }
164
165 disp_al_smbl_tasklet(smbl->disp);
166 dimming = disp_al_smbl_get_status(smbl->disp);
167 if (smblp->info.backlight_dimming != dimming) {
168 smblp->info.backlight_dimming = dimming;
169 dimming_update = true;
170 }
171
172 mgr = smbl->manager;
173 if (mgr && mgr->device) {
174 struct disp_device *dispdev = mgr->device;
175
176 if (dispdev->set_bright_dimming && dimming_update) {
177 if (dispdev->set_bright_dimming)
178 dispdev->set_bright_dimming(dispdev,
179 smblp->info.backlight_dimming);
180 }
181 }
182
183 return 0;
184 }
185
disp_smbl_is_enabled(struct disp_smbl * smbl)186 static bool disp_smbl_is_enabled(struct disp_smbl *smbl)
187 {
188 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
189
190 if ((smbl == NULL) || (smblp == NULL)) {
191 DE_INF("NULL hdl!\n");
192 return false;
193 }
194
195 return (smblp->info.enable == 1);
196 }
197
disp_smbl_enable(struct disp_smbl * smbl)198 static s32 disp_smbl_enable(struct disp_smbl *smbl)
199 {
200 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
201 struct disp_device *dispdev = NULL;
202
203 if ((smbl == NULL) || (smblp == NULL)) {
204 DE_INF("NULL hdl!\n");
205 return -1;
206 }
207 if (smbl->manager)
208 dispdev = smbl->manager->device;
209 if (dispdev)
210 dispdev->get_resolution(dispdev, &smblp->info.size.width,
211 &smblp->info.size.height);
212
213 if ((smblp->info.window.width == 0)
214 || (smblp->info.window.height == 0)) {
215 smblp->info.window.width = smblp->info.size.width;
216 smblp->info.window.height = smblp->info.size.height;
217 }
218
219 DE_INF("smbl %d enable\n", smbl->disp);
220 disp_sys_mutex_lock(&smblp->mlock);
221 smblp->info.enable = 1;
222 smblp->info.flags |= SMBL_DIRTY_ENABLE;
223 disp_smbl_apply(smbl);
224 disp_sys_mutex_unlock(&smblp->mlock);
225
226 return 0;
227 }
228
disp_smbl_disable(struct disp_smbl * smbl)229 static s32 disp_smbl_disable(struct disp_smbl *smbl)
230 {
231 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
232
233 if ((smbl == NULL) || (smblp == NULL)) {
234 DE_INF("NULL hdl!\n");
235 return -1;
236 }
237 DE_INF("smbl %d disable\n", smbl->disp);
238
239 disp_sys_mutex_lock(&smblp->mlock);
240 smblp->info.enable = 0;
241 smblp->info.flags |= SMBL_DIRTY_ENABLE;
242 disp_smbl_apply(smbl);
243 disp_sys_mutex_unlock(&smblp->mlock);
244
245 return 0;
246 }
247
disp_smbl_shadow_protect(struct disp_smbl * smbl,bool protect)248 s32 disp_smbl_shadow_protect(struct disp_smbl *smbl, bool protect)
249 {
250 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
251
252 if ((smbl == NULL) || (smblp == NULL)) {
253 DE_INF("NULL hdl!\n");
254 return -1;
255 }
256
257 if (smblp->shadow_protect)
258 return smblp->shadow_protect(smbl->disp, protect);
259
260 return -1;
261 }
262
disp_smbl_set_window(struct disp_smbl * smbl,struct disp_rect * window)263 static s32 disp_smbl_set_window(struct disp_smbl *smbl,
264 struct disp_rect *window)
265 {
266 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
267
268 if ((smbl == NULL) || (smblp == NULL)) {
269 DE_INF("NULL hdl!\n");
270 return -1;
271 }
272 disp_sys_mutex_lock(&smblp->mlock);
273 memcpy(&smblp->info.window, window, sizeof(struct disp_rect));
274 smblp->info.flags |= SMBL_DIRTY_WINDOW;
275 disp_smbl_apply(smbl);
276 disp_sys_mutex_unlock(&smblp->mlock);
277
278 return 0;
279 }
280
disp_smbl_get_window(struct disp_smbl * smbl,struct disp_rect * window)281 static s32 disp_smbl_get_window(struct disp_smbl *smbl,
282 struct disp_rect *window)
283 {
284 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
285
286 if ((smbl == NULL) || (smblp == NULL)) {
287 DE_INF("NULL hdl!\n");
288 return -1;
289 }
290 disp_sys_mutex_lock(&smblp->mlock);
291 memcpy(window, &smblp->info.window, sizeof(struct disp_rect));
292 disp_sys_mutex_unlock(&smblp->mlock);
293
294 return 0;
295 }
296
disp_smbl_set_manager(struct disp_smbl * smbl,struct disp_manager * mgr)297 static s32 disp_smbl_set_manager(struct disp_smbl *smbl,
298 struct disp_manager *mgr)
299 {
300 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
301
302 if ((smbl == NULL) || (mgr == NULL) || (smblp == NULL)) {
303 DE_INF("NULL hdl!\n");
304 return -1;
305 }
306
307 DE_INF("smbl %d -> mgr %d\n", smbl->disp, mgr->disp);
308 disp_sys_mutex_lock(&smblp->mlock);
309 smbl->manager = mgr;
310 mgr->smbl = smbl;
311 disp_sys_mutex_unlock(&smblp->mlock);
312
313 return 0;
314 }
315
disp_smbl_unset_manager(struct disp_smbl * smbl)316 static s32 disp_smbl_unset_manager(struct disp_smbl *smbl)
317 {
318 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
319
320 if ((smbl == NULL) || (smblp == NULL)) {
321 DE_INF("NULL hdl!\n");
322 return -1;
323 }
324 disp_sys_mutex_lock(&smblp->mlock);
325 if (smbl->manager)
326 smbl->manager->smbl = NULL;
327 smbl->manager = NULL;
328 disp_sys_mutex_unlock(&smblp->mlock);
329
330 return 0;
331 }
332
disp_smbl_dump(struct disp_smbl * smbl,char * buf)333 static s32 disp_smbl_dump(struct disp_smbl *smbl, char *buf)
334 {
335 struct disp_smbl_info info;
336 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
337 u32 count = 0;
338
339 if ((smbl == NULL) || (smblp == NULL)) {
340 DE_INF("NULL hdl!\n");
341 return -1;
342 }
343
344 memcpy(&info, &smblp->info, sizeof(struct disp_smbl_info));
345
346 count +=
347 sprintf(buf + count,
348 "smart_backlight %d: %s, window<%d,%d,%d,%d>, backlight=%d, save_power=%d percent\n",
349 smbl->disp, (info.enable == 1) ? "enable" : "disable",
350 info.window.x, info.window.y, info.window.width,
351 info.window.height, smbl->backlight,
352 100 - info.backlight_dimming * 100 / 256);
353
354 return count;
355 }
356
disp_smbl_init(struct disp_smbl * smbl)357 static s32 disp_smbl_init(struct disp_smbl *smbl)
358 {
359 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
360
361 if ((smbl == NULL) || (smblp == NULL)) {
362 DE_INF("NULL hdl!\n");
363 return -1;
364 }
365
366 return 0;
367 }
368
disp_smbl_exit(struct disp_smbl * smbl)369 static s32 disp_smbl_exit(struct disp_smbl *smbl)
370 {
371 struct disp_smbl_private_data *smblp = disp_smbl_get_priv(smbl);
372
373 if ((smbl == NULL) || (smblp == NULL)) {
374 DE_INF("NULL hdl!\n");
375 return -1;
376 }
377
378 return 0;
379 }
380
disp_init_smbl(struct disp_bsp_init_para * para)381 s32 disp_init_smbl(struct disp_bsp_init_para *para)
382 {
383 u32 num_smbls;
384 u32 disp;
385 struct disp_smbl *smbl;
386 struct disp_smbl_private_data *smblp;
387
388 DE_INF("disp_init_smbl\n");
389
390 smbl_data_lock = 0;
391 num_smbls = bsp_disp_feat_get_num_screens();
392 smbls =
393 disp_sys_malloc(num_smbls * sizeof(struct disp_smbl));
394 if (smbls == NULL) {
395 DE_WRN("malloc memory fail!\n");
396 goto malloc_err;
397 }
398 smbl_private =
399 (struct disp_smbl_private_data *)
400 disp_sys_malloc(sizeof(struct disp_smbl_private_data)
401 * num_smbls);
402 if (smbl_private == NULL) {
403 DE_WRN("malloc memory fail!\n");
404 goto malloc_err;
405 }
406
407 for (disp = 0; disp < num_smbls; disp++) {
408 if (!bsp_disp_feat_is_support_smbl(disp))
409 continue;
410
411 smbl = &smbls[disp];
412 smblp = &smbl_private[disp];
413 disp_sys_mutex_init(&smblp->mlock);
414
415 switch (disp) {
416 case 0:
417 smbl->name = "smbl0";
418 smbl->disp = 0;
419
420 break;
421 case 1:
422 smbl->name = "smbl1";
423 smbl->disp = 1;
424
425 break;
426 case 2:
427 smbl->name = "smbl2";
428 smbl->disp = 2;
429
430 break;
431 }
432 smblp->shadow_protect = para->shadow_protect;
433
434 smbl->enable = disp_smbl_enable;
435 smbl->disable = disp_smbl_disable;
436 smbl->is_enabled = disp_smbl_is_enabled;
437 smbl->init = disp_smbl_init;
438 smbl->exit = disp_smbl_exit;
439 smbl->apply = disp_smbl_apply;
440 smbl->force_apply = disp_smbl_force_apply;
441 smbl->update_regs = disp_smbl_update_regs;
442 smbl->sync = disp_smbl_sync;
443 smbl->tasklet = disp_smbl_tasklet;
444 smbl->set_manager = disp_smbl_set_manager;
445 smbl->unset_manager = disp_smbl_unset_manager;
446 smbl->set_window = disp_smbl_set_window;
447 smbl->get_window = disp_smbl_get_window;
448 smbl->update_backlight = disp_smbl_update_backlight;
449 smbl->dump = disp_smbl_dump;
450
451 smbl->init(smbl);
452 }
453
454 return 0;
455
456 malloc_err:
457 disp_sys_free(smbl_private);
458 disp_sys_free(smbls);
459 smbl_private = NULL;
460 smbls = NULL;
461
462 return -1;
463 }
464
disp_exit_smbl(void)465 s32 disp_exit_smbl(void)
466 {
467 u32 num_smbls;
468 u32 disp;
469 struct disp_smbl *smbl;
470
471 if (!smbls)
472 return 0;
473
474 num_smbls = bsp_disp_feat_get_num_screens();
475 for (disp = 0; disp < num_smbls; disp++) {
476 if (!bsp_disp_feat_is_support_smbl(disp))
477 continue;
478
479 smbl = &smbls[disp];
480 smbl->exit(smbl);
481 }
482
483 disp_sys_free(smbl_private);
484 disp_sys_free(smbls);
485 smbl_private = NULL;
486 smbls = NULL;
487
488 return 0;
489 }
490
491