162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for 362306a36Sopenharmony_ci * interleaved bitplanes à la Atari (4 462306a36Sopenharmony_ci * planes, 2 bytes interleave) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Created 5 Apr 1997 by Geert Uytterhoeven 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 962306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 1062306a36Sopenharmony_ci * more details. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/fb.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/setup.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "atafb.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define BPL 4 2162306a36Sopenharmony_ci#include "atafb_utils.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_civoid atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, 2462306a36Sopenharmony_ci int sy, int sx, int dy, int dx, 2562306a36Sopenharmony_ci int height, int width) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci /* bmove() has to distinguish two major cases: If both, source and 2862306a36Sopenharmony_ci * destination, start at even addresses or both are at odd 2962306a36Sopenharmony_ci * addresses, just the first odd and last even column (if present) 3062306a36Sopenharmony_ci * require special treatment (memmove_col()). The rest between 3162306a36Sopenharmony_ci * then can be copied by normal operations, because all adjacent 3262306a36Sopenharmony_ci * bytes are affected and are to be stored in the same order. 3362306a36Sopenharmony_ci * The pathological case is when the move should go from an odd 3462306a36Sopenharmony_ci * address to an even or vice versa. Since the bytes in the plane 3562306a36Sopenharmony_ci * words must be assembled in new order, it seems wisest to make 3662306a36Sopenharmony_ci * all movements by memmove_col(). 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci u8 *src, *dst; 4062306a36Sopenharmony_ci u32 *s, *d; 4162306a36Sopenharmony_ci int w, l , i, j; 4262306a36Sopenharmony_ci u_int colsize; 4362306a36Sopenharmony_ci u_int upwards = (dy < sy) || (dy == sy && dx < sx); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci colsize = height; 4662306a36Sopenharmony_ci if (!((sx ^ dx) & 15)) { 4762306a36Sopenharmony_ci /* odd->odd or even->even */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (upwards) { 5062306a36Sopenharmony_ci src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); 5162306a36Sopenharmony_ci dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); 5262306a36Sopenharmony_ci if (sx & 15) { 5362306a36Sopenharmony_ci memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); 5462306a36Sopenharmony_ci src += BPL * 2; 5562306a36Sopenharmony_ci dst += BPL * 2; 5662306a36Sopenharmony_ci width -= 8; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci w = width >> 4; 5962306a36Sopenharmony_ci if (w) { 6062306a36Sopenharmony_ci s = (u32 *)src; 6162306a36Sopenharmony_ci d = (u32 *)dst; 6262306a36Sopenharmony_ci w *= BPL / 2; 6362306a36Sopenharmony_ci l = next_line - w * 4; 6462306a36Sopenharmony_ci for (j = height; j > 0; j--) { 6562306a36Sopenharmony_ci for (i = w; i > 0; i--) 6662306a36Sopenharmony_ci *d++ = *s++; 6762306a36Sopenharmony_ci s = (u32 *)((u8 *)s + l); 6862306a36Sopenharmony_ci d = (u32 *)((u8 *)d + l); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci if (width & 15) 7262306a36Sopenharmony_ci memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), 7362306a36Sopenharmony_ci 0xff00ff00, height, next_line - BPL * 2); 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); 7662306a36Sopenharmony_ci dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if ((sx + width) & 15) { 7962306a36Sopenharmony_ci src -= BPL * 2; 8062306a36Sopenharmony_ci dst -= BPL * 2; 8162306a36Sopenharmony_ci memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); 8262306a36Sopenharmony_ci width -= 8; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci w = width >> 4; 8562306a36Sopenharmony_ci if (w) { 8662306a36Sopenharmony_ci s = (u32 *)src; 8762306a36Sopenharmony_ci d = (u32 *)dst; 8862306a36Sopenharmony_ci w *= BPL / 2; 8962306a36Sopenharmony_ci l = next_line - w * 4; 9062306a36Sopenharmony_ci for (j = height; j > 0; j--) { 9162306a36Sopenharmony_ci for (i = w; i > 0; i--) 9262306a36Sopenharmony_ci *--d = *--s; 9362306a36Sopenharmony_ci s = (u32 *)((u8 *)s - l); 9462306a36Sopenharmony_ci d = (u32 *)((u8 *)d - l); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci if (sx & 15) 9862306a36Sopenharmony_ci memmove32_col(dst - (width - 16) / (8 / BPL), 9962306a36Sopenharmony_ci src - (width - 16) / (8 / BPL), 10062306a36Sopenharmony_ci 0xff00ff, colsize, -next_line - BPL * 2); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci /* odd->even or even->odd */ 10462306a36Sopenharmony_ci if (upwards) { 10562306a36Sopenharmony_ci u32 *src32, *dst32; 10662306a36Sopenharmony_ci u32 pval[4], v, v1, mask; 10762306a36Sopenharmony_ci int i, j, w, f; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); 11062306a36Sopenharmony_ci dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mask = 0xff00ff00; 11362306a36Sopenharmony_ci f = 0; 11462306a36Sopenharmony_ci w = width; 11562306a36Sopenharmony_ci if (sx & 15) { 11662306a36Sopenharmony_ci f = 1; 11762306a36Sopenharmony_ci w += 8; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci if ((sx + width) & 15) 12062306a36Sopenharmony_ci f |= 2; 12162306a36Sopenharmony_ci w >>= 4; 12262306a36Sopenharmony_ci for (i = height; i; i--) { 12362306a36Sopenharmony_ci src32 = (u32 *)src; 12462306a36Sopenharmony_ci dst32 = (u32 *)dst; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (f & 1) { 12762306a36Sopenharmony_ci pval[0] = (*src32++ << 8) & mask; 12862306a36Sopenharmony_ci pval[1] = (*src32++ << 8) & mask; 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci pval[0] = dst32[0] & mask; 13162306a36Sopenharmony_ci pval[1] = dst32[1] & mask; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci for (j = w; j > 0; j--) { 13562306a36Sopenharmony_ci v = *src32++; 13662306a36Sopenharmony_ci v1 = v & mask; 13762306a36Sopenharmony_ci *dst32++ = pval[0] | (v1 >> 8); 13862306a36Sopenharmony_ci pval[0] = (v ^ v1) << 8; 13962306a36Sopenharmony_ci v = *src32++; 14062306a36Sopenharmony_ci v1 = v & mask; 14162306a36Sopenharmony_ci *dst32++ = pval[1] | (v1 >> 8); 14262306a36Sopenharmony_ci pval[1] = (v ^ v1) << 8; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (f & 2) { 14662306a36Sopenharmony_ci dst32[0] = (dst32[0] & mask) | pval[0]; 14762306a36Sopenharmony_ci dst32[1] = (dst32[1] & mask) | pval[1]; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci src += next_line; 15162306a36Sopenharmony_ci dst += next_line; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci } else { 15462306a36Sopenharmony_ci u32 *src32, *dst32; 15562306a36Sopenharmony_ci u32 pval[4], v, v1, mask; 15662306a36Sopenharmony_ci int i, j, w, f; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); 15962306a36Sopenharmony_ci dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci mask = 0xff00ff; 16262306a36Sopenharmony_ci f = 0; 16362306a36Sopenharmony_ci w = width; 16462306a36Sopenharmony_ci if ((dx + width) & 15) 16562306a36Sopenharmony_ci f = 1; 16662306a36Sopenharmony_ci if (sx & 15) { 16762306a36Sopenharmony_ci f |= 2; 16862306a36Sopenharmony_ci w += 8; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci w >>= 4; 17162306a36Sopenharmony_ci for (i = height; i; i--) { 17262306a36Sopenharmony_ci src32 = (u32 *)src; 17362306a36Sopenharmony_ci dst32 = (u32 *)dst; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (f & 1) { 17662306a36Sopenharmony_ci pval[0] = dst32[-1] & mask; 17762306a36Sopenharmony_ci pval[1] = dst32[-2] & mask; 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci pval[0] = (*--src32 >> 8) & mask; 18062306a36Sopenharmony_ci pval[1] = (*--src32 >> 8) & mask; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci for (j = w; j > 0; j--) { 18462306a36Sopenharmony_ci v = *--src32; 18562306a36Sopenharmony_ci v1 = v & mask; 18662306a36Sopenharmony_ci *--dst32 = pval[0] | (v1 << 8); 18762306a36Sopenharmony_ci pval[0] = (v ^ v1) >> 8; 18862306a36Sopenharmony_ci v = *--src32; 18962306a36Sopenharmony_ci v1 = v & mask; 19062306a36Sopenharmony_ci *--dst32 = pval[1] | (v1 << 8); 19162306a36Sopenharmony_ci pval[1] = (v ^ v1) >> 8; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!(f & 2)) { 19562306a36Sopenharmony_ci dst32[-1] = (dst32[-1] & mask) | pval[0]; 19662306a36Sopenharmony_ci dst32[-2] = (dst32[-2] & mask) | pval[1]; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci src -= next_line; 20062306a36Sopenharmony_ci dst -= next_line; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_civoid atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color, 20762306a36Sopenharmony_ci int sy, int sx, int height, int width) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci u32 *dest; 21062306a36Sopenharmony_ci int rows, i; 21162306a36Sopenharmony_ci u32 cval[4]; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); 21462306a36Sopenharmony_ci if (sx & 15) { 21562306a36Sopenharmony_ci u8 *dest8 = (u8 *)dest + 1; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci expand8_col2mask(color, cval); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci for (i = height; i; i--) { 22062306a36Sopenharmony_ci fill8_col(dest8, cval); 22162306a36Sopenharmony_ci dest8 += next_line; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci dest += BPL / 2; 22462306a36Sopenharmony_ci width -= 8; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci expand16_col2mask(color, cval); 22862306a36Sopenharmony_ci rows = width >> 4; 22962306a36Sopenharmony_ci if (rows) { 23062306a36Sopenharmony_ci u32 *d = dest; 23162306a36Sopenharmony_ci u32 off = next_line - rows * BPL * 2; 23262306a36Sopenharmony_ci for (i = height; i; i--) { 23362306a36Sopenharmony_ci d = fill16_col(d, rows, cval); 23462306a36Sopenharmony_ci d = (u32 *)((long)d + off); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci dest += rows * BPL / 2; 23762306a36Sopenharmony_ci width &= 15; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (width) { 24162306a36Sopenharmony_ci u8 *dest8 = (u8 *)dest; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci expand8_col2mask(color, cval); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci for (i = height; i; i--) { 24662306a36Sopenharmony_ci fill8_col(dest8, cval); 24762306a36Sopenharmony_ci dest8 += next_line; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_civoid atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line, 25362306a36Sopenharmony_ci int dy, int dx, u32 width, 25462306a36Sopenharmony_ci const u8 *data, u32 bgcolor, u32 fgcolor) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci u32 *dest; 25762306a36Sopenharmony_ci const u16 *data16; 25862306a36Sopenharmony_ci int rows; 25962306a36Sopenharmony_ci u32 fgm[4], bgm[4], m; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); 26262306a36Sopenharmony_ci if (dx & 15) { 26362306a36Sopenharmony_ci fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); 26462306a36Sopenharmony_ci dest += BPL / 2; 26562306a36Sopenharmony_ci width -= 8; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (width >= 16) { 26962306a36Sopenharmony_ci data16 = (const u16 *)data; 27062306a36Sopenharmony_ci expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci for (rows = width / 16; rows; rows--) { 27362306a36Sopenharmony_ci u16 d = *data16++; 27462306a36Sopenharmony_ci m = d | ((u32)d << 16); 27562306a36Sopenharmony_ci *dest++ = (m & fgm[0]) ^ bgm[0]; 27662306a36Sopenharmony_ci *dest++ = (m & fgm[1]) ^ bgm[1]; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci data = (const u8 *)data16; 28062306a36Sopenharmony_ci width &= 15; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (width) 28462306a36Sopenharmony_ci fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); 28562306a36Sopenharmony_ci} 286