2 * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
4 * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
5 * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
6 * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of this
10 * archive for more details.
13 #include <linux/aperture.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
19 #include <linux/delay.h>
21 #include <linux/ioport.h>
22 #include <linux/init.h>
23 #include <linux/platform_device.h>
24 #include <linux/screen_info.h>
27 #include <video/vga.h>
34 /* --------------------------------------------------------------------- */
41 /* structure holding original VGA register settings when the
44 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
45 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
46 unsigned char CrtMiscIO
; /* Miscellaneous register */
47 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
48 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
49 unsigned char StartHorizRetrace
;/* CRT-Controller:04h */
50 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
51 unsigned char Overflow
; /* CRT-Controller:07h */
52 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
53 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
54 unsigned char ModeControl
; /* CRT-Controller:17h */
55 unsigned char ClockingMode
; /* Seq-Controller:01h */
57 struct vgastate state
;
58 unsigned int ref_count
;
59 int palette_blanked
, vesa_blanked
, mode
, isVGA
;
60 u8 misc
, pel_msk
, vss
, clkdiv
;
64 /* --------------------------------------------------------------------- */
66 static struct fb_var_screeninfo vga16fb_defined
= {
72 .activate
= FB_ACTIVATE_TEST
,
82 .vmode
= FB_VMODE_NONINTERLACED
,
85 /* name should not depend on EGA/VGA */
86 static const struct fb_fix_screeninfo vga16fb_fix
= {
88 .smem_start
= VGA_FB_PHYS_BASE
,
89 .smem_len
= VGA_FB_PHYS_SIZE
,
90 .type
= FB_TYPE_VGA_PLANES
,
91 .type_aux
= FB_AUX_VGA_PLANES_VGA4
,
92 .visual
= FB_VISUAL_PSEUDOCOLOR
,
95 .line_length
= 640 / 8,
96 .accel
= FB_ACCEL_NONE
99 /* The VGA's weird architecture often requires that we read a byte and
100 write a byte to the same location. It doesn't matter *what* byte
101 we write, however. This is because all the action goes on behind
102 the scenes in the VGA's 32-bit latch register, and reading and writing
103 video memory just invokes latch behavior.
105 To avoid race conditions (is this necessary?), reading and writing
106 the memory byte should be done with a single instruction. One
107 suitable instruction is the x86 bitwise OR. The following
108 read-modify-write routine should optimize to one such bitwise
110 static inline void rmw(volatile char __iomem
*p
)
116 /* Set the Graphics Mode Register, and return its previous value.
117 Bits 0-1 are write mode, bit 3 is read mode. */
118 static inline int setmode(int mode
)
122 oldmode
= vga_io_rgfx(VGA_GFX_MODE
);
123 vga_io_w(VGA_GFX_D
, mode
);
127 /* Select the Bit Mask Register and return its value. */
128 static inline int selectmask(void)
130 return vga_io_rgfx(VGA_GFX_BIT_MASK
);
133 /* Set the value of the Bit Mask Register. It must already have been
134 selected with selectmask(). */
135 static inline void setmask(int mask
)
137 vga_io_w(VGA_GFX_D
, mask
);
140 /* Set the Data Rotate Register and return its old value.
141 Bits 0-2 are rotate count, bits 3-4 are logical operation
142 (0=NOP, 1=AND, 2=OR, 3=XOR). */
143 static inline int setop(int op
)
147 oldop
= vga_io_rgfx(VGA_GFX_DATA_ROTATE
);
148 vga_io_w(VGA_GFX_D
, op
);
152 /* Set the Enable Set/Reset Register and return its old value.
153 The code here always uses value 0xf for this register. */
154 static inline int setsr(int sr
)
158 oldsr
= vga_io_rgfx(VGA_GFX_SR_ENABLE
);
159 vga_io_w(VGA_GFX_D
, sr
);
163 /* Set the Set/Reset Register and return its old value. */
164 static inline int setcolor(int color
)
168 oldcolor
= vga_io_rgfx(VGA_GFX_SR_VALUE
);
169 vga_io_w(VGA_GFX_D
, color
);
173 /* Return the value in the Graphics Address Register. */
174 static inline int getindex(void)
176 return vga_io_r(VGA_GFX_I
);
179 /* Set the value in the Graphics Address Register. */
180 static inline void setindex(int index
)
182 vga_io_w(VGA_GFX_I
, index
);
185 /* Check if the video mode is supported by the driver */
186 static inline int check_mode_supported(const struct screen_info
*si
)
188 /* only EGA and VGA in 16 color graphic mode are supported */
189 if (si
->orig_video_isVGA
!= VIDEO_TYPE_EGAC
&&
190 si
->orig_video_isVGA
!= VIDEO_TYPE_VGAC
)
193 if (si
->orig_video_mode
!= 0x0D && /* 320x200/4 (EGA) */
194 si
->orig_video_mode
!= 0x0E && /* 640x200/4 (EGA) */
195 si
->orig_video_mode
!= 0x10 && /* 640x350/4 (EGA) */
196 si
->orig_video_mode
!= 0x12) /* 640x480/4 (VGA) */
202 static void vga16fb_pan_var(struct fb_info
*info
,
203 struct fb_var_screeninfo
*var
)
205 struct vga16fb_par
*par
= info
->par
;
208 xoffset
= var
->xoffset
;
209 if (info
->var
.bits_per_pixel
== 8) {
210 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 2;
211 } else if (par
->mode
& MODE_TEXT
) {
212 int fh
= 16; // FIXME !!! font height. Fugde for now.
213 pos
= (info
->var
.xres_virtual
* (var
->yoffset
/ fh
) + xoffset
) >> 3;
215 if (info
->var
.nonstd
)
217 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 3;
219 vga_io_wcrt(VGA_CRTC_START_HI
, pos
>> 8);
220 vga_io_wcrt(VGA_CRTC_START_LO
, pos
& 0xFF);
221 /* if we support CFB4, then we must! support xoffset with pixel
222 * granularity if someone supports xoffset in bit resolution */
223 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
224 vga_io_w(VGA_ATT_IW
, VGA_ATC_PEL
);
225 if (info
->var
.bits_per_pixel
== 8)
226 vga_io_w(VGA_ATT_IW
, (xoffset
& 3) << 1);
228 vga_io_w(VGA_ATT_IW
, xoffset
& 7);
229 vga_io_r(VGA_IS1_RC
);
230 vga_io_w(VGA_ATT_IW
, 0x20);
233 static void vga16fb_update_fix(struct fb_info
*info
)
235 if (info
->var
.bits_per_pixel
== 4) {
236 if (info
->var
.nonstd
) {
237 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
238 info
->fix
.line_length
= info
->var
.xres_virtual
/ 2;
240 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
241 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_VGA4
;
242 info
->fix
.line_length
= info
->var
.xres_virtual
/ 8;
244 } else if (info
->var
.bits_per_pixel
== 0) {
245 info
->fix
.type
= FB_TYPE_TEXT
;
246 info
->fix
.type_aux
= FB_AUX_TEXT_CGA
;
247 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
249 if (info
->var
.nonstd
) {
250 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
251 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_CFB8
;
252 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
254 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
255 info
->fix
.line_length
= info
->var
.xres_virtual
;
260 static void vga16fb_clock_chip(struct vga16fb_par
*par
,
261 unsigned int *pixclock
,
262 const struct fb_info
*info
,
265 static const struct {
269 } *ptr
, *best
, vgaclocks
[] = {
270 { 79442 /* 12.587 */, 0x00, 0x08},
271 { 70616 /* 14.161 */, 0x04, 0x08},
272 { 39721 /* 25.175 */, 0x00, 0x00},
273 { 35308 /* 28.322 */, 0x04, 0x00},
274 { 0 /* bad */, 0x00, 0x00}};
277 *pixclock
= (*pixclock
* mul
) / div
;
279 err
= *pixclock
- best
->pixclock
;
280 if (err
< 0) err
= -err
;
281 for (ptr
= vgaclocks
+ 1; ptr
->pixclock
; ptr
++) {
284 tmp
= *pixclock
- ptr
->pixclock
;
285 if (tmp
< 0) tmp
= -tmp
;
291 par
->misc
|= best
->misc
;
292 par
->clkdiv
= best
->seq_clock_mode
;
293 *pixclock
= (best
->pixclock
* div
) / mul
;
296 #define FAIL(X) return -EINVAL
298 static int vga16fb_open(struct fb_info
*info
, int user
)
300 struct vga16fb_par
*par
= info
->par
;
302 if (!par
->ref_count
) {
303 memset(&par
->state
, 0, sizeof(struct vgastate
));
304 par
->state
.flags
= VGA_SAVE_FONTS
| VGA_SAVE_MODE
|
306 save_vga(&par
->state
);
313 static int vga16fb_release(struct fb_info
*info
, int user
)
315 struct vga16fb_par
*par
= info
->par
;
320 if (par
->ref_count
== 1)
321 restore_vga(&par
->state
);
327 static int vga16fb_check_var(struct fb_var_screeninfo
*var
,
328 struct fb_info
*info
)
330 struct vga16fb_par
*par
= info
->par
;
331 u32 xres
, right
, hslen
, left
, xtotal
;
332 u32 yres
, lower
, vslen
, upper
, ytotal
;
333 u32 vxres
, xoffset
, vyres
, yoffset
;
342 if (var
->bits_per_pixel
== 4) {
347 mode
= MODE_SKIP4
| MODE_CFB
;
355 } else if (var
->bits_per_pixel
== 8) {
357 return -EINVAL
; /* no support on EGA */
360 mode
= MODE_8BPP
| MODE_CFB
;
363 mode
= MODE_SKIP4
| MODE_8BPP
| MODE_CFB
;
369 xres
= (var
->xres
+ 7) & ~7;
370 vxres
= (var
->xres_virtual
+ 0xF) & ~0xF;
371 xoffset
= (var
->xoffset
+ 7) & ~7;
372 left
= (var
->left_margin
+ 7) & ~7;
373 right
= (var
->right_margin
+ 7) & ~7;
374 hslen
= (var
->hsync_len
+ 7) & ~7;
378 if (xres
+ xoffset
> vxres
)
379 xoffset
= vxres
- xres
;
382 var
->right_margin
= right
;
383 var
->hsync_len
= hslen
;
384 var
->left_margin
= left
;
385 var
->xres_virtual
= vxres
;
386 var
->xoffset
= xoffset
;
393 xtotal
= xres
+ right
+ hslen
+ left
;
395 FAIL("xtotal too big");
397 FAIL("hslen too big");
398 if (right
+ hslen
+ left
> 64)
399 FAIL("hblank too big");
400 par
->crtc
[VGA_CRTC_H_TOTAL
] = xtotal
- 5;
401 par
->crtc
[VGA_CRTC_H_BLANK_START
] = xres
- 1;
402 par
->crtc
[VGA_CRTC_H_DISP
] = xres
- 1;
404 par
->crtc
[VGA_CRTC_H_SYNC_START
] = pos
;
406 par
->crtc
[VGA_CRTC_H_SYNC_END
] = pos
& 0x1F;
407 pos
+= left
- 2; /* blank_end + 2 <= total + 5 */
408 par
->crtc
[VGA_CRTC_H_BLANK_END
] = (pos
& 0x1F) | 0x80;
410 par
->crtc
[VGA_CRTC_H_SYNC_END
] |= 0x80;
413 lower
= var
->lower_margin
;
414 vslen
= var
->vsync_len
;
415 upper
= var
->upper_margin
;
416 vyres
= var
->yres_virtual
;
417 yoffset
= var
->yoffset
;
421 if (vxres
* vyres
> maxmem
) {
422 vyres
= maxmem
/ vxres
;
426 if (yoffset
+ yres
> vyres
)
427 yoffset
= vyres
- yres
;
429 var
->lower_margin
= lower
;
430 var
->vsync_len
= vslen
;
431 var
->upper_margin
= upper
;
432 var
->yres_virtual
= vyres
;
433 var
->yoffset
= yoffset
;
435 if (var
->vmode
& FB_VMODE_DOUBLE
) {
441 ytotal
= yres
+ lower
+ vslen
+ upper
;
452 FAIL("ytotal too big");
454 FAIL("vslen too big");
455 par
->crtc
[VGA_CRTC_V_TOTAL
] = ytotal
- 2;
456 r7
= 0x10; /* disable linecompare */
457 if (ytotal
& 0x100) r7
|= 0x01;
458 if (ytotal
& 0x200) r7
|= 0x20;
459 par
->crtc
[VGA_CRTC_PRESET_ROW
] = 0;
460 par
->crtc
[VGA_CRTC_MAX_SCAN
] = 0x40; /* 1 scanline, no linecmp */
461 if (var
->vmode
& FB_VMODE_DOUBLE
)
462 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x80;
463 par
->crtc
[VGA_CRTC_CURSOR_START
] = 0x20;
464 par
->crtc
[VGA_CRTC_CURSOR_END
] = 0x00;
465 if ((mode
& (MODE_CFB
| MODE_8BPP
)) == MODE_CFB
)
467 pos
= yoffset
* vxres
+ (xoffset
>> shift
);
468 par
->crtc
[VGA_CRTC_START_HI
] = pos
>> 8;
469 par
->crtc
[VGA_CRTC_START_LO
] = pos
& 0xFF;
470 par
->crtc
[VGA_CRTC_CURSOR_HI
] = 0x00;
471 par
->crtc
[VGA_CRTC_CURSOR_LO
] = 0x00;
473 par
->crtc
[VGA_CRTC_V_DISP_END
] = pos
& 0xFF;
474 par
->crtc
[VGA_CRTC_V_BLANK_START
] = pos
& 0xFF;
476 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
478 r7
|= 0x40; /* 0x40 -> DISP_END */
479 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
482 par
->crtc
[VGA_CRTC_V_SYNC_START
] = pos
& 0xFF;
488 par
->crtc
[VGA_CRTC_V_SYNC_END
] = (pos
& 0x0F) & ~0x10; /* disabled IRQ */
489 pos
+= upper
- 1; /* blank_end + 1 <= ytotal + 2 */
490 par
->crtc
[VGA_CRTC_V_BLANK_END
] = pos
& 0xFF; /* 0x7F for original VGA,
491 but some SVGA chips requires all 8 bits to set */
493 FAIL("vxres too long");
494 par
->crtc
[VGA_CRTC_OFFSET
] = vxres
>> 1;
495 if (mode
& MODE_SKIP4
)
496 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x5F; /* 256, cfb8 */
498 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x1F; /* 16, vgap */
499 par
->crtc
[VGA_CRTC_MODE
] = rMode
| ((mode
& MODE_TEXT
) ? 0xA3 : 0xE3);
500 par
->crtc
[VGA_CRTC_LINE_COMPARE
] = 0xFF;
501 par
->crtc
[VGA_CRTC_OVERFLOW
] = r7
;
503 par
->vss
= 0x00; /* 3DA */
505 par
->misc
= 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
506 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
508 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
513 if (mode
& MODE_8BPP
)
514 /* pixel clock == vga clock / 2 */
515 vga16fb_clock_chip(par
, &var
->pixclock
, info
, 1, 2);
517 /* pixel clock == vga clock */
518 vga16fb_clock_chip(par
, &var
->pixclock
, info
, 1, 1);
520 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
=
521 var
->transp
.offset
= 0;
522 var
->red
.length
= var
->green
.length
= var
->blue
.length
=
523 (par
->isVGA
) ? 6 : 2;
524 var
->transp
.length
= 0;
525 var
->activate
= FB_ACTIVATE_NOW
;
528 var
->accel_flags
= 0;
533 static int vga16fb_set_par(struct fb_info
*info
)
535 struct vga16fb_par
*par
= info
->par
;
541 seq
[VGA_SEQ_CLOCK_MODE
] = 0x01 | par
->clkdiv
;
542 if (par
->mode
& MODE_TEXT
)
543 seq
[VGA_SEQ_PLANE_WRITE
] = 0x03;
545 seq
[VGA_SEQ_PLANE_WRITE
] = 0x0F;
546 seq
[VGA_SEQ_CHARACTER_MAP
] = 0x00;
547 if (par
->mode
& MODE_TEXT
)
548 seq
[VGA_SEQ_MEMORY_MODE
] = 0x03;
549 else if (par
->mode
& MODE_SKIP4
)
550 seq
[VGA_SEQ_MEMORY_MODE
] = 0x0E;
552 seq
[VGA_SEQ_MEMORY_MODE
] = 0x06;
554 gdc
[VGA_GFX_SR_VALUE
] = 0x00;
555 gdc
[VGA_GFX_SR_ENABLE
] = 0x00;
556 gdc
[VGA_GFX_COMPARE_VALUE
] = 0x00;
557 gdc
[VGA_GFX_DATA_ROTATE
] = 0x00;
558 gdc
[VGA_GFX_PLANE_READ
] = 0;
559 if (par
->mode
& MODE_TEXT
) {
560 gdc
[VGA_GFX_MODE
] = 0x10;
561 gdc
[VGA_GFX_MISC
] = 0x06;
563 if (par
->mode
& MODE_CFB
)
564 gdc
[VGA_GFX_MODE
] = 0x40;
566 gdc
[VGA_GFX_MODE
] = 0x00;
567 gdc
[VGA_GFX_MISC
] = 0x05;
569 gdc
[VGA_GFX_COMPARE_MASK
] = 0x0F;
570 gdc
[VGA_GFX_BIT_MASK
] = 0xFF;
572 for (i
= 0x00; i
< 0x10; i
++)
574 if (par
->mode
& MODE_TEXT
)
575 atc
[VGA_ATC_MODE
] = 0x04;
576 else if (par
->mode
& MODE_8BPP
)
577 atc
[VGA_ATC_MODE
] = 0x41;
579 atc
[VGA_ATC_MODE
] = 0x81;
580 atc
[VGA_ATC_OVERSCAN
] = 0x00; /* 0 for EGA, 0xFF for VGA */
581 atc
[VGA_ATC_PLANE_ENABLE
] = 0x0F;
582 if (par
->mode
& MODE_8BPP
)
583 atc
[VGA_ATC_PEL
] = (info
->var
.xoffset
& 3) << 1;
585 atc
[VGA_ATC_PEL
] = info
->var
.xoffset
& 7;
586 atc
[VGA_ATC_COLOR_PAGE
] = 0x00;
588 if (par
->mode
& MODE_TEXT
) {
589 fh
= 16; // FIXME !!! Fudge font height.
590 par
->crtc
[VGA_CRTC_MAX_SCAN
] = (par
->crtc
[VGA_CRTC_MAX_SCAN
]
594 vga_io_w(VGA_MIS_W
, vga_io_r(VGA_MIS_R
) | 0x01);
596 /* Enable graphics register modification */
598 vga_io_w(EGA_GFX_E0
, 0x00);
599 vga_io_w(EGA_GFX_E1
, 0x01);
602 /* update misc output register */
603 vga_io_w(VGA_MIS_W
, par
->misc
);
605 /* synchronous reset on */
606 vga_io_wseq(0x00, 0x01);
609 vga_io_w(VGA_PEL_MSK
, par
->pel_msk
);
611 /* write sequencer registers */
612 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
] | 0x20);
613 for (i
= 2; i
< VGA_SEQ_C
; i
++) {
614 vga_io_wseq(i
, seq
[i
]);
617 /* synchronous reset off */
618 vga_io_wseq(0x00, 0x03);
620 /* deprotect CRT registers 0-7 */
621 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, par
->crtc
[VGA_CRTC_V_SYNC_END
]);
623 /* write CRT registers */
624 for (i
= 0; i
< VGA_CRTC_REGS
; i
++) {
625 vga_io_wcrt(i
, par
->crtc
[i
]);
628 /* write graphics controller registers */
629 for (i
= 0; i
< VGA_GFX_C
; i
++) {
630 vga_io_wgfx(i
, gdc
[i
]);
633 /* write attribute controller registers */
634 for (i
= 0; i
< VGA_ATT_C
; i
++) {
635 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
636 vga_io_wattr(i
, atc
[i
]);
639 /* Wait for screen to stabilize. */
642 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
]);
644 vga_io_r(VGA_IS1_RC
);
645 vga_io_w(VGA_ATT_IW
, 0x20);
647 vga16fb_update_fix(info
);
651 static void ega16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
653 static const unsigned char map
[] = { 000, 001, 010, 011 };
658 val
= map
[red
>>14] | ((map
[green
>>14]) << 1) | ((map
[blue
>>14]) << 2);
659 vga_io_r(VGA_IS1_RC
); /* ! 0x3BA */
660 vga_io_wattr(regno
, val
);
661 vga_io_r(VGA_IS1_RC
); /* some clones need it */
662 vga_io_w(VGA_ATT_IW
, 0x20); /* unblank screen */
665 static void vga16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
667 outb(regno
, VGA_PEL_IW
);
668 outb(red
>> 10, VGA_PEL_D
);
669 outb(green
>> 10, VGA_PEL_D
);
670 outb(blue
>> 10, VGA_PEL_D
);
673 static int vga16fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
674 unsigned blue
, unsigned transp
,
675 struct fb_info
*info
)
677 struct vga16fb_par
*par
= info
->par
;
681 * Set a single color register. The values supplied are
682 * already rounded down to the hardware's capabilities
683 * (according to the entries in the `var' structure). Return
684 * != 0 for invalid regno.
690 gray
= info
->var
.grayscale
;
693 /* gray = 0.30*R + 0.59*G + 0.11*B */
694 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
697 vga16_setpalette(regno
,red
,green
,blue
);
699 ega16_setpalette(regno
,red
,green
,blue
);
703 static int vga16fb_pan_display(struct fb_var_screeninfo
*var
,
704 struct fb_info
*info
)
706 vga16fb_pan_var(info
, var
);
710 /* The following VESA blanking code is taken from vgacon.c. The VGA
711 blanking code was originally by Huang shi chao, and modified by
712 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
713 (tjd@barefoot.org) for Linux. */
715 static void vga_vesa_blank(struct vga16fb_par
*par
, int mode
)
717 unsigned char SeqCtrlIndex
= vga_io_r(VGA_SEQ_I
);
718 unsigned char CrtCtrlIndex
= vga_io_r(VGA_CRT_IC
);
720 /* save original values of VGA controller registers */
721 if(!par
->vesa_blanked
) {
722 par
->vga_state
.CrtMiscIO
= vga_io_r(VGA_MIS_R
);
725 par
->vga_state
.HorizontalTotal
= vga_io_rcrt(0x00); /* HorizontalTotal */
726 par
->vga_state
.HorizDisplayEnd
= vga_io_rcrt(0x01); /* HorizDisplayEnd */
727 par
->vga_state
.StartHorizRetrace
= vga_io_rcrt(0x04); /* StartHorizRetrace */
728 par
->vga_state
.EndHorizRetrace
= vga_io_rcrt(0x05); /* EndHorizRetrace */
729 par
->vga_state
.Overflow
= vga_io_rcrt(0x07); /* Overflow */
730 par
->vga_state
.StartVertRetrace
= vga_io_rcrt(0x10); /* StartVertRetrace */
731 par
->vga_state
.EndVertRetrace
= vga_io_rcrt(0x11); /* EndVertRetrace */
732 par
->vga_state
.ModeControl
= vga_io_rcrt(0x17); /* ModeControl */
733 par
->vga_state
.ClockingMode
= vga_io_rseq(0x01); /* ClockingMode */
736 /* assure that video is enabled */
737 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
738 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
| 0x20);
740 /* test for vertical retrace in process.... */
741 if ((par
->vga_state
.CrtMiscIO
& 0x80) == 0x80)
742 vga_io_w(VGA_MIS_W
, par
->vga_state
.CrtMiscIO
& 0xef);
745 * Set <End of vertical retrace> to minimum (0) and
746 * <Start of vertical Retrace> to maximum (incl. overflow)
747 * Result: turn off vertical sync (VSync) pulse.
749 if (mode
& FB_BLANK_VSYNC_SUSPEND
) {
750 vga_io_wcrt(VGA_CRTC_V_SYNC_START
, 0xff);
751 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, 0x40);
752 /* bits 9,10 of vert. retrace */
753 vga_io_wcrt(VGA_CRTC_OVERFLOW
, par
->vga_state
.Overflow
| 0x84);
756 if (mode
& FB_BLANK_HSYNC_SUSPEND
) {
758 * Set <End of horizontal retrace> to minimum (0) and
759 * <Start of horizontal Retrace> to maximum
760 * Result: turn off horizontal sync (HSync) pulse.
762 vga_io_wcrt(VGA_CRTC_H_SYNC_START
, 0xff);
763 vga_io_wcrt(VGA_CRTC_H_SYNC_END
, 0x00);
766 /* restore both index registers */
767 outb_p(SeqCtrlIndex
, VGA_SEQ_I
);
768 outb_p(CrtCtrlIndex
, VGA_CRT_IC
);
771 static void vga_vesa_unblank(struct vga16fb_par
*par
)
773 unsigned char SeqCtrlIndex
= vga_io_r(VGA_SEQ_I
);
774 unsigned char CrtCtrlIndex
= vga_io_r(VGA_CRT_IC
);
776 /* restore original values of VGA controller registers */
777 vga_io_w(VGA_MIS_W
, par
->vga_state
.CrtMiscIO
);
779 /* HorizontalTotal */
780 vga_io_wcrt(0x00, par
->vga_state
.HorizontalTotal
);
781 /* HorizDisplayEnd */
782 vga_io_wcrt(0x01, par
->vga_state
.HorizDisplayEnd
);
783 /* StartHorizRetrace */
784 vga_io_wcrt(0x04, par
->vga_state
.StartHorizRetrace
);
785 /* EndHorizRetrace */
786 vga_io_wcrt(0x05, par
->vga_state
.EndHorizRetrace
);
788 vga_io_wcrt(0x07, par
->vga_state
.Overflow
);
789 /* StartVertRetrace */
790 vga_io_wcrt(0x10, par
->vga_state
.StartVertRetrace
);
792 vga_io_wcrt(0x11, par
->vga_state
.EndVertRetrace
);
794 vga_io_wcrt(0x17, par
->vga_state
.ModeControl
);
796 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
);
798 /* restore index/control registers */
799 vga_io_w(VGA_SEQ_I
, SeqCtrlIndex
);
800 vga_io_w(VGA_CRT_IC
, CrtCtrlIndex
);
803 static void vga_pal_blank(void)
807 for (i
=0; i
<16; i
++) {
808 outb_p(i
, VGA_PEL_IW
);
809 outb_p(0, VGA_PEL_D
);
810 outb_p(0, VGA_PEL_D
);
811 outb_p(0, VGA_PEL_D
);
815 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
816 static int vga16fb_blank(int blank
, struct fb_info
*info
)
818 struct vga16fb_par
*par
= info
->par
;
821 case FB_BLANK_UNBLANK
: /* Unblank */
822 if (par
->vesa_blanked
) {
823 vga_vesa_unblank(par
);
824 par
->vesa_blanked
= 0;
826 if (par
->palette_blanked
) {
827 par
->palette_blanked
= 0;
830 case FB_BLANK_NORMAL
: /* blank */
832 par
->palette_blanked
= 1;
834 default: /* VESA blanking */
835 vga_vesa_blank(par
, blank
);
836 par
->vesa_blanked
= 1;
842 static void vga_8planes_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
844 u32 dx
= rect
->dx
, width
= rect
->width
;
845 char oldindex
= getindex();
846 char oldmode
= setmode(0x40);
847 char oldmask
= selectmask();
848 int line_ofs
, height
;
853 where
= info
->screen_base
+ dx
+ rect
->dy
* info
->fix
.line_length
;
855 if (rect
->rop
== ROP_COPY
) {
860 line_ofs
= info
->fix
.line_length
- width
;
863 height
= rect
->height
;
868 /* we can do memset... */
869 for (x
= width
; x
> 0; --x
) {
870 writeb(rect
->color
, where
);
876 char oldcolor
= setcolor(0xf);
882 for (y
= 0; y
< rect
->height
; y
++) {
885 where
+= info
->fix
.line_length
;
896 static void vga16fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
898 int x
, x2
, y2
, vxres
, vyres
, width
, height
, line_ofs
;
901 vxres
= info
->var
.xres_virtual
;
902 vyres
= info
->var
.yres_virtual
;
904 if (!rect
->width
|| !rect
->height
|| rect
->dx
> vxres
|| rect
->dy
> vyres
)
907 /* We could use hardware clipping but on many cards you get around
908 * hardware clipping by writing to framebuffer directly. */
910 x2
= rect
->dx
+ rect
->width
;
911 y2
= rect
->dy
+ rect
->height
;
912 x2
= x2
< vxres
? x2
: vxres
;
913 y2
= y2
< vyres
? y2
: vyres
;
914 width
= x2
- rect
->dx
;
916 switch (info
->fix
.type
) {
917 case FB_TYPE_VGA_PLANES
:
918 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
920 height
= y2
- rect
->dy
;
921 width
= rect
->width
/8;
923 line_ofs
= info
->fix
.line_length
- width
;
924 dst
= info
->screen_base
+ (rect
->dx
/8) + rect
->dy
* info
->fix
.line_length
;
931 setcolor(rect
->color
);
937 for (x
= 0; x
< width
; x
++) {
953 for (x
= 0; x
< width
; x
++) {
962 vga_8planes_fillrect(info
, rect
);
964 case FB_TYPE_PACKED_PIXELS
:
966 cfb_fillrect(info
, rect
);
971 static void vga_8planes_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
973 char oldindex
= getindex();
974 char oldmode
= setmode(0x41);
975 char oldop
= setop(0);
976 char oldsr
= setsr(0xf);
977 int height
, line_ofs
, x
;
982 height
= area
->height
;
986 width
= area
->width
/ 4;
988 if (area
->dy
< area
->sy
|| (area
->dy
== area
->sy
&& dx
< sx
)) {
989 line_ofs
= info
->fix
.line_length
- width
;
990 dest
= info
->screen_base
+ dx
+ area
->dy
* info
->fix
.line_length
;
991 src
= info
->screen_base
+ sx
+ area
->sy
* info
->fix
.line_length
;
993 for (x
= 0; x
< width
; x
++) {
1003 line_ofs
= info
->fix
.line_length
- width
;
1004 dest
= info
->screen_base
+ dx
+ width
+
1005 (area
->dy
+ height
- 1) * info
->fix
.line_length
;
1006 src
= info
->screen_base
+ sx
+ width
+
1007 (area
->sy
+ height
- 1) * info
->fix
.line_length
;
1009 for (x
= 0; x
< width
; x
++) {
1026 static void vga16fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1028 u32 dx
= area
->dx
, dy
= area
->dy
, sx
= area
->sx
, sy
= area
->sy
;
1029 int x
, x2
, y2
, old_dx
, old_dy
, vxres
, vyres
;
1030 int height
, width
, line_ofs
;
1031 char __iomem
*dst
= NULL
;
1032 char __iomem
*src
= NULL
;
1034 vxres
= info
->var
.xres_virtual
;
1035 vyres
= info
->var
.yres_virtual
;
1037 if (area
->dx
> vxres
|| area
->sx
> vxres
|| area
->dy
> vyres
||
1041 /* clip the destination */
1046 * We could use hardware clipping but on many cards you get around
1047 * hardware clipping by writing to framebuffer directly.
1049 x2
= area
->dx
+ area
->width
;
1050 y2
= area
->dy
+ area
->height
;
1051 dx
= area
->dx
> 0 ? area
->dx
: 0;
1052 dy
= area
->dy
> 0 ? area
->dy
: 0;
1053 x2
= x2
< vxres
? x2
: vxres
;
1054 y2
= y2
< vyres
? y2
: vyres
;
1058 if (sx
+ dx
< old_dx
|| sy
+ dy
< old_dy
)
1061 /* update sx1,sy1 */
1062 sx
+= (dx
- old_dx
);
1063 sy
+= (dy
- old_dy
);
1065 /* the source must be completely inside the virtual screen */
1066 if (sx
+ width
> vxres
|| sy
+ height
> vyres
)
1069 switch (info
->fix
.type
) {
1070 case FB_TYPE_VGA_PLANES
:
1071 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1073 line_ofs
= info
->fix
.line_length
- width
;
1079 if (dy
< sy
|| (dy
== sy
&& dx
< sx
)) {
1080 dst
= info
->screen_base
+ (dx
/8) + dy
* info
->fix
.line_length
;
1081 src
= info
->screen_base
+ (sx
/8) + sy
* info
->fix
.line_length
;
1083 for (x
= 0; x
< width
; x
++) {
1093 dst
= info
->screen_base
+ (dx
/8) + width
+
1094 (dy
+ height
- 1) * info
->fix
.line_length
;
1095 src
= info
->screen_base
+ (sx
/8) + width
+
1096 (sy
+ height
- 1) * info
->fix
.line_length
;
1098 for (x
= 0; x
< width
; x
++) {
1109 vga_8planes_copyarea(info
, area
);
1111 case FB_TYPE_PACKED_PIXELS
:
1113 cfb_copyarea(info
, area
);
1118 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1119 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1120 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1122 #if defined(__LITTLE_ENDIAN)
1123 static const u16 transl_l
[] = TRANS_MASK_LOW
;
1124 static const u16 transl_h
[] = TRANS_MASK_HIGH
;
1125 #elif defined(__BIG_ENDIAN)
1126 static const u16 transl_l
[] = TRANS_MASK_HIGH
;
1127 static const u16 transl_h
[] = TRANS_MASK_LOW
;
1129 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1132 static void vga_8planes_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1134 char oldindex
= getindex();
1135 char oldmode
= setmode(0x40);
1136 char oldop
= setop(0);
1137 char oldsr
= setsr(0);
1138 char oldmask
= selectmask();
1139 const unsigned char *cdat
= image
->data
;
1141 char __iomem
*where
;
1145 where
= info
->screen_base
+ dx
+ image
->dy
* info
->fix
.line_length
;
1148 writeb(image
->bg_color
, where
);
1151 setmask(image
->fg_color
^ image
->bg_color
);
1154 for (y
= 0; y
< image
->height
; y
++, where
+= info
->fix
.line_length
)
1155 writew(transl_h
[cdat
[y
]&0xF] | transl_l
[cdat
[y
] >> 4], where
);
1163 static void vga_imageblit_expand(struct fb_info
*info
, const struct fb_image
*image
)
1165 char __iomem
*where
= info
->screen_base
+ (image
->dx
/8) +
1166 image
->dy
* info
->fix
.line_length
;
1167 struct vga16fb_par
*par
= info
->par
;
1168 char *cdat
= (char *) image
->data
;
1172 switch (info
->fix
.type
) {
1173 case FB_TYPE_VGA_PLANES
:
1174 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1179 setcolor(image
->fg_color
);
1183 writeb(image
->bg_color
, where
);
1185 readb(where
); /* fill latches */
1188 for (y
= 0; y
< image
->height
; y
++) {
1190 for (x
= image
->width
/8; x
--;)
1191 writeb(*cdat
++, dst
++);
1192 where
+= info
->fix
.line_length
;
1199 setcolor(image
->bg_color
);
1203 for (y
= 0; y
< image
->height
; y
++) {
1205 for (x
=image
->width
/8; x
--;){
1207 setcolor(image
->fg_color
);
1214 where
+= info
->fix
.line_length
;
1218 vga_8planes_imageblit(info
, image
);
1220 case FB_TYPE_PACKED_PIXELS
:
1222 cfb_imageblit(info
, image
);
1227 static void vga_imageblit_color(struct fb_info
*info
, const struct fb_image
*image
)
1232 struct vga16fb_par
*par
= info
->par
;
1233 char __iomem
*where
=
1234 info
->screen_base
+ image
->dy
* info
->fix
.line_length
+
1236 const char *cdat
= image
->data
;
1240 switch (info
->fix
.type
) {
1241 case FB_TYPE_VGA_PLANES
:
1242 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
&&
1248 for (y
= 0; y
< image
->height
; y
++) {
1249 for (x
= 0; x
< image
->width
; x
++) {
1254 setmask(1 << (7 - (x
% 8)));
1260 where
+= info
->fix
.line_length
;
1264 case FB_TYPE_PACKED_PIXELS
:
1265 cfb_imageblit(info
, image
);
1272 static void vga16fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1274 if (image
->depth
== 1)
1275 vga_imageblit_expand(info
, image
);
1277 vga_imageblit_color(info
, image
);
1280 static void vga16fb_destroy(struct fb_info
*info
)
1282 iounmap(info
->screen_base
);
1283 fb_dealloc_cmap(&info
->cmap
);
1284 /* XXX unshare VGA regions */
1285 framebuffer_release(info
);
1288 static const struct fb_ops vga16fb_ops
= {
1289 .owner
= THIS_MODULE
,
1290 .fb_open
= vga16fb_open
,
1291 .fb_release
= vga16fb_release
,
1292 __FB_DEFAULT_IOMEM_OPS_RDWR
,
1293 .fb_destroy
= vga16fb_destroy
,
1294 .fb_check_var
= vga16fb_check_var
,
1295 .fb_set_par
= vga16fb_set_par
,
1296 .fb_setcolreg
= vga16fb_setcolreg
,
1297 .fb_pan_display
= vga16fb_pan_display
,
1298 .fb_blank
= vga16fb_blank
,
1299 .fb_fillrect
= vga16fb_fillrect
,
1300 .fb_copyarea
= vga16fb_copyarea
,
1301 .fb_imageblit
= vga16fb_imageblit
,
1302 __FB_DEFAULT_IOMEM_OPS_MMAP
,
1305 static int vga16fb_probe(struct platform_device
*dev
)
1307 struct screen_info
*si
;
1308 struct fb_info
*info
;
1309 struct vga16fb_par
*par
;
1313 si
= dev_get_platdata(&dev
->dev
);
1317 ret
= check_mode_supported(si
);
1321 printk(KERN_DEBUG
"vga16fb: initializing\n");
1322 info
= framebuffer_alloc(sizeof(struct vga16fb_par
), &dev
->dev
);
1329 /* XXX share VGA_FB_PHYS_BASE and I/O region with vgacon and others */
1330 info
->screen_base
= (void __iomem
*)VGA_MAP_MEM(VGA_FB_PHYS_BASE
, 0);
1332 if (!info
->screen_base
) {
1333 printk(KERN_ERR
"vga16fb: unable to map device\n");
1338 printk(KERN_INFO
"vga16fb: mapped to 0x%p\n", info
->screen_base
);
1341 par
->isVGA
= si
->orig_video_isVGA
== VIDEO_TYPE_VGAC
;
1342 par
->palette_blanked
= 0;
1343 par
->vesa_blanked
= 0;
1345 i
= par
->isVGA
? 6 : 2;
1347 vga16fb_defined
.red
.length
= i
;
1348 vga16fb_defined
.green
.length
= i
;
1349 vga16fb_defined
.blue
.length
= i
;
1351 /* name should not depend on EGA/VGA */
1352 info
->fbops
= &vga16fb_ops
;
1353 info
->var
= vga16fb_defined
;
1354 info
->fix
= vga16fb_fix
;
1355 /* supports rectangles with widths of multiples of 8 */
1356 bitmap_zero(info
->pixmap
.blit_x
, FB_MAX_BLIT_WIDTH
);
1357 set_bit(8 - 1, info
->pixmap
.blit_x
);
1358 set_bit(16 - 1, info
->pixmap
.blit_x
);
1359 set_bit(24 - 1, info
->pixmap
.blit_x
);
1360 set_bit(32 - 1, info
->pixmap
.blit_x
);
1361 info
->flags
= FBINFO_HWACCEL_YPAN
;
1363 i
= (info
->var
.bits_per_pixel
== 8) ? 256 : 16;
1364 ret
= fb_alloc_cmap(&info
->cmap
, i
, 0);
1366 printk(KERN_ERR
"vga16fb: unable to allocate colormap\n");
1368 goto err_alloc_cmap
;
1371 if (vga16fb_check_var(&info
->var
, info
)) {
1372 printk(KERN_ERR
"vga16fb: unable to validate variable\n");
1377 vga16fb_update_fix(info
);
1379 ret
= devm_aperture_acquire_for_platform_device(dev
, VGA_FB_PHYS_BASE
, VGA_FB_PHYS_SIZE
);
1382 if (register_framebuffer(info
) < 0) {
1383 printk(KERN_ERR
"vga16fb: unable to register framebuffer\n");
1388 fb_info(info
, "%s frame buffer device\n", info
->fix
.id
);
1389 platform_set_drvdata(dev
, info
);
1394 fb_dealloc_cmap(&info
->cmap
);
1396 iounmap(info
->screen_base
);
1398 framebuffer_release(info
);
1403 static void vga16fb_remove(struct platform_device
*dev
)
1405 struct fb_info
*info
= platform_get_drvdata(dev
);
1408 unregister_framebuffer(info
);
1411 static const struct platform_device_id vga16fb_driver_id_table
[] = {
1412 {"ega-framebuffer", 0},
1413 {"vga-framebuffer", 0},
1416 MODULE_DEVICE_TABLE(platform
, vga16fb_driver_id_table
);
1418 static struct platform_driver vga16fb_driver
= {
1419 .probe
= vga16fb_probe
,
1420 .remove
= vga16fb_remove
,
1424 .id_table
= vga16fb_driver_id_table
,
1427 module_platform_driver(vga16fb_driver
);
1429 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1430 MODULE_LICENSE("GPL");