Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fbdev: da8xx/omap-l1xx: implement double buffering

This work includes the following:

- Implement handler for FBIO_WAITFORVSYNC ioctl.

- Allocate the data and palette buffers separately. A consequence of
this is that the palette and data loading is now done in different
phases. And that the LCD must be disabled temporarily after the palette
is loaded but this will only happen once after init and each time the
palette is changed. I think this is OK.

- Allocate two (ping and pong) framebuffers from memory.

- Add pan_display handler which toggles the LCDC DMA registers between
the ping and pong buffers.

Signed-off-by: Martin Ambrose <martin@ti.com>
Cc: Chaithrika U S <chaithrika@ti.com>
Cc: Sudhakar Rajashekhara <sudhakar.raj@ti.com>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Martin Ambrose and committed by
Linus Torvalds
1f9c3e1f fb6cb327

+232 -64
+231 -64
drivers/video/da8xx-fb.c
··· 36 36 #define DRIVER_NAME "da8xx_lcdc" 37 37 38 38 /* LCD Status Register */ 39 + #define LCD_END_OF_FRAME1 BIT(9) 39 40 #define LCD_END_OF_FRAME0 BIT(8) 41 + #define LCD_PL_LOAD_DONE BIT(6) 40 42 #define LCD_FIFO_UNDERFLOW BIT(5) 41 43 #define LCD_SYNC_LOST BIT(2) 42 44 ··· 60 58 #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) 61 59 #define PALETTE_AND_DATA 0x00 62 60 #define PALETTE_ONLY 0x01 61 + #define DATA_ONLY 0x02 63 62 64 63 #define LCD_MONO_8BIT_MODE BIT(9) 65 64 #define LCD_RASTER_ORDER BIT(8) 66 65 #define LCD_TFT_MODE BIT(7) 67 66 #define LCD_UNDERFLOW_INT_ENA BIT(6) 67 + #define LCD_PL_ENABLE BIT(4) 68 68 #define LCD_MONOCHROME_MODE BIT(1) 69 69 #define LCD_RASTER_ENABLE BIT(0) 70 70 #define LCD_TFT_ALT_ENABLE BIT(23) ··· 91 87 #define LCD_DMA_CTRL_REG 0x40 92 88 #define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 93 89 #define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 90 + #define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C 91 + #define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 92 + 93 + #define LCD_NUM_BUFFERS 2 94 94 95 95 #define WSI_TIMEOUT 50 96 96 #define PALETTE_SIZE 256 ··· 119 111 struct da8xx_fb_par { 120 112 resource_size_t p_palette_base; 121 113 unsigned char *v_palette_base; 114 + dma_addr_t vram_phys; 115 + unsigned long vram_size; 116 + void *vram_virt; 117 + unsigned int dma_start; 118 + unsigned int dma_end; 122 119 struct clk *lcdc_clk; 123 120 int irq; 124 121 unsigned short pseudo_palette[16]; 125 - unsigned int databuf_sz; 126 122 unsigned int palette_sz; 127 123 unsigned int pxl_clk; 128 124 int blank; 125 + wait_queue_head_t vsync_wait; 126 + int vsync_flag; 127 + int vsync_timeout; 129 128 #ifdef CONFIG_CPU_FREQ 130 129 struct notifier_block freq_transition; 131 130 #endif ··· 163 148 .type = FB_TYPE_PACKED_PIXELS, 164 149 .type_aux = 0, 165 150 .visual = FB_VISUAL_PSEUDOCOLOR, 166 - .xpanstep = 1, 151 + .xpanstep = 0, 167 152 .ypanstep = 1, 168 - .ywrapstep = 1, 153 + .ywrapstep = 0, 169 154 .accel = FB_ACCEL_NONE 170 155 }; 171 156 ··· 236 221 237 222 static void lcd_blit(int load_mode, struct da8xx_fb_par *par) 238 223 { 239 - u32 tmp = par->p_palette_base + par->databuf_sz - 4; 240 - u32 reg; 224 + u32 start; 225 + u32 end; 226 + u32 reg_ras; 227 + u32 reg_dma; 241 228 242 - /* Update the databuf in the hw. */ 243 - lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); 244 - lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); 229 + /* init reg to clear PLM (loading mode) fields */ 230 + reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); 231 + reg_ras &= ~(3 << 20); 245 232 246 - /* Start the DMA. */ 247 - reg = lcdc_read(LCD_RASTER_CTRL_REG); 248 - reg &= ~(3 << 20); 249 - if (load_mode == LOAD_DATA) 250 - reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); 251 - else if (load_mode == LOAD_PALETTE) 252 - reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); 233 + reg_dma = lcdc_read(LCD_DMA_CTRL_REG); 253 234 254 - lcdc_write(reg, LCD_RASTER_CTRL_REG); 235 + if (load_mode == LOAD_DATA) { 236 + start = par->dma_start; 237 + end = par->dma_end; 238 + 239 + reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); 240 + reg_dma |= LCD_END_OF_FRAME_INT_ENA; 241 + reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; 242 + 243 + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); 244 + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); 245 + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); 246 + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); 247 + } else if (load_mode == LOAD_PALETTE) { 248 + start = par->p_palette_base; 249 + end = start + par->palette_sz - 1; 250 + 251 + reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); 252 + reg_ras |= LCD_PL_ENABLE; 253 + 254 + lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); 255 + lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); 256 + } 257 + 258 + lcdc_write(reg_dma, LCD_DMA_CTRL_REG); 259 + lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); 260 + 261 + /* 262 + * The Raster enable bit must be set after all other control fields are 263 + * set. 264 + */ 265 + lcd_enable_raster(); 255 266 } 256 267 257 268 /* Configure the Burst Size of DMA */ ··· 409 368 static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, 410 369 u32 bpp, u32 raster_order) 411 370 { 412 - u32 bpl, reg; 371 + u32 reg; 413 372 414 - /* Disable Dual Frame Buffer. */ 415 - reg = lcdc_read(LCD_DMA_CTRL_REG); 416 - lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, 417 - LCD_DMA_CTRL_REG); 418 373 /* Set the Panel Width */ 419 374 /* Pixels per line = (PPL + 1)*16 */ 420 375 /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ ··· 447 410 return -EINVAL; 448 411 } 449 412 450 - bpl = width * bpp / 8; 451 - par->databuf_sz = height * bpl + par->palette_sz; 452 - 453 413 return 0; 454 414 } 455 415 ··· 455 421 struct fb_info *info) 456 422 { 457 423 struct da8xx_fb_par *par = info->par; 458 - unsigned short *palette = (unsigned short *)par->v_palette_base; 424 + unsigned short *palette = (unsigned short *) par->v_palette_base; 459 425 u_short pal; 426 + int update_hw = 0; 460 427 461 428 if (regno > 255) 462 429 return 1; ··· 474 439 pal |= (green & 0x00f0); 475 440 pal |= (blue & 0x000f); 476 441 477 - palette[regno] = pal; 478 - 442 + if (palette[regno] != pal) { 443 + update_hw = 1; 444 + palette[regno] = pal; 445 + } 479 446 } else if ((info->var.bits_per_pixel == 16) && regno < 16) { 480 447 red >>= (16 - info->var.red.length); 481 448 red <<= info->var.red.offset; ··· 490 453 491 454 par->pseudo_palette[regno] = red | green | blue; 492 455 493 - palette[0] = 0x4000; 456 + if (palette[0] != 0x4000) { 457 + update_hw = 1; 458 + palette[0] = 0x4000; 459 + } 494 460 } 461 + 462 + /* Update the palette in the h/w as needed. */ 463 + if (update_hw) 464 + lcd_blit(LOAD_PALETTE, par); 495 465 496 466 return 0; 497 467 } ··· 585 541 586 542 static irqreturn_t lcdc_irq_handler(int irq, void *arg) 587 543 { 544 + struct da8xx_fb_par *par = arg; 588 545 u32 stat = lcdc_read(LCD_STAT_REG); 546 + u32 reg_ras; 589 547 590 548 if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { 591 549 lcd_disable_raster(); 592 550 lcdc_write(stat, LCD_STAT_REG); 593 551 lcd_enable_raster(); 594 - } else 552 + } else if (stat & LCD_PL_LOAD_DONE) { 553 + /* 554 + * Must disable raster before changing state of any control bit. 555 + * And also must be disabled before clearing the PL loading 556 + * interrupt via the following write to the status register. If 557 + * this is done after then one gets multiple PL done interrupts. 558 + */ 559 + lcd_disable_raster(); 560 + 595 561 lcdc_write(stat, LCD_STAT_REG); 562 + 563 + /* Disable PL completion inerrupt */ 564 + reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); 565 + reg_ras &= ~LCD_PL_ENABLE; 566 + lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); 567 + 568 + /* Setup and start data loading mode */ 569 + lcd_blit(LOAD_DATA, par); 570 + } else { 571 + lcdc_write(stat, LCD_STAT_REG); 572 + 573 + if (stat & LCD_END_OF_FRAME0) { 574 + lcdc_write(par->dma_start, 575 + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); 576 + lcdc_write(par->dma_end, 577 + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); 578 + par->vsync_flag = 1; 579 + wake_up_interruptible(&par->vsync_wait); 580 + } 581 + 582 + if (stat & LCD_END_OF_FRAME1) { 583 + lcdc_write(par->dma_start, 584 + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); 585 + lcdc_write(par->dma_end, 586 + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); 587 + par->vsync_flag = 1; 588 + wake_up_interruptible(&par->vsync_wait); 589 + } 590 + } 596 591 597 592 return IRQ_HANDLED; 598 593 } ··· 737 654 738 655 unregister_framebuffer(info); 739 656 fb_dealloc_cmap(&info->cmap); 740 - dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, 741 - info->screen_base - PAGE_SIZE, 742 - info->fix.smem_start); 657 + dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, 658 + par->p_palette_base); 659 + dma_free_coherent(NULL, par->vram_size, par->vram_virt, 660 + par->vram_phys); 743 661 free_irq(par->irq, par); 744 662 clk_disable(par->lcdc_clk); 745 663 clk_put(par->lcdc_clk); ··· 749 665 release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); 750 666 751 667 } 668 + return 0; 669 + } 670 + 671 + /* 672 + * Function to wait for vertical sync which for this LCD peripheral 673 + * translates into waiting for the current raster frame to complete. 674 + */ 675 + static int fb_wait_for_vsync(struct fb_info *info) 676 + { 677 + struct da8xx_fb_par *par = info->par; 678 + int ret; 679 + 680 + /* 681 + * Set flag to 0 and wait for isr to set to 1. It would seem there is a 682 + * race condition here where the ISR could have occured just before or 683 + * just after this set. But since we are just coarsely waiting for 684 + * a frame to complete then that's OK. i.e. if the frame completed 685 + * just before this code executed then we have to wait another full 686 + * frame time but there is no way to avoid such a situation. On the 687 + * other hand if the frame completed just after then we don't need 688 + * to wait long at all. Either way we are guaranteed to return to the 689 + * user immediately after a frame completion which is all that is 690 + * required. 691 + */ 692 + par->vsync_flag = 0; 693 + ret = wait_event_interruptible_timeout(par->vsync_wait, 694 + par->vsync_flag != 0, 695 + par->vsync_timeout); 696 + if (ret < 0) 697 + return ret; 698 + if (ret == 0) 699 + return -ETIMEDOUT; 700 + 752 701 return 0; 753 702 } 754 703 ··· 814 697 sync_arg.pulse_width, 815 698 sync_arg.front_porch); 816 699 break; 700 + case FBIO_WAITFORVSYNC: 701 + return fb_wait_for_vsync(info); 817 702 default: 818 703 return -EINVAL; 819 704 } ··· 851 732 return ret; 852 733 } 853 734 735 + /* 736 + * Set new x,y offsets in the virtual display for the visible area and switch 737 + * to the new mode. 738 + */ 739 + static int da8xx_pan_display(struct fb_var_screeninfo *var, 740 + struct fb_info *fbi) 741 + { 742 + int ret = 0; 743 + struct fb_var_screeninfo new_var; 744 + struct da8xx_fb_par *par = fbi->par; 745 + struct fb_fix_screeninfo *fix = &fbi->fix; 746 + unsigned int end; 747 + unsigned int start; 748 + 749 + if (var->xoffset != fbi->var.xoffset || 750 + var->yoffset != fbi->var.yoffset) { 751 + memcpy(&new_var, &fbi->var, sizeof(new_var)); 752 + new_var.xoffset = var->xoffset; 753 + new_var.yoffset = var->yoffset; 754 + if (fb_check_var(&new_var, fbi)) 755 + ret = -EINVAL; 756 + else { 757 + memcpy(&fbi->var, &new_var, sizeof(new_var)); 758 + 759 + start = fix->smem_start + 760 + new_var.yoffset * fix->line_length + 761 + new_var.xoffset * var->bits_per_pixel / 8; 762 + end = start + var->yres * fix->line_length - 1; 763 + par->dma_start = start; 764 + par->dma_end = end; 765 + } 766 + } 767 + 768 + return ret; 769 + } 770 + 854 771 static struct fb_ops da8xx_fb_ops = { 855 772 .owner = THIS_MODULE, 856 773 .fb_check_var = fb_check_var, 857 774 .fb_setcolreg = fb_setcolreg, 775 + .fb_pan_display = da8xx_pan_display, 858 776 .fb_ioctl = fb_ioctl, 859 777 .fb_fillrect = cfb_fillrect, 860 778 .fb_copyarea = cfb_copyarea, ··· 985 829 } 986 830 987 831 /* allocate frame buffer */ 988 - da8xx_fb_info->screen_base = dma_alloc_coherent(NULL, 989 - par->databuf_sz + PAGE_SIZE, 990 - (resource_size_t *) 991 - &da8xx_fb_info->fix.smem_start, 992 - GFP_KERNEL | GFP_DMA); 832 + par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; 833 + par->vram_size = PAGE_ALIGN(par->vram_size/8); 834 + par->vram_size = par->vram_size * LCD_NUM_BUFFERS; 993 835 994 - if (!da8xx_fb_info->screen_base) { 836 + par->vram_virt = dma_alloc_coherent(NULL, 837 + par->vram_size, 838 + (resource_size_t *) &par->vram_phys, 839 + GFP_KERNEL | GFP_DMA); 840 + if (!par->vram_virt) { 995 841 dev_err(&device->dev, 996 842 "GLCD: kmalloc for frame buffer failed\n"); 997 843 ret = -EINVAL; 998 844 goto err_release_fb; 999 845 } 1000 846 1001 - /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ 1002 - par->v_palette_base = da8xx_fb_info->screen_base + 1003 - (PAGE_SIZE - par->palette_sz); 1004 - par->p_palette_base = da8xx_fb_info->fix.smem_start + 1005 - (PAGE_SIZE - par->palette_sz); 847 + da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; 848 + da8xx_fb_fix.smem_start = par->vram_phys; 849 + da8xx_fb_fix.smem_len = par->vram_size; 850 + da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; 1006 851 1007 - /* the rest of the frame buffer is pixel data */ 1008 - da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz; 1009 - da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz; 1010 - da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; 1011 - da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; 852 + par->dma_start = par->vram_phys; 853 + par->dma_end = par->dma_start + lcdc_info->height * 854 + da8xx_fb_fix.line_length - 1; 855 + 856 + /* allocate palette buffer */ 857 + par->v_palette_base = dma_alloc_coherent(NULL, 858 + PALETTE_SIZE, 859 + (resource_size_t *) 860 + &par->p_palette_base, 861 + GFP_KERNEL | GFP_DMA); 862 + if (!par->v_palette_base) { 863 + dev_err(&device->dev, 864 + "GLCD: kmalloc for palette buffer failed\n"); 865 + ret = -EINVAL; 866 + goto err_release_fb_mem; 867 + } 868 + memset(par->v_palette_base, 0, PALETTE_SIZE); 1012 869 1013 870 par->irq = platform_get_irq(device, 0); 1014 871 if (par->irq < 0) { 1015 872 ret = -ENOENT; 1016 - goto err_release_fb_mem; 873 + goto err_release_pl_mem; 1017 874 } 1018 875 1019 876 ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); 1020 877 if (ret) 1021 - goto err_release_fb_mem; 878 + goto err_release_pl_mem; 1022 879 1023 880 /* Initialize par */ 1024 881 da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; ··· 1039 870 da8xx_fb_var.xres = lcdc_info->width; 1040 871 da8xx_fb_var.xres_virtual = lcdc_info->width; 1041 872 1042 - da8xx_fb_var.yres = lcdc_info->height; 1043 - da8xx_fb_var.yres_virtual = lcdc_info->height; 873 + da8xx_fb_var.yres = lcdc_info->height; 874 + da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS; 1044 875 1045 876 da8xx_fb_var.grayscale = 1046 877 lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; ··· 1061 892 ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); 1062 893 if (ret) 1063 894 goto err_free_irq; 1064 - 1065 - /* First palette_sz byte of the frame buffer is the palette */ 1066 895 da8xx_fb_info->cmap.len = par->palette_sz; 1067 - 1068 - /* Flush the buffer to the screen. */ 1069 - lcd_blit(LOAD_DATA, par); 1070 896 1071 897 /* initialize var_screeninfo */ 1072 898 da8xx_fb_var.activate = FB_ACTIVATE_FORCE; 1073 899 fb_set_var(da8xx_fb_info, &da8xx_fb_var); 1074 900 1075 901 dev_set_drvdata(&device->dev, da8xx_fb_info); 902 + 903 + /* initialize the vsync wait queue */ 904 + init_waitqueue_head(&par->vsync_wait); 905 + par->vsync_timeout = HZ / 5; 906 + 1076 907 /* Register the Frame Buffer */ 1077 908 if (register_framebuffer(da8xx_fb_info) < 0) { 1078 909 dev_err(&device->dev, ··· 1088 919 goto err_cpu_freq; 1089 920 } 1090 921 #endif 1091 - 1092 - /* enable raster engine */ 1093 - lcd_enable_raster(); 1094 - 1095 922 return 0; 1096 923 1097 924 #ifdef CONFIG_CPU_FREQ ··· 1101 936 err_free_irq: 1102 937 free_irq(par->irq, par); 1103 938 939 + err_release_pl_mem: 940 + dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, 941 + par->p_palette_base); 942 + 1104 943 err_release_fb_mem: 1105 - dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, 1106 - da8xx_fb_info->screen_base - PAGE_SIZE, 1107 - da8xx_fb_info->fix.smem_start); 944 + dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); 1108 945 1109 946 err_release_fb: 1110 947 framebuffer_release(da8xx_fb_info);
+1
include/video/da8xx-fb.h
··· 99 99 #define FBIPUT_COLOR _IOW('F', 6, int) 100 100 #define FBIPUT_HSYNC _IOW('F', 9, int) 101 101 #define FBIPUT_VSYNC _IOW('F', 10, int) 102 + #define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) 102 103 103 104 #endif /* ifndef DA8XX_FB_H */ 104 105