diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2007-10-16 01:28:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 09:43:14 -0700 |
commit | e7f76df9648ccd69a99fe6bc7d774dc05922f2f0 (patch) | |
tree | 6ec2d9ad3aeef81b0a89f2eb8f8c63414582d8db /drivers/video/pm3fb.c | |
parent | 0a0b53f66043b4f4da728b391232de5e5d22f145 (diff) |
pm3fb: copyarea and partial imageblit suppor
This patch adds accelerated copyarea and partially accelerated imageblit
functions. There is also fixed one register address in the pm3fb.h file.
Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Antonino Daplas <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/pm3fb.c')
-rw-r--r-- | drivers/video/pm3fb.c | 180 |
1 files changed, 169 insertions, 11 deletions
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 5b3f54c0918e..438872a5f43f 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -276,15 +276,22 @@ static void pm3fb_init_engine(struct fb_info *info) PM3_WAIT(par, 2); { - unsigned long rm = 1; + /* invert bits in bitmask */ + unsigned long rm = 1 | (3 << 7); switch (info->var.bits_per_pixel) { case 8: PM3_WRITE_REG(par, PM3PixelSize, PM3PixelSize_GLOBAL_8BIT); +#ifdef __BIG_ENDIAN + rm |= 3 << 15; +#endif break; case 16: PM3_WRITE_REG(par, PM3PixelSize, PM3PixelSize_GLOBAL_16BIT); +#ifdef __BIG_ENDIAN + rm |= 2 << 15; +#endif break; case 32: PM3_WRITE_REG(par, PM3PixelSize, @@ -394,18 +401,18 @@ static void pm3fb_fillrect (struct fb_info *info, color |= color << 16; PM3_WAIT(par, 4); - + /* ROP Ox3 is GXcopy */ PM3_WRITE_REG(par, PM3Config2D, - PM3Config2D_UseConstantSource | - PM3Config2D_ForegroundROPEnable | - (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ - PM3Config2D_FBWriteEnable); + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | + PM3Config2D_FBWriteEnable); PM3_WRITE_REG(par, PM3ForegroundColor, color); PM3_WRITE_REG(par, PM3RectanglePosition, - (PM3RectanglePosition_XOffset(modded.dx)) | - (PM3RectanglePosition_YOffset(modded.dy))); + (PM3RectanglePosition_XOffset(modded.dx)) | + (PM3RectanglePosition_YOffset(modded.dy))); PM3_WRITE_REG(par, PM3Render2D, PM3Render2D_XPositive | @@ -415,6 +422,154 @@ static void pm3fb_fillrect (struct fb_info *info, (PM3Render2D_Width(modded.width)) | (PM3Render2D_Height(modded.height))); } + +static void pm3fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct pm3_par *par = info->par; + struct fb_copyarea modded; + u32 vxres, vyres; + int x_align, o_x, o_y; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_copyarea(info, area); + return; + } + + memcpy(&modded, area, sizeof(struct fb_copyarea)); + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if(!modded.width || !modded.height || + modded.sx >= vxres || modded.sy >= vyres || + modded.dx >= vxres || modded.dy >= vyres) + return; + + if(modded.sx + modded.width > vxres) + modded.width = vxres - modded.sx; + if(modded.dx + modded.width > vxres) + modded.width = vxres - modded.dx; + if(modded.sy + modded.height > vyres) + modded.height = vyres - modded.sy; + if(modded.dy + modded.height > vyres) + modded.height = vyres - modded.dy; + + o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ + o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ + + x_align = (modded.sx & 0x1f); + + PM3_WAIT(par, 6); + + PM3_WRITE_REG(par, PM3Config2D, + PM3Config2D_UserScissorEnable | + PM3Config2D_ForegroundROPEnable | + PM3Config2D_Blocking | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(par, PM3ScissorMinXY, + ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff)); + PM3_WRITE_REG(par, PM3ScissorMaxXY, + (((modded.dy + modded.height) & 0x0fff) << 16) | + ((modded.dx + modded.width) & 0x0fff)); + + PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, + PM3FBSourceReadBufferOffset_XOffset(o_x) | + PM3FBSourceReadBufferOffset_YOffset(o_y)); + + PM3_WRITE_REG(par, PM3RectanglePosition, + (PM3RectanglePosition_XOffset(modded.dx - x_align)) | + (PM3RectanglePosition_YOffset(modded.dy))); + + PM3_WRITE_REG(par, PM3Render2D, + ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) | + ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + PM3Render2D_FBSourceReadEnable | + (PM3Render2D_Width(modded.width + x_align)) | + (PM3Render2D_Height(modded.height))); +} + +static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct pm3_par *par = info->par; + u32 height = image->height; + u32 fgx, bgx; + const u32 *src = (const u32*)image->data; + + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + fgx = image->fg_color; + bgx = image->bg_color; + break; + case FB_VISUAL_TRUECOLOR: + default: + fgx = par->palette[image->fg_color]; + bgx = par->palette[image->bg_color]; + break; + } + if (image->depth != 1 || (image->width & 0x1f)) { + return cfb_imageblit(info, image); + } + if (info->var.bits_per_pixel == 8) { + fgx |= fgx << 8; + bgx |= bgx << 8; + } + if (info->var.bits_per_pixel <= 16) { + fgx |= fgx << 16; + bgx |= bgx << 16; + } + + PM3_WAIT(par, 5); + + PM3_WRITE_REG(par, PM3ForegroundColor, fgx); + PM3_WRITE_REG(par, PM3BackgroundColor, bgx); + + /* ROP Ox3 is GXcopy */ + PM3_WRITE_REG(par, PM3Config2D, + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | + PM3Config2D_OpaqueSpan | + PM3Config2D_FBWriteEnable); + PM3_WRITE_REG(par, PM3RectanglePosition, + (PM3RectanglePosition_XOffset(image->dx)) | + (PM3RectanglePosition_YOffset(image->dy))); + PM3_WRITE_REG(par, PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_SyncOnBitMask | + PM3Render2D_SpanOperation | + (PM3Render2D_Width(image->width)) | + (PM3Render2D_Height(image->height))); + + + while (height--) { + u32 width = (image->width + 31) >> 5; + + while (width >= PM3_FIFO_SIZE) { + int i = PM3_FIFO_SIZE - 1; + + PM3_WAIT(par, PM3_FIFO_SIZE); + while (i--) { + PM3_WRITE_REG(par, PM3BitMaskPattern, *src); + src++; + } + width -= PM3_FIFO_SIZE - 1; + } + + PM3_WAIT(par, width + 1); + while (width--) { + PM3_WRITE_REG(par, PM3BitMaskPattern, *src); + src++; + } + } +} /* end of acceleration functions */ /* write the mode to registers */ @@ -907,8 +1062,8 @@ static struct fb_ops pm3fb_ops = { .fb_setcolreg = pm3fb_setcolreg, .fb_pan_display = pm3fb_pan_display, .fb_fillrect = pm3fb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_copyarea = pm3fb_copyarea, + .fb_imageblit = pm3fb_imageblit, .fb_blank = pm3fb_blank, .fb_sync = pm3fb_sync, }; @@ -1080,7 +1235,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, info->fix = pm3fb_fix; info->pseudo_palette = par->palette; info->flags = FBINFO_DEFAULT | - FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/ +/* FBINFO_HWACCEL_YPAN |*/ + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_FILLRECT; /* * This should give a reasonable default video mode. The following is |