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