18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for 38c2ecf20Sopenharmony_ci * interleaved bitplanes à la Atari (2 48c2ecf20Sopenharmony_ci * planes, 2 bytes interleave) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Created 5 Apr 1997 by Geert Uytterhoeven 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 98c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 108c2ecf20Sopenharmony_ci * more details. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/fb.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/setup.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "atafb.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define BPL 2 218c2ecf20Sopenharmony_ci#include "atafb_utils.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_civoid atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, 248c2ecf20Sopenharmony_ci int sy, int sx, int dy, int dx, 258c2ecf20Sopenharmony_ci int height, int width) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci /* bmove() has to distinguish two major cases: If both, source and 288c2ecf20Sopenharmony_ci * destination, start at even addresses or both are at odd 298c2ecf20Sopenharmony_ci * addresses, just the first odd and last even column (if present) 308c2ecf20Sopenharmony_ci * require special treatment (memmove_col()). The rest between 318c2ecf20Sopenharmony_ci * then can be copied by normal operations, because all adjacent 328c2ecf20Sopenharmony_ci * bytes are affected and are to be stored in the same order. 338c2ecf20Sopenharmony_ci * The pathological case is when the move should go from an odd 348c2ecf20Sopenharmony_ci * address to an even or vice versa. Since the bytes in the plane 358c2ecf20Sopenharmony_ci * words must be assembled in new order, it seems wisest to make 368c2ecf20Sopenharmony_ci * all movements by memmove_col(). 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci u8 *src, *dst; 408c2ecf20Sopenharmony_ci u32 *s, *d; 418c2ecf20Sopenharmony_ci int w, l , i, j; 428c2ecf20Sopenharmony_ci u_int colsize; 438c2ecf20Sopenharmony_ci u_int upwards = (dy < sy) || (dy == sy && dx < sx); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci colsize = height; 468c2ecf20Sopenharmony_ci if (!((sx ^ dx) & 15)) { 478c2ecf20Sopenharmony_ci /* odd->odd or even->even */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (upwards) { 508c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); 518c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); 528c2ecf20Sopenharmony_ci if (sx & 15) { 538c2ecf20Sopenharmony_ci memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); 548c2ecf20Sopenharmony_ci src += BPL * 2; 558c2ecf20Sopenharmony_ci dst += BPL * 2; 568c2ecf20Sopenharmony_ci width -= 8; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci w = width >> 4; 598c2ecf20Sopenharmony_ci if (w) { 608c2ecf20Sopenharmony_ci s = (u32 *)src; 618c2ecf20Sopenharmony_ci d = (u32 *)dst; 628c2ecf20Sopenharmony_ci w *= BPL / 2; 638c2ecf20Sopenharmony_ci l = next_line - w * 4; 648c2ecf20Sopenharmony_ci for (j = height; j > 0; j--) { 658c2ecf20Sopenharmony_ci for (i = w; i > 0; i--) 668c2ecf20Sopenharmony_ci *d++ = *s++; 678c2ecf20Sopenharmony_ci s = (u32 *)((u8 *)s + l); 688c2ecf20Sopenharmony_ci d = (u32 *)((u8 *)d + l); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci if (width & 15) 728c2ecf20Sopenharmony_ci memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), 738c2ecf20Sopenharmony_ci 0xff00ff00, height, next_line - BPL * 2); 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); 768c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if ((sx + width) & 15) { 798c2ecf20Sopenharmony_ci src -= BPL * 2; 808c2ecf20Sopenharmony_ci dst -= BPL * 2; 818c2ecf20Sopenharmony_ci memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); 828c2ecf20Sopenharmony_ci width -= 8; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci w = width >> 4; 858c2ecf20Sopenharmony_ci if (w) { 868c2ecf20Sopenharmony_ci s = (u32 *)src; 878c2ecf20Sopenharmony_ci d = (u32 *)dst; 888c2ecf20Sopenharmony_ci w *= BPL / 2; 898c2ecf20Sopenharmony_ci l = next_line - w * 4; 908c2ecf20Sopenharmony_ci for (j = height; j > 0; j--) { 918c2ecf20Sopenharmony_ci for (i = w; i > 0; i--) 928c2ecf20Sopenharmony_ci *--d = *--s; 938c2ecf20Sopenharmony_ci s = (u32 *)((u8 *)s - l); 948c2ecf20Sopenharmony_ci d = (u32 *)((u8 *)d - l); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci if (sx & 15) 988c2ecf20Sopenharmony_ci memmove32_col(dst - (width - 16) / (8 / BPL), 998c2ecf20Sopenharmony_ci src - (width - 16) / (8 / BPL), 1008c2ecf20Sopenharmony_ci 0xff00ff, colsize, -next_line - BPL * 2); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci /* odd->even or even->odd */ 1048c2ecf20Sopenharmony_ci if (upwards) { 1058c2ecf20Sopenharmony_ci u32 *src32, *dst32; 1068c2ecf20Sopenharmony_ci u32 pval[4], v, v1, mask; 1078c2ecf20Sopenharmony_ci int i, j, w, f; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); 1108c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci mask = 0xff00ff00; 1138c2ecf20Sopenharmony_ci f = 0; 1148c2ecf20Sopenharmony_ci w = width; 1158c2ecf20Sopenharmony_ci if (sx & 15) { 1168c2ecf20Sopenharmony_ci f = 1; 1178c2ecf20Sopenharmony_ci w += 8; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci if ((sx + width) & 15) 1208c2ecf20Sopenharmony_ci f |= 2; 1218c2ecf20Sopenharmony_ci w >>= 4; 1228c2ecf20Sopenharmony_ci for (i = height; i; i--) { 1238c2ecf20Sopenharmony_ci src32 = (u32 *)src; 1248c2ecf20Sopenharmony_ci dst32 = (u32 *)dst; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (f & 1) { 1278c2ecf20Sopenharmony_ci pval[0] = (*src32++ << 8) & mask; 1288c2ecf20Sopenharmony_ci } else { 1298c2ecf20Sopenharmony_ci pval[0] = dst32[0] & mask; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci for (j = w; j > 0; j--) { 1338c2ecf20Sopenharmony_ci v = *src32++; 1348c2ecf20Sopenharmony_ci v1 = v & mask; 1358c2ecf20Sopenharmony_ci *dst32++ = pval[0] | (v1 >> 8); 1368c2ecf20Sopenharmony_ci pval[0] = (v ^ v1) << 8; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (f & 2) { 1408c2ecf20Sopenharmony_ci dst32[0] = (dst32[0] & mask) | pval[0]; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci src += next_line; 1448c2ecf20Sopenharmony_ci dst += next_line; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci } else { 1478c2ecf20Sopenharmony_ci u32 *src32, *dst32; 1488c2ecf20Sopenharmony_ci u32 pval[4], v, v1, mask; 1498c2ecf20Sopenharmony_ci int i, j, w, f; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); 1528c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci mask = 0xff00ff; 1558c2ecf20Sopenharmony_ci f = 0; 1568c2ecf20Sopenharmony_ci w = width; 1578c2ecf20Sopenharmony_ci if ((dx + width) & 15) 1588c2ecf20Sopenharmony_ci f = 1; 1598c2ecf20Sopenharmony_ci if (sx & 15) { 1608c2ecf20Sopenharmony_ci f |= 2; 1618c2ecf20Sopenharmony_ci w += 8; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci w >>= 4; 1648c2ecf20Sopenharmony_ci for (i = height; i; i--) { 1658c2ecf20Sopenharmony_ci src32 = (u32 *)src; 1668c2ecf20Sopenharmony_ci dst32 = (u32 *)dst; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (f & 1) { 1698c2ecf20Sopenharmony_ci pval[0] = dst32[-1] & mask; 1708c2ecf20Sopenharmony_ci } else { 1718c2ecf20Sopenharmony_ci pval[0] = (*--src32 >> 8) & mask; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci for (j = w; j > 0; j--) { 1758c2ecf20Sopenharmony_ci v = *--src32; 1768c2ecf20Sopenharmony_ci v1 = v & mask; 1778c2ecf20Sopenharmony_ci *--dst32 = pval[0] | (v1 << 8); 1788c2ecf20Sopenharmony_ci pval[0] = (v ^ v1) >> 8; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!(f & 2)) { 1828c2ecf20Sopenharmony_ci dst32[-1] = (dst32[-1] & mask) | pval[0]; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci src -= next_line; 1868c2ecf20Sopenharmony_ci dst -= next_line; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_civoid atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color, 1938c2ecf20Sopenharmony_ci int sy, int sx, int height, int width) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u32 *dest; 1968c2ecf20Sopenharmony_ci int rows, i; 1978c2ecf20Sopenharmony_ci u32 cval[4]; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); 2008c2ecf20Sopenharmony_ci if (sx & 15) { 2018c2ecf20Sopenharmony_ci u8 *dest8 = (u8 *)dest + 1; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci expand8_col2mask(color, cval); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (i = height; i; i--) { 2068c2ecf20Sopenharmony_ci fill8_col(dest8, cval); 2078c2ecf20Sopenharmony_ci dest8 += next_line; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci dest += BPL / 2; 2108c2ecf20Sopenharmony_ci width -= 8; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci expand16_col2mask(color, cval); 2148c2ecf20Sopenharmony_ci rows = width >> 4; 2158c2ecf20Sopenharmony_ci if (rows) { 2168c2ecf20Sopenharmony_ci u32 *d = dest; 2178c2ecf20Sopenharmony_ci u32 off = next_line - rows * BPL * 2; 2188c2ecf20Sopenharmony_ci for (i = height; i; i--) { 2198c2ecf20Sopenharmony_ci d = fill16_col(d, rows, cval); 2208c2ecf20Sopenharmony_ci d = (u32 *)((long)d + off); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci dest += rows * BPL / 2; 2238c2ecf20Sopenharmony_ci width &= 15; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (width) { 2278c2ecf20Sopenharmony_ci u8 *dest8 = (u8 *)dest; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci expand8_col2mask(color, cval); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci for (i = height; i; i--) { 2328c2ecf20Sopenharmony_ci fill8_col(dest8, cval); 2338c2ecf20Sopenharmony_ci dest8 += next_line; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_civoid atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line, 2398c2ecf20Sopenharmony_ci int dy, int dx, u32 width, 2408c2ecf20Sopenharmony_ci const u8 *data, u32 bgcolor, u32 fgcolor) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci u32 *dest; 2438c2ecf20Sopenharmony_ci const u16 *data16; 2448c2ecf20Sopenharmony_ci int rows; 2458c2ecf20Sopenharmony_ci u32 fgm[4], bgm[4], m; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); 2488c2ecf20Sopenharmony_ci if (dx & 15) { 2498c2ecf20Sopenharmony_ci fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); 2508c2ecf20Sopenharmony_ci dest += BPL / 2; 2518c2ecf20Sopenharmony_ci width -= 8; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (width >= 16) { 2558c2ecf20Sopenharmony_ci data16 = (const u16 *)data; 2568c2ecf20Sopenharmony_ci expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci for (rows = width / 16; rows; rows--) { 2598c2ecf20Sopenharmony_ci u16 d = *data16++; 2608c2ecf20Sopenharmony_ci m = d | ((u32)d << 16); 2618c2ecf20Sopenharmony_ci *dest++ = (m & fgm[0]) ^ bgm[0]; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci data = (const u8 *)data16; 2658c2ecf20Sopenharmony_ci width &= 15; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (width) 2698c2ecf20Sopenharmony_ci fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); 2708c2ecf20Sopenharmony_ci} 271