diff options
| -rw-r--r-- | Documentation/fb/pxafb.txt | 84 | ||||
| -rw-r--r-- | arch/arm/mach-pxa/include/mach/regs-lcd.h | 34 | ||||
| -rw-r--r-- | drivers/video/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/video/pxafb.c | 364 | ||||
| -rw-r--r-- | drivers/video/pxafb.h | 45 |
5 files changed, 516 insertions, 16 deletions
diff --git a/Documentation/fb/pxafb.txt b/Documentation/fb/pxafb.txt index ad94b5ca009..d143a0a749f 100644 --- a/Documentation/fb/pxafb.txt +++ b/Documentation/fb/pxafb.txt | |||
| @@ -56,3 +56,87 @@ outputen:POLARITY | |||
| 56 | pixclockpol:POLARITY | 56 | pixclockpol:POLARITY |
| 57 | pixel clock polarity | 57 | pixel clock polarity |
| 58 | 0 => falling edge, 1 => rising edge | 58 | 0 => falling edge, 1 => rising edge |
| 59 | |||
| 60 | |||
| 61 | Overlay Support for PXA27x and later LCD controllers | ||
| 62 | ==================================================== | ||
| 63 | |||
| 64 | PXA27x and later processors support overlay1 and overlay2 on-top of the | ||
| 65 | base framebuffer (although under-neath the base is also possible). They | ||
| 66 | support palette and no-palette RGB formats, as well as YUV formats (only | ||
| 67 | available on overlay2). These overlays have dedicated DMA channels and | ||
| 68 | behave in a similar way as a framebuffer. | ||
| 69 | |||
| 70 | However, there are some differences between these overlay framebuffers | ||
| 71 | and normal framebuffers, as listed below: | ||
| 72 | |||
| 73 | 1. overlay can start at a 32-bit word aligned position within the base | ||
| 74 | framebuffer, which means they have a start (x, y). This information | ||
| 75 | is encoded into var->nonstd (no, var->xoffset and var->yoffset are | ||
| 76 | not for such purpose). | ||
| 77 | |||
| 78 | 2. overlay framebuffer is allocated dynamically according to specified | ||
| 79 | 'struct fb_var_screeninfo', the amount is decided by: | ||
| 80 | |||
| 81 | var->xres_virtual * var->yres_virtual * bpp | ||
| 82 | |||
| 83 | bpp = 16 -- for RGB565 or RGBT555 | ||
| 84 | = 24 -- for YUV444 packed | ||
| 85 | = 24 -- for YUV444 planar | ||
| 86 | = 16 -- for YUV422 planar (1 pixel = 1 Y + 1/2 Cb + 1/2 Cr) | ||
| 87 | = 12 -- for YUV420 planar (1 pixel = 1 Y + 1/4 Cb + 1/4 Cr) | ||
| 88 | |||
| 89 | NOTE: | ||
| 90 | |||
| 91 | a. overlay does not support panning in x-direction, thus | ||
| 92 | var->xres_virtual will always be equal to var->xres | ||
| 93 | |||
| 94 | b. line length of overlay(s) must be on a 32-bit word boundary, | ||
| 95 | for YUV planar modes, it is a requirement for the component | ||
| 96 | with minimum bits per pixel, e.g. for YUV420, Cr component | ||
| 97 | for one pixel is actually 2-bits, it means the line length | ||
| 98 | should be a multiple of 16-pixels | ||
| 99 | |||
| 100 | c. starting horizontal position (XPOS) should start on a 32-bit | ||
| 101 | word boundary, otherwise the fb_check_var() will just fail. | ||
| 102 | |||
| 103 | d. the rectangle of the overlay should be within the base plane, | ||
| 104 | otherwise fail | ||
| 105 | |||
| 106 | Applications should follow the sequence below to operate an overlay | ||
| 107 | framebuffer: | ||
| 108 | |||
| 109 | a. open("/dev/fb[1-2]", ...) | ||
| 110 | b. ioctl(fd, FBIOGET_VSCREENINFO, ...) | ||
| 111 | c. modify 'var' with desired parameters: | ||
| 112 | 1) var->xres and var->yres | ||
| 113 | 2) larger var->yres_virtual if more memory is required, | ||
| 114 | usually for double-buffering | ||
| 115 | 3) var->nonstd for starting (x, y) and color format | ||
| 116 | 4) var->{red, green, blue, transp} if RGB mode is to be used | ||
| 117 | d. ioctl(fd, FBIOPUT_VSCREENINFO, ...) | ||
| 118 | e. ioctl(fd, FBIOGET_FSCREENINFO, ...) | ||
| 119 | f. mmap | ||
| 120 | g. ... | ||
| 121 | |||
| 122 | 3. for YUV planar formats, these are actually not supported within the | ||
| 123 | framebuffer framework, application has to take care of the offsets | ||
| 124 | and lengths of each component within the framebuffer. | ||
| 125 | |||
| 126 | 4. var->nonstd is used to pass starting (x, y) position and color format, | ||
| 127 | the detailed bit fields are shown below: | ||
| 128 | |||
| 129 | 31 23 20 10 0 | ||
| 130 | +-----------------+---+----------+----------+ | ||
| 131 | | ... unused ... |FOR| XPOS | YPOS | | ||
| 132 | +-----------------+---+----------+----------+ | ||
| 133 | |||
| 134 | FOR - color format, as defined by OVERLAY_FORMAT_* in pxafb.h | ||
| 135 | 0 - RGB | ||
| 136 | 1 - YUV444 PACKED | ||
| 137 | 2 - YUV444 PLANAR | ||
| 138 | 3 - YUV422 PLANAR | ||
| 139 | 4 - YUR420 PLANAR | ||
| 140 | |||
| 141 | XPOS - starting horizontal position | ||
| 142 | YPOS - starting vertical position | ||
diff --git a/arch/arm/mach-pxa/include/mach/regs-lcd.h b/arch/arm/mach-pxa/include/mach/regs-lcd.h index aff3b876a7b..f82dcea792d 100644 --- a/arch/arm/mach-pxa/include/mach/regs-lcd.h +++ b/arch/arm/mach-pxa/include/mach/regs-lcd.h | |||
| @@ -12,7 +12,8 @@ | |||
| 12 | #define LCCR3 (0x00C) /* LCD Controller Control Register 3 */ | 12 | #define LCCR3 (0x00C) /* LCD Controller Control Register 3 */ |
| 13 | #define LCCR4 (0x010) /* LCD Controller Control Register 4 */ | 13 | #define LCCR4 (0x010) /* LCD Controller Control Register 4 */ |
| 14 | #define LCCR5 (0x014) /* LCD Controller Control Register 5 */ | 14 | #define LCCR5 (0x014) /* LCD Controller Control Register 5 */ |
| 15 | #define LCSR (0x038) /* LCD Controller Status Register */ | 15 | #define LCSR (0x038) /* LCD Controller Status Register 0 */ |
| 16 | #define LCSR1 (0x034) /* LCD Controller Status Register 1 */ | ||
| 16 | #define LIIDR (0x03C) /* LCD Controller Interrupt ID Register */ | 17 | #define LIIDR (0x03C) /* LCD Controller Interrupt ID Register */ |
| 17 | #define TMEDRGBR (0x040) /* TMED RGB Seed Register */ | 18 | #define TMEDRGBR (0x040) /* TMED RGB Seed Register */ |
| 18 | #define TMEDCR (0x044) /* TMED Control Register */ | 19 | #define TMEDCR (0x044) /* TMED Control Register */ |
| @@ -25,6 +26,11 @@ | |||
| 25 | #define FBR5 (0x110) /* DMA Channel 2 Frame Branch Register */ | 26 | #define FBR5 (0x110) /* DMA Channel 2 Frame Branch Register */ |
| 26 | #define FBR6 (0x114) /* DMA Channel 2 Frame Branch Register */ | 27 | #define FBR6 (0x114) /* DMA Channel 2 Frame Branch Register */ |
| 27 | 28 | ||
| 29 | #define OVL1C1 (0x050) /* Overlay 1 Control Register 1 */ | ||
| 30 | #define OVL1C2 (0x060) /* Overlay 1 Control Register 2 */ | ||
| 31 | #define OVL2C1 (0x070) /* Overlay 2 Control Register 1 */ | ||
| 32 | #define OVL2C2 (0x080) /* Overlay 2 Control Register 2 */ | ||
| 33 | |||
| 28 | #define CMDCR (0x100) /* Command Control Register */ | 34 | #define CMDCR (0x100) /* Command Control Register */ |
| 29 | #define PRSR (0x104) /* Panel Read Status Register */ | 35 | #define PRSR (0x104) /* Panel Read Status Register */ |
| 30 | 36 | ||
| @@ -42,16 +48,12 @@ | |||
| 42 | #define LCCR4_PAL_FOR_MASK (3 << 15) | 48 | #define LCCR4_PAL_FOR_MASK (3 << 15) |
| 43 | 49 | ||
| 44 | #define FDADR0 (0x200) /* DMA Channel 0 Frame Descriptor Address Register */ | 50 | #define FDADR0 (0x200) /* DMA Channel 0 Frame Descriptor Address Register */ |
| 45 | #define FSADR0 (0x204) /* DMA Channel 0 Frame Source Address Register */ | ||
| 46 | #define FIDR0 (0x208) /* DMA Channel 0 Frame ID Register */ | ||
| 47 | #define LDCMD0 (0x20C) /* DMA Channel 0 Command Register */ | ||
| 48 | #define FDADR1 (0x210) /* DMA Channel 1 Frame Descriptor Address Register */ | 51 | #define FDADR1 (0x210) /* DMA Channel 1 Frame Descriptor Address Register */ |
| 49 | #define FSADR1 (0x214) /* DMA Channel 1 Frame Source Address Register */ | 52 | #define FDADR2 (0x220) /* DMA Channel 2 Frame Descriptor Address Register */ |
| 50 | #define FIDR1 (0x218) /* DMA Channel 1 Frame ID Register */ | 53 | #define FDADR3 (0x230) /* DMA Channel 3 Frame Descriptor Address Register */ |
| 51 | #define LDCMD1 (0x21C) /* DMA Channel 1 Command Register */ | 54 | #define FDADR4 (0x240) /* DMA Channel 4 Frame Descriptor Address Register */ |
| 55 | #define FDADR5 (0x250) /* DMA Channel 5 Frame Descriptor Address Register */ | ||
| 52 | #define FDADR6 (0x260) /* DMA Channel 6 Frame Descriptor Address Register */ | 56 | #define FDADR6 (0x260) /* DMA Channel 6 Frame Descriptor Address Register */ |
| 53 | #define FSADR6 (0x264) /* DMA Channel 6 Frame Source Address Register */ | ||
| 54 | #define FIDR6 (0x268) /* DMA Channel 6 Frame ID Register */ | ||
| 55 | 57 | ||
| 56 | #define LCCR0_ENB (1 << 0) /* LCD Controller enable */ | 58 | #define LCCR0_ENB (1 << 0) /* LCD Controller enable */ |
| 57 | #define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */ | 59 | #define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */ |
| @@ -151,8 +153,22 @@ | |||
| 151 | #define LCSR_RD_ST (1 << 11) /* read status */ | 153 | #define LCSR_RD_ST (1 << 11) /* read status */ |
| 152 | #define LCSR_CMD_INT (1 << 12) /* command interrupt */ | 154 | #define LCSR_CMD_INT (1 << 12) /* command interrupt */ |
| 153 | 155 | ||
| 156 | #define LCSR1_IU(x) (1 << ((x) + 23)) /* Input FIFO underrun */ | ||
| 157 | #define LCSR1_BS(x) (1 << ((x) + 15)) /* Branch Status */ | ||
| 158 | #define LCSR1_EOF(x) (1 << ((x) + 7)) /* End of Frame Status */ | ||
| 159 | #define LCSR1_SOF(x) (1 << ((x) - 1)) /* Start of Frame Status */ | ||
| 160 | |||
| 154 | #define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ | 161 | #define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ |
| 155 | 162 | ||
| 163 | /* overlay control registers */ | ||
| 164 | #define OVLxC1_PPL(x) ((((x) - 1) & 0x3ff) << 0) /* Pixels Per Line */ | ||
| 165 | #define OVLxC1_LPO(x) ((((x) - 1) & 0x3ff) << 10) /* Number of Lines */ | ||
| 166 | #define OVLxC1_BPP(x) (((x) & 0xf) << 20) /* Bits Per Pixel */ | ||
| 167 | #define OVLxC1_OEN (1 << 31) /* Enable bit for Overlay */ | ||
| 168 | #define OVLxC2_XPOS(x) (((x) & 0x3ff) << 0) /* Horizontal Position */ | ||
| 169 | #define OVLxC2_YPOS(x) (((x) & 0x3ff) << 10) /* Vertical Position */ | ||
| 170 | #define OVL2C2_PFOR(x) (((x) & 0x7) << 20) /* Pixel Format */ | ||
| 171 | |||
| 156 | /* smartpanel related */ | 172 | /* smartpanel related */ |
| 157 | #define PRSR_DATA(x) ((x) & 0xff) /* Panel Data */ | 173 | #define PRSR_DATA(x) ((x) & 0xff) /* Panel Data */ |
| 158 | #define PRSR_A0 (1 << 8) /* Read Data Source */ | 174 | #define PRSR_A0 (1 << 8) /* Read Data Source */ |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3f3ce13fef4..486d81ca02a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
| @@ -1817,6 +1817,11 @@ config FB_PXA | |||
| 1817 | 1817 | ||
| 1818 | If unsure, say N. | 1818 | If unsure, say N. |
| 1819 | 1819 | ||
| 1820 | config FB_PXA_OVERLAY | ||
| 1821 | bool "Support PXA27x/PXA3xx Overlay(s) as framebuffer" | ||
| 1822 | default n | ||
| 1823 | depends on FB_PXA && (PXA27x || PXA3xx) | ||
| 1824 | |||
| 1820 | config FB_PXA_SMARTPANEL | 1825 | config FB_PXA_SMARTPANEL |
| 1821 | bool "PXA Smartpanel LCD support" | 1826 | bool "PXA Smartpanel LCD support" |
| 1822 | default n | 1827 | default n |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 7935706a756..3a41ea10e8e 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
| @@ -20,6 +20,16 @@ | |||
| 20 | * | 20 | * |
| 21 | * linux-arm-kernel@lists.arm.linux.org.uk | 21 | * linux-arm-kernel@lists.arm.linux.org.uk |
| 22 | * | 22 | * |
| 23 | * Add support for overlay1 and overlay2 based on pxafb_overlay.c: | ||
| 24 | * | ||
| 25 | * Copyright (C) 2004, Intel Corporation | ||
| 26 | * | ||
| 27 | * 2003/08/27: <yu.tang@intel.com> | ||
| 28 | * 2004/03/10: <stanley.cai@intel.com> | ||
| 29 | * 2004/10/28: <yan.yin@intel.com> | ||
| 30 | * | ||
| 31 | * Copyright (C) 2006-2008 Marvell International Ltd. | ||
| 32 | * All Rights Reserved | ||
| 23 | */ | 33 | */ |
| 24 | 34 | ||
| 25 | #include <linux/module.h> | 35 | #include <linux/module.h> |
| @@ -72,6 +82,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, | |||
| 72 | struct pxafb_info *); | 82 | struct pxafb_info *); |
| 73 | static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); | 83 | static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); |
| 74 | static void setup_base_frame(struct pxafb_info *fbi, int branch); | 84 | static void setup_base_frame(struct pxafb_info *fbi, int branch); |
| 85 | static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, | ||
| 86 | unsigned long offset, size_t size); | ||
| 75 | 87 | ||
| 76 | static unsigned long video_mem_size = 0; | 88 | static unsigned long video_mem_size = 0; |
| 77 | 89 | ||
| @@ -581,6 +593,330 @@ static struct fb_ops pxafb_ops = { | |||
| 581 | .fb_blank = pxafb_blank, | 593 | .fb_blank = pxafb_blank, |
| 582 | }; | 594 | }; |
| 583 | 595 | ||
| 596 | #ifdef CONFIG_FB_PXA_OVERLAY | ||
| 597 | static void overlay1fb_setup(struct pxafb_layer *ofb) | ||
| 598 | { | ||
| 599 | int size = ofb->fb.fix.line_length * ofb->fb.var.yres_virtual; | ||
| 600 | unsigned long start = ofb->video_mem_phys; | ||
| 601 | setup_frame_dma(ofb->fbi, DMA_OV1, PAL_NONE, start, size); | ||
| 602 | } | ||
| 603 | |||
| 604 | /* Depending on the enable status of overlay1/2, the DMA should be | ||
| 605 | * updated from FDADRx (when disabled) or FBRx (when enabled). | ||
| 606 | */ | ||
| 607 | static void overlay1fb_enable(struct pxafb_layer *ofb) | ||
| 608 | { | ||
| 609 | int enabled = lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN; | ||
| 610 | uint32_t fdadr1 = ofb->fbi->fdadr[DMA_OV1] | (enabled ? 0x1 : 0); | ||
| 611 | |||
| 612 | lcd_writel(ofb->fbi, enabled ? FBR1 : FDADR1, fdadr1); | ||
| 613 | lcd_writel(ofb->fbi, OVL1C2, ofb->control[1]); | ||
| 614 | lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] | OVLxC1_OEN); | ||
| 615 | } | ||
| 616 | |||
| 617 | static void overlay1fb_disable(struct pxafb_layer *ofb) | ||
| 618 | { | ||
| 619 | uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5); | ||
| 620 | |||
| 621 | lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN); | ||
| 622 | |||
| 623 | lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(1)); | ||
| 624 | lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(1)); | ||
| 625 | lcd_writel(ofb->fbi, FBR1, ofb->fbi->fdadr[DMA_OV1] | 0x3); | ||
| 626 | |||
| 627 | if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) == 0) | ||
| 628 | pr_warning("%s: timeout disabling overlay1\n", __func__); | ||
| 629 | |||
| 630 | lcd_writel(ofb->fbi, LCCR5, lccr5); | ||
| 631 | } | ||
| 632 | |||
| 633 | static void overlay2fb_setup(struct pxafb_layer *ofb) | ||
| 634 | { | ||
| 635 | int size, div = 1, pfor = NONSTD_TO_PFOR(ofb->fb.var.nonstd); | ||
| 636 | unsigned long start[3] = { ofb->video_mem_phys, 0, 0 }; | ||
| 637 | |||
| 638 | if (pfor == OVERLAY_FORMAT_RGB || pfor == OVERLAY_FORMAT_YUV444_PACKED) { | ||
| 639 | size = ofb->fb.fix.line_length * ofb->fb.var.yres_virtual; | ||
| 640 | setup_frame_dma(ofb->fbi, DMA_OV2_Y, -1, start[0], size); | ||
| 641 | } else { | ||
| 642 | size = ofb->fb.var.xres_virtual * ofb->fb.var.yres_virtual; | ||
| 643 | switch (pfor) { | ||
| 644 | case OVERLAY_FORMAT_YUV444_PLANAR: div = 1; break; | ||
| 645 | case OVERLAY_FORMAT_YUV422_PLANAR: div = 2; break; | ||
| 646 | case OVERLAY_FORMAT_YUV420_PLANAR: div = 4; break; | ||
| 647 | } | ||
| 648 | start[1] = start[0] + size; | ||
| 649 | start[2] = start[1] + size / div; | ||
| 650 | setup_frame_dma(ofb->fbi, DMA_OV2_Y, -1, start[0], size); | ||
| 651 | setup_frame_dma(ofb->fbi, DMA_OV2_Cb, -1, start[1], size / div); | ||
| 652 | setup_frame_dma(ofb->fbi, DMA_OV2_Cr, -1, start[2], size / div); | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | static void overlay2fb_enable(struct pxafb_layer *ofb) | ||
| 657 | { | ||
| 658 | int pfor = NONSTD_TO_PFOR(ofb->fb.var.nonstd); | ||
| 659 | int enabled = lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN; | ||
| 660 | uint32_t fdadr2 = ofb->fbi->fdadr[DMA_OV2_Y] | (enabled ? 0x1 : 0); | ||
| 661 | uint32_t fdadr3 = ofb->fbi->fdadr[DMA_OV2_Cb] | (enabled ? 0x1 : 0); | ||
| 662 | uint32_t fdadr4 = ofb->fbi->fdadr[DMA_OV2_Cr] | (enabled ? 0x1 : 0); | ||
| 663 | |||
| 664 | if (pfor == OVERLAY_FORMAT_RGB || pfor == OVERLAY_FORMAT_YUV444_PACKED) | ||
| 665 | lcd_writel(ofb->fbi, enabled ? FBR2 : FDADR2, fdadr2); | ||
| 666 | else { | ||
| 667 | lcd_writel(ofb->fbi, enabled ? FBR2 : FDADR2, fdadr2); | ||
| 668 | lcd_writel(ofb->fbi, enabled ? FBR3 : FDADR3, fdadr3); | ||
| 669 | lcd_writel(ofb->fbi, enabled ? FBR4 : FDADR4, fdadr4); | ||
| 670 | } | ||
| 671 | lcd_writel(ofb->fbi, OVL2C2, ofb->control[1]); | ||
| 672 | lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] | OVLxC1_OEN); | ||
| 673 | } | ||
| 674 | |||
| 675 | static void overlay2fb_disable(struct pxafb_layer *ofb) | ||
| 676 | { | ||
| 677 | uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5); | ||
| 678 | |||
| 679 | lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN); | ||
| 680 | |||
| 681 | lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(2)); | ||
| 682 | lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(2)); | ||
| 683 | lcd_writel(ofb->fbi, FBR2, ofb->fbi->fdadr[DMA_OV2_Y] | 0x3); | ||
| 684 | lcd_writel(ofb->fbi, FBR3, ofb->fbi->fdadr[DMA_OV2_Cb] | 0x3); | ||
| 685 | lcd_writel(ofb->fbi, FBR4, ofb->fbi->fdadr[DMA_OV2_Cr] | 0x3); | ||
| 686 | |||
| 687 | if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) == 0) | ||
| 688 | pr_warning("%s: timeout disabling overlay2\n", __func__); | ||
| 689 | } | ||
| 690 | |||
| 691 | static struct pxafb_layer_ops ofb_ops[] = { | ||
| 692 | [0] = { | ||
| 693 | .enable = overlay1fb_enable, | ||
| 694 | .disable = overlay1fb_disable, | ||
| 695 | .setup = overlay1fb_setup, | ||
| 696 | }, | ||
| 697 | [1] = { | ||
| 698 | .enable = overlay2fb_enable, | ||
| 699 | .disable = overlay2fb_disable, | ||
| 700 | .setup = overlay2fb_setup, | ||
| 701 | }, | ||
| 702 | }; | ||
| 703 | |||
| 704 | static int overlayfb_open(struct fb_info *info, int user) | ||
| 705 | { | ||
| 706 | struct pxafb_layer *ofb = (struct pxafb_layer *)info; | ||
| 707 | |||
| 708 | /* no support for framebuffer console on overlay */ | ||
| 709 | if (user == 0) | ||
| 710 | return -ENODEV; | ||
| 711 | |||
| 712 | /* allow only one user at a time */ | ||
| 713 | if (atomic_inc_and_test(&ofb->usage)) | ||
| 714 | return -EBUSY; | ||
| 715 | |||
| 716 | /* unblank the base framebuffer */ | ||
| 717 | fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK); | ||
| 718 | return 0; | ||
| 719 | } | ||
| 720 | |||
| 721 | static int overlayfb_release(struct fb_info *info, int user) | ||
| 722 | { | ||
| 723 | struct pxafb_layer *ofb = (struct pxafb_layer*) info; | ||
| 724 | |||
| 725 | atomic_dec(&ofb->usage); | ||
| 726 | ofb->ops->disable(ofb); | ||
| 727 | |||
| 728 | free_pages_exact(ofb->video_mem, ofb->video_mem_size); | ||
| 729 | ofb->video_mem = NULL; | ||
| 730 | ofb->video_mem_size = 0; | ||
| 731 | return 0; | ||
| 732 | } | ||
| 733 | |||
| 734 | static int overlayfb_check_var(struct fb_var_screeninfo *var, | ||
| 735 | struct fb_info *info) | ||
| 736 | { | ||
| 737 | struct pxafb_layer *ofb = (struct pxafb_layer *)info; | ||
| 738 | struct fb_var_screeninfo *base_var = &ofb->fbi->fb.var; | ||
| 739 | int xpos, ypos, pfor, bpp; | ||
| 740 | |||
| 741 | xpos = NONSTD_TO_XPOS(var->nonstd); | ||
| 742 | ypos = NONSTD_TO_XPOS(var->nonstd); | ||
| 743 | pfor = NONSTD_TO_PFOR(var->nonstd); | ||
| 744 | |||
| 745 | bpp = pxafb_var_to_bpp(var); | ||
| 746 | if (bpp < 0) | ||
| 747 | return -EINVAL; | ||
| 748 | |||
| 749 | /* no support for YUV format on overlay1 */ | ||
| 750 | if (ofb->id == OVERLAY1 && pfor != 0) | ||
| 751 | return -EINVAL; | ||
| 752 | |||
| 753 | /* for YUV packed formats, bpp = 'minimum bpp of YUV components' */ | ||
| 754 | switch (pfor) { | ||
| 755 | case OVERLAY_FORMAT_RGB: | ||
| 756 | bpp = pxafb_var_to_bpp(var); | ||
| 757 | if (bpp < 0) | ||
| 758 | return -EINVAL; | ||
| 759 | |||
| 760 | pxafb_set_pixfmt(var, var_to_depth(var)); | ||
| 761 | break; | ||
| 762 | case OVERLAY_FORMAT_YUV444_PACKED: bpp = 24; break; | ||
| 763 | case OVERLAY_FORMAT_YUV444_PLANAR: bpp = 8; break; | ||
| 764 | case OVERLAY_FORMAT_YUV422_PLANAR: bpp = 4; break; | ||
| 765 | case OVERLAY_FORMAT_YUV420_PLANAR: bpp = 2; break; | ||
| 766 | default: | ||
| 767 | return -EINVAL; | ||
| 768 | } | ||
| 769 | |||
| 770 | /* each line must start at a 32-bit word boundary */ | ||
| 771 | if ((xpos * bpp) % 32) | ||
| 772 | return -EINVAL; | ||
| 773 | |||
| 774 | /* xres must align on 32-bit word boundary */ | ||
| 775 | var->xres = roundup(var->xres * bpp, 32) / bpp; | ||
| 776 | |||
| 777 | if ((xpos + var->xres > base_var->xres) || | ||
| 778 | (ypos + var->yres > base_var->yres)) | ||
| 779 | return -EINVAL; | ||
| 780 | |||
| 781 | var->xres_virtual = var->xres; | ||
| 782 | var->yres_virtual = max(var->yres, var->yres_virtual); | ||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 786 | static int overlayfb_map_video_memory(struct pxafb_layer *ofb) | ||
| 787 | { | ||
| 788 | struct fb_var_screeninfo *var = &ofb->fb.var; | ||
| 789 | int pfor = NONSTD_TO_PFOR(var->nonstd); | ||
| 790 | int size, bpp = 0; | ||
| 791 | |||
| 792 | switch (pfor) { | ||
| 793 | case OVERLAY_FORMAT_RGB: bpp = var->bits_per_pixel; break; | ||
| 794 | case OVERLAY_FORMAT_YUV444_PACKED: bpp = 24; break; | ||
| 795 | case OVERLAY_FORMAT_YUV444_PLANAR: bpp = 24; break; | ||
| 796 | case OVERLAY_FORMAT_YUV422_PLANAR: bpp = 16; break; | ||
| 797 | case OVERLAY_FORMAT_YUV420_PLANAR: bpp = 12; break; | ||
| 798 | } | ||
| 799 | |||
| 800 | ofb->fb.fix.line_length = var->xres_virtual * bpp / 8; | ||
| 801 | |||
| 802 | size = PAGE_ALIGN(ofb->fb.fix.line_length * var->yres_virtual); | ||
| 803 | |||
| 804 | /* don't re-allocate if the original video memory is enough */ | ||
| 805 | if (ofb->video_mem) { | ||
| 806 | if (ofb->video_mem_size >= size) | ||
| 807 | return 0; | ||
| 808 | |||
| 809 | free_pages_exact(ofb->video_mem, ofb->video_mem_size); | ||
| 810 | } | ||
| 811 | |||
| 812 | ofb->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); | ||
| 813 | if (ofb->video_mem == NULL) | ||
| 814 | return -ENOMEM; | ||
| 815 | |||
| 816 | ofb->video_mem_phys = virt_to_phys(ofb->video_mem); | ||
| 817 | ofb->video_mem_size = size; | ||
| 818 | |||
| 819 | ofb->fb.fix.smem_start = ofb->video_mem_phys; | ||
| 820 | ofb->fb.fix.smem_len = ofb->fb.fix.line_length * var->yres_virtual; | ||
| 821 | ofb->fb.screen_base = ofb->video_mem; | ||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | |||
| 825 | static int overlayfb_set_par(struct fb_info *info) | ||
| 826 | { | ||
| 827 | struct pxafb_layer *ofb = (struct pxafb_layer *)info; | ||
| 828 | struct fb_var_screeninfo *var = &info->var; | ||
| 829 | int xpos, ypos, pfor, bpp, ret; | ||
| 830 | |||
| 831 | ret = overlayfb_map_video_memory(ofb); | ||
| 832 | if (ret) | ||
| 833 | return ret; | ||
| 834 | |||
| 835 | bpp = pxafb_var_to_bpp(var); | ||
| 836 | xpos = NONSTD_TO_XPOS(var->nonstd); | ||
| 837 | ypos = NONSTD_TO_XPOS(var->nonstd); | ||
| 838 | pfor = NONSTD_TO_PFOR(var->nonstd); | ||
| 839 | |||
| 840 | ofb->control[0] = OVLxC1_PPL(var->xres) | OVLxC1_LPO(var->yres) | | ||
| 841 | OVLxC1_BPP(bpp); | ||
| 842 | ofb->control[1] = OVLxC2_XPOS(xpos) | OVLxC2_YPOS(ypos); | ||
| 843 | |||
| 844 | if (ofb->id == OVERLAY2) | ||
| 845 | ofb->control[1] |= OVL2C2_PFOR(pfor); | ||
| 846 | |||
| 847 | ofb->ops->setup(ofb); | ||
| 848 | ofb->ops->enable(ofb); | ||
| 849 | return 0; | ||
| 850 | } | ||
| 851 | |||
| 852 | static struct fb_ops overlay_fb_ops = { | ||
| 853 | .owner = THIS_MODULE, | ||
| 854 | .fb_open = overlayfb_open, | ||
| 855 | .fb_release = overlayfb_release, | ||
| 856 | .fb_check_var = overlayfb_check_var, | ||
| 857 | .fb_set_par = overlayfb_set_par, | ||
| 858 | }; | ||
| 859 | |||
| 860 | static void __devinit init_pxafb_overlay(struct pxafb_info *fbi, | ||
| 861 | struct pxafb_layer *ofb, int id) | ||
| 862 | { | ||
| 863 | sprintf(ofb->fb.fix.id, "overlay%d", id + 1); | ||
| 864 | |||
| 865 | ofb->fb.fix.type = FB_TYPE_PACKED_PIXELS; | ||
| 866 | ofb->fb.fix.xpanstep = 0; | ||
| 867 | ofb->fb.fix.ypanstep = 1; | ||
| 868 | |||
| 869 | ofb->fb.var.activate = FB_ACTIVATE_NOW; | ||
| 870 | ofb->fb.var.height = -1; | ||
| 871 | ofb->fb.var.width = -1; | ||
| 872 | ofb->fb.var.vmode = FB_VMODE_NONINTERLACED; | ||
| 873 | |||
| 874 | ofb->fb.fbops = &overlay_fb_ops; | ||
| 875 | ofb->fb.flags = FBINFO_FLAG_DEFAULT; | ||
| 876 | ofb->fb.node = -1; | ||
| 877 | ofb->fb.pseudo_palette = NULL; | ||
| 878 | |||
| 879 | ofb->id = id; | ||
| 880 | ofb->ops = &ofb_ops[id]; | ||
| 881 | atomic_set(&ofb->usage, 0); | ||
| 882 | ofb->fbi = fbi; | ||
| 883 | init_completion(&ofb->branch_done); | ||
| 884 | } | ||
| 885 | |||
| 886 | static int __devinit pxafb_overlay_init(struct pxafb_info *fbi) | ||
| 887 | { | ||
| 888 | int i, ret; | ||
| 889 | |||
| 890 | for (i = 0; i < 2; i++) { | ||
| 891 | init_pxafb_overlay(fbi, &fbi->overlay[i], i); | ||
| 892 | ret = register_framebuffer(&fbi->overlay[i].fb); | ||
| 893 | if (ret) { | ||
| 894 | dev_err(fbi->dev, "failed to register overlay %d\n", i); | ||
| 895 | return ret; | ||
| 896 | } | ||
| 897 | } | ||
| 898 | |||
| 899 | /* mask all IU/BS/EOF/SOF interrupts */ | ||
| 900 | lcd_writel(fbi, LCCR5, ~0); | ||
| 901 | |||
| 902 | /* place overlay(s) on top of base */ | ||
| 903 | fbi->lccr0 |= LCCR0_OUC; | ||
| 904 | pr_info("PXA Overlay driver loaded successfully!\n"); | ||
| 905 | return 0; | ||
| 906 | } | ||
| 907 | |||
| 908 | static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi) | ||
| 909 | { | ||
| 910 | int i; | ||
| 911 | |||
| 912 | for (i = 0; i < 2; i++) | ||
| 913 | unregister_framebuffer(&fbi->overlay[i].fb); | ||
| 914 | } | ||
| 915 | #else | ||
| 916 | static inline void pxafb_overlay_init(struct pxafb_info *fbi) {} | ||
| 917 | static inline void pxafb_overlay_exit(struct pxafb_info *fbi) {} | ||
| 918 | #endif /* CONFIG_FB_PXA_OVERLAY */ | ||
| 919 | |||
| 584 | /* | 920 | /* |
| 585 | * Calculate the PCD value from the clock rate (in picoseconds). | 921 | * Calculate the PCD value from the clock rate (in picoseconds). |
| 586 | * We take account of the PPCR clock setting. | 922 | * We take account of the PPCR clock setting. |
| @@ -660,7 +996,7 @@ unsigned long pxafb_get_hsync_time(struct device *dev) | |||
| 660 | EXPORT_SYMBOL(pxafb_get_hsync_time); | 996 | EXPORT_SYMBOL(pxafb_get_hsync_time); |
| 661 | 997 | ||
| 662 | static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, | 998 | static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, |
| 663 | unsigned int offset, size_t size) | 999 | unsigned long start, size_t size) |
| 664 | { | 1000 | { |
| 665 | struct pxafb_dma_descriptor *dma_desc, *pal_desc; | 1001 | struct pxafb_dma_descriptor *dma_desc, *pal_desc; |
| 666 | unsigned int dma_desc_off, pal_desc_off; | 1002 | unsigned int dma_desc_off, pal_desc_off; |
| @@ -671,7 +1007,7 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, | |||
| 671 | dma_desc = &fbi->dma_buff->dma_desc[dma]; | 1007 | dma_desc = &fbi->dma_buff->dma_desc[dma]; |
| 672 | dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]); | 1008 | dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]); |
| 673 | 1009 | ||
| 674 | dma_desc->fsadr = fbi->video_mem_phys + offset; | 1010 | dma_desc->fsadr = start; |
| 675 | dma_desc->fidr = 0; | 1011 | dma_desc->fidr = 0; |
| 676 | dma_desc->ldcmd = size; | 1012 | dma_desc->ldcmd = size; |
| 677 | 1013 | ||
| @@ -705,14 +1041,14 @@ static void setup_base_frame(struct pxafb_info *fbi, int branch) | |||
| 705 | { | 1041 | { |
| 706 | struct fb_var_screeninfo *var = &fbi->fb.var; | 1042 | struct fb_var_screeninfo *var = &fbi->fb.var; |
| 707 | struct fb_fix_screeninfo *fix = &fbi->fb.fix; | 1043 | struct fb_fix_screeninfo *fix = &fbi->fb.fix; |
| 708 | unsigned int nbytes, offset; | 1044 | int nbytes, dma, pal, bpp = var->bits_per_pixel; |
| 709 | int dma, pal, bpp = var->bits_per_pixel; | 1045 | unsigned long offset; |
| 710 | 1046 | ||
| 711 | dma = DMA_BASE + (branch ? DMA_MAX : 0); | 1047 | dma = DMA_BASE + (branch ? DMA_MAX : 0); |
| 712 | pal = (bpp >= 16) ? PAL_NONE : PAL_BASE + (branch ? PAL_MAX : 0); | 1048 | pal = (bpp >= 16) ? PAL_NONE : PAL_BASE + (branch ? PAL_MAX : 0); |
| 713 | 1049 | ||
| 714 | nbytes = fix->line_length * var->yres; | 1050 | nbytes = fix->line_length * var->yres; |
| 715 | offset = fix->line_length * var->yoffset; | 1051 | offset = fix->line_length * var->yoffset + fbi->video_mem_phys; |
| 716 | 1052 | ||
| 717 | if (fbi->lccr0 & LCCR0_SDS) { | 1053 | if (fbi->lccr0 & LCCR0_SDS) { |
| 718 | nbytes = nbytes / 2; | 1054 | nbytes = nbytes / 2; |
| @@ -1090,8 +1426,9 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) | |||
| 1090 | static irqreturn_t pxafb_handle_irq(int irq, void *dev_id) | 1426 | static irqreturn_t pxafb_handle_irq(int irq, void *dev_id) |
| 1091 | { | 1427 | { |
| 1092 | struct pxafb_info *fbi = dev_id; | 1428 | struct pxafb_info *fbi = dev_id; |
| 1093 | unsigned int lccr0, lcsr = lcd_readl(fbi, LCSR); | 1429 | unsigned int lccr0, lcsr, lcsr1; |
| 1094 | 1430 | ||
| 1431 | lcsr = lcd_readl(fbi, LCSR); | ||
| 1095 | if (lcsr & LCSR_LDD) { | 1432 | if (lcsr & LCSR_LDD) { |
| 1096 | lccr0 = lcd_readl(fbi, LCCR0); | 1433 | lccr0 = lcd_readl(fbi, LCCR0); |
| 1097 | lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM); | 1434 | lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM); |
| @@ -1102,8 +1439,18 @@ static irqreturn_t pxafb_handle_irq(int irq, void *dev_id) | |||
| 1102 | if (lcsr & LCSR_CMD_INT) | 1439 | if (lcsr & LCSR_CMD_INT) |
| 1103 | complete(&fbi->command_done); | 1440 | complete(&fbi->command_done); |
| 1104 | #endif | 1441 | #endif |
| 1105 | |||
| 1106 | lcd_writel(fbi, LCSR, lcsr); | 1442 | lcd_writel(fbi, LCSR, lcsr); |
| 1443 | |||
| 1444 | #ifdef CONFIG_FB_PXA_OVERLAY | ||
| 1445 | lcsr1 = lcd_readl(fbi, LCSR1); | ||
| 1446 | if (lcsr1 & LCSR1_BS(1)) | ||
| 1447 | complete(&fbi->overlay[0].branch_done); | ||
| 1448 | |||
| 1449 | if (lcsr1 & LCSR1_BS(2)) | ||
| 1450 | complete(&fbi->overlay[1].branch_done); | ||
| 1451 | |||
| 1452 | lcd_writel(fbi, LCSR1, lcsr1); | ||
| 1453 | #endif | ||
| 1107 | return IRQ_HANDLED; | 1454 | return IRQ_HANDLED; |
| 1108 | } | 1455 | } |
| 1109 | 1456 | ||
| @@ -1802,6 +2149,8 @@ static int __devinit pxafb_probe(struct platform_device *dev) | |||
| 1802 | goto failed_free_cmap; | 2149 | goto failed_free_cmap; |
| 1803 | } | 2150 | } |
| 1804 | 2151 | ||
| 2152 | pxafb_overlay_init(fbi); | ||
| 2153 | |||
| 1805 | #ifdef CONFIG_CPU_FREQ | 2154 | #ifdef CONFIG_CPU_FREQ |
| 1806 | fbi->freq_transition.notifier_call = pxafb_freq_transition; | 2155 | fbi->freq_transition.notifier_call = pxafb_freq_transition; |
| 1807 | fbi->freq_policy.notifier_call = pxafb_freq_policy; | 2156 | fbi->freq_policy.notifier_call = pxafb_freq_policy; |
| @@ -1852,6 +2201,7 @@ static int __devexit pxafb_remove(struct platform_device *dev) | |||
| 1852 | 2201 | ||
| 1853 | info = &fbi->fb; | 2202 | info = &fbi->fb; |
| 1854 | 2203 | ||
| 2204 | pxafb_overlay_exit(fbi); | ||
| 1855 | unregister_framebuffer(info); | 2205 | unregister_framebuffer(info); |
| 1856 | 2206 | ||
| 1857 | pxafb_disable_controller(fbi); | 2207 | pxafb_disable_controller(fbi); |
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index ae3cbc1ca64..2353521c5c8 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h | |||
| @@ -64,6 +64,47 @@ struct pxafb_dma_buff { | |||
| 64 | struct pxafb_dma_descriptor dma_desc[DMA_MAX * 2]; | 64 | struct pxafb_dma_descriptor dma_desc[DMA_MAX * 2]; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | enum { | ||
| 68 | OVERLAY1, | ||
| 69 | OVERLAY2, | ||
| 70 | }; | ||
| 71 | |||
| 72 | enum { | ||
| 73 | OVERLAY_FORMAT_RGB = 0, | ||
| 74 | OVERLAY_FORMAT_YUV444_PACKED, | ||
| 75 | OVERLAY_FORMAT_YUV444_PLANAR, | ||
| 76 | OVERLAY_FORMAT_YUV422_PLANAR, | ||
| 77 | OVERLAY_FORMAT_YUV420_PLANAR, | ||
| 78 | }; | ||
| 79 | |||
| 80 | #define NONSTD_TO_XPOS(x) (((x) >> 0) & 0x3ff) | ||
| 81 | #define NONSTD_TO_YPOS(x) (((x) >> 10) & 0x3ff) | ||
| 82 | #define NONSTD_TO_PFOR(x) (((x) >> 20) & 0x7) | ||
| 83 | |||
| 84 | struct pxafb_layer; | ||
| 85 | |||
| 86 | struct pxafb_layer_ops { | ||
| 87 | void (*enable)(struct pxafb_layer *); | ||
| 88 | void (*disable)(struct pxafb_layer *); | ||
| 89 | void (*setup)(struct pxafb_layer *); | ||
| 90 | }; | ||
| 91 | |||
| 92 | struct pxafb_layer { | ||
| 93 | struct fb_info fb; | ||
| 94 | int id; | ||
| 95 | atomic_t usage; | ||
| 96 | uint32_t control[2]; | ||
| 97 | |||
| 98 | struct pxafb_layer_ops *ops; | ||
| 99 | |||
| 100 | void __iomem *video_mem; | ||
| 101 | unsigned long video_mem_phys; | ||
| 102 | size_t video_mem_size; | ||
| 103 | struct completion branch_done; | ||
| 104 | |||
| 105 | struct pxafb_info *fbi; | ||
| 106 | }; | ||
| 107 | |||
| 67 | struct pxafb_info { | 108 | struct pxafb_info { |
| 68 | struct fb_info fb; | 109 | struct fb_info fb; |
| 69 | struct device *dev; | 110 | struct device *dev; |
| @@ -114,6 +155,10 @@ struct pxafb_info { | |||
| 114 | struct task_struct *smart_thread; | 155 | struct task_struct *smart_thread; |
| 115 | #endif | 156 | #endif |
| 116 | 157 | ||
| 158 | #ifdef CONFIG_FB_PXA_OVERLAY | ||
| 159 | struct pxafb_layer overlay[2]; | ||
| 160 | #endif | ||
| 161 | |||
| 117 | #ifdef CONFIG_CPU_FREQ | 162 | #ifdef CONFIG_CPU_FREQ |
| 118 | struct notifier_block freq_transition; | 163 | struct notifier_block freq_transition; |
| 119 | struct notifier_block freq_policy; | 164 | struct notifier_block freq_policy; |
