1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/mm.h>
18#include <linux/delay.h>
19#include <linux/fb.h>
20#include <linux/ioport.h>
21#include <linux/init.h>
22#include <linux/platform_device.h>
23#include <linux/screen_info.h>
24
25#include <asm/io.h>
26#include <video/vga.h>
27
28#define VGA_FB_PHYS 0xA0000
29#define VGA_FB_PHYS_LEN 65536
30
31#define MODE_SKIP4 1
32#define MODE_8BPP 2
33#define MODE_CFB 4
34#define MODE_TEXT 8
35
36
37
38
39
40
41
42struct vga16fb_par {
43
44
45 struct {
46 unsigned char SeqCtrlIndex;
47 unsigned char CrtCtrlIndex;
48 unsigned char CrtMiscIO;
49 unsigned char HorizontalTotal;
50 unsigned char HorizDisplayEnd;
51 unsigned char StartHorizRetrace;
52 unsigned char EndHorizRetrace;
53 unsigned char Overflow;
54 unsigned char StartVertRetrace;
55 unsigned char EndVertRetrace;
56 unsigned char ModeControl;
57 unsigned char ClockingMode;
58 } vga_state;
59 struct vgastate state;
60 unsigned int ref_count;
61 int palette_blanked, vesa_blanked, mode, isVGA;
62 u8 misc, pel_msk, vss, clkdiv;
63 u8 crtc[VGA_CRT_C];
64};
65
66
67
68static struct fb_var_screeninfo vga16fb_defined = {
69 .xres = 640,
70 .yres = 480,
71 .xres_virtual = 640,
72 .yres_virtual = 480,
73 .bits_per_pixel = 4,
74 .activate = FB_ACTIVATE_TEST,
75 .height = -1,
76 .width = -1,
77 .pixclock = 39721,
78 .left_margin = 48,
79 .right_margin = 16,
80 .upper_margin = 33,
81 .lower_margin = 10,
82 .hsync_len = 96,
83 .vsync_len = 2,
84 .vmode = FB_VMODE_NONINTERLACED,
85};
86
87
88static const struct fb_fix_screeninfo vga16fb_fix = {
89 .id = "VGA16 VGA",
90 .smem_start = VGA_FB_PHYS,
91 .smem_len = VGA_FB_PHYS_LEN,
92 .type = FB_TYPE_VGA_PLANES,
93 .type_aux = FB_AUX_VGA_PLANES_VGA4,
94 .visual = FB_VISUAL_PSEUDOCOLOR,
95 .xpanstep = 8,
96 .ypanstep = 1,
97 .line_length = 640 / 8,
98 .accel = FB_ACCEL_NONE
99};
100
101
102
103
104
105
106
107
108
109
110
111
112static inline void rmw(volatile char __iomem *p)
113{
114 readb(p);
115 writeb(1, p);
116}
117
118
119
120static inline int setmode(int mode)
121{
122 int oldmode;
123
124 oldmode = vga_io_rgfx(VGA_GFX_MODE);
125 vga_io_w(VGA_GFX_D, mode);
126 return oldmode;
127}
128
129
130static inline int selectmask(void)
131{
132 return vga_io_rgfx(VGA_GFX_BIT_MASK);
133}
134
135
136
137static inline void setmask(int mask)
138{
139 vga_io_w(VGA_GFX_D, mask);
140}
141
142
143
144
145static inline int setop(int op)
146{
147 int oldop;
148
149 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
150 vga_io_w(VGA_GFX_D, op);
151 return oldop;
152}
153
154
155
156static inline int setsr(int sr)
157{
158 int oldsr;
159
160 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
161 vga_io_w(VGA_GFX_D, sr);
162 return oldsr;
163}
164
165
166static inline int setcolor(int color)
167{
168 int oldcolor;
169
170 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
171 vga_io_w(VGA_GFX_D, color);
172 return oldcolor;
173}
174
175
176static inline int getindex(void)
177{
178 return vga_io_r(VGA_GFX_I);
179}
180
181
182static inline void setindex(int index)
183{
184 vga_io_w(VGA_GFX_I, index);
185}
186
187
188static inline int check_mode_supported(void)
189{
190
191#if defined(CONFIG_X86)
192
193 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EGAC &&
194 screen_info.orig_video_isVGA != VIDEO_TYPE_VGAC)
195 return -ENODEV;
196
197 if (screen_info.orig_video_mode != 0x0D &&
198 screen_info.orig_video_mode != 0x0E &&
199 screen_info.orig_video_mode != 0x10 &&
200 screen_info.orig_video_mode != 0x12)
201 return -ENODEV;
202#endif
203 return 0;
204}
205
206static void vga16fb_pan_var(struct fb_info *info,
207 struct fb_var_screeninfo *var)
208{
209 struct vga16fb_par *par = info->par;
210 u32 xoffset, pos;
211
212 xoffset = var->xoffset;
213 if (info->var.bits_per_pixel == 8) {
214 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
215 } else if (par->mode & MODE_TEXT) {
216 int fh = 16;
217 pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
218 } else {
219 if (info->var.nonstd)
220 xoffset--;
221 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
222 }
223 vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
224 vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
225
226
227 vga_io_r(VGA_IS1_RC);
228 vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
229 if (info->var.bits_per_pixel == 8)
230 vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
231 else
232 vga_io_w(VGA_ATT_IW, xoffset & 7);
233 vga_io_r(VGA_IS1_RC);
234 vga_io_w(VGA_ATT_IW, 0x20);
235}
236
237static void vga16fb_update_fix(struct fb_info *info)
238{
239 if (info->var.bits_per_pixel == 4) {
240 if (info->var.nonstd) {
241 info->fix.type = FB_TYPE_PACKED_PIXELS;
242 info->fix.line_length = info->var.xres_virtual / 2;
243 } else {
244 info->fix.type = FB_TYPE_VGA_PLANES;
245 info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
246 info->fix.line_length = info->var.xres_virtual / 8;
247 }
248 } else if (info->var.bits_per_pixel == 0) {
249 info->fix.type = FB_TYPE_TEXT;
250 info->fix.type_aux = FB_AUX_TEXT_CGA;
251 info->fix.line_length = info->var.xres_virtual / 4;
252 } else {
253 if (info->var.nonstd) {
254 info->fix.type = FB_TYPE_VGA_PLANES;
255 info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
256 info->fix.line_length = info->var.xres_virtual / 4;
257 } else {
258 info->fix.type = FB_TYPE_PACKED_PIXELS;
259 info->fix.line_length = info->var.xres_virtual;
260 }
261 }
262}
263
264static void vga16fb_clock_chip(struct vga16fb_par *par,
265 unsigned int *pixclock,
266 const struct fb_info *info,
267 int mul, int div)
268{
269 static const struct {
270 u32 pixclock;
271 u8 misc;
272 u8 seq_clock_mode;
273 } *ptr, *best, vgaclocks[] = {
274 { 79442 , 0x00, 0x08},
275 { 70616 , 0x04, 0x08},
276 { 39721 , 0x00, 0x00},
277 { 35308 , 0x04, 0x00},
278 { 0 , 0x00, 0x00}};
279 int err;
280
281 *pixclock = (*pixclock * mul) / div;
282 best = vgaclocks;
283 err = *pixclock - best->pixclock;
284 if (err < 0) err = -err;
285 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
286 int tmp;
287
288 tmp = *pixclock - ptr->pixclock;
289 if (tmp < 0) tmp = -tmp;
290 if (tmp < err) {
291 err = tmp;
292 best = ptr;
293 }
294 }
295 par->misc |= best->misc;
296 par->clkdiv = best->seq_clock_mode;
297 *pixclock = (best->pixclock * div) / mul;
298}
299
300#define FAIL(X) return -EINVAL
301
302static int vga16fb_open(struct fb_info *info, int user)
303{
304 struct vga16fb_par *par = info->par;
305
306 if (!par->ref_count) {
307 memset(&par->state, 0, sizeof(struct vgastate));
308 par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
309 VGA_SAVE_CMAP;
310 save_vga(&par->state);
311 }
312 par->ref_count++;
313
314 return 0;
315}
316
317static int vga16fb_release(struct fb_info *info, int user)
318{
319 struct vga16fb_par *par = info->par;
320
321 if (!par->ref_count)
322 return -EINVAL;
323
324 if (par->ref_count == 1)
325 restore_vga(&par->state);
326 par->ref_count--;
327
328 return 0;
329}
330
331static int vga16fb_check_var(struct fb_var_screeninfo *var,
332 struct fb_info *info)
333{
334 struct vga16fb_par *par = info->par;
335 u32 xres, right, hslen, left, xtotal;
336 u32 yres, lower, vslen, upper, ytotal;
337 u32 vxres, xoffset, vyres, yoffset;
338 u32 pos;
339 u8 r7, rMode;
340 int shift;
341 int mode;
342 u32 maxmem;
343
344 par->pel_msk = 0xFF;
345
346 if (var->bits_per_pixel == 4) {
347 if (var->nonstd) {
348 if (!par->isVGA)
349 return -EINVAL;
350 shift = 3;
351 mode = MODE_SKIP4 | MODE_CFB;
352 maxmem = 16384;
353 par->pel_msk = 0x0F;
354 } else {
355 shift = 3;
356 mode = 0;
357 maxmem = 65536;
358 }
359 } else if (var->bits_per_pixel == 8) {
360 if (!par->isVGA)
361 return -EINVAL;
362 shift = 2;
363 if (var->nonstd) {
364 mode = MODE_8BPP | MODE_CFB;
365 maxmem = 65536;
366 } else {
367 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
368 maxmem = 16384;
369 }
370 } else
371 return -EINVAL;
372
373 xres = (var->xres + 7) & ~7;
374 vxres = (var->xres_virtual + 0xF) & ~0xF;
375 xoffset = (var->xoffset + 7) & ~7;
376 left = (var->left_margin + 7) & ~7;
377 right = (var->right_margin + 7) & ~7;
378 hslen = (var->hsync_len + 7) & ~7;
379
380 if (vxres < xres)
381 vxres = xres;
382 if (xres + xoffset > vxres)
383 xoffset = vxres - xres;
384
385 var->xres = xres;
386 var->right_margin = right;
387 var->hsync_len = hslen;
388 var->left_margin = left;
389 var->xres_virtual = vxres;
390 var->xoffset = xoffset;
391
392 xres >>= shift;
393 right >>= shift;
394 hslen >>= shift;
395 left >>= shift;
396 vxres >>= shift;
397 xtotal = xres + right + hslen + left;
398 if (xtotal >= 256)
399 FAIL("xtotal too big");
400 if (hslen > 32)
401 FAIL("hslen too big");
402 if (right + hslen + left > 64)
403 FAIL("hblank too big");
404 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
405 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
406 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
407 pos = xres + right;
408 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
409 pos += hslen;
410 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
411 pos += left - 2;
412 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
413 if (pos & 0x20)
414 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
415
416 yres = var->yres;
417 lower = var->lower_margin;
418 vslen = var->vsync_len;
419 upper = var->upper_margin;
420 vyres = var->yres_virtual;
421 yoffset = var->yoffset;
422
423 if (yres > vyres)
424 vyres = yres;
425 if (vxres * vyres > maxmem) {
426 vyres = maxmem / vxres;
427 if (vyres < yres)
428 return -ENOMEM;
429 }
430 if (yoffset + yres > vyres)
431 yoffset = vyres - yres;
432 var->yres = yres;
433 var->lower_margin = lower;
434 var->vsync_len = vslen;
435 var->upper_margin = upper;
436 var->yres_virtual = vyres;
437 var->yoffset = yoffset;
438
439 if (var->vmode & FB_VMODE_DOUBLE) {
440 yres <<= 1;
441 lower <<= 1;
442 vslen <<= 1;
443 upper <<= 1;
444 }
445 ytotal = yres + lower + vslen + upper;
446 if (ytotal > 1024) {
447 ytotal >>= 1;
448 yres >>= 1;
449 lower >>= 1;
450 vslen >>= 1;
451 upper >>= 1;
452 rMode = 0x04;
453 } else
454 rMode = 0x00;
455 if (ytotal > 1024)
456 FAIL("ytotal too big");
457 if (vslen > 16)
458 FAIL("vslen too big");
459 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
460 r7 = 0x10;
461 if (ytotal & 0x100) r7 |= 0x01;
462 if (ytotal & 0x200) r7 |= 0x20;
463 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
464 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;
465 if (var->vmode & FB_VMODE_DOUBLE)
466 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
467 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
468 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
469 if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
470 xoffset--;
471 pos = yoffset * vxres + (xoffset >> shift);
472 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
473 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
474 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
475 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
476 pos = yres - 1;
477 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
478 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
479 if (pos & 0x100)
480 r7 |= 0x0A;
481 if (pos & 0x200) {
482 r7 |= 0x40;
483 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
484 }
485 pos += lower;
486 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
487 if (pos & 0x100)
488 r7 |= 0x04;
489 if (pos & 0x200)
490 r7 |= 0x80;
491 pos += vslen;
492 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10;
493 pos += upper - 1;
494 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF;
495
496 if (vxres >= 512)
497 FAIL("vxres too long");
498 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
499 if (mode & MODE_SKIP4)
500 par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;
501 else
502 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;
503 par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
504 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
505 par->crtc[VGA_CRTC_OVERFLOW] = r7;
506
507 par->vss = 0x00;
508
509 par->misc = 0xE3;
510 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
511 par->misc &= ~0x40;
512 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
513 par->misc &= ~0x80;
514
515 par->mode = mode;
516
517 if (mode & MODE_8BPP)
518
519 vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
520 else
521
522 vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
523
524 var->red.offset = var->green.offset = var->blue.offset =
525 var->transp.offset = 0;
526 var->red.length = var->green.length = var->blue.length =
527 (par->isVGA) ? 6 : 2;
528 var->transp.length = 0;
529 var->activate = FB_ACTIVATE_NOW;
530 var->height = -1;
531 var->width = -1;
532 var->accel_flags = 0;
533 return 0;
534}
535#undef FAIL
536
537static int vga16fb_set_par(struct fb_info *info)
538{
539 struct vga16fb_par *par = info->par;
540 u8 gdc[VGA_GFX_C];
541 u8 seq[VGA_SEQ_C];
542 u8 atc[VGA_ATT_C];
543 int fh, i;
544
545 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
546 if (par->mode & MODE_TEXT)
547 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
548 else
549 seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
550 seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
551 if (par->mode & MODE_TEXT)
552 seq[VGA_SEQ_MEMORY_MODE] = 0x03;
553 else if (par->mode & MODE_SKIP4)
554 seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
555 else
556 seq[VGA_SEQ_MEMORY_MODE] = 0x06;
557
558 gdc[VGA_GFX_SR_VALUE] = 0x00;
559 gdc[VGA_GFX_SR_ENABLE] = 0x00;
560 gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
561 gdc[VGA_GFX_DATA_ROTATE] = 0x00;
562 gdc[VGA_GFX_PLANE_READ] = 0;
563 if (par->mode & MODE_TEXT) {
564 gdc[VGA_GFX_MODE] = 0x10;
565 gdc[VGA_GFX_MISC] = 0x06;
566 } else {
567 if (par->mode & MODE_CFB)
568 gdc[VGA_GFX_MODE] = 0x40;
569 else
570 gdc[VGA_GFX_MODE] = 0x00;
571 gdc[VGA_GFX_MISC] = 0x05;
572 }
573 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
574 gdc[VGA_GFX_BIT_MASK] = 0xFF;
575
576 for (i = 0x00; i < 0x10; i++)
577 atc[i] = i;
578 if (par->mode & MODE_TEXT)
579 atc[VGA_ATC_MODE] = 0x04;
580 else if (par->mode & MODE_8BPP)
581 atc[VGA_ATC_MODE] = 0x41;
582 else
583 atc[VGA_ATC_MODE] = 0x81;
584 atc[VGA_ATC_OVERSCAN] = 0x00;
585 atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
586 if (par->mode & MODE_8BPP)
587 atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
588 else
589 atc[VGA_ATC_PEL] = info->var.xoffset & 7;
590 atc[VGA_ATC_COLOR_PAGE] = 0x00;
591
592 if (par->mode & MODE_TEXT) {
593 fh = 16;
594 par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
595 & ~0x1F) | (fh - 1);
596 }
597
598 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
599
600
601 if (!par->isVGA) {
602 vga_io_w(EGA_GFX_E0, 0x00);
603 vga_io_w(EGA_GFX_E1, 0x01);
604 }
605
606
607 vga_io_w(VGA_MIS_W, par->misc);
608
609
610 vga_io_wseq(0x00, 0x01);
611
612 if (par->isVGA)
613 vga_io_w(VGA_PEL_MSK, par->pel_msk);
614
615
616 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
617 for (i = 2; i < VGA_SEQ_C; i++) {
618 vga_io_wseq(i, seq[i]);
619 }
620
621
622 vga_io_wseq(0x00, 0x03);
623
624
625 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
626
627
628 for (i = 0; i < VGA_CRTC_REGS; i++) {
629 vga_io_wcrt(i, par->crtc[i]);
630 }
631
632
633 for (i = 0; i < VGA_GFX_C; i++) {
634 vga_io_wgfx(i, gdc[i]);
635 }
636
637
638 for (i = 0; i < VGA_ATT_C; i++) {
639 vga_io_r(VGA_IS1_RC);
640 vga_io_wattr(i, atc[i]);
641 }
642
643
644 mdelay(50);
645
646 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
647
648 vga_io_r(VGA_IS1_RC);
649 vga_io_w(VGA_ATT_IW, 0x20);
650
651 vga16fb_update_fix(info);
652 return 0;
653}
654
655static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
656{
657 static const unsigned char map[] = { 000, 001, 010, 011 };
658 int val;
659
660 if (regno >= 16)
661 return;
662 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
663 vga_io_r(VGA_IS1_RC);
664 vga_io_wattr(regno, val);
665 vga_io_r(VGA_IS1_RC);
666 vga_io_w(VGA_ATT_IW, 0x20);
667}
668
669static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
670{
671 outb(regno, VGA_PEL_IW);
672 outb(red >> 10, VGA_PEL_D);
673 outb(green >> 10, VGA_PEL_D);
674 outb(blue >> 10, VGA_PEL_D);
675}
676
677static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
678 unsigned blue, unsigned transp,
679 struct fb_info *info)
680{
681 struct vga16fb_par *par = info->par;
682 int gray;
683
684
685
686
687
688
689
690
691 if (regno >= 256)
692 return 1;
693
694 gray = info->var.grayscale;
695
696 if (gray) {
697
698 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
699 }
700 if (par->isVGA)
701 vga16_setpalette(regno,red,green,blue);
702 else
703 ega16_setpalette(regno,red,green,blue);
704 return 0;
705}
706
707static int vga16fb_pan_display(struct fb_var_screeninfo *var,
708 struct fb_info *info)
709{
710 vga16fb_pan_var(info, var);
711 return 0;
712}
713
714
715
716
717
718
719static void vga_vesa_blank(struct vga16fb_par *par, int mode)
720{
721 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
722 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
723
724
725 if(!par->vesa_blanked) {
726 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
727
728
729 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00);
730 par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01);
731 par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);
732 par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05);
733 par->vga_state.Overflow = vga_io_rcrt(0x07);
734 par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);
735 par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);
736 par->vga_state.ModeControl = vga_io_rcrt(0x17);
737 par->vga_state.ClockingMode = vga_io_rseq(0x01);
738 }
739
740
741
742 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
743
744
745 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
746 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
747
748
749
750
751
752
753 if (mode & FB_BLANK_VSYNC_SUSPEND) {
754 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
755 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
756
757 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
758 }
759
760 if (mode & FB_BLANK_HSYNC_SUSPEND) {
761
762
763
764
765
766 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
767 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
768 }
769
770
771 outb_p(SeqCtrlIndex, VGA_SEQ_I);
772 outb_p(CrtCtrlIndex, VGA_CRT_IC);
773}
774
775static void vga_vesa_unblank(struct vga16fb_par *par)
776{
777 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
778 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
779
780
781 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
782
783
784 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
785
786 vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
787
788 vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
789
790 vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
791
792 vga_io_wcrt(0x07, par->vga_state.Overflow);
793
794 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
795
796 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
797
798 vga_io_wcrt(0x17, par->vga_state.ModeControl);
799
800 vga_io_wseq(0x01, par->vga_state.ClockingMode);
801
802
803 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
804 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
805}
806
807static void vga_pal_blank(void)
808{
809 int i;
810
811 for (i=0; i<16; i++) {
812 outb_p(i, VGA_PEL_IW);
813 outb_p(0, VGA_PEL_D);
814 outb_p(0, VGA_PEL_D);
815 outb_p(0, VGA_PEL_D);
816 }
817}
818
819
820static int vga16fb_blank(int blank, struct fb_info *info)
821{
822 struct vga16fb_par *par = info->par;
823
824 switch (blank) {
825 case FB_BLANK_UNBLANK:
826 if (par->vesa_blanked) {
827 vga_vesa_unblank(par);
828 par->vesa_blanked = 0;
829 }
830 if (par->palette_blanked) {
831 par->palette_blanked = 0;
832 }
833 break;
834 case FB_BLANK_NORMAL:
835 vga_pal_blank();
836 par->palette_blanked = 1;
837 break;
838 default:
839 vga_vesa_blank(par, blank);
840 par->vesa_blanked = 1;
841 break;
842 }
843 return 0;
844}
845
846static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
847{
848 u32 dx = rect->dx, width = rect->width;
849 char oldindex = getindex();
850 char oldmode = setmode(0x40);
851 char oldmask = selectmask();
852 int line_ofs, height;
853 char oldop, oldsr;
854 char __iomem *where;
855
856 dx /= 4;
857 where = info->screen_base + dx + rect->dy * info->fix.line_length;
858
859 if (rect->rop == ROP_COPY) {
860 oldop = setop(0);
861 oldsr = setsr(0);
862
863 width /= 4;
864 line_ofs = info->fix.line_length - width;
865 setmask(0xff);
866
867 height = rect->height;
868
869 while (height--) {
870 int x;
871
872
873 for (x = width; x > 0; --x) {
874 writeb(rect->color, where);
875 where++;
876 }
877 where += line_ofs;
878 }
879 } else {
880 char oldcolor = setcolor(0xf);
881 int y;
882
883 oldop = setop(0x18);
884 oldsr = setsr(0xf);
885 setmask(0x0F);
886 for (y = 0; y < rect->height; y++) {
887 rmw(where);
888 rmw(where+1);
889 where += info->fix.line_length;
890 }
891 setcolor(oldcolor);
892 }
893 setmask(oldmask);
894 setsr(oldsr);
895 setop(oldop);
896 setmode(oldmode);
897 setindex(oldindex);
898}
899
900static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
901{
902 int x, x2, y2, vxres, vyres, width, height, line_ofs;
903 char __iomem *dst;
904
905 vxres = info->var.xres_virtual;
906 vyres = info->var.yres_virtual;
907
908 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
909 return;
910
911
912
913
914 x2 = rect->dx + rect->width;
915 y2 = rect->dy + rect->height;
916 x2 = x2 < vxres ? x2 : vxres;
917 y2 = y2 < vyres ? y2 : vyres;
918 width = x2 - rect->dx;
919
920 switch (info->fix.type) {
921 case FB_TYPE_VGA_PLANES:
922 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
923
924 height = y2 - rect->dy;
925 width = rect->width/8;
926
927 line_ofs = info->fix.line_length - width;
928 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
929
930 switch (rect->rop) {
931 case ROP_COPY:
932 setmode(0);
933 setop(0);
934 setsr(0xf);
935 setcolor(rect->color);
936 selectmask();
937
938 setmask(0xff);
939
940 while (height--) {
941 for (x = 0; x < width; x++) {
942 writeb(0, dst);
943 dst++;
944 }
945 dst += line_ofs;
946 }
947 break;
948 case ROP_XOR:
949 setmode(0);
950 setop(0x18);
951 setsr(0xf);
952 setcolor(0xf);
953 selectmask();
954
955 setmask(0xff);
956 while (height--) {
957 for (x = 0; x < width; x++) {
958 rmw(dst);
959 dst++;
960 }
961 dst += line_ofs;
962 }
963 break;
964 }
965 } else
966 vga_8planes_fillrect(info, rect);
967 break;
968 case FB_TYPE_PACKED_PIXELS:
969 default:
970 cfb_fillrect(info, rect);
971 break;
972 }
973}
974
975static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
976{
977 char oldindex = getindex();
978 char oldmode = setmode(0x41);
979 char oldop = setop(0);
980 char oldsr = setsr(0xf);
981 int height, line_ofs, x;
982 u32 sx, dx, width;
983 char __iomem *dest;
984 char __iomem *src;
985
986 height = area->height;
987
988 sx = area->sx / 4;
989 dx = area->dx / 4;
990 width = area->width / 4;
991
992 if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
993 line_ofs = info->fix.line_length - width;
994 dest = info->screen_base + dx + area->dy * info->fix.line_length;
995 src = info->screen_base + sx + area->sy * info->fix.line_length;
996 while (height--) {
997 for (x = 0; x < width; x++) {
998 readb(src);
999 writeb(0, dest);
1000 src++;
1001 dest++;
1002 }
1003 src += line_ofs;
1004 dest += line_ofs;
1005 }
1006 } else {
1007 line_ofs = info->fix.line_length - width;
1008 dest = info->screen_base + dx + width +
1009 (area->dy + height - 1) * info->fix.line_length;
1010 src = info->screen_base + sx + width +
1011 (area->sy + height - 1) * info->fix.line_length;
1012 while (height--) {
1013 for (x = 0; x < width; x++) {
1014 --src;
1015 --dest;
1016 readb(src);
1017 writeb(0, dest);
1018 }
1019 src -= line_ofs;
1020 dest -= line_ofs;
1021 }
1022 }
1023
1024 setsr(oldsr);
1025 setop(oldop);
1026 setmode(oldmode);
1027 setindex(oldindex);
1028}
1029
1030static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1031{
1032 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1033 int x, x2, y2, old_dx, old_dy, vxres, vyres;
1034 int height, width, line_ofs;
1035 char __iomem *dst = NULL;
1036 char __iomem *src = NULL;
1037
1038 vxres = info->var.xres_virtual;
1039 vyres = info->var.yres_virtual;
1040
1041 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1042 area->sy > vyres)
1043 return;
1044
1045
1046 old_dx = area->dx;
1047 old_dy = area->dy;
1048
1049
1050
1051
1052
1053 x2 = area->dx + area->width;
1054 y2 = area->dy + area->height;
1055 dx = area->dx > 0 ? area->dx : 0;
1056 dy = area->dy > 0 ? area->dy : 0;
1057 x2 = x2 < vxres ? x2 : vxres;
1058 y2 = y2 < vyres ? y2 : vyres;
1059 width = x2 - dx;
1060 height = y2 - dy;
1061
1062 if (sx + dx < old_dx || sy + dy < old_dy)
1063 return;
1064
1065
1066 sx += (dx - old_dx);
1067 sy += (dy - old_dy);
1068
1069
1070 if (sx + width > vxres || sy + height > vyres)
1071 return;
1072
1073 switch (info->fix.type) {
1074 case FB_TYPE_VGA_PLANES:
1075 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1076 width = width/8;
1077 line_ofs = info->fix.line_length - width;
1078
1079 setmode(1);
1080 setop(0);
1081 setsr(0xf);
1082
1083 if (dy < sy || (dy == sy && dx < sx)) {
1084 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1085 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1086 while (height--) {
1087 for (x = 0; x < width; x++) {
1088 readb(src);
1089 writeb(0, dst);
1090 dst++;
1091 src++;
1092 }
1093 src += line_ofs;
1094 dst += line_ofs;
1095 }
1096 } else {
1097 dst = info->screen_base + (dx/8) + width +
1098 (dy + height - 1) * info->fix.line_length;
1099 src = info->screen_base + (sx/8) + width +
1100 (sy + height - 1) * info->fix.line_length;
1101 while (height--) {
1102 for (x = 0; x < width; x++) {
1103 dst--;
1104 src--;
1105 readb(src);
1106 writeb(0, dst);
1107 }
1108 src -= line_ofs;
1109 dst -= line_ofs;
1110 }
1111 }
1112 } else
1113 vga_8planes_copyarea(info, area);
1114 break;
1115 case FB_TYPE_PACKED_PIXELS:
1116 default:
1117 cfb_copyarea(info, area);
1118 break;
1119 }
1120}
1121
1122#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1123#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1124 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1125
1126#if defined(__LITTLE_ENDIAN)
1127static const u16 transl_l[] = TRANS_MASK_LOW;
1128static const u16 transl_h[] = TRANS_MASK_HIGH;
1129#elif defined(__BIG_ENDIAN)
1130static const u16 transl_l[] = TRANS_MASK_HIGH;
1131static const u16 transl_h[] = TRANS_MASK_LOW;
1132#else
1133#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1134#endif
1135
1136static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1137{
1138 char oldindex = getindex();
1139 char oldmode = setmode(0x40);
1140 char oldop = setop(0);
1141 char oldsr = setsr(0);
1142 char oldmask = selectmask();
1143 const unsigned char *cdat = image->data;
1144 u32 dx = image->dx;
1145 char __iomem *where;
1146 int y;
1147
1148 dx /= 4;
1149 where = info->screen_base + dx + image->dy * info->fix.line_length;
1150
1151 setmask(0xff);
1152 writeb(image->bg_color, where);
1153 readb(where);
1154 selectmask();
1155 setmask(image->fg_color ^ image->bg_color);
1156 setmode(0x42);
1157 setop(0x18);
1158 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1159 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1160 setmask(oldmask);
1161 setsr(oldsr);
1162 setop(oldop);
1163 setmode(oldmode);
1164 setindex(oldindex);
1165}
1166
1167static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1168{
1169 char __iomem *where = info->screen_base + (image->dx/8) +
1170 image->dy * info->fix.line_length;
1171 struct vga16fb_par *par = info->par;
1172 char *cdat = (char *) image->data;
1173 char __iomem *dst;
1174 int x, y;
1175
1176 switch (info->fix.type) {
1177 case FB_TYPE_VGA_PLANES:
1178 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1179 if (par->isVGA) {
1180 setmode(2);
1181 setop(0);
1182 setsr(0xf);
1183 setcolor(image->fg_color);
1184 selectmask();
1185
1186 setmask(0xff);
1187 writeb(image->bg_color, where);
1188 rmb();
1189 readb(where);
1190 setmode(3);
1191 wmb();
1192 for (y = 0; y < image->height; y++) {
1193 dst = where;
1194 for (x = image->width/8; x--;)
1195 writeb(*cdat++, dst++);
1196 where += info->fix.line_length;
1197 }
1198 wmb();
1199 } else {
1200 setmode(0);
1201 setop(0);
1202 setsr(0xf);
1203 setcolor(image->bg_color);
1204 selectmask();
1205
1206 setmask(0xff);
1207 for (y = 0; y < image->height; y++) {
1208 dst = where;
1209 for (x=image->width/8; x--;){
1210 rmw(dst);
1211 setcolor(image->fg_color);
1212 selectmask();
1213 if (*cdat) {
1214 setmask(*cdat++);
1215 rmw(dst++);
1216 }
1217 }
1218 where += info->fix.line_length;
1219 }
1220 }
1221 } else
1222 vga_8planes_imageblit(info, image);
1223 break;
1224 case FB_TYPE_PACKED_PIXELS:
1225 default:
1226 cfb_imageblit(info, image);
1227 break;
1228 }
1229}
1230
1231static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1232{
1233
1234
1235
1236 struct vga16fb_par *par = info->par;
1237 char __iomem *where =
1238 info->screen_base + image->dy * info->fix.line_length +
1239 image->dx/8;
1240 const char *cdat = image->data;
1241 char __iomem *dst;
1242 int x, y;
1243
1244 switch (info->fix.type) {
1245 case FB_TYPE_VGA_PLANES:
1246 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1247 par->isVGA) {
1248 setsr(0xf);
1249 setop(0);
1250 setmode(0);
1251
1252 for (y = 0; y < image->height; y++) {
1253 for (x = 0; x < image->width; x++) {
1254 dst = where + x/8;
1255
1256 setcolor(*cdat);
1257 selectmask();
1258 setmask(1 << (7 - (x % 8)));
1259 fb_readb(dst);
1260 fb_writeb(0, dst);
1261
1262 cdat++;
1263 }
1264 where += info->fix.line_length;
1265 }
1266 }
1267 break;
1268 case FB_TYPE_PACKED_PIXELS:
1269 cfb_imageblit(info, image);
1270 break;
1271 default:
1272 break;
1273 }
1274}
1275
1276static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1277{
1278 if (image->depth == 1)
1279 vga_imageblit_expand(info, image);
1280 else
1281 vga_imageblit_color(info, image);
1282}
1283
1284static void vga16fb_destroy(struct fb_info *info)
1285{
1286 iounmap(info->screen_base);
1287 fb_dealloc_cmap(&info->cmap);
1288
1289 framebuffer_release(info);
1290}
1291
1292static const struct fb_ops vga16fb_ops = {
1293 .owner = THIS_MODULE,
1294 .fb_open = vga16fb_open,
1295 .fb_release = vga16fb_release,
1296 .fb_destroy = vga16fb_destroy,
1297 .fb_check_var = vga16fb_check_var,
1298 .fb_set_par = vga16fb_set_par,
1299 .fb_setcolreg = vga16fb_setcolreg,
1300 .fb_pan_display = vga16fb_pan_display,
1301 .fb_blank = vga16fb_blank,
1302 .fb_fillrect = vga16fb_fillrect,
1303 .fb_copyarea = vga16fb_copyarea,
1304 .fb_imageblit = vga16fb_imageblit,
1305};
1306
1307#ifndef MODULE
1308static int __init vga16fb_setup(char *options)
1309{
1310 char *this_opt;
1311
1312 if (!options || !*options)
1313 return 0;
1314
1315 while ((this_opt = strsep(&options, ",")) != NULL) {
1316 if (!*this_opt) continue;
1317 }
1318 return 0;
1319}
1320#endif
1321
1322static int vga16fb_probe(struct platform_device *dev)
1323{
1324 struct fb_info *info;
1325 struct vga16fb_par *par;
1326 int i;
1327 int ret = 0;
1328
1329 printk(KERN_DEBUG "vga16fb: initializing\n");
1330 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1331
1332 if (!info) {
1333 ret = -ENOMEM;
1334 goto err_fb_alloc;
1335 }
1336 info->apertures = alloc_apertures(1);
1337 if (!info->apertures) {
1338 ret = -ENOMEM;
1339 goto err_ioremap;
1340 }
1341
1342
1343 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1344
1345 if (!info->screen_base) {
1346 printk(KERN_ERR "vga16fb: unable to map device\n");
1347 ret = -ENOMEM;
1348 goto err_ioremap;
1349 }
1350
1351 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1352 par = info->par;
1353
1354 par->isVGA = screen_info.orig_video_isVGA;
1355 par->palette_blanked = 0;
1356 par->vesa_blanked = 0;
1357
1358 i = par->isVGA? 6 : 2;
1359
1360 vga16fb_defined.red.length = i;
1361 vga16fb_defined.green.length = i;
1362 vga16fb_defined.blue.length = i;
1363
1364
1365 info->fbops = &vga16fb_ops;
1366 info->var = vga16fb_defined;
1367 info->fix = vga16fb_fix;
1368
1369 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1370 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
1371 FBINFO_HWACCEL_YPAN;
1372
1373 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1374 ret = fb_alloc_cmap(&info->cmap, i, 0);
1375 if (ret) {
1376 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1377 ret = -ENOMEM;
1378 goto err_alloc_cmap;
1379 }
1380
1381 if (vga16fb_check_var(&info->var, info)) {
1382 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1383 ret = -EINVAL;
1384 goto err_check_var;
1385 }
1386
1387 vga16fb_update_fix(info);
1388
1389 info->apertures->ranges[0].base = VGA_FB_PHYS;
1390 info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
1391
1392 if (register_framebuffer(info) < 0) {
1393 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1394 ret = -EINVAL;
1395 goto err_check_var;
1396 }
1397
1398 fb_info(info, "%s frame buffer device\n", info->fix.id);
1399 platform_set_drvdata(dev, info);
1400
1401 return 0;
1402
1403 err_check_var:
1404 fb_dealloc_cmap(&info->cmap);
1405 err_alloc_cmap:
1406 iounmap(info->screen_base);
1407 err_ioremap:
1408 framebuffer_release(info);
1409 err_fb_alloc:
1410 return ret;
1411}
1412
1413static int vga16fb_remove(struct platform_device *dev)
1414{
1415 struct fb_info *info = platform_get_drvdata(dev);
1416
1417 if (info)
1418 unregister_framebuffer(info);
1419
1420 return 0;
1421}
1422
1423static struct platform_driver vga16fb_driver = {
1424 .probe = vga16fb_probe,
1425 .remove = vga16fb_remove,
1426 .driver = {
1427 .name = "vga16fb",
1428 },
1429};
1430
1431static struct platform_device *vga16fb_device;
1432
1433static int __init vga16fb_init(void)
1434{
1435 int ret;
1436#ifndef MODULE
1437 char *option = NULL;
1438
1439 if (fb_get_options("vga16fb", &option))
1440 return -ENODEV;
1441
1442 vga16fb_setup(option);
1443#endif
1444
1445 ret = check_mode_supported();
1446 if (ret)
1447 return ret;
1448
1449 ret = platform_driver_register(&vga16fb_driver);
1450
1451 if (!ret) {
1452 vga16fb_device = platform_device_alloc("vga16fb", 0);
1453
1454 if (vga16fb_device)
1455 ret = platform_device_add(vga16fb_device);
1456 else
1457 ret = -ENOMEM;
1458
1459 if (ret) {
1460 platform_device_put(vga16fb_device);
1461 platform_driver_unregister(&vga16fb_driver);
1462 }
1463 }
1464
1465 return ret;
1466}
1467
1468static void __exit vga16fb_exit(void)
1469{
1470 platform_device_unregister(vga16fb_device);
1471 platform_driver_unregister(&vga16fb_driver);
1472}
1473
1474MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1475MODULE_LICENSE("GPL");
1476module_init(vga16fb_init);
1477module_exit(vga16fb_exit);
1478