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