• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Allwinner SoCs display driver.
2  *
3  * Copyright (C) 2016 Allwinner.
4  *
5  * This file is licensed under the terms of the GNU General Public
6  * License version 2.  This program is licensed "as is" without any
7  * warranty of any kind, whether express or implied.
8  */
9 
10 #include "dev_disp.h"
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/version.h>
14 #include <linux/fb.h>
15 #include <linux/memblock.h>
16 #if defined(SUPPORT_EDP)
17 #include "de/disp_edp.h"
18 #endif /*endif defined(SUPPORT_EDP) */
19 #include "fb_g2d_rot.h"
20 #include <linux/decompress/unlzma.h>
21 #include <linux/dma-buf.h>
22 #include <linux/dma-mapping.h>
23 
24 #ifndef dma_mmap_writecombine
25 #define dma_mmap_writecombine dma_mmap_wc
26 #endif
27 
28 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT) ||                         \
29     defined(CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT)
30 #define SUPPORT_ROTATE
31 #endif
32 
33 #define VSYNC_NUM 4
34 #define SUNXI_FB_MAX 1
35 struct fb_info_t {
36 	struct device *dev;
37 
38 	bool fb_enable[SUNXI_FB_MAX];
39 	enum disp_fb_mode fb_mode[SUNXI_FB_MAX];
40 	u32 layer_hdl[SUNXI_FB_MAX][2];	/* channel, layer_id */
41 	struct fb_info *fbinfo[SUNXI_FB_MAX];
42 	struct disp_fb_create_info fb_para[SUNXI_FB_MAX];
43 	u32 pseudo_palette[SUNXI_FB_MAX][16];
44 	wait_queue_head_t wait[3];
45 	unsigned long wait_count[3];
46 	struct fb_g2d_rot_t *fb_rot[FB_MAX];
47 	int mem_cache_flag[SUNXI_FB_MAX];
48 
49 	int blank[3];
50 	struct disp_ion_mem *mem[SUNXI_FB_MAX];
51 	struct disp_layer_config config[SUNXI_FB_MAX];
52 };
53 
54 static struct fb_info_t g_fbi;
55 static phys_addr_t bootlogo_addr;
56 static int bootlogo_sz;
57 
58 #define FBHANDTOID(handle)  ((handle) - 100)
59 #define FBIDTOHAND(ID)  ((ID) + 100)
60 
61 static struct __fb_addr_para g_fb_addr;
62 
sunxi_get_fb_addr_para(struct __fb_addr_para * fb_addr_para)63 s32 sunxi_get_fb_addr_para(struct __fb_addr_para *fb_addr_para)
64 {
65 	if (fb_addr_para) {
66 		fb_addr_para->fb_paddr = g_fb_addr.fb_paddr;
67 		fb_addr_para->fb_size = g_fb_addr.fb_size;
68 		return 0;
69 	}
70 
71 	return -1;
72 }
73 EXPORT_SYMBOL(sunxi_get_fb_addr_para);
74 
75 #define sys_put_wvalue(addr, data) writel(data, (void __iomem *)addr)
76 
fb_draw_gray_pictures(char * base,u32 width,u32 height,struct fb_var_screeninfo * var)77 s32 fb_draw_gray_pictures(char *base, u32 width, u32 height,
78 			  struct fb_var_screeninfo *var)
79 {
80 	u32 time = 0;
81 
82 	for (time = 0; time < 18; time++) {
83 		u32 i = 0, j = 0;
84 
85 		for (i = 0; i < height; i++) {
86 			for (j = 0; j < width; j++) {
87 				char *addr = base + (i * width + j) * 4;
88 				u32 value =
89 				    (0xff << 24) | ((time * 15) << 16) |
90 				    ((time * 15) << 8) | (time * 15);
91 
92 				sys_put_wvalue((void *)addr, value);
93 			}
94 		}
95 	}
96 	return 0;
97 }
98 
fb_map_video_memory(struct fb_info * info)99 static int fb_map_video_memory(struct fb_info *info)
100 {
101 #if defined(CONFIG_DMABUF_HEAPS)
102 	g_fbi.mem[info->node] =
103 	    disp_ion_malloc(info->fix.smem_len, (u32 *)(&info->fix.smem_start));
104 	if (g_fbi.mem[info->node])
105 		info->screen_base = (char __iomem *)g_fbi.mem[info->node]->vaddr;
106 #else
107 	info->screen_base =
108 	    (char __iomem *)disp_malloc(info->fix.smem_len,
109 					(u32 *) (&info->fix.smem_start));
110 #endif
111 	if (info->screen_base) {
112 		__inf("%s(reserve),va=0x%p, pa=0x%p size:0x%x\n", __func__,
113 		      (void *)info->screen_base,
114 		      (void *)info->fix.smem_start,
115 		      (unsigned int)info->fix.smem_len);
116 		memset((void *__force)info->screen_base, 0x0,
117 		       info->fix.smem_len);
118 
119 		g_fb_addr.fb_paddr = (uintptr_t) info->fix.smem_start;
120 		g_fb_addr.fb_size = info->fix.smem_len;
121 
122 		return 0;
123 	}
124 
125 	__wrn("disp_malloc fail!\n");
126 	return -ENOMEM;
127 
128 	return 0;
129 }
130 
fb_unmap_video_memory(struct fb_info * info)131 static inline void fb_unmap_video_memory(struct fb_info *info)
132 {
133 	if (!info->screen_base) {
134 		__wrn("%s: screen_base is null\n", __func__);
135 		return;
136 	}
137 	__inf("%s: screen_base=0x%p, smem=0x%p, len=0x%x\n", __func__,
138 	      (void *)info->screen_base,
139 	      (void *)info->fix.smem_start, info->fix.smem_len);
140 #if defined(CONFIG_DMABUF_HEAPS)
141 	disp_ion_free((void *__force)info->screen_base,
142 		  (void *)info->fix.smem_start, info->fix.smem_len);
143 #else
144 	disp_free((void *__force)info->screen_base,
145 		  (void *)info->fix.smem_start, info->fix.smem_len);
146 #endif
147 	info->screen_base = 0;
148 	info->fix.smem_start = 0;
149 	g_fb_addr.fb_paddr = 0;
150 	g_fb_addr.fb_size = 0;
151 }
152 
Fb_map_kernel(unsigned long phys_addr,unsigned long size)153 static void *Fb_map_kernel(unsigned long phys_addr, unsigned long size)
154 {
155 	int npages = PAGE_ALIGN(size) / PAGE_SIZE;
156 	struct page **pages = vmalloc(sizeof(struct page *) * npages);
157 	struct page **tmp = pages;
158 	struct page *cur_page = phys_to_page(phys_addr);
159 	pgprot_t pgprot;
160 	void *vaddr = NULL;
161 	int i;
162 
163 	if (!pages)
164 		return NULL;
165 
166 	for (i = 0; i < npages; i++)
167 		*(tmp++) = cur_page++;
168 
169 	pgprot = pgprot_noncached(PAGE_KERNEL);
170 	vaddr = vmap(pages, npages, VM_MAP, pgprot);
171 
172 	vfree(pages);
173 	return vaddr;
174 }
175 
Fb_map_kernel_cache(unsigned long phys_addr,unsigned long size)176 static void *Fb_map_kernel_cache(unsigned long phys_addr, unsigned long size)
177 {
178 	int npages = PAGE_ALIGN(size) / PAGE_SIZE;
179 	struct page **pages = vmalloc(sizeof(struct page *) * npages);
180 	struct page **tmp = pages;
181 	struct page *cur_page = phys_to_page(phys_addr);
182 	pgprot_t pgprot;
183 	void *vaddr = NULL;
184 	int i;
185 
186 	if (!pages)
187 		return NULL;
188 
189 	for (i = 0; i < npages; i++)
190 		*(tmp++) = cur_page++;
191 
192 	pgprot = PAGE_KERNEL;
193 	vaddr = vmap(pages, npages, VM_MAP, pgprot);
194 	vfree(pages);
195 	return vaddr;
196 }
197 
Fb_unmap_kernel(void * vaddr)198 static void Fb_unmap_kernel(void *vaddr)
199 {
200 	vunmap(vaddr);
201 }
202 
disp_fb_to_var(enum disp_pixel_format format,struct fb_var_screeninfo * var)203 static s32 disp_fb_to_var(enum disp_pixel_format format,
204 			  struct fb_var_screeninfo *var)
205 {
206 	switch (format) {
207 	case DISP_FORMAT_ARGB_8888:
208 		var->bits_per_pixel = 32;
209 		var->transp.length = 8;
210 		var->red.length = 8;
211 		var->green.length = 8;
212 		var->blue.length = 8;
213 		var->blue.offset = 0;
214 		var->green.offset = var->blue.offset + var->blue.length;
215 		var->red.offset = var->green.offset + var->green.length;
216 		var->transp.offset = var->red.offset + var->red.length;
217 		break;
218 	case DISP_FORMAT_ABGR_8888:
219 		var->bits_per_pixel = 32;
220 		var->transp.length = 8;
221 		var->red.length = 8;
222 		var->green.length = 8;
223 		var->blue.length = 8;
224 		var->red.offset = 0;
225 		var->green.offset = var->red.offset + var->red.length;
226 		var->blue.offset = var->green.offset + var->green.length;
227 		var->transp.offset = var->blue.offset + var->blue.length;
228 		break;
229 	case DISP_FORMAT_RGBA_8888:
230 		var->bits_per_pixel = 32;
231 		var->transp.length = 8;
232 		var->red.length = 8;
233 		var->green.length = 8;
234 		var->blue.length = 8;
235 		var->transp.offset = 0;
236 		var->blue.offset = var->transp.offset + var->transp.length;
237 		var->green.offset = var->blue.offset + var->blue.length;
238 		var->red.offset = var->green.offset + var->green.length;
239 		break;
240 	case DISP_FORMAT_BGRA_8888:
241 		var->bits_per_pixel = 32;
242 		var->transp.length = 8;
243 		var->red.length = 8;
244 		var->green.length = 8;
245 		var->blue.length = 8;
246 		var->transp.offset = 0;
247 		var->red.offset = var->transp.offset + var->transp.length;
248 		var->green.offset = var->red.offset + var->red.length;
249 		var->blue.offset = var->green.offset + var->green.length;
250 		break;
251 	case DISP_FORMAT_RGB_888:
252 		var->bits_per_pixel = 24;
253 		var->red.length = 8;
254 		var->green.length = 8;
255 		var->blue.length = 8;
256 		var->blue.offset = 0;
257 		var->green.offset = var->blue.offset + var->blue.length;
258 		var->red.offset = var->green.offset + var->green.length;
259 
260 		break;
261 	case DISP_FORMAT_BGR_888:
262 		var->bits_per_pixel = 24;
263 		var->transp.length = 0;
264 		var->red.length = 8;
265 		var->green.length = 8;
266 		var->blue.length = 8;
267 		var->red.offset = 0;
268 		var->green.offset = var->red.offset + var->red.length;
269 		var->blue.offset = var->green.offset + var->green.length;
270 
271 		break;
272 	case DISP_FORMAT_RGB_565:
273 		var->bits_per_pixel = 16;
274 		var->transp.length = 0;
275 		var->red.length = 5;
276 		var->green.length = 6;
277 		var->blue.length = 5;
278 		var->blue.offset = 0;
279 		var->green.offset = var->blue.offset + var->blue.length;
280 		var->red.offset = var->green.offset + var->green.length;
281 
282 		break;
283 	case DISP_FORMAT_BGR_565:
284 		var->bits_per_pixel = 16;
285 		var->transp.length = 0;
286 		var->red.length = 5;
287 		var->green.length = 6;
288 		var->blue.length = 5;
289 		var->red.offset = 0;
290 		var->green.offset = var->red.offset + var->red.length;
291 		var->blue.offset = var->green.offset + var->green.length;
292 
293 		break;
294 	case DISP_FORMAT_ARGB_4444:
295 		var->bits_per_pixel = 16;
296 		var->transp.length = 4;
297 		var->red.length = 4;
298 		var->green.length = 4;
299 		var->blue.length = 4;
300 		var->blue.offset = 0;
301 		var->green.offset = var->blue.offset + var->blue.length;
302 		var->red.offset = var->green.offset + var->green.length;
303 		var->transp.offset = var->red.offset + var->red.length;
304 
305 		break;
306 	case DISP_FORMAT_ABGR_4444:
307 		var->bits_per_pixel = 16;
308 		var->transp.length = 4;
309 		var->red.length = 4;
310 		var->green.length = 4;
311 		var->blue.length = 4;
312 		var->red.offset = 0;
313 		var->green.offset = var->red.offset + var->red.length;
314 		var->blue.offset = var->green.offset + var->green.length;
315 		var->transp.offset = var->blue.offset + var->blue.length;
316 
317 		break;
318 	case DISP_FORMAT_RGBA_4444:
319 		var->bits_per_pixel = 16;
320 		var->transp.length = 4;
321 		var->red.length = 4;
322 		var->green.length = 5;
323 		var->blue.length = 4;
324 		var->transp.offset = 0;
325 		var->blue.offset = var->transp.offset + var->transp.length;
326 		var->green.offset = var->blue.offset + var->blue.length;
327 		var->red.offset = var->green.offset + var->green.length;
328 
329 		break;
330 	case DISP_FORMAT_BGRA_4444:
331 		var->bits_per_pixel = 16;
332 		var->transp.length = 4;
333 		var->red.length = 4;
334 		var->green.length = 4;
335 		var->blue.length = 4;
336 		var->transp.offset = 0;
337 		var->red.offset = var->transp.offset + var->transp.length;
338 		var->green.offset = var->red.offset + var->red.length;
339 		var->blue.offset = var->green.offset + var->green.length;
340 
341 		break;
342 	case DISP_FORMAT_ARGB_1555:
343 		var->bits_per_pixel = 16;
344 		var->transp.length = 1;
345 		var->red.length = 5;
346 		var->green.length = 5;
347 		var->blue.length = 5;
348 		var->blue.offset = 0;
349 		var->green.offset = var->blue.offset + var->blue.length;
350 		var->red.offset = var->green.offset + var->green.length;
351 		var->transp.offset = var->red.offset + var->red.length;
352 
353 		break;
354 	case DISP_FORMAT_ABGR_1555:
355 		var->bits_per_pixel = 16;
356 		var->transp.length = 1;
357 		var->red.length = 5;
358 		var->green.length = 5;
359 		var->blue.length = 5;
360 		var->red.offset = 0;
361 		var->green.offset = var->red.offset + var->red.length;
362 		var->blue.offset = var->green.offset + var->green.length;
363 		var->transp.offset = var->blue.offset + var->blue.length;
364 
365 		break;
366 	case DISP_FORMAT_RGBA_5551:
367 		var->bits_per_pixel = 16;
368 		var->transp.length = 1;
369 		var->red.length = 5;
370 		var->green.length = 5;
371 		var->blue.length = 5;
372 		var->transp.offset = 0;
373 		var->blue.offset = var->transp.offset + var->transp.length;
374 		var->green.offset = var->blue.offset + var->blue.length;
375 		var->red.offset = var->green.offset + var->green.length;
376 
377 		break;
378 	case DISP_FORMAT_BGRA_5551:
379 		var->bits_per_pixel = 16;
380 		var->transp.length = 1;
381 		var->red.length = 5;
382 		var->green.length = 5;
383 		var->blue.length = 5;
384 		var->transp.offset = 0;
385 		var->red.offset = var->transp.offset + var->transp.length;
386 		var->green.offset = var->red.offset + var->red.length;
387 		var->blue.offset = var->green.offset + var->green.length;
388 
389 		break;
390 	default:
391 		__wrn("[FB]not support format %d\n", format);
392 	}
393 
394 	__inf
395 	    ("fmt%d para: %dbpp, a(%d,%d),r(%d,%d),g(%d,%d),b(%d,%d)\n",
396 	     (int)format, (int)var->bits_per_pixel, (int)var->transp.offset,
397 	     (int)var->transp.length, (int)var->red.offset,
398 	     (int)var->red.length, (int)var->green.offset,
399 	     (int)var->green.length, (int)var->blue.offset,
400 	     (int)var->blue.length);
401 
402 	return 0;
403 }
404 
var_to_disp_fb(struct disp_fb_info * fb,struct fb_var_screeninfo * var,struct fb_fix_screeninfo * fix)405 static s32 var_to_disp_fb(struct disp_fb_info *fb,
406 			  struct fb_var_screeninfo *var,
407 			  struct fb_fix_screeninfo *fix)
408 {
409 	if (var->nonstd == 0) {
410 		/* argb */
411 		switch (var->bits_per_pixel) {
412 		case 32:
413 			if (var->red.offset == 16 && var->green.offset == 8
414 			    && var->blue.offset == 0)
415 				fb->format = DISP_FORMAT_ARGB_8888;
416 			else if (var->blue.offset == 24
417 				 && var->green.offset == 16
418 				 && var->red.offset == 8)
419 				fb->format = DISP_FORMAT_BGRA_8888;
420 			else if (var->blue.offset == 16
421 				 && var->green.offset == 8
422 				 && var->red.offset == 0)
423 				fb->format = DISP_FORMAT_ABGR_8888;
424 			else if (var->red.offset == 24
425 				 && var->green.offset == 16
426 				 && var->blue.offset == 8)
427 				fb->format = DISP_FORMAT_RGBA_8888;
428 			else
429 				__wrn
430 				    ("invalid fmt,off<a:%d,r:%d,g:%d,b:%d>\n",
431 				     var->transp.offset, var->red.offset,
432 				     var->green.offset, var->blue.offset);
433 
434 			break;
435 		case 24:
436 			if ((var->red.offset == 16)
437 			 && (var->green.offset == 8)
438 			 && (var->blue.offset == 0)) {	/* rgb */
439 				fb->format = DISP_FORMAT_RGB_888;
440 			} else if ((var->blue.offset == 16)
441 			       && (var->green.offset == 8)
442 			       && (var->red.offset == 0)) {	/* bgr */
443 				fb->format = DISP_FORMAT_BGR_888;
444 			} else {
445 				__wrn
446 				    ("invalid fmt,off<a:%d,r:%d,g:%d,b:%d>\n",
447 				     var->transp.offset, var->red.offset,
448 				     var->green.offset, var->blue.offset);
449 			}
450 
451 			break;
452 		case 16:
453 			if (var->red.offset == 11 && var->green.offset == 5
454 			    && var->blue.offset == 0) {
455 				fb->format = DISP_FORMAT_RGB_565;
456 			} else if (var->blue.offset == 11
457 				   && var->green.offset == 5
458 				   && var->red.offset == 0) {
459 				fb->format = DISP_FORMAT_BGR_565;
460 			} else if (var->transp.offset == 12
461 				   && var->red.offset == 8
462 				   && var->green.offset == 4
463 				   && var->blue.offset == 0) {
464 				fb->format = DISP_FORMAT_ARGB_4444;
465 			} else if (var->transp.offset == 12
466 				   && var->blue.offset == 8
467 				   && var->green.offset == 4
468 				   && var->red.offset == 0) {
469 				fb->format = DISP_FORMAT_ABGR_4444;
470 			} else if (var->red.offset == 12
471 				   && var->green.offset == 8
472 				   && var->blue.offset == 4
473 				   && var->transp.offset == 0) {
474 				fb->format = DISP_FORMAT_RGBA_4444;
475 			} else if (var->blue.offset == 12
476 				   && var->green.offset == 8
477 				   && var->red.offset == 4
478 				   && var->transp.offset == 0) {
479 				fb->format = DISP_FORMAT_BGRA_4444;
480 			} else if (var->transp.offset == 15
481 				   && var->red.offset == 10
482 				   && var->green.offset == 5
483 				   && var->blue.offset == 0) {
484 				fb->format = DISP_FORMAT_ARGB_1555;
485 			} else if (var->transp.offset == 15
486 				   && var->blue.offset == 10
487 				   && var->green.offset == 5
488 				   && var->red.offset == 0) {
489 				fb->format = DISP_FORMAT_ABGR_1555;
490 			} else if (var->red.offset == 11
491 				   && var->green.offset == 6
492 				   && var->blue.offset == 1
493 				   && var->transp.offset == 0) {
494 				fb->format = DISP_FORMAT_RGBA_5551;
495 			} else if (var->blue.offset == 11
496 				   && var->green.offset == 6
497 				   && var->red.offset == 1
498 				   && var->transp.offset == 0) {
499 				fb->format = DISP_FORMAT_BGRA_5551;
500 			} else {
501 				__wrn
502 				    ("invalid fmt,off<a:%d,r:%d,g:%d,b:%d>\n",
503 				     var->transp.offset, var->red.offset,
504 				     var->green.offset, var->blue.offset);
505 			}
506 
507 			break;
508 
509 		default:
510 			__wrn("invalid bits_per_pixel :%d\n",
511 			      var->bits_per_pixel);
512 			return -EINVAL;
513 		}
514 	}
515 	__inf
516 	    ("format%d,para:%dbpp,a(%d,%d),r(%d,%d),g(%d,%d),b(%d,%d)\n",
517 	     (int)fb->format, (int)var->bits_per_pixel, (int)var->transp.offset,
518 	     (int)var->transp.length, (int)var->red.offset,
519 	     (int)var->red.length, (int)var->green.offset,
520 	     (int)var->green.length, (int)var->blue.offset,
521 	     (int)var->blue.length);
522 
523 	fb->size[0].width = var->xres_virtual;
524 	fb->size[1].width = var->xres_virtual;
525 	fb->size[2].width = var->xres_virtual;
526 
527 	fix->line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
528 
529 	return 0;
530 }
531 
sunxi_fb_open(struct fb_info * info,int user)532 static int sunxi_fb_open(struct fb_info *info, int user)
533 {
534 	u32 num_screens;
535 	u32 sel = 0;
536 
537 	num_screens = bsp_disp_feat_get_num_screens();
538 	for (sel = 0; sel < num_screens; sel++) {
539 		if (sel == g_fbi.fb_mode[info->node]) {
540 			struct disp_manager *mgr = g_disp_drv.mgr[sel];
541 
542 			if (mgr && mgr->device) {
543 				if (mgr->device->is_enabled) {
544 					if (!mgr->device->is_enabled(mgr->device)) {
545 						if (mgr->device->enable)
546 							mgr->device->enable(mgr->device);
547 						mgr->set_layer_config(mgr, &g_fbi.config[sel],
548 								      1);
549 						disp_delay_ms(20);
550 					}
551 				}
552 			}
553 		}
554 	}
555 	return 0;
556 }
sunxi_fb_release(struct fb_info * info,int user)557 static int sunxi_fb_release(struct fb_info *info, int user)
558 {
559 	return 0;
560 }
561 
fb_wait_for_vsync(struct fb_info * info)562 static int fb_wait_for_vsync(struct fb_info *info)
563 {
564 	unsigned long count;
565 	u32 sel = 0;
566 	int ret;
567 	int num_screens;
568 
569 	num_screens = bsp_disp_feat_get_num_screens();
570 
571 	for (sel = 0; sel < num_screens; sel++) {
572 		if (sel == g_fbi.fb_mode[info->node]) {
573 			struct disp_manager *mgr = g_disp_drv.mgr[sel];
574 
575 			if (!mgr || !mgr->device
576 			    || (mgr->device->is_enabled == NULL))
577 				return 0;
578 
579 			if (mgr->device->is_enabled(mgr->device) == 0)
580 				return 0;
581 
582 			count = g_fbi.wait_count[sel];
583 			ret =
584 			    wait_event_interruptible_timeout(g_fbi.wait[sel],
585 							     count !=
586 							     g_fbi.
587 							     wait_count[sel],
588 							     msecs_to_jiffies
589 							     (50));
590 			if (ret == 0) {
591 				__inf("timeout\n");
592 				return -ETIMEDOUT;
593 			}
594 		}
595 	}
596 
597 	return 0;
598 }
599 
sunxi_fb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)600 static int sunxi_fb_pan_display(struct fb_var_screeninfo *var,
601 				struct fb_info *info)
602 {
603 	u32 sel = 0;
604 	u32 num_screens;
605 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT)
606 	s32 type_switch_flag = 0;
607 	u32 y_offset = var->yoffset;
608 #endif
609 	int need_wait_vsync = 1;
610 
611 	num_screens = bsp_disp_feat_get_num_screens();
612 
613 	for (sel = 0; sel < num_screens; sel++) {
614 		if (sel == g_fbi.fb_mode[info->node]) {
615 			u32 buffer_num = 1;
616 			s32 chan = g_fbi.layer_hdl[info->node][0];
617 			s32 layer_id = g_fbi.layer_hdl[info->node][1];
618 			struct disp_layer_config config;
619 			struct disp_manager *mgr = g_disp_drv.mgr[sel];
620 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT)
621 			struct disp_rect dirty_rect;
622 #endif
623 
624 			memset(&config, 0, sizeof(struct disp_layer_config));
625 			if (mgr && mgr->get_layer_config
626 			    && mgr->set_layer_config) {
627 				config.channel = chan;
628 				config.layer_id = layer_id;
629 				if (mgr->get_layer_config(mgr, &config, 1)
630 				    != 0) {
631 					__wrn
632 					    ("fb%d,get_lyr_cfg(%d,%d,%d)fail\n",
633 					     info->node, sel, chan, layer_id);
634 					return -1;
635 				}
636 
637 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT)
638 				if (mgr->rot_sw) {
639 					if (0 != var->reserved[2] &&
640 					    0 != var->reserved[3]) {
641 						dirty_rect.x = var->reserved[0];
642 						dirty_rect.y = var->reserved[1];
643 						dirty_rect.width =
644 						    var->reserved[2];
645 						dirty_rect.height =
646 						    var->reserved[3];
647 					} else {
648 						dirty_rect.x = 0;
649 						dirty_rect.y = 0;
650 						dirty_rect.width = 0;
651 						dirty_rect.height = 0;
652 						return 0;
653 					}
654 
655 					if (mgr->rot_sw->checkout) {
656 						type_switch_flag =
657 						    mgr->rot_sw->checkout(
658 							mgr->rot_sw, &config);
659 						if (type_switch_flag == 1) {
660 							dirty_rect.x = 0;
661 							dirty_rect.y = 0;
662 							dirty_rect.width =
663 							    config.info.fb
664 								.size[0]
665 								.width;
666 							dirty_rect.height =
667 							    config.info.fb
668 								.size[0]
669 								.height;
670 						}
671 					}
672 				}
673 #endif
674 				config.info.fb.crop.x =
675 				    ((long long)var->xoffset) << 32;
676 				config.info.fb.crop.y =
677 				    ((unsigned long long)(var->yoffset)) << 32;
678 				config.info.fb.crop.width =
679 				    ((long long)var->xres) << 32;
680 				config.info.fb.crop.height =
681 				    ((long long)(var->yres / buffer_num)) << 32;
682 
683 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT)
684 				if (mgr->rot_sw && mgr->rot_sw->apply) {
685 					if (0 !=
686 					    mgr->rot_sw->apply(mgr->rot_sw,
687 							       &config,
688 							       dirty_rect)) {
689 						__wrn("not need to rot sw\n");
690 						return 0;
691 					}
692 					config.info.fb.crop.x =
693 						((unsigned long long)(y_offset)) << 32;
694 					need_wait_vsync = 0;
695 				}
696 #endif
697 #if defined(CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT)
698 				if (g_fbi.fb_rot[sel])
699 					g_fbi.fb_rot[sel]->apply(g_fbi.fb_rot[sel], &config);
700 #endif
701 				if (mgr->set_layer_config(mgr, &config, 1)
702 				    != 0) {
703 					__wrn
704 					    ("fb%d,set_lyr_cfg(%d,%d,%d)fail\n",
705 					     info->node, sel, chan, layer_id);
706 					return -1;
707 				} else {
708 					memcpy(&g_fbi.config[sel], &config, sizeof(struct disp_layer_config));
709 				}
710 			}
711 		}
712 	}
713 
714 	if (need_wait_vsync == 1)
715 		fb_wait_for_vsync(info);
716 
717 	return 0;
718 }
719 
sunxi_fb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)720 static int sunxi_fb_check_var(struct fb_var_screeninfo *var,
721 			      struct fb_info *info)
722 {
723 	struct disp_fb_info disp_fb;
724 	struct fb_fix_screeninfo fix;
725 
726 	if (var_to_disp_fb(&disp_fb, var, &fix) != 0) {
727 		switch (var->bits_per_pixel) {
728 		case 8:
729 		case 4:
730 		case 2:
731 		case 1:
732 			disp_fb_to_var(DISP_FORMAT_ARGB_8888, var);
733 			break;
734 
735 		case 19:
736 		case 18:
737 		case 16:
738 			disp_fb_to_var(DISP_FORMAT_RGB_565, var);
739 			break;
740 
741 		case 32:
742 		case 28:
743 		case 25:
744 		case 24:
745 			disp_fb_to_var(DISP_FORMAT_ARGB_8888, var);
746 			break;
747 
748 		default:
749 			return -EINVAL;
750 		}
751 	}
752 
753 	return 0;
754 }
755 
sunxi_fb_blank(int blank_mode,struct fb_info * info)756 static int sunxi_fb_blank(int blank_mode, struct fb_info *info)
757 {
758 	u32 sel = 0;
759 	u32 num_screens;
760 
761 	num_screens = bsp_disp_feat_get_num_screens();
762 
763 	__inf("sunxi_fb_blank,mode:%d\n", blank_mode);
764 
765 	for (sel = 0; sel < num_screens; sel++) {
766 		if (sel == g_fbi.fb_mode[info->node]) {
767 			s32 chan = g_fbi.layer_hdl[info->node][0];
768 			s32 layer_id = g_fbi.layer_hdl[info->node][1];
769 			struct disp_layer_config config;
770 			struct disp_manager *mgr = g_disp_drv.mgr[sel];
771 
772 			memcpy(&config, &g_fbi.config[sel], sizeof(struct disp_layer_config));
773 			if (blank_mode == FB_BLANK_POWERDOWN) {
774 				if (mgr && mgr->set_layer_config) {
775 					config.enable = 0;
776 					mgr->set_layer_config(mgr, &config, 1);
777 				}
778 			} else {
779 				if (mgr && mgr->set_layer_config) {
780 					config.channel = chan;
781 					config.layer_id = layer_id;
782 					config.enable = 1;
783 					mgr->set_layer_config(mgr, &config, 1);
784 				}
785 			}
786 		}
787 	}
788 	return 0;
789 }
790 
sunxi_fb_cursor(struct fb_info * info,struct fb_cursor * cursor)791 static int sunxi_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
792 {
793 	__inf("sunxi_fb_cursor\n");
794 
795 	return 0;
796 }
797 
sunxi_fb_mmap(struct fb_info * info,struct vm_area_struct * vma)798 static int sunxi_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
799 {
800 	unsigned int off = vma->vm_pgoff << PAGE_SHIFT;
801 
802 	if (off < info->fix.smem_len) {
803 #if defined(CONFIG_DMABUF_HEAPS)
804 		return g_fbi.mem[info->node]->p_item->dmabuf->ops->mmap(
805 		    g_fbi.mem[info->node]->p_item->dmabuf, vma);
806 
807 #else /* CONFIG_DMABUF_HEAPS */
808 		return dma_mmap_writecombine(g_fbi.dev, vma, info->screen_base,
809 				info->fix.smem_start,
810 				info->fix.smem_len);
811 #endif /* CONFIG_DMABUF_HEAPS */
812 	}
813 
814 	return -EINVAL;
815 }
816 
817 
DRV_disp_int_process(u32 sel)818 void DRV_disp_int_process(u32 sel)
819 {
820 	g_fbi.wait_count[sel]++;
821 	wake_up_interruptible(&g_fbi.wait[sel]);
822 }
823 
convert_bitfield(int val,struct fb_bitfield * bf)824 static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
825 {
826 	u32 mask = ((1 << bf->length) - 1) << bf->offset;
827 
828 	return (val << bf->offset) & mask;
829 }
830 
sunxi_fb_setcolreg(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue,unsigned int transp,struct fb_info * info)831 static int sunxi_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
832 			      unsigned int blue, unsigned int transp,
833 			      struct fb_info *info)
834 {
835 	u32 val;
836 	u32 ret = 0;
837 
838 	switch (info->fix.visual) {
839 	case FB_VISUAL_PSEUDOCOLOR:
840 		ret = -EINVAL;
841 		break;
842 	case FB_VISUAL_TRUECOLOR:
843 		if (regno < 16) {
844 			val = convert_bitfield(transp, &info->var.transp) |
845 			    convert_bitfield(red, &info->var.red) |
846 			    convert_bitfield(green, &info->var.green) |
847 			    convert_bitfield(blue, &info->var.blue);
848 			__inf("regno=%2d,a=%2X,r=%2X,g=%2X,b=%2X,result=%08X\n",
849 			      regno, transp, red, green, blue,
850 			      val);
851 			((u32 *) info->pseudo_palette)[regno] = val;
852 		} else {
853 			ret = 0;
854 		}
855 		break;
856 	default:
857 		ret = -EINVAL;
858 		break;
859 	}
860 
861 	return ret;
862 }
863 
sunxi_fb_setcmap(struct fb_cmap * cmap,struct fb_info * info)864 static int sunxi_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
865 {
866 	unsigned int j, r = 0;
867 	unsigned char hred, hgreen, hblue, htransp = 0xff;
868 	unsigned short *red, *green, *blue, *transp;
869 
870 	__inf("Fb_setcmap, cmap start:%d len:%d, %dbpp\n", cmap->start,
871 	      cmap->len, info->var.bits_per_pixel);
872 
873 	red = cmap->red;
874 	green = cmap->green;
875 	blue = cmap->blue;
876 	transp = cmap->transp;
877 
878 	for (j = 0; j < cmap->len; j++) {
879 		hred = *red++;
880 		hgreen = *green++;
881 		hblue = *blue++;
882 		if (transp)
883 			htransp = (*transp++) & 0xff;
884 		else
885 			htransp = 0xff;
886 
887 		r = sunxi_fb_setcolreg(cmap->start + j, hred, hgreen, hblue,
888 				       htransp, info);
889 		if (r)
890 			return r;
891 	}
892 
893 	return 0;
894 }
895 
896 struct fb_dmabuf_export {
897 	int fd;
898 	__u32 flags;
899 };
900 
901 /*custom ioctl command here*/
902 #define FBIO_CACHE_SYNC         0x4630
903 #define FBIO_ENABLE_CACHE       0x4631
904 #define FBIO_GET_IONFD          0x4632
905 #define FBIO_GET_PHY_ADDR       0x4633
906 #define FBIOGET_DMABUF         _IOR('F', 0x21, struct fb_dmabuf_export)
907 
908 #if !defined(CONFIG_DMABUF_HEAPS)
909 
910 struct sunxi_dmabuf_info {
911 	struct sg_table *s_sg_table;
912 	struct fb_info *info;
913 	struct kref ref;
914 	void *ker_addr;
915 };
916 
917 static struct sunxi_dmabuf_info *sunxi_info[SUNXI_FB_MAX];
918 
sunxi_info_free(struct kref * kref)919 void sunxi_info_free(struct kref *kref)
920 {
921 	struct sunxi_dmabuf_info *s_info;
922 	struct fb_info *f_info;
923 
924 	s_info = container_of(kref, struct sunxi_dmabuf_info, ref);
925 	f_info = s_info->info;
926 
927 	lock_fb_info(f_info);
928 
929 	sg_free_table(s_info->s_sg_table);
930 	Fb_unmap_kernel(s_info->ker_addr);
931 	kfree(s_info->s_sg_table);
932 	kfree(s_info);
933 	sunxi_info[f_info->node%SUNXI_FB_MAX] = NULL;
934 
935 	unlock_fb_info(f_info);
936 }
937 
sunxi_map_dma_buf(struct dma_buf_attachment * attachment,enum dma_data_direction direction)938 static struct sg_table *sunxi_map_dma_buf(struct dma_buf_attachment *attachment,
939 					enum dma_data_direction direction)
940 {
941 	struct sunxi_dmabuf_info *s_info;
942 
943 	s_info = (struct sunxi_dmabuf_info *)attachment->dmabuf->priv;
944 
945 	kref_get(&s_info->ref);
946 
947 	return s_info->s_sg_table;
948 }
949 
sunxi_unmap_dma_buf(struct dma_buf_attachment * attachment,struct sg_table * sg_tab,enum dma_data_direction direction)950 static void sunxi_unmap_dma_buf(struct dma_buf_attachment *attachment,
951 						struct sg_table *sg_tab,
952 						enum dma_data_direction direction)
953 {
954 	struct sunxi_dmabuf_info *s_info;
955 
956 	s_info = (struct sunxi_dmabuf_info *)attachment->dmabuf->priv;
957 
958 	kref_put(&s_info->ref, sunxi_info_free);
959 }
960 
sunxi_user_mmap(struct dma_buf * buff,struct vm_area_struct * vma)961 static int sunxi_user_mmap(struct dma_buf *buff, struct vm_area_struct *vma)
962 {
963 	struct sunxi_dmabuf_info *s_info = (struct sunxi_dmabuf_info *)buff->priv;
964 	struct sg_table *table = s_info->s_sg_table;
965 	unsigned long addr = vma->vm_start;
966 	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
967 	struct scatterlist *sg;
968 	int i;
969 	int ret;
970 
971 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
972 	for_each_sg(table->sgl, sg, table->nents, i) {
973 		struct page *page = sg_page(sg);
974 		unsigned long remainder = vma->vm_end - addr;
975 		unsigned long len = sg->length;
976 
977 		if (offset >= sg->length) {
978 			offset -= sg->length;
979 			continue;
980 		} else if (offset) {
981 			page += offset / PAGE_SIZE;
982 			len = sg->length - offset;
983 			offset = 0;
984 		}
985 		len = min(len, remainder);
986 		ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
987 				      vma->vm_page_prot);
988 		if (ret)
989 			return ret;
990 		addr += len;
991 		if (addr >= vma->vm_end)
992 			return 0;
993 	}
994 
995 	return 0;
996 }
997 
sunxi_dma_buf_release(struct dma_buf * buff)998 static void sunxi_dma_buf_release(struct dma_buf *buff)
999 {
1000 	struct sunxi_dmabuf_info *s_info;
1001 
1002 	s_info = (struct sunxi_dmabuf_info *)buff->priv;
1003 
1004 	kref_put(&s_info->ref, sunxi_info_free);
1005 }
1006 
sunxi_dma_buf_attach(struct dma_buf * buff,struct device * dev,struct dma_buf_attachment * attachment)1007 static int sunxi_dma_buf_attach(struct dma_buf *buff,
1008 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
1009 			struct device *dev,
1010 #endif
1011 			struct dma_buf_attachment *attachment)
1012 {
1013 	struct sunxi_dmabuf_info *s_info;
1014 
1015 	s_info = (struct sunxi_dmabuf_info *)buff->priv;
1016 	attachment->priv = (void *)s_info;
1017 
1018 	kref_get(&s_info->ref);
1019 	return 0;
1020 }
1021 
sunxi_dma_buf_detach(struct dma_buf * buff,struct dma_buf_attachment * attachment)1022 static void sunxi_dma_buf_detach(struct dma_buf *buff, struct dma_buf_attachment *attachment)
1023 {
1024 	struct sunxi_dmabuf_info *s_info;
1025 
1026 	s_info = (struct sunxi_dmabuf_info *)buff->priv;
1027 
1028 	attachment->priv = NULL;
1029 
1030 	kref_put(&s_info->ref, sunxi_info_free);
1031 }
1032 
1033 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
sunxi_dma_buf_kmap(struct dma_buf * buff,unsigned long page_num)1034 static void *sunxi_dma_buf_kmap(struct dma_buf *buff, unsigned long page_num)
1035 {
1036 	struct sunxi_dmabuf_info *s_info;
1037 
1038 	s_info = (struct sunxi_dmabuf_info *)buff->priv;
1039 
1040 	return s_info->ker_addr + page_num * PAGE_SIZE;
1041 }
1042 
sunxi_dma_buf_kunmap(struct dma_buf * buff,unsigned long page_num,void * ptr)1043 static void sunxi_dma_buf_kunmap(struct dma_buf *buff, unsigned long page_num,
1044 			       void *ptr)
1045 {
1046 
1047 }
1048 #endif
1049 
1050 static struct dma_buf_ops sunxi_dma_buf_ops = {
1051 	.attach = sunxi_dma_buf_attach,
1052 	.detach = sunxi_dma_buf_detach,
1053 	.map_dma_buf = sunxi_map_dma_buf,
1054 	.unmap_dma_buf = sunxi_unmap_dma_buf,
1055 	.mmap = sunxi_user_mmap,
1056 	.release = sunxi_dma_buf_release,
1057 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1058 	.kmap_atomic = sunxi_dma_buf_kmap,
1059 	.kunmap_atomic = sunxi_dma_buf_kunmap,
1060 	.kmap = sunxi_dma_buf_kmap,
1061 	.kunmap = sunxi_dma_buf_kunmap,
1062 #endif
1063 };
1064 #endif
1065 
1066 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
sunxi_share_dma_buf(struct fb_info * info)1067 static struct dma_buf *sunxi_share_dma_buf(struct fb_info *info)
1068 {
1069 	struct dma_buf *dmabuf = NULL;
1070 #if !defined(CONFIG_DMABUF_HEAPS)
1071 	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
1072 	struct sunxi_dmabuf_info *s_info;
1073 #else
1074 	struct ion_handle *handle;
1075 #endif
1076 	if (info->fix.smem_start == 0 || info->fix.smem_len == 0)
1077 		return NULL;
1078 
1079 #if defined(CONFIG_DMABUF_HEAPS)
1080 	handle = g_fbi.mem[info->node%SUNXI_FB_MAX]->handle;
1081 	dmabuf = ion_share_dma_buf(g_disp_drv.ion_mgr.client, handle);
1082 #else /* CONFIG_DMABUF_HEAPS */
1083 	s_info = sunxi_info[info->node%SUNXI_FB_MAX];
1084 	if (s_info == NULL) {
1085 		s_info = kzalloc(sizeof(struct sunxi_dmabuf_info), GFP_KERNEL);
1086 		if (s_info == NULL)
1087 			goto ret_err;
1088 		s_info->s_sg_table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
1089 		if (!s_info->s_sg_table) {
1090 			kfree(s_info);
1091 			goto ret_err;
1092 		}
1093 		if (sg_alloc_table(s_info->s_sg_table, 1, GFP_KERNEL)) {
1094 			kfree(s_info->s_sg_table);
1095 			kfree(s_info);
1096 			goto ret_err;
1097 		}
1098 		sg_set_page(s_info->s_sg_table->sgl, pfn_to_page(PFN_DOWN(info->fix.smem_start)),
1099 				info->fix.smem_len, info->fix.smem_start&PAGE_MASK);
1100 		s_info->info = info;
1101 		kref_init(&s_info->ref);
1102 		s_info->ker_addr = (void *)((char *)Fb_map_kernel(info->fix.smem_start
1103 						+ (info->fix.smem_start&PAGE_MASK), info->fix.smem_len));
1104 		sunxi_info[info->node%SUNXI_FB_MAX] = s_info;
1105 	} else {
1106 		kref_get(&s_info->ref);
1107 	}
1108 	exp_info.ops = &sunxi_dma_buf_ops;
1109 	exp_info.size = info->fix.smem_len;
1110 	exp_info.flags = O_RDWR;
1111 	exp_info.priv = s_info;
1112 
1113 	dmabuf = dma_buf_export(&exp_info);
1114 	if (IS_ERR_OR_NULL(dmabuf)) {
1115 		kref_put(&s_info->ref, sunxi_info_free);
1116 		return dmabuf;
1117 	}
1118 #endif /* CONFIG_DMABUF_HEAPS */
1119 	return dmabuf;
1120 #if !defined(CONFIG_DMABUF_HEAPS)
1121 ret_err:
1122 	__wrn("%s, alloc mem err...\n", __func__);
1123 
1124 	return NULL;
1125 #endif
1126 }
1127 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
1128 
sunxi_fb_ioctl(struct fb_info * info,unsigned int cmd,unsigned long arg)1129 static int sunxi_fb_ioctl(struct fb_info *info, unsigned int cmd,
1130 			  unsigned long arg)
1131 {
1132 	long ret = 0;
1133 	void __user *argp = (void __user *)arg;
1134 	unsigned long karg[4];
1135 #if defined(CONFIG_DMABUF_HEAPS)
1136 	void *get_phy_addr = NULL;
1137 #endif
1138 	switch (cmd) {
1139 #if 0
1140 	case FBIOGET_VBLANK:
1141 		{
1142 			struct fb_vblank vblank;
1143 			struct disp_video_timings tt;
1144 			u32 line = 0;
1145 			u32 sel;
1146 
1147 			sel =
1148 			    (g_fbi.fb_mode[info->node] ==
1149 			     FB_MODE_SCREEN1) ? 1 : 0;
1150 			line = bsp_disp_get_cur_line(sel);
1151 			bsp_disp_get_timming(sel, &tt);
1152 
1153 			memset(&vblank, 0, sizeof(struct fb_vblank));
1154 			vblank.flags |= FB_VBLANK_HAVE_VBLANK;
1155 			vblank.flags |= FB_VBLANK_HAVE_VSYNC;
1156 			if (line <= (tt.ver_total_time - tt.y_res))
1157 				vblank.flags |= FB_VBLANK_VBLANKING;
1158 			if ((line > tt.ver_front_porch)
1159 			    && (line <
1160 				(tt.ver_front_porch + tt.ver_sync_time))) {
1161 				vblank.flags |= FB_VBLANK_VSYNCING;
1162 			}
1163 
1164 			if (copy_to_user
1165 			    ((void __user *)arg, &vblank,
1166 			     sizeof(struct fb_vblank)))
1167 				ret = -EFAULT;
1168 
1169 			break;
1170 		}
1171 #endif
1172 
1173 	case FBIO_ENABLE_CACHE:
1174 		{
1175 			if (copy_from_user((void *)karg, argp,
1176 					   sizeof(unsigned long)))
1177 				return -EFAULT;
1178 			g_fbi.mem_cache_flag[info->node] = (karg[0] == 1)?1:0;
1179 			break;
1180 		}
1181 
1182 	case FBIO_WAITFORVSYNC:
1183 		{
1184 			/* ret = fb_wait_for_vsync(info); */
1185 			break;
1186 		}
1187 
1188 	case FBIO_FREE:
1189 		{
1190 			int fb_id = 0;	/* fb0 */
1191 			struct fb_info *fbinfo = g_fbi.fbinfo[fb_id];
1192 
1193 			if ((!g_fbi.fb_enable[fb_id])
1194 			    || (fbinfo != info)) {
1195 				__wrn("%s, fb%d already release ? or fb_info mismatch: fbinfo=0x%p, info=0x%p\n",
1196 				      __func__, fb_id, fbinfo, info);
1197 				return -1;
1198 			}
1199 
1200 			__inf("### FBIO_FREE ###\n");
1201 
1202 			fb_unmap_video_memory(fbinfo);
1203 #if defined(CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT)
1204 			if (g_fbi.fb_rot[fb_id])
1205 				g_fbi.fb_rot[fb_id]->free(g_fbi.fb_rot[fb_id]);
1206 #endif
1207 
1208 			/* unbound fb0 from layer(1,0)  */
1209 			g_fbi.layer_hdl[fb_id][0] = 0;
1210 			g_fbi.layer_hdl[fb_id][1] = 0;
1211 			g_fbi.fb_mode[fb_id] = 0;
1212 			g_fbi.fb_enable[fb_id] = 0;
1213 			break;
1214 		}
1215 
1216 	case FBIO_ALLOC:
1217 		{
1218 			int fb_id = 0;	/* fb0 */
1219 			struct fb_info *fbinfo = g_fbi.fbinfo[fb_id];
1220 
1221 			if (g_fbi.fb_enable[fb_id]
1222 			    || (fbinfo != info)) {
1223 				__wrn("%s, fb%d already enable ? or fb_info mismatch: fbinfo=0x%p, info=0x%p\n",
1224 				      __func__, fb_id, fbinfo, info);
1225 				return -1;
1226 			}
1227 
1228 			__inf("### FBIO_ALLOC ###\n");
1229 
1230 			/* fb0 bound to layer(1,0)  */
1231 			g_fbi.layer_hdl[fb_id][0] = 1;
1232 			g_fbi.layer_hdl[fb_id][1] = 0;
1233 
1234 			fb_map_video_memory(fbinfo);
1235 
1236 			g_fbi.fb_mode[fb_id] = g_fbi.fb_para[fb_id].fb_mode;
1237 			g_fbi.fb_enable[fb_id] = 1;
1238 #if defined(CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT)
1239 			g_fbi.fb_rot[fb_id] = fb_g2d_rot_create(
1240 								info, fb_id, &g_fbi.config[fb_id]);
1241 #endif
1242 			break;
1243 		}
1244 
1245 	case FBIO_GET_IONFD:{
1246 	if (argp) {
1247 		if (copy_from_user((struct disp_ion_mem *)karg, argp,
1248 				2 * sizeof(unsigned long)))
1249 			return -EFAULT;
1250 		}
1251 #if defined(CONFIG_DMABUF_HEAPS)
1252 	if (argp == NULL) {
1253 		ret = disp_get_ion_fd((struct disp_ion_mem *)g_fbi.mem[info->node]);
1254 	} else {
1255 		ret = disp_get_ion_fd((struct disp_ion_mem *)karg[0]);
1256 	}
1257 #endif
1258 		break;
1259 	}
1260 	case FBIO_GET_PHY_ADDR:{
1261 	if (argp) {
1262 		if (copy_from_user((struct disp_ion_mem *)karg, argp,
1263 				sizeof(dma_addr_t)))
1264 			return -EFAULT;
1265 		}
1266 #if defined(CONFIG_DMABUF_HEAPS)
1267 	if (argp == NULL) {
1268 		get_phy_addr = disp_get_phy_addr((struct disp_ion_mem *)g_fbi.mem[info->node]);
1269 		return get_phy_addr == NULL ? -1 : 0;
1270 	} else {
1271 		get_phy_addr = disp_get_phy_addr((struct disp_ion_mem *)g_fbi.mem[info->node]);
1272 		ret = get_phy_addr == NULL ? -1 : 0;
1273 		get_phy_addr = get_phy_addr + karg[0];
1274 		return ret;
1275 	}
1276 #endif
1277 		break;
1278 	}
1279 	case FBIOGET_DMABUF:
1280 	{
1281 		struct dma_buf *dmabuf;
1282 		struct fb_dmabuf_export k_ret = {-1, 0};
1283 
1284 		ret = -1;
1285 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1286 		dmabuf = sunxi_share_dma_buf(info);
1287 #else
1288 		dmabuf = g_fbi.mem[info->node%SUNXI_FB_MAX]->p_item->dmabuf;
1289 #endif
1290 		if (IS_ERR_OR_NULL(dmabuf))
1291 			return PTR_ERR(dmabuf);
1292 
1293 		k_ret.fd = dma_buf_fd(dmabuf, O_CLOEXEC);
1294 		if (k_ret.fd < 0) {
1295 			dma_buf_put(dmabuf);
1296 			break;
1297 		}
1298 
1299 		if (copy_to_user(argp, &k_ret, sizeof(struct fb_dmabuf_export))) {
1300 			__wrn("%s, copy to user err\n", __func__);
1301 		}
1302 		ret = 0;
1303 		break;
1304 	}
1305 	default:
1306 		break;
1307 	}
1308 	return ret;
1309 }
1310 
1311 static struct fb_ops dispfb_ops = {
1312 	.owner = THIS_MODULE,
1313 	.fb_open = sunxi_fb_open,
1314 	.fb_release = sunxi_fb_release,
1315 	.fb_pan_display = sunxi_fb_pan_display,
1316 #if defined(CONFIG_COMPAT)
1317 	.fb_compat_ioctl = sunxi_fb_ioctl,
1318 #endif
1319 	.fb_ioctl = sunxi_fb_ioctl,
1320 	.fb_check_var = sunxi_fb_check_var,
1321 	.fb_blank = sunxi_fb_blank,
1322 	.fb_cursor = sunxi_fb_cursor,
1323 	.fb_mmap = sunxi_fb_mmap,
1324 #if defined(CONFIG_FB_CONSOLE_SUNXI)
1325 	.fb_fillrect = cfb_fillrect,
1326 	.fb_copyarea = cfb_copyarea,
1327 	.fb_imageblit = cfb_imageblit,
1328 #endif
1329 	.fb_setcmap = sunxi_fb_setcmap,
1330 	.fb_setcolreg = sunxi_fb_setcolreg,
1331 
1332 };
1333 
Fb_copy_boot_fb(u32 sel,struct fb_info * info)1334 static int Fb_copy_boot_fb(u32 sel, struct fb_info *info)
1335 {
1336 	enum {
1337 		BOOT_FB_ADDR = 0,
1338 		BOOT_FB_WIDTH,
1339 		BOOT_FB_HEIGHT,
1340 		BOOT_FB_BPP,
1341 		BOOT_FB_STRIDE,
1342 		BOOT_FB_CROP_L,
1343 		BOOT_FB_CROP_T,
1344 		BOOT_FB_CROP_R,
1345 		BOOT_FB_CROP_B,
1346 	};
1347 
1348 	char *boot_fb_str = NULL;
1349 	char *src_phy_addr = NULL;
1350 	char *src_addr = NULL;
1351 	char *src_addr_b = NULL;
1352 	char *src_addr_e = NULL;
1353 	int src_width = 0;
1354 	int src_height = 0;
1355 	int fb_height = 0;
1356 	int src_bpp = 0;
1357 	int src_stride = 0;
1358 	int src_cp_btyes = 0;
1359 	int src_crop_l = 0;
1360 	int src_crop_t = 0;
1361 	int src_crop_r = 0;
1362 	int src_crop_b = 0;
1363 
1364 	char *dst_addr = NULL;
1365 	int dst_width = 0;
1366 	int dst_height = 0;
1367 	int dst_bpp = 0;
1368 	int dst_stride = 0;
1369 	int ret;
1370 
1371 	unsigned long map_offset;
1372 
1373 	if (info == NULL) {
1374 		__wrn("%s,%d: null pointer\n", __func__, __LINE__);
1375 		return -1;
1376 	}
1377 
1378 	boot_fb_str = (char *)disp_boot_para_parse_str("boot_fb0");
1379 	if (boot_fb_str != NULL) {
1380 		int i = 0;
1381 		char boot_fb[128] = { 0 };
1382 		int len = strlen(boot_fb_str);
1383 
1384 		if (sizeof(boot_fb) - 1 < len) {
1385 			__wrn("need bigger array size[%d] for boot_fb\n", len);
1386 			return -1;
1387 		}
1388 		memcpy((void *)boot_fb, (void *)boot_fb_str, len);
1389 		boot_fb[len] = '\0';
1390 		boot_fb_str = boot_fb;
1391 		for (i = 0;; ++i) {
1392 			char *p = strstr(boot_fb_str, ",");
1393 
1394 			if (p != NULL)
1395 				*p = '\0';
1396 			if (i == BOOT_FB_ADDR) {
1397 				ret = kstrtoul(boot_fb_str, 16,
1398 				    (unsigned long *)&src_phy_addr);
1399 				if (ret)
1400 					pr_warn("parse src_phy_addr fail!\n");
1401 			} else if (i == BOOT_FB_WIDTH) {
1402 				ret = kstrtou32(boot_fb_str, 16, &src_width);
1403 				if (ret)
1404 					pr_warn("parse src_width fail!\n");
1405 			} else if (i == BOOT_FB_HEIGHT) {
1406 				ret = kstrtou32(boot_fb_str, 16, &src_height);
1407 				fb_height = src_height;
1408 				if (ret)
1409 					pr_warn("parse src_height fail!\n");
1410 			} else if (i == BOOT_FB_BPP) {
1411 				ret = kstrtou32(boot_fb_str, 16, &src_bpp);
1412 				if (ret)
1413 					pr_warn("parse src_bpp fail!\n");
1414 			} else if (i == BOOT_FB_STRIDE) {
1415 				ret = kstrtou32(boot_fb_str, 16, &src_stride);
1416 				if (ret)
1417 					pr_warn("parse src_stride fail!\n");
1418 			} else if (i == BOOT_FB_CROP_L) {
1419 				ret = kstrtou32(boot_fb_str, 16, &src_crop_l);
1420 				if (ret)
1421 					pr_warn("parse src_crop_l fail!\n");
1422 			} else if (i == BOOT_FB_CROP_T) {
1423 				ret = kstrtou32(boot_fb_str, 16, &src_crop_t);
1424 				if (ret)
1425 					pr_warn("parse src_crop_t fail!\n");
1426 			} else if (i == BOOT_FB_CROP_R) {
1427 				ret = kstrtou32(boot_fb_str, 16, &src_crop_r);
1428 				if (ret)
1429 					pr_warn("parse src_crop_r fail!\n");
1430 			} else if (i == BOOT_FB_CROP_B) {
1431 				ret = kstrtou32(boot_fb_str, 16, &src_crop_b);
1432 				if (ret)
1433 					pr_warn("parse src_crop_b fail!\n");
1434 			} else {
1435 				break;
1436 			}
1437 
1438 			if (p == NULL)
1439 				break;
1440 			boot_fb_str = p + 1;
1441 		}
1442 	} else {
1443 		__wrn("no boot_fb0\n");
1444 		return -1;
1445 	}
1446 
1447 	dst_addr = (char *)(info->screen_base);
1448 	dst_width = info->var.xres;
1449 	dst_height = info->var.yres;
1450 	dst_bpp = info->var.bits_per_pixel;
1451 	dst_stride = info->fix.line_length;
1452 
1453 	if ((src_phy_addr == NULL)
1454 	    || (src_width <= 0)
1455 	    || (src_height <= 0)
1456 	    || (src_stride <= 0)
1457 	    || (src_bpp <= 0)
1458 	    || (dst_addr == NULL)
1459 	    || (dst_width <= 0)
1460 	    || (dst_height <= 0)
1461 	    || (dst_stride <= 0)
1462 	    || (dst_bpp <= 0)
1463 	    || (src_bpp != dst_bpp)) {
1464 		__wrn
1465 		    ("wrong para: src[phy_addr=%p,w=%d,h=%d,bpp=%d,stride=%d], dst[addr=%p,w=%d,h=%d,bpp=%d,stride=%d]\n",
1466 		     src_phy_addr,
1467 		     src_width, src_height, src_bpp, src_stride, dst_addr,
1468 		     dst_width, dst_height, dst_bpp, dst_stride);
1469 		return -1;
1470 	}
1471 
1472 	map_offset = (unsigned long)src_phy_addr + PAGE_SIZE
1473 	    - PAGE_ALIGN((unsigned long)src_phy_addr + 1);
1474 	src_addr = (char *)Fb_map_kernel_cache((unsigned long)src_phy_addr -
1475 					       map_offset,
1476 					       src_stride * src_height +
1477 					       map_offset);
1478 	if (src_addr == NULL) {
1479 		__wrn("Fb_map_kernel_cache for src_addr failed\n");
1480 		return -1;
1481 	}
1482 
1483 	src_addr_b = src_addr + map_offset;
1484 	if ((src_crop_b > src_crop_t) &&
1485 	    (src_height > src_crop_b - src_crop_t) &&
1486 	    (src_crop_t >= 0) &&
1487 	    (src_height >= src_crop_b)) {
1488 		src_height = src_crop_b - src_crop_t;
1489 		src_addr_b += (src_stride * src_crop_t);
1490 	}
1491 	if ((src_crop_r > src_crop_l)
1492 	    && (src_width > src_crop_r - src_crop_l)
1493 	    && (src_crop_l >= 0)
1494 	    && (src_width >= src_crop_r)) {
1495 		src_width = src_crop_r - src_crop_l;
1496 		src_addr_b += (src_crop_l * src_bpp >> 3);
1497 	}
1498 	if (src_height < dst_height) {
1499 		int dst_crop_t = (dst_height - src_height) >> 1;
1500 
1501 		dst_addr += (dst_stride * dst_crop_t);
1502 	} else if (src_height > dst_height) {
1503 		__wrn("src_height(%d) > dst_height(%d),please cut the height\n",
1504 		      src_height,
1505 		      dst_height);
1506 		Fb_unmap_kernel(src_addr);
1507 		return -1;
1508 	}
1509 	if (src_width < dst_width) {
1510 		int dst_crop_l = (dst_width - src_width) >> 1;
1511 
1512 		dst_addr += (dst_crop_l * dst_bpp >> 3);
1513 	} else if (src_width > dst_width) {
1514 		__wrn("src_width(%d) > dst_width(%d),please cut the width!\n",
1515 		      src_width,
1516 		      dst_width);
1517 		Fb_unmap_kernel(src_addr);
1518 		return -1;
1519 	}
1520 
1521 	src_cp_btyes = src_width * src_bpp >> 3;
1522 	src_addr_e = src_addr_b + src_stride * src_height;
1523 	for (; src_addr_b != src_addr_e; src_addr_b += src_stride) {
1524 		memcpy((void *)dst_addr, (void *)src_addr_b, src_cp_btyes);
1525 		dst_addr += dst_stride;
1526 	}
1527 	Fb_unmap_kernel(src_addr);
1528 
1529 	memblock_free((unsigned long)src_phy_addr, src_stride * fb_height);
1530 	return 0;
1531 }
1532 
1533 #if defined(SUPPORT_ROTATE)
rgb24_to_rgb32(const void * psrc,struct bmp_header * bmp_header,struct fb_info * info,void * pdst,int zero_num)1534 static int rgb24_to_rgb32(const void *psrc, struct bmp_header *bmp_header,
1535 			  struct fb_info *info, void *pdst, int zero_num)
1536 {
1537 	int srclinesize, dstlinesize, w, h;
1538 	const unsigned char *psrcline = NULL, *psrcdot = NULL;
1539 	unsigned char *pdstline = NULL, *pdstdot = NULL;
1540 	int i = 0, j = 0;
1541 
1542 	if (!psrc || !pdst || !bmp_header || !info) {
1543 		__wrn("Invalid parameter\n");
1544 		return -1;
1545 	}
1546 
1547 	w = (info->var.xres < bmp_header->width) ? info->var.xres
1548 						 : bmp_header->width;
1549 	h = (bmp_header->height & 0x80000000) ? (-bmp_header->
1550 						 height) : (bmp_header->height);
1551 	h = (info->var.yres < h) ? info->var.yres : h;
1552 
1553 	srclinesize = w * 3 + zero_num;
1554 	dstlinesize = info->var.xres * 4;
1555 	psrcline = (const unsigned char *)psrc;
1556 	pdstline = (unsigned char *)pdst;
1557 
1558 	if (bmp_header->height & 0x80000000) {
1559 		for (i = 0; i < h; ++i) {
1560 			psrcdot = psrcline;
1561 			pdstdot = pdstline;
1562 			for (j = 0; j < w; ++j) {
1563 				*pdstdot++ = psrcdot[j*3];
1564 				*pdstdot++ = psrcdot[j*3+1];
1565 				*pdstdot++ = psrcdot[j*3+2];
1566 				*pdstdot++ = 0xff;
1567 			}
1568 			psrcline += srclinesize;
1569 			pdstline += dstlinesize;
1570 		}
1571 	} else {
1572 		for (i = h - 1; i >= 0; --i) {
1573 			psrcdot = psrcline;
1574 			pdstdot = pdstline;
1575 			for (j = 0; j < w; ++j) {
1576 				*pdstdot++ = psrcdot[j*3];
1577 				*pdstdot++ = psrcdot[j*3+1];
1578 				*pdstdot++ = psrcdot[j*3+2];
1579 				*pdstdot++ = 0xff;
1580 			}
1581 			psrcline -= srclinesize;
1582 			pdstline += dstlinesize;
1583 		}
1584 	}
1585 	info->var.bits_per_pixel = 32;
1586 
1587 	return 0;
1588 }
1589 #endif
1590 
1591 #if defined(CONFIG_DECOMPRESS_LZMA)
lzma_decode(uintptr_t paddr,struct fb_info * info)1592 int lzma_decode(uintptr_t paddr, struct fb_info *info)
1593 {
1594 	void *vaddr = NULL;
1595 	long pos = 0;
1596 	unsigned char *out = NULL;
1597 	int ret = -1, i = 0;
1598 	struct lzma_header lzma_head;
1599 	struct bmp_header bmp_header;
1600 	unsigned int x, y, bmp_bpix, fb_width, fb_height;
1601 	unsigned int effective_width, effective_height;
1602 	int zero_num = 0;
1603 	struct sunxi_bmp_store bmp_info;
1604 	void *screen_offset = NULL, *image_offset = NULL;
1605 	char *tmp_buffer = NULL;
1606 	char *bmp_data = NULL;
1607 
1608 	if (!paddr || !info) {
1609 		__wrn("Null pointer!\n");
1610 		goto OUT;
1611 	}
1612 
1613 	vaddr = (void *)Fb_map_kernel(paddr, sizeof(struct lzma_header));
1614 	if (vaddr == NULL) {
1615 		__wrn("fb_map_kernel failed, paddr=0x%p,size=0x%x\n",
1616 		      (void *)paddr, (unsigned int)sizeof(struct lzma_header));
1617 		goto OUT;
1618 	}
1619 
1620 	memcpy(&lzma_head.signature[0], vaddr, sizeof(struct lzma_header));
1621 
1622 	if ((lzma_head.signature[0] != 'L') ||
1623 	    (lzma_head.signature[1] != 'Z') ||
1624 	    (lzma_head.signature[2] != 'M') ||
1625 	    (lzma_head.signature[3] != 'A')) {
1626 		__wrn("this is not a LZMA file.\n");
1627 		Fb_unmap_kernel(vaddr);
1628 		goto OUT;
1629 	}
1630 
1631 	Fb_unmap_kernel(vaddr);
1632 
1633 	out = kmalloc(lzma_head.original_file_size, GFP_KERNEL | __GFP_ZERO);
1634 	if (!out) {
1635 		__wrn("kmalloc outbuffer fail!\n");
1636 		goto OUT;
1637 	}
1638 
1639 	vaddr = (void *)Fb_map_kernel(paddr, lzma_head.file_size +
1640 						 sizeof(struct lzma_header));
1641 	if (vaddr == NULL) {
1642 		__wrn("fb_map_kernel failed, paddr=0x%p,size=0x%x\n",
1643 		      (void *)paddr,
1644 		      (unsigned int)(lzma_head.file_size +
1645 				     sizeof(struct lzma_header)));
1646 		goto FREE_OUT;
1647 	}
1648 
1649 	ret = unlzma((unsigned char *)(vaddr + sizeof(struct lzma_header)),
1650 		     lzma_head.file_size, NULL, NULL, out, &pos, NULL);
1651 	if (ret) {
1652 		__wrn("unlzma fail:%d\n", ret);
1653 		goto UMAPKERNEL;
1654 	}
1655 
1656 	memcpy(&bmp_header, out, sizeof(struct bmp_header));
1657 
1658 	if ((bmp_header.signature[0] != 'B') ||
1659 	    (bmp_header.signature[1] != 'M')) {
1660 		__wrn("%s:this is not a bmp picture.\n", __func__);
1661 		goto UMAPKERNEL;
1662 	}
1663 
1664 	bmp_bpix = bmp_header.bit_count / 8;
1665 
1666 	if ((bmp_bpix != 3) && (bmp_bpix != 4)) {
1667 		__wrn("%s:not support bmp format:%d.\n", __func__, bmp_bpix);
1668 		goto UMAPKERNEL;
1669 	}
1670 
1671 	x = bmp_header.width;
1672 	y = (bmp_header.height & 0x80000000) ? (-bmp_header.height)
1673 					     : (bmp_header.height);
1674 	if (bmp_bpix == 3)
1675 		zero_num = (4 - ((3 * x) % 4)) & 3;
1676 	fb_width = info->var.xres;
1677 	fb_height = info->var.yres;
1678 	bmp_info.x = x;
1679 	bmp_info.y = y;
1680 	bmp_info.bit = bmp_header.bit_count;
1681 	bmp_info.buffer = (void *__force)(info->screen_base);
1682 
1683 	if (bmp_bpix == 3)
1684 		info->var.bits_per_pixel = 24;
1685 	else if (bmp_bpix == 4)
1686 		info->var.bits_per_pixel = 32;
1687 	else
1688 		info->var.bits_per_pixel = 32;
1689 
1690 	tmp_buffer = (char *)bmp_info.buffer;
1691 	screen_offset = (void *)bmp_info.buffer;
1692 	bmp_data =
1693 	    (char *)(out + bmp_header.data_offset + sizeof(struct lzma_header));
1694 	image_offset = (void *)bmp_data;
1695 	effective_width = (fb_width < x) ? fb_width : x;
1696 	effective_height = (fb_height < y) ? fb_height : y;
1697 
1698 	if (bmp_header.height & 0x80000000) {
1699 #if defined(SUPPORT_ROTATE)
1700 		if (info->var.bits_per_pixel == 24) {
1701 			screen_offset =
1702 			    (void *)((void *__force)info->screen_base +
1703 				     (fb_width * (abs(fb_height - y) / 2) +
1704 				      abs(fb_width - x) / 2) *
1705 					 4);
1706 			rgb24_to_rgb32(image_offset, &bmp_header, info,
1707 				       screen_offset, zero_num);
1708 		} else
1709 #endif
1710 		{
1711 			screen_offset =
1712 			    (void *)((void *__force)info->screen_base +
1713 				     (fb_width * (abs(fb_height - y) / 2) +
1714 				      abs(fb_width - x) / 2) *
1715 					 (info->var.bits_per_pixel >> 3));
1716 			for (i = 0; i < effective_height; i++) {
1717 				memcpy((void *)screen_offset, image_offset,
1718 				       effective_width *
1719 					   (info->var.bits_per_pixel >> 3));
1720 				screen_offset =
1721 				    (void *)(screen_offset +
1722 					     fb_width *
1723 						 (info->var.bits_per_pixel >>
1724 						  3));
1725 				image_offset =
1726 				    (void *)image_offset +
1727 				    x * (info->var.bits_per_pixel >> 3);
1728 			}
1729 		}
1730 
1731 	} else {
1732 
1733 #if defined(SUPPORT_ROTATE)
1734 		if (info->var.bits_per_pixel == 24) {
1735 			screen_offset =
1736 			    (void *)((void *__force)info->screen_base +
1737 				     (fb_width * (abs(fb_height - y) / 2) +
1738 				      abs(fb_width - x) / 2) *
1739 					 4);
1740 
1741 			image_offset =
1742 			    (void *)bmp_data +
1743 			    (effective_height - 1) * (x * 3 + zero_num);
1744 			rgb24_to_rgb32(image_offset, &bmp_header, info,
1745 				       screen_offset, zero_num);
1746 		} else
1747 #endif
1748 		{
1749 			screen_offset =
1750 			    (void *)((void *__force)info->screen_base +
1751 				     (fb_width * (abs(fb_height - y) / 2) +
1752 				      abs(fb_width - x) / 2) *
1753 					 (info->var.bits_per_pixel >> 3));
1754 
1755 			image_offset = (void *)bmp_data +
1756 				       (effective_height - 1) * x *
1757 					   (info->var.bits_per_pixel >> 3);
1758 			for (i = effective_height - 1; i >= 0; i--) {
1759 				memcpy((void *)screen_offset, image_offset,
1760 				       effective_width *
1761 					   (info->var.bits_per_pixel >> 3));
1762 				screen_offset =
1763 				    (void *)(screen_offset +
1764 					     fb_width *
1765 						 (info->var.bits_per_pixel >>
1766 						  3));
1767 				image_offset =
1768 				    (void *)bmp_data +
1769 				    i * x * (info->var.bits_per_pixel >> 3);
1770 			}
1771 		}
1772 	}
1773 
1774 UMAPKERNEL:
1775 	Fb_unmap_kernel(vaddr);
1776 FREE_OUT:
1777 	kfree(out);
1778 OUT:
1779 	return ret;
1780 }
1781 #endif
1782 
Fb_map_kernel_logo(u32 sel,struct fb_info * info)1783 static int Fb_map_kernel_logo(u32 sel, struct fb_info *info)
1784 {
1785 	void *vaddr = NULL;
1786 	uintptr_t paddr = 0;
1787 	void *screen_offset = NULL, *image_offset = NULL;
1788 	char *tmp_buffer = NULL;
1789 	char *bmp_data = NULL;
1790 	struct sunxi_bmp_store s_bmp_info;
1791 	struct sunxi_bmp_store *bmp_info = &s_bmp_info;
1792 	struct bmp_pad_header bmp_pad_header;
1793 	struct bmp_header *bmp_header;
1794 	int zero_num = 0;
1795 	unsigned int x, y, bmp_bpix, fb_width, fb_height;
1796 	unsigned int effective_width, effective_height;
1797 	uintptr_t offset;
1798 	int i = 0;
1799 	struct disp_manager *mgr;
1800 
1801 	mgr = g_disp_drv.mgr[sel];
1802 
1803 	paddr = bootlogo_addr;
1804 	if (paddr == 0) {
1805 		__inf("Fb_map_kernel_logo failed!");
1806 		return Fb_copy_boot_fb(sel, info);
1807 	}
1808 
1809 	/* parser bmp header */
1810 	offset = paddr & ~PAGE_MASK;
1811 	vaddr = (void *)Fb_map_kernel(paddr, sizeof(struct bmp_header));
1812 	if (vaddr == NULL) {
1813 		__wrn("fb_map_kernel failed, paddr=0x%p,size=0x%x\n",
1814 		      (void *)paddr, (unsigned int)sizeof(struct bmp_header));
1815 		return -1;
1816 	}
1817 
1818 	memcpy(&bmp_pad_header.signature[0], vaddr + offset,
1819 	       sizeof(struct bmp_header));
1820 	bmp_header = (struct bmp_header *) &bmp_pad_header.signature[0];
1821 	if ((bmp_header->signature[0] != 'B')
1822 	    || (bmp_header->signature[1] != 'M')) {
1823 		Fb_unmap_kernel(vaddr);
1824 #if defined(CONFIG_DECOMPRESS_LZMA)
1825 		return lzma_decode(paddr, info);
1826 #else
1827 		__wrn("this is not a bmp picture.\n");
1828 		return -1;
1829 
1830 #endif
1831 	}
1832 
1833 	bmp_bpix = bmp_header->bit_count / 8;
1834 
1835 	if ((bmp_bpix != 3) && (bmp_bpix != 4))
1836 		return -1;
1837 
1838 	x = bmp_header->width;
1839 	y = (bmp_header->height & 0x80000000) ? (-bmp_header->
1840 						 height) : (bmp_header->height);
1841 
1842 	if (bmp_bpix == 3) {
1843 		zero_num = (4 - ((3 * x) % 4)) & 3;
1844 #ifndef SUPPORT_ROTATE
1845 		/*uboot have removed zero for us*/
1846 		zero_num = 0;
1847 #endif
1848 	}
1849 	fb_width = info->var.xres;
1850 	fb_height = info->var.yres;
1851 	if ((paddr <= 0) || x <= 1 || y <= 1) {
1852 		__wrn("kernel logo para error!\n");
1853 		return -EINVAL;
1854 	}
1855 
1856 	bmp_info->x = x;
1857 	bmp_info->y = y;
1858 	bmp_info->bit = bmp_header->bit_count;
1859 	bmp_info->buffer = (void *__force)(info->screen_base);
1860 
1861 	if (bmp_bpix == 3)
1862 		info->var.bits_per_pixel = 24;
1863 	else if (bmp_bpix == 4)
1864 		info->var.bits_per_pixel = 32;
1865 	else
1866 		info->var.bits_per_pixel = 32;
1867 
1868 	Fb_unmap_kernel(vaddr);
1869 
1870 	/* map the total bmp buffer */
1871 	vaddr =
1872 	    (void *)Fb_map_kernel(paddr,
1873 				  (x * bmp_bpix + zero_num) * y + sizeof(struct bmp_header));
1874 	if (vaddr == NULL) {
1875 		__wrn("fb_map_kernel failed, paddr=0x%p,size=0x%x\n",
1876 		      (void *)paddr,
1877 		      (unsigned int)(x * y * bmp_bpix +
1878 		       sizeof(struct bmp_header)));
1879 		return -1;
1880 	}
1881 
1882 	tmp_buffer = (char *)bmp_info->buffer;
1883 	screen_offset = (void *)bmp_info->buffer;
1884 	bmp_data = (char *)(vaddr + bmp_header->data_offset);
1885 	image_offset = (void *)bmp_data;
1886 	effective_width = (fb_width < x) ? fb_width : x;
1887 	effective_height = (fb_height < y) ? fb_height : y;
1888 
1889 	if (bmp_header->height & 0x80000000) {
1890 #if defined(SUPPORT_ROTATE)
1891 		if (info->var.bits_per_pixel == 24) {
1892 			screen_offset =
1893 				(void *)((void *__force)info->screen_base +
1894 					 (fb_width * (abs(fb_height - y) / 2)
1895 					  + abs(fb_width - x) / 2)
1896 					 * 4);
1897 			rgb24_to_rgb32(image_offset, bmp_header, info,
1898 				       screen_offset, zero_num);
1899 		} else
1900 #endif
1901 		{
1902 		screen_offset =
1903 			(void *)((void *__force)info->screen_base +
1904 				 (fb_width * (abs(fb_height - y) / 2)
1905 				  + abs(fb_width - x) / 2)
1906 				 * (info->var.bits_per_pixel >> 3));
1907 			for (i = 0; i < effective_height; i++) {
1908 				memcpy((void *)screen_offset, image_offset,
1909 				       effective_width *
1910 				       (info->var.bits_per_pixel >> 3));
1911 				screen_offset =
1912 					(void *)(screen_offset + fb_width *
1913 						 (info->var.bits_per_pixel >> 3));
1914 				image_offset =
1915 					(void *)image_offset +
1916 					x * (info->var.bits_per_pixel >> 3);
1917 			}
1918 		}
1919 
1920 	} else {
1921 
1922 #if defined(SUPPORT_ROTATE)
1923 		if (info->var.bits_per_pixel == 24) {
1924 			screen_offset =
1925 				(void *)((void *__force)info->screen_base +
1926 					 (fb_width * (abs(fb_height - y) / 2)
1927 					  + abs(fb_width - x) / 2)
1928 					 * 4);
1929 
1930 			image_offset =
1931 			    (void *)bmp_data +
1932 			    (effective_height - 1) * (x * 3 + zero_num);
1933 			rgb24_to_rgb32(image_offset, bmp_header, info,
1934 				       screen_offset, zero_num);
1935 		} else
1936 #endif
1937 		{
1938 			screen_offset =
1939 				(void *)((void *__force)info->screen_base +
1940 					 (fb_width * (abs(fb_height - y) / 2)
1941 					  + abs(fb_width - x) / 2)
1942 					 * (info->var.bits_per_pixel >> 3));
1943 
1944 			image_offset =
1945 				(void *)bmp_data + (effective_height -
1946 						    1) * x *
1947 				(info->var.bits_per_pixel >> 3);
1948 			for (i = effective_height - 1; i >= 0; i--) {
1949 				memcpy((void *)screen_offset, image_offset,
1950 				       effective_width *
1951 				       (info->var.bits_per_pixel >> 3));
1952 				screen_offset =
1953 					(void *)(screen_offset +
1954 						 fb_width *
1955 						 (info->var.bits_per_pixel >> 3));
1956 				image_offset =
1957 					(void *)bmp_data +
1958 					i * x * (info->var.bits_per_pixel >> 3);
1959 			}
1960 		}
1961 	}
1962 
1963 	Fb_unmap_kernel(vaddr);
1964 	return 0;
1965 }
1966 
display_fb_request(u32 fb_id,struct disp_fb_create_info * fb_para)1967 static s32 display_fb_request(u32 fb_id, struct disp_fb_create_info *fb_para)
1968 {
1969 	struct fb_info *info = NULL;
1970 	struct disp_layer_config config;
1971 	u32 sel;
1972 	u32 xres, yres;
1973 	u32 num_screens;
1974 	s32 ret = 0;
1975 
1976 #if defined(CONFIG_ARCH_SUN8IW12) || defined(CONFIG_ARCH_SUN8IW16)\
1977     || defined(CONFIG_ARCH_SUN8IW19)
1978 	/* fb bound to layer(2,0)  */
1979 	g_fbi.layer_hdl[fb_id][0] = 2;
1980 	g_fbi.layer_hdl[fb_id][1] = 0;
1981 #else
1982 	/* fb bound to layer(1,0)  */
1983 	g_fbi.layer_hdl[fb_id][0] = 1;
1984 	g_fbi.layer_hdl[fb_id][1] = 0;
1985 #endif
1986 
1987 
1988 	num_screens = bsp_disp_feat_get_num_screens();
1989 
1990 	printk("%s,fb_id:%d\n", __func__, fb_id);
1991 
1992 	if (g_fbi.fb_enable[fb_id]) {
1993 		__wrn("%s, fb%d is already requested!\n", __func__, fb_id);
1994 		return -1;
1995 	}
1996 	info = g_fbi.fbinfo[fb_id];
1997 
1998 	xres = fb_para->width;
1999 	yres = fb_para->height;
2000 	if ((xres == 0) || (yres == 0) || (info->var.bits_per_pixel == 0)) {
2001 		__wrn("invalid paras xres(%d), yres(%d) bpp(%d)\n", xres, yres,
2002 		      info->var.bits_per_pixel);
2003 		return -1;
2004 	}
2005 
2006 	info->var.xoffset = 0;
2007 	info->var.yoffset = 0;
2008 	info->var.xres = xres;
2009 	info->var.yres = yres;
2010 	info->var.xres_virtual = xres;
2011 	info->fix.line_length =
2012 	    (fb_para->width * info->var.bits_per_pixel) >> 3;
2013 	info->fix.smem_len =
2014 	    info->fix.line_length * fb_para->height * fb_para->buffer_num;
2015 	if (info->fix.line_length != 0)
2016 		info->var.yres_virtual =
2017 		    info->fix.smem_len / info->fix.line_length;
2018 	ret = fb_map_video_memory(info);
2019 	if (ret)
2020 		goto OUT;
2021 
2022 	for (sel = 0; sel < num_screens; sel++) {
2023 		if (sel == fb_para->fb_mode) {
2024 			u32 y_offset = 0, src_width = xres, src_height = yres;
2025 			struct disp_video_timings tt;
2026 			struct disp_manager *mgr = NULL;
2027 
2028 			mgr = g_disp_drv.mgr[sel];
2029 			if (mgr && mgr->device && mgr->device->get_timings) {
2030 				mgr->device->get_timings(mgr->device, &tt);
2031 				if (tt.pixel_clk != 0)
2032 					g_fbi.fbinfo[fb_id]->var.pixclock =
2033 					    1000000000 / tt.pixel_clk;
2034 				g_fbi.fbinfo[fb_id]->var.left_margin =
2035 				    tt.hor_back_porch;
2036 				g_fbi.fbinfo[fb_id]->var.right_margin =
2037 				    tt.hor_front_porch;
2038 				g_fbi.fbinfo[fb_id]->var.upper_margin =
2039 				    tt.ver_back_porch;
2040 				g_fbi.fbinfo[fb_id]->var.lower_margin =
2041 				    tt.ver_front_porch;
2042 				g_fbi.fbinfo[fb_id]->var.hsync_len =
2043 				    tt.hor_sync_time;
2044 				g_fbi.fbinfo[fb_id]->var.vsync_len =
2045 				    tt.ver_sync_time;
2046 			}
2047 			info->var.width =
2048 			    bsp_disp_get_screen_physical_width(sel);
2049 			info->var.height =
2050 			    bsp_disp_get_screen_physical_height(sel);
2051 
2052 			memset(&config, 0, sizeof(struct disp_layer_config));
2053 
2054 			config.channel = g_fbi.layer_hdl[fb_id][0];
2055 			config.layer_id = g_fbi.layer_hdl[fb_id][1];
2056 			config.enable = 1;
2057 			Fb_map_kernel_logo(sel, info);
2058 			if (g_disp_drv.para.boot_info.sync == 1) {
2059 				if ((sel == g_disp_drv.para.boot_info.disp) &&
2060 				    (g_disp_drv.para.boot_info.type !=
2061 				     DISP_OUTPUT_TYPE_NONE)) {
2062 					bsp_disp_get_display_size(sel,
2063 					      &fb_para->output_width,
2064 					      &fb_para->output_height);
2065 				}
2066 			}
2067 
2068 
2069 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT)
2070 			if (mgr && mgr->rot_sw &&
2071 			    (ROTATION_SW_90 == mgr->rot_sw->degree ||
2072 			     ROTATION_SW_270 == mgr->rot_sw->degree)) {
2073 				config.info.screen_win.height =
2074 					(fb_para->output_width == 0)
2075 					? src_width
2076 					: fb_para->output_width;
2077 				config.info.screen_win.width =
2078 					(fb_para->output_height == 0)
2079 					? src_width
2080 					: fb_para->output_height;
2081 			} else
2082 #endif
2083 			{
2084 				config.info.screen_win.width =
2085 					(0 ==
2086 					 fb_para->output_width) ? src_width : fb_para->
2087 					output_width;
2088 				config.info.screen_win.height =
2089 					(0 ==
2090 					 fb_para->output_height) ? src_width : fb_para->
2091 					output_height;
2092 			}
2093 
2094 			config.info.mode = LAYER_MODE_BUFFER;
2095 			config.info.zorder = 16;
2096 			config.info.alpha_mode = 0;
2097 			config.info.alpha_value = 0xff;
2098 			config.info.fb.crop.x = (0LL) << 32;
2099 			config.info.fb.crop.y = ((long long)y_offset) << 32;
2100 			config.info.fb.crop.width =
2101 			    ((long long)src_width) << 32;
2102 			config.info.fb.crop.height =
2103 			    ((long long)src_height) << 32;
2104 			config.info.screen_win.x = 0;
2105 			config.info.screen_win.y = 0;
2106 			var_to_disp_fb(&(config.info.fb), &(info->var),
2107 				       &(info->fix));
2108 			config.info.fb.addr[0] =
2109 			    (unsigned long long)info->fix.smem_start;
2110 			config.info.fb.addr[1] = 0;
2111 			config.info.fb.addr[2] = 0;
2112 			config.info.fb.flags = DISP_BF_NORMAL;
2113 			config.info.fb.scan = DISP_SCAN_PROGRESSIVE;
2114 			config.info.fb.size[0].width = fb_para->width;
2115 			config.info.fb.size[0].height = fb_para->height;
2116 			config.info.fb.size[1].width = fb_para->width;
2117 			config.info.fb.size[1].height = fb_para->height;
2118 			config.info.fb.size[2].width = fb_para->width;
2119 			config.info.fb.size[2].height = fb_para->height;
2120 			config.info.fb.color_space = DISP_BT601;
2121 
2122 #if defined(CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT)
2123 			if (mgr && mgr->rot_sw && mgr->rot_sw->apply) {
2124 				struct disp_rect dirty_rect;
2125 
2126 				dirty_rect.x = config.info.fb.crop.x >> 32;
2127 				dirty_rect.y = config.info.fb.crop.y >> 32;
2128 				dirty_rect.width =
2129 				    config.info.fb.crop.width >> 32;
2130 				dirty_rect.height =
2131 				    config.info.fb.crop.height >> 32;
2132 
2133 				mgr->rot_sw->apply(mgr->rot_sw, &config,
2134 						   dirty_rect);
2135 			}
2136 #endif
2137 #if defined(CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT)
2138 			g_fbi.fb_rot[fb_id] = fb_g2d_rot_create(info, fb_id, &config);
2139 			if (g_fbi.fb_rot[fb_id])
2140 				g_fbi.fb_rot[fb_id]->apply(g_fbi.fb_rot[fb_id], &config);
2141 #endif
2142 
2143 #if (!IS_ENABLED(CONFIG_EINK_PANEL_USED)) && (!IS_ENABLED(CONFIG_EINK200_SUNXI))
2144 			if (mgr && mgr->set_layer_config)
2145 				mgr->set_layer_config(mgr, &config, 1);
2146 #endif
2147 			memcpy(&g_fbi.config[fb_id], &config, sizeof(struct disp_layer_config));
2148 		}
2149 	}
2150 
2151 	g_fbi.fb_enable[fb_id] = 1;
2152 	g_fbi.fb_mode[fb_id] = fb_para->fb_mode;
2153 	memcpy(&g_fbi.fb_para[fb_id], fb_para,
2154 	       sizeof(struct disp_fb_create_info));
2155 OUT:
2156 	return ret;
2157 }
2158 
display_fb_release(u32 fb_id)2159 static s32 display_fb_release(u32 fb_id)
2160 {
2161 	u32 num_screens;
2162 
2163 	num_screens = bsp_disp_feat_get_num_screens();
2164 
2165 	__inf("%s, fb_id:%d\n", __func__, fb_id);
2166 
2167 	if (g_fbi.fb_enable[fb_id]) {
2168 		u32 sel = 0;
2169 		struct fb_info *info = g_fbi.fbinfo[fb_id];
2170 
2171 		for (sel = 0; sel < num_screens; sel++) {
2172 			if (sel == g_fbi.fb_mode[fb_id]) {
2173 				struct disp_manager *mgr = NULL;
2174 				struct disp_layer_config config;
2175 
2176 				mgr = g_disp_drv.mgr[sel];
2177 				memset(&config, 0,
2178 				       sizeof(struct disp_layer_config));
2179 				config.channel = g_fbi.layer_hdl[fb_id][0];
2180 				config.layer_id = g_fbi.layer_hdl[fb_id][1];
2181 				if (mgr && mgr->set_layer_config)
2182 					mgr->set_layer_config(mgr, &config, 1);
2183 			}
2184 		}
2185 		g_fbi.layer_hdl[fb_id][0] = 0;
2186 		g_fbi.layer_hdl[fb_id][1] = 0;
2187 		g_fbi.fb_mode[fb_id] = FB_MODE_SCREEN0;
2188 		memset(&g_fbi.fb_para[fb_id], 0,
2189 		       sizeof(struct disp_fb_create_info));
2190 		g_fbi.fb_enable[fb_id] = 0;
2191 #if defined(CONFIG_FB_CONSOLE_SUNXI)
2192 		fb_dealloc_cmap(&info->cmap);
2193 #endif
2194 		fb_unmap_video_memory(info);
2195 #if defined(CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT)
2196 		if (g_fbi.fb_rot[fb_id])
2197 			g_fbi.fb_rot[fb_id]->free(g_fbi.fb_rot[fb_id]);
2198 #endif
2199 
2200 		return 0;
2201 	}
2202 
2203 	__wrn("invalid paras fb_id:%d in %s\n", fb_id, __func__);
2204 	return -1;
2205 }
2206 
Display_set_fb_timming(u32 sel)2207 s32 Display_set_fb_timming(u32 sel)
2208 {
2209 	u8 fb_id = 0;
2210 
2211 	for (fb_id = 0; fb_id < SUNXI_FB_MAX; fb_id++) {
2212 		if (g_fbi.fb_enable[fb_id]) {
2213 			if (sel == g_fbi.fb_mode[fb_id]) {
2214 				struct disp_video_timings tt;
2215 				struct disp_manager *mgr = g_disp_drv.mgr[sel];
2216 
2217 				if (mgr && mgr->device
2218 				    && mgr->device->get_timings) {
2219 					mgr->device->get_timings(mgr->device,
2220 								 &tt);
2221 					if (tt.pixel_clk != 0)
2222 						g_fbi.fbinfo[fb_id]->var.
2223 						    pixclock =
2224 						    1000000000 / tt.pixel_clk;
2225 					g_fbi.fbinfo[fb_id]->var.left_margin =
2226 					    tt.hor_back_porch;
2227 					g_fbi.fbinfo[fb_id]->var.right_margin =
2228 					    tt.hor_front_porch;
2229 					g_fbi.fbinfo[fb_id]->var.upper_margin =
2230 					    tt.ver_back_porch;
2231 					g_fbi.fbinfo[fb_id]->var.lower_margin =
2232 					    tt.ver_front_porch;
2233 					g_fbi.fbinfo[fb_id]->var.hsync_len =
2234 					    tt.hor_sync_time;
2235 					g_fbi.fbinfo[fb_id]->var.vsync_len =
2236 					    tt.ver_sync_time;
2237 				}
2238 			}
2239 		}
2240 	}
2241 
2242 	return 0;
2243 }
2244 
fb_parse_bootlogo_base(phys_addr_t * fb_base,int * fb_size)2245 static s32 fb_parse_bootlogo_base(phys_addr_t *fb_base, int *fb_size)
2246 {
2247 	*fb_base = (phys_addr_t) disp_boot_para_parse("fb_base");
2248 
2249 	return 0;
2250 }
2251 
fb_get_address_info(u32 fb_id,u32 phy_virt_flag)2252 unsigned long fb_get_address_info(u32 fb_id, u32 phy_virt_flag)
2253 {
2254 	struct fb_info *info = NULL;
2255 	unsigned long phy_addr = 0;
2256 	unsigned long virt_addr = 0;
2257 
2258 	if (fb_id >= SUNXI_FB_MAX)
2259 		return 0;
2260 
2261 	info = g_fbi.fbinfo[fb_id];
2262 	phy_addr = info->fix.smem_start;
2263 	virt_addr = (unsigned long)info->screen_base;
2264 
2265 	if (phy_virt_flag == 0)
2266 		/* get virtual address */
2267 		return virt_addr;
2268 
2269 	/* get phy address */
2270 	return phy_addr;
2271 }
2272 
fb_init(struct platform_device * pdev)2273 s32 fb_init(struct platform_device *pdev)
2274 {
2275 	struct disp_fb_create_info fb_para;
2276 	unsigned long i;
2277 	u32 num_screens;
2278 	s32 ret = 0;
2279 #if IS_ENABLED(CONFIG_EINK200_SUNXI)
2280 	s32 value = 0;
2281 	char primary_key[20];
2282 
2283 	sprintf(primary_key, "eink");
2284 #endif
2285 	/* struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; */
2286 
2287 	g_fbi.dev = &pdev->dev;
2288 	num_screens = bsp_disp_feat_get_num_screens();
2289 
2290 	__inf("[DISP] %s\n", __func__);
2291 
2292 	fb_parse_bootlogo_base(&bootlogo_addr, &bootlogo_sz);
2293 	init_waitqueue_head(&g_fbi.wait[0]);
2294 	init_waitqueue_head(&g_fbi.wait[1]);
2295 	init_waitqueue_head(&g_fbi.wait[2]);
2296 	disp_register_sync_finish_proc(DRV_disp_int_process);
2297 
2298 	for (i = 0; i < SUNXI_FB_MAX; i++) {
2299 		g_fbi.fbinfo[i] = framebuffer_alloc(0, g_fbi.dev);
2300 		g_fbi.fbinfo[i]->fbops = &dispfb_ops;
2301 		g_fbi.fbinfo[i]->flags = 0;
2302 		g_fbi.fbinfo[i]->device = g_fbi.dev;
2303 		g_fbi.fbinfo[i]->par = &g_fbi;
2304 		g_fbi.fbinfo[i]->var.xoffset = 0;
2305 		g_fbi.fbinfo[i]->var.yoffset = 0;
2306 		g_fbi.fbinfo[i]->var.xres = 800;
2307 		g_fbi.fbinfo[i]->var.yres = 480;
2308 		g_fbi.fbinfo[i]->var.xres_virtual = 800;
2309 		g_fbi.fbinfo[i]->var.yres_virtual = 480 * 2;
2310 		g_fbi.fbinfo[i]->var.nonstd = 0;
2311 		g_fbi.fbinfo[i]->var.bits_per_pixel = 32;
2312 		g_fbi.fbinfo[i]->var.transp.length = 8;
2313 		g_fbi.fbinfo[i]->var.red.length = 8;
2314 		g_fbi.fbinfo[i]->var.green.length = 8;
2315 		g_fbi.fbinfo[i]->var.blue.length = 8;
2316 		g_fbi.fbinfo[i]->var.transp.offset = 24;
2317 		g_fbi.fbinfo[i]->var.red.offset = 16;
2318 		g_fbi.fbinfo[i]->var.green.offset = 8;
2319 		g_fbi.fbinfo[i]->var.blue.offset = 0;
2320 		g_fbi.fbinfo[i]->var.activate = FB_ACTIVATE_FORCE;
2321 		g_fbi.fbinfo[i]->fix.type = FB_TYPE_PACKED_PIXELS;
2322 		g_fbi.fbinfo[i]->fix.type_aux = 0;
2323 		g_fbi.fbinfo[i]->fix.visual = FB_VISUAL_TRUECOLOR;
2324 		g_fbi.fbinfo[i]->fix.xpanstep = 1;
2325 		g_fbi.fbinfo[i]->fix.ypanstep = 1;
2326 		g_fbi.fbinfo[i]->fix.ywrapstep = 0;
2327 		g_fbi.fbinfo[i]->fix.accel = FB_ACCEL_NONE;
2328 		g_fbi.fbinfo[i]->fix.line_length =
2329 		    g_fbi.fbinfo[i]->var.xres_virtual * 4;
2330 		g_fbi.fbinfo[i]->fix.smem_len =
2331 		    g_fbi.fbinfo[i]->fix.line_length *
2332 		    g_fbi.fbinfo[i]->var.yres_virtual * 2;
2333 		g_fbi.fbinfo[i]->screen_base = NULL;
2334 		g_fbi.fbinfo[i]->pseudo_palette = g_fbi.pseudo_palette[i];
2335 		g_fbi.fbinfo[i]->fix.smem_start = 0x0;
2336 		g_fbi.fbinfo[i]->fix.mmio_start = 0;
2337 		g_fbi.fbinfo[i]->fix.mmio_len = 0;
2338 
2339 		if (fb_alloc_cmap(&g_fbi.fbinfo[i]->cmap, 256, 1) < 0)
2340 			return -ENOMEM;
2341 	}
2342 
2343 	if (g_disp_drv.disp_init.b_init) {
2344 		struct disp_init_para *disp_init = &g_disp_drv.disp_init;
2345 
2346 		for (i = 0; i < SUNXI_FB_MAX; i++) {
2347 			u32 screen_id = g_disp_drv.disp_init.disp_mode;
2348 
2349 			if (g_disp_drv.para.boot_info.sync)
2350 				screen_id = g_disp_drv.para.boot_info.disp;
2351 
2352 			disp_fb_to_var(disp_init->format[i],
2353 				       &(g_fbi.fbinfo[i]->var));
2354 			fb_para.buffer_num = g_disp_drv.disp_init.buffer_num[i];
2355 			if ((disp_init->fb_width[i] == 0)
2356 			    || (disp_init->fb_height[i] == 0)) {
2357 				fb_para.width =
2358 				    bsp_disp_get_screen_width_from_output_type
2359 				    (screen_id,
2360 				     disp_init->output_type[screen_id],
2361 				     disp_init->output_mode[screen_id]);
2362 				fb_para.height =
2363 				    bsp_disp_get_screen_height_from_output_type
2364 				    (screen_id,
2365 				     disp_init->output_type[screen_id],
2366 				     disp_init->output_mode[screen_id]);
2367 			} else {
2368 				fb_para.width = disp_init->fb_width[i];
2369 				fb_para.height = disp_init->fb_height[i];
2370 			}
2371 
2372 			fb_para.output_width =
2373 			    bsp_disp_get_screen_width_from_output_type
2374 			    (screen_id,
2375 			     disp_init->output_type[screen_id],
2376 			     disp_init->output_mode[screen_id]);
2377 			fb_para.output_height =
2378 			    bsp_disp_get_screen_height_from_output_type
2379 			    (screen_id,
2380 			     disp_init->output_type[screen_id],
2381 			     disp_init->output_mode[screen_id]);
2382 			fb_para.fb_mode = screen_id;
2383 
2384 #if (defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED))
2385 			fb_para.output_width = fb_para.width;
2386 			fb_para.output_height = fb_para.height;
2387 #elif IS_ENABLED(CONFIG_EINK200_SUNXI)
2388 			ret = disp_sys_script_get_item(primary_key, "eink_width", &value, 1);
2389 			if (ret == 1)
2390 				fb_para.output_width = value;
2391 			ret = disp_sys_script_get_item(primary_key, "eink_height", &value, 1);
2392 			if (ret == 1)
2393 				fb_para.output_height = value;
2394 			pr_err("%s:fb width = %d, height = %d\n", __func__,
2395 					fb_para.output_width, fb_para.output_height);
2396 			fb_para.width = fb_para.output_width;
2397 			fb_para.height = fb_para.output_height;
2398 #endif
2399 
2400 			ret = display_fb_request(i, &fb_para);
2401 			if (ret)
2402 				break;
2403 #if defined(CONFIG_DISP2_SUNXI_BOOT_COLORBAR)
2404 			disp_draw_colorbar(screen_id, 0);
2405 #endif
2406 		}
2407 		for (i = 0; i < SUNXI_FB_MAX; i++)
2408 			register_framebuffer(g_fbi.fbinfo[i]);
2409 	}
2410 
2411 	return ret;
2412 }
2413 
fb_exit(void)2414 s32 fb_exit(void)
2415 {
2416 	unsigned int fb_id = 0;
2417 
2418 	disp_unregister_sync_finish_proc(DRV_disp_int_process);
2419 	for (fb_id = 0; fb_id < SUNXI_FB_MAX; fb_id++) {
2420 		if (g_fbi.fbinfo[fb_id]) {
2421 			fb_dealloc_cmap(&g_fbi.fbinfo[fb_id]->cmap);
2422 			display_fb_release(fb_id);
2423 			unregister_framebuffer(g_fbi.fbinfo[fb_id]);
2424 			framebuffer_release(g_fbi.fbinfo[fb_id]);
2425 			g_fbi.fbinfo[fb_id] = NULL;
2426 		}
2427 	}
2428 
2429 	return 0;
2430 }
2431 
2432