1/* 2 * linux/drivers/video/cfb24.c -- Low level frame buffer operations for 24 bpp 3 * truecolor packed pixels 4 * 5 * Created 7 Mar 1998 by Geert Uytterhoeven 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file COPYING in the main directory of this archive for 9 * more details. 10 */ 11 12#include <linux/module.h> 13#include <linux/tty.h> 14#include <linux/console.h> 15#include <linux/string.h> 16#include <linux/fb.h> 17 18#include <video/fbcon.h> 19#include <video/fbcon-cfb24.h> 20 21 22 /* 23 * 24 bpp packed pixels 24 */ 25 26void fbcon_cfb24_setup(struct display *p) 27{ 28 p->next_line = p->line_length ? p->line_length : p->var.xres_virtual*3; 29 p->next_plane = 0; 30} 31 32void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx, 33 int height, int width) 34{ 35 int bytes = p->next_line, linesize = bytes * fontheight(p), rows; 36 u8 *src, *dst; 37 38 if (sx == 0 && dx == 0 && width * fontwidth(p) * 3 == bytes) { 39 fb_memmove(p->screen_base + dy * linesize, 40 p->screen_base + sy * linesize, 41 height * linesize); 42 return; 43 } 44 if (fontwidthlog(p)) { 45 sx <<= fontwidthlog(p); 46 dx <<= fontwidthlog(p); 47 width <<= fontwidthlog(p); 48 } else { 49 sx *= fontwidth(p); 50 dx *= fontwidth(p); 51 width *= fontwidth(p); 52 } 53 sx *= 3; dx *= 3; width *= 3; 54 if (dy < sy || (dy == sy && dx < sx)) { 55 src = p->screen_base + sy * linesize + sx; 56 dst = p->screen_base + dy * linesize + dx; 57 for (rows = height * fontheight(p); rows--;) { 58 fb_memmove(dst, src, width); 59 src += bytes; 60 dst += bytes; 61 } 62 } else { 63 src = p->screen_base + (sy+height) * linesize + sx - bytes; 64 dst = p->screen_base + (dy+height) * linesize + dx - bytes; 65 for (rows = height * fontheight(p); rows--;) { 66 fb_memmove(dst, src, width); 67 src -= bytes; 68 dst -= bytes; 69 } 70 } 71} 72 73#if defined(__BIG_ENDIAN) 74#define convert4to3(in1, in2, in3, in4, out1, out2, out3) \ 75 do { \ 76 out1 = (in1<<8) | (in2>>16); \ 77 out2 = (in2<<16) | (in3>>8); \ 78 out3 = (in3<<24) | in4; \ 79 } while (0) 80#elif defined(__LITTLE_ENDIAN) 81#define convert4to3(in1, in2, in3, in4, out1, out2, out3) \ 82 do { \ 83 out1 = in1 | (in2<<24); \ 84 out2 = (in2>> 8) | (in3<<16); \ 85 out3 = (in3>>16) | (in4<< 8); \ 86 } while (0) 87#else 88#error FIXME: No endianness?? 89#endif 90 91static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest) 92{ 93 u32 o1, o2, o3; 94 convert4to3(d1, d2, d3, d4, o1, o2, o3); 95 fb_writel (o1, dest++); 96 fb_writel (o2, dest++); 97 fb_writel (o3, dest); 98} 99 100static inline void rectfill(u8 *dest, int width, int height, u32 data, 101 int linesize) 102{ 103 u32 d1, d2, d3; 104 int i; 105 106 convert4to3(data, data, data, data, d1, d2, d3); 107 while (height-- > 0) { 108 u32 *p = (u32 *)dest; 109 for (i = 0; i < width/4; i++) { 110 fb_writel(d1, p++); 111 fb_writel(d2, p++); 112 fb_writel(d3, p++); 113 } 114 dest += linesize; 115 } 116} 117 118void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx, 119 int height, int width) 120{ 121 u8 *dest; 122 int bytes = p->next_line, lines = height * fontheight(p); 123 u32 bgx; 124 125 dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 3; 126 127 bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; 128 129 width *= fontwidth(p)/4; 130 if (width * 12 == bytes) 131 rectfill(dest, lines * width * 4, 1, bgx, bytes); 132 else 133 rectfill(dest, width * 4, lines, bgx, bytes); 134} 135 136void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy, 137 int xx) 138{ 139 u8 *dest, *cdat, bits; 140 int bytes = p->next_line, rows; 141 u32 eorx, fgx, bgx, d1, d2, d3, d4; 142 143 dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3; 144 if (fontwidth(p) <= 8) 145 cdat = p->fontdata + (c & p->charmask) * fontheight(p); 146 else 147 cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); 148 149 fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)]; 150 bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)]; 151 eorx = fgx ^ bgx; 152 153 for (rows = fontheight(p); rows--; dest += bytes) { 154 bits = *cdat++; 155 d1 = (-(bits >> 7) & eorx) ^ bgx; 156 d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; 157 d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; 158 d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; 159 store4pixels(d1, d2, d3, d4, (u32 *)dest); 160 if (fontwidth(p) < 8) 161 continue; 162 d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; 163 d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; 164 d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; 165 d4 = (-(bits & 1) & eorx) ^ bgx; 166 store4pixels(d1, d2, d3, d4, (u32 *)(dest+12)); 167 if (fontwidth(p) < 12) 168 continue; 169 bits = *cdat++; 170 d1 = (-(bits >> 7) & eorx) ^ bgx; 171 d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; 172 d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; 173 d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; 174 store4pixels(d1, d2, d3, d4, (u32 *)(dest+24)); 175 if (fontwidth(p) < 16) 176 continue; 177 d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; 178 d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; 179 d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; 180 d4 = (-(bits & 1) & eorx) ^ bgx; 181 store4pixels(d1, d2, d3, d4, (u32 *)(dest+36)); 182 } 183} 184 185void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, 186 const unsigned short *s, int count, int yy, int xx) 187{ 188 u8 *cdat, *dest, *dest0, bits; 189 u16 c; 190 int rows, bytes = p->next_line; 191 u32 eorx, fgx, bgx, d1, d2, d3, d4; 192 193 dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3; 194 c = scr_readw(s); 195 fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)]; 196 bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)]; 197 eorx = fgx ^ bgx; 198 while (count--) { 199 c = scr_readw(s++) & p->charmask; 200 if (fontwidth(p) <= 8) 201 cdat = p->fontdata + c * fontheight(p); 202 203 else 204 cdat = p->fontdata + (c * fontheight(p) << 1); 205 for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) { 206 bits = *cdat++; 207 d1 = (-(bits >> 7) & eorx) ^ bgx; 208 d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; 209 d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; 210 d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; 211 store4pixels(d1, d2, d3, d4, (u32 *)dest); 212 if (fontwidth(p) < 8) 213 continue; 214 d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; 215 d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; 216 d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; 217 d4 = (-(bits & 1) & eorx) ^ bgx; 218 store4pixels(d1, d2, d3, d4, (u32 *)(dest+12)); 219 if (fontwidth(p) < 12) 220 continue; 221 bits = *cdat++; 222 d1 = (-(bits >> 7) & eorx) ^ bgx; 223 d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; 224 d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; 225 d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; 226 store4pixels(d1, d2, d3, d4, (u32 *)(dest+24)); 227 if (fontwidth(p) < 16) 228 continue; 229 d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; 230 d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; 231 d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; 232 d4 = (-(bits & 1) & eorx) ^ bgx; 233 store4pixels(d1, d2, d3, d4, (u32 *)(dest+36)); 234 } 235 dest0 += fontwidth(p)*3; 236 } 237} 238 239void fbcon_cfb24_revc(struct display *p, int xx, int yy) 240{ 241 u8 *dest; 242 int bytes = p->next_line, rows; 243 244 dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3; 245 for (rows = fontheight(p); rows--; dest += bytes) { 246 switch (fontwidth(p)) { 247 case 16: 248 fb_writel(fb_readl(dest+36) ^ 0xffffffff, dest+36); 249 fb_writel(fb_readl(dest+40) ^ 0xffffffff, dest+40); 250 fb_writel(fb_readl(dest+44) ^ 0xffffffff, dest+44); 251 /* FALL THROUGH */ 252 case 12: 253 fb_writel(fb_readl(dest+24) ^ 0xffffffff, dest+24); 254 fb_writel(fb_readl(dest+28) ^ 0xffffffff, dest+28); 255 fb_writel(fb_readl(dest+32) ^ 0xffffffff, dest+32); 256 /* FALL THROUGH */ 257 case 8: 258 fb_writel(fb_readl(dest+12) ^ 0xffffffff, dest+12); 259 fb_writel(fb_readl(dest+16) ^ 0xffffffff, dest+16); 260 fb_writel(fb_readl(dest+20) ^ 0xffffffff, dest+20); 261 /* FALL THROUGH */ 262 case 4: 263 fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0); 264 fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4); 265 fb_writel(fb_readl(dest+8) ^ 0xffffffff, dest+8); 266 } 267 } 268} 269 270void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p, 271 int bottom_only) 272{ 273 int bytes = p->next_line; 274 u32 bgx; 275 276 unsigned int right_start = conp->vc_cols*fontwidth(p); 277 unsigned int bottom_start = conp->vc_rows*fontheight(p); 278 unsigned int right_width, bottom_width; 279 280 bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; 281 282 if (!bottom_only && (right_width = p->var.xres-right_start)) 283 rectfill(p->screen_base+right_start*3, right_width, 284 p->var.yres_virtual, bgx, bytes); 285 if ((bottom_width = p->var.yres-bottom_start)) 286 rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes, 287 right_start, bottom_width, bgx, bytes); 288} 289 290 291 /* 292 * `switch' for the low level operations 293 */ 294 295struct display_switch fbcon_cfb24 = { 296 setup: fbcon_cfb24_setup, 297 bmove: fbcon_cfb24_bmove, 298 clear: fbcon_cfb24_clear, 299 putc: fbcon_cfb24_putc, 300 putcs: fbcon_cfb24_putcs, 301 revc: fbcon_cfb24_revc, 302 clear_margins: fbcon_cfb24_clear_margins, 303 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) 304}; 305 306 307#ifdef MODULE 308MODULE_LICENSE("GPL"); 309 310int init_module(void) 311{ 312 return 0; 313} 314 315void cleanup_module(void) 316{} 317#endif /* MODULE */ 318 319 320 /* 321 * Visible symbols for modules 322 */ 323 324EXPORT_SYMBOL(fbcon_cfb24); 325EXPORT_SYMBOL(fbcon_cfb24_setup); 326EXPORT_SYMBOL(fbcon_cfb24_bmove); 327EXPORT_SYMBOL(fbcon_cfb24_clear); 328EXPORT_SYMBOL(fbcon_cfb24_putc); 329EXPORT_SYMBOL(fbcon_cfb24_putcs); 330EXPORT_SYMBOL(fbcon_cfb24_revc); 331EXPORT_SYMBOL(fbcon_cfb24_clear_margins); 332