18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for 38c2ecf20Sopenharmony_ci * interleaved bitplanes à la Atari (8 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 8 218c2ecf20Sopenharmony_ci#include "atafb_utils.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* Copies a 8 plane column from 's', height 'h', to 'd'. */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* This expands a 8 bit color into two longs for two movepl (8 plane) 278c2ecf20Sopenharmony_ci * operations. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_civoid atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, 318c2ecf20Sopenharmony_ci int sy, int sx, int dy, int dx, 328c2ecf20Sopenharmony_ci int height, int width) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci /* bmove() has to distinguish two major cases: If both, source and 358c2ecf20Sopenharmony_ci * destination, start at even addresses or both are at odd 368c2ecf20Sopenharmony_ci * addresses, just the first odd and last even column (if present) 378c2ecf20Sopenharmony_ci * require special treatment (memmove_col()). The rest between 388c2ecf20Sopenharmony_ci * then can be copied by normal operations, because all adjacent 398c2ecf20Sopenharmony_ci * bytes are affected and are to be stored in the same order. 408c2ecf20Sopenharmony_ci * The pathological case is when the move should go from an odd 418c2ecf20Sopenharmony_ci * address to an even or vice versa. Since the bytes in the plane 428c2ecf20Sopenharmony_ci * words must be assembled in new order, it seems wisest to make 438c2ecf20Sopenharmony_ci * all movements by memmove_col(). 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci u8 *src, *dst; 478c2ecf20Sopenharmony_ci u32 *s, *d; 488c2ecf20Sopenharmony_ci int w, l , i, j; 498c2ecf20Sopenharmony_ci u_int colsize; 508c2ecf20Sopenharmony_ci u_int upwards = (dy < sy) || (dy == sy && dx < sx); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci colsize = height; 538c2ecf20Sopenharmony_ci if (!((sx ^ dx) & 15)) { 548c2ecf20Sopenharmony_ci /* odd->odd or even->even */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (upwards) { 578c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); 588c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); 598c2ecf20Sopenharmony_ci if (sx & 15) { 608c2ecf20Sopenharmony_ci memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); 618c2ecf20Sopenharmony_ci src += BPL * 2; 628c2ecf20Sopenharmony_ci dst += BPL * 2; 638c2ecf20Sopenharmony_ci width -= 8; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci w = width >> 4; 668c2ecf20Sopenharmony_ci if (w) { 678c2ecf20Sopenharmony_ci s = (u32 *)src; 688c2ecf20Sopenharmony_ci d = (u32 *)dst; 698c2ecf20Sopenharmony_ci w *= BPL / 2; 708c2ecf20Sopenharmony_ci l = next_line - w * 4; 718c2ecf20Sopenharmony_ci for (j = height; j > 0; j--) { 728c2ecf20Sopenharmony_ci for (i = w; i > 0; i--) 738c2ecf20Sopenharmony_ci *d++ = *s++; 748c2ecf20Sopenharmony_ci s = (u32 *)((u8 *)s + l); 758c2ecf20Sopenharmony_ci d = (u32 *)((u8 *)d + l); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci if (width & 15) 798c2ecf20Sopenharmony_ci memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), 808c2ecf20Sopenharmony_ci 0xff00ff00, height, next_line - BPL * 2); 818c2ecf20Sopenharmony_ci } else { 828c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); 838c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if ((sx + width) & 15) { 868c2ecf20Sopenharmony_ci src -= BPL * 2; 878c2ecf20Sopenharmony_ci dst -= BPL * 2; 888c2ecf20Sopenharmony_ci memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); 898c2ecf20Sopenharmony_ci width -= 8; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci w = width >> 4; 928c2ecf20Sopenharmony_ci if (w) { 938c2ecf20Sopenharmony_ci s = (u32 *)src; 948c2ecf20Sopenharmony_ci d = (u32 *)dst; 958c2ecf20Sopenharmony_ci w *= BPL / 2; 968c2ecf20Sopenharmony_ci l = next_line - w * 4; 978c2ecf20Sopenharmony_ci for (j = height; j > 0; j--) { 988c2ecf20Sopenharmony_ci for (i = w; i > 0; i--) 998c2ecf20Sopenharmony_ci *--d = *--s; 1008c2ecf20Sopenharmony_ci s = (u32 *)((u8 *)s - l); 1018c2ecf20Sopenharmony_ci d = (u32 *)((u8 *)d - l); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (sx & 15) 1058c2ecf20Sopenharmony_ci memmove32_col(dst - (width - 16) / (8 / BPL), 1068c2ecf20Sopenharmony_ci src - (width - 16) / (8 / BPL), 1078c2ecf20Sopenharmony_ci 0xff00ff, colsize, -next_line - BPL * 2); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci } else { 1108c2ecf20Sopenharmony_ci /* odd->even or even->odd */ 1118c2ecf20Sopenharmony_ci if (upwards) { 1128c2ecf20Sopenharmony_ci u32 *src32, *dst32; 1138c2ecf20Sopenharmony_ci u32 pval[4], v, v1, mask; 1148c2ecf20Sopenharmony_ci int i, j, w, f; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); 1178c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci mask = 0xff00ff00; 1208c2ecf20Sopenharmony_ci f = 0; 1218c2ecf20Sopenharmony_ci w = width; 1228c2ecf20Sopenharmony_ci if (sx & 15) { 1238c2ecf20Sopenharmony_ci f = 1; 1248c2ecf20Sopenharmony_ci w += 8; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if ((sx + width) & 15) 1278c2ecf20Sopenharmony_ci f |= 2; 1288c2ecf20Sopenharmony_ci w >>= 4; 1298c2ecf20Sopenharmony_ci for (i = height; i; i--) { 1308c2ecf20Sopenharmony_ci src32 = (u32 *)src; 1318c2ecf20Sopenharmony_ci dst32 = (u32 *)dst; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (f & 1) { 1348c2ecf20Sopenharmony_ci pval[0] = (*src32++ << 8) & mask; 1358c2ecf20Sopenharmony_ci pval[1] = (*src32++ << 8) & mask; 1368c2ecf20Sopenharmony_ci pval[2] = (*src32++ << 8) & mask; 1378c2ecf20Sopenharmony_ci pval[3] = (*src32++ << 8) & mask; 1388c2ecf20Sopenharmony_ci } else { 1398c2ecf20Sopenharmony_ci pval[0] = dst32[0] & mask; 1408c2ecf20Sopenharmony_ci pval[1] = dst32[1] & mask; 1418c2ecf20Sopenharmony_ci pval[2] = dst32[2] & mask; 1428c2ecf20Sopenharmony_ci pval[3] = dst32[3] & mask; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci for (j = w; j > 0; j--) { 1468c2ecf20Sopenharmony_ci v = *src32++; 1478c2ecf20Sopenharmony_ci v1 = v & mask; 1488c2ecf20Sopenharmony_ci *dst32++ = pval[0] | (v1 >> 8); 1498c2ecf20Sopenharmony_ci pval[0] = (v ^ v1) << 8; 1508c2ecf20Sopenharmony_ci v = *src32++; 1518c2ecf20Sopenharmony_ci v1 = v & mask; 1528c2ecf20Sopenharmony_ci *dst32++ = pval[1] | (v1 >> 8); 1538c2ecf20Sopenharmony_ci pval[1] = (v ^ v1) << 8; 1548c2ecf20Sopenharmony_ci v = *src32++; 1558c2ecf20Sopenharmony_ci v1 = v & mask; 1568c2ecf20Sopenharmony_ci *dst32++ = pval[2] | (v1 >> 8); 1578c2ecf20Sopenharmony_ci pval[2] = (v ^ v1) << 8; 1588c2ecf20Sopenharmony_ci v = *src32++; 1598c2ecf20Sopenharmony_ci v1 = v & mask; 1608c2ecf20Sopenharmony_ci *dst32++ = pval[3] | (v1 >> 8); 1618c2ecf20Sopenharmony_ci pval[3] = (v ^ v1) << 8; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (f & 2) { 1658c2ecf20Sopenharmony_ci dst32[0] = (dst32[0] & mask) | pval[0]; 1668c2ecf20Sopenharmony_ci dst32[1] = (dst32[1] & mask) | pval[1]; 1678c2ecf20Sopenharmony_ci dst32[2] = (dst32[2] & mask) | pval[2]; 1688c2ecf20Sopenharmony_ci dst32[3] = (dst32[3] & mask) | pval[3]; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci src += next_line; 1728c2ecf20Sopenharmony_ci dst += next_line; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } else { 1758c2ecf20Sopenharmony_ci u32 *src32, *dst32; 1768c2ecf20Sopenharmony_ci u32 pval[4], v, v1, mask; 1778c2ecf20Sopenharmony_ci int i, j, w, f; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); 1808c2ecf20Sopenharmony_ci dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci mask = 0xff00ff; 1838c2ecf20Sopenharmony_ci f = 0; 1848c2ecf20Sopenharmony_ci w = width; 1858c2ecf20Sopenharmony_ci if ((dx + width) & 15) 1868c2ecf20Sopenharmony_ci f = 1; 1878c2ecf20Sopenharmony_ci if (sx & 15) { 1888c2ecf20Sopenharmony_ci f |= 2; 1898c2ecf20Sopenharmony_ci w += 8; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci w >>= 4; 1928c2ecf20Sopenharmony_ci for (i = height; i; i--) { 1938c2ecf20Sopenharmony_ci src32 = (u32 *)src; 1948c2ecf20Sopenharmony_ci dst32 = (u32 *)dst; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (f & 1) { 1978c2ecf20Sopenharmony_ci pval[0] = dst32[-1] & mask; 1988c2ecf20Sopenharmony_ci pval[1] = dst32[-2] & mask; 1998c2ecf20Sopenharmony_ci pval[2] = dst32[-3] & mask; 2008c2ecf20Sopenharmony_ci pval[3] = dst32[-4] & mask; 2018c2ecf20Sopenharmony_ci } else { 2028c2ecf20Sopenharmony_ci pval[0] = (*--src32 >> 8) & mask; 2038c2ecf20Sopenharmony_ci pval[1] = (*--src32 >> 8) & mask; 2048c2ecf20Sopenharmony_ci pval[2] = (*--src32 >> 8) & mask; 2058c2ecf20Sopenharmony_ci pval[3] = (*--src32 >> 8) & mask; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci for (j = w; j > 0; j--) { 2098c2ecf20Sopenharmony_ci v = *--src32; 2108c2ecf20Sopenharmony_ci v1 = v & mask; 2118c2ecf20Sopenharmony_ci *--dst32 = pval[0] | (v1 << 8); 2128c2ecf20Sopenharmony_ci pval[0] = (v ^ v1) >> 8; 2138c2ecf20Sopenharmony_ci v = *--src32; 2148c2ecf20Sopenharmony_ci v1 = v & mask; 2158c2ecf20Sopenharmony_ci *--dst32 = pval[1] | (v1 << 8); 2168c2ecf20Sopenharmony_ci pval[1] = (v ^ v1) >> 8; 2178c2ecf20Sopenharmony_ci v = *--src32; 2188c2ecf20Sopenharmony_ci v1 = v & mask; 2198c2ecf20Sopenharmony_ci *--dst32 = pval[2] | (v1 << 8); 2208c2ecf20Sopenharmony_ci pval[2] = (v ^ v1) >> 8; 2218c2ecf20Sopenharmony_ci v = *--src32; 2228c2ecf20Sopenharmony_ci v1 = v & mask; 2238c2ecf20Sopenharmony_ci *--dst32 = pval[3] | (v1 << 8); 2248c2ecf20Sopenharmony_ci pval[3] = (v ^ v1) >> 8; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!(f & 2)) { 2288c2ecf20Sopenharmony_ci dst32[-1] = (dst32[-1] & mask) | pval[0]; 2298c2ecf20Sopenharmony_ci dst32[-2] = (dst32[-2] & mask) | pval[1]; 2308c2ecf20Sopenharmony_ci dst32[-3] = (dst32[-3] & mask) | pval[2]; 2318c2ecf20Sopenharmony_ci dst32[-4] = (dst32[-4] & mask) | pval[3]; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci src -= next_line; 2358c2ecf20Sopenharmony_ci dst -= next_line; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color, 2428c2ecf20Sopenharmony_ci int sy, int sx, int height, int width) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci u32 *dest; 2458c2ecf20Sopenharmony_ci int rows, i; 2468c2ecf20Sopenharmony_ci u32 cval[4]; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); 2498c2ecf20Sopenharmony_ci if (sx & 15) { 2508c2ecf20Sopenharmony_ci u8 *dest8 = (u8 *)dest + 1; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci expand8_col2mask(color, cval); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci for (i = height; i; i--) { 2558c2ecf20Sopenharmony_ci fill8_col(dest8, cval); 2568c2ecf20Sopenharmony_ci dest8 += next_line; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci dest += BPL / 2; 2598c2ecf20Sopenharmony_ci width -= 8; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci expand16_col2mask(color, cval); 2638c2ecf20Sopenharmony_ci rows = width >> 4; 2648c2ecf20Sopenharmony_ci if (rows) { 2658c2ecf20Sopenharmony_ci u32 *d = dest; 2668c2ecf20Sopenharmony_ci u32 off = next_line - rows * BPL * 2; 2678c2ecf20Sopenharmony_ci for (i = height; i; i--) { 2688c2ecf20Sopenharmony_ci d = fill16_col(d, rows, cval); 2698c2ecf20Sopenharmony_ci d = (u32 *)((long)d + off); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci dest += rows * BPL / 2; 2728c2ecf20Sopenharmony_ci width &= 15; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (width) { 2768c2ecf20Sopenharmony_ci u8 *dest8 = (u8 *)dest; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci expand8_col2mask(color, cval); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = height; i; i--) { 2818c2ecf20Sopenharmony_ci fill8_col(dest8, cval); 2828c2ecf20Sopenharmony_ci dest8 += next_line; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_civoid atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line, 2888c2ecf20Sopenharmony_ci int dy, int dx, u32 width, 2898c2ecf20Sopenharmony_ci const u8 *data, u32 bgcolor, u32 fgcolor) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci u32 *dest; 2928c2ecf20Sopenharmony_ci const u16 *data16; 2938c2ecf20Sopenharmony_ci int rows; 2948c2ecf20Sopenharmony_ci u32 fgm[4], bgm[4], m; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); 2978c2ecf20Sopenharmony_ci if (dx & 15) { 2988c2ecf20Sopenharmony_ci fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); 2998c2ecf20Sopenharmony_ci dest += BPL / 2; 3008c2ecf20Sopenharmony_ci width -= 8; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (width >= 16) { 3048c2ecf20Sopenharmony_ci data16 = (const u16 *)data; 3058c2ecf20Sopenharmony_ci expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci for (rows = width / 16; rows; rows--) { 3088c2ecf20Sopenharmony_ci u16 d = *data16++; 3098c2ecf20Sopenharmony_ci m = d | ((u32)d << 16); 3108c2ecf20Sopenharmony_ci *dest++ = (m & fgm[0]) ^ bgm[0]; 3118c2ecf20Sopenharmony_ci *dest++ = (m & fgm[1]) ^ bgm[1]; 3128c2ecf20Sopenharmony_ci *dest++ = (m & fgm[2]) ^ bgm[2]; 3138c2ecf20Sopenharmony_ci *dest++ = (m & fgm[3]) ^ bgm[3]; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci data = (const u8 *)data16; 3178c2ecf20Sopenharmony_ci width &= 15; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (width) 3218c2ecf20Sopenharmony_ci fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); 3228c2ecf20Sopenharmony_ci} 323