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/tty.h>
57 #include <linux/slab.h>
58 #include <linux/delay.h>
59 #include <linux/init.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 currcon=0;
178 static int mono_moni=0;
180 static struct display disp;
184 /* external video handling */
186 static unsigned external_xres;
187 static unsigned external_xres_virtual;
188 static unsigned external_yres;
189 /* not needed - atafb will never support panning/hardwarescroll with external
190 * static unsigned external_yres_virtual;
193 static unsigned external_depth;
194 static int external_pmode;
195 static void *external_addr = 0;
196 static unsigned long external_len;
197 static unsigned long external_vgaiobase = 0;
198 static unsigned int external_bitspercol = 6;
201 JOE <joe@amber.dinoco.de>:
202 added card type for external driver, is only needed for
206 enum cardtype { IS_VGA, IS_MV300 };
207 static enum cardtype external_card_type = IS_VGA;
210 The MV300 mixes the color registers. So we need an array of munged
211 indices in order to access the correct reg.
213 static int MV300_reg_1bit[2]={0,1};
214 static int MV300_reg_4bit[16]={
215 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
216 static int MV300_reg_8bit[256]={
217 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
218 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
219 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
220 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
221 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
222 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
223 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
224 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
225 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
226 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
227 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
228 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
229 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
230 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
231 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
232 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 };
234 static int *MV300_reg = MV300_reg_8bit;
237 And on the MV300 it's difficult to read out the hardware palette. So we
238 just keep track of the set colors in our own array here, and use that!
241 static struct { unsigned char red,green,blue,pad; } ext_color[256];
242 #endif /* ATAFB_EXT */
245 static int inverse=0;
247 extern int fontheight_8x8;
248 extern int fontwidth_8x8;
249 extern unsigned char fontdata_8x8[];
251 extern int fontheight_8x16;
252 extern int fontwidth_8x16;
253 extern unsigned char fontdata_8x16[];
255 /* ++roman: This structure abstracts from the underlying hardware (ST(e),
258 * int (*detect)( void )
259 * This function should detect the current video mode settings and
260 * store them in atafb_predefined[0] for later reference by the
261 * user. Return the index+1 of an equivalent predefined mode or 0
262 * if there is no such.
264 * int (*encode_fix)( struct fb_fix_screeninfo *fix,
265 * struct atafb_par *par )
266 * This function should fill in the 'fix' structure based on the
267 * values in the 'par' structure.
269 * int (*decode_var)( struct fb_var_screeninfo *var,
270 * struct atafb_par *par )
271 * Get the video params out of 'var'. If a value doesn't fit, round
272 * it up, if it's too big, return EINVAL.
273 * Round up in the following order: bits_per_pixel, xres, yres,
274 * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
275 * horizontal timing, vertical timing.
277 * int (*encode_var)( struct fb_var_screeninfo *var,
278 * struct atafb_par *par );
279 * Fill the 'var' structure based on the values in 'par' and maybe
280 * other values read out of the hardware.
282 * void (*get_par)( struct atafb_par *par )
283 * Fill the hardware's 'par' structure.
285 * void (*set_par)( struct atafb_par *par )
286 * Set the hardware according to 'par'.
288 * int (*setcolreg)( unsigned regno, unsigned red,
289 * unsigned green, unsigned blue,
290 * unsigned transp, struct fb_info *info )
291 * Set a single color register. The values supplied are already
292 * rounded down to the hardware's capabilities (according to the
293 * entries in the var structure). Return != 0 for invalid regno.
295 * int (*getcolreg)( unsigned regno, unsigned *red,
296 * unsigned *green, unsigned *blue,
297 * unsigned *transp, struct fb_info *info )
298 * Read a single color register and split it into
299 * colors/transparent. Return != 0 for invalid regno.
301 * void (*set_screen_base)(void *s_base)
302 * Set the base address of the displayed frame buffer. Only called
303 * if yres_virtual > yres or xres_virtual > xres.
305 * int (*blank)( int blank_mode )
306 * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
307 * the caller blanks by setting the CLUT to all black. Return 0 if blanking
308 * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
309 * doesn't support it. Implements VESA suspend and powerdown modes on
310 * hardware that supports disabling hsync/vsync:
311 * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
314 static struct fb_hwswitch {
315 int (*detect)( void );
316 int (*encode_fix)( struct fb_fix_screeninfo *fix,
317 struct atafb_par *par );
318 int (*decode_var)( struct fb_var_screeninfo *var,
319 struct atafb_par *par );
320 int (*encode_var)( struct fb_var_screeninfo *var,
321 struct atafb_par *par );
322 void (*get_par)( struct atafb_par *par );
323 void (*set_par)( struct atafb_par *par );
324 int (*getcolreg)( unsigned regno, unsigned *red,
325 unsigned *green, unsigned *blue,
326 unsigned *transp, struct fb_info *info );
327 int (*setcolreg)( unsigned regno, unsigned red,
328 unsigned green, unsigned blue,
329 unsigned transp, struct fb_info *info );
330 void (*set_screen_base)(void *s_base);
331 int (*blank)( int blank_mode );
332 int (*pan_display)( struct fb_var_screeninfo *var,
333 struct atafb_par *par);
336 static char *autodetect_names[] = {"autodetect", NULL};
337 static char *stlow_names[] = {"stlow", NULL};
338 static char *stmid_names[] = {"stmid", "default5", NULL};
339 static char *sthigh_names[] = {"sthigh", "default4", NULL};
340 static char *ttlow_names[] = {"ttlow", NULL};
341 static char *ttmid_names[]= {"ttmid", "default1", NULL};
342 static char *tthigh_names[]= {"tthigh", "default2", NULL};
343 static char *vga2_names[] = {"vga2", NULL};
344 static char *vga4_names[] = {"vga4", NULL};
345 static char *vga16_names[] = {"vga16", "default3", NULL};
346 static char *vga256_names[] = {"vga256", NULL};
347 static char *falh2_names[] = {"falh2", NULL};
348 static char *falh16_names[] = {"falh16", NULL};
350 static char **fb_var_names[] = {
351 /* Writing the name arrays directly in this array (via "(char *[]){...}")
352 * crashes gcc 2.5.8 (sigsegv) if the inner array
353 * contains more than two items. I've also seen that all elements
354 * were identical to the last (my cross-gcc) :-(*/
369 /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
372 static struct fb_var_screeninfo atafb_predefined[] = {
374 * yres_virtual==0 means use hw-scrolling if possible, else yres
377 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
378 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
379 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
381 320, 200, 320, 0, 0, 0, 4, 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, 200, 640, 0, 0, 0, 2, 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 640, 400, 640, 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 320, 480, 320, 0, 0, 0, 8, 0,
394 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
395 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
397 640, 480, 640, 0, 0, 0, 4, 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 1280, 960, 1280, 0, 0, 0, 1, 0,
402 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
403 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
405 640, 480, 640, 0, 0, 0, 1, 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 640, 480, 640, 0, 0, 0, 2, 0,
410 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
411 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
413 640, 480, 640, 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 },
417 640, 480, 640, 0, 0, 0, 8, 0,
418 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
419 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
421 896, 608, 896, 0, 0, 0, 1, 0,
422 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
423 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
425 896, 608, 896, 0, 0, 0, 4, 0,
426 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
427 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
430 static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
434 get_video_mode(char *vname)
439 name_list=fb_var_names;
440 for (i = 0 ; i < num_atafb_predefined ; i++) {
442 if (! name || ! *name)
445 if (! strcmp(vname, *name))
455 /* ------------------- TT specific functions ---------------------- */
459 static int tt_encode_fix( struct fb_fix_screeninfo *fix,
460 struct atafb_par *par )
465 strcpy(fix->id,"Atari Builtin");
466 fix->smem_start = (unsigned long)real_screen_base;
467 fix->smem_len = screen_len;
468 fix->type=FB_TYPE_INTERLEAVED_PLANES;
470 fix->visual=FB_VISUAL_PSEUDOCOLOR;
471 mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
472 if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
473 fix->type=FB_TYPE_PACKED_PIXELS;
475 if (mode == TT_SHIFTER_TTHIGH)
476 fix->visual=FB_VISUAL_MONO01;
481 fix->line_length = 0;
482 fix->accel = FB_ACCEL_ATARIBLITT;
487 static int tt_decode_var( struct fb_var_screeninfo *var,
488 struct atafb_par *par )
492 int bpp=var->bits_per_pixel;
494 int yres_virtual = var->yres_virtual;
497 if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
499 par->hw.tt.mode=TT_SHIFTER_TTHIGH;
504 if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
507 if (xres > sttt_xres/2 || yres > tt_yres)
509 par->hw.tt.mode=TT_SHIFTER_TTLOW;
515 if (xres > sttt_xres || yres > tt_yres)
517 if (xres > sttt_xres/2 || yres > st_yres/2) {
518 par->hw.tt.mode=TT_SHIFTER_TTMID;
524 par->hw.tt.mode=TT_SHIFTER_STLOW;
531 if (xres > sttt_xres || yres > st_yres/2)
533 par->hw.tt.mode=TT_SHIFTER_STMID;
538 else if (var->xres > sttt_xres || var->yres > st_yres) {
542 par->hw.tt.mode=TT_SHIFTER_STHIGH;
548 if (yres_virtual <= 0)
550 else if (yres_virtual < yres)
552 if (var->sync & FB_SYNC_EXT)
557 if (yres_virtual * linelen > screen_len && screen_len)
559 if (yres * linelen > screen_len && screen_len)
561 if (var->yoffset + yres > yres_virtual && yres_virtual)
563 par->yres_virtual = yres_virtual;
564 par->screen_base = screen_base + var->yoffset * linelen;
568 static int tt_encode_var( struct fb_var_screeninfo *var,
569 struct atafb_par *par )
572 memset(var, 0, sizeof(struct fb_var_screeninfo));
575 var->red.msb_right=0;
579 var->left_margin=120; /* these may be incorrect */
580 var->right_margin=100;
582 var->lower_margin=16;
589 if (par->hw.tt.sync & 1)
592 var->sync=FB_SYNC_EXT;
594 switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
595 case TT_SHIFTER_STLOW:
596 var->xres=sttt_xres/2;
597 var->xres_virtual=sttt_xres_virtual/2;
599 var->bits_per_pixel=4;
601 case TT_SHIFTER_STMID:
603 var->xres_virtual=sttt_xres_virtual;
605 var->bits_per_pixel=2;
607 case TT_SHIFTER_STHIGH:
609 var->xres_virtual=sttt_xres_virtual;
611 var->bits_per_pixel=1;
613 case TT_SHIFTER_TTLOW:
614 var->xres=sttt_xres/2;
615 var->xres_virtual=sttt_xres_virtual/2;
617 var->bits_per_pixel=8;
619 case TT_SHIFTER_TTMID:
621 var->xres_virtual=sttt_xres_virtual;
623 var->bits_per_pixel=4;
625 case TT_SHIFTER_TTHIGH:
627 var->xres=sttt_xres*2;
628 var->xres_virtual=sttt_xres_virtual*2;
630 var->bits_per_pixel=1;
633 var->blue=var->green=var->red;
634 var->transp.offset=0;
635 var->transp.length=0;
636 var->transp.msb_right=0;
637 linelen=var->xres_virtual * var->bits_per_pixel / 8;
639 var->yres_virtual=var->yres;
640 else if (screen_len) {
641 if (par->yres_virtual)
642 var->yres_virtual = par->yres_virtual;
644 /* yres_virtual==0 means use maximum */
645 var->yres_virtual = screen_len / linelen;
648 var->yres_virtual = 2 * var->yres;
650 var->yres_virtual=var->yres+hwscroll * 16;
654 var->yoffset=(par->screen_base - screen_base)/linelen;
659 var->vmode=FB_VMODE_NONINTERLACED;
664 static void tt_get_par( struct atafb_par *par )
667 par->hw.tt.mode=shifter_tt.tt_shiftmode;
668 par->hw.tt.sync=shifter.syncmode;
669 addr = ((shifter.bas_hi & 0xff) << 16) |
670 ((shifter.bas_md & 0xff) << 8) |
671 ((shifter.bas_lo & 0xff));
672 par->screen_base = phys_to_virt(addr);
675 static void tt_set_par( struct atafb_par *par )
677 shifter_tt.tt_shiftmode=par->hw.tt.mode;
678 shifter.syncmode=par->hw.tt.sync;
679 /* only set screen_base if really necessary */
680 if (current_par.screen_base != par->screen_base)
681 fbhw->set_screen_base(par->screen_base);
685 static int tt_getcolreg(unsigned regno, unsigned *red,
686 unsigned *green, unsigned *blue,
687 unsigned *transp, struct fb_info *info)
691 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
695 t = tt_palette[regno];
713 static int tt_setcolreg(unsigned regno, unsigned red,
714 unsigned green, unsigned blue,
715 unsigned transp, struct fb_info *info)
717 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
721 tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
723 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
724 TT_SHIFTER_STHIGH && regno == 254)
730 static int tt_detect( void )
732 { struct atafb_par par;
734 /* Determine the connected monitor: The DMA sound must be
735 * disabled before reading the MFP GPIP, because the Sound
736 * Done Signal and the Monochrome Detect are XORed together!
738 * Even on a TT, we should look if there is a DMA sound. It was
739 * announced that the Eagle is TT compatible, but only the PCM is
742 if (ATARIHW_PRESENT(PCM_8BIT)) {
743 tt_dmasnd.ctrl = DMASND_CTRL_OFF;
744 udelay(20); /* wait a while for things to settle down */
746 mono_moni = (mfp.par_dt_reg & 0x80) == 0;
749 tt_encode_var(&atafb_predefined[0], &par);
754 #endif /* ATAFB_TT */
756 /* ------------------- Falcon specific functions ---------------------- */
760 static int mon_type; /* Falcon connected monitor */
761 static int f030_bus_width; /* Falcon ram bus width (for vid_control) */
767 static struct pixel_clock {
768 unsigned long f; /* f/[Hz] */
769 unsigned long t; /* t/[ps] (=1/f) */
770 int right, hsync, left; /* standard timing in clock cycles, not pixel */
771 /* hsync initialized in falcon_detect() */
772 int sync_mask; /* or-mask for hw.falcon.sync to set this clock */
773 int control_mask; /* ditto, for hw.falcon.vid_control */
775 f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
776 f32 = {32000000, 31250, 18, 0, 42, 0x0, 0},
777 fext = { 0, 0, 18, 0, 42, 0x1, 0};
779 /* VIDEL-prescale values [mon_type][pixel_length from VCO] */
780 static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
782 /* Default hsync timing [mon_type] in picoseconds */
783 static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
785 #ifdef FBCON_HAS_CFB16
786 static u16 fbcon_cfb16_cmap[16];
789 static inline int hxx_prescale(struct falcon_hw *hw)
791 return hw->ste_mode ? 16 :
792 vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
795 static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
796 struct atafb_par *par )
798 strcpy(fix->id, "Atari Builtin");
799 fix->smem_start = (unsigned long)real_screen_base;
800 fix->smem_len = screen_len;
801 fix->type = FB_TYPE_INTERLEAVED_PLANES;
803 fix->visual = FB_VISUAL_PSEUDOCOLOR;
807 if (par->hw.falcon.mono) {
808 fix->type = FB_TYPE_PACKED_PIXELS;
810 /* no smooth scrolling with longword aligned video mem */
813 else if (par->hw.falcon.f_shift & 0x100) {
814 fix->type = FB_TYPE_PACKED_PIXELS;
816 /* Is this ok or should it be DIRECTCOLOR? */
817 fix->visual = FB_VISUAL_TRUECOLOR;
820 fix->line_length = 0;
821 fix->accel = FB_ACCEL_ATARIBLITT;
826 static int falcon_decode_var( struct fb_var_screeninfo *var,
827 struct atafb_par *par )
829 int bpp = var->bits_per_pixel;
830 int xres = var->xres;
831 int yres = var->yres;
832 int xres_virtual = var->xres_virtual;
833 int yres_virtual = var->yres_virtual;
834 int left_margin, right_margin, hsync_len;
835 int upper_margin, lower_margin, vsync_len;
837 int interlace = 0, doubleline = 0;
838 struct pixel_clock *pclock;
839 int plen; /* width of pixel in clock cycles */
846 Get the video params out of 'var'. If a value doesn't fit, round
847 it up, if it's too big, return EINVAL.
848 Round up in the following order: bits_per_pixel, xres, yres,
849 xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
850 horizontal timing, vertical timing.
852 There is a maximum of screen resolution determined by pixelclock
853 and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
854 In interlace mode this is " * " *vfmin <= pixelclock.
855 Additional constraints: hfreq.
856 Frequency range for multisync monitors is given via command line.
857 For TV and SM124 both frequencies are fixed.
859 X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
860 Y % 16 == 0 to fit 8x16 font
863 Currently interlace and doubleline mode in var are ignored.
864 On SM124 and TV only the standard resolutions can be used.
867 /* Reject uninitialized mode */
868 if (!xres || !yres || !bpp)
871 if (mon_type == F_MON_SM && bpp != 1) {
876 par->hw.falcon.f_shift = 0x400;
877 par->hw.falcon.st_shift = 0x200;
881 par->hw.falcon.f_shift = 0x000;
882 par->hw.falcon.st_shift = 0x100;
886 par->hw.falcon.f_shift = 0x000;
887 par->hw.falcon.st_shift = 0x000;
891 par->hw.falcon.f_shift = 0x010;
893 else if (bpp <= 16) {
894 bpp = 16; /* packed pixel mode */
895 par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
899 par->hw.falcon.bpp = bpp;
901 if (mon_type == F_MON_SM || DontCalcRes) {
902 /* Skip all calculations. VGA/TV/SC1224 only supported. */
903 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
905 if (bpp > myvar->bits_per_pixel ||
906 var->xres > myvar->xres ||
907 var->yres > myvar->yres)
909 fbhw->get_par(par); /* Current par will be new par */
910 goto set_screen_base; /* Don't forget this */
913 /* Only some fixed resolutions < 640x400 */
916 else if (xres <= 640 && bpp != 16)
920 else if (yres <= 240)
922 else if (yres <= 400)
925 /* 2 planes must use STE compatibility mode */
926 par->hw.falcon.ste_mode = bpp==2;
927 par->hw.falcon.mono = bpp==1;
929 /* Total and visible scanline length must be a multiple of one longword,
930 * this and the console fontwidth yields the alignment for xres and
932 * TODO: this way "odd" fontheights are not supported
934 * Special case in STE mode: blank and graphic positions don't align,
935 * avoid trash at right margin
937 if (par->hw.falcon.ste_mode)
938 xres = (xres + 63) & ~63;
940 xres = (xres + 31) & ~31;
942 xres = (xres + 15) & ~15;
944 yres = (yres + 15) & ~15;
946 yres = (yres + 7) & ~7;
948 if (xres_virtual < xres)
951 xres_virtual = (xres_virtual + 31) & ~31;
953 xres_virtual = (xres_virtual + 15) & ~15;
955 if (yres_virtual <= 0)
957 else if (yres_virtual < yres)
960 /* backward bug-compatibility */
961 if (var->pixclock > 1)
964 par->hw.falcon.line_width = bpp * xres / 16;
965 par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
967 /* single or double pixel width */
968 xstretch = (xres < 640) ? 2 : 1;
970 #if 0 /* SM124 supports only 640x400, this is rejected above */
971 if (mon_type == F_MON_SM) {
972 if (xres != 640 && yres != 400)
976 /* SM124-mode is special */
977 par->hw.falcon.ste_mode = 1;
978 par->hw.falcon.f_shift = 0x000;
979 par->hw.falcon.st_shift = 0x200;
980 left_margin = hsync_len = 128 / plen;
982 /* TODO set all margins */
986 if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
988 if (var->pixclock > f32.t * plen)
993 if (var->pixclock == 0) {
994 /* set some minimal margins which center the screen */
997 hsync_len = pclock->hsync / plen;
1000 vsync_len = interlace ? 3 : 4;
1002 left_margin = var->left_margin;
1003 right_margin = var->right_margin;
1004 hsync_len = var->hsync_len;
1005 upper_margin = var->upper_margin;
1006 lower_margin = var->lower_margin;
1007 vsync_len = var->vsync_len;
1008 if (var->vmode & FB_VMODE_INTERLACED) {
1009 upper_margin = (upper_margin + 1) / 2;
1010 lower_margin = (lower_margin + 1) / 2;
1011 vsync_len = (vsync_len + 1) / 2;
1012 } else if (var->vmode & FB_VMODE_DOUBLE) {
1022 xstretch = 2; /* Double pixel width only for hicolor */
1023 /* Default values are used for vert./hor. timing if no pixelclock given. */
1024 if (var->pixclock == 0) {
1027 /* Choose master pixelclock depending on hor. timing */
1028 plen = 1 * xstretch;
1029 if ((plen * xres + f25.right+f25.hsync+f25.left) *
1030 fb_info.monspecs.hfmin < f25.f)
1032 else if ((plen * xres + f32.right+f32.hsync+f32.left) *
1033 fb_info.monspecs.hfmin < f32.f)
1035 else if ((plen * xres + fext.right+fext.hsync+fext.left) *
1036 fb_info.monspecs.hfmin < fext.f
1042 left_margin = pclock->left / plen;
1043 right_margin = pclock->right / plen;
1044 hsync_len = pclock->hsync / plen;
1045 linesize = left_margin + xres + right_margin + hsync_len;
1051 /* Choose largest pixelclock <= wanted clock */
1053 unsigned long pcl = ULONG_MAX;
1055 for (i=1; i <= 4; i *= 2) {
1056 if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
1060 if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
1064 if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
1071 plen = pcl / pclock->t;
1073 left_margin = var->left_margin;
1074 right_margin = var->right_margin;
1075 hsync_len = var->hsync_len;
1076 upper_margin = var->upper_margin;
1077 lower_margin = var->lower_margin;
1078 vsync_len = var->vsync_len;
1079 /* Internal unit is [single lines per (half-)frame] */
1080 if (var->vmode & FB_VMODE_INTERLACED) {
1081 /* # lines in half frame */
1082 /* External unit is [lines per full frame] */
1083 upper_margin = (upper_margin + 1) / 2;
1084 lower_margin = (lower_margin + 1) / 2;
1085 vsync_len = (vsync_len + 1) / 2;
1087 else if (var->vmode & FB_VMODE_DOUBLE) {
1088 /* External unit is [double lines per frame] */
1094 if (pclock == &fext)
1095 longoffset = 1; /* VIDEL doesn't synchronize on short offset */
1097 /* Is video bus bandwidth (32MB/s) too low for this resolution? */
1098 /* this is definitely wrong if bus clock != 32MHz */
1099 if (pclock->f / plen / 8 * bpp > 32000000L)
1105 /* include sync lengths in right/lower margin for all calculations */
1106 right_margin += hsync_len;
1107 lower_margin += vsync_len;
1109 /* ! In all calculations of margins we use # of lines in half frame
1110 * (which is a full frame in non-interlace mode), so we can switch
1111 * between interlace and non-interlace without messing around
1115 /* Set base_offset 128 and video bus width */
1116 par->hw.falcon.vid_control = mon_type | f030_bus_width;
1118 par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */
1119 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1120 par->hw.falcon.vid_control |= VCO_HSYPOS;
1121 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1122 par->hw.falcon.vid_control |= VCO_VSYPOS;
1124 par->hw.falcon.vid_control |= pclock->control_mask;
1125 /* External or internal clock */
1126 par->hw.falcon.sync = pclock->sync_mask | 0x2;
1127 /* Pixellength and prescale */
1128 par->hw.falcon.vid_mode = (2/plen) << 2;
1130 par->hw.falcon.vid_mode |= VMO_DOUBLE;
1132 par->hw.falcon.vid_mode |= VMO_INTER;
1134 /*********************
1135 Horizontal timing: unit = [master clock cycles]
1136 unit of hxx-registers: [master clock cycles * prescale]
1137 Hxx-registers are 9 bit wide
1139 1 line = ((hht + 2) * 2 * prescale) clock cycles
1141 graphic output = hdb & 0x200 ?
1142 ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
1143 ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
1144 (this must be a multiple of plen*128/bpp, on VGA pixels
1145 to the right may be cut off with a bigger right margin)
1147 start of graphics relative to start of 1st halfline = hdb & 0x200 ?
1148 (hdb - hht - 2) * prescale + hdboff :
1149 hdb * prescale + hdboff
1151 end of graphics relative to start of 1st halfline =
1152 (hde + hht + 2) * prescale + hdeoff
1153 *********************/
1154 /* Calculate VIDEL registers */
1156 int hdb_off, hde_off, base_off;
1157 int gstart, gend1, gend2, align;
1159 prescale = hxx_prescale(&par->hw.falcon);
1160 base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
1162 /* Offsets depend on video mode */
1163 /* Offsets are in clock cycles, divide by prescale to
1164 * calculate hd[be]-registers
1166 if (par->hw.falcon.f_shift & 0x100) {
1169 hdb_off = (base_off + 16 * plen) + prescale;
1173 hde_off = ((128 / bpp + 2) * plen);
1174 if (par->hw.falcon.ste_mode)
1175 hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
1177 hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
1180 gstart = (prescale/2 + plen * left_margin) / prescale;
1181 /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
1182 gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
1183 /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
1184 gend2 = gstart + xres * plen / prescale;
1185 par->HHT = plen * (left_margin + xres + right_margin) /
1187 /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
1189 par->HDB = gstart - hdb_off/prescale;
1191 if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
1192 par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
1193 par->HBB = gend2 - par->HHT - 2;
1195 /* One more Videl constraint: data fetch of two lines must not overlap */
1196 if (par->HDB & 0x200 && par->HDB & ~0x200 - par->HDE <= 5) {
1197 /* if this happens increase margins, decrease hfreq. */
1200 if (hde_off % prescale)
1201 par->HBB++; /* compensate for non matching hde and hbb */
1202 par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
1203 if (par->HSS < par->HBB)
1204 par->HSS = par->HBB;
1207 /* check hor. frequency */
1208 hfreq = pclock->f / ((par->HHT+2)*prescale*2);
1209 if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
1210 /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
1211 /* Too high -> enlarge margin */
1216 if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin)
1220 /* All Vxx must be odd in non-interlace, since frame starts in the middle
1221 * of the first displayed line!
1222 * One frame consists of VFT+1 half lines. VFT+1 must be even in
1223 * non-interlace, odd in interlace mode for synchronisation.
1224 * Vxx-registers are 11 bit wide
1226 par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
1227 par->VDB = par->VBE;
1229 if (!interlace) par->VDE <<= 1;
1230 if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */
1231 par->VDE += par->VDB;
1232 par->VBB = par->VDE;
1233 par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
1234 par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
1235 /* vbb,vss,vft must be even in interlace mode */
1242 /* V-frequency check, hope I didn't create any loop here. */
1243 /* Interlace and doubleline are mutually exclusive. */
1244 vfreq = (hfreq * 2) / (par->VFT + 1);
1245 if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
1246 /* Too high -> try again with doubleline */
1250 else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
1251 /* Too low -> try again with interlace */
1255 else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
1256 /* Doubleline too low -> clear doubleline and enlarge margins */
1260 (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
1263 upper_margin += lines;
1264 lower_margin += lines;
1267 else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
1268 /* Doubleline too high -> enlarge margins */
1271 (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
1274 upper_margin += lines;
1275 lower_margin += lines;
1278 else if (vfreq > fb_info.monspecs.vfmax && interlace) {
1279 /* Interlace, too high -> enlarge margins */
1282 (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
1285 upper_margin += lines;
1286 lower_margin += lines;
1289 else if (vfreq < fb_info.monspecs.vfmin ||
1290 vfreq > fb_info.monspecs.vfmax)
1294 linelen = xres_virtual * bpp / 8;
1295 if (yres_virtual * linelen > screen_len && screen_len)
1297 if (yres * linelen > screen_len && screen_len)
1299 if (var->yoffset + yres > yres_virtual && yres_virtual)
1301 par->yres_virtual = yres_virtual;
1302 par->screen_base = screen_base + var->yoffset * linelen;
1303 par->hw.falcon.xoffset = 0;
1308 static int falcon_encode_var( struct fb_var_screeninfo *var,
1309 struct atafb_par *par )
1311 /* !!! only for VGA !!! */
1314 int hdb_off, hde_off, base_off;
1315 struct falcon_hw *hw = &par->hw.falcon;
1317 memset(var, 0, sizeof(struct fb_var_screeninfo));
1318 /* possible frequencies: 25.175 or 32MHz */
1319 var->pixclock = hw->sync & 0x1 ? fext.t :
1320 hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
1326 if (hw->vid_control & VCO_HSYPOS)
1327 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1328 if (hw->vid_control & VCO_VSYPOS)
1329 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1331 var->vmode = FB_VMODE_NONINTERLACED;
1332 if (hw->vid_mode & VMO_INTER)
1333 var->vmode |= FB_VMODE_INTERLACED;
1334 if (hw->vid_mode & VMO_DOUBLE)
1335 var->vmode |= FB_VMODE_DOUBLE;
1337 /* visible y resolution:
1338 * Graphics display starts at line VDB and ends at line
1339 * VDE. If interlace mode off unit of VC-registers is
1340 * half lines, else lines.
1342 var->yres = hw->vde - hw->vdb;
1343 if (!(var->vmode & FB_VMODE_INTERLACED))
1345 if (var->vmode & FB_VMODE_DOUBLE)
1348 /* to get bpp, we must examine f_shift and st_shift.
1349 * f_shift is valid if any of bits no. 10, 8 or 4
1350 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
1351 * if bit 10 set then bit 8 and bit 4 don't care...
1352 * If all these bits are 0 get display depth from st_shift
1353 * (as for ST and STE)
1355 if (hw->f_shift & 0x400) /* 2 colors */
1356 var->bits_per_pixel = 1;
1357 else if (hw->f_shift & 0x100) /* hicolor */
1358 var->bits_per_pixel = 16;
1359 else if (hw->f_shift & 0x010) /* 8 bitplanes */
1360 var->bits_per_pixel = 8;
1361 else if (hw->st_shift == 0)
1362 var->bits_per_pixel = 4;
1363 else if (hw->st_shift == 0x100)
1364 var->bits_per_pixel = 2;
1365 else /* if (hw->st_shift == 0x200) */
1366 var->bits_per_pixel = 1;
1368 var->xres = hw->line_width * 16 / var->bits_per_pixel;
1369 var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
1371 var->xres_virtual += 16;
1373 if (var->bits_per_pixel == 16) {
1376 var->red.msb_right=0;
1377 var->green.offset=5;
1378 var->green.length=6;
1379 var->green.msb_right=0;
1382 var->blue.msb_right=0;
1386 var->red.length = hw->ste_mode ? 4 : 6;
1387 var->red.msb_right=0;
1389 var->blue=var->green=var->red;
1391 var->transp.offset=0;
1392 var->transp.length=0;
1393 var->transp.msb_right=0;
1395 linelen = var->xres_virtual * var->bits_per_pixel / 8;
1397 if (par->yres_virtual)
1398 var->yres_virtual = par->yres_virtual;
1400 /* yres_virtual==0 means use maximum */
1401 var->yres_virtual = screen_len / linelen;
1405 var->yres_virtual = 2 * var->yres;
1407 var->yres_virtual=var->yres+hwscroll * 16;
1409 var->xoffset=0; /* TODO change this */
1412 prescale = hxx_prescale(hw);
1413 plen = 4 >> (hw->vid_mode >> 2 & 0x3);
1414 base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
1415 if (hw->f_shift & 0x100) {
1417 hdb_off = (base_off + 16 * plen) + prescale;
1420 hde_off = ((128 / var->bits_per_pixel + 2) * plen);
1422 hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
1425 hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
1429 /* Right margin includes hsync */
1430 var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
1431 (hw->hdb & 0x200 ? 2+hw->hht : 0));
1432 if (hw->ste_mode || mon_type!=F_MON_VGA)
1433 var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
1435 /* can't use this in ste_mode, because hbb is +1 off */
1436 var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
1437 var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
1439 /* Lower margin includes vsync */
1440 var->upper_margin = hw->vdb / 2 ; /* round down to full lines */
1441 var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
1442 var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
1443 if (var->vmode & FB_VMODE_INTERLACED) {
1444 var->upper_margin *= 2;
1445 var->lower_margin *= 2;
1446 var->vsync_len *= 2;
1448 else if (var->vmode & FB_VMODE_DOUBLE) {
1449 var->upper_margin = (var->upper_margin + 1) / 2;
1450 var->lower_margin = (var->lower_margin + 1) / 2;
1451 var->vsync_len = (var->vsync_len + 1) / 2;
1454 var->pixclock *= plen;
1455 var->left_margin /= plen;
1456 var->right_margin /= plen;
1457 var->hsync_len /= plen;
1459 var->right_margin -= var->hsync_len;
1460 var->lower_margin -= var->vsync_len;
1463 var->yoffset=(par->screen_base - screen_base)/linelen;
1466 var->nonstd=0; /* what is this for? */
1472 static int f_change_mode = 0;
1473 static struct falcon_hw f_new_mode;
1474 static int f_pan_display = 0;
1476 static void falcon_get_par( struct atafb_par *par )
1479 struct falcon_hw *hw = &par->hw.falcon;
1481 hw->line_width = shifter_f030.scn_width;
1482 hw->line_offset = shifter_f030.off_next;
1483 hw->st_shift = videl.st_shift & 0x300;
1484 hw->f_shift = videl.f_shift;
1485 hw->vid_control = videl.control;
1486 hw->vid_mode = videl.mode;
1487 hw->sync = shifter.syncmode & 0x1;
1488 hw->xoffset = videl.xoffset & 0xf;
1489 hw->hht = videl.hht;
1490 hw->hbb = videl.hbb;
1491 hw->hbe = videl.hbe;
1492 hw->hdb = videl.hdb;
1493 hw->hde = videl.hde;
1494 hw->hss = videl.hss;
1495 hw->vft = videl.vft;
1496 hw->vbb = videl.vbb;
1497 hw->vbe = videl.vbe;
1498 hw->vdb = videl.vdb;
1499 hw->vde = videl.vde;
1500 hw->vss = videl.vss;
1502 addr = (shifter.bas_hi & 0xff) << 16 |
1503 (shifter.bas_md & 0xff) << 8 |
1504 (shifter.bas_lo & 0xff);
1505 par->screen_base = phys_to_virt(addr);
1507 /* derived parameters */
1508 hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
1509 hw->mono = (hw->f_shift & 0x400) ||
1510 ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
1513 static void falcon_set_par( struct atafb_par *par )
1517 /* only set screen_base if really necessary */
1518 if (current_par.screen_base != par->screen_base)
1519 fbhw->set_screen_base(par->screen_base);
1521 /* Don't touch any other registers if we keep the default resolution */
1525 /* Tell vbl-handler to change video mode.
1526 * We change modes only on next VBL, to avoid desynchronisation
1527 * (a shift to the right and wrap around by a random number of pixels
1528 * in all monochrome modes).
1529 * This seems to work on my Falcon.
1531 f_new_mode = par->hw.falcon;
1536 static void falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
1538 struct falcon_hw *hw = &f_new_mode;
1540 if (f_change_mode) {
1543 if (hw->sync & 0x1) {
1544 /* Enable external pixelclock. This code only for ScreenWonder */
1545 *(volatile unsigned short*)0xffff9202 = 0xffbf;
1548 /* Turn off external clocks. Read sets all output bits to 1. */
1549 *(volatile unsigned short*)0xffff9202;
1551 shifter.syncmode = hw->sync;
1553 videl.hht = hw->hht;
1554 videl.hbb = hw->hbb;
1555 videl.hbe = hw->hbe;
1556 videl.hdb = hw->hdb;
1557 videl.hde = hw->hde;
1558 videl.hss = hw->hss;
1559 videl.vft = hw->vft;
1560 videl.vbb = hw->vbb;
1561 videl.vbe = hw->vbe;
1562 videl.vdb = hw->vdb;
1563 videl.vde = hw->vde;
1564 videl.vss = hw->vss;
1566 videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
1568 videl.st_shift = hw->st_shift; /* write enables STE palette */
1572 * set st_shift 0, so we can tell the screen-depth if f_shift==0.
1573 * Writing 0 to f_shift enables 4 plane Falcon mode but
1574 * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
1575 * with Falcon palette.
1578 /* now back to Falcon palette mode */
1579 videl.f_shift = hw->f_shift;
1581 /* writing to st_shift changed scn_width and vid_mode */
1582 videl.xoffset = hw->xoffset;
1583 shifter_f030.scn_width = hw->line_width;
1584 shifter_f030.off_next = hw->line_offset;
1585 videl.control = hw->vid_control;
1586 videl.mode = hw->vid_mode;
1588 if (f_pan_display) {
1590 videl.xoffset = current_par.hw.falcon.xoffset;
1591 shifter_f030.off_next = current_par.hw.falcon.line_offset;
1596 static int falcon_pan_display( struct fb_var_screeninfo *var,
1597 struct atafb_par *par )
1600 int bpp = fb_display[currcon].var.bits_per_pixel;
1603 var->xoffset = up(var->xoffset, 32);
1605 par->hw.falcon.xoffset = var->xoffset & 15;
1607 par->hw.falcon.xoffset = 0;
1608 var->xoffset = up(var->xoffset, 2);
1610 par->hw.falcon.line_offset = bpp *
1611 (fb_display[currcon].var.xres_virtual - fb_display[currcon].var.xres) / 16;
1612 if (par->hw.falcon.xoffset)
1613 par->hw.falcon.line_offset -= bpp;
1614 xoffset = var->xoffset - par->hw.falcon.xoffset;
1616 par->screen_base = screen_base +
1617 (var->yoffset * fb_display[currcon].var.xres_virtual + xoffset) * bpp / 8;
1618 if (fbhw->set_screen_base)
1619 fbhw->set_screen_base (par->screen_base);
1621 return -EINVAL; /* shouldn't happen */
1627 static int falcon_getcolreg( unsigned regno, unsigned *red,
1628 unsigned *green, unsigned *blue,
1629 unsigned *transp, struct fb_info *info )
1630 { unsigned long col;
1634 /* This works in STE-mode (with 4bit/color) since f030_col-registers
1635 * hold up to 6bit/color.
1636 * Even with hicolor r/g/b=5/6/5 bit!
1638 col = f030_col[regno];
1639 *red = (col >> 16) & 0xff00;
1640 *green = (col >> 8) & 0xff00;
1641 *blue = (col << 8) & 0xff00;
1647 static int falcon_setcolreg( unsigned regno, unsigned red,
1648 unsigned green, unsigned blue,
1649 unsigned transp, struct fb_info *info )
1653 f030_col[regno] = (((red & 0xfc00) << 16) |
1654 ((green & 0xfc00) << 8) |
1655 ((blue & 0xfc00) >> 8));
1657 shifter_tt.color_reg[regno] =
1658 (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) |
1659 (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) |
1660 ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
1661 #ifdef FBCON_HAS_CFB16
1662 fbcon_cfb16_cmap[regno] = ((red & 0xf800) |
1663 ((green & 0xfc00) >> 5) |
1664 ((blue & 0xf800) >> 11));
1671 static int falcon_blank( int blank_mode )
1673 /* ++guenther: we can switch off graphics by changing VDB and VDE,
1674 * so VIDEL doesn't hog the bus while saving.
1675 * (this may affect usleep()).
1677 int vdb, vss, hbe, hss;
1679 if (mon_type == F_MON_SM) /* this doesn't work on SM124 */
1682 vdb = current_par.VDB;
1683 vss = current_par.VSS;
1684 hbe = current_par.HBE;
1685 hss = current_par.HSS;
1687 if (blank_mode >= 1) {
1688 /* disable graphics output (this speeds up the CPU) ... */
1689 vdb = current_par.VFT + 1;
1690 /* ... and blank all lines */
1691 hbe = current_par.HHT + 2;
1693 /* use VESA suspend modes on VGA monitors */
1694 if (mon_type == F_MON_VGA) {
1695 if (blank_mode == 2 || blank_mode == 4)
1696 vss = current_par.VFT + 1;
1697 if (blank_mode == 3 || blank_mode == 4)
1698 hss = current_par.HHT + 2;
1710 static int falcon_detect( void )
1712 struct atafb_par par;
1715 /* Determine connected monitor and set monitor parameters */
1716 fhw = *(unsigned char*)0xffff8006;
1717 mon_type = fhw >> 6 & 0x3;
1718 /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
1719 f030_bus_width = fhw << 6 & 0x80;
1722 fb_info.monspecs.vfmin = 70;
1723 fb_info.monspecs.vfmax = 72;
1724 fb_info.monspecs.hfmin = 35713;
1725 fb_info.monspecs.hfmax = 35715;
1730 fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
1731 fb_info.monspecs.vfmax = 60;
1732 fb_info.monspecs.hfmin = 15620;
1733 fb_info.monspecs.hfmax = 15755;
1736 /* initialize hsync-len */
1737 f25.hsync = h_syncs[mon_type] / f25.t;
1738 f32.hsync = h_syncs[mon_type] / f32.t;
1740 fext.hsync = h_syncs[mon_type] / fext.t;
1742 falcon_get_par(&par);
1743 falcon_encode_var(&atafb_predefined[0], &par);
1745 /* Detected mode is always the "autodetect" slot */
1749 #endif /* ATAFB_FALCON */
1751 /* ------------------- ST(E) specific functions ---------------------- */
1755 static int stste_encode_fix( struct fb_fix_screeninfo *fix,
1756 struct atafb_par *par )
1761 strcpy(fix->id,"Atari Builtin");
1762 fix->smem_start = (unsigned long)real_screen_base;
1763 fix->smem_len = screen_len;
1764 fix->type = FB_TYPE_INTERLEAVED_PLANES;
1766 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1767 mode = par->hw.st.mode & 3;
1768 if (mode == ST_HIGH) {
1769 fix->type = FB_TYPE_PACKED_PIXELS;
1771 fix->visual = FB_VISUAL_MONO10;
1773 if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
1781 fix->line_length = 0;
1782 fix->accel = FB_ACCEL_ATARIBLITT;
1787 static int stste_decode_var( struct fb_var_screeninfo *var,
1788 struct atafb_par *par )
1792 int bpp=var->bits_per_pixel;
1794 int yres_virtual = var->yres_virtual;
1797 if (bpp > 1 || xres > sttt_xres || yres > st_yres)
1799 par->hw.st.mode=ST_HIGH;
1804 if (bpp > 4 || xres > sttt_xres || yres > st_yres)
1807 if (xres > sttt_xres/2 || yres > st_yres/2)
1809 par->hw.st.mode=ST_LOW;
1815 if (xres > sttt_xres || yres > st_yres/2)
1817 par->hw.st.mode=ST_MID;
1825 if (yres_virtual <= 0)
1827 else if (yres_virtual < yres)
1828 yres_virtual = yres;
1829 if (var->sync & FB_SYNC_EXT)
1830 par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
1832 par->hw.st.sync=(par->hw.st.sync & ~1);
1834 if (yres_virtual * linelen > screen_len && screen_len)
1836 if (yres * linelen > screen_len && screen_len)
1838 if (var->yoffset + yres > yres_virtual && yres_virtual)
1840 par->yres_virtual = yres_virtual;
1841 par->screen_base=screen_base+ var->yoffset*linelen;
1845 static int stste_encode_var( struct fb_var_screeninfo *var,
1846 struct atafb_par *par )
1849 memset(var, 0, sizeof(struct fb_var_screeninfo));
1851 var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
1852 var->red.msb_right=0;
1855 var->pixclock=31041;
1856 var->left_margin=120; /* these are incorrect */
1857 var->right_margin=100;
1858 var->upper_margin=8;
1859 var->lower_margin=16;
1866 if (!(par->hw.st.sync & 1))
1869 var->sync=FB_SYNC_EXT;
1871 switch (par->hw.st.mode & 3) {
1873 var->xres=sttt_xres/2;
1874 var->yres=st_yres/2;
1875 var->bits_per_pixel=4;
1878 var->xres=sttt_xres;
1879 var->yres=st_yres/2;
1880 var->bits_per_pixel=2;
1883 var->xres=sttt_xres;
1885 var->bits_per_pixel=1;
1888 var->blue=var->green=var->red;
1889 var->transp.offset=0;
1890 var->transp.length=0;
1891 var->transp.msb_right=0;
1892 var->xres_virtual=sttt_xres_virtual;
1893 linelen=var->xres_virtual * var->bits_per_pixel / 8;
1894 ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
1897 var->yres_virtual=var->yres;
1898 else if (screen_len) {
1899 if (par->yres_virtual)
1900 var->yres_virtual = par->yres_virtual;
1902 /* yres_virtual==0 means use maximum */
1903 var->yres_virtual = screen_len / linelen;
1907 var->yres_virtual = 2 * var->yres;
1909 var->yres_virtual=var->yres+hwscroll * 16;
1913 var->yoffset=(par->screen_base - screen_base)/linelen;
1918 var->vmode=FB_VMODE_NONINTERLACED;
1923 static void stste_get_par( struct atafb_par *par )
1926 par->hw.st.mode=shifter_tt.st_shiftmode;
1927 par->hw.st.sync=shifter.syncmode;
1928 addr = ((shifter.bas_hi & 0xff) << 16) |
1929 ((shifter.bas_md & 0xff) << 8);
1930 if (ATARIHW_PRESENT(EXTD_SHIFTER))
1931 addr |= (shifter.bas_lo & 0xff);
1932 par->screen_base = phys_to_virt(addr);
1935 static void stste_set_par( struct atafb_par *par )
1937 shifter_tt.st_shiftmode=par->hw.st.mode;
1938 shifter.syncmode=par->hw.st.sync;
1939 /* only set screen_base if really necessary */
1940 if (current_par.screen_base != par->screen_base)
1941 fbhw->set_screen_base(par->screen_base);
1945 static int stste_getcolreg(unsigned regno, unsigned *red,
1946 unsigned *green, unsigned *blue,
1947 unsigned *transp, struct fb_info *info)
1953 col = shifter_tt.color_reg[regno];
1954 if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
1955 t = ((col >> 7) & 0xe) | ((col >> 11) & 1);
1957 *red = t | (t << 8);
1958 t = ((col >> 3) & 0xe) | ((col >> 7) & 1);
1960 *green = t | (t << 8);
1961 t = ((col << 1) & 0xe) | ((col >> 3) & 1);
1963 *blue = t | (t << 8);
1966 t = (col >> 7) & 0xe;
1968 *red = t | (t << 8);
1969 t = (col >> 3) & 0xe;
1971 *green = t | (t << 8);
1972 t = (col << 1) & 0xe;
1974 *blue = t | (t << 8);
1981 static int stste_setcolreg(unsigned regno, unsigned red,
1982 unsigned green, unsigned blue,
1983 unsigned transp, struct fb_info *info)
1990 if (ATARIHW_PRESENT(EXTD_SHIFTER))
1991 shifter_tt.color_reg[regno] =
1992 (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
1993 (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
1994 ((blue & 0xe) >> 1) | ((blue & 1) << 3);
1996 shifter_tt.color_reg[regno] =
1997 ((red & 0xe) << 7) |
1998 ((green & 0xe) << 3) |
1999 ((blue & 0xe) >> 1);
2004 static int stste_detect( void )
2006 { struct atafb_par par;
2008 /* Determine the connected monitor: The DMA sound must be
2009 * disabled before reading the MFP GPIP, because the Sound
2010 * Done Signal and the Monochrome Detect are XORed together!
2012 if (ATARIHW_PRESENT(PCM_8BIT)) {
2013 tt_dmasnd.ctrl = DMASND_CTRL_OFF;
2014 udelay(20); /* wait a while for things to settle down */
2016 mono_moni = (mfp.par_dt_reg & 0x80) == 0;
2018 stste_get_par(&par);
2019 stste_encode_var(&atafb_predefined[0], &par);
2021 if (!ATARIHW_PRESENT(EXTD_SHIFTER))
2026 static void stste_set_screen_base(void *s_base)
2029 addr= virt_to_phys(s_base);
2030 /* Setup Screen Memory */
2031 shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
2032 shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
2033 if (ATARIHW_PRESENT(EXTD_SHIFTER))
2034 shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
2037 #endif /* ATAFB_STE */
2039 /* Switching the screen size should be done during vsync, otherwise
2040 * the margins may get messed up. This is a well known problem of
2041 * the ST's video system.
2043 * Unfortunately there is hardly any way to find the vsync, as the
2044 * vertical blank interrupt is no longer in time on machines with
2045 * overscan type modifications.
2047 * We can, however, use Timer B to safely detect the black shoulder,
2048 * but then we've got to guess an appropriate delay to find the vsync.
2049 * This might not work on every machine.
2051 * martin_rogge @ ki.maus.de, 8th Aug 1995
2054 #define LINE_DELAY (mono_moni ? 30 : 70)
2055 #define SYNC_DELAY (mono_moni ? 1500 : 2000)
2057 /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
2058 static void st_ovsc_switch(void)
2060 unsigned long flags;
2061 register unsigned char old, new;
2063 if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
2068 mfp.tim_ct_b = 0x10;
2069 mfp.active_edge |= 8;
2071 mfp.tim_dt_b = 0xf0;
2073 while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
2080 } while (old != new);
2081 mfp.tim_ct_b = 0x10;
2084 if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
2085 acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
2086 if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
2087 acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
2088 if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
2089 sound_ym.rd_data_reg_sel = 14;
2090 sound_ym.wd_data = sound_ym.rd_data_reg_sel |
2091 ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
2092 ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
2094 restore_flags(flags);
2097 /* ------------------- External Video ---------------------- */
2101 static int ext_encode_fix( struct fb_fix_screeninfo *fix,
2102 struct atafb_par *par )
2105 strcpy(fix->id,"Unknown Extern");
2106 fix->smem_start = (unsigned long)external_addr;
2107 fix->smem_len = PAGE_ALIGN(external_len);
2108 if (external_depth == 1) {
2109 fix->type = FB_TYPE_PACKED_PIXELS;
2110 /* The letters 'n' and 'i' in the "atavideo=external:" stand
2111 * for "normal" and "inverted", rsp., in the monochrome case */
2113 (external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
2114 external_pmode == FB_TYPE_PACKED_PIXELS) ?
2119 /* Use STATIC if we don't know how to access color registers */
2120 int visual = external_vgaiobase ?
2121 FB_VISUAL_PSEUDOCOLOR :
2122 FB_VISUAL_STATIC_PSEUDOCOLOR;
2123 switch (external_pmode) {
2124 case -1: /* truecolor */
2125 fix->type=FB_TYPE_PACKED_PIXELS;
2126 fix->visual=FB_VISUAL_TRUECOLOR;
2128 case FB_TYPE_PACKED_PIXELS:
2129 fix->type=FB_TYPE_PACKED_PIXELS;
2132 case FB_TYPE_PLANES:
2133 fix->type=FB_TYPE_PLANES;
2136 case FB_TYPE_INTERLEAVED_PLANES:
2137 fix->type=FB_TYPE_INTERLEAVED_PLANES;
2146 fix->line_length = 0;
2151 static int ext_decode_var( struct fb_var_screeninfo *var,
2152 struct atafb_par *par )
2154 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
2156 if (var->bits_per_pixel > myvar->bits_per_pixel ||
2157 var->xres > myvar->xres ||
2158 var->xres_virtual > myvar->xres_virtual ||
2159 var->yres > myvar->yres ||
2167 static int ext_encode_var( struct fb_var_screeninfo *var,
2168 struct atafb_par *par )
2170 memset(var, 0, sizeof(struct fb_var_screeninfo));
2172 var->red.length=(external_pmode == -1) ? external_depth/3 :
2173 (external_vgaiobase ? external_bitspercol : 0);
2174 var->red.msb_right=0;
2177 var->pixclock=31041;
2178 var->left_margin=120; /* these are surely incorrect */
2179 var->right_margin=100;
2180 var->upper_margin=8;
2181 var->lower_margin=16;
2190 var->xres = external_xres;
2191 var->yres = external_yres;
2192 var->xres_virtual = external_xres_virtual;
2193 var->bits_per_pixel = external_depth;
2195 var->blue=var->green=var->red;
2196 var->transp.offset=0;
2197 var->transp.length=0;
2198 var->transp.msb_right=0;
2199 var->yres_virtual=var->yres;
2204 var->vmode=FB_VMODE_NONINTERLACED;
2209 static void ext_get_par( struct atafb_par *par )
2211 par->screen_base = external_addr;
2214 static void ext_set_par( struct atafb_par *par )
2218 #define OUTB(port,val) \
2219 *((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
2221 (*((unsigned volatile char *) ((port)+external_vgaiobase)))
2224 unsigned char tmp=INB(0x3da); \
2228 static int ext_getcolreg( unsigned regno, unsigned *red,
2229 unsigned *green, unsigned *blue,
2230 unsigned *transp, struct fb_info *info )
2232 if (! external_vgaiobase)
2235 *red = ext_color[regno].red;
2236 *green = ext_color[regno].green;
2237 *blue = ext_color[regno].blue;
2242 static int ext_setcolreg( unsigned regno, unsigned red,
2243 unsigned green, unsigned blue,
2244 unsigned transp, struct fb_info *info )
2246 { unsigned char colmask = (1 << external_bitspercol) - 1;
2248 if (! external_vgaiobase)
2251 ext_color[regno].red = red;
2252 ext_color[regno].green = green;
2253 ext_color[regno].blue = blue;
2255 switch (external_card_type) {
2259 OUTB(0x3c9, red & colmask);
2261 OUTB(0x3c9, green & colmask);
2263 OUTB(0x3c9, blue & colmask);
2268 OUTB((MV300_reg[regno] << 2)+1, red);
2269 OUTB((MV300_reg[regno] << 2)+1, green);
2270 OUTB((MV300_reg[regno] << 2)+1, blue);
2279 static int ext_detect( void )
2282 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
2283 struct atafb_par dummy_par;
2285 myvar->xres = external_xres;
2286 myvar->xres_virtual = external_xres_virtual;
2287 myvar->yres = external_yres;
2288 myvar->bits_per_pixel = external_depth;
2289 ext_encode_var(myvar, &dummy_par);
2293 #endif /* ATAFB_EXT */
2295 /* ------ This is the same for most hardware types -------- */
2297 static void set_screen_base(void *s_base)
2300 addr= virt_to_phys(s_base);
2301 /* Setup Screen Memory */
2302 shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
2303 shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
2304 shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
2308 static int pan_display( struct fb_var_screeninfo *var,
2309 struct atafb_par *par )
2311 if (!fbhw->set_screen_base ||
2312 (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
2314 var->xoffset = up(var->xoffset, 16);
2315 par->screen_base = screen_base +
2316 (var->yoffset * fb_display[currcon].var.xres_virtual + var->xoffset)
2317 * fb_display[currcon].var.bits_per_pixel / 8;
2318 fbhw->set_screen_base (par->screen_base);
2323 /* ------------ Interfaces to hardware functions ------------ */
2327 static struct fb_hwswitch tt_switch = {
2328 tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
2329 tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg,
2330 set_screen_base, NULL, pan_display
2335 static struct fb_hwswitch falcon_switch = {
2336 falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
2337 falcon_get_par, falcon_set_par, falcon_getcolreg,
2338 falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display
2343 static struct fb_hwswitch st_switch = {
2344 stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
2345 stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg,
2346 stste_set_screen_base, NULL, pan_display
2351 static struct fb_hwswitch ext_switch = {
2352 ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
2353 ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL
2359 static void atafb_get_par( struct atafb_par *par )
2361 if (current_par_valid) {
2369 static void atafb_set_par( struct atafb_par *par )
2373 current_par_valid=1;
2378 /* =========================================================== */
2379 /* ============== Hardware Independent Functions ============= */
2380 /* =========================================================== */
2383 /* used for hardware scrolling */
2386 fb_update_var(int con, struct fb_info *info)
2388 int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
2389 fb_display[con].var.bits_per_pixel>>3;
2391 current_par.screen_base=screen_base + off;
2393 if (fbhw->set_screen_base)
2394 fbhw->set_screen_base(current_par.screen_base);
2399 do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
2402 struct atafb_par par;
2403 if ((err=fbhw->decode_var(var, &par)))
2405 activate=var->activate;
2406 if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
2407 atafb_set_par(&par);
2408 fbhw->encode_var(var, &par);
2409 var->activate=activate;
2413 /* Functions for handling colormap */
2416 do_install_cmap(int con, struct fb_info *info)
2420 if (fb_display[con].cmap.len)
2421 fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info);
2423 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
2424 1, fbhw->setcolreg, info);
2428 atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2430 struct atafb_par par;
2432 atafb_get_par(&par);
2435 if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
2438 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2439 return fbhw->encode_fix(fix, &par);
2443 atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
2445 struct atafb_par par;
2447 atafb_get_par(&par);
2448 fbhw->encode_var(var, &par);
2451 *var=fb_display[con].var;
2456 atafb_set_disp(int con, struct fb_info *info)
2458 struct fb_fix_screeninfo fix;
2459 struct fb_var_screeninfo var;
2460 struct display *display;
2463 display = &fb_display[con];
2465 display = &disp; /* used during initialization */
2467 atafb_get_fix(&fix, con, info);
2468 atafb_get_var(&var, con, info);
2471 display->screen_base = (void *)fix.smem_start;
2472 display->visual = fix.visual;
2473 display->type = fix.type;
2474 display->type_aux = fix.type_aux;
2475 display->ypanstep = fix.ypanstep;
2476 display->ywrapstep = fix.ywrapstep;
2477 display->line_length = fix.line_length;
2478 if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
2479 fix.visual != FB_VISUAL_DIRECTCOLOR)
2480 display->can_soft_blank = 0;
2482 display->can_soft_blank = 1;
2484 (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
2486 case FB_TYPE_INTERLEAVED_PLANES:
2487 switch (var.bits_per_pixel) {
2488 #ifdef FBCON_HAS_IPLAN2P2
2490 display->dispsw = &fbcon_iplan2p2;
2493 #ifdef FBCON_HAS_IPLAN2P4
2495 display->dispsw = &fbcon_iplan2p4;
2498 #ifdef FBCON_HAS_IPLAN2P8
2500 display->dispsw = &fbcon_iplan2p8;
2505 case FB_TYPE_PACKED_PIXELS:
2506 switch (var.bits_per_pixel) {
2507 #ifdef FBCON_HAS_MFB
2509 display->dispsw = &fbcon_mfb;
2512 #ifdef FBCON_HAS_CFB8
2514 display->dispsw = &fbcon_cfb8;
2517 #ifdef FBCON_HAS_CFB16
2519 display->dispsw = &fbcon_cfb16;
2520 display->dispsw_data = fbcon_cfb16_cmap;
2529 atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
2531 int err,oldxres,oldyres,oldbpp,oldxres_virtual,
2532 oldyres_virtual,oldyoffset;
2533 if ((err=do_fb_set_var(var, con==currcon)))
2535 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
2536 oldxres=fb_display[con].var.xres;
2537 oldyres=fb_display[con].var.yres;
2538 oldxres_virtual=fb_display[con].var.xres_virtual;
2539 oldyres_virtual=fb_display[con].var.yres_virtual;
2540 oldbpp=fb_display[con].var.bits_per_pixel;
2541 oldyoffset=fb_display[con].var.yoffset;
2542 fb_display[con].var=*var;
2543 if (oldxres != var->xres || oldyres != var->yres
2544 || oldxres_virtual != var->xres_virtual
2545 || oldyres_virtual != var->yres_virtual
2546 || oldbpp != var->bits_per_pixel
2547 || oldyoffset != var->yoffset) {
2548 atafb_set_disp(con, info);
2549 (*fb_info.changevar)(con);
2550 fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
2551 do_install_cmap(con, info);
2561 atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
2563 if (con == currcon) /* current console ? */
2564 return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info);
2566 if (fb_display[con].cmap.len) /* non default colormap ? */
2567 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
2569 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
2570 cmap, kspc ? 0 : 2);
2575 atafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
2578 if (! fb_display[con].cmap.len) { /* no colormap allocated ? */
2579 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
2580 1 << fb_display[con].var.bits_per_pixel,
2584 if (con == currcon) /* current console ? */
2585 return fb_set_cmap(cmap, kspc, fbhw->setcolreg, info);
2587 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
2592 atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
2594 int xoffset = var->xoffset;
2595 int yoffset = var->yoffset;
2598 if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
2599 || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
2602 if (con == currcon) {
2603 if (fbhw->pan_display) {
2604 if ((err = fbhw->pan_display(var, ¤t_par)))
2610 fb_display[con].var.xoffset = var->xoffset;
2611 fb_display[con].var.yoffset = var->yoffset;
2616 atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
2617 unsigned long arg, int con, struct fb_info *info)
2620 #ifdef FBCMD_GET_CURRENTPAR
2621 case FBCMD_GET_CURRENTPAR:
2622 if (copy_to_user((void *)arg, (void *)¤t_par,
2623 sizeof(struct atafb_par)))
2627 #ifdef FBCMD_SET_CURRENTPAR
2628 case FBCMD_SET_CURRENTPAR:
2629 if (copy_from_user((void *)¤t_par, (void *)arg,
2630 sizeof(struct atafb_par)))
2632 atafb_set_par(¤t_par);
2639 static struct fb_ops atafb_ops = {
2641 fb_get_fix: atafb_get_fix,
2642 fb_get_var: atafb_get_var,
2643 fb_set_var: atafb_set_var,
2644 fb_get_cmap: atafb_get_cmap,
2645 fb_set_cmap: atafb_set_cmap,
2646 fb_pan_display: atafb_pan_display,
2647 fb_ioctl: atafb_ioctl,
2651 check_default_par( int detected_mode )
2653 char default_name[10];
2655 struct fb_var_screeninfo var;
2656 unsigned long min_mem;
2658 /* First try the user supplied mode */
2660 var=atafb_predefined[default_par-1];
2661 var.activate = FB_ACTIVATE_TEST;
2662 if (do_fb_set_var(&var,1))
2663 default_par=0; /* failed */
2665 /* Next is the autodetected one */
2666 if (! default_par) {
2667 var=atafb_predefined[detected_mode-1]; /* autodetect */
2668 var.activate = FB_ACTIVATE_TEST;
2669 if (!do_fb_set_var(&var,1))
2670 default_par=detected_mode;
2672 /* If that also failed, try some default modes... */
2673 if (! default_par) {
2674 /* try default1, default2... */
2675 for (i=1 ; i < 10 ; i++) {
2676 sprintf(default_name,"default%d",i);
2677 default_par=get_video_mode(default_name);
2679 panic("can't set default video mode");
2680 var=atafb_predefined[default_par-1];
2681 var.activate = FB_ACTIVATE_TEST;
2682 if (! do_fb_set_var(&var,1))
2686 min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
2687 if (default_mem_req < min_mem)
2688 default_mem_req=min_mem;
2692 atafb_switch(int con, struct fb_info *info)
2694 /* Do we have to save the colormap ? */
2695 if (fb_display[currcon].cmap.len)
2696 fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg,
2698 do_fb_set_var(&fb_display[con].var,1);
2700 /* Install new colormap */
2701 do_install_cmap(con, info);
2705 /* (un)blank/poweroff
2713 atafb_blank(int blank, struct fb_info *info)
2715 unsigned short black[16];
2716 struct fb_cmap cmap;
2717 if (fbhw->blank && !fbhw->blank(blank))
2720 memset(black, 0, 16*sizeof(unsigned short));
2727 fb_set_cmap(&cmap, 1, fbhw->setcolreg, info);
2730 do_install_cmap(currcon, info);
2733 int __init atafb_init(void)
2737 unsigned long mem_req;
2744 if (external_addr) {
2750 if (ATARIHW_PRESENT(TT_SHIFTER)) {
2756 if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
2757 fbhw = &falcon_switch;
2758 request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
2759 "framebuffer/modeswitch", falcon_vbl_switcher);
2764 if (ATARIHW_PRESENT(STND_SHIFTER) ||
2765 ATARIHW_PRESENT(EXTD_SHIFTER)) {
2770 printk("Cannot determine video hardware; defaulting to ST(e)\n");
2771 #else /* ATAFB_STE */
2772 /* no default driver included */
2773 /* Nobody will ever see this message :-) */
2774 panic("Cannot initialize video hardware");
2778 /* Multisync monitor capabilities */
2779 /* Atari-TOS defaults if no boot option present */
2780 if (fb_info.monspecs.hfmin == 0) {
2781 fb_info.monspecs.hfmin = 31000;
2782 fb_info.monspecs.hfmax = 32000;
2783 fb_info.monspecs.vfmin = 58;
2784 fb_info.monspecs.vfmax = 62;
2787 detected_mode = fbhw->detect();
2788 check_default_par(detected_mode);
2790 if (!external_addr) {
2791 #endif /* ATAFB_EXT */
2792 mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
2793 mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
2794 screen_base = atari_stram_alloc(mem_req, "atafb");
2796 panic("Cannot allocate screen memory");
2797 memset(screen_base, 0, mem_req);
2798 pad = -(unsigned long)screen_base & (PAGE_SIZE-1);
2800 real_screen_base=screen_base+ovsc_offset;
2801 screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
2803 if (CPU_IS_040_OR_060) {
2804 /* On a '040+, the cache mode of video RAM must be set to
2805 * write-through also for internal video hardware! */
2806 cache_push(virt_to_phys(screen_base), screen_len);
2807 kernel_set_cachemode(screen_base, screen_len,
2808 IOMAP_WRITETHROUGH);
2813 /* Map the video memory (physical address given) to somewhere
2814 * in the kernel address space.
2817 ioremap_writethrough((unsigned long)external_addr,
2819 if (external_vgaiobase)
2820 external_vgaiobase =
2821 (unsigned long)ioremap(external_vgaiobase, 0x10000);
2823 real_screen_base = external_addr;
2824 screen_len = external_len & PAGE_MASK;
2825 memset (screen_base, 0, external_len);
2827 #endif /* ATAFB_EXT */
2829 strcpy(fb_info.modename, "Atari Builtin ");
2830 fb_info.changevar = NULL;
2832 fb_info.fbops = &atafb_ops;
2833 fb_info.disp = &disp;
2834 fb_info.switch_con = &atafb_switch;
2835 fb_info.updatevar = &fb_update_var;
2836 fb_info.blank = &atafb_blank;
2837 fb_info.flags = FBINFO_FLAG_DEFAULT;
2838 do_fb_set_var(&atafb_predefined[default_par-1], 1);
2839 strcat(fb_info.modename, fb_var_names[default_par-1][0]);
2841 atafb_get_var(&disp.var, -1, &fb_info);
2842 atafb_set_disp(-1, &fb_info);
2843 do_install_cmap(0, &fb_info);
2845 if (register_framebuffer(&fb_info) < 0)
2848 printk("Determined %dx%d, depth %d\n",
2849 disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
2850 if ((disp.var.xres != disp.var.xres_virtual) ||
2851 (disp.var.yres != disp.var.yres_virtual))
2852 printk(" virtual %dx%d\n",
2853 disp.var.xres_virtual, disp.var.yres_virtual);
2854 printk("fb%d: %s frame buffer device, using %dK of video memory\n",
2855 GET_FB_IDX(fb_info.node), fb_info.modename, screen_len>>10);
2857 /* TODO: This driver cannot be unloaded yet */
2863 /* a strtok which returns empty strings, too */
2865 static char * strtoke(char * s,const char * ct)
2867 char *sbegin, *send;
2868 static char *ssave = NULL;
2870 sbegin = s ? s : ssave;
2874 if (*sbegin == '\0') {
2878 send = strpbrk(sbegin, ct);
2879 if (send && *send != '\0')
2885 int __init atafb_setup( char *options )
2889 char ext_str[80], int_str[100];
2897 fb_info.fontname[0] = '\0';
2899 if (!options || !*options)
2902 for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
2903 if (!*this_opt) continue;
2904 if ((temp=get_video_mode(this_opt)))
2906 else if (! strcmp(this_opt, "inverse"))
2908 else if (!strncmp(this_opt, "font:", 5))
2909 strcpy(fb_info.fontname, this_opt+5);
2910 else if (! strncmp(this_opt, "hwscroll_",9)) {
2911 hwscroll=simple_strtoul(this_opt+9, NULL, 10);
2918 else if (!strcmp(this_opt,"mv300")) {
2919 external_bitspercol = 8;
2920 external_card_type = IS_MV300;
2922 else if (!strncmp(this_opt,"external:",9))
2923 strcpy(ext_str, this_opt+9);
2925 else if (!strncmp(this_opt,"internal:",9))
2926 strcpy(int_str, this_opt+9);
2928 else if (!strncmp(this_opt, "eclock:", 7)) {
2929 fext.f = simple_strtoul(this_opt+7, NULL, 10);
2930 /* external pixelclock in kHz --> ps */
2931 fext.t = 1000000000/fext.f;
2934 else if (!strncmp(this_opt, "monitorcap:", 11))
2935 strcpy(mcap_spec, this_opt+11);
2937 else if (!strcmp(this_opt, "keep"))
2939 else if (!strncmp(this_opt, "R", 1))
2940 strcpy(user_mode, this_opt+1);
2944 /* Format to config extended internal video hardware like OverScan:
2945 "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
2947 <xres>: x-resolution
2948 <yres>: y-resolution
2949 The following are only needed if you have an overscan which
2950 needs a black border:
2951 <xres_max>: max. length of a line in pixels your OverScan hardware would allow
2952 <yres_max>: max. number of lines your OverScan hardware would allow
2953 <offset>: Offset from physical beginning to visible beginning
2959 if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid;
2960 xres = simple_strtoul(p, NULL, 10);
2961 if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
2963 tt_yres=st_yres=simple_strtoul(p, NULL, 10);
2964 if ((p=strtoke(NULL, ";")) && *p) {
2965 sttt_xres_virtual=simple_strtoul(p, NULL, 10);
2967 if ((p=strtoke(NULL, ";")) && *p) {
2968 sttt_yres_virtual=simple_strtoul(p, NULL, 0);
2970 if ((p=strtoke(NULL, ";")) && *p) {
2971 ovsc_offset=simple_strtoul(p, NULL, 0);
2974 if (ovsc_offset || (sttt_yres_virtual != st_yres))
2982 int xres, xres_virtual, yres, depth, planes;
2983 unsigned long addr, len;
2986 /* Format is: <xres>;<yres>;<depth>;<plane organ.>;
2988 * [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type>
2989 * [;<xres-virtual>]]]]]
2992 * <xres_virtual>: hardware's x-resolution (f.e. ProMST)
2994 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
2996 if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid;
2997 xres_virtual = xres = simple_strtoul(p, NULL, 10);
2998 if (xres <= 0) goto ext_invalid;
3000 if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
3001 yres = simple_strtoul(p, NULL, 10);
3002 if (yres <= 0) goto ext_invalid;
3004 if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
3005 depth = simple_strtoul(p, NULL, 10);
3006 if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
3007 depth != 16 && depth != 24) goto ext_invalid;
3009 if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
3011 planes = FB_TYPE_INTERLEAVED_PLANES;
3013 planes = FB_TYPE_PACKED_PIXELS;
3015 planes = FB_TYPE_PLANES;
3017 planes = -1; /* true color */
3022 if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
3023 addr = simple_strtoul(p, NULL, 0);
3025 if (!(p = strtoke(NULL, ";")) ||!*p)
3026 len = xres*yres*depth/8;
3028 len = simple_strtoul(p, NULL, 0);
3030 if ((p = strtoke(NULL, ";")) && *p) {
3031 external_vgaiobase=simple_strtoul(p, NULL, 0);
3034 if ((p = strtoke(NULL, ";")) && *p) {
3035 external_bitspercol = simple_strtoul(p, NULL, 0);
3036 if (external_bitspercol > 8)
3037 external_bitspercol = 8;
3038 else if (external_bitspercol < 1)
3039 external_bitspercol = 1;
3042 if ((p = strtoke(NULL, ";")) && *p) {
3043 if (!strcmp(p, "vga"))
3044 external_card_type = IS_VGA;
3045 if (!strcmp(p, "mv300"))
3046 external_card_type = IS_MV300;
3049 if ((p = strtoke(NULL, ";")) && *p) {
3050 xres_virtual = simple_strtoul(p, NULL, 10);
3051 if (xres_virtual < xres)
3052 xres_virtual = xres;
3053 if (xres_virtual*yres*depth/8 > len)
3054 len=xres_virtual*yres*depth/8;
3057 external_xres = xres;
3058 external_xres_virtual = xres_virtual;
3059 external_yres = yres;
3060 external_depth = depth;
3061 external_pmode = planes;
3062 external_addr = (void *)addr;
3065 if (external_card_type == IS_MV300)
3066 switch (external_depth) {
3068 MV300_reg = MV300_reg_1bit;
3071 MV300_reg = MV300_reg_4bit;
3074 MV300_reg = MV300_reg_8bit;
3081 #endif /* ATAFB_EXT */
3086 int vmin, vmax, hmin, hmax;
3088 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
3089 * <V*> vertical freq. in Hz
3090 * <H*> horizontal freq. in kHz
3092 if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
3093 vmin = simple_strtoul(p, NULL, 10);
3094 if (vmin <= 0) goto cap_invalid;
3095 if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
3096 vmax = simple_strtoul(p, NULL, 10);
3097 if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
3098 if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
3099 hmin = 1000 * simple_strtoul(p, NULL, 10);
3100 if (hmin <= 0) goto cap_invalid;
3101 if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
3102 hmax = 1000 * simple_strtoul(p, NULL, 10);
3103 if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
3105 fb_info.monspecs.vfmin = vmin;
3106 fb_info.monspecs.vfmax = vmax;
3107 fb_info.monspecs.hfmin = hmin;
3108 fb_info.monspecs.hfmax = hmax;
3115 /* Format of user defined video mode is: <xres>;<yres>;<depth>
3118 int xres, yres, depth, temp;
3120 if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid;
3121 xres = simple_strtoul(p, NULL, 10);
3122 if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid;
3123 yres = simple_strtoul(p, NULL, 10);
3124 if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid;
3125 depth = simple_strtoul(p, NULL, 10);
3126 if ((temp=get_video_mode("user0"))) {
3128 atafb_predefined[default_par-1].xres = xres;
3129 atafb_predefined[default_par-1].yres = yres;
3130 atafb_predefined[default_par-1].bits_per_pixel = depth;
3140 MODULE_LICENSE("GPL");
3142 int init_module(void)
3144 return atafb_init();
3147 void cleanup_module(void)
3149 /* Not reached because the usecount will never
3150 be decremented to zero */
3151 unregister_framebuffer(&fb_info);
3152 /* atari_stram_free( screen_base ); */
3153 /* TODO: further clean up ... */