Merge tag 'trace-v5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux/fpc-iii.git] / drivers / video / fbdev / atafb.c
blobe3812a8ff55a4fb8546a1683888aa7def9e51b63
1 /*
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
8 * for more details.
10 * History:
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
31 * supported.
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
39 * To do:
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.
45 #define ATAFB_TT
46 #define ATAFB_STE
47 #define ATAFB_EXT
48 #define ATAFB_FALCON
50 #include <linux/kernel.h>
51 #include <linux/errno.h>
52 #include <linux/string.h>
53 #include <linux/mm.h>
54 #include <linux/delay.h>
55 #include <linux/init.h>
56 #include <linux/interrupt.h>
57 #include <linux/platform_device.h>
59 #include <asm/setup.h>
60 #include <linux/uaccess.h>
61 #include <asm/irq.h>
62 #include <asm/io.h>
64 #include <asm/atarihw.h>
65 #include <asm/atariints.h>
66 #include <asm/atari_stram.h>
68 #include <linux/fb.h>
69 #include <asm/atarikb.h>
71 #include "c2p.h"
72 #include "atafb.h"
74 #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
75 #define SWITCH_SND6 0x40
76 #define SWITCH_SND7 0x80
77 #define SWITCH_NONE 0x00
79 #define up(x, r) (((x) + (r) - 1) & ~((r)-1))
82 static int default_par; /* default resolution (0=none) */
84 static unsigned long default_mem_req;
86 static int hwscroll = -1;
88 static int use_hwscroll = 1;
90 static int sttt_xres = 640, st_yres = 400, tt_yres = 480;
91 static int sttt_xres_virtual = 640, sttt_yres_virtual = 400;
92 static int ovsc_offset, ovsc_addlen;
95 * Hardware parameters for current mode
98 static struct atafb_par {
99 void *screen_base;
100 int yres_virtual;
101 u_long next_line;
102 #if defined ATAFB_TT || defined ATAFB_STE
103 union {
104 struct {
105 int mode;
106 int sync;
107 } tt, st;
108 #endif
109 #ifdef ATAFB_FALCON
110 struct falcon_hw {
111 /* Here are fields for storing a video mode, as direct
112 * parameters for the hardware.
114 short sync;
115 short line_width;
116 short line_offset;
117 short st_shift;
118 short f_shift;
119 short vid_control;
120 short vid_mode;
121 short xoffset;
122 short hht, hbb, hbe, hdb, hde, hss;
123 short vft, vbb, vbe, vdb, vde, vss;
124 /* auxiliary information */
125 short mono;
126 short ste_mode;
127 short bpp;
128 u32 pseudo_palette[16];
129 } falcon;
130 #endif
131 /* Nothing needed for external mode */
132 } hw;
133 } current_par;
135 /* Don't calculate an own resolution, and thus don't change the one found when
136 * booting (currently used for the Falcon to keep settings for internal video
137 * hardware extensions (e.g. ScreenBlaster) */
138 static int DontCalcRes = 0;
140 #ifdef ATAFB_FALCON
141 #define HHT hw.falcon.hht
142 #define HBB hw.falcon.hbb
143 #define HBE hw.falcon.hbe
144 #define HDB hw.falcon.hdb
145 #define HDE hw.falcon.hde
146 #define HSS hw.falcon.hss
147 #define VFT hw.falcon.vft
148 #define VBB hw.falcon.vbb
149 #define VBE hw.falcon.vbe
150 #define VDB hw.falcon.vdb
151 #define VDE hw.falcon.vde
152 #define VSS hw.falcon.vss
153 #define VCO_CLOCK25 0x04
154 #define VCO_CSYPOS 0x10
155 #define VCO_VSYPOS 0x20
156 #define VCO_HSYPOS 0x40
157 #define VCO_SHORTOFFS 0x100
158 #define VMO_DOUBLE 0x01
159 #define VMO_INTER 0x02
160 #define VMO_PREMASK 0x0c
161 #endif
163 static struct fb_info fb_info = {
164 .fix = {
165 .id = "Atari ",
166 .visual = FB_VISUAL_PSEUDOCOLOR,
167 .accel = FB_ACCEL_NONE,
171 static void *screen_base; /* base address of screen */
172 static unsigned long phys_screen_base; /* (only for Overscan) */
174 static int screen_len;
176 static int current_par_valid;
178 static int mono_moni;
181 #ifdef ATAFB_EXT
183 /* external video handling */
184 static unsigned int external_xres;
185 static unsigned int external_xres_virtual;
186 static unsigned int external_yres;
189 * not needed - atafb will never support panning/hardwarescroll with external
190 * static unsigned int external_yres_virtual;
192 static unsigned int external_depth;
193 static int external_pmode;
194 static void *external_screen_base;
195 static unsigned long external_addr;
196 static unsigned long external_len;
197 static unsigned long external_vgaiobase;
198 static unsigned int external_bitspercol = 6;
201 * JOE <joe@amber.dinoco.de>:
202 * added card type for external driver, is only needed for
203 * colormap handling.
205 enum cardtype { IS_VGA, IS_MV300 };
206 static enum cardtype external_card_type = IS_VGA;
209 * The MV300 mixes the color registers. So we need an array of munged
210 * indices in order to access the correct reg.
212 static int MV300_reg_1bit[2] = {
213 0, 1
215 static int MV300_reg_4bit[16] = {
216 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
218 static int MV300_reg_8bit[256] = {
219 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
220 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
221 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
222 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
223 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
224 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
225 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
226 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
227 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
228 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
229 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
230 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
231 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
232 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
233 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
234 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
237 static int *MV300_reg = MV300_reg_8bit;
238 #endif /* ATAFB_EXT */
241 static int inverse;
244 * struct fb_ops {
245 * * open/release and usage marking
246 * struct module *owner;
247 * int (*fb_open)(struct fb_info *info, int user);
248 * int (*fb_release)(struct fb_info *info, int user);
250 * * For framebuffers with strange non linear layouts or that do not
251 * * work with normal memory mapped access
252 * ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
253 * ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
255 * * checks var and eventually tweaks it to something supported,
256 * * DOES NOT MODIFY PAR *
257 * int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
259 * * set the video mode according to info->var *
260 * int (*fb_set_par)(struct fb_info *info);
262 * * set color register *
263 * int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green,
264 * unsigned int blue, unsigned int transp, struct fb_info *info);
266 * * set color registers in batch *
267 * int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
269 * * blank display *
270 * int (*fb_blank)(int blank, struct fb_info *info);
272 * * pan display *
273 * int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
275 * *** The meat of the drawing engine ***
276 * * Draws a rectangle *
277 * void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
278 * * Copy data from area to another *
279 * void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
280 * * Draws a image to the display *
281 * void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
283 * * Draws cursor *
284 * int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
286 * * wait for blit idle, optional *
287 * int (*fb_sync)(struct fb_info *info);
289 * * perform fb specific ioctl (optional) *
290 * int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
291 * unsigned long arg);
293 * * Handle 32bit compat ioctl (optional) *
294 * int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
295 * unsigned long arg);
297 * * perform fb specific mmap *
298 * int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
299 * } ;
303 /* ++roman: This structure abstracts from the underlying hardware (ST(e),
304 * TT, or Falcon.
306 * int (*detect)(void)
307 * This function should detect the current video mode settings and
308 * store them in atafb_predefined[0] for later reference by the
309 * user. Return the index+1 of an equivalent predefined mode or 0
310 * if there is no such.
312 * int (*encode_fix)(struct fb_fix_screeninfo *fix,
313 * struct atafb_par *par)
314 * This function should fill in the 'fix' structure based on the
315 * values in the 'par' structure.
316 * !!! Obsolete, perhaps !!!
318 * int (*decode_var)(struct fb_var_screeninfo *var,
319 * struct atafb_par *par)
320 * Get the video params out of 'var'. If a value doesn't fit, round
321 * it up, if it's too big, return EINVAL.
322 * Round up in the following order: bits_per_pixel, xres, yres,
323 * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
324 * horizontal timing, vertical timing.
326 * int (*encode_var)(struct fb_var_screeninfo *var,
327 * struct atafb_par *par);
328 * Fill the 'var' structure based on the values in 'par' and maybe
329 * other values read out of the hardware.
331 * void (*get_par)(struct atafb_par *par)
332 * Fill the hardware's 'par' structure.
333 * !!! Used only by detect() !!!
335 * void (*set_par)(struct atafb_par *par)
336 * Set the hardware according to 'par'.
338 * void (*set_screen_base)(void *s_base)
339 * Set the base address of the displayed frame buffer. Only called
340 * if yres_virtual > yres or xres_virtual > xres.
342 * int (*blank)(int blank_mode)
343 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL then
344 * the caller blanks by setting the CLUT to all black. Return 0 if blanking
345 * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
346 * doesn't support it. Implements VESA suspend and powerdown modes on
347 * hardware that supports disabling hsync/vsync:
348 * blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown.
351 static struct fb_hwswitch {
352 int (*detect)(void);
353 int (*encode_fix)(struct fb_fix_screeninfo *fix,
354 struct atafb_par *par);
355 int (*decode_var)(struct fb_var_screeninfo *var,
356 struct atafb_par *par);
357 int (*encode_var)(struct fb_var_screeninfo *var,
358 struct atafb_par *par);
359 void (*get_par)(struct atafb_par *par);
360 void (*set_par)(struct atafb_par *par);
361 void (*set_screen_base)(void *s_base);
362 int (*blank)(int blank_mode);
363 int (*pan_display)(struct fb_var_screeninfo *var,
364 struct fb_info *info);
365 } *fbhw;
367 static char *autodetect_names[] = { "autodetect", NULL };
368 static char *stlow_names[] = { "stlow", NULL };
369 static char *stmid_names[] = { "stmid", "default5", NULL };
370 static char *sthigh_names[] = { "sthigh", "default4", NULL };
371 static char *ttlow_names[] = { "ttlow", NULL };
372 static char *ttmid_names[] = { "ttmid", "default1", NULL };
373 static char *tthigh_names[] = { "tthigh", "default2", NULL };
374 static char *vga2_names[] = { "vga2", NULL };
375 static char *vga4_names[] = { "vga4", NULL };
376 static char *vga16_names[] = { "vga16", "default3", NULL };
377 static char *vga256_names[] = { "vga256", NULL };
378 static char *falh2_names[] = { "falh2", NULL };
379 static char *falh16_names[] = { "falh16", NULL };
381 static char **fb_var_names[] = {
382 autodetect_names,
383 stlow_names,
384 stmid_names,
385 sthigh_names,
386 ttlow_names,
387 ttmid_names,
388 tthigh_names,
389 vga2_names,
390 vga4_names,
391 vga16_names,
392 vga256_names,
393 falh2_names,
394 falh16_names,
395 NULL
398 static struct fb_var_screeninfo atafb_predefined[] = {
400 * yres_virtual == 0 means use hw-scrolling if possible, else yres
402 { /* autodetect */
403 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
404 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
405 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
406 { /* st low */
407 320, 200, 320, 0, 0, 0, 4, 0,
408 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
409 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
410 { /* st mid */
411 640, 200, 640, 0, 0, 0, 2, 0,
412 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
413 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
414 { /* st high */
415 640, 400, 640, 0, 0, 0, 1, 0,
416 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
417 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
418 { /* tt low */
419 320, 480, 320, 0, 0, 0, 8, 0,
420 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
421 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
422 { /* tt mid */
423 640, 480, 640, 0, 0, 0, 4, 0,
424 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
425 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
426 { /* tt high */
427 1280, 960, 1280, 0, 0, 0, 1, 0,
428 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
429 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
430 { /* vga2 */
431 640, 480, 640, 0, 0, 0, 1, 0,
432 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
433 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
434 { /* vga4 */
435 640, 480, 640, 0, 0, 0, 2, 0,
436 {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
437 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
438 { /* vga16 */
439 640, 480, 640, 0, 0, 0, 4, 0,
440 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
441 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
442 { /* vga256 */
443 640, 480, 640, 0, 0, 0, 8, 0,
444 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
445 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
446 { /* falh2 */
447 896, 608, 896, 0, 0, 0, 1, 0,
448 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
449 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
450 { /* falh16 */
451 896, 608, 896, 0, 0, 0, 4, 0,
452 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
453 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
456 static int num_atafb_predefined = ARRAY_SIZE(atafb_predefined);
458 static struct fb_videomode atafb_modedb[] __initdata = {
460 * Atari Video Modes
462 * If you change these, make sure to update DEFMODE_* as well!
466 * ST/TT Video Modes
470 /* 320x200, 15 kHz, 60 Hz (ST low) */
471 "st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4,
472 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
473 }, {
474 /* 640x200, 15 kHz, 60 Hz (ST medium) */
475 "st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4,
476 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
477 }, {
478 /* 640x400, 30.25 kHz, 63.5 Hz (ST high) */
479 "st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4,
480 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
481 }, {
482 /* 320x480, 15 kHz, 60 Hz (TT low) */
483 "tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30,
484 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
485 }, {
486 /* 640x480, 29 kHz, 57 Hz (TT medium) */
487 "tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30,
488 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
489 }, {
490 /* 1280x960, 29 kHz, 60 Hz (TT high) */
491 "tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30,
492 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
496 * VGA Video Modes
500 /* 640x480, 31 kHz, 60 Hz (VGA) */
501 "vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3,
502 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
503 }, {
504 /* 640x400, 31 kHz, 70 Hz (VGA) */
505 "vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3,
506 FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
510 * Falcon HiRes Video Modes
514 /* 896x608, 31 kHz, 60 Hz (Falcon High) */
515 "falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3,
516 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
520 #define NUM_TOTAL_MODES ARRAY_SIZE(atafb_modedb)
522 static char *mode_option __initdata = NULL;
524 /* default modes */
526 #define DEFMODE_TT 5 /* "tt-high" for TT */
527 #define DEFMODE_F30 7 /* "vga70" for Falcon */
528 #define DEFMODE_STE 2 /* "st-high" for ST/E */
529 #define DEFMODE_EXT 6 /* "vga" for external */
532 static int get_video_mode(char *vname)
534 char ***name_list;
535 char **name;
536 int i;
538 name_list = fb_var_names;
539 for (i = 0; i < num_atafb_predefined; i++) {
540 name = *name_list++;
541 if (!name || !*name)
542 break;
543 while (*name) {
544 if (!strcmp(vname, *name))
545 return i + 1;
546 name++;
549 return 0;
554 /* ------------------- TT specific functions ---------------------- */
556 #ifdef ATAFB_TT
558 static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
560 int mode;
562 strcpy(fix->id, "Atari Builtin");
563 fix->smem_start = phys_screen_base;
564 fix->smem_len = screen_len;
565 fix->type = FB_TYPE_INTERLEAVED_PLANES;
566 fix->type_aux = 2;
567 fix->visual = FB_VISUAL_PSEUDOCOLOR;
568 mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
569 if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
570 fix->type = FB_TYPE_PACKED_PIXELS;
571 fix->type_aux = 0;
572 if (mode == TT_SHIFTER_TTHIGH)
573 fix->visual = FB_VISUAL_MONO01;
575 fix->xpanstep = 0;
576 fix->ypanstep = 1;
577 fix->ywrapstep = 0;
578 fix->line_length = par->next_line;
579 fix->accel = FB_ACCEL_ATARIBLITT;
580 return 0;
583 static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
585 int xres = var->xres;
586 int yres = var->yres;
587 int bpp = var->bits_per_pixel;
588 int linelen;
589 int yres_virtual = var->yres_virtual;
591 if (mono_moni) {
592 if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2)
593 return -EINVAL;
594 par->hw.tt.mode = TT_SHIFTER_TTHIGH;
595 xres = sttt_xres * 2;
596 yres = tt_yres * 2;
597 bpp = 1;
598 } else {
599 if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
600 return -EINVAL;
601 if (bpp > 4) {
602 if (xres > sttt_xres / 2 || yres > tt_yres)
603 return -EINVAL;
604 par->hw.tt.mode = TT_SHIFTER_TTLOW;
605 xres = sttt_xres / 2;
606 yres = tt_yres;
607 bpp = 8;
608 } else if (bpp > 2) {
609 if (xres > sttt_xres || yres > tt_yres)
610 return -EINVAL;
611 if (xres > sttt_xres / 2 || yres > st_yres / 2) {
612 par->hw.tt.mode = TT_SHIFTER_TTMID;
613 xres = sttt_xres;
614 yres = tt_yres;
615 bpp = 4;
616 } else {
617 par->hw.tt.mode = TT_SHIFTER_STLOW;
618 xres = sttt_xres / 2;
619 yres = st_yres / 2;
620 bpp = 4;
622 } else if (bpp > 1) {
623 if (xres > sttt_xres || yres > st_yres / 2)
624 return -EINVAL;
625 par->hw.tt.mode = TT_SHIFTER_STMID;
626 xres = sttt_xres;
627 yres = st_yres / 2;
628 bpp = 2;
629 } else if (var->xres > sttt_xres || var->yres > st_yres) {
630 return -EINVAL;
631 } else {
632 par->hw.tt.mode = TT_SHIFTER_STHIGH;
633 xres = sttt_xres;
634 yres = st_yres;
635 bpp = 1;
638 if (yres_virtual <= 0)
639 yres_virtual = 0;
640 else if (yres_virtual < yres)
641 yres_virtual = yres;
642 if (var->sync & FB_SYNC_EXT)
643 par->hw.tt.sync = 0;
644 else
645 par->hw.tt.sync = 1;
646 linelen = xres * bpp / 8;
647 if (yres_virtual * linelen > screen_len && screen_len)
648 return -EINVAL;
649 if (yres * linelen > screen_len && screen_len)
650 return -EINVAL;
651 if (var->yoffset + yres > yres_virtual && yres_virtual)
652 return -EINVAL;
653 par->yres_virtual = yres_virtual;
654 par->screen_base = screen_base + var->yoffset * linelen;
655 par->next_line = linelen;
656 return 0;
659 static int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
661 int linelen;
662 memset(var, 0, sizeof(struct fb_var_screeninfo));
663 var->red.offset = 0;
664 var->red.length = 4;
665 var->red.msb_right = 0;
666 var->grayscale = 0;
668 var->pixclock = 31041;
669 var->left_margin = 120; /* these may be incorrect */
670 var->right_margin = 100;
671 var->upper_margin = 8;
672 var->lower_margin = 16;
673 var->hsync_len = 140;
674 var->vsync_len = 30;
676 var->height = -1;
677 var->width = -1;
679 if (par->hw.tt.sync & 1)
680 var->sync = 0;
681 else
682 var->sync = FB_SYNC_EXT;
684 switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
685 case TT_SHIFTER_STLOW:
686 var->xres = sttt_xres / 2;
687 var->xres_virtual = sttt_xres_virtual / 2;
688 var->yres = st_yres / 2;
689 var->bits_per_pixel = 4;
690 break;
691 case TT_SHIFTER_STMID:
692 var->xres = sttt_xres;
693 var->xres_virtual = sttt_xres_virtual;
694 var->yres = st_yres / 2;
695 var->bits_per_pixel = 2;
696 break;
697 case TT_SHIFTER_STHIGH:
698 var->xres = sttt_xres;
699 var->xres_virtual = sttt_xres_virtual;
700 var->yres = st_yres;
701 var->bits_per_pixel = 1;
702 break;
703 case TT_SHIFTER_TTLOW:
704 var->xres = sttt_xres / 2;
705 var->xres_virtual = sttt_xres_virtual / 2;
706 var->yres = tt_yres;
707 var->bits_per_pixel = 8;
708 break;
709 case TT_SHIFTER_TTMID:
710 var->xres = sttt_xres;
711 var->xres_virtual = sttt_xres_virtual;
712 var->yres = tt_yres;
713 var->bits_per_pixel = 4;
714 break;
715 case TT_SHIFTER_TTHIGH:
716 var->red.length = 0;
717 var->xres = sttt_xres * 2;
718 var->xres_virtual = sttt_xres_virtual * 2;
719 var->yres = tt_yres * 2;
720 var->bits_per_pixel = 1;
721 break;
723 var->blue = var->green = var->red;
724 var->transp.offset = 0;
725 var->transp.length = 0;
726 var->transp.msb_right = 0;
727 linelen = var->xres_virtual * var->bits_per_pixel / 8;
728 if (!use_hwscroll)
729 var->yres_virtual = var->yres;
730 else if (screen_len) {
731 if (par->yres_virtual)
732 var->yres_virtual = par->yres_virtual;
733 else
734 /* yres_virtual == 0 means use maximum */
735 var->yres_virtual = screen_len / linelen;
736 } else {
737 if (hwscroll < 0)
738 var->yres_virtual = 2 * var->yres;
739 else
740 var->yres_virtual = var->yres + hwscroll * 16;
742 var->xoffset = 0;
743 if (screen_base)
744 var->yoffset = (par->screen_base - screen_base) / linelen;
745 else
746 var->yoffset = 0;
747 var->nonstd = 0;
748 var->activate = 0;
749 var->vmode = FB_VMODE_NONINTERLACED;
750 return 0;
753 static void tt_get_par(struct atafb_par *par)
755 unsigned long addr;
756 par->hw.tt.mode = shifter_tt.tt_shiftmode;
757 par->hw.tt.sync = shifter_st.syncmode;
758 addr = ((shifter_st.bas_hi & 0xff) << 16) |
759 ((shifter_st.bas_md & 0xff) << 8) |
760 ((shifter_st.bas_lo & 0xff));
761 par->screen_base = atari_stram_to_virt(addr);
764 static void tt_set_par(struct atafb_par *par)
766 shifter_tt.tt_shiftmode = par->hw.tt.mode;
767 shifter_st.syncmode = par->hw.tt.sync;
768 /* only set screen_base if really necessary */
769 if (current_par.screen_base != par->screen_base)
770 fbhw->set_screen_base(par->screen_base);
773 static int tt_setcolreg(unsigned int regno, unsigned int red,
774 unsigned int green, unsigned int blue,
775 unsigned int transp, struct fb_info *info)
777 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
778 regno += 254;
779 if (regno > 255)
780 return 1;
781 tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
782 (blue >> 12));
783 if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
784 TT_SHIFTER_STHIGH && regno == 254)
785 tt_palette[0] = 0;
786 return 0;
789 static int tt_detect(void)
791 struct atafb_par par;
793 /* Determine the connected monitor: The DMA sound must be
794 * disabled before reading the MFP GPIP, because the Sound
795 * Done Signal and the Monochrome Detect are XORed together!
797 * Even on a TT, we should look if there is a DMA sound. It was
798 * announced that the Eagle is TT compatible, but only the PCM is
799 * missing...
801 if (ATARIHW_PRESENT(PCM_8BIT)) {
802 tt_dmasnd.ctrl = DMASND_CTRL_OFF;
803 udelay(20); /* wait a while for things to settle down */
805 mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
807 tt_get_par(&par);
808 tt_encode_var(&atafb_predefined[0], &par);
810 return 1;
813 #endif /* ATAFB_TT */
815 /* ------------------- Falcon specific functions ---------------------- */
817 #ifdef ATAFB_FALCON
819 static int mon_type; /* Falcon connected monitor */
820 static int f030_bus_width; /* Falcon ram bus width (for vid_control) */
821 #define F_MON_SM 0
822 #define F_MON_SC 1
823 #define F_MON_VGA 2
824 #define F_MON_TV 3
826 static struct pixel_clock {
827 unsigned long f; /* f/[Hz] */
828 unsigned long t; /* t/[ps] (=1/f) */
829 int right, hsync, left; /* standard timing in clock cycles, not pixel */
830 /* hsync initialized in falcon_detect() */
831 int sync_mask; /* or-mask for hw.falcon.sync to set this clock */
832 int control_mask; /* ditto, for hw.falcon.vid_control */
833 } f25 = {
834 25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25
835 }, f32 = {
836 32000000, 31250, 18, 0, 42, 0x0, 0
837 }, fext = {
838 0, 0, 18, 0, 42, 0x1, 0
841 /* VIDEL-prescale values [mon_type][pixel_length from VCO] */
842 static int vdl_prescale[4][3] = {
843 { 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 }
846 /* Default hsync timing [mon_type] in picoseconds */
847 static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 };
849 static inline int hxx_prescale(struct falcon_hw *hw)
851 return hw->ste_mode ? 16
852 : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
855 static int falcon_encode_fix(struct fb_fix_screeninfo *fix,
856 struct atafb_par *par)
858 strcpy(fix->id, "Atari Builtin");
859 fix->smem_start = phys_screen_base;
860 fix->smem_len = screen_len;
861 fix->type = FB_TYPE_INTERLEAVED_PLANES;
862 fix->type_aux = 2;
863 fix->visual = FB_VISUAL_PSEUDOCOLOR;
864 fix->xpanstep = 1;
865 fix->ypanstep = 1;
866 fix->ywrapstep = 0;
867 if (par->hw.falcon.mono) {
868 fix->type = FB_TYPE_PACKED_PIXELS;
869 fix->type_aux = 0;
870 /* no smooth scrolling with longword aligned video mem */
871 fix->xpanstep = 32;
872 } else if (par->hw.falcon.f_shift & 0x100) {
873 fix->type = FB_TYPE_PACKED_PIXELS;
874 fix->type_aux = 0;
875 /* Is this ok or should it be DIRECTCOLOR? */
876 fix->visual = FB_VISUAL_TRUECOLOR;
877 fix->xpanstep = 2;
879 fix->line_length = par->next_line;
880 fix->accel = FB_ACCEL_ATARIBLITT;
881 return 0;
884 static int falcon_decode_var(struct fb_var_screeninfo *var,
885 struct atafb_par *par)
887 int bpp = var->bits_per_pixel;
888 int xres = var->xres;
889 int yres = var->yres;
890 int xres_virtual = var->xres_virtual;
891 int yres_virtual = var->yres_virtual;
892 int left_margin, right_margin, hsync_len;
893 int upper_margin, lower_margin, vsync_len;
894 int linelen;
895 int interlace = 0, doubleline = 0;
896 struct pixel_clock *pclock;
897 int plen; /* width of pixel in clock cycles */
898 int xstretch;
899 int prescale;
900 int longoffset = 0;
901 int hfreq, vfreq;
902 int hdb_off, hde_off, base_off;
903 int gstart, gend1, gend2, align;
906 Get the video params out of 'var'. If a value doesn't fit, round
907 it up, if it's too big, return EINVAL.
908 Round up in the following order: bits_per_pixel, xres, yres,
909 xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
910 horizontal timing, vertical timing.
912 There is a maximum of screen resolution determined by pixelclock
913 and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
914 In interlace mode this is " * " *vfmin <= pixelclock.
915 Additional constraints: hfreq.
916 Frequency range for multisync monitors is given via command line.
917 For TV and SM124 both frequencies are fixed.
919 X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0)
920 Y % 16 == 0 to fit 8x16 font
921 Y % 8 == 0 if Y<400
923 Currently interlace and doubleline mode in var are ignored.
924 On SM124 and TV only the standard resolutions can be used.
927 /* Reject uninitialized mode */
928 if (!xres || !yres || !bpp)
929 return -EINVAL;
931 if (mon_type == F_MON_SM && bpp != 1)
932 return -EINVAL;
934 if (bpp <= 1) {
935 bpp = 1;
936 par->hw.falcon.f_shift = 0x400;
937 par->hw.falcon.st_shift = 0x200;
938 } else if (bpp <= 2) {
939 bpp = 2;
940 par->hw.falcon.f_shift = 0x000;
941 par->hw.falcon.st_shift = 0x100;
942 } else if (bpp <= 4) {
943 bpp = 4;
944 par->hw.falcon.f_shift = 0x000;
945 par->hw.falcon.st_shift = 0x000;
946 } else if (bpp <= 8) {
947 bpp = 8;
948 par->hw.falcon.f_shift = 0x010;
949 } else if (bpp <= 16) {
950 bpp = 16; /* packed pixel mode */
951 par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
952 } else
953 return -EINVAL;
954 par->hw.falcon.bpp = bpp;
956 if (mon_type == F_MON_SM || DontCalcRes) {
957 /* Skip all calculations. VGA/TV/SC1224 only supported. */
958 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
960 if (bpp > myvar->bits_per_pixel ||
961 var->xres > myvar->xres ||
962 var->yres > myvar->yres)
963 return -EINVAL;
964 fbhw->get_par(par); /* Current par will be new par */
965 goto set_screen_base; /* Don't forget this */
968 /* Only some fixed resolutions < 640x400 */
969 if (xres <= 320)
970 xres = 320;
971 else if (xres <= 640 && bpp != 16)
972 xres = 640;
973 if (yres <= 200)
974 yres = 200;
975 else if (yres <= 240)
976 yres = 240;
977 else if (yres <= 400)
978 yres = 400;
980 /* 2 planes must use STE compatibility mode */
981 par->hw.falcon.ste_mode = bpp == 2;
982 par->hw.falcon.mono = bpp == 1;
984 /* Total and visible scanline length must be a multiple of one longword,
985 * this and the console fontwidth yields the alignment for xres and
986 * xres_virtual.
987 * TODO: this way "odd" fontheights are not supported
989 * Special case in STE mode: blank and graphic positions don't align,
990 * avoid trash at right margin
992 if (par->hw.falcon.ste_mode)
993 xres = (xres + 63) & ~63;
994 else if (bpp == 1)
995 xres = (xres + 31) & ~31;
996 else
997 xres = (xres + 15) & ~15;
998 if (yres >= 400)
999 yres = (yres + 15) & ~15;
1000 else
1001 yres = (yres + 7) & ~7;
1003 if (xres_virtual < xres)
1004 xres_virtual = xres;
1005 else if (bpp == 1)
1006 xres_virtual = (xres_virtual + 31) & ~31;
1007 else
1008 xres_virtual = (xres_virtual + 15) & ~15;
1010 if (yres_virtual <= 0)
1011 yres_virtual = 0;
1012 else if (yres_virtual < yres)
1013 yres_virtual = yres;
1015 /* backward bug-compatibility */
1016 if (var->pixclock > 1)
1017 var->pixclock -= 1;
1019 par->hw.falcon.line_width = bpp * xres / 16;
1020 par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
1022 /* single or double pixel width */
1023 xstretch = (xres < 640) ? 2 : 1;
1025 #if 0 /* SM124 supports only 640x400, this is rejected above */
1026 if (mon_type == F_MON_SM) {
1027 if (xres != 640 && yres != 400)
1028 return -EINVAL;
1029 plen = 1;
1030 pclock = &f32;
1031 /* SM124-mode is special */
1032 par->hw.falcon.ste_mode = 1;
1033 par->hw.falcon.f_shift = 0x000;
1034 par->hw.falcon.st_shift = 0x200;
1035 left_margin = hsync_len = 128 / plen;
1036 right_margin = 0;
1037 /* TODO set all margins */
1038 } else
1039 #endif
1040 if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
1041 plen = 2 * xstretch;
1042 if (var->pixclock > f32.t * plen)
1043 return -EINVAL;
1044 pclock = &f32;
1045 if (yres > 240)
1046 interlace = 1;
1047 if (var->pixclock == 0) {
1048 /* set some minimal margins which center the screen */
1049 left_margin = 32;
1050 right_margin = 18;
1051 hsync_len = pclock->hsync / plen;
1052 upper_margin = 31;
1053 lower_margin = 14;
1054 vsync_len = interlace ? 3 : 4;
1055 } else {
1056 left_margin = var->left_margin;
1057 right_margin = var->right_margin;
1058 hsync_len = var->hsync_len;
1059 upper_margin = var->upper_margin;
1060 lower_margin = var->lower_margin;
1061 vsync_len = var->vsync_len;
1062 if (var->vmode & FB_VMODE_INTERLACED) {
1063 upper_margin = (upper_margin + 1) / 2;
1064 lower_margin = (lower_margin + 1) / 2;
1065 vsync_len = (vsync_len + 1) / 2;
1066 } else if (var->vmode & FB_VMODE_DOUBLE) {
1067 upper_margin *= 2;
1068 lower_margin *= 2;
1069 vsync_len *= 2;
1072 } else { /* F_MON_VGA */
1073 if (bpp == 16)
1074 xstretch = 2; /* Double pixel width only for hicolor */
1075 /* Default values are used for vert./hor. timing if no pixelclock given. */
1076 if (var->pixclock == 0) {
1077 int linesize;
1079 /* Choose master pixelclock depending on hor. timing */
1080 plen = 1 * xstretch;
1081 if ((plen * xres + f25.right + f25.hsync + f25.left) *
1082 fb_info.monspecs.hfmin < f25.f)
1083 pclock = &f25;
1084 else if ((plen * xres + f32.right + f32.hsync +
1085 f32.left) * fb_info.monspecs.hfmin < f32.f)
1086 pclock = &f32;
1087 else if ((plen * xres + fext.right + fext.hsync +
1088 fext.left) * fb_info.monspecs.hfmin < fext.f &&
1089 fext.f)
1090 pclock = &fext;
1091 else
1092 return -EINVAL;
1094 left_margin = pclock->left / plen;
1095 right_margin = pclock->right / plen;
1096 hsync_len = pclock->hsync / plen;
1097 linesize = left_margin + xres + right_margin + hsync_len;
1098 upper_margin = 31;
1099 lower_margin = 11;
1100 vsync_len = 3;
1101 } else {
1102 /* Choose largest pixelclock <= wanted clock */
1103 int i;
1104 unsigned long pcl = ULONG_MAX;
1105 pclock = 0;
1106 for (i = 1; i <= 4; i *= 2) {
1107 if (f25.t * i >= var->pixclock &&
1108 f25.t * i < pcl) {
1109 pcl = f25.t * i;
1110 pclock = &f25;
1112 if (f32.t * i >= var->pixclock &&
1113 f32.t * i < pcl) {
1114 pcl = f32.t * i;
1115 pclock = &f32;
1117 if (fext.t && fext.t * i >= var->pixclock &&
1118 fext.t * i < pcl) {
1119 pcl = fext.t * i;
1120 pclock = &fext;
1123 if (!pclock)
1124 return -EINVAL;
1125 plen = pcl / pclock->t;
1127 left_margin = var->left_margin;
1128 right_margin = var->right_margin;
1129 hsync_len = var->hsync_len;
1130 upper_margin = var->upper_margin;
1131 lower_margin = var->lower_margin;
1132 vsync_len = var->vsync_len;
1133 /* Internal unit is [single lines per (half-)frame] */
1134 if (var->vmode & FB_VMODE_INTERLACED) {
1135 /* # lines in half frame */
1136 /* External unit is [lines per full frame] */
1137 upper_margin = (upper_margin + 1) / 2;
1138 lower_margin = (lower_margin + 1) / 2;
1139 vsync_len = (vsync_len + 1) / 2;
1140 } else if (var->vmode & FB_VMODE_DOUBLE) {
1141 /* External unit is [double lines per frame] */
1142 upper_margin *= 2;
1143 lower_margin *= 2;
1144 vsync_len *= 2;
1147 if (pclock == &fext)
1148 longoffset = 1; /* VIDEL doesn't synchronize on short offset */
1150 /* Is video bus bandwidth (32MB/s) too low for this resolution? */
1151 /* this is definitely wrong if bus clock != 32MHz */
1152 if (pclock->f / plen / 8 * bpp > 32000000L)
1153 return -EINVAL;
1155 if (vsync_len < 1)
1156 vsync_len = 1;
1158 /* include sync lengths in right/lower margin for all calculations */
1159 right_margin += hsync_len;
1160 lower_margin += vsync_len;
1162 /* ! In all calculations of margins we use # of lines in half frame
1163 * (which is a full frame in non-interlace mode), so we can switch
1164 * between interlace and non-interlace without messing around
1165 * with these.
1167 again:
1168 /* Set base_offset 128 and video bus width */
1169 par->hw.falcon.vid_control = mon_type | f030_bus_width;
1170 if (!longoffset)
1171 par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */
1172 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1173 par->hw.falcon.vid_control |= VCO_HSYPOS;
1174 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1175 par->hw.falcon.vid_control |= VCO_VSYPOS;
1176 /* Pixelclock */
1177 par->hw.falcon.vid_control |= pclock->control_mask;
1178 /* External or internal clock */
1179 par->hw.falcon.sync = pclock->sync_mask | 0x2;
1180 /* Pixellength and prescale */
1181 par->hw.falcon.vid_mode = (2 / plen) << 2;
1182 if (doubleline)
1183 par->hw.falcon.vid_mode |= VMO_DOUBLE;
1184 if (interlace)
1185 par->hw.falcon.vid_mode |= VMO_INTER;
1187 /*********************
1188 * Horizontal timing: unit = [master clock cycles]
1189 * unit of hxx-registers: [master clock cycles * prescale]
1190 * Hxx-registers are 9 bit wide
1192 * 1 line = ((hht + 2) * 2 * prescale) clock cycles
1194 * graphic output = hdb & 0x200 ?
1195 * ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff:
1196 * (hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
1197 * (this must be a multiple of plen*128/bpp, on VGA pixels
1198 * to the right may be cut off with a bigger right margin)
1200 * start of graphics relative to start of 1st halfline = hdb & 0x200 ?
1201 * (hdb - hht - 2) * prescale + hdboff :
1202 * hdb * prescale + hdboff
1204 * end of graphics relative to start of 1st halfline =
1205 * (hde + hht + 2) * prescale + hdeoff
1206 *********************/
1207 /* Calculate VIDEL registers */
1209 prescale = hxx_prescale(&par->hw.falcon);
1210 base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
1212 /* Offsets depend on video mode */
1213 /* Offsets are in clock cycles, divide by prescale to
1214 * calculate hd[be]-registers
1216 if (par->hw.falcon.f_shift & 0x100) {
1217 align = 1;
1218 hde_off = 0;
1219 hdb_off = (base_off + 16 * plen) + prescale;
1220 } else {
1221 align = 128 / bpp;
1222 hde_off = ((128 / bpp + 2) * plen);
1223 if (par->hw.falcon.ste_mode)
1224 hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
1225 else
1226 hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
1229 gstart = (prescale / 2 + plen * left_margin) / prescale;
1230 /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
1231 gend1 = gstart + roundup(xres, align) * plen / prescale;
1232 /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
1233 gend2 = gstart + xres * plen / prescale;
1234 par->HHT = plen * (left_margin + xres + right_margin) /
1235 (2 * prescale) - 2;
1236 /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
1238 par->HDB = gstart - hdb_off / prescale;
1239 par->HBE = gstart;
1240 if (par->HDB < 0)
1241 par->HDB += par->HHT + 2 + 0x200;
1242 par->HDE = gend1 - par->HHT - 2 - hde_off / prescale;
1243 par->HBB = gend2 - par->HHT - 2;
1244 #if 0
1245 /* One more Videl constraint: data fetch of two lines must not overlap */
1246 if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
1247 /* if this happens increase margins, decrease hfreq. */
1249 #endif
1250 if (hde_off % prescale)
1251 par->HBB++; /* compensate for non matching hde and hbb */
1252 par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
1253 if (par->HSS < par->HBB)
1254 par->HSS = par->HBB;
1257 /* check hor. frequency */
1258 hfreq = pclock->f / ((par->HHT + 2) * prescale * 2);
1259 if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) {
1260 /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
1261 /* Too high -> enlarge margin */
1262 left_margin += 1;
1263 right_margin += 1;
1264 goto again;
1266 if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin)
1267 return -EINVAL;
1269 /* Vxx-registers */
1270 /* All Vxx must be odd in non-interlace, since frame starts in the middle
1271 * of the first displayed line!
1272 * One frame consists of VFT+1 half lines. VFT+1 must be even in
1273 * non-interlace, odd in interlace mode for synchronisation.
1274 * Vxx-registers are 11 bit wide
1276 par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
1277 par->VDB = par->VBE;
1278 par->VDE = yres;
1279 if (!interlace)
1280 par->VDE <<= 1;
1281 if (doubleline)
1282 par->VDE <<= 1; /* VDE now half lines per (half-)frame */
1283 par->VDE += par->VDB;
1284 par->VBB = par->VDE;
1285 par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
1286 par->VSS = par->VFT + 1 - (vsync_len * 2 - 1);
1287 /* vbb,vss,vft must be even in interlace mode */
1288 if (interlace) {
1289 par->VBB++;
1290 par->VSS++;
1291 par->VFT++;
1294 /* V-frequency check, hope I didn't create any loop here. */
1295 /* Interlace and doubleline are mutually exclusive. */
1296 vfreq = (hfreq * 2) / (par->VFT + 1);
1297 if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
1298 /* Too high -> try again with doubleline */
1299 doubleline = 1;
1300 goto again;
1301 } else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
1302 /* Too low -> try again with interlace */
1303 interlace = 1;
1304 goto again;
1305 } else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
1306 /* Doubleline too low -> clear doubleline and enlarge margins */
1307 int lines;
1308 doubleline = 0;
1309 for (lines = 0;
1310 (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) >
1311 fb_info.monspecs.vfmax;
1312 lines++)
1314 upper_margin += lines;
1315 lower_margin += lines;
1316 goto again;
1317 } else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
1318 /* Doubleline too high -> enlarge margins */
1319 int lines;
1320 for (lines = 0;
1321 (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
1322 fb_info.monspecs.vfmax;
1323 lines += 2)
1325 upper_margin += lines;
1326 lower_margin += lines;
1327 goto again;
1328 } else if (vfreq > fb_info.monspecs.vfmax && interlace) {
1329 /* Interlace, too high -> enlarge margins */
1330 int lines;
1331 for (lines = 0;
1332 (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
1333 fb_info.monspecs.vfmax;
1334 lines++)
1336 upper_margin += lines;
1337 lower_margin += lines;
1338 goto again;
1339 } else if (vfreq < fb_info.monspecs.vfmin ||
1340 vfreq > fb_info.monspecs.vfmax)
1341 return -EINVAL;
1343 set_screen_base:
1344 linelen = xres_virtual * bpp / 8;
1345 if (yres_virtual * linelen > screen_len && screen_len)
1346 return -EINVAL;
1347 if (yres * linelen > screen_len && screen_len)
1348 return -EINVAL;
1349 if (var->yoffset + yres > yres_virtual && yres_virtual)
1350 return -EINVAL;
1351 par->yres_virtual = yres_virtual;
1352 par->screen_base = screen_base + var->yoffset * linelen;
1353 par->hw.falcon.xoffset = 0;
1355 par->next_line = linelen;
1357 return 0;
1360 static int falcon_encode_var(struct fb_var_screeninfo *var,
1361 struct atafb_par *par)
1363 /* !!! only for VGA !!! */
1364 int linelen;
1365 int prescale, plen;
1366 int hdb_off, hde_off, base_off;
1367 struct falcon_hw *hw = &par->hw.falcon;
1369 memset(var, 0, sizeof(struct fb_var_screeninfo));
1370 /* possible frequencies: 25.175 or 32MHz */
1371 var->pixclock = hw->sync & 0x1 ? fext.t :
1372 hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
1374 var->height = -1;
1375 var->width = -1;
1377 var->sync = 0;
1378 if (hw->vid_control & VCO_HSYPOS)
1379 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1380 if (hw->vid_control & VCO_VSYPOS)
1381 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1383 var->vmode = FB_VMODE_NONINTERLACED;
1384 if (hw->vid_mode & VMO_INTER)
1385 var->vmode |= FB_VMODE_INTERLACED;
1386 if (hw->vid_mode & VMO_DOUBLE)
1387 var->vmode |= FB_VMODE_DOUBLE;
1389 /* visible y resolution:
1390 * Graphics display starts at line VDB and ends at line
1391 * VDE. If interlace mode off unit of VC-registers is
1392 * half lines, else lines.
1394 var->yres = hw->vde - hw->vdb;
1395 if (!(var->vmode & FB_VMODE_INTERLACED))
1396 var->yres >>= 1;
1397 if (var->vmode & FB_VMODE_DOUBLE)
1398 var->yres >>= 1;
1401 * to get bpp, we must examine f_shift and st_shift.
1402 * f_shift is valid if any of bits no. 10, 8 or 4
1403 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
1404 * if bit 10 set then bit 8 and bit 4 don't care...
1405 * If all these bits are 0 get display depth from st_shift
1406 * (as for ST and STE)
1408 if (hw->f_shift & 0x400) /* 2 colors */
1409 var->bits_per_pixel = 1;
1410 else if (hw->f_shift & 0x100) /* hicolor */
1411 var->bits_per_pixel = 16;
1412 else if (hw->f_shift & 0x010) /* 8 bitplanes */
1413 var->bits_per_pixel = 8;
1414 else if (hw->st_shift == 0)
1415 var->bits_per_pixel = 4;
1416 else if (hw->st_shift == 0x100)
1417 var->bits_per_pixel = 2;
1418 else /* if (hw->st_shift == 0x200) */
1419 var->bits_per_pixel = 1;
1421 var->xres = hw->line_width * 16 / var->bits_per_pixel;
1422 var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
1423 if (hw->xoffset)
1424 var->xres_virtual += 16;
1426 if (var->bits_per_pixel == 16) {
1427 var->red.offset = 11;
1428 var->red.length = 5;
1429 var->red.msb_right = 0;
1430 var->green.offset = 5;
1431 var->green.length = 6;
1432 var->green.msb_right = 0;
1433 var->blue.offset = 0;
1434 var->blue.length = 5;
1435 var->blue.msb_right = 0;
1436 } else {
1437 var->red.offset = 0;
1438 var->red.length = hw->ste_mode ? 4 : 6;
1439 if (var->red.length > var->bits_per_pixel)
1440 var->red.length = var->bits_per_pixel;
1441 var->red.msb_right = 0;
1442 var->grayscale = 0;
1443 var->blue = var->green = var->red;
1445 var->transp.offset = 0;
1446 var->transp.length = 0;
1447 var->transp.msb_right = 0;
1449 linelen = var->xres_virtual * var->bits_per_pixel / 8;
1450 if (screen_len) {
1451 if (par->yres_virtual)
1452 var->yres_virtual = par->yres_virtual;
1453 else
1454 /* yres_virtual == 0 means use maximum */
1455 var->yres_virtual = screen_len / linelen;
1456 } else {
1457 if (hwscroll < 0)
1458 var->yres_virtual = 2 * var->yres;
1459 else
1460 var->yres_virtual = var->yres + hwscroll * 16;
1462 var->xoffset = 0; /* TODO change this */
1464 /* hdX-offsets */
1465 prescale = hxx_prescale(hw);
1466 plen = 4 >> (hw->vid_mode >> 2 & 0x3);
1467 base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
1468 if (hw->f_shift & 0x100) {
1469 hde_off = 0;
1470 hdb_off = (base_off + 16 * plen) + prescale;
1471 } else {
1472 hde_off = ((128 / var->bits_per_pixel + 2) * plen);
1473 if (hw->ste_mode)
1474 hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
1475 + prescale;
1476 else
1477 hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
1478 + prescale;
1481 /* Right margin includes hsync */
1482 var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
1483 (hw->hdb & 0x200 ? 2 + hw->hht : 0));
1484 if (hw->ste_mode || mon_type != F_MON_VGA)
1485 var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
1486 else
1487 /* can't use this in ste_mode, because hbb is +1 off */
1488 var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
1489 var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
1491 /* Lower margin includes vsync */
1492 var->upper_margin = hw->vdb / 2; /* round down to full lines */
1493 var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2; /* round up */
1494 var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2; /* round up */
1495 if (var->vmode & FB_VMODE_INTERLACED) {
1496 var->upper_margin *= 2;
1497 var->lower_margin *= 2;
1498 var->vsync_len *= 2;
1499 } else if (var->vmode & FB_VMODE_DOUBLE) {
1500 var->upper_margin = (var->upper_margin + 1) / 2;
1501 var->lower_margin = (var->lower_margin + 1) / 2;
1502 var->vsync_len = (var->vsync_len + 1) / 2;
1505 var->pixclock *= plen;
1506 var->left_margin /= plen;
1507 var->right_margin /= plen;
1508 var->hsync_len /= plen;
1510 var->right_margin -= var->hsync_len;
1511 var->lower_margin -= var->vsync_len;
1513 if (screen_base)
1514 var->yoffset = (par->screen_base - screen_base) / linelen;
1515 else
1516 var->yoffset = 0;
1517 var->nonstd = 0; /* what is this for? */
1518 var->activate = 0;
1519 return 0;
1522 static int f_change_mode;
1523 static struct falcon_hw f_new_mode;
1524 static int f_pan_display;
1526 static void falcon_get_par(struct atafb_par *par)
1528 unsigned long addr;
1529 struct falcon_hw *hw = &par->hw.falcon;
1531 hw->line_width = shifter_f030.scn_width;
1532 hw->line_offset = shifter_f030.off_next;
1533 hw->st_shift = videl.st_shift & 0x300;
1534 hw->f_shift = videl.f_shift;
1535 hw->vid_control = videl.control;
1536 hw->vid_mode = videl.mode;
1537 hw->sync = shifter_st.syncmode & 0x1;
1538 hw->xoffset = videl.xoffset & 0xf;
1539 hw->hht = videl.hht;
1540 hw->hbb = videl.hbb;
1541 hw->hbe = videl.hbe;
1542 hw->hdb = videl.hdb;
1543 hw->hde = videl.hde;
1544 hw->hss = videl.hss;
1545 hw->vft = videl.vft;
1546 hw->vbb = videl.vbb;
1547 hw->vbe = videl.vbe;
1548 hw->vdb = videl.vdb;
1549 hw->vde = videl.vde;
1550 hw->vss = videl.vss;
1552 addr = (shifter_st.bas_hi & 0xff) << 16 |
1553 (shifter_st.bas_md & 0xff) << 8 |
1554 (shifter_st.bas_lo & 0xff);
1555 par->screen_base = atari_stram_to_virt(addr);
1557 /* derived parameters */
1558 hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100;
1559 hw->mono = (hw->f_shift & 0x400) ||
1560 ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200);
1563 static void falcon_set_par(struct atafb_par *par)
1565 f_change_mode = 0;
1567 /* only set screen_base if really necessary */
1568 if (current_par.screen_base != par->screen_base)
1569 fbhw->set_screen_base(par->screen_base);
1571 /* Don't touch any other registers if we keep the default resolution */
1572 if (DontCalcRes)
1573 return;
1575 /* Tell vbl-handler to change video mode.
1576 * We change modes only on next VBL, to avoid desynchronisation
1577 * (a shift to the right and wrap around by a random number of pixels
1578 * in all monochrome modes).
1579 * This seems to work on my Falcon.
1581 f_new_mode = par->hw.falcon;
1582 f_change_mode = 1;
1585 static irqreturn_t falcon_vbl_switcher(int irq, void *dummy)
1587 struct falcon_hw *hw = &f_new_mode;
1589 if (f_change_mode) {
1590 f_change_mode = 0;
1592 if (hw->sync & 0x1) {
1593 /* Enable external pixelclock. This code only for ScreenWonder */
1594 *(volatile unsigned short *)0xffff9202 = 0xffbf;
1595 } else {
1596 /* Turn off external clocks. Read sets all output bits to 1. */
1597 *(volatile unsigned short *)0xffff9202;
1599 shifter_st.syncmode = hw->sync;
1601 videl.hht = hw->hht;
1602 videl.hbb = hw->hbb;
1603 videl.hbe = hw->hbe;
1604 videl.hdb = hw->hdb;
1605 videl.hde = hw->hde;
1606 videl.hss = hw->hss;
1607 videl.vft = hw->vft;
1608 videl.vbb = hw->vbb;
1609 videl.vbe = hw->vbe;
1610 videl.vdb = hw->vdb;
1611 videl.vde = hw->vde;
1612 videl.vss = hw->vss;
1614 videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
1615 if (hw->ste_mode) {
1616 videl.st_shift = hw->st_shift; /* write enables STE palette */
1617 } else {
1618 /* IMPORTANT:
1619 * set st_shift 0, so we can tell the screen-depth if f_shift == 0.
1620 * Writing 0 to f_shift enables 4 plane Falcon mode but
1621 * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible
1622 * with Falcon palette.
1624 videl.st_shift = 0;
1625 /* now back to Falcon palette mode */
1626 videl.f_shift = hw->f_shift;
1628 /* writing to st_shift changed scn_width and vid_mode */
1629 videl.xoffset = hw->xoffset;
1630 shifter_f030.scn_width = hw->line_width;
1631 shifter_f030.off_next = hw->line_offset;
1632 videl.control = hw->vid_control;
1633 videl.mode = hw->vid_mode;
1635 if (f_pan_display) {
1636 f_pan_display = 0;
1637 videl.xoffset = current_par.hw.falcon.xoffset;
1638 shifter_f030.off_next = current_par.hw.falcon.line_offset;
1640 return IRQ_HANDLED;
1643 static int falcon_pan_display(struct fb_var_screeninfo *var,
1644 struct fb_info *info)
1646 struct atafb_par *par = (struct atafb_par *)info->par;
1648 int xoffset;
1649 int bpp = info->var.bits_per_pixel;
1651 if (bpp == 1)
1652 var->xoffset = up(var->xoffset, 32);
1653 if (bpp != 16)
1654 par->hw.falcon.xoffset = var->xoffset & 15;
1655 else {
1656 par->hw.falcon.xoffset = 0;
1657 var->xoffset = up(var->xoffset, 2);
1659 par->hw.falcon.line_offset = bpp *
1660 (info->var.xres_virtual - info->var.xres) / 16;
1661 if (par->hw.falcon.xoffset)
1662 par->hw.falcon.line_offset -= bpp;
1663 xoffset = var->xoffset - par->hw.falcon.xoffset;
1665 par->screen_base = screen_base +
1666 (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8;
1667 if (fbhw->set_screen_base)
1668 fbhw->set_screen_base(par->screen_base);
1669 else
1670 return -EINVAL; /* shouldn't happen */
1671 f_pan_display = 1;
1672 return 0;
1675 static int falcon_setcolreg(unsigned int regno, unsigned int red,
1676 unsigned int green, unsigned int blue,
1677 unsigned int transp, struct fb_info *info)
1679 if (regno > 255)
1680 return 1;
1681 f030_col[regno] = (((red & 0xfc00) << 16) |
1682 ((green & 0xfc00) << 8) |
1683 ((blue & 0xfc00) >> 8));
1684 if (regno < 16) {
1685 shifter_tt.color_reg[regno] =
1686 (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) |
1687 (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) |
1688 ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
1689 ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) |
1690 ((green & 0xfc00) >> 5) |
1691 ((blue & 0xf800) >> 11));
1693 return 0;
1696 static int falcon_blank(int blank_mode)
1698 /* ++guenther: we can switch off graphics by changing VDB and VDE,
1699 * so VIDEL doesn't hog the bus while saving.
1700 * (this may affect usleep()).
1702 int vdb, vss, hbe, hss;
1704 if (mon_type == F_MON_SM) /* this doesn't work on SM124 */
1705 return 1;
1707 vdb = current_par.VDB;
1708 vss = current_par.VSS;
1709 hbe = current_par.HBE;
1710 hss = current_par.HSS;
1712 if (blank_mode >= 1) {
1713 /* disable graphics output (this speeds up the CPU) ... */
1714 vdb = current_par.VFT + 1;
1715 /* ... and blank all lines */
1716 hbe = current_par.HHT + 2;
1718 /* use VESA suspend modes on VGA monitors */
1719 if (mon_type == F_MON_VGA) {
1720 if (blank_mode == 2 || blank_mode == 4)
1721 vss = current_par.VFT + 1;
1722 if (blank_mode == 3 || blank_mode == 4)
1723 hss = current_par.HHT + 2;
1726 videl.vdb = vdb;
1727 videl.vss = vss;
1728 videl.hbe = hbe;
1729 videl.hss = hss;
1731 return 0;
1734 static int falcon_detect(void)
1736 struct atafb_par par;
1737 unsigned char fhw;
1739 /* Determine connected monitor and set monitor parameters */
1740 fhw = *(unsigned char *)0xffff8006;
1741 mon_type = fhw >> 6 & 0x3;
1742 /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
1743 f030_bus_width = fhw << 6 & 0x80;
1744 switch (mon_type) {
1745 case F_MON_SM:
1746 fb_info.monspecs.vfmin = 70;
1747 fb_info.monspecs.vfmax = 72;
1748 fb_info.monspecs.hfmin = 35713;
1749 fb_info.monspecs.hfmax = 35715;
1750 break;
1751 case F_MON_SC:
1752 case F_MON_TV:
1753 /* PAL...NTSC */
1754 fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
1755 fb_info.monspecs.vfmax = 60;
1756 fb_info.monspecs.hfmin = 15620;
1757 fb_info.monspecs.hfmax = 15755;
1758 break;
1760 /* initialize hsync-len */
1761 f25.hsync = h_syncs[mon_type] / f25.t;
1762 f32.hsync = h_syncs[mon_type] / f32.t;
1763 if (fext.t)
1764 fext.hsync = h_syncs[mon_type] / fext.t;
1766 falcon_get_par(&par);
1767 falcon_encode_var(&atafb_predefined[0], &par);
1769 /* Detected mode is always the "autodetect" slot */
1770 return 1;
1773 #endif /* ATAFB_FALCON */
1775 /* ------------------- ST(E) specific functions ---------------------- */
1777 #ifdef ATAFB_STE
1779 static int stste_encode_fix(struct fb_fix_screeninfo *fix,
1780 struct atafb_par *par)
1782 int mode;
1784 strcpy(fix->id, "Atari Builtin");
1785 fix->smem_start = phys_screen_base;
1786 fix->smem_len = screen_len;
1787 fix->type = FB_TYPE_INTERLEAVED_PLANES;
1788 fix->type_aux = 2;
1789 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1790 mode = par->hw.st.mode & 3;
1791 if (mode == ST_HIGH) {
1792 fix->type = FB_TYPE_PACKED_PIXELS;
1793 fix->type_aux = 0;
1794 fix->visual = FB_VISUAL_MONO10;
1796 if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
1797 fix->xpanstep = 16;
1798 fix->ypanstep = 1;
1799 } else {
1800 fix->xpanstep = 0;
1801 fix->ypanstep = 0;
1803 fix->ywrapstep = 0;
1804 fix->line_length = par->next_line;
1805 fix->accel = FB_ACCEL_ATARIBLITT;
1806 return 0;
1809 static int stste_decode_var(struct fb_var_screeninfo *var,
1810 struct atafb_par *par)
1812 int xres = var->xres;
1813 int yres = var->yres;
1814 int bpp = var->bits_per_pixel;
1815 int linelen;
1816 int yres_virtual = var->yres_virtual;
1818 if (mono_moni) {
1819 if (bpp > 1 || xres > sttt_xres || yres > st_yres)
1820 return -EINVAL;
1821 par->hw.st.mode = ST_HIGH;
1822 xres = sttt_xres;
1823 yres = st_yres;
1824 bpp = 1;
1825 } else {
1826 if (bpp > 4 || xres > sttt_xres || yres > st_yres)
1827 return -EINVAL;
1828 if (bpp > 2) {
1829 if (xres > sttt_xres / 2 || yres > st_yres / 2)
1830 return -EINVAL;
1831 par->hw.st.mode = ST_LOW;
1832 xres = sttt_xres / 2;
1833 yres = st_yres / 2;
1834 bpp = 4;
1835 } else if (bpp > 1) {
1836 if (xres > sttt_xres || yres > st_yres / 2)
1837 return -EINVAL;
1838 par->hw.st.mode = ST_MID;
1839 xres = sttt_xres;
1840 yres = st_yres / 2;
1841 bpp = 2;
1842 } else
1843 return -EINVAL;
1845 if (yres_virtual <= 0)
1846 yres_virtual = 0;
1847 else if (yres_virtual < yres)
1848 yres_virtual = yres;
1849 if (var->sync & FB_SYNC_EXT)
1850 par->hw.st.sync = (par->hw.st.sync & ~1) | 1;
1851 else
1852 par->hw.st.sync = (par->hw.st.sync & ~1);
1853 linelen = xres * bpp / 8;
1854 if (yres_virtual * linelen > screen_len && screen_len)
1855 return -EINVAL;
1856 if (yres * linelen > screen_len && screen_len)
1857 return -EINVAL;
1858 if (var->yoffset + yres > yres_virtual && yres_virtual)
1859 return -EINVAL;
1860 par->yres_virtual = yres_virtual;
1861 par->screen_base = screen_base + var->yoffset * linelen;
1862 par->next_line = linelen;
1863 return 0;
1866 static int stste_encode_var(struct fb_var_screeninfo *var,
1867 struct atafb_par *par)
1869 int linelen;
1870 memset(var, 0, sizeof(struct fb_var_screeninfo));
1871 var->red.offset = 0;
1872 var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
1873 var->red.msb_right = 0;
1874 var->grayscale = 0;
1876 var->pixclock = 31041;
1877 var->left_margin = 120; /* these are incorrect */
1878 var->right_margin = 100;
1879 var->upper_margin = 8;
1880 var->lower_margin = 16;
1881 var->hsync_len = 140;
1882 var->vsync_len = 30;
1884 var->height = -1;
1885 var->width = -1;
1887 if (!(par->hw.st.sync & 1))
1888 var->sync = 0;
1889 else
1890 var->sync = FB_SYNC_EXT;
1892 switch (par->hw.st.mode & 3) {
1893 case ST_LOW:
1894 var->xres = sttt_xres / 2;
1895 var->yres = st_yres / 2;
1896 var->bits_per_pixel = 4;
1897 break;
1898 case ST_MID:
1899 var->xres = sttt_xres;
1900 var->yres = st_yres / 2;
1901 var->bits_per_pixel = 2;
1902 break;
1903 case ST_HIGH:
1904 var->xres = sttt_xres;
1905 var->yres = st_yres;
1906 var->bits_per_pixel = 1;
1907 break;
1909 var->blue = var->green = var->red;
1910 var->transp.offset = 0;
1911 var->transp.length = 0;
1912 var->transp.msb_right = 0;
1913 var->xres_virtual = sttt_xres_virtual;
1914 linelen = var->xres_virtual * var->bits_per_pixel / 8;
1915 ovsc_addlen = linelen * (sttt_yres_virtual - st_yres);
1917 if (!use_hwscroll)
1918 var->yres_virtual = var->yres;
1919 else if (screen_len) {
1920 if (par->yres_virtual)
1921 var->yres_virtual = par->yres_virtual;
1922 else
1923 /* yres_virtual == 0 means use maximum */
1924 var->yres_virtual = screen_len / linelen;
1925 } else {
1926 if (hwscroll < 0)
1927 var->yres_virtual = 2 * var->yres;
1928 else
1929 var->yres_virtual = var->yres + hwscroll * 16;
1931 var->xoffset = 0;
1932 if (screen_base)
1933 var->yoffset = (par->screen_base - screen_base) / linelen;
1934 else
1935 var->yoffset = 0;
1936 var->nonstd = 0;
1937 var->activate = 0;
1938 var->vmode = FB_VMODE_NONINTERLACED;
1939 return 0;
1942 static void stste_get_par(struct atafb_par *par)
1944 unsigned long addr;
1945 par->hw.st.mode = shifter_tt.st_shiftmode;
1946 par->hw.st.sync = shifter_st.syncmode;
1947 addr = ((shifter_st.bas_hi & 0xff) << 16) |
1948 ((shifter_st.bas_md & 0xff) << 8);
1949 if (ATARIHW_PRESENT(EXTD_SHIFTER))
1950 addr |= (shifter_st.bas_lo & 0xff);
1951 par->screen_base = atari_stram_to_virt(addr);
1954 static void stste_set_par(struct atafb_par *par)
1956 shifter_tt.st_shiftmode = par->hw.st.mode;
1957 shifter_st.syncmode = par->hw.st.sync;
1958 /* only set screen_base if really necessary */
1959 if (current_par.screen_base != par->screen_base)
1960 fbhw->set_screen_base(par->screen_base);
1963 static int stste_setcolreg(unsigned int regno, unsigned int red,
1964 unsigned int green, unsigned int blue,
1965 unsigned int transp, struct fb_info *info)
1967 if (regno > 15)
1968 return 1;
1969 red >>= 12;
1970 blue >>= 12;
1971 green >>= 12;
1972 if (ATARIHW_PRESENT(EXTD_SHIFTER))
1973 shifter_tt.color_reg[regno] =
1974 (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
1975 (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
1976 ((blue & 0xe) >> 1) | ((blue & 1) << 3);
1977 else
1978 shifter_tt.color_reg[regno] =
1979 ((red & 0xe) << 7) |
1980 ((green & 0xe) << 3) |
1981 ((blue & 0xe) >> 1);
1982 return 0;
1985 static int stste_detect(void)
1987 struct atafb_par par;
1989 /* Determine the connected monitor: The DMA sound must be
1990 * disabled before reading the MFP GPIP, because the Sound
1991 * Done Signal and the Monochrome Detect are XORed together!
1993 if (ATARIHW_PRESENT(PCM_8BIT)) {
1994 tt_dmasnd.ctrl = DMASND_CTRL_OFF;
1995 udelay(20); /* wait a while for things to settle down */
1997 mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
1999 stste_get_par(&par);
2000 stste_encode_var(&atafb_predefined[0], &par);
2002 if (!ATARIHW_PRESENT(EXTD_SHIFTER))
2003 use_hwscroll = 0;
2004 return 1;
2007 static void stste_set_screen_base(void *s_base)
2009 unsigned long addr;
2010 addr = atari_stram_to_phys(s_base);
2011 /* Setup Screen Memory */
2012 shifter_st.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
2013 shifter_st.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
2014 if (ATARIHW_PRESENT(EXTD_SHIFTER))
2015 shifter_st.bas_lo = (unsigned char)(addr & 0x0000ff);
2018 #endif /* ATAFB_STE */
2020 /* Switching the screen size should be done during vsync, otherwise
2021 * the margins may get messed up. This is a well known problem of
2022 * the ST's video system.
2024 * Unfortunately there is hardly any way to find the vsync, as the
2025 * vertical blank interrupt is no longer in time on machines with
2026 * overscan type modifications.
2028 * We can, however, use Timer B to safely detect the black shoulder,
2029 * but then we've got to guess an appropriate delay to find the vsync.
2030 * This might not work on every machine.
2032 * martin_rogge @ ki.maus.de, 8th Aug 1995
2035 #define LINE_DELAY (mono_moni ? 30 : 70)
2036 #define SYNC_DELAY (mono_moni ? 1500 : 2000)
2038 /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
2039 static void st_ovsc_switch(void)
2041 unsigned long flags;
2042 register unsigned char old, new;
2044 if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
2045 return;
2046 local_irq_save(flags);
2048 st_mfp.tim_ct_b = 0x10;
2049 st_mfp.active_edge |= 8;
2050 st_mfp.tim_ct_b = 0;
2051 st_mfp.tim_dt_b = 0xf0;
2052 st_mfp.tim_ct_b = 8;
2053 while (st_mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
2055 new = st_mfp.tim_dt_b;
2056 do {
2057 udelay(LINE_DELAY);
2058 old = new;
2059 new = st_mfp.tim_dt_b;
2060 } while (old != new);
2061 st_mfp.tim_ct_b = 0x10;
2062 udelay(SYNC_DELAY);
2064 if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
2065 acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
2066 if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
2067 acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
2068 if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
2069 sound_ym.rd_data_reg_sel = 14;
2070 sound_ym.wd_data = sound_ym.rd_data_reg_sel |
2071 ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
2072 ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
2074 local_irq_restore(flags);
2077 /* ------------------- External Video ---------------------- */
2079 #ifdef ATAFB_EXT
2081 static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
2083 strcpy(fix->id, "Unknown Extern");
2084 fix->smem_start = external_addr;
2085 fix->smem_len = PAGE_ALIGN(external_len);
2086 if (external_depth == 1) {
2087 fix->type = FB_TYPE_PACKED_PIXELS;
2088 /* The letters 'n' and 'i' in the "atavideo=external:" stand
2089 * for "normal" and "inverted", rsp., in the monochrome case */
2090 fix->visual =
2091 (external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
2092 external_pmode == FB_TYPE_PACKED_PIXELS) ?
2093 FB_VISUAL_MONO10 : FB_VISUAL_MONO01;
2094 } else {
2095 /* Use STATIC if we don't know how to access color registers */
2096 int visual = external_vgaiobase ?
2097 FB_VISUAL_PSEUDOCOLOR :
2098 FB_VISUAL_STATIC_PSEUDOCOLOR;
2099 switch (external_pmode) {
2100 case -1: /* truecolor */
2101 fix->type = FB_TYPE_PACKED_PIXELS;
2102 fix->visual = FB_VISUAL_TRUECOLOR;
2103 break;
2104 case FB_TYPE_PACKED_PIXELS:
2105 fix->type = FB_TYPE_PACKED_PIXELS;
2106 fix->visual = visual;
2107 break;
2108 case FB_TYPE_PLANES:
2109 fix->type = FB_TYPE_PLANES;
2110 fix->visual = visual;
2111 break;
2112 case FB_TYPE_INTERLEAVED_PLANES:
2113 fix->type = FB_TYPE_INTERLEAVED_PLANES;
2114 fix->type_aux = 2;
2115 fix->visual = visual;
2116 break;
2119 fix->xpanstep = 0;
2120 fix->ypanstep = 0;
2121 fix->ywrapstep = 0;
2122 fix->line_length = par->next_line;
2123 return 0;
2126 static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
2128 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
2130 if (var->bits_per_pixel > myvar->bits_per_pixel ||
2131 var->xres > myvar->xres ||
2132 var->xres_virtual > myvar->xres_virtual ||
2133 var->yres > myvar->yres ||
2134 var->xoffset > 0 ||
2135 var->yoffset > 0)
2136 return -EINVAL;
2138 par->next_line = external_xres_virtual * external_depth / 8;
2139 return 0;
2142 static int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
2144 memset(var, 0, sizeof(struct fb_var_screeninfo));
2145 var->red.offset = 0;
2146 var->red.length = (external_pmode == -1) ? external_depth / 3 :
2147 (external_vgaiobase ? external_bitspercol : 0);
2148 var->red.msb_right = 0;
2149 var->grayscale = 0;
2151 var->pixclock = 31041;
2152 var->left_margin = 120; /* these are surely incorrect */
2153 var->right_margin = 100;
2154 var->upper_margin = 8;
2155 var->lower_margin = 16;
2156 var->hsync_len = 140;
2157 var->vsync_len = 30;
2159 var->height = -1;
2160 var->width = -1;
2162 var->sync = 0;
2164 var->xres = external_xres;
2165 var->yres = external_yres;
2166 var->xres_virtual = external_xres_virtual;
2167 var->bits_per_pixel = external_depth;
2169 var->blue = var->green = var->red;
2170 var->transp.offset = 0;
2171 var->transp.length = 0;
2172 var->transp.msb_right = 0;
2173 var->yres_virtual = var->yres;
2174 var->xoffset = 0;
2175 var->yoffset = 0;
2176 var->nonstd = 0;
2177 var->activate = 0;
2178 var->vmode = FB_VMODE_NONINTERLACED;
2179 return 0;
2182 static void ext_get_par(struct atafb_par *par)
2184 par->screen_base = external_screen_base;
2187 static void ext_set_par(struct atafb_par *par)
2191 #define OUTB(port,val) \
2192 *((unsigned volatile char *) ((port)+external_vgaiobase)) = (val)
2193 #define INB(port) \
2194 (*((unsigned volatile char *) ((port)+external_vgaiobase)))
2195 #define DACDelay \
2196 do { \
2197 unsigned char tmp = INB(0x3da); \
2198 tmp = INB(0x3da); \
2199 } while (0)
2201 static int ext_setcolreg(unsigned int regno, unsigned int red,
2202 unsigned int green, unsigned int blue,
2203 unsigned int transp, struct fb_info *info)
2205 unsigned char colmask = (1 << external_bitspercol) - 1;
2207 if (!external_vgaiobase)
2208 return 1;
2210 if (regno > 255)
2211 return 1;
2213 switch (external_card_type) {
2214 case IS_VGA:
2215 OUTB(0x3c8, regno);
2216 DACDelay;
2217 OUTB(0x3c9, red & colmask);
2218 DACDelay;
2219 OUTB(0x3c9, green & colmask);
2220 DACDelay;
2221 OUTB(0x3c9, blue & colmask);
2222 DACDelay;
2223 return 0;
2225 case IS_MV300:
2226 OUTB((MV300_reg[regno] << 2) + 1, red);
2227 OUTB((MV300_reg[regno] << 2) + 1, green);
2228 OUTB((MV300_reg[regno] << 2) + 1, blue);
2229 return 0;
2231 default:
2232 return 1;
2236 static int ext_detect(void)
2238 struct fb_var_screeninfo *myvar = &atafb_predefined[0];
2239 struct atafb_par dummy_par;
2241 myvar->xres = external_xres;
2242 myvar->xres_virtual = external_xres_virtual;
2243 myvar->yres = external_yres;
2244 myvar->bits_per_pixel = external_depth;
2245 ext_encode_var(myvar, &dummy_par);
2246 return 1;
2249 #endif /* ATAFB_EXT */
2251 /* ------ This is the same for most hardware types -------- */
2253 static void set_screen_base(void *s_base)
2255 unsigned long addr;
2257 addr = atari_stram_to_phys(s_base);
2258 /* Setup Screen Memory */
2259 shifter_st.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
2260 shifter_st.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
2261 shifter_st.bas_lo = (unsigned char)(addr & 0x0000ff);
2264 static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
2266 struct atafb_par *par = (struct atafb_par *)info->par;
2268 if (!fbhw->set_screen_base ||
2269 (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
2270 return -EINVAL;
2271 var->xoffset = up(var->xoffset, 16);
2272 par->screen_base = screen_base +
2273 (var->yoffset * info->var.xres_virtual + var->xoffset)
2274 * info->var.bits_per_pixel / 8;
2275 fbhw->set_screen_base(par->screen_base);
2276 return 0;
2279 /* ------------ Interfaces to hardware functions ------------ */
2281 #ifdef ATAFB_TT
2282 static struct fb_hwswitch tt_switch = {
2283 .detect = tt_detect,
2284 .encode_fix = tt_encode_fix,
2285 .decode_var = tt_decode_var,
2286 .encode_var = tt_encode_var,
2287 .get_par = tt_get_par,
2288 .set_par = tt_set_par,
2289 .set_screen_base = set_screen_base,
2290 .pan_display = pan_display,
2292 #endif
2294 #ifdef ATAFB_FALCON
2295 static struct fb_hwswitch falcon_switch = {
2296 .detect = falcon_detect,
2297 .encode_fix = falcon_encode_fix,
2298 .decode_var = falcon_decode_var,
2299 .encode_var = falcon_encode_var,
2300 .get_par = falcon_get_par,
2301 .set_par = falcon_set_par,
2302 .set_screen_base = set_screen_base,
2303 .blank = falcon_blank,
2304 .pan_display = falcon_pan_display,
2306 #endif
2308 #ifdef ATAFB_STE
2309 static struct fb_hwswitch st_switch = {
2310 .detect = stste_detect,
2311 .encode_fix = stste_encode_fix,
2312 .decode_var = stste_decode_var,
2313 .encode_var = stste_encode_var,
2314 .get_par = stste_get_par,
2315 .set_par = stste_set_par,
2316 .set_screen_base = stste_set_screen_base,
2317 .pan_display = pan_display
2319 #endif
2321 #ifdef ATAFB_EXT
2322 static struct fb_hwswitch ext_switch = {
2323 .detect = ext_detect,
2324 .encode_fix = ext_encode_fix,
2325 .decode_var = ext_decode_var,
2326 .encode_var = ext_encode_var,
2327 .get_par = ext_get_par,
2328 .set_par = ext_set_par,
2330 #endif
2332 static void ata_get_par(struct atafb_par *par)
2334 if (current_par_valid)
2335 *par = current_par;
2336 else
2337 fbhw->get_par(par);
2340 static void ata_set_par(struct atafb_par *par)
2342 fbhw->set_par(par);
2343 current_par = *par;
2344 current_par_valid = 1;
2348 /* =========================================================== */
2349 /* ============== Hardware Independent Functions ============= */
2350 /* =========================================================== */
2352 /* used for hardware scrolling */
2354 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
2356 int err, activate;
2357 struct atafb_par par;
2359 err = fbhw->decode_var(var, &par);
2360 if (err)
2361 return err;
2362 activate = var->activate;
2363 if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
2364 ata_set_par(&par);
2365 fbhw->encode_var(var, &par);
2366 var->activate = activate;
2367 return 0;
2370 /* fbhw->encode_fix() must be called with fb_info->mm_lock held
2371 * if it is called after the register_framebuffer() - not a case here
2373 static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
2375 struct atafb_par par;
2376 int err;
2377 // Get fix directly (case con == -1 before)??
2378 err = fbhw->decode_var(&info->var, &par);
2379 if (err)
2380 return err;
2381 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2382 err = fbhw->encode_fix(fix, &par);
2383 return err;
2386 static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
2388 struct atafb_par par;
2390 ata_get_par(&par);
2391 fbhw->encode_var(var, &par);
2393 return 0;
2396 // No longer called by fbcon!
2397 // Still called by set_var internally
2399 static void atafb_set_disp(struct fb_info *info)
2401 atafb_get_var(&info->var, info);
2402 atafb_get_fix(&info->fix, info);
2404 /* Note: smem_start derives from phys_screen_base, not screen_base! */
2405 info->screen_base = (external_addr ? external_screen_base :
2406 atari_stram_to_virt(info->fix.smem_start));
2409 static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
2410 u_int transp, struct fb_info *info)
2412 red >>= 8;
2413 green >>= 8;
2414 blue >>= 8;
2416 return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info);
2419 static int
2420 atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
2422 int xoffset = var->xoffset;
2423 int yoffset = var->yoffset;
2424 int err;
2426 if (var->vmode & FB_VMODE_YWRAP) {
2427 if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset)
2428 return -EINVAL;
2429 } else {
2430 if (xoffset + info->var.xres > info->var.xres_virtual ||
2431 yoffset + info->var.yres > info->var.yres_virtual)
2432 return -EINVAL;
2435 if (fbhw->pan_display) {
2436 err = fbhw->pan_display(var, info);
2437 if (err)
2438 return err;
2439 } else
2440 return -EINVAL;
2442 info->var.xoffset = xoffset;
2443 info->var.yoffset = yoffset;
2445 if (var->vmode & FB_VMODE_YWRAP)
2446 info->var.vmode |= FB_VMODE_YWRAP;
2447 else
2448 info->var.vmode &= ~FB_VMODE_YWRAP;
2450 return 0;
2454 * generic drawing routines; imageblit needs updating for image depth > 1
2457 #if BITS_PER_LONG == 32
2458 #define BYTES_PER_LONG 4
2459 #define SHIFT_PER_LONG 5
2460 #elif BITS_PER_LONG == 64
2461 #define BYTES_PER_LONG 8
2462 #define SHIFT_PER_LONG 6
2463 #else
2464 #define Please update me
2465 #endif
2468 static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
2470 struct atafb_par *par = (struct atafb_par *)info->par;
2471 int x2, y2;
2472 u32 width, height;
2474 if (!rect->width || !rect->height)
2475 return;
2477 #ifdef ATAFB_FALCON
2478 if (info->var.bits_per_pixel == 16) {
2479 cfb_fillrect(info, rect);
2480 return;
2482 #endif
2485 * We could use hardware clipping but on many cards you get around
2486 * hardware clipping by writing to framebuffer directly.
2487 * */
2488 x2 = rect->dx + rect->width;
2489 y2 = rect->dy + rect->height;
2490 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2491 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2492 width = x2 - rect->dx;
2493 height = y2 - rect->dy;
2495 if (info->var.bits_per_pixel == 1)
2496 atafb_mfb_fillrect(info, par->next_line, rect->color,
2497 rect->dy, rect->dx, height, width);
2498 else if (info->var.bits_per_pixel == 2)
2499 atafb_iplan2p2_fillrect(info, par->next_line, rect->color,
2500 rect->dy, rect->dx, height, width);
2501 else if (info->var.bits_per_pixel == 4)
2502 atafb_iplan2p4_fillrect(info, par->next_line, rect->color,
2503 rect->dy, rect->dx, height, width);
2504 else
2505 atafb_iplan2p8_fillrect(info, par->next_line, rect->color,
2506 rect->dy, rect->dx, height, width);
2508 return;
2511 static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
2513 struct atafb_par *par = (struct atafb_par *)info->par;
2514 int x2, y2;
2515 u32 dx, dy, sx, sy, width, height;
2516 int rev_copy = 0;
2518 #ifdef ATAFB_FALCON
2519 if (info->var.bits_per_pixel == 16) {
2520 cfb_copyarea(info, area);
2521 return;
2523 #endif
2525 /* clip the destination */
2526 x2 = area->dx + area->width;
2527 y2 = area->dy + area->height;
2528 dx = area->dx > 0 ? area->dx : 0;
2529 dy = area->dy > 0 ? area->dy : 0;
2530 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2531 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2532 width = x2 - dx;
2533 height = y2 - dy;
2535 if (area->sx + dx < area->dx || area->sy + dy < area->dy)
2536 return;
2538 /* update sx,sy */
2539 sx = area->sx + (dx - area->dx);
2540 sy = area->sy + (dy - area->dy);
2542 /* the source must be completely inside the virtual screen */
2543 if (sx + width > info->var.xres_virtual ||
2544 sy + height > info->var.yres_virtual)
2545 return;
2547 if (dy > sy || (dy == sy && dx > sx)) {
2548 dy += height;
2549 sy += height;
2550 rev_copy = 1;
2553 if (info->var.bits_per_pixel == 1)
2554 atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
2555 else if (info->var.bits_per_pixel == 2)
2556 atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
2557 else if (info->var.bits_per_pixel == 4)
2558 atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
2559 else
2560 atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
2562 return;
2565 static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
2567 struct atafb_par *par = (struct atafb_par *)info->par;
2568 int x2, y2;
2569 unsigned long *dst;
2570 int dst_idx;
2571 const char *src;
2572 u32 dx, dy, width, height, pitch;
2574 #ifdef ATAFB_FALCON
2575 if (info->var.bits_per_pixel == 16) {
2576 cfb_imageblit(info, image);
2577 return;
2579 #endif
2582 * We could use hardware clipping but on many cards you get around
2583 * hardware clipping by writing to framebuffer directly like we are
2584 * doing here.
2586 x2 = image->dx + image->width;
2587 y2 = image->dy + image->height;
2588 dx = image->dx;
2589 dy = image->dy;
2590 x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
2591 y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
2592 width = x2 - dx;
2593 height = y2 - dy;
2595 if (image->depth == 1) {
2596 // used for font data
2597 dst = (unsigned long *)
2598 ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
2599 dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
2600 dst_idx += dy * par->next_line * 8 + dx;
2601 src = image->data;
2602 pitch = (image->width + 7) / 8;
2603 while (height--) {
2605 if (info->var.bits_per_pixel == 1)
2606 atafb_mfb_linefill(info, par->next_line,
2607 dy, dx, width, src,
2608 image->bg_color, image->fg_color);
2609 else if (info->var.bits_per_pixel == 2)
2610 atafb_iplan2p2_linefill(info, par->next_line,
2611 dy, dx, width, src,
2612 image->bg_color, image->fg_color);
2613 else if (info->var.bits_per_pixel == 4)
2614 atafb_iplan2p4_linefill(info, par->next_line,
2615 dy, dx, width, src,
2616 image->bg_color, image->fg_color);
2617 else
2618 atafb_iplan2p8_linefill(info, par->next_line,
2619 dy, dx, width, src,
2620 image->bg_color, image->fg_color);
2621 dy++;
2622 src += pitch;
2624 } else {
2625 c2p_iplan2(info->screen_base, image->data, dx, dy, width,
2626 height, par->next_line, image->width,
2627 info->var.bits_per_pixel);
2631 static int
2632 atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
2634 switch (cmd) {
2635 #ifdef FBCMD_GET_CURRENTPAR
2636 case FBCMD_GET_CURRENTPAR:
2637 if (copy_to_user((void *)arg, (void *)&current_par,
2638 sizeof(struct atafb_par)))
2639 return -EFAULT;
2640 return 0;
2641 #endif
2642 #ifdef FBCMD_SET_CURRENTPAR
2643 case FBCMD_SET_CURRENTPAR:
2644 if (copy_from_user((void *)&current_par, (void *)arg,
2645 sizeof(struct atafb_par)))
2646 return -EFAULT;
2647 ata_set_par(&current_par);
2648 return 0;
2649 #endif
2651 return -EINVAL;
2654 /* (un)blank/poweroff
2655 * 0 = unblank
2656 * 1 = blank
2657 * 2 = suspend vsync
2658 * 3 = suspend hsync
2659 * 4 = off
2661 static int atafb_blank(int blank, struct fb_info *info)
2663 unsigned short black[16];
2664 struct fb_cmap cmap;
2665 if (fbhw->blank && !fbhw->blank(blank))
2666 return 1;
2667 if (blank) {
2668 memset(black, 0, 16 * sizeof(unsigned short));
2669 cmap.red = black;
2670 cmap.green = black;
2671 cmap.blue = black;
2672 cmap.transp = NULL;
2673 cmap.start = 0;
2674 cmap.len = 16;
2675 fb_set_cmap(&cmap, info);
2677 #if 0
2678 else
2679 do_install_cmap(info);
2680 #endif
2681 return 0;
2685 * New fbcon interface ...
2688 /* check var by decoding var into hw par, rounding if necessary,
2689 * then encoding hw par back into new, validated var */
2690 static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
2692 int err;
2693 struct atafb_par par;
2695 /* Validate wanted screen parameters */
2696 // if ((err = ata_decode_var(var, &par)))
2697 err = fbhw->decode_var(var, &par);
2698 if (err)
2699 return err;
2701 /* Encode (possibly rounded) screen parameters */
2702 fbhw->encode_var(var, &par);
2703 return 0;
2706 /* actually set hw par by decoding var, then setting hardware from
2707 * hw par just decoded */
2708 static int atafb_set_par(struct fb_info *info)
2710 struct atafb_par *par = (struct atafb_par *)info->par;
2712 /* Decode wanted screen parameters */
2713 fbhw->decode_var(&info->var, par);
2714 mutex_lock(&info->mm_lock);
2715 fbhw->encode_fix(&info->fix, par);
2716 mutex_unlock(&info->mm_lock);
2718 /* Set new videomode */
2719 ata_set_par(par);
2721 return 0;
2725 static struct fb_ops atafb_ops = {
2726 .owner = THIS_MODULE,
2727 .fb_check_var = atafb_check_var,
2728 .fb_set_par = atafb_set_par,
2729 .fb_setcolreg = atafb_setcolreg,
2730 .fb_blank = atafb_blank,
2731 .fb_pan_display = atafb_pan_display,
2732 .fb_fillrect = atafb_fillrect,
2733 .fb_copyarea = atafb_copyarea,
2734 .fb_imageblit = atafb_imageblit,
2735 .fb_ioctl = atafb_ioctl,
2738 static void check_default_par(int detected_mode)
2740 char default_name[10];
2741 int i;
2742 struct fb_var_screeninfo var;
2743 unsigned long min_mem;
2745 /* First try the user supplied mode */
2746 if (default_par) {
2747 var = atafb_predefined[default_par - 1];
2748 var.activate = FB_ACTIVATE_TEST;
2749 if (do_fb_set_var(&var, 1))
2750 default_par = 0; /* failed */
2752 /* Next is the autodetected one */
2753 if (!default_par) {
2754 var = atafb_predefined[detected_mode - 1]; /* autodetect */
2755 var.activate = FB_ACTIVATE_TEST;
2756 if (!do_fb_set_var(&var, 1))
2757 default_par = detected_mode;
2759 /* If that also failed, try some default modes... */
2760 if (!default_par) {
2761 /* try default1, default2... */
2762 for (i = 1; i < 10; i++) {
2763 sprintf(default_name,"default%d", i);
2764 default_par = get_video_mode(default_name);
2765 if (!default_par)
2766 panic("can't set default video mode");
2767 var = atafb_predefined[default_par - 1];
2768 var.activate = FB_ACTIVATE_TEST;
2769 if (!do_fb_set_var(&var,1))
2770 break; /* ok */
2773 min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8;
2774 if (default_mem_req < min_mem)
2775 default_mem_req = min_mem;
2778 #ifdef ATAFB_EXT
2779 static void __init atafb_setup_ext(char *spec)
2781 int xres, xres_virtual, yres, depth, planes;
2782 unsigned long addr, len;
2783 char *p;
2785 /* Format is: <xres>;<yres>;<depth>;<plane organ.>;
2786 * <screen mem addr>
2787 * [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type>
2788 * [;<xres-virtual>]]]]]
2790 * 09/23/97 Juergen
2791 * <xres_virtual>: hardware's x-resolution (f.e. ProMST)
2793 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
2795 p = strsep(&spec, ";");
2796 if (!p || !*p)
2797 return;
2798 xres_virtual = xres = simple_strtoul(p, NULL, 10);
2799 if (xres <= 0)
2800 return;
2802 p = strsep(&spec, ";");
2803 if (!p || !*p)
2804 return;
2805 yres = simple_strtoul(p, NULL, 10);
2806 if (yres <= 0)
2807 return;
2809 p = strsep(&spec, ";");
2810 if (!p || !*p)
2811 return;
2812 depth = simple_strtoul(p, NULL, 10);
2813 if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
2814 depth != 16 && depth != 24)
2815 return;
2817 p = strsep(&spec, ";");
2818 if (!p || !*p)
2819 return;
2820 if (*p == 'i')
2821 planes = FB_TYPE_INTERLEAVED_PLANES;
2822 else if (*p == 'p')
2823 planes = FB_TYPE_PACKED_PIXELS;
2824 else if (*p == 'n')
2825 planes = FB_TYPE_PLANES;
2826 else if (*p == 't')
2827 planes = -1; /* true color */
2828 else
2829 return;
2831 p = strsep(&spec, ";");
2832 if (!p || !*p)
2833 return;
2834 addr = simple_strtoul(p, NULL, 0);
2836 p = strsep(&spec, ";");
2837 if (!p || !*p)
2838 len = xres * yres * depth / 8;
2839 else
2840 len = simple_strtoul(p, NULL, 0);
2842 p = strsep(&spec, ";");
2843 if (p && *p)
2844 external_vgaiobase = simple_strtoul(p, NULL, 0);
2846 p = strsep(&spec, ";");
2847 if (p && *p) {
2848 external_bitspercol = simple_strtoul(p, NULL, 0);
2849 if (external_bitspercol > 8)
2850 external_bitspercol = 8;
2851 else if (external_bitspercol < 1)
2852 external_bitspercol = 1;
2855 p = strsep(&spec, ";");
2856 if (p && *p) {
2857 if (!strcmp(p, "vga"))
2858 external_card_type = IS_VGA;
2859 if (!strcmp(p, "mv300"))
2860 external_card_type = IS_MV300;
2863 p = strsep(&spec, ";");
2864 if (p && *p) {
2865 xres_virtual = simple_strtoul(p, NULL, 10);
2866 if (xres_virtual < xres)
2867 xres_virtual = xres;
2868 if (xres_virtual * yres * depth / 8 > len)
2869 len = xres_virtual * yres * depth / 8;
2872 external_xres = xres;
2873 external_xres_virtual = xres_virtual;
2874 external_yres = yres;
2875 external_depth = depth;
2876 external_pmode = planes;
2877 external_addr = addr;
2878 external_len = len;
2880 if (external_card_type == IS_MV300) {
2881 switch (external_depth) {
2882 case 1:
2883 MV300_reg = MV300_reg_1bit;
2884 break;
2885 case 4:
2886 MV300_reg = MV300_reg_4bit;
2887 break;
2888 case 8:
2889 MV300_reg = MV300_reg_8bit;
2890 break;
2894 #endif /* ATAFB_EXT */
2896 static void __init atafb_setup_int(char *spec)
2898 /* Format to config extended internal video hardware like OverScan:
2899 * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
2900 * Explanation:
2901 * <xres>: x-resolution
2902 * <yres>: y-resolution
2903 * The following are only needed if you have an overscan which
2904 * needs a black border:
2905 * <xres_max>: max. length of a line in pixels your OverScan hardware would allow
2906 * <yres_max>: max. number of lines your OverScan hardware would allow
2907 * <offset>: Offset from physical beginning to visible beginning
2908 * of screen in bytes
2910 int xres;
2911 char *p;
2913 if (!(p = strsep(&spec, ";")) || !*p)
2914 return;
2915 xres = simple_strtoul(p, NULL, 10);
2916 if (!(p = strsep(&spec, ";")) || !*p)
2917 return;
2918 sttt_xres = xres;
2919 tt_yres = st_yres = simple_strtoul(p, NULL, 10);
2920 if ((p = strsep(&spec, ";")) && *p)
2921 sttt_xres_virtual = simple_strtoul(p, NULL, 10);
2922 if ((p = strsep(&spec, ";")) && *p)
2923 sttt_yres_virtual = simple_strtoul(p, NULL, 0);
2924 if ((p = strsep(&spec, ";")) && *p)
2925 ovsc_offset = simple_strtoul(p, NULL, 0);
2927 if (ovsc_offset || (sttt_yres_virtual != st_yres))
2928 use_hwscroll = 0;
2931 #ifdef ATAFB_FALCON
2932 static void __init atafb_setup_mcap(char *spec)
2934 char *p;
2935 int vmin, vmax, hmin, hmax;
2937 /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
2938 * <V*> vertical freq. in Hz
2939 * <H*> horizontal freq. in kHz
2941 if (!(p = strsep(&spec, ";")) || !*p)
2942 return;
2943 vmin = simple_strtoul(p, NULL, 10);
2944 if (vmin <= 0)
2945 return;
2946 if (!(p = strsep(&spec, ";")) || !*p)
2947 return;
2948 vmax = simple_strtoul(p, NULL, 10);
2949 if (vmax <= 0 || vmax <= vmin)
2950 return;
2951 if (!(p = strsep(&spec, ";")) || !*p)
2952 return;
2953 hmin = 1000 * simple_strtoul(p, NULL, 10);
2954 if (hmin <= 0)
2955 return;
2956 if (!(p = strsep(&spec, "")) || !*p)
2957 return;
2958 hmax = 1000 * simple_strtoul(p, NULL, 10);
2959 if (hmax <= 0 || hmax <= hmin)
2960 return;
2962 fb_info.monspecs.vfmin = vmin;
2963 fb_info.monspecs.vfmax = vmax;
2964 fb_info.monspecs.hfmin = hmin;
2965 fb_info.monspecs.hfmax = hmax;
2967 #endif /* ATAFB_FALCON */
2969 static void __init atafb_setup_user(char *spec)
2971 /* Format of user defined video mode is: <xres>;<yres>;<depth>
2973 char *p;
2974 int xres, yres, depth, temp;
2976 p = strsep(&spec, ";");
2977 if (!p || !*p)
2978 return;
2979 xres = simple_strtoul(p, NULL, 10);
2980 p = strsep(&spec, ";");
2981 if (!p || !*p)
2982 return;
2983 yres = simple_strtoul(p, NULL, 10);
2984 p = strsep(&spec, "");
2985 if (!p || !*p)
2986 return;
2987 depth = simple_strtoul(p, NULL, 10);
2988 temp = get_video_mode("user0");
2989 if (temp) {
2990 default_par = temp;
2991 atafb_predefined[default_par - 1].xres = xres;
2992 atafb_predefined[default_par - 1].yres = yres;
2993 atafb_predefined[default_par - 1].bits_per_pixel = depth;
2997 int __init atafb_setup(char *options)
2999 char *this_opt;
3000 int temp;
3002 if (!options || !*options)
3003 return 0;
3005 while ((this_opt = strsep(&options, ",")) != NULL) {
3006 if (!*this_opt)
3007 continue;
3008 if ((temp = get_video_mode(this_opt))) {
3009 default_par = temp;
3010 mode_option = this_opt;
3011 } else if (!strcmp(this_opt, "inverse"))
3012 inverse = 1;
3013 else if (!strncmp(this_opt, "hwscroll_", 9)) {
3014 hwscroll = simple_strtoul(this_opt + 9, NULL, 10);
3015 if (hwscroll < 0)
3016 hwscroll = 0;
3017 if (hwscroll > 200)
3018 hwscroll = 200;
3020 #ifdef ATAFB_EXT
3021 else if (!strcmp(this_opt, "mv300")) {
3022 external_bitspercol = 8;
3023 external_card_type = IS_MV300;
3024 } else if (!strncmp(this_opt, "external:", 9))
3025 atafb_setup_ext(this_opt + 9);
3026 #endif
3027 else if (!strncmp(this_opt, "internal:", 9))
3028 atafb_setup_int(this_opt + 9);
3029 #ifdef ATAFB_FALCON
3030 else if (!strncmp(this_opt, "eclock:", 7)) {
3031 fext.f = simple_strtoul(this_opt + 7, NULL, 10);
3032 /* external pixelclock in kHz --> ps */
3033 fext.t = 1000000000 / fext.f;
3034 fext.f *= 1000;
3035 } else if (!strncmp(this_opt, "monitorcap:", 11))
3036 atafb_setup_mcap(this_opt + 11);
3037 #endif
3038 else if (!strcmp(this_opt, "keep"))
3039 DontCalcRes = 1;
3040 else if (!strncmp(this_opt, "R", 1))
3041 atafb_setup_user(this_opt + 1);
3043 return 0;
3046 static int __init atafb_probe(struct platform_device *pdev)
3048 int pad, detected_mode, error;
3049 unsigned int defmode = 0;
3050 unsigned long mem_req;
3051 char *option = NULL;
3053 if (fb_get_options("atafb", &option))
3054 return -ENODEV;
3055 atafb_setup(option);
3056 dev_dbg(&pdev->dev, "%s: start\n", __func__);
3058 do {
3059 #ifdef ATAFB_EXT
3060 if (external_addr) {
3061 dev_dbg(&pdev->dev, "initializing external hw\n");
3062 fbhw = &ext_switch;
3063 atafb_ops.fb_setcolreg = &ext_setcolreg;
3064 defmode = DEFMODE_EXT;
3065 break;
3067 #endif
3068 #ifdef ATAFB_TT
3069 if (ATARIHW_PRESENT(TT_SHIFTER)) {
3070 dev_dbg(&pdev->dev, "initializing TT hw\n");
3071 fbhw = &tt_switch;
3072 atafb_ops.fb_setcolreg = &tt_setcolreg;
3073 defmode = DEFMODE_TT;
3074 break;
3076 #endif
3077 #ifdef ATAFB_FALCON
3078 if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
3079 dev_dbg(&pdev->dev, "initializing Falcon hw\n");
3080 fbhw = &falcon_switch;
3081 atafb_ops.fb_setcolreg = &falcon_setcolreg;
3082 error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, 0,
3083 "framebuffer:modeswitch",
3084 falcon_vbl_switcher);
3085 if (error)
3086 return error;
3087 defmode = DEFMODE_F30;
3088 break;
3090 #endif
3091 #ifdef ATAFB_STE
3092 if (ATARIHW_PRESENT(STND_SHIFTER) ||
3093 ATARIHW_PRESENT(EXTD_SHIFTER)) {
3094 dev_dbg(&pdev->dev, "initializing ST/E hw\n");
3095 fbhw = &st_switch;
3096 atafb_ops.fb_setcolreg = &stste_setcolreg;
3097 defmode = DEFMODE_STE;
3098 break;
3100 fbhw = &st_switch;
3101 atafb_ops.fb_setcolreg = &stste_setcolreg;
3102 dev_warn(&pdev->dev,
3103 "Cannot determine video hardware; defaulting to ST(e)\n");
3104 #else /* ATAFB_STE */
3105 /* no default driver included */
3106 /* Nobody will ever see this message :-) */
3107 panic("Cannot initialize video hardware");
3108 #endif
3109 } while (0);
3111 /* Multisync monitor capabilities */
3112 /* Atari-TOS defaults if no boot option present */
3113 if (fb_info.monspecs.hfmin == 0) {
3114 fb_info.monspecs.hfmin = 31000;
3115 fb_info.monspecs.hfmax = 32000;
3116 fb_info.monspecs.vfmin = 58;
3117 fb_info.monspecs.vfmax = 62;
3120 detected_mode = fbhw->detect();
3121 check_default_par(detected_mode);
3122 #ifdef ATAFB_EXT
3123 if (!external_addr) {
3124 #endif /* ATAFB_EXT */
3125 mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
3126 mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
3127 screen_base = atari_stram_alloc(mem_req, "atafb");
3128 if (!screen_base)
3129 panic("Cannot allocate screen memory");
3130 memset(screen_base, 0, mem_req);
3131 pad = -(unsigned long)screen_base & (PAGE_SIZE - 1);
3132 screen_base += pad;
3133 phys_screen_base = atari_stram_to_phys(screen_base + ovsc_offset);
3134 screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
3135 st_ovsc_switch();
3136 if (CPU_IS_040_OR_060) {
3137 /* On a '040+, the cache mode of video RAM must be set to
3138 * write-through also for internal video hardware! */
3139 cache_push(atari_stram_to_phys(screen_base), screen_len);
3140 kernel_set_cachemode(screen_base, screen_len,
3141 IOMAP_WRITETHROUGH);
3143 dev_info(&pdev->dev, "phys_screen_base %lx screen_len %d\n",
3144 phys_screen_base, screen_len);
3145 #ifdef ATAFB_EXT
3146 } else {
3147 /* Map the video memory (physical address given) to somewhere
3148 * in the kernel address space.
3150 external_screen_base = ioremap_wt(external_addr, external_len);
3151 if (external_vgaiobase)
3152 external_vgaiobase =
3153 (unsigned long)ioremap(external_vgaiobase, 0x10000);
3154 screen_base = external_screen_base;
3155 phys_screen_base = external_addr;
3156 screen_len = external_len & PAGE_MASK;
3157 memset (screen_base, 0, external_len);
3159 #endif /* ATAFB_EXT */
3161 // strcpy(fb_info.mode->name, "Atari Builtin ");
3162 fb_info.fbops = &atafb_ops;
3163 // try to set default (detected; requested) var
3164 do_fb_set_var(&atafb_predefined[default_par - 1], 1);
3165 // reads hw state into current par, which may not be sane yet
3166 ata_get_par(&current_par);
3167 fb_info.par = &current_par;
3168 // tries to read from HW which may not be initialized yet
3169 // so set sane var first, then call atafb_set_par
3170 atafb_get_var(&fb_info.var, &fb_info);
3172 #ifdef ATAFB_FALCON
3173 fb_info.pseudo_palette = current_par.hw.falcon.pseudo_palette;
3174 #endif
3175 fb_info.flags = FBINFO_FLAG_DEFAULT;
3177 if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
3178 NUM_TOTAL_MODES, &atafb_modedb[defmode],
3179 fb_info.var.bits_per_pixel)) {
3180 return -EINVAL;
3183 fb_videomode_to_modelist(atafb_modedb, NUM_TOTAL_MODES,
3184 &fb_info.modelist);
3186 atafb_set_disp(&fb_info);
3188 fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
3191 dev_info(&pdev->dev, "Determined %dx%d, depth %d\n", fb_info.var.xres,
3192 fb_info.var.yres, fb_info.var.bits_per_pixel);
3193 if ((fb_info.var.xres != fb_info.var.xres_virtual) ||
3194 (fb_info.var.yres != fb_info.var.yres_virtual))
3195 dev_info(&pdev->dev, " virtual %dx%d\n",
3196 fb_info.var.xres_virtual, fb_info.var.yres_virtual);
3198 if (register_framebuffer(&fb_info) < 0) {
3199 #ifdef ATAFB_EXT
3200 if (external_addr) {
3201 iounmap(external_screen_base);
3202 external_addr = 0;
3204 if (external_vgaiobase) {
3205 iounmap((void*)external_vgaiobase);
3206 external_vgaiobase = 0;
3208 #endif
3209 return -EINVAL;
3212 fb_info(&fb_info, "frame buffer device, using %dK of video memory\n",
3213 screen_len >> 10);
3215 /* TODO: This driver cannot be unloaded yet */
3216 return 0;
3219 static void atafb_shutdown(struct platform_device *pdev)
3221 /* Unblank before kexec */
3222 if (fbhw->blank)
3223 fbhw->blank(0);
3226 static struct platform_driver atafb_driver = {
3227 .shutdown = atafb_shutdown,
3228 .driver = {
3229 .name = "atafb",
3233 static int __init atafb_init(void)
3235 struct platform_device *pdev;
3237 if (!MACH_IS_ATARI)
3238 return -ENODEV;
3240 pdev = platform_device_register_simple("atafb", -1, NULL, 0);
3241 if (IS_ERR(pdev))
3242 return PTR_ERR(pdev);
3244 return platform_driver_probe(&atafb_driver, atafb_probe);
3247 device_initcall(atafb_init);