2 * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device
4 * Copyright (C) 1994 Martin Schaller & Roman Hodek
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
11 * - 03 Jan 95: Original version by Martin Schaller: The TT driver and
12 * all the device independent stuff
13 * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
14 * and wrote the Falcon, ST(E), and External drivers
15 * based on the original TT driver.
16 * - 07 May 95: Martin: Added colormap operations for the external driver
17 * - 21 May 95: Martin: Added support for overscan
18 * Andreas: some bug fixes for this
19 * - Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>:
20 * Programmable Falcon video modes
21 * (thanks to Christian Cartus for documentation
22 * of VIDEL registers).
23 * - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]"
24 * on minor 24...31. "user0" may be set on commandline by
25 * "R<x>;<y>;<depth>". (Makes sense only on Falcon)
26 * Video mode switch on Falcon now done at next VBL interrupt
27 * to avoid the annoying right shift of the screen.
28 * - 23 Sep 97: Juergen: added xres_virtual for cards like ProMST
29 * The external-part is legacy, therefore hardware-specific
30 * functions like panning/hardwarescrolling/blanking isn't
32 * - 29 Sep 97: Juergen: added Romans suggestion for pan_display
33 * (var->xoffset was changed even if no set_screen_base avail.)
34 * - 05 Oct 97: Juergen: extfb (PACKED_PIXEL) is FB_PSEUDOCOLOR 'cause
35 * we know how to set the colors
36 * ext_*palette: read from ext_colors (former MV300_colors)
37 * write to ext_colors and RAMDAC
40 * - For the Falcon it is not possible to set random video modes on
41 * SM124 and SC/TV, only the bootup resolution is supported.
50 #include <linux/module.h>
51 #include <linux/kernel.h>
52 #include <linux/sched.h>
53 #include <linux/errno.h>
54 #include <linux/string.h>
56 #include <linux/slab.h>
57 #include <linux/delay.h>
58 #include <linux/init.h>
59 #include <linux/interrupt.h>
61 #include <asm/setup.h>
62 #include <asm/uaccess.h>
63 #include <asm/pgtable.h>
67 #include <asm/atarihw.h>
68 #include <asm/atariints.h>
69 #include <asm/atari_stram.h>
72 #include <asm/atarikb.h>
74 #include <video/fbcon.h>
75 #include <video/fbcon-cfb8.h>
76 #include <video/fbcon-cfb16.h>
77 #include <video/fbcon-iplan2p2.h>
78 #include <video/fbcon-iplan2p4.h>
79 #include <video/fbcon-iplan2p8.h>
80 #include <video/fbcon-mfb.h>
83 #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
84 #define SWITCH_SND6 0x40
85 #define SWITCH_SND7 0x80
86 #define SWITCH_NONE 0x00
89 #define up(x, r) (((x) + (r) - 1) & ~((r)-1))
92 static int default_par=0; /* default resolution (0=none) */
94 static unsigned long default_mem_req=0;
96 static int hwscroll=-1;
98 static int use_hwscroll = 1;
100 static int sttt_xres=640,st_yres=400,tt_yres=480;
101 static int sttt_xres_virtual=640,sttt_yres_virtual=400;
102 static int ovsc_offset=0, ovsc_addlen=0;
104 static struct atafb_par {
107 #if defined ATAFB_TT || defined ATAFB_STE
116 /* Here are fields for storing a video mode, as direct
117 * parameters for the hardware.
127 short hht, hbb, hbe, hdb, hde, hss;
128 short vft, vbb, vbe, vdb, vde, vss;
129 /* auxiliary information */
135 /* Nothing needed for external mode */
139 /* Don't calculate an own resolution, and thus don't change the one found when
140 * booting (currently used for the Falcon to keep settings for internal video
141 * hardware extensions (e.g. ScreenBlaster) */
142 static int DontCalcRes = 0;
145 #define HHT hw.falcon.hht
146 #define HBB hw.falcon.hbb
147 #define HBE hw.falcon.hbe
148 #define HDB hw.falcon.hdb
149 #define HDE hw.falcon.hde
150 #define HSS hw.falcon.hss
151 #define VFT hw.falcon.vft
152 #define VBB hw.falcon.vbb
153 #define VBE hw.falcon.vbe
154 #define VDB hw.falcon.vdb
155 #define VDE hw.falcon.vde
156 #define VSS hw.falcon.vss
157 #define VCO_CLOCK25 0x04
158 #define VCO_CSYPOS 0x10
159 #define VCO_VSYPOS 0x20
160 #define VCO_HSYPOS 0x40
161 #define VCO_SHORTOFFS 0x100
162 #define VMO_DOUBLE 0x01
163 #define VMO_INTER 0x02
164 #define VMO_PREMASK 0x0c
167 static struct fb_info fb_info;
169 static void *screen_base; /* base address of screen */
170 static void *real_screen_base; /* (only for Overscan) */
172 static int screen_len;
174 static int current_par_valid=0;
176 static int mono_moni=0;
178 static struct display disp;
182 /* external video handling */
184 static unsigned external_xres;
185 static unsigned external_xres_virtual;
186 static unsigned external_yres;
187 /* not needed - atafb will never support panning/hardwarescroll with external
188 * static unsigned external_yres_virtual;
191 static unsigned external_depth;
192 static int external_pmode;
193 static void *external_addr = 0;
194 static unsigned long external_len;
195 static unsigned long external_vgaiobase = 0;
196 static unsigned int external_bitspercol = 6;
199 JOE <joe@amber.dinoco.de>:
200 added card type for external driver, is only needed for
204 enum cardtype { IS_VGA, IS_MV300 };
205 static enum cardtype external_card_type = IS_VGA;
208 The MV300 mixes the color registers. So we need an array of munged
209 indices in order to access the correct reg.
211 static int MV300_reg_1bit[2]={0,1};
212 static int MV300_reg_4bit[16]={
213 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
214 static int MV300_reg_8bit[256]={
215 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
216 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
217 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
218 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
219 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
220 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
221 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
222 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
223 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
224 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
225 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
226 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
227 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
228 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
229 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
230 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 };
232 static int *MV300_reg = MV300_reg_8bit;
235 And on the MV300 it's difficult to read out the hardware palette. So we
236 just keep track of the set colors in our own array here, and use that!
239 static struct { unsigned char red,green,blue,pad; } ext_color[256];
240 #endif /* ATAFB_EXT */
243 static int inverse=0;
245 extern int fontheight_8x8;
246 extern int fontwidth_8x8;
247 extern unsigned char fontdata_8x8[];
249 extern int fontheight_8x16;
250 extern int fontwidth_8x16;
251 extern unsigned char fontdata_8x16[];
253 /* ++roman: This structure abstracts from the underlying hardware (ST(e),
256 * int (*detect)( void )
257 * This function should detect the current video mode settings and
258 * store them in atafb_predefined[0] for later reference by the
259 * user. Return the index+1 of an equivalent predefined mode or 0
260 * if there is no such.
262 * int (*encode_fix)( struct fb_fix_screeninfo *fix,
263 * struct atafb_par *par )
264 * This function should fill in the 'fix' structure based on the
265 * values in the 'par' structure.
267 * int (*decode_var)( struct fb_var_screeninfo *var,
268 * struct atafb_par *par )
269 * Get the video params out of 'var'. If a value doesn't fit, round
270 * it up, if it's too big, return EINVAL.
271 * Round up in the following order: bits_per_pixel, xres, yres,
272 * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
273 * horizontal timing, vertical timing.
275 * int (*encode_var)( struct fb_var_screeninfo *var,
276 * struct atafb_par *par );
277 * Fill the 'var' structure based on the values in 'par' and maybe
278 * other values read out of the hardware.
280 * void (*get_par)( struct atafb_par *par )
281 * Fill the hardware's 'par' structure.
283 * void (*set_par)( struct atafb_par *par )
284 * Set the hardware according to 'par'.
286 * int (*getcolreg)( unsigned regno, unsigned *red,
287 * unsigned *green, unsigned *blue,
288 * unsigned *transp, struct fb_info *info )
289 * Read a single color register and split it into
290 * colors/transparent. Return != 0 for invalid regno.
292 * void (*set_screen_base)(void *s_base)
293 * Set the base address of the displayed frame buffer. Only called
294 * if yres_virtual > yres or xres_virtual > xres.
296 * int (*blank)( int blank_mode )
297 * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
298 * the caller blanks by setting the CLUT to all black. Return 0 if blanking
299 * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
300 * doesn't support it. Implements VESA suspend and powerdown modes on
301 * hardware that supports disabling hsync/vsync:
302 * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
305 static struct fb_hwswitch {
306 int (*detect)( void );
307 int (*encode_fix)( struct fb_fix_screeninfo *fix,
308 struct atafb_par *par );
309 int (*decode_var)( struct fb_var_screeninfo *var,
310 struct atafb_par *par );
311 int (*encode_var)( struct fb_var_screeninfo *var,
312 struct atafb_par *par );
313 void (*get_par)( struct atafb_par *par );
314 void (*set_par)( struct atafb_par *par );
315 int (*getcolreg)( unsigned regno, unsigned *red,
316 unsigned *green, unsigned *blue,
317 unsigned *transp, struct fb_info *info );
318 void (*set_screen_base)(void *s_base);
319 int (*blank)( int blank_mode );
320 int (*pan_display)( struct fb_var_screeninfo *var,
321 struct atafb_par *par);
324 static char *autodetect_names[] = {"autodetect", NULL};
325 static char *stlow_names[] = {"stlow", NULL};
326 static char *stmid_names[] = {"stmid", "default5", NULL};
327 static char *sthigh_names[] = {"sthigh", "default4", NULL};
328 static char *ttlow_names[] = {"ttlow", NULL};
329 static char *ttmid_names[]= {"ttmid", "default1", NULL};
330 static char *tthigh_names[]= {"tthigh", "default2", NULL};
331 static char *vga2_names[] = {"vga2", NULL};
332 static char *vga4_names[] = {"vga4", NULL};
333 static char *vga16_names[] = {"vga16", "default3", NULL};
334 static char *vga256_names[] = {"vga256", NULL};
335 static char *falh2_names[] = {"falh2", NULL};
336 static char *falh16_names[] = {"falh16", NULL};
338 static char **fb_var_names[] = {
339 /* Writing the name arrays directly in this array (via "(char *[]){...}")
340 * crashes gcc 2.5.8 (sigsegv) if the inner array
341 * contains more than two items. I've also seen that all elements
342 * were identical to the last (my cross-gcc) :-(*/
357 /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
360 static struct fb_var_screeninfo atafb_predefined[] = {
362 * yres_virtual==0 means use hw-scrolling if possible, else yres
365 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
366 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
367 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
369 320, 200, 320, 0, 0, 0, 4, 0,
370 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
371 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
373 640, 200, 640, 0, 0, 0, 2, 0,
374 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
375 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
377 640, 400, 640, 0, 0, 0, 1, 0,
378 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
379 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
381 320, 480, 320, 0, 0, 0, 8, 0,
382 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
383 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
385 640, 480, 640, 0, 0, 0, 4, 0,
386 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
387 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
389 1280, 960, 1280, 0, 0, 0, 1, 0,
390 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
391 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
393 640, 480, 640, 0, 0, 0, 1, 0,
394 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
395 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
397 640, 480, 640, 0, 0, 0, 2, 0,
398 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
399 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
401 640, 480, 640, 0, 0, 0, 4, 0,
402 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
403 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
405 640, 480, 640, 0, 0, 0, 8, 0,
406 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
407 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
409 896, 608, 896, 0, 0, 0, 1, 0,
410 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
411 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
413 896, 608, 896, 0, 0, 0, 4, 0,
414 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
415 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
418 static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
422 get_video_mode(char *vname)
427 name_list=fb_var_names;
428 for (i = 0 ; i < num_atafb_predefined ; i++) {
430 if (! name || ! *name)
433 if (! strcmp(vname, *name))
443 /* ------------------- TT specific functions ---------------------- */
447 static int tt_encode_fix( struct fb_fix_screeninfo *fix,
448 struct atafb_par *par )
453 strcpy(fix->id,"Atari Builtin");
454 fix->smem_start = (unsigned long)real_screen_base;
455 fix->smem_len = screen_len;
456 fix->type=FB_TYPE_INTERLEAVED_PLANES;
458 fix->visual=FB_VISUAL_PSEUDOCOLOR;
459 mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
460 if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
461 fix->type=FB_TYPE_PACKED_PIXELS;
463 if (mode == TT_SHIFTER_TTHIGH)
464 fix->visual=FB_VISUAL_MONO01;
469 fix->line_length = 0;
470 fix->accel = FB_ACCEL_ATARIBLITT;
475 static int tt_decode_var( struct fb_var_screeninfo *var,
476 struct atafb_par *par )
480 int bpp=var->bits_per_pixel;
482 int yres_virtual = var->yres_virtual;
485 if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
487 par->hw.tt.mode=TT_SHIFTER_TTHIGH;
492 if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
495 if (xres > sttt_xres/2 || yres > tt_yres)
497 par->hw.tt.mode=TT_SHIFTER_TTLOW;
503 if (xres > sttt_xres || yres > tt_yres)
505 if (xres > sttt_xres/2 || yres > st_yres/2) {
506 par->hw.tt.mode=TT_SHIFTER_TTMID;
512 par->hw.tt.mode=TT_SHIFTER_STLOW;
519 if (xres > sttt_xres || yres > st_yres/2)
521 par->hw.tt.mode=TT_SHIFTER_STMID;
526 else if (var->xres > sttt_xres || var->yres > st_yres) {
530 par->hw.tt.mode=TT_SHIFTER_STHIGH;
536 if (yres_virtual <= 0)
538 else if (yres_virtual < yres)
540 if (var->sync & FB_SYNC_EXT)
545 if (yres_virtual * linelen > screen_len && screen_len)
547 if (yres * linelen > screen_len && screen_len)
549 if (var->yoffset + yres > yres_virtual && yres_virtual)
551 par->yres_virtual = yres_virtual;
552 par->screen_base = screen_base + var->yoffset * linelen;
556 static int tt_encode_var( struct fb_var_screeninfo *var,
557 struct atafb_par *par )
560 memset(var, 0, sizeof(struct fb_var_screeninfo));
563 var->red.msb_right=0;
567 var->left_margin=120; /* these may be incorrect */
568 var->right_margin=100;
570 var->lower_margin=16;
577 if (par->hw.tt.sync & 1)
580 var->sync=FB_SYNC_EXT;
582 switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
583 case TT_SHIFTER_STLOW:
584 var->xres=sttt_xres/2;
585 var->xres_virtual=sttt_xres_virtual/2;
587 var->bits_per_pixel=4;
589 case TT_SHIFTER_STMID:
591 var->xres_virtual=sttt_xres_virtual;
593 var->bits_per_pixel=2;
595 case TT_SHIFTER_STHIGH:
597 var->xres_virtual=sttt_xres_virtual;
599 var->bits_per_pixel=1;
601 case TT_SHIFTER_TTLOW:
602 var->xres=sttt_xres/2;
603 var->xres_virtual=sttt_xres_virtual/2;
605 var->bits_per_pixel=8;
607 case TT_SHIFTER_TTMID:
609 var->xres_virtual=sttt_xres_virtual;
611 var->bits_per_pixel=4;
613 case TT_SHIFTER_TTHIGH:
615 var->xres=sttt_xres*2;
616 var->xres_virtual=sttt_xres_virtual*2;
618 var->bits_per_pixel=1;
621 var->blue=var->green=var->red;
622 var->transp.offset=0;
623 var->transp.length=0;
624 var->transp.msb_right=0;
625 linelen=var->xres_virtual * var->bits_per_pixel / 8;
627 var->yres_virtual=var->yres;
628 else if (screen_len) {
629 if (par->yres_virtual)
630 var->yres_virtual = par->yres_virtual;
632 /* yres_virtual==0 means use maximum */
633 var->yres_virtual = screen_len / linelen;
636 var->yres_virtual = 2 * var->yres;
638 var->yres_virtual=var->yres+hwscroll * 16;
642 var->yoffset=(par->screen_base - screen_base)/linelen;
647 var->vmode=FB_VMODE_NONINTERLACED;
652 static void tt_get_par( struct atafb_par *par )
655 par->hw.tt.mode=shifter_tt.tt_shiftmode;
656 par->hw.tt.sync=shifter.syncmode;
657 addr = ((shifter.bas_hi & 0xff) << 16) |
658 ((shifter.bas_md & 0xff) << 8) |
659 ((shifter.bas_lo & 0xff));
660 par->screen_base = phys_to_virt(addr);
663 static void tt_set_par( struct atafb_par *par )
665 shifter_tt.tt_shiftmode=par->hw.tt.mode;
666 shifter.syncmode=par->hw.tt.sync;
667 /* only set screen_base if really necessary */
668 if (current_par.screen_base != par->screen_base)
669 fbhw->set_screen_base(par->screen_base);
673 static int tt_getcolreg(unsigned regno, unsigned *red,
674 unsigned *green, unsigned *blue,
675 unsigned *transp, struct fb_info *info)
679 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
683 t = tt_palette[regno];
701 static int tt_setcolreg(unsigned regno, unsigned red,
702 unsigned green, unsigned blue,
703 unsigned transp, struct fb_info *info)
705 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
709 tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
711 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
712 TT_SHIFTER_STHIGH && regno == 254)
718 static int tt_detect( void )
720 { struct atafb_par par;
722 /* Determine the connected monitor: The DMA sound must be
723 * disabled before reading the MFP GPIP, because the Sound
724 * Done Signal and the Monochrome Detect are XORed together!
726 * Even on a TT, we should look if there is a DMA sound. It was
727 * announced that the Eagle is TT compatible, but only the PCM is
730 if (ATARIHW_PRESENT(PCM_8BIT)) {
731 tt_dmasnd.ctrl = DMASND_CTRL_OFF;
732 udelay(20); /* wait a while for things to settle down */
734 mono_moni = (mfp.par_dt_reg & 0x80) == 0;
737 tt_encode_var(&atafb_predefined[0], &par);
742 #endif /* ATAFB_TT */
744 /* ------------------- Falcon specific functions ---------------------- */
748 static int mon_type; /* Falcon connected monitor */
749 static int f030_bus_width; /* Falcon ram bus width (for vid_control) */
755 static struct pixel_clock {
756 unsigned long f; /* f/[Hz] */
757 unsigned long t; /* t/[ps] (=1/f) */
758 int right, hsync, left; /* standard timing in clock cycles, not pixel */
759 /* hsync initialized in falcon_detect() */
760 int sync_mask; /* or-mask for hw.falcon.sync to set this clock */
761 int control_mask; /* ditto, for hw.falcon.vid_control */
763 f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
764 f32 = {32000000, 31250, 18, 0, 42, 0x0, 0},
765 fext = { 0, 0, 18, 0, 42, 0x1, 0};
767 /* VIDEL-prescale values [mon_type][pixel_length from VCO] */
768 static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
770 /* Default hsync timing [mon_type] in picoseconds */
771 static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
773 #ifdef FBCON_HAS_CFB16
774 static u16 fbcon_cfb16_cmap[16];
777 static inline int hxx_prescale(struct falcon_hw *hw)
779 return hw->ste_mode ? 16 :
780 vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
783 static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
784 struct atafb_par *par )
786 strcpy(fix->id, "Atari Builtin");
787 fix->smem_start = (unsigned long)real_screen_base;
788 fix->smem_len = screen_len;
789 fix->type = FB_TYPE_INTERLEAVED_PLANES;
791 fix->visual = FB_VISUAL_PSEUDOCOLOR;
795 if (par->hw.falcon.mono) {
796 fix->type = FB_TYPE_PACKED_PIXELS;
798 /* no smooth scrolling with longword aligned video mem */
801 else if (par->hw.falcon.f_shift & 0x100) {
802 fix->type = FB_TYPE_PACKED_PIXELS;
804 /* Is this ok or should it be DIRECTCOLOR? */
805 fix->visual = FB_VISUAL_TRUECOLOR;
808 fix->line_length = 0;
809 fix->accel = FB_ACCEL_ATARIBLITT;
814 static int falcon_decode_var( struct fb_var_screeninfo *var,
815 struct atafb_par *par )
817 int bpp = var->bits_per_pixel;
818 int xres = var->xres;
819 int yres = var->yres;
820 int xres_virtual = var->xres_virtual;
821 int yres_virtual = var->yres_virtual;
822 int left_margin, right_margin, hsync_len;
823 int upper_margin, lower_margin, vsync_len;
825 int interlace = 0, doubleline = 0;
826 struct pixel_clock *pclock;
827 int plen; /* width of pixel in clock cycles */
834 Get the video params out of 'var'. If a value doesn't fit, round
835 it up, if it's too big, return EINVAL.
836 Round up in the following order: bits_per_pixel, xres, yres,
837 xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
838 horizontal timing, vertical timing.
840 There is a maximum of screen resolution determined by pixelclock
841 and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
842 In interlace mode this is " * " *vfmin <= pixelclock.
843 Additional constraints: hfreq.
844 Frequency range for multisync monitors is given via command line.
845 For TV and SM124 both frequencies are fixed.
847 X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
848 Y % 16 == 0 to fit 8x16 font
851 Currently interlace and doubleline mode in var are ignored.
852 On SM124 and TV only the standard resolutions can be used.
855 /* Reject uninitialized mode */
856 if (!xres || !yres || !bpp)
859 if (mon_type == F_MON_SM && bpp != 1) {
864 par->hw.falcon.f_shift = 0x400;
865 par->hw.falcon.st_shift = 0x200;
869 par->hw.falcon.f_shift = 0x000;
870 par->hw.falcon.st_shift = 0x100;
874 par->hw.falcon.f_shift = 0x000;
875 par->hw.falcon.st_shift = 0x000;
879 par->hw.falcon.f_shift = 0x010;
881 else if (bpp <= 16) {
882 bpp = 16; /* packed pixel mode */
883 par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
887 par->hw.falcon.bpp = bpp;
889 if (mon_type == F_MON_SM || DontCalcRes) {
890 /* Skip all calculations. VGA/TV/SC1224 only supported. */
891 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
893 if (bpp > myvar->bits_per_pixel ||
894 var->xres > myvar->xres ||
895 var->yres > myvar->yres)
897 fbhw->get_par(par); /* Current par will be new par */
898 goto set_screen_base; /* Don't forget this */
901 /* Only some fixed resolutions < 640x400 */
904 else if (xres <= 640 && bpp != 16)
908 else if (yres <= 240)
910 else if (yres <= 400)
913 /* 2 planes must use STE compatibility mode */
914 par->hw.falcon.ste_mode = bpp==2;
915 par->hw.falcon.mono = bpp==1;
917 /* Total and visible scanline length must be a multiple of one longword,
918 * this and the console fontwidth yields the alignment for xres and
920 * TODO: this way "odd" fontheights are not supported
922 * Special case in STE mode: blank and graphic positions don't align,
923 * avoid trash at right margin
925 if (par->hw.falcon.ste_mode)
926 xres = (xres + 63) & ~63;
928 xres = (xres + 31) & ~31;
930 xres = (xres + 15) & ~15;
932 yres = (yres + 15) & ~15;
934 yres = (yres + 7) & ~7;
936 if (xres_virtual < xres)
939 xres_virtual = (xres_virtual + 31) & ~31;
941 xres_virtual = (xres_virtual + 15) & ~15;
943 if (yres_virtual <= 0)
945 else if (yres_virtual < yres)
948 /* backward bug-compatibility */
949 if (var->pixclock > 1)
952 par->hw.falcon.line_width = bpp * xres / 16;
953 par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
955 /* single or double pixel width */
956 xstretch = (xres < 640) ? 2 : 1;
958 #if 0 /* SM124 supports only 640x400, this is rejected above */
959 if (mon_type == F_MON_SM) {
960 if (xres != 640 && yres != 400)
964 /* SM124-mode is special */
965 par->hw.falcon.ste_mode = 1;
966 par->hw.falcon.f_shift = 0x000;
967 par->hw.falcon.st_shift = 0x200;
968 left_margin = hsync_len = 128 / plen;
970 /* TODO set all margins */
974 if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
976 if (var->pixclock > f32.t * plen)
981 if (var->pixclock == 0) {
982 /* set some minimal margins which center the screen */
985 hsync_len = pclock->hsync / plen;
988 vsync_len = interlace ? 3 : 4;
990 left_margin = var->left_margin;
991 right_margin = var->right_margin;
992 hsync_len = var->hsync_len;
993 upper_margin = var->upper_margin;
994 lower_margin = var->lower_margin;
995 vsync_len = var->vsync_len;
996 if (var->vmode & FB_VMODE_INTERLACED) {
997 upper_margin = (upper_margin + 1) / 2;
998 lower_margin = (lower_margin + 1) / 2;
999 vsync_len = (vsync_len + 1) / 2;
1000 } else if (var->vmode & FB_VMODE_DOUBLE) {
1010 xstretch = 2; /* Double pixel width only for hicolor */
1011 /* Default values are used for vert./hor. timing if no pixelclock given. */
1012 if (var->pixclock == 0) {
1015 /* Choose master pixelclock depending on hor. timing */
1016 plen = 1 * xstretch;
1017 if ((plen * xres + f25.right+f25.hsync+f25.left) *
1018 fb_info.monspecs.hfmin < f25.f)
1020 else if ((plen * xres + f32.right+f32.hsync+f32.left) *
1021 fb_info.monspecs.hfmin < f32.f)
1023 else if ((plen * xres + fext.right+fext.hsync+fext.left) *
1024 fb_info.monspecs.hfmin < fext.f
1030 left_margin = pclock->left / plen;
1031 right_margin = pclock->right / plen;
1032 hsync_len = pclock->hsync / plen;
1033 linesize = left_margin + xres + right_margin + hsync_len;
1039 /* Choose largest pixelclock <= wanted clock */
1041 unsigned long pcl = ULONG_MAX;
1043 for (i=1; i <= 4; i *= 2) {
1044 if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
1048 if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
1052 if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
1059 plen = pcl / pclock->t;
1061 left_margin = var->left_margin;
1062 right_margin = var->right_margin;
1063 hsync_len = var->hsync_len;
1064 upper_margin = var->upper_margin;
1065 lower_margin = var->lower_margin;
1066 vsync_len = var->vsync_len;
1067 /* Internal unit is [single lines per (half-)frame] */
1068 if (var->vmode & FB_VMODE_INTERLACED) {
1069 /* # lines in half frame */
1070 /* External unit is [lines per full frame] */
1071 upper_margin = (upper_margin + 1) / 2;
1072 lower_margin = (lower_margin + 1) / 2;
1073 vsync_len = (vsync_len + 1) / 2;
1075 else if (var->vmode & FB_VMODE_DOUBLE) {
1076 /* External unit is [double lines per frame] */
1082 if (pclock == &fext)
1083 longoffset = 1; /* VIDEL doesn't synchronize on short offset */
1085 /* Is video bus bandwidth (32MB/s) too low for this resolution? */
1086 /* this is definitely wrong if bus clock != 32MHz */
1087 if (pclock->f / plen / 8 * bpp > 32000000L)
1093 /* include sync lengths in right/lower margin for all calculations */
1094 right_margin += hsync_len;
1095 lower_margin += vsync_len;
1097 /* ! In all calculations of margins we use # of lines in half frame
1098 * (which is a full frame in non-interlace mode), so we can switch
1099 * between interlace and non-interlace without messing around
1103 /* Set base_offset 128 and video bus width */
1104 par->hw.falcon.vid_control = mon_type | f030_bus_width;
1106 par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */
1107 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1108 par->hw.falcon.vid_control |= VCO_HSYPOS;
1109 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1110 par->hw.falcon.vid_control |= VCO_VSYPOS;
1112 par->hw.falcon.vid_control |= pclock->control_mask;
1113 /* External or internal clock */
1114 par->hw.falcon.sync = pclock->sync_mask | 0x2;
1115 /* Pixellength and prescale */
1116 par->hw.falcon.vid_mode = (2/plen) << 2;
1118 par->hw.falcon.vid_mode |= VMO_DOUBLE;
1120 par->hw.falcon.vid_mode |= VMO_INTER;
1122 /*********************
1123 Horizontal timing: unit = [master clock cycles]
1124 unit of hxx-registers: [master clock cycles * prescale]
1125 Hxx-registers are 9 bit wide
1127 1 line = ((hht + 2) * 2 * prescale) clock cycles
1129 graphic output = hdb & 0x200 ?
1130 ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
1131 ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
1132 (this must be a multiple of plen*128/bpp, on VGA pixels
1133 to the right may be cut off with a bigger right margin)
1135 start of graphics relative to start of 1st halfline = hdb & 0x200 ?
1136 (hdb - hht - 2) * prescale + hdboff :
1137 hdb * prescale + hdboff
1139 end of graphics relative to start of 1st halfline =
1140 (hde + hht + 2) * prescale + hdeoff
1141 *********************/
1142 /* Calculate VIDEL registers */
1144 int hdb_off, hde_off, base_off;
1145 int gstart, gend1, gend2, align;
1147 prescale = hxx_prescale(&par->hw.falcon);
1148 base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
1150 /* Offsets depend on video mode */
1151 /* Offsets are in clock cycles, divide by prescale to
1152 * calculate hd[be]-registers
1154 if (par->hw.falcon.f_shift & 0x100) {
1157 hdb_off = (base_off + 16 * plen) + prescale;
1161 hde_off = ((128 / bpp + 2) * plen);
1162 if (par->hw.falcon.ste_mode)
1163 hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
1165 hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
1168 gstart = (prescale/2 + plen * left_margin) / prescale;
1169 /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
1170 gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
1171 /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
1172 gend2 = gstart + xres * plen / prescale;
1173 par->HHT = plen * (left_margin + xres + right_margin) /
1175 /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
1177 par->HDB = gstart - hdb_off/prescale;
1179 if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
1180 par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
1181 par->HBB = gend2 - par->HHT - 2;
1183 /* One more Videl constraint: data fetch of two lines must not overlap */
1184 if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
1185 /* if this happens increase margins, decrease hfreq. */
1188 if (hde_off % prescale)
1189 par->HBB++; /* compensate for non matching hde and hbb */
1190 par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
1191 if (par->HSS < par->HBB)
1192 par->HSS = par->HBB;
1195 /* check hor. frequency */
1196 hfreq = pclock->f / ((par->HHT+2)*prescale*2);
1197 if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
1198 /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
1199 /* Too high -> enlarge margin */
1204 if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin)
1208 /* All Vxx must be odd in non-interlace, since frame starts in the middle
1209 * of the first displayed line!
1210 * One frame consists of VFT+1 half lines. VFT+1 must be even in
1211 * non-interlace, odd in interlace mode for synchronisation.
1212 * Vxx-registers are 11 bit wide
1214 par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
1215 par->VDB = par->VBE;
1217 if (!interlace) par->VDE <<= 1;
1218 if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */
1219 par->VDE += par->VDB;
1220 par->VBB = par->VDE;
1221 par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
1222 par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
1223 /* vbb,vss,vft must be even in interlace mode */
1230 /* V-frequency check, hope I didn't create any loop here. */
1231 /* Interlace and doubleline are mutually exclusive. */
1232 vfreq = (hfreq * 2) / (par->VFT + 1);
1233 if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
1234 /* Too high -> try again with doubleline */
1238 else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
1239 /* Too low -> try again with interlace */
1243 else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
1244 /* Doubleline too low -> clear doubleline and enlarge margins */
1248 (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
1251 upper_margin += lines;
1252 lower_margin += lines;
1255 else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
1256 /* Doubleline too high -> enlarge margins */
1259 (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
1262 upper_margin += lines;
1263 lower_margin += lines;
1266 else if (vfreq > fb_info.monspecs.vfmax && interlace) {
1267 /* Interlace, too high -> enlarge margins */
1270 (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
1273 upper_margin += lines;
1274 lower_margin += lines;
1277 else if (vfreq < fb_info.monspecs.vfmin ||
1278 vfreq > fb_info.monspecs.vfmax)
1282 linelen = xres_virtual * bpp / 8;
1283 if (yres_virtual * linelen > screen_len && screen_len)
1285 if (yres * linelen > screen_len && screen_len)
1287 if (var->yoffset + yres > yres_virtual && yres_virtual)
1289 par->yres_virtual = yres_virtual;
1290 par->screen_base = screen_base + var->yoffset * linelen;
1291 par->hw.falcon.xoffset = 0;
1296 static int falcon_encode_var( struct fb_var_screeninfo *var,
1297 struct atafb_par *par )
1299 /* !!! only for VGA !!! */
1302 int hdb_off, hde_off, base_off;
1303 struct falcon_hw *hw = &par->hw.falcon;
1305 memset(var, 0, sizeof(struct fb_var_screeninfo));
1306 /* possible frequencies: 25.175 or 32MHz */
1307 var->pixclock = hw->sync & 0x1 ? fext.t :
1308 hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
1314 if (hw->vid_control & VCO_HSYPOS)
1315 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1316 if (hw->vid_control & VCO_VSYPOS)
1317 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1319 var->vmode = FB_VMODE_NONINTERLACED;
1320 if (hw->vid_mode & VMO_INTER)
1321 var->vmode |= FB_VMODE_INTERLACED;
1322 if (hw->vid_mode & VMO_DOUBLE)
1323 var->vmode |= FB_VMODE_DOUBLE;
1325 /* visible y resolution:
1326 * Graphics display starts at line VDB and ends at line
1327 * VDE. If interlace mode off unit of VC-registers is
1328 * half lines, else lines.
1330 var->yres = hw->vde - hw->vdb;
1331 if (!(var->vmode & FB_VMODE_INTERLACED))
1333 if (var->vmode & FB_VMODE_DOUBLE)
1336 /* to get bpp, we must examine f_shift and st_shift.
1337 * f_shift is valid if any of bits no. 10, 8 or 4
1338 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
1339 * if bit 10 set then bit 8 and bit 4 don't care...
1340 * If all these bits are 0 get display depth from st_shift
1341 * (as for ST and STE)
1343 if (hw->f_shift & 0x400) /* 2 colors */
1344 var->bits_per_pixel = 1;
1345 else if (hw->f_shift & 0x100) /* hicolor */
1346 var->bits_per_pixel = 16;
1347 else if (hw->f_shift & 0x010) /* 8 bitplanes */
1348 var->bits_per_pixel = 8;
1349 else if (hw->st_shift == 0)
1350 var->bits_per_pixel = 4;
1351 else if (hw->st_shift == 0x100)
1352 var->bits_per_pixel = 2;
1353 else /* if (hw->st_shift == 0x200) */
1354 var->bits_per_pixel = 1;
1356 var->xres = hw->line_width * 16 / var->bits_per_pixel;
1357 var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
1359 var->xres_virtual += 16;
1361 if (var->bits_per_pixel == 16) {
1364 var->red.msb_right=0;
1365 var->green.offset=5;
1366 var->green.length=6;
1367 var->green.msb_right=0;
1370 var->blue.msb_right=0;
1374 var->red.length = hw->ste_mode ? 4 : 6;
1375 var->red.msb_right=0;
1377 var->blue=var->green=var->red;
1379 var->transp.offset=0;
1380 var->transp.length=0;
1381 var->transp.msb_right=0;
1383 linelen = var->xres_virtual * var->bits_per_pixel / 8;
1385 if (par->yres_virtual)
1386 var->yres_virtual = par->yres_virtual;
1388 /* yres_virtual==0 means use maximum */
1389 var->yres_virtual = screen_len / linelen;
1393 var->yres_virtual = 2 * var->yres;
1395 var->yres_virtual=var->yres+hwscroll * 16;
1397 var->xoffset=0; /* TODO change this */
1400 prescale = hxx_prescale(hw);
1401 plen = 4 >> (hw->vid_mode >> 2 & 0x3);
1402 base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
1403 if (hw->f_shift & 0x100) {
1405 hdb_off = (base_off + 16 * plen) + prescale;
1408 hde_off = ((128 / var->bits_per_pixel + 2) * plen);
1410 hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
1413 hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
1417 /* Right margin includes hsync */
1418 var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
1419 (hw->hdb & 0x200 ? 2+hw->hht : 0));
1420 if (hw->ste_mode || mon_type!=F_MON_VGA)
1421 var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
1423 /* can't use this in ste_mode, because hbb is +1 off */
1424 var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
1425 var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
1427 /* Lower margin includes vsync */
1428 var->upper_margin = hw->vdb / 2 ; /* round down to full lines */
1429 var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
1430 var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
1431 if (var->vmode & FB_VMODE_INTERLACED) {
1432 var->upper_margin *= 2;
1433 var->lower_margin *= 2;
1434 var->vsync_len *= 2;
1436 else if (var->vmode & FB_VMODE_DOUBLE) {
1437 var->upper_margin = (var->upper_margin + 1) / 2;
1438 var->lower_margin = (var->lower_margin + 1) / 2;
1439 var->vsync_len = (var->vsync_len + 1) / 2;
1442 var->pixclock *= plen;
1443 var->left_margin /= plen;
1444 var->right_margin /= plen;
1445 var->hsync_len /= plen;
1447 var->right_margin -= var->hsync_len;
1448 var->lower_margin -= var->vsync_len;
1451 var->yoffset=(par->screen_base - screen_base)/linelen;
1454 var->nonstd=0; /* what is this for? */
1460 static int f_change_mode = 0;
1461 static struct falcon_hw f_new_mode;
1462 static int f_pan_display = 0;
1464 static void falcon_get_par( struct atafb_par *par )
1467 struct falcon_hw *hw = &par->hw.falcon;
1469 hw->line_width = shifter_f030.scn_width;
1470 hw->line_offset = shifter_f030.off_next;
1471 hw->st_shift = videl.st_shift & 0x300;
1472 hw->f_shift = videl.f_shift;
1473 hw->vid_control = videl.control;
1474 hw->vid_mode = videl.mode;
1475 hw->sync = shifter.syncmode & 0x1;
1476 hw->xoffset = videl.xoffset & 0xf;
1477 hw->hht = videl.hht;
1478 hw->hbb = videl.hbb;
1479 hw->hbe = videl.hbe;
1480 hw->hdb = videl.hdb;
1481 hw->hde = videl.hde;
1482 hw->hss = videl.hss;
1483 hw->vft = videl.vft;
1484 hw->vbb = videl.vbb;
1485 hw->vbe = videl.vbe;
1486 hw->vdb = videl.vdb;
1487 hw->vde = videl.vde;
1488 hw->vss = videl.vss;
1490 addr = (shifter.bas_hi & 0xff) << 16 |
1491 (shifter.bas_md & 0xff) << 8 |
1492 (shifter.bas_lo & 0xff);
1493 par->screen_base = phys_to_virt(addr);
1495 /* derived parameters */
1496 hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
1497 hw->mono = (hw->f_shift & 0x400) ||
1498 ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
1501 static void falcon_set_par( struct atafb_par *par )
1505 /* only set screen_base if really necessary */
1506 if (current_par.screen_base != par->screen_base)
1507 fbhw->set_screen_base(par->screen_base);
1509 /* Don't touch any other registers if we keep the default resolution */
1513 /* Tell vbl-handler to change video mode.
1514 * We change modes only on next VBL, to avoid desynchronisation
1515 * (a shift to the right and wrap around by a random number of pixels
1516 * in all monochrome modes).
1517 * This seems to work on my Falcon.
1519 f_new_mode = par->hw.falcon;
1524 static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
1526 struct falcon_hw *hw = &f_new_mode;
1528 if (f_change_mode) {
1531 if (hw->sync & 0x1) {
1532 /* Enable external pixelclock. This code only for ScreenWonder */
1533 *(volatile unsigned short*)0xffff9202 = 0xffbf;
1536 /* Turn off external clocks. Read sets all output bits to 1. */
1537 *(volatile unsigned short*)0xffff9202;
1539 shifter.syncmode = hw->sync;
1541 videl.hht = hw->hht;
1542 videl.hbb = hw->hbb;
1543 videl.hbe = hw->hbe;
1544 videl.hdb = hw->hdb;
1545 videl.hde = hw->hde;
1546 videl.hss = hw->hss;
1547 videl.vft = hw->vft;
1548 videl.vbb = hw->vbb;
1549 videl.vbe = hw->vbe;
1550 videl.vdb = hw->vdb;
1551 videl.vde = hw->vde;
1552 videl.vss = hw->vss;
1554 videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
1556 videl.st_shift = hw->st_shift; /* write enables STE palette */
1560 * set st_shift 0, so we can tell the screen-depth if f_shift==0.
1561 * Writing 0 to f_shift enables 4 plane Falcon mode but
1562 * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
1563 * with Falcon palette.
1566 /* now back to Falcon palette mode */
1567 videl.f_shift = hw->f_shift;
1569 /* writing to st_shift changed scn_width and vid_mode */
1570 videl.xoffset = hw->xoffset;
1571 shifter_f030.scn_width = hw->line_width;
1572 shifter_f030.off_next = hw->line_offset;
1573 videl.control = hw->vid_control;
1574 videl.mode = hw->vid_mode;
1576 if (f_pan_display) {
1578 videl.xoffset = current_par.hw.falcon.xoffset;
1579 shifter_f030.off_next = current_par.hw.falcon.line_offset;
1585 static int falcon_pan_display( struct fb_var_screeninfo *var,
1586 struct atafb_par *par )
1589 int bpp = fb_display[fb_info.currcon].var.bits_per_pixel;
1592 var->xoffset = up(var->xoffset, 32);
1594 par->hw.falcon.xoffset = var->xoffset & 15;
1596 par->hw.falcon.xoffset = 0;
1597 var->xoffset = up(var->xoffset, 2);
1599 par->hw.falcon.line_offset = bpp *
1600 (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16;
1601 if (par->hw.falcon.xoffset)
1602 par->hw.falcon.line_offset -= bpp;
1603 xoffset = var->xoffset - par->hw.falcon.xoffset;
1605 par->screen_base = screen_base +
1606 (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8;
1607 if (fbhw->set_screen_base)
1608 fbhw->set_screen_base (par->screen_base);
1610 return -EINVAL; /* shouldn't happen */
1616 static int falcon_getcolreg( unsigned regno, unsigned *red,
1617 unsigned *green, unsigned *blue,
1618 unsigned *transp, struct fb_info *info )
1619 { unsigned long col;
1623 /* This works in STE-mode (with 4bit/color) since f030_col-registers
1624 * hold up to 6bit/color.
1625 * Even with hicolor r/g/b=5/6/5 bit!
1627 col = f030_col[regno];
1628 *red = (col >> 16) & 0xff00;
1629 *green = (col >> 8) & 0xff00;
1630 *blue = (col << 8) & 0xff00;
1636 static int falcon_setcolreg( unsigned regno, unsigned red,
1637 unsigned green, unsigned blue,
1638 unsigned transp, struct fb_info *info )
1642 f030_col[regno] = (((red & 0xfc00) << 16) |
1643 ((green & 0xfc00) << 8) |
1644 ((blue & 0xfc00) >> 8));
1646 shifter_tt.color_reg[regno] =
1647 (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) |
1648 (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) |
1649 ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
1650 #ifdef FBCON_HAS_CFB16
1651 fbcon_cfb16_cmap[regno] = ((red & 0xf800) |
1652 ((green & 0xfc00) >> 5) |
1653 ((blue & 0xf800) >> 11));
1660 static int falcon_blank( int blank_mode )
1662 /* ++guenther: we can switch off graphics by changing VDB and VDE,
1663 * so VIDEL doesn't hog the bus while saving.
1664 * (this may affect usleep()).
1666 int vdb, vss, hbe, hss;
1668 if (mon_type == F_MON_SM) /* this doesn't work on SM124 */
1671 vdb = current_par.VDB;
1672 vss = current_par.VSS;
1673 hbe = current_par.HBE;
1674 hss = current_par.HSS;
1676 if (blank_mode >= 1) {
1677 /* disable graphics output (this speeds up the CPU) ... */
1678 vdb = current_par.VFT + 1;
1679 /* ... and blank all lines */
1680 hbe = current_par.HHT + 2;
1682 /* use VESA suspend modes on VGA monitors */
1683 if (mon_type == F_MON_VGA) {
1684 if (blank_mode == 2 || blank_mode == 4)
1685 vss = current_par.VFT + 1;
1686 if (blank_mode == 3 || blank_mode == 4)
1687 hss = current_par.HHT + 2;
1699 static int falcon_detect( void )
1701 struct atafb_par par;
1704 /* Determine connected monitor and set monitor parameters */
1705 fhw = *(unsigned char*)0xffff8006;
1706 mon_type = fhw >> 6 & 0x3;
1707 /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
1708 f030_bus_width = fhw << 6 & 0x80;
1711 fb_info.monspecs.vfmin = 70;
1712 fb_info.monspecs.vfmax = 72;
1713 fb_info.monspecs.hfmin = 35713;
1714 fb_info.monspecs.hfmax = 35715;
1719 fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
1720 fb_info.monspecs.vfmax = 60;
1721 fb_info.monspecs.hfmin = 15620;
1722 fb_info.monspecs.hfmax = 15755;
1725 /* initialize hsync-len */
1726 f25.hsync = h_syncs[mon_type] / f25.t;
1727 f32.hsync = h_syncs[mon_type] / f32.t;
1729 fext.hsync = h_syncs[mon_type] / fext.t;
1731 falcon_get_par(&par);
1732 falcon_encode_var(&atafb_predefined[0], &par);
1734 /* Detected mode is always the "autodetect" slot */
1738 #endif /* ATAFB_FALCON */
1740 /* ------------------- ST(E) specific functions ---------------------- */
1744 static int stste_encode_fix( struct fb_fix_screeninfo *fix,
1745 struct atafb_par *par )
1750 strcpy(fix->id,"Atari Builtin");
1751 fix->smem_start = (unsigned long)real_screen_base;
1752 fix->smem_len = screen_len;
1753 fix->type = FB_TYPE_INTERLEAVED_PLANES;
1755 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1756 mode = par->hw.st.mode & 3;
1757 if (mode == ST_HIGH) {
1758 fix->type = FB_TYPE_PACKED_PIXELS;
1760 fix->visual = FB_VISUAL_MONO10;
1762 if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
1770 fix->line_length = 0;
1771 fix->accel = FB_ACCEL_ATARIBLITT;
1776 static int stste_decode_var( struct fb_var_screeninfo *var,
1777 struct atafb_par *par )
1781 int bpp=var->bits_per_pixel;
1783 int yres_virtual = var->yres_virtual;
1786 if (bpp > 1 || xres > sttt_xres || yres > st_yres)
1788 par->hw.st.mode=ST_HIGH;
1793 if (bpp > 4 || xres > sttt_xres || yres > st_yres)
1796 if (xres > sttt_xres/2 || yres > st_yres/2)
1798 par->hw.st.mode=ST_LOW;
1804 if (xres > sttt_xres || yres > st_yres/2)
1806 par->hw.st.mode=ST_MID;
1814 if (yres_virtual <= 0)
1816 else if (yres_virtual < yres)
1817 yres_virtual = yres;
1818 if (var->sync & FB_SYNC_EXT)
1819 par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
1821 par->hw.st.sync=(par->hw.st.sync & ~1);
1823 if (yres_virtual * linelen > screen_len && screen_len)
1825 if (yres * linelen > screen_len && screen_len)
1827 if (var->yoffset + yres > yres_virtual && yres_virtual)
1829 par->yres_virtual = yres_virtual;
1830 par->screen_base=screen_base+ var->yoffset*linelen;
1834 static int stste_encode_var( struct fb_var_screeninfo *var,
1835 struct atafb_par *par )
1838 memset(var, 0, sizeof(struct fb_var_screeninfo));
1840 var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
1841 var->red.msb_right=0;
1844 var->pixclock=31041;
1845 var->left_margin=120; /* these are incorrect */
1846 var->right_margin=100;
1847 var->upper_margin=8;
1848 var->lower_margin=16;
1855 if (!(par->hw.st.sync & 1))
1858 var->sync=FB_SYNC_EXT;
1860 switch (par->hw.st.mode & 3) {
1862 var->xres=sttt_xres/2;
1863 var->yres=st_yres/2;
1864 var->bits_per_pixel=4;
1867 var->xres=sttt_xres;
1868 var->yres=st_yres/2;
1869 var->bits_per_pixel=2;
1872 var->xres=sttt_xres;
1874 var->bits_per_pixel=1;
1877 var->blue=var->green=var->red;
1878 var->transp.offset=0;
1879 var->transp.length=0;
1880 var->transp.msb_right=0;
1881 var->xres_virtual=sttt_xres_virtual;
1882 linelen=var->xres_virtual * var->bits_per_pixel / 8;
1883 ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
1886 var->yres_virtual=var->yres;
1887 else if (screen_len) {
1888 if (par->yres_virtual)
1889 var->yres_virtual = par->yres_virtual;
1891 /* yres_virtual==0 means use maximum */
1892 var->yres_virtual = screen_len / linelen;
1896 var->yres_virtual = 2 * var->yres;
1898 var->yres_virtual=var->yres+hwscroll * 16;
1902 var->yoffset=(par->screen_base - screen_base)/linelen;
1907 var->vmode=FB_VMODE_NONINTERLACED;
1912 static void stste_get_par( struct atafb_par *par )
1915 par->hw.st.mode=shifter_tt.st_shiftmode;
1916 par->hw.st.sync=shifter.syncmode;
1917 addr = ((shifter.bas_hi & 0xff) << 16) |
1918 ((shifter.bas_md & 0xff) << 8);
1919 if (ATARIHW_PRESENT(EXTD_SHIFTER))
1920 addr |= (shifter.bas_lo & 0xff);
1921 par->screen_base = phys_to_virt(addr);
1924 static void stste_set_par( struct atafb_par *par )
1926 shifter_tt.st_shiftmode=par->hw.st.mode;
1927 shifter.syncmode=par->hw.st.sync;
1928 /* only set screen_base if really necessary */
1929 if (current_par.screen_base != par->screen_base)
1930 fbhw->set_screen_base(par->screen_base);
1934 static int stste_getcolreg(unsigned regno, unsigned *red,
1935 unsigned *green, unsigned *blue,
1936 unsigned *transp, struct fb_info *info)
1942 col = shifter_tt.color_reg[regno];
1943 if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
1944 t = ((col >> 7) & 0xe) | ((col >> 11) & 1);
1946 *red = t | (t << 8);
1947 t = ((col >> 3) & 0xe) | ((col >> 7) & 1);
1949 *green = t | (t << 8);
1950 t = ((col << 1) & 0xe) | ((col >> 3) & 1);
1952 *blue = t | (t << 8);
1955 t = (col >> 7) & 0xe;
1957 *red = t | (t << 8);
1958 t = (col >> 3) & 0xe;
1960 *green = t | (t << 8);
1961 t = (col << 1) & 0xe;
1963 *blue = t | (t << 8);
1970 static int stste_setcolreg(unsigned regno, unsigned red,
1971 unsigned green, unsigned blue,
1972 unsigned transp, struct fb_info *info)
1979 if (ATARIHW_PRESENT(EXTD_SHIFTER))
1980 shifter_tt.color_reg[regno] =
1981 (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
1982 (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
1983 ((blue & 0xe) >> 1) | ((blue & 1) << 3);
1985 shifter_tt.color_reg[regno] =
1986 ((red & 0xe) << 7) |
1987 ((green & 0xe) << 3) |
1988 ((blue & 0xe) >> 1);
1993 static int stste_detect( void )
1995 { struct atafb_par par;
1997 /* Determine the connected monitor: The DMA sound must be
1998 * disabled before reading the MFP GPIP, because the Sound
1999 * Done Signal and the Monochrome Detect are XORed together!
2001 if (ATARIHW_PRESENT(PCM_8BIT)) {
2002 tt_dmasnd.ctrl = DMASND_CTRL_OFF;
2003 udelay(20); /* wait a while for things to settle down */
2005 mono_moni = (mfp.par_dt_reg & 0x80) == 0;
2007 stste_get_par(&par);
2008 stste_encode_var(&atafb_predefined[0], &par);
2010 if (!ATARIHW_PRESENT(EXTD_SHIFTER))
2015 static void stste_set_screen_base(void *s_base)
2018 addr= virt_to_phys(s_base);
2019 /* Setup Screen Memory */
2020 shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
2021 shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
2022 if (ATARIHW_PRESENT(EXTD_SHIFTER))
2023 shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
2026 #endif /* ATAFB_STE */
2028 /* Switching the screen size should be done during vsync, otherwise
2029 * the margins may get messed up. This is a well known problem of
2030 * the ST's video system.
2032 * Unfortunately there is hardly any way to find the vsync, as the
2033 * vertical blank interrupt is no longer in time on machines with
2034 * overscan type modifications.
2036 * We can, however, use Timer B to safely detect the black shoulder,
2037 * but then we've got to guess an appropriate delay to find the vsync.
2038 * This might not work on every machine.
2040 * martin_rogge @ ki.maus.de, 8th Aug 1995
2043 #define LINE_DELAY (mono_moni ? 30 : 70)
2044 #define SYNC_DELAY (mono_moni ? 1500 : 2000)
2046 /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
2047 static void st_ovsc_switch(void)
2049 unsigned long flags;
2050 register unsigned char old, new;
2052 if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
2054 local_irq_save(flags);
2056 mfp.tim_ct_b = 0x10;
2057 mfp.active_edge |= 8;
2059 mfp.tim_dt_b = 0xf0;
2061 while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
2068 } while (old != new);
2069 mfp.tim_ct_b = 0x10;
2072 if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
2073 acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
2074 if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
2075 acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
2076 if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
2077 sound_ym.rd_data_reg_sel = 14;
2078 sound_ym.wd_data = sound_ym.rd_data_reg_sel |
2079 ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
2080 ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
2082 local_irq_restore(flags);
2085 /* ------------------- External Video ---------------------- */
2089 static int ext_encode_fix( struct fb_fix_screeninfo *fix,
2090 struct atafb_par *par )
2093 strcpy(fix->id,"Unknown Extern");
2094 fix->smem_start = (unsigned long)external_addr;
2095 fix->smem_len = PAGE_ALIGN(external_len);
2096 if (external_depth == 1) {
2097 fix->type = FB_TYPE_PACKED_PIXELS;
2098 /* The letters 'n' and 'i' in the "atavideo=external:" stand
2099 * for "normal" and "inverted", rsp., in the monochrome case */
2101 (external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
2102 external_pmode == FB_TYPE_PACKED_PIXELS) ?
2107 /* Use STATIC if we don't know how to access color registers */
2108 int visual = external_vgaiobase ?
2109 FB_VISUAL_PSEUDOCOLOR :
2110 FB_VISUAL_STATIC_PSEUDOCOLOR;
2111 switch (external_pmode) {
2112 case -1: /* truecolor */
2113 fix->type=FB_TYPE_PACKED_PIXELS;
2114 fix->visual=FB_VISUAL_TRUECOLOR;
2116 case FB_TYPE_PACKED_PIXELS:
2117 fix->type=FB_TYPE_PACKED_PIXELS;
2120 case FB_TYPE_PLANES:
2121 fix->type=FB_TYPE_PLANES;
2124 case FB_TYPE_INTERLEAVED_PLANES:
2125 fix->type=FB_TYPE_INTERLEAVED_PLANES;
2134 fix->line_length = 0;
2139 static int ext_decode_var( struct fb_var_screeninfo *var,
2140 struct atafb_par *par )
2142 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
2144 if (var->bits_per_pixel > myvar->bits_per_pixel ||
2145 var->xres > myvar->xres ||
2146 var->xres_virtual > myvar->xres_virtual ||
2147 var->yres > myvar->yres ||
2155 static int ext_encode_var( struct fb_var_screeninfo *var,
2156 struct atafb_par *par )
2158 memset(var, 0, sizeof(struct fb_var_screeninfo));
2160 var->red.length=(external_pmode == -1) ? external_depth/3 :
2161 (external_vgaiobase ? external_bitspercol : 0);
2162 var->red.msb_right=0;
2165 var->pixclock=31041;
2166 var->left_margin=120; /* these are surely incorrect */
2167 var->right_margin=100;
2168 var->upper_margin=8;
2169 var->lower_margin=16;
2178 var->xres = external_xres;
2179 var->yres = external_yres;
2180 var->xres_virtual = external_xres_virtual;
2181 var->bits_per_pixel = external_depth;
2183 var->blue=var->green=var->red;
2184 var->transp.offset=0;
2185 var->transp.length=0;
2186 var->transp.msb_right=0;
2187 var->yres_virtual=var->yres;
2192 var->vmode=FB_VMODE_NONINTERLACED;
2197 static void ext_get_par( struct atafb_par *par )
2199 par->screen_base = external_addr;
2202 static void ext_set_par( struct atafb_par *par )
2206 #define OUTB(port,val) \
2207 *((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
2209 (*((unsigned volatile char *) ((port)+external_vgaiobase)))
2212 unsigned char tmp=INB(0x3da); \
2216 static int ext_getcolreg( unsigned regno, unsigned *red,
2217 unsigned *green, unsigned *blue,
2218 unsigned *transp, struct fb_info *info )
2220 if (! external_vgaiobase)
2223 *red = ext_color[regno].red;
2224 *green = ext_color[regno].green;
2225 *blue = ext_color[regno].blue;
2230 static int ext_setcolreg( unsigned regno, unsigned red,
2231 unsigned green, unsigned blue,
2232 unsigned transp, struct fb_info *info )
2234 { unsigned char colmask = (1 << external_bitspercol) - 1;
2236 if (! external_vgaiobase)
2239 ext_color[regno].red = red;
2240 ext_color[regno].green = green;
2241 ext_color[regno].blue = blue;
2243 switch (external_card_type) {
2247 OUTB(0x3c9, red & colmask);
2249 OUTB(0x3c9, green & colmask);
2251 OUTB(0x3c9, blue & colmask);
2256 OUTB((MV300_reg[regno] << 2)+1, red);
2257 OUTB((MV300_reg[regno] << 2)+1, green);
2258 OUTB((MV300_reg[regno] << 2)+1, blue);
2267 static int ext_detect( void )
2270 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
2271 struct atafb_par dummy_par;
2273 myvar->xres = external_xres;
2274 myvar->xres_virtual = external_xres_virtual;
2275 myvar->yres = external_yres;
2276 myvar->bits_per_pixel = external_depth;
2277 ext_encode_var(myvar, &dummy_par);
2281 #endif /* ATAFB_EXT */
2283 /* ------ This is the same for most hardware types -------- */
2285 static void set_screen_base(void *s_base)
2288 addr= virt_to_phys(s_base);
2289 /* Setup Screen Memory */
2290 shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
2291 shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
2292 shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
2296 static int pan_display( struct fb_var_screeninfo *var,
2297 struct atafb_par *par )
2299 if (!fbhw->set_screen_base ||
2300 (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
2302 var->xoffset = up(var->xoffset, 16);
2303 par->screen_base = screen_base +
2304 (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset)
2305 * fb_display[fb_info.currcon].var.bits_per_pixel / 8;
2306 fbhw->set_screen_base (par->screen_base);
2311 /* ------------ Interfaces to hardware functions ------------ */
2315 static struct fb_hwswitch tt_switch = {
2316 tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
2317 tt_get_par, tt_set_par, tt_getcolreg,
2318 set_screen_base, NULL, pan_display
2323 static struct fb_hwswitch falcon_switch = {
2324 falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
2325 falcon_get_par, falcon_set_par, falcon_getcolreg,
2326 set_screen_base, falcon_blank, falcon_pan_display
2331 static struct fb_hwswitch st_switch = {
2332 stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
2333 stste_get_par, stste_set_par, stste_getcolreg,
2334 stste_set_screen_base, NULL, pan_display
2339 static struct fb_hwswitch ext_switch = {
2340 ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
2341 ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL
2347 static void atafb_get_par( struct atafb_par *par )
2349 if (current_par_valid) {
2357 static void atafb_set_par( struct atafb_par *par )
2361 current_par_valid=1;
2366 /* =========================================================== */
2367 /* ============== Hardware Independent Functions ============= */
2368 /* =========================================================== */
2371 /* used for hardware scrolling */
2374 fb_update_var(int con, struct fb_info *info)
2376 int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
2377 fb_display[con].var.bits_per_pixel>>3;
2379 current_par.screen_base=screen_base + off;
2381 if (fbhw->set_screen_base)
2382 fbhw->set_screen_base(current_par.screen_base);
2387 do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
2390 struct atafb_par par;
2391 if ((err=fbhw->decode_var(var, &par)))
2393 activate=var->activate;
2394 if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
2395 atafb_set_par(&par);
2396 fbhw->encode_var(var, &par);
2397 var->activate=activate;
2402 atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2404 struct atafb_par par;
2406 atafb_get_par(&par);
2409 if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
2412 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2413 return fbhw->encode_fix(fix, &par);
2417 atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
2419 struct atafb_par par;
2421 atafb_get_par(&par);
2422 fbhw->encode_var(var, &par);
2425 *var=fb_display[con].var;
2430 atafb_set_disp(int con, struct fb_info *info)
2432 struct fb_fix_screeninfo fix;
2433 struct fb_var_screeninfo var;
2434 struct display *display;
2437 display = &fb_display[con];
2439 display = &disp; /* used during initialization */
2441 atafb_get_fix(&fix, con, info);
2442 atafb_get_var(&var, con, info);
2445 info->screen_base = (void *)fix.smem_start;
2446 display->visual = fix.visual;
2447 display->type = fix.type;
2448 display->type_aux = fix.type_aux;
2449 display->ypanstep = fix.ypanstep;
2450 display->ywrapstep = fix.ywrapstep;
2451 display->line_length = fix.line_length;
2452 if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
2453 fix.visual != FB_VISUAL_DIRECTCOLOR)
2454 display->can_soft_blank = 0;
2456 display->can_soft_blank = 1;
2458 (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
2460 case FB_TYPE_INTERLEAVED_PLANES:
2461 switch (var.bits_per_pixel) {
2462 #ifdef FBCON_HAS_IPLAN2P2
2464 display->dispsw = &fbcon_iplan2p2;
2467 #ifdef FBCON_HAS_IPLAN2P4
2469 display->dispsw = &fbcon_iplan2p4;
2472 #ifdef FBCON_HAS_IPLAN2P8
2474 display->dispsw = &fbcon_iplan2p8;
2479 case FB_TYPE_PACKED_PIXELS:
2480 switch (var.bits_per_pixel) {
2481 #ifdef FBCON_HAS_MFB
2483 display->dispsw = &fbcon_mfb;
2486 #ifdef FBCON_HAS_CFB8
2488 display->dispsw = &fbcon_cfb8;
2491 #ifdef FBCON_HAS_CFB16
2493 display->dispsw = &fbcon_cfb16;
2494 display->dispsw_data = fbcon_cfb16_cmap;
2503 atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
2505 int err,oldxres,oldyres,oldbpp,oldxres_virtual,
2506 oldyres_virtual,oldyoffset;
2507 if ((err=do_fb_set_var(var, con==info->currcon)))
2509 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
2510 oldxres=fb_display[con].var.xres;
2511 oldyres=fb_display[con].var.yres;
2512 oldxres_virtual=fb_display[con].var.xres_virtual;
2513 oldyres_virtual=fb_display[con].var.yres_virtual;
2514 oldbpp=fb_display[con].var.bits_per_pixel;
2515 oldyoffset=fb_display[con].var.yoffset;
2516 fb_display[con].var=*var;
2517 if (oldxres != var->xres || oldyres != var->yres
2518 || oldxres_virtual != var->xres_virtual
2519 || oldyres_virtual != var->yres_virtual
2520 || oldbpp != var->bits_per_pixel
2521 || oldyoffset != var->yoffset) {
2522 atafb_set_disp(con, info);
2523 (*fb_info.changevar)(con);
2524 fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
2525 do_install_cmap(con, info);
2535 atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
2537 if (con == info->currcon) /* current console ? */
2538 return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info);
2540 if (fb_display[con].cmap.len) /* non default colormap ? */
2541 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
2543 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
2544 cmap, kspc ? 0 : 2);
2549 atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
2551 int xoffset = var->xoffset;
2552 int yoffset = var->yoffset;
2555 if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
2556 || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
2559 if (con == info->currcon) {
2560 if (fbhw->pan_display) {
2561 if ((err = fbhw->pan_display(var, ¤t_par)))
2567 fb_display[con].var.xoffset = var->xoffset;
2568 fb_display[con].var.yoffset = var->yoffset;
2573 atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
2576 #ifdef FBCMD_GET_CURRENTPAR
2577 case FBCMD_GET_CURRENTPAR:
2578 if (copy_to_user((void *)arg, (void *)¤t_par,
2579 sizeof(struct atafb_par)))
2583 #ifdef FBCMD_SET_CURRENTPAR
2584 case FBCMD_SET_CURRENTPAR:
2585 if (copy_from_user((void *)¤t_par, (void *)arg,
2586 sizeof(struct atafb_par)))
2588 atafb_set_par(¤t_par);
2595 /* (un)blank/poweroff
2603 atafb_blank(int blank, struct fb_info *info)
2605 unsigned short black[16];
2606 struct fb_cmap cmap;
2607 if (fbhw->blank && !fbhw->blank(blank))
2610 memset(black, 0, 16*sizeof(unsigned short));
2617 fb_set_cmap(&cmap, 1, info);
2620 do_install_cmap(info->currcon, info);
2624 static struct fb_ops atafb_ops = {
2625 .owner = THIS_MODULE,
2626 .fb_get_fix = atafb_get_fix,
2627 .fb_get_var = atafb_get_var,
2628 .fb_set_var = atafb_set_var,
2629 .fb_get_cmap = atafb_get_cmap,
2630 .fb_set_cmap = gen_set_cmap,
2631 .fb_pan_display =atafb_pan_display,
2632 .fb_blank = atafb_blank,
2633 .fb_ioctl = atafb_ioctl,
2637 check_default_par( int detected_mode )
2639 char default_name[10];
2641 struct fb_var_screeninfo var;
2642 unsigned long min_mem;
2644 /* First try the user supplied mode */
2646 var=atafb_predefined[default_par-1];
2647 var.activate = FB_ACTIVATE_TEST;
2648 if (do_fb_set_var(&var,1))
2649 default_par=0; /* failed */
2651 /* Next is the autodetected one */
2652 if (! default_par) {
2653 var=atafb_predefined[detected_mode-1]; /* autodetect */
2654 var.activate = FB_ACTIVATE_TEST;
2655 if (!do_fb_set_var(&var,1))
2656 default_par=detected_mode;
2658 /* If that also failed, try some default modes... */
2659 if (! default_par) {
2660 /* try default1, default2... */
2661 for (i=1 ; i < 10 ; i++) {
2662 sprintf(default_name,"default%d",i);
2663 default_par=get_video_mode(default_name);
2665 panic("can't set default video mode");
2666 var=atafb_predefined[default_par-1];
2667 var.activate = FB_ACTIVATE_TEST;
2668 if (! do_fb_set_var(&var,1))
2672 min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
2673 if (default_mem_req < min_mem)
2674 default_mem_req=min_mem;
2678 atafb_switch(int con, struct fb_info *info)
2680 /* Do we have to save the colormap ? */
2681 if (fb_display[info->currcon].cmap.len)
2682 fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg,
2684 do_fb_set_var(&fb_display[con].var,1);
2686 /* Install new colormap */
2687 do_install_cmap(con, info);
2691 int __init atafb_init(void)
2695 unsigned long mem_req;
2702 if (external_addr) {
2704 atafb_ops.fb_setcolreg = &ext_setcolreg;
2709 if (ATARIHW_PRESENT(TT_SHIFTER)) {
2711 atafb_ops.fb_setcolreg = &tt_setcolreg;
2716 if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
2717 fbhw = &falcon_switch;
2718 atafb_ops.fb_setcolreg = &falcon_setcolreg;
2719 request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
2720 "framebuffer/modeswitch", falcon_vbl_switcher);
2725 if (ATARIHW_PRESENT(STND_SHIFTER) ||
2726 ATARIHW_PRESENT(EXTD_SHIFTER)) {
2728 atafb_ops.fb_setcolreg = &stste_setcolreg;
2732 atafb_ops.fb_setcolreg = &stste_setcolreg;
2733 printk("Cannot determine video hardware; defaulting to ST(e)\n");
2734 #else /* ATAFB_STE */
2735 /* no default driver included */
2736 /* Nobody will ever see this message :-) */
2737 panic("Cannot initialize video hardware");
2741 /* Multisync monitor capabilities */
2742 /* Atari-TOS defaults if no boot option present */
2743 if (fb_info.monspecs.hfmin == 0) {
2744 fb_info.monspecs.hfmin = 31000;
2745 fb_info.monspecs.hfmax = 32000;
2746 fb_info.monspecs.vfmin = 58;
2747 fb_info.monspecs.vfmax = 62;
2750 detected_mode = fbhw->detect();
2751 check_default_par(detected_mode);
2753 if (!external_addr) {
2754 #endif /* ATAFB_EXT */
2755 mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
2756 mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
2757 screen_base = atari_stram_alloc(mem_req, "atafb");
2759 panic("Cannot allocate screen memory");
2760 memset(screen_base, 0, mem_req);
2761 pad = -(unsigned long)screen_base & (PAGE_SIZE-1);
2763 real_screen_base=screen_base+ovsc_offset;
2764 screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
2766 if (CPU_IS_040_OR_060) {
2767 /* On a '040+, the cache mode of video RAM must be set to
2768 * write-through also for internal video hardware! */
2769 cache_push(virt_to_phys(screen_base), screen_len);
2770 kernel_set_cachemode(screen_base, screen_len,
2771 IOMAP_WRITETHROUGH);
2776 /* Map the video memory (physical address given) to somewhere
2777 * in the kernel address space.
2780 ioremap_writethrough((unsigned long)external_addr,
2782 if (external_vgaiobase)
2783 external_vgaiobase =
2784 (unsigned long)ioremap(external_vgaiobase, 0x10000);
2786 real_screen_base = external_addr;
2787 screen_len = external_len & PAGE_MASK;
2788 memset (screen_base, 0, external_len);
2790 #endif /* ATAFB_EXT */
2792 strcpy(fb_info.modename, "Atari Builtin ");
2793 fb_info.changevar = NULL;
2794 fb_info.fbops = &atafb_ops;
2795 fb_info.disp = &disp;
2796 fb_info.currcon = -1;
2797 fb_info.switch_con = &atafb_switch;
2798 fb_info.updatevar = &fb_update_var;
2799 fb_info.flags = FBINFO_FLAG_DEFAULT;
2800 do_fb_set_var(&atafb_predefined[default_par-1], 1);
2801 strcat(fb_info.modename, fb_var_names[default_par-1][0]);
2803 atafb_get_var(&disp.var, -1, &fb_info);
2804 atafb_set_disp(-1, &fb_info);
2805 do_install_cmap(0, &fb_info);
2807 if (register_framebuffer(&fb_info) < 0)
2810 printk("Determined %dx%d, depth %d\n",
2811 disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
2812 if ((disp.var.xres != disp.var.xres_virtual) ||
2813 (disp.var.yres != disp.var.yres_virtual))
2814 printk(" virtual %dx%d\n",
2815 disp.var.xres_virtual, disp.var.yres_virtual);
2816 printk("fb%d: %s frame buffer device, using %dK of video memory\n",
2817 fb_info.node, fb_info.modename, screen_len>>10);
2819 /* TODO: This driver cannot be unloaded yet */
2825 static void __init atafb_setup_ext(char *spec)
2827 int xres, xres_virtual, yres, depth, planes;
2828 unsigned long addr, len;
2831 /* Format is: <xres>;<yres>;<depth>;<plane organ.>;
2833 * [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type>
2834 * [;<xres-virtual>]]]]]
2837 * <xres_virtual>: hardware's x-resolution (f.e. ProMST)
2839 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
2841 if (!(p = strsep(&spec, ";")) || !*p)
2843 xres_virtual = xres = simple_strtoul(p, NULL, 10);
2847 if (!(p = strsep(&spec, ";")) || !*p)
2849 yres = simple_strtoul(p, NULL, 10);
2853 if (!(p = strsep(&spec, ";")) || !*p)
2855 depth = simple_strtoul(p, NULL, 10);
2856 if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
2857 depth != 16 && depth != 24)
2860 if (!(p = strsep(&spec, ";")) || !*p)
2863 planes = FB_TYPE_INTERLEAVED_PLANES;
2865 planes = FB_TYPE_PACKED_PIXELS;
2867 planes = FB_TYPE_PLANES;
2869 planes = -1; /* true color */
2874 if (!(p = strsep(&spec, ";")) || !*p)
2876 addr = simple_strtoul(p, NULL, 0);
2878 if (!(p = strsep(&spec, ";")) || !*p)
2879 len = xres*yres*depth/8;
2881 len = simple_strtoul(p, NULL, 0);
2883 if ((p = strsep(&spec, ";")) && *p) {
2884 external_vgaiobase=simple_strtoul(p, NULL, 0);
2887 if ((p = strsep(&spec, ";")) && *p) {
2888 external_bitspercol = simple_strtoul(p, NULL, 0);
2889 if (external_bitspercol > 8)
2890 external_bitspercol = 8;
2891 else if (external_bitspercol < 1)
2892 external_bitspercol = 1;
2895 if ((p = strsep(&spec, ";")) && *p) {
2896 if (!strcmp(p, "vga"))
2897 external_card_type = IS_VGA;
2898 if (!strcmp(p, "mv300"))
2899 external_card_type = IS_MV300;
2902 if ((p = strsep(&spec, ";")) && *p) {
2903 xres_virtual = simple_strtoul(p, NULL, 10);
2904 if (xres_virtual < xres)
2905 xres_virtual = xres;
2906 if (xres_virtual*yres*depth/8 > len)
2907 len=xres_virtual*yres*depth/8;
2910 external_xres = xres;
2911 external_xres_virtual = xres_virtual;
2912 external_yres = yres;
2913 external_depth = depth;
2914 external_pmode = planes;
2915 external_addr = (void *)addr;
2918 if (external_card_type == IS_MV300)
2919 switch (external_depth) {
2921 MV300_reg = MV300_reg_1bit;
2924 MV300_reg = MV300_reg_4bit;
2927 MV300_reg = MV300_reg_8bit;
2931 #endif /* ATAFB_EXT */
2934 static void __init atafb_setup_int(char *spec)
2936 /* Format to config extended internal video hardware like OverScan:
2937 "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
2939 <xres>: x-resolution
2940 <yres>: y-resolution
2941 The following are only needed if you have an overscan which
2942 needs a black border:
2943 <xres_max>: max. length of a line in pixels your OverScan hardware would allow
2944 <yres_max>: max. number of lines your OverScan hardware would allow
2945 <offset>: Offset from physical beginning to visible beginning
2951 if (!(p = strsep(&spec, ";")) || !*p)
2953 xres = simple_strtoul(p, NULL, 10);
2954 if (!(p = strsep(&spec, ";")) || !*p)
2957 tt_yres=st_yres=simple_strtoul(p, NULL, 10);
2958 if ((p=strsep(&spec, ";")) && *p) {
2959 sttt_xres_virtual=simple_strtoul(p, NULL, 10);
2961 if ((p=strsep(&spec, ";")) && *p) {
2962 sttt_yres_virtual=simple_strtoul(p, NULL, 0);
2964 if ((p=strsep(&spec, ";")) && *p) {
2965 ovsc_offset=simple_strtoul(p, NULL, 0);
2968 if (ovsc_offset || (sttt_yres_virtual != st_yres))
2974 static void __init atafb_setup_mcap(char *spec)
2977 int vmin, vmax, hmin, hmax;
2979 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
2980 * <V*> vertical freq. in Hz
2981 * <H*> horizontal freq. in kHz
2983 if (!(p = strsep(&spec, ";")) || !*p)
2985 vmin = simple_strtoul(p, NULL, 10);
2988 if (!(p = strsep(&spec, ";")) || !*p)
2990 vmax = simple_strtoul(p, NULL, 10);
2991 if (vmax <= 0 || vmax <= vmin)
2993 if (!(p = strsep(&spec, ";")) || !*p)
2995 hmin = 1000 * simple_strtoul(p, NULL, 10);
2998 if (!(p = strsep(&spec, "")) || !*p)
3000 hmax = 1000 * simple_strtoul(p, NULL, 10);
3001 if (hmax <= 0 || hmax <= hmin)
3004 fb_info.monspecs.vfmin = vmin;
3005 fb_info.monspecs.vfmax = vmax;
3006 fb_info.monspecs.hfmin = hmin;
3007 fb_info.monspecs.hfmax = hmax;
3009 #endif /* ATAFB_FALCON */
3012 static void __init atafb_setup_user(char *spec)
3014 /* Format of user defined video mode is: <xres>;<yres>;<depth>
3017 int xres, yres, depth, temp;
3019 if (!(p = strsep(&spec, ";")) || !*p)
3021 xres = simple_strtoul(p, NULL, 10);
3022 if (!(p = strsep(&spec, ";")) || !*p)
3024 yres = simple_strtoul(p, NULL, 10);
3025 if (!(p = strsep(&spec, "")) || !*p)
3027 depth = simple_strtoul(p, NULL, 10);
3028 if ((temp=get_video_mode("user0"))) {
3030 atafb_predefined[default_par-1].xres = xres;
3031 atafb_predefined[default_par-1].yres = yres;
3032 atafb_predefined[default_par-1].bits_per_pixel = depth;
3036 int __init atafb_setup( char *options )
3041 fb_info.fontname[0] = '\0';
3043 if (!options || !*options)
3046 while ((this_opt = strsep(&options, ",")) != NULL) {
3047 if (!*this_opt) continue;
3048 if ((temp=get_video_mode(this_opt)))
3050 else if (! strcmp(this_opt, "inverse"))
3052 else if (!strncmp(this_opt, "font:", 5))
3053 strcpy(fb_info.fontname, this_opt+5);
3054 else if (! strncmp(this_opt, "hwscroll_",9)) {
3055 hwscroll=simple_strtoul(this_opt+9, NULL, 10);
3062 else if (!strcmp(this_opt,"mv300")) {
3063 external_bitspercol = 8;
3064 external_card_type = IS_MV300;
3066 else if (!strncmp(this_opt,"external:",9))
3067 atafb_setup_ext(this_opt+9);
3069 else if (!strncmp(this_opt,"internal:",9))
3070 atafb_setup_int(this_opt+9);
3072 else if (!strncmp(this_opt, "eclock:", 7)) {
3073 fext.f = simple_strtoul(this_opt+7, NULL, 10);
3074 /* external pixelclock in kHz --> ps */
3075 fext.t = 1000000000/fext.f;
3078 else if (!strncmp(this_opt, "monitorcap:", 11))
3079 atafb_setup_mcap(this_opt+11);
3081 else if (!strcmp(this_opt, "keep"))
3083 else if (!strncmp(this_opt, "R", 1))
3084 atafb_setup_user(this_opt+1);
3090 MODULE_LICENSE("GPL");
3092 int init_module(void)
3094 return atafb_init();