Revision c1230df7e19e0f27655c0eb9d966c7e03be7cc50 authored by Paulo Zanoni on 03 May 2012, 01:55:43 UTC, committed by Daniel Vetter on 03 May 2012, 13:55:38 UTC
While testing with the intel_infoframes tool on gen4, I see that when video DIP is disabled, what we write to the DATA memory is not exactly what we read back later. This regression has been introduce in commit 64a8fc0145a1d0fdc25fc9367c2e6c621955fb3b Author: Jesse Barnes <jbarnes@virtuousgeek.org> Date: Thu Sep 22 11:16:00 2011 +0530 drm/i915: fix ILK+ infoframe support That commit was setting VIDEO_DIP_CTL to 0 when initializing, which caused the problem. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43947 Cc: stable@kernel.org Tested-by: Yang Guang <guang.a.yang@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com> [danvet: Pimped commit message by using the usual commit citation layout.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent 6200497
cfbcopyarea.c
/*
* Generic function for frame buffer with packed pixels of any depth.
*
* Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* NOTES:
*
* This is for cfb packed pixels. Iplan and such are incorporated in the
* drivers that need them.
*
* FIXME
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
*
* The two functions or copying forward and backward could be split up like
* the ones for filling, i.e. in aligned and unaligned versions. This would
* help moving some redundant computations and branches out of the loop, too.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/types.h>
#include <asm/io.h>
#include "fb_draw.h"
#if BITS_PER_LONG == 32
# define FB_WRITEL fb_writel
# define FB_READL fb_readl
#else
# define FB_WRITEL fb_writeq
# define FB_READL fb_readq
#endif
/*
* Generic bitwise copy algorithm
*/
static void
bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
const unsigned long __iomem *src, int src_idx, int bits,
unsigned n, u32 bswapmask)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
int left, right;
first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
if (!shift) {
// Same alignment for source and dest
if (dst_idx+n <= bits) {
// Single word
if (last)
first &= last;
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
} else {
// Multiple destination words
// Leading bits
if (first != ~0UL) {
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
dst++;
src++;
n -= bits - dst_idx;
}
// Main chunk
n /= bits;
while (n >= 8) {
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
n -= 8;
}
while (n--)
FB_WRITEL(FB_READL(src++), dst++);
// Trailing bits
if (last)
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
}
} else {
/* Different alignment for source and dest */
unsigned long d0, d1;
int m;
right = shift & (bits - 1);
left = -shift & (bits - 1);
bswapmask &= shift;
if (dst_idx+n <= bits) {
// Single destination word
if (last)
first &= last;
d0 = FB_READL(src);
d0 = fb_rev_pixels_in_long(d0, bswapmask);
if (shift > 0) {
// Single source word
d0 >>= right;
} else if (src_idx+n <= bits) {
// Single source word
d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src + 1);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0<<left | d1>>right;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
} else {
// Multiple destination words
/** We must always remember the last value read, because in case
SRC and DST overlap bitwise (e.g. when moving just one pixel in
1bpp), we always collect one full long for DST and that might
overlap with the current long from SRC. We store this value in
'd0'. */
d0 = FB_READL(src++);
d0 = fb_rev_pixels_in_long(d0, bswapmask);
// Leading bits
if (shift > 0) {
// Single source word
d1 = d0;
d0 >>= right;
dst++;
n -= bits - dst_idx;
} else {
// 2 source words
d1 = FB_READL(src++);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0<<left | d1>>right;
dst++;
n -= bits - dst_idx;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
d0 = d1;
// Main chunk
m = n % bits;
n /= bits;
while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
n -= 4;
}
while (n--) {
d1 = FB_READL(src++);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0 << left | d1 >> right;
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(d0, dst++);
d0 = d1;
}
// Trailing bits
if (last) {
if (m <= right) {
// Single source word
d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src);
d1 = fb_rev_pixels_in_long(d1,
bswapmask);
d0 = d0<<left | d1>>right;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
}
}
}
}
/*
* Generic bitwise copy algorithm, operating backward
*/
static void
bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
const unsigned long __iomem *src, int src_idx, int bits,
unsigned n, u32 bswapmask)
{
unsigned long first, last;
int shift;
dst += (n-1)/bits;
src += (n-1)/bits;
if ((n-1) % bits) {
dst_idx += (n-1) % bits;
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= bits - 1;
src_idx += (n-1) % bits;
src += src_idx >> (ffs(bits) - 1);
src_idx &= bits - 1;
}
shift = dst_idx-src_idx;
first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
bswapmask);
if (!shift) {
// Same alignment for source and dest
if ((unsigned long)dst_idx+1 >= n) {
// Single word
if (last)
first &= last;
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
} else {
// Multiple destination words
// Leading bits
if (first != ~0UL) {
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
dst--;
src--;
n -= dst_idx+1;
}
// Main chunk
n /= bits;
while (n >= 8) {
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
n -= 8;
}
while (n--)
FB_WRITEL(FB_READL(src--), dst--);
// Trailing bits
if (last)
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
}
} else {
// Different alignment for source and dest
unsigned long d0, d1;
int m;
int const left = -shift & (bits-1);
int const right = shift & (bits-1);
bswapmask &= shift;
if ((unsigned long)dst_idx+1 >= n) {
// Single destination word
if (last)
first &= last;
d0 = FB_READL(src);
if (shift < 0) {
// Single source word
d0 <<= left;
} else if (1+(unsigned long)src_idx >= n) {
// Single source word
d0 >>= right;
} else {
// 2 source words
d1 = FB_READL(src - 1);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0>>right | d1<<left;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
} else {
// Multiple destination words
/** We must always remember the last value read, because in case
SRC and DST overlap bitwise (e.g. when moving just one pixel in
1bpp), we always collect one full long for DST and that might
overlap with the current long from SRC. We store this value in
'd0'. */
d0 = FB_READL(src--);
d0 = fb_rev_pixels_in_long(d0, bswapmask);
// Leading bits
if (shift < 0) {
// Single source word
d1 = d0;
d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src--);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0>>right | d1<<left;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
d0 = d1;
dst--;
n -= dst_idx+1;
// Main chunk
m = n % bits;
n /= bits;
while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
n -= 4;
}
while (n--) {
d1 = FB_READL(src--);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
d0 = d0 >> right | d1 << left;
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(d0, dst--);
d0 = d1;
}
// Trailing bits
if (last) {
if (m <= left) {
// Single source word
d0 >>= right;
} else {
// 2 source words
d1 = FB_READL(src);
d1 = fb_rev_pixels_in_long(d1,
bswapmask);
d0 = d0>>right | d1<<left;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
}
}
}
}
void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
u32 height = area->height, width = area->width;
unsigned long const bits_per_line = p->fix.line_length*8u;
unsigned long __iomem *dst = NULL, *src = NULL;
int bits = BITS_PER_LONG, bytes = bits >> 3;
int dst_idx = 0, src_idx = 0, rev_copy = 0;
u32 bswapmask = fb_compute_bswapmask(p);
if (p->state != FBINFO_STATE_RUNNING)
return;
/* if the beginning of the target area might overlap with the end of
the source area, be have to copy the area reverse. */
if ((dy == sy && dx > sx) || (dy > sy)) {
dy += height;
sy += height;
rev_copy = 1;
}
// split the base of the framebuffer into a long-aligned address and the
// index of the first bit
dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
// add offset of source and target area
dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
if (p->fbops->fb_sync)
p->fbops->fb_sync(p);
if (rev_copy) {
while (height--) {
dst_idx -= bits_per_line;
src_idx -= bits_per_line;
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel, bswapmask);
}
} else {
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel, bswapmask);
dst_idx += bits_per_line;
src_idx += bits_per_line;
}
}
}
EXPORT_SYMBOL(cfb_copyarea);
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("Generic software accelerated copyarea");
MODULE_LICENSE("GPL");
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...