2 * linux/drivers/video/fbcon-iplan2p2.c -- Low level frame buffer operations
3 * for interleaved bitplanes à la Atari (2
4 * planes, 2 bytes interleave)
6 * Created 5 Apr 1997 by Geert Uytterhoeven
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
13 #include <linux/module.h>
14 #include <linux/tty.h>
15 #include <linux/console.h>
16 #include <linux/string.h>
19 #include <asm/byteorder.h>
20 #include <asm/setup.h>
22 #include <video/fbcon.h>
23 #include <video/fbcon-iplan2p2.h>
27 * Interleaved bitplanes à la Atari (2 planes, 2 bytes interleave)
30 /* Increment/decrement 2 plane addresses */
32 #define INC_2P(p) do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
33 #define DEC_2P(p) do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
35 /* Convert a standard 4 bit color to our 2 bit color assignment:
36 * If at least two RGB channels are active, the low bit is turned on;
37 * The intensity bit (b3) is shifted into b1.
40 static const u8 color_2p
[] = { 0, 0, 0, 1, 0, 1, 1, 1, 2, 2, 2, 3, 2, 3, 3, 3 };
41 #define COLOR_2P(c) color_2p[c]
43 /* Perform the m68k movepw operation. */
44 static inline void movepw(u8
*d
, u16 val
)
46 #if defined __mc68000__ && !defined CPU_M68060_ONLY
47 asm volatile ("movepw %1,%0@(0)" : : "a" (d
), "d" (val
));
49 d
[0] = (val
>> 16) & 0xff;
54 /* Sets the bytes in the visible column at d, height h, to the value
55 * val for a 2 plane screen. The bits of the color in 'color' are
56 * moved (8 times) to the respective bytes. This means:
58 * for(h times; d += bpr)
59 * *d = (color & 1) ? 0xff : 0;
60 * *(d+2) = (color & 2) ? 0xff : 0;
63 static __inline__
void memclear_2p_col(void *d
, size_t h
, u16 val
, int bpr
)
72 /* Sets a 2 plane region from 'd', length 'count' bytes, to the color
73 * in val1. 'd' has to be an even address and count must be divisible
74 * by 8, because only whole words and all planes are accessed. I.e.:
77 * *d = *(d+1) = (color & 1) ? 0xff : 0;
78 * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
81 static __inline__
void memset_even_2p(void *d
, size_t count
, u32 val
)
90 /* Copies a 2 plane column from 's', height 'h', to 'd'. */
92 static __inline__
void memmove_2p_col (void *d
, void *s
, int h
, int bpr
)
105 /* This expands a 2 bit color into a short for movepw (2 plane) operations. */
107 static const u16 two2byte
[] = {
108 0x0000, 0xff00, 0x00ff, 0xffff
111 static __inline__ u16
expand2w(u8 c
)
117 /* This expands a 2 bit color into one long for a movel operation
121 static const u32 two2word
[] = {
122 #ifndef __LITTLE_ENDIAN
123 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
125 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
129 static __inline__ u32
expand2l(u8 c
)
135 /* This duplicates a byte 2 times into a short. */
137 static __inline__ u16
dup2w(u8 c
)
147 void fbcon_iplan2p2_setup(struct display
*p
)
149 p
->next_line
= p
->var
.xres_virtual
>>2;
153 void fbcon_iplan2p2_bmove(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
154 int height
, int width
)
156 /* bmove() has to distinguish two major cases: If both, source and
157 * destination, start at even addresses or both are at odd
158 * addresses, just the first odd and last even column (if present)
159 * require special treatment (memmove_col()). The rest between
160 * then can be copied by normal operations, because all adjacent
161 * bytes are affected and are to be stored in the same order.
162 * The pathological case is when the move should go from an odd
163 * address to an even or vice versa. Since the bytes in the plane
164 * words must be assembled in new order, it seems wisest to make
165 * all movements by memmove_col().
168 if (sx
== 0 && dx
== 0 && width
* 2 == p
->next_line
) {
169 /* Special (but often used) case: Moving whole lines can be
170 * done with memmove()
172 mymemmove(p
->screen_base
+ dy
* p
->next_line
* fontheight(p
),
173 p
->screen_base
+ sy
* p
->next_line
* fontheight(p
),
174 p
->next_line
* height
* fontheight(p
));
179 int bytes
= p
->next_line
;
182 u_int upwards
= (dy
< sy
) || (dy
== sy
&& dx
< sx
);
184 if (fontheightlog(p
)) {
185 linesize
= bytes
<< fontheightlog(p
);
186 colsize
= height
<< fontheightlog(p
);
188 linesize
= bytes
* fontheight(p
);
189 colsize
= height
* fontheight(p
);
191 if ((sx
& 1) == (dx
& 1)) {
192 /* odd->odd or even->even */
194 src
= p
->screen_base
+ sy
* linesize
+ (sx
>>1)*4 + (sx
& 1);
195 dst
= p
->screen_base
+ dy
* linesize
+ (dx
>>1)*4 + (dx
& 1);
197 memmove_2p_col(dst
, src
, colsize
, bytes
);
203 for (rows
= colsize
; rows
> 0; --rows
) {
204 mymemmove(dst
, src
, (width
>>1)*4);
210 src
-= colsize
* bytes
;
211 dst
-= colsize
* bytes
;
212 memmove_2p_col(dst
+ (width
>>1)*4, src
+ (width
>>1)*4,
216 if (!((sx
+width
-1) & 1)) {
217 src
= p
->screen_base
+ sy
* linesize
+ ((sx
+width
-1)>>1)*4;
218 dst
= p
->screen_base
+ dy
* linesize
+ ((dx
+width
-1)>>1)*4;
219 memmove_2p_col(dst
, src
, colsize
, bytes
);
222 src
= p
->screen_base
+ sy
* linesize
+ (sx
>>1)*4 + (sx
& 1);
223 dst
= p
->screen_base
+ dy
* linesize
+ (dx
>>1)*4 + (dx
& 1);
225 src
+= colsize
* bytes
+ (sx
& 1)*3;
226 dst
+= colsize
* bytes
+ (sx
& 1)*3;
227 for(rows
= colsize
; rows
> 0; --rows
) {
230 mymemmove(dst
, src
, (width
>>1)*4);
234 memmove_2p_col(dst
-3, src
-3, colsize
, bytes
);
237 /* odd->even or even->odd */
239 src
= p
->screen_base
+ sy
* linesize
+ (sx
>>1)*4 + (sx
& 1);
240 dst
= p
->screen_base
+ dy
* linesize
+ (dx
>>1)*4 + (dx
& 1);
241 for (cols
= width
; cols
> 0; --cols
) {
242 memmove_2p_col(dst
, src
, colsize
, bytes
);
249 src
= p
->screen_base
+ sy
* linesize
+ (sx
>>1)*4 + (sx
& 1);
250 dst
= p
->screen_base
+ dy
* linesize
+ (dx
>>1)*4 + (dx
& 1);
251 for(cols
= width
; cols
> 0; --cols
) {
252 memmove_2p_col(dst
, src
, colsize
, bytes
);
261 void fbcon_iplan2p2_clear(struct vc_data
*conp
, struct display
*p
, int sy
,
262 int sx
, int height
, int width
)
267 int bytes
= p
->next_line
;
273 cval
= expand2l (COLOR_2P (attr_bgcol_ec(p
,conp
)));
275 if (fontheightlog(p
))
276 lines
= height
<< fontheightlog(p
);
278 lines
= height
* fontheight(p
);
280 if (sx
== 0 && width
* 2 == bytes
) {
281 if (fontheightlog(p
))
282 offset
= (sy
* bytes
) << fontheightlog(p
);
284 offset
= sy
* bytes
* fontheight(p
);
285 size
= lines
* bytes
;
286 memset_even_2p(p
->screen_base
+offset
, size
, cval
);
288 if (fontheightlog(p
))
289 offset
= ((sy
* bytes
) << fontheightlog(p
)) + (sx
>>1)*4 + (sx
& 1);
291 offset
= sy
* bytes
* fontheight(p
) + (sx
>>1)*4 + (sx
& 1);
292 start
= p
->screen_base
+ offset
;
293 pcval
= expand2w(COLOR_2P(attr_bgcol_ec(p
,conp
)));
295 /* Clears are split if the region starts at an odd column or
296 * end at an even column. These extra columns are spread
297 * across the interleaved planes. All in between can be
298 * cleared by normal mymemclear_small(), because both bytes of
299 * the single plane words are affected.
303 memclear_2p_col(start
, lines
, pcval
, bytes
);
308 memclear_2p_col(start
+ (width
>>1)*4, lines
, pcval
, bytes
);
312 for (rows
= lines
; rows
-- ; start
+= bytes
)
313 memset_even_2p(start
, width
*2, cval
);
318 void fbcon_iplan2p2_putc(struct vc_data
*conp
, struct display
*p
, int c
,
324 int bytes
= p
->next_line
;
325 u16 eorx
, fgx
, bgx
, fdx
;
327 if (fontheightlog(p
)) {
328 dest
= (p
->screen_base
+ ((yy
* bytes
) << fontheightlog(p
)) +
329 (xx
>>1)*4 + (xx
& 1));
330 cdat
= p
->fontdata
+ ((c
& p
->charmask
) << fontheightlog(p
));
332 dest
= (p
->screen_base
+ yy
* bytes
* fontheight(p
) +
333 (xx
>>1)*4 + (xx
& 1));
334 cdat
= p
->fontdata
+ (c
& p
->charmask
) * fontheight(p
);
337 fgx
= expand2w(COLOR_2P(attr_fgcol(p
,c
)));
338 bgx
= expand2w(COLOR_2P(attr_bgcol(p
,c
)));
341 for (rows
= fontheight(p
) ; rows
-- ; dest
+= bytes
) {
342 fdx
= dup2w(*cdat
++);
343 movepw(dest
, (fdx
& eorx
) ^ bgx
);
347 void fbcon_iplan2p2_putcs(struct vc_data
*conp
, struct display
*p
,
348 const unsigned short *s
, int count
, int yy
, int xx
)
355 u16 eorx
, fgx
, bgx
, fdx
;
357 bytes
= p
->next_line
;
358 if (fontheightlog(p
))
359 dest0
= (p
->screen_base
+ ((yy
* bytes
) << fontheightlog(p
)) +
360 (xx
>>1)*4 + (xx
& 1));
362 dest0
= (p
->screen_base
+ yy
* bytes
* fontheight(p
) +
363 (xx
>>1)*4 + (xx
& 1));
364 fgx
= expand2w(COLOR_2P(attr_fgcol(p
,*s
)));
365 bgx
= expand2w(COLOR_2P(attr_bgcol(p
,*s
)));
369 c
= *s
++ & p
->charmask
;
370 if (fontheightlog(p
))
371 cdat
= p
->fontdata
+ (c
<< fontheightlog(p
));
373 cdat
= p
->fontdata
+ c
* fontheight(p
);
375 for (rows
= fontheight(p
), dest
= dest0
; rows
-- ; dest
+= bytes
) {
376 fdx
= dup2w(*cdat
++);
377 movepw(dest
, (fdx
& eorx
) ^ bgx
);
383 void fbcon_iplan2p2_revc(struct display
*p
, int xx
, int yy
)
389 if (fontheightlog(p
))
390 dest
= (p
->screen_base
+ ((yy
* p
->next_line
) << fontheightlog(p
)) +
391 (xx
>>1)*4 + (xx
& 1));
393 dest
= (p
->screen_base
+ yy
* p
->next_line
* fontheight(p
) +
394 (xx
>>1)*4 + (xx
& 1));
396 bytes
= p
->next_line
;
398 /* This should really obey the individual character's
399 * background and foreground colors instead of simply
408 void fbcon_iplan2p2_clear_margins(struct vc_data
*conp
, struct display
*p
,
416 /* No need to handle right margin, cannot occur with fontwidth == 8 */
418 bytes
= p
->next_line
;
419 if (fontheightlog(p
)) {
420 lines
= p
->var
.yres
- (conp
->vc_rows
<< fontheightlog(p
));
421 offset
= ((p
->yscroll
+ conp
->vc_rows
) * bytes
) << fontheightlog(p
);
423 lines
= p
->var
.yres
- conp
->vc_rows
* fontheight(p
);
424 offset
= (p
->yscroll
+ conp
->vc_rows
) * bytes
* fontheight(p
);
427 cval
= expand2l(COLOR_2P(attr_bgcol_ec(p
,conp
)));
428 memset_even_2p(p
->screen_base
+offset
, lines
* bytes
, cval
);
434 * `switch' for the low level operations
437 struct display_switch fbcon_iplan2p2
= {
438 fbcon_iplan2p2_setup
, fbcon_iplan2p2_bmove
, fbcon_iplan2p2_clear
,
439 fbcon_iplan2p2_putc
, fbcon_iplan2p2_putcs
, fbcon_iplan2p2_revc
, NULL
,
440 NULL
, fbcon_iplan2p2_clear_margins
, FONTWIDTH(8)
445 int init_module(void)
450 void cleanup_module(void)
456 * Visible symbols for modules
459 EXPORT_SYMBOL(fbcon_iplan2p2
);
460 EXPORT_SYMBOL(fbcon_iplan2p2_setup
);
461 EXPORT_SYMBOL(fbcon_iplan2p2_bmove
);
462 EXPORT_SYMBOL(fbcon_iplan2p2_clear
);
463 EXPORT_SYMBOL(fbcon_iplan2p2_putc
);
464 EXPORT_SYMBOL(fbcon_iplan2p2_putcs
);
465 EXPORT_SYMBOL(fbcon_iplan2p2_revc
);
466 EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins
);