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